3 #include <polylib/polylib.h>
7 Both this software and its documentation are
9 Copyright 1993 by IRISA /Universite de Rennes I - France,
10 Copyright 1995,1996 by BYU, Provo, Utah
19 /*---------------------------------------------------------------------*/
20 /* int exist_points(pos,P,context) */
21 /* pos : index position of current loop index (0..hdim-1) */
23 /* context : context values for fixed indices */
24 /* recursive procedure, recurs for each imbriquation */
25 /* returns 1 if there exists any integer points in this polyhedron */
26 /* returns 0 if there are none */
27 /*---------------------------------------------------------------------*/
28 static int exist_points(int pos
,Polyhedron
*Pol
,Value
*context
) {
32 value_init(LB
); value_init(UB
);
33 value_init(k
); value_init(tmp
);
37 /* Problem if UB or LB is INFINITY */
38 if (lower_upper_bounds(pos
,Pol
,context
,&LB
,&UB
) !=0) {
39 errormsg1("exist_points", "infdom", "infinite domain");
46 value_set_si(context
[pos
],0);
55 value_subtract(tmp
,UB
,LB
);
56 value_increment(tmp
,tmp
);
60 return (value_pos_p(tmp
));
63 for (value_assign(k
,LB
);value_le(k
,UB
);value_increment(k
,k
)) {
65 /* insert k in context */
66 value_assign(context
[pos
],k
);
67 if (exist_points(pos
+1,Pol
->next
,context
) > 0 ) {
68 value_clear(LB
); value_clear(UB
);
69 value_clear(k
); value_clear(tmp
);
74 value_set_si(context
[pos
],0);
75 value_clear(UB
); value_clear(LB
);
76 value_clear(k
); value_clear(tmp
);
80 /*--------------------------------------------------------------*/
81 /* Test to see if there are any integral points in a polyhedron */
82 /*--------------------------------------------------------------*/
83 int Polyhedron_Not_Empty(Polyhedron
*P
,Polyhedron
*C
,int MAXRAYS
) {
90 POL_ENSURE_VERTICES(P
);
92 POL_ENSURE_VERTICES(C
);
94 /* Create a context vector size dim+2 and set it to all zeros */
95 context
= (Value
*) malloc((P
->Dimension
+2)*sizeof(Value
));
97 /* Initialize array 'context' */
98 for (i
=0;i
<(P
->Dimension
+2);i
++)
99 value_init(context
[i
]);
101 Vector_Set(context
,0,(P
->Dimension
+2));
103 /* Set context[P->Dimension+1] = 1 (the constant) */
104 value_set_si(context
[P
->Dimension
+1],1);
106 L
= Polyhedron_Scan(P
,C
,MAXRAYS
);
107 res
= exist_points(1,L
,context
);
110 /* Clear array 'context' */
111 for (i
=0;i
<(P
->Dimension
+2);i
++)
112 value_clear(context
[i
]);
117 /* PolyhedronLTQ ( P1, P2 ) */
118 /* P1 and P2 must be simple polyhedra */
119 /* result = 0 --> not comparable */
120 /* result = -1 --> P1 < P2 */
121 /* result = 1 --> P1 > P2 */
122 /* INDEX = 1 .... Dimension */
123 int PolyhedronLTQ (Polyhedron
*Pol1
,Polyhedron
*Pol2
,int INDEX
, int PDIM
, int NbMaxConstrs
) {
125 int res
, dim
, i
, j
, k
;
126 Polyhedron
*Q1
, *Q2
, *Q3
, *Q4
, *Q
;
129 if (Pol1
->next
|| Pol2
->next
) {
130 errormsg1("PolyhedronLTQ", "compoly", "Can only compare polyhedra");
133 if (Pol1
->Dimension
!= Pol2
->Dimension
) {
134 errormsg1("PolyhedronLTQ","diffdim","Polyhedra are not same dimension");
137 dim
= Pol1
->Dimension
+2;
139 POL_ENSURE_FACETS(Pol1
);
140 POL_ENSURE_VERTICES(Pol1
);
141 POL_ENSURE_FACETS(Pol2
);
142 POL_ENSURE_VERTICES(Pol2
);
145 fprintf(stdout
, "P1\n");
146 Polyhedron_Print(stdout
,P_VALUE_FMT
,Pol1
);
147 fprintf(stdout
, "P2\n");
148 Polyhedron_Print(stdout
,P_VALUE_FMT
,Pol2
);
151 /* Create the Line to add */
152 k
= Pol1
->Dimension
-INDEX
+1-PDIM
;
153 Mat
= Matrix_Alloc(k
,dim
);
154 Vector_Set(Mat
->p_Init
,0,dim
*k
);
155 for(j
=0,i
=INDEX
;j
<k
;i
++,j
++)
156 value_set_si(Mat
->p
[j
][i
],1);
158 Q1
= AddRays(Mat
->p
[0],k
,Pol1
,NbMaxConstrs
);
159 Q2
= AddRays(Mat
->p
[0],k
,Pol2
,NbMaxConstrs
);
162 fprintf(stdout
, "Q1\n");
163 Polyhedron_Print(stdout
,P_VALUE_FMT
,Q1
);
164 fprintf(stdout
, "Q2\n");
165 Polyhedron_Print(stdout
,P_VALUE_FMT
,Q2
);
169 Q
= DomainIntersection(Q1
,Q2
,NbMaxConstrs
);
172 fprintf(stdout
, "Q\n");
173 Polyhedron_Print(stdout
,P_VALUE_FMT
,Q
);
179 if (emptyQ(Q
)) res
= 0; /* not comparable */
181 Q1
= DomainIntersection(Pol1
,Q
,NbMaxConstrs
);
182 Q2
= DomainIntersection(Pol2
,Q
,NbMaxConstrs
);
185 fprintf(stdout
, "Q1\n");
186 Polyhedron_Print(stdout
,P_VALUE_FMT
,Q1
);
187 fprintf(stdout
, "Q2\n");
188 Polyhedron_Print(stdout
,P_VALUE_FMT
,Q2
);
191 k
= Q1
->NbConstraints
+ Q2
->NbConstraints
;
192 Mat
= Matrix_Alloc(k
, dim
);
193 Vector_Set(Mat
->p_Init
,0,k
*dim
);
195 /* First compute surrounding polyhedron */
197 for (i
=0; i
<Q1
->NbConstraints
; i
++) {
198 if ((value_one_p(Q1
->Constraint
[i
][0])) && (value_pos_p(Q1
->Constraint
[i
][INDEX
]))) {
200 /* keep Q1's lower bounds */
201 for (k
=0; k
<dim
; k
++)
202 value_assign(Mat
->p
[j
][k
],Q1
->Constraint
[i
][k
]);
206 for (i
=0; i
<Q2
->NbConstraints
; i
++) {
207 if ((value_one_p(Q2
->Constraint
[i
][0])) && (value_neg_p(Q2
->Constraint
[i
][INDEX
]))) {
209 /* and keep Q2's upper bounds */
210 for (k
=0; k
<dim
; k
++)
211 value_assign(Mat
->p
[j
][k
],Q2
->Constraint
[i
][k
]);
215 Q4
= AddConstraints(Mat
->p
[0], j
, Q
, NbMaxConstrs
);
219 fprintf(stderr
, "Q4 surrounding polyhedron\n");
220 Polyhderon_Print(stderr
,P_VALUE_FMT
, Q4
);
223 /* if surrounding polyhedron is empty, D1>D2 */
228 fprintf(stderr
, "Surrounding polyhedron is empty\n");
233 /* Test if Q1 < Q2 */
234 /* Build a constraint array for >= Q1 and <= Q2 */
235 Mat
= Matrix_Alloc(2,dim
);
236 Vector_Set(Mat
->p_Init
,0,2*dim
);
238 /* Choose a contraint from Q1 */
239 for (i
=0; i
<Q1
->NbConstraints
; i
++) {
240 if (value_zero_p(Q1
->Constraint
[i
][0])) {
243 if (value_zero_p(Q1
->Constraint
[i
][INDEX
])) {
245 /* Ignore side constraint (they are in Q) */
248 else if (value_neg_p(Q1
->Constraint
[i
][INDEX
])) {
250 /* copy -constraint to Mat */
251 value_set_si(Mat
->p
[0][0],1);
252 for (k
=1; k
<dim
; k
++)
253 value_oppose(Mat
->p
[0][k
],Q1
->Constraint
[i
][k
]);
257 /* Copy constraint to Mat */
259 value_set_si(Mat
->p
[0][0],1);
260 for (k
=1; k
<dim
; k
++)
261 value_assign(Mat
->p
[0][k
],Q1
->Constraint
[i
][k
]);
264 else if(value_neg_p(Q1
->Constraint
[i
][INDEX
])) {
266 /* Upper bound -- make a lower bound from it */
267 value_set_si(Mat
->p
[0][0],1);
268 for (k
=1; k
<dim
; k
++)
269 value_oppose(Mat
->p
[0][k
],Q1
->Constraint
[i
][k
]);
273 /* Lower or side bound -- ignore it */
277 /* Choose a constraint from Q2 */
278 for (j
=0; j
<Q2
->NbConstraints
; j
++) {
279 if (value_zero_p(Q2
->Constraint
[j
][0])) { /* equality */
280 if (value_zero_p(Q2
->Constraint
[j
][INDEX
])) {
282 /* Ignore side constraint (they are in Q) */
285 else if (value_pos_p(Q2
->Constraint
[j
][INDEX
])) {
287 /* Copy -constraint to Mat */
288 value_set_si(Mat
->p
[1][0],1);
289 for (k
=1; k
<dim
; k
++)
290 value_oppose(Mat
->p
[1][k
],Q2
->Constraint
[j
][k
]);
294 /* Copy constraint to Mat */
295 value_set_si(Mat
->p
[1][0],1);
296 for (k
=1; k
<dim
; k
++)
297 value_assign(Mat
->p
[1][k
],Q2
->Constraint
[j
][k
]);
300 else if (value_pos_p(Q2
->Constraint
[j
][INDEX
])) {
302 /* Lower bound -- make an upper bound from it */
303 value_set_si(Mat
->p
[1][0],1);
305 value_oppose(Mat
->p
[1][k
],Q2
->Constraint
[j
][k
]);
309 /* Upper or side bound -- ignore it */
314 fprintf(stdout
, "i=%d j=%d M=\n", i
+1, j
+1);
315 Matrix_Print(stdout
,P_VALUE_FMT
,Mat
);
318 /* Add Mat to Q and see if anything is made */
319 Q3
= AddConstraints(Mat
->p
[0],2,Q
,NbMaxConstrs
);
322 fprintf(stdout
, "Q3\n");
323 Polyhedron_Print(stdout
,P_VALUE_FMT
,Q3
);
330 fprintf(stdout
, "not empty\n");
336 fprintf(stdout
,"empty\n");
352 fprintf(stdout
, "res = %d\n", res
);
356 } /* PolyhedronLTQ */
359 Given Mat1, a matrix of equalities, performs Gaussian elimination.
360 Find a minimum basis, Returns the rank.
361 Mat1 is context, Mat2 is reduced in context of Mat1
363 int GaussSimplify(Matrix
*Mat1
,Matrix
*Mat2
) {
365 int NbRows
= Mat1
->NbRows
;
366 int NbCols
= Mat1
->NbColumns
;
368 int i
, j
, k
, n
, t
, pivot
, Rank
;
371 column_index
=(int *)malloc(NbCols
* sizeof(int));
373 errormsg1("GaussSimplify", "outofmem", "out of memory space\n");
378 /* Initialize all the 'Value' variables */
379 value_init(gcd
); value_init(tmp
);
382 for (j
=0; j
<NbCols
; j
++) { /* for each column starting at */
383 for (i
=Rank
; i
<NbRows
; i
++) /* diagonal, look down to find */
384 if (value_notzero_p(Mat1
->p
[i
][j
])) /* the first non-zero entry */
386 if (i
!=NbRows
) { /* was one found ? */
387 if (i
!=Rank
) /* was it found below the diagonal?*/
388 Vector_Exchange(Mat1
->p
[Rank
],Mat1
->p
[i
],NbCols
);
390 /* Normalize the pivot row */
391 Vector_Gcd(Mat1
->p
[Rank
],NbCols
,&gcd
);
395 if (value_ge(gcd
,tmp
)) {
397 for (k
=0; k
<NbCols
; k
++,cp
++)
398 value_division(*cp
,*cp
,gcd
);
400 if (value_neg_p(Mat1
->p
[Rank
][j
])) {
402 for (k
=0; k
<NbCols
; k
++,cp
++)
403 value_oppose(*cp
,*cp
);
405 /* End of normalize */
407 for (i
=0;i
<NbRows
;i
++) /* Zero out the rest of the column */
409 if (value_notzero_p(Mat1
->p
[i
][j
])) {
410 Value a
, a1
, a2
, a1abs
, a2abs
;
411 value_init(a
); value_init(a1
); value_init(a2
);
412 value_init(a1abs
); value_init(a2abs
);
413 value_assign(a1
,Mat1
->p
[i
][j
]);
414 value_absolute(a1abs
,a1
);
415 value_assign(a2
,Mat1
->p
[Rank
][j
]);
416 value_absolute(a2abs
,a2
);
417 value_gcd(a
, a1abs
, a2abs
);
418 value_divexact(a1
, a1
, a
);
419 value_divexact(a2
, a2
, a
);
421 Vector_Combine(Mat1
->p
[i
],Mat1
->p
[Rank
],Mat1
->p
[i
],a2
,
423 Vector_Normalize(Mat1
->p
[i
],NbCols
);
424 value_clear(a
); value_clear(a1
); value_clear(a2
);
425 value_clear(a1abs
); value_clear(a2abs
);
428 column_index
[Rank
]=j
;
431 } /* end of Gauss elimination */
434 if (Mat2
) { /* Mat2 is a transformation matrix (i,j->f(i,j))....
435 can't scale it because can't scale both sides of -> */
436 /* normalizes an affine transformation */
437 /* priority of forms */
438 /* 1. i' -> i (identity) */
439 /* 2. i' -> i + constant (uniform) */
440 /* 3. i' -> constant (broadcast) */
441 /* 4. i' -> j (permutation) */
442 /* 5. i' -> j + constant ( ) */
443 /* 6. i' -> i + j + constant (non-uniform) */
444 for (k
=0; k
<Rank
; k
++) {
446 for (i
=0; i
<(Mat2
->NbRows
-1);i
++) { /* all but the last row 0...0 1 */
447 if ((i
!=j
) && value_notzero_p(Mat2
->p
[i
][j
])) {
449 /* Remove dependency of i' on j */
450 Value a
, a1
, a1abs
, a2
, a2abs
;
451 value_init(a
); value_init(a1
); value_init(a2
);
452 value_init(a1abs
); value_init(a2abs
);
453 value_assign(a1
,Mat2
->p
[i
][j
]);
454 value_absolute(a1abs
,a1
);
455 value_assign(a2
,Mat1
->p
[k
][j
]);
456 value_absolute(a2abs
,a2
);
457 value_gcd(a
, a1abs
, a2abs
);
458 value_divexact(a1
, a1
, a
);
459 value_divexact(a2
, a2
, a
);
461 if (value_one_p(a2
)) {
462 Vector_Combine(Mat2
->p
[i
],Mat1
->p
[k
],Mat2
->p
[i
],a2
,
465 /* Vector_Normalize(Mat2->p[i],NbCols); -- can't do T */
466 } /* otherwise, can't do it without mult lhs prod (2i,3j->...) */
467 value_clear(a
); value_clear(a1
); value_clear(a2
);
468 value_clear(a1abs
); value_clear(a2abs
);
471 else if ((i
==j
) && value_zero_p(Mat2
->p
[i
][j
])) {
473 /* 'i' does not depend on j */
474 for (n
=j
+1; n
< (NbCols
-1); n
++) {
475 if (value_notzero_p(Mat2
->p
[i
][n
])) { /* i' depends on some n */
477 Vector_Combine(Mat2
->p
[i
],Mat1
->p
[k
],Mat2
->p
[i
],tmp
,
480 } /* if 'i' depends on just a constant, then leave it alone.*/
486 /* Check last row of transformation Mat2 */
487 for (j
=0; j
<(NbCols
-1); j
++)
488 if (value_notzero_p(Mat2
->p
[Mat2
->NbRows
-1][j
])) {
489 errormsg1("GaussSimplify", "corrtrans", "Corrupted transformation\n");
493 if (value_notone_p(Mat2
->p
[Mat2
->NbRows
-1][NbCols
-1])) {
494 errormsg1("GaussSimplify", "corrtrans", "Corrupted transformation\n");
497 value_clear(gcd
); value_clear(tmp
);
500 } /* GaussSimplify */
503 * Topologically sort 'n' polyhdera and return 0 on failure, otherwise return
504 * 1 on success. Here 'L' is a an array of pointers to polyhedra, 'n' is the
505 * number of polyhedra, 'index' is the level to consider for partial ordering
506 * 'pdim' is the parameter space dimension, 'time' is an array of 'n' integers
507 * to store logical time values, 'pvect', if not NULL, is an array of 'n'
508 * integers that contains a permutation specification after call and MAXRAYS is
509 * the workspace size for polyhedra operations.
511 int PolyhedronTSort (Polyhedron
**L
,unsigned int n
,unsigned int index
,unsigned int pdim
,int *time
,int *pvect
,unsigned int MAXRAYS
) {
513 unsigned int const nbcells
= ((n
*(n
-1))>>1); /* Number of memory cells
514 to allocate, see below */
515 int *dag
; /* The upper triangular matrix */
516 int **p
; /* Array of matrix row addresses */
517 unsigned int i
, j
, k
;
518 unsigned int t
, nb
, isroot
;
522 /* we need an upper triangular matrix (example with n=4):
525 . . o o . are unuseful cells, o are useful cells
529 so we need to allocate (n)(n-1)/2 cells
530 - dag will point to this memory.
531 - p[i] will point to row i of the matrix
532 p[0] = dag - 1 (such that p[0][1] == dag[0])
533 p[1] = dag - 1 + (n-1)
534 p[2] = dag - 1 + (n-1) + (n-2)
536 p[i] = p[i-1] + (n-1-i)
539 /* malloc n(n-1)/2 for dag and n-1 for p (node n does not have any row) */
540 dag
= (int *) malloc(nbcells
*sizeof(int));
542 p
= (int **) malloc ((n
-1) * sizeof(int *));
547 /* Initialize 'p' and 'dag' */
549 for (i
=1; i
<n
-1; i
++)
550 p
[i
] = p
[i
-1] + (n
-1)-i
;
551 for (i
=0; i
<nbcells
; i
++)
552 dag
[i
] = -2; /* -2 means 'not computed yet' */
553 for (i
=0; i
<n
; i
++) time
[i
] = -1;
555 /* Compute the dag using transitivity to reduce the number of */
556 /* PolyhedronLTQ calls. */
557 for (i
=0; i
<n
-1; i
++) {
558 POL_ENSURE_FACETS(L
[i
]);
559 POL_ENSURE_VERTICES(L
[i
]);
560 for (j
=i
+1; j
<n
; j
++) {
561 if (p
[i
][j
] == -2) /* not computed yes */
562 p
[i
][j
] = PolyhedronLTQ(L
[i
], L
[j
], index
, pdim
, MAXRAYS
);
565 /* if p[i][j] is 1 or -1, look for -p[i][j] on the same row:
566 p[i][j] == -p[i][k] ==> p[j][k] = p[i][k] (transitivity)
567 note: p[r][c] == -p[c][r], use this to avoid reading or writing
568 under the matrix diagonal
571 /* first, k<i so look for p[i][j] == p[k][i] (i.e. -p[i][k]) */
573 if (p
[k
][i
] == p
[i
][j
]) p
[k
][j
] = p
[k
][i
];
575 /* then, i<k<j so look for p[i][j] == -p[i][k] */
576 for (k
=i
+1; k
<j
; k
++)
577 if (p
[i
][k
] == -p
[i
][j
]) p
[k
][j
] = -p
[i
][k
];
579 /* last, k>j same search but */
580 for (k
=j
+1; k
<n
; k
++)
581 if (p
[i
][k
] == -p
[i
][j
]) p
[j
][k
] = p
[i
][k
];
586 /* walk thru the dag to compute the partial order (and optionally
588 Note: this is not the fastest way to do it but it takes
589 negligible time compared to a single call of PolyhedronLTQ !
590 Each macro-step (while loop) gives the same logical time to all
591 found roots and optionally add these nodes in the permutation vector
594 t
= 0; /* current logical time, assigned to current roots and
595 increased by 1 at the end of each step */
596 nb
= 0; /* number of processed nodes (have been given a time) */
598 for (i
=0; i
<n
; i
++) { /* search for roots */
599 /* for any node, if it's not already been given a logical time
600 then walk thru the node row; if we find a 1 at some column j,
601 it means that node j preceeds the current node, so it is not
604 isroot
= 1; /* assume that it is until it is definitely not */
605 /* first search on a column */
606 for (j
=0; j
<i
; j
++) {
607 if (p
[j
][i
]==-1) { /* found a node lower than it */
611 if /*still*/ (isroot
)
612 for (j
=i
+1; j
<n
; j
++) {
613 if (p
[i
][j
]==1) { /* greater than this node */
617 if (isroot
) { /* then it definitely is */
618 time
[i
] = t
; /* this node gets current logical time */
620 pvect
[nb
] = i
+1; /* nodes will be numbered from 1 to n */
621 nb
++; /* one more node processed */
625 /* now make roots become neutral, i.e. non comparable with all other nodes */
626 for (i
=0; i
<n
; i
++) {
630 for (j
=i
+1; j
<n
; j
++)
634 t
++; /* ready for next set of root nodes */
637 free (p
); /* let's be clean, collect the garbage */
640 } /* PolyhedronTSort */