1 #include <polylib/polylibgmp.h>
7 #ifndef HAVE_ENUMERATE4
8 #define Polyhedron_Enumerate(a,b,c,d) Polyhedron_Enumerate(a,b,c)
12 #define ALLOC(p) p = (typeof(p))malloc(sizeof(*p))
13 #define NALLOC(p,n) p = (typeof(p))malloc((n) * sizeof(*p))
15 #define ALLOC(p) p = (void *)malloc(sizeof(*p))
16 #define NALLOC(p,n) p = (void *)malloc((n) * sizeof(*p))
19 #ifndef HAVE_ENUMERATION_FREE
20 #define Enumeration_Free(en) /* just leak some memory */
23 void manual_count(Polyhedron
*P
, Value
* result
)
25 Polyhedron
*U
= Universe_Polyhedron(0);
26 Enumeration
*en
= Polyhedron_Enumerate(P
,U
,1024,NULL
);
27 Value
*v
= compute_poly(en
,NULL
);
28 value_assign(*result
, *v
);
35 #ifndef HAVE_ENUMERATION_FREE
36 #undef Enumeration_Free
43 /* Return random value between 0 and max-1 inclusive
45 int random_int(int max
) {
46 return (int) (((double)(max
))*rand()/(RAND_MAX
+1.0));
49 /* Inplace polarization
51 void Polyhedron_Polarize(Polyhedron
*P
)
53 unsigned NbRows
= P
->NbConstraints
+ P
->NbRays
;
57 q
= (Value
**)malloc(NbRows
* sizeof(Value
*));
59 for (i
= 0; i
< P
->NbRays
; ++i
)
61 for (; i
< NbRows
; ++i
)
62 q
[i
] = P
->Constraint
[i
-P
->NbRays
];
63 P
->NbConstraints
= NbRows
- P
->NbConstraints
;
64 P
->NbRays
= NbRows
- P
->NbRays
;
67 P
->Ray
= q
+ P
->NbConstraints
;
71 * Rather general polar
72 * We can optimize it significantly if we assume that
75 * Also, we calculate the polar as defined in Schrijver
76 * The opposite should probably work as well and would
77 * eliminate the need for multiplying by -1
79 Polyhedron
* Polyhedron_Polar(Polyhedron
*P
, unsigned NbMaxRays
)
83 unsigned dim
= P
->Dimension
+ 2;
84 Matrix
*M
= Matrix_Alloc(P
->NbRays
, dim
);
88 value_set_si(mone
, -1);
89 for (i
= 0; i
< P
->NbRays
; ++i
) {
90 Vector_Scale(P
->Ray
[i
], M
->p
[i
], mone
, dim
);
91 value_multiply(M
->p
[i
][0], M
->p
[i
][0], mone
);
92 value_multiply(M
->p
[i
][dim
-1], M
->p
[i
][dim
-1], mone
);
94 P
= Constraints2Polyhedron(M
, NbMaxRays
);
102 * Returns the supporting cone of P at the vertex with index v
104 Polyhedron
* supporting_cone(Polyhedron
*P
, int v
)
109 unsigned char *supporting
= (unsigned char *)malloc(P
->NbConstraints
);
110 unsigned dim
= P
->Dimension
+ 2;
112 assert(v
>=0 && v
< P
->NbRays
);
113 assert(value_pos_p(P
->Ray
[v
][dim
-1]));
117 for (i
= 0, n
= 0; i
< P
->NbConstraints
; ++i
) {
118 Inner_Product(P
->Constraint
[i
] + 1, P
->Ray
[v
] + 1, dim
- 1, &tmp
);
119 if ((supporting
[i
] = value_zero_p(tmp
)))
122 assert(n
>= dim
- 2);
124 M
= Matrix_Alloc(n
, dim
);
126 for (i
= 0, j
= 0; i
< P
->NbConstraints
; ++i
)
128 value_set_si(M
->p
[j
][dim
-1], 0);
129 Vector_Copy(P
->Constraint
[i
], M
->p
[j
++], dim
-1);
132 P
= Constraints2Polyhedron(M
, P
->NbRays
+1);
138 void value_lcm(Value i
, Value j
, Value
* lcm
)
142 value_multiply(aux
,i
,j
);
144 value_division(*lcm
,aux
,*lcm
);
148 Polyhedron
* supporting_cone_p(Polyhedron
*P
, Param_Vertices
*v
)
151 Value lcm
, tmp
, tmp2
;
152 unsigned char *supporting
= (unsigned char *)malloc(P
->NbConstraints
);
153 unsigned dim
= P
->Dimension
+ 2;
154 unsigned nparam
= v
->Vertex
->NbColumns
- 2;
155 unsigned nvar
= dim
- nparam
- 2;
160 row
= Vector_Alloc(nparam
+1);
165 value_set_si(lcm
, 1);
166 for (i
= 0, n
= 0; i
< P
->NbConstraints
; ++i
) {
167 Vector_Set(row
->p
, 0, nparam
+1);
168 for (j
= 0 ; j
< nvar
; ++j
) {
169 value_set_si(tmp
, 1);
170 value_assign(tmp2
, P
->Constraint
[i
][j
+1]);
171 if (value_ne(lcm
, v
->Vertex
->p
[j
][nparam
+1])) {
172 value_assign(tmp
, lcm
);
173 value_lcm(lcm
, v
->Vertex
->p
[j
][nparam
+1], &lcm
);
174 value_division(tmp
, lcm
, tmp
);
175 value_multiply(tmp2
, tmp2
, lcm
);
176 value_division(tmp2
, tmp2
, v
->Vertex
->p
[j
][nparam
+1]);
178 Vector_Combine(row
->p
, v
->Vertex
->p
[j
], row
->p
,
179 tmp
, tmp2
, nparam
+1);
181 value_set_si(tmp
, 1);
182 Vector_Combine(row
->p
, P
->Constraint
[i
]+1+nvar
, row
->p
, tmp
, lcm
, nparam
+1);
183 for (j
= 0; j
< nparam
+1; ++j
)
184 if (value_notzero_p(row
->p
[j
]))
186 if ((supporting
[i
] = (j
== nparam
+ 1)))
194 M
= Matrix_Alloc(n
, nvar
+2);
196 for (i
= 0, j
= 0; i
< P
->NbConstraints
; ++i
)
198 value_set_si(M
->p
[j
][nvar
+1], 0);
199 Vector_Copy(P
->Constraint
[i
], M
->p
[j
++], nvar
+1);
202 P
= Constraints2Polyhedron(M
, P
->NbRays
+1);
208 Polyhedron
* triangulate_cone(Polyhedron
*P
, unsigned NbMaxCons
)
210 const static int MAX_TRY
=10;
213 unsigned dim
= P
->Dimension
;
214 Matrix
*M
= Matrix_Alloc(P
->NbRays
+1, dim
+3);
216 Polyhedron
*L
, *R
, *T
;
217 assert(P
->NbEq
== 0);
222 Vector_Set(M
->p
[0]+1, 0, dim
+1);
223 value_set_si(M
->p
[0][0], 1);
224 value_set_si(M
->p
[0][dim
+2], 1);
225 Vector_Set(M
->p
[P
->NbRays
]+1, 0, dim
+2);
226 value_set_si(M
->p
[P
->NbRays
][0], 1);
227 value_set_si(M
->p
[P
->NbRays
][dim
+1], 1);
229 /* Delaunay triangulation */
230 for (i
= 0, r
= 1; i
< P
->NbRays
; ++i
) {
231 if (value_notzero_p(P
->Ray
[i
][dim
+1]))
233 Vector_Copy(P
->Ray
[i
], M
->p
[r
], dim
+1);
234 Inner_Product(M
->p
[r
]+1, M
->p
[r
]+1, dim
, &tmp
);
235 value_assign(M
->p
[r
][dim
+1], tmp
);
236 value_set_si(M
->p
[r
][dim
+2], 0);
241 L
= Rays2Polyhedron(M3
, NbMaxCons
);
244 M2
= Matrix_Alloc(dim
+1, dim
+2);
249 /* Usually R should still be 0 */
252 for (r
= 1; r
< P
->NbRays
; ++r
) {
253 value_set_si(M
->p
[r
][dim
+1], random_int((t
+1)*dim
)+1);
256 L
= Rays2Polyhedron(M3
, NbMaxCons
);
260 assert(t
<= MAX_TRY
);
265 for (i
= 0; i
< L
->NbConstraints
; ++i
) {
266 /* Ignore perpendicular facets, i.e., facets with 0 z-coordinate */
267 if (value_negz_p(L
->Constraint
[i
][dim
+1]))
269 if (value_notzero_p(L
->Constraint
[i
][dim
+2]))
271 for (j
= 1, r
= 1; j
< M
->NbRows
; ++j
) {
272 Inner_Product(M
->p
[j
]+1, L
->Constraint
[i
]+1, dim
+1, &tmp
);
273 if (value_notzero_p(tmp
))
277 Vector_Copy(M
->p
[j
]+1, M2
->p
[r
]+1, dim
);
278 value_set_si(M2
->p
[r
][0], 1);
279 value_set_si(M2
->p
[r
][dim
+1], 0);
283 Vector_Set(M2
->p
[0]+1, 0, dim
);
284 value_set_si(M2
->p
[0][0], 1);
285 value_set_si(M2
->p
[0][dim
+1], 1);
286 T
= Rays2Polyhedron(M2
, P
->NbConstraints
+1);
300 void check_triangulization(Polyhedron
*P
, Polyhedron
*T
)
302 Polyhedron
*C
, *D
, *E
, *F
, *G
, *U
;
303 for (C
= T
; C
; C
= C
->next
) {
307 U
= DomainConvex(DomainUnion(U
, C
, 100), 100);
308 for (D
= C
->next
; D
; D
= D
->next
) {
313 E
= DomainIntersection(C
, D
, 600);
314 assert(E
->NbRays
== 0 || E
->NbEq
>= 1);
320 assert(PolyhedronIncludes(U
, P
));
321 assert(PolyhedronIncludes(P
, U
));
324 static void Euclid(Value a
, Value b
, Value
*x
, Value
*y
, Value
*g
)
326 Value c
, d
, e
, f
, tmp
;
333 value_absolute(c
, a
);
334 value_absolute(d
, b
);
337 while(value_pos_p(d
)) {
338 value_division(tmp
, c
, d
);
339 value_multiply(tmp
, tmp
, f
);
340 value_subtract(e
, e
, tmp
);
341 value_division(tmp
, c
, d
);
342 value_multiply(tmp
, tmp
, d
);
343 value_subtract(c
, c
, tmp
);
350 else if (value_pos_p(a
))
352 else value_oppose(*x
, e
);
356 value_multiply(tmp
, a
, *x
);
357 value_subtract(tmp
, c
, tmp
);
358 value_division(*y
, tmp
, b
);
367 Matrix
* unimodular_complete(Vector
*row
)
369 Value g
, b
, c
, old
, tmp
;
378 m
= Matrix_Alloc(row
->Size
, row
->Size
);
379 for (j
= 0; j
< row
->Size
; ++j
) {
380 value_assign(m
->p
[0][j
], row
->p
[j
]);
382 value_assign(g
, row
->p
[0]);
383 for (i
= 1; value_zero_p(g
) && i
< row
->Size
; ++i
) {
384 for (j
= 0; j
< row
->Size
; ++j
) {
386 value_set_si(m
->p
[i
][j
], 1);
388 value_set_si(m
->p
[i
][j
], 0);
390 value_assign(g
, row
->p
[i
]);
392 for (; i
< row
->Size
; ++i
) {
393 value_assign(old
, g
);
394 Euclid(old
, row
->p
[i
], &c
, &b
, &g
);
396 for (j
= 0; j
< row
->Size
; ++j
) {
398 value_multiply(tmp
, row
->p
[j
], b
);
399 value_division(m
->p
[i
][j
], tmp
, old
);
401 value_assign(m
->p
[i
][j
], c
);
403 value_set_si(m
->p
[i
][j
], 0);
415 * Returns a full-dimensional polyhedron with the same number
416 * of integer points as P
418 Polyhedron
*remove_equalities(Polyhedron
*P
)
422 Polyhedron
*p
= Polyhedron_Copy(P
), *q
;
423 unsigned dim
= p
->Dimension
;
428 while (p
->NbEq
> 0) {
430 Vector_Gcd(p
->Constraint
[0]+1, dim
+1, &g
);
431 Vector_AntiScale(p
->Constraint
[0]+1, p
->Constraint
[0]+1, g
, dim
+1);
432 Vector_Gcd(p
->Constraint
[0]+1, dim
, &g
);
433 if (value_notone_p(g
) && value_notmone_p(g
)) {
435 p
= Empty_Polyhedron(0);
438 v
= Vector_Alloc(dim
);
439 Vector_Copy(p
->Constraint
[0]+1, v
->p
, dim
);
440 m1
= unimodular_complete(v
);
441 m2
= Matrix_Alloc(dim
, dim
+1);
442 for (i
= 0; i
< dim
-1 ; ++i
) {
443 Vector_Copy(m1
->p
[i
+1], m2
->p
[i
], dim
);
444 value_set_si(m2
->p
[i
][dim
], 0);
446 Vector_Set(m2
->p
[dim
-1], 0, dim
);
447 value_set_si(m2
->p
[dim
-1][dim
], 1);
448 q
= Polyhedron_Image(p
, m2
, p
->NbConstraints
+1+p
->NbRays
);
461 * Returns a full-dimensional polyhedron with the same number
462 * of integer points as P
463 * nvar specifies the number of variables
464 * The remaining dimensions are assumed to be parameters
466 * factor is NbEq x (nparam+2) matrix, containing stride constraints
467 * on the parameters; column nparam is the constant;
468 * column nparam+1 is the stride
470 * if factor is NULL, only remove equalities that don't affect
471 * the number of points
473 Polyhedron
*remove_equalities_p(Polyhedron
*P
, unsigned nvar
, Matrix
**factor
)
477 Polyhedron
*p
= P
, *q
;
478 unsigned dim
= p
->Dimension
;
484 f
= Matrix_Alloc(p
->NbEq
, dim
-nvar
+2);
489 while (nvar
> 0 && p
->NbEq
- skip
> 0) {
492 while (value_zero_p(p
->Constraint
[skip
][0]) &&
493 First_Non_Zero(p
->Constraint
[skip
]+1, nvar
) == -1)
498 Vector_Gcd(p
->Constraint
[skip
]+1, dim
+1, &g
);
499 Vector_AntiScale(p
->Constraint
[skip
]+1, p
->Constraint
[skip
]+1, g
, dim
+1);
500 Vector_Gcd(p
->Constraint
[skip
]+1, nvar
, &g
);
501 if (!factor
&& value_notone_p(g
) && value_notmone_p(g
)) {
506 Vector_Copy(p
->Constraint
[skip
]+1+nvar
, f
->p
[j
], dim
-nvar
+1);
507 value_assign(f
->p
[j
][dim
-nvar
+1], g
);
509 v
= Vector_Alloc(dim
);
510 Vector_AntiScale(p
->Constraint
[skip
]+1, v
->p
, g
, nvar
);
511 Vector_Set(v
->p
+nvar
, 0, dim
-nvar
);
512 m1
= unimodular_complete(v
);
513 m2
= Matrix_Alloc(dim
, dim
+1);
514 for (i
= 0; i
< dim
-1 ; ++i
) {
515 Vector_Copy(m1
->p
[i
+1], m2
->p
[i
], dim
);
516 value_set_si(m2
->p
[i
][dim
], 0);
518 Vector_Set(m2
->p
[dim
-1], 0, dim
);
519 value_set_si(m2
->p
[dim
-1][dim
], 1);
520 q
= Polyhedron_Image(p
, m2
, p
->NbConstraints
+1+p
->NbRays
);
534 void Line_Length(Polyhedron
*P
, Value
*len
)
540 assert(P
->Dimension
== 1);
546 for (i
= 0; i
< P
->NbConstraints
; ++i
) {
547 value_oppose(tmp
, P
->Constraint
[i
][2]);
548 if (value_pos_p(P
->Constraint
[i
][1])) {
549 mpz_cdiv_q(tmp
, tmp
, P
->Constraint
[i
][1]);
550 if (!p
|| value_gt(tmp
, pos
))
551 value_assign(pos
, tmp
);
554 mpz_fdiv_q(tmp
, tmp
, P
->Constraint
[i
][1]);
555 if (!n
|| value_lt(tmp
, neg
))
556 value_assign(neg
, tmp
);
560 value_subtract(tmp
, neg
, pos
);
561 value_increment(*len
, tmp
);
563 value_set_si(*len
, -1);
572 * Factors the polyhedron P into polyhedra Q_i such that
573 * the number of integer points in P is equal to the product
574 * of the number of integer points in the individual Q_i
576 * If no factors can be found, NULL is returned.
577 * Otherwise, a linked list of the factors is returned.
579 * The algorithm works by first computing the Hermite normal form
580 * and then grouping columns linked by one or more constraints together,
581 * where a constraints "links" two or more columns if the constraint
582 * has nonzero coefficients in the columns.
584 Polyhedron
* Polyhedron_Factor(Polyhedron
*P
, unsigned nparam
,
588 Matrix
*M
, *H
, *Q
, *U
;
589 int *pos
; /* for each column: row position of pivot */
590 int *group
; /* group to which a column belongs */
591 int *cnt
; /* number of columns in the group */
592 int *rowgroup
; /* group to which a constraint belongs */
593 int nvar
= P
->Dimension
- nparam
;
594 Polyhedron
*F
= NULL
;
602 NALLOC(rowgroup
, P
->NbConstraints
);
604 M
= Matrix_Alloc(P
->NbConstraints
, nvar
);
605 for (i
= 0; i
< P
->NbConstraints
; ++i
)
606 Vector_Copy(P
->Constraint
[i
]+1, M
->p
[i
], nvar
);
607 left_hermite(M
, &H
, &Q
, &U
);
612 for (i
= 0; i
< P
->NbConstraints
; ++i
)
614 for (i
= 0, j
= 0; i
< H
->NbColumns
; ++i
) {
615 for ( ; j
< H
->NbRows
; ++j
)
616 if (value_notzero_p(H
->p
[j
][i
]))
618 assert (j
< H
->NbRows
);
621 for (i
= 0; i
< nvar
; ++i
) {
625 for (i
= 0; i
< H
->NbColumns
&& cnt
[0] < nvar
; ++i
) {
626 if (rowgroup
[pos
[i
]] == -1)
627 rowgroup
[pos
[i
]] = i
;
628 for (j
= pos
[i
]+1; j
< H
->NbRows
; ++j
) {
629 if (value_zero_p(H
->p
[j
][i
]))
631 if (rowgroup
[j
] != -1)
633 rowgroup
[j
] = group
[i
];
634 for (k
= i
+1; k
< H
->NbColumns
&& j
>= pos
[k
]; ++k
) {
639 if (group
[k
] != group
[i
] && value_notzero_p(H
->p
[j
][k
])) {
640 assert(cnt
[group
[k
]] != 0);
641 assert(cnt
[group
[i
]] != 0);
642 if (group
[i
] < group
[k
]) {
643 cnt
[group
[i
]] += cnt
[group
[k
]];
647 cnt
[group
[k
]] += cnt
[group
[i
]];
656 if (cnt
[0] != nvar
) {
657 /* Extract out pure context constraints separately */
658 Polyhedron
**next
= &F
;
659 for (i
= nparam
? -1 : 0; i
< nvar
; ++i
) {
663 for (j
= 0, k
= 0; j
< P
->NbConstraints
; ++j
)
664 if (rowgroup
[j
] == -1) {
665 if (First_Non_Zero(P
->Constraint
[j
]+1+nvar
,
678 for (j
= 0, k
= 0; j
< P
->NbConstraints
; ++j
)
679 if (rowgroup
[j
] >= 0 && group
[rowgroup
[j
]] == i
) {
685 M
= Matrix_Alloc(k
, d
+nparam
+2);
686 for (j
= 0, k
= 0; j
< P
->NbConstraints
; ++j
) {
688 if (rowgroup
[j
] != i
)
690 value_assign(M
->p
[k
][0], P
->Constraint
[j
][0]);
691 for (l
= 0, m
= 0; m
< d
; ++l
) {
694 value_assign(M
->p
[k
][1+m
++], H
->p
[j
][l
]);
696 Vector_Copy(P
->Constraint
[j
]+1+nvar
, M
->p
[k
]+1+m
, nparam
+1);
699 *next
= Constraints2Polyhedron(M
, NbMaxRays
);
700 next
= &(*next
)->next
;
713 * Replaces constraint a x >= c by x >= ceil(c/a)
714 * where "a" is a common factor in the coefficients
715 * old is the constraint; v points to an initialized
716 * value that this procedure can use.
717 * Return non-zero if something changed.
718 * Result is placed in new.
720 int ConstraintSimplify(Value
*old
, Value
*new, int len
, Value
* v
)
722 Vector_Gcd(old
+1, len
- 2, v
);
727 Vector_AntiScale(old
+1, new+1, *v
, len
-2);
728 mpz_fdiv_q(new[len
-1], old
[len
-1], *v
);
733 * Project on final dim dimensions
735 Polyhedron
* Polyhedron_Project(Polyhedron
*P
, int dim
)
738 int remove
= P
->Dimension
- dim
;
742 if (P
->Dimension
== dim
)
743 return Polyhedron_Copy(P
);
745 T
= Matrix_Alloc(dim
+1, P
->Dimension
+1);
746 for (i
= 0; i
< dim
+1; ++i
)
747 value_set_si(T
->p
[i
][i
+remove
], 1);
748 I
= Polyhedron_Image(P
, T
, P
->NbConstraints
);
753 /* Constructs a new constraint that ensures that
754 * the first constraint is (strictly) smaller than
757 static void smaller_constraint(Value
*a
, Value
*b
, Value
*c
, int pos
, int shift
,
758 int len
, int strict
, Value
*tmp
)
760 value_oppose(*tmp
, b
[pos
+1]);
761 value_set_si(c
[0], 1);
762 Vector_Combine(a
+1+shift
, b
+1+shift
, c
+1, *tmp
, a
[pos
+1], len
-shift
-1);
764 value_decrement(c
[len
-shift
-1], c
[len
-shift
-1]);
765 ConstraintSimplify(c
, c
, len
-shift
, tmp
);
768 struct section
{ Polyhedron
* D
; evalue E
; };
770 evalue
* ParamLine_Length_mod(Polyhedron
*P
, Polyhedron
*C
, int MaxRays
)
772 unsigned dim
= P
->Dimension
;
773 unsigned nvar
= dim
- C
->Dimension
;
788 NALLOC(pos
, P
->NbConstraints
);
791 evalue_set_si(&mone
, -1, 1);
793 for (i
= 0, z
= 0; i
< P
->NbConstraints
; ++i
)
794 if (value_zero_p(P
->Constraint
[i
][1]))
796 /* put those with positive coefficients first; number: p */
797 for (i
= 0, p
= 0, n
= P
->NbConstraints
-z
-1; i
< P
->NbConstraints
; ++i
)
798 if (value_pos_p(P
->Constraint
[i
][1]))
800 else if (value_neg_p(P
->Constraint
[i
][1]))
802 n
= P
->NbConstraints
-z
-p
;
803 assert (p
>= 1 && n
>= 1);
804 s
= (struct section
*) malloc(p
* n
* sizeof(struct section
));
805 M
= Matrix_Alloc((p
-1) + (n
-1), dim
-nvar
+2);
806 for (k
= 0; k
< p
; ++k
) {
807 for (k2
= 0; k2
< p
; ++k2
) {
812 P
->Constraint
[pos
[k
]],
813 P
->Constraint
[pos
[k2
]],
814 M
->p
[q
], 0, nvar
, dim
+2, k2
> k
, &g
);
816 for (l
= p
; l
< p
+n
; ++l
) {
817 for (l2
= p
; l2
< p
+n
; ++l2
) {
822 P
->Constraint
[pos
[l2
]],
823 P
->Constraint
[pos
[l
]],
824 M
->p
[q
], 0, nvar
, dim
+2, l2
> l
, &g
);
827 T
= Constraints2Polyhedron(M2
, P
->NbRays
);
829 s
[nd
].D
= DomainIntersection(T
, C
, MaxRays
);
831 POL_ENSURE_VERTICES(s
[nd
].D
);
832 if (emptyQ(s
[nd
].D
)) {
833 Polyhedron_Free(s
[nd
].D
);
836 L
= bv_ceil3(P
->Constraint
[pos
[k
]]+1+nvar
,
838 P
->Constraint
[pos
[k
]][0+1], s
[nd
].D
);
839 U
= bv_ceil3(P
->Constraint
[pos
[l
]]+1+nvar
,
841 P
->Constraint
[pos
[l
]][0+1], s
[nd
].D
);
857 value_set_si(F
->d
, 0);
858 F
->x
.p
= new_enode(partition
, 2*nd
, dim
-nvar
);
859 for (k
= 0; k
< nd
; ++k
) {
860 EVALUE_SET_DOMAIN(F
->x
.p
->arr
[2*k
], s
[k
].D
);
861 value_clear(F
->x
.p
->arr
[2*k
+1].d
);
862 F
->x
.p
->arr
[2*k
+1] = s
[k
].E
;
866 free_evalue_refs(&mone
);
874 evalue
* ParamLine_Length(Polyhedron
*P
, Polyhedron
*C
, unsigned MaxRays
)
876 return ParamLine_Length_mod(P
, C
, MaxRays
);
879 evalue
* ParamLine_Length(Polyhedron
*P
, Polyhedron
*C
, unsigned MaxRays
)
882 tmp
= ParamLine_Length_mod(P
, C
);
883 evalue_mod2table(tmp
, C
->Dimension
);
889 Bool
isIdentity(Matrix
*M
)
892 if (M
->NbRows
!= M
->NbColumns
)
895 for (i
= 0;i
< M
->NbRows
; i
++)
896 for (j
= 0; j
< M
->NbColumns
; j
++)
898 if(value_notone_p(M
->p
[i
][j
]))
901 if(value_notzero_p(M
->p
[i
][j
]))
907 void Param_Polyhedron_Print(FILE* DST
, Param_Polyhedron
*PP
, char **param_names
)
912 for(P
=PP
->D
;P
;P
=P
->next
) {
914 /* prints current val. dom. */
915 printf( "---------------------------------------\n" );
916 printf( "Domain :\n");
917 Print_Domain( stdout
, P
->Domain
, param_names
);
919 /* scan the vertices */
920 printf( "Vertices :\n");
921 FORALL_PVertex_in_ParamPolyhedron(V
,P
,PP
) {
923 /* prints each vertex */
924 Print_Vertex( stdout
, V
->Vertex
, param_names
);
927 END_FORALL_PVertex_in_ParamPolyhedron
;
931 void Enumeration_Print(FILE *Dst
, Enumeration
*en
, char **params
)
933 for (; en
; en
= en
->next
) {
934 Print_Domain(Dst
, en
->ValidityDomain
, params
);
935 print_evalue(Dst
, &en
->EP
, params
);
939 void Enumeration_Free(Enumeration
*en
)
945 free_evalue_refs( &(en
->EP
) );
946 Polyhedron_Free( en
->ValidityDomain
);
953 void Enumeration_mod2table(Enumeration
*en
, unsigned nparam
)
955 for (; en
; en
= en
->next
) {
956 evalue_mod2table(&en
->EP
, nparam
);
957 reduce_evalue(&en
->EP
);
961 size_t Enumeration_size(Enumeration
*en
)
965 for (; en
; en
= en
->next
) {
966 s
+= domain_size(en
->ValidityDomain
);
967 s
+= evalue_size(&en
->EP
);
972 void Free_ParamNames(char **params
, int m
)
979 int DomainIncludes(Polyhedron
*Pol1
, Polyhedron
*Pol2
)
982 for ( ; Pol1
; Pol1
= Pol1
->next
) {
983 for (P2
= Pol2
; P2
; P2
= P2
->next
)
984 if (!PolyhedronIncludes(Pol1
, P2
))
992 static Polyhedron
*p_simplify_constraints(Polyhedron
*P
, Vector
*row
,
993 Value
*g
, unsigned MaxRays
)
995 Polyhedron
*T
, *R
= P
;
996 int len
= P
->Dimension
+2;
999 /* Also look at equalities.
1000 * If an equality can be "simplified" then there
1001 * are no integer solutions anyway and the following loop
1002 * will add a conflicting constraint
1004 for (r
= 0; r
< R
->NbConstraints
; ++r
) {
1005 if (ConstraintSimplify(R
->Constraint
[r
], row
->p
, len
, g
)) {
1007 R
= AddConstraints(row
->p
, 1, R
, MaxRays
);
1019 * Replaces constraint a x >= c by x >= ceil(c/a)
1020 * where "a" is a common factor in the coefficients
1021 * Destroys P and returns a newly allocated Polyhedron
1022 * or just returns P in case no changes were made
1024 Polyhedron
*DomainConstraintSimplify(Polyhedron
*P
, unsigned MaxRays
)
1027 int len
= P
->Dimension
+2;
1028 Vector
*row
= Vector_Alloc(len
);
1030 Polyhedron
*R
= P
, *N
;
1031 value_set_si(row
->p
[0], 1);
1034 for (prev
= &R
; P
; P
= N
) {
1037 T
= p_simplify_constraints(P
, row
, &g
, MaxRays
);
1039 if (emptyQ(T
) && prev
!= &R
) {
1051 if (R
->next
&& emptyQ(R
)) {
1062 int line_minmax(Polyhedron
*I
, Value
*min
, Value
*max
)
1067 value_oppose(I
->Constraint
[0][2], I
->Constraint
[0][2]);
1068 /* There should never be a remainder here */
1069 if (value_pos_p(I
->Constraint
[0][1]))
1070 mpz_fdiv_q(*min
, I
->Constraint
[0][2], I
->Constraint
[0][1]);
1072 mpz_fdiv_q(*min
, I
->Constraint
[0][2], I
->Constraint
[0][1]);
1073 value_assign(*max
, *min
);
1074 } else for (i
= 0; i
< I
->NbConstraints
; ++i
) {
1075 if (value_zero_p(I
->Constraint
[i
][1])) {
1080 value_oppose(I
->Constraint
[i
][2], I
->Constraint
[i
][2]);
1081 if (value_pos_p(I
->Constraint
[i
][1]))
1082 mpz_cdiv_q(*min
, I
->Constraint
[i
][2], I
->Constraint
[i
][1]);
1084 mpz_fdiv_q(*max
, I
->Constraint
[i
][2], I
->Constraint
[i
][1]);
1092 PROCEDURES TO COMPUTE ENUMERATION. recursive procedure, recurse for
1095 @param pos index position of current loop index (1..hdim-1)
1096 @param P loop domain
1097 @param context context values for fixed indices
1098 @param exist number of existential variables
1099 @return the number of integer points in this
1103 void count_points_e (int pos
, Polyhedron
*P
, int exist
, int nparam
,
1104 Value
*context
, Value
*res
)
1109 value_set_si(*res
, 0);
1113 value_init(LB
); value_init(UB
); value_init(k
);
1117 if (lower_upper_bounds(pos
,P
,context
,&LB
,&UB
) !=0) {
1118 /* Problem if UB or LB is INFINITY */
1119 value_clear(LB
); value_clear(UB
); value_clear(k
);
1120 if (pos
> P
->Dimension
- nparam
- exist
)
1121 value_set_si(*res
, 1);
1123 value_set_si(*res
, -1);
1130 for (value_assign(k
,LB
); value_le(k
,UB
); value_increment(k
,k
)) {
1131 fprintf(stderr
, "(");
1132 for (i
=1; i
<pos
; i
++) {
1133 value_print(stderr
,P_VALUE_FMT
,context
[i
]);
1134 fprintf(stderr
,",");
1136 value_print(stderr
,P_VALUE_FMT
,k
);
1137 fprintf(stderr
,")\n");
1142 value_set_si(context
[pos
],0);
1143 if (value_lt(UB
,LB
)) {
1144 value_clear(LB
); value_clear(UB
); value_clear(k
);
1145 value_set_si(*res
, 0);
1150 value_set_si(*res
, 1);
1152 value_subtract(k
,UB
,LB
);
1153 value_add_int(k
,k
,1);
1154 value_assign(*res
, k
);
1156 value_clear(LB
); value_clear(UB
); value_clear(k
);
1160 /*-----------------------------------------------------------------*/
1161 /* Optimization idea */
1162 /* If inner loops are not a function of k (the current index) */
1163 /* i.e. if P->Constraint[i][pos]==0 for all P following this and */
1165 /* Then CNT = (UB-LB+1)*count_points(pos+1, P->next, context) */
1166 /* (skip the for loop) */
1167 /*-----------------------------------------------------------------*/
1170 value_set_si(*res
, 0);
1171 for (value_assign(k
,LB
);value_le(k
,UB
);value_increment(k
,k
)) {
1172 /* Insert k in context */
1173 value_assign(context
[pos
],k
);
1174 count_points_e(pos
+1, P
->next
, exist
, nparam
, context
, &c
);
1175 if(value_notmone_p(c
))
1176 value_addto(*res
, *res
, c
);
1178 value_set_si(*res
, -1);
1181 if (pos
> P
->Dimension
- nparam
- exist
&&
1188 fprintf(stderr
,"%d\n",CNT
);
1192 value_set_si(context
[pos
],0);
1193 value_clear(LB
); value_clear(UB
); value_clear(k
);
1195 } /* count_points_e */
1197 int DomainContains(Polyhedron
*P
, Value
*list_args
, int len
,
1198 unsigned MaxRays
, int set
)
1203 if (P
->Dimension
== len
)
1204 return in_domain(P
, list_args
);
1206 assert(set
); // assume list_args is large enough
1207 assert((P
->Dimension
- len
) % 2 == 0);
1209 for (i
= 0; i
< P
->Dimension
- len
; i
+= 2) {
1211 for (j
= 0 ; j
< P
->NbEq
; ++j
)
1212 if (value_notzero_p(P
->Constraint
[j
][1+len
+i
]))
1214 assert(j
< P
->NbEq
);
1215 value_absolute(m
, P
->Constraint
[j
][1+len
+i
]);
1216 k
= First_Non_Zero(P
->Constraint
[j
]+1, len
);
1218 assert(First_Non_Zero(P
->Constraint
[j
]+1+k
+1, len
- k
- 1) == -1);
1219 mpz_fdiv_q(list_args
[len
+i
], list_args
[k
], m
);
1220 mpz_fdiv_r(list_args
[len
+i
+1], list_args
[k
], m
);
1224 return in_domain(P
, list_args
);
1227 #ifdef HAVE_RANKINGPOLYTOPES
1228 #include <polylib/ranking.h>
1230 evalue
*barvinok_ranking_ev(Polyhedron
*P
, Polyhedron
*D
, Polyhedron
*C
,
1234 Polyhedron
*RC
, *RD
, *Q
;
1236 RC
= RankingPolytopes(P
, D
, C
, MaxRays
);
1240 for (Q
= RD
; Q
; Q
= Q
->next
) {
1242 Polyhedron
*next
= Q
->next
;
1245 t
= barvinok_enumerate_ev(RD
, RC
, MaxRays
);
1251 free_evalue_refs(t
);
1259 Polyhedron_Free(RC
);
1264 Enumeration
*barvinok_ranking(Polyhedron
*P
, Polyhedron
*D
, Polyhedron
*C
,
1267 evalue
*EP
= barvinok_ranking_ev(P
, D
, C
, MaxRays
);
1269 return partition2enumeration(EP
);
1273 const char *barvinok_version(void)
1276 "barvinok " VERSION
" (" GIT_HEAD_ID
")\n"
1282 #ifdef USE_INCREMENTAL_BF
1284 #elif defined USE_INCREMENTAL_DF
1290 #ifdef HAVE_CORRECT_VERTICES
1291 " +CORRECT_VERTICES"
1293 " -CORRECT_VERTICES"