2 #include <barvinok/barvinok.h>
3 #include <barvinok/util.h>
4 #include "genfun_constructor.h"
5 #include "lattice_width.h"
6 #include "remove_equalities.h"
11 /* Check whether all rays point in the positive directions
14 static bool Polyhedron_has_positive_rays(Polyhedron
*P
, unsigned nparam
)
17 for (r
= 0; r
< P
->NbRays
; ++r
)
18 if (value_zero_p(P
->Ray
[r
][P
->Dimension
+1])) {
20 for (i
= P
->Dimension
- nparam
; i
< P
->Dimension
; ++i
)
21 if (value_neg_p(P
->Ray
[r
][i
+1]))
27 gen_fun
*barvinok_enumerate_series(Polyhedron
*P
, unsigned nparam
,
28 barvinok_options
*options
)
32 Polyhedron
*P_orig
= P
;
35 return new gen_fun(Empty_Polyhedron(nparam
));
37 assert(!Polyhedron_is_unbounded(P
, nparam
, options
->MaxRays
));
38 assert(P
->NbBid
== 0);
39 assert(Polyhedron_has_revlex_positive_rays(P
, nparam
));
41 remove_all_equalities(&P
, NULL
, &CP
, NULL
, nparam
, options
->MaxRays
);
42 assert(emptyQ2(P
) || P
->NbEq
== 0);
44 nparam
= CP
->NbColumns
-1;
49 barvinok_count_with_options(P
, &c
, options
);
53 POL_ENSURE_VERTICES(P
);
55 gf
= barvinok_enumerate_series(P
, nparam
, options
);
58 red
= gf_base::create(Polyhedron_Project(P
, nparam
),
59 P
->Dimension
, nparam
, options
);
60 red
->start_gf(P
, options
);
74 gen_fun
* barvinok_series_with_options(Polyhedron
*P
, Polyhedron
* C
,
75 barvinok_options
*options
)
78 unsigned nparam
= C
->Dimension
;
81 CA
= align_context(C
, P
->Dimension
, options
->MaxRays
);
82 P
= DomainIntersection(P
, CA
, options
->MaxRays
);
85 gf
= barvinok_enumerate_series(P
, nparam
, options
);
91 gen_fun
* barvinok_series(Polyhedron
*P
, Polyhedron
* C
, unsigned MaxRays
)
94 barvinok_options
*options
= barvinok_options_new_with_defaults();
95 options
->MaxRays
= MaxRays
;
96 gf
= barvinok_series_with_options(P
, C
, options
);
97 barvinok_options_free(options
);
101 static Polyhedron
*skew_into_positive_orthant(Polyhedron
*D
, unsigned nparam
,
107 for (Polyhedron
*P
= D
; P
; P
= P
->next
) {
108 POL_ENSURE_VERTICES(P
);
109 assert(!Polyhedron_is_unbounded(P
, nparam
, MaxRays
));
110 assert(P
->NbBid
== 0);
111 assert(Polyhedron_has_positive_rays(P
, nparam
));
113 for (int r
= 0; r
< P
->NbRays
; ++r
) {
114 if (value_notzero_p(P
->Ray
[r
][P
->Dimension
+1]))
116 for (int i
= 0; i
< nparam
; ++i
) {
118 if (value_posz_p(P
->Ray
[r
][i
+1]))
121 M
= Matrix_Alloc(D
->Dimension
+1, D
->Dimension
+1);
122 for (int i
= 0; i
< D
->Dimension
+1; ++i
)
123 value_set_si(M
->p
[i
][i
], 1);
125 Inner_Product(P
->Ray
[r
]+1, M
->p
[i
], D
->Dimension
+1, &tmp
);
126 if (value_posz_p(tmp
))
129 for (j
= P
->Dimension
- nparam
; j
< P
->Dimension
; ++j
)
130 if (value_pos_p(P
->Ray
[r
][j
+1]))
132 assert(j
< P
->Dimension
);
133 value_pdivision(tmp
, P
->Ray
[r
][j
+1], P
->Ray
[r
][i
+1]);
134 value_subtract(M
->p
[i
][j
], M
->p
[i
][j
], tmp
);
140 D
= DomainImage(D
, M
, MaxRays
);
146 gen_fun
* barvinok_enumerate_union_series_with_options(Polyhedron
*D
, Polyhedron
* C
,
147 barvinok_options
*options
)
149 Polyhedron
*conv
, *D2
;
151 gen_fun
*gf
= NULL
, *gf2
;
152 unsigned nparam
= C
->Dimension
;
157 CA
= align_context(C
, D
->Dimension
, options
->MaxRays
);
158 D
= DomainIntersection(D
, CA
, options
->MaxRays
);
161 D2
= skew_into_positive_orthant(D
, nparam
, options
->MaxRays
);
162 for (Polyhedron
*P
= D2
; P
; P
= P
->next
) {
163 assert(P
->Dimension
== D2
->Dimension
);
166 P_gf
= barvinok_enumerate_series(P
, P
->Dimension
, options
);
170 gf
->add_union(P_gf
, options
);
174 /* we actually only need the convex union of the parameter space
175 * but the reducer classes currently expect a polyhedron in
178 Polyhedron_Free(gf
->context
);
179 gf
->context
= DomainConvex(D2
, options
->MaxRays
);
181 gf2
= gf
->summate(D2
->Dimension
- nparam
, options
);
190 gen_fun
* barvinok_enumerate_union_series(Polyhedron
*D
, Polyhedron
* C
,
194 barvinok_options
*options
= barvinok_options_new_with_defaults();
195 options
->MaxRays
= MaxRays
;
196 gf
= barvinok_enumerate_union_series_with_options(D
, C
, options
);
197 barvinok_options_free(options
);
201 /* Unimodularly transform the polyhedron P, such that
202 * the direction specified by dir corresponds to the last
203 * variable in the transformed polyhedron.
204 * The number of variables is given by the length of dir.
206 static Polyhedron
*put_direction_last(Polyhedron
*P
, Vector
*dir
,
213 T
= Matrix_Alloc(P
->Dimension
+1, P
->Dimension
+1);
214 T
->NbColumns
= T
->NbRows
= n
;
215 Vector_Copy(dir
->p
, T
->p
[0], n
);
216 unimodular_complete(T
, 1);
217 Vector_Exchange(T
->p
[0], T
->p
[n
-1], n
);
218 T
->NbColumns
= T
->NbRows
= P
->Dimension
+1;
219 for (int j
= n
; j
< P
->Dimension
+1; ++j
)
220 value_set_si(T
->p
[j
][j
], 1);
222 R
= Polyhedron_Image(P
, T
, MaxRays
);
228 /* Do we need to continue shifting and subtracting?
229 * i is the number of times we shifted so far
230 * n is the number of coordinates projected out
232 static bool more_shifts_needed(int j
, int n
,
233 gen_fun
*S
, gen_fun
*S_divide
, const vec_ZZ
& up
,
234 barvinok_options
*options
)
240 /* For the 2-dimensional case, we need to subtract at most once */
246 /* Assume that we have to subtract at least once */
250 hp
= S
->Hadamard_product(S_divide
, options
);
254 empty
= hp
->summate(&c
) && value_zero_p(c
);
262 /* Return gf of P projected on last dim(P)-n coordinates, i.e.,
263 * project out the first n coordinates.
265 gen_fun
*project(Polyhedron
*P
, unsigned n
, barvinok_options
*options
)
271 struct width_direction_array
*dirs
;
274 up
.SetLength(P
->Dimension
- (n
-1));
276 for (int i
= 1; i
< P
->Dimension
- (n
-1); ++i
)
280 gen_fun
*S
, *S_shift
, *hp
;
282 S
= barvinok_enumerate_series(P
, P
->Dimension
, options
);
283 S_shift
= new gen_fun(S
);
285 hp
= S
->Hadamard_product(S_shift
, options
);
286 S
->add(mone
, hp
, options
);
290 gf
= S
->summate(1, options
);
296 U
= Universe_Polyhedron(P
->Dimension
- n
);
297 dirs
= Polyhedron_Lattice_Width_Directions(P
, U
, options
);
300 for (int i
= 0; i
< dirs
->n
; ++i
) {
303 gen_fun
*S
, *S_shift
, *S_divide
, *sum
;
305 CA
= align_context(dirs
->wd
[i
].domain
, P
->Dimension
, options
->MaxRays
);
306 R
= DomainIntersection(P
, CA
, options
->MaxRays
);
308 assert(dirs
->wd
[i
].dir
->Size
== n
);
309 Pi
= put_direction_last(R
, dirs
->wd
[i
].dir
, options
->MaxRays
);
312 S
= project(Pi
, n
-1, options
);
315 S_shift
= new gen_fun(S
);
316 S_divide
= new gen_fun(S
);
317 S_divide
->divide(up
);
319 for (int j
= 0; more_shifts_needed(j
, n
, S
, S_divide
, up
, options
); ++j
) {
323 hp
= S
->Hadamard_product(S_shift
, options
);
324 S
->add(mone
, hp
, options
);
329 sum
= S
->summate(1, options
);
338 gf
->add(one
, sum
, options
);
342 free_width_direction_array(dirs
);
347 gen_fun
*barvinok_enumerate_e_series(Polyhedron
*P
,
348 unsigned exist
, unsigned nparam
, barvinok_options
*options
)
351 Polyhedron
*P_orig
= P
;
353 unsigned nvar
= P
->Dimension
- exist
- nparam
;
356 return barvinok_enumerate_series(P
, nparam
, options
);
359 return new gen_fun(Empty_Polyhedron(nparam
));
361 assert(!Polyhedron_is_unbounded(P
, nparam
, options
->MaxRays
));
362 assert(P
->NbBid
== 0);
363 assert(Polyhedron_has_revlex_positive_rays(P
, nparam
));
365 /* Move existentially quantified variables to the front.*/
368 T
= Matrix_Alloc(exist
+nvar
+nparam
+1, nvar
+exist
+nparam
+1);
369 for (int i
= 0; i
< exist
; ++i
)
370 value_set_si(T
->p
[i
][nvar
+i
], 1);
371 for (int i
= 0; i
< nvar
; ++i
)
372 value_set_si(T
->p
[exist
+i
][i
], 1);
373 for (int i
= 0; i
< nparam
+1; ++i
)
374 value_set_si(T
->p
[exist
+nvar
+i
][nvar
+exist
+i
], 1);
375 P
= Polyhedron_Image(P
, T
, options
->MaxRays
);
380 remove_all_equalities(&P
, NULL
, &CP
, NULL
, nvar
+nparam
,
382 exist
= P
->Dimension
- (CP
->NbColumns
-1);
387 proj
= project(P
, exist
, options
);
389 proj
->substitute(CP
);
399 gf
= proj
->summate(nvar
, options
);