Makefile.am: keep better track of failed tests
[barvinok.git] / topcom.c
blob9ad655482c5f54ac892eb60de15ab5c011655625
1 #include <assert.h>
2 #include <barvinok/util.h>
3 #include <barvinok/options.h>
4 #include <unistd.h>
5 #include "normalization.h"
6 #include "topcom.h"
7 #include "config.h"
9 #define ALLOC(type) (type*)malloc(sizeof(type))
11 void run_points2triangs(pid_t *child, int *in, int *out)
13 int in_fd[2], out_fd[2];
15 if (pipe(in_fd))
16 assert(0);
17 if (pipe(out_fd))
18 assert(0);
19 *child = fork();
20 assert(*child >= 0);
21 if (!*child) {
22 int rc;
24 dup2(in_fd[0], 0);
25 dup2(out_fd[1], 1);
26 close(in_fd[0]);
27 close(out_fd[1]);
28 close(in_fd[1]);
29 close(out_fd[0]);
31 rc = execl(POINTS2TRIANGS_PATH, "points2triangs", "--regular", NULL);
32 assert(0);
34 close(in_fd[0]);
35 close(out_fd[1]);
36 *in = in_fd[1];
37 *out = out_fd[0];
40 struct domain {
41 Param_Domain domain;
42 int F_len;
45 static Param_Vertices *construct_vertex(unsigned *vertex_facets,
46 Matrix *Constraints,
47 int d, unsigned nparam, unsigned MaxRays)
49 unsigned nvar = Constraints->NbColumns-2 - nparam;
50 Matrix *A = Matrix_Alloc(nvar+1, nvar+1);
51 Matrix *inv = Matrix_Alloc(nvar+1, nvar+1);
52 Matrix *B = Matrix_Alloc(nvar, nparam+2);
53 Matrix *V = Matrix_Alloc(nvar, nparam+2);
54 Matrix *Domain = Matrix_Alloc(d-nvar, nparam+2);
55 Polyhedron *AD;
56 unsigned bx;
57 int i, j, ix;
58 int ok;
59 Param_Vertices *vertex;
61 for (j = 0, i = 0, ix = 0, bx = MSB; i < d; ++i) {
62 if ((vertex_facets[ix] & bx) == bx) {
63 Vector_Copy(Constraints->p[i]+1, A->p[j], nvar);
64 Vector_Oppose(Constraints->p[i]+1+nvar, B->p[j++], nparam+1);
66 NEXT(ix, bx);
68 assert(j == nvar);
69 value_set_si(A->p[nvar][nvar], 1);
70 ok = Matrix_Inverse(A, inv);
71 assert(ok);
72 Matrix_Free(A);
73 inv->NbRows = nvar;
74 inv->NbColumns = nvar;
75 Matrix_Product(inv, B, V);
76 Matrix_Free(B);
77 for (i = 0; i < nvar; ++i) {
78 value_assign(V->p[i][nparam+1], inv->p[nvar][nvar]);
79 Vector_Normalize(V->p[i], V->NbColumns);
81 Matrix_Free(inv);
82 for (j = 0, i = 0, ix = 0, bx = MSB; i < d; ++i) {
83 if ((vertex_facets[ix] & bx) == bx) {
84 NEXT(ix, bx);
85 continue;
87 Param_Inner_Product(Constraints->p[i], V, Domain->p[j]);
88 if (First_Non_Zero(Domain->p[j]+1, nparam+1) == -1)
89 vertex_facets[ix] |= bx;
90 else
91 value_set_si(Domain->p[j++][0], 1);
92 NEXT(ix, bx);
94 Domain->NbRows = j;
95 A = Matrix_Copy(Domain);
96 AD = Constraints2Polyhedron(A, MaxRays);
97 Matrix_Free(A);
98 POL_ENSURE_VERTICES(AD);
99 /* A vertex with a lower-dimensional activity domain
100 * saturates more facets than derived above and is actually
101 * the superimposition of two or more vertices.
102 * We therefore discard the domain and (ultimately)
103 * the chamber containing it.
104 * We keep the vertex, though, since it may reappear
105 * in other chambers, which will then likewise be discarded.
106 * The same holds if the activity domain is empty.
108 if (AD->NbEq > 0) {
109 Matrix_Free(Domain);
110 Domain = NULL;
112 Polyhedron_Free(AD);
113 vertex = calloc(1, sizeof(Param_Vertices));
114 vertex->Facets = vertex_facets;
115 vertex->Vertex = V;
116 vertex->Domain = Domain;
117 return vertex;
120 static int add_vertex_to_domain(Param_Vertices **vertices, int words,
121 unsigned *vertex_facets,
122 Matrix *Constraints, int d, unsigned nparam,
123 struct domain *domain,
124 unsigned MaxRays)
126 Param_Vertices *vertex;
127 unsigned vbx;
128 int vi, vix;
130 for (vi = 0, vix = 0, vbx = MSB;
131 *vertices;
132 vertices = &(*vertices)->next, ++vi) {
133 int i;
134 for (i = 0; i < words; ++i)
135 if (((*vertices)->Facets[i] & vertex_facets[i]) != vertex_facets[i])
136 break;
137 if (i >= words) {
138 if (!(*vertices)->Domain)
139 domain->F_len = 0;
140 else
141 domain->domain.F[vix] |= vbx;
142 free(vertex_facets);
143 return 0;
145 NEXT(vix, vbx);
147 if (domain->F_len <= vix) {
148 domain->F_len++;
149 domain->domain.F = realloc(domain->domain.F,
150 domain->F_len * sizeof(unsigned));
151 domain->domain.F[domain->F_len-1] = 0;
153 vertex = construct_vertex(vertex_facets, Constraints, d, nparam, MaxRays);
154 if (!vertex->Domain)
155 domain->F_len = 0;
156 else
157 domain->domain.F[vix] |= vbx;
158 vertex->next = *vertices;
159 *vertices = vertex;
160 return 1;
163 static void compute_domain(struct domain *domain, Param_Vertices *vertices,
164 Polyhedron *C, unsigned MaxRays)
166 unsigned bx;
167 int i, ix, j;
168 int nbV = bit_vector_count(domain->domain.F, domain->F_len);
169 unsigned cols = vertices->Domain->NbColumns;
170 unsigned rows = vertices->Domain->NbRows;
171 Matrix *Constraints = Matrix_Alloc(nbV * rows + C->NbConstraints, cols);
173 for (i = 0, j = 0, ix = 0, bx = MSB;
174 vertices;
175 vertices = vertices->next, ++i) {
176 if ((domain->domain.F[ix] & bx) == bx)
177 Vector_Copy(vertices->Domain->p[0],
178 Constraints->p[(j++)*rows], rows * cols);
179 NEXT(ix, bx);
181 Vector_Copy(C->Constraint[0], Constraints->p[j*rows], C->NbConstraints * cols);
182 domain->domain.Domain = Constraints2Polyhedron(Constraints, MaxRays);
183 Matrix_Free(Constraints);
186 static void add_domain(struct domain **domains, struct domain *domain,
187 Param_Vertices *vertices, Polyhedron *C,
188 struct barvinok_options *options)
190 options->stats->topcom_chambers++;
192 for (; *domains; domains = (struct domain **)&(*domains)->domain.next) {
193 int i;
194 for (i = 0; i < (*domains)->F_len; ++i)
195 if (((*domains)->domain.F[i] & domain->domain.F[i])
196 != domain->domain.F[i])
197 break;
198 if (i < (*domains)->F_len)
199 continue;
200 for (; i < domain->F_len; ++i)
201 if (domain->domain.F[i])
202 break;
203 if (i >= domain->F_len) {
204 Param_Domain_Free(&domain->domain);
205 return;
208 options->stats->topcom_distinct_chambers++;
209 compute_domain(domain, vertices, C, options->MaxRays);
210 *domains = domain;
213 #define INT_BITS (sizeof(unsigned) * 8)
215 /* Remove any empty or lower-dimensional chamber. The latter
216 * lie on the boundary of the context and are facets of other chambers.
218 * While we are examining each chamber, also extend the F vector
219 * of each chamber to the maximum.
221 static void remove_empty_chambers(Param_Domain **PD, unsigned vertex_words)
223 while (*PD) {
224 int remove = 0;
225 int i;
227 if ((*PD)->Domain->NbEq > 0)
228 remove = 1;
229 else {
230 POL_ENSURE_FACETS((*PD)->Domain);
231 if ((*PD)->Domain->NbEq > 0)
232 remove = 1;
234 if (remove) {
235 Param_Domain *D = *PD;
236 *PD = (*PD)->next;
237 D->next = NULL;
238 Param_Domain_Free(D);
239 continue;
241 if ((i = ((struct domain*)(*PD))->F_len) < vertex_words)
242 (*PD)->F = realloc((*PD)->F, vertex_words * sizeof(unsigned));
243 for (; i < vertex_words; ++i)
244 (*PD)->F[i] = 0;
245 PD = &(*PD)->next;
249 static Param_Polyhedron *points2triangs(Matrix *K, Polyhedron *P, Polyhedron *C,
250 struct barvinok_options *options)
252 int in, out;
253 int i, j;
254 pid_t child;
255 FILE *fin, *fout;
256 int d = K->NbRows;
257 int words = (d+INT_BITS-1)/INT_BITS;
258 Param_Vertices *vertices = NULL;
259 struct domain *domains = NULL;
260 int vertex_words = 1;
261 Param_Polyhedron *PP = ALLOC(Param_Polyhedron);
262 unsigned MaxRays = options->MaxRays;
264 PP->Rays = NULL;
265 PP->nbV = 0;
266 PP->Constraints = Polyhedron2Constraints(P);
267 /* We need the exact facets, because we may make some of them open later */
268 POL_UNSET(options->MaxRays, POL_INTEGER);
270 run_points2triangs(&child, &in, &out);
272 fin = fdopen(in, "w");
273 fprintf(fin, "[\n");
274 for (i = 0; i < K->NbRows; ++i) {
275 fprintf(fin, "[");
276 for (j = 0; j < K->NbColumns; ++j)
277 value_print(fin, P_VALUE_FMT, K->p[i][j]);
278 fprintf(fin, "]");
280 fprintf(fin, "]\n");
281 fclose(fin);
283 fout = fdopen(out, "r");
284 while (fscanf(fout, "T[%d]:={", &i) == 1) {
285 struct domain *domain = ALLOC(struct domain);
286 memset(domain, 0, sizeof(*domain));
287 domain->domain.F = calloc(vertex_words, sizeof(unsigned));
288 domain->F_len = vertex_words;
290 while (fgetc(fout) == '{') { /* '{' or closing '}' */
291 int c;
292 unsigned *F = calloc(words, sizeof(unsigned));
294 for (j = 0; j < K->NbColumns; ++j) {
295 unsigned v, shift;
296 fscanf(fout, "%d", &v);
297 shift = INT_BITS - (v % INT_BITS) - 1;
298 F[v / INT_BITS] |= 1u << shift;
299 fgetc(fout); /* , or } */
301 if (!domain->F_len)
302 free(F);
303 else if (add_vertex_to_domain(&vertices, words, F, PP->Constraints,
304 d, C->Dimension,
305 domain, options->MaxRays))
306 ++PP->nbV;
307 if ((c = fgetc(fout)) != ',') /* , or } */
308 ungetc(c, fout);
310 if (domain->F_len)
311 vertex_words = domain->F_len;
312 fgetc(fout); /* ; */
313 fgetc(fout); /* \n */
314 if (bit_vector_count(domain->domain.F, domain->F_len) > 0)
315 add_domain(&domains, domain, vertices, C, options);
316 else {
317 options->stats->topcom_empty_chambers++;
318 Param_Domain_Free(&domain->domain);
321 fclose(fout);
323 PP->V = vertices;
324 PP->D = &domains->domain;
326 remove_empty_chambers(&PP->D, vertex_words);
328 options->MaxRays = MaxRays;
330 return PP;
333 /* Assumes M is of full row rank */
334 static Matrix *null_space(Matrix *M)
336 Matrix *H, *Q, *U;
337 Matrix *N;
338 int i;
340 left_hermite(M, &H, &Q, &U);
341 N = Matrix_Alloc(M->NbColumns, M->NbColumns - M->NbRows);
342 for (i = 0; i < N->NbRows; ++i)
343 Vector_Copy(U->p[i] + M->NbRows, N->p[i], N->NbColumns);
344 Matrix_Free(H);
345 Matrix_Free(Q);
346 Matrix_Free(U);
347 return N;
350 static void SwapColumns(Value **V, int n, int i, int j)
352 int r;
354 for (r = 0; r < n; ++r)
355 value_swap(V[r][i], V[r][j]);
358 /* C is assumed to be the "true" context, i.e., it has been intersected
359 * with the projection of P onto the parameter space.
360 * Furthermore, P and C are assumed to be full-dimensional.
362 Param_Polyhedron *TC_P2PP(Polyhedron *P, Polyhedron *C,
363 struct barvinok_options *options)
365 unsigned nparam = C->Dimension;
366 unsigned nvar = P->Dimension - C->Dimension;
367 int i, j;
368 Matrix *H;
369 Matrix *A;
370 Matrix *K;
371 int rows;
372 Param_Polyhedron *PP;
373 Matrix M;
375 assert(C->NbEq == 0);
377 Polyhedron_Matrix_View(P, &M, P->NbConstraints);
378 H = standard_constraints(&M, nparam, &rows, NULL);
380 A = Matrix_Alloc(rows, nvar+rows);
381 for (i = nvar; i < H->NbRows; ++i) {
382 Vector_Oppose(H->p[i], A->p[i-nvar], H->NbColumns);
383 value_set_si(A->p[i-nvar][i], 1);
385 for (i = 0, j = H->NbRows-nvar; i < nvar; ++i) {
386 if (First_Non_Zero(H->p[i], i) == -1)
387 continue;
388 Vector_Oppose(H->p[i], A->p[j], H->NbColumns);
389 value_set_si(A->p[j][j+nvar], 1);
390 SwapColumns(A->p, A->NbRows, j+nvar, i);
391 ++j;
393 K = null_space(A);
394 Matrix_Free(A);
395 /* Ignore extra constraints */
396 K->NbRows = H->NbRows;
397 Matrix_Free(H);
398 PP = points2triangs(K, P, C, options);
399 Matrix_Free(K);
400 return PP;