polylib 7.01
Zpolyhedron.c
Go to the documentation of this file.
1#include <polylib/polylib.h>
2#include <stdlib.h>
3
4// DEFINITIONS USED BELOW:
5//
6// - a single LBL (sLBL function prefix) is a single lattice associated to
7// a polyhedral domain - can be a union of polyhedra
8//
9// - an LBL is a chained list of single LBLs, with possibly multiple
10// different lattices using the ->next structure element.
11//
12// They use the same type (LBL *), but next is not used in the first case.
13//
14// See the header of Zpolyhedron.h for more information
15
16
17// debug all functions:
18// #define DEBUG
19#ifdef DEBUG
20#define CANONICAL_DEBUG 1
21#define INTERSECTION_DEBUG 1
22#define DIFFERENCE_DEBUG 1
23#define LBLDIFF_DEBUG 1
24#define COMP_DEBUG 1
25#define HOLES_DEBUG 1
26#define SIMPLIFY_DEBUG 1
27#define SIMPLIFY2_DEBUG 1
28#endif
29
30static LBL *LBLConcatenate(LBL *A, LBL *B);
31static LBL *sLBLIntersection(LBL *, LBL *);
32static LBL *sLBLCopy(LBL *A);
33static void sLBLFree(LBL *L);
34static LBL *sLBLComplement(LBL *A);
36// static LBL *sLBL_Difference(LBL *, LBL *);
37static LBL *sLBLImage(LBL *, Matrix *);
38static LBL *sLBLPreimage(LBL *, Matrix *);
39static void sLBLCanonical(LBL *A);
40// static LBL *LBL_sLBL_Difference(LBL *A, LBL *B);
41static Polyhedron *sLBLCompute_holes(LBL *A, Polyhedron **pExact);
42static Bool polyhedron_int_solution(Polyhedron *scan, Value *val, int position);
44static Polyhedron *domain_project(Polyhedron *P, int eliminate);
45static Polyhedron *domain_insert_dim(Polyhedron *D, int move);
46static void LBL_Remove_Empty(LBL *A);
47static void sLBLMake_lattice_equal_to(LBL *A, Matrix *ref);
48
49
50/*
51 * Returns True if 'A' is empty, otherwise returns False.
52 * A can be a non-simplified list of empty LBLs
53 */
55{
56 if(A == NULL)
57 return True;
58 if(A->P == NULL)
59 return True;
60 if(emptyQ(A->P)) {
61 // this one is empty.
62 // return the emptiness of next
63 return(isEmptyLBL(A->next));
64 }
65 return False;
66} /* isEmptyLBL */
67
68
69/*
70 * Given a matrix 'Lat' and a domain 'Domain', allocate space and return
71 * the LBL corresponding to the image of the integer points of 'Poly'
72 * by the affine function 'Lat', in canonical form (HNF, no equalities in
73 * Domain).
74 */
76{
77 LBL *A;
78
79 if(Domain && (Lat->NbColumns != Domain->Dimension + 1)) {
80 errormsg1("LBLAlloc", "dimincomp",
81 "the Lattice and the Polyhedron are not compatible to form a LBL");
82 return NULL;
83 }
84 if(Domain && emptyQ(Domain)) {
85 Domain = NULL;
86 }
87
88 A = malloc(sizeof(LBL));
89 if (!A) {
90 errormsg1("LBLAlloc", "outofmem", "Out of Memory");
91 return NULL;
92 }
93 A->next = NULL;
94 A->P = Domain_Copy(Domain);
95 A->Lat = Matrix_Copy(Lat);
96
97 CanonicalLBL(A);
98 return A;
99} /* LBLAlloc */
100
101
102/*
103 * Free the memory used by the single LBL 'L'
104 * Internal function, users should use LBLFree.
105 */
106static void sLBLFree(LBL *L)
107{
108 if (L == NULL)
109 return;
110 if(L->Lat)
111 Matrix_Free(L->Lat);
112 if(L->P)
113 Domain_Free(L->P);
114 free(L);
115 return;
116} /* sLBLFree */
117
118
119/*
120 * Free the memory used by the LBL 'L'
121 */
122void LBLFree(LBL *L)
123{
124 if (L == NULL)
125 return;
126 LBLFree(L->next);
127 sLBLFree(L);
128} /* LBLFree */
129
130
131/*
132 * Return a copy of the single LBL 'A'.
133 * Internal function, users should use LBLCopy.
134 */
135static LBL *sLBLCopy(LBL *A)
136{
137 return (LBLAlloc(A->Lat, A->P));
138} /* sLBLCopy */
139
140
141/*
142 * Return a copy of the LBL 'L'
143 */
145{
146 LBL *copy;
147 copy = sLBLCopy(L);
148
149 if (L->next != NULL)
150 copy->next = LBLCopy(L->next);
151 return copy;
152} /* LBLCopy */
153
154
155/*
156 * Concatenate the LBLs 'A' and 'B',
157 * and return a pointer to the new LBL.
158 * Consumes the memory of A and of B (no need to free) to build
159 * the result. Internal function only, do not use to build unions.
160 * No simplification, just join them.
161 */
162static LBL *LBLConcatenate(LBL *A, LBL *B)
163{
164 LBL *tmp;
165
166 if (isEmptyLBL(A)) {
167 LBLFree(A);
168 return (B);
169 }
170 if (isEmptyLBL(B)) {
171 LBLFree(B);
172 return (A);
173 }
174
175 // go to the end of A and link B there:
176 for(tmp = A; tmp->next; tmp = tmp->next)
177 ;
178 tmp->next = B;
179
180 return (A);
181} /* LBLConcatenate */
182
183
184/*
185 * Return the empty LBL of dimension 'dimension'
186 * Lat = (0 ... 0 1)^T
187 * P = empty polyhedron of dimension 0
188 */
189LBL *EmptyLBL(int dimension)
190{
191 LBL *A;
192
193 A = malloc(sizeof(LBL));
194 if(!A) {
195 errormsg1("EmptyLBL", "outofmem", "Out of Memory");
196 return(NULL);
197 }
198
199 A->Lat = Matrix_Alloc(dimension+1, 1);
200 for(int j = 0 ; j < dimension; j++) {
201 value_set_si(A->Lat->p[0][j], 0);
202 }
203 value_set_si(A->Lat->p[0][dimension], 1);
204
205 // A->P = Empty_Polyhedron(0);
206 A->P = NULL;
207 A->next = NULL;
208
209 return (A);
210} /* EmptyLBL */
211
212
213/*
214 * Return the universe Z-polyhedron of dimension 'dimension'
215 * Lat = Id
216 * P = Universe_Polyhedron()
217 */
218LBL *UniverseLBL(int dimension)
219{
220 LBL *A;
221
222 A = malloc(sizeof(LBL));
223 if(!A) {
224 errormsg1("EmptyLBL", "outofmem", "Out of Memory");
225 return(NULL);
226 }
227 A->Lat = NULL;
228 Matrix_identity(dimension + 1, &(A->Lat));
229 A->P = Universe_Polyhedron(dimension);
230 A->next = NULL;
231
232 return (A);
233} /* UniverseLBL */
234
235
236/*
237 * Simple inclusion test, return True if all sLBLs of A are also part of B.
238 *
239 * Check if all sLBLs of A are present in B (same Lat matrix, domain covered)
240 */
242{
243 // check if all pieces of A are also present in B
244 for( ; A; A = A->next) {
245 LBL *tmpB;
246 Polyhedron *ddiff;
247 for(tmpB = B; tmpB; tmpB = tmpB->next) {
248 if(isEqualLattice(A->Lat, tmpB->Lat))
249 break; // found
250 }
251 if(! tmpB)
252 return(False); // did not find A->Lat in B
253
254 // check if A->P is included in tmpB->P
255 // (A->P - tmpB->P) should be empty.
256 ddiff = DomainDifference(A->P, tmpB->P, MAXNOOFRAYS);
257 if(! emptyQ(ddiff)) {
258 Domain_Free(ddiff);
259 return(False); // not included
260 }
261 Domain_Free(ddiff);
262 }
263 // every part of A was found in B
264 return(True);
265}
266
267
268/*
269 * Given LBLs A and B, return True if A is included in B,
270 * otherwise return False.
271 */
273{
274 Bool ret = False;
275 LBL *diff;
276
278 return(True);
279 }
280
281 // Could we do better on ZDomains?
282 // the answer is no: the complicated part of the difference is not executed
283 // anyway when the input LBLs are ZDomains.
284
285 diff = LBLDifference(A, B);
286
287 // check if diff is integer empty
288 // search an integer solution, stop as soon as found
289 for(LBL *tmp = diff; tmp; tmp = tmp->next) {
290 if((tmp->P = Domain_Remove_Integer_Empty(tmp->P))) {
291 break;
292 }
293 }
294
295 if(isEmptyLBL(diff)) {
296 ret = True;
297 }
298 LBLFree(diff);
299
300 return ret;
301} /* LBLIncluded */
302
303
304/*
305 * Print the contents of a single LBL 'A'
306 */
307static void sLBLPrint(FILE *fp, const char *format, LBL *A)
308{
309 fprintf(fp, "LBL: Dimension %d\n", A->Lat->NbRows - 1);
310 if(!A->P ) {
311 fprintf(fp, "\n<empty>\n");
312 }
313 else {
314 fprintf(fp, "\nLATTICE:\n");
315 Matrix_Print(fp, format, A->Lat);
316 Polyhedron_Print(fp, format, A->P);
317 }
318} /* LBLPrint */
319
320
321/*
322 * Print the contents of an LBL 'A'
323 */
324void LBLPrint(FILE *fp, const char *format, LBL *A)
325{
326 if(!A) {
327 fprintf(fp, "\n<empty>\n");
328 return;
329 }
330
331 sLBLPrint(fp, format, A);
332 for( A = A->next; A; A = A->next) {
333 fprintf(fp, "\nUNION ");
334 sLBLPrint(fp, format, A);
335 }
336} /* LBLPrint */
337
338
339/*
340 * Return the LBL union of the LBLs 'A' and 'B'. The dimensions of
341 * 'A' and 'B' must be equal.
342 * All the LBLs of the resulting union are in Canonical form.
343 */
345{
346 LBL *Result = NULL;
347
348 // copy A and B, concatenate, Canonicalize, and return :)
349
350 Result = LBLConcatenate(LBLCopy(A), LBLCopy(B));
351
352 CanonicalLBL(Result);
353
354 return Result;
355} /* LBLUnion */
356
357/*
358 * Return the intersection of the LBLs 'A' and 'B'.
359 * The dimensions of 'A' and 'B' must be equal.
360 *
361 * Algorithm:
362 * intersect each piece of A with each piece of B and union all results
363 */
365{
366 LBL *Result = NULL, *tempA, *tempB;
367
368 if (A->Lat->NbRows != B->Lat->NbRows) {
369 errormsg1("LBLIntersection", "dimincomp",
370 "incompatible dimensions between domains");
371 return (NULL);
372 }
373
374 for (tempA = A; tempA; tempA = tempA->next) {
375 for (tempB = B; tempB; tempB = tempB->next) {
376 LBL *Inter;
377 Inter = sLBLIntersection(tempA, tempB);
378 if(Inter) {
379 Result = LBLConcatenate(Inter, Result);
380 }
381 }
382 }
383
384 if (!Result)
385 return (EmptyLBL(A->Lat->NbRows - 1));
386
387 CanonicalLBL(Result);
388
389 return (Result);
390} /* LBLIntersection */
391
392
393/*
394 * Return the difference of the LBLs 'A' - 'B' in canonical form.
395 * The dimensions of 'A' and 'B' must be equal. Note that the
396 * difference of two single LBLs can be a union of LBLs.
397 *
398 * Algorithm:
399 * Let I = A inter B
400 * - check if I is empty -> result = A
401 * - check if A included in I -> result = empty
402 * - general case:
403 * successively remove each single LBL of I from A, return the rest.
404 *
405 */
407{
408 LBL *inter, *res = NULL;
409
410 #ifdef LBLDIFF_DEBUG
411 fprintf(stderr, "-----Entering LBLDiff-----\n");
412 fprintf(stderr, "---- A = ");
413 LBLPrint(stderr, P_VALUE_FMT, A);
414 fprintf(stderr, "---- B = ");
415 LBLPrint(stderr, P_VALUE_FMT, B);
416 #endif
417
418 if(!A) {
419 return(NULL);
420 }
421 if(!B) {
422 return(LBLCopy(A));
423 }
424 if (A->Lat->NbRows != B->Lat->NbRows) {
425 errormsg1("LBLDifference", "dimincomp",
426 "incompatible dimensions between domains");
427 return (NULL);
428 }
429
430 // compute the intersection of A and B
431 inter = LBLIntersection(A, B);
432 if(isEmptyLBL(inter)) {
433 LBLFree(inter);
434 return(LBLCopy(A));
435 }
436
437 // simple check if A is included in inter, then inter == A and result = empty.
438 if(LBL_simple_inclusion_check(A, inter)) {
439 LBLFree(inter);
440 return(EmptyLBL(A->Lat->NbRows - 1));
441 }
442
443 // compute res = A - inter
444 // initialize result: A
445 res = A;
446 // remove all single LBLs composing inter from res:
447 for (LBL *tmpi = inter; tmpi; tmpi = tmpi->next) {
448 LBL *diff, *comp;
449
450 // compute res - tmpi:
451 comp = sLBLComplement(tmpi);
452 diff = LBLIntersection(res, comp);
453 LBLFree(comp);
454
455 if(res != A)
456 LBLFree(res); // free previous res
457 res = diff; // new res = diff
458
459 // early exit if empty
460 if(isEmptyLBL(res))
461 break;
462 }
463
464 LBLFree(inter);
465
466 return (res);
467} /* LBLDifference */
468
469/*
470 * Return the image of the LBL 'A' under the affine transformation function
471 * 'Func'. The number of columns of the function must be equal to the number
472 * of rows in the matrix representing the lattice of 'A'.
473 * Note:: Image((Z1 U Z2), F) = Image(Z1,F) U Image(Z2 U F).
474 */
476{
477 LBL *Result = NULL;
478
479 for (LBL *temp = A; temp; temp = temp->next) {
480 LBL *Im;
481 Im = sLBLImage(temp, Func);
482 Result = LBLConcatenate(Im, Result);
483 }
484 if (Result == NULL)
485 return EmptyLBL(A->Lat->NbRows - 1);
486
487 CanonicalLBL(Result);
488
489 return Result;
490} /* LBLImage */
491
492/*
493 * Return the preimage of the LBL 'A' under the affine transformation 'Func'.
494 * The number of rows of the matrix representing the function 'Func' must be
495 * equal to the number of rows of the matrix representing the lattice of 'A'.
496 */
498
499 LBL *Result = NULL;
500
501 for (LBL *temp = A; temp; temp = temp->next) {
502 LBL *B;
503 B = sLBLPreimage(temp, Func);
504 Result = LBLConcatenate(B, Result);
505 }
506
507 if (Result == NULL)
508 return (EmptyLBL(Func->NbColumns - 1));
509
510 CanonicalLBL(Result);
511 return Result;
512} /* LBLPreimage */
513
514
515
516/*
517 * Return the LBL intersection of the single-LBLs 'A' and 'B'.
518 * The result is always a single LBL, NULL if empty.
519 *
520 * USAGE: A and B's first Lattice considered only (no chained list),
521 * but can contain a polyhedral domain in ->P.
522 *
523 * Algorithm:
524 * - IF the input LBLs are Z-Polyhedra, we can simply compute:
525 * LInter is the intersection of the two lattices AL and BL.
526 * Compute PI = the intersection of the images of AP by AL, and BP by BL
527 * Build the result Z-polyhedron (Linter, preimage of PI by Linter)
528 * - ELSE:
529 * build explicit equalities between points of A and B and simplify.
530 * build the LBL { AL z | BL z' = AL z, z \in AP, z' \in BP },
531 * and remove z' by normalizing the result
532 */
534{
535 LBL *Result = NULL;
536 Matrix *LInter;
537 Polyhedron *PInter, *ImageA, *ImageB, *PreImage;
538
539 #ifdef INTERSECTION_DEBUG
540 fprintf(stderr, "-- Entering sLBLIntersection\nA = ");
541 sLBLPrint(stderr, P_VALUE_FMT, A);
542 fprintf(stderr, "B = ");
543 sLBLPrint(stderr, P_VALUE_FMT, B);
544 #endif
545 if(isEmptyLBL(A) || isEmptyLBL(B))
546 {
547 return(EmptyLBL(A->Lat->NbRows - 1));
548 }
549 LInter = LatticeIntersection(A->Lat, B->Lat);
550 if(isEmptyLattice(LInter)) {
551 Matrix_Free(LInter);
552 #ifdef INTERSECTION_DEBUG
553 fprintf(stderr, "Empty Lattice intersection, result = <empty>\n");
554 fprintf(stderr, "-- exit sLBLIntersection\n");
555 #endif
556 return (NULL);
557 }
558 #ifdef INTERSECTION_DEBUG
559 // fprintf(stderr, "Lattice intersection = LInter = ");
560 // Matrix_Print(stderr, P_VALUE_FMT, LInter);
561 #endif
562
563 if(LatCountZeroCols(A->Lat) == 0 && LatCountZeroCols(B->Lat) == 0 &&
564 LatCountZeroCols(LInter) == 0)
565 {
566 // This works only IF there are no columns of zeros in the LBLs:
567 // they are Z-polyhedra
568
569 ImageA = DomainImage(A->P, A->Lat, MAXNOOFRAYS);
570 ImageB = DomainImage(B->P, B->Lat, MAXNOOFRAYS);
571 PInter = DomainIntersection(ImageA, ImageB, MAXNOOFRAYS);
572 Domain_Free(ImageB);
573 Domain_Free(ImageA);
574 #ifdef INTERSECTION_DEBUG
575 // fprintf(stderr, "imageA inter imageB = PInter = ");
576 // Polyhedron_Print(stderr, P_VALUE_FMT, PInter);
577 #endif
578 if (emptyQ(PInter))
579 Result = NULL;
580 else {
581 PreImage = DomainPreimage(PInter, LInter, MAXNOOFRAYS);
582 Result = LBLAlloc(LInter, PreImage);
583 Domain_Free(PreImage);
584 }
585
586 Matrix_Free(LInter);
587 Domain_Free(PInter);
588 #ifdef INTERSECTION_DEBUG
589 fprintf(stderr, "Z-polyhedra, simplified intersection = ");
590 if(!Result)
591 fprintf(stderr, "empty\n");
592 else
593 LBLPrint(stderr, P_VALUE_FMT, Result);
594 fprintf(stderr, "-- exit sLBLIntersection\n");
595 #endif
596
597 return (Result);
598 }
599 else {
600 // there's an LBL, need to build the exact LBL manually:
601 // { AL z | BL z' = AL z, z \in AP, z' \in BP }
602 // { (0 AL) z' | (-BL AL Al-Bl) z' = 0, z' \in BP
603 // z | z z \in AP }
604 int extra_max_rows = 0, extra_B_row = A->Lat->NbRows - 1;
605 Matrix *newL = NULL, *extra;
606 Polyhedron *newP = NULL, *AP_aligned;
607 Matrix_Free(LInter);
608
609 // (size) BLCols ALCols 1
610 // z' z cst
611 // newL = 0 | AL | Al |
612 // 0 | 0 | 1 | <- this row is in AL already
613 newL = Matrix_Alloc(A->Lat->NbRows,
614 A->Lat->NbColumns + B->Lat->NbColumns - 1);
615 for(int i = 0; i < newL->NbRows; i++) {
616 Vector_Set(newL->p[i], 0, B->Lat->NbColumns-1);
617 Vector_Copy(A->Lat->p[i], &newL->p[i][B->Lat->NbColumns-1],
618 A->Lat->NbColumns);
619 }
620
621 // newP:
622
623 // scan the polyhedra of domains A->P and B->P, and build their constraints
624 // intersections.
625 // Build the constraints:
626 // 0/1 z' z cst
627 // ap0 0 AP Ap # from A->P -> AP_aligned
628 // 0 -BL AL Al-Bl # equalities \ extra
629 // bp0 BP 0 Bp # from B->P /
630
631 // start with a domain of the right dimension (expand dimension of A)
632 AP_aligned = align_context(A->P, A->P->Dimension + B->P->Dimension,
634 #ifdef INTERSECTION_DEBUG
635 fprintf(stderr, "AP_aligned = ");
636 Polyhedron_Print(stderr, P_VALUE_FMT, AP_aligned);
637 #endif
638 // extra will be the matrix containing the extra constraints (including
639 // equalities: AL z = BL z', initialized once before scanning the polyhedra)
640 // count max nbrows of extra
641 for(Polyhedron *BP = B->P; BP; BP = BP->next) {
642 if(A->Lat->NbRows + BP->NbConstraints > extra_max_rows) {
643 extra_max_rows = A->Lat->NbRows + BP->NbConstraints;
644 }
645 }
646 extra = Matrix_Alloc(extra_max_rows, AP_aligned->Dimension + 2);
647 Vector_Set(extra->p[0], 0, extra->NbRows * extra->NbColumns); // init 0
648 // initialize |0 -BL AL Al-Bl| in extra
649 for(int row = 0; row < extra_B_row; row++) {
650 // equality (0 is set already)
651 Vector_Oppose(&B->Lat->p[row][0], &extra->p[row][1],
652 B->Lat->NbColumns - 1); // -BL
653 Vector_Copy (&A->Lat->p[row][0], &extra->p[row][B->Lat->NbColumns],
654 A->Lat->NbColumns - 1); // AL
655 value_substract(extra->p[row][extra->NbColumns - 1], // constant
656 A->Lat->p[row][A->Lat->NbColumns - 1],
657 B->Lat->p[row][B->Lat->NbColumns - 1]);
658 }
659 // scan the intersections of each BP with each AP and build union newP
660 for(Polyhedron *BP = B->P; BP; BP = BP->next) {
661 Polyhedron *P;
662 // complement extra with the Constraints of BP
663 for(int con = 0; con < BP->NbConstraints; con++) {
664 // constraint BP
665 Vector_Copy(BP->Constraint[con], extra->p[extra_B_row + con],
666 BP->Dimension + 1);
667 // + constant Bp
668 value_assign(extra->p[extra_B_row + con][extra->NbColumns-1],
669 BP->Constraint[con][BP->Dimension+1]);
670 }
671 extra->NbRows = extra_B_row + BP->NbConstraints;
672 #ifdef INTERSECTION_DEBUG
673 fprintf(stderr, "extra = ");
674 Matrix_Print(stderr, P_VALUE_FMT, extra);
675 #endif
676
677 for(Polyhedron *AP = AP_aligned; AP; AP = AP->next) {
678 P = AddConstraints(extra->p[0], extra->NbRows, AP, MAXNOOFRAYS);
679 #ifdef INTERSECTION_DEBUG
680 fprintf(stderr, "Adding P = ");
681 Polyhedron_Print(stderr, P_VALUE_FMT, P);
682 #endif
683 if(emptyQ(P)) {
685 }
686 else {
687 newP = AddPolyToDomain(P, newP); // consumes P and newP
688 }
689 }
690 }
691 Matrix_Free(extra);
692 Domain_Free(AP_aligned);
693
694 // Use newL and newP to build result
695 if(newP) {
696 Result = LBLAlloc(newL, newP);
697 }
698 Matrix_Free(newL);
699 Domain_Free(newP);
700 #ifdef INTERSECTION_DEBUG
701 fprintf(stderr, "Manual built intersection = ");
702 LBLPrint(stderr, P_VALUE_FMT, Result);
703 fprintf(stderr, "-- exit sLBLIntersection\n");
704 #endif
705
706 return(Result);
707 }
708
709} /* sLBLIntersection */
710
711
712// /*
713// * Return the difference A - B
714// * between a union of LBLs 'A' and a single LBL 'B'.
715// *
716// * Algo: remove B from each part of A, and build a list of the resulting LBLs
717// *
718// * USAGE: only the first lattice of B is considered
719// * (even if next is not NULL).
720// * Creates a new allocated LBL, not necessarily in canonical form
721// */
722// static LBL *LBL_sLBL_Difference(LBL *A, LBL *B)
723// {
724// LBL *Result = NULL;
725
726// for(; A; A = A->next) {
727// LBL *diff;
728
729// #ifdef LBLDIFF_DEBUG
730// fprintf(stderr, " LBL_sLBL_diff: Removing B from (a part of) A. A = ");
731// sLBLPrint(stderr, P_VALUE_FMT, A);
732// fprintf(stderr, " LBL_sLBL_diff: Removing B from (a part of) A. B = ");
733// sLBLPrint(stderr, P_VALUE_FMT, B);
734// #endif
735
736// diff = sLBL_Difference(A, B); // A - B
737// #ifdef LBLDIFF_DEBUG
738// fprintf(stderr, " LBL_sLBL_diff: diff = ");
739// LBLPrint(stderr, P_VALUE_FMT, diff);
740// #endif
741
742// // simple concatenate of diff and result (not canonical)
743// Result = LBLConcatenate(diff, Result);
744// }
745
746// // Result contains every piece of the solution,
747// // but it is not necessarily in canonical form (will be done be callee)
748// return Result;
749// } /* LBL_sLBL_Difference */
750
751
752/*
753 * Compute the complement of sLBL A: all points z such that z is not in A.
754 *
755 * Algorithm:
756 * Let L = A->Lat, P = A->P.
757 * complement(A) = Universe() - A = union of:
758 * 1- LBL (Z^d, complement hull(A)), with hull(A) = image by L of P
759 * 2- LBL ((Z^d - L), hull(A)) ---- or ((Z^d - L), universe())
760 * 3- holes of A
761 * if L has no zero columns -> empty
762 * = L z' such that there exist no z in A->P such that L z' = L z
763 * -> need exact shadow
764 */
766{
767 // testing a new version, just add dimensions and 0 columns in L, and
768 // compute the complement of the coordinate polyhedron
769 // and add the holes of A at the end.
770 Matrix *id = NULL;
771 Polyhedron *univ, *comp, *holes;
772
773 // compute holes of A:
774 holes = sLBLCompute_holes(A, NULL);
775
776 Matrix_identity(A->Lat->NbRows, &id);
777 A = sLBLCopy(A);
779 Matrix_Free(id);
780 fprintf(stderr, "A lattice equal to Id = ");
781 sLBLPrint(stderr, P_VALUE_FMT, A);
782
783 // // remove the zero dimensions of A->P:
784 // nz = LatCountZeroCols(A->Lat);
785 // Polyhedron *newP = A->P;
786 // for(int dim = 0; dim < nz; dim++) {
787
788 // }
789 // fprintf(stderr, "A expanded with lines in 0-dims = ");
790 // sLBLPrint(stderr, P_VALUE_FMT, A);
791
792 // Compute Universe - A->P
793 univ = Universe_Polyhedron(A->P->Dimension);
794 comp = DomainDifference(univ, A->P, MAXNOOFRAYS);
795 Domain_Free(univ);
796
797 fprintf(stderr, "LINKING: holes(A) = ");
798 Polyhedron_Print(stderr, P_VALUE_FMT, holes);
799 fprintf(stderr, " with comp = ");
800 Polyhedron_Print(stderr, P_VALUE_FMT, comp);
801
802 // just link holes at the end of comp (they are separated)
803 Polyhedron *compEnd = comp;
804 while(compEnd->next)
805 compEnd = compEnd->next;
806 compEnd->next = holes;
807 Domain_Free(A->P);
808 A->P = comp;
809
810 CanonicalLBL(A);
811 fprintf(stderr, "comp(A) = ");
812 sLBLPrint(stderr, P_VALUE_FMT, A);
813
814 return(A);
815}
817{
818 LBL *Result = NULL;
819 Polyhedron *Univ, *hullA, *comp_hullA;
820 LatticeUnion *LatDiff;
821 int nbzeros;
822 #ifdef COMP_DEBUG
823 fprintf(stderr, "\n-- Entering sLBLComplement. A = ");
824 sLBLPrint(stderr, P_VALUE_FMT, A);
825 #endif
826
827 // STEP 1: complement of hull(A)
828 hullA = DomainImage(A->P, A->Lat, MAXNOOFRAYS);
829 Univ = Universe_Polyhedron(A->Lat->NbRows - 1);
830 comp_hullA = DomainDifference(Univ, hullA, MAXNOOFRAYS);
831 #ifdef COMP_DEBUG
832 fprintf(stderr, "STEP 1: Adding hull complement polyhedron: ");
833 Polyhedron_Print(stderr, P_VALUE_FMT, comp_hullA);
834 #endif
835 if (!emptyQ(comp_hullA)) {
836 Matrix *Id;
837 Id = Identity_Matrix(comp_hullA->Dimension + 1);
838 Result = LBLAlloc(Id, comp_hullA);
839 Matrix_Free(Id);
840 }
841 Domain_Free(comp_hullA);
842 Domain_Free(Univ);
843
844 // STEP 2: lattice differences (not L) on hull(A) /or Universe
845 if(hullA && !emptyQ(hullA))
846 {
847 LatDiff = LatticeDifference(NULL, A->Lat);
848 #ifdef COMP_DEBUG
849 fprintf(stderr, "\nSTEP 2: LatDiff =\n");
850 PrintLatticeUnion(stderr, P_VALUE_FMT, LatDiff);
851 #endif
852 // Add all Z-polyhedra to Result: the list of lattices on Universe
853 for(LatticeUnion *lat = LatDiff; lat; lat = lat->next) {
854 LBL *Ztmp;
855 #ifdef COMP_DEBUG
856 fprintf(stderr, "Considering Lat diff: ");
857 Matrix_Print(stderr, P_VALUE_FMT, lat->M);
858 #endif
859 Ztmp = malloc(sizeof(LBL));
860 Ztmp->Lat = lat->M;
861 // can use universe, no need to restrict on the more complicated hullA:
862 // Ztmp->P = DomainPreimage(hullA, lat->M, MAXNOOFRAYS);
863 Ztmp->P = Universe_Polyhedron(lat->M->NbColumns - 1);
864 // remove obvious simplification?
865 // -> not necessary since preimage by integer function.
866 // Ztmp->P = DomainConstraintSimplify(Ztmp->P, MAXNOOFRAYS);
867 #ifdef COMP_DEBUG
868 fprintf(stderr, "Adding: ");
869 sLBLPrint(stderr, P_VALUE_FMT, Ztmp);
870 #endif
871 Ztmp->next = Result;
872 Result = Ztmp;
873 }
874 // free LatticeUnion remaining memory (M has been reused as a lattice)
875 while(LatDiff) {
876 LatticeUnion *next = LatDiff->next;
877 free(LatDiff);
878 LatDiff = next;
879 }
880 }
881 Domain_Free(hullA);
882
883 // STEP 3: holes (if there are zero columns in Lat)
884 if((nbzeros = LatCountZeroCols(A->Lat))) {
885 // there are potential holes
886 Matrix *newL;
887 Polyhedron *holes;
888 holes = sLBLCompute_holes(A, NULL);
889 #ifdef COMP_DEBUG
890 fprintf(stderr, "\nSTEP 3 adding holes = ");
891 Polyhedron_Print(stderr, P_VALUE_FMT, holes);
892 #endif
893
894 if(holes && !emptyQ(holes))
895 {
896 newL = RemoveNColumns(A->Lat, A->Lat->NbColumns-1-nbzeros, nbzeros);
897
898 Result = LBLConcatenate(LBLAlloc(newL, holes), Result);
899 Matrix_Free(newL);
900 }
901 Domain_Free(holes);
902 }
903
904 // CanonicalLBL(Result);
905
906 // Don't need to simplify (remove integer-empty polyhedra)
907 // LBLSimplifyEmpty(Result);
908 #ifdef COMP_DEBUG
909 fprintf(stderr, "\n-- sLBLComplement final result (normalized) = ");
910 LBLPrint(stderr, P_VALUE_FMT, Result);
911 #endif
912
913 return (Result);
914} /* sLBLComplement */
915
916
917/*
918 * complement of LBL A.
919 *
920 * Intersection of the complements of the single LBLs of A
921 */
923{
924 LBL *Result;
925 Result = sLBLComplement(A);
926 for(LBL *tmp = A->next; tmp && Result; tmp = tmp->next) {
927 LBL *comp, *inter;
928 comp = sLBLComplement(tmp);
929 inter = LBLIntersection(Result, comp);
930 LBLFree(Result);
931 LBLFree(comp);
932 Result = inter;
933 }
934
935 CanonicalLBL(Result);
936
937 return(Result);
938} /* LBLComplement */
939
940
941// /*
942// * Return the difference of two single LBLs A - B.
943// * A and B are single LBLs, but the return value can be a union of LBLs!
944// * Creates a new allocated LBL union
945// *
946// * USAGE: only the first lattice of A and B is considered (no union),
947// * but A and B can contain several coordinate polyhedra (in ->P).
948// *
949// * Algorithm:
950// * -> New version: compute A inter complement(B).
951// * -> Former version inspired from the method Gautam describes in his thesis,
952// * modified to handle LBLs.
953// */
954// static LBL *sLBL_Difference(LBL* A, LBL* B)
955// {
956// LBL *Result, *Bcomp; // union of LBLs
957// LBL *Binter; // intersection = single LBL.
958
959// #ifdef DIFFERENCE_DEBUG
960// fprintf(stderr, "-- Entering sLBL_Difference. A = ");
961// sLBLPrint(stderr, P_VALUE_FMT, A);
962// #endif
963// if (A->Lat->NbRows != B->Lat->NbRows) {
964// errormsg1("sLBL_Difference", "dimincomp", "incompatible dimensions");
965// return(NULL);
966// }
967
968// // treat the simple case where the LBLs do not intersect
969// Binter = sLBLIntersection(A, B); // reused below
970// #ifdef DIFFERENCE_DEBUG
971// fprintf(stderr, "Binter = ");
972// LBLPrint(stderr, P_VALUE_FMT, Binter);
973// #endif
974// if(isEmptyLBL(Binter)) {
975// // if B does not intersect A, return A.
976// #ifdef DIFFERENCE_DEBUG
977// fprintf(stderr,
978// "Binter=(A inter B) is empty, so B does not intersect A, we return A\n");
979// #endif
980// LBLFree(Binter);
981// return(LBLCopy(A));
982// }
983
984// // // Separate the computation in 3 phases:
985// // // 0. compute the difference of the image polyhedra P_A \ P_B (=ImDiff) and
986// // // add it to the solution LBL (with lattice L_A).
987// // // This can be an over-approximation of A if A->Lat has zero columns
988// // // (but not of B)
989// // // 1. compute the rest where the intersection of P_A and P_B have same
990// // // dimensions (required for lattice difference)
991// // // 2. intersect the result with A to get rid of the over-approximations
992
993// // LBL *Result = NULL, *Final_Result; // U. of LBLs
994// // LBL *Ainter, *Binter; // single LBL
995// // LatticeUnion *LatDiff;
996// // Polyhedron *imA, *imB, *preimA, *ImDiff, *ImInter; // polyhedral domains
997
998// // // [STEP 0 (includes Gautam's Step 2)]
999// // imA = DomainImage(A->P, A->Lat, MAXNOOFRAYS);
1000// // imB = DomainImage(B->P, B->Lat, MAXNOOFRAYS);
1001// // ImDiff = DomainDifference(imA, imB, MAXNOOFRAYS);
1002// // #ifdef DIFFERENCE_DEBUG
1003// // fprintf(stderr, "ImDiff (hull of A that does not cover B) = ");
1004// // Polyhedron_Print(stderr, P_VALUE_FMT, ImDiff);
1005// // #endif
1006
1007// // // Add (A->Lat, A->P - hull(B)) to the result:
1008// // if (!emptyQ(ImDiff)) {
1009// // Polyhedron *RedPolyDiff;
1010// // RedPolyDiff = DomainPreimage(ImDiff, A->Lat, MAXNOOFRAYS);
1011// // // NOTICE: this can be an over-approximation of A
1012// // Result = LBLAlloc(A->Lat, RedPolyDiff);
1013// // #ifdef DIFFERENCE_DEBUG
1014// // fprintf(stderr, "Adding this to the temporary result: ");
1015// // LBLPrint(stderr, P_VALUE_FMT, Result);
1016// // #endif
1017// // Domain_Free(RedPolyDiff);
1018// // }
1019
1020// // // compute the images intersection of A and B
1021// // ImInter = DomainIntersection(imA, imB, MAXNOOFRAYS);
1022// // #ifdef DIFFERENCE_DEBUG
1023// // fprintf(stderr, "ImInter (hull of A inter B) = ");
1024// // Polyhedron_Print(stderr, P_VALUE_FMT, ImInter);
1025// // #endif
1026
1027// // // (TODO) can be simplified, Ainter not really needed!
1028
1029// // // compute the part of A that intersects the hull of B in the image space
1030// // preimA = DomainPreimage(ImInter, A->Lat, MAXNOOFRAYS);
1031// // Ainter = LBLAlloc(A->Lat, preimA);
1032// // // NOTICE: this Ainter can be a over-approximation of A
1033
1034// // Domain_Free(preimA);
1035// // Domain_Free(ImDiff);
1036// // Domain_Free(imA);
1037// // Domain_Free(imB);
1038
1039// // // now Ainter and Binter have same lattices and polyhedra dimensions
1040// // #ifdef DIFFERENCE_DEBUG
1041// // fprintf(stderr,
1042// // "-- [STEP1] now we compute the intersection on same lattice dimensions\n");
1043// // fprintf(stderr, "Ainter = ");
1044// // LBLPrint(stderr, P_VALUE_FMT, Ainter);
1045// // fprintf(stderr, "and Binter = ");
1046// // LBLPrint(stderr, P_VALUE_FMT, Binter);
1047// // #endif
1048
1049// // // LatDiff (union of lattices) is the difference : (A->Lat) - (B->Lat) of
1050// // // same dimensions
1051// // LatDiff = LatticeDifference(Ainter->Lat, Binter->Lat);
1052// // #ifdef DIFFERENCE_DEBUG
1053// // if(!LatDiff)
1054// // fprintf(stderr, "Empty Lattice difference\n");
1055// // #endif
1056
1057// // // [STEP 1 of Gautam]:
1058// // // Add all Z-polyhedra applying the (list of) lattice difference on ImInter
1059// // for(LatticeUnion *tmp = LatDiff; tmp; tmp = tmp->next) {
1060// // LBL *Ztmp;
1061// // #ifdef DIFFERENCE_DEBUG
1062// // fprintf(stderr, "Considering Lat diff: ");
1063// // Matrix_Print(stderr, P_VALUE_FMT, tmp->M);
1064// // #endif
1065// // Ztmp = malloc(sizeof(*Ztmp));
1066// // Ztmp->next = Result;
1067// // Ztmp->Lat = tmp->M;
1068// // Ztmp->P = DomainPreimage(ImInter, tmp->M, MAXNOOFRAYS);
1069// // // NOTICE: this can be an over-approximation of A (but not of B)
1070
1071// // Result = Ztmp;
1072// // }
1073// // // free LatticeUnion remaining memory (M has been reused as a lattice of
1074// // // Result)
1075// // while(LatDiff) {
1076// // LatticeUnion *next = LatDiff->next;
1077// // free(LatDiff);
1078// // LatDiff = next;
1079// // }
1080
1081// // // (TODO) also consider the intersection of lattices, where some points of
1082// // // lattice B->Lat could have no integer antecedent in B->P and should
1083// // // be kept in the result A - B:
1084// // // Add the holes of B (that can be included in A but not in B).
1085
1086
1087// // Domain_Free(ImInter);
1088// // LBLFree(Ainter);
1089// // LBLFree(Binter);
1090
1091// // if(!Result) {
1092// // #ifdef DIFFERENCE_DEBUG
1093// // fprintf(stderr, "-- result = (NULL)\n");
1094// // #endif
1095// // return(NULL);
1096// // }
1097
1098// // #ifdef DIFFERENCE_DEBUG
1099// // fprintf(stderr, "-- temporary over-approximation of result = ");
1100// // LBLPrint(stderr, P_VALUE_FMT, Result);
1101// // #endif
1102// // // intersect the result with A to get the exact LBL in case there was an
1103// // // over-approximation of A before.
1104// // Final_Result = LBLIntersection(Result, A);
1105// // LBLFree(Result);
1106// // return(Final_Result);
1107
1108// // Which one to use to compute the complement, Binter or B?
1109// // which one is simpler? B is larger... but Binter is part of A
1110// // Binter is probably better to prepare for the intersection
1111// Bcomp = sLBLComplement(Binter);
1112// #ifdef DIFFERENCE_DEBUG
1113// fprintf(stderr, "Difference = intersection (between A and) Bcomp = ");
1114// LBLPrint(stderr, P_VALUE_FMT, Bcomp);
1115// #endif
1116// LBL *nextA = A->next; A->next = NULL; // unlink A from its next
1117// Result = LBLIntersection(Bcomp, A);
1118// A->next = nextA;
1119
1120// LBLFree(Binter);
1121// LBLFree(Bcomp);
1122
1123// #ifdef DIFFERENCE_DEBUG
1124// fprintf(stderr, "Difference = ");
1125// LBLPrint(stderr, P_VALUE_FMT, Result);
1126// #endif
1127
1128// return(Result);
1129// } /* sLBL_Difference */
1130
1131
1132/*
1133 * Return the image of the single LBL 'A' under the affine function 'Func'
1134 *
1135 * Algorithm:
1136 * - Multiply Lat by Func,
1137 * - Canonicalize the result (done by LBLAlloc)
1138 */
1139static LBL *sLBLImage(LBL *A, Matrix *Func)
1140{
1141 Matrix *newL;
1142 LBL *result;
1143
1144 if ((Func->NbColumns != A->Lat->NbRows)) {
1145 errormsg1("sLBLImage", "dimincomp", "Incompatible dimensions");
1146 return NULL;
1147 }
1148
1149 // if there is an eliminated column of zeros in the result:
1150 // LBLAlloc will ensure that eliminated points in the projection
1151 // are integer.
1152
1153 newL = Matrix_Alloc(Func->NbRows, A->Lat->NbColumns);
1154 Matrix_Product(Func, A->Lat, newL);
1155 result = LBLAlloc(newL, A->P);
1156
1157 Matrix_Free(newL);
1158 return(result);
1159} /* sLBLImage */
1160
1161/*
1162 * Return the preimage of the single LBL 'Z' under an affine
1163 * transformation function 'G'. The number of rows of matrix 'G' must
1164 * be equal to the number of rows of the matrix representing the
1165 * lattice of Z.
1166 * Algorithm:
1167 * - if G is invertible, compute the LBL {G^{-1} L, D},
1168 * - else, build the LBL { z' | L z = G z', z \in A->P, z' free},
1169 * and remove z by normalizing the result
1170 */
1172{
1173 LBL *Result;
1174 Polyhedron *P, *newP;
1175 Matrix *Con;
1176
1177 // first try if G is invertible
1178 if(G->NbColumns == G->NbRows) {
1179 const int dim = G->NbColumns;
1180 Matrix *tmp, *inv;
1181 tmp = Matrix_Copy(G);
1182 inv = Matrix_Alloc(dim, dim);
1183 if(Matrix_Inverse(tmp, inv) && value_one_p(inv->p[dim-1][dim-1])) {
1184 // reuse tmp to compute the product Inv Lat
1185 Matrix_Product(inv, Z->Lat, tmp);
1186 Result = LBLAlloc(tmp, Z->P);
1187 Matrix_Free(tmp);
1188 Matrix_Free(inv);
1189 return(Result);
1190 }
1191 Matrix_Free(tmp);
1192 Matrix_Free(inv);
1193 }
1194
1195 if(G->NbRows != Z->Lat->NbRows) {
1196 // G z' = L z
1197 errormsg1("sLBLPreimage", "dimincomp", "incompatible dimensions");
1198 return(NULL);
1199 }
1200
1201 // d is the dimension of Z.
1202 // d' is the number of columns of G = the dimension of the result
1203 // build the Z-polyhedron = { z' | with P in dimension d + d'
1204 // such that L z = G z' }
1205 // then eliminate z by simplifying the result
1206
1207 // the lattice is spreading z'
1208 // homogeneous d and d', homogeneous sum is d+d'-1
1209 int d = Z->Lat->NbRows;
1210 int dp = G->NbColumns;
1211
1212 // z' z cst
1213 // newL = Id | 0 | 0 |
1214 // 0 | 0 | 1 |
1215 Matrix *newL = Matrix_Alloc(dp, d+dp-1);
1216 for(int i = 0; i < newL->NbRows; i++) {
1217 for(int j = 0; j < newL->NbColumns; j++) {
1218 if(j == i && i != newL->NbRows-1) { // left diagonal
1219 value_set_si(newL->p[i][j], 1);
1220 }
1221 else {
1222 value_set_si(newL->p[i][j], 0);
1223 }
1224 }
1225 }
1226 value_set_si(newL->p[newL->NbRows-1][newL->NbColumns-1], 1);
1227
1228 // add the extra dimension on P (first dimensions!)
1229 newP = align_context(Z->P, d+dp-2, MAXNOOFRAYS);
1230
1231 // build the extra constraint to be added to newP: G z' = L z
1232 // con = 0 | | |
1233 // . | G | -L | (g-l)
1234 // 0 | | |
1235 Con = Matrix_Alloc(d-1, d+dp-1+1);
1236 // copy G
1237 for(int i = 0; i < Con->NbRows; i++) {
1238 value_set_si(Con->p[i][0], 0); // equality
1239 for(int j = 0; j < dp-1; j++) {
1240 value_assign(Con->p[i][j+1], G->p[i][j]);
1241 }
1242 // constant
1243 value_assign(Con->p[i][Con->NbColumns-1], G->p[i][G->NbColumns-1]);
1244 }
1245 // copy NEGATIVE L
1246 for(int i = 0; i < Con->NbRows; i++) {
1247 for(int j = 0; j < d-1; j++) {
1248 value_oppose(Con->p[i][j+dp-1+1], Z->Lat->p[i][j]);
1249 }
1250 // substract constant l from g
1251 value_substract(Con->p[i][Con->NbColumns-1],
1252 Con->p[i][Con->NbColumns-1], Z->Lat->p[i][Z->Lat->NbColumns-1]);
1253 }
1254
1255 P = DomainAddConstraints(newP, Con, MAXNOOFRAYS);
1256 Matrix_Free(Con);
1257 Domain_Free(newP);
1258
1259 Result = LBLAlloc(newL, P);
1260 Domain_Free(P);
1261 Matrix_Free(newL);
1262
1263 return(Result);
1264} /* sLBLPreimage */
1265
1266
1267// typedef struct forsimplify {
1268// Polyhedron *Pol;
1269// LatticeUnion *LatUni;
1270// struct forsimplify *next;
1271// } ForSimplify;
1272// /*
1273// * Return the simplified representation of the Z-domain 'ZDom'. It attempts to
1274// * convexize unions of polyhedra when they correspond to the same lattices and
1275// * to simplify union of lattices when they correspond to the same polyhdera.
1276// */
1277// LBL *ZDomainSimplify(LBL *ZDom) {
1278
1279// LBL *Ztmp, *Result;
1280// ForSimplify *Head, *Prev, *Curr;
1281// LBL *ZDomHead, *Emp;
1282
1283// if (ZDom == NULL) {
1284// fprintf(stderr, "\nError in ZDomainSimplify - ZDomHead = NULL\n");
1285// return NULL;
1286// }
1287// if (ZDom->next == NULL)
1288// return (LBLCopy(ZDom));
1289// Emp = EmptyLBL(ZDom->Lat->NbRows - 1);
1290// ZDomHead = LBLUnion(ZDom, Emp);
1291// LBLFree(Emp);
1292// Head = NULL;
1293// Ztmp = ZDomHead;
1294// do {
1295// Polyhedron *Img;
1296// Img = DomainImage(Ztmp->P, Ztmp->Lat, MAXNOOFRAYS);
1297// for (Curr = Head; Curr != NULL; Curr = Curr->next) {
1298// Polyhedron *Diff1;
1299// Bool flag = False;
1300
1301// Diff1 = DomainDifference(Img, Curr->Pol, MAXNOOFRAYS);
1302// if (emptyQ(Diff1)) {
1303// Polyhedron *Diff2;
1304
1305// Diff2 = DomainDifference(Curr->Pol, Img, MAXNOOFRAYS);
1306// if (emptyQ(Diff2))
1307// flag = True;
1308// Domain_Free(Diff2);
1309// }
1310// Domain_Free(Diff1);
1311// if (flag == True) {
1312// LatticeUnion *temp;
1313
1314// temp = malloc(sizeof(LatticeUnion));
1315// temp->M = Matrix_Copy(Ztmp->Lat);
1316// temp->next = Curr->LatUni;
1317// Curr->LatUni = temp;
1318// break;
1319// }
1320// }
1321// if (Curr == NULL) {
1322// Curr = malloc(sizeof(ForSimplify));
1323// Curr->Pol = Domain_Copy(Img);
1324// Curr->LatUni = malloc(sizeof(LatticeUnion));
1325// Curr->LatUni->M = Matrix_Copy(Ztmp->Lat);
1326// Curr->LatUni->next = NULL;
1327// Curr->next = Head;
1328// Head = Curr;
1329// }
1330// Domain_Free(Img);
1331// Ztmp = Ztmp->next;
1332// } while (Ztmp != NULL);
1333
1334// for (Curr = Head; Curr != NULL; Curr = Curr->next)
1335// Curr->LatUni = LatticeSimplify(Curr->LatUni);
1336// Result = NULL;
1337// for (Curr = Head; Curr != NULL; Curr = Curr->next) {
1338// LatticeUnion *L;
1339// for (L = Curr->LatUni; L != NULL; L = L->next) {
1340// Polyhedron *Preim;
1341// LBL *Zpol;
1342
1343// Preim = DomainPreimage(Curr->Pol, L->M, MAXNOOFRAYS);
1344// Zpol = LBLAlloc(L->M, Preim);
1345// Zpol->next = Result;
1346// Result = Zpol;
1347// Domain_Free(Preim);
1348// }
1349// }
1350// Curr = Head;
1351// while (Curr != NULL) {
1352// Prev = Curr;
1353// Curr = Curr->next;
1354// LatticeUnion_Free(Prev->LatUni);
1355// Domain_Free(Prev->Pol);
1356// free(Prev);
1357// }
1358// return Result;
1359// } /* ZDomainSimplify */
1360
1361// /*
1362// *
1363// *
1364// */
1365
1366// LBL *SplitLBL(LBL *ZPol, Matrix *B) {
1367
1368// Matrix *H, *U1, *X, *Y;
1369// LBL *zpnew, *Result;
1370// LatticeUnion *Head = NULL, *tempHead = NULL;
1371
1372// #ifdef DOMDEBUG
1373// FILE *fp;
1374// fp = fopen("_debug", "a");
1375// fprintf(fp, "\nEntered SplitLBL \n");
1376// fclose(fp);
1377// #endif
1378
1379// if (B->NbRows != B->NbColumns) {
1380// fprintf(
1381// stderr,
1382// "\n SplitLBL : The Input Matrix B is not a proper Lattice \n");
1383// return NULL;
1384// }
1385
1386// if (ZPol->Lat->NbRows != B->NbRows) {
1387// fprintf(stderr,
1388// "\nSplitLBL : The Lattice in LBL and B have ");
1389// fprintf(stderr, "incompatible dimensions \n");
1390// return NULL;
1391// }
1392
1393// if (isNormalLattice(ZPol->Lat) != True) {
1394// AffineHermite(ZPol->Lat, &H, &U1);
1395// X = Matrix_Copy(H);
1396// Matrix_Free(U1);
1397// Matrix_Free(H);
1398// } else
1399// X = Matrix_Copy(ZPol->Lat);
1400
1401// if (isNormalLattice(B) != True) {
1402// AffineHermite(B, &H, &U1);
1403// Y = Matrix_Copy(H);
1404// Matrix_Free(H);
1405// Matrix_Free(U1);
1406// } else
1407// Y = Matrix_Copy(B);
1408// if (isEmptyLattice(X)) {
1409// return NULL;
1410// }
1411
1412// Head = Lattice2LatticeUnion(X, Y);
1413
1414// /* If the spliting operation can't be done the result is the original
1415// * Zplyhedron. */
1416
1417// if (Head == NULL) {
1418// Matrix_Free(X);
1419// Matrix_Free(Y);
1420// return LBLCopy(ZPol);
1421// }
1422
1423// Result = NULL;
1424
1425// while (Head) {
1426// tempHead = Head;
1427// Head = Head->next;
1428// zpnew = LBLAlloc(tempHead->M, ZPol->P);
1429// Result = ZDconcatenate(zpnew, Result);
1430// tempHead->next = NULL;
1431// Matrix_Free(tempHead->M);
1432// free(tempHead);
1433// }
1434// Matrix_Free(X);
1435// Matrix_Free(Y);
1436// return Result;
1437// } /* SplitLBL */
1438
1439
1440
1441/***************************************************************************/
1442/* Utility functions for LBL simplification and normalization */
1443/***************************************************************************/
1444
1445/*
1446 * get the matrix of equalities from a polyhedron
1447 * (without the first columns of 0's)
1448 */
1450{
1451 // Eq is the matrix of equations of P (including the constant)
1452 Matrix* Eq = Matrix_Alloc(P->NbEq, P->Dimension+1);
1453 // get equalities (first rows of P->Constraint)
1454 for(int i=0; i<P->NbEq; i++) {
1455 for(int j=0; j<Eq->NbColumns; j++) {
1456 value_assign(Eq->p[i][j], P->Constraint[i][j+1]);
1457 }
1458 }
1459 return (Eq);
1460} /* get_equalities */
1461
1462/*
1463 * compare a matrix of equalities to the one of a polyhedron P
1464 */
1466{
1467 if(P->NbEq != Eq->NbRows)
1468 return (False);
1469
1470 for(int i=0; i<P->NbEq && i<Eq->NbRows; i++) {
1471 for(int j=0; j<Eq->NbColumns; j++) {
1472 if(value_ne(Eq->p[i][j], P->Constraint[i][j+1]))
1473 return (False);
1474 }
1475 }
1476 return (True);
1477} /* same_equalities */
1478
1479
1480/*
1481 * Change A->P such that all polyhedra in this domain have the same set of
1482 * equalities, that is, the equalities of the first polyhedron of this domain.
1483 * All the other ones are added to a new LBL, linked to LBL A (in A->next).
1484 */
1486{
1487 #ifdef CANONICAL_DEBUG
1488 fprintf(stderr, "Checking for equalites in P\n");
1489 #endif
1490 LBL *new = NULL;
1491 Matrix *Equalities = get_equalities(A->P); // get eq from the first one
1492 Polyhedron *nextpp, *prevpp, *pp;
1493
1494 prevpp = A->P;
1495 pp = A->P->next;
1496 while(pp)
1497 {
1498 // check if the equalities of pp->Constraints are the same as the ones
1499 // of matrix Equalities.
1500 nextpp = pp->next;
1501 // nextpp = next polyhedron of the domain (pp can be relinked below:)
1502 if(!same_equalities(Equalities, pp)) {
1503 // if not, get pp out.
1504 if(!new) {
1505 new = malloc(sizeof(LBL));
1506 if (!new) {
1507 errormsg1("sLBLHomogenize_equalities", "outofmem", "Out of Memory");
1508 return(NULL);
1509 }
1510 new->P = NULL;
1511 new->Lat = Matrix_Copy(A->Lat);
1512 }
1513 // remove pp from the list A->P, and get the right next iteration
1514 prevpp->next = pp->next;
1515 // add pp to new->P
1516 pp->next = new->P;
1517 new->P = pp;
1518 // prevpp does not change
1519 }
1520 else {
1521 // move on, keep a pointer to the previous one to relink easily
1522 prevpp = pp;
1523 }
1524 pp = nextpp;
1525 }
1526
1527 if(new) {
1528 // include new in the LBL list A
1529 new->next = A->next;
1530 A->next = new;
1531 #ifdef CANONICAL_DEBUG
1532 fprintf(stderr, "Unified equalites in A->P!\n - First A->P = ");
1533 Polyhedron_Print(stderr, P_VALUE_FMT, A->P);
1534 fprintf(stderr, " - A Next ->P = ");
1535 Polyhedron_Print(stderr, P_VALUE_FMT, A->next->P);
1536 #endif
1537 }
1538 // Now all polyhedra of domain A->P have the same equalities
1539 return(Equalities);
1540}
1541
1542
1543/*
1544 * Simplify the equalities from A->P, in the single LBL A.
1545 * In place. A->P is a domain (all polyhedra have the same set of equalities).
1546 *
1547 * Modifies A->Lat and A->P.
1548 */
1549static void sLBLSimplify_equalities(LBL *A, Matrix *Equalities)
1550{
1551 Matrix *H = NULL, *NewL;
1552 Matrix *eq_hermite = NULL, *ker = NULL;
1553 #ifdef CANONICAL_DEBUG
1554 fprintf(stderr, "P has equalities\n");
1555 fprintf(stderr, "Equality matrix (including constants): ");
1556 Matrix_Print(stderr, P_VALUE_FMT, Equalities);
1557 #endif
1558
1559 // compute the kernel of Equalities matrix using Hermite:
1560 left_hermite(Equalities, &eq_hermite, NULL, &ker);
1561 Matrix_Free(eq_hermite);
1562
1563 // the kernel of Equalities is the last (NbEq) columns of ker
1564 // -----NbEq------
1565 // ker = *..* k_0..k_{NbEq-1} c
1566 // move them left, matrix ker becomes:
1567 // -----NbEq------
1568 // ker = k_0..k_{NbEq-1} c *..*
1569 for(int i = 0; i < ker->NbRows; i++) {
1570 for(int j = 0; j < ker->NbColumns - A->P->NbEq; j++) {
1571 value_assign(ker->p[i][j], ker->p[i][j + A->P->NbEq]);
1572 }
1573 }
1574 // set the right number of columns
1575 ker->NbColumns = ker->NbColumns - A->P->NbEq;
1576 #ifdef CANONICAL_DEBUG
1577 fprintf(stderr, "ker of Eq: ");
1578 Matrix_Print(stderr, P_VALUE_FMT, ker);
1579 #endif
1580
1581 // Compute H = affine HNF of ker:
1582 AffineHermite(ker, &H, NULL);
1583 Matrix_Free(ker);
1584 // We know that: Eq . H = Eq . Ker(Eq) = 0
1585 #ifdef CANONICAL_DEBUG
1586 fprintf(stderr, "Matrix H: ");
1587 Matrix_Print(stderr, P_VALUE_FMT, H);
1588 #endif
1589
1590 // The result is just empty (because it is rational) when the bottom-right
1591 // value of H is not one.
1592 // ----> But this never happens since H is HNF!
1593 // if(value_notone_p(H->p[H->NbRows-1][H->NbColumns-1])) {
1594 // Domain_Free(A->P);
1595 // A->P = NULL; // empty
1596 // }
1597 // else
1598 {
1599 // NewL = L . H
1600 NewL = Matrix_Alloc(A->Lat->NbRows, H->NbColumns);
1601 Matrix_Product(A->Lat, H, NewL);
1602
1603 // NewP = H^{-1} . P
1604 Polyhedron* NewP = DomainPreimage(A->P, H, MAXNOOFRAYS);
1605 // H is not necessarily unimodular, but it has multiplied Lat: this
1606 // newP could have less points than the original one, which is correct
1607 // since some non-integer solutions to the equalities have been removed.
1608
1609 // update A
1610 Domain_Free(A->P);
1611 Matrix_Free(A->Lat);
1612 A->P = NewP;
1613 A->Lat = NewL;
1614 }
1615
1616 Matrix_Free(H);
1617 #ifdef CANONICAL_DEBUG
1618 fprintf(stderr, "New Lat: ");
1619 Matrix_Print(stderr, P_VALUE_FMT, A->Lat);
1620 fprintf(stderr, "New P: ");
1621 Polyhedron_Print(stderr, P_VALUE_FMT, A->P);
1622 #endif
1623} /* sLBLSimplify_equalities */
1624
1625
1626/*
1627 * compute the inside of polyhedron P that can be projected (along dim) to
1628 * get the dark shadow.
1629 *
1630 * consider P a single polyhedron, even if P->next is set.
1631 * return NULL if dark == input P
1632 */
1634{
1635 // check if that dimension is constrained in P
1636 // - if it is not constrained, ignore.
1637 // - if it is positive constrained,
1638 // scan all positive constraints on i_dim of the form:
1639 // {... + alpha . i_dim + ... + c >= 0}, with alpha > 0
1640 // and add this constraint to P:
1641 // {... + alpha . i_dim + ... + c + alpha-1 >= 0}
1642 // - if negative constrained do the opposite
1643 // (take the smallest number of constraints between them)
1644
1645 int pos_constrained = 0, // number of alpha's > 1
1646 neg_constrained = 0, // number of alpha's < -1
1647 eq_constrained = 0; // equality (both pos and neg)
1648 Polyhedron *result;
1649
1650 #ifdef CANONICAL_DEBUG
1651 fprintf(stderr, "Entering dark_source. dimension: %d\n", dim);
1652 fprintf(stderr, "Polyhedron: ");
1653 Polyhedron_Print(stderr, P_VALUE_FMT, P);
1654 #endif
1655 // count constraints abs(alpha) > 1 on this variable (dim)
1656 for(int c = 0; c < P->NbConstraints; c++) {
1657 if(value_zero_p(P->Constraint[c][dim+1])) {
1658 // alpha = 0
1659 continue;
1660 }
1661 if(value_zero_p(P->Constraint[c][0])) {
1662 // should not happen, equalities have been removed before
1663 eq_constrained++;
1664 }
1665 else if(value_pos_p(P->Constraint[c][dim+1]) &&
1666 value_notone_p(P->Constraint[c][dim+1])) {
1667 // alpha > 1 (strict)
1668 pos_constrained++;
1669 }
1670 else if(value_neg_p(P->Constraint[c][dim+1]) &&
1671 value_notmone_p(P->Constraint[c][dim+1])) {
1672 // alpha < -1 (strict)
1673 neg_constrained++;
1674 }
1675 }
1676
1677 if(eq_constrained > 0 || pos_constrained == 0 || neg_constrained == 0) {
1678 // at least one side of the polyhedron is integer or open to infinite,
1679 // so the dark source is just equal to P
1680 return(NULL);
1681 }
1682 else {
1683 // pos_constrained > 0 and neg_constrained > 0.
1684 Matrix *extra;
1685 int nb_extra = 0;
1686 if(pos_constrained < neg_constrained) {
1687 // consider it pos_constrained (less extra to add)
1688 extra = Matrix_Alloc(pos_constrained, P->Dimension + 2);
1689 // add extra constraints on positive ones
1690 for(int c = 0; c < P->NbConstraints; c++) {
1691 if(value_zero_p(P->Constraint[c][dim+1]) ||
1692 value_zero_p(P->Constraint[c][0])) {
1693 continue;
1694 }
1695 if(value_pos_p(P->Constraint[c][dim+1]) &&
1696 value_notone_p(P->Constraint[c][dim+1])) { // alpha > 1 (strict)
1697 // from constraint:
1698 // {... + alpha . i_dim + ... + c >= 0}
1699 // add constraint:
1700 // {... + alpha . i_dim + ... + c - (alpha-1) >= 0}
1701 Vector_Copy(P->Constraint[c], extra->p[nb_extra], P->Dimension + 2);
1702 // constant update: - alpha + 1
1703 value_substract(extra->p[nb_extra][extra->NbColumns-1],
1704 extra->p[nb_extra][extra->NbColumns-1],
1705 extra->p[nb_extra][dim+1]);
1706 value_add_int(extra->p[nb_extra][extra->NbColumns-1],
1707 extra->p[nb_extra][extra->NbColumns-1], 1);
1708 nb_extra++;
1709 }
1710 }
1711 }
1712 else { // neg_constrained
1713 extra = Matrix_Alloc(neg_constrained, P->Dimension + 2);
1714 for(int c = 0; c < P->NbConstraints; c++) {
1715 if(value_zero_p(P->Constraint[c][dim+1]) ||
1716 value_zero_p(P->Constraint[c][0])) {
1717 continue;
1718 }
1719 if(value_neg_p(P->Constraint[c][dim+1]) &&
1720 value_notmone_p(P->Constraint[c][dim+1])) { // alpha < -1 (strict)
1721 // from constraint:
1722 // {... + alpha . i_dim + ... + c >= 0}
1723 // add constraint:
1724 // {... + alpha . i_dim + ... + c - (-alpha-1) >= 0}
1725 Vector_Copy(P->Constraint[c], extra->p[nb_extra], P->Dimension + 2);
1726 // constant update: + alpha + 1
1727 value_addto(extra->p[nb_extra][extra->NbColumns-1],
1728 extra->p[nb_extra][extra->NbColumns-1],
1729 extra->p[nb_extra][dim+1]);
1730 value_add_int(extra->p[nb_extra][extra->NbColumns-1],
1731 extra->p[nb_extra][extra->NbColumns-1], 1);
1732 nb_extra++;
1733 }
1734 }
1735 }
1736 // add the extra constraints
1737 #ifdef CANONICAL_DEBUG
1738 fprintf(stderr, "Adding constraints: ");
1739 Matrix_Print(stderr, P_VALUE_FMT, extra);
1740 #endif
1741 result = AddConstraints(extra->p[0], nb_extra, P, MAXNOOFRAYS);
1742 Matrix_Free(extra);
1743 }
1744
1745 return (result);
1746} /* polyhedron_dark_source */
1747
1748
1749/*
1750 * compute the projection of domain P along dimension eliminate.
1751 *
1752 * P is a polyhedral domain
1753 */
1754static Polyhedron *domain_project(Polyhedron *P, int eliminate)
1755{
1756 Polyhedron *Pext;
1757 Matrix *ray;
1758 // # 1 .......... elim+1 elim+2... dim cst
1759 // --- elim+1 --- xx --- dim-elim ---
1760 //
1761 // new homogeneous dimension of cons and ray matrices: dim + 1.
1762 const int rest = P->Dimension - eliminate;
1763
1764 if(!P || emptyQ(P)) {
1765 return(NULL);
1766 }
1767 #ifdef CANONICAL_DEBUG
1768 fprintf(stderr, "Entering exact shadow -dimension %d- of:", eliminate);
1769 Polyhedron_Print(stderr, P_VALUE_FMT, P);
1770 #endif
1771
1772 // add ray: a line along dimension dim
1773 ray = Matrix_Alloc(1, P->Dimension + 2);
1774 Vector_Set(ray->p[0], 0, P->Dimension + 2);
1775 value_set_si(ray->p[0][eliminate+1], 1);
1776
1777 Pext = DomainAddRays(P, ray, MAXNOOFRAYS);
1778 Matrix_Free(ray);
1779
1780
1781 // just remove the dimension from Pext
1782 for(Polyhedron *tmp = Pext; tmp; tmp = tmp->next) {
1783 // eliminate dimension in constraint matrix
1784 // (keep memory alignment of the Constraints vector of values)
1785 for(int c = 0; c < tmp->NbConstraints; c++) {
1786 if(c != 0)
1787 Vector_Copy(tmp->Constraint[c]+0, tmp->Constraint[c]-c, eliminate + 1);
1788 Vector_Copy(tmp->Constraint[c]+eliminate+2, tmp->Constraint[c]-c+eliminate+1, rest);
1789 tmp->Constraint[c] -= c;
1790 }
1791 // eliminate dimension in ray matrix
1792 // (keep memory alignment of the Ray vector of values)
1793 for(int r = 0; r < tmp->NbRays; r++) {
1794 if(r != 0)
1795 Vector_Copy(tmp->Ray[r]+0, tmp->Ray[r]-r, eliminate + 1);
1796 Vector_Copy(tmp->Ray[r]+eliminate+2, tmp->Ray[r]-r+eliminate+1, rest);
1797 tmp->Ray[r] -= r;
1798 }
1799 tmp->Dimension--;
1800
1801 // remove the null ray that is somewhere...
1802 for(int r = 0; r < tmp->NbRays; r++) {
1803 int i;
1804 for(i = 0; i <= tmp->Dimension; i++) {
1805 if(value_notzero_p(tmp->Ray[r][i]))
1806 break;
1807 }
1808 if(i == tmp->Dimension + 1) {
1809 // r is the null ray, erase it with the end of the ray matrix.
1810 Vector_Copy(tmp->Ray[r+1], tmp->Ray[r], (tmp->NbRays - r - 1) * (tmp->Dimension + 2));
1811 tmp->NbBid--;
1812 tmp->NbRays--;
1813 }
1814 }
1815 }
1816 #ifdef CANONICAL_DEBUG
1817 fprintf(stderr, "projected result P = ");
1818 Polyhedron_Print(stderr, P_VALUE_FMT, Pext);
1819 #endif
1820
1821 return(Pext);
1822} /* domain_project */
1823
1824// // previous version (much slower on large polyhedra!)
1825// static Polyhedron *domain_project1(Polyhedron *P, int dim)
1826// {
1827// Matrix *T; // transformation: Id without the dim column
1828// Polyhedron *image;
1829// #ifdef CANONICAL_DEBUG
1830// fprintf(stderr, "Entering exact shadow -dimension %d- of:", dim);
1831// Polyhedron_Print(stderr, P_VALUE_FMT, P);
1832// #endif
1833
1834// T = Matrix_Alloc(P->Dimension, P->Dimension + 1);
1835// Vector_Set(T->p_Init, 0, T->p_Init_size);
1836// for(int i = 0; i < P->Dimension; i++) {
1837// if(i >= dim) {
1838// value_set_si(T->p[i][i+1], 1);
1839// }
1840// else {
1841// value_set_si(T->p[i][i], 1);
1842// }
1843// }
1844
1845// image = DomainImage(P, T, MAXNOOFRAYS);
1846// #ifdef CANONICAL_DEBUG
1847// fprintf(stderr, "projected result P = ");
1848// Polyhedron_Print(stderr, P_VALUE_FMT, image);
1849// #endif
1850// Matrix_Free(T);
1851
1852// return (image);
1853// } /* domain_project */
1854
1855
1856/*
1857 * compute the dark shadow of domain P projected along dimension dim.
1858 *
1859 * P is a polyhedral domain
1860 */
1862{
1863 Polyhedron *dark = NULL;
1864 for(Polyhedron *pp = P; pp; pp = pp->next) {
1865 Polyhedron *pp_inside, *pp_shadow;
1866
1867 pp_inside = polyhedron_dark_source(pp, dim);
1868 if(pp_inside) {
1869 pp_shadow = domain_project(pp_inside, dim);
1870 }
1871 else {
1872 // pp_inside == pp
1873 Polyhedron *ppnext = pp->next;
1874 pp->next = NULL;
1875 pp_shadow = domain_project(pp, dim);
1876 pp->next = ppnext;
1877 }
1878 dark = AddPolyToDomain(pp_shadow, dark);
1879 if(pp_inside) {
1880 Polyhedron_Free(pp_inside);
1881 }
1882 }
1883 return(dark);
1884} /* domain_dark_shadow */
1885
1886
1887/*
1888 * Generate a polyhedron of just one point
1889 */
1890Polyhedron *GenPoly(int dim, Value *val)
1891{
1892 Matrix *rays;
1893 Polyhedron *res;
1894
1895 rays = Matrix_Alloc(1, dim + 2);
1896 Vector_Copy(val, rays->p[0], dim + 1);
1897 value_set_si(rays->p[0][0], 1); // vertex
1898 value_set_si(rays->p[0][dim + 1], 1); // denominator = 1
1899 res = Rays2Polyhedron(rays, MAXNOOFRAYS);
1900 #ifdef HOLES_DEBUG
1901 fprintf(stderr, "*** generating polyhedron for vertex ***: ");
1902 Matrix_Print(stderr, P_VALUE_FMT, rays);
1903 #endif
1904
1905 Matrix_Free(rays);
1906 return(res);
1907}
1908
1909
1910/*
1911 * Scan a single (hopefully small) pointy polyhedron R, and check if the
1912 * scan hits an integer point.
1913 * R is the intersection of:
1914 * - the shadow (rest) to be scanned whole,
1915 * - AP, the whole domain to check for an integer solution
1916 * Returns the union of polyhedra in the rest that are not holes.
1917 *
1918 * Uses the allocated array of values val of dimension R->dimension+2
1919 * position = index position of current loop index
1920 * (from 1 to R->Dimension)
1921 *
1922 * Recursive,
1923 * - if scanning the shadow (position <= dimrest), scan all possible values
1924 * and recursive call to scan, accumulating all results together
1925 * - if the shadow is scanned already (position > dimrest),
1926 * recursive scan R, but stop as soon as an integer solution is found
1927 *
1928 * val must be set to 0's where not used, val[Dimension+1] must be set to 1.
1929 */
1930Polyhedron *Scan_RestAP(Polyhedron *R, Value *val, int position, int dimrest)
1931{
1932 Polyhedron *Result = NULL;
1933 Value LB, UB;
1934
1935 // -----------------R------------------
1936 // -------rest------- ----------------
1937 // val = 0 * ... * * ... * 1
1938 // idx: 0 1 ... dimrest ... R->Dimension
1939 // |-> position...
1940
1941 if(!R) {
1942 // end here, it is a hit!
1943 // generate polyhedron of the point = value val
1944 return(GenPoly(dimrest, val));
1945 }
1946
1947 #ifdef HOLES_DEBUG
1948 fprintf(stderr, "Enter Scan_Rest, position = %2d.", position);
1949 fprintf(stderr, "val = (");
1950 for(int i=0; i <= R->Dimension + 1; i++) {
1951 value_print(stderr, P_VALUE_FMT, val[i]);
1952 if(i == dimrest || i == 0 || i == R->Dimension)
1953 fprintf(stderr, "::");
1954 }
1955 fprintf(stderr, ")\n");
1956 #endif
1957 value_init(LB);
1958 value_init(UB);
1959
1960 if(position <= dimrest) {
1961 // scan Rest
1962 if(lower_upper_bounds(position, R, val, &LB, &UB) != 0) {
1963 errormsg1("Scan_RestAP", "infinite", "trying to scan infinity!");
1964 return(NULL);
1965 }
1966 // #ifdef HOLES_DEBUG
1967 // fprintf(stderr, "scanR - position %d - looping from ", position);
1968 // value_print(stderr, P_VALUE_FMT, LB);
1969 // fprintf(stderr, "to ");
1970 // value_print(stderr, P_VALUE_FMT "\n", UB);
1971 // #endif
1972
1973 // loop LB -> UB
1974 for(; value_le(LB, UB); value_increment(LB, LB)) {
1975 value_assign(val[position], LB);
1976
1977 Result = AddPolyToDomain(Scan_RestAP(R->next, val, position + 1,
1978 dimrest), Result);
1979 // and continue with all other values
1980 }
1981 // reset value[position] for next scans
1982 value_set_si(val[position], 0);
1983 }
1984 else {
1985 // scan AP
1986 if(lower_upper_bounds(position, R, val, &LB, &UB) != 0) {
1987 // infinite AP, has an int solution.
1988 return(GenPoly(dimrest, val));
1989 }
1990 // #ifdef HOLES_DEBUG
1991 // fprintf(stderr, "scanAP - position %d - looping from ", position);
1992 // value_print(stderr, P_VALUE_FMT, LB);
1993 // fprintf(stderr, "to ");
1994 // value_print(stderr, P_VALUE_FMT "\n", UB);
1995 // #endif
1996
1997 for(; value_le(LB, UB); value_increment(LB, LB)) {
1998 value_assign(val[position], LB);
1999
2000 if((Result = Scan_RestAP(R->next, val, position + 1, dimrest))) {
2001 // it's a hit: stop here and add this point to result :)
2002 value_clear(UB);
2003 value_clear(LB);
2004 value_set_si(val[position], 0);
2005 // early exit
2006 return(Result);
2007 }
2008 }
2009 // reset value for next scans
2010 value_set_si(val[position], 0);
2011 }
2012
2013 value_clear(UB);
2014 value_clear(LB);
2015 return(Result);
2016} /* Scan_RestAP */
2017
2018
2020{
2021 int num_lr; // number of lines+rays
2022 const int dim = D->Dimension;
2023 Value ONE;
2024 Matrix *new_rays;
2025 Polyhedron *res;
2026
2027 value_init(ONE);
2028 value_set_si(ONE, 1);
2029
2030 // count number of lines/rays
2031 for(num_lr = 0; num_lr < D->NbRays; num_lr++) {
2032 if(value_notzero_p(D->Ray[num_lr][0])
2033 && value_notzero_p(D->Ray[num_lr][dim + 1])) {
2034 break;
2035 }
2036 }
2037
2038 // build the matrix of vertices of the bounded D:
2039 // original vertices + each line/ray added to each of them.
2040 new_rays = Matrix_Alloc((D->NbRays - num_lr) * (num_lr + 1), dim + 2);
2041 new_rays->NbRows = 0;
2042
2043 for(int v = num_lr; v < D->NbRays; v++) {
2044 // copy the original vertex v:
2045 Vector_Copy(D->Ray[v], new_rays->p[new_rays->NbRows], dim + 2);
2046 new_rays->NbRows++;
2047 // add each line/ray to v (taking v's divisor into account)
2048 for(int l = 0; l < num_lr; l++) {
2049 Vector_Combine(D->Ray[v], D->Ray[l], new_rays->p[new_rays->NbRows], ONE,
2050 D->Ray[v][dim + 1], dim + 1);
2051 value_assign(new_rays->p[new_rays->NbRows][dim + 1], D->Ray[v][dim + 1]);
2052 new_rays->NbRows++;
2053 }
2054 }
2055 res = Rays2Polyhedron(new_rays, MAXNOOFRAYS);
2056 Matrix_Free(new_rays);
2057 value_clear(ONE);
2058 return(res);
2059}
2060
2061/*
2062 * Compute the coordinate polyhedron containing the holes of the single LBL A.
2063 *
2064 * Usage: set *pExact to the exact shadow if the pointer is not NULL
2065 * (can be used by caller)
2066 *
2067 * Algo:
2068 * - compute the domain rest = (exact shadow - dark shadow)
2069 * - scan all its integer points and verify for each point:
2070 * if there is an integer point in the intersection with the coordinate
2071 * polyhedron, add it to the polyhedral domain not_a_hole
2072 * - return (rest - not_a_hole)
2073 *
2074 * TODO: the output is not necessarily a bounded polyhedron!
2075 * we can add the rays from the rest polyhedra to the result...
2076 * but the rays have to be removed from rest before the scan (bound rest with
2077 * those rays -> vertices), else the scan is not bounded!
2078 */
2080{
2081 int nbzeros;
2082 Polyhedron *exact = A->P, *dark = A->P; // initialize with P then project
2083 Polyhedron *rest, *rest_AP; // exact shadow - dark shadow (polyhedral domain)
2084 Polyhedron *tmp, *U0, *not_a_hole = NULL, *holes;
2085 Vector *v;
2086
2087
2088 #ifdef HOLES_DEBUG
2089 fprintf(stderr, "\n-- Entering compute holes. A = ");
2090 sLBLPrint(stderr, P_VALUE_FMT, A);
2091 #endif
2092 nbzeros = LatCountZeroCols(A->Lat);
2093 if(nbzeros == 0) {
2094 return(NULL);
2095 }
2096 for(int z = 0; z < nbzeros; z++) {
2097 Polyhedron *d, *e; // shadow polyhedra after eliminating the column
2098 int col = A->Lat->NbColumns - 2 - z;
2099
2100 d = domain_dark_shadow(dark, col);
2101 e = domain_project(exact, col);
2102 if(dark != A->P) { // (do not free the original A->P first ones)
2103 Domain_Free(dark); // no longer need the previous calculated ones
2104 Domain_Free(exact);
2105 }
2106 dark = d;
2107 exact = e;
2108 }
2109 #ifdef HOLES_DEBUG
2110 fprintf(stderr, "\nDark = ");
2111 Polyhedron_Print(stderr, P_VALUE_FMT, dark);
2112 fprintf(stderr, "Exact = ");
2113 Polyhedron_Print(stderr, P_VALUE_FMT, exact);
2114 #endif
2115
2116 // rest is the polyhedral domain (exact - dark) in origin-nbzero col space
2117 rest = DomainDifference(exact, dark, MAXNOOFRAYS);
2118 Domain_Free(dark);
2119 if(pExact) {
2120 *pExact = exact; // keep a copy of exact shadow (caller can reuse it)
2121 }
2122 else {
2123 Domain_Free(exact);
2124 }
2125
2126 // make rest disjoint to scan each point once
2127 tmp = Disjoint_Domain(rest, 0, MAXNOOFRAYS);
2128 Domain_Free(rest);
2129 rest = tmp;
2130
2131 // simplify obvious non integer cases
2133
2134 // exit if rest is empty
2135 if(!rest || emptyQ(rest)) {
2136 Domain_Free(rest);
2137 return(NULL);
2138 }
2139 #ifdef HOLES_DEBUG
2140 fprintf(stderr, "Rest = (Exact - Dark) = ");
2141 Polyhedron_Print(stderr, P_VALUE_FMT, rest);
2142 #endif
2143
2144 // // PREPARE SCAN:
2145 // vector of fixed values
2146 v = Vector_Alloc(A->P->Dimension + 2);
2147 // universe (dim 0)
2148 U0 = Universe_Polyhedron(0);
2149
2150
2151 // scan each piece of rest_AP
2152 for(Polyhedron *R = rest; R; R = R->next) {
2153 Polyhedron *nextR, *inter, *bounded_rest;
2154 Polyhedron *new_not_a_hole = NULL;
2155 // nullify next R to ensure we work on a single rest
2156 nextR = R->next; // save and
2157 R->next = NULL; // unlink next
2158
2159 // Check if R is bounded. If it is not, just make it a bounded box
2160 // (add the lines/rays to the vertices to get vertices)
2161 // the holes are necessarily regular in a not bounded piece of R.
2162 // keep memory of the lines/rays in R to add them back to the solution
2163 if(value_zero_p(R->Ray[0][0])
2164 || value_zero_p(R->Ray[0][R->Dimension + 1]))
2165 bounded_rest = bound_polyhedron(R);
2166 else
2167 bounded_rest = R;
2168
2169 // rest_AP = bounded_rest dimension expanded to A->P
2170 rest_AP = bounded_rest;
2171 for(int d = R->Dimension + 1; d <= A->P->Dimension; d++) {
2172 tmp = domain_insert_dim(rest_AP, d);
2173 if(rest_AP != bounded_rest)
2174 Domain_Free(rest_AP);
2175 rest_AP = tmp;
2176 }
2177 // intersect with A->P
2178 inter = DomainIntersection(rest_AP, A->P, MAXNOOFRAYS);
2179 inter = DomainConstraintSimplify(inter, MAXNOOFRAYS);
2180 if(rest_AP != bounded_rest)
2181 Domain_Free(rest_AP);
2182
2183 // scan the pieces of inter = (R inter A->P), compute holes
2184 while(inter) {
2185 Polyhedron *scanR, *nextI;
2186 nextI = inter->next;
2187 inter->next = NULL;
2188
2189 // prepare to scan the points of rest
2190 scanR = Polyhedron_Scan(inter, U0, MAXNOOFRAYS);
2191
2192 // init vector to (0...0 1)
2193 Vector_Set(v->p, v->Size-1, 0);
2194 value_set_si(v->p[v->Size-1], 1);
2195
2196 // scan
2197 #ifdef HOLES_DEBUG
2198 fprintf(stderr, "------- Calling Scan_Rest -------\n");
2199 fprintf(stderr, " scanR = ");
2200 Polyhedron_Print(stderr, P_VALUE_FMT, scanR);
2201 #endif
2202 // scan: search points that are not holes
2203 // (*original* R dimension passed to the function)
2204 tmp = Scan_RestAP(scanR, v->p, 1, R->Dimension);
2205 // update new_not_a_hole
2206 while(tmp) {
2207 Polyhedron *next = tmp->next;
2208 tmp->next = NULL;
2209 new_not_a_hole = AddPolyToDomain(tmp, new_not_a_hole);
2210 tmp = next;
2211 }
2212
2213 Domain_Free(scanR);
2214 Polyhedron_Free(inter);
2215 inter = nextI;
2216 } // while(inter)
2217
2218 #ifdef HOLES_DEBUG
2219 fprintf(stderr, "got not holes = ");
2220 Polyhedron_Print(stderr, P_VALUE_FMT, new_not_a_hole);
2221 fprintf(stderr, "------- End Scan_Rest -------\n");
2222 #endif
2223
2224 // if R was unbounded
2225 if(bounded_rest != R) {
2226 int num_lr;
2227 Matrix *lines_rays;
2228 Domain_Free(bounded_rest);
2229
2230 if(new_not_a_hole) {
2231 // add lines/rays of rest to new_not_a_hole
2232 for(num_lr = 0; num_lr < R->NbRays; num_lr++) {
2233 if(value_notzero_p(R->Ray[num_lr][0])
2234 && value_notzero_p(R->Ray[num_lr][R->Dimension + 1])) {
2235 break;
2236 }
2237 }
2238 lines_rays = Matrix_Alloc(num_lr, R->Dimension + 2);
2239 Vector_Copy(R->Ray[0], lines_rays->p[0], num_lr * (R->Dimension + 2));
2240 tmp = DomainAddRays(new_not_a_hole, lines_rays, MAXNOOFRAYS);
2241 Domain_Free(new_not_a_hole);
2242 new_not_a_hole = tmp;
2243 Matrix_Free(lines_rays);
2244 }
2245 #ifdef HOLES_DEBUG
2246 fprintf(stderr, "not holes was unbounded, new_not_a_hole = ");
2247 Polyhedron_Print(stderr, P_VALUE_FMT, new_not_a_hole);
2248 #endif
2249 }
2250 // not_a_hole = link new_not_a_hole and not_a_hole
2251 if(new_not_a_hole) {
2252 Polyhedron *end = new_not_a_hole;
2253 while(end->next)
2254 end = end->next;
2255 end->next = not_a_hole;
2256 not_a_hole = new_not_a_hole;
2257 }
2258
2259 R->next = nextR;
2260 } // for(R)
2261
2262 Vector_Free(v);
2263 Domain_Free(U0);
2264 #ifdef HOLES_DEBUG
2265 fprintf(stderr, "------- end loop on rest -------\n");
2266 fprintf(stderr, "not holes in (exact-dark) = ");
2267 Polyhedron_Print(stderr, P_VALUE_FMT, not_a_hole);
2268 #endif
2269
2270 // build final domain: (rest - not_a_hole)
2271 holes = DomainDifference(rest, not_a_hole, MAXNOOFRAYS);
2272 holes = DomainConstraintSimplify(holes, MAXNOOFRAYS);
2273 holes = Domain_Remove_Integer_Empty(holes);
2274 Domain_Free(rest);
2275 Domain_Free(not_a_hole);
2276 if(!holes || emptyQ(holes)) {
2277 #ifdef HOLES_DEBUG
2278 fprintf(stderr, "sLBLCompute_holes returning: <NULL>\n");
2279 #endif
2280 Domain_Free(holes);
2281 return(NULL); // no holes
2282 }
2283
2284 #ifdef HOLES_DEBUG
2285 fprintf(stderr, "------- end sLBLCompute_holes -------\n");
2286 fprintf(stderr, "returning holes = ");
2287 Polyhedron_Print(stderr, P_VALUE_FMT, holes);
2288 #endif
2289 return(holes);
2290} /* sLBLCompute_holes */
2291
2292
2293/*
2294 * Try to eliminate the zero columns of lattice A->Lat through
2295 * projection.
2296 *
2297 * Successive (along each zero-dimension)
2298 * elimination if exact shadow == dark shadow
2299 * Restart again from last column after a successful column elimination.
2300 */
2302{
2303 Bool modified = False; // True if something was projected
2304 #ifdef CANONICAL_DEBUG
2305 fprintf(stderr, "Entering sLBL_Simplify_Zero_Dimensions\n");
2306 #endif
2307
2308 // scan the zero columns on the right of A->Lat
2309 for (int col = A->Lat->NbColumns-2 ; col >= 0; col--) {
2310 int i;
2311 for (i = 0; i < A->Lat->NbRows; i++) {
2312 if (value_notzero_p(A->Lat->p[i][col])) {
2313 break;
2314 }
2315 }
2316 if(i == A->Lat->NbRows) {
2317 // col is empty
2318 // Compute the dark shadow and the exact shadow.
2319 // If dark shadow is in exact shadow: can project out the dimension
2320 // else: keep
2321
2322 // What if some polyhedra of the union can be simplified and others
2323 // cannot? should we separate them or just stay at the domain level?
2324 // -> staying at the domain level keeps the number of lattices low,
2325 // so it's probably best, even if they have zero-columns...
2326 Polyhedron *dark = domain_dark_shadow(A->P, col);
2327 // compute exact projection of P and check if dark covers exact:
2328 Polyhedron *exact = domain_project(A->P, col);
2329 Polyhedron *diff;
2330 diff = DomainDifference(exact, dark, MAXNOOFRAYS); // diff = exact - dark
2331
2332 if(! emptyQ(diff)) {
2333 // try to remove obvious integer-empty solutions.
2335 }
2336 // could check if diff has no integer solution... but this is complex.
2337 // Reserved for LBLSimplify()
2338
2339 if(emptyQ(diff)) {
2340 // if exact - dark = 0, project out the column :)
2341 Matrix *newL;
2342 #ifdef CANONICAL_DEBUG
2343 fprintf(stderr, "Exact == Dark. Removing column %d of Lat\n", col);
2344 #endif
2345
2346 Domain_Free(A->P);
2347 A->P = exact;
2348 // remove column from A->Lat
2349 newL = RemoveColumn(A->Lat, col);
2350 Matrix_Free(A->Lat);
2351 A->Lat = newL;
2352 if(col != A->Lat->NbColumns-2) {
2353 // one of the "inner" columns was eliminated, check at the end if
2354 // one of the outer one can be eliminated now: call this same
2355 // function at the end to try again.
2356 modified = True;
2357 }
2358 }
2359 else {
2360 #ifdef CANONICAL_DEBUG
2361 fprintf(stderr, "Exact != Dark. Keeping column %d of Lat\n", col);
2362 #endif
2363 Domain_Free(exact);
2364 }
2365 Domain_Free(diff);
2366 Domain_Free(dark);
2367 }
2368 else {
2369 // non empty column, everything on the left is also non empty, exit loop.
2370 break;
2371 }
2372 }
2373 #ifdef CANONICAL_DEBUG
2374 fprintf(stderr, "Exiting sLBL_Simplify_Zero_Dimensions\n");
2375 LBLPrint(stderr, P_VALUE_FMT, A);
2376 #endif
2377 if(modified) {
2378 // an inner column was eliminated, we can try again to eliminate
2379 // another one
2381 }
2382} /* sLBL_Simplify_Zero_Dimensions */
2383
2384
2385/*
2386 * Set the affine function A->Lat to normal form in single LBL 'A'.
2387 * In place. A->P is a domain.
2388 */
2390{
2391 // check if A->Lat is in Hermite form
2392 if(!isNormalLattice(A->Lat)) {
2393 #ifdef CANONICAL_DEBUG
2394 fprintf(stderr, "A is not HNF\n");
2395 #endif
2396 Matrix* U = NULL;
2397 Matrix* H = NULL;
2398
2399 // to compute HNF of the lattice (constant part moved left/top)
2401
2402 // We will use U of left Hermite, such that LU = H.
2403 left_hermite(A->Lat, &H, NULL, &U);
2404
2405 // Move the constant back to right/bottom in H and U.
2408
2409 // set the new Lat matrix as H
2410 Matrix_Free(A->Lat);
2411 A->Lat = H;
2412
2413 #ifdef CANONICAL_DEBUG
2414 fprintf(stderr, "New Lat (HNF): ");
2415 Matrix_Print(stderr, P_VALUE_FMT, A->Lat);
2416 fprintf(stderr, "U = ");
2417 Matrix_Print(stderr, P_VALUE_FMT, U);
2418 #endif
2419
2420 // Now update of A->P using the preimage by U (is unimodular)
2421 Polyhedron *NewP = DomainPreimage(A->P, U, MAXNOOFRAYS);
2422 Domain_Free(A->P);
2423 A->P = NewP;
2424 Matrix_Free(U);
2425
2426 #ifdef CANONICAL_DEBUG
2427 fprintf(stderr, "New P: ");
2428 Polyhedron_Print(stderr, P_VALUE_FMT, A->P);
2429 #endif
2430 // A->Lat is now in canonical form
2431 }
2432 else {
2433 #ifdef CANONICAL_DEBUG
2434 fprintf(stderr, "A is HNF.\n");
2435 #endif
2436 }
2437} /* sLBL_Lat_Normalize */
2438
2439
2440/*
2441 * Remove the empty sLBL's from a list of LBLs.
2442 * In place.
2443 */
2444static void LBL_Remove_Empty(LBL *A)
2445{
2446 LBL *current, *previous;
2447 #ifdef CANONICAL_DEBUG
2448 fprintf(stderr, "Entering Remove_Empty\n");
2449 #endif
2450
2451 if(!A)
2452 return;
2453
2454 // Scan from A->next, and relink previous to next if empty found
2455 previous = A;
2456 current = A->next;
2457 while(current) {
2458 if(!current->P || emptyQ(current->P)) {
2459 // remove current
2460 #ifdef CANONICAL_DEBUG
2461 fprintf(stderr, "Found empty sLBL, relinking previous to next\n");
2462 #endif
2463 previous->next = current->next; // relink previous
2464 Domain_Free(current->P); // free current
2465 Matrix_Free(current->Lat);
2466 free(current);
2467 current = previous->next; // new current (previous does not change)
2468 }
2469 else {
2470 // advance to next
2471 previous = current;
2472 current = current->next;
2473 }
2474 }
2475
2476 // At the end, if there is something linked to an empty LBL, need to replace
2477 // the content of head A with the one of A->next (and free A->next)
2478 if(A->next && (!A->P || emptyQ(A->P))) {
2479 LBL *nextA;
2480 #ifdef CANONICAL_DEBUG
2481 fprintf(stderr, "Found empty sLBL at head, replacing head with next\n");
2482 #endif
2483 nextA = A->next;
2484 Domain_Free(A->P);
2485 Matrix_Free(A->Lat);
2486 *A = *nextA;
2487 free(nextA);
2488 }
2489
2490 // If A is empty, make sure it is canonical
2491 if(A->P && emptyQ(A->P)) {
2492 // not canonical if A->P is not NULL
2493 Domain_Free(A->P);
2494 A->P = NULL;
2495 // if empty, we do not care about the number of columns of A
2496 // (was:)
2497 // int dimension = A->Lat->NbRows;
2498 // if(A->Lat->NbColumns != 1) {
2499 // Matrix_Free(A->Lat);
2500 // A->Lat = Matrix_Alloc(dimension, 1);
2501 // for(int j=0 ; j < dimension-1; j++) {
2502 // value_set_si(A->Lat->p[0][j], 0);
2503 // }
2504 // value_set_si(A->Lat->p[0][dimension-1], 1);
2505 // }
2506 }
2507 #ifdef CANONICAL_DEBUG
2508 fprintf(stderr, "Exit Remove_Empty, A = ");
2509 LBLPrint(stderr, P_VALUE_FMT, A);
2510 #endif
2511} /* LBL_Remove_Empty */
2512
2513
2514/*
2515 * check for an integer solution of a polyhedron scan, return True if found
2516 * else, return False
2517 *
2518 * scan P, and return True as soon as an integer point is found.
2519 * The found integer solution is in the array val.
2520 */
2521static Bool polyhedron_int_solution(Polyhedron *scan, Value *val, int position)
2522{
2523 Value LB, UB;
2524
2525 #ifdef SIMPLIFY_DEBUG2
2526 fprintf(stderr, " Entering polyhedron_int_solution: position = %d, val = [",
2527 position);
2528 for(int p=1 ; p<=position; p++)
2529 value_print(stderr, P_VALUE_FMT, val[p]);
2530 fprintf(stderr, "]\n");
2531 #endif
2532 if(! scan) {
2533 // found an integer point, exit
2534 return(True);
2535 }
2536
2537 value_init(LB);
2538 value_init(UB);
2539 if(lower_upper_bounds(position, scan, val, &LB, &UB)) {
2540 #ifdef SIMPLIFY_DEBUG2
2541 fprintf(stderr, " polyhedron_int_solution: lower_upper_bounds not zero\n");
2542 #endif
2543 // infinite, should never happen here (should not call the scan)
2544 fprintf(stderr, "polyhedron_int_solution: infinite lower/upper bound\n");
2545 value_clear(UB);
2546 value_clear(LB);
2547 return(True); // True if infinity
2548 }
2549 else {
2550 #ifdef SIMPLIFY_DEBUG2
2551 fprintf(stderr, " polyhedron_int_solution: LB/UB = ");
2552 value_print(stderr, P_VALUE_FMT, LB);
2553 value_print(stderr, P_VALUE_FMT, UB);
2554 fprintf(stderr, "\n");
2555 #endif
2556 // LB increment till UB:
2557 for(; value_le(LB, UB); value_increment(LB, LB)) {
2558 value_assign(val[position], LB);
2559 if(polyhedron_int_solution(scan->next, val, position + 1)) {
2560 // early exit as soon as an integer point is found
2561 value_clear(UB);
2562 value_clear(LB);
2563 return(True);
2564 }
2565 }
2566 // reset val[position] to 0 after the scan, to prepare for next scans
2567 value_set_si(val[position], 0);
2568 }
2569
2570 // cleanup
2571 value_clear(UB);
2572 value_clear(LB);
2573 return(False);
2574}
2575
2576/*
2577 * Remove polyhedra that have no integer solutions from a domain.
2578 * Return a polyhedral domain, reusing the memory of D (do not free)
2579 *
2580 * Note: DomainConstraintSimplify() has been called already by
2581 * canonicalLBL, before entering this function. So if there is a line
2582 * or ray in one of these polyhedra then it has an integer solution.
2583 */
2585{
2586 Polyhedron *result = NULL, *universe = NULL;
2587 Vector *vec = NULL;
2588
2589 #ifdef SIMPLIFY_DEBUG
2590 fprintf(stderr, "--- Entering Domain_Remove_Integer_Empty\n");
2591 #endif
2592
2593 // scan each polyhedron, if no integer solution eliminate it
2594 // (do not copy to result, free memory)
2595 while(D) {
2596 Polyhedron *scan = NULL, *next;
2597 int ray;
2598 Bool int_solution_found = False;
2599
2600 next = D->next;
2601 D->next = NULL;
2602
2603 if(emptyQ(D)) { // D is rational-empty, eliminate.
2604 Polyhedron_Free(D);
2605 D = next;
2606 continue;
2607 }
2608 #ifdef SIMPLIFY_DEBUG
2609 fprintf(stderr, "Checking integer emptyness of: ");
2610 Polyhedron_Print(stderr, P_VALUE_FMT, D);
2611 #endif
2612
2613 // If one of the vertices is integer or if there is a ray/line,
2614 // it's not empty
2615 for(ray = 0; ray < D->NbRays; ray++) {
2616 if(value_zero_p(D->Ray[ray][0]) || // line, or
2617 value_zero_p(D->Ray[ray][D->Dimension + 1]) || // ray, or
2618 value_one_p(D->Ray[ray][D->Dimension + 1])) // integer vertex
2619 {
2620 int_solution_found = True;
2621 break;
2622 }
2623 }
2624
2625 // Here: could check if dark shadow to 0-dim space is non empty.
2626
2627 if(!int_solution_found) {
2628 // if there is no obvious integer solution, try a scan.
2629
2630 // allocate memory if not done yet
2631 if(!vec)
2632 {
2633 vec = Vector_Alloc(D->Dimension + 2);
2634 Vector_Set(vec->p, 0, D->Dimension + 1);
2635 value_set_si(vec->p[D->Dimension + 1], 1);
2636 universe = Universe_Polyhedron(0);
2637 }
2638
2639 scan = Polyhedron_Scan(D, universe, MAXNOOFRAYS);
2640 #ifdef SIMPLIFY_DEBUG
2641 fprintf(stderr, " scan = ");
2642 Polyhedron_Print(stderr, P_VALUE_FMT, scan);
2643 #endif
2644 int_solution_found = polyhedron_int_solution(scan, vec->p, 1);
2645
2646 Domain_Free(scan);
2647
2648 // If found, then vec->p contains an integer solution of D,
2649 // use it to simplify D
2650 // -> at least set integer bound on first dimension
2651 // -> or can we force the vertex to be in D?
2652 // splitting the polyhedron in parts? -> can be very complex in
2653 // higher dimensions, don't!
2654 if(int_solution_found) {
2655 Polyhedron *tmp;
2656 // at least we can cut the first dimension of D to the lower bound
2657 // reuse vec to build the constraint on first dimension to be added:
2658 value_set_si(vec->p[0], 1); // inequality
2659 value_oppose(vec->p[vec->Size - 1], vec->p[1]); // constant = -vec[1]
2660 value_set_si(vec->p[1], 1); // vec[1] = 1
2661 Vector_Set(vec->p + 2, 0, vec->Size - 3); // 0's everywhere else
2662 tmp = AddConstraints(vec->p, 1, D, MAXNOOFRAYS);
2663 Polyhedron_Free(D);
2664 D = tmp;
2665 value_set_si(vec->p[vec->Size - 1], 1); // restore vec constant
2666 }
2667 }
2668
2669 if(int_solution_found) {
2670 // link polyhedron D to result
2671 D->next = result;
2672 result = D;
2673 #ifdef SIMPLIFY_DEBUG
2674 fprintf(stderr, "-> not empty\n");
2675 #endif
2676 }
2677 else {
2678 // free the polyhedron (next was saved above)
2679 Polyhedron_Free(D);
2680 #ifdef SIMPLIFY_DEBUG
2681 fprintf(stderr, "-> empty\n");
2682 #endif
2683 }
2684
2685 D = next;
2686 }
2687 if(vec) {
2688 // free memory used for scan, if allocated
2689 Polyhedron_Free(universe);
2690 Vector_Free(vec);
2691 }
2692
2693 #ifdef SIMPLIFY_DEBUG
2694 fprintf(stderr, "--- Exit Domain_Remove_Integer_Empty with result = ");
2695 Polyhedron_Print(stderr, P_VALUE_FMT, result);
2696 #endif
2697 return(result);
2698}
2699
2700/*
2701 * Return a new domain that is D expanded such that the dimension 'move' is
2702 * moved to a new dimension (right) and the existing one is left empty
2703 * (add a line along this dimension)
2704 * 1 <= move <= D->Dimension + 1.
2705 *
2706 * In D we have constraints/rays:
2707 * flag d_1 d_2 ... move-1 move move+1 ... d_dim constant
2708 * the function will build:
2709 * flag d_1 d_2 ... move-1 0 move+1 ... d_dim move constant
2710 *
2711 * if move == D->Dimension + 1, this function will just just add a dimension.
2712*/
2714{
2715 Polyhedron *R = NULL; // result
2716 #ifdef SIMPLIFY2_DEBUG
2717 fprintf(stderr, "Entering domain_insert_dim. move = %d\n", move);
2718 // Polyhedron_Print(stderr, P_VALUE_FMT, D);
2719 #endif
2720 for(Polyhedron *p = D; p; p = p->next) {
2721 Polyhedron *new;
2722 new = Polyhedron_Alloc(p->Dimension + 1, p->NbConstraints, p->NbRays + 1);
2723 new->NbBid = p->NbBid + 1;
2724 new->NbEq = p->NbEq;
2725 new->flags = p->flags;
2726 // copy+expand Constraint matrix:
2727 for(int c = 0; c < p->NbConstraints; c++) {
2728 // linear part
2729 Vector_Copy(p->Constraint[c], new->Constraint[c], p->Dimension + 1);
2730 // constant
2731 value_assign(new->Constraint[c][new->Dimension + 1],
2732 p->Constraint[c][p->Dimension + 1]);
2733 // new dim and move
2734 value_assign(new->Constraint[c][new->Dimension], p->Constraint[c][move]);
2735 value_set_si(new->Constraint[c][move], 0);
2736 }
2737 // add new line (0 0 ... 0 1 0 ... 0) in new->Ray[0]
2738 Vector_Set(new->Ray[0], 0, new->Dimension + 2);
2739 value_set_si(new->Ray[0][move], 1);
2740 // copy+expand Ray matrix (in new->Ray[1+])
2741 for(int r = 0; r < p->NbRays; r++) {
2742 // linear part
2743 Vector_Copy(p->Ray[r], new->Ray[r+1], p->Dimension + 1);
2744 // constant
2745 value_assign(new->Ray[r+1][new->Dimension + 1],
2746 p->Ray[r][p->Dimension + 1]);
2747 // new dim and move
2748 value_assign(new->Ray[r+1][new->Dimension], p->Ray[r][move]);
2749 value_set_si(new->Ray[r+1][move], 0);
2750 }
2751 // link new to result
2752 new->next = R;
2753 R = new;
2754 }
2755 #ifdef SIMPLIFY2_DEBUG
2756 // fprintf(stderr, "Exiting domain_insert_dim. Result = ");
2757 // Polyhedron_Print(stderr, P_VALUE_FMT, R);
2758 #endif
2759
2760 return(R);
2761} /* domain_insert_dim */
2762
2763
2764/*
2765 * Fonction to expand the lattice of LBL A such that it is equal to the ref
2766 * lattice (ignore zero columns). The ref lattice includes the lattice
2767 * A->Lat.
2768 * This function will expand the domain D to the required dimension and add
2769 * equalities, such that the same LBL points are spread (does the opposite
2770 * of remove_equalities)
2771 * In place: modifies A.
2772 */
2774{
2775 // A->Lat is included in ref, so we know that
2776 // the pivots of A are multiple of the pivots of ref.
2777
2778 // some examples:
2779 /*
2780 merging A = LBL: Dimension 2
2781
2782 LATTICE:
2783 3 3
2784 6 0 4 -> 6i+0j+4, transf. into:
2785 2i'+0j+0 and \exists i' such that 2i' = 6i+4
2786 0 1 0
2787 0 0 1
2788 [included in] tmp = LBL: Dimension 2
2789
2790 LATTICE:
2791 3 3
2792 2 0 0
2793 0 1 0
2794 0 0 1
2795 */
2796
2797 // a more complex example:
2798 /*
2799 LATTICE:
2800 4 4
2801 2 0 0 0 -> 2i + 0j + 0, transf. into:
2802 i' + 0j + 0 and \exists i' with i'=2i
2803 0 0 0 0
2804 1 3 0 1 -> i + 3j + 1, transf. into:
2805 1j'+ 0 -> \exists j' with j'=i+3j+1
2806 0 0 0 1
2807
2808 [included in] tmp = LBL: Dimension 3
2809
2810 LATTICE:
2811 4 4
2812 1 0 0 0
2813
2814 0 0 0 0
2815 0 1 0 0
2816 0 0 0 1
2817 */
2818
2819 // and a difficult one:
2820 /*
2821 LATTICE:
2822 4 4
2823 2 0 0 0 -> same i = i'
2824 5 15 0 10 -> 5i+15j+10 transf. into:
2825 5j' \exists j', 5j'=5i+15j+10
2826 and a domain transfo
2827 13 15 66 54 -> 13i + 15j + 66k + 54 transf. into:
2828 52i + 27j' + 66k' + 0 -> same k = k'
2829
2830 (27j' = 27i + 3*27j + 54 so the line becomes
2831 79i + 81j + 66k + 54, do modulo 66 =
2832 13i + 15j + 66k + 54 that is correct.
2833 )
2834 0 0 0 1
2835
2836 [included in] tmp = LBL: Dimension 3
2837 LATTICE:
2838 4 4
2839 2 0 0 0
2840 0 5 0 0
2841 52 27 66 0
2842 0 0 0 1
2843
2844 */
2845
2846 // dimension reduction:
2847 /*
2848 LATTICE:
2849 3 2
2850 0 3 -> add column (0 0 0)^T and add new dimension with equality {3i=3}
2851 1 0 (same procedure as above!)
2852 0 1
2853 [included in] tmp = LBL: Dimension 2
2854 LATTICE:
2855 3 3
2856 3 0 0
2857 0 1 0
2858 0 0 1
2859 */
2860 // A included in ref
2861 // the pivot of A->Lat is a multiple of the pivot of ref (if exists)
2862
2863 // search the pivot in ref, it's not necessarily the same columns than
2864 // A->Lat since nbcolumns(A->Lat) can be different than nbcolumns(ref)
2865
2866 int nb_added_dims = 0;
2867 Matrix *L = A->Lat;
2868 #ifdef SIMPLIFY2_DEBUG
2869 fprintf(stderr, "Entering sLBLMake_lattice_equal_to\n");
2870 #endif
2871
2872 for(int col = 0; col < ref->NbColumns - 1; col++) {
2873 int row;
2874 Polyhedron *expand, *new;
2875
2876 // search pivot of column col
2877 for(row = 0; row < ref->NbRows ; row++) {
2878 if(value_notzero_p(ref->p[row][col])) {
2879 break;
2880 }
2881 }
2882 if(row == ref->NbRows) {
2883 // no more pivots (zero column), exit the loop.
2884 break;
2885 }
2886
2887 // no corresponding pivot in L!
2888 if(col == L->NbColumns - 1 || value_zero_p(L->p[row][col])) {
2889 // need to add a column in L
2890 nb_added_dims--;
2891
2892 Matrix *newL;
2893 newL = Matrix_Alloc(L->NbRows, L->NbColumns + 1);
2894 for(int r = 0; r < L->NbRows; r++) {
2895 // column number col is just a zero column
2896 Vector_Copy(L->p[r], newL->p[r], col); // 0 to col-1
2897 value_set_si(newL->p[r][col], 0); // col
2898 Vector_Copy(L->p[r] + col, newL->p[r] + col + 1, L->NbColumns - col);
2899 }
2900 Matrix_Free(A->Lat);
2901 A->Lat = newL;
2902 L = newL;
2903 }
2904 // now pivot is in position [row][col] of both matrices.
2905 // if same row, just ignore, goto next
2906 else {
2907 int c;
2908 for(c = 0; c <= col ; c++) {
2909 if(value_ne(L->p[row][c], ref->p[row][c])) {
2910 break;
2911 }
2912 }
2913 if(c == col + 1) {
2914 // all values are equal
2915 // if constant is equal too, continue to next pivot
2916 if(value_eq(L->p[row][L->NbColumns-1], ref->p[row][ref->NbColumns-1]))
2917 {
2918 continue;
2919 }
2920 }
2921 }
2922
2923 nb_added_dims++;
2924 // update A->P (if not NULL)
2925 // expand one dimension of the domain (the pivot one)
2926 // and add equality L[row] = ref[row]
2927 // the original dimension should be moved to the right (eliminated) column,
2928 // such that the new lattice is just ref
2929 if(A->P)
2930 {
2931 Matrix *new_equality = Matrix_Alloc(1, A->P->Dimension + 2 + 1);
2932
2933 expand = domain_insert_dim(A->P, col + 1);
2934
2935 // build equality L[row] = ref[row],
2936 // (the dimension col+1 of L moved to the new dimension)
2937 Vector_Set(new_equality->p[0], 0, new_equality->NbColumns);
2938 // (1) copy linear part of L:
2939 Vector_Copy(L->p[row], new_equality->p[0] + 1, L->NbColumns - 1);
2940 // constant
2941 value_assign(new_equality->p[0][new_equality->NbColumns-1],
2942 L->p[row][L->NbColumns-1]);
2943 // move the pivot to the new dimension
2944 value_assign(new_equality->p[0][new_equality->NbColumns-2],
2945 new_equality->p[0][col+1]);
2946 // and replace it with 0.
2947 value_set_si(new_equality->p[0][col+1], 0);
2948 // (2) substract linear part of ref[row] from the equality:
2949 for(int c = 0; c < ref->NbColumns-1 && c < new_equality->NbColumns-1; c++) {
2950 value_substract(new_equality->p[0][c+1], new_equality->p[0][c+1],
2951 ref->p[row][c]);
2952 }
2953 // substract constant:
2954 value_substract(new_equality->p[0][new_equality->NbColumns-1],
2955 new_equality->p[0][new_equality->NbColumns-1],
2956 ref->p[row][ref->NbColumns-1]);
2957 #ifdef SIMPLIFY2_DEBUG
2958 fprintf(stderr, "Adding equality: ");
2959 Matrix_Print(stderr, P_VALUE_FMT, new_equality);
2960 #endif
2961
2962 // build the final domain and update A->P
2963 new = DomainAddConstraints(expand, new_equality, MAXNOOFRAYS);
2964 // Domain_Free(expand);
2965 Domain_Free(A->P);
2966 A->P = new;
2967 Matrix_Free(new_equality);
2968 }
2969 }
2970
2971 // update A->Lat:
2972 // replace Lat with ref
2973 // and add zero columns for the extra dimensions
2974 Matrix *Lat;
2975 // Lat = Matrix_Alloc(A->Lat->NbRows, A->P->Dimension + 1);
2976 // new nbcolumns = nbcolumns of A->Lat + number of added dimensions
2977 Lat = Matrix_Alloc(A->Lat->NbRows, A->Lat->NbColumns + nb_added_dims);
2978 for(int r = 0; r < Lat->NbRows; r++) {
2979 if(Lat->NbColumns > ref->NbColumns) {
2980 // linear part:
2981 Vector_Copy(ref->p[r], Lat->p[r], ref->NbColumns - 1);
2982 // add zero columns:
2983 Vector_Set(Lat->p[r] + ref->NbColumns - 1, 0,
2984 Lat->NbColumns - ref->NbColumns);
2985 }
2986 else {
2987 // in case ref has more zero columns than the new Lat:
2988 Vector_Copy(ref->p[r], Lat->p[r], Lat->NbColumns - 1);
2989 }
2990 // constant:
2991 value_assign(Lat->p[r][Lat->NbColumns - 1], ref->p[r][ref->NbColumns - 1]);
2992 }
2993 Matrix_Free(A->Lat);
2994 A->Lat = Lat;
2995 #ifdef SIMPLIFY2_DEBUG
2996 fprintf(stderr, "New Lat: ");
2997 Matrix_Print(stderr, P_VALUE_FMT, A->Lat);
2998 #endif
2999
3000 // just normalize lattice (+update domain) without removing equalities
3002
3003 #ifdef SIMPLIFY2_DEBUG
3004 fprintf(stderr, "Exit sLBLMake_lattice_equal_to. A = ");
3005 sLBLPrint(stderr, P_VALUE_FMT, A);
3006 #endif
3007} /* sLBLMake_lattice_equal_to */
3008
3009
3010/***************************************************************************/
3011/* CanonicalLBL, LBL2ZDomain, and LBLSimplify */
3012/***************************************************************************/
3013
3014/*
3015 * Modify the single LBL 'A' to be in canonical form:
3016 * A->Lat in HNF and no equalities in A->P.
3017 * Also tries to remove the columns of zeros from A->Lat if possible:
3018 * do the projection along those dimensions and eliminate only if
3019 * dark shadow = exact shadow
3020 *
3021 * USAGE: in place, modifies A itself.
3022 *
3023 * This function can leave an arbitrary number of empty LBLs in the list
3024 * (will be removed later on).
3025 * Can modify A->next to insert new sub-LBLs.
3026 */
3027static void sLBLCanonical(LBL *A)
3028{
3029 #ifdef CANONICAL_DEBUG
3030 fprintf(stderr, "Entering sLBLCanonical\n");
3031 fprintf(stderr, "--------- Input Lat: ");
3032 Matrix_Print(stderr, P_VALUE_FMT, A->Lat);
3033 fprintf(stderr, "--------- Input P: ");
3034 Polyhedron_Print(stderr, P_VALUE_FMT, A->P);
3035 #endif
3036
3037 if(!A->P) {
3038 return;
3039 }
3040 if (A->P->Dimension+1 != A->Lat->NbColumns) {
3041 errormsg1("sLBLCanonical", "dimincomp", "incompatible dimensions");
3042 return;
3043 }
3044
3045 // ************************
3046 // STEP 1: normalize A->Lat
3047 // ************************
3048
3049 // Normalize the affine lattice of A (update A->Lat and A->P)
3051
3052 // simplify non-integer constraints such that they intersect at least one
3053 // integer point (to avoid infinite integer-empty polyhedra and obviously
3054 // empty polyhedra)
3056
3057 // check emptyness (A->P = NULL or rational empty)
3058 if(!A->P) {
3059 return;
3060 }
3061 if(emptyQ(A->P)) {
3062 Domain_Free(A->P);
3063 A->P = NULL;
3064 return;
3065 }
3066
3067 // ***********************************
3068 // STEP 2: remove equalities from A->P
3069 // ***********************************
3070
3071 // homogenize the equalities of A->P: ensure that all polyhedra of the
3072 // domain verify the same set of equalities
3073 Matrix *Equalities = sLBLHomogenize_equalities(A);
3074
3075 if (A->P->Dimension > 0 && A->P->NbEq != 0) {
3076 // Remove the equalities from A->P
3077 sLBLSimplify_equalities(A, Equalities);
3078
3079 // some equalities were eliminated. Do we need to start again from scratch?
3080 // Lat and P changed, but Lat is kept in HNF, so no.
3081 // Matrix_Free(Equalities);
3082 // sLBLCanonical(A);
3083 // return;
3084 }
3085 Matrix_Free(Equalities);
3086 if(!A->P) {
3087 // empty, done.
3088 return;
3089 }
3090
3091 // ****************************************
3092 // STEP 3: eliminate zero columns of A->Lat
3093 // ****************************************
3094
3095 // Remove the columns of zeros from A->Lat if possible:
3096 // do the projection along the zero-dimensions,
3097 // eliminate only if dark shadow \in exact shadow
3098 // (do not convert into ZDomains/check for integer-emptyness of polyhedra)
3100
3101 return;
3102} /* sLBLCanonical */
3103
3104
3105/*
3106 * The function takes an LBL 'A' and transforms it into its canonical form:
3107 * - all lattices in HNF, and
3108 * - no equalities in all polyhedral domains.
3109 * Performs the operation IN PLACE (modifies A)
3110 *
3111 * USAGE NOTICE:
3112 * If A is a real LBL and not a Z-polyhedron, there will remain zero-columns
3113 * on the right of the lattice matrice(s).
3114 * To transform a union of LBLs into a union of Z-polyhedra, you need to
3115 * call LBL2ZDomain().
3116 */
3118{
3119 #ifdef CANONICAL_DEBUG
3120 fprintf(stderr, "Entering CanonicalLBL.\nA =");
3121 LBLPrint(stderr, P_VALUE_FMT, A);
3122 #endif
3123
3124 // transform every LBL of the list individually
3125 for(LBL *tmp = A; tmp; tmp = tmp->next) {
3126 sLBLCanonical(tmp);
3127 }
3128
3129 // remove empty LBLs from the list, keep at least something in A
3131
3132 #ifdef CANONICAL_DEBUG
3133 fprintf(stderr, "sLBLCanonical and RemoveEmpty done.\nA =");
3134 LBLPrint(stderr, P_VALUE_FMT, A);
3135 #endif
3136
3137 // check if a lattice is present twice in A, and if it is, union the second
3138 // polyhedral domain with the first one and remove the second sLBL
3139 for(; A; A = A->next)
3140 {
3141 LBL *previous = A, *current = A->next;
3142 while(current) {
3143 if(isEqualLattice(A->Lat, current->Lat)) {
3144 // move current->P to A->P, remove current, and relink previous to next
3145 Polyhedron *pp = current->P;
3146 while(pp) {
3147 Polyhedron *nextpp = pp->next;
3148 pp->next = NULL;
3149 A->P = AddPolyToDomain(pp, A->P);
3150 pp = nextpp;
3151 }
3152 Matrix_Free(current->Lat);
3153 previous->next = current->next;
3154 free(current);
3155 current = previous->next;
3156 // and previous does not change
3157 }
3158 else {
3159 previous = current;
3160 current = current->next;
3161 }
3162 }
3163 }
3164} /* CanonicalLBL */
3165
3166
3167/*
3168 * Transform a single LBL into a list of Z-domains
3169 *
3170 * Remove zero columns from the lattice, build a union of Z-polyhedra
3171 *
3172 */
3174{
3175 int nbzeros;
3176 LBL *Result;
3177
3178 if((nbzeros = LatCountZeroCols(A->Lat))) {
3179 // there are potential holes
3180 Matrix *newL;
3181 Polyhedron *holes, *not_holes, *exact;
3182 holes = sLBLCompute_holes(A, &exact);
3183
3184 not_holes = DomainDifference(exact, holes, MAXNOOFRAYS);
3185 #ifdef HOLES_DEBUG
3186 fprintf(stderr, "-- in LBL2ZDomain - Not holes = ");
3187 Polyhedron_Print(stderr, P_VALUE_FMT, not_holes);
3188 #endif
3189 Domain_Free(holes);
3190 Domain_Free(exact);
3191
3192 // build result LBL
3193 newL = RemoveNColumns(A->Lat, A->Lat->NbColumns-1-nbzeros, nbzeros);
3194 Result = LBLAlloc(newL, not_holes);
3195 Matrix_Free(newL);
3196 Domain_Free(not_holes);
3197 }
3198 else {
3199 Result = sLBLCopy(A);
3200 }
3201 return(Result);
3202}
3203
3204/*
3205 * Build a union of Z-domains from a union of LBLs.
3206 *
3207 * The resulting Z-domain union lattices do not contain any zero columns.
3208 *
3209 * The result is proved to be finite, but can pretty easily explode in
3210 * complexity, for example with a very pointy initial LBL
3211 * -- take something based on (2^16 x - (2^16-1) y) for example.
3212 */
3214{
3215 LBL *Result = NULL;
3216 for(LBL *Z = A; Z; Z = Z->next)
3217 {
3218 LBL *tmp;
3219 tmp = sLBL2ZDomain(Z);
3220 Result = LBLConcatenate(tmp, Result);
3221 }
3222 CanonicalLBL(Result);
3223 LBLSimplifyEmpty(Result);
3224 return(Result);
3225}
3226
3227
3228/*
3229 * Remove integer empty single LBLs from an LBL, in place.
3230 *
3231 * Algorithm:
3232 * Check all polyhedra for integer-emptiness, remove if a polyhedron does not
3233 * contain any integer point
3234 */
3236{
3237 // just for testing, call simplify from simplifyEmpty:
3238 #ifdef SIMPLIFY2_DEBUG
3239 LBLSimplify(A);
3240 #endif
3241
3242 for(LBL *tmp = A; tmp; tmp = tmp->next) {
3243 tmp->P = Domain_Remove_Integer_Empty(tmp->P);
3244 }
3245 LBL_Remove_Empty(A); // remove emptied LBLs from the list
3246
3247 CanonicalLBL(A);
3248} /* LBLSimplifyEmpty */
3249
3250/*
3251 * Simplify an LBL, in place.
3252 *
3253 * Algorithm:
3254 * Merge all the lattices that can be merged. Ideas... :
3255 * a- merge same lattices, ignore zero columns (extend dimension of P) -> easy.
3256 * b- check lattice inclusion and merge?
3257 * (involves a-) but how to merge?
3258 * only if poly included too?
3259 * or separate the part that is not included?
3260 * -> or at least their hulls should intersect?
3261 * if merge, transform the lattices to be equal:
3262 * add equalities to P in order to generate the original points
3263 * of L x | x \in P
3264 * c- sort lattices by linear part...
3265 * and try to merge same ones..., when domains overlap?
3266 * or split domains such that a part of it does overlap?
3267 * example: can (2i+0) be merged with (2i+1)? -> yes if P is same (but this is unlikely)
3268 * let A = im((2i+0),P), and B = im((2i+1),P') -> if A = B then (i+0), preim((i+0), A) -> Z-pol only
3269
3270 another idea: make all lattices = (Id 0), adding existential variables in the domains to generate the right lbls
3271 then merge everything together
3272 -> can be pretty complex..., but obviously covers all cases!
3273
3274 lattice inclusion test covers this case too, if the lattice Id is in the LBL list
3275 and the hulls intersect.
3276
3277 * Then:
3278 * - fuse/simplify all adjacent polyhedral domains (complement of simplify of complement)
3279 * - CanonicalLBL to remove equalities
3280 */
3282{
3283 // LBL A should be canonical (all functions return a canonical LBL)
3284 if(isEmptyLBL(A))
3285 return;
3286
3287 // TESTING, add lattice Id as first lattice in LBL A (with an empty domain).
3288 // this ensures that all lattices are merged together!
3289
3290 // LBL *first;
3291 // first = malloc(sizeof(LBL));
3292 // // copy A in first
3293 // *first = *A;
3294 // // set A to (Z^d, empty)
3295 // A->next = first;
3296 // A->Lat = Identity_Matrix(A->Lat->NbRows);
3297 // A->P = NULL;
3298
3299 // check if a lattice of A is included in another, merge them if yes.
3300 // warning, need to modify A while scanning it: check inclusion both ways
3301 // and always merge with the first one (suppress the last one)
3302 for(LBL *tmp = A; tmp; tmp = tmp->next) {
3303 LBL *current = tmp->next, *prec = tmp;
3304 while(current) {
3305 int flag = 0; // if flag, current included in tmp
3306
3307 if(isSameLatticeSpace(current->Lat, tmp->Lat)) {
3308 // the two lattices do not have the same zero columns but are equal
3309 flag = 2;
3310 }
3311 else if(LatticeIncluded(current->Lat, tmp->Lat)) {
3312 // current is included in tmp
3313 flag = 1;
3314 }
3315 else if(LatticeIncluded(tmp->Lat, current->Lat)) {
3316 Matrix *L;
3317 Polyhedron *P;
3318 // tmp is included in current
3319 flag = 1;
3320 // exchange tmp and current, so that current is included in tmp.
3321 L = tmp->Lat; P = tmp->P;
3322 tmp->Lat = current->Lat; tmp->P = current->P;
3323 current->Lat = L; current->P = P;
3324 }
3325 if(flag) {
3326 #ifdef SIMPLIFY2_DEBUG
3327 fprintf(stderr, "merging current = ");
3328 sLBLPrint(stderr, P_VALUE_FMT, current);
3329 fprintf(stderr, "[included in] tmp = ");
3330 sLBLPrint(stderr, P_VALUE_FMT, tmp);
3331 #endif
3332 if(flag == 1) {
3333 // make the lattice of current equal to the one of tmp
3334 // apart from zero columns
3335 // (current is included in tmp)
3336
3337 sLBLMake_lattice_equal_to(current, tmp->Lat);
3338 }
3339
3340 // after this, merge the zero columns such that the two lattices are
3341 // perfectly equal
3342 // can require to swap dimensions to align same existential variables,
3343 // or to increase dimension to take in all of them (lazy) <- do that
3344
3345 int current_nbzero, tmp_nbzero;
3346 Polyhedron *newP;
3347 Matrix *newL;
3348 // expand domains current and tmp:
3349 current_nbzero = LatCountZeroCols(current->Lat);
3350 tmp_nbzero = LatCountZeroCols(tmp->Lat);
3351 if(current->P) {
3352 for(int i = 0; i < tmp_nbzero; i++) {
3353 // add tmp_nbzero dimensions to current->P
3354 newP = domain_insert_dim(current->P, current->P->Dimension + 1);
3355 Domain_Free(current->P);
3356 current->P = newP;
3357 }
3358 }
3359 if(tmp->P) {
3360 for(int i = 0; i < current_nbzero; i++) {
3361 // add current_nbzero dimensions to tmp->P
3362 assert(tmp->P);
3363 newP = domain_insert_dim(tmp->P, tmp->P->Dimension + 1);
3364 Domain_Free(tmp->P);
3365 tmp->P = newP;
3366 }
3367 }
3368
3369 // merge current in tmp:
3370 // - update tmp->P
3371 newP = DomainUnion(tmp->P, current->P, MAXNOOFRAYS);
3372 Domain_Free(tmp->P);
3373 tmp->P = newP;
3374
3375 // - update tmp->Lat
3376 newL = Matrix_Alloc(tmp->Lat->NbRows,
3377 tmp->Lat->NbColumns + current_nbzero);
3378 for(int r = 0; r < newL->NbRows; r++) {
3379 // linear part
3380 Vector_Copy(tmp->Lat->p[r], newL->p[r], tmp->Lat->NbColumns - 1);
3381 // zeros
3382 Vector_Set(newL->p[r] + tmp->Lat->NbColumns - 1, 0, current_nbzero);
3383 // constant
3384 value_assign(newL->p[r][newL->NbColumns - 1],
3385 tmp->Lat->p[r][tmp->Lat->NbColumns - 1]);
3386 }
3387 Matrix_Free(tmp->Lat);
3388 tmp->Lat = newL;
3389 #ifdef SIMPLIFY2_DEBUG
3390 fprintf(stderr, "[new merged] tmp = ");
3391 sLBLPrint(stderr, P_VALUE_FMT, tmp);
3392 #endif
3393
3394 // remove current, update prec->next and current
3395 Domain_Free(current->P);
3396 Matrix_Free(current->Lat);
3397 prec->next = current->next;
3398 free(current);
3399 current = prec->next;
3400 }
3401 else {
3402 // simple advance prec and current
3403 prec = current;
3404 current = current->next;
3405 }
3406 }
3407 }
3408 // now the the polyhedra have their equalities back and are merged together,
3409 // what to do with them??
3410
3411
3412 // THIS IS EASY BUT DOES NOT HELP :(
3413 for(LBL *tmp = A; tmp; tmp = tmp->next) {
3414 tmp->P = DomainConstraintSimplify(tmp->P, MAXNOOFRAYS);
3415 }
3416
3417
3418 // // THIS IS TOO COMPLEX! -> ZDiff11 takes ages...
3419 // Polyhedron *universe;
3420 // universe = Universe_Polyhedron(A->P->Dimension);
3421
3422 // for(LBL *tmp = A; tmp; tmp = tmp->next) {
3423 // Polyhedron *newP;
3424
3425 // // compute complement -> complement
3426 // // first complement
3427 // newP = DomainDifference(universe, tmp->P, MAXNOOFRAYS);
3428 // Domain_Free(tmp->P);
3429 // tmp->P = newP;
3430
3431 // // disjoint of complement + simplify
3432 // // TOO COMPLEX:
3433 // // tmp->P = Disjoint_Domain(tmp->P, 0, MAXNOOFRAYS);
3434 // // tmp->P = DomainConstraintSimplify(tmp->P, MAXNOOFRAYS);
3435
3436 // // and complement + simplify:
3437 // newP = DomainDifference(universe, tmp->P, MAXNOOFRAYS);
3438 // Domain_Free(tmp->P);
3439 // tmp->P = newP;
3440 // tmp->P = DomainConstraintSimplify(tmp->P, MAXNOOFRAYS);
3441 // }
3442
3443
3444 // // THIS IS NOT WHAT WE WANT!
3445 // // but could be useful to count?
3446 // for(LBL *tmp = A; tmp; tmp = tmp->next) {
3447 // Polyhedron *newP;
3448
3449 // // disjoint + simplify
3450 // newP = Disjoint_Domain(tmp->P, 0, MAXNOOFRAYS);
3451 // Domain_Free(tmp->P);
3452 // tmp->P = DomainConstraintSimplify(newP, MAXNOOFRAYS);
3453 // }
3454
3455 // TODO: simplify the polyhedral domains stored in A to get a minimal
3456 // and disjoint(?) form
3457
3458
3459 #ifdef SIMPLIFY2_DEBUG
3460 fprintf(stderr, "\n Exit LBLSimplify. A (before simplify) = ");
3461 LBLPrint(stderr, P_VALUE_FMT, A);
3462 #endif
3463 CanonicalLBL(A);
3464
3465 // avoid recursive loop, just for testing:
3466 #ifndef SIMPLIFY2_DEBUG
3468 #endif
3469} /* LBLSimplify */
3470
3471
3472/***************************************************************************/
3473/* LBLDisjointUnion */
3474/***************************************************************************/
3475
3476/*
3477 * Compute the disjoint union of LBL A, by performing succesive intersections
3478 * and differences.
3479 */
3481{
3482 if(!A)
3483 return(NULL);
3484
3485 // TODO: infinite loop for ZDisj11b.in
3486
3487 // TODO: split lattices first, then polyhedra in them
3488
3489 // need a ZDomain version?
3490 // A = LBL2ZDomain(A);
3491
3492 // get a copy of the first domain of A
3493 LBL *res = sLBLCopy(A);
3494
3495 // then compute the inter/diff of each sLBL stored in A
3496 for(LBL *tmpA = A->next; tmpA; tmpA = tmpA->next) {
3497 LBL *next, *inter, *diffA, *diffB, *newres;
3498
3499 // unlink next
3500 next = tmpA->next;
3501 tmpA->next = NULL;
3502
3503 // compute intersections and differences
3504 inter = LBLIntersection(res, tmpA);
3505 diffA = LBLDifference(tmpA, res);
3506 diffB = LBLDifference(res, tmpA);
3507
3508 newres = LBLConcatenate(LBLConcatenate(inter, diffA), diffB);
3509 CanonicalLBL(newres);
3510 LBLFree(res);
3511 res = newres;
3512
3513 // relink next
3514 tmpA->next = next;
3515 }
3516
3517 return(res);
3518}
LatticeUnion * LatticeDifference(Matrix *A, Matrix *B)
Definition: Lattice.c:423
void Matrix_Move_Homogeneous_Dim_First(Matrix *A)
Definition: Lattice.c:71
int LatCountZeroCols(Matrix *M)
Definition: Lattice.c:312
Bool isSameLatticeSpace(Matrix *A, Matrix *B)
Definition: Lattice.c:356
Matrix * LatticeIntersection(Matrix *A, Matrix *B)
Definition: Lattice.c:620
Bool isEqualLattice(Matrix *A, Matrix *B)
Definition: Lattice.c:394
void AffineHermite(Matrix *A, Matrix **H, Matrix **U)
Definition: Lattice.c:221
Bool isNormalLattice(Matrix *A)
Definition: Lattice.c:136
Bool isEmptyLattice(Matrix *A)
Definition: Lattice.c:57
Bool LatticeIncluded(Matrix *A, Matrix *B)
Definition: Lattice.c:336
void PrintLatticeUnion(FILE *fp, char *format, LatticeUnion *Head)
Definition: Lattice.c:16
void Matrix_Move_Homogeneous_Dim_Last(Matrix *A)
Definition: Lattice.c:107
Matrix * RemoveColumn(Matrix *M, int Columnnumber)
Definition: Matop.c:293
Matrix * Matrix_Copy(Matrix const *Src)
Definition: Matop.c:98
Matrix * RemoveNColumns(Matrix *M, int FirstColumnnumber, int NumColumns)
Definition: Matop.c:274
void LBLSimplifyEmpty(LBL *A)
Definition: Zpolyhedron.c:3235
static Polyhedron * sLBLCompute_holes(LBL *A, Polyhedron **pExact)
Definition: Zpolyhedron.c:2079
static Polyhedron * Domain_Remove_Integer_Empty(Polyhedron *D)
Definition: Zpolyhedron.c:2584
void CanonicalLBL(LBL *A)
Definition: Zpolyhedron.c:3117
static void sLBLCanonical(LBL *A)
Definition: Zpolyhedron.c:3027
static LBL * sLBLComplement2(LBL *A)
Definition: Zpolyhedron.c:765
LBL * LBLImage(LBL *A, Matrix *Func)
Definition: Zpolyhedron.c:475
static Polyhedron * domain_project(Polyhedron *P, int eliminate)
Definition: Zpolyhedron.c:1754
static Matrix * get_equalities(Polyhedron *P)
Definition: Zpolyhedron.c:1449
static Bool polyhedron_int_solution(Polyhedron *scan, Value *val, int position)
Definition: Zpolyhedron.c:2521
static LBL * sLBLCopy(LBL *A)
Definition: Zpolyhedron.c:135
static LBL * sLBLPreimage(LBL *, Matrix *)
Definition: Zpolyhedron.c:1171
static LBL * sLBLImage(LBL *, Matrix *)
Definition: Zpolyhedron.c:1139
LBL * LBLPreimage(LBL *A, Matrix *Func)
Definition: Zpolyhedron.c:497
LBL * LBL2ZDomain(LBL *A)
Definition: Zpolyhedron.c:3213
Polyhedron * Scan_RestAP(Polyhedron *R, Value *val, int position, int dimrest)
Definition: Zpolyhedron.c:1930
void LBLSimplify(LBL *A)
Definition: Zpolyhedron.c:3281
static Polyhedron * bound_polyhedron(Polyhedron *D)
Definition: Zpolyhedron.c:2019
static LBL * LBLConcatenate(LBL *A, LBL *B)
Definition: Zpolyhedron.c:162
static LBL * sLBL2ZDomain(LBL *A)
Definition: Zpolyhedron.c:3173
LBL * LBLUnion(LBL *A, LBL *B)
Definition: Zpolyhedron.c:344
Polyhedron * GenPoly(int dim, Value *val)
Definition: Zpolyhedron.c:1890
static Matrix * sLBLHomogenize_equalities(LBL *A)
Definition: Zpolyhedron.c:1485
static void sLBLSimplify_equalities(LBL *A, Matrix *Equalities)
Definition: Zpolyhedron.c:1549
LBL * LBLDisjointUnion(LBL *A)
Definition: Zpolyhedron.c:3480
static void sLBLPrint(FILE *fp, const char *format, LBL *A)
Definition: Zpolyhedron.c:307
static Polyhedron * domain_dark_shadow(Polyhedron *P, int dim)
Definition: Zpolyhedron.c:1861
LBL * LBLComplement(LBL *A)
Definition: Zpolyhedron.c:922
static void LBL_Remove_Empty(LBL *A)
Definition: Zpolyhedron.c:2444
void LBLFree(LBL *L)
Definition: Zpolyhedron.c:122
static Bool LBL_simple_inclusion_check(LBL *A, LBL *B)
Definition: Zpolyhedron.c:241
LBL * UniverseLBL(int dimension)
Definition: Zpolyhedron.c:218
void LBLPrint(FILE *fp, const char *format, LBL *A)
Definition: Zpolyhedron.c:324
static void sLBLFree(LBL *L)
Definition: Zpolyhedron.c:106
static void sLBL_Simplify_Zero_Dimensions(LBL *A)
Definition: Zpolyhedron.c:2301
LBL * LBLDifference(LBL *A, LBL *B)
Definition: Zpolyhedron.c:406
static Polyhedron * domain_insert_dim(Polyhedron *D, int move)
Definition: Zpolyhedron.c:2713
Bool isEmptyLBL(LBL *A)
Definition: Zpolyhedron.c:54
static void sLBL_Lat_Normalize(LBL *A)
Definition: Zpolyhedron.c:2389
Bool LBLIncluded(LBL *A, LBL *B)
Definition: Zpolyhedron.c:272
LBL * EmptyLBL(int dimension)
Definition: Zpolyhedron.c:189
static Bool same_equalities(Matrix *Eq, Polyhedron *P)
Definition: Zpolyhedron.c:1465
static LBL * sLBLComplement(LBL *A)
Definition: Zpolyhedron.c:816
static LBL * sLBLIntersection(LBL *, LBL *)
Definition: Zpolyhedron.c:533
LBL * LBLCopy(LBL *L)
Definition: Zpolyhedron.c:144
LBL * LBLIntersection(LBL *A, LBL *B)
Definition: Zpolyhedron.c:364
LBL * LBLAlloc(Matrix *Lat, Polyhedron *Domain)
Definition: Zpolyhedron.c:75
static void sLBLMake_lattice_equal_to(LBL *A, Matrix *ref)
Definition: Zpolyhedron.c:2773
static Polyhedron * polyhedron_dark_source(Polyhedron *P, int dim)
Definition: Zpolyhedron.c:1633
#define value_pos_p(val)
Definition: arithmetique.h:574
#define value_oppose(ref, val)
Definition: arithmetique.h:555
#define value_le(v1, v2)
Definition: arithmetique.h:510
#define value_notzero_p(val)
Definition: arithmetique.h:579
#define value_notone_p(val)
Definition: arithmetique.h:581
#define value_one_p(val)
Definition: arithmetique.h:580
#define value_substract(ref, val1, val2)
Definition: arithmetique.h:725
#define value_add_int(ref, val, vint)
Definition: arithmetique.h:541
#define value_ne(v1, v2)
Definition: arithmetique.h:506
#define value_zero_p(val)
Definition: arithmetique.h:578
#define value_assign(v1, v2)
Definition: arithmetique.h:485
#define value_increment(ref, val)
Definition: arithmetique.h:543
int Value
Definition: arithmetique.h:294
#define value_set_si(val, i)
Definition: arithmetique.h:486
#define value_notmone_p(val)
Definition: arithmetique.h:583
#define value_eq(v1, v2)
Definition: arithmetique.h:505
#define value_clear(val)
Definition: arithmetique.h:488
#define value_print(Dst, fmt, val)
Definition: arithmetique.h:490
#define value_addto(ref, val1, val2)
Definition: arithmetique.h:540
#define value_neg_p(val)
Definition: arithmetique.h:575
#define value_init(val)
Definition: arithmetique.h:484
#define assert(ex)
Definition: assert.h:16
void errormsg1(const char *f, const char *msgname, const char *msg)
Definition: errormsg.c:25
void Matrix_Product(Matrix *Mat1, Matrix *Mat2, Matrix *Mat3)
Definition: matrix.c:880
Matrix * Matrix_Alloc(unsigned NbRows, unsigned NbColumns)
Definition: matrix.c:24
int Matrix_Inverse(Matrix *Mat, Matrix *MatInv)
Definition: matrix.c:925
void Matrix_Print(FILE *Dst, const char *Format, Matrix *Mat)
Definition: matrix.c:118
void left_hermite(Matrix *A, Matrix **Hp, Matrix **Qp, Matrix **Up)
Definition: matrix.c:523
void Matrix_Free(Matrix *Mat)
Definition: matrix.c:69
Matrix * Identity_Matrix(unsigned int dim)
Definition: matrix_addon.c:58
void Matrix_identity(unsigned int dim, Matrix **I)
returns the dim-dimensional identity matrix.
Definition: matrix_addon.c:77
Polyhedron * DomainAddRays(Polyhedron *Pol, Matrix *Ray, unsigned NbMaxConstrs)
Add rays pointed by 'Ray' to each and every polyhedron in the polyhedral domain 'Pol'.
Definition: polyhedron.c:2805
Polyhedron * align_context(Polyhedron *Pol, int align_dimension, int NbMaxRays)
Definition: polyhedron.c:3704
Polyhedron * Disjoint_Domain(Polyhedron *P, int flag, unsigned NbMaxRays)
Definition: polyhedron.c:4503
Polyhedron * DomainAddConstraints(Polyhedron *Pol, Matrix *Mat, unsigned NbMaxRays)
Definition: polyhedron.c:4448
void Polyhedron_Free(Polyhedron *Pol)
Definition: polyhedron.c:1621
Polyhedron * DomainConstraintSimplify(Polyhedron *P, unsigned MaxRays)
Definition: polyhedron.c:4760
Polyhedron * Polyhedron_Scan(Polyhedron *D, Polyhedron *C, unsigned NbMaxRays)
Definition: polyhedron.c:3791
Polyhedron * DomainDifference(Polyhedron *Pol1, Polyhedron *Pol2, unsigned NbMaxRays)
Definition: polyhedron.c:3641
Polyhedron * AddPolyToDomain(Polyhedron *Pol, Polyhedron *PolDomain)
Definition: polyhedron.c:2460
Polyhedron * DomainIntersection(Polyhedron *Pol1, Polyhedron *Pol2, unsigned NbMaxRays)
Definition: polyhedron.c:2648
Polyhedron * Domain_Copy(Polyhedron *Pol)
Definition: polyhedron.c:2878
Polyhedron * DomainPreimage(Polyhedron *Pol, Matrix *Func, unsigned NbMaxRays)
Definition: polyhedron.c:4138
Polyhedron * Universe_Polyhedron(unsigned Dimension)
Definition: polyhedron.c:1761
Polyhedron * Rays2Polyhedron(Matrix *Ray, unsigned NbMaxConstrs)
Given a matrix of rays 'Ray', create and return a polyhedron.
Definition: polyhedron.c:2094
Polyhedron * DomainUnion(Polyhedron *Pol1, Polyhedron *Pol2, unsigned NbMaxRays)
Definition: polyhedron.c:3530
int lower_upper_bounds(int pos, Polyhedron *P, Value *context, Value *LBp, Value *UBp)
Definition: polyhedron.c:3859
Polyhedron * DomainImage(Polyhedron *Pol, Matrix *Func, unsigned NbMaxConstrs)
Definition: polyhedron.c:4266
Polyhedron * Polyhedron_Alloc(unsigned Dimension, unsigned NbConstraints, unsigned NbRays)
Definition: polyhedron.c:1573
Polyhedron * AddConstraints(Value *Con, unsigned NbConstraints, Polyhedron *Pol, unsigned NbMaxRays)
Definition: polyhedron.c:2311
void Polyhedron_Print(FILE *Dst, const char *Format, const Polyhedron *Pol)
Definition: polyhedron.c:1646
void Domain_Free(Polyhedron *Pol)
Definition: polyhedron.c:1633
Definition: types.h:82
unsigned Size
Definition: types.h:83
Value * p
Definition: types.h:84
struct lattice_union * next
Definition: types.h:240
Definition: types.h:245
Matrix * Lat
Definition: types.h:246
Polyhedron * P
Definition: types.h:247
struct lbl * next
Definition: types.h:248
Definition: types.h:88
unsigned NbRows
Definition: types.h:89
Value ** p
Definition: types.h:90
unsigned NbColumns
Definition: types.h:89
Value ** Ray
Definition: types.h:112
unsigned Dimension
Definition: types.h:110
unsigned NbConstraints
Definition: types.h:110
unsigned NbRays
Definition: types.h:110
struct polyhedron * next
Definition: types.h:115
Value ** Constraint
Definition: types.h:111
unsigned NbEq
Definition: types.h:110
#define emptyQ(P)
Definition: types.h:134
Bool
Definition: types.h:45
@ True
Definition: types.h:45
@ False
Definition: types.h:45
#define MAXNOOFRAYS
Definition: types.h:31
#define P_VALUE_FMT
Definition: types.h:42
void Vector_Free(Vector *vector)
Definition: vector.c:187
void Vector_Set(Value *p, int n, unsigned length)
Definition: vector.c:248
void Vector_Combine(Value *p1, Value *p2, Value *p3, Value lambda, Value mu, unsigned length)
Definition: vector.c:455
Vector * Vector_Alloc(unsigned length)
Definition: vector.c:134
void Vector_Copy(Value *p1, Value *p2, unsigned length)
Definition: vector.c:276
void Vector_Oppose(Value *p1, Value *p2, unsigned len)
Definition: vector.c:392