volume.c: drop redundant arguments to volume_simplex
[barvinok.git] / barvinok_enumerate.cc
blob4b99fcf0251fe8ea6b94aa1161578e764e1c78c5
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 "fdstream.h"
7 #include "argp.h"
8 #include "verify.h"
9 #include "verif_ehrhart.h"
10 #include "remove_equalities.h"
11 #include "evalue_convert.h"
13 #undef CS /* for Solaris 10 */
15 /* The input of this example program is the same as that of testehrhart
16 * in the PolyLib distribution, i.e., a polytope in combined
17 * data and parameter space, a context polytope in parameter space
18 * and (optionally) the names of the parameters.
19 * Both polytopes are in PolyLib notation.
22 #define PRINT_STATS (BV_OPT_LAST+1)
24 struct argp_option argp_options[] = {
25 { "size", 'S' },
26 { "series", 's', 0, 0, "compute rational generating function" },
27 { "explicit", 'e', 0, 0, "convert rgf to psp" },
28 { "verbose", 'v' },
29 { "print-stats", PRINT_STATS, 0, 0 },
30 { 0 }
33 struct arguments {
34 int size;
35 int series;
36 int function;
37 int verbose;
38 int print_stats;
39 struct verify_options verify;
40 struct convert_options convert;
43 static error_t parse_opt(int key, char *arg, struct argp_state *state)
45 struct arguments *options = (struct arguments*) state->input;
47 switch (key) {
48 case ARGP_KEY_INIT:
49 state->child_inputs[0] = options->verify.barvinok;
50 state->child_inputs[1] = &options->verify;
51 state->child_inputs[2] = &options->convert;
52 options->size = 0;
53 options->series = 0;
54 options->function = 0;
55 options->verbose = 0;
56 options->print_stats = 0;
57 break;
58 case PRINT_STATS:
59 options->print_stats = 1;
60 break;
61 case 'S':
62 options->size = 1;
63 break;
64 case 'e':
65 options->function = 1;
66 /* fall through */
67 case 's':
68 options->series = 1;
69 break;
70 case 'v':
71 options->verbose = 1;
72 break;
73 default:
74 return ARGP_ERR_UNKNOWN;
76 return 0;
79 struct skewed_gen_fun {
80 gen_fun *gf;
81 /* maps original space to space in which gf is defined */
82 Matrix *T;
83 /* equalities in the original space that need to be satisfied for
84 * gf to be valid
86 Matrix *eq;
87 /* divisibilities in the original space that need to be satisfied for
88 * gf to be valid
90 Matrix *div;
92 skewed_gen_fun(gen_fun *gf, Matrix *T, Matrix *eq, Matrix *div) :
93 gf(gf), T(T), eq(eq), div(div) {}
94 ~skewed_gen_fun() {
95 if (T)
96 Matrix_Free(T);
97 if (eq)
98 Matrix_Free(eq);
99 if (div)
100 Matrix_Free(div);
101 delete gf;
104 void print(FILE *out, unsigned int nparam, char **param_name) const;
105 operator evalue *() const {
106 assert(T == NULL && eq == NULL); /* other cases not supported for now */
107 return *gf;
109 void coefficient(Value* params, Value* c, barvinok_options *options) const;
112 void skewed_gen_fun::print(FILE *out, unsigned int nparam,
113 char **param_name) const
115 fdostream os(dup(fileno(out)));
116 if (T) {
117 fprintf(out, "T:\n");
118 Matrix_Print(out, P_VALUE_FMT, T);
120 if (eq) {
121 fprintf(out, "eq:\n");
122 Matrix_Print(out, P_VALUE_FMT, eq);
124 if (div) {
125 fprintf(out, "div:\n");
126 Matrix_Print(out, P_VALUE_FMT, div);
128 gf->print(os, nparam, param_name);
131 void skewed_gen_fun::coefficient(Value* params, Value* c,
132 barvinok_options *options) const
134 if (eq) {
135 for (int i = 0; i < eq->NbRows; ++i) {
136 Inner_Product(eq->p[i]+1, params, eq->NbColumns-2, eq->p[i]);
137 if (value_notzero_p(eq->p[i][0])) {
138 value_set_si(*c, 0);
139 return;
143 if (div) {
144 Value tmp;
145 value_init(tmp);
146 for (int i = 0; i < div->NbRows; ++i) {
147 Inner_Product(div->p[i], params, div->NbColumns-1, &tmp);
148 if (!mpz_divisible_p(tmp, div->p[i][div->NbColumns-1])) {
149 value_set_si(*c, 0);
150 return;
153 value_clear(tmp);
156 ZZ coeff;
157 if (!T)
158 coeff = gf->coefficient(params, options);
159 else {
160 Vector *p2 = Vector_Alloc(T->NbRows);
161 Matrix_Vector_Product(T, params, p2->p);
162 if (value_notone_p(p2->p[T->NbRows-1]))
163 Vector_AntiScale(p2->p, p2->p, p2->p[T->NbRows-1], T->NbRows);
164 coeff = gf->coefficient(p2->p, options);
165 Vector_Free(p2);
168 zz2value(coeff, *c);
171 static int check_series(Polyhedron *S, Polyhedron *CS, skewed_gen_fun *gf,
172 int nparam, int pos, Value *z, verify_options *options)
174 int k;
175 Value c, tmp;
176 Value LB, UB;
178 value_init(c);
179 value_init(tmp);
180 value_init(LB);
181 value_init(UB);
183 if (pos == nparam) {
184 /* Computes the coefficient */
185 gf->coefficient(&z[S->Dimension-nparam+1], &c, options->barvinok);
187 /* if c=0 we may be out of context. */
188 /* scanning is useless in this case*/
190 if (options->print_all) {
191 printf("EP( ");
192 value_print(stdout,VALUE_FMT,z[S->Dimension-nparam+1]);
193 for(k=S->Dimension-nparam+2;k<=S->Dimension;++k) {
194 printf(", ");
195 value_print(stdout,VALUE_FMT,z[k]);
197 printf(" ) = ");
198 value_print(stdout,VALUE_FMT,c);
199 printf(" ");
202 /* Manually count the number of points */
203 count_points(1,S,z,&tmp);
204 if (options->print_all) {
205 printf(", count = ");
206 value_print(stdout, P_VALUE_FMT, tmp);
207 printf(". ");
210 if (value_ne(tmp,c)) {
211 printf("\n");
212 fflush(stdout);
213 fprintf(stderr,"Error !\n");
214 fprintf(stderr,"EP( ");
215 value_print(stderr,VALUE_FMT,z[S->Dimension-nparam+1]);
216 for (k=S->Dimension-nparam+2;k<=S->Dimension;++k) {
217 fprintf(stderr,", ");
218 value_print(stderr,VALUE_FMT,z[k]);
220 fprintf(stderr," ) should be ");
221 value_print(stderr,VALUE_FMT,tmp);
222 fprintf(stderr,", while EP eval gives ");
223 value_print(stderr,VALUE_FMT,c);
224 fprintf(stderr,".\n");
225 if (!options->continue_on_error) {
226 value_clear(c); value_clear(tmp);
227 return 0;
229 } else if (options->print_all)
230 printf("OK.\n");
231 } else {
232 int ok =
233 !(lower_upper_bounds(1+pos, CS, &z[S->Dimension-nparam], &LB, &UB));
234 assert(ok);
235 for (value_assign(tmp,LB); value_le(tmp,UB); value_increment(tmp,tmp)) {
236 if (!options->print_all) {
237 k = VALUE_TO_INT(tmp);
238 if(!pos && !(k % options->st)) {
239 printf("o");
240 fflush(stdout);
243 value_assign(z[pos+S->Dimension-nparam+1],tmp);
244 if (!check_series(S, CS->next, gf, nparam, pos+1, z, options)) {
245 value_clear(c); value_clear(tmp);
246 value_clear(LB);
247 value_clear(UB);
248 return(0);
251 value_set_si(z[pos+S->Dimension-nparam+1],0);
254 value_clear(c);
255 value_clear(tmp);
256 value_clear(LB);
257 value_clear(UB);
258 return 1;
261 static int verify(Polyhedron *P, Polyhedron *C, evalue *EP, skewed_gen_fun *gf,
262 arguments *options)
264 Polyhedron *CS, *S;
265 Vector *p;
266 int result = 0;
268 CS = check_poly_context_scan(P, &C, C->Dimension, &options->verify);
270 p = Vector_Alloc(P->Dimension+2);
271 value_set_si(p->p[P->Dimension+1], 1);
273 /* S = scanning list of polyhedra */
274 S = Polyhedron_Scan(P, C, options->verify.barvinok->MaxRays);
276 check_poly_init(C, &options->verify);
278 /******* CHECK NOW *********/
279 if (S) {
280 if (!options->series || options->function) {
281 if (!check_poly_EP(S, CS, EP, 0, C->Dimension, 0, p->p,
282 &options->verify))
283 result = -1;
284 } else {
285 if (!check_series(S, CS, gf, C->Dimension, 0, p->p, &options->verify))
286 result = -1;
288 Domain_Free(S);
291 if (result == -1)
292 fprintf(stderr,"Check failed !\n");
294 if (!options->verify.print_all)
295 printf( "\n" );
297 Vector_Free(p);
298 if (CS) {
299 Domain_Free(CS);
300 Domain_Free(C);
303 return result;
306 static void unimodular_complete(Matrix *M, int row)
308 Matrix *H, *Q, *U;
309 left_hermite(M, &H, &Q, &U);
310 Matrix_Free(H);
311 Matrix_Free(U);
312 for (int r = row; r < M->NbRows; ++r)
313 Vector_Copy(Q->p[r], M->p[r], M->NbColumns);
314 Matrix_Free(Q);
317 /* frees M and Minv */
318 static void apply_transformation(Polyhedron **P, Polyhedron **C,
319 bool free_P, bool free_C,
320 Matrix *M, Matrix *Minv, Matrix **inv,
321 barvinok_options *options)
323 Polyhedron *T;
324 Matrix *M2;
326 M2 = align_matrix(M, (*P)->Dimension + 1);
327 T = *P;
328 *P = Polyhedron_Preimage(*P, M2, options->MaxRays);
329 if (free_P)
330 Polyhedron_Free(T);
331 Matrix_Free(M2);
333 T = *C;
334 *C = Polyhedron_Preimage(*C, M, options->MaxRays);
335 if (free_C)
336 Polyhedron_Free(T);
338 Matrix_Free(M);
340 if (*inv) {
341 Matrix *T = *inv;
342 *inv = Matrix_Alloc(Minv->NbRows, T->NbColumns);
343 Matrix_Product(Minv, T, *inv);
344 Matrix_Free(T);
345 Matrix_Free(Minv);
346 } else
347 *inv = Minv;
350 static skewed_gen_fun *series(Polyhedron *P, Polyhedron* C,
351 barvinok_options *options)
353 Polyhedron *C1, *C2;
354 gen_fun *gf;
355 Matrix *inv = NULL;
356 Matrix *eq = NULL;
357 Matrix *div = NULL;
358 Polyhedron *PT = P;
360 /* Compute true context */
361 C1 = Polyhedron_Project(P, C->Dimension);
362 C2 = DomainIntersection(C, C1, options->MaxRays);
363 Polyhedron_Free(C1);
365 POL_ENSURE_VERTICES(C2);
366 if (C2->NbBid != 0) {
367 Polyhedron *T;
368 Matrix *M, *Minv, *M2;
369 Matrix *CP;
370 if (C2->NbEq || P->NbEq) {
371 /* We remove all equalities to be sure all lines are unit vectors */
372 Polyhedron *CT = C2;
373 remove_all_equalities(&PT, &CT, &CP, NULL, C2->Dimension,
374 options->MaxRays);
375 if (CT != C2) {
376 Polyhedron_Free(C2);
377 C2 = CT;
379 if (CP) {
380 inv = left_inverse(CP, &eq);
381 Matrix_Free(CP);
383 int d = 0;
384 Value tmp;
385 value_init(tmp);
386 div = Matrix_Alloc(inv->NbRows-1, inv->NbColumns+1);
387 for (int i = 0; i < inv->NbRows-1; ++i) {
388 Vector_Gcd(inv->p[i], inv->NbColumns, &tmp);
389 if (mpz_divisible_p(tmp,
390 inv->p[inv->NbRows-1][inv->NbColumns-1]))
391 continue;
392 Vector_Copy(inv->p[i], div->p[d], inv->NbColumns);
393 value_assign(div->p[d][inv->NbColumns],
394 inv->p[inv->NbRows-1][inv->NbColumns-1]);
395 ++d;
397 value_clear(tmp);
399 if (!d) {
400 Matrix_Free(div);
401 div = NULL;
402 } else
403 div->NbRows = d;
406 POL_ENSURE_VERTICES(C2);
408 /* Since we have "compressed" the parameters (in case there were
409 * any equalities), the result is independent of the coordinates in the
410 * coordinate subspace spanned by the lines. We can therefore assume
411 * these coordinates are zero and compute the inverse image of the map
412 * from a lower dimensional space that adds zeros in the appropriate
413 * places.
415 M = Matrix_Alloc(C2->Dimension+1, C2->Dimension-C2->NbBid+1);
416 int k = 0;
417 for (int i = 0; i < C2->NbBid; ++i) {
418 int j = First_Non_Zero(C2->Ray[i]+1, C2->Dimension);
419 assert(First_Non_Zero(C2->Ray[i]+1+j+1, C2->Dimension-j-1) == -1);
420 for ( ; k < j; k++)
421 value_set_si(M->p[k+i][k], 1);
423 for ( ; k < C2->Dimension-C2->NbBid+1; k++)
424 value_set_si(M->p[k+C2->NbBid][k], 1);
425 Minv = Transpose(M);
427 apply_transformation(&PT, &C2, PT != P, C2 != C, M, Minv, &inv, options);
429 POL_ENSURE_VERTICES(C2);
430 if (!Polyhedron_has_revlex_positive_rays(C2, C2->Dimension)) {
431 Polyhedron *T;
432 Matrix *Constraints;
433 Matrix *H, *Q, *U;
434 Constraints = Matrix_Alloc(C2->NbConstraints, C2->Dimension+1);
435 for (int i = 0; i < C2->NbConstraints; ++i)
436 Vector_Copy(C2->Constraint[i]+1, Constraints->p[i], C2->Dimension);
437 left_hermite(Constraints, &H, &Q, &U);
438 /* flip rows of Q */
439 for (int i = 0; i < C2->Dimension/2; ++i)
440 Vector_Exchange(Q->p[i], Q->p[C2->Dimension-1-i], C2->Dimension);
441 Matrix_Free(H);
442 Matrix_Free(U);
443 Matrix *M = Matrix_Alloc(C2->Dimension+1, C2->Dimension+1);
444 U = Matrix_Copy(Q);
445 int ok = Matrix_Inverse(U, M);
446 assert(ok);
447 Matrix_Free(U);
449 apply_transformation(&PT, &C2, PT != P, C2 != C, M, Q, &inv, options);
451 gf = barvinok_series_with_options(PT, C2, options);
452 Polyhedron_Free(C2);
453 if (PT != P)
454 Polyhedron_Free(PT);
455 return new skewed_gen_fun(gf, inv, eq, div);
458 int main(int argc, char **argv)
460 Polyhedron *A, *C;
461 Matrix *M;
462 evalue *EP = NULL;
463 skewed_gen_fun *gf = NULL;
464 char **param_name;
465 int print_solution = 1;
466 int result = 0;
467 struct arguments options;
468 static struct argp_child argp_children[] = {
469 { &barvinok_argp, 0, 0, 0 },
470 { &verify_argp, 0, "verification", BV_GRP_LAST+1 },
471 { &convert_argp, 0, "output conversion", BV_GRP_LAST+2 },
472 { 0 }
474 static struct argp argp = { argp_options, parse_opt, 0, 0, argp_children };
475 struct barvinok_options *bv_options = barvinok_options_new_with_defaults();
477 options.verify.barvinok = bv_options;
478 argp_parse(&argp, argc, argv, 0, 0, &options);
480 M = Matrix_Read();
481 A = Constraints2Polyhedron(M, bv_options->MaxRays);
482 Matrix_Free(M);
483 M = Matrix_Read();
484 C = Constraints2Polyhedron(M, bv_options->MaxRays);
485 Matrix_Free(M);
486 param_name = Read_ParamNames(stdin, C->Dimension);
488 if (options.verify.verify) {
489 verify_options_set_range(&options.verify, A->Dimension);
490 if (!options.verbose)
491 print_solution = 0;
494 if (print_solution && options.verbose) {
495 Polyhedron_Print(stdout, P_VALUE_FMT, A);
496 Polyhedron_Print(stdout, P_VALUE_FMT, C);
499 if (options.series) {
500 gf = series(A, C, bv_options);
501 if (print_solution) {
502 gf->print(stdout, C->Dimension, param_name);
503 puts("");
505 if (options.function) {
506 EP = *gf;
507 if (print_solution)
508 print_evalue(stdout, EP, param_name);
510 } else {
511 EP = barvinok_enumerate_with_options(A, C, bv_options);
512 if (evalue_convert(EP, &options.convert, options.verbose, C->Dimension,
513 param_name))
514 print_solution = 0;
515 if (options.size)
516 printf("\nSize: %d\n", evalue_size(EP));
518 if (print_solution)
519 print_evalue(stdout, EP, param_name);
521 if (options.verify.verify) {
522 options.verify.params = param_name;
523 result = verify(A, C, EP, gf, &options);
526 if (gf)
527 delete gf;
528 if (EP) {
529 free_evalue_refs(EP);
530 free(EP);
533 if (options.print_stats)
534 barvinok_stats_print(options.verify.barvinok->stats, stdout);
536 Free_ParamNames(param_name, C->Dimension);
537 Polyhedron_Free(A);
538 Polyhedron_Free(C);
539 barvinok_options_free(bv_options);
540 return result;