1 #include <assert.h>
2 #include <stdlib.h>
3 #include <sstream>
4 #include <NTL/vec_ZZ.h>
5 #include <NTL/mat_ZZ.h>
6 #include <barvinok/NTL_QQ.h>
7 #include <barvinok/polylib.h>
8 #include <barvinok/barvinok.h>
9 #include <barvinok/set.h>
10 #include <barvinok/options.h>
11 #include <barvinok/basis_reduction.h>
12 #include <barvinok/evalue.h>
13 #include <barvinok/util.h>
14 #include "conversion.h"
15 #include "evalue_read.h"
16 #include "dpoly.h"
17 #include "lattice_point.h"
18 #include "counter.h"
19 #include "bernoulli.h"
20 #include "hilbert.h"
21 #include "hull.h"
22 #include "ilp.h"
23 #include "laurent.h"
24 #include "matrix_read.h"
25 #include "remove_equalities.h"
26 #include "config.h"
27 
28 using std::cout;
29 using std::cerr;
30 using std::endl;
31 
32 template <typename T>
set_from_string(T & v,const char * s)33 void set_from_string(T& v, const char *s)
34 {
35     std::istringstream str(s);
36     str >> v;
37 }
38 
matrix_read_from_str(const char * s)39 static Matrix *matrix_read_from_str(const char *s)
40 {
41     std::istringstream str(s);
42     return Matrix_Read(str);
43 }
44 
test_equalities(struct barvinok_options * options)45 static int test_equalities(struct barvinok_options *options)
46 {
47     Matrix *M = matrix_read_from_str(
48 	"11 11\n"
49 	"   0   23    0    0  -10    0    0    0    7  -44   -8 \n"
50 	"   0    0   23    0    5    0    0    0  -15  114   27 \n"
51 	"   0    0    0    1    0    0    0    0    0   -1    2 \n"
52 	"   0    0    0    0    0    1    0    0   -1    8    0 \n"
53 	"   0    0    0    0    0    0    1    0    0   -1    2 \n"
54 	"   0    0    0    0    0    0    0    1    0   -1   -1 \n"
55 	"   1    0    0    0   10    0    0    0   -7   44    8 \n"
56 	"   1    0    0    0   -5    0    0    0   15 -114  -27 \n"
57 	"   1    0    0    0    1    0    0    0    0    0    0 \n"
58 	"   1    0    0    0    0    0    0    0    1   -8    0 \n"
59 	"   1    0    0    0    0    0    0    0    0    1   -2 \n");
60     Polyhedron *P = Constraints2Polyhedron(M, options->MaxRays);
61     Matrix_Free(M);
62     Polyhedron *Q = P;
63     remove_all_equalities(&P, NULL, NULL, NULL, 2, options->MaxRays);
64     assert(P->NbEq == 0);
65     if (P != Q)
66 	Polyhedron_Free(Q);
67     Polyhedron_Free(P);
68     return 0;
69 }
70 
test_evalue_read(struct barvinok_options * options)71 int test_evalue_read(struct barvinok_options *options)
72 {
73     unsigned nvar, nparam;
74     const char **all_vars;
75     evalue *e1, *e2;
76 
77     e1 = evalue_read_from_str("(1 * aa + 2 * a)",
78 			    NULL, &all_vars, &nvar, &nparam, options->MaxRays);
79     Free_ParamNames(all_vars, nvar+nparam);
80     e2 = evalue_read_from_str("(3 * aa)",
81 			    NULL, &all_vars, &nvar, &nparam, options->MaxRays);
82     Free_ParamNames(all_vars, nvar+nparam);
83     assert(!eequal(e1, e2));
84     evalue_free(e1);
85     evalue_free(e2);
86     return 0;
87 }
88 
evalue_check_disjoint(evalue * e)89 static void evalue_check_disjoint(evalue *e)
90 {
91     int i, j;
92 
93     if (!e)
94 	return;
95     if (EVALUE_IS_ZERO(*e))
96 	return;
97     for (i = 0; i < e->x.p->size/2; ++i) {
98 	Polyhedron *A = EVALUE_DOMAIN(e->x.p->arr[2*i]);
99 	for (j = i+1; j < e->x.p->size/2; ++j) {
100 	    Polyhedron *B = EVALUE_DOMAIN(e->x.p->arr[2*j]);
101 	    Polyhedron *I = DomainIntersection(A, B, 0);
102 	    assert(emptyQ(I));
103 	    Polyhedron_Free(I);
104 	}
105     }
106 }
107 
test_eadd(struct barvinok_options * options)108 static int test_eadd(struct barvinok_options *options)
109 {
110     unsigned nvar, nparam;
111     const char **all_vars;
112     evalue *e1, *e2;
113 
114     e1 = evalue_read_from_str("         d  -1 = 0\n"
115 			      "         h  -3 >= 0\n"
116 			      "         - h + 100 >= 0\n"
117 		      	      "\n"
118 			      "(1)\n",
119 			      "d,h", &all_vars, &nvar, &nparam,
120 			      options->MaxRays);
121     Free_ParamNames(all_vars, nvar+nparam);
122     e2 = evalue_read_from_str(
123 				"         h  -3 = 0\n"
124 				"         d  -1 >= 0\n"
125 				"         - d + 3 >= 0\n"
126 				"\n"
127 				"(0)\n"
128 				"         d  -1 >= 0\n"
129 				"         - d + 3 >= 0\n"
130 				"         h  -4 >= 0\n"
131 				"         - h + 100 >= 0\n"
132 				"\n"
133 				"(1)\n",
134 			      	"d,h", &all_vars, &nvar, &nparam,
135 			      	options->MaxRays);
136     Free_ParamNames(all_vars, nvar+nparam);
137     eadd(e2, e1);
138     evalue_check_disjoint(e1);
139     evalue_free(e1);
140     evalue_free(e2);
141     return 0;
142 }
143 
test_evalue(struct barvinok_options * options)144 int test_evalue(struct barvinok_options *options)
145 {
146     unsigned nvar, nparam;
147     const char **all_vars;
148     evalue *poly1, poly2;
149 
150     poly1 = evalue_read_from_str("(1/4 * n^4 + 1/2 * n^3 + 1/4 * n^2)",
151 				 NULL, &all_vars, &nvar, &nparam,
152 				 options->MaxRays);
153     Free_ParamNames(all_vars, nvar+nparam);
154 
155     value_init(poly2.d);
156     evalue_copy(&poly2, poly1);
157     evalue_negate(poly1);
158     eadd(&poly2, poly1);
159     reduce_evalue(poly1);
160     assert(EVALUE_IS_ZERO(*poly1));
161     evalue_free(poly1);
162     free_evalue_refs(&poly2);
163     return 0;
164 }
165 
test_substitute(struct barvinok_options * options)166 int test_substitute(struct barvinok_options *options)
167 {
168     unsigned nvar, nparam;
169     const char **all_vars;
170     const char *vars = "a,b";
171     evalue *e1, *e2;
172     evalue *subs[2];
173 
174     e1 = evalue_read_from_str("[ { 1/3 * a } = 0 ] * \n"
175 			      "	    ([ { 1/5 * b + 2/5 } = 0 ] * 5) + \n"
176 			      "[ { 1/3 * a } != 0 ] * 42",
177 			      vars, &all_vars, &nvar, &nparam,
178 			      options->MaxRays);
179     Free_ParamNames(all_vars, nvar+nparam);
180 
181     subs[0] = evalue_read_from_str("(2 * b + 5)",
182 				   vars, &all_vars, &nvar, &nparam,
183 				   options->MaxRays);
184     Free_ParamNames(all_vars, nvar+nparam);
185     subs[1] = evalue_read_from_str("(a + 1)",
186 				   vars, &all_vars, &nvar, &nparam,
187 				   options->MaxRays);
188     Free_ParamNames(all_vars, nvar+nparam);
189 
190     evalue_substitute(e1, subs);
191     evalue_free(subs[0]);
192     evalue_free(subs[1]);
193     reduce_evalue(e1);
194 
195     e2 = evalue_read_from_str("[ { 2/3 * b + 2/3 } = 0 ] * \n"
196 			      "	    ([ { 1/5 * a + 3/5 } = 0 ] * 5) + \n"
197 			      "[ { 2/3 * b + 2/3 } != 0 ] * 42",
198 			      vars, &all_vars, &nvar, &nparam,
199 			      options->MaxRays);
200     Free_ParamNames(all_vars, nvar+nparam);
201     reduce_evalue(e2);
202 
203     assert(eequal(e1, e2));
204 
205     evalue_free(e1);
206     evalue_free(e2);
207     return 0;
208 }
209 
test_specialization(struct barvinok_options * options)210 int test_specialization(struct barvinok_options *options)
211 {
212     Value v;
213     value_init(v);
214     mpq_t count;
215     mpq_init(count);
216 
217     value_set_si(v, 5);
218     dpoly n(2, v);
219     assert(value_cmp_si(n.coeff->p[0], 1) == 0);
220     assert(value_cmp_si(n.coeff->p[1], 5) == 0);
221     assert(value_cmp_si(n.coeff->p[2], 10) == 0);
222 
223     value_set_si(v, 1);
224     dpoly d(2, v, 1);
225     value_set_si(v, 2);
226     dpoly d2(2, v, 1);
227     d *= d2;
228     assert(value_cmp_si(d.coeff->p[0], 2) == 0);
229     assert(value_cmp_si(d.coeff->p[1], 1) == 0);
230     assert(value_cmp_si(d.coeff->p[2], 0) == 0);
231 
232     n.div(d, count, 1);
233     mpq_canonicalize(count);
234     assert(value_cmp_si(mpq_numref(count), 31) == 0);
235     assert(value_cmp_si(mpq_denref(count), 8) == 0);
236 
237     value_set_si(v, -2);
238     dpoly n2(2, v);
239     assert(value_cmp_si(n2.coeff->p[0], 1) == 0);
240     assert(value_cmp_si(n2.coeff->p[1], -2) == 0);
241     assert(value_cmp_si(n2.coeff->p[2], 3) == 0);
242 
243     n2.div(d, count, 1);
244     mpq_canonicalize(count);
245     assert(value_cmp_si(mpq_numref(count), 6) == 0);
246     assert(value_cmp_si(mpq_denref(count), 1) == 0);
247 
248     value_clear(v);
249     mpq_clear(count);
250     return 0;
251 }
252 
test_lattice_points(struct barvinok_options * options)253 int test_lattice_points(struct barvinok_options *options)
254 {
255     Param_Vertices V;
256     mat_ZZ tmp;
257     set_from_string(tmp, "[[0 0 0 0 4][0 0 0 0 4][-1 0 1 0 4]]");
258     V.Vertex = zz2matrix(tmp);
259     vec_ZZ lambda;
260     set_from_string(lambda, "[3 5 7]");
261     mat_ZZ rays;
262     set_from_string(rays, "[[0 1 0][4 0 1][0 0 -1]]");
263     term_info num;
264     evalue *point[4];
265 
266     unsigned nvar, nparam;
267     const char **all_vars;
268     point[0] = evalue_read_from_str("( -7/4 * a + ( 7/4 * c + "
269 		    "( 7 * {( 1/4 * a + ( 3/4 * c + 3/4 ) ) } + -21/4 ) ) )",
270 		    "a,b,c", &all_vars, &nvar, &nparam, options->MaxRays);
271     Free_ParamNames(all_vars, nvar+nparam);
272     point[1] = evalue_read_from_str("( -7/4 * a + ( 7/4 * c + "
273 		    "( 7 * {( 1/4 * a + ( 3/4 * c + 1/2 ) ) } + -1/2 ) ) )",
274 		    "a,b,c", &all_vars, &nvar, &nparam, options->MaxRays);
275     Free_ParamNames(all_vars, nvar+nparam);
276     point[2] = evalue_read_from_str("( -7/4 * a + ( 7/4 * c + "
277 		    "( 7 * {( 1/4 * a + ( 3/4 * c + 1/4 ) ) } + 17/4 ) ) )",
278 		    "a,b,c", &all_vars, &nvar, &nparam, options->MaxRays);
279     Free_ParamNames(all_vars, nvar+nparam);
280     point[3] = evalue_read_from_str("( -7/4 * a + ( 7/4 * c + "
281 		    "( 7 * {( 1/4 * a + ( 3/4 * c + 0 ) ) } + 9 ) ) )",
282 		    "a,b,c", &all_vars, &nvar, &nparam, options->MaxRays);
283     Free_ParamNames(all_vars, nvar+nparam);
284 
285     lattice_point(&V, rays, lambda, &num, 4, options);
286     Matrix_Free(V.Vertex);
287 
288     for (int i = 0; i < 4; ++i) {
289 	assert(eequal(num.E[i], point[i]));
290 	evalue_free(point[i]);
291 	evalue_free(num.E[i]);
292     }
293     delete [] num.E;
294     return 0;
295 }
296 
test_icounter(struct barvinok_options * options)297 static int test_icounter(struct barvinok_options *options)
298 {
299     icounter cnt(2);
300     vec_QQ n_coeff;
301     mat_ZZ n_power;
302     mat_ZZ d_power;
303     set_from_string(n_coeff, "[-2/1 1/1]");
304     set_from_string(n_power, "[[2 6][3 6]]");
305     d_power.SetDims(0, 2);
306     cnt.reduce(n_coeff, n_power, d_power);
307     assert(value_cmp_si(mpq_numref(cnt.count), -1) == 0);
308     assert(value_cmp_si(mpq_denref(cnt.count), 1) == 0);
309     return 0;
310 }
311 
test_infinite_counter(struct barvinok_options * options)312 static int test_infinite_counter(struct barvinok_options *options)
313 {
314     Matrix *M = matrix_read_from_str("1 3\n	1 1 0\n");
315     Polyhedron *ctx = Constraints2Polyhedron(M, options->MaxRays);
316     Matrix_Free(M);
317 
318     /* (1 -1/2 x^5 - 1/2 x^7)/(1-x) */
319     infinite_counter *cnt = new infinite_counter(1, 1);
320     cnt->init(ctx, 0);
321     vec_QQ n_coeff;
322     mat_ZZ n_power;
323     mat_ZZ d_power;
324     set_from_string(n_coeff, "[1/1 -1/2 -1/2]");
325     set_from_string(n_power, "[[0][5][7]]");
326     set_from_string(d_power, "[[1]]");
327     cnt->reduce(n_coeff, n_power, d_power);
328     assert(value_cmp_si(mpq_numref(cnt->count[0]), 6) == 0);
329     assert(value_cmp_si(mpq_denref(cnt->count[0]), 1) == 0);
330     assert(value_cmp_si(mpq_numref(cnt->count[1]), 0) == 0);
331     assert(value_cmp_si(mpq_denref(cnt->count[1]), 1) == 0);
332     delete cnt;
333     Polyhedron_Free(ctx);
334 
335     M = matrix_read_from_str("2 4\n	1 1 0 0\n   1 0 1 0\n");
336     ctx = Constraints2Polyhedron(M, options->MaxRays);
337     Matrix_Free(M);
338 
339     /* (1 - xy)/((1-x)(1-xy)) */
340     cnt = new infinite_counter(2, 3);
341     cnt->init(ctx, 0);
342     set_from_string(n_coeff, "[1/1 -1/1]");
343     set_from_string(n_power, "[[0 0][1 1]]");
344     set_from_string(d_power, "[[1 0][1 1]]");
345     cnt->reduce(n_coeff, n_power, d_power);
346     assert(value_cmp_si(mpq_numref(cnt->count[1]), 0) != 0);
347     assert(value_cmp_si(mpq_numref(cnt->count[2]), 0) == 0);
348     assert(value_cmp_si(mpq_denref(cnt->count[2]), 1) == 0);
349     assert(value_cmp_si(mpq_numref(cnt->count[3]), 0) == 0);
350     assert(value_cmp_si(mpq_denref(cnt->count[3]), 1) == 0);
351     delete cnt;
352 
353     cnt = new infinite_counter(2, 2);
354     cnt->init(ctx, 0);
355     set_from_string(n_coeff, "[-1/2 1/1 -1/3]");
356     set_from_string(n_power, "[[2 6][3 6]]");
357     d_power.SetDims(0, 2);
358     cnt->reduce(n_coeff, n_power, d_power);
359     assert(value_cmp_si(mpq_numref(cnt->count[0]), 1) == 0);
360     assert(value_cmp_si(mpq_denref(cnt->count[0]), 6) == 0);
361     assert(value_cmp_si(mpq_numref(cnt->count[1]), 0) == 0);
362     assert(value_cmp_si(mpq_denref(cnt->count[1]), 1) == 0);
363     assert(value_cmp_si(mpq_numref(cnt->count[2]), 0) == 0);
364     assert(value_cmp_si(mpq_denref(cnt->count[2]), 1) == 0);
365     delete cnt;
366 
367     cnt = new infinite_counter(2, 2);
368     cnt->init(ctx, 0);
369     set_from_string(n_coeff, "[1/1]");
370     set_from_string(n_power, "[[0 11]]");
371     set_from_string(d_power, "[[0 1]]");
372     cnt->reduce(n_coeff, n_power, d_power);
373     assert(value_cmp_si(mpq_numref(cnt->count[1]), 0) != 0);
374     assert(value_cmp_si(mpq_numref(cnt->count[2]), 0) == 0);
375     assert(value_cmp_si(mpq_denref(cnt->count[2]), 1) == 0);
376     delete cnt;
377 
378     Polyhedron_Free(ctx);
379 
380     return 0;
381 }
382 
test_series(struct barvinok_options * options)383 static int test_series(struct barvinok_options *options)
384 {
385     Matrix *M;
386     Polyhedron *P, *C;
387     gen_fun *gf;
388 
389     M = matrix_read_from_str(
390 	"2 3\n"
391 	"1  1  0\n"
392 	"1 -1 10\n");
393     P = Constraints2Polyhedron(M, options->MaxRays);
394     Matrix_Free(M);
395     C = Universe_Polyhedron(1);
396     gf = barvinok_series_with_options(P, C, options);
397     Polyhedron_Free(P);
398     Polyhedron_Free(C);
399     gen_fun *sum = gf->summate(1, options);
400     delete gf;
401     delete sum;
402 
403     return 0;
404 }
405 
test_todd(struct barvinok_options * options)406 int test_todd(struct barvinok_options *options)
407 {
408     tcounter t(2, options->max_index);
409     assert(value_cmp_si(t.todd.coeff->p[0], 1) == 0);
410     assert(value_cmp_si(t.todd.coeff->p[1], -3) == 0);
411     assert(value_cmp_si(t.todd.coeff->p[2], 3) == 0);
412     assert(value_cmp_si(t.todd_denom->p[0], 1) == 0);
413     assert(value_cmp_si(t.todd_denom->p[1], 6) == 0);
414     assert(value_cmp_si(t.todd_denom->p[2], 36) == 0);
415 
416     vec_ZZ lambda;
417     set_from_string(lambda, "[1 -1]");
418     zz2values(lambda, t.lambda->p);
419 
420     mat_ZZ rays;
421     set_from_string(rays, "[[-1 0][-1 1]]");
422 
423     QQ one(1, 1);
424 
425     vec_ZZ v;
426     set_from_string(v, "[2 0 1]");
427     Vector *vertex = Vector_Alloc(3);
428     zz2values(v, vertex->p);
429 
430     t.handle(rays, vertex->p, one, 1, options);
431     assert(value_cmp_si(mpq_numref(t.count), 71) == 0);
432     assert(value_cmp_si(mpq_denref(t.count), 24) == 0);
433 
434     set_from_string(rays, "[[0 -1][1 -1]]");
435     set_from_string(v, "[0 2 1]");
436     zz2values(v, vertex->p);
437 
438     t.handle(rays, vertex->p, one, 1, options);
439     assert(value_cmp_si(mpq_numref(t.count), 71) == 0);
440     assert(value_cmp_si(mpq_denref(t.count), 12) == 0);
441 
442     set_from_string(rays, "[[1 0][0 1]]");
443     set_from_string(v, "[0 0 1]");
444     zz2values(v, vertex->p);
445 
446     t.handle(rays, vertex->p, one, 1, options);
447     assert(value_cmp_si(mpq_numref(t.count), 6) == 0);
448     assert(value_cmp_si(mpq_denref(t.count), 1) == 0);
449 
450     Vector_Free(vertex);
451     return 0;
452 }
453 
test_bernoulli(struct barvinok_options * options)454 int test_bernoulli(struct barvinok_options *options)
455 {
456     struct bernoulli_coef *bernoulli_coef;
457     struct poly_list *faulhaber, *bernoulli;
458     bernoulli_coef = bernoulli_coef_compute(2);
459     faulhaber = faulhaber_compute(4);
460     bernoulli_coef = bernoulli_coef_compute(8);
461     assert(value_cmp_si(bernoulli_coef->num->p[6], 1) == 0);
462     assert(value_cmp_si(bernoulli_coef->den->p[6], 42) == 0);
463     assert(value_cmp_si(faulhaber->poly[3]->p[0], 0) == 0);
464     assert(value_cmp_si(faulhaber->poly[3]->p[1], 0) == 0);
465     assert(value_cmp_si(faulhaber->poly[3]->p[2], 1) == 0);
466     assert(value_cmp_si(faulhaber->poly[3]->p[3], -2) == 0);
467     assert(value_cmp_si(faulhaber->poly[3]->p[4], 1) == 0);
468     assert(value_cmp_si(faulhaber->poly[3]->p[5], 4) == 0);
469 
470     bernoulli = bernoulli_compute(6);
471     assert(value_cmp_si(bernoulli->poly[6]->p[0], 1) == 0);
472     assert(value_cmp_si(bernoulli->poly[6]->p[1], 0) == 0);
473     assert(value_cmp_si(bernoulli->poly[6]->p[2], -21) == 0);
474     assert(value_cmp_si(bernoulli->poly[6]->p[3], 0) == 0);
475     assert(value_cmp_si(bernoulli->poly[6]->p[4], 105) == 0);
476     assert(value_cmp_si(bernoulli->poly[6]->p[5], -126) == 0);
477     assert(value_cmp_si(bernoulli->poly[6]->p[6], 42) == 0);
478     assert(value_cmp_si(bernoulli->poly[6]->p[7], 42) == 0);
479 
480     unsigned nvar, nparam;
481     const char **all_vars;
482     evalue *base, *sum1, *sum2;
483     base = evalue_read_from_str("(1 * n + 1)", NULL, &all_vars, &nvar, &nparam,
484 				options->MaxRays);
485 
486     sum1 = evalue_polynomial(faulhaber->poly[3], base);
487     Free_ParamNames(all_vars, nvar+nparam);
488 
489     sum2 = evalue_read_from_str("(1/4 * n^4 + 1/2 * n^3 + 1/4 * n^2)",
490 				NULL, &all_vars, &nvar, &nparam,
491 				options->MaxRays);
492     Free_ParamNames(all_vars, nvar+nparam);
493     assert(eequal(sum1, sum2));
494     evalue_free(base);
495     evalue_free(sum1);
496     evalue_free(sum2);
497     return 0;
498 }
499 
test_bernoulli_sum(struct barvinok_options * options)500 int test_bernoulli_sum(struct barvinok_options *options)
501 {
502     int summation = options->summation;
503     options->summation = BV_SUM_BERNOULLI;
504 
505     unsigned nvar, nparam;
506     const char **all_vars;
507     evalue *e, *sum1, *sum2;
508     e = evalue_read_from_str("i + -1 >= 0\n -i + n >= 0\n\n 1 + (-1 *i) + i^2",
509 			     "i", &all_vars, &nvar, &nparam,
510 				options->MaxRays);
511     Free_ParamNames(all_vars, nvar+nparam);
512 
513     sum1 = barvinok_summate(e, 1, options);
514     sum2 = evalue_read_from_str("n -1 >= 0\n\n (1/3 * n^3 + 2/3 * n)",
515 				NULL, &all_vars, &nvar, &nparam,
516 				options->MaxRays);
517     Free_ParamNames(all_vars, nvar+nparam);
518     evalue_negate(sum1);
519     eadd(sum2, sum1);
520     reduce_evalue(sum1);
521     assert(EVALUE_IS_ZERO(*sum1));
522     evalue_free(e);
523     evalue_free(sum1);
524 
525     e = evalue_read_from_str("-i + -1 >= 0\n i + n >= 0\n\n 1 + i + i^2",
526 			     "i", &all_vars, &nvar, &nparam,
527 				options->MaxRays);
528     Free_ParamNames(all_vars, nvar+nparam);
529     sum1 = barvinok_summate(e, 1, options);
530     evalue_negate(sum1);
531     eadd(sum2, sum1);
532     reduce_evalue(sum1);
533     assert(EVALUE_IS_ZERO(*sum1));
534     evalue_free(e);
535     evalue_free(sum1);
536 
537     evalue_free(sum2);
538 
539     e = evalue_read_from_str("i + 4 >= 0\n -i + n >= 0\n\n i",
540 			     "i", &all_vars, &nvar, &nparam,
541 				options->MaxRays);
542     Free_ParamNames(all_vars, nvar+nparam);
543     sum1 = barvinok_summate(e, 1, options);
544     sum2 = evalue_read_from_str("n + 0 >= 0\n\n (1/2 * n^2 + 1/2 * n + (-10))\n"
545 		    "n + 4 >= 0\n -n -1 >= 0\n\n (1/2 * n^2 + 1/2 * n + (-10))",
546 				NULL, &all_vars, &nvar, &nparam,
547 				options->MaxRays);
548     Free_ParamNames(all_vars, nvar+nparam);
549     evalue_negate(sum1);
550     eadd(sum2, sum1);
551     reduce_evalue(sum1);
552     assert(EVALUE_IS_ZERO(*sum1));
553     evalue_free(e);
554     evalue_free(sum1);
555     evalue_free(sum2);
556 
557     e = evalue_read_from_str("i -5 >= 0\n -i + n >= 0\n j -1 >= 0\n i -j >= 0\n"
558 			     "k -1 >= 0\n j -k >= 0\n\n1",
559 			     "i,j,k", &all_vars, &nvar, &nparam,
560 				options->MaxRays);
561     Free_ParamNames(all_vars, nvar+nparam);
562     sum1 = barvinok_summate(e, 3, options);
563     sum2 = evalue_read_from_str("n -5 >= 0\n\n"
564 				"1/6 * n^3 + 1/2 * n^2 + 1/3 * n + -20",
565 				NULL, &all_vars, &nvar, &nparam,
566 				options->MaxRays);
567     Free_ParamNames(all_vars, nvar+nparam);
568     evalue_negate(sum1);
569     eadd(sum2, sum1);
570     reduce_evalue(sum1);
571     assert(EVALUE_IS_ZERO(*sum1));
572     evalue_free(e);
573     evalue_free(sum1);
574     evalue_free(sum2);
575 
576     options->summation = summation;
577     return 0;
578 }
579 
test_hilbert(struct barvinok_options * options)580 int test_hilbert(struct barvinok_options *options)
581 {
582 #ifdef USE_ZSOLVE
583     Matrix *M = matrix_read_from_str(
584 	"2 4\n"
585 	"   1    4   -3    0 \n"
586 	"   1    3    2    0 \n");
587     Polyhedron *P = Constraints2Polyhedron(M, options->MaxRays);
588     Matrix_Free(M);
589 
590     M = Cone_Hilbert_Basis(P, options->MaxRays);
591     assert(M->NbRows == 5);
592     assert(M->NbColumns == 3);
593     Matrix_Free(M);
594 
595     M = Cone_Integer_Hull(P, NULL, 0, options);
596     assert(M->NbRows == 4);
597     assert(M->NbColumns == 3);
598     Matrix_Free(M);
599 
600     Polyhedron_Free(P);
601 #endif
602     return 0;
603 }
604 
test_ilp(struct barvinok_options * options)605 int test_ilp(struct barvinok_options *options)
606 {
607     Matrix *M = matrix_read_from_str(
608 	"2 4\n"
609 	"   1    4   -3    0 \n"
610 	"   1    3    2    0 \n");
611     Polyhedron *P = Constraints2Polyhedron(M, options->MaxRays);
612     Matrix_Free(M);
613     Vector *obj = Vector_Alloc(2);
614     value_set_si(obj->p[0], 7);
615     value_set_si(obj->p[1], -1);
616     Value min, max;
617     value_init(min);
618     value_init(max);
619 
620     value_set_si(min, 1);
621     value_set_si(max, 17);
622     Vector *opt = Polyhedron_Integer_Minimum(P, obj->p, min, max,
623 					     NULL, 0, options);
624     assert(opt);
625     assert(value_cmp_si(opt->p[0], 1) == 0);
626     assert(value_cmp_si(opt->p[1], 1) == 0);
627     assert(value_cmp_si(opt->p[2], 1) == 0);
628     Vector_Free(opt);
629 
630     value_clear(min);
631     value_clear(max);
632     Vector_Free(obj);
633     Polyhedron_Free(P);
634     return 0;
635 }
636 
test_hull(struct barvinok_options * options)637 int test_hull(struct barvinok_options *options)
638 {
639     Matrix *M = matrix_read_from_str(
640 	"4 4\n"
641 	"1  32  -20    7\n"
642 	"1   8  -44  187\n"
643 	"1 -48   -4  285\n"
644 	"1   8   68 -199\n");
645     Polyhedron *P = Constraints2Polyhedron(M, options->MaxRays);
646     Matrix_Free(M);
647 
648     Matrix *hull = Polyhedron_Integer_Hull(P, options);
649     Polyhedron_Free(P);
650     assert(hull->NbRows == 4);
651     M = Matrix_Alloc(hull->NbRows, 1+hull->NbColumns);
652     for (int i = 0; i < hull->NbRows; ++i) {
653 	value_set_si(M->p[i][0], 1);
654 	Vector_Copy(hull->p[i], M->p[i]+1, hull->NbColumns);
655     }
656     Matrix_Free(hull);
657     Polyhedron *H = Constraints2Polyhedron(M, options->MaxRays);
658     Matrix_Free(M);
659 
660     M = matrix_read_from_str(
661 	"4 4\n"
662 	"1    2    3    1 \n"
663 	"1    3    4    1 \n"
664 	"1    5    3    1 \n"
665 	"1    5    5    1 \n");
666     P = Constraints2Polyhedron(M, options->MaxRays);
667     Matrix_Free(M);
668     assert(PolyhedronIncludes(P, H) && PolyhedronIncludes(H, P));
669     Polyhedron_Free(P);
670     Polyhedron_Free(H);
671 
672     M = matrix_read_from_str(
673 	"3 4\n"
674 	"1   2    6   -3 \n"
675 	"1   2   -6    3 \n"
676 	"1  -2    0    3 \n");
677     P = Constraints2Polyhedron(M, options->MaxRays);
678     Matrix_Free(M);
679     assert(!emptyQ(P));
680     hull = Polyhedron_Integer_Hull(P, options);
681     Polyhedron_Free(P);
682     assert(hull->NbRows == 0);
683     Matrix_Free(hull);
684     return 0;
685 }
686 
test_laurent(struct barvinok_options * options)687 static int test_laurent(struct barvinok_options *options)
688 {
689     unsigned nvar, nparam;
690     const char **all_vars;
691     evalue *e, *sum, *res;
692 
693     e = evalue_read_from_str("         x1 >= 0\n"
694 			     "         x2 >= 0\n"
695 			     "         -x1 -x2 + 2 >= 0\n"
696 			     "\n"
697 			     "(N + M * x2)\n",
698 			     "x1,x2", &all_vars, &nvar, &nparam,
699 			     options->MaxRays);
700     Free_ParamNames(all_vars, nvar+nparam);
701 
702     int summation = options->summation;
703     options->summation = BV_SUM_LAURENT;
704     sum = barvinok_summate(e, nvar, options);
705     options->summation = summation;
706 
707     res = evalue_read_from_str("(6 * N + 4 * M)",
708 			       "", &all_vars, &nvar, &nparam,
709 			       options->MaxRays);
710     Free_ParamNames(all_vars, nvar+nparam);
711 
712     assert(value_zero_p(sum->d));
713     assert(sum->x.p->type == partition);
714     assert(sum->x.p->size == 2);
715 
716     assert(eequal(res, &sum->x.p->arr[1]));
717 
718     evalue_free(e);
719     evalue_free(sum);
720     evalue_free(res);
721     return 0;
722 }
723 
724 /* Check that Polyhedron_Reduced_Basis produces a result
725  * of the expected dimensions (without crashing).
726  */
test_basis_reduction(struct barvinok_options * options)727 static int test_basis_reduction(struct barvinok_options *options)
728 {
729     Matrix *M;
730     Polyhedron *P;
731 
732     M = matrix_read_from_str(
733 	"4 4\n"
734 	"1    1    0    0 \n"
735 	"1    0    1    0 \n"
736 	"1   -1    0    1 \n"
737 	"1    0   -1    1 \n");
738     P = Constraints2Polyhedron(M, options->MaxRays);
739     Matrix_Free(M);
740 
741     M = Polyhedron_Reduced_Basis(P, options);
742 
743     assert(M);
744     assert(M->NbRows == 2);
745     assert(M->NbColumns == 2);
746 
747     Polyhedron_Free(P);
748     Matrix_Free(M);
749 
750     return 0;
751 }
752 
main(int argc,char ** argv)753 int main(int argc, char **argv)
754 {
755     struct barvinok_options *options = barvinok_options_new_with_defaults();
756     test_equalities(options);
757     test_evalue_read(options);
758     test_eadd(options);
759     test_evalue(options);
760     test_substitute(options);
761     test_specialization(options);
762     test_lattice_points(options);
763     test_icounter(options);
764     test_infinite_counter(options);
765     test_series(options);
766     test_todd(options);
767     test_bernoulli(options);
768     test_bernoulli_sum(options);
769     test_hilbert(options);
770     test_ilp(options);
771     test_hull(options);
772     test_laurent(options);
773     test_basis_reduction(options);
774     barvinok_options_free(options);
775 
776     return EXIT_SUCCESS;
777 }
778