1 #include <barvinok/util.h>
6 #ifndef HAVE_ENUMERATE4
7 #define Polyhedron_Enumerate(a,b,c,d) Polyhedron_Enumerate(a,b,c)
10 #define ALLOC(type) (type*)malloc(sizeof(type))
11 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
14 #define NALLOC(p,n) p = (typeof(p))malloc((n) * 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
39 #include <barvinok/evalue.h>
40 #include <barvinok/util.h>
41 #include <barvinok/barvinok.h>
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 Polyhedron
*Polyhedron_Read(unsigned MaxRays
)
52 unsigned NbRows
, NbColumns
;
57 while (fgets(s
, sizeof(s
), stdin
)) {
60 if (strncasecmp(s
, "vertices", sizeof("vertices")-1) == 0)
62 if (sscanf(s
, "%u %u", &NbRows
, &NbColumns
) == 2)
67 M
= Matrix_Alloc(NbRows
,NbColumns
);
70 P
= Rays2Polyhedron(M
, MaxRays
);
72 P
= Constraints2Polyhedron(M
, MaxRays
);
77 /* Inplace polarization
79 void Polyhedron_Polarize(Polyhedron
*P
)
81 unsigned NbRows
= P
->NbConstraints
+ P
->NbRays
;
85 q
= (Value
**)malloc(NbRows
* sizeof(Value
*));
87 for (i
= 0; i
< P
->NbRays
; ++i
)
89 for (; i
< NbRows
; ++i
)
90 q
[i
] = P
->Constraint
[i
-P
->NbRays
];
91 P
->NbConstraints
= NbRows
- P
->NbConstraints
;
92 P
->NbRays
= NbRows
- P
->NbRays
;
95 P
->Ray
= q
+ P
->NbConstraints
;
99 * Rather general polar
100 * We can optimize it significantly if we assume that
103 * Also, we calculate the polar as defined in Schrijver
104 * The opposite should probably work as well and would
105 * eliminate the need for multiplying by -1
107 Polyhedron
* Polyhedron_Polar(Polyhedron
*P
, unsigned NbMaxRays
)
111 unsigned dim
= P
->Dimension
+ 2;
112 Matrix
*M
= Matrix_Alloc(P
->NbRays
, dim
);
116 value_set_si(mone
, -1);
117 for (i
= 0; i
< P
->NbRays
; ++i
) {
118 Vector_Scale(P
->Ray
[i
], M
->p
[i
], mone
, dim
);
119 value_multiply(M
->p
[i
][0], M
->p
[i
][0], mone
);
120 value_multiply(M
->p
[i
][dim
-1], M
->p
[i
][dim
-1], mone
);
122 P
= Constraints2Polyhedron(M
, NbMaxRays
);
130 * Returns the supporting cone of P at the vertex with index v
132 Polyhedron
* supporting_cone(Polyhedron
*P
, int v
)
137 unsigned char *supporting
= (unsigned char *)malloc(P
->NbConstraints
);
138 unsigned dim
= P
->Dimension
+ 2;
140 assert(v
>=0 && v
< P
->NbRays
);
141 assert(value_pos_p(P
->Ray
[v
][dim
-1]));
145 for (i
= 0, n
= 0; i
< P
->NbConstraints
; ++i
) {
146 Inner_Product(P
->Constraint
[i
] + 1, P
->Ray
[v
] + 1, dim
- 1, &tmp
);
147 if ((supporting
[i
] = value_zero_p(tmp
)))
150 assert(n
>= dim
- 2);
152 M
= Matrix_Alloc(n
, dim
);
154 for (i
= 0, j
= 0; i
< P
->NbConstraints
; ++i
)
156 value_set_si(M
->p
[j
][dim
-1], 0);
157 Vector_Copy(P
->Constraint
[i
], M
->p
[j
++], dim
-1);
160 P
= Constraints2Polyhedron(M
, P
->NbRays
+1);
166 void value_lcm(Value i
, Value j
, Value
* lcm
)
170 value_multiply(aux
,i
,j
);
172 value_division(*lcm
,aux
,*lcm
);
176 Polyhedron
* supporting_cone_p(Polyhedron
*P
, Param_Vertices
*v
)
179 Value lcm
, tmp
, tmp2
;
180 unsigned char *supporting
= (unsigned char *)malloc(P
->NbConstraints
);
181 unsigned dim
= P
->Dimension
+ 2;
182 unsigned nparam
= v
->Vertex
->NbColumns
- 2;
183 unsigned nvar
= dim
- nparam
- 2;
188 row
= Vector_Alloc(nparam
+1);
193 value_set_si(lcm
, 1);
194 for (i
= 0, n
= 0; i
< P
->NbConstraints
; ++i
) {
195 Vector_Set(row
->p
, 0, nparam
+1);
196 for (j
= 0 ; j
< nvar
; ++j
) {
197 value_set_si(tmp
, 1);
198 value_assign(tmp2
, P
->Constraint
[i
][j
+1]);
199 if (value_ne(lcm
, v
->Vertex
->p
[j
][nparam
+1])) {
200 value_assign(tmp
, lcm
);
201 value_lcm(lcm
, v
->Vertex
->p
[j
][nparam
+1], &lcm
);
202 value_division(tmp
, lcm
, tmp
);
203 value_multiply(tmp2
, tmp2
, lcm
);
204 value_division(tmp2
, tmp2
, v
->Vertex
->p
[j
][nparam
+1]);
206 Vector_Combine(row
->p
, v
->Vertex
->p
[j
], row
->p
,
207 tmp
, tmp2
, nparam
+1);
209 value_set_si(tmp
, 1);
210 Vector_Combine(row
->p
, P
->Constraint
[i
]+1+nvar
, row
->p
, tmp
, lcm
, nparam
+1);
211 for (j
= 0; j
< nparam
+1; ++j
)
212 if (value_notzero_p(row
->p
[j
]))
214 if ((supporting
[i
] = (j
== nparam
+ 1)))
222 M
= Matrix_Alloc(n
, nvar
+2);
224 for (i
= 0, j
= 0; i
< P
->NbConstraints
; ++i
)
226 value_set_si(M
->p
[j
][nvar
+1], 0);
227 Vector_Copy(P
->Constraint
[i
], M
->p
[j
++], nvar
+1);
230 P
= Constraints2Polyhedron(M
, P
->NbRays
+1);
236 Polyhedron
* triangulate_cone(Polyhedron
*P
, unsigned NbMaxCons
)
238 const static int MAX_TRY
=10;
241 unsigned dim
= P
->Dimension
;
242 Matrix
*M
= Matrix_Alloc(P
->NbRays
+1, dim
+3);
244 Polyhedron
*L
, *R
, *T
;
245 assert(P
->NbEq
== 0);
250 Vector_Set(M
->p
[0]+1, 0, dim
+1);
251 value_set_si(M
->p
[0][0], 1);
252 value_set_si(M
->p
[0][dim
+2], 1);
253 Vector_Set(M
->p
[P
->NbRays
]+1, 0, dim
+2);
254 value_set_si(M
->p
[P
->NbRays
][0], 1);
255 value_set_si(M
->p
[P
->NbRays
][dim
+1], 1);
257 /* Delaunay triangulation */
258 for (i
= 0, r
= 1; i
< P
->NbRays
; ++i
) {
259 if (value_notzero_p(P
->Ray
[i
][dim
+1]))
261 Vector_Copy(P
->Ray
[i
], M
->p
[r
], dim
+1);
262 Inner_Product(M
->p
[r
]+1, M
->p
[r
]+1, dim
, &tmp
);
263 value_assign(M
->p
[r
][dim
+1], tmp
);
264 value_set_si(M
->p
[r
][dim
+2], 0);
269 L
= Rays2Polyhedron(M3
, NbMaxCons
);
272 M2
= Matrix_Alloc(dim
+1, dim
+2);
277 /* Usually R should still be 0 */
280 for (r
= 1; r
< P
->NbRays
; ++r
) {
281 value_set_si(M
->p
[r
][dim
+1], random_int((t
+1)*dim
*P
->NbRays
)+1);
284 L
= Rays2Polyhedron(M3
, NbMaxCons
);
288 assert(t
<= MAX_TRY
);
293 for (i
= 0; i
< L
->NbConstraints
; ++i
) {
294 /* Ignore perpendicular facets, i.e., facets with 0 z-coordinate */
295 if (value_negz_p(L
->Constraint
[i
][dim
+1]))
297 if (value_notzero_p(L
->Constraint
[i
][dim
+2]))
299 for (j
= 1, r
= 1; j
< M
->NbRows
; ++j
) {
300 Inner_Product(M
->p
[j
]+1, L
->Constraint
[i
]+1, dim
+1, &tmp
);
301 if (value_notzero_p(tmp
))
305 Vector_Copy(M
->p
[j
]+1, M2
->p
[r
]+1, dim
);
306 value_set_si(M2
->p
[r
][0], 1);
307 value_set_si(M2
->p
[r
][dim
+1], 0);
311 Vector_Set(M2
->p
[0]+1, 0, dim
);
312 value_set_si(M2
->p
[0][0], 1);
313 value_set_si(M2
->p
[0][dim
+1], 1);
314 T
= Rays2Polyhedron(M2
, P
->NbConstraints
+1);
328 void check_triangulization(Polyhedron
*P
, Polyhedron
*T
)
330 Polyhedron
*C
, *D
, *E
, *F
, *G
, *U
;
331 for (C
= T
; C
; C
= C
->next
) {
335 U
= DomainConvex(DomainUnion(U
, C
, 100), 100);
336 for (D
= C
->next
; D
; D
= D
->next
) {
341 E
= DomainIntersection(C
, D
, 600);
342 assert(E
->NbRays
== 0 || E
->NbEq
>= 1);
348 assert(PolyhedronIncludes(U
, P
));
349 assert(PolyhedronIncludes(P
, U
));
352 /* Computes x, y and g such that g = gcd(a,b) and a*x+b*y = g */
353 void Extended_Euclid(Value a
, Value b
, Value
*x
, Value
*y
, Value
*g
)
355 Value c
, d
, e
, f
, tmp
;
362 value_absolute(c
, a
);
363 value_absolute(d
, b
);
366 while(value_pos_p(d
)) {
367 value_division(tmp
, c
, d
);
368 value_multiply(tmp
, tmp
, f
);
369 value_subtract(e
, e
, tmp
);
370 value_division(tmp
, c
, d
);
371 value_multiply(tmp
, tmp
, d
);
372 value_subtract(c
, c
, tmp
);
379 else if (value_pos_p(a
))
381 else value_oppose(*x
, e
);
385 value_multiply(tmp
, a
, *x
);
386 value_subtract(tmp
, c
, tmp
);
387 value_division(*y
, tmp
, b
);
396 Matrix
* unimodular_complete(Vector
*row
)
398 Value g
, b
, c
, old
, tmp
;
407 m
= Matrix_Alloc(row
->Size
, row
->Size
);
408 for (j
= 0; j
< row
->Size
; ++j
) {
409 value_assign(m
->p
[0][j
], row
->p
[j
]);
411 value_assign(g
, row
->p
[0]);
412 for (i
= 1; value_zero_p(g
) && i
< row
->Size
; ++i
) {
413 for (j
= 0; j
< row
->Size
; ++j
) {
415 value_set_si(m
->p
[i
][j
], 1);
417 value_set_si(m
->p
[i
][j
], 0);
419 value_assign(g
, row
->p
[i
]);
421 for (; i
< row
->Size
; ++i
) {
422 value_assign(old
, g
);
423 Extended_Euclid(old
, row
->p
[i
], &c
, &b
, &g
);
425 for (j
= 0; j
< row
->Size
; ++j
) {
427 value_multiply(tmp
, row
->p
[j
], b
);
428 value_division(m
->p
[i
][j
], tmp
, old
);
430 value_assign(m
->p
[i
][j
], c
);
432 value_set_si(m
->p
[i
][j
], 0);
444 * Returns a full-dimensional polyhedron with the same number
445 * of integer points as P
447 Polyhedron
*remove_equalities(Polyhedron
*P
)
451 Polyhedron
*p
= Polyhedron_Copy(P
), *q
;
452 unsigned dim
= p
->Dimension
;
457 while (!emptyQ2(p
) && p
->NbEq
> 0) {
459 Vector_Gcd(p
->Constraint
[0]+1, dim
+1, &g
);
460 Vector_AntiScale(p
->Constraint
[0]+1, p
->Constraint
[0]+1, g
, dim
+1);
461 Vector_Gcd(p
->Constraint
[0]+1, dim
, &g
);
462 if (value_notone_p(g
) && value_notmone_p(g
)) {
464 p
= Empty_Polyhedron(0);
467 v
= Vector_Alloc(dim
);
468 Vector_Copy(p
->Constraint
[0]+1, v
->p
, dim
);
469 m1
= unimodular_complete(v
);
470 m2
= Matrix_Alloc(dim
, dim
+1);
471 for (i
= 0; i
< dim
-1 ; ++i
) {
472 Vector_Copy(m1
->p
[i
+1], m2
->p
[i
], dim
);
473 value_set_si(m2
->p
[i
][dim
], 0);
475 Vector_Set(m2
->p
[dim
-1], 0, dim
);
476 value_set_si(m2
->p
[dim
-1][dim
], 1);
477 q
= Polyhedron_Image(p
, m2
, p
->NbConstraints
+1+p
->NbRays
);
490 * Returns a full-dimensional polyhedron with the same number
491 * of integer points as P
492 * nvar specifies the number of variables
493 * The remaining dimensions are assumed to be parameters
495 * factor is NbEq x (nparam+2) matrix, containing stride constraints
496 * on the parameters; column nparam is the constant;
497 * column nparam+1 is the stride
499 * if factor is NULL, only remove equalities that don't affect
500 * the number of points
502 Polyhedron
*remove_equalities_p(Polyhedron
*P
, unsigned nvar
, Matrix
**factor
)
506 Polyhedron
*p
= P
, *q
;
507 unsigned dim
= p
->Dimension
;
513 f
= Matrix_Alloc(p
->NbEq
, dim
-nvar
+2);
518 while (nvar
> 0 && p
->NbEq
- skip
> 0) {
521 while (skip
< p
->NbEq
&&
522 First_Non_Zero(p
->Constraint
[skip
]+1, nvar
) == -1)
527 Vector_Gcd(p
->Constraint
[skip
]+1, dim
+1, &g
);
528 Vector_AntiScale(p
->Constraint
[skip
]+1, p
->Constraint
[skip
]+1, g
, dim
+1);
529 Vector_Gcd(p
->Constraint
[skip
]+1, nvar
, &g
);
530 if (!factor
&& value_notone_p(g
) && value_notmone_p(g
)) {
535 Vector_Copy(p
->Constraint
[skip
]+1+nvar
, f
->p
[j
], dim
-nvar
+1);
536 value_assign(f
->p
[j
][dim
-nvar
+1], g
);
538 v
= Vector_Alloc(dim
);
539 Vector_AntiScale(p
->Constraint
[skip
]+1, v
->p
, g
, nvar
);
540 Vector_Set(v
->p
+nvar
, 0, dim
-nvar
);
541 m1
= unimodular_complete(v
);
542 m2
= Matrix_Alloc(dim
, dim
+1);
543 for (i
= 0; i
< dim
-1 ; ++i
) {
544 Vector_Copy(m1
->p
[i
+1], m2
->p
[i
], dim
);
545 value_set_si(m2
->p
[i
][dim
], 0);
547 Vector_Set(m2
->p
[dim
-1], 0, dim
);
548 value_set_si(m2
->p
[dim
-1][dim
], 1);
549 q
= Polyhedron_Image(p
, m2
, p
->NbConstraints
+1+p
->NbRays
);
563 void Line_Length(Polyhedron
*P
, Value
*len
)
569 assert(P
->Dimension
== 1);
575 for (i
= 0; i
< P
->NbConstraints
; ++i
) {
576 value_oppose(tmp
, P
->Constraint
[i
][2]);
577 if (value_pos_p(P
->Constraint
[i
][1])) {
578 mpz_cdiv_q(tmp
, tmp
, P
->Constraint
[i
][1]);
579 if (!p
|| value_gt(tmp
, pos
))
580 value_assign(pos
, tmp
);
583 mpz_fdiv_q(tmp
, tmp
, P
->Constraint
[i
][1]);
584 if (!n
|| value_lt(tmp
, neg
))
585 value_assign(neg
, tmp
);
589 value_subtract(tmp
, neg
, pos
);
590 value_increment(*len
, tmp
);
592 value_set_si(*len
, -1);
601 * Factors the polyhedron P into polyhedra Q_i such that
602 * the number of integer points in P is equal to the product
603 * of the number of integer points in the individual Q_i
605 * If no factors can be found, NULL is returned.
606 * Otherwise, a linked list of the factors is returned.
608 * The algorithm works by first computing the Hermite normal form
609 * and then grouping columns linked by one or more constraints together,
610 * where a constraints "links" two or more columns if the constraint
611 * has nonzero coefficients in the columns.
613 Polyhedron
* Polyhedron_Factor(Polyhedron
*P
, unsigned nparam
,
617 Matrix
*M
, *H
, *Q
, *U
;
618 int *pos
; /* for each column: row position of pivot */
619 int *group
; /* group to which a column belongs */
620 int *cnt
; /* number of columns in the group */
621 int *rowgroup
; /* group to which a constraint belongs */
622 int nvar
= P
->Dimension
- nparam
;
623 Polyhedron
*F
= NULL
;
631 NALLOC(rowgroup
, P
->NbConstraints
);
633 M
= Matrix_Alloc(P
->NbConstraints
, nvar
);
634 for (i
= 0; i
< P
->NbConstraints
; ++i
)
635 Vector_Copy(P
->Constraint
[i
]+1, M
->p
[i
], nvar
);
636 left_hermite(M
, &H
, &Q
, &U
);
641 for (i
= 0; i
< P
->NbConstraints
; ++i
)
643 for (i
= 0, j
= 0; i
< H
->NbColumns
; ++i
) {
644 for ( ; j
< H
->NbRows
; ++j
)
645 if (value_notzero_p(H
->p
[j
][i
]))
647 assert (j
< H
->NbRows
);
650 for (i
= 0; i
< nvar
; ++i
) {
654 for (i
= 0; i
< H
->NbColumns
&& cnt
[0] < nvar
; ++i
) {
655 if (rowgroup
[pos
[i
]] == -1)
656 rowgroup
[pos
[i
]] = i
;
657 for (j
= pos
[i
]+1; j
< H
->NbRows
; ++j
) {
658 if (value_zero_p(H
->p
[j
][i
]))
660 if (rowgroup
[j
] != -1)
662 rowgroup
[j
] = group
[i
];
663 for (k
= i
+1; k
< H
->NbColumns
&& j
>= pos
[k
]; ++k
) {
668 if (group
[k
] != group
[i
] && value_notzero_p(H
->p
[j
][k
])) {
669 assert(cnt
[group
[k
]] != 0);
670 assert(cnt
[group
[i
]] != 0);
671 if (group
[i
] < group
[k
]) {
672 cnt
[group
[i
]] += cnt
[group
[k
]];
676 cnt
[group
[k
]] += cnt
[group
[i
]];
685 if (cnt
[0] != nvar
) {
686 /* Extract out pure context constraints separately */
687 Polyhedron
**next
= &F
;
688 for (i
= nparam
? -1 : 0; i
< nvar
; ++i
) {
692 for (j
= 0, k
= 0; j
< P
->NbConstraints
; ++j
)
693 if (rowgroup
[j
] == -1) {
694 if (First_Non_Zero(P
->Constraint
[j
]+1+nvar
,
707 for (j
= 0, k
= 0; j
< P
->NbConstraints
; ++j
)
708 if (rowgroup
[j
] >= 0 && group
[rowgroup
[j
]] == i
) {
714 M
= Matrix_Alloc(k
, d
+nparam
+2);
715 for (j
= 0, k
= 0; j
< P
->NbConstraints
; ++j
) {
717 if (rowgroup
[j
] != i
)
719 value_assign(M
->p
[k
][0], P
->Constraint
[j
][0]);
720 for (l
= 0, m
= 0; m
< d
; ++l
) {
723 value_assign(M
->p
[k
][1+m
++], H
->p
[j
][l
]);
725 Vector_Copy(P
->Constraint
[j
]+1+nvar
, M
->p
[k
]+1+m
, nparam
+1);
728 *next
= Constraints2Polyhedron(M
, NbMaxRays
);
729 next
= &(*next
)->next
;
742 * Project on final dim dimensions
744 Polyhedron
* Polyhedron_Project(Polyhedron
*P
, int dim
)
747 int remove
= P
->Dimension
- dim
;
751 if (P
->Dimension
== dim
)
752 return Polyhedron_Copy(P
);
754 T
= Matrix_Alloc(dim
+1, P
->Dimension
+1);
755 for (i
= 0; i
< dim
+1; ++i
)
756 value_set_si(T
->p
[i
][i
+remove
], 1);
757 I
= Polyhedron_Image(P
, T
, P
->NbConstraints
);
762 /* Constructs a new constraint that ensures that
763 * the first constraint is (strictly) smaller than
766 static void smaller_constraint(Value
*a
, Value
*b
, Value
*c
, int pos
, int shift
,
767 int len
, int strict
, Value
*tmp
)
769 value_oppose(*tmp
, b
[pos
+1]);
770 value_set_si(c
[0], 1);
771 Vector_Combine(a
+1+shift
, b
+1+shift
, c
+1, *tmp
, a
[pos
+1], len
-shift
-1);
773 value_decrement(c
[len
-shift
-1], c
[len
-shift
-1]);
774 ConstraintSimplify(c
, c
, len
-shift
, tmp
);
777 struct section
{ Polyhedron
* D
; evalue E
; };
779 evalue
* ParamLine_Length_mod(Polyhedron
*P
, Polyhedron
*C
, int MaxRays
)
781 unsigned dim
= P
->Dimension
;
782 unsigned nvar
= dim
- C
->Dimension
;
797 NALLOC(pos
, P
->NbConstraints
);
800 evalue_set_si(&mone
, -1, 1);
802 for (i
= 0, z
= 0; i
< P
->NbConstraints
; ++i
)
803 if (value_zero_p(P
->Constraint
[i
][1]))
805 /* put those with positive coefficients first; number: p */
806 for (i
= 0, p
= 0, n
= P
->NbConstraints
-z
-1; i
< P
->NbConstraints
; ++i
)
807 if (value_pos_p(P
->Constraint
[i
][1]))
809 else if (value_neg_p(P
->Constraint
[i
][1]))
811 n
= P
->NbConstraints
-z
-p
;
812 assert (p
>= 1 && n
>= 1);
813 s
= (struct section
*) malloc(p
* n
* sizeof(struct section
));
814 M
= Matrix_Alloc((p
-1) + (n
-1), dim
-nvar
+2);
815 for (k
= 0; k
< p
; ++k
) {
816 for (k2
= 0; k2
< p
; ++k2
) {
821 P
->Constraint
[pos
[k
]],
822 P
->Constraint
[pos
[k2
]],
823 M
->p
[q
], 0, nvar
, dim
+2, k2
> k
, &g
);
825 for (l
= p
; l
< p
+n
; ++l
) {
826 for (l2
= p
; l2
< p
+n
; ++l2
) {
831 P
->Constraint
[pos
[l2
]],
832 P
->Constraint
[pos
[l
]],
833 M
->p
[q
], 0, nvar
, dim
+2, l2
> l
, &g
);
836 T
= Constraints2Polyhedron(M2
, P
->NbRays
);
838 s
[nd
].D
= DomainIntersection(T
, C
, MaxRays
);
840 POL_ENSURE_VERTICES(s
[nd
].D
);
841 if (emptyQ(s
[nd
].D
)) {
842 Polyhedron_Free(s
[nd
].D
);
845 L
= bv_ceil3(P
->Constraint
[pos
[k
]]+1+nvar
,
847 P
->Constraint
[pos
[k
]][0+1], s
[nd
].D
);
848 U
= bv_ceil3(P
->Constraint
[pos
[l
]]+1+nvar
,
850 P
->Constraint
[pos
[l
]][0+1], s
[nd
].D
);
866 value_set_si(F
->d
, 0);
867 F
->x
.p
= new_enode(partition
, 2*nd
, dim
-nvar
);
868 for (k
= 0; k
< nd
; ++k
) {
869 EVALUE_SET_DOMAIN(F
->x
.p
->arr
[2*k
], s
[k
].D
);
870 value_clear(F
->x
.p
->arr
[2*k
+1].d
);
871 F
->x
.p
->arr
[2*k
+1] = s
[k
].E
;
875 free_evalue_refs(&mone
);
883 evalue
* ParamLine_Length(Polyhedron
*P
, Polyhedron
*C
, unsigned MaxRays
)
885 return ParamLine_Length_mod(P
, C
, MaxRays
);
888 evalue
* ParamLine_Length(Polyhedron
*P
, Polyhedron
*C
, unsigned MaxRays
)
891 tmp
= ParamLine_Length_mod(P
, C
, MaxRays
);
892 evalue_mod2table(tmp
, C
->Dimension
);
898 Bool
isIdentity(Matrix
*M
)
901 if (M
->NbRows
!= M
->NbColumns
)
904 for (i
= 0;i
< M
->NbRows
; i
++)
905 for (j
= 0; j
< M
->NbColumns
; j
++)
907 if(value_notone_p(M
->p
[i
][j
]))
910 if(value_notzero_p(M
->p
[i
][j
]))
916 void Param_Polyhedron_Print(FILE* DST
, Param_Polyhedron
*PP
, char **param_names
)
921 for(P
=PP
->D
;P
;P
=P
->next
) {
923 /* prints current val. dom. */
924 printf( "---------------------------------------\n" );
925 printf( "Domain :\n");
926 Print_Domain( stdout
, P
->Domain
, param_names
);
928 /* scan the vertices */
929 printf( "Vertices :\n");
930 FORALL_PVertex_in_ParamPolyhedron(V
,P
,PP
) {
932 /* prints each vertex */
933 Print_Vertex( stdout
, V
->Vertex
, param_names
);
936 END_FORALL_PVertex_in_ParamPolyhedron
;
940 void Enumeration_Print(FILE *Dst
, Enumeration
*en
, char **params
)
942 for (; en
; en
= en
->next
) {
943 Print_Domain(Dst
, en
->ValidityDomain
, params
);
944 print_evalue(Dst
, &en
->EP
, params
);
948 void Enumeration_Free(Enumeration
*en
)
954 free_evalue_refs( &(en
->EP
) );
955 Domain_Free( en
->ValidityDomain
);
962 void Enumeration_mod2table(Enumeration
*en
, unsigned nparam
)
964 for (; en
; en
= en
->next
) {
965 evalue_mod2table(&en
->EP
, nparam
);
966 reduce_evalue(&en
->EP
);
970 size_t Enumeration_size(Enumeration
*en
)
974 for (; en
; en
= en
->next
) {
975 s
+= domain_size(en
->ValidityDomain
);
976 s
+= evalue_size(&en
->EP
);
981 void Free_ParamNames(char **params
, int m
)
988 int DomainIncludes(Polyhedron
*Pol1
, Polyhedron
*Pol2
)
991 for ( ; Pol1
; Pol1
= Pol1
->next
) {
992 for (P2
= Pol2
; P2
; P2
= P2
->next
)
993 if (!PolyhedronIncludes(Pol1
, P2
))
1001 int line_minmax(Polyhedron
*I
, Value
*min
, Value
*max
)
1006 value_oppose(I
->Constraint
[0][2], I
->Constraint
[0][2]);
1007 /* There should never be a remainder here */
1008 if (value_pos_p(I
->Constraint
[0][1]))
1009 mpz_fdiv_q(*min
, I
->Constraint
[0][2], I
->Constraint
[0][1]);
1011 mpz_fdiv_q(*min
, I
->Constraint
[0][2], I
->Constraint
[0][1]);
1012 value_assign(*max
, *min
);
1013 } else for (i
= 0; i
< I
->NbConstraints
; ++i
) {
1014 if (value_zero_p(I
->Constraint
[i
][1])) {
1019 value_oppose(I
->Constraint
[i
][2], I
->Constraint
[i
][2]);
1020 if (value_pos_p(I
->Constraint
[i
][1]))
1021 mpz_cdiv_q(*min
, I
->Constraint
[i
][2], I
->Constraint
[i
][1]);
1023 mpz_fdiv_q(*max
, I
->Constraint
[i
][2], I
->Constraint
[i
][1]);
1031 PROCEDURES TO COMPUTE ENUMERATION. recursive procedure, recurse for
1034 @param pos index position of current loop index (1..hdim-1)
1035 @param P loop domain
1036 @param context context values for fixed indices
1037 @param exist number of existential variables
1038 @return the number of integer points in this
1042 void count_points_e (int pos
, Polyhedron
*P
, int exist
, int nparam
,
1043 Value
*context
, Value
*res
)
1048 value_set_si(*res
, 0);
1052 value_init(LB
); value_init(UB
); value_init(k
);
1056 if (lower_upper_bounds(pos
,P
,context
,&LB
,&UB
) !=0) {
1057 /* Problem if UB or LB is INFINITY */
1058 value_clear(LB
); value_clear(UB
); value_clear(k
);
1059 if (pos
> P
->Dimension
- nparam
- exist
)
1060 value_set_si(*res
, 1);
1062 value_set_si(*res
, -1);
1069 for (value_assign(k
,LB
); value_le(k
,UB
); value_increment(k
,k
)) {
1070 fprintf(stderr
, "(");
1071 for (i
=1; i
<pos
; i
++) {
1072 value_print(stderr
,P_VALUE_FMT
,context
[i
]);
1073 fprintf(stderr
,",");
1075 value_print(stderr
,P_VALUE_FMT
,k
);
1076 fprintf(stderr
,")\n");
1081 value_set_si(context
[pos
],0);
1082 if (value_lt(UB
,LB
)) {
1083 value_clear(LB
); value_clear(UB
); value_clear(k
);
1084 value_set_si(*res
, 0);
1089 value_set_si(*res
, 1);
1091 value_subtract(k
,UB
,LB
);
1092 value_add_int(k
,k
,1);
1093 value_assign(*res
, k
);
1095 value_clear(LB
); value_clear(UB
); value_clear(k
);
1099 /*-----------------------------------------------------------------*/
1100 /* Optimization idea */
1101 /* If inner loops are not a function of k (the current index) */
1102 /* i.e. if P->Constraint[i][pos]==0 for all P following this and */
1104 /* Then CNT = (UB-LB+1)*count_points(pos+1, P->next, context) */
1105 /* (skip the for loop) */
1106 /*-----------------------------------------------------------------*/
1109 value_set_si(*res
, 0);
1110 for (value_assign(k
,LB
);value_le(k
,UB
);value_increment(k
,k
)) {
1111 /* Insert k in context */
1112 value_assign(context
[pos
],k
);
1113 count_points_e(pos
+1, P
->next
, exist
, nparam
, context
, &c
);
1114 if(value_notmone_p(c
))
1115 value_addto(*res
, *res
, c
);
1117 value_set_si(*res
, -1);
1120 if (pos
> P
->Dimension
- nparam
- exist
&&
1127 fprintf(stderr
,"%d\n",CNT
);
1131 value_set_si(context
[pos
],0);
1132 value_clear(LB
); value_clear(UB
); value_clear(k
);
1134 } /* count_points_e */
1136 int DomainContains(Polyhedron
*P
, Value
*list_args
, int len
,
1137 unsigned MaxRays
, int set
)
1142 if (P
->Dimension
== len
)
1143 return in_domain(P
, list_args
);
1145 assert(set
); // assume list_args is large enough
1146 assert((P
->Dimension
- len
) % 2 == 0);
1148 for (i
= 0; i
< P
->Dimension
- len
; i
+= 2) {
1150 for (j
= 0 ; j
< P
->NbEq
; ++j
)
1151 if (value_notzero_p(P
->Constraint
[j
][1+len
+i
]))
1153 assert(j
< P
->NbEq
);
1154 value_absolute(m
, P
->Constraint
[j
][1+len
+i
]);
1155 k
= First_Non_Zero(P
->Constraint
[j
]+1, len
);
1157 assert(First_Non_Zero(P
->Constraint
[j
]+1+k
+1, len
- k
- 1) == -1);
1158 mpz_fdiv_q(list_args
[len
+i
], list_args
[k
], m
);
1159 mpz_fdiv_r(list_args
[len
+i
+1], list_args
[k
], m
);
1163 return in_domain(P
, list_args
);
1166 Polyhedron
*DomainConcat(Polyhedron
*head
, Polyhedron
*tail
)
1171 for (S
= head
; S
->next
; S
= S
->next
)
1177 #ifndef HAVE_LEXSMALLER
1179 evalue
*barvinok_lexsmaller_ev(Polyhedron
*P
, Polyhedron
*D
, unsigned dim
,
1180 Polyhedron
*C
, unsigned MaxRays
)
1186 #include <polylib/ranking.h>
1188 evalue
*barvinok_lexsmaller_ev(Polyhedron
*P
, Polyhedron
*D
, unsigned dim
,
1189 Polyhedron
*C
, unsigned MaxRays
)
1192 Polyhedron
*RC
, *RD
, *Q
;
1193 unsigned nparam
= dim
+ C
->Dimension
;
1197 RC
= LexSmaller(P
, D
, dim
, C
, MaxRays
);
1201 exist
= RD
->Dimension
- nparam
- dim
;
1202 CA
= align_context(RC
, RD
->Dimension
, MaxRays
);
1203 Q
= DomainIntersection(RD
, CA
, MaxRays
);
1204 Polyhedron_Free(CA
);
1206 Polyhedron_Free(RC
);
1209 for (Q
= RD
; Q
; Q
= Q
->next
) {
1211 Polyhedron
*next
= Q
->next
;
1214 t
= barvinok_enumerate_e(Q
, exist
, nparam
, MaxRays
);
1220 free_evalue_refs(t
);
1232 Enumeration
*barvinok_lexsmaller(Polyhedron
*P
, Polyhedron
*D
, unsigned dim
,
1233 Polyhedron
*C
, unsigned MaxRays
)
1235 evalue
*EP
= barvinok_lexsmaller_ev(P
, D
, dim
, C
, MaxRays
);
1237 return partition2enumeration(EP
);
1241 /* "align" matrix to have nrows by inserting
1242 * the necessary number of rows and an equal number of columns in front
1244 Matrix
*align_matrix(Matrix
*M
, int nrows
)
1247 int newrows
= nrows
- M
->NbRows
;
1248 Matrix
*M2
= Matrix_Alloc(nrows
, newrows
+ M
->NbColumns
);
1249 for (i
= 0; i
< newrows
; ++i
)
1250 value_set_si(M2
->p
[i
][i
], 1);
1251 for (i
= 0; i
< M
->NbRows
; ++i
)
1252 Vector_Copy(M
->p
[i
], M2
->p
[newrows
+i
]+newrows
, M
->NbColumns
);
1256 static void print_varlist(FILE *out
, int n
, char **names
)
1260 for (i
= 0; i
< n
; ++i
) {
1263 fprintf(out
, "%s", names
[i
]);
1268 static void print_term(FILE *out
, Value v
, int pos
, int dim
, int nparam
,
1269 char **iter_names
, char **param_names
, int *first
)
1271 if (value_zero_p(v
)) {
1272 if (first
&& *first
&& pos
>= dim
+ nparam
)
1278 if (!*first
&& value_pos_p(v
))
1282 if (pos
< dim
+ nparam
) {
1283 if (value_mone_p(v
))
1285 else if (!value_one_p(v
))
1286 value_print(out
, VALUE_FMT
, v
);
1288 fprintf(out
, "%s", iter_names
[pos
]);
1290 fprintf(out
, "%s", param_names
[pos
-dim
]);
1292 value_print(out
, VALUE_FMT
, v
);
1295 char **util_generate_names(int n
, char *prefix
)
1298 int len
= (prefix
? strlen(prefix
) : 0) + 10;
1299 char **names
= ALLOCN(char*, n
);
1301 fprintf(stderr
, "ERROR: memory overflow.\n");
1304 for (i
= 0; i
< n
; ++i
) {
1305 names
[i
] = ALLOCN(char, len
);
1307 fprintf(stderr
, "ERROR: memory overflow.\n");
1311 snprintf(names
[i
], len
, "%d", i
);
1313 snprintf(names
[i
], len
, "%s%d", prefix
, i
);
1319 void util_free_names(int n
, char **names
)
1322 for (i
= 0; i
< n
; ++i
)
1327 void Polyhedron_pprint(FILE *out
, Polyhedron
*P
, int dim
, int nparam
,
1328 char **iter_names
, char **param_names
)
1333 assert(dim
+ nparam
== P
->Dimension
);
1339 print_varlist(out
, nparam
, param_names
);
1340 fprintf(out
, " -> ");
1342 print_varlist(out
, dim
, iter_names
);
1343 fprintf(out
, " : ");
1346 fprintf(out
, "FALSE");
1347 else for (i
= 0; i
< P
->NbConstraints
; ++i
) {
1349 int v
= First_Non_Zero(P
->Constraint
[i
]+1, P
->Dimension
);
1350 if (v
== -1 && value_pos_p(P
->Constraint
[i
][0]))
1353 fprintf(out
, " && ");
1354 if (v
== -1 && value_notzero_p(P
->Constraint
[i
][1+P
->Dimension
]))
1355 fprintf(out
, "FALSE");
1356 else if (value_pos_p(P
->Constraint
[i
][v
+1])) {
1357 print_term(out
, P
->Constraint
[i
][v
+1], v
, dim
, nparam
,
1358 iter_names
, param_names
, NULL
);
1359 if (value_zero_p(P
->Constraint
[i
][0]))
1360 fprintf(out
, " = ");
1362 fprintf(out
, " >= ");
1363 for (j
= v
+1; j
<= dim
+nparam
; ++j
) {
1364 value_oppose(tmp
, P
->Constraint
[i
][1+j
]);
1365 print_term(out
, tmp
, j
, dim
, nparam
,
1366 iter_names
, param_names
, &first
);
1369 value_oppose(tmp
, P
->Constraint
[i
][1+v
]);
1370 print_term(out
, tmp
, v
, dim
, nparam
,
1371 iter_names
, param_names
, NULL
);
1372 fprintf(out
, " <= ");
1373 for (j
= v
+1; j
<= dim
+nparam
; ++j
)
1374 print_term(out
, P
->Constraint
[i
][1+j
], j
, dim
, nparam
,
1375 iter_names
, param_names
, &first
);
1379 fprintf(out
, " }\n");
1384 /* Construct a cone over P with P placed at x_d = 1, with
1385 * x_d the coordinate of an extra dimension
1387 * It's probably a mistake to depend so much on the internal
1388 * representation. We should probably simply compute the
1389 * vertices/facets first.
1391 Polyhedron
*Cone_over_Polyhedron(Polyhedron
*P
)
1393 unsigned NbConstraints
= 0;
1394 unsigned NbRays
= 0;
1398 if (POL_HAS(P
, POL_INEQUALITIES
))
1399 NbConstraints
= P
->NbConstraints
+ 1;
1400 if (POL_HAS(P
, POL_POINTS
))
1401 NbRays
= P
->NbRays
+ 1;
1403 C
= Polyhedron_Alloc(P
->Dimension
+1, NbConstraints
, NbRays
);
1404 if (POL_HAS(P
, POL_INEQUALITIES
)) {
1406 for (i
= 0; i
< P
->NbConstraints
; ++i
)
1407 Vector_Copy(P
->Constraint
[i
], C
->Constraint
[i
], P
->Dimension
+2);
1409 value_set_si(C
->Constraint
[P
->NbConstraints
][0], 1);
1410 value_set_si(C
->Constraint
[P
->NbConstraints
][1+P
->Dimension
], 1);
1412 if (POL_HAS(P
, POL_POINTS
)) {
1413 C
->NbBid
= P
->NbBid
;
1414 for (i
= 0; i
< P
->NbRays
; ++i
)
1415 Vector_Copy(P
->Ray
[i
], C
->Ray
[i
], P
->Dimension
+2);
1417 value_set_si(C
->Ray
[P
->NbRays
][0], 1);
1418 value_set_si(C
->Ray
[P
->NbRays
][1+C
->Dimension
], 1);
1420 POL_SET(C
, POL_VALID
);
1421 if (POL_HAS(P
, POL_INEQUALITIES
))
1422 POL_SET(C
, POL_INEQUALITIES
);
1423 if (POL_HAS(P
, POL_POINTS
))
1424 POL_SET(C
, POL_POINTS
);
1425 if (POL_HAS(P
, POL_VERTICES
))
1426 POL_SET(C
, POL_VERTICES
);
1430 /* Returns a (dim+nparam+1)x((dim-n)+nparam+1) matrix
1431 * mapping the transformed subspace back to the original space.
1432 * n is the number of equalities involving the variables
1433 * (i.e., not purely the parameters).
1434 * The remaining n coordinates in the transformed space would
1435 * have constant (parametric) values and are therefore not
1436 * included in the variables of the new space.
1438 Matrix
*compress_variables(Matrix
*Equalities
, unsigned nparam
)
1440 unsigned dim
= (Equalities
->NbColumns
-2) - nparam
;
1441 Matrix
*M
, *H
, *Q
, *U
, *C
, *ratH
, *invH
, *Ul
, *T1
, *T2
, *T
;
1446 for (n
= 0; n
< Equalities
->NbRows
; ++n
)
1447 if (First_Non_Zero(Equalities
->p
[n
]+1, dim
) == -1)
1450 return Identity(dim
+nparam
+1);
1452 value_set_si(mone
, -1);
1453 M
= Matrix_Alloc(n
, dim
);
1454 C
= Matrix_Alloc(n
+1, nparam
+1);
1455 for (i
= 0; i
< n
; ++i
) {
1456 Vector_Copy(Equalities
->p
[i
]+1, M
->p
[i
], dim
);
1457 Vector_Scale(Equalities
->p
[i
]+1+dim
, C
->p
[i
], mone
, nparam
+1);
1459 value_set_si(C
->p
[n
][nparam
], 1);
1460 left_hermite(M
, &H
, &Q
, &U
);
1465 ratH
= Matrix_Alloc(n
+1, n
+1);
1466 invH
= Matrix_Alloc(n
+1, n
+1);
1467 for (i
= 0; i
< n
; ++i
)
1468 Vector_Copy(H
->p
[i
], ratH
->p
[i
], n
);
1469 value_set_si(ratH
->p
[n
][n
], 1);
1470 ok
= Matrix_Inverse(ratH
, invH
);
1474 T1
= Matrix_Alloc(n
+1, nparam
+1);
1475 Matrix_Product(invH
, C
, T1
);
1478 if (value_notone_p(T1
->p
[n
][nparam
])) {
1479 for (i
= 0; i
< n
; ++i
) {
1480 if (!mpz_divisible_p(T1
->p
[i
][nparam
], T1
->p
[n
][nparam
])) {
1485 /* compress_params should have taken care of this */
1486 for (j
= 0; j
< nparam
; ++j
)
1487 assert(mpz_divisible_p(T1
->p
[i
][j
], T1
->p
[n
][nparam
]));
1488 Vector_AntiScale(T1
->p
[i
], T1
->p
[i
], T1
->p
[n
][nparam
], nparam
+1);
1490 value_set_si(T1
->p
[n
][nparam
], 1);
1492 Ul
= Matrix_Alloc(dim
+1, n
+1);
1493 for (i
= 0; i
< dim
; ++i
)
1494 Vector_Copy(U
->p
[i
], Ul
->p
[i
], n
);
1495 value_set_si(Ul
->p
[dim
][n
], 1);
1496 T2
= Matrix_Alloc(dim
+1, nparam
+1);
1497 Matrix_Product(Ul
, T1
, T2
);
1501 T
= Matrix_Alloc(dim
+nparam
+1, (dim
-n
)+nparam
+1);
1502 for (i
= 0; i
< dim
; ++i
) {
1503 Vector_Copy(U
->p
[i
]+n
, T
->p
[i
], dim
-n
);
1504 Vector_Copy(T2
->p
[i
], T
->p
[i
]+dim
-n
, nparam
+1);
1506 for (i
= 0; i
< nparam
+1; ++i
)
1507 value_set_si(T
->p
[dim
+i
][(dim
-n
)+i
], 1);
1508 assert(value_one_p(T2
->p
[dim
][nparam
]));