1 /*
2 * Copyright 2010 INRIA Saclay
3 *
4 * Use of this software is governed by the MIT license
5 *
6 * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
7 * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
8 * 91893 Orsay, France
9 */
10
11 #include <isl_map_private.h>
12 #include <isl/set.h>
13 #include <isl_space_private.h>
14 #include <isl_seq.h>
15 #include <isl_aff_private.h>
16 #include <isl_mat_private.h>
17 #include <isl_factorization.h>
18
19 /*
20 * Let C be a cone and define
21 *
22 * C' := { y | forall x in C : y x >= 0 }
23 *
24 * C' contains the coefficients of all linear constraints
25 * that are valid for C.
26 * Furthermore, C'' = C.
27 *
28 * If C is defined as { x | A x >= 0 }
29 * then any element in C' must be a non-negative combination
30 * of the rows of A, i.e., y = t A with t >= 0. That is,
31 *
32 * C' = { y | exists t >= 0 : y = t A }
33 *
34 * If any of the rows in A actually represents an equality, then
35 * also negative combinations of this row are allowed and so the
36 * non-negativity constraint on the corresponding element of t
37 * can be dropped.
38 *
39 * A polyhedron P = { x | b + A x >= 0 } can be represented
40 * in homogeneous coordinates by the cone
41 * C = { [z,x] | b z + A x >= and z >= 0 }
42 * The valid linear constraints on C correspond to the valid affine
43 * constraints on P.
44 * This is essentially Farkas' lemma.
45 *
46 * Since
47 * [ 1 0 ]
48 * [ w y ] = [t_0 t] [ b A ]
49 *
50 * we have
51 *
52 * C' = { w, y | exists t_0, t >= 0 : y = t A and w = t_0 + t b }
53 * or
54 *
55 * C' = { w, y | exists t >= 0 : y = t A and w - t b >= 0 }
56 *
57 * In practice, we introduce an extra variable (w), shifting all
58 * other variables to the right, and an extra inequality
59 * (w - t b >= 0) corresponding to the positivity constraint on
60 * the homogeneous coordinate.
61 *
62 * When going back from coefficients to solutions, we immediately
63 * plug in 1 for z, which corresponds to shifting all variables
64 * to the left, with the leftmost ending up in the constant position.
65 */
66
67 /* Add the given prefix to all named isl_dim_set dimensions in "space".
68 */
isl_space_prefix(__isl_take isl_space * space,const char * prefix)69 static __isl_give isl_space *isl_space_prefix(__isl_take isl_space *space,
70 const char *prefix)
71 {
72 int i;
73 isl_ctx *ctx;
74 isl_size nvar;
75 size_t prefix_len = strlen(prefix);
76
77 if (!space)
78 return NULL;
79
80 ctx = isl_space_get_ctx(space);
81 nvar = isl_space_dim(space, isl_dim_set);
82 if (nvar < 0)
83 return isl_space_free(space);
84
85 for (i = 0; i < nvar; ++i) {
86 const char *name;
87 char *prefix_name;
88
89 name = isl_space_get_dim_name(space, isl_dim_set, i);
90 if (!name)
91 continue;
92
93 prefix_name = isl_alloc_array(ctx, char,
94 prefix_len + strlen(name) + 1);
95 if (!prefix_name)
96 goto error;
97 memcpy(prefix_name, prefix, prefix_len);
98 strcpy(prefix_name + prefix_len, name);
99
100 space = isl_space_set_dim_name(space,
101 isl_dim_set, i, prefix_name);
102 free(prefix_name);
103 }
104
105 return space;
106 error:
107 isl_space_free(space);
108 return NULL;
109 }
110
111 /* Given a dimension specification of the solutions space, construct
112 * a dimension specification for the space of coefficients.
113 *
114 * In particular transform
115 *
116 * [params] -> { S }
117 *
118 * to
119 *
120 * { coefficients[[cst, params] -> S] }
121 *
122 * and prefix each dimension name with "c_".
123 */
isl_space_coefficients(__isl_take isl_space * space)124 static __isl_give isl_space *isl_space_coefficients(__isl_take isl_space *space)
125 {
126 isl_space *space_param;
127 isl_size nvar;
128 isl_size nparam;
129
130 nvar = isl_space_dim(space, isl_dim_set);
131 nparam = isl_space_dim(space, isl_dim_param);
132 if (nvar < 0 || nparam < 0)
133 return isl_space_free(space);
134 space_param = isl_space_copy(space);
135 space_param = isl_space_drop_dims(space_param, isl_dim_set, 0, nvar);
136 space_param = isl_space_move_dims(space_param, isl_dim_set, 0,
137 isl_dim_param, 0, nparam);
138 space_param = isl_space_prefix(space_param, "c_");
139 space_param = isl_space_insert_dims(space_param, isl_dim_set, 0, 1);
140 space_param = isl_space_set_dim_name(space_param,
141 isl_dim_set, 0, "c_cst");
142 space = isl_space_drop_dims(space, isl_dim_param, 0, nparam);
143 space = isl_space_prefix(space, "c_");
144 space = isl_space_join(isl_space_from_domain(space_param),
145 isl_space_from_range(space));
146 space = isl_space_wrap(space);
147 space = isl_space_set_tuple_name(space, isl_dim_set, "coefficients");
148
149 return space;
150 }
151
152 /* Drop the given prefix from all named dimensions of type "type" in "space".
153 */
isl_space_unprefix(__isl_take isl_space * space,enum isl_dim_type type,const char * prefix)154 static __isl_give isl_space *isl_space_unprefix(__isl_take isl_space *space,
155 enum isl_dim_type type, const char *prefix)
156 {
157 int i;
158 isl_size n;
159 size_t prefix_len = strlen(prefix);
160
161 n = isl_space_dim(space, type);
162 if (n < 0)
163 return isl_space_free(space);
164
165 for (i = 0; i < n; ++i) {
166 const char *name;
167
168 name = isl_space_get_dim_name(space, type, i);
169 if (!name)
170 continue;
171 if (strncmp(name, prefix, prefix_len))
172 continue;
173
174 space = isl_space_set_dim_name(space,
175 type, i, name + prefix_len);
176 }
177
178 return space;
179 }
180
181 /* Given a dimension specification of the space of coefficients, construct
182 * a dimension specification for the space of solutions.
183 *
184 * In particular transform
185 *
186 * { coefficients[[cst, params] -> S] }
187 *
188 * to
189 *
190 * [params] -> { S }
191 *
192 * and drop the "c_" prefix from the dimension names.
193 */
isl_space_solutions(__isl_take isl_space * space)194 static __isl_give isl_space *isl_space_solutions(__isl_take isl_space *space)
195 {
196 isl_size nparam;
197
198 space = isl_space_unwrap(space);
199 space = isl_space_drop_dims(space, isl_dim_in, 0, 1);
200 space = isl_space_unprefix(space, isl_dim_in, "c_");
201 space = isl_space_unprefix(space, isl_dim_out, "c_");
202 nparam = isl_space_dim(space, isl_dim_in);
203 if (nparam < 0)
204 return isl_space_free(space);
205 space = isl_space_move_dims(space,
206 isl_dim_param, 0, isl_dim_in, 0, nparam);
207 space = isl_space_range(space);
208
209 return space;
210 }
211
212 /* Return the rational universe basic set in the given space.
213 */
rational_universe(__isl_take isl_space * space)214 static __isl_give isl_basic_set *rational_universe(__isl_take isl_space *space)
215 {
216 isl_basic_set *bset;
217
218 bset = isl_basic_set_universe(space);
219 bset = isl_basic_set_set_rational(bset);
220
221 return bset;
222 }
223
224 /* Compute the dual of "bset" by applying Farkas' lemma.
225 * As explained above, we add an extra dimension to represent
226 * the coefficient of the constant term when going from solutions
227 * to coefficients (shift == 1) and we drop the extra dimension when going
228 * in the opposite direction (shift == -1).
229 * The dual can be created in an arbitrary space.
230 * The caller is responsible for putting the result in the appropriate space.
231 *
232 * If "bset" is (obviously) empty, then the way this emptiness
233 * is represented by the constraints does not allow for the application
234 * of the standard farkas algorithm. We therefore handle this case
235 * specifically and return the universe basic set.
236 */
farkas(__isl_take isl_basic_set * bset,int shift)237 static __isl_give isl_basic_set *farkas(__isl_take isl_basic_set *bset,
238 int shift)
239 {
240 int i, j, k;
241 isl_ctx *ctx;
242 isl_space *space;
243 isl_basic_set *dual = NULL;
244 isl_size total;
245
246 total = isl_basic_set_dim(bset, isl_dim_all);
247 if (total < 0)
248 return isl_basic_set_free(bset);
249
250 ctx = isl_basic_set_get_ctx(bset);
251 space = isl_space_set_alloc(ctx, 0, total + shift);
252 if (isl_basic_set_plain_is_empty(bset)) {
253 isl_basic_set_free(bset);
254 return rational_universe(space);
255 }
256
257 dual = isl_basic_set_alloc_space(space, bset->n_eq + bset->n_ineq,
258 total, bset->n_ineq + (shift > 0));
259 dual = isl_basic_set_set_rational(dual);
260
261 for (i = 0; i < bset->n_eq + bset->n_ineq; ++i) {
262 k = isl_basic_set_alloc_div(dual);
263 if (k < 0)
264 goto error;
265 isl_int_set_si(dual->div[k][0], 0);
266 }
267
268 for (i = 0; i < total; ++i) {
269 k = isl_basic_set_alloc_equality(dual);
270 if (k < 0)
271 goto error;
272 isl_seq_clr(dual->eq[k], 1 + shift + total);
273 isl_int_set_si(dual->eq[k][1 + shift + i], -1);
274 for (j = 0; j < bset->n_eq; ++j)
275 isl_int_set(dual->eq[k][1 + shift + total + j],
276 bset->eq[j][1 + i]);
277 for (j = 0; j < bset->n_ineq; ++j)
278 isl_int_set(dual->eq[k][1 + shift + total + bset->n_eq + j],
279 bset->ineq[j][1 + i]);
280 }
281
282 for (i = 0; i < bset->n_ineq; ++i) {
283 k = isl_basic_set_alloc_inequality(dual);
284 if (k < 0)
285 goto error;
286 isl_seq_clr(dual->ineq[k],
287 1 + shift + total + bset->n_eq + bset->n_ineq);
288 isl_int_set_si(dual->ineq[k][1 + shift + total + bset->n_eq + i], 1);
289 }
290
291 if (shift > 0) {
292 k = isl_basic_set_alloc_inequality(dual);
293 if (k < 0)
294 goto error;
295 isl_seq_clr(dual->ineq[k], 2 + total);
296 isl_int_set_si(dual->ineq[k][1], 1);
297 for (j = 0; j < bset->n_eq; ++j)
298 isl_int_neg(dual->ineq[k][2 + total + j],
299 bset->eq[j][0]);
300 for (j = 0; j < bset->n_ineq; ++j)
301 isl_int_neg(dual->ineq[k][2 + total + bset->n_eq + j],
302 bset->ineq[j][0]);
303 }
304
305 dual = isl_basic_set_remove_divs(dual);
306 dual = isl_basic_set_simplify(dual);
307 dual = isl_basic_set_finalize(dual);
308
309 isl_basic_set_free(bset);
310 return dual;
311 error:
312 isl_basic_set_free(bset);
313 isl_basic_set_free(dual);
314 return NULL;
315 }
316
317 /* Construct a basic set containing the tuples of coefficients of all
318 * valid affine constraints on the given basic set, ignoring
319 * the space of input and output and without any further decomposition.
320 */
isl_basic_set_coefficients_base(__isl_take isl_basic_set * bset)321 static __isl_give isl_basic_set *isl_basic_set_coefficients_base(
322 __isl_take isl_basic_set *bset)
323 {
324 return farkas(bset, 1);
325 }
326
327 /* Return the inverse mapping of "morph".
328 */
peek_inv(__isl_keep isl_morph * morph)329 static __isl_give isl_mat *peek_inv(__isl_keep isl_morph *morph)
330 {
331 return morph ? morph->inv : NULL;
332 }
333
334 /* Return a copy of the inverse mapping of "morph".
335 */
get_inv(__isl_keep isl_morph * morph)336 static __isl_give isl_mat *get_inv(__isl_keep isl_morph *morph)
337 {
338 return isl_mat_copy(peek_inv(morph));
339 }
340
341 /* Information about a single factor within isl_basic_set_coefficients_product.
342 *
343 * "start" is the position of the first coefficient (beyond
344 * the one corresponding to the constant term) in this factor.
345 * "dim" is the number of coefficients (other than
346 * the one corresponding to the constant term) in this factor.
347 * "n_line" is the number of lines in "coeff".
348 * "n_ray" is the number of rays (other than lines) in "coeff".
349 * "n_vertex" is the number of vertices in "coeff".
350 *
351 * While iterating over the vertices,
352 * "pos" represents the inequality constraint corresponding
353 * to the current vertex.
354 */
355 struct isl_coefficients_factor_data {
356 isl_basic_set *coeff;
357 int start;
358 int dim;
359 int n_line;
360 int n_ray;
361 int n_vertex;
362 int pos;
363 };
364
365 /* Internal data structure for isl_basic_set_coefficients_product.
366 * "n" is the number of factors in the factorization.
367 * "pos" is the next factor that will be considered.
368 * "start_next" is the position of the first coefficient (beyond
369 * the one corresponding to the constant term) in the next factor.
370 * "factors" contains information about the individual "n" factors.
371 */
372 struct isl_coefficients_product_data {
373 int n;
374 int pos;
375 int start_next;
376 struct isl_coefficients_factor_data *factors;
377 };
378
379 /* Initialize the internal data structure for
380 * isl_basic_set_coefficients_product.
381 */
isl_coefficients_product_data_init(isl_ctx * ctx,struct isl_coefficients_product_data * data,int n)382 static isl_stat isl_coefficients_product_data_init(isl_ctx *ctx,
383 struct isl_coefficients_product_data *data, int n)
384 {
385 data->n = n;
386 data->pos = 0;
387 data->start_next = 0;
388 data->factors = isl_calloc_array(ctx,
389 struct isl_coefficients_factor_data, n);
390 if (!data->factors)
391 return isl_stat_error;
392 return isl_stat_ok;
393 }
394
395 /* Free all memory allocated in "data".
396 */
isl_coefficients_product_data_clear(struct isl_coefficients_product_data * data)397 static void isl_coefficients_product_data_clear(
398 struct isl_coefficients_product_data *data)
399 {
400 int i;
401
402 if (data->factors) {
403 for (i = 0; i < data->n; ++i) {
404 isl_basic_set_free(data->factors[i].coeff);
405 }
406 }
407 free(data->factors);
408 }
409
410 /* Does inequality "ineq" in the (dual) basic set "bset" represent a ray?
411 * In particular, does it have a zero denominator
412 * (i.e., a zero coefficient for the constant term)?
413 */
is_ray(__isl_keep isl_basic_set * bset,int ineq)414 static int is_ray(__isl_keep isl_basic_set *bset, int ineq)
415 {
416 return isl_int_is_zero(bset->ineq[ineq][1]);
417 }
418
419 /* isl_factorizer_every_factor_basic_set callback that
420 * constructs a basic set containing the tuples of coefficients of all
421 * valid affine constraints on the factor "bset" and
422 * extracts further information that will be used
423 * when combining the results over the different factors.
424 */
isl_basic_set_coefficients_factor(__isl_keep isl_basic_set * bset,void * user)425 static isl_bool isl_basic_set_coefficients_factor(
426 __isl_keep isl_basic_set *bset, void *user)
427 {
428 struct isl_coefficients_product_data *data = user;
429 isl_basic_set *coeff;
430 isl_size n_eq, n_ineq, dim;
431 int i, n_ray, n_vertex;
432
433 coeff = isl_basic_set_coefficients_base(isl_basic_set_copy(bset));
434 data->factors[data->pos].coeff = coeff;
435 if (!coeff)
436 return isl_bool_error;
437
438 dim = isl_basic_set_dim(bset, isl_dim_set);
439 n_eq = isl_basic_set_n_equality(coeff);
440 n_ineq = isl_basic_set_n_inequality(coeff);
441 if (dim < 0 || n_eq < 0 || n_ineq < 0)
442 return isl_bool_error;
443 n_ray = n_vertex = 0;
444 for (i = 0; i < n_ineq; ++i) {
445 if (is_ray(coeff, i))
446 n_ray++;
447 else
448 n_vertex++;
449 }
450 data->factors[data->pos].start = data->start_next;
451 data->factors[data->pos].dim = dim;
452 data->factors[data->pos].n_line = n_eq;
453 data->factors[data->pos].n_ray = n_ray;
454 data->factors[data->pos].n_vertex = n_vertex;
455 data->pos++;
456 data->start_next += dim;
457
458 return isl_bool_true;
459 }
460
461 /* Clear an entry in the product, given that there is a "total" number
462 * of coefficients (other than that of the constant term).
463 */
clear_entry(isl_int * entry,int total)464 static void clear_entry(isl_int *entry, int total)
465 {
466 isl_seq_clr(entry, 1 + 1 + total);
467 }
468
469 /* Set the part of the entry corresponding to factor "data",
470 * from the factor coefficients in "src".
471 */
set_factor(isl_int * entry,isl_int * src,struct isl_coefficients_factor_data * data)472 static void set_factor(isl_int *entry, isl_int *src,
473 struct isl_coefficients_factor_data *data)
474 {
475 isl_seq_cpy(entry + 1 + 1 + data->start, src + 1 + 1, data->dim);
476 }
477
478 /* Set the part of the entry corresponding to factor "data",
479 * from the factor coefficients in "src" multiplied by "f".
480 */
scale_factor(isl_int * entry,isl_int * src,isl_int f,struct isl_coefficients_factor_data * data)481 static void scale_factor(isl_int *entry, isl_int *src, isl_int f,
482 struct isl_coefficients_factor_data *data)
483 {
484 isl_seq_scale(entry + 1 + 1 + data->start, src + 1 + 1, f, data->dim);
485 }
486
487 /* Add all lines from the given factor to "bset",
488 * given that there is a "total" number of coefficients
489 * (other than that of the constant term).
490 */
add_lines(__isl_take isl_basic_set * bset,struct isl_coefficients_factor_data * factor,int total)491 static __isl_give isl_basic_set *add_lines(__isl_take isl_basic_set *bset,
492 struct isl_coefficients_factor_data *factor, int total)
493 {
494 int i;
495
496 for (i = 0; i < factor->n_line; ++i) {
497 int k;
498
499 k = isl_basic_set_alloc_equality(bset);
500 if (k < 0)
501 return isl_basic_set_free(bset);
502 clear_entry(bset->eq[k], total);
503 set_factor(bset->eq[k], factor->coeff->eq[i], factor);
504 }
505
506 return bset;
507 }
508
509 /* Add all rays (other than lines) from the given factor to "bset",
510 * given that there is a "total" number of coefficients
511 * (other than that of the constant term).
512 */
add_rays(__isl_take isl_basic_set * bset,struct isl_coefficients_factor_data * data,int total)513 static __isl_give isl_basic_set *add_rays(__isl_take isl_basic_set *bset,
514 struct isl_coefficients_factor_data *data, int total)
515 {
516 int i;
517 int n_ineq = data->n_ray + data->n_vertex;
518
519 for (i = 0; i < n_ineq; ++i) {
520 int k;
521
522 if (!is_ray(data->coeff, i))
523 continue;
524
525 k = isl_basic_set_alloc_inequality(bset);
526 if (k < 0)
527 return isl_basic_set_free(bset);
528 clear_entry(bset->ineq[k], total);
529 set_factor(bset->ineq[k], data->coeff->ineq[i], data);
530 }
531
532 return bset;
533 }
534
535 /* Move to the first vertex of the given factor starting
536 * at inequality constraint "start", setting factor->pos and
537 * returning 1 if a vertex is found.
538 */
factor_first_vertex(struct isl_coefficients_factor_data * factor,int start)539 static int factor_first_vertex(struct isl_coefficients_factor_data *factor,
540 int start)
541 {
542 int j;
543 int n = factor->n_ray + factor->n_vertex;
544
545 for (j = start; j < n; ++j) {
546 if (is_ray(factor->coeff, j))
547 continue;
548 factor->pos = j;
549 return 1;
550 }
551
552 return 0;
553 }
554
555 /* Move to the first constraint in each factor starting at "first"
556 * that represents a vertex.
557 * In particular, skip the initial constraints that correspond to rays.
558 */
first_vertex(struct isl_coefficients_product_data * data,int first)559 static void first_vertex(struct isl_coefficients_product_data *data, int first)
560 {
561 int i;
562
563 for (i = first; i < data->n; ++i)
564 factor_first_vertex(&data->factors[i], 0);
565 }
566
567 /* Move to the next vertex in the product.
568 * In particular, move to the next vertex of the last factor.
569 * If all vertices of this last factor have already been considered,
570 * then move to the next vertex of the previous factor(s)
571 * until a factor is found that still has a next vertex.
572 * Once such a next vertex has been found, the subsequent
573 * factors are reset to the first vertex.
574 * Return 1 if any next vertex was found.
575 */
next_vertex(struct isl_coefficients_product_data * data)576 static int next_vertex(struct isl_coefficients_product_data *data)
577 {
578 int i;
579
580 for (i = data->n - 1; i >= 0; --i) {
581 struct isl_coefficients_factor_data *factor = &data->factors[i];
582
583 if (!factor_first_vertex(factor, factor->pos + 1))
584 continue;
585 first_vertex(data, i + 1);
586 return 1;
587 }
588
589 return 0;
590 }
591
592 /* Add a vertex to the product "bset" combining the currently selected
593 * vertices of the factors.
594 *
595 * In the dual representation, the constant term is always zero.
596 * The vertex itself is the sum of the contributions of the factors
597 * with a shared denominator in position 1.
598 *
599 * First compute the shared denominator (lcm) and
600 * then scale the numerators to this shared denominator.
601 */
add_vertex(__isl_take isl_basic_set * bset,struct isl_coefficients_product_data * data)602 static __isl_give isl_basic_set *add_vertex(__isl_take isl_basic_set *bset,
603 struct isl_coefficients_product_data *data)
604 {
605 int i;
606 int k;
607 isl_int lcm, f;
608
609 k = isl_basic_set_alloc_inequality(bset);
610 if (k < 0)
611 return isl_basic_set_free(bset);
612
613 isl_int_init(lcm);
614 isl_int_init(f);
615 isl_int_set_si(lcm, 1);
616 for (i = 0; i < data->n; ++i) {
617 struct isl_coefficients_factor_data *factor = &data->factors[i];
618 isl_basic_set *coeff = factor->coeff;
619 int pos = factor->pos;
620 isl_int_lcm(lcm, lcm, coeff->ineq[pos][1]);
621 }
622 isl_int_set_si(bset->ineq[k][0], 0);
623 isl_int_set(bset->ineq[k][1], lcm);
624
625 for (i = 0; i < data->n; ++i) {
626 struct isl_coefficients_factor_data *factor = &data->factors[i];
627 isl_basic_set *coeff = factor->coeff;
628 int pos = factor->pos;
629 isl_int_divexact(f, lcm, coeff->ineq[pos][1]);
630 scale_factor(bset->ineq[k], coeff->ineq[pos], f, factor);
631 }
632
633 isl_int_clear(f);
634 isl_int_clear(lcm);
635
636 return bset;
637 }
638
639 /* Combine the duals of the factors in the factorization of a basic set
640 * to form the dual of the entire basic set.
641 * The dual share the coefficient of the constant term.
642 * All other coefficients are specific to a factor.
643 * Any constraint not involving the coefficient of the constant term
644 * can therefor simply be copied into the appropriate position.
645 * This includes all equality constraints since the coefficient
646 * of the constant term can always be increased and therefore
647 * never appears in an equality constraint.
648 * The inequality constraints involving the coefficient of
649 * the constant term need to be combined across factors.
650 * In particular, if this coefficient needs to be greater than or equal
651 * to some linear combination of the other coefficients in each factor,
652 * then it needs to be greater than or equal to the sum of
653 * these linear combinations across the factors.
654 *
655 * Alternatively, the constraints of the dual can be seen
656 * as the vertices, rays and lines of the original basic set.
657 * Clearly, rays and lines can simply be copied,
658 * while vertices needs to be combined across factors.
659 * This means that the number of rays and lines in the product
660 * is equal to the sum of the numbers in the factors,
661 * while the number of vertices is the product
662 * of the number of vertices in the factors. Note that each
663 * factor has at least one vertex.
664 * The only exception is when the factor is the dual of an obviously empty set,
665 * in which case a universe dual is created.
666 * In this case, return a universe dual for the product as well.
667 *
668 * While constructing the vertices, look for the first combination
669 * of inequality constraints that represent a vertex,
670 * construct the corresponding vertex and then move on
671 * to the next combination of inequality constraints until
672 * all combinations have been considered.
673 */
construct_product(isl_ctx * ctx,struct isl_coefficients_product_data * data)674 static __isl_give isl_basic_set *construct_product(isl_ctx *ctx,
675 struct isl_coefficients_product_data *data)
676 {
677 int i;
678 int n_line, n_ray, n_vertex;
679 int total;
680 isl_space *space;
681 isl_basic_set *product;
682
683 if (!data->factors)
684 return NULL;
685
686 total = data->start_next;
687
688 n_line = 0;
689 n_ray = 0;
690 n_vertex = 1;
691 for (i = 0; i < data->n; ++i) {
692 n_line += data->factors[i].n_line;
693 n_ray += data->factors[i].n_ray;
694 n_vertex *= data->factors[i].n_vertex;
695 }
696
697 space = isl_space_set_alloc(ctx, 0, 1 + total);
698 if (n_vertex == 0)
699 return rational_universe(space);
700 product = isl_basic_set_alloc_space(space, 0, n_line, n_ray + n_vertex);
701 product = isl_basic_set_set_rational(product);
702
703 for (i = 0; i < data->n; ++i)
704 product = add_lines(product, &data->factors[i], total);
705 for (i = 0; i < data->n; ++i)
706 product = add_rays(product, &data->factors[i], total);
707
708 first_vertex(data, 0);
709 do {
710 product = add_vertex(product, data);
711 } while (next_vertex(data));
712
713 return product;
714 }
715
716 /* Given a factorization "f" of a basic set,
717 * construct a basic set containing the tuples of coefficients of all
718 * valid affine constraints on the product of the factors, ignoring
719 * the space of input and output.
720 * Note that this product may not be equal to the original basic set,
721 * if a non-trivial transformation is involved.
722 * This is handled by the caller.
723 *
724 * Compute the tuples of coefficients for each factor separately and
725 * then combine the results.
726 */
isl_basic_set_coefficients_product(__isl_take isl_factorizer * f)727 static __isl_give isl_basic_set *isl_basic_set_coefficients_product(
728 __isl_take isl_factorizer *f)
729 {
730 struct isl_coefficients_product_data data;
731 isl_ctx *ctx;
732 isl_basic_set *coeff;
733 isl_bool every;
734
735 ctx = isl_factorizer_get_ctx(f);
736 if (isl_coefficients_product_data_init(ctx, &data, f->n_group) < 0)
737 f = isl_factorizer_free(f);
738 every = isl_factorizer_every_factor_basic_set(f,
739 &isl_basic_set_coefficients_factor, &data);
740 isl_factorizer_free(f);
741 if (every >= 0)
742 coeff = construct_product(ctx, &data);
743 else
744 coeff = NULL;
745 isl_coefficients_product_data_clear(&data);
746
747 return coeff;
748 }
749
750 /* Given a factorization "f" of a basic set,
751 * construct a basic set containing the tuples of coefficients of all
752 * valid affine constraints on the basic set, ignoring
753 * the space of input and output.
754 *
755 * The factorization may involve a linear transformation of the basic set.
756 * In particular, the transformed basic set is formulated
757 * in terms of x' = U x, i.e., x = V x', with V = U^{-1}.
758 * The dual is then computed in terms of y' with y'^t [z; x'] >= 0.
759 * Plugging in y' = [1 0; 0 V^t] y yields
760 * y^t [1 0; 0 V] [z; x'] >= 0, i.e., y^t [z; x] >= 0, which is
761 * the desired set of coefficients y.
762 * Note that this transformation to y' only needs to be applied
763 * if U is not the identity matrix.
764 */
isl_basic_set_coefficients_morphed_product(__isl_take isl_factorizer * f)765 static __isl_give isl_basic_set *isl_basic_set_coefficients_morphed_product(
766 __isl_take isl_factorizer *f)
767 {
768 isl_bool is_identity;
769 isl_space *space;
770 isl_mat *inv;
771 isl_multi_aff *ma;
772 isl_basic_set *coeff;
773
774 if (!f)
775 goto error;
776 is_identity = isl_mat_is_scaled_identity(peek_inv(f->morph));
777 if (is_identity < 0)
778 goto error;
779 if (is_identity)
780 return isl_basic_set_coefficients_product(f);
781
782 inv = get_inv(f->morph);
783 inv = isl_mat_transpose(inv);
784 inv = isl_mat_lin_to_aff(inv);
785
786 coeff = isl_basic_set_coefficients_product(f);
787 space = isl_space_map_from_set(isl_basic_set_get_space(coeff));
788 ma = isl_multi_aff_from_aff_mat(space, inv);
789 coeff = isl_basic_set_preimage_multi_aff(coeff, ma);
790
791 return coeff;
792 error:
793 isl_factorizer_free(f);
794 return NULL;
795 }
796
797 /* Construct a basic set containing the tuples of coefficients of all
798 * valid affine constraints on the given basic set, ignoring
799 * the space of input and output.
800 *
801 * The caller has already checked that "bset" does not involve
802 * any local variables. It may have parameters, though.
803 * Treat them as regular variables internally.
804 * This is especially important for the factorization,
805 * since the (original) parameters should be taken into account
806 * explicitly in this factorization.
807 *
808 * Check if the basic set can be factorized.
809 * If so, compute constraints on the coefficients of the factors
810 * separately and combine the results.
811 * Otherwise, compute the results for the input basic set as a whole.
812 */
basic_set_coefficients(__isl_take isl_basic_set * bset)813 static __isl_give isl_basic_set *basic_set_coefficients(
814 __isl_take isl_basic_set *bset)
815 {
816 isl_factorizer *f;
817 isl_size nparam;
818
819 nparam = isl_basic_set_dim(bset, isl_dim_param);
820 if (nparam < 0)
821 return isl_basic_set_free(bset);
822 bset = isl_basic_set_move_dims(bset, isl_dim_set, 0,
823 isl_dim_param, 0, nparam);
824
825 f = isl_basic_set_factorizer(bset);
826 if (!f)
827 return isl_basic_set_free(bset);
828 if (f->n_group > 0) {
829 isl_basic_set_free(bset);
830 return isl_basic_set_coefficients_morphed_product(f);
831 }
832 isl_factorizer_free(f);
833 return isl_basic_set_coefficients_base(bset);
834 }
835
836 /* Construct a basic set containing the tuples of coefficients of all
837 * valid affine constraints on the given basic set.
838 */
isl_basic_set_coefficients(__isl_take isl_basic_set * bset)839 __isl_give isl_basic_set *isl_basic_set_coefficients(
840 __isl_take isl_basic_set *bset)
841 {
842 isl_space *space;
843
844 if (!bset)
845 return NULL;
846 if (bset->n_div)
847 isl_die(bset->ctx, isl_error_invalid,
848 "input set not allowed to have local variables",
849 goto error);
850
851 space = isl_basic_set_get_space(bset);
852 space = isl_space_coefficients(space);
853
854 bset = basic_set_coefficients(bset);
855 bset = isl_basic_set_reset_space(bset, space);
856 return bset;
857 error:
858 isl_basic_set_free(bset);
859 return NULL;
860 }
861
862 /* Construct a basic set containing the elements that satisfy all
863 * affine constraints whose coefficient tuples are
864 * contained in the given basic set.
865 */
isl_basic_set_solutions(__isl_take isl_basic_set * bset)866 __isl_give isl_basic_set *isl_basic_set_solutions(
867 __isl_take isl_basic_set *bset)
868 {
869 isl_space *space;
870
871 if (!bset)
872 return NULL;
873 if (bset->n_div)
874 isl_die(bset->ctx, isl_error_invalid,
875 "input set not allowed to have local variables",
876 goto error);
877
878 space = isl_basic_set_get_space(bset);
879 space = isl_space_solutions(space);
880
881 bset = farkas(bset, -1);
882 bset = isl_basic_set_reset_space(bset, space);
883 return bset;
884 error:
885 isl_basic_set_free(bset);
886 return NULL;
887 }
888
889 /* Construct a basic set containing the tuples of coefficients of all
890 * valid affine constraints on the given set.
891 */
isl_set_coefficients(__isl_take isl_set * set)892 __isl_give isl_basic_set *isl_set_coefficients(__isl_take isl_set *set)
893 {
894 int i;
895 isl_basic_set *coeff;
896
897 if (!set)
898 return NULL;
899 if (set->n == 0) {
900 isl_space *space = isl_set_get_space(set);
901 space = isl_space_coefficients(space);
902 isl_set_free(set);
903 return rational_universe(space);
904 }
905
906 coeff = isl_basic_set_coefficients(isl_basic_set_copy(set->p[0]));
907
908 for (i = 1; i < set->n; ++i) {
909 isl_basic_set *bset, *coeff_i;
910 bset = isl_basic_set_copy(set->p[i]);
911 coeff_i = isl_basic_set_coefficients(bset);
912 coeff = isl_basic_set_intersect(coeff, coeff_i);
913 }
914
915 isl_set_free(set);
916 return coeff;
917 }
918
919 /* Wrapper around isl_basic_set_coefficients for use
920 * as a isl_basic_set_list_map callback.
921 */
coefficients_wrap(__isl_take isl_basic_set * bset,void * user)922 static __isl_give isl_basic_set *coefficients_wrap(
923 __isl_take isl_basic_set *bset, void *user)
924 {
925 return isl_basic_set_coefficients(bset);
926 }
927
928 /* Replace the elements of "list" by the result of applying
929 * isl_basic_set_coefficients to them.
930 */
isl_basic_set_list_coefficients(__isl_take isl_basic_set_list * list)931 __isl_give isl_basic_set_list *isl_basic_set_list_coefficients(
932 __isl_take isl_basic_set_list *list)
933 {
934 return isl_basic_set_list_map(list, &coefficients_wrap, NULL);
935 }
936
937 /* Construct a basic set containing the elements that satisfy all
938 * affine constraints whose coefficient tuples are
939 * contained in the given set.
940 */
isl_set_solutions(__isl_take isl_set * set)941 __isl_give isl_basic_set *isl_set_solutions(__isl_take isl_set *set)
942 {
943 int i;
944 isl_basic_set *sol;
945
946 if (!set)
947 return NULL;
948 if (set->n == 0) {
949 isl_space *space = isl_set_get_space(set);
950 space = isl_space_solutions(space);
951 isl_set_free(set);
952 return rational_universe(space);
953 }
954
955 sol = isl_basic_set_solutions(isl_basic_set_copy(set->p[0]));
956
957 for (i = 1; i < set->n; ++i) {
958 isl_basic_set *bset, *sol_i;
959 bset = isl_basic_set_copy(set->p[i]);
960 sol_i = isl_basic_set_solutions(bset);
961 sol = isl_basic_set_intersect(sol, sol_i);
962 }
963
964 isl_set_free(set);
965 return sol;
966 }
967