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
);
169 unsigned cols
= vertices
->Domain
->NbColumns
;
170 unsigned rows
= vertices
->Domain
->NbRows
;
171 Matrix
*Constraints
= Matrix_Alloc(nbV
* rows
+ C
->NbConstraints
, cols
);
173 for (i
= 0, j
= 0, ix
= 0, bx
= MSB
;
175 vertices
= vertices
->next
, ++i
) {
176 if ((domain
->domain
.F
[ix
] & bx
) == bx
)
177 Vector_Copy(vertices
->Domain
->p
[0],
178 Constraints
->p
[(j
++)*rows
], rows
* cols
);
181 Vector_Copy(C
->Constraint
[0], Constraints
->p
[j
*rows
], C
->NbConstraints
* cols
);
182 domain
->domain
.Domain
= Constraints2Polyhedron(Constraints
, MaxRays
);
183 Matrix_Free(Constraints
);
186 static void add_domain(struct domain
**domains
, struct domain
*domain
,
187 Param_Vertices
*vertices
, Polyhedron
*C
,
188 struct barvinok_options
*options
)
190 options
->stats
->topcom_chambers
++;
192 for (; *domains
; domains
= (struct domain
**)&(*domains
)->domain
.next
) {
194 for (i
= 0; i
< (*domains
)->F_len
; ++i
)
195 if (((*domains
)->domain
.F
[i
] & domain
->domain
.F
[i
])
196 != domain
->domain
.F
[i
])
198 if (i
< (*domains
)->F_len
)
200 for (; i
< domain
->F_len
; ++i
)
201 if (domain
->domain
.F
[i
])
203 if (i
>= domain
->F_len
) {
204 Param_Domain_Free(&domain
->domain
);
208 options
->stats
->topcom_distinct_chambers
++;
209 compute_domain(domain
, vertices
, C
, options
->MaxRays
);
213 #define INT_BITS (sizeof(unsigned) * 8)
215 /* Remove any empty or lower-dimensional chamber. The latter
216 * lie on the boundary of the context and are facets of other chambers.
218 * While we are examining each chamber, also extend the F vector
219 * of each chamber to the maximum.
221 static void remove_empty_chambers(Param_Domain
**PD
, unsigned vertex_words
)
227 if ((*PD
)->Domain
->NbEq
> 0)
230 POL_ENSURE_FACETS((*PD
)->Domain
);
231 if ((*PD
)->Domain
->NbEq
> 0)
235 Param_Domain
*D
= *PD
;
238 Param_Domain_Free(D
);
241 if ((i
= ((struct domain
*)(*PD
))->F_len
) < vertex_words
)
242 (*PD
)->F
= realloc((*PD
)->F
, vertex_words
* sizeof(unsigned));
243 for (; i
< vertex_words
; ++i
)
249 static Param_Polyhedron
*points2triangs(Matrix
*K
, Polyhedron
*P
, Polyhedron
*C
,
250 struct barvinok_options
*options
)
257 int words
= (d
+INT_BITS
-1)/INT_BITS
;
258 Param_Vertices
*vertices
= NULL
;
259 struct domain
*domains
= NULL
;
260 int vertex_words
= 1;
261 Param_Polyhedron
*PP
= ALLOC(Param_Polyhedron
);
262 unsigned MaxRays
= options
->MaxRays
;
265 PP
->Constraints
= Polyhedron2Constraints(P
);
266 /* We need the exact facets, because we may make some of them open later */
267 POL_UNSET(options
->MaxRays
, POL_INTEGER
);
269 run_points2triangs(&child
, &in
, &out
);
271 fin
= fdopen(in
, "w");
273 for (i
= 0; i
< K
->NbRows
; ++i
) {
275 for (j
= 0; j
< K
->NbColumns
; ++j
)
276 value_print(fin
, P_VALUE_FMT
, K
->p
[i
][j
]);
282 fout
= fdopen(out
, "r");
283 while (fscanf(fout
, "T[%d]:={", &i
) == 1) {
284 struct domain
*domain
= ALLOC(struct domain
);
285 memset(domain
, 0, sizeof(*domain
));
286 domain
->domain
.F
= calloc(vertex_words
, sizeof(unsigned));
287 domain
->F_len
= vertex_words
;
289 while (fgetc(fout
) == '{') { /* '{' or closing '}' */
291 unsigned *F
= calloc(words
, sizeof(unsigned));
293 for (j
= 0; j
< K
->NbColumns
; ++j
) {
295 fscanf(fout
, "%d", &v
);
296 shift
= INT_BITS
- (v
% INT_BITS
) - 1;
297 F
[v
/ INT_BITS
] |= 1u << shift
;
298 fgetc(fout
); /* , or } */
302 else if (add_vertex_to_domain(&vertices
, words
, F
, PP
->Constraints
,
304 domain
, options
->MaxRays
))
306 if ((c
= fgetc(fout
)) != ',') /* , or } */
310 vertex_words
= domain
->F_len
;
312 fgetc(fout
); /* \n */
313 if (bit_vector_count(domain
->domain
.F
, domain
->F_len
) > 0)
314 add_domain(&domains
, domain
, vertices
, C
, options
);
316 options
->stats
->topcom_empty_chambers
++;
317 Param_Domain_Free(&domain
->domain
);
323 PP
->D
= &domains
->domain
;
325 remove_empty_chambers(&PP
->D
, vertex_words
);
327 options
->MaxRays
= MaxRays
;
332 /* Assumes M is of full row rank */
333 static Matrix
*null_space(Matrix
*M
)
339 left_hermite(M
, &H
, &Q
, &U
);
340 N
= Matrix_Alloc(M
->NbColumns
, M
->NbColumns
- M
->NbRows
);
341 for (i
= 0; i
< N
->NbRows
; ++i
)
342 Vector_Copy(U
->p
[i
] + M
->NbRows
, N
->p
[i
], N
->NbColumns
);
349 static void SwapColumns(Value
**V
, int n
, int i
, int j
)
353 for (r
= 0; r
< n
; ++r
)
354 value_swap(V
[r
][i
], V
[r
][j
]);
357 /* C is assumed to be the "true" context, i.e., it has been intersected
358 * with the projection of P onto the parameter space.
359 * Furthermore, P and C are assumed to be full-dimensional.
361 Param_Polyhedron
*TC_P2PP(Polyhedron
*P
, Polyhedron
*C
,
362 struct barvinok_options
*options
)
364 unsigned nparam
= C
->Dimension
;
365 unsigned nvar
= P
->Dimension
- C
->Dimension
;
371 Param_Polyhedron
*PP
;
374 assert(C
->NbEq
== 0);
376 Polyhedron_Matrix_View(P
, &M
, P
->NbConstraints
);
377 H
= standard_constraints(&M
, nparam
, &rows
, NULL
);
379 A
= Matrix_Alloc(rows
, nvar
+rows
);
380 for (i
= nvar
; i
< H
->NbRows
; ++i
) {
381 Vector_Oppose(H
->p
[i
], A
->p
[i
-nvar
], H
->NbColumns
);
382 value_set_si(A
->p
[i
-nvar
][i
], 1);
384 for (i
= 0, j
= H
->NbRows
-nvar
; i
< nvar
; ++i
) {
385 if (First_Non_Zero(H
->p
[i
], i
) == -1)
387 Vector_Oppose(H
->p
[i
], A
->p
[j
], H
->NbColumns
);
388 value_set_si(A
->p
[j
][j
+nvar
], 1);
389 SwapColumns(A
->p
, A
->NbRows
, j
+nvar
, i
);
394 /* Ignore extra constraints */
395 K
->NbRows
= H
->NbRows
;
397 PP
= points2triangs(K
, P
, C
, options
);