evalue.c: reorder_terms: fix typo
[barvinok.git] / barvinok_enumerate.cc
blob90ebae13c41e1f4f88c1bfed43f0181b0f6e76e5
1 #include <unistd.h>
2 #include <stdlib.h>
3 #include <barvinok/evalue.h>
4 #include <barvinok/util.h>
5 #include <barvinok/barvinok.h>
6 #include "argp.h"
7 #include "progname.h"
8 #include "verify.h"
9 #include "verif_ehrhart.h"
10 #include "remove_equalities.h"
11 #include "evalue_convert.h"
12 #include "conversion.h"
14 #undef CS /* for Solaris 10 */
16 using std::cout;
17 using std::endl;
19 /* The input of this example program is the same as that of testehrhart
20 * in the PolyLib distribution, i.e., a polytope in combined
21 * data and parameter space, a context polytope in parameter space
22 * and (optionally) the names of the parameters.
23 * Both polytopes are in PolyLib notation.
26 #define PRINT_STATS (BV_OPT_LAST+1)
28 struct argp_option argp_options[] = {
29 { "size", 'S' },
30 { "series", 's', 0, 0, "compute rational generating function" },
31 { "explicit", 'e', 0, 0, "convert rgf to psp" },
32 { "verbose", 'v' },
33 { "print-stats", PRINT_STATS, 0, 0 },
34 { 0 }
37 struct arguments {
38 int size;
39 int series;
40 int function;
41 int verbose;
42 int print_stats;
43 struct verify_options verify;
44 struct convert_options convert;
47 static error_t parse_opt(int key, char *arg, struct argp_state *state)
49 struct arguments *options = (struct arguments*) state->input;
51 switch (key) {
52 case ARGP_KEY_INIT:
53 state->child_inputs[0] = options->verify.barvinok;
54 state->child_inputs[1] = &options->verify;
55 state->child_inputs[2] = &options->convert;
56 options->size = 0;
57 options->series = 0;
58 options->function = 0;
59 options->verbose = 0;
60 options->print_stats = 0;
61 break;
62 case PRINT_STATS:
63 options->print_stats = 1;
64 break;
65 case 'S':
66 options->size = 1;
67 break;
68 case 'e':
69 options->function = 1;
70 /* fall through */
71 case 's':
72 options->series = 1;
73 break;
74 case 'v':
75 options->verbose = 1;
76 break;
77 default:
78 return ARGP_ERR_UNKNOWN;
80 return 0;
83 struct skewed_gen_fun {
84 gen_fun *gf;
85 /* maps original space to space in which gf is defined */
86 Matrix *T;
87 /* equalities in the original space that need to be satisfied for
88 * gf to be valid
90 Matrix *eq;
91 /* divisibilities in the original space that need to be satisfied for
92 * gf to be valid
94 Matrix *div;
96 skewed_gen_fun(gen_fun *gf, Matrix *T, Matrix *eq, Matrix *div) :
97 gf(gf), T(T), eq(eq), div(div) {}
98 ~skewed_gen_fun() {
99 if (T)
100 Matrix_Free(T);
101 if (eq)
102 Matrix_Free(eq);
103 if (div)
104 Matrix_Free(div);
105 delete gf;
108 void print(std::ostream& os, unsigned int nparam, char **param_name) const;
109 operator evalue *() const {
110 assert(T == NULL && eq == NULL); /* other cases not supported for now */
111 return *gf;
113 void coefficient(Value* params, Value* c, barvinok_options *options) const;
116 void skewed_gen_fun::print(std::ostream& os, unsigned int nparam,
117 char **param_name) const
119 mat_ZZ m;
120 if (T) {
121 os << "T:" << endl;
122 matrix2zz(T, m, T->NbRows, T->NbColumns);
123 os << m << endl;
125 if (eq) {
126 os << "eq:" << endl;
127 matrix2zz(eq, m, eq->NbRows, eq->NbColumns);
128 os << m << endl;
130 if (div) {
131 os << "div:" << endl;
132 matrix2zz(div, m, div->NbRows, div->NbColumns);
133 os << m << endl;
135 gf->print(os, nparam, param_name);
138 void skewed_gen_fun::coefficient(Value* params, Value* c,
139 barvinok_options *options) const
141 if (eq) {
142 for (int i = 0; i < eq->NbRows; ++i) {
143 Inner_Product(eq->p[i]+1, params, eq->NbColumns-2, eq->p[i]);
144 if (value_notzero_p(eq->p[i][0])) {
145 value_set_si(*c, 0);
146 return;
150 if (div) {
151 Value tmp;
152 value_init(tmp);
153 for (int i = 0; i < div->NbRows; ++i) {
154 Inner_Product(div->p[i], params, div->NbColumns-1, &tmp);
155 if (!mpz_divisible_p(tmp, div->p[i][div->NbColumns-1])) {
156 value_set_si(*c, 0);
157 return;
160 value_clear(tmp);
163 ZZ coeff;
164 if (!T)
165 coeff = gf->coefficient(params, options);
166 else {
167 Vector *p2 = Vector_Alloc(T->NbRows);
168 Matrix_Vector_Product(T, params, p2->p);
169 if (value_notone_p(p2->p[T->NbRows-1]))
170 Vector_AntiScale(p2->p, p2->p, p2->p[T->NbRows-1], T->NbRows);
171 coeff = gf->coefficient(p2->p, options);
172 Vector_Free(p2);
175 zz2value(coeff, *c);
178 static int check_series(Polyhedron *S, Polyhedron *CS, skewed_gen_fun *gf,
179 int nparam, int pos, Value *z, verify_options *options)
181 int k;
182 Value c, tmp;
183 Value LB, UB;
185 value_init(c);
186 value_init(tmp);
187 value_init(LB);
188 value_init(UB);
190 if (pos == nparam) {
191 /* Computes the coefficient */
192 gf->coefficient(&z[S->Dimension-nparam+1], &c, options->barvinok);
194 /* if c=0 we may be out of context. */
195 /* scanning is useless in this case*/
197 if (options->print_all) {
198 printf("EP( ");
199 value_print(stdout,VALUE_FMT,z[S->Dimension-nparam+1]);
200 for(k=S->Dimension-nparam+2;k<=S->Dimension;++k) {
201 printf(", ");
202 value_print(stdout,VALUE_FMT,z[k]);
204 printf(" ) = ");
205 value_print(stdout,VALUE_FMT,c);
206 printf(" ");
209 /* Manually count the number of points */
210 count_points(1,S,z,&tmp);
211 if (options->print_all) {
212 printf(", count = ");
213 value_print(stdout, P_VALUE_FMT, tmp);
214 printf(". ");
217 if (value_ne(tmp,c)) {
218 printf("\n");
219 fflush(stdout);
220 fprintf(stderr,"Error !\n");
221 fprintf(stderr,"EP( ");
222 value_print(stderr,VALUE_FMT,z[S->Dimension-nparam+1]);
223 for (k=S->Dimension-nparam+2;k<=S->Dimension;++k) {
224 fprintf(stderr,", ");
225 value_print(stderr,VALUE_FMT,z[k]);
227 fprintf(stderr," ) should be ");
228 value_print(stderr,VALUE_FMT,tmp);
229 fprintf(stderr,", while EP eval gives ");
230 value_print(stderr,VALUE_FMT,c);
231 fprintf(stderr,".\n");
232 if (!options->continue_on_error) {
233 value_clear(c); value_clear(tmp);
234 return 0;
236 } else if (options->print_all)
237 printf("OK.\n");
238 } else {
239 int ok =
240 !(lower_upper_bounds(1+pos, CS, &z[S->Dimension-nparam], &LB, &UB));
241 assert(ok);
242 for (value_assign(tmp,LB); value_le(tmp,UB); value_increment(tmp,tmp)) {
243 if (!options->print_all) {
244 k = VALUE_TO_INT(tmp);
245 if(!pos && !(k % options->st)) {
246 printf("o");
247 fflush(stdout);
250 value_assign(z[pos+S->Dimension-nparam+1],tmp);
251 if (!check_series(S, CS->next, gf, nparam, pos+1, z, options)) {
252 value_clear(c); value_clear(tmp);
253 value_clear(LB);
254 value_clear(UB);
255 return(0);
258 value_set_si(z[pos+S->Dimension-nparam+1],0);
261 value_clear(c);
262 value_clear(tmp);
263 value_clear(LB);
264 value_clear(UB);
265 return 1;
268 static int verify(Polyhedron *P, Polyhedron *C, evalue *EP, skewed_gen_fun *gf,
269 arguments *options)
271 Polyhedron *CS, *S;
272 Vector *p;
273 int result = 0;
275 CS = check_poly_context_scan(P, &C, C->Dimension, &options->verify);
277 p = Vector_Alloc(P->Dimension+2);
278 value_set_si(p->p[P->Dimension+1], 1);
280 /* S = scanning list of polyhedra */
281 S = Polyhedron_Scan(P, C, options->verify.barvinok->MaxRays);
283 check_poly_init(C, &options->verify);
285 /******* CHECK NOW *********/
286 if (S) {
287 if (!options->series || options->function) {
288 if (!check_poly_EP(S, CS, EP, 0, C->Dimension, 0, p->p,
289 &options->verify))
290 result = -1;
291 } else {
292 if (!check_series(S, CS, gf, C->Dimension, 0, p->p, &options->verify))
293 result = -1;
295 Domain_Free(S);
298 if (result == -1)
299 fprintf(stderr,"Check failed !\n");
301 if (!options->verify.print_all)
302 printf( "\n" );
304 Vector_Free(p);
305 if (CS) {
306 Domain_Free(CS);
307 Domain_Free(C);
310 return result;
313 /* frees M and Minv */
314 static void apply_transformation(Polyhedron **P, Polyhedron **C,
315 bool free_P, bool free_C,
316 Matrix *M, Matrix *Minv, Matrix **inv,
317 barvinok_options *options)
319 Polyhedron *T;
320 Matrix *M2;
322 M2 = align_matrix(M, (*P)->Dimension + 1);
323 T = *P;
324 *P = Polyhedron_Preimage(*P, M2, options->MaxRays);
325 if (free_P)
326 Polyhedron_Free(T);
327 Matrix_Free(M2);
329 T = *C;
330 *C = Polyhedron_Preimage(*C, M, options->MaxRays);
331 if (free_C)
332 Polyhedron_Free(T);
334 Matrix_Free(M);
336 if (*inv) {
337 Matrix *T = *inv;
338 *inv = Matrix_Alloc(Minv->NbRows, T->NbColumns);
339 Matrix_Product(Minv, T, *inv);
340 Matrix_Free(T);
341 Matrix_Free(Minv);
342 } else
343 *inv = Minv;
346 /* Since we have "compressed" the parameters (in case there were
347 * any equalities), the result is independent of the coordinates in the
348 * coordinate subspace spanned by the lines. We can therefore assume
349 * these coordinates are zero and compute the inverse image of the map
350 * from a lower dimensional space that adds zeros in the appropriate
351 * places.
353 static void remove_lines(Polyhedron *C, Matrix **M, Matrix **Minv)
355 Matrix *L = Matrix_Alloc(C->Dimension+1, C->Dimension+1);
356 for (int r = 0; r < C->NbBid; ++r)
357 Vector_Copy(C->Ray[r]+1, L->p[r], C->Dimension);
358 unimodular_complete(L, C->NbBid);
359 assert(value_one_p(L->p[C->Dimension][C->Dimension]));
360 assert(First_Non_Zero(L->p[C->Dimension], C->Dimension) == -1);
361 Matrix_Transposition(L);
362 assert(First_Non_Zero(L->p[C->Dimension], C->Dimension) == -1);
364 *M = Matrix_Alloc(C->Dimension+1, C->Dimension-C->NbBid+1);
365 for (int i = 0; i < C->Dimension+1; ++i)
366 Vector_Copy(L->p[i]+C->NbBid, (*M)->p[i], C->Dimension-C->NbBid+1);
368 Matrix *Linv = Matrix_Alloc(C->Dimension+1, C->Dimension+1);
369 int ok = Matrix_Inverse(L, Linv);
370 assert(ok);
371 Matrix_Free(L);
373 *Minv = Matrix_Alloc(C->Dimension-C->NbBid+1, C->Dimension+1);
374 for (int i = C->NbBid; i < C->Dimension+1; ++i)
375 Vector_AntiScale(Linv->p[i], (*Minv)->p[i-C->NbBid],
376 Linv->p[C->Dimension][C->Dimension], C->Dimension+1);
377 Matrix_Free(Linv);
380 static skewed_gen_fun *series(Polyhedron *P, Polyhedron* C,
381 barvinok_options *options)
383 Polyhedron *C1, *C2;
384 gen_fun *gf;
385 Matrix *inv = NULL;
386 Matrix *eq = NULL;
387 Matrix *div = NULL;
388 Polyhedron *PT = P;
390 /* Compute true context */
391 C1 = Polyhedron_Project(P, C->Dimension);
392 C2 = DomainIntersection(C, C1, options->MaxRays);
393 Polyhedron_Free(C1);
395 POL_ENSURE_VERTICES(C2);
396 if (C2->NbBid != 0) {
397 Polyhedron *T;
398 Matrix *M, *Minv, *M2;
399 Matrix *CP;
400 if (C2->NbEq || P->NbEq) {
401 /* We remove all equalities to be sure all lines are unit vectors */
402 Polyhedron *CT = C2;
403 remove_all_equalities(&PT, &CT, &CP, NULL, C2->Dimension,
404 options->MaxRays);
405 if (CT != C2) {
406 Polyhedron_Free(C2);
407 C2 = CT;
409 if (CP) {
410 inv = left_inverse(CP, &eq);
411 Matrix_Free(CP);
413 int d = 0;
414 Value tmp;
415 value_init(tmp);
416 div = Matrix_Alloc(inv->NbRows-1, inv->NbColumns+1);
417 for (int i = 0; i < inv->NbRows-1; ++i) {
418 Vector_Gcd(inv->p[i], inv->NbColumns, &tmp);
419 if (mpz_divisible_p(tmp,
420 inv->p[inv->NbRows-1][inv->NbColumns-1]))
421 continue;
422 Vector_Copy(inv->p[i], div->p[d], inv->NbColumns);
423 value_assign(div->p[d][inv->NbColumns],
424 inv->p[inv->NbRows-1][inv->NbColumns-1]);
425 ++d;
427 value_clear(tmp);
429 if (!d) {
430 Matrix_Free(div);
431 div = NULL;
432 } else
433 div->NbRows = d;
436 POL_ENSURE_VERTICES(C2);
438 if (C2->NbBid) {
439 Matrix *M, *Minv;
440 remove_lines(C2, &M, &Minv);
441 apply_transformation(&PT, &C2, PT != P, C2 != C, M, Minv, &inv,
442 options);
445 POL_ENSURE_VERTICES(C2);
446 if (!Polyhedron_has_revlex_positive_rays(C2, C2->Dimension)) {
447 Polyhedron *T;
448 Matrix *Constraints;
449 Matrix *H, *Q, *U;
450 Constraints = Matrix_Alloc(C2->NbConstraints, C2->Dimension+1);
451 for (int i = 0; i < C2->NbConstraints; ++i)
452 Vector_Copy(C2->Constraint[i]+1, Constraints->p[i], C2->Dimension);
453 left_hermite(Constraints, &H, &Q, &U);
454 Matrix_Free(Constraints);
455 /* flip rows of Q */
456 for (int i = 0; i < C2->Dimension/2; ++i)
457 Vector_Exchange(Q->p[i], Q->p[C2->Dimension-1-i], C2->Dimension);
458 Matrix_Free(H);
459 Matrix_Free(U);
460 Matrix *M = Matrix_Alloc(C2->Dimension+1, C2->Dimension+1);
461 U = Matrix_Copy(Q);
462 int ok = Matrix_Inverse(U, M);
463 assert(ok);
464 Matrix_Free(U);
466 apply_transformation(&PT, &C2, PT != P, C2 != C, M, Q, &inv, options);
468 gf = barvinok_series_with_options(PT, C2, options);
469 Polyhedron_Free(C2);
470 if (PT != P)
471 Polyhedron_Free(PT);
472 return new skewed_gen_fun(gf, inv, eq, div);
475 int main(int argc, char **argv)
477 Polyhedron *A, *C;
478 Matrix *M;
479 evalue *EP = NULL;
480 skewed_gen_fun *gf = NULL;
481 char **param_name;
482 int print_solution = 1;
483 int result = 0;
484 struct arguments options;
485 static struct argp_child argp_children[] = {
486 { &barvinok_argp, 0, 0, 0 },
487 { &verify_argp, 0, "verification", BV_GRP_LAST+1 },
488 { &convert_argp, 0, "output conversion", BV_GRP_LAST+2 },
489 { 0 }
491 static struct argp argp = { argp_options, parse_opt, 0, 0, argp_children };
492 struct barvinok_options *bv_options = barvinok_options_new_with_defaults();
494 options.verify.barvinok = bv_options;
495 set_program_name(argv[0]);
496 argp_parse(&argp, argc, argv, 0, 0, &options);
498 M = Matrix_Read();
499 A = Constraints2Polyhedron(M, bv_options->MaxRays);
500 Matrix_Free(M);
501 M = Matrix_Read();
502 C = Constraints2Polyhedron(M, bv_options->MaxRays);
503 Matrix_Free(M);
504 param_name = Read_ParamNames(stdin, C->Dimension);
506 if (options.verify.verify) {
507 verify_options_set_range(&options.verify, A->Dimension);
508 if (!options.verbose)
509 print_solution = 0;
512 if (print_solution && options.verbose) {
513 Polyhedron_Print(stdout, P_VALUE_FMT, A);
514 Polyhedron_Print(stdout, P_VALUE_FMT, C);
517 if (options.series) {
518 gf = series(A, C, bv_options);
519 if (print_solution) {
520 gf->print(cout, C->Dimension, param_name);
521 puts("");
523 if (options.function) {
524 EP = *gf;
525 if (print_solution)
526 print_evalue(stdout, EP, param_name);
528 } else {
529 EP = barvinok_enumerate_with_options(A, C, bv_options);
530 if (evalue_convert(EP, &options.convert, options.verbose, C->Dimension,
531 param_name))
532 print_solution = 0;
533 if (options.size)
534 printf("\nSize: %d\n", evalue_size(EP));
535 if (print_solution)
536 print_evalue(stdout, EP, param_name);
539 if (options.verify.verify) {
540 options.verify.params = param_name;
541 result = verify(A, C, EP, gf, &options);
544 if (gf)
545 delete gf;
546 if (EP) {
547 free_evalue_refs(EP);
548 free(EP);
551 if (options.print_stats)
552 barvinok_stats_print(options.verify.barvinok->stats, stdout);
554 Free_ParamNames(param_name, C->Dimension);
555 Polyhedron_Free(A);
556 Polyhedron_Free(C);
557 barvinok_options_free(bv_options);
558 return result;