version.c: move barvinok_version from util.c
[barvinok.git] / util.c
blob8a18292a92523db319d9b98ec5a928ac7c70b4db
1 #include <polylib/polylibgmp.h>
2 #include <stdlib.h>
3 #include <assert.h>
4 #include "config.h"
6 #ifndef HAVE_ENUMERATE4
7 #define Polyhedron_Enumerate(a,b,c,d) Polyhedron_Enumerate(a,b,c)
8 #endif
10 #define ALLOC(type) (type*)malloc(sizeof(type))
11 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
13 #ifdef __GNUC__
14 #define NALLOC(p,n) p = (typeof(p))malloc((n) * sizeof(*p))
15 #else
16 #define NALLOC(p,n) p = (void *)malloc((n) * sizeof(*p))
17 #endif
19 #ifndef HAVE_ENUMERATION_FREE
20 #define Enumeration_Free(en) /* just leak some memory */
21 #endif
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);
29 value_clear(*v);
30 free(v);
31 Enumeration_Free(en);
32 Polyhedron_Free(U);
35 #ifndef HAVE_ENUMERATION_FREE
36 #undef Enumeration_Free
37 #endif
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 /* Inplace polarization
51 void Polyhedron_Polarize(Polyhedron *P)
53 unsigned NbRows = P->NbConstraints + P->NbRays;
54 int i;
55 Value **q;
57 q = (Value **)malloc(NbRows * sizeof(Value *));
58 assert(q);
59 for (i = 0; i < P->NbRays; ++i)
60 q[i] = P->Ray[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;
65 free(P->Constraint);
66 P->Constraint = q;
67 P->Ray = q + P->NbConstraints;
71 * Rather general polar
72 * We can optimize it significantly if we assume that
73 * P includes zero
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)
81 int i;
82 Value mone;
83 unsigned dim = P->Dimension + 2;
84 Matrix *M = Matrix_Alloc(P->NbRays, dim);
86 assert(M);
87 value_init(mone);
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);
95 assert(P);
96 Matrix_Free(M);
97 value_clear(mone);
98 return P;
102 * Returns the supporting cone of P at the vertex with index v
104 Polyhedron* supporting_cone(Polyhedron *P, int v)
106 Matrix *M;
107 Value tmp;
108 int i, n, j;
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]));
114 assert(supporting);
116 value_init(tmp);
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)))
120 ++n;
122 assert(n >= dim - 2);
123 value_clear(tmp);
124 M = Matrix_Alloc(n, dim);
125 assert(M);
126 for (i = 0, j = 0; i < P->NbConstraints; ++i)
127 if (supporting[i]) {
128 value_set_si(M->p[j][dim-1], 0);
129 Vector_Copy(P->Constraint[i], M->p[j++], dim-1);
131 free(supporting);
132 P = Constraints2Polyhedron(M, P->NbRays+1);
133 assert(P);
134 Matrix_Free(M);
135 return P;
138 void value_lcm(Value i, Value j, Value* lcm)
140 Value aux;
141 value_init(aux);
142 value_multiply(aux,i,j);
143 Gcd(i,j,lcm);
144 value_division(*lcm,aux,*lcm);
145 value_clear(aux);
148 Polyhedron* supporting_cone_p(Polyhedron *P, Param_Vertices *v)
150 Matrix *M;
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;
156 int i, n, j;
157 Vector *row;
159 assert(supporting);
160 row = Vector_Alloc(nparam+1);
161 assert(row);
162 value_init(lcm);
163 value_init(tmp);
164 value_init(tmp2);
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]))
185 break;
186 if ((supporting[i] = (j == nparam + 1)))
187 ++n;
189 assert(n >= nvar);
190 value_clear(tmp);
191 value_clear(tmp2);
192 value_clear(lcm);
193 Vector_Free(row);
194 M = Matrix_Alloc(n, nvar+2);
195 assert(M);
196 for (i = 0, j = 0; i < P->NbConstraints; ++i)
197 if (supporting[i]) {
198 value_set_si(M->p[j][nvar+1], 0);
199 Vector_Copy(P->Constraint[i], M->p[j++], nvar+1);
201 free(supporting);
202 P = Constraints2Polyhedron(M, P->NbRays+1);
203 assert(P);
204 Matrix_Free(M);
205 return P;
208 Polyhedron* triangulate_cone(Polyhedron *P, unsigned NbMaxCons)
210 const static int MAX_TRY=10;
211 int i, j, r, n, t;
212 Value tmp;
213 unsigned dim = P->Dimension;
214 Matrix *M = Matrix_Alloc(P->NbRays+1, dim+3);
215 Matrix *M2, *M3;
216 Polyhedron *L, *R, *T;
217 assert(P->NbEq == 0);
219 R = NULL;
220 value_init(tmp);
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]))
232 continue;
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);
237 ++r;
240 M3 = Matrix_Copy(M);
241 L = Rays2Polyhedron(M3, NbMaxCons);
242 Matrix_Free(M3);
244 M2 = Matrix_Alloc(dim+1, dim+2);
246 t = 1;
247 if (0) {
248 try_again:
249 /* Usually R should still be 0 */
250 Domain_Free(R);
251 Polyhedron_Free(L);
252 for (r = 1; r < P->NbRays; ++r) {
253 value_set_si(M->p[r][dim+1], random_int((t+1)*dim)+1);
255 M3 = Matrix_Copy(M);
256 L = Rays2Polyhedron(M3, NbMaxCons);
257 Matrix_Free(M3);
258 ++t;
260 assert(t <= MAX_TRY);
262 R = NULL;
263 n = 0;
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]))
268 continue;
269 if (value_notzero_p(L->Constraint[i][dim+2]))
270 continue;
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))
274 continue;
275 if (r > dim)
276 goto try_again;
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);
280 ++r;
282 assert(r == dim+1);
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);
287 T->next = R;
288 R = T;
289 ++n;
291 Matrix_Free(M2);
293 Polyhedron_Free(L);
294 value_clear(tmp);
295 Matrix_Free(M);
297 return R;
300 void check_triangulization(Polyhedron *P, Polyhedron *T)
302 Polyhedron *C, *D, *E, *F, *G, *U;
303 for (C = T; C; C = C->next) {
304 if (C == T)
305 U = C;
306 else
307 U = DomainConvex(DomainUnion(U, C, 100), 100);
308 for (D = C->next; D; D = D->next) {
309 F = C->next;
310 G = D->next;
311 C->next = NULL;
312 D->next = NULL;
313 E = DomainIntersection(C, D, 600);
314 assert(E->NbRays == 0 || E->NbEq >= 1);
315 Polyhedron_Free(E);
316 C->next = F;
317 D->next = G;
320 assert(PolyhedronIncludes(U, P));
321 assert(PolyhedronIncludes(P, U));
324 /* Computes x, y and g such that g = gcd(a,b) and a*x+b*y = g */
325 void Extended_Euclid(Value a, Value b, Value *x, Value *y, Value *g)
327 Value c, d, e, f, tmp;
329 value_init(c);
330 value_init(d);
331 value_init(e);
332 value_init(f);
333 value_init(tmp);
334 value_absolute(c, a);
335 value_absolute(d, b);
336 value_set_si(e, 1);
337 value_set_si(f, 0);
338 while(value_pos_p(d)) {
339 value_division(tmp, c, d);
340 value_multiply(tmp, tmp, f);
341 value_subtract(e, e, tmp);
342 value_division(tmp, c, d);
343 value_multiply(tmp, tmp, d);
344 value_subtract(c, c, tmp);
345 value_swap(c, d);
346 value_swap(e, f);
348 value_assign(*g, c);
349 if (value_zero_p(a))
350 value_set_si(*x, 0);
351 else if (value_pos_p(a))
352 value_assign(*x, e);
353 else value_oppose(*x, e);
354 if (value_zero_p(b))
355 value_set_si(*y, 0);
356 else {
357 value_multiply(tmp, a, *x);
358 value_subtract(tmp, c, tmp);
359 value_division(*y, tmp, b);
361 value_clear(c);
362 value_clear(d);
363 value_clear(e);
364 value_clear(f);
365 value_clear(tmp);
368 Matrix * unimodular_complete(Vector *row)
370 Value g, b, c, old, tmp;
371 Matrix *m;
372 unsigned i, j;
374 value_init(b);
375 value_init(c);
376 value_init(g);
377 value_init(old);
378 value_init(tmp);
379 m = Matrix_Alloc(row->Size, row->Size);
380 for (j = 0; j < row->Size; ++j) {
381 value_assign(m->p[0][j], row->p[j]);
383 value_assign(g, row->p[0]);
384 for (i = 1; value_zero_p(g) && i < row->Size; ++i) {
385 for (j = 0; j < row->Size; ++j) {
386 if (j == i-1)
387 value_set_si(m->p[i][j], 1);
388 else
389 value_set_si(m->p[i][j], 0);
391 value_assign(g, row->p[i]);
393 for (; i < row->Size; ++i) {
394 value_assign(old, g);
395 Extended_Euclid(old, row->p[i], &c, &b, &g);
396 value_oppose(b, b);
397 for (j = 0; j < row->Size; ++j) {
398 if (j < i) {
399 value_multiply(tmp, row->p[j], b);
400 value_division(m->p[i][j], tmp, old);
401 } else if (j == i)
402 value_assign(m->p[i][j], c);
403 else
404 value_set_si(m->p[i][j], 0);
407 value_clear(b);
408 value_clear(c);
409 value_clear(g);
410 value_clear(old);
411 value_clear(tmp);
412 return m;
416 * Returns a full-dimensional polyhedron with the same number
417 * of integer points as P
419 Polyhedron *remove_equalities(Polyhedron *P)
421 Value g;
422 Vector *v;
423 Polyhedron *p = Polyhedron_Copy(P), *q;
424 unsigned dim = p->Dimension;
425 Matrix *m1, *m2;
426 int i;
428 value_init(g);
429 while (!emptyQ2(p) && p->NbEq > 0) {
430 assert(dim > 0);
431 Vector_Gcd(p->Constraint[0]+1, dim+1, &g);
432 Vector_AntiScale(p->Constraint[0]+1, p->Constraint[0]+1, g, dim+1);
433 Vector_Gcd(p->Constraint[0]+1, dim, &g);
434 if (value_notone_p(g) && value_notmone_p(g)) {
435 Polyhedron_Free(p);
436 p = Empty_Polyhedron(0);
437 break;
439 v = Vector_Alloc(dim);
440 Vector_Copy(p->Constraint[0]+1, v->p, dim);
441 m1 = unimodular_complete(v);
442 m2 = Matrix_Alloc(dim, dim+1);
443 for (i = 0; i < dim-1 ; ++i) {
444 Vector_Copy(m1->p[i+1], m2->p[i], dim);
445 value_set_si(m2->p[i][dim], 0);
447 Vector_Set(m2->p[dim-1], 0, dim);
448 value_set_si(m2->p[dim-1][dim], 1);
449 q = Polyhedron_Image(p, m2, p->NbConstraints+1+p->NbRays);
450 Vector_Free(v);
451 Matrix_Free(m1);
452 Matrix_Free(m2);
453 Polyhedron_Free(p);
454 p = q;
455 --dim;
457 value_clear(g);
458 return p;
462 * Returns a full-dimensional polyhedron with the same number
463 * of integer points as P
464 * nvar specifies the number of variables
465 * The remaining dimensions are assumed to be parameters
466 * Destroys P
467 * factor is NbEq x (nparam+2) matrix, containing stride constraints
468 * on the parameters; column nparam is the constant;
469 * column nparam+1 is the stride
471 * if factor is NULL, only remove equalities that don't affect
472 * the number of points
474 Polyhedron *remove_equalities_p(Polyhedron *P, unsigned nvar, Matrix **factor)
476 Value g;
477 Vector *v;
478 Polyhedron *p = P, *q;
479 unsigned dim = p->Dimension;
480 Matrix *m1, *m2, *f;
481 int i, j, skip;
483 value_init(g);
484 if (factor) {
485 f = Matrix_Alloc(p->NbEq, dim-nvar+2);
486 *factor = f;
488 j = 0;
489 skip = 0;
490 while (nvar > 0 && p->NbEq - skip > 0) {
491 assert(dim > 0);
493 while (skip < p->NbEq &&
494 First_Non_Zero(p->Constraint[skip]+1, nvar) == -1)
495 ++skip;
496 if (p->NbEq == skip)
497 break;
499 Vector_Gcd(p->Constraint[skip]+1, dim+1, &g);
500 Vector_AntiScale(p->Constraint[skip]+1, p->Constraint[skip]+1, g, dim+1);
501 Vector_Gcd(p->Constraint[skip]+1, nvar, &g);
502 if (!factor && value_notone_p(g) && value_notmone_p(g)) {
503 ++skip;
504 continue;
506 if (factor) {
507 Vector_Copy(p->Constraint[skip]+1+nvar, f->p[j], dim-nvar+1);
508 value_assign(f->p[j][dim-nvar+1], g);
510 v = Vector_Alloc(dim);
511 Vector_AntiScale(p->Constraint[skip]+1, v->p, g, nvar);
512 Vector_Set(v->p+nvar, 0, dim-nvar);
513 m1 = unimodular_complete(v);
514 m2 = Matrix_Alloc(dim, dim+1);
515 for (i = 0; i < dim-1 ; ++i) {
516 Vector_Copy(m1->p[i+1], m2->p[i], dim);
517 value_set_si(m2->p[i][dim], 0);
519 Vector_Set(m2->p[dim-1], 0, dim);
520 value_set_si(m2->p[dim-1][dim], 1);
521 q = Polyhedron_Image(p, m2, p->NbConstraints+1+p->NbRays);
522 Vector_Free(v);
523 Matrix_Free(m1);
524 Matrix_Free(m2);
525 Polyhedron_Free(p);
526 p = q;
527 --dim;
528 --nvar;
529 ++j;
531 value_clear(g);
532 return p;
535 void Line_Length(Polyhedron *P, Value *len)
537 Value tmp, pos, neg;
538 int p = 0, n = 0;
539 int i;
541 assert(P->Dimension == 1);
543 value_init(tmp);
544 value_init(pos);
545 value_init(neg);
547 for (i = 0; i < P->NbConstraints; ++i) {
548 value_oppose(tmp, P->Constraint[i][2]);
549 if (value_pos_p(P->Constraint[i][1])) {
550 mpz_cdiv_q(tmp, tmp, P->Constraint[i][1]);
551 if (!p || value_gt(tmp, pos))
552 value_assign(pos, tmp);
553 p = 1;
554 } else {
555 mpz_fdiv_q(tmp, tmp, P->Constraint[i][1]);
556 if (!n || value_lt(tmp, neg))
557 value_assign(neg, tmp);
558 n = 1;
560 if (n && p) {
561 value_subtract(tmp, neg, pos);
562 value_increment(*len, tmp);
563 } else
564 value_set_si(*len, -1);
567 value_clear(tmp);
568 value_clear(pos);
569 value_clear(neg);
573 * Factors the polyhedron P into polyhedra Q_i such that
574 * the number of integer points in P is equal to the product
575 * of the number of integer points in the individual Q_i
577 * If no factors can be found, NULL is returned.
578 * Otherwise, a linked list of the factors is returned.
580 * The algorithm works by first computing the Hermite normal form
581 * and then grouping columns linked by one or more constraints together,
582 * where a constraints "links" two or more columns if the constraint
583 * has nonzero coefficients in the columns.
585 Polyhedron* Polyhedron_Factor(Polyhedron *P, unsigned nparam,
586 unsigned NbMaxRays)
588 int i, j, k;
589 Matrix *M, *H, *Q, *U;
590 int *pos; /* for each column: row position of pivot */
591 int *group; /* group to which a column belongs */
592 int *cnt; /* number of columns in the group */
593 int *rowgroup; /* group to which a constraint belongs */
594 int nvar = P->Dimension - nparam;
595 Polyhedron *F = NULL;
597 if (nvar <= 1)
598 return NULL;
600 NALLOC(pos, nvar);
601 NALLOC(group, nvar);
602 NALLOC(cnt, nvar);
603 NALLOC(rowgroup, P->NbConstraints);
605 M = Matrix_Alloc(P->NbConstraints, nvar);
606 for (i = 0; i < P->NbConstraints; ++i)
607 Vector_Copy(P->Constraint[i]+1, M->p[i], nvar);
608 left_hermite(M, &H, &Q, &U);
609 Matrix_Free(M);
610 Matrix_Free(Q);
611 Matrix_Free(U);
613 for (i = 0; i < P->NbConstraints; ++i)
614 rowgroup[i] = -1;
615 for (i = 0, j = 0; i < H->NbColumns; ++i) {
616 for ( ; j < H->NbRows; ++j)
617 if (value_notzero_p(H->p[j][i]))
618 break;
619 assert (j < H->NbRows);
620 pos[i] = j;
622 for (i = 0; i < nvar; ++i) {
623 group[i] = i;
624 cnt[i] = 1;
626 for (i = 0; i < H->NbColumns && cnt[0] < nvar; ++i) {
627 if (rowgroup[pos[i]] == -1)
628 rowgroup[pos[i]] = i;
629 for (j = pos[i]+1; j < H->NbRows; ++j) {
630 if (value_zero_p(H->p[j][i]))
631 continue;
632 if (rowgroup[j] != -1)
633 continue;
634 rowgroup[j] = group[i];
635 for (k = i+1; k < H->NbColumns && j >= pos[k]; ++k) {
636 int g = group[k];
637 while (cnt[g] == 0)
638 g = group[g];
639 group[k] = g;
640 if (group[k] != group[i] && value_notzero_p(H->p[j][k])) {
641 assert(cnt[group[k]] != 0);
642 assert(cnt[group[i]] != 0);
643 if (group[i] < group[k]) {
644 cnt[group[i]] += cnt[group[k]];
645 cnt[group[k]] = 0;
646 group[k] = group[i];
647 } else {
648 cnt[group[k]] += cnt[group[i]];
649 cnt[group[i]] = 0;
650 group[i] = group[k];
657 if (cnt[0] != nvar) {
658 /* Extract out pure context constraints separately */
659 Polyhedron **next = &F;
660 for (i = nparam ? -1 : 0; i < nvar; ++i) {
661 int d;
663 if (i == -1) {
664 for (j = 0, k = 0; j < P->NbConstraints; ++j)
665 if (rowgroup[j] == -1) {
666 if (First_Non_Zero(P->Constraint[j]+1+nvar,
667 nparam) == -1)
668 rowgroup[j] = -2;
669 else
670 ++k;
672 if (k == 0)
673 continue;
674 d = 0;
675 } else {
676 if (cnt[i] == 0)
677 continue;
678 d = cnt[i];
679 for (j = 0, k = 0; j < P->NbConstraints; ++j)
680 if (rowgroup[j] >= 0 && group[rowgroup[j]] == i) {
681 rowgroup[j] = i;
682 ++k;
686 M = Matrix_Alloc(k, d+nparam+2);
687 for (j = 0, k = 0; j < P->NbConstraints; ++j) {
688 int l, m;
689 if (rowgroup[j] != i)
690 continue;
691 value_assign(M->p[k][0], P->Constraint[j][0]);
692 for (l = 0, m = 0; m < d; ++l) {
693 if (group[l] != i)
694 continue;
695 value_assign(M->p[k][1+m++], H->p[j][l]);
697 Vector_Copy(P->Constraint[j]+1+nvar, M->p[k]+1+m, nparam+1);
698 ++k;
700 *next = Constraints2Polyhedron(M, NbMaxRays);
701 next = &(*next)->next;
702 Matrix_Free(M);
705 Matrix_Free(H);
706 free(pos);
707 free(group);
708 free(cnt);
709 free(rowgroup);
710 return F;
714 * Project on final dim dimensions
716 Polyhedron* Polyhedron_Project(Polyhedron *P, int dim)
718 int i;
719 int remove = P->Dimension - dim;
720 Matrix *T;
721 Polyhedron *I;
723 if (P->Dimension == dim)
724 return Polyhedron_Copy(P);
726 T = Matrix_Alloc(dim+1, P->Dimension+1);
727 for (i = 0; i < dim+1; ++i)
728 value_set_si(T->p[i][i+remove], 1);
729 I = Polyhedron_Image(P, T, P->NbConstraints);
730 Matrix_Free(T);
731 return I;
734 /* Constructs a new constraint that ensures that
735 * the first constraint is (strictly) smaller than
736 * the second.
738 static void smaller_constraint(Value *a, Value *b, Value *c, int pos, int shift,
739 int len, int strict, Value *tmp)
741 value_oppose(*tmp, b[pos+1]);
742 value_set_si(c[0], 1);
743 Vector_Combine(a+1+shift, b+1+shift, c+1, *tmp, a[pos+1], len-shift-1);
744 if (strict)
745 value_decrement(c[len-shift-1], c[len-shift-1]);
746 ConstraintSimplify(c, c, len-shift, tmp);
749 struct section { Polyhedron * D; evalue E; };
751 evalue * ParamLine_Length_mod(Polyhedron *P, Polyhedron *C, int MaxRays)
753 unsigned dim = P->Dimension;
754 unsigned nvar = dim - C->Dimension;
755 int *pos;
756 int i, j, p, n, z;
757 struct section *s;
758 Matrix *M, *M2;
759 int nd = 0;
760 int k, l, k2, l2, q;
761 evalue *L, *U;
762 evalue *F;
763 Value g;
764 Polyhedron *T;
765 evalue mone;
767 assert(nvar == 1);
769 NALLOC(pos, P->NbConstraints);
770 value_init(g);
771 value_init(mone.d);
772 evalue_set_si(&mone, -1, 1);
774 for (i = 0, z = 0; i < P->NbConstraints; ++i)
775 if (value_zero_p(P->Constraint[i][1]))
776 ++z;
777 /* put those with positive coefficients first; number: p */
778 for (i = 0, p = 0, n = P->NbConstraints-z-1; i < P->NbConstraints; ++i)
779 if (value_pos_p(P->Constraint[i][1]))
780 pos[p++] = i;
781 else if (value_neg_p(P->Constraint[i][1]))
782 pos[n--] = i;
783 n = P->NbConstraints-z-p;
784 assert (p >= 1 && n >= 1);
785 s = (struct section *) malloc(p * n * sizeof(struct section));
786 M = Matrix_Alloc((p-1) + (n-1), dim-nvar+2);
787 for (k = 0; k < p; ++k) {
788 for (k2 = 0; k2 < p; ++k2) {
789 if (k2 == k)
790 continue;
791 q = k2 - (k2 > k);
792 smaller_constraint(
793 P->Constraint[pos[k]],
794 P->Constraint[pos[k2]],
795 M->p[q], 0, nvar, dim+2, k2 > k, &g);
797 for (l = p; l < p+n; ++l) {
798 for (l2 = p; l2 < p+n; ++l2) {
799 if (l2 == l)
800 continue;
801 q = l2-1 - (l2 > l);
802 smaller_constraint(
803 P->Constraint[pos[l2]],
804 P->Constraint[pos[l]],
805 M->p[q], 0, nvar, dim+2, l2 > l, &g);
807 M2 = Matrix_Copy(M);
808 T = Constraints2Polyhedron(M2, P->NbRays);
809 Matrix_Free(M2);
810 s[nd].D = DomainIntersection(T, C, MaxRays);
811 Domain_Free(T);
812 POL_ENSURE_VERTICES(s[nd].D);
813 if (emptyQ(s[nd].D)) {
814 Polyhedron_Free(s[nd].D);
815 continue;
817 L = bv_ceil3(P->Constraint[pos[k]]+1+nvar,
818 dim-nvar+1,
819 P->Constraint[pos[k]][0+1], s[nd].D);
820 U = bv_ceil3(P->Constraint[pos[l]]+1+nvar,
821 dim-nvar+1,
822 P->Constraint[pos[l]][0+1], s[nd].D);
823 eadd(L, U);
824 eadd(&mone, U);
825 emul(&mone, U);
826 s[nd].E = *U;
827 free_evalue_refs(L);
828 free(L);
829 free(U);
830 ++nd;
834 Matrix_Free(M);
836 F = ALLOC(evalue);
837 value_init(F->d);
838 value_set_si(F->d, 0);
839 F->x.p = new_enode(partition, 2*nd, dim-nvar);
840 for (k = 0; k < nd; ++k) {
841 EVALUE_SET_DOMAIN(F->x.p->arr[2*k], s[k].D);
842 value_clear(F->x.p->arr[2*k+1].d);
843 F->x.p->arr[2*k+1] = s[k].E;
845 free(s);
847 free_evalue_refs(&mone);
848 value_clear(g);
849 free(pos);
851 return F;
854 #ifdef USE_MODULO
855 evalue* ParamLine_Length(Polyhedron *P, Polyhedron *C, unsigned MaxRays)
857 return ParamLine_Length_mod(P, C, MaxRays);
859 #else
860 evalue* ParamLine_Length(Polyhedron *P, Polyhedron *C, unsigned MaxRays)
862 evalue* tmp;
863 tmp = ParamLine_Length_mod(P, C, MaxRays);
864 evalue_mod2table(tmp, C->Dimension);
865 reduce_evalue(tmp);
866 return tmp;
868 #endif
870 Bool isIdentity(Matrix *M)
872 unsigned i, j;
873 if (M->NbRows != M->NbColumns)
874 return False;
876 for (i = 0;i < M->NbRows; i ++)
877 for (j = 0; j < M->NbColumns; j ++)
878 if (i == j) {
879 if(value_notone_p(M->p[i][j]))
880 return False;
881 } else {
882 if(value_notzero_p(M->p[i][j]))
883 return False;
885 return True;
888 void Param_Polyhedron_Print(FILE* DST, Param_Polyhedron *PP, char **param_names)
890 Param_Domain *P;
891 Param_Vertices *V;
893 for(P=PP->D;P;P=P->next) {
895 /* prints current val. dom. */
896 printf( "---------------------------------------\n" );
897 printf( "Domain :\n");
898 Print_Domain( stdout, P->Domain, param_names );
900 /* scan the vertices */
901 printf( "Vertices :\n");
902 FORALL_PVertex_in_ParamPolyhedron(V,P,PP) {
904 /* prints each vertex */
905 Print_Vertex( stdout, V->Vertex, param_names );
906 printf( "\n" );
908 END_FORALL_PVertex_in_ParamPolyhedron;
912 void Enumeration_Print(FILE *Dst, Enumeration *en, char **params)
914 for (; en; en = en->next) {
915 Print_Domain(Dst, en->ValidityDomain, params);
916 print_evalue(Dst, &en->EP, params);
920 void Enumeration_Free(Enumeration *en)
922 Enumeration *ee;
924 while( en )
926 free_evalue_refs( &(en->EP) );
927 Domain_Free( en->ValidityDomain );
928 ee = en ->next;
929 free( en );
930 en = ee;
934 void Enumeration_mod2table(Enumeration *en, unsigned nparam)
936 for (; en; en = en->next) {
937 evalue_mod2table(&en->EP, nparam);
938 reduce_evalue(&en->EP);
942 size_t Enumeration_size(Enumeration *en)
944 size_t s = 0;
946 for (; en; en = en->next) {
947 s += domain_size(en->ValidityDomain);
948 s += evalue_size(&en->EP);
950 return s;
953 void Free_ParamNames(char **params, int m)
955 while (--m >= 0)
956 free(params[m]);
957 free(params);
960 int DomainIncludes(Polyhedron *Pol1, Polyhedron *Pol2)
962 Polyhedron *P2;
963 for ( ; Pol1; Pol1 = Pol1->next) {
964 for (P2 = Pol2; P2; P2 = P2->next)
965 if (!PolyhedronIncludes(Pol1, P2))
966 break;
967 if (!P2)
968 return 1;
970 return 0;
973 int line_minmax(Polyhedron *I, Value *min, Value *max)
975 int i;
977 if (I->NbEq >= 1) {
978 value_oppose(I->Constraint[0][2], I->Constraint[0][2]);
979 /* There should never be a remainder here */
980 if (value_pos_p(I->Constraint[0][1]))
981 mpz_fdiv_q(*min, I->Constraint[0][2], I->Constraint[0][1]);
982 else
983 mpz_fdiv_q(*min, I->Constraint[0][2], I->Constraint[0][1]);
984 value_assign(*max, *min);
985 } else for (i = 0; i < I->NbConstraints; ++i) {
986 if (value_zero_p(I->Constraint[i][1])) {
987 Polyhedron_Free(I);
988 return 0;
991 value_oppose(I->Constraint[i][2], I->Constraint[i][2]);
992 if (value_pos_p(I->Constraint[i][1]))
993 mpz_cdiv_q(*min, I->Constraint[i][2], I->Constraint[i][1]);
994 else
995 mpz_fdiv_q(*max, I->Constraint[i][2], I->Constraint[i][1]);
997 Polyhedron_Free(I);
998 return 1;
1001 /**
1003 PROCEDURES TO COMPUTE ENUMERATION. recursive procedure, recurse for
1004 each imbriquation
1006 @param pos index position of current loop index (1..hdim-1)
1007 @param P loop domain
1008 @param context context values for fixed indices
1009 @param exist number of existential variables
1010 @return the number of integer points in this
1011 polyhedron
1014 void count_points_e (int pos, Polyhedron *P, int exist, int nparam,
1015 Value *context, Value *res)
1017 Value LB, UB, k, c;
1019 if (emptyQ(P)) {
1020 value_set_si(*res, 0);
1021 return;
1024 value_init(LB); value_init(UB); value_init(k);
1025 value_set_si(LB,0);
1026 value_set_si(UB,0);
1028 if (lower_upper_bounds(pos,P,context,&LB,&UB) !=0) {
1029 /* Problem if UB or LB is INFINITY */
1030 value_clear(LB); value_clear(UB); value_clear(k);
1031 if (pos > P->Dimension - nparam - exist)
1032 value_set_si(*res, 1);
1033 else
1034 value_set_si(*res, -1);
1035 return;
1038 #ifdef EDEBUG1
1039 if (!P->next) {
1040 int i;
1041 for (value_assign(k,LB); value_le(k,UB); value_increment(k,k)) {
1042 fprintf(stderr, "(");
1043 for (i=1; i<pos; i++) {
1044 value_print(stderr,P_VALUE_FMT,context[i]);
1045 fprintf(stderr,",");
1047 value_print(stderr,P_VALUE_FMT,k);
1048 fprintf(stderr,")\n");
1051 #endif
1053 value_set_si(context[pos],0);
1054 if (value_lt(UB,LB)) {
1055 value_clear(LB); value_clear(UB); value_clear(k);
1056 value_set_si(*res, 0);
1057 return;
1059 if (!P->next) {
1060 if (exist)
1061 value_set_si(*res, 1);
1062 else {
1063 value_subtract(k,UB,LB);
1064 value_add_int(k,k,1);
1065 value_assign(*res, k);
1067 value_clear(LB); value_clear(UB); value_clear(k);
1068 return;
1071 /*-----------------------------------------------------------------*/
1072 /* Optimization idea */
1073 /* If inner loops are not a function of k (the current index) */
1074 /* i.e. if P->Constraint[i][pos]==0 for all P following this and */
1075 /* for all i, */
1076 /* Then CNT = (UB-LB+1)*count_points(pos+1, P->next, context) */
1077 /* (skip the for loop) */
1078 /*-----------------------------------------------------------------*/
1080 value_init(c);
1081 value_set_si(*res, 0);
1082 for (value_assign(k,LB);value_le(k,UB);value_increment(k,k)) {
1083 /* Insert k in context */
1084 value_assign(context[pos],k);
1085 count_points_e(pos+1, P->next, exist, nparam, context, &c);
1086 if(value_notmone_p(c))
1087 value_addto(*res, *res, c);
1088 else {
1089 value_set_si(*res, -1);
1090 break;
1092 if (pos > P->Dimension - nparam - exist &&
1093 value_pos_p(*res))
1094 break;
1096 value_clear(c);
1098 #ifdef EDEBUG11
1099 fprintf(stderr,"%d\n",CNT);
1100 #endif
1102 /* Reset context */
1103 value_set_si(context[pos],0);
1104 value_clear(LB); value_clear(UB); value_clear(k);
1105 return;
1106 } /* count_points_e */
1108 int DomainContains(Polyhedron *P, Value *list_args, int len,
1109 unsigned MaxRays, int set)
1111 int i;
1112 Value m;
1114 if (P->Dimension == len)
1115 return in_domain(P, list_args);
1117 assert(set); // assume list_args is large enough
1118 assert((P->Dimension - len) % 2 == 0);
1119 value_init(m);
1120 for (i = 0; i < P->Dimension - len; i += 2) {
1121 int j, k;
1122 for (j = 0 ; j < P->NbEq; ++j)
1123 if (value_notzero_p(P->Constraint[j][1+len+i]))
1124 break;
1125 assert(j < P->NbEq);
1126 value_absolute(m, P->Constraint[j][1+len+i]);
1127 k = First_Non_Zero(P->Constraint[j]+1, len);
1128 assert(k != -1);
1129 assert(First_Non_Zero(P->Constraint[j]+1+k+1, len - k - 1) == -1);
1130 mpz_fdiv_q(list_args[len+i], list_args[k], m);
1131 mpz_fdiv_r(list_args[len+i+1], list_args[k], m);
1133 value_clear(m);
1135 return in_domain(P, list_args);
1138 Polyhedron *DomainConcat(Polyhedron *head, Polyhedron *tail)
1140 Polyhedron *S;
1141 if (!head)
1142 return tail;
1143 for (S = head; S->next; S = S->next)
1145 S->next = tail;
1146 return head;
1149 #ifndef HAVE_LEXSMALLER
1151 evalue *barvinok_lexsmaller_ev(Polyhedron *P, Polyhedron *D, unsigned dim,
1152 Polyhedron *C, unsigned MaxRays)
1154 assert(0);
1157 #else
1158 #include <polylib/ranking.h>
1160 evalue *barvinok_lexsmaller_ev(Polyhedron *P, Polyhedron *D, unsigned dim,
1161 Polyhedron *C, unsigned MaxRays)
1163 evalue *ranking;
1164 Polyhedron *RC, *RD, *Q;
1165 unsigned nparam = dim + C->Dimension;
1166 unsigned exist;
1167 Polyhedron *CA;
1169 RC = LexSmaller(P, D, dim, C, MaxRays);
1170 RD = RC->next;
1171 RC->next = NULL;
1173 exist = RD->Dimension - nparam - dim;
1174 CA = align_context(RC, RD->Dimension, MaxRays);
1175 Q = DomainIntersection(RD, CA, MaxRays);
1176 Polyhedron_Free(CA);
1177 Domain_Free(RD);
1178 Polyhedron_Free(RC);
1179 RD = Q;
1181 for (Q = RD; Q; Q = Q->next) {
1182 evalue *t;
1183 Polyhedron *next = Q->next;
1184 Q->next = 0;
1186 t = barvinok_enumerate_e(Q, exist, nparam, MaxRays);
1188 if (Q == RD)
1189 ranking = t;
1190 else {
1191 eadd(t, ranking);
1192 free_evalue_refs(t);
1193 free(t);
1196 Q->next = next;
1199 Domain_Free(RD);
1201 return ranking;
1204 Enumeration *barvinok_lexsmaller(Polyhedron *P, Polyhedron *D, unsigned dim,
1205 Polyhedron *C, unsigned MaxRays)
1207 evalue *EP = barvinok_lexsmaller_ev(P, D, dim, C, MaxRays);
1209 return partition2enumeration(EP);
1211 #endif
1213 /* "align" matrix to have nrows by inserting
1214 * the necessary number of rows and an equal number of columns in front
1216 Matrix *align_matrix(Matrix *M, int nrows)
1218 int i;
1219 int newrows = nrows - M->NbRows;
1220 Matrix *M2 = Matrix_Alloc(nrows, newrows + M->NbColumns);
1221 for (i = 0; i < newrows; ++i)
1222 value_set_si(M2->p[i][i], 1);
1223 for (i = 0; i < M->NbRows; ++i)
1224 Vector_Copy(M->p[i], M2->p[newrows+i]+newrows, M->NbColumns);
1225 return M2;
1228 static void print_varlist(FILE *out, int n, char **names)
1230 int i;
1231 fprintf(out, "[");
1232 for (i = 0; i < n; ++i) {
1233 if (i)
1234 fprintf(out, ",");
1235 fprintf(out, "%s", names[i]);
1237 fprintf(out, "]");
1240 static void print_term(FILE *out, Value v, int pos, int dim, int nparam,
1241 char **iter_names, char **param_names, int *first)
1243 if (value_zero_p(v)) {
1244 if (first && *first && pos >= dim + nparam)
1245 fprintf(out, "0");
1246 return;
1249 if (first) {
1250 if (!*first && value_pos_p(v))
1251 fprintf(out, "+");
1252 *first = 0;
1254 if (pos < dim + nparam) {
1255 if (value_mone_p(v))
1256 fprintf(out, "-");
1257 else if (!value_one_p(v))
1258 value_print(out, VALUE_FMT, v);
1259 if (pos < dim)
1260 fprintf(out, "%s", iter_names[pos]);
1261 else
1262 fprintf(out, "%s", param_names[pos-dim]);
1263 } else
1264 value_print(out, VALUE_FMT, v);
1267 char **util_generate_names(int n, char *prefix)
1269 int i;
1270 int len = (prefix ? strlen(prefix) : 0) + 10;
1271 char **names = ALLOCN(char*, n);
1272 if (!names) {
1273 fprintf(stderr, "ERROR: memory overflow.\n");
1274 exit(1);
1276 for (i = 0; i < n; ++i) {
1277 names[i] = ALLOCN(char, len);
1278 if (!names[i]) {
1279 fprintf(stderr, "ERROR: memory overflow.\n");
1280 exit(1);
1282 if (!prefix)
1283 snprintf(names[i], len, "%d", i);
1284 else
1285 snprintf(names[i], len, "%s%d", prefix, i);
1288 return names;
1291 void util_free_names(int n, char **names)
1293 int i;
1294 for (i = 0; i < n; ++i)
1295 free(names[i]);
1296 free(names);
1299 void Polyhedron_pprint(FILE *out, Polyhedron *P, int dim, int nparam,
1300 char **iter_names, char **param_names)
1302 int i, j;
1303 Value tmp;
1305 assert(dim + nparam == P->Dimension);
1307 value_init(tmp);
1309 fprintf(out, "{ ");
1310 if (nparam) {
1311 print_varlist(out, nparam, param_names);
1312 fprintf(out, " -> ");
1314 print_varlist(out, dim, iter_names);
1315 fprintf(out, " : ");
1317 if (emptyQ2(P))
1318 fprintf(out, "FALSE");
1319 else for (i = 0; i < P->NbConstraints; ++i) {
1320 int first = 1;
1321 int v = First_Non_Zero(P->Constraint[i]+1, P->Dimension);
1322 if (v == -1 && value_pos_p(P->Constraint[i][0]))
1323 continue;
1324 if (i)
1325 fprintf(out, " && ");
1326 if (v == -1 && value_notzero_p(P->Constraint[i][1+P->Dimension]))
1327 fprintf(out, "FALSE");
1328 else if (value_pos_p(P->Constraint[i][v+1])) {
1329 print_term(out, P->Constraint[i][v+1], v, dim, nparam,
1330 iter_names, param_names, NULL);
1331 if (value_zero_p(P->Constraint[i][0]))
1332 fprintf(out, " = ");
1333 else
1334 fprintf(out, " >= ");
1335 for (j = v+1; j <= dim+nparam; ++j) {
1336 value_oppose(tmp, P->Constraint[i][1+j]);
1337 print_term(out, tmp, j, dim, nparam,
1338 iter_names, param_names, &first);
1340 } else {
1341 value_oppose(tmp, P->Constraint[i][1+v]);
1342 print_term(out, tmp, v, dim, nparam,
1343 iter_names, param_names, NULL);
1344 fprintf(out, " <= ");
1345 for (j = v+1; j <= dim+nparam; ++j)
1346 print_term(out, P->Constraint[i][1+j], j, dim, nparam,
1347 iter_names, param_names, &first);
1351 fprintf(out, " }\n");
1353 value_clear(tmp);
1356 /* Construct a cone over P with P placed at x_d = 1, with
1357 * x_d the coordinate of an extra dimension
1359 * It's probably a mistake to depend so much on the internal
1360 * representation. We should probably simply compute the
1361 * vertices/facets first.
1363 Polyhedron *Cone_over_Polyhedron(Polyhedron *P)
1365 unsigned NbConstraints = 0;
1366 unsigned NbRays = 0;
1367 Polyhedron *C;
1368 int i;
1370 if (POL_HAS(P, POL_INEQUALITIES))
1371 NbConstraints = P->NbConstraints + 1;
1372 if (POL_HAS(P, POL_POINTS))
1373 NbRays = P->NbRays + 1;
1375 C = Polyhedron_Alloc(P->Dimension+1, NbConstraints, NbRays);
1376 if (POL_HAS(P, POL_INEQUALITIES)) {
1377 C->NbEq = P->NbEq;
1378 for (i = 0; i < P->NbConstraints; ++i)
1379 Vector_Copy(P->Constraint[i], C->Constraint[i], P->Dimension+2);
1380 /* n >= 0 */
1381 value_set_si(C->Constraint[P->NbConstraints][0], 1);
1382 value_set_si(C->Constraint[P->NbConstraints][1+P->Dimension], 1);
1384 if (POL_HAS(P, POL_POINTS)) {
1385 C->NbBid = P->NbBid;
1386 for (i = 0; i < P->NbRays; ++i)
1387 Vector_Copy(P->Ray[i], C->Ray[i], P->Dimension+2);
1388 /* vertex 0 */
1389 value_set_si(C->Ray[P->NbRays][0], 1);
1390 value_set_si(C->Ray[P->NbRays][1+C->Dimension], 1);
1392 POL_SET(C, POL_VALID);
1393 if (POL_HAS(P, POL_INEQUALITIES))
1394 POL_SET(C, POL_INEQUALITIES);
1395 if (POL_HAS(P, POL_POINTS))
1396 POL_SET(C, POL_POINTS);
1397 if (POL_HAS(P, POL_VERTICES))
1398 POL_SET(C, POL_VERTICES);
1399 return C;
1402 Matrix *compress_variables(Matrix *Equalities, unsigned nparam)
1404 unsigned dim = (Equalities->NbColumns-2) - nparam;
1405 Matrix *M, *H, *Q, *U, *C, *ratH, *invH, *Ul, *T1, *T2, *T;
1406 Value mone;
1407 int n, i;
1408 int ok;
1410 for (n = 0; n < Equalities->NbRows; ++n)
1411 if (First_Non_Zero(Equalities->p[n]+1, dim) == -1)
1412 break;
1413 if (n == 0)
1414 return Identity(dim+nparam+1);
1415 value_init(mone);
1416 value_set_si(mone, -1);
1417 M = Matrix_Alloc(n, dim);
1418 C = Matrix_Alloc(n+1, nparam+1);
1419 for (i = 0; i < n; ++i) {
1420 Vector_Copy(Equalities->p[i]+1, M->p[i], dim);
1421 Vector_Scale(Equalities->p[i]+1+dim, C->p[i], mone, nparam+1);
1423 value_set_si(C->p[n][nparam], 1);
1424 left_hermite(M, &H, &Q, &U);
1425 Matrix_Free(M);
1426 Matrix_Free(Q);
1427 value_clear(mone);
1429 /* we will need to treat scalings later */
1430 if (nparam > 0)
1431 for (i = 0; i < n; ++i)
1432 assert(value_one_p(H->p[i][i]));
1434 ratH = Matrix_Alloc(n+1, n+1);
1435 invH = Matrix_Alloc(n+1, n+1);
1436 for (i = 0; i < n; ++i)
1437 Vector_Copy(H->p[i], ratH->p[i], n);
1438 value_set_si(ratH->p[n][n], 1);
1439 ok = Matrix_Inverse(ratH, invH);
1440 assert(ok);
1441 Matrix_Free(H);
1442 Matrix_Free(ratH);
1443 T1 = Matrix_Alloc(n+1, nparam+1);
1444 Matrix_Product(invH, C, T1);
1445 Matrix_Free(C);
1446 Matrix_Free(invH);
1447 if (nparam == 0 && value_notone_p(T1->p[n][nparam])) {
1448 for (i = 0; i < n; ++i) {
1449 if (!mpz_divisible_p(T1->p[i][nparam], T1->p[n][nparam])) {
1450 Matrix_Free(T1);
1451 Matrix_Free(U);
1452 return NULL;
1454 value_division(T1->p[i][nparam], T1->p[i][nparam], T1->p[n][nparam]);
1456 value_set_si(T1->p[n][nparam], 1);
1458 Ul = Matrix_Alloc(dim+1, n+1);
1459 for (i = 0; i < dim; ++i)
1460 Vector_Copy(U->p[i], Ul->p[i], n);
1461 value_set_si(Ul->p[dim][n], 1);
1462 T2 = Matrix_Alloc(dim+1, nparam+1);
1463 Matrix_Product(Ul, T1, T2);
1464 Matrix_Free(Ul);
1465 Matrix_Free(T1);
1467 T = Matrix_Alloc(dim+nparam+1, (dim-n)+nparam+1);
1468 for (i = 0; i < dim; ++i) {
1469 Vector_Copy(U->p[i]+n, T->p[i], dim-n);
1470 Vector_Copy(T2->p[i], T->p[i]+dim-n, nparam+1);
1472 for (i = 0; i < nparam+1; ++i)
1473 value_set_si(T->p[dim+i][(dim-n)+i], 1);
1474 assert(value_one_p(T2->p[dim][nparam]));
1475 Matrix_Free(U);
1476 Matrix_Free(T2);
1478 return T;