barvinok 0.41.7
[barvinok.git] / barvinok_enumerate.cc
blob5f63dd8ca0a6041dc9434747de8863e91527cf6a
1 #include <assert.h>
2 #include <unistd.h>
3 #include <stdlib.h>
4 #include <gmp.h>
5 #include <isl/ctx.h>
6 #include <isl/val.h>
7 #include <isl/space.h>
8 #include <isl/point.h>
9 #include <isl/set.h>
10 #include <isl/polynomial.h>
11 #include <isl/printer.h>
12 #include <isl_set_polylib.h>
13 #include <barvinok/evalue.h>
14 #include <barvinok/util.h>
15 #include <barvinok/barvinok.h>
16 #include "barvinok_enumerate_options.h"
17 #include "verify.h"
18 #include "verify_series.h"
19 #include "remove_equalities.h"
20 #include "evalue_convert.h"
21 #include "conversion.h"
22 #include "skewed_genfun.h"
24 #undef CS /* for Solaris 10 */
26 using std::cout;
27 using std::endl;
29 /* The input of this example program is the same as that of testehrhart
30 * in the PolyLib distribution, i.e., a polytope in combined
31 * data and parameter space, a context polytope in parameter space
32 * and (optionally) the names of the parameters.
33 * Both polytopes are in PolyLib notation.
36 struct verify_point_enum {
37 struct verify_point_data vpd;
38 isl_set *set;
39 isl_pw_qpolynomial *pwqp;
42 static isl_stat verify_point(__isl_take isl_point *pnt, void *user)
44 struct verify_point_enum *vpe = (struct verify_point_enum *) user;
45 isl_set *set;
46 int i;
47 unsigned nparam;
48 isl_val *v, *n, *t;
49 int pa = vpe->vpd.options->barvinok->approx->approximation;
50 int ok;
51 FILE *out = vpe->vpd.options->print_all ? stdout : stderr;
53 vpe->vpd.n--;
55 set = isl_set_copy(vpe->set);
56 nparam = isl_set_dim(set, isl_dim_param);
57 for (i = 0; i < nparam; ++i) {
58 v = isl_point_get_coordinate_val(pnt, isl_dim_param, i);
59 set = isl_set_fix_val(set, isl_dim_param, i, v);
62 v = isl_set_count_val(set);
64 n = isl_pw_qpolynomial_eval(isl_pw_qpolynomial_copy(vpe->pwqp),
65 isl_point_copy(pnt));
67 if (pa == BV_APPROX_SIGN_LOWER)
68 n = isl_val_ceil(n);
69 else if (pa == BV_APPROX_SIGN_UPPER)
70 n = isl_val_floor(n);
71 else
72 n = isl_val_trunc(n);
74 if (pa == BV_APPROX_SIGN_APPROX)
75 /* just accept everything */
76 ok = 1;
77 else if (pa == BV_APPROX_SIGN_LOWER)
78 ok = isl_val_le(n, v);
79 else if (pa == BV_APPROX_SIGN_UPPER)
80 ok = isl_val_ge(n, v);
81 else
82 ok = isl_val_eq(n, v);
84 if (vpe->vpd.options->print_all || !ok) {
85 isl_ctx *ctx = isl_point_get_ctx(pnt);
86 isl_printer *p;
87 p = isl_printer_to_file(ctx, out);
88 p = isl_printer_print_str(p, "EP(");
89 for (i = 0; i < nparam; ++i) {
90 if (i)
91 p = isl_printer_print_str(p, ", ");
92 t = isl_point_get_coordinate_val(pnt, isl_dim_param, i);
93 p = isl_printer_print_val(p, t);
94 isl_val_free(t);
96 p = isl_printer_print_str(p, ") = ");
97 p = isl_printer_print_val(p, n);
98 p = isl_printer_print_str(p, ", count = ");
99 p = isl_printer_print_val(p, v);
100 if (ok)
101 p = isl_printer_print_str(p, ". OK");
102 else
103 p = isl_printer_print_str(p, ". NOT OK");
104 p = isl_printer_end_line(p);
105 isl_printer_free(p);
106 } else if ((vpe->vpd.n % vpe->vpd.s) == 0) {
107 printf("o");
108 fflush(stdout);
111 isl_set_free(set);
112 isl_val_free(v);
113 isl_val_free(n);
114 isl_point_free(pnt);
116 if (!ok)
117 vpe->vpd.error = 1;
119 if (vpe->vpd.options->continue_on_error)
120 ok = 1;
122 return (vpe->vpd.n >= 1 && ok) ? isl_stat_ok : isl_stat_error;
125 static int verify_isl(Polyhedron *P, Polyhedron *C,
126 evalue *EP, const struct verify_options *options)
128 struct verify_point_enum vpe = { { options } };
129 int i;
130 isl_ctx *ctx = isl_ctx_alloc();
131 isl_space *space;
132 isl_set *set;
133 isl_set *set_C;
134 int r;
136 space = isl_space_set_alloc(ctx, C->Dimension,
137 P->Dimension - C->Dimension);
138 for (i = 0; i < C->Dimension; ++i)
139 space = isl_space_set_dim_name(space, isl_dim_param, i,
140 options->params[i]);
141 set = isl_set_new_from_polylib(P, isl_space_copy(space));
142 space = isl_space_params(space);
143 set_C = isl_set_new_from_polylib(C, space);
144 set_C = isl_set_intersect_params(isl_set_copy(set), set_C);
145 set_C = isl_set_params(set_C);
147 set_C = verify_context_set_bounds(set_C, options);
149 r = verify_point_data_init(&vpe.vpd, set_C);
151 vpe.set = set;
152 vpe.pwqp = isl_pw_qpolynomial_from_evalue(isl_set_get_space(set_C), EP);
153 if (r == 0)
154 isl_set_foreach_point(set_C, verify_point, &vpe);
155 if (vpe.vpd.error)
156 r = -1;
158 isl_pw_qpolynomial_free(vpe.pwqp);
159 isl_set_free(set);
160 isl_set_free(set_C);
162 isl_ctx_free(ctx);
164 verify_point_data_fini(&vpe.vpd);
166 return r;
169 static int verify(Polyhedron *P, Polyhedron *C, evalue *EP, skewed_gen_fun *gf,
170 struct enumerate_options *options)
172 Polyhedron *CS, *S;
173 Vector *p;
174 int result = 0;
176 if (!options->series || options->function)
177 return verify_isl(P, C, EP, options->verify);
179 CS = check_poly_context_scan(P, &C, C->Dimension, options->verify);
181 p = Vector_Alloc(P->Dimension+2);
182 value_set_si(p->p[P->Dimension+1], 1);
184 /* S = scanning list of polyhedra */
185 S = Polyhedron_Scan(P, C, options->verify->barvinok->MaxRays);
187 check_poly_init(C, options->verify);
189 /******* CHECK NOW *********/
190 if (S) {
191 if (!check_poly_gf(S, CS, gf, 0, C->Dimension, 0, p->p,
192 options->verify))
193 result = -1;
194 Domain_Free(S);
197 if (result == -1)
198 fprintf(stderr,"Check failed !\n");
200 if (!options->verify->print_all)
201 printf( "\n" );
203 Vector_Free(p);
204 if (CS) {
205 Domain_Free(CS);
206 Domain_Free(C);
209 return result;
212 /* frees M and Minv */
213 static void apply_transformation(Polyhedron **P, Polyhedron **C,
214 bool free_P, bool free_C,
215 Matrix *M, Matrix *Minv, Matrix **inv,
216 barvinok_options *options)
218 Polyhedron *T;
219 Matrix *M2;
221 M2 = align_matrix(M, (*P)->Dimension + 1);
222 T = *P;
223 *P = Polyhedron_Preimage(*P, M2, options->MaxRays);
224 if (free_P)
225 Polyhedron_Free(T);
226 Matrix_Free(M2);
228 T = *C;
229 *C = Polyhedron_Preimage(*C, M, options->MaxRays);
230 if (free_C)
231 Polyhedron_Free(T);
233 Matrix_Free(M);
235 if (*inv) {
236 Matrix *T = *inv;
237 *inv = Matrix_Alloc(Minv->NbRows, T->NbColumns);
238 Matrix_Product(Minv, T, *inv);
239 Matrix_Free(T);
240 Matrix_Free(Minv);
241 } else
242 *inv = Minv;
245 /* Since we have "compressed" the parameters (in case there were
246 * any equalities), the result is independent of the coordinates in the
247 * coordinate subspace spanned by the lines. We can therefore assume
248 * these coordinates are zero and compute the inverse image of the map
249 * from a lower dimensional space that adds zeros in the appropriate
250 * places.
252 static void remove_lines(Polyhedron *C, Matrix **M, Matrix **Minv)
254 Matrix *L = Matrix_Alloc(C->Dimension+1, C->Dimension+1);
255 for (int r = 0; r < C->NbBid; ++r)
256 Vector_Copy(C->Ray[r]+1, L->p[r], C->Dimension);
257 unimodular_complete(L, C->NbBid);
258 assert(value_one_p(L->p[C->Dimension][C->Dimension]));
259 assert(First_Non_Zero(L->p[C->Dimension], C->Dimension) == -1);
260 Matrix_Transposition(L);
261 assert(First_Non_Zero(L->p[C->Dimension], C->Dimension) == -1);
263 *M = Matrix_Alloc(C->Dimension+1, C->Dimension-C->NbBid+1);
264 for (int i = 0; i < C->Dimension+1; ++i)
265 Vector_Copy(L->p[i]+C->NbBid, (*M)->p[i], C->Dimension-C->NbBid+1);
267 Matrix *Linv = Matrix_Alloc(C->Dimension+1, C->Dimension+1);
268 int ok = Matrix_Inverse(L, Linv);
269 assert(ok);
270 Matrix_Free(L);
272 *Minv = Matrix_Alloc(C->Dimension-C->NbBid+1, C->Dimension+1);
273 for (int i = C->NbBid; i < C->Dimension+1; ++i)
274 Vector_AntiScale(Linv->p[i], (*Minv)->p[i-C->NbBid],
275 Linv->p[C->Dimension][C->Dimension], C->Dimension+1);
276 Matrix_Free(Linv);
279 static skewed_gen_fun *series(Polyhedron *P, Polyhedron* C,
280 barvinok_options *options)
282 Polyhedron *C1, *C2;
283 gen_fun *gf;
284 Matrix *inv = NULL;
285 Matrix *eq = NULL;
286 Matrix *div = NULL;
287 Polyhedron *PT = P;
289 /* Compute true context */
290 C1 = Polyhedron_Project(P, C->Dimension);
291 C2 = DomainIntersection(C, C1, options->MaxRays);
292 Polyhedron_Free(C1);
294 POL_ENSURE_VERTICES(C2);
295 if (C2->NbBid != 0) {
296 Matrix *CP;
297 if (C2->NbEq || P->NbEq) {
298 /* We remove all equalities to be sure all lines are unit vectors */
299 Polyhedron *CT = C2;
300 remove_all_equalities(&PT, &CT, &CP, NULL, C2->Dimension,
301 options->MaxRays);
302 if (CT != C2) {
303 Polyhedron_Free(C2);
304 C2 = CT;
306 if (CP) {
307 inv = left_inverse(CP, &eq);
308 Matrix_Free(CP);
310 int d = 0;
311 Value tmp;
312 value_init(tmp);
313 div = Matrix_Alloc(inv->NbRows-1, inv->NbColumns+1);
314 for (int i = 0; i < inv->NbRows-1; ++i) {
315 Vector_Gcd(inv->p[i], inv->NbColumns, &tmp);
316 if (mpz_divisible_p(tmp,
317 inv->p[inv->NbRows-1][inv->NbColumns-1]))
318 continue;
319 Vector_Copy(inv->p[i], div->p[d], inv->NbColumns);
320 value_assign(div->p[d][inv->NbColumns],
321 inv->p[inv->NbRows-1][inv->NbColumns-1]);
322 ++d;
324 value_clear(tmp);
326 if (!d) {
327 Matrix_Free(div);
328 div = NULL;
329 } else
330 div->NbRows = d;
333 POL_ENSURE_VERTICES(C2);
335 if (C2->NbBid) {
336 Matrix *M, *Minv;
337 remove_lines(C2, &M, &Minv);
338 apply_transformation(&PT, &C2, PT != P, C2 != C, M, Minv, &inv,
339 options);
342 POL_ENSURE_VERTICES(C2);
343 if (!Polyhedron_has_revlex_positive_rays(C2, C2->Dimension)) {
344 Matrix *Constraints;
345 Matrix *H, *Q, *U;
346 Constraints = Matrix_Alloc(C2->NbConstraints, C2->Dimension+1);
347 for (int i = 0; i < C2->NbConstraints; ++i)
348 Vector_Copy(C2->Constraint[i]+1, Constraints->p[i], C2->Dimension);
349 left_hermite(Constraints, &H, &Q, &U);
350 Matrix_Free(Constraints);
351 /* flip rows of Q */
352 for (int i = 0; i < C2->Dimension/2; ++i)
353 Vector_Exchange(Q->p[i], Q->p[C2->Dimension-1-i], C2->Dimension);
354 Matrix_Free(H);
355 Matrix_Free(U);
356 Matrix *M = Matrix_Alloc(C2->Dimension+1, C2->Dimension+1);
357 U = Matrix_Copy(Q);
358 int ok = Matrix_Inverse(U, M);
359 assert(ok);
360 Matrix_Free(U);
362 apply_transformation(&PT, &C2, PT != P, C2 != C, M, Q, &inv, options);
364 gf = barvinok_series_with_options(PT, C2, options);
365 Polyhedron_Free(C2);
366 if (PT != P)
367 Polyhedron_Free(PT);
368 return new skewed_gen_fun(gf, inv, eq, div);
371 int main(int argc, char **argv)
373 Polyhedron *A, *C;
374 Matrix *M;
375 evalue *EP = NULL;
376 skewed_gen_fun *gf = NULL;
377 const char **param_name;
378 int print_solution = 1;
379 int result = 0;
380 struct enumerate_options *options = enumerate_options_new_with_defaults();
382 argc = enumerate_options_parse(options, argc, argv, ISL_ARG_ALL);
384 M = Matrix_Read();
385 assert(M);
386 A = Constraints2Polyhedron(M, options->verify->barvinok->MaxRays);
387 Matrix_Free(M);
388 M = Matrix_Read();
389 assert(M);
390 C = Constraints2Polyhedron(M, options->verify->barvinok->MaxRays);
391 Matrix_Free(M);
392 assert(A->Dimension >= C->Dimension);
393 param_name = Read_ParamNames(stdin, C->Dimension);
395 if (options->verify->verify) {
396 verify_options_set_range(options->verify, A->Dimension);
397 if (!options->verify->barvinok->verbose)
398 print_solution = 0;
401 if (print_solution && options->verify->barvinok->verbose) {
402 Polyhedron_Print(stdout, P_VALUE_FMT, A);
403 Polyhedron_Print(stdout, P_VALUE_FMT, C);
406 if (options->series) {
407 gf = series(A, C, options->verify->barvinok);
408 if (print_solution) {
409 gf->print(cout, C->Dimension, param_name);
410 puts("");
412 if (options->function) {
413 EP = *gf;
414 if (print_solution)
415 print_evalue(stdout, EP, param_name);
417 } else {
418 EP = barvinok_enumerate_with_options(A, C, options->verify->barvinok);
419 assert(EP);
420 if (evalue_convert(EP, options->convert, options->verify->barvinok->verbose,
421 C->Dimension, param_name))
422 print_solution = 0;
423 if (options->size)
424 printf("\nSize: %zd\n", evalue_size(EP));
425 if (print_solution)
426 print_evalue(stdout, EP, param_name);
429 if (options->verify->verify) {
430 options->verify->params = param_name;
431 result = verify(A, C, EP, gf, options);
434 if (gf)
435 delete gf;
436 if (EP)
437 evalue_free(EP);
439 if (options->verify->barvinok->print_stats)
440 barvinok_stats_print(options->verify->barvinok->stats, stdout);
442 Free_ParamNames(param_name, C->Dimension);
443 Polyhedron_Free(A);
444 Polyhedron_Free(C);
445 enumerate_options_free(options);
446 return result;