update isl for change in isl_vertex inspectors
[barvinok.git] / barvinok_enumerate.cc
blobf9bb7b5611c9e1add8c56ff1dc0d2791f04871eb
1 #include <assert.h>
2 #include <unistd.h>
3 #include <stdlib.h>
4 #include <gmp.h>
5 #include <isl_set_polylib.h>
6 #include <barvinok/evalue.h>
7 #include <barvinok/util.h>
8 #include <barvinok/barvinok.h>
9 #include "barvinok_enumerate_options.h"
10 #include "verify.h"
11 #include "verif_ehrhart.h"
12 #include "verify_series.h"
13 #include "remove_equalities.h"
14 #include "evalue_convert.h"
15 #include "conversion.h"
16 #include "skewed_genfun.h"
18 #undef CS /* for Solaris 10 */
20 using std::cout;
21 using std::endl;
23 /* The input of this example program is the same as that of testehrhart
24 * in the PolyLib distribution, i.e., a polytope in combined
25 * data and parameter space, a context polytope in parameter space
26 * and (optionally) the names of the parameters.
27 * Both polytopes are in PolyLib notation.
30 struct verify_point_enum {
31 struct verify_point_data vpd;
32 isl_set *set;
33 isl_pw_qpolynomial *pwqp;
36 static int verify_point(__isl_take isl_point *pnt, void *user)
38 struct verify_point_enum *vpe = (struct verify_point_enum *) user;
39 isl_set *set;
40 int i;
41 unsigned nparam;
42 isl_val *v, *n, *t;
43 int pa = vpe->vpd.options->barvinok->approx->approximation;
44 int cst;
45 int ok;
46 FILE *out = vpe->vpd.options->print_all ? stdout : stderr;
48 vpe->vpd.n--;
50 set = isl_set_copy(vpe->set);
51 nparam = isl_set_dim(set, isl_dim_param);
52 for (i = 0; i < nparam; ++i) {
53 v = isl_point_get_coordinate_val(pnt, isl_dim_param, i);
54 set = isl_set_fix_val(set, isl_dim_param, i, v);
57 v = isl_set_count_val(set);
59 n = isl_pw_qpolynomial_eval(isl_pw_qpolynomial_copy(vpe->pwqp),
60 isl_point_copy(pnt));
62 if (pa == BV_APPROX_SIGN_LOWER)
63 n = isl_val_ceil(n);
64 else if (pa == BV_APPROX_SIGN_UPPER)
65 n = isl_val_floor(n);
66 else
67 n = isl_val_trunc(n);
69 if (pa == BV_APPROX_SIGN_APPROX)
70 /* just accept everything */
71 ok = 1;
72 else if (pa == BV_APPROX_SIGN_LOWER)
73 ok = isl_val_le(n, v);
74 else if (pa == BV_APPROX_SIGN_UPPER)
75 ok = isl_val_ge(n, v);
76 else
77 ok = isl_val_eq(n, v);
79 if (vpe->vpd.options->print_all || !ok) {
80 isl_ctx *ctx = isl_point_get_ctx(pnt);
81 isl_printer *p;
82 p = isl_printer_to_file(ctx, out);
83 p = isl_printer_print_str(p, "EP(");
84 for (i = 0; i < nparam; ++i) {
85 if (i)
86 p = isl_printer_print_str(p, ", ");
87 t = isl_point_get_coordinate_val(pnt, isl_dim_param, i);
88 p = isl_printer_print_val(p, t);
89 isl_val_free(t);
91 p = isl_printer_print_str(p, ") = ");
92 p = isl_printer_print_val(p, n);
93 p = isl_printer_print_str(p, ", count = ");
94 p = isl_printer_print_val(p, v);
95 if (ok)
96 p = isl_printer_print_str(p, ". OK");
97 else
98 p = isl_printer_print_str(p, ". NOT OK");
99 p = isl_printer_end_line(p);
100 isl_printer_free(p);
101 } else if ((vpe->vpd.n % vpe->vpd.s) == 0) {
102 printf("o");
103 fflush(stdout);
106 if (0) {
107 error:
108 ok = 0;
110 isl_set_free(set);
111 isl_val_free(v);
112 isl_val_free(n);
113 isl_point_free(pnt);
115 if (!ok)
116 vpe->vpd.error = 1;
118 if (vpe->vpd.options->continue_on_error)
119 ok = 1;
121 return (vpe->vpd.n >= 1 && ok) ? 0 : -1;
124 static int verify_isl(Polyhedron *P, Polyhedron *C,
125 evalue *EP, const struct verify_options *options)
127 struct verify_point_enum vpe = { { options } };
128 int i;
129 isl_ctx *ctx = isl_ctx_alloc();
130 isl_space *dim;
131 isl_set *set;
132 isl_set *set_C;
133 int r;
135 dim = isl_space_set_alloc(ctx, C->Dimension, P->Dimension - C->Dimension);
136 for (i = 0; i < C->Dimension; ++i)
137 dim = isl_space_set_dim_name(dim, isl_dim_param, i, options->params[i]);
138 set = isl_set_new_from_polylib(P, isl_space_copy(dim));
139 dim = isl_space_params(dim);
140 set_C = isl_set_new_from_polylib(C, dim);
141 set_C = isl_set_intersect_params(isl_set_copy(set), set_C);
142 set_C = isl_set_params(set_C);
144 set_C = verify_context_set_bounds(set_C, options);
146 r = verify_point_data_init(&vpe.vpd, set_C);
148 vpe.set = set;
149 vpe.pwqp = isl_pw_qpolynomial_from_evalue(isl_set_get_space(set_C), EP);
150 if (r == 0)
151 isl_set_foreach_point(set_C, verify_point, &vpe);
152 if (vpe.vpd.error)
153 r = -1;
155 isl_pw_qpolynomial_free(vpe.pwqp);
156 isl_set_free(set);
157 isl_set_free(set_C);
159 isl_ctx_free(ctx);
161 verify_point_data_fini(&vpe.vpd);
163 return r;
166 static int verify(Polyhedron *P, Polyhedron *C, evalue *EP, skewed_gen_fun *gf,
167 struct enumerate_options *options)
169 Polyhedron *CS, *S;
170 Vector *p;
171 int result = 0;
173 if (!options->series || options->function)
174 return verify_isl(P, C, EP, options->verify);
176 CS = check_poly_context_scan(P, &C, C->Dimension, options->verify);
178 p = Vector_Alloc(P->Dimension+2);
179 value_set_si(p->p[P->Dimension+1], 1);
181 /* S = scanning list of polyhedra */
182 S = Polyhedron_Scan(P, C, options->verify->barvinok->MaxRays);
184 check_poly_init(C, options->verify);
186 /******* CHECK NOW *********/
187 if (S) {
188 if (!options->series || options->function) {
189 if (!check_poly_EP(S, CS, EP, 0, C->Dimension, 0, p->p,
190 options->verify))
191 result = -1;
192 } else {
193 if (!check_poly_gf(S, CS, gf, 0, C->Dimension, 0, p->p,
194 options->verify))
195 result = -1;
197 Domain_Free(S);
200 if (result == -1)
201 fprintf(stderr,"Check failed !\n");
203 if (!options->verify->print_all)
204 printf( "\n" );
206 Vector_Free(p);
207 if (CS) {
208 Domain_Free(CS);
209 Domain_Free(C);
212 return result;
215 /* frees M and Minv */
216 static void apply_transformation(Polyhedron **P, Polyhedron **C,
217 bool free_P, bool free_C,
218 Matrix *M, Matrix *Minv, Matrix **inv,
219 barvinok_options *options)
221 Polyhedron *T;
222 Matrix *M2;
224 M2 = align_matrix(M, (*P)->Dimension + 1);
225 T = *P;
226 *P = Polyhedron_Preimage(*P, M2, options->MaxRays);
227 if (free_P)
228 Polyhedron_Free(T);
229 Matrix_Free(M2);
231 T = *C;
232 *C = Polyhedron_Preimage(*C, M, options->MaxRays);
233 if (free_C)
234 Polyhedron_Free(T);
236 Matrix_Free(M);
238 if (*inv) {
239 Matrix *T = *inv;
240 *inv = Matrix_Alloc(Minv->NbRows, T->NbColumns);
241 Matrix_Product(Minv, T, *inv);
242 Matrix_Free(T);
243 Matrix_Free(Minv);
244 } else
245 *inv = Minv;
248 /* Since we have "compressed" the parameters (in case there were
249 * any equalities), the result is independent of the coordinates in the
250 * coordinate subspace spanned by the lines. We can therefore assume
251 * these coordinates are zero and compute the inverse image of the map
252 * from a lower dimensional space that adds zeros in the appropriate
253 * places.
255 static void remove_lines(Polyhedron *C, Matrix **M, Matrix **Minv)
257 Matrix *L = Matrix_Alloc(C->Dimension+1, C->Dimension+1);
258 for (int r = 0; r < C->NbBid; ++r)
259 Vector_Copy(C->Ray[r]+1, L->p[r], C->Dimension);
260 unimodular_complete(L, C->NbBid);
261 assert(value_one_p(L->p[C->Dimension][C->Dimension]));
262 assert(First_Non_Zero(L->p[C->Dimension], C->Dimension) == -1);
263 Matrix_Transposition(L);
264 assert(First_Non_Zero(L->p[C->Dimension], C->Dimension) == -1);
266 *M = Matrix_Alloc(C->Dimension+1, C->Dimension-C->NbBid+1);
267 for (int i = 0; i < C->Dimension+1; ++i)
268 Vector_Copy(L->p[i]+C->NbBid, (*M)->p[i], C->Dimension-C->NbBid+1);
270 Matrix *Linv = Matrix_Alloc(C->Dimension+1, C->Dimension+1);
271 int ok = Matrix_Inverse(L, Linv);
272 assert(ok);
273 Matrix_Free(L);
275 *Minv = Matrix_Alloc(C->Dimension-C->NbBid+1, C->Dimension+1);
276 for (int i = C->NbBid; i < C->Dimension+1; ++i)
277 Vector_AntiScale(Linv->p[i], (*Minv)->p[i-C->NbBid],
278 Linv->p[C->Dimension][C->Dimension], C->Dimension+1);
279 Matrix_Free(Linv);
282 static skewed_gen_fun *series(Polyhedron *P, Polyhedron* C,
283 barvinok_options *options)
285 Polyhedron *C1, *C2;
286 gen_fun *gf;
287 Matrix *inv = NULL;
288 Matrix *eq = NULL;
289 Matrix *div = NULL;
290 Polyhedron *PT = P;
292 /* Compute true context */
293 C1 = Polyhedron_Project(P, C->Dimension);
294 C2 = DomainIntersection(C, C1, options->MaxRays);
295 Polyhedron_Free(C1);
297 POL_ENSURE_VERTICES(C2);
298 if (C2->NbBid != 0) {
299 Polyhedron *T;
300 Matrix *M, *Minv, *M2;
301 Matrix *CP;
302 if (C2->NbEq || P->NbEq) {
303 /* We remove all equalities to be sure all lines are unit vectors */
304 Polyhedron *CT = C2;
305 remove_all_equalities(&PT, &CT, &CP, NULL, C2->Dimension,
306 options->MaxRays);
307 if (CT != C2) {
308 Polyhedron_Free(C2);
309 C2 = CT;
311 if (CP) {
312 inv = left_inverse(CP, &eq);
313 Matrix_Free(CP);
315 int d = 0;
316 Value tmp;
317 value_init(tmp);
318 div = Matrix_Alloc(inv->NbRows-1, inv->NbColumns+1);
319 for (int i = 0; i < inv->NbRows-1; ++i) {
320 Vector_Gcd(inv->p[i], inv->NbColumns, &tmp);
321 if (mpz_divisible_p(tmp,
322 inv->p[inv->NbRows-1][inv->NbColumns-1]))
323 continue;
324 Vector_Copy(inv->p[i], div->p[d], inv->NbColumns);
325 value_assign(div->p[d][inv->NbColumns],
326 inv->p[inv->NbRows-1][inv->NbColumns-1]);
327 ++d;
329 value_clear(tmp);
331 if (!d) {
332 Matrix_Free(div);
333 div = NULL;
334 } else
335 div->NbRows = d;
338 POL_ENSURE_VERTICES(C2);
340 if (C2->NbBid) {
341 Matrix *M, *Minv;
342 remove_lines(C2, &M, &Minv);
343 apply_transformation(&PT, &C2, PT != P, C2 != C, M, Minv, &inv,
344 options);
347 POL_ENSURE_VERTICES(C2);
348 if (!Polyhedron_has_revlex_positive_rays(C2, C2->Dimension)) {
349 Polyhedron *T;
350 Matrix *Constraints;
351 Matrix *H, *Q, *U;
352 Constraints = Matrix_Alloc(C2->NbConstraints, C2->Dimension+1);
353 for (int i = 0; i < C2->NbConstraints; ++i)
354 Vector_Copy(C2->Constraint[i]+1, Constraints->p[i], C2->Dimension);
355 left_hermite(Constraints, &H, &Q, &U);
356 Matrix_Free(Constraints);
357 /* flip rows of Q */
358 for (int i = 0; i < C2->Dimension/2; ++i)
359 Vector_Exchange(Q->p[i], Q->p[C2->Dimension-1-i], C2->Dimension);
360 Matrix_Free(H);
361 Matrix_Free(U);
362 Matrix *M = Matrix_Alloc(C2->Dimension+1, C2->Dimension+1);
363 U = Matrix_Copy(Q);
364 int ok = Matrix_Inverse(U, M);
365 assert(ok);
366 Matrix_Free(U);
368 apply_transformation(&PT, &C2, PT != P, C2 != C, M, Q, &inv, options);
370 gf = barvinok_series_with_options(PT, C2, options);
371 Polyhedron_Free(C2);
372 if (PT != P)
373 Polyhedron_Free(PT);
374 return new skewed_gen_fun(gf, inv, eq, div);
377 int main(int argc, char **argv)
379 Polyhedron *A, *C;
380 Matrix *M;
381 evalue *EP = NULL;
382 skewed_gen_fun *gf = NULL;
383 const char **param_name;
384 int print_solution = 1;
385 int result = 0;
386 struct enumerate_options *options = enumerate_options_new_with_defaults();
388 argc = enumerate_options_parse(options, argc, argv, ISL_ARG_ALL);
390 M = Matrix_Read();
391 assert(M);
392 A = Constraints2Polyhedron(M, options->verify->barvinok->MaxRays);
393 Matrix_Free(M);
394 M = Matrix_Read();
395 assert(M);
396 C = Constraints2Polyhedron(M, options->verify->barvinok->MaxRays);
397 Matrix_Free(M);
398 assert(A->Dimension >= C->Dimension);
399 param_name = Read_ParamNames(stdin, C->Dimension);
401 if (options->verify->verify) {
402 verify_options_set_range(options->verify, A->Dimension);
403 if (!options->verify->barvinok->verbose)
404 print_solution = 0;
407 if (print_solution && options->verify->barvinok->verbose) {
408 Polyhedron_Print(stdout, P_VALUE_FMT, A);
409 Polyhedron_Print(stdout, P_VALUE_FMT, C);
412 if (options->series) {
413 gf = series(A, C, options->verify->barvinok);
414 if (print_solution) {
415 gf->print(cout, C->Dimension, param_name);
416 puts("");
418 if (options->function) {
419 EP = *gf;
420 if (print_solution)
421 print_evalue(stdout, EP, param_name);
423 } else {
424 EP = barvinok_enumerate_with_options(A, C, options->verify->barvinok);
425 assert(EP);
426 if (evalue_convert(EP, options->convert, options->verify->barvinok->verbose,
427 C->Dimension, param_name))
428 print_solution = 0;
429 if (options->size)
430 printf("\nSize: %zd\n", evalue_size(EP));
431 if (print_solution)
432 print_evalue(stdout, EP, param_name);
435 if (options->verify->verify) {
436 options->verify->params = param_name;
437 result = verify(A, C, EP, gf, options);
440 if (gf)
441 delete gf;
442 if (EP)
443 evalue_free(EP);
445 if (options->verify->barvinok->print_stats)
446 barvinok_stats_print(options->verify->barvinok->stats, stdout);
448 Free_ParamNames(param_name, C->Dimension);
449 Polyhedron_Free(A);
450 Polyhedron_Free(C);
451 enumerate_options_free(options);
452 return result;