2 #include <barvinok/util.h>
3 #include <barvinok/options.h>
5 #include "normalization.h"
9 #define ALLOC(type) (type*)malloc(sizeof(type))
11 void run_points2triangs(pid_t
*child
, int *in
, int *out
)
13 int in_fd
[2], out_fd
[2];
31 rc
= execl(POINTS2TRIANGS_PATH
, "points2triangs", "--regular", NULL
);
45 static Param_Vertices
*construct_vertex(unsigned *vertex_facets
,
47 int d
, unsigned nparam
, unsigned MaxRays
)
49 unsigned nvar
= Constraints
->NbColumns
-2 - nparam
;
50 Matrix
*A
= Matrix_Alloc(nvar
+1, nvar
+1);
51 Matrix
*inv
= Matrix_Alloc(nvar
+1, nvar
+1);
52 Matrix
*B
= Matrix_Alloc(nvar
, nparam
+2);
53 Matrix
*V
= Matrix_Alloc(nvar
, nparam
+2);
54 Matrix
*Domain
= Matrix_Alloc(d
-nvar
, nparam
+2);
59 Param_Vertices
*vertex
;
61 for (j
= 0, i
= 0, ix
= 0, bx
= MSB
; i
< d
; ++i
) {
62 if ((vertex_facets
[ix
] & bx
) == bx
) {
63 Vector_Copy(Constraints
->p
[i
]+1, A
->p
[j
], nvar
);
64 Vector_Oppose(Constraints
->p
[i
]+1+nvar
, B
->p
[j
++], nparam
+1);
69 value_set_si(A
->p
[nvar
][nvar
], 1);
70 ok
= Matrix_Inverse(A
, inv
);
74 inv
->NbColumns
= nvar
;
75 Matrix_Product(inv
, B
, V
);
77 for (i
= 0; i
< nvar
; ++i
) {
78 value_assign(V
->p
[i
][nparam
+1], inv
->p
[nvar
][nvar
]);
79 Vector_Normalize(V
->p
[i
], V
->NbColumns
);
82 for (j
= 0, i
= 0, ix
= 0, bx
= MSB
; i
< d
; ++i
) {
83 if ((vertex_facets
[ix
] & bx
) == bx
) {
87 Param_Inner_Product(Constraints
->p
[i
], V
, Domain
->p
[j
]);
88 if (First_Non_Zero(Domain
->p
[j
]+1, nparam
+1) == -1)
89 vertex_facets
[ix
] |= bx
;
91 value_set_si(Domain
->p
[j
++][0], 1);
95 A
= Matrix_Copy(Domain
);
96 AD
= Constraints2Polyhedron(A
, MaxRays
);
98 POL_ENSURE_VERTICES(AD
);
99 /* A vertex with a lower-dimensional activity domain
100 * saturates more facets than derived above and is actually
101 * the superimposition of two or more vertices.
102 * We therefore discard the domain and (ultimately)
103 * the chamber containing it.
104 * We keep the vertex, though, since it may reappear
105 * in other chambers, which will then likewise be discarded.
106 * The same holds if the activity domain is empty.
113 vertex
= calloc(1, sizeof(Param_Vertices
));
114 vertex
->Facets
= vertex_facets
;
116 vertex
->Domain
= Domain
;
120 static int add_vertex_to_domain(Param_Vertices
**vertices
, int words
,
121 unsigned *vertex_facets
,
122 Matrix
*Constraints
, int d
, unsigned nparam
,
123 struct domain
*domain
,
126 Param_Vertices
*vertex
;
130 for (vi
= 0, vix
= 0, vbx
= MSB
;
132 vertices
= &(*vertices
)->next
, ++vi
) {
134 for (i
= 0; i
< words
; ++i
)
135 if (((*vertices
)->Facets
[i
] & vertex_facets
[i
]) != vertex_facets
[i
])
138 if (!(*vertices
)->Domain
)
141 domain
->domain
.F
[vix
] |= vbx
;
147 if (domain
->F_len
<= vix
) {
149 domain
->domain
.F
= realloc(domain
->domain
.F
,
150 domain
->F_len
* sizeof(unsigned));
151 domain
->domain
.F
[domain
->F_len
-1] = 0;
153 vertex
= construct_vertex(vertex_facets
, Constraints
, d
, nparam
, MaxRays
);
157 domain
->domain
.F
[vix
] |= vbx
;
158 vertex
->next
= *vertices
;
163 static void compute_domain(struct domain
*domain
, Param_Vertices
*vertices
,
164 Polyhedron
*C
, unsigned MaxRays
)
168 int nbV
= bit_vector_count(domain
->domain
.F
, domain
->F_len
);
173 for (ix
= 0, bx
= MSB
; !vertices
->Domain
; vertices
= vertices
->next
)
176 cols
= vertices
->Domain
->NbColumns
;
177 rows
= vertices
->Domain
->NbRows
;
178 Constraints
= Matrix_Alloc(nbV
* rows
+ C
->NbConstraints
, cols
);
180 for (j
= 0; vertices
; vertices
= vertices
->next
) {
181 if ((domain
->domain
.F
[ix
] & bx
) == bx
)
182 Vector_Copy(vertices
->Domain
->p
[0],
183 Constraints
->p
[(j
++)*rows
], rows
* cols
);
186 Vector_Copy(C
->Constraint
[0], Constraints
->p
[j
*rows
], C
->NbConstraints
* cols
);
187 domain
->domain
.Domain
= Constraints2Polyhedron(Constraints
, MaxRays
);
188 Matrix_Free(Constraints
);
191 static void add_domain(struct domain
**domains
, struct domain
*domain
,
192 Param_Vertices
*vertices
, Polyhedron
*C
,
193 struct barvinok_options
*options
)
195 options
->stats
->topcom_chambers
++;
197 for (; *domains
; domains
= (struct domain
**)&(*domains
)->domain
.next
) {
199 for (i
= 0; i
< (*domains
)->F_len
; ++i
)
200 if (((*domains
)->domain
.F
[i
] & domain
->domain
.F
[i
])
201 != domain
->domain
.F
[i
])
203 if (i
< (*domains
)->F_len
)
205 for (; i
< domain
->F_len
; ++i
)
206 if (domain
->domain
.F
[i
])
208 if (i
>= domain
->F_len
) {
209 Param_Domain_Free(&domain
->domain
);
213 options
->stats
->topcom_distinct_chambers
++;
214 compute_domain(domain
, vertices
, C
, options
->MaxRays
);
218 #define INT_BITS (sizeof(unsigned) * 8)
220 /* Remove any empty or lower-dimensional chamber. The latter
221 * lie on the boundary of the context and are facets of other chambers.
223 * While we are examining each chamber, also extend the F vector
224 * of each chamber to the maximum.
226 static void remove_empty_chambers(Param_Domain
**PD
, unsigned vertex_words
)
232 if ((*PD
)->Domain
->NbEq
> 0)
235 POL_ENSURE_FACETS((*PD
)->Domain
);
236 if ((*PD
)->Domain
->NbEq
> 0)
240 Param_Domain
*D
= *PD
;
243 Param_Domain_Free(D
);
246 if ((i
= ((struct domain
*)(*PD
))->F_len
) < vertex_words
)
247 (*PD
)->F
= realloc((*PD
)->F
, vertex_words
* sizeof(unsigned));
248 for (; i
< vertex_words
; ++i
)
254 static Param_Polyhedron
*points2triangs(Matrix
*K
, Polyhedron
*P
, Polyhedron
*C
,
255 struct barvinok_options
*options
)
262 int words
= (d
+INT_BITS
-1)/INT_BITS
;
263 Param_Vertices
*vertices
= NULL
;
264 struct domain
*domains
= NULL
;
265 int vertex_words
= 1;
266 Param_Polyhedron
*PP
= ALLOC(Param_Polyhedron
);
267 unsigned MaxRays
= options
->MaxRays
;
271 PP
->Constraints
= Polyhedron2Constraints(P
);
272 /* We need the exact facets, because we may make some of them open later */
273 POL_UNSET(options
->MaxRays
, POL_INTEGER
);
275 run_points2triangs(&child
, &in
, &out
);
277 fin
= fdopen(in
, "w");
279 for (i
= 0; i
< K
->NbRows
; ++i
) {
281 for (j
= 0; j
< K
->NbColumns
; ++j
)
282 value_print(fin
, P_VALUE_FMT
, K
->p
[i
][j
]);
288 fout
= fdopen(out
, "r");
289 while (fscanf(fout
, "T[%d]:=", &i
) == 1) {
291 struct domain
*domain
= ALLOC(struct domain
);
292 memset(domain
, 0, sizeof(*domain
));
293 domain
->domain
.F
= calloc(vertex_words
, sizeof(unsigned));
294 domain
->F_len
= vertex_words
;
298 fscanf(fout
, "%d,%d:{", &a
, &b
);
300 while (fgetc(fout
) == '{') { /* '{' or closing '}' */
302 unsigned *F
= calloc(words
, sizeof(unsigned));
304 for (j
= 0; j
< K
->NbColumns
; ++j
) {
306 fscanf(fout
, "%d", &v
);
307 shift
= INT_BITS
- (v
% INT_BITS
) - 1;
308 F
[v
/ INT_BITS
] |= 1u << shift
;
309 fgetc(fout
); /* , or } */
313 else if (add_vertex_to_domain(&vertices
, words
, F
, PP
->Constraints
,
315 domain
, options
->MaxRays
))
317 if ((c
= fgetc(fout
)) != ',') /* , or } */
321 vertex_words
= domain
->F_len
;
325 fgetc(fout
); /* \n */
326 if (bit_vector_count(domain
->domain
.F
, domain
->F_len
) > 0)
327 add_domain(&domains
, domain
, vertices
, C
, options
);
329 options
->stats
->topcom_empty_chambers
++;
330 Param_Domain_Free(&domain
->domain
);
336 PP
->D
= &domains
->domain
;
338 remove_empty_chambers(&PP
->D
, vertex_words
);
340 options
->MaxRays
= MaxRays
;
345 /* Assumes M is of full row rank */
346 static Matrix
*null_space(Matrix
*M
)
352 left_hermite(M
, &H
, &Q
, &U
);
353 N
= Matrix_Alloc(M
->NbColumns
, M
->NbColumns
- M
->NbRows
);
354 for (i
= 0; i
< N
->NbRows
; ++i
)
355 Vector_Copy(U
->p
[i
] + M
->NbRows
, N
->p
[i
], N
->NbColumns
);
362 static void SwapColumns(Value
**V
, int n
, int i
, int j
)
366 for (r
= 0; r
< n
; ++r
)
367 value_swap(V
[r
][i
], V
[r
][j
]);
370 /* C is assumed to be the "true" context, i.e., it has been intersected
371 * with the projection of P onto the parameter space.
372 * Furthermore, P and C are assumed to be full-dimensional.
374 Param_Polyhedron
*TC_P2PP(Polyhedron
*P
, Polyhedron
*C
,
375 struct barvinok_options
*options
)
377 unsigned nparam
= C
->Dimension
;
378 unsigned nvar
= P
->Dimension
- C
->Dimension
;
384 Param_Polyhedron
*PP
;
387 assert(C
->NbEq
== 0);
389 Polyhedron_Matrix_View(P
, &M
, P
->NbConstraints
);
390 H
= standard_constraints(&M
, nparam
, &rows
, NULL
);
392 A
= Matrix_Alloc(rows
, nvar
+rows
);
393 for (i
= nvar
; i
< H
->NbRows
; ++i
) {
394 Vector_Oppose(H
->p
[i
], A
->p
[i
-nvar
], H
->NbColumns
);
395 value_set_si(A
->p
[i
-nvar
][i
], 1);
397 for (i
= 0, j
= H
->NbRows
-nvar
; i
< nvar
; ++i
) {
398 if (First_Non_Zero(H
->p
[i
], i
) == -1)
400 Vector_Oppose(H
->p
[i
], A
->p
[j
], H
->NbColumns
);
401 value_set_si(A
->p
[j
][j
+nvar
], 1);
402 SwapColumns(A
->p
, A
->NbRows
, j
+nvar
, i
);
407 /* Ignore extra constraints */
408 K
->NbRows
= H
->NbRows
;
410 PP
= points2triangs(K
, P
, C
, options
);