barvinok_enumerate_e_series: handle all existentials being eliminated
[barvinok.git] / series.cc
blob9b7019bc9b017bc5eb85cf567dd04614b1ff17c8
1 #include <assert.h>
2 #include <barvinok/barvinok.h>
3 #include <barvinok/util.h>
4 #include "genfun_constructor.h"
5 #include "lattice_width.h"
6 #include "remove_equalities.h"
8 using std::cerr;
9 using std::endl;
11 /* Check whether all rays point in the positive directions
12 * for the parameters
14 static bool Polyhedron_has_positive_rays(Polyhedron *P, unsigned nparam)
16 int r;
17 for (r = 0; r < P->NbRays; ++r)
18 if (value_zero_p(P->Ray[r][P->Dimension+1])) {
19 int i;
20 for (i = P->Dimension - nparam; i < P->Dimension; ++i)
21 if (value_neg_p(P->Ray[r][i+1]))
22 return false;
24 return true;
27 gen_fun *barvinok_enumerate_series(Polyhedron *P, unsigned nparam,
28 barvinok_options *options)
30 Matrix *CP = NULL;
31 gen_fun *gf;
32 Polyhedron *P_orig = P;
34 if (emptyQ2(P))
35 return new gen_fun(Empty_Polyhedron(nparam));
37 assert(!Polyhedron_is_unbounded(P, nparam, options->MaxRays));
38 assert(P->NbBid == 0);
39 assert(Polyhedron_has_revlex_positive_rays(P, nparam));
40 if (P->NbEq != 0)
41 remove_all_equalities(&P, NULL, &CP, NULL, nparam, options->MaxRays);
42 assert(emptyQ2(P) || P->NbEq == 0);
43 if (CP)
44 nparam = CP->NbColumns-1;
46 if (nparam == 0) {
47 Value c;
48 value_init(c);
49 barvinok_count_with_options(P, &c, options);
50 gf = new gen_fun(c);
51 value_clear(c);
52 } else {
53 POL_ENSURE_VERTICES(P);
54 if (P->NbEq)
55 gf = barvinok_enumerate_series(P, nparam, options);
56 else {
57 gf_base *red;
58 red = gf_base::create(Polyhedron_Project(P, nparam),
59 P->Dimension, nparam, options);
60 red->start_gf(P, options);
61 gf = red->gf;
62 delete red;
65 if (CP) {
66 gf->substitute(CP);
67 Matrix_Free(CP);
69 if (P != P_orig)
70 Polyhedron_Free(P);
71 return gf;
74 gen_fun * barvinok_series_with_options(Polyhedron *P, Polyhedron* C,
75 barvinok_options *options)
77 Polyhedron *CA;
78 unsigned nparam = C->Dimension;
79 gen_fun *gf;
81 CA = align_context(C, P->Dimension, options->MaxRays);
82 P = DomainIntersection(P, CA, options->MaxRays);
83 Polyhedron_Free(CA);
85 gf = barvinok_enumerate_series(P, nparam, options);
86 Polyhedron_Free(P);
88 return gf;
91 gen_fun * barvinok_series(Polyhedron *P, Polyhedron* C, unsigned MaxRays)
93 gen_fun *gf;
94 barvinok_options *options = barvinok_options_new_with_defaults();
95 options->MaxRays = MaxRays;
96 gf = barvinok_series_with_options(P, C, options);
97 barvinok_options_free(options);
98 return gf;
101 static Polyhedron *skew_into_positive_orthant(Polyhedron *D, unsigned nparam,
102 unsigned MaxRays)
104 Matrix *M = NULL;
105 Value tmp;
106 value_init(tmp);
107 for (Polyhedron *P = D; P; P = P->next) {
108 POL_ENSURE_VERTICES(P);
109 assert(!Polyhedron_is_unbounded(P, nparam, MaxRays));
110 assert(P->NbBid == 0);
111 assert(Polyhedron_has_positive_rays(P, nparam));
113 for (int r = 0; r < P->NbRays; ++r) {
114 if (value_notzero_p(P->Ray[r][P->Dimension+1]))
115 continue;
116 for (int i = 0; i < nparam; ++i) {
117 int j;
118 if (value_posz_p(P->Ray[r][i+1]))
119 continue;
120 if (!M) {
121 M = Matrix_Alloc(D->Dimension+1, D->Dimension+1);
122 for (int i = 0; i < D->Dimension+1; ++i)
123 value_set_si(M->p[i][i], 1);
124 } else {
125 Inner_Product(P->Ray[r]+1, M->p[i], D->Dimension+1, &tmp);
126 if (value_posz_p(tmp))
127 continue;
129 for (j = P->Dimension - nparam; j < P->Dimension; ++j)
130 if (value_pos_p(P->Ray[r][j+1]))
131 break;
132 assert(j < P->Dimension);
133 value_pdivision(tmp, P->Ray[r][j+1], P->Ray[r][i+1]);
134 value_subtract(M->p[i][j], M->p[i][j], tmp);
138 value_clear(tmp);
139 if (M) {
140 D = DomainImage(D, M, MaxRays);
141 Matrix_Free(M);
143 return D;
146 gen_fun* barvinok_enumerate_union_series_with_options(Polyhedron *D, Polyhedron* C,
147 barvinok_options *options)
149 Polyhedron *conv, *D2;
150 Polyhedron *CA;
151 gen_fun *gf = NULL, *gf2;
152 unsigned nparam = C->Dimension;
153 ZZ one, mone;
154 one = 1;
155 mone = -1;
157 CA = align_context(C, D->Dimension, options->MaxRays);
158 D = DomainIntersection(D, CA, options->MaxRays);
159 Polyhedron_Free(CA);
161 D2 = skew_into_positive_orthant(D, nparam, options->MaxRays);
162 for (Polyhedron *P = D2; P; P = P->next) {
163 assert(P->Dimension == D2->Dimension);
164 gen_fun *P_gf;
166 P_gf = barvinok_enumerate_series(P, P->Dimension, options);
167 if (!gf)
168 gf = P_gf;
169 else {
170 gf->add_union(P_gf, options);
171 delete P_gf;
174 /* we actually only need the convex union of the parameter space
175 * but the reducer classes currently expect a polyhedron in
176 * the combined space
178 Polyhedron_Free(gf->context);
179 gf->context = DomainConvex(D2, options->MaxRays);
181 gf2 = gf->summate(D2->Dimension - nparam, options);
183 delete gf;
184 if (D != D2)
185 Domain_Free(D2);
186 Domain_Free(D);
187 return gf2;
190 gen_fun* barvinok_enumerate_union_series(Polyhedron *D, Polyhedron* C,
191 unsigned MaxRays)
193 gen_fun *gf;
194 barvinok_options *options = barvinok_options_new_with_defaults();
195 options->MaxRays = MaxRays;
196 gf = barvinok_enumerate_union_series_with_options(D, C, options);
197 barvinok_options_free(options);
198 return gf;
201 /* Unimodularly transform the polyhedron P, such that
202 * the direction specified by dir corresponds to the last
203 * variable in the transformed polyhedron.
204 * The number of variables is given by the length of dir.
206 static Polyhedron *put_direction_last(Polyhedron *P, Vector *dir,
207 unsigned MaxRays)
209 Polyhedron *R;
210 Matrix *T;
211 int n = dir->Size;
213 T = Matrix_Alloc(P->Dimension+1, P->Dimension+1);
214 T->NbColumns = T->NbRows = n;
215 Vector_Copy(dir->p, T->p[0], n);
216 unimodular_complete(T, 1);
217 Vector_Exchange(T->p[0], T->p[n-1], n);
218 T->NbColumns = T->NbRows = P->Dimension+1;
219 for (int j = n; j < P->Dimension+1; ++j)
220 value_set_si(T->p[j][j], 1);
222 R = Polyhedron_Image(P, T, MaxRays);
223 Matrix_Free(T);
225 return R;
228 /* Do we need to continue shifting and subtracting?
229 * i is the number of times we shifted so far
230 * n is the number of coordinates projected out
232 static bool more_shifts_needed(int j, int n,
233 gen_fun *S, gen_fun *S_divide, const vec_ZZ& up,
234 barvinok_options *options)
236 bool empty;
237 gen_fun *hp;
238 Value c;
240 /* For the 2-dimensional case, we need to subtract at most once */
241 if (n == 2 && j > 0)
242 return false;
244 S_divide->shift(up);
246 /* Assume that we have to subtract at least once */
247 if (j == 0)
248 return true;
250 hp = S->Hadamard_product(S_divide, options);
252 value_init(c);
254 empty = hp->summate(&c) && value_zero_p(c);
255 delete hp;
257 value_clear(c);
259 return !empty;
262 /* Return gf of P projected on last dim(P)-n coordinates, i.e.,
263 * project out the first n coordinates.
265 static gen_fun *project(Polyhedron *P, unsigned n, barvinok_options *options)
267 QQ one(1, 1);
268 QQ mone(-1, 1);
269 vec_ZZ up;
270 gen_fun *gf = NULL;
271 struct width_direction_array *dirs;
272 Polyhedron *U;
274 if (n == 0)
275 return barvinok_enumerate_series(P, P->Dimension, options);
277 up.SetLength(P->Dimension - (n-1));
278 up[0] = 1;
279 for (int i = 1; i < P->Dimension - (n-1); ++i)
280 up[i] = 0;
282 if (n == 1) {
283 gen_fun *S, *S_shift, *hp;
285 S = barvinok_enumerate_series(P, P->Dimension, options);
286 S_shift = new gen_fun(S);
287 S_shift->shift(up);
288 hp = S->Hadamard_product(S_shift, options);
289 S->add(mone, hp, options);
290 delete S_shift;
291 delete hp;
293 gf = S->summate(1, options);
294 delete S;
296 return gf;
299 U = Universe_Polyhedron(P->Dimension - n);
300 dirs = Polyhedron_Lattice_Width_Directions(P, U, options);
301 Polyhedron_Free(U);
303 for (int i = 0; i < dirs->n; ++i) {
304 Polyhedron *Pi, *R;
305 Polyhedron *CA;
306 gen_fun *S, *S_shift, *S_divide, *sum;
308 CA = align_context(dirs->wd[i].domain, P->Dimension, options->MaxRays);
309 R = DomainIntersection(P, CA, options->MaxRays);
310 Polyhedron_Free(CA);
311 assert(dirs->wd[i].dir->Size == n);
312 Pi = put_direction_last(R, dirs->wd[i].dir, options->MaxRays);
313 Polyhedron_Free(R);
315 S = project(Pi, n-1, options);
316 Polyhedron_Free(Pi);
318 S_shift = new gen_fun(S);
319 S_divide = new gen_fun(S);
320 S_divide->divide(up);
322 for (int j = 0; more_shifts_needed(j, n, S, S_divide, up, options); ++j) {
323 gen_fun *hp;
325 S_shift->shift(up);
326 hp = S->Hadamard_product(S_shift, options);
327 S->add(mone, hp, options);
329 delete hp;
332 sum = S->summate(1, options);
334 delete S_shift;
335 delete S_divide;
336 delete S;
338 if (!gf)
339 gf = sum;
340 else {
341 gf->add(one, sum, options);
342 delete sum;
345 free_width_direction_array(dirs);
347 return gf;
350 gen_fun *barvinok_enumerate_e_series(Polyhedron *P,
351 unsigned exist, unsigned nparam, barvinok_options *options)
353 Matrix *CP = NULL;
354 Polyhedron *P_orig = P;
355 gen_fun *gf, *proj;
356 unsigned nvar = P->Dimension - exist - nparam;
358 if (exist == 0)
359 return barvinok_enumerate_series(P, nparam, options);
361 if (emptyQ(P))
362 return new gen_fun(Empty_Polyhedron(nparam));
364 assert(!Polyhedron_is_unbounded(P, nparam, options->MaxRays));
365 assert(P->NbBid == 0);
366 assert(Polyhedron_has_revlex_positive_rays(P, nparam));
368 /* Move existentially quantified variables to the front.*/
369 if (nvar) {
370 Matrix *T;
371 T = Matrix_Alloc(exist+nvar+nparam+1, nvar+exist+nparam+1);
372 for (int i = 0; i < exist; ++i)
373 value_set_si(T->p[i][nvar+i], 1);
374 for (int i = 0; i < nvar; ++i)
375 value_set_si(T->p[exist+i][i], 1);
376 for (int i = 0; i < nparam+1; ++i)
377 value_set_si(T->p[exist+nvar+i][nvar+exist+i], 1);
378 P = Polyhedron_Image(P, T, options->MaxRays);
379 Matrix_Free(T);
381 if (P->NbEq != 0) {
382 Polyhedron *Q = P;
383 remove_all_equalities(&P, NULL, &CP, NULL, nvar+nparam,
384 options->MaxRays);
385 if (CP)
386 exist = P->Dimension - (CP->NbColumns-1);
387 else
388 exist = P->Dimension - (nvar + nparam);
389 if (Q != P_orig)
390 Polyhedron_Free(Q);
393 proj = project(P, exist, options);
394 if (CP) {
395 proj->substitute(CP);
396 Matrix_Free(CP);
399 if (P != P_orig)
400 Polyhedron_Free(P);
402 if (!nvar)
403 gf = proj;
404 else {
405 gf = proj->summate(nvar, options);
406 delete proj;
408 return gf;