use test scripts for performing tests
[barvinok.git] / counter.cc
blob763f6d7c24496b7b394c6c235a3a8a29215c4bb9
1 #include <assert.h>
2 #include <NTL/ZZ.h>
3 #include <NTL/vec_ZZ.h>
4 #include <NTL/mat_ZZ.h>
5 #include <barvinok/polylib.h>
6 #include <barvinok/util.h>
7 #include "counter.h"
8 #include "lattice_point.h"
10 /* Computes the integer points in the fundamental parallelepiped and
11 * passes them along (in num) to the counter specific (i.e., specialization
12 * specific) add_lattice_points.
14 void counter_base::handle(const mat_ZZ& rays, Value *V, const QQ& c,
15 unsigned long det, barvinok_options *options)
17 Matrix* Rays = zz2matrix(rays);
19 assert(c.d == 1);
20 assert(c.n == 1 || c.n == -1);
21 int sign = to_int(c.n);
23 Matrix_Vector_Product(Rays, lambda->p, den->p_Init);
24 for (int k = 0; k < dim; ++k)
25 if (value_zero_p(den->p_Init[k])) {
26 Matrix_Free(Rays);
27 throw Orthogonal;
29 Inner_Product(lambda->p, V, dim, &tmp);
30 lattice_points_fixed(V, &tmp, Rays, den, num, det);
31 num->NbRows = det;
32 Matrix_Free(Rays);
34 if (dim % 2)
35 sign = -sign;
37 add_lattice_points(sign);
40 static void add_falling_powers(dpoly& n, Value degree)
42 value_increment(n.coeff->p[0], n.coeff->p[0]);
43 if (n.coeff->Size == 1)
44 return;
46 int min = n.coeff->Size-1;
47 if (value_posz_p(degree) && value_cmp_si(degree, min) < 0)
48 min = VALUE_TO_INT(degree);
50 Value tmp;
51 value_init(tmp);
52 value_assign(tmp, degree);
53 value_addto(n.coeff->p[1], n.coeff->p[1], tmp);
54 for (int i = 2; i <= min; ++i) {
55 value_decrement(degree, degree);
56 value_multiply(tmp, tmp, degree);
57 mpz_divexact_ui(tmp, tmp, i);
58 value_addto(n.coeff->p[i], n.coeff->p[i], tmp);
60 value_clear(tmp);
63 void counter::add_lattice_points(int sign)
65 dpoly d(dim);
66 for (int k = 0; k < num->NbRows; ++k)
67 add_falling_powers(d, num->p_Init[k]);
68 dpoly n(dim, den->p_Init[0], 1);
69 for (int k = 1; k < dim; ++k) {
70 dpoly fact(dim, den->p_Init[k], 1);
71 n *= fact;
73 d.div(n, count, sign);
79 void tcounter::setup_todd(unsigned dim)
81 value_set_si(todd.coeff->p[0], 1);
83 dpoly d(dim);
84 value_set_si(d.coeff->p[dim], 1);
85 for (int i = dim-1; i >= 0; --i)
86 mpz_mul_ui(d.coeff->p[i], d.coeff->p[i+1], i+2);
88 todd_denom = todd.div(d);
89 /* shift denominators up -> divide by (dim+1)! */
90 for (int i = todd.coeff->Size-1; i >= 1; --i)
91 value_assign(todd_denom->p[i], todd_denom->p[i-1]);
92 value_set_si(todd_denom->p[0], 1);
95 void tcounter::adapt_todd(dpoly& t, const Value c)
97 if (t.coeff->Size <= 1)
98 return;
99 value_assign(tmp, c);
100 value_multiply(t.coeff->p[1], t.coeff->p[1], tmp);
101 for (int i = 2; i < t.coeff->Size; ++i) {
102 value_multiply(tmp, tmp, c);
103 value_multiply(t.coeff->p[i], t.coeff->p[i], tmp);
107 void tcounter::add_powers(dpoly& n, const Value c)
109 value_increment(n.coeff->p[0], n.coeff->p[0]);
110 if (n.coeff->Size == 1)
111 return;
112 value_assign(tmp, c);
113 value_addto(n.coeff->p[1], n.coeff->p[1], tmp);
114 for (int i = 2; i < n.coeff->Size; ++i) {
115 value_multiply(tmp, tmp, c);
116 value_addto(n.coeff->p[i], n.coeff->p[i], tmp);
120 void tcounter::add_lattice_points(int sign)
122 dpoly t(todd);
123 value_assign(denom, den->p_Init[0]);
124 adapt_todd(t, den->p_Init[0]);
125 for (int k = 1; k < dim; ++k) {
126 dpoly fact(todd);
127 value_multiply(denom, denom, den->p_Init[k]);
128 adapt_todd(fact, den->p_Init[k]);
129 t *= fact;
132 dpoly n(dim);
133 for (int k = 0; k < num->NbRows; ++k)
134 add_powers(n, num->p_Init[k]);
136 for (int i = 0; i < n.coeff->Size; ++i)
137 value_multiply(n.coeff->p[i], n.coeff->p[i], todd_denom->p[i]);
138 value_multiply(denom, denom, todd_denom->p[todd_denom->Size-1]);
140 value_set_si(tmp, 1);
141 for (int i = 2; i < n.coeff->Size; ++i) {
142 mpz_mul_ui(tmp, tmp, i);
143 mpz_divexact(n.coeff->p[i], n.coeff->p[i], tmp);
146 value_multiply(tmp, t.coeff->p[0], n.coeff->p[n.coeff->Size-1]);
147 for (int i = 1; i < n.coeff->Size; ++i)
148 value_addmul(tmp, t.coeff->p[i], n.coeff->p[n.coeff->Size-1-i]);
150 value_assign(mpq_numref(tcount), tmp);
151 value_assign(mpq_denref(tcount), denom);
152 mpq_canonicalize(tcount);
153 if (sign == -1)
154 mpq_sub(count, count, tcount);
155 else
156 mpq_add(count, count, tcount);
161 * Set lambda to a random vector that has a positive inner product
162 * with all the rays of the context { x | A x + b >= 0 }.
164 * To do so, we take d rows A' from the constraint matrix A.
165 * For every ray, we have
166 * A' r >= 0
167 * We compute a random positive row vector x' and set x = x' A'.
168 * We then have, for each ray r,
169 * x r = x' A' r >= 0
170 * Although we can take any d rows from A, we choose linearly
171 * independent rows from A to avoid the elements of the transformed
172 * random vector to have simple linear relations, which would
173 * increase the risk of the vector being orthogonal to one of
174 * powers in the denominator of one of the terms in the generating
175 * function.
177 void infinite_counter::init(Polyhedron *context, int n_try)
179 Matrix *M, *H, *Q, *U;
180 mat_ZZ A;
182 randomvector(context, lambda, context->Dimension, n_try);
184 M = Matrix_Alloc(context->NbConstraints, context->Dimension);
185 for (int i = 0; i < context->NbConstraints; ++i)
186 Vector_Copy(context->Constraint[i]+1, M->p[i], context->Dimension);
187 left_hermite(M, &H, &Q, &U);
188 Matrix_Free(Q);
189 Matrix_Free(U);
191 for (int col = 0, row = 0; col < H->NbColumns; ++col, ++row) {
192 for (; row < H->NbRows; ++row)
193 if (value_notzero_p(H->p[row][col]))
194 break;
195 assert(row < H->NbRows);
196 Vector_Copy(M->p[row], M->p[col], M->NbColumns);
198 matrix2zz(M, A, context->Dimension, context->Dimension);
199 Matrix_Free(H);
200 Matrix_Free(M);
202 for (int i = 0; i < lambda.length(); ++i)
203 lambda[i] = abs(lambda[i]);
204 lambda = lambda * A;
207 static ZZ LCM(const ZZ& a, const ZZ& b)
209 return a * b / GCD(a, b);
212 /* Normalize the powers in the denominator to be positive
213 * and return -1 is the sign has to be changed.
215 static int normalized_sign(vec_ZZ& num, vec_ZZ& den)
217 int change = 0;
219 for (int j = 0; j < den.length(); ++j) {
220 if (den[j] > 0)
221 change ^= 1;
222 else {
223 den[j] = abs(den[j]);
224 for (int k = 0; k < num.length(); ++k)
225 num[k] += den[j];
228 return change ? -1 : 1;
231 void infinite_counter::reduce(const vec_QQ& c, const mat_ZZ& num,
232 const mat_ZZ& den_f)
234 mpq_t factor;
235 mpq_init(factor);
236 unsigned len = den_f.NumRows();
238 ZZ lcm = c[0].d;
239 for (int i = 1; i < c.length(); ++i)
240 lcm = LCM(lcm, c[i].d);
242 vec_ZZ coeff;
243 coeff.SetLength(c.length());
244 for (int i = 0; i < c.length(); ++i)
245 coeff[i] = c[i].n * lcm/c[i].d;
247 if (len == 0) {
248 for (int i = 0; i < c.length(); ++i) {
249 zz2value(coeff[i], tz);
250 value_addto(mpq_numref(factor), mpq_numref(factor), tz);
252 zz2value(lcm, tz);
253 value_assign(mpq_denref(factor), tz);
254 mpq_add(count[0], count[0], factor);
255 mpq_clear(factor);
256 return;
259 vec_ZZ num_s = num * lambda;
260 vec_ZZ den_s = den_f * lambda;
261 for (int i = 0; i < den_s.length(); ++i)
262 assert(den_s[i] != 0);
263 int sign = normalized_sign(num_s, den_s);
264 if (sign < 0)
265 coeff = -coeff;
267 dpoly n(len);
268 zz2value(num_s[0], tz);
269 add_falling_powers(n, tz);
270 zz2value(coeff[0], tz);
271 n *= tz;
272 for (int i = 1; i < c.length(); ++i) {
273 dpoly t(len);
274 zz2value(num_s[i], tz);
275 add_falling_powers(t, tz);
276 zz2value(coeff[i], tz);
277 t *= tz;
278 n += t;
280 zz2value(den_s[0], tz);
281 dpoly d(len, tz, 1);
282 for (int i = 1; i < len; ++i) {
283 zz2value(den_s[i], tz);
284 dpoly fact(len, tz, 1);
285 d *= fact;
287 value_set_si(mpq_numref(factor), 1);
288 zz2value(lcm, tz);
289 value_assign(mpq_denref(factor), tz);
290 n.div(d, count, factor);
292 mpq_clear(factor);