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 void manual_count(Polyhedron
*P
, Value
* result
)
21 Polyhedron
*U
= Universe_Polyhedron(0);
22 Enumeration
*en
= Polyhedron_Enumerate(P
,U
,1024,NULL
);
23 Value
*v
= compute_poly(en
,NULL
);
24 value_assign(*result
, *v
);
31 #include "ev_operations.h"
35 /* Return random value between 0 and max-1 inclusive
37 int random_int(int max
) {
38 return (int) (((double)(max
))*rand()/(RAND_MAX
+1.0));
41 /* Inplace polarization
43 void Polyhedron_Polarize(Polyhedron
*P
)
45 unsigned NbRows
= P
->NbConstraints
+ P
->NbRays
;
49 q
= (Value
**)malloc(NbRows
* sizeof(Value
*));
51 for (i
= 0; i
< P
->NbRays
; ++i
)
53 for (; i
< NbRows
; ++i
)
54 q
[i
] = P
->Constraint
[i
-P
->NbRays
];
55 P
->NbConstraints
= NbRows
- P
->NbConstraints
;
56 P
->NbRays
= NbRows
- P
->NbRays
;
59 P
->Ray
= q
+ P
->NbConstraints
;
63 * Rather general polar
64 * We can optimize it significantly if we assume that
67 * Also, we calculate the polar as defined in Schrijver
68 * The opposite should probably work as well and would
69 * eliminate the need for multiplying by -1
71 Polyhedron
* Polyhedron_Polar(Polyhedron
*P
, unsigned NbMaxRays
)
75 unsigned dim
= P
->Dimension
+ 2;
76 Matrix
*M
= Matrix_Alloc(P
->NbRays
, dim
);
80 value_set_si(mone
, -1);
81 for (i
= 0; i
< P
->NbRays
; ++i
) {
82 Vector_Scale(P
->Ray
[i
], M
->p
[i
], mone
, dim
);
83 value_multiply(M
->p
[i
][0], M
->p
[i
][0], mone
);
84 value_multiply(M
->p
[i
][dim
-1], M
->p
[i
][dim
-1], mone
);
86 P
= Constraints2Polyhedron(M
, NbMaxRays
);
94 * Returns the supporting cone of P at the vertex with index v
96 Polyhedron
* supporting_cone(Polyhedron
*P
, int v
)
101 unsigned char *supporting
= (unsigned char *)malloc(P
->NbConstraints
);
102 unsigned dim
= P
->Dimension
+ 2;
104 assert(v
>=0 && v
< P
->NbRays
);
105 assert(value_pos_p(P
->Ray
[v
][dim
-1]));
109 for (i
= 0, n
= 0; i
< P
->NbConstraints
; ++i
) {
110 Inner_Product(P
->Constraint
[i
] + 1, P
->Ray
[v
] + 1, dim
- 1, &tmp
);
111 if ((supporting
[i
] = value_zero_p(tmp
)))
114 assert(n
>= dim
- 2);
116 M
= Matrix_Alloc(n
, dim
);
118 for (i
= 0, j
= 0; i
< P
->NbConstraints
; ++i
)
120 value_set_si(M
->p
[j
][dim
-1], 0);
121 Vector_Copy(P
->Constraint
[i
], M
->p
[j
++], dim
-1);
124 P
= Constraints2Polyhedron(M
, P
->NbRays
+1);
130 void value_lcm(Value i
, Value j
, Value
* lcm
)
134 value_multiply(aux
,i
,j
);
136 value_division(*lcm
,aux
,*lcm
);
140 Polyhedron
* supporting_cone_p(Polyhedron
*P
, Param_Vertices
*v
)
143 Value lcm
, tmp
, tmp2
;
144 unsigned char *supporting
= (unsigned char *)malloc(P
->NbConstraints
);
145 unsigned dim
= P
->Dimension
+ 2;
146 unsigned nparam
= v
->Vertex
->NbColumns
- 2;
147 unsigned nvar
= dim
- nparam
- 2;
152 row
= Vector_Alloc(nparam
+1);
157 value_set_si(lcm
, 1);
158 for (i
= 0, n
= 0; i
< P
->NbConstraints
; ++i
) {
159 Vector_Set(row
->p
, 0, nparam
+1);
160 for (j
= 0 ; j
< nvar
; ++j
) {
161 value_set_si(tmp
, 1);
162 value_assign(tmp2
, P
->Constraint
[i
][j
+1]);
163 if (value_ne(lcm
, v
->Vertex
->p
[j
][nparam
+1])) {
164 value_assign(tmp
, lcm
);
165 value_lcm(lcm
, v
->Vertex
->p
[j
][nparam
+1], &lcm
);
166 value_division(tmp
, lcm
, tmp
);
167 value_multiply(tmp2
, tmp2
, lcm
);
168 value_division(tmp2
, tmp2
, v
->Vertex
->p
[j
][nparam
+1]);
170 Vector_Combine(row
->p
, v
->Vertex
->p
[j
], row
->p
,
171 tmp
, tmp2
, nparam
+1);
173 value_set_si(tmp
, 1);
174 Vector_Combine(row
->p
, P
->Constraint
[i
]+1+nvar
, row
->p
, tmp
, lcm
, nparam
+1);
175 for (j
= 0; j
< nparam
+1; ++j
)
176 if (value_notzero_p(row
->p
[j
]))
178 if ((supporting
[i
] = (j
== nparam
+ 1)))
186 M
= Matrix_Alloc(n
, nvar
+2);
188 for (i
= 0, j
= 0; i
< P
->NbConstraints
; ++i
)
190 value_set_si(M
->p
[j
][nvar
+1], 0);
191 Vector_Copy(P
->Constraint
[i
], M
->p
[j
++], nvar
+1);
194 P
= Constraints2Polyhedron(M
, P
->NbRays
+1);
200 Polyhedron
* triangularize_cone(Polyhedron
*P
, unsigned NbMaxCons
)
202 const static int MAX_TRY
=10;
205 unsigned dim
= P
->Dimension
;
206 Matrix
*M
= Matrix_Alloc(P
->NbRays
+1, dim
+3);
208 Polyhedron
*L
, *R
, *T
;
209 assert(P
->NbEq
== 0);
214 Vector_Set(M
->p
[0]+1, 0, dim
+1);
215 value_set_si(M
->p
[0][0], 1);
216 value_set_si(M
->p
[0][dim
+2], 1);
217 Vector_Set(M
->p
[P
->NbRays
]+1, 0, dim
+2);
218 value_set_si(M
->p
[P
->NbRays
][0], 1);
219 value_set_si(M
->p
[P
->NbRays
][dim
+1], 1);
221 /* Delaunay triangulation */
222 for (i
= 0, r
= 1; i
< P
->NbRays
; ++i
) {
223 if (value_notzero_p(P
->Ray
[i
][dim
+1]))
225 Vector_Copy(P
->Ray
[i
], M
->p
[r
], dim
+1);
226 Inner_Product(M
->p
[r
]+1, M
->p
[r
]+1, dim
, &tmp
);
227 value_assign(M
->p
[r
][dim
+1], tmp
);
228 value_set_si(M
->p
[r
][dim
+2], 0);
233 L
= Rays2Polyhedron(M3
, NbMaxCons
);
236 M2
= Matrix_Alloc(dim
+1, dim
+2);
241 /* Usually R should still be 0 */
244 for (r
= 1; r
< P
->NbRays
; ++r
) {
245 value_set_si(M
->p
[r
][dim
+1], random_int((t
+1)*dim
)+1);
248 L
= Rays2Polyhedron(M3
, NbMaxCons
);
252 assert(t
<= MAX_TRY
);
257 for (i
= 0; i
< L
->NbConstraints
; ++i
) {
258 /* Ignore perpendicular facets, i.e., facets with 0 z-coordinate */
259 if (value_negz_p(L
->Constraint
[i
][dim
+1]))
261 if (value_notzero_p(L
->Constraint
[i
][dim
+2]))
263 for (j
= 1, r
= 1; j
< M
->NbRows
; ++j
) {
264 Inner_Product(M
->p
[j
]+1, L
->Constraint
[i
]+1, dim
+1, &tmp
);
265 if (value_notzero_p(tmp
))
269 Vector_Copy(M
->p
[j
]+1, M2
->p
[r
]+1, dim
);
270 value_set_si(M2
->p
[r
][0], 1);
271 value_set_si(M2
->p
[r
][dim
+1], 0);
275 Vector_Set(M2
->p
[0]+1, 0, dim
);
276 value_set_si(M2
->p
[0][0], 1);
277 value_set_si(M2
->p
[0][dim
+1], 1);
278 T
= Rays2Polyhedron(M2
, P
->NbConstraints
+1);
292 void check_triangulization(Polyhedron
*P
, Polyhedron
*T
)
294 Polyhedron
*C
, *D
, *E
, *F
, *G
, *U
;
295 for (C
= T
; C
; C
= C
->next
) {
299 U
= DomainConvex(DomainUnion(U
, C
, 100), 100);
300 for (D
= C
->next
; D
; D
= D
->next
) {
305 E
= DomainIntersection(C
, D
, 600);
306 assert(E
->NbRays
== 0 || E
->NbEq
>= 1);
312 assert(PolyhedronIncludes(U
, P
));
313 assert(PolyhedronIncludes(P
, U
));
316 static void Euclid(Value a
, Value b
, Value
*x
, Value
*y
, Value
*g
)
318 Value c
, d
, e
, f
, tmp
;
325 value_absolute(c
, a
);
326 value_absolute(d
, b
);
329 while(value_pos_p(d
)) {
330 value_division(tmp
, c
, d
);
331 value_multiply(tmp
, tmp
, f
);
332 value_subtract(e
, e
, tmp
);
333 value_division(tmp
, c
, d
);
334 value_multiply(tmp
, tmp
, d
);
335 value_subtract(c
, c
, tmp
);
342 else if (value_pos_p(a
))
344 else value_oppose(*x
, e
);
348 value_multiply(tmp
, a
, *x
);
349 value_subtract(tmp
, c
, tmp
);
350 value_division(*y
, tmp
, b
);
359 Matrix
* unimodular_complete(Vector
*row
)
361 Value g
, b
, c
, old
, tmp
;
370 m
= Matrix_Alloc(row
->Size
, row
->Size
);
371 for (j
= 0; j
< row
->Size
; ++j
) {
372 value_assign(m
->p
[0][j
], row
->p
[j
]);
374 value_assign(g
, row
->p
[0]);
375 for (i
= 1; value_zero_p(g
) && i
< row
->Size
; ++i
) {
376 for (j
= 0; j
< row
->Size
; ++j
) {
378 value_set_si(m
->p
[i
][j
], 1);
380 value_set_si(m
->p
[i
][j
], 0);
382 value_assign(g
, row
->p
[i
]);
384 for (; i
< row
->Size
; ++i
) {
385 value_assign(old
, g
);
386 Euclid(old
, row
->p
[i
], &c
, &b
, &g
);
388 for (j
= 0; j
< row
->Size
; ++j
) {
390 value_multiply(tmp
, row
->p
[j
], b
);
391 value_division(m
->p
[i
][j
], tmp
, old
);
393 value_assign(m
->p
[i
][j
], c
);
395 value_set_si(m
->p
[i
][j
], 0);
407 * Returns a full-dimensional polyhedron with the same number
408 * of integer points as P
410 Polyhedron
*remove_equalities(Polyhedron
*P
)
414 Polyhedron
*p
= Polyhedron_Copy(P
), *q
;
415 unsigned dim
= p
->Dimension
;
420 while (p
->NbEq
> 0) {
422 Vector_Gcd(p
->Constraint
[0]+1, dim
+1, &g
);
423 Vector_AntiScale(p
->Constraint
[0]+1, p
->Constraint
[0]+1, g
, dim
+1);
424 Vector_Gcd(p
->Constraint
[0]+1, dim
, &g
);
425 if (value_notone_p(g
) && value_notmone_p(g
)) {
427 p
= Empty_Polyhedron(0);
430 v
= Vector_Alloc(dim
);
431 Vector_Copy(p
->Constraint
[0]+1, v
->p
, dim
);
432 m1
= unimodular_complete(v
);
433 m2
= Matrix_Alloc(dim
, dim
+1);
434 for (i
= 0; i
< dim
-1 ; ++i
) {
435 Vector_Copy(m1
->p
[i
+1], m2
->p
[i
], dim
);
436 value_set_si(m2
->p
[i
][dim
], 0);
438 Vector_Set(m2
->p
[dim
-1], 0, dim
);
439 value_set_si(m2
->p
[dim
-1][dim
], 1);
440 q
= Polyhedron_Image(p
, m2
, p
->NbConstraints
+1+p
->NbRays
);
453 * Returns a full-dimensional polyhedron with the same number
454 * of integer points as P
455 * nvar specifies the number of variables
456 * The remaining dimensions are assumed to be parameters
458 * factor is NbEq x (nparam+2) matrix, containing stride constraints
459 * on the parameters; column nparam is the constant;
460 * column nparam+1 is the stride
462 * if factor is NULL, only remove equalities that don't affect
463 * the number of points
465 Polyhedron
*remove_equalities_p(Polyhedron
*P
, unsigned nvar
, Matrix
**factor
)
469 Polyhedron
*p
= P
, *q
;
470 unsigned dim
= p
->Dimension
;
476 f
= Matrix_Alloc(p
->NbEq
, dim
-nvar
+2);
481 while (nvar
> 0 && p
->NbEq
- skip
> 0) {
484 while (value_zero_p(p
->Constraint
[skip
][0]) &&
485 First_Non_Zero(p
->Constraint
[skip
]+1, nvar
) == -1)
490 Vector_Gcd(p
->Constraint
[skip
]+1, dim
+1, &g
);
491 Vector_AntiScale(p
->Constraint
[skip
]+1, p
->Constraint
[skip
]+1, g
, dim
+1);
492 Vector_Gcd(p
->Constraint
[skip
]+1, nvar
, &g
);
493 if (!factor
&& value_notone_p(g
) && value_notmone_p(g
)) {
498 Vector_Copy(p
->Constraint
[skip
]+1+nvar
, f
->p
[j
], dim
-nvar
+1);
499 value_assign(f
->p
[j
][dim
-nvar
+1], g
);
501 v
= Vector_Alloc(dim
);
502 Vector_AntiScale(p
->Constraint
[skip
]+1, v
->p
, g
, nvar
);
503 Vector_Set(v
->p
+nvar
, 0, dim
-nvar
);
504 m1
= unimodular_complete(v
);
505 m2
= Matrix_Alloc(dim
, dim
+1);
506 for (i
= 0; i
< dim
-1 ; ++i
) {
507 Vector_Copy(m1
->p
[i
+1], m2
->p
[i
], dim
);
508 value_set_si(m2
->p
[i
][dim
], 0);
510 Vector_Set(m2
->p
[dim
-1], 0, dim
);
511 value_set_si(m2
->p
[dim
-1][dim
], 1);
512 q
= Polyhedron_Image(p
, m2
, p
->NbConstraints
+1+p
->NbRays
);
531 static void free_singles(int **singles
, int dim
)
534 for (i
= 0; i
< dim
; ++i
)
539 static int **find_singles(Polyhedron
*P
, int dim
, int max
, int *nsingle
)
542 int **singles
= (int **) malloc(dim
* sizeof(int *));
545 for (i
= 0; i
< dim
; ++i
) {
546 singles
[i
] = (int *) malloc((max
+ 1) *sizeof(int));
550 for (i
= 0; i
< P
->NbConstraints
; ++i
) {
551 for (j
= 0, prev
= -1; j
< dim
; ++j
) {
552 if (value_notzero_p(P
->Constraint
[i
][j
+1])) {
557 singles
[prev
][0] = -1;
563 if (prev
>= 0 && singles
[prev
][0] >= 0)
564 singles
[prev
][++singles
[prev
][0]] = i
;
567 for (j
= 0; j
< dim
; ++j
)
568 if (singles
[j
][0] > 0)
571 free_singles(singles
, dim
);
578 * The number of points in P is equal to factor time
579 * the number of points in the polyhedron returned.
580 * The return value is zero if no reduction can be found.
582 Polyhedron
* Polyhedron_Reduce(Polyhedron
*P
, Value
* factor
)
584 int i
, j
, nsingle
, k
, p
;
585 unsigned dim
= P
->Dimension
;
588 value_set_si(*factor
, 1);
590 assert (P
->NbEq
== 0);
592 singles
= find_singles(P
, dim
, 2, &nsingle
);
605 for (i
= 0, j
= 0; i
< dim
; ++i
) {
606 if (singles
[i
][0] != 2)
608 for (k
= 0; k
<= 1; ++k
) {
610 value_oppose(tmp
, P
->Constraint
[p
][dim
+1]);
611 if (value_pos_p(P
->Constraint
[p
][i
+1]))
612 mpz_cdiv_q(pos
, tmp
, P
->Constraint
[p
][i
+1]);
614 mpz_fdiv_q(neg
, tmp
, P
->Constraint
[p
][i
+1]);
616 value_subtract(tmp
, neg
, pos
);
617 value_increment(tmp
, tmp
);
618 value_multiply(*factor
, *factor
, tmp
);
625 m
= Matrix_Alloc(P
->NbConstraints
- 2*nsingle
, 1+dim
-nsingle
+1);
627 for (i
= 0, j
= 0; i
< P
->NbConstraints
; ++i
) {
628 k
= First_Non_Zero(P
->Constraint
[i
]+1, dim
);
629 if (singles
[k
][0] == 2)
632 value_assign(m
->p
[j
][0], P
->Constraint
[i
][0]);
633 value_assign(m
->p
[j
][1+dim
-nsingle
], P
->Constraint
[i
][1+dim
]);
634 for (k
= 0, p
= 0; k
< dim
; ++k
) {
635 if (singles
[k
][0] != 2)
636 value_assign(m
->p
[j
][1+p
++], P
->Constraint
[i
][1+k
]);
640 P
= Constraints2Polyhedron(m
, POL_NO_DUAL
?
641 POL_NO_DUAL
: (P
->NbRays
>> nsingle
));
643 free_singles(singles
, dim
);
649 void Line_Length(Polyhedron
*P
, Value
*len
)
655 assert(P
->Dimension
== 1);
661 for (i
= 0; i
< P
->NbConstraints
; ++i
) {
662 value_oppose(tmp
, P
->Constraint
[i
][2]);
663 if (value_pos_p(P
->Constraint
[i
][1])) {
664 mpz_cdiv_q(tmp
, tmp
, P
->Constraint
[i
][1]);
665 if (!p
|| value_gt(tmp
, pos
))
666 value_assign(pos
, tmp
);
669 mpz_fdiv_q(tmp
, tmp
, P
->Constraint
[i
][1]);
670 if (!n
|| value_lt(tmp
, neg
))
671 value_assign(neg
, tmp
);
675 value_subtract(tmp
, neg
, pos
);
676 value_increment(*len
, tmp
);
678 value_set_si(*len
, -1);
687 * Factors the polyhedron P into polyhedra Q_i such that
688 * the number of integer points in P is equal to the product
689 * of the number of integer points in the individual Q_i
691 * If no factors can be found, NULL is returned.
692 * Otherwise, a linked list of the factors is returned.
694 * The algorithm works by first computing the Hermite normal form
695 * and then grouping columns linked by one or more constraints together,
696 * where a constraints "links" two or more columns if the constraint
697 * has nonzero coefficients in the columns.
699 Polyhedron
* Polyhedron_Factor(Polyhedron
*P
, unsigned nparam
,
703 Matrix
*M
, *H
, *Q
, *U
;
704 int *pos
; /* for each column: row position of pivot */
705 int *group
; /* group to which a column belongs */
706 int *cnt
; /* number of columns in the group */
707 int *rowgroup
; /* group to which a constraint belongs */
708 int nvar
= P
->Dimension
- nparam
;
709 Polyhedron
*F
= NULL
;
717 NALLOC(rowgroup
, P
->NbConstraints
);
719 M
= Matrix_Alloc(P
->NbConstraints
, nvar
);
720 for (i
= 0; i
< P
->NbConstraints
; ++i
)
721 Vector_Copy(P
->Constraint
[i
]+1, M
->p
[i
], nvar
);
722 left_hermite(M
, &H
, &Q
, &U
);
727 for (i
= 0; i
< P
->NbConstraints
; ++i
)
729 for (i
= 0, j
= 0; i
< H
->NbColumns
; ++i
) {
730 for ( ; j
< H
->NbRows
; ++j
)
731 if (value_notzero_p(H
->p
[j
][i
]))
733 assert (j
< H
->NbRows
);
736 for (i
= 0; i
< nvar
; ++i
) {
740 for (i
= 0; i
< H
->NbColumns
&& cnt
[0] < nvar
; ++i
) {
741 if (rowgroup
[pos
[i
]] == -1)
742 rowgroup
[pos
[i
]] = i
;
743 for (j
= pos
[i
]+1; j
< H
->NbRows
; ++j
) {
744 if (value_zero_p(H
->p
[j
][i
]))
746 if (rowgroup
[j
] != -1)
748 rowgroup
[j
] = group
[i
];
749 for (k
= i
+1; k
< H
->NbColumns
&& j
>= pos
[k
]; ++k
) {
754 if (group
[k
] != group
[i
] && value_notzero_p(H
->p
[j
][k
])) {
755 assert(cnt
[group
[k
]] != 0);
756 assert(cnt
[group
[i
]] != 0);
757 if (group
[i
] < group
[k
]) {
758 cnt
[group
[i
]] += cnt
[group
[k
]];
762 cnt
[group
[k
]] += cnt
[group
[i
]];
771 if (cnt
[0] != nvar
) {
772 /* Extract out pure context constraints separately */
773 Polyhedron
**next
= &F
;
774 for (i
= nparam
? -1 : 0; i
< nvar
; ++i
) {
778 for (j
= 0, k
= 0; j
< P
->NbConstraints
; ++j
)
779 if (rowgroup
[j
] == -1) {
780 if (First_Non_Zero(P
->Constraint
[j
]+1+nvar
,
793 for (j
= 0, k
= 0; j
< P
->NbConstraints
; ++j
)
794 if (rowgroup
[j
] >= 0 && group
[rowgroup
[j
]] == i
) {
800 M
= Matrix_Alloc(k
, d
+nparam
+2);
801 for (j
= 0, k
= 0; j
< P
->NbConstraints
; ++j
) {
803 if (rowgroup
[j
] != i
)
805 value_assign(M
->p
[k
][0], P
->Constraint
[j
][0]);
806 for (l
= 0, m
= 0; m
< d
; ++l
) {
809 value_assign(M
->p
[k
][1+m
++], H
->p
[j
][l
]);
811 Vector_Copy(P
->Constraint
[j
]+1+nvar
, M
->p
[k
]+1+m
, nparam
+1);
814 *next
= Constraints2Polyhedron(M
, NbMaxRays
);
815 next
= &(*next
)->next
;
828 * Replaces constraint a x >= c by x >= ceil(c/a)
829 * where "a" is a common factor in the coefficients
830 * old is the constraint; v points to an initialized
831 * value that this procedure can use.
832 * Return non-zero if something changed.
833 * Result is placed in new.
835 int ConstraintSimplify(Value
*old
, Value
*new, int len
, Value
* v
)
837 Vector_Gcd(old
+1, len
- 2, v
);
842 Vector_AntiScale(old
+1, new+1, *v
, len
-2);
843 mpz_fdiv_q(new[len
-1], old
[len
-1], *v
);
848 * Project on final dim dimensions
850 Polyhedron
* Polyhedron_Project(Polyhedron
*P
, int dim
)
853 int remove
= P
->Dimension
- dim
;
857 if (P
->Dimension
== dim
)
858 return Polyhedron_Copy(P
);
860 T
= Matrix_Alloc(dim
+1, P
->Dimension
+1);
861 for (i
= 0; i
< dim
+1; ++i
)
862 value_set_si(T
->p
[i
][i
+remove
], 1);
863 I
= Polyhedron_Image(P
, T
, P
->NbConstraints
);
868 /* Constructs a new constraint that ensures that
869 * the first constraint is (strictly) smaller than
872 static void smaller_constraint(Value
*a
, Value
*b
, Value
*c
, int pos
, int shift
,
873 int len
, int strict
, Value
*tmp
)
875 value_oppose(*tmp
, b
[pos
+1]);
876 value_set_si(c
[0], 1);
877 Vector_Combine(a
+1+shift
, b
+1+shift
, c
+1, *tmp
, a
[pos
+1], len
-shift
-1);
879 value_decrement(c
[len
-shift
-1], c
[len
-shift
-1]);
880 ConstraintSimplify(c
, c
, len
-shift
, tmp
);
883 struct section
{ Polyhedron
* D
; evalue E
; };
885 static Polyhedron
* ParamPolyhedron_Reduce_mod(Polyhedron
*P
, unsigned nvar
,
890 unsigned dim
= P
->Dimension
;
892 singles
= find_singles(P
, nvar
, P
->NbConstraints
, &nsingle
);
900 Matrix
*m
= Matrix_Alloc((dim
-nsingle
)+1, dim
+1);
904 evalue_set_si(&mone
, -1, 1);
905 C
= Polyhedron_Project(P
, dim
-nvar
);
909 for (i
= 0, j
= 0; i
< dim
; ++i
) {
910 if (i
>= nvar
|| singles
[i
][0] < 2)
911 value_set_si(m
->p
[j
++][i
], 1);
919 /* put those with positive coefficients first; number: p */
920 for (p
= 0, n
= singles
[i
][0]-1; p
<= n
; ) {
921 while (value_pos_p(P
->Constraint
[singles
[i
][1+p
]][i
+1]))
923 while (value_neg_p(P
->Constraint
[singles
[i
][1+n
]][i
+1]))
926 int t
= singles
[i
][1+p
];
927 singles
[i
][1+p
] = singles
[i
][1+n
];
934 assert (p
>= 1 && n
>= 1);
935 s
= (struct section
*) malloc(p
* n
* sizeof(struct section
));
936 M
= Matrix_Alloc((p
-1) + (n
-1), dim
-nvar
+2);
937 for (k
= 0; k
< p
; ++k
) {
938 for (k2
= 0; k2
< p
; ++k2
) {
943 P
->Constraint
[singles
[i
][1+k
]],
944 P
->Constraint
[singles
[i
][1+k2
]],
945 M
->p
[q
], i
, nvar
, dim
+2, k2
> k
, &g
);
947 for (l
= p
; l
< p
+n
; ++l
) {
948 for (l2
= p
; l2
< p
+n
; ++l2
) {
953 P
->Constraint
[singles
[i
][1+l2
]],
954 P
->Constraint
[singles
[i
][1+l
]],
955 M
->p
[q
], i
, nvar
, dim
+2, l2
> l
, &g
);
958 s
[nd
].D
= Constraints2Polyhedron(M2
, P
->NbRays
);
960 if (emptyQ(s
[nd
].D
)) {
961 Polyhedron_Free(s
[nd
].D
);
964 T
= DomainIntersection(s
[nd
].D
, C
, 0);
965 L
= bv_ceil3(P
->Constraint
[singles
[i
][1+k
]]+1+nvar
,
967 P
->Constraint
[singles
[i
][1+k
]][i
+1], T
);
968 U
= bv_ceil3(P
->Constraint
[singles
[i
][1+l
]]+1+nvar
,
970 P
->Constraint
[singles
[i
][1+l
]][i
+1], T
);
986 value_set_si(F
.d
, 0);
987 F
.x
.p
= new_enode(partition
, 2*nd
, dim
-nvar
);
988 for (k
= 0; k
< nd
; ++k
) {
989 EVALUE_SET_DOMAIN(F
.x
.p
->arr
[2*k
], s
[k
].D
);
990 value_clear(F
.x
.p
->arr
[2*k
+1].d
);
991 F
.x
.p
->arr
[2*k
+1] = s
[k
].E
;
996 free_evalue_refs(&F
);
999 value_set_si(m
->p
[dim
-nsingle
][dim
], 1);
1000 P
= Polyhedron_Image(P
, m
, P
->NbConstraints
);
1002 free_singles(singles
, nvar
);
1006 free_evalue_refs(&mone
);
1010 reduce_evalue(factor
);
1015 evalue
* ParamLine_Length_mod(Polyhedron
*P
, Polyhedron
*C
, int MaxRays
)
1017 unsigned dim
= P
->Dimension
;
1018 unsigned nvar
= dim
- C
->Dimension
;
1024 int k
, l
, k2
, l2
, q
;
1030 Polyhedron
*Corig
= C
;
1034 NALLOC(pos
, P
->NbConstraints
);
1037 evalue_set_si(&mone
, -1, 1);
1039 for (i
= 0, z
= 0; i
< P
->NbConstraints
; ++i
)
1040 if (value_zero_p(P
->Constraint
[i
][1]))
1044 First_Non_Zero(P
->Constraint
[P
->NbConstraints
-1]+1, dim
) != -1)) {
1045 Polyhedron
*C2
= Polyhedron_Project(P
, C
->Dimension
);
1046 C
= DomainIntersection(C
, C2
, MaxRays
);
1047 Polyhedron_Free(C2
);
1050 /* put those with positive coefficients first; number: p */
1051 for (i
= 0, p
= 0, n
= P
->NbConstraints
-z
-1; i
< P
->NbConstraints
; ++i
)
1052 if (value_pos_p(P
->Constraint
[i
][1]))
1054 else if (value_neg_p(P
->Constraint
[i
][1]))
1056 n
= P
->NbConstraints
-z
-p
;
1057 assert (p
>= 1 && n
>= 1);
1058 s
= (struct section
*) malloc(p
* n
* sizeof(struct section
));
1059 M
= Matrix_Alloc((p
-1) + (n
-1), dim
-nvar
+2);
1060 for (k
= 0; k
< p
; ++k
) {
1061 for (k2
= 0; k2
< p
; ++k2
) {
1066 P
->Constraint
[pos
[k
]],
1067 P
->Constraint
[pos
[k2
]],
1068 M
->p
[q
], 0, nvar
, dim
+2, k2
> k
, &g
);
1070 for (l
= p
; l
< p
+n
; ++l
) {
1071 for (l2
= p
; l2
< p
+n
; ++l2
) {
1074 q
= l2
-1 - (l2
> l
);
1076 P
->Constraint
[pos
[l2
]],
1077 P
->Constraint
[pos
[l
]],
1078 M
->p
[q
], 0, nvar
, dim
+2, l2
> l
, &g
);
1080 M2
= Matrix_Copy(M
);
1081 T
= Constraints2Polyhedron(M2
, P
->NbRays
);
1083 s
[nd
].D
= DomainIntersection(T
, C
, MaxRays
);
1085 POL_ENSURE_VERTICES(s
[nd
].D
);
1086 if (emptyQ(s
[nd
].D
)) {
1087 Polyhedron_Free(s
[nd
].D
);
1090 L
= bv_ceil3(P
->Constraint
[pos
[k
]]+1+nvar
,
1092 P
->Constraint
[pos
[k
]][0+1], s
[nd
].D
);
1093 U
= bv_ceil3(P
->Constraint
[pos
[l
]]+1+nvar
,
1095 P
->Constraint
[pos
[l
]][0+1], s
[nd
].D
);
1100 free_evalue_refs(L
);
1111 value_set_si(F
->d
, 0);
1112 F
->x
.p
= new_enode(partition
, 2*nd
, dim
-nvar
);
1113 for (k
= 0; k
< nd
; ++k
) {
1114 EVALUE_SET_DOMAIN(F
->x
.p
->arr
[2*k
], s
[k
].D
);
1115 value_clear(F
->x
.p
->arr
[2*k
+1].d
);
1116 F
->x
.p
->arr
[2*k
+1] = s
[k
].E
;
1120 free_evalue_refs(&mone
);
1131 evalue
* ParamLine_Length(Polyhedron
*P
, Polyhedron
*C
, unsigned MaxRays
)
1133 return ParamLine_Length_mod(P
, C
, MaxRays
);
1136 evalue
* ParamLine_Length(Polyhedron
*P
, Polyhedron
*C
, unsigned MaxRays
)
1139 tmp
= ParamLine_Length_mod(P
, C
);
1140 evalue_mod2table(tmp
, C
->Dimension
);
1147 Polyhedron
* ParamPolyhedron_Reduce(Polyhedron
*P
, unsigned nvar
,
1150 return ParamPolyhedron_Reduce_mod(P
, nvar
, factor
);
1153 Polyhedron
* ParamPolyhedron_Reduce(Polyhedron
*P
, unsigned nvar
,
1159 evalue_set_si(&tmp
, 1, 1);
1160 R
= ParamPolyhedron_Reduce_mod(P
, nvar
, &tmp
);
1161 evalue_mod2table(&tmp
, P
->Dimension
- nvar
);
1162 reduce_evalue(&tmp
);
1164 free_evalue_refs(&tmp
);
1169 Bool
isIdentity(Matrix
*M
)
1172 if (M
->NbRows
!= M
->NbColumns
)
1175 for (i
= 0;i
< M
->NbRows
; i
++)
1176 for (j
= 0; j
< M
->NbColumns
; j
++)
1178 if(value_notone_p(M
->p
[i
][j
]))
1181 if(value_notzero_p(M
->p
[i
][j
]))
1187 void Param_Polyhedron_Print(FILE* DST
, Param_Polyhedron
*PP
, char **param_names
)
1192 for(P
=PP
->D
;P
;P
=P
->next
) {
1194 /* prints current val. dom. */
1195 printf( "---------------------------------------\n" );
1196 printf( "Domain :\n");
1197 Print_Domain( stdout
, P
->Domain
, param_names
);
1199 /* scan the vertices */
1200 printf( "Vertices :\n");
1201 FORALL_PVertex_in_ParamPolyhedron(V
,P
,PP
) {
1203 /* prints each vertex */
1204 Print_Vertex( stdout
, V
->Vertex
, param_names
);
1207 END_FORALL_PVertex_in_ParamPolyhedron
;
1211 void Enumeration_Print(FILE *Dst
, Enumeration
*en
, char **params
)
1213 for (; en
; en
= en
->next
) {
1214 Print_Domain(Dst
, en
->ValidityDomain
, params
);
1215 print_evalue(Dst
, &en
->EP
, params
);
1219 void Enumeration_mod2table(Enumeration
*en
, unsigned nparam
)
1221 for (; en
; en
= en
->next
) {
1222 evalue_mod2table(&en
->EP
, nparam
);
1223 reduce_evalue(&en
->EP
);
1227 size_t Enumeration_size(Enumeration
*en
)
1231 for (; en
; en
= en
->next
) {
1232 s
+= domain_size(en
->ValidityDomain
);
1233 s
+= evalue_size(&en
->EP
);
1238 void Free_ParamNames(char **params
, int m
)
1245 int DomainIncludes(Polyhedron
*Pol1
, Polyhedron
*Pol2
)
1248 for ( ; Pol1
; Pol1
= Pol1
->next
) {
1249 for (P2
= Pol2
; P2
; P2
= P2
->next
)
1250 if (!PolyhedronIncludes(Pol1
, P2
))
1258 static Polyhedron
*p_simplify_constraints(Polyhedron
*P
, Vector
*row
,
1259 Value
*g
, unsigned MaxRays
)
1261 Polyhedron
*T
, *R
= P
;
1262 int len
= P
->Dimension
+2;
1265 /* Also look at equalities.
1266 * If an equality can be "simplified" then there
1267 * are no integer solutions anyway and the following loop
1268 * will add a conflicting constraint
1270 for (r
= 0; r
< R
->NbConstraints
; ++r
) {
1271 if (ConstraintSimplify(R
->Constraint
[r
], row
->p
, len
, g
)) {
1273 R
= AddConstraints(row
->p
, 1, R
, MaxRays
);
1285 * Replaces constraint a x >= c by x >= ceil(c/a)
1286 * where "a" is a common factor in the coefficients
1287 * Destroys P and returns a newly allocated Polyhedron
1288 * or just returns P in case no changes were made
1290 Polyhedron
*DomainConstraintSimplify(Polyhedron
*P
, unsigned MaxRays
)
1293 int len
= P
->Dimension
+2;
1294 Vector
*row
= Vector_Alloc(len
);
1296 Polyhedron
*R
= P
, *N
;
1297 value_set_si(row
->p
[0], 1);
1300 for (prev
= &R
; P
; P
= N
) {
1303 T
= p_simplify_constraints(P
, row
, &g
, MaxRays
);
1305 if (emptyQ(T
) && prev
!= &R
) {
1317 if (R
->next
&& emptyQ(R
)) {
1328 int line_minmax(Polyhedron
*I
, Value
*min
, Value
*max
)
1333 value_oppose(I
->Constraint
[0][2], I
->Constraint
[0][2]);
1334 /* There should never be a remainder here */
1335 if (value_pos_p(I
->Constraint
[0][1]))
1336 mpz_fdiv_q(*min
, I
->Constraint
[0][2], I
->Constraint
[0][1]);
1338 mpz_fdiv_q(*min
, I
->Constraint
[0][2], I
->Constraint
[0][1]);
1339 value_assign(*max
, *min
);
1340 } else for (i
= 0; i
< I
->NbConstraints
; ++i
) {
1341 if (value_zero_p(I
->Constraint
[i
][1])) {
1346 value_oppose(I
->Constraint
[i
][2], I
->Constraint
[i
][2]);
1347 if (value_pos_p(I
->Constraint
[i
][1]))
1348 mpz_cdiv_q(*min
, I
->Constraint
[i
][2], I
->Constraint
[i
][1]);
1350 mpz_fdiv_q(*max
, I
->Constraint
[i
][2], I
->Constraint
[i
][1]);
1358 PROCEDURES TO COMPUTE ENUMERATION. recursive procedure, recurse for
1361 @param pos index position of current loop index (1..hdim-1)
1362 @param P loop domain
1363 @param context context values for fixed indices
1364 @param exist number of existential variables
1365 @return the number of integer points in this
1369 void count_points_e (int pos
, Polyhedron
*P
, int exist
, int nparam
,
1370 Value
*context
, Value
*res
)
1375 value_set_si(*res
, 0);
1379 value_init(LB
); value_init(UB
); value_init(k
);
1383 if (lower_upper_bounds(pos
,P
,context
,&LB
,&UB
) !=0) {
1384 /* Problem if UB or LB is INFINITY */
1385 value_clear(LB
); value_clear(UB
); value_clear(k
);
1386 if (pos
> P
->Dimension
- nparam
- exist
)
1387 value_set_si(*res
, 1);
1389 value_set_si(*res
, -1);
1396 for (value_assign(k
,LB
); value_le(k
,UB
); value_increment(k
,k
)) {
1397 fprintf(stderr
, "(");
1398 for (i
=1; i
<pos
; i
++) {
1399 value_print(stderr
,P_VALUE_FMT
,context
[i
]);
1400 fprintf(stderr
,",");
1402 value_print(stderr
,P_VALUE_FMT
,k
);
1403 fprintf(stderr
,")\n");
1408 value_set_si(context
[pos
],0);
1409 if (value_lt(UB
,LB
)) {
1410 value_clear(LB
); value_clear(UB
); value_clear(k
);
1411 value_set_si(*res
, 0);
1416 value_set_si(*res
, 1);
1418 value_subtract(k
,UB
,LB
);
1419 value_add_int(k
,k
,1);
1420 value_assign(*res
, k
);
1422 value_clear(LB
); value_clear(UB
); value_clear(k
);
1426 /*-----------------------------------------------------------------*/
1427 /* Optimization idea */
1428 /* If inner loops are not a function of k (the current index) */
1429 /* i.e. if P->Constraint[i][pos]==0 for all P following this and */
1431 /* Then CNT = (UB-LB+1)*count_points(pos+1, P->next, context) */
1432 /* (skip the for loop) */
1433 /*-----------------------------------------------------------------*/
1436 value_set_si(*res
, 0);
1437 for (value_assign(k
,LB
);value_le(k
,UB
);value_increment(k
,k
)) {
1438 /* Insert k in context */
1439 value_assign(context
[pos
],k
);
1440 count_points_e(pos
+1, P
->next
, exist
, nparam
, context
, &c
);
1441 if(value_notmone_p(c
))
1442 value_addto(*res
, *res
, c
);
1444 value_set_si(*res
, -1);
1447 if (pos
> P
->Dimension
- nparam
- exist
&&
1454 fprintf(stderr
,"%d\n",CNT
);
1458 value_set_si(context
[pos
],0);
1459 value_clear(LB
); value_clear(UB
); value_clear(k
);
1461 } /* count_points_e */
1463 int DomainContains(Polyhedron
*P
, Value
*list_args
, int len
,
1464 unsigned MaxRays
, int set
)
1469 if (P
->Dimension
== len
)
1470 return in_domain(P
, list_args
);
1472 assert(set
); // assume list_args is large enough
1473 assert((P
->Dimension
- len
) % 2 == 0);
1475 for (i
= 0; i
< P
->Dimension
- len
; i
+= 2) {
1477 for (j
= 0 ; j
< P
->NbEq
; ++j
)
1478 if (value_notzero_p(P
->Constraint
[j
][1+len
+i
]))
1480 assert(j
< P
->NbEq
);
1481 value_absolute(m
, P
->Constraint
[j
][1+len
+i
]);
1482 k
= First_Non_Zero(P
->Constraint
[j
]+1, len
);
1484 assert(First_Non_Zero(P
->Constraint
[j
]+1+k
+1, len
- k
- 1) == -1);
1485 mpz_fdiv_q(list_args
[len
+i
], list_args
[k
], m
);
1486 mpz_fdiv_r(list_args
[len
+i
+1], list_args
[k
], m
);
1490 return in_domain(P
, list_args
);
1493 const char *barvinok_version(void)
1496 "barvinok " VERSION
" (" GIT_HEAD_ID
")\n"
1502 #ifdef USE_INCREMENTAL_BF
1504 #elif defined USE_INCREMENTAL_DF
1510 #ifdef HAVE_CORRECT_VERTICES
1511 " +CORRECT_VERTICES"
1513 " -CORRECT_VERTICES"