4 #include <NTL/mat_ZZ.h>
6 #include <barvinok/barvinok.h>
7 #include <barvinok/util.h>
8 #include "conversion.h"
9 #include "decomposer.h"
17 * Returns the largest absolute value in the vector
19 static ZZ
max(vec_ZZ
& v
)
22 for (int i
= 1; i
< v
.length(); ++i
)
30 cone(const mat_ZZ
& r
, int row
, const vec_ZZ
& w
) {
36 cone(const signed_cone
& sc
) {
39 set_closed(sc
.closed
);
42 det
= determinant(rays
);
44 void set_closed(int *cl
) {
47 closed
= new int[rays
.NumRows()];
48 for (int i
= 0; i
< rays
.NumRows(); ++i
)
53 void short_vector(vec_ZZ
& v
, vec_ZZ
& lambda
, barvinok_options
*options
) {
54 Matrix
*M
= rays2matrix(rays
);
55 Matrix
*inv
= Matrix_Alloc(M
->NbRows
, M
->NbColumns
);
56 int ok
= Matrix_Inverse(M
, inv
);
63 matrix2zz(inv
, B
, inv
->NbRows
- 1, inv
->NbColumns
- 1);
64 long r
= LLL(det2
, B
, U
, options
->LLL_a
, options
->LLL_b
);
68 for (int i
= 1; i
< B
.NumRows(); ++i
) {
83 for (i
= 0; i
< lambda
.length(); ++i
)
86 if (i
== lambda
.length()) {
102 static void decompose(const signed_cone
& sc
, signed_cone_consumer
& scc
,
103 barvinok_options
*options
)
105 vector
<cone
*> nonuni
;
106 cone
* c
= new cone(sc
);
114 options
->stats
.unimodular_cones
++;
115 scc
.handle(sc
, options
);
125 int closed
[c
->rays
.NumRows()];
126 while (!nonuni
.empty()) {
129 c
->short_vector(v
, lambda
, options
);
130 for (int i
= 0; i
< c
->rays
.NumRows(); ++i
) {
133 cone
*pc
= new cone(c
->rays
, i
, v
);
135 for (int j
= 0; j
< c
->rays
.NumRows(); ++j
) {
137 closed
[j
] = c
->closed
[j
];
140 closed
[j
] = c
->closed
[j
];
142 closed
[j
] = !c
->closed
[j
];
143 } else if (sign(lambda
[i
]) == sign(lambda
[j
])) {
144 if (c
->closed
[i
] == c
->closed
[j
])
147 closed
[j
] = c
->closed
[j
];
149 closed
[j
] = c
->closed
[i
] && c
->closed
[j
];
151 pc
->set_closed(closed
);
153 assert (pc
->det
!= 0);
154 if (abs(pc
->det
) > 1) {
155 assert(abs(pc
->det
) < abs(c
->det
));
156 nonuni
.push_back(pc
);
159 options
->stats
.unimodular_cones
++;
161 scc
.handle(signed_cone(pc
->rays
, sign(pc
->det
) * s
,
162 pc
->closed
), options
);
164 scc
.handle(signed_cone(pc
->rays
, sign(pc
->det
) * s
),
170 while (!nonuni
.empty()) {
183 struct polar_signed_cone_consumer
: public signed_cone_consumer
{
184 signed_cone_consumer
& scc
;
186 polar_signed_cone_consumer(signed_cone_consumer
& scc
) : scc(scc
) {}
187 virtual void handle(const signed_cone
& sc
, barvinok_options
*options
) {
188 Polyhedron
*C
= sc
.C
;
190 Matrix
*M
= Matrix_Alloc(sc
.rays
.NumRows()+1, sc
.rays
.NumCols()+2);
191 for (int i
= 0; i
< sc
.rays
.NumRows(); ++i
) {
192 zz2values(sc
.rays
[i
], M
->p
[i
]+1);
193 value_set_si(M
->p
[i
][0], 1);
195 value_set_si(M
->p
[sc
.rays
.NumRows()][0], 1);
196 value_set_si(M
->p
[sc
.rays
.NumRows()][1+sc
.rays
.NumCols()], 1);
197 C
= Rays2Polyhedron(M
, M
->NbRows
+1);
198 assert(C
->NbConstraints
== C
->NbRays
);
201 Polyhedron_Polarize(C
);
203 scc
.handle(signed_cone(C
, r
, sc
.sign
), options
);
209 static void polar_decompose(Polyhedron
*cone
, signed_cone_consumer
& scc
,
210 barvinok_options
*options
)
212 POL_ENSURE_VERTICES(cone
);
213 Polyhedron_Polarize(cone
);
214 if (cone
->NbRays
- 1 != cone
->Dimension
) {
215 Polyhedron
*tmp
= cone
;
216 cone
= triangulate_cone(cone
, options
->MaxRays
);
217 Polyhedron_Free(tmp
);
219 polar_signed_cone_consumer
pssc(scc
);
222 for (Polyhedron
*Polar
= cone
; Polar
; Polar
= Polar
->next
) {
224 decompose(signed_cone(Polar
, r
, 1), pssc
, options
);
233 static void primal_decompose(Polyhedron
*cone
, signed_cone_consumer
& scc
,
234 barvinok_options
*options
)
236 POL_ENSURE_VERTICES(cone
);
238 if (cone
->NbRays
- 1 == cone
->Dimension
)
241 parts
= triangulate_cone(cone
, options
->MaxRays
);
242 int closed
[cone
->Dimension
];
243 Vector
*average
= NULL
;
247 average
= Vector_Alloc(cone
->Dimension
);
248 for (int i
= 0; i
< cone
->NbRays
; ++i
) {
249 if (value_notzero_p(cone
->Ray
[i
][1+cone
->Dimension
]))
251 Vector_Add(average
->p
, cone
->Ray
[i
]+1, average
->p
, cone
->Dimension
);
256 for (Polyhedron
*simple
= parts
; simple
; simple
= simple
->next
) {
257 for (int i
= 0, r
= 0; r
< simple
->NbRays
; ++r
) {
258 if (value_notzero_p(simple
->Ray
[r
][1+simple
->Dimension
]))
260 if (simple
== cone
) {
264 for (f
= 0; f
< simple
->NbConstraints
; ++f
) {
265 Inner_Product(simple
->Ray
[r
]+1, simple
->Constraint
[f
]+1,
266 simple
->Dimension
, &tmp
);
267 if (value_notzero_p(tmp
))
270 assert(f
< simple
->NbConstraints
);
271 Inner_Product(simple
->Constraint
[f
]+1, average
->p
,
272 simple
->Dimension
, &tmp
);
273 if (value_notzero_p(tmp
))
274 closed
[i
] = value_pos_p(tmp
);
276 int p
= First_Non_Zero(simple
->Constraint
[f
]+1,
278 closed
[i
] = value_pos_p(simple
->Constraint
[f
][1+p
]);
284 decompose(signed_cone(simple
, ray
, 1, closed
), scc
, options
);
290 Vector_Free(average
);
297 Vector_Free(average
);
303 void barvinok_decompose(Polyhedron
*C
, signed_cone_consumer
& scc
,
304 barvinok_options
*options
)
307 primal_decompose(C
, scc
, options
);
309 polar_decompose(C
, scc
, options
);
312 void vertex_decomposer::decompose_at_vertex(Param_Vertices
*V
, int _i
,
313 barvinok_options
*options
)
315 Polyhedron
*C
= supporting_cone_p(P
, V
);
319 barvinok_decompose(C
, scc
, options
);
322 struct posneg_collector
: public signed_cone_consumer
{
323 posneg_collector(Polyhedron
*pos
, Polyhedron
*neg
) : pos(pos
), neg(neg
) {}
324 virtual void handle(const signed_cone
& sc
, barvinok_options
*options
) {
325 Polyhedron
*p
= Polyhedron_Copy(sc
.C
);
339 * Barvinok's Decomposition of a simplicial cone
341 * Returns two lists of polyhedra
343 void barvinok_decompose(Polyhedron
*C
, Polyhedron
**ppos
, Polyhedron
**pneg
)
345 barvinok_options
*options
= barvinok_options_new_with_defaults();
346 posneg_collector
pc(*ppos
, *pneg
);
347 POL_ENSURE_VERTICES(C
);
350 decompose(signed_cone(C
, r
, 1), pc
, options
);