2 #include <barvinok/util.h>
3 #include <barvinok/options.h>
5 #include "normalization.h"
6 #include "param_util.h"
10 #define ALLOC(type) (type*)malloc(sizeof(type))
12 void run_points2triangs(pid_t
*child
, int *in
, int *out
)
14 int in_fd
[2], out_fd
[2];
32 rc
= execl(POINTS2TRIANGS_PATH
, "points2triangs", "--regular", NULL
);
46 static Param_Vertices
*construct_vertex(unsigned *vertex_facets
,
48 int d
, unsigned nparam
, unsigned MaxRays
)
50 unsigned nvar
= Constraints
->NbColumns
-2 - nparam
;
51 Matrix
*A
= Matrix_Alloc(nvar
+1, nvar
+1);
52 Matrix
*inv
= Matrix_Alloc(nvar
+1, nvar
+1);
53 Matrix
*B
= Matrix_Alloc(nvar
, nparam
+2);
54 Matrix
*V
= Matrix_Alloc(nvar
, nparam
+2);
55 Matrix
*Domain
= Matrix_Alloc(d
-nvar
, nparam
+2);
60 Param_Vertices
*vertex
;
62 for (j
= 0, i
= 0, ix
= 0, bx
= MSB
; i
< d
; ++i
) {
63 if ((vertex_facets
[ix
] & bx
) == bx
) {
64 Vector_Copy(Constraints
->p
[i
]+1, A
->p
[j
], nvar
);
65 Vector_Oppose(Constraints
->p
[i
]+1+nvar
, B
->p
[j
++], nparam
+1);
70 value_set_si(A
->p
[nvar
][nvar
], 1);
71 ok
= Matrix_Inverse(A
, inv
);
75 inv
->NbColumns
= nvar
;
76 Matrix_Product(inv
, B
, V
);
78 for (i
= 0; i
< nvar
; ++i
) {
79 value_assign(V
->p
[i
][nparam
+1], inv
->p
[nvar
][nvar
]);
80 Vector_Normalize(V
->p
[i
], V
->NbColumns
);
83 for (j
= 0, i
= 0, ix
= 0, bx
= MSB
; i
< d
; ++i
) {
84 if ((vertex_facets
[ix
] & bx
) == bx
) {
88 Param_Inner_Product(Constraints
->p
[i
], V
, Domain
->p
[j
]);
89 if (First_Non_Zero(Domain
->p
[j
]+1, nparam
+1) == -1)
90 vertex_facets
[ix
] |= bx
;
92 value_set_si(Domain
->p
[j
++][0], 1);
96 A
= Matrix_Copy(Domain
);
97 AD
= Constraints2Polyhedron(A
, MaxRays
);
99 POL_ENSURE_VERTICES(AD
);
100 /* A vertex with a lower-dimensional activity domain
101 * saturates more facets than derived above and is actually
102 * the superimposition of two or more vertices.
103 * We therefore discard the domain and (ultimately)
104 * the chamber containing it.
105 * We keep the vertex, though, since it may reappear
106 * in other chambers, which will then likewise be discarded.
107 * The same holds if the activity domain is empty.
114 vertex
= calloc(1, sizeof(Param_Vertices
));
115 vertex
->Facets
= vertex_facets
;
117 vertex
->Domain
= Domain
;
121 static int add_vertex_to_domain(Param_Vertices
**vertices
, int words
,
122 unsigned *vertex_facets
,
123 Matrix
*Constraints
, int d
, unsigned nparam
,
124 struct domain
*domain
,
127 Param_Vertices
*vertex
;
131 for (vi
= 0, vix
= 0, vbx
= MSB
;
133 vertices
= &(*vertices
)->next
, ++vi
) {
135 for (i
= 0; i
< words
; ++i
)
136 if (((*vertices
)->Facets
[i
] & vertex_facets
[i
]) != vertex_facets
[i
])
139 if (!(*vertices
)->Domain
)
142 domain
->domain
.F
[vix
] |= vbx
;
148 if (domain
->F_len
<= vix
) {
150 domain
->domain
.F
= realloc(domain
->domain
.F
,
151 domain
->F_len
* sizeof(unsigned));
152 domain
->domain
.F
[domain
->F_len
-1] = 0;
154 vertex
= construct_vertex(vertex_facets
, Constraints
, d
, nparam
, MaxRays
);
158 domain
->domain
.F
[vix
] |= vbx
;
159 vertex
->next
= *vertices
;
164 static void compute_domain(struct domain
*domain
, Param_Vertices
*vertices
,
165 Polyhedron
*C
, unsigned MaxRays
)
169 int nbV
= bit_vector_count(domain
->domain
.F
, domain
->F_len
);
174 for (ix
= 0, bx
= MSB
; !vertices
->Domain
; vertices
= vertices
->next
)
177 cols
= vertices
->Domain
->NbColumns
;
178 rows
= vertices
->Domain
->NbRows
;
179 Constraints
= Matrix_Alloc(nbV
* rows
+ C
->NbConstraints
, cols
);
181 for (j
= 0; vertices
; vertices
= vertices
->next
) {
182 if ((domain
->domain
.F
[ix
] & bx
) == bx
)
183 Vector_Copy(vertices
->Domain
->p
[0],
184 Constraints
->p
[(j
++)*rows
], rows
* cols
);
187 Vector_Copy(C
->Constraint
[0], Constraints
->p
[j
*rows
], C
->NbConstraints
* cols
);
188 domain
->domain
.Domain
= Constraints2Polyhedron(Constraints
, MaxRays
);
189 Matrix_Free(Constraints
);
192 static void add_domain(struct domain
**domains
, struct domain
*domain
,
193 Param_Vertices
*vertices
, Polyhedron
*C
,
194 struct barvinok_options
*options
)
196 options
->stats
->topcom_chambers
++;
198 for (; *domains
; domains
= (struct domain
**)&(*domains
)->domain
.next
) {
200 for (i
= 0; i
< (*domains
)->F_len
; ++i
)
201 if (((*domains
)->domain
.F
[i
] & domain
->domain
.F
[i
])
202 != domain
->domain
.F
[i
])
204 if (i
< (*domains
)->F_len
)
206 for (; i
< domain
->F_len
; ++i
)
207 if (domain
->domain
.F
[i
])
209 if (i
>= domain
->F_len
) {
210 Param_Domain_Free(&domain
->domain
);
214 options
->stats
->topcom_distinct_chambers
++;
215 compute_domain(domain
, vertices
, C
, options
->MaxRays
);
219 #define INT_BITS (sizeof(unsigned) * 8)
221 /* Remove any empty or lower-dimensional chamber. The latter
222 * lie on the boundary of the context and are facets of other chambers.
224 * While we are examining each chamber, also extend the F vector
225 * of each chamber to the maximum.
227 static void remove_empty_chambers(Param_Domain
**PD
, unsigned vertex_words
)
233 if ((*PD
)->Domain
->NbEq
> 0)
236 POL_ENSURE_FACETS((*PD
)->Domain
);
237 if ((*PD
)->Domain
->NbEq
> 0)
241 Param_Domain
*D
= *PD
;
244 Param_Domain_Free(D
);
247 if ((i
= ((struct domain
*)(*PD
))->F_len
) < vertex_words
)
248 (*PD
)->F
= realloc((*PD
)->F
, vertex_words
* sizeof(unsigned));
249 for (; i
< vertex_words
; ++i
)
255 static Param_Polyhedron
*points2triangs(Matrix
*K
, Polyhedron
*P
, Polyhedron
*C
,
256 struct barvinok_options
*options
)
263 int words
= (d
+INT_BITS
-1)/INT_BITS
;
264 Param_Vertices
*vertices
= NULL
;
265 struct domain
*domains
= NULL
;
266 int vertex_words
= 1;
267 Param_Polyhedron
*PP
= ALLOC(Param_Polyhedron
);
268 unsigned MaxRays
= options
->MaxRays
;
272 PP
->Constraints
= Polyhedron2Constraints(P
);
273 /* We need the exact facets, because we may make some of them open later */
274 POL_UNSET(options
->MaxRays
, POL_INTEGER
);
276 run_points2triangs(&child
, &in
, &out
);
278 fin
= fdopen(in
, "w");
280 for (i
= 0; i
< K
->NbRows
; ++i
) {
282 for (j
= 0; j
< K
->NbColumns
; ++j
)
283 value_print(fin
, P_VALUE_FMT
, K
->p
[i
][j
]);
289 fout
= fdopen(out
, "r");
290 while (fscanf(fout
, "T[%d]:=", &i
) == 1) {
292 struct domain
*domain
= ALLOC(struct domain
);
293 memset(domain
, 0, sizeof(*domain
));
294 domain
->domain
.F
= calloc(vertex_words
, sizeof(unsigned));
295 domain
->F_len
= vertex_words
;
299 fscanf(fout
, "%d,%d:{", &a
, &b
);
301 while (fgetc(fout
) == '{') { /* '{' or closing '}' */
303 unsigned *F
= calloc(words
, sizeof(unsigned));
305 for (j
= 0; j
< K
->NbColumns
; ++j
) {
307 fscanf(fout
, "%d", &v
);
308 shift
= INT_BITS
- (v
% INT_BITS
) - 1;
309 F
[v
/ INT_BITS
] |= 1u << shift
;
310 fgetc(fout
); /* , or } */
314 else if (add_vertex_to_domain(&vertices
, words
, F
, PP
->Constraints
,
316 domain
, options
->MaxRays
))
318 if ((c
= fgetc(fout
)) != ',') /* , or } */
322 vertex_words
= domain
->F_len
;
326 fgetc(fout
); /* \n */
327 if (bit_vector_count(domain
->domain
.F
, domain
->F_len
) > 0)
328 add_domain(&domains
, domain
, vertices
, C
, options
);
330 options
->stats
->topcom_empty_chambers
++;
331 Param_Domain_Free(&domain
->domain
);
337 PP
->D
= &domains
->domain
;
339 remove_empty_chambers(&PP
->D
, vertex_words
);
341 options
->MaxRays
= MaxRays
;
346 /* Assumes M is of full row rank */
347 static Matrix
*null_space(Matrix
*M
)
353 left_hermite(M
, &H
, &Q
, &U
);
354 N
= Matrix_Alloc(M
->NbColumns
, M
->NbColumns
- M
->NbRows
);
355 for (i
= 0; i
< N
->NbRows
; ++i
)
356 Vector_Copy(U
->p
[i
] + M
->NbRows
, N
->p
[i
], N
->NbColumns
);
363 static void SwapColumns(Value
**V
, int n
, int i
, int j
)
367 for (r
= 0; r
< n
; ++r
)
368 value_swap(V
[r
][i
], V
[r
][j
]);
371 /* C is assumed to be the "true" context, i.e., it has been intersected
372 * with the projection of P onto the parameter space.
373 * Furthermore, P and C are assumed to be full-dimensional.
375 Param_Polyhedron
*TC_P2PP(Polyhedron
*P
, Polyhedron
*C
,
376 struct barvinok_options
*options
)
378 unsigned nparam
= C
->Dimension
;
379 unsigned nvar
= P
->Dimension
- C
->Dimension
;
385 Param_Polyhedron
*PP
;
388 assert(C
->NbEq
== 0);
390 Polyhedron_Matrix_View(P
, &M
, P
->NbConstraints
);
391 H
= standard_constraints(&M
, nparam
, &rows
, NULL
);
393 A
= Matrix_Alloc(rows
, nvar
+rows
);
394 for (i
= nvar
; i
< H
->NbRows
; ++i
) {
395 Vector_Oppose(H
->p
[i
], A
->p
[i
-nvar
], H
->NbColumns
);
396 value_set_si(A
->p
[i
-nvar
][i
], 1);
398 for (i
= 0, j
= H
->NbRows
-nvar
; i
< nvar
; ++i
) {
399 if (First_Non_Zero(H
->p
[i
], i
) == -1)
401 Vector_Oppose(H
->p
[i
], A
->p
[j
], H
->NbColumns
);
402 value_set_si(A
->p
[j
][j
+nvar
], 1);
403 SwapColumns(A
->p
, A
->NbRows
, j
+nvar
, i
);
408 /* Ignore extra constraints */
409 K
->NbRows
= H
->NbRows
;
411 PP
= points2triangs(K
, P
, C
, options
);