remove_all_equalities: keep removing parameter equalities until none left
[barvinok.git] / topcom.c
blob53e68bb1b2df2234f81f9452c3e07bcce7aec9d6
1 #include <assert.h>
2 #include <barvinok/util.h>
3 #include <barvinok/options.h>
4 #include <unistd.h>
5 #include "polysign.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->nbV = 0;
265 PP->Constraints = Polyhedron2Constraints(P);
266 /* We need the exact facets, because we may make some of them open later */
267 POL_UNSET(options->MaxRays, POL_INTEGER);
269 run_points2triangs(&child, &in, &out);
271 fin = fdopen(in, "w");
272 fprintf(fin, "[\n");
273 for (i = 0; i < K->NbRows; ++i) {
274 fprintf(fin, "[");
275 for (j = 0; j < K->NbColumns; ++j)
276 value_print(fin, P_VALUE_FMT, K->p[i][j]);
277 fprintf(fin, "]");
279 fprintf(fin, "]\n");
280 fclose(fin);
282 fout = fdopen(out, "r");
283 while (fscanf(fout, "T[%d]:={", &i) == 1) {
284 struct domain *domain = ALLOC(struct domain);
285 memset(domain, 0, sizeof(*domain));
286 domain->domain.F = calloc(vertex_words, sizeof(unsigned));
287 domain->F_len = vertex_words;
289 while (fgetc(fout) == '{') { /* '{' or closing '}' */
290 int c;
291 unsigned *F = calloc(words, sizeof(unsigned));
293 for (j = 0; j < K->NbColumns; ++j) {
294 unsigned v, shift;
295 fscanf(fout, "%d", &v);
296 shift = INT_BITS - (v % INT_BITS) - 1;
297 F[v / INT_BITS] |= 1u << shift;
298 fgetc(fout); /* , or } */
300 if (!domain->F_len)
301 free(F);
302 else if (add_vertex_to_domain(&vertices, words, F, PP->Constraints,
303 d, C->Dimension,
304 domain, options->MaxRays))
305 ++PP->nbV;
306 if ((c = fgetc(fout)) != ',') /* , or } */
307 ungetc(c, fout);
309 if (domain->F_len)
310 vertex_words = domain->F_len;
311 fgetc(fout); /* ; */
312 fgetc(fout); /* \n */
313 if (bit_vector_count(domain->domain.F, domain->F_len) > 0)
314 add_domain(&domains, domain, vertices, C, options);
315 else {
316 options->stats->topcom_empty_chambers++;
317 Param_Domain_Free(&domain->domain);
320 fclose(fout);
322 PP->V = vertices;
323 PP->D = &domains->domain;
325 remove_empty_chambers(&PP->D, vertex_words);
327 options->MaxRays = MaxRays;
329 return PP;
332 /* Assumes M is of full row rank */
333 static Matrix *null_space(Matrix *M)
335 Matrix *H, *Q, *U;
336 Matrix *N;
337 int i;
339 left_hermite(M, &H, &Q, &U);
340 N = Matrix_Alloc(M->NbColumns, M->NbColumns - M->NbRows);
341 for (i = 0; i < N->NbRows; ++i)
342 Vector_Copy(U->p[i] + M->NbRows, N->p[i], N->NbColumns);
343 Matrix_Free(H);
344 Matrix_Free(Q);
345 Matrix_Free(U);
346 return N;
349 static void SwapColumns(Value **V, int n, int i, int j)
351 int r;
353 for (r = 0; r < n; ++r)
354 value_swap(V[r][i], V[r][j]);
357 /* C is assumed to be the "true" context, i.e., it has been intersected
358 * with the projection of P onto the parameter space.
359 * Furthermore, P and C are assumed to be full-dimensional.
361 Param_Polyhedron *TC_P2PP(Polyhedron *P, Polyhedron *C,
362 struct barvinok_options *options)
364 unsigned nparam = C->Dimension;
365 unsigned nvar = P->Dimension - C->Dimension;
366 int i, j;
367 Matrix *H;
368 Matrix *A;
369 Matrix *K;
370 int rows;
371 Param_Polyhedron *PP;
373 assert(C->NbEq == 0);
375 H = standard_constraints(P, nparam, &rows, NULL);
377 A = Matrix_Alloc(rows, nvar+rows);
378 for (i = nvar; i < H->NbRows; ++i) {
379 Vector_Oppose(H->p[i], A->p[i-nvar], H->NbColumns);
380 value_set_si(A->p[i-nvar][i], 1);
382 for (i = 0, j = H->NbRows-nvar; i < nvar; ++i) {
383 if (First_Non_Zero(H->p[i], i) == -1)
384 continue;
385 Vector_Oppose(H->p[i], A->p[j], H->NbColumns);
386 value_set_si(A->p[j][j+nvar], 1);
387 SwapColumns(A->p, A->NbRows, j+nvar, i);
388 ++j;
390 K = null_space(A);
391 Matrix_Free(A);
392 /* Ignore extra constraints */
393 K->NbRows = H->NbRows;
394 Matrix_Free(H);
395 PP = points2triangs(K, P, C, options);
396 Matrix_Free(K);
397 return PP;