Expect PPL version 0.10.
[cloog-ppl.git] / source / ppl / domain.c
blob0f2cc6497c0f15110840c35d67aa2881b0fcd577
2 /**-------------------------------------------------------------------**
3 ** CLooG **
4 **-------------------------------------------------------------------**
5 ** domain.c **
6 **-------------------------------------------------------------------**
7 ** First version: october 28th 2001 **
8 **-------------------------------------------------------------------**/
11 /******************************************************************************
12 * CLooG : the Chunky Loop Generator (experimental) *
13 ******************************************************************************
14 * *
15 * Copyright (C) 2001-2005 Cedric Bastoul *
16 * *
17 * This is free software; you can redistribute it and/or modify it under the *
18 * terms of the GNU General Public License as published by the Free Software *
19 * Foundation; either version 2 of the License, or (at your option) any later *
20 * version. *
21 * *
22 * This software is distributed in the hope that it will be useful, but *
23 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
24 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
25 * for more details. *
26 * *
27 * You should have received a copy of the GNU General Public License along *
28 * with software; if not, write to the Free Software Foundation, Inc., *
29 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
30 * *
31 * CLooG, the Chunky Loop Generator *
32 * Written by Cedric Bastoul, Cedric.Bastoul@inria.fr *
33 * *
34 ******************************************************************************/
35 /* CAUTION: the english used for comments is probably the worst you ever read,
36 * please feel free to correct and improve it !
39 # include <stdlib.h>
40 # include <stdio.h>
41 # include <ctype.h>
42 # include "../../include/cloog/cloog.h"
43 #include "matrix.h"
45 /* Variables names for pretty printing. */
46 static char wild_name[200][40];
48 static inline const char*
49 variable_output_function (ppl_dimension_type var)
51 if (var < 40)
52 return wild_name[var + 1];
53 else
54 return 0;
57 static inline void
58 error_handler (enum ppl_enum_error_code code, const char* description)
60 fprintf (stderr, "PPL error code %d\n%s", code, description);
61 exit (1);
64 void
65 cloog_initialize (void)
67 sprintf (wild_name[0], "1");
68 sprintf (wild_name[1], "a");
69 sprintf (wild_name[2], "b");
70 sprintf (wild_name[3], "c");
71 sprintf (wild_name[4], "d");
72 sprintf (wild_name[5], "e");
73 sprintf (wild_name[6], "f");
74 sprintf (wild_name[7], "g");
75 sprintf (wild_name[8], "h");
76 sprintf (wild_name[9], "i");
77 sprintf (wild_name[10], "j");
78 sprintf (wild_name[11], "k");
79 sprintf (wild_name[12], "l");
80 sprintf (wild_name[13], "m");
81 sprintf (wild_name[14], "n");
82 sprintf (wild_name[15], "o");
83 sprintf (wild_name[16], "p");
84 sprintf (wild_name[17], "q");
85 sprintf (wild_name[18], "r");
86 sprintf (wild_name[19], "s");
87 sprintf (wild_name[20], "t");
88 sprintf (wild_name[21], "alpha");
89 sprintf (wild_name[22], "beta");
90 sprintf (wild_name[23], "gamma");
91 sprintf (wild_name[24], "delta");
92 sprintf (wild_name[25], "tau");
93 sprintf (wild_name[26], "sigma");
94 sprintf (wild_name[27], "chi");
95 sprintf (wild_name[28], "omega");
96 sprintf (wild_name[29], "pi");
97 sprintf (wild_name[30], "ni");
98 sprintf (wild_name[31], "Alpha");
99 sprintf (wild_name[32], "Beta");
100 sprintf (wild_name[33], "Gamma");
101 sprintf (wild_name[34], "Delta");
102 sprintf (wild_name[35], "Tau");
103 sprintf (wild_name[36], "Sigma");
104 sprintf (wild_name[37], "Chi");
105 sprintf (wild_name[38], "Omega");
106 sprintf (wild_name[39], "xxx");
108 if (ppl_initialize() < 0)
110 fprintf (stderr, "Cannot initialize the Parma Polyhedra Library.\n");
111 exit (1);
114 if (ppl_set_error_handler (error_handler) < 0)
116 fprintf (stderr, "Cannot install the custom error handler.\n");
117 exit (1);
120 if (ppl_io_set_variable_output_function (variable_output_function) < 0)
122 fprintf (stderr, "Cannot install the PPL custom variable output function. \n");
123 exit (1);
127 polyhedron
128 cloog_pol_copy (polyhedron pol)
130 polyhedron res;
132 if (!pol)
133 return 0;
135 res = cloog_new_pol (cloog_pol_dim (pol), cloog_pol_nbc (pol));
137 if (cloog_pol_nbc (pol))
138 cloog_vector_copy (pol->Constraint[0], res->Constraint[0],
139 cloog_pol_nbc (pol) * (cloog_pol_dim (pol) + 2));
141 return res;
145 * The maximal number of rays allowed to be allocated by PolyLib. In fact since
146 * version 5.20, PolyLib automatically tune the number of rays by multiplying
147 * by 2 this number each time the maximum is reached. For unknown reasons
148 * PolyLib makes a segmentation fault if this number is too small. If this
149 * number is too small, performances will be reduced, if it is too high, memory
150 * will be saturated. Note that the option "-rays X" set this number to X.
152 int MAX_RAYS = 50;
154 /* Unused in this backend. */
156 int cloog_domain_allocated = 0;
157 int cloog_domain_freed = 0;
158 int cloog_domain_max = 0;
160 /* The same for Value variables since in GMP mode they have to be freed. */
161 int cloog_value_allocated = 0;
162 int cloog_value_freed = 0;
163 int cloog_value_max = 0;
166 static inline void
167 cloog_domain_polyhedron_set (CloogDomain * d, polyhedra_union p)
169 d->_union = p;
172 static inline void
173 cloog_domain_set_references (CloogDomain * d, int i)
175 d->_references = i;
178 static CloogDomain *
179 cloog_new_domain (polyhedra_union p)
181 CloogDomain *domain = (CloogDomain *) malloc (sizeof (CloogDomain));
182 domain->_union = p;
183 cloog_domain_set_references (domain, 1);
184 return domain;
187 static CloogDomain *
188 cloog_domain_alloc (polyhedron p)
190 return cloog_new_domain (cloog_new_upol (p));
193 static inline CloogDomain *
194 cloog_check_domain_id (CloogDomain *dom)
196 return dom;
199 static inline CloogDomain *
200 cloog_check_domain (CloogDomain *dom)
202 if (!dom)
203 return dom;
205 return dom;
208 static inline void
209 cloog_vector_min_not_zero (Value * p, unsigned len, int *index, Value * min)
211 Value x;
212 int i = cloog_first_non_zero (p, len);
214 if (i == -1)
216 value_set_si (*min, 1);
217 return;
220 *index = i;
221 value_absolute (*min, p[i]);
222 value_init (x);
224 for (i = i + 1; i < (int) len; i++)
226 if (value_zero_p (p[i]))
227 continue;
229 value_absolute (x, p[i]);
230 if (value_lt (x, *min))
232 value_assign (*min, x);
233 *index = i;
237 value_clear (x);
240 void
241 cloog_vector_gcd (Value * p, int len, Value * gcd)
243 Value *q, *cq, *cp;
244 int i, non_zero, min_index = 0;
246 q = (Value *) malloc (len * sizeof (Value));
248 for (i = 0; i < len; i++)
249 value_init (q[i]);
251 for (cp = p, cq = q, i = 0; i < len; i++, cq++, cp++)
252 value_absolute (*cq, *cp);
256 cloog_vector_min_not_zero (q, len, &min_index, gcd);
258 if (value_notone_p (*gcd))
260 for (cq = q, non_zero = 0, i = 0; i < len; i++, cq++)
261 if (i != min_index)
263 value_modulus (*cq, *cq, *gcd);
264 non_zero |= value_notzero_p (*cq);
267 else
268 break;
271 while (non_zero);
273 for (i = 0; i < len; i++)
274 value_clear (q[i]);
276 free (q);
279 static inline void
280 cloog_matrix_combine (Value * p1, Value * p2, Value * p3, int x, unsigned len)
282 Value a1, a2, gcd, b1, b2, n1;
284 value_init (a1), value_init (a2), value_init (gcd),
285 value_init (b1), value_init (b2), value_init (n1);
287 value_assign (a1, p1[x]);
288 value_assign (a2, p2[x]);
290 value_absolute (b1, a1);
291 value_absolute (b2, a2);
293 Gcd (b1, b2, &gcd);
295 value_division (a1, a1, gcd);
296 value_division (a2, a2, gcd);
297 value_oppose (n1, a1);
298 cloog_vector_combine (p1 + 1, p2 + 1, p3 + 1, a2, n1, len);
299 cloog_vector_normalize (p3 + 1, len);
301 value_clear (a1), value_clear (a2), value_clear (gcd),
302 value_clear (b1), value_clear (b2), value_clear (n1);
305 /* In the matrix representation an equality has a 0 in the first
306 column. When the value of the first column is 1, the row
307 represents an inequality. */
309 static inline int
310 cloog_matrix_row_is_eq_p (CloogMatrix *matrix, int row)
312 return value_zero_p (matrix->p[row][0]);
315 static ppl_Constraint_t
316 cloog_build_ppl_cstr (ppl_Linear_Expression_t expr, int ineq)
318 ppl_Constraint_t cstr;
320 switch (ineq)
322 case 0:
323 ppl_new_Constraint (&cstr, expr, PPL_CONSTRAINT_TYPE_EQUAL);
324 break;
326 case 1:
327 ppl_new_Constraint (&cstr, expr, PPL_CONSTRAINT_TYPE_GREATER_OR_EQUAL);
328 break;
330 default:
331 /* Should not happen. */
332 exit (1);
335 return cstr;
338 /* Translates to PPL row I from MATRIX. CST is the constant part that
339 is added to the constraint. When INEQ is 1 the constraint is
340 translated as an inequality, when INEQ is 0 it is translated as an
341 equality, when INEQ has another value, the first column of the
342 matrix is read for determining the type of the constraint. */
344 static ppl_Constraint_t
345 cloog_translate_constraint (CloogMatrix *matrix, int i, int cst, int ineq)
347 int j;
348 ppl_Constraint_t res;
349 ppl_Coefficient_t coef;
350 ppl_Linear_Expression_t expr;
351 ppl_dimension_type dim = matrix->NbColumns - 2;
352 Value val;
354 value_init (val);
355 ppl_new_Coefficient (&coef);
356 ppl_new_Linear_Expression_with_dimension (&expr, dim);
358 for (j = 1; j < matrix->NbColumns - 1; j++)
360 ppl_assign_Coefficient_from_mpz_t (coef, matrix->p[i][j]);
361 ppl_Linear_Expression_add_to_coefficient (expr, j - 1, coef);
364 value_set_si (val, cst);
365 value_addto (val, matrix->p[i][matrix->NbColumns - 1], val);
366 ppl_assign_Coefficient_from_mpz_t (coef, val);
367 value_clear (val);
368 ppl_Linear_Expression_add_to_inhomogeneous (expr, coef);
369 ppl_delete_Coefficient (coef);
371 if (ineq != 0 && ineq != 1)
372 ineq = !cloog_matrix_row_is_eq_p (matrix, i);
374 res = cloog_build_ppl_cstr (expr, ineq);
375 ppl_delete_Linear_Expression (expr);
376 return res;
379 /* Translates to PPL the opposite of row I from MATRIX. When INEQ is
380 1 the constraint is translated as an inequality, when INEQ is 0 it
381 is translated as an equality, when INEQ has another value, the
382 first column of the matrix is read for determining the type of the
383 constraint. */
385 static ppl_Constraint_t
386 cloog_translate_oppose_constraint (CloogMatrix *matrix, int i, int cst, int ineq)
388 int j;
389 ppl_Constraint_t res;
390 ppl_Coefficient_t coef;
391 ppl_Linear_Expression_t expr;
392 ppl_dimension_type dim = matrix->NbColumns - 2;
393 Value val, val1;
395 value_init (val);
396 value_init (val1);
397 ppl_new_Coefficient (&coef);
398 ppl_new_Linear_Expression_with_dimension (&expr, dim);
400 for (j = 1; j < matrix->NbColumns - 1; j++)
402 value_oppose (val, matrix->p[i][j]);
403 ppl_assign_Coefficient_from_mpz_t (coef, val);
404 ppl_Linear_Expression_add_to_coefficient (expr, j - 1, coef);
407 value_oppose (val, matrix->p[i][matrix->NbColumns - 1]);
408 value_set_si (val1, cst);
409 value_addto (val, val, val1);
410 ppl_assign_Coefficient_from_mpz_t (coef, val);
411 ppl_Linear_Expression_add_to_inhomogeneous (expr, coef);
412 ppl_delete_Coefficient (coef);
414 if (ineq != 0 && ineq != 1)
415 ineq = !cloog_matrix_row_is_eq_p (matrix, i);
417 res = cloog_build_ppl_cstr (expr, ineq);
418 ppl_delete_Linear_Expression (expr);
419 return res;
422 /* Adds to PPL the constraints from MATRIX. */
424 static void
425 cloog_translate_constraint_matrix_1 (ppl_Polyhedron_t ppl, CloogMatrix *matrix)
427 int i;
429 for (i = 0; i < matrix->NbRows; i++)
431 ppl_Constraint_t c = cloog_translate_constraint (matrix, i, 0, -1);
432 ppl_Polyhedron_add_constraint_and_minimize (ppl, c);
433 ppl_delete_Constraint (c);
437 static ppl_Polyhedron_t
438 cloog_translate_constraint_matrix (CloogMatrix *matrix)
440 ppl_Polyhedron_t ppl;
441 ppl_dimension_type dim = matrix->NbColumns - 2;
443 ppl_new_NNC_Polyhedron_from_space_dimension (&ppl, dim, 0);
444 cloog_translate_constraint_matrix_1 (ppl, matrix);
445 return ppl;
448 /* Put the constraint matrix of polyhedron RES under Cloog's normal
449 form: Cloog expects to see
451 0 1 1 -9
452 1 0 1 -1
454 instead of this:
456 0 1 1 -9
457 1 -1 0 8
459 These two forms are equivalent but the expected form uses rightmost
460 indices for inequalities. */
462 static void
463 cloog_pol_normal_form (polyhedron res)
465 int dim = cloog_pol_dim (res);
466 int nrows = cloog_pol_nbc (res);
467 int i, j;
468 int neqs = cloog_pol_nbeq (res);
470 for (j = 1; j <= dim; j++)
472 int rank;
474 for (rank = 0; rank < neqs; rank++)
475 if (j - 1 == cloog_first_non_zero (res->Constraint[rank] + 1, dim))
477 for (i = neqs; i < nrows; i++)
478 if (value_notzero_p (res->Constraint[i][j]))
479 cloog_matrix_combine (res->Constraint[i],
480 res->Constraint[rank],
481 res->Constraint[i], j, dim + 1);
483 break;
488 static polyhedron
489 cloog_translate_ppl_polyhedron_1 (ppl_Polyhedron_t pol)
491 polyhedron res;
492 ppl_dimension_type dim;
493 ppl_const_Constraint_System_t pcs;
494 ppl_Constraint_System_const_iterator_t cit, end;
495 int eqs, orig_ineqs, ineqs, row, i;
496 ppl_const_Constraint_t pc;
498 ppl_Polyhedron_get_minimized_constraints (pol, &pcs);
499 ppl_new_Constraint_System_const_iterator (&cit);
500 ppl_new_Constraint_System_const_iterator (&end);
502 for (eqs = 0, ineqs = 0,
503 ppl_Constraint_System_begin (pcs, cit),
504 ppl_Constraint_System_end (pcs, end);
505 !ppl_Constraint_System_const_iterator_equal_test (cit, end);
506 ppl_Constraint_System_const_iterator_increment (cit))
508 ppl_Constraint_System_const_iterator_dereference (cit, &pc);
509 (ppl_Constraint_type (pc) == PPL_CONSTRAINT_TYPE_EQUAL) ? eqs++ : ineqs++;
512 ppl_Polyhedron_space_dimension (pol, &dim);
514 orig_ineqs = ineqs;
515 if (1 || orig_ineqs == 0)
516 res = cloog_new_pol (dim, eqs + ineqs + 1);
517 else
518 res = cloog_new_pol (dim, eqs + ineqs);
521 /* Sort constraints: Cloog expects to see in matrices the equalities
522 followed by inequalities. */
523 ineqs = eqs;
524 eqs = 0;
525 for (ppl_Constraint_System_begin (pcs, cit), ppl_Constraint_System_end (pcs, end);
526 !ppl_Constraint_System_const_iterator_equal_test (cit, end);
527 ppl_Constraint_System_const_iterator_increment (cit))
529 ppl_Coefficient_t coef;
530 ppl_dimension_type col;
531 Value val;
532 int neg;
534 value_init (val);
535 ppl_new_Coefficient (&coef);
536 ppl_Constraint_System_const_iterator_dereference (cit, &pc);
538 neg = (ppl_Constraint_type (pc) == PPL_CONSTRAINT_TYPE_LESS_THAN
539 || ppl_Constraint_type (pc) == PPL_CONSTRAINT_TYPE_LESS_OR_EQUAL) ? 1 : 0;
540 row = (ppl_Constraint_type (pc) == PPL_CONSTRAINT_TYPE_EQUAL) ? eqs++ : ineqs++;
542 for (col = 0; col < dim; col++)
544 ppl_Constraint_coefficient (pc, col, coef);
545 ppl_Coefficient_to_mpz_t (coef, val);
547 if (neg)
548 value_oppose (val, val);
550 value_assign (res->Constraint[row][col + 1], val);
553 ppl_Constraint_inhomogeneous_term (pc, coef);
554 ppl_Coefficient_to_mpz_t (coef, val);
555 value_assign (res->Constraint[row][dim + 1], val);
556 ppl_delete_Coefficient (coef);
558 switch (ppl_Constraint_type (pc))
560 case PPL_CONSTRAINT_TYPE_EQUAL:
561 value_set_si (res->Constraint[row][0], 0);
562 break;
564 case PPL_CONSTRAINT_TYPE_LESS_THAN:
565 case PPL_CONSTRAINT_TYPE_GREATER_THAN:
566 value_decrement (res->Constraint[row][dim + 1],
567 res->Constraint[row][dim + 1]);
568 value_set_si (res->Constraint[row][0], 1);
569 break;
571 case PPL_CONSTRAINT_TYPE_LESS_OR_EQUAL:
572 case PPL_CONSTRAINT_TYPE_GREATER_OR_EQUAL:
573 value_set_si (res->Constraint[row][0], 1);
574 break;
576 default:
577 fprintf (stderr, "PPL_CONSTRAINT_TYPE_%d not implemented yet\n",
578 ppl_Constraint_type (pc));
579 exit (1);
582 ppl_delete_Constraint_System_const_iterator (cit);
583 ppl_delete_Constraint_System_const_iterator (end);
585 if (cloog_pol_nbeq (res) == 2 && cloog_pol_nbc (res) == 2
586 && cloog_first_non_zero (res->Constraint[0], dim + 2) == (int) dim + 1)
588 cloog_pol_free (res);
589 return cloog_empty_polyhedron (dim);
592 /* Add the positivity constraint. */
593 if (1 || orig_ineqs == 0)
595 row = ineqs;
596 value_set_si (res->Constraint[row][0], 1);
597 for (i = 0; i < (int) dim; i++)
598 value_set_si (res->Constraint[row][i + 1], 0);
599 value_set_si (res->Constraint[row][dim + 1], 1);
602 /* Put the matrix of RES in normal form. */
603 cloog_pol_normal_form (res);
605 /* If we do not sort the matrices, Cloog is a random loop
606 generator. */
607 cloog_pol_sort_rows (res);
609 return res;
612 polyhedron
613 cloog_pol_from_matrix (CloogMatrix * m)
615 polyhedron res;
616 int ncolumns = cloog_matrix_ncolumns (m);
617 int nrows = cloog_matrix_nrows (m);
618 ppl_Polyhedron_t p;
620 if (nrows == 0)
621 return cloog_universe_polyhedron (ncolumns - 2);
624 p = cloog_translate_constraint_matrix (m);
625 res = cloog_translate_ppl_polyhedron_1 (p);
626 ppl_delete_Polyhedron (p);
627 if ((int) cloog_pol_nbc (res) < cloog_matrix_nrows (m))
628 return res;
630 cloog_pol_free (res);
631 res = cloog_new_pol (ncolumns - 2, nrows);
632 cloog_vector_copy (m->p[0], res->Constraint[0], m->NbRows * m->NbColumns);
634 return res;
637 CloogDomain *
638 cloog_domain_matrix2domain (CloogMatrix * matrix)
640 return cloog_domain_alloc (cloog_pol_from_matrix (matrix));
643 static CloogDomain *
644 cloog_translate_ppl_polyhedron (ppl_Polyhedron_t p)
646 polyhedron res = cloog_translate_ppl_polyhedron_1 (p);
647 return cloog_domain_alloc (res);
650 static void
651 cloog_pol_print (FILE * file, polyhedron pol)
653 unsigned dim, nbc;
654 int i, j;
655 Value *p;
657 if (!pol)
659 fprintf (file, "<null polyhedron>\n");
660 return;
663 dim = cloog_pol_dim (pol) + 2;
664 nbc = cloog_pol_nbc (pol);
665 fprintf (file, "POLYHEDRON Dimension:%d\n", cloog_pol_dim (pol));
666 fprintf (file,
667 " Constraints:%d Equations:%d\n",
668 cloog_pol_nbc (pol), cloog_pol_nbeq (pol));
669 fprintf (file, "Constraints %d %d\n", nbc, dim);
671 for (i = 0; i < (int) nbc; i++)
673 p = pol->Constraint[i];
675 if (value_notzero_p (*p))
676 fprintf (file, "Inequality: [");
677 else
678 fprintf (file, "Equality: [");
680 p++;
682 for (j = 1; j < (int) dim; j++)
683 value_print (file, "%4s ", *p++);
685 fprintf (file, " ]\n");
689 void debug_poly (polyhedron p)
691 cloog_pol_print (stderr, p);
694 void
695 debug_ppl_poly (ppl_Polyhedron_t p)
697 debug_poly (cloog_domain_polyhedron (cloog_translate_ppl_polyhedron (p)));
700 static inline int
701 cloog_domain_references (CloogDomain * d)
703 return d->_references;
707 * cloog_domain_print function:
708 * This function prints the content of a CloogDomain structure (domain) into
709 * a file (foo, possibly stdout).
711 void
712 cloog_domain_print (FILE * foo, CloogDomain * domain)
714 polyhedra_union upol = cloog_domain_upol (domain);
716 while (upol)
718 cloog_pol_print (foo, cloog_upol_polyhedron (upol));
719 upol = cloog_upol_next (upol);
722 fprintf (foo, "Number of active references: %d\n",
723 cloog_domain_references (domain));
727 * cloog_domain_free function:
728 * This function frees the allocated memory for a CloogDomain structure
729 * (domain). It decrements the number of active references to this structure,
730 * if there are no more references on the structure, it frees it (with the
731 * included list of polyhedra).
733 void
734 cloog_domain_free (CloogDomain * domain)
736 if (domain)
738 cloog_domain_set_references (domain,
739 cloog_domain_references (domain) - 1);
741 if (cloog_domain_references (domain) == 0)
744 polyhedra_union upol = cloog_domain_upol (domain);
746 while (upol)
748 polyhedra_union next_upol;
750 cloog_pol_free (cloog_upol_polyhedron (upol));
751 next_upol = cloog_upol_next (upol);
752 cloog_upol_free (upol);
753 upol = next_upol;
756 free (domain);
763 * cloog_domain_copy function:
764 * This function returns a copy of a CloogDomain structure (domain). To save
765 * memory this is not a memory copy but we increment a counter of active
766 * references inside the structure, then return a pointer to that structure.
768 CloogDomain *
769 cloog_domain_copy (CloogDomain * domain)
771 cloog_domain_set_references (domain, cloog_domain_references (domain) + 1);
772 return domain;
776 * cloog_domain_convex function:
777 * Given a polyhedral domain (polyhedron), this function concatenates the lists
778 * of rays and lines of the two (or more) polyhedra in the domain into one
779 * combined list, and find the set of constraints which tightly bound all of
780 * those objects. It returns the corresponding polyhedron.
782 CloogDomain *
783 cloog_domain_convex (CloogDomain * domain)
785 CloogDomain *res;
786 ppl_Polyhedron_t p2;
787 polyhedra_union upol = cloog_domain_upol (domain);
788 CloogMatrix *m = cloog_upol_domain2matrix (upol);
789 ppl_Polyhedron_t p1 = cloog_translate_constraint_matrix (m);
791 upol = cloog_upol_next (upol);
792 while (upol)
794 ppl_const_Generator_System_t g;
796 m = cloog_upol_domain2matrix (upol);
797 p2 = cloog_translate_constraint_matrix (m);
798 ppl_Polyhedron_get_generators (p2, &g);
799 ppl_Polyhedron_add_generators_and_minimize (p1, g);
800 ppl_delete_Polyhedron (p2);
802 upol = cloog_upol_next (upol);
805 res = cloog_translate_ppl_polyhedron (p1);
806 ppl_delete_Polyhedron (p1);
808 return res;
812 cloog_domain_isconvex (CloogDomain * domain)
814 if (cloog_domain_polyhedron (domain))
815 return !cloog_upol_next (cloog_domain_upol (domain));
817 return 1;
821 * cloog_domain_simple_convex:
822 * Given a list (union) of polyhedra, this function returns a "simple"
823 * convex hull of this union. In particular, the constraints of the
824 * the returned polyhedron consist of (parametric) lower and upper
825 * bounds on individual variables and constraints that appear in the
826 * original polyhedra.
828 * nb_par is the number of parameters of the domain.
830 CloogDomain *
831 cloog_domain_simple_convex (CloogDomain * domain, int nb_par)
833 fprintf (stderr, "cloog_domain_simple_convex (domain, nb_par = %d) is not implemented yet.\n", nb_par);
834 fprintf (stderr, "domain = \n");
835 cloog_domain_print (stderr, domain);
836 exit (1);
839 /* Returns non-zero when the constraint I in MATRIX is the positivity
840 constraint: "0 >= 0". */
842 static int
843 cloog_positivity_constraint_p (CloogMatrix *matrix, int i, int dim)
845 int j;
847 for (j = 1; j < dim; j++)
848 if (value_notzero_p (matrix->p[i][j]))
849 break;
851 return j == dim;
854 /* Returns one when the constraint C is not in P, returns zero when C
855 is already in P. */
857 static int
858 non_redundant_constraint (ppl_Constraint_t c, ppl_Polyhedron_t p)
860 int rel = ppl_Polyhedron_relation_with_Constraint (p, c);
862 if (rel & PPL_POLY_CON_RELATION_IS_DISJOINT)
863 return 1;
865 if (rel & PPL_POLY_CON_RELATION_IS_INCLUDED)
866 return 0;
868 if (rel & PPL_POLY_CON_RELATION_STRICTLY_INTERSECTS)
870 ppl_Constraint_System_t cs;
871 ppl_Polyhedron_t p1;
872 ppl_const_Generator_System_t g;
873 ppl_Generator_System_const_iterator_t git, end;
874 ppl_const_Generator_t cg;
876 ppl_new_Constraint_System_from_Constraint (&cs, c);
877 ppl_new_NNC_Polyhedron_from_Constraint_System (&p1, cs);
878 ppl_Polyhedron_get_generators (p1, &g);
879 ppl_new_Generator_System_const_iterator (&git);
880 ppl_new_Generator_System_const_iterator (&end);
882 for (ppl_Generator_System_begin (g, git), ppl_Generator_System_end (g, end);
883 !ppl_Generator_System_const_iterator_equal_test (git, end);
884 ppl_Generator_System_const_iterator_increment (git))
886 ppl_Generator_System_const_iterator_dereference (git, &cg);
887 rel = ppl_Polyhedron_relation_with_Generator (p, cg);
889 if (!(rel & PPL_POLY_GEN_RELATION_SUBSUMES))
890 break;
892 ppl_delete_Constraint_System (cs);
893 ppl_delete_Polyhedron (p1);
894 ppl_delete_Generator_System_const_iterator (git);
895 ppl_delete_Generator_System_const_iterator (end);
897 /* All generators are redundant. */
898 if (rel & PPL_POLY_GEN_RELATION_SUBSUMES)
899 return 0;
902 return 1;
905 /* Returns 1 if adding constraint C to polyhedron P changes the number
906 of constraints of P. */
908 static int
909 changes_constraints (ppl_Constraint_t c, ppl_Polyhedron_t p)
911 int a1 = 0, a2 = 0, a3 = 0, a4 = 0, a5 = 0;
912 int b1 = 0, b2 = 0, b3 = 0, b4 = 0, b5 = 0;
913 ppl_Polyhedron_t q;
914 ppl_const_Constraint_System_t g;
915 ppl_Constraint_System_const_iterator_t git, end;
917 ppl_new_Constraint_System_const_iterator (&git);
918 ppl_new_Constraint_System_const_iterator (&end);
919 ppl_Polyhedron_get_minimized_constraints (p, &g);
921 for (ppl_Constraint_System_begin (g, git), ppl_Constraint_System_end (g, end);
922 !ppl_Constraint_System_const_iterator_equal_test (git, end);
923 ppl_Constraint_System_const_iterator_increment (git))
925 ppl_const_Constraint_t pg;
927 ppl_Constraint_System_const_iterator_dereference (git, &pg);
928 switch (ppl_Constraint_type (pg))
930 case PPL_CONSTRAINT_TYPE_LESS_THAN:
931 a1++;
932 break;
934 case PPL_CONSTRAINT_TYPE_LESS_OR_EQUAL:
935 a2++;
936 break;
938 case PPL_CONSTRAINT_TYPE_EQUAL:
939 a3++;
940 break;
942 case PPL_CONSTRAINT_TYPE_GREATER_OR_EQUAL:
943 a4++;
944 break;
946 case PPL_CONSTRAINT_TYPE_GREATER_THAN:
947 a5++;
948 break;
950 default:
951 break;
955 ppl_new_NNC_Polyhedron_from_NNC_Polyhedron (&q, p);
956 ppl_Polyhedron_add_constraint_and_minimize (q, c);
957 ppl_Polyhedron_get_minimized_constraints (q, &g);
959 for (ppl_Constraint_System_begin (g, git), ppl_Constraint_System_end (g, end);
960 !ppl_Constraint_System_const_iterator_equal_test (git, end);
961 ppl_Constraint_System_const_iterator_increment (git))
963 ppl_const_Constraint_t pg;
965 ppl_Constraint_System_const_iterator_dereference (git, &pg);
966 switch (ppl_Constraint_type (pg))
968 case PPL_CONSTRAINT_TYPE_LESS_THAN:
969 b1++;
970 break;
972 case PPL_CONSTRAINT_TYPE_LESS_OR_EQUAL:
973 b2++;
974 break;
976 case PPL_CONSTRAINT_TYPE_EQUAL:
977 b3++;
978 break;
980 case PPL_CONSTRAINT_TYPE_GREATER_OR_EQUAL:
981 b4++;
982 break;
984 case PPL_CONSTRAINT_TYPE_GREATER_THAN:
985 b5++;
986 break;
988 default:
989 break;
993 ppl_delete_Constraint_System_const_iterator (git);
994 ppl_delete_Constraint_System_const_iterator (end);
995 ppl_delete_Polyhedron (q);
997 if (a1 != b1 || a2 != b2 || a3 != b3 || a4 != b4 || a5 != b5)
998 return 1;
1000 return 0;
1003 /* Returns 1 if adding constraint C to polyhedron P changes the
1004 generators of P. */
1006 static int
1007 changes_generators (ppl_Constraint_t c, ppl_Polyhedron_t p)
1009 int a1 = 0, a2 = 0;
1010 int b1 = 0, b2 = 0;
1011 ppl_Polyhedron_t q;
1012 ppl_const_Generator_System_t g;
1013 ppl_Generator_System_const_iterator_t git, end;
1015 ppl_new_Generator_System_const_iterator (&git);
1016 ppl_new_Generator_System_const_iterator (&end);
1017 ppl_Polyhedron_get_minimized_generators (p, &g);
1019 for (ppl_Generator_System_begin (g, git), ppl_Generator_System_end (g, end);
1020 !ppl_Generator_System_const_iterator_equal_test (git, end);
1021 ppl_Generator_System_const_iterator_increment (git))
1023 ppl_const_Generator_t pg;
1025 ppl_Generator_System_const_iterator_dereference (git, &pg);
1026 switch (ppl_Generator_type (pg))
1028 case PPL_GENERATOR_TYPE_LINE:
1029 case PPL_GENERATOR_TYPE_RAY:
1030 a1++;
1031 break;
1033 case PPL_GENERATOR_TYPE_POINT:
1034 case PPL_GENERATOR_TYPE_CLOSURE_POINT:
1035 a2++;
1036 break;
1038 default:
1039 break;
1043 ppl_new_NNC_Polyhedron_from_NNC_Polyhedron (&q, p);
1044 ppl_Polyhedron_add_constraint (q, c);
1045 ppl_Polyhedron_get_minimized_generators (q, &g);
1047 for (ppl_Generator_System_begin (g, git), ppl_Generator_System_end (g, end);
1048 !ppl_Generator_System_const_iterator_equal_test (git, end);
1049 ppl_Generator_System_const_iterator_increment (git))
1051 ppl_const_Generator_t pg;
1053 ppl_Generator_System_const_iterator_dereference (git, &pg);
1054 switch (ppl_Generator_type (pg))
1056 case PPL_GENERATOR_TYPE_LINE:
1057 case PPL_GENERATOR_TYPE_RAY:
1058 b1++;
1059 break;
1061 case PPL_GENERATOR_TYPE_POINT:
1062 case PPL_GENERATOR_TYPE_CLOSURE_POINT:
1063 b2++;
1064 break;
1066 default:
1067 break;
1071 ppl_delete_Generator_System_const_iterator (git);
1072 ppl_delete_Generator_System_const_iterator (end);
1073 ppl_delete_Polyhedron (q);
1075 if (a1 >= b1 && a2 >= b2)
1076 return 0;
1078 return 1;
1081 /* Simplifies DOM1 in the context of DOM2. For example, DOM1 can
1082 contain the following conditions: i >= 0, i <= 5, and DOM2 is a
1083 loop around, i.e. the context of DOM1, that also contains the
1084 conditions i >= 0, i <= 5. So instead of generating a loop like:
1086 | for (i = 0; i < 6; i++)
1088 | if (i >= 0 && i <= 5)
1089 | S;
1092 this function allows to detect that in the context of DOM2, the
1093 constraints of DOM1 are redundant, and so the following code should
1094 be produced:
1096 | for (i = 0; i < 6; i++)
1097 | S;
1100 CloogDomain *
1101 cloog_domain_simplify (CloogDomain * dom1, CloogDomain * dom2)
1103 int i;
1104 CloogDomain *res = NULL;
1105 polyhedra_union u1, u2;
1106 unsigned dim = cloog_domain_dim (dom1);
1107 CloogDomain *inter = cloog_domain_intersection (dom1, dom2);
1109 for (u1 = cloog_domain_upol (inter); u1; u1 = cloog_upol_next (u1))
1111 CloogMatrix *m1 = cloog_upol_domain2matrix (u1);
1113 for (u2 = cloog_domain_upol (dom2); u2; u2 = cloog_upol_next (u2))
1115 CloogMatrix *m2 = cloog_upol_domain2matrix (u2);
1116 ppl_Polyhedron_t p2 = cloog_translate_constraint_matrix (m2);
1117 ppl_Polyhedron_t p3;
1119 ppl_new_NNC_Polyhedron_from_space_dimension (&p3, dim, 0);
1121 for (i = 0; i < m1->NbRows; i++)
1122 if (!cloog_positivity_constraint_p (m1, i, dim + 1))
1124 ppl_Constraint_t c1 = cloog_translate_constraint (m1, i, 0, -1);
1126 if (non_redundant_constraint (c1, p2)
1127 || changes_generators (c1, p2)
1128 || changes_constraints (c1, p2))
1129 ppl_Polyhedron_add_constraint_and_minimize (p3, c1);
1131 ppl_delete_Constraint (c1);
1134 res = cloog_domain_union (res, cloog_translate_ppl_polyhedron (p3));
1136 ppl_delete_Polyhedron (p2);
1137 ppl_delete_Polyhedron (p3);
1141 return res;
1145 static polyhedra_union
1146 cloog_upol_copy (polyhedra_union p)
1148 polyhedra_union res = cloog_new_upol (cloog_pol_copy (cloog_upol_polyhedron (p)));
1149 polyhedra_union upol = res;
1151 while (cloog_upol_next (p))
1153 cloog_upol_set_next (upol, cloog_new_upol (cloog_pol_copy (cloog_upol_polyhedron (p))));
1154 upol = cloog_upol_next (upol);
1155 p = cloog_upol_next (p);
1158 return res;
1161 /* Adds to D1 the union of polyhedra from D2, with no checks of
1162 redundancies between polyhedra. */
1164 static CloogDomain *
1165 cloog_domain_add_domain (CloogDomain *d1, CloogDomain *d2)
1167 polyhedra_union upol;
1169 if (!d1)
1170 return d2;
1172 if (!d2)
1173 return d1;
1175 upol = cloog_domain_upol (d1);
1176 while (cloog_upol_next (upol))
1177 upol = cloog_upol_next (upol);
1179 cloog_upol_set_next (upol, cloog_domain_upol (d2));
1180 return d1;
1184 * cloog_domain_union function:
1185 * This function returns a new CloogDomain structure including a polyhedral
1186 * domain which is the union of two polyhedral domains (pol1) U (pol2) inside
1187 * two CloogDomain structures.
1189 CloogDomain *
1190 cloog_domain_union (CloogDomain * dom1, CloogDomain * dom2)
1192 CloogDomain *res;
1193 polyhedra_union head1, head2, tail1, tail2;
1194 polyhedra_union d1, d2;
1196 if (!dom1)
1197 return dom2;
1199 if (!dom2)
1200 return dom1;
1202 if (cloog_domain_dim (dom1) != cloog_domain_dim (dom2))
1204 fprintf (stderr, "cloog_domain_union should not be called on domains of different dimensions.\n");
1205 exit (1);
1208 head1 = NULL;
1209 tail1 = NULL;
1210 for (d1 = cloog_domain_upol (dom1); d1; d1 = cloog_upol_next (d1))
1212 int found = 0;
1213 ppl_Polyhedron_t ppl1 = cloog_translate_constraint_matrix (cloog_upol_domain2matrix (d1));
1215 for (d2 = cloog_domain_upol (dom2); d2; d2 = cloog_upol_next (d2))
1217 ppl_Polyhedron_t ppl2 = cloog_translate_constraint_matrix (cloog_upol_domain2matrix (d2));
1219 if (ppl_Polyhedron_contains_Polyhedron (ppl2, ppl1))
1221 ppl_delete_Polyhedron (ppl2);
1222 found = 1;
1223 break;
1225 ppl_delete_Polyhedron (ppl2);
1227 ppl_delete_Polyhedron (ppl1);
1229 if (!found)
1231 if (!tail1)
1233 head1 = cloog_upol_copy (d1);
1234 tail1 = head1;
1236 else
1238 cloog_upol_set_next (tail1, cloog_upol_copy (d1));
1239 tail1 = cloog_upol_next (tail1);
1244 head2 = NULL;
1245 tail2 = NULL;
1246 for (d2 = cloog_domain_upol (dom2); d2; d2 = cloog_upol_next (d2))
1248 int found = 0;
1249 ppl_Polyhedron_t ppl2 = cloog_translate_constraint_matrix (cloog_upol_domain2matrix (d2));
1251 for (d1 = head1; d1; d1 = cloog_upol_next (d1))
1253 ppl_Polyhedron_t ppl1 = cloog_translate_constraint_matrix (cloog_upol_domain2matrix (d1));
1255 if (ppl_Polyhedron_contains_Polyhedron (ppl1, ppl2))
1257 ppl_delete_Polyhedron (ppl1);
1258 found = 1;
1259 break;
1261 ppl_delete_Polyhedron (ppl1);
1263 ppl_delete_Polyhedron (ppl2);
1265 if (!found)
1267 if (!tail2)
1269 head2 = cloog_upol_copy (d2);
1270 tail2 = head2;
1272 else
1274 cloog_upol_set_next (tail2, cloog_upol_copy (d2));
1275 tail2 = cloog_upol_next (tail2);
1280 if (!head1)
1281 res = cloog_new_domain (head2);
1282 else
1284 cloog_upol_set_next (tail1, head2);
1285 res = cloog_new_domain (head1);
1288 return cloog_check_domain (res);
1292 * cloog_domain_intersection function:
1293 * This function returns a new CloogDomain structure including a polyhedral
1294 * domain which is the intersection of two polyhedral domains (pol1)inter(pol2)
1295 * inside two CloogDomain structures.
1297 CloogDomain *
1298 cloog_domain_intersection (CloogDomain * dom1, CloogDomain * dom2)
1300 CloogDomain *res = NULL;
1301 polyhedra_union p1, p2;
1302 ppl_Polyhedron_t ppl1, ppl2;
1304 for (p1 = cloog_domain_upol (dom1); p1; p1 = cloog_upol_next (p1))
1306 ppl1 = cloog_translate_constraint_matrix (cloog_upol_domain2matrix (p1));
1308 for (p2 = cloog_domain_upol (dom2); p2; p2 = cloog_upol_next (p2))
1310 ppl2 = cloog_translate_constraint_matrix (cloog_upol_domain2matrix (p2));
1311 ppl_Polyhedron_intersection_assign (ppl2, ppl1);
1312 res = cloog_domain_union (res, cloog_translate_ppl_polyhedron (ppl2));
1313 ppl_delete_Polyhedron (ppl2);
1315 ppl_delete_Polyhedron (ppl1);
1318 return res;
1321 /* Returns d1 minus d2. */
1323 CloogDomain *
1324 cloog_domain_difference (CloogDomain * d1, CloogDomain * d2)
1326 CloogDomain *res = NULL, *d = d1;
1327 polyhedra_union p1, p2;
1329 if (cloog_domain_isempty (d2))
1330 return cloog_domain_copy (d1);
1332 for (p2 = cloog_domain_upol (d2); p2; p2 = cloog_upol_next (p2))
1334 CloogMatrix *matrix = cloog_upol_domain2matrix (p2);
1336 for (p1 = cloog_domain_upol (d); p1; p1 = cloog_upol_next (p1))
1338 int i;
1339 CloogMatrix *m1 = cloog_upol_domain2matrix (p1);
1341 for (i = 0; i < matrix->NbRows; i++)
1343 ppl_Polyhedron_t p3;
1344 ppl_Constraint_t cstr;
1346 /* Don't handle "0 >= 0". */
1347 if (cloog_positivity_constraint_p (matrix, i,
1348 cloog_domain_dim (d) + 1))
1349 continue;
1351 /* Add the constraint "-matrix[i] - 1 >= 0". */
1352 p3 = cloog_translate_constraint_matrix (m1);
1353 cstr = cloog_translate_oppose_constraint (matrix, i, -1, 1);
1354 ppl_Polyhedron_add_constraint_and_minimize (p3, cstr);
1355 ppl_delete_Constraint (cstr);
1356 res = cloog_domain_union (res, cloog_translate_ppl_polyhedron (p3));
1357 ppl_delete_Polyhedron (p3);
1359 /* For an equality, add the constraint "matrix[i] - 1 >= 0". */
1360 if (cloog_matrix_row_is_eq_p (matrix, i))
1362 p3 = cloog_translate_constraint_matrix (m1);
1363 cstr = cloog_translate_constraint (matrix, i, -1, 1);
1364 ppl_Polyhedron_add_constraint_and_minimize (p3, cstr);
1365 ppl_delete_Constraint (cstr);
1366 res = cloog_domain_union (res, cloog_translate_ppl_polyhedron (p3));
1367 ppl_delete_Polyhedron (p3);
1371 d = res;
1372 res = NULL;
1375 if (!d)
1376 res = cloog_domain_empty (cloog_domain_dim (d2));
1377 else
1378 res = d;
1380 return res;
1385 * cloog_domain_addconstraints function :
1386 * This function adds source's polyhedron constraints to target polyhedron: for
1387 * each element of the polyhedron inside 'target' (i.e. element of the union
1388 * of polyhedra) it adds the constraints of the corresponding element in
1389 * 'source'.
1390 * - August 10th 2002: first version.
1391 * Nota bene for future : it is possible that source and target don't have the
1392 * same number of elements (try iftest2 without non-shared constraint
1393 * elimination in cloog_loop_separate !). This function is yet another part
1394 * of the DomainSimplify patching problem...
1396 CloogDomain *
1397 cloog_domain_addconstraints (CloogDomain *domain_source, CloogDomain *domain_target)
1399 CloogDomain *res;
1400 ppl_Polyhedron_t ppl;
1401 polyhedra_union source, target, last;
1402 int dim = cloog_domain_dim (domain_target);
1404 source = cloog_domain_upol (domain_source);
1405 target = cloog_domain_upol (domain_target);
1407 ppl_new_NNC_Polyhedron_from_space_dimension (&ppl, dim, 0);
1408 cloog_translate_constraint_matrix_1 (ppl, cloog_upol_domain2matrix (target));
1409 cloog_translate_constraint_matrix_1 (ppl, cloog_upol_domain2matrix (source));
1410 res = cloog_translate_ppl_polyhedron (ppl);
1411 ppl_delete_Polyhedron (ppl);
1412 last = cloog_domain_upol (res);
1414 source = cloog_upol_next (source);
1415 target = cloog_upol_next (target);
1417 while (target)
1419 ppl_new_NNC_Polyhedron_from_space_dimension (&ppl, dim, 0);
1420 cloog_translate_constraint_matrix_1 (ppl, cloog_upol_domain2matrix (target));
1422 if (source)
1424 cloog_translate_constraint_matrix_1 (ppl, cloog_upol_domain2matrix (source));
1425 source = cloog_upol_next (source);
1428 cloog_upol_set_next
1429 (last, cloog_domain_upol (cloog_translate_ppl_polyhedron (ppl)));
1430 ppl_delete_Polyhedron (ppl);
1432 last = cloog_upol_next (last);
1433 target = cloog_upol_next (target);
1436 return res;
1439 /* Compares P1 to P2: returns 0 when the polyhedra don't overlap,
1440 returns 1 when p1 >= p2, and returns -1 when p1 < p2. The ">"
1441 relation is the "contains" relation. */
1443 static int
1444 cloog_domain_polyhedron_compare (CloogMatrix *m1, CloogMatrix *m2, int level, int nb_par, int dimension)
1446 int i, j;
1447 ppl_Polyhedron_t q1, q2, q3, q4, q5, q;
1448 ppl_Polyhedron_t p1, p2;
1450 p1 = cloog_translate_constraint_matrix (m1);
1451 if (ppl_Polyhedron_is_empty (p1))
1453 ppl_delete_Polyhedron (p1);
1454 return 0;
1457 p2 = cloog_translate_constraint_matrix (m2);
1458 if (ppl_Polyhedron_is_empty (p2))
1460 ppl_delete_Polyhedron (p2);
1461 return 0;
1464 ppl_new_NNC_Polyhedron_from_NNC_Polyhedron (&q1, p1);
1465 ppl_new_NNC_Polyhedron_from_NNC_Polyhedron (&q2, p2);
1467 for (i = level; i < dimension - nb_par + 1; i++)
1469 Value val;
1470 ppl_Coefficient_t d;
1471 ppl_Linear_Expression_t expr;
1472 ppl_Generator_t g;
1474 value_init (val);
1475 value_set_si (val, 1);
1476 ppl_new_Coefficient_from_mpz_t (&d, val);
1477 ppl_new_Linear_Expression_with_dimension (&expr, dimension);
1478 ppl_Linear_Expression_add_to_coefficient (expr, i - 1, d);
1479 ppl_new_Generator (&g, expr, PPL_GENERATOR_TYPE_LINE, d);
1480 ppl_Polyhedron_add_generator (q1, g);
1481 ppl_Polyhedron_add_generator (q2, g);
1482 ppl_delete_Generator (g);
1483 ppl_delete_Linear_Expression (expr);
1484 ppl_delete_Coefficient (d);
1487 ppl_new_NNC_Polyhedron_from_NNC_Polyhedron (&q, q1);
1488 ppl_Polyhedron_intersection_assign (q, q2);
1489 ppl_delete_Polyhedron (q1);
1490 ppl_delete_Polyhedron (q2);
1492 if (ppl_Polyhedron_is_empty (q))
1494 ppl_delete_Polyhedron (p1);
1495 ppl_delete_Polyhedron (p2);
1496 ppl_delete_Polyhedron (q);
1497 return 0;
1500 ppl_new_NNC_Polyhedron_from_NNC_Polyhedron (&q1, p1);
1501 ppl_new_NNC_Polyhedron_from_NNC_Polyhedron (&q2, p2);
1502 ppl_delete_Polyhedron (p1);
1503 ppl_delete_Polyhedron (p2);
1505 ppl_Polyhedron_intersection_assign (q1, q);
1506 ppl_Polyhedron_intersection_assign (q2, q);
1508 m1 = cloog_upol_domain2matrix (cloog_domain_upol (cloog_translate_ppl_polyhedron (q1)));
1509 m2 = cloog_upol_domain2matrix (cloog_domain_upol (cloog_translate_ppl_polyhedron (q2)));
1511 ppl_new_NNC_Polyhedron_from_NNC_Polyhedron (&q4, q);
1512 for (i = 0; i < m1->NbRows; i++)
1513 if (value_one_p (m1->p[i][0])
1514 && value_pos_p (m1->p[i][level]))
1516 ppl_Constraint_t c = cloog_translate_constraint (m1, i, 0, 1);
1517 ppl_Polyhedron_add_constraint (q4, c);
1518 ppl_delete_Constraint (c);
1521 for (i = 0; i < m2->NbRows; i++)
1522 if (value_one_p (m2->p[i][0])
1523 && value_neg_p (m2->p[i][level]))
1525 ppl_Constraint_t c = cloog_translate_constraint (m2, i, 0, 1);
1526 ppl_Polyhedron_add_constraint (q4, c);
1527 ppl_delete_Constraint (c);
1530 if (ppl_Polyhedron_is_empty (q4))
1532 ppl_delete_Polyhedron (q);
1533 ppl_delete_Polyhedron (q1);
1534 ppl_delete_Polyhedron (q2);
1535 ppl_delete_Polyhedron (q4);
1536 return 1;
1539 ppl_delete_Polyhedron (q4);
1540 ppl_new_NNC_Polyhedron_from_NNC_Polyhedron (&q3, q);
1541 for (i = 0; i < m1->NbRows; i++)
1543 if (value_zero_p (m1->p[i][0]))
1545 if (value_zero_p (m1->p[i][level]))
1546 continue;
1548 else if (value_neg_p (m1->p[i][level]))
1550 ppl_Constraint_t c = cloog_translate_oppose_constraint (m1, i, 0, 1);
1551 ppl_Polyhedron_add_constraint (q3, c);
1552 ppl_delete_Constraint (c);
1555 else
1557 ppl_Constraint_t c = cloog_translate_constraint (m1, i, 0, 1);
1558 ppl_Polyhedron_add_constraint (q3, c);
1559 ppl_delete_Constraint (c);
1563 else if (value_neg_p (m1->p[i][level]))
1565 ppl_Constraint_t c = cloog_translate_oppose_constraint (m1, i, 0, 1);
1566 ppl_Polyhedron_add_constraint (q3, c);
1567 ppl_delete_Constraint (c);
1570 else
1571 continue;
1573 ppl_new_NNC_Polyhedron_from_NNC_Polyhedron (&q5, q3);
1574 for (j = 0; j < m2->NbRows; j++)
1576 if (value_zero_p (m2->p[j][0]))
1578 if (value_zero_p (m2->p[j][level]))
1579 continue;
1581 else if (value_pos_p (m2->p[j][level]))
1583 ppl_Constraint_t c = cloog_translate_oppose_constraint (m2, j, 0, 1);
1584 ppl_Polyhedron_add_constraint (q5, c);
1585 ppl_delete_Constraint (c);
1588 else
1590 ppl_Constraint_t c = cloog_translate_constraint (m2, j, 0, 1);
1591 ppl_Polyhedron_add_constraint (q5, c);
1592 ppl_delete_Constraint (c);
1596 else if (value_pos_p (m2->p[j][level]))
1598 ppl_Constraint_t c = cloog_translate_oppose_constraint (m2, j, 0, 1);
1599 ppl_Polyhedron_add_constraint (q5, c);
1600 ppl_delete_Constraint (c);
1603 else
1604 continue;
1606 if (!ppl_Polyhedron_is_empty (q5))
1608 ppl_delete_Polyhedron (q);
1609 ppl_delete_Polyhedron (q1);
1610 ppl_delete_Polyhedron (q2);
1611 ppl_delete_Polyhedron (q3);
1612 ppl_delete_Polyhedron (q5);
1613 return -1;
1616 /* Reinitialize Q5. */
1617 ppl_delete_Polyhedron (q5);
1618 ppl_new_NNC_Polyhedron_from_NNC_Polyhedron (&q5, q3);
1621 /* Reinitialize Q3. */
1622 ppl_delete_Polyhedron (q3);
1623 ppl_new_NNC_Polyhedron_from_NNC_Polyhedron (&q3, q);
1626 ppl_delete_Polyhedron (q);
1627 ppl_delete_Polyhedron (q1);
1628 ppl_delete_Polyhedron (q2);
1629 ppl_delete_Polyhedron (q3);
1630 ppl_delete_Polyhedron (q5);
1631 return 1;
1635 * cloog_domain_sort function:
1636 * This function topologically sorts (nb_pols) polyhedra. Here (pols) is a an
1637 * array of pointers to polyhedra, (nb_pols) is the number of polyhedra,
1638 * (level) is the level to consider for partial ordering (nb_par) is the
1639 * parameter space dimension, (permut) if not NULL, is an array of (nb_pols)
1640 * integers that contains a permutation specification after call in order to
1641 * apply the topological sorting.
1644 void
1645 cloog_domain_sort (CloogDomain **doms, unsigned nb_pols, unsigned level,
1646 unsigned nb_par, int *permut)
1648 int i, j;
1649 int dim = cloog_domain_dim (doms[0]);
1651 for (i = 0; i < (int) nb_pols; i++)
1652 permut[i] = i + 1;
1654 /* Note that here we do a comparison per tuple of polyhedra.
1655 PolyLib does not do this, but instead it does fewer comparisons
1656 and with a complex reasoning they infer that it some comparisons
1657 are not useful. The result is that PolyLib has wrong permutations.
1659 FIXME: In the PolyLib backend, Cloog should use this algorithm
1660 instead of PolyhedronTSort, and cloog_domain_polyhedron_compare
1661 should be implemented with a simple call to PolyhedronLTQ: these
1662 two functions produce identical answers. */
1663 for (i = 0; i < (int) nb_pols; i++)
1664 for (j = i + 1; j < (int) nb_pols; j++)
1666 CloogMatrix *m1 = cloog_upol_domain2matrix (cloog_domain_upol (doms[i]));
1667 CloogMatrix *m2 = cloog_upol_domain2matrix (cloog_domain_upol (doms[j]));
1669 if (cloog_domain_polyhedron_compare (m1, m2, level, nb_par, dim) == 1)
1671 int v = permut[i];
1672 permut[i] = permut[j];
1673 permut[j] = v;
1679 * cloog_domain_empty function:
1680 * This function allocates the memory space for a CloogDomain structure and
1681 * sets its polyhedron to an empty polyhedron with 'dimension' dimensions.
1682 * Then it returns a pointer to the allocated space.
1683 * - June 10th 2005: first version.
1685 CloogDomain *
1686 cloog_domain_empty (int dimension)
1688 return cloog_domain_alloc (cloog_empty_polyhedron (dimension));
1692 /******************************************************************************
1693 * Structure display function *
1694 ******************************************************************************/
1698 * cloog_domain_print_structure :
1699 * this function is a more human-friendly way to display the CloogDomain data
1700 * structure, it only shows the constraint system and includes an indentation
1701 * level (level) in order to work with others print_structure functions.
1702 * Written by Olivier Chorier, Luc Marchaud, Pierre Martin and Romain Tartiere.
1703 * - April 24th 2005: Initial version.
1704 * - May 26th 2005: Memory leak hunt.
1705 * - June 16th 2005: (Ced) Integration in domain.c.
1707 void
1708 cloog_domain_print_structure (FILE * file, CloogDomain * domain, int level)
1710 int i;
1711 CloogMatrix *matrix;
1713 /* Go to the right level. */
1714 for (i = 0; i < level; i++)
1715 fprintf (file, "|\t");
1717 if (domain != NULL)
1719 fprintf (file, "+-- CloogDomain\n");
1721 /* Print the matrix. */
1722 matrix = cloog_upol_domain2matrix (cloog_domain_upol (domain));
1723 cloog_matrix_print_structure (file, matrix, level);
1724 cloog_matrix_free (matrix);
1726 /* A blank line. */
1727 for (i = 0; i < level + 1; i++)
1728 fprintf (file, "|\t");
1729 fprintf (file, "\n");
1731 else
1732 fprintf (file, "+-- Null CloogDomain\n");
1738 * cloog_domain_list_print function:
1739 * This function prints the content of a CloogDomainList structure into a
1740 * file (foo, possibly stdout).
1741 * - November 6th 2001: first version.
1743 void
1744 cloog_domain_list_print (FILE * foo, CloogDomainList * list)
1746 while (list != NULL)
1748 cloog_domain_print (foo, cloog_domain (list));
1749 list = cloog_next_domain (list);
1754 /******************************************************************************
1755 * Memory deallocation function *
1756 ******************************************************************************/
1760 * cloog_domain_list_free function:
1761 * This function frees the allocated memory for a CloogDomainList structure.
1762 * - November 6th 2001: first version.
1764 void
1765 cloog_domain_list_free (CloogDomainList * list)
1767 CloogDomainList *temp;
1769 while (list != NULL)
1771 temp = cloog_next_domain (list);
1772 cloog_domain_free (cloog_domain (list));
1773 free (list);
1774 list = temp;
1779 /******************************************************************************
1780 * Reading function *
1781 ******************************************************************************/
1785 * cloog_domain_read function:
1786 * Adaptation from the PolyLib. This function reads a matrix into a file (foo,
1787 * posibly stdin) and returns a pointer to a polyhedron containing the read
1788 * information.
1789 * - October 18th 2001: first version.
1791 CloogDomain *
1792 cloog_domain_read (FILE * foo)
1794 CloogMatrix *matrix;
1795 CloogDomain *domain;
1797 matrix = cloog_matrix_read (foo);
1798 domain = cloog_domain_matrix2domain (matrix);
1799 cloog_matrix_free (matrix);
1801 return domain;
1806 * cloog_domain_union_read function:
1807 * This function reads a union of polyhedra into a file (foo, posibly stdin) and
1808 * returns a pointer to a Polyhedron containing the read information.
1809 * - September 9th 2002: first version.
1810 * - October 29th 2005: (debug) removal of a leak counting "correction" that
1811 * was just false since ages.
1813 CloogDomain *
1814 cloog_domain_union_read (FILE * foo)
1816 int i, nb_components;
1817 char s[MAX_STRING];
1818 CloogDomain *domain, *temp, *old;
1820 /* domain reading: nb_components (constraint matrices). */
1821 while (fgets (s, MAX_STRING, foo) == 0);
1822 while ((*s == '#' || *s == '\n') || (sscanf (s, " %d", &nb_components) < 1))
1823 fgets (s, MAX_STRING, foo);
1825 if (nb_components > 0)
1826 { /* 1. first part of the polyhedra union, */
1827 domain = cloog_domain_read (foo);
1828 /* 2. and the nexts. */
1829 for (i = 1; i < nb_components; i++)
1830 { /* Leak counting is OK since next allocated domain is freed here. */
1831 temp = cloog_domain_read (foo);
1832 old = domain;
1833 domain = cloog_domain_union (temp, old);
1834 cloog_domain_free (temp);
1835 cloog_domain_free (old);
1837 return cloog_check_domain (domain);
1839 else
1840 return NULL;
1845 * cloog_domain_list_read function:
1846 * This function reads a list of polyhedra into a file (foo, posibly stdin) and
1847 * returns a pointer to a CloogDomainList containing the read information.
1848 * - November 6th 2001: first version.
1850 CloogDomainList *
1851 cloog_domain_list_read (FILE * foo)
1853 int i, nb_pols;
1854 char s[MAX_STRING];
1855 CloogDomainList *list, *now, *next;
1858 /* We read first the number of polyhedra in the list. */
1859 while (fgets (s, MAX_STRING, foo) == 0);
1860 while ((*s == '#' || *s == '\n') || (sscanf (s, " %d", &nb_pols) < 1))
1861 fgets (s, MAX_STRING, foo);
1863 /* Then we read the polyhedra. */
1864 list = NULL;
1865 if (nb_pols > 0)
1867 list = (CloogDomainList *) malloc (sizeof (CloogDomainList));
1868 cloog_set_domain (list, cloog_domain_read (foo));
1869 cloog_set_next_domain (list, NULL);
1870 now = list;
1871 for (i = 1; i < nb_pols; i++)
1873 next = (CloogDomainList *) malloc (sizeof (CloogDomainList));
1874 cloog_set_domain (next, cloog_domain_read (foo));
1875 cloog_set_next_domain (next, NULL);
1876 cloog_set_next_domain (now, next);
1877 now = cloog_next_domain (now);
1880 return list;
1884 /******************************************************************************
1885 * Processing functions *
1886 ******************************************************************************/
1889 * cloog_domain_isempty function:
1890 * This function returns 1 if the polyhedron given as input is empty, 0
1891 * otherwise.
1892 * - October 28th 2001: first version.
1895 cloog_domain_isempty (CloogDomain * domain)
1897 if (cloog_domain_polyhedron (domain) == NULL)
1898 return 1;
1900 if (cloog_upol_next (cloog_domain_upol (domain)))
1901 return 0;
1903 return (cloog_domain_dim (domain) < cloog_domain_nbeq (domain)) ? 1 : 0;
1907 * cloog_domain_project function:
1908 * From Quillere's LoopGen 0.4. This function returns the projection of
1909 * (domain) on the (level) first dimensions (i.e. outer loops). It returns a
1910 * pointer to the projected Polyhedron.
1911 * - nb_par is the number of parameters.
1913 * - October 27th 2001: first version.
1914 * - June 21rd 2005: Adaptation for GMP (based on S. Verdoolaege's version of
1915 * CLooG 0.12.1).
1917 CloogDomain *
1918 cloog_domain_project (CloogDomain * domain, int level, int nb_par)
1920 CloogDomain *res = NULL;
1921 polyhedra_union upol = cloog_domain_upol (domain);
1922 int i, diff = cloog_domain_dim (domain) - level - nb_par;
1923 int n;
1924 ppl_dimension_type *to_remove;
1926 if (diff < 0)
1928 fprintf (stderr, "cloog_domain_project should not be called with"
1929 "cloog_domain_dim (domain) < level + nb_par");
1930 exit (1);
1933 if (diff == 0)
1934 return cloog_domain_copy (domain);
1936 n = diff;
1937 to_remove = (ppl_dimension_type *) malloc (n * sizeof (ppl_dimension_type));
1939 for (i = 0; i < n; i++)
1940 to_remove[i] = i + level;
1942 while (upol)
1944 ppl_Polyhedron_t ppl = cloog_translate_constraint_matrix (cloog_upol_domain2matrix (upol));
1946 ppl_Polyhedron_remove_space_dimensions (ppl, to_remove, n);
1947 res = cloog_domain_add_domain (res, cloog_translate_ppl_polyhedron (ppl));
1948 ppl_delete_Polyhedron (ppl);
1949 upol = cloog_upol_next (upol);
1952 return res;
1956 * cloog_domain_extend function:
1957 * From Quillere's LoopGen 0.4. This function returns the (domain) given as
1958 * input with (dim)+(nb_par) dimensions. The new dimensions are added before
1959 * the (nb_par) parameters. This function does not free (domain), and returns
1960 * a new polyhedron.
1961 * - nb_par is the number of parameters.
1963 * - October 27th 2001: first version.
1964 * - June 21rd 2005: Adaptation for GMP (based on S. Verdoolaege's version of
1965 * CLooG 0.12.1).
1967 CloogDomain *
1968 cloog_domain_extend (CloogDomain * domain, int dim, int nb_par)
1970 CloogDomain *res = NULL;
1971 polyhedra_union upol = cloog_domain_upol (domain);
1972 int i, k, n, diff = dim + nb_par - cloog_domain_dim (domain);
1973 ppl_dimension_type *map;
1974 ppl_dimension_type to_add = diff;
1976 if (diff == 0)
1977 return cloog_domain_copy (domain);
1979 n = dim + nb_par;
1980 map = (ppl_dimension_type *) malloc (n * sizeof (ppl_dimension_type));
1982 k = cloog_domain_dim (domain) - nb_par;
1983 for (i = 0; i < k; i++)
1984 map[i] = i;
1986 k += nb_par;
1987 for (; i < k; i++)
1988 map[i] = i + diff;
1990 k += diff;
1991 for (; i < k; i++)
1992 map[i] = i - nb_par;
1994 while (upol)
1996 ppl_Polyhedron_t ppl = cloog_translate_constraint_matrix (cloog_upol_domain2matrix (upol));
1998 ppl_Polyhedron_add_space_dimensions_and_embed (ppl, to_add);
1999 ppl_Polyhedron_map_space_dimensions (ppl, map, n);
2000 res = cloog_domain_add_domain (res, cloog_translate_ppl_polyhedron (ppl));
2001 ppl_delete_Polyhedron (ppl);
2002 upol = cloog_upol_next (upol);
2005 return res;
2009 * cloog_domain_never_integral function:
2010 * For us, an equality like 3*i -4 = 0 is always false since 4%3 != 0. This
2011 * function returns a boolean set to 1 if there is this kind of 'never true'
2012 * constraint inside a polyhedron, 0 otherwise.
2013 * - domain is the polyhedron to check,
2015 * - November 28th 2001: first version.
2016 * - June 26th 2003: for iterators, more 'never true' constraints are found
2017 * (compare cholesky2 and vivien with a previous version),
2018 * checking for the parameters created (compare using vivien).
2019 * - June 28th 2003: Previously in loop.c and called
2020 * cloog_loop_simplify_nevertrue, now here !
2021 * - June 21rd 2005: Adaptation for GMP (based on S. Verdoolaege's version of
2022 * CLooG 0.12.1).
2023 * - October 14th 2005: Complete rewriting, not faster but code quite shorter.
2026 cloog_domain_never_integral (CloogDomain * domain)
2028 int i, dimension, nbc;
2029 Value gcd, modulo;
2030 polyhedron p;
2032 if ((domain == NULL) || (cloog_domain_polyhedron (domain) == NULL))
2033 return 1;
2035 value_init_c (gcd);
2036 value_init_c (modulo);
2037 p = cloog_domain_polyhedron (domain);
2038 dimension = cloog_domain_dim (domain) + 2;
2039 nbc = cloog_domain_nbconstraints (domain);
2041 /* For each constraint... */
2042 for (i = 0; i < nbc; i++)
2043 { /* If we have an equality and the scalar part is not zero... */
2044 if (value_zero_p (p->Constraint[i][0]) &&
2045 value_notzero_p (p->Constraint[i][dimension - 1]))
2046 { /* Then we check whether the scalar can be divided by the gcd of the
2047 * unknown vector (including iterators and parameters) or not. If not,
2048 * there is no integer point in the polyhedron and we return 1.
2050 cloog_vector_gcd (&(p->Constraint[i][1]), dimension - 2, &gcd);
2051 value_modulus (modulo,
2052 p->Constraint[i][dimension - 1],
2053 gcd);
2055 if (value_notzero_p (modulo))
2057 value_clear_c (gcd);
2058 value_clear_c (modulo);
2059 return 1;
2064 value_clear_c (gcd);
2065 value_clear_c (modulo);
2066 return 0;
2069 static int
2070 cloog_vector_matrix_smallest_column (Value * a, int n, int p, int q)
2072 int res, numero = 0, k, allzero;
2073 Value minus, comp;
2074 Value *c;
2076 value_init (minus);
2077 value_init (comp);
2078 c = a + q - 1 + p * (n - 1);
2079 allzero = 1;
2080 value_absolute (comp, *c);
2082 for (k = n; k > q; k--, c -= p, value_absolute (comp, *c))
2084 if (value_notzero_p (comp))
2086 if (allzero == 1)
2088 value_assign (minus, comp);
2089 numero = k;
2090 allzero = 0;
2092 else if (value_ge (minus, comp))
2094 value_assign (minus, comp);
2095 numero = k;
2100 if (allzero)
2101 res = 0;
2102 else
2104 value_absolute (comp, *c);
2105 if ((value_notzero_p (comp)) && (value_ge (minus, comp)))
2106 res = q;
2107 else
2108 res = numero;
2111 value_clear (minus);
2112 value_clear (comp);
2114 return res;
2117 static void
2118 cloog_vector_matrix_swap_rows (Value * a, int i, int j, int p)
2120 int k;
2121 Value *c1 = a + (i - 1) * p;
2122 Value *c2 = a + (j - 1) * p;
2123 Value s;
2125 value_init (s);
2127 for (k = 1; k <= p; k++)
2129 value_assign (s, *c1);
2130 value_assign (*c1, *c2);
2131 value_assign (*c2, s);
2132 c1++;
2133 c2++;
2135 value_clear (s);
2136 return;
2139 static void
2140 cloog_vector_matrix_swap_columns (Value * a, int i, int j, int n, int p)
2142 int k;
2143 Value s;
2144 Value *c1, *c2;
2146 value_init (s);
2147 c1 = a + (i - 1);
2148 c2 = a + (j - 1);
2150 for (k = 1; k <= n; k++)
2152 value_assign (s, *c1);
2153 value_assign (*c1, *c2);
2154 value_assign (*c2, s);
2155 c1 = c1 + p;
2156 c2 = c2 + p;
2158 value_clear (s);
2159 return;
2162 static void
2163 cloog_vector_matrix_oppose_line (Value * a, int i, int p)
2165 int k;
2166 Value *c = a + (i - 1) * p;
2168 for (k = 1; k <= p; k++, c++)
2169 value_oppose (*c, *c);
2172 static void
2173 cloog_vector_matrix_oppose_column (Value * a, int i, int n, int p)
2175 int k;
2176 Value *c = a + (i - 1);
2178 for (k = 1; k <= n; k++, c += p)
2179 value_oppose (*c, *c);
2182 static void
2183 cloog_vector_matrix_combine_line (Value * a, int i, int j,
2184 Value x, int p)
2186 int k;
2187 Value *c1 = a + (i - 1) * p;
2188 Value *c2 = a + (j - 1) * p;
2190 for (k = 1; k <= p; k++, c1++, c2++)
2191 value_addmul (*c1, x, *c2);
2194 static void
2195 cloog_vector_matrix_combine_column (Value * a, int i, int j, Value x, int n, int p)
2197 int k;
2198 Value *c1 = a + (i - 1);
2199 Value *c2 = a + (j - 1);
2201 for (k = 1; k <= n; k++, c1 = c1 + p, c2 = c2 + p)
2202 value_addmul (*c1, x, *c2);
2205 static void
2206 cloog_matrix_hermite_combine (Value *a, Value *b, Value c, Value *d, int k, int n,
2207 int p, int q, Value pivot, Value x, Value x_inv)
2209 Value tmp;
2211 value_init (tmp);
2212 value_division (x, c, pivot);
2213 value_modulus (tmp, c, pivot);
2215 if (value_neg_p (tmp))
2216 value_decrement (x, x);
2218 value_clear (tmp);
2220 value_oppose (x_inv, x);
2221 cloog_vector_matrix_combine_line (a, k, q, x_inv, p);
2222 cloog_vector_matrix_combine_column (b, q, k, x, n, n);
2223 cloog_vector_matrix_combine_line (d, k, q, x_inv, n);
2226 static void
2227 cloog_matrix_hermite_oppose (Value *a, Value *b, Value *d, int n, int p, int q, Value pivot)
2229 cloog_vector_matrix_oppose_line (a, q, p);
2230 cloog_vector_matrix_oppose_line (d, q, n);
2231 cloog_vector_matrix_oppose_column (b, q, n, n);
2232 value_oppose (pivot, pivot);
2235 static void
2236 cloog_matrix_hermite_1 (Value * a, Value * b, Value * d, int n, int p, int q)
2238 int i, k;
2239 Value x, pivot, x_inv;
2240 Value *c;
2242 if (q > p || q > n)
2243 return;
2245 value_init (pivot);
2246 value_init (x);
2247 value_init (x_inv);
2249 for (i = cloog_vector_matrix_smallest_column (a, n, p, q); i != 0;
2250 i = cloog_vector_matrix_smallest_column (a, n, p, q))
2252 if (i != q)
2254 cloog_vector_matrix_swap_rows (a, i, q, p);
2255 cloog_vector_matrix_swap_columns (b, i, q, n, n);
2256 cloog_vector_matrix_swap_rows (d, i, q, n);
2259 c = a + (q - 1) * (p + 1);
2260 value_assign (pivot, *c);
2261 if (value_neg_p (pivot))
2262 cloog_matrix_hermite_oppose (a, b, d, n, p, q, pivot);
2264 for (c += p, k = q + 1; k <= n; k++, c += p)
2265 if (value_notzero_p (*c))
2266 cloog_matrix_hermite_combine (a, b, *c, d, k, n, p, q, pivot, x, x_inv);
2269 c = a + (q - 1);
2270 value_assign (pivot, *(c + (q - 1) * p));
2271 if (value_neg_p (pivot))
2272 cloog_matrix_hermite_oppose (a, b, d, n, p, q, pivot);
2274 if (value_notzero_p (pivot))
2275 for (k = 1; k < q; k++, c += p)
2276 if (value_notzero_p (*c))
2277 cloog_matrix_hermite_combine (a, b, *c, d, k, n, p, q, pivot, x, x_inv);
2279 cloog_matrix_hermite_1 (a, b, d, n, p, q + 1);
2281 value_clear (pivot);
2282 value_clear (x);
2283 value_clear (x_inv);
2284 return;
2287 static CloogMatrix *
2288 cloog_matrix_add_null_row (CloogMatrix * M)
2290 int i, j;
2291 CloogMatrix *res = cloog_matrix_alloc (M->NbRows + 1, M->NbColumns);
2293 for (i = 0; i < M->NbRows; i++)
2294 for (j = 0; j < M->NbColumns; j++)
2295 value_assign (res->p[i][j], M->p[i][j]);
2297 for (j = 0; j < M->NbColumns; j++)
2298 value_set_si (res->p[i][j], 0);
2300 return res;
2303 static CloogMatrix *
2304 cloog_matrix_transpose (CloogMatrix * m)
2306 int i, j;
2307 CloogMatrix *res = cloog_matrix_alloc (m->NbColumns, m->NbRows);
2309 for (i = 0; i < (int) m->NbRows; i++)
2310 for (j = 0; j < (int) m->NbColumns; j++)
2311 value_assign (res->p[j][i], m->p[i][j]);
2313 return res;
2316 static Value *
2317 cloog_vector_matrix_vectorify (CloogMatrix * A)
2319 int i, j;
2320 Value *res = (Value *) malloc (sizeof (Value) * A->NbRows * A->NbColumns);
2322 for (i = 0; i < A->NbRows * A->NbColumns; i++)
2323 value_init (res[i]);
2325 for (i = 0; i < A->NbRows; i++)
2326 for (j = 0; j < A->NbColumns; j++)
2327 value_assign (res[i * A->NbColumns + j], A->p[i][j]);
2329 return res;
2332 static CloogMatrix *
2333 cloog_vector_matrix_matrixify (Value * A, int NbRows, int NbCols)
2335 int i, j;
2336 CloogMatrix *res = cloog_matrix_alloc (NbRows, NbCols);
2338 for (i = 0; i < NbRows; i++)
2339 for (j = 0; j < NbCols; j++)
2340 value_assign (res->p[i][j], A[i * NbCols + j]);
2342 return res;
2345 static Value *
2346 cloog_vector_matrix_identity (int n)
2348 int i, j;
2349 Value *res = (Value *) malloc (sizeof (Value) * n * n);
2350 Value *ptr = res;
2352 for (i = 0; i < n * n; i++)
2353 value_init (res[i]);
2355 for (i = 1; i <= n; i++)
2356 for (j = 1; j <= n; j++, ptr++)
2357 if (i == j)
2358 value_set_si (*ptr, 1);
2359 else
2360 value_set_si (*ptr, 0);
2362 return res;
2365 static void
2366 cloog_matrix_hermite (CloogMatrix * a, CloogMatrix ** H, CloogMatrix ** U)
2368 int i;
2369 CloogMatrix *tu, *transpose = cloog_matrix_transpose (a);
2370 Value *va = cloog_vector_matrix_vectorify (transpose);
2371 Value *vid = cloog_vector_matrix_identity (a->NbColumns);
2372 Value *vid_inv = cloog_vector_matrix_identity (a->NbColumns);
2374 cloog_matrix_free (transpose);
2376 cloog_matrix_hermite_1 (va, vid, vid_inv,
2377 a->NbColumns, a->NbRows, 1);
2379 transpose = cloog_vector_matrix_matrixify (va, a->NbColumns, a->NbRows);
2380 H[0] = cloog_matrix_transpose (transpose);
2381 cloog_matrix_free (transpose);
2383 tu = cloog_vector_matrix_matrixify (vid, a->NbColumns, a->NbColumns);
2384 U[0] = cloog_matrix_transpose (tu);
2385 cloog_matrix_free (tu);
2387 for (i = 0; i < a->NbRows * a->NbColumns; i++)
2388 value_clear (va[i]);
2390 for (i = 0; i < a->NbColumns * a->NbColumns; i++)
2391 value_clear (vid[i]);
2393 for (i = 0; i < a->NbColumns * a->NbColumns; i++)
2394 value_clear (vid_inv[i]);
2396 free (va);
2397 free (vid);
2398 free (vid_inv);
2401 static inline void
2402 cloog_exchange_rows (CloogMatrix * m, int row1, int row2)
2404 int i;
2406 for (i = 0; i < (int) m->NbColumns; i++)
2407 value_swap (m->p[row1][i], m->p[row2][i]);
2410 static CloogMatrix *
2411 cloog_dio_copy_submatrix (CloogMatrix * matrix)
2413 int i, j ;
2414 CloogMatrix * copy = cloog_matrix_alloc (matrix->NbRows - 1, matrix->NbColumns - 1) ;
2416 for (i = 0; i < copy->NbRows; i++)
2417 for (j = 0; j < copy->NbColumns; j++)
2418 value_assign(copy->p[i][j], matrix->p[i][j]) ;
2420 return copy;
2423 static void
2424 cloog_dio_rearrange_redundant_rows (CloogMatrix * M)
2426 int i, end, row, rank = 1;
2427 CloogMatrix *A, *L, *H, *U;
2429 L = cloog_dio_copy_submatrix (M);
2430 if (L->NbRows < 2)
2431 goto done;
2433 A = cloog_matrix_alloc (1, L->NbColumns);
2434 for (i = 0; i < L->NbColumns; i++)
2435 value_assign (A->p[0][i], L->p[0][i]);
2437 end = L->NbRows - 1;
2438 row = 1;
2440 while (1)
2442 int n;
2443 CloogMatrix *temp = cloog_matrix_add_null_row (A);
2445 for (i = 0; i < A->NbColumns; i++)
2446 value_assign (temp->p[row][i], L->p[row][i]);
2448 cloog_matrix_hermite (temp, &H, &U);
2449 cloog_matrix_free (U);
2451 n = H->NbRows;
2452 for (i = 0; i < n; i++)
2453 if (value_zero_p (H->p[i][i]))
2454 break;
2456 cloog_matrix_free (H);
2458 if (i != n)
2460 /* This is a redundant row: put it at the end. */
2461 cloog_exchange_rows (M, row, end);
2462 end--;
2464 else
2466 row++;
2467 rank++;
2468 cloog_matrix_free (A);
2469 A = cloog_matrix_copy (temp);
2470 cloog_matrix_free (temp);
2473 if (rank == (end >= L->NbColumns ? L->NbColumns : end)
2474 || row >= end)
2475 break;
2478 cloog_matrix_free (A);
2480 done:
2481 cloog_matrix_free (L);
2482 return;
2485 static void
2486 cloog_matrix_inverse_pivot (CloogMatrix *m, int low, int up, int i, int j,
2487 Value m1, Value m2, Value x, Value piv)
2489 int c;
2491 for (c = low; c < up; ++c)
2493 value_multiply (m1, piv, m->p[j][c]);
2494 value_multiply (m2, x, m->p[i][c]);
2495 value_subtract (m->p[j][c], m1, m2);
2499 static Value *
2500 cloog_matrix_inverse_den (CloogMatrix *Mat, CloogMatrix *MatInv, int k, Value *x)
2502 int j, c;
2503 Value gcd;
2504 Value *res = (Value *) malloc (k * sizeof (Value));
2505 Value m1;
2507 value_init (m1);
2508 value_init (gcd);
2509 value_set_si (*x, 1);
2511 for (j = 0; j < cloog_matrix_nrows (Mat); ++j)
2513 value_init (res[j]);
2514 value_assign (res[j], Mat->p[j][j]);
2515 cloog_vector_gcd (&MatInv->p[j][0], k, &gcd);
2516 Gcd (gcd, res[j], &gcd);
2518 if (value_neg_p (res[j]))
2519 value_oppose (gcd, gcd);
2521 if (value_notone_p (gcd))
2523 for (c = 0; c < k; c++)
2524 value_division (MatInv->p[j][c], MatInv->p[j][c], gcd);
2525 value_division (res[j], res[j], gcd);
2528 Gcd (*x, res[j], &gcd);
2529 value_division (m1, res[j], gcd);
2530 value_multiply (*x, *x, m1);
2533 value_clear (m1);
2534 value_clear (gcd);
2535 return res;
2538 static void
2539 cloog_matrix_inverse_div (CloogMatrix *MatInv, Value *den, Value m1, Value x)
2541 int j, c;
2543 if (value_notone_p (x))
2544 for (j = 0; j < MatInv->NbRows; ++j)
2546 for (c = 0; c < MatInv->NbColumns; c++)
2548 value_division (m1, x, den[j]);
2549 value_multiply (MatInv->p[j][c], MatInv->p[j][c], m1);
2554 static int
2555 cloog_matrix_inverse_triang (CloogMatrix *Mat, CloogMatrix *MatInv, Value *m1, Value *m2)
2557 int i, j;
2558 Value gcd, piv, x;
2559 int res = 0;
2561 value_init (gcd);
2562 value_init (piv);
2563 value_init (x);
2565 for (i = 0; i < cloog_matrix_ncolumns (Mat); ++i)
2567 if (value_zero_p (Mat->p[i][i]))
2569 for (j = i; j < cloog_matrix_nrows (Mat); ++j)
2570 if (value_notzero_p (Mat->p[j][i]))
2571 break;
2573 if (j == cloog_matrix_nrows (Mat))
2574 goto done;
2576 cloog_matrix_exchange_rows (Mat, i, j);
2577 cloog_matrix_exchange_rows (MatInv, i, j);
2580 for (j = 0; j < cloog_matrix_nrows (Mat) ; ++j)
2582 if (j == i
2583 || !value_notzero_p (Mat->p[j][i]))
2584 continue;
2586 value_assign (x, Mat->p[j][i]);
2587 value_assign (piv, Mat->p[i][i]);
2588 Gcd (x, piv, &gcd);
2589 if (value_notone_p (gcd))
2591 value_division (x, x, gcd);
2592 value_division (piv, piv, gcd);
2595 cloog_matrix_inverse_pivot (Mat, ((j > i) ? i : 0),
2596 cloog_matrix_nrows (Mat),
2597 i, j, *m1, *m2, x, piv);
2598 cloog_matrix_inverse_pivot (MatInv, 0, cloog_matrix_nrows (Mat),
2599 i, j, *m1, *m2, x, piv);
2601 cloog_vector_gcd (&MatInv->p[j][0], (unsigned) cloog_matrix_nrows (Mat), m1);
2602 cloog_vector_gcd (&Mat->p[j][0], (unsigned) cloog_matrix_nrows (Mat), m2);
2603 Gcd (*m1, *m2, &gcd);
2604 if (value_notone_p (gcd))
2606 int c;
2608 for (c = 0; c < cloog_matrix_nrows (Mat); ++c)
2610 value_division (Mat->p[j][c], Mat->p[j][c], gcd);
2611 value_division (MatInv->p[j][c], MatInv->p[j][c], gcd);
2617 res = 1;
2619 done:
2620 value_clear (x);
2621 value_clear (piv);
2622 value_clear (gcd);
2623 return res;
2626 static int
2627 cloog_matrix_inverse (CloogMatrix * Mat, CloogMatrix * MatInv)
2629 int res = 0;
2630 int i, j;
2631 Value x;
2632 Value m1, m2;
2633 Value *den;
2635 if (Mat->NbRows != Mat->NbColumns)
2636 return 0;
2638 value_init (x);
2639 value_init (m1);
2640 value_init (m2);
2642 cloog_vector_set (MatInv->p[0], 0, cloog_matrix_nrows (Mat) * cloog_matrix_nrows (Mat));
2644 for (i = 0; i < cloog_matrix_nrows (Mat); ++i)
2645 value_set_si (MatInv->p[i][i], 1);
2647 if (!cloog_matrix_inverse_triang (Mat, MatInv, &m1, &m2))
2648 goto done;
2650 den = cloog_matrix_inverse_den (Mat, MatInv, cloog_matrix_nrows (Mat), &x);
2651 cloog_matrix_inverse_div (MatInv, den, m1, x);
2653 res = 1;
2655 for (j = 0; j < cloog_matrix_nrows (Mat); ++j)
2656 value_clear (den[j]);
2657 free (den);
2659 done:
2660 value_clear (x);
2661 value_clear (m1);
2662 value_clear (m2);
2664 return res;
2667 static void
2668 cloog_dio_copy (CloogMatrix *m1, CloogMatrix *m2)
2670 int i, j;
2671 int n = m2->NbRows - 1;
2672 int m = m2->NbColumns - 1;
2674 for (i = 0; i < n; i++)
2675 for (j = 0; j < m; j++)
2676 value_assign (m1->p[i][j], m2->p[i][j]);
2679 static Value *
2680 cloog_dio_negate_coeffs (CloogMatrix *m)
2682 int i;
2683 int n = m->NbRows - 1;
2684 int k = m->NbColumns - 1;
2685 Value *res = (Value *) malloc (sizeof (Value) * (n));
2687 for (i = 0; i < n; i++)
2689 value_init (res[i]);
2690 value_oppose (res[i], m->p[i][k]);
2693 return res;
2696 static int
2697 cloog_dio_get_first_diagonal_zero (CloogMatrix *m)
2699 int i, n = m->NbRows <= m->NbColumns ? m->NbRows : m->NbColumns;
2700 int res = 0;
2702 for (i = 0; i < n; i++)
2703 if (value_notzero_p (m->p[i][i]))
2704 res++;
2705 else
2706 break;
2708 return res;
2711 static Value *
2712 cloog_dio_reduce_diagonal (CloogMatrix *m, Value *coeffs, int nbc, int rank)
2714 int i, j;
2715 Value *res = (Value *) malloc (sizeof (Value) * nbc);
2716 Value sum, tmp;
2718 value_init (tmp);
2719 value_init (sum);
2721 for (i = 0; i < nbc; i++)
2722 value_init (res[i]);
2724 for (i = 0; i < rank; i++)
2726 value_set_si (sum, 0);
2727 for (j = 0; j < i; j++)
2728 value_addmul (sum, res[j], m->p[i][j]);
2730 value_subtract (tmp, coeffs[i], sum);
2731 value_modulus (tmp, tmp, m->p[i][i]);
2732 if (value_notzero_p (tmp))
2734 for (i = 0; i < nbc; i++)
2735 value_clear (res[i]);
2736 free (res);
2738 value_clear (tmp);
2739 value_clear (sum);
2741 return NULL;
2744 value_subtract (tmp, coeffs[i], sum);
2745 value_division (res[i], tmp, m->p[i][i]);
2748 for (i = rank; i < m->NbColumns; i++)
2749 value_set_si (res[i], 0);
2751 return res;
2754 static int
2755 cloog_dio_check_coeffs (CloogMatrix *m, Value *T, Value *coeffs, int nbr, int nbc, int rank)
2757 Value sum, tmp;
2758 int i, j;
2760 value_init (sum);
2761 value_init (tmp);
2763 for (i = rank; i < m->NbRows; i++)
2765 value_set_si (sum, 0);
2766 for (j = 0; j < m->NbColumns; j++)
2767 value_addmul (sum, T[j], m->p[i][j]);
2769 if (value_ne (sum, coeffs[i]))
2771 for (i = 0; i < nbr; i++)
2772 value_clear (coeffs[i]);
2773 for (i = 0; i < nbc; i++)
2774 value_clear (T[i]);
2775 free (coeffs);
2776 free (T);
2778 value_clear (sum);
2779 value_clear (tmp);
2781 return 0;
2785 return 1;
2788 static CloogMatrix *
2789 cloog_dio_init_U (CloogMatrix *u, int n, int rank)
2791 int i, j;
2792 CloogMatrix *res;
2794 if (rank == n)
2795 return cloog_matrix_alloc (0, 0);
2797 res = cloog_matrix_alloc (n, n - rank);
2799 for (i = 0; i < res->NbRows; i++)
2800 for (j = 0; j < res->NbColumns; j++)
2801 value_assign (res->p[i][j], u->p[i][j + rank]);
2803 return res;
2806 static Vector *
2807 cloog_dio_init_X (CloogMatrix *u, Value *t, int n)
2809 int i, j;
2810 Vector *res = Vector_Alloc (n);
2811 Value sum;
2813 value_init (sum);
2814 for (i = 0; i < u->NbRows; i++)
2816 value_set_si (sum, 0);
2818 for (j = 0; j < u->NbColumns; j++)
2819 value_addmul (sum, u->p[i][j], t[j]);
2821 value_assign (res->p[i], sum);
2824 value_clear (sum);
2825 return res;
2828 static int
2829 cloog_solve_diophantine (CloogMatrix * m, CloogMatrix ** u, Vector ** x)
2831 int i, nbr, nbc, rank;
2832 CloogMatrix *A, *temp, *hermi, *unimod, *unimodinv;
2833 Value *coeffs;
2834 Value *T;
2836 A = cloog_matrix_copy (m);
2837 nbr = A->NbRows - 1;
2839 cloog_dio_rearrange_redundant_rows (A);
2841 temp = cloog_matrix_alloc (A->NbRows - 1, A->NbColumns - 1);
2842 cloog_dio_copy (temp, A);
2843 coeffs = cloog_dio_negate_coeffs (A);
2844 cloog_matrix_free (A);
2846 cloog_matrix_hermite (temp, &hermi, &unimod);
2847 rank = cloog_dio_get_first_diagonal_zero (hermi);
2848 nbc = temp->NbColumns;
2850 T = cloog_dio_reduce_diagonal (hermi, coeffs, nbc, rank);
2851 unimodinv = cloog_matrix_alloc (unimod->NbRows, unimod->NbColumns);
2853 if (!T
2854 || !cloog_dio_check_coeffs (hermi, T, coeffs, nbr, nbc, rank)
2855 || !cloog_matrix_inverse (unimod, unimodinv))
2857 *u = cloog_matrix_alloc (0, 0);
2858 *x = Vector_Alloc (0);
2860 for (i = 0; i < nbr; i++)
2861 value_clear (coeffs[i]);
2863 free (coeffs);
2864 return -1;
2867 *u = cloog_dio_init_U (unimodinv, hermi->NbColumns, rank);
2868 *x = cloog_dio_init_X (unimodinv, T, m->NbColumns - 1);
2870 cloog_matrix_free (unimod);
2871 cloog_matrix_free (unimodinv);
2872 cloog_matrix_free (hermi);
2873 cloog_matrix_free (temp);
2875 for (i = 0; i < nbr; i++)
2876 value_clear (coeffs[i]);
2878 for (i = 0; i < nbc; i++)
2879 value_clear (T[i]);
2881 free (coeffs);
2882 free (T);
2883 return rank;
2887 * cloog_domain_stride function:
2888 * This function finds the stride imposed to unknown with the column number
2889 * 'strided_level' in order to be integral. For instance, if we have a
2890 * constraint like -i - 2j + 2k = 0, and we consider k, then k can be integral
2891 * only if (i + 2j)%2 = 0. Then only if i%2 = 0. Then k imposes a stride 2 to
2892 * the unknown i. The function returns the imposed stride in a parameter field.
2893 * - domain is the set of constraint we have to consider,
2894 * - strided_level is the column number of the unknown for which a stride have
2895 * to be found,
2896 * - looking_level is the column number of the unknown that impose a stride to
2897 * the first unknown.
2898 * - stride is the stride that is returned back as a function parameter.
2899 * - offset is the value of the constant c if the condition is of the shape
2900 * (i + c)%s = 0, s being the stride.
2902 * - June 28th 2003: first version.
2903 * - July 14th 2003: can now look for multiple striding constraints and returns
2904 * the GCD of the strides and the common offset.
2905 * - June 21rd 2005: Adaptation for GMP (based on S. Verdoolaege's version of
2906 * CLooG 0.12.1).
2908 void
2909 cloog_domain_stride (CloogDomain *domain, int strided_level, int nb_par, Value *stride, Value *offset)
2911 int i;
2912 int n_col, n_row, rank;
2913 CloogMatrix *M;
2914 CloogMatrix *U;
2915 Vector *V;
2916 polyhedron p = cloog_domain_polyhedron (domain);
2917 int dimension = cloog_domain_dim (domain);
2918 int nbeq = cloog_domain_nbeq (domain);
2920 /* Look at all equalities involving strided_level and the inner
2921 * iterators. We can ignore the outer iterators and the parameters
2922 * here because the lower bound on strided_level is assumed to
2923 * be a constant.
2925 n_col = (1 + dimension - nb_par) - strided_level;
2926 for (i = 0, n_row = 0; i < nbeq; i++)
2927 if (cloog_first_non_zero
2928 (p->Constraint[i] + strided_level, n_col) != -1)
2929 ++n_row;
2931 M = cloog_matrix_alloc (n_row + 1, n_col + 1);
2932 for (i = 0, n_row = 0; i < nbeq; i++)
2934 if (cloog_first_non_zero
2935 (p->Constraint[i] + strided_level, n_col) == -1)
2936 continue;
2937 cloog_vector_copy (p->Constraint[i] + strided_level,
2938 M->p[n_row], n_col);
2939 value_assign (M->p[n_row][n_col],
2940 p->Constraint[i][1 + dimension]);
2941 ++n_row;
2943 value_set_si (M->p[n_row][n_col], 1);
2945 /* Then look at the general solution to the above equalities. */
2946 rank = cloog_solve_diophantine (M, &U, &V);
2947 cloog_matrix_free (M);
2949 if (rank == -1)
2951 /* There is no solution, so the body of this loop will
2952 * never execute. We just leave the constraints alone here so
2953 * that they will ensure the body will not be executed.
2954 * We should probably propagate this information up so that
2955 * the loop can be removed entirely.
2957 value_set_si (*offset, 0);
2958 value_set_si (*stride, 1);
2960 else
2962 /* Compute the gcd of the coefficients defining strided_level. */
2963 cloog_vector_gcd (U->p[0], U->NbColumns, stride);
2964 value_oppose (*offset, V->p[0]);
2965 value_pmodulus (*offset, *offset, *stride);
2968 cloog_matrix_free (U);
2969 Vector_Free (V);
2970 return;
2975 * cloog_domain_integral_lowerbound function:
2976 * This function returns 1 if the lower bound of an iterator (such as its
2977 * column rank in the constraint set 'domain' is 'level') is integral,
2978 * 0 otherwise. If the lower bound is actually integral, the function fills
2979 * the 'lower' field with the lower bound value.
2980 * - June 29th 2003: first version.
2981 * - June 21rd 2005: Adaptation for GMP (based on S. Verdoolaege's version of
2982 * CLooG 0.12.1).
2985 cloog_domain_integral_lowerbound (CloogDomain *domain, int level, Value *lower)
2987 int i, first_lower = 1, dimension, lower_constraint = -1, nbc;
2988 Value iterator, constant, tmp;
2989 polyhedron p = cloog_domain_polyhedron (domain);
2990 dimension = cloog_domain_dim (domain);
2991 nbc = cloog_domain_nbconstraints (domain);
2993 /* We want one and only one lower bound (e.g. no equality, no maximum
2994 * calculation...).
2996 for (i = 0; i < nbc; i++)
2997 if (value_zero_p (p->Constraint[i][0])
2998 && value_notzero_p (p->Constraint[i][level]))
2999 return 0;
3001 for (i = 0; i < nbc; i++)
3002 if (value_pos_p (p->Constraint[i][level]))
3004 if (first_lower)
3006 first_lower = 0;
3007 lower_constraint = i;
3009 else
3010 return 0;
3013 if (first_lower)
3014 return 0;
3016 /* We want an integral lower bound: no other non-zero entry except the
3017 * iterator coefficient and the constant.
3019 for (i = 1; i < level; i++)
3020 if (value_notzero_p
3021 (p->Constraint[lower_constraint][i]))
3022 return 0;
3024 for (i = level + 1; i <= dimension; i++)
3025 if (value_notzero_p
3026 (p->Constraint[lower_constraint][i]))
3028 return 0;
3031 value_init_c (iterator);
3032 value_init_c (constant);
3033 value_init_c (tmp);
3035 /* If all is passed, then find the lower bound and return 1. */
3036 value_assign (iterator,
3037 p->Constraint[lower_constraint][level]);
3038 value_oppose (constant,
3039 p->Constraint[lower_constraint][dimension + 1]);
3041 value_modulus (tmp, constant, iterator);
3042 value_division (*lower, constant, iterator);
3044 if (!(value_zero_p (tmp) || value_neg_p (constant)))
3045 value_increment (*lower, *lower);
3047 value_clear_c (iterator);
3048 value_clear_c (constant);
3049 value_clear_c (tmp);
3050 return 1;
3055 * cloog_domain_lowerbound_update function:
3056 * This function updates the integral lower bound of an iterator (such as its
3057 * column rank in the constraint set 'domain' is 'level') into 'lower'.
3058 * - Jun 29th 2003: first version.
3059 * - June 21rd 2005: Adaptation for GMP (based on S. Verdoolaege's version of
3060 * CLooG 0.12.1).
3062 void
3063 cloog_domain_lowerbound_update (CloogDomain *domain, int level, Value lower)
3065 int i;
3066 int nbc = cloog_domain_nbconstraints (domain);
3067 int dim = cloog_domain_dim (domain);
3068 polyhedron p = cloog_domain_polyhedron (domain);
3070 /* There is only one lower bound, the first one is the good one. */
3071 for (i = 0; i < nbc; i++)
3072 if (value_pos_p (p->Constraint[i][level]))
3074 value_set_si (p->Constraint[i][level], 1);
3075 value_oppose (p->Constraint[i][dim + 1], lower);
3076 break;
3082 * cloog_domain_lazy_equal function:
3083 * This function returns 1 if the domains given as input are the same, 0 if it
3084 * is unable to decide. This function makes an entry-to-entry comparison between
3085 * the constraint systems, if all the entries are the same, the domains are
3086 * obviously the same and it returns 1, at the first difference, it returns 0.
3087 * This is a very fast way to verify this property. It has been shown (with the
3088 * CLooG benchmarks) that operations on equal domains are 17% of all the
3089 * polyhedral computations. For 75% of the actually identical domains, this
3090 * function answer that they are the same and allow to give immediately the
3091 * trivial solution instead of calling the heavy general functions of PolyLib.
3092 * - August 22th 2003: first version.
3093 * - June 21rd 2005: Adaptation for GMP (based on S. Verdoolaege's version of
3094 * CLooG 0.12.1).
3097 cloog_domain_lazy_equal (CloogDomain * d1, CloogDomain * d2)
3099 int i, j;
3100 polyhedra_union u1 = cloog_domain_upol (d1);
3101 polyhedra_union u2 = cloog_domain_upol (d2);
3103 while (u1 && u2)
3105 if ((cloog_upol_nbc (u1) != cloog_upol_nbc (u2)) ||
3106 (cloog_upol_dim (u1) != cloog_upol_dim (u2)))
3107 return 0;
3109 for (i = 0; i < (int) cloog_upol_nbc (u1); i++)
3110 for (j = 0; j < (int) cloog_upol_dim (u1) + 2; j++)
3111 if (value_ne (cloog_upol_polyhedron (u1)->Constraint[i][j],
3112 cloog_upol_polyhedron (u2)->Constraint[i][j]))
3113 return 0;
3115 u1 = cloog_upol_next (u1);
3116 u2 = cloog_upol_next (u2);
3119 if (u1 || u2)
3120 return 0;
3122 return 1;
3127 * cloog_domain_lazy_block function:
3128 * This function returns 1 if the two domains d1 and d2 given as input are the
3129 * same (possibly except for a dimension equal to a constant where we accept
3130 * a difference of 1) AND if we are sure that there are no other domain in
3131 * the code generation problem that may put integral points between those of
3132 * d1 and d2 (0 otherwise). In fact this function answers the question "can I
3133 * safely consider the two domains as only one with two statements (a block) ?".
3134 * This function is lazy: it asks for very standard scattering representation
3135 * (only one constraint per dimension which is an equality, and the constraints
3136 * are ordered per dimension depth: the left hand side of the constraint matrix
3137 * is the identity) and will answer NO at the very first problem.
3138 * - d1 and d2 are the two domains to check for blocking,
3139 * - scattering is the linked list of all domains,
3140 * - scattdims is the total number of scattering dimentions.
3142 * - April 30th 2005: beginning
3143 * - June 9th 2005: first working version.
3144 * - June 10th 2005: debugging.
3145 * - June 21rd 2005: Adaptation for GMP.
3146 * - October 16th 2005: (debug) some false blocks have been removed.
3149 cloog_domain_lazy_block (CloogDomain *d1, CloogDomain *d2, CloogDomainList *scattering, int scattdims)
3151 int i, j, difference = 0, different_constraint = 0, nbc;
3152 int dim1, dim2;
3153 Value date1, date2, date3, temp;
3154 polyhedron p1, p2;
3156 /* Some basic checks: we only accept convex domains, with same constraint
3157 * and dimension numbers.
3159 if (!cloog_domain_isconvex (d1) || !cloog_domain_isconvex (d2) ||
3160 (cloog_domain_nbconstraints (d1) != cloog_domain_nbconstraints (d2)) ||
3161 (cloog_domain_dim (d1) != cloog_domain_dim (d2)))
3162 return 0;
3164 p1 = cloog_domain_polyhedron (d1);
3165 p2 = cloog_domain_polyhedron (d2);
3166 nbc = cloog_domain_nbconstraints (d1);
3167 dim1 = cloog_domain_dim (d1);
3168 dim2 = cloog_domain_dim (d2);
3170 /* There should be only one difference between the two domains, it
3171 * has to be at the constant level and the difference must be of +1,
3172 * moreover, after the difference all domain coefficient has to be 0.
3173 * The matrix shape is:
3175 * |===========|=====|<- 0 line
3176 * |===========|=====|
3177 * |===========|====?|<- different_constraint line (found here)
3178 * |===========|0000=|
3179 * |===========|0000=|<- pX->NbConstraints line
3180 * ^ ^ ^
3181 * | | |
3182 * | | (pX->Dimension + 2) column
3183 * | scattdims column
3184 * 0 column
3187 value_init_c (temp);
3188 for (i = 0; i < nbc; i++)
3190 if (difference == 0)
3191 { /* All elements except scalar must be equal. */
3192 for (j = 0; j < dim1 + 1; j++)
3193 if (value_ne (p1->Constraint[i][j],
3194 p2->Constraint[i][j]))
3196 value_clear_c (temp);
3197 return 0;
3199 /* The scalar may differ from +1 (now j=(p1->Dimension + 1)). */
3200 if (value_ne (p1->Constraint[i][j],
3201 p2->Constraint[i][j]))
3203 value_increment (temp, p2->Constraint[i][j]);
3204 if (value_ne (p1->Constraint[i][j], temp))
3206 value_clear_c (temp);
3207 return 0;
3209 else
3211 difference = 1;
3212 different_constraint = i;
3216 else
3217 { /* Scattering coefficients must be equal. */
3218 for (j = 0; j < (scattdims + 1); j++)
3219 if (value_ne (p1->Constraint[i][j],
3220 p2->Constraint[i][j]))
3222 value_clear_c (temp);
3223 return 0;
3226 /* Domain coefficients must be 0. */
3227 for (; j < dim1 + 1; j++)
3228 if (value_notzero_p (p1->Constraint[i][j])
3229 || value_notzero_p (p2->Constraint[i][j]))
3231 value_clear_c (temp);
3232 return 0;
3235 /* Scalar must be equal. */
3236 if (value_ne (p1->Constraint[i][j],
3237 p2->Constraint[i][j]))
3239 value_clear_c (temp);
3240 return 0;
3244 value_clear_c (temp);
3246 /* If the domains are exactly the same, this is a block. */
3247 if (difference == 0)
3248 return 1;
3250 /* Now a basic check that the constraint with the difference is an
3251 * equality of a dimension with a constant.
3253 for (i = 0; i <= different_constraint; i++)
3254 if (value_notzero_p (p1->Constraint[different_constraint][i]))
3255 return 0;
3257 if (value_notone_p (p1->Constraint[different_constraint][different_constraint + 1]))
3258 return 0;
3260 for (i = different_constraint + 2; i < dim1 + 1; i++)
3261 if (value_notzero_p (p1->Constraint[different_constraint][i]))
3262 return 0;
3264 /* For the moment, d1 and d2 are a block candidate. There remains to check
3265 * that there is no other domain that may put an integral point between
3266 * them. In our lazy test we ensure this property by verifying that the
3267 * constraint matrices have a very strict shape: let us consider that the
3268 * dimension with the difference is d. Then the first d dimensions are
3269 * defined in their depth order using equalities (thus the first column begins
3270 * with d zeroes, there is a d*d identity matrix and a zero-matrix for
3271 * the remaining simensions). If a domain can put integral points between the
3272 * domains of the block candidate, this means that the other entries on the
3273 * first d constraints are equal to those of d1 or d2. Thus we are looking for
3274 * such a constraint system, if it exists d1 and d2 is considered to not be
3275 * a block, it is a bock otherwise.
3277 * 1. Only equalities (for the first different_constraint+1 lines).
3278 * | 2. Must be the identity.
3279 * | | 3. Must be zero.
3280 * | | | 4. Elements are equal, the last one is either date1 or 2.
3281 * | | | |
3282 * | /-\ /---\ /---\
3283 * |0|100|00000|=====|<- 0 line
3284 * |0|010|00000|=====|
3285 * |0|001|00000|====?|<- different_constraint line
3286 * |*|***|*****|*****|
3287 * |*|***|*****|*****|<- pX->NbConstraints line
3288 * ^ ^ ^ ^
3289 * | | | |
3290 * | | | (pX->Dimension + 2) column
3291 * | | scattdims column
3292 * | different_constraint+1 column
3293 * 0 column
3296 /* Step 1 and 2. This is only necessary to check one domain because
3297 * we checked that they are equal on this part before.
3299 for (i = 0; i <= different_constraint; i++)
3301 for (j = 0; j < i + 1; j++)
3302 if (value_notzero_p (p1->Constraint[i][j]))
3303 return 0;
3305 if (value_notone_p (p1->Constraint[i][i + 1]))
3306 return 0;
3308 for (j = i + 2; j <= different_constraint + 1; j++)
3309 if (value_notzero_p (p1->Constraint[i][j]))
3310 return 0;
3313 /* Step 3. */
3314 for (i = 0; i <= different_constraint; i++)
3315 for (j = different_constraint + 2; j <= scattdims; j++)
3316 if (value_notzero_p (p1->Constraint[i][j]))
3317 return 0;
3319 value_init_c (date1);
3320 value_init_c (date2);
3321 value_init_c (date3);
3323 /* Now we have to check that the two different dates are unique. */
3324 value_assign (date1, p1->Constraint[different_constraint][dim1 + 1]);
3325 value_assign (date2, p2->Constraint[different_constraint][dim2 + 1]);
3327 /* Step 4. We check all domains except d1 and d2 and we look for at least
3328 * a difference with d1 or d2 on the first different_constraint+1 dimensions.
3330 while (scattering != NULL)
3332 if ((cloog_domain (scattering) != d1)
3333 && (cloog_domain (scattering) != d2))
3335 CloogDomain *d3 = cloog_domain (scattering);
3336 polyhedron p3 = cloog_domain_polyhedron (d3);
3337 int dim3 = cloog_domain_dim (d3);
3339 value_assign (date3,
3340 p3->Constraint[different_constraint][dim3 + 1]);
3341 difference = 0;
3343 if (value_ne (date3, date2) && value_ne (date3, date1))
3344 difference = 1;
3346 for (i = 0; (i < different_constraint) && (!difference); i++)
3347 for (j = 0; (j < dim3 + 2) && !difference; j++)
3348 if (value_ne
3349 (p1->Constraint[i][j],
3350 p3->Constraint[i][j]))
3351 difference = 1;
3353 for (j = 0; (j < dim3 + 1) && !difference; j++)
3354 if (value_ne
3355 (p1->Constraint[different_constraint][j],
3356 p3->Constraint[different_constraint][j]))
3357 difference = 1;
3359 if (!difference)
3361 value_clear_c (date1);
3362 value_clear_c (date2);
3363 value_clear_c (date3);
3364 return 0;
3368 scattering = cloog_next_domain (scattering);
3371 value_clear_c (date1);
3372 value_clear_c (date2);
3373 value_clear_c (date3);
3374 return 1;
3379 * cloog_domain_lazy_disjoint function:
3380 * This function returns 1 if the domains given as input are disjoint, 0 if it
3381 * is unable to decide. This function finds the unknown with fixed values in
3382 * both domains (on a given constraint, their column entry is not zero and
3383 * only the constant coefficient can be different from zero) and verify that
3384 * their values are the same. If not, the domains are obviously disjoint and
3385 * it returns 1, if there is not such case it returns 0. This is a very fast
3386 * way to verify this property. It has been shown (with the CLooG benchmarks)
3387 * that operations on disjoint domains are 36% of all the polyhedral
3388 * computations. For 94% of the actually identical domains, this
3389 * function answer that they are disjoint and allow to give immediately the
3390 * trivial solution instead of calling the heavy general functions of PolyLib.
3391 * - August 22th 2003: first version.
3392 * - June 21rd 2005: Adaptation for GMP (based on S. Verdoolaege's version of
3393 * CLooG 0.12.1).
3396 cloog_domain_lazy_disjoint (CloogDomain * d1, CloogDomain * d2)
3398 int i1, j1, i2, j2, scat_dim, nbc1, nbc2;
3399 int dim1, dim2;
3400 Value scat_val;
3401 polyhedron p1, p2;
3403 if (!cloog_domain_isconvex (d1) || !cloog_domain_isconvex (d2))
3404 return 0;
3406 p1 = cloog_domain_polyhedron (d1);
3407 p2 = cloog_domain_polyhedron (d2);
3408 nbc1 = cloog_domain_nbconstraints (d1);
3409 nbc2 = cloog_domain_nbconstraints (d2);
3410 dim1 = cloog_domain_dim (d1);
3411 dim2 = cloog_domain_dim (d2);
3412 value_init_c (scat_val);
3414 for (i1 = 0; i1 < nbc1; i1++)
3416 if (value_notzero_p (p1->Constraint[i1][0]))
3417 continue;
3419 scat_dim = 1;
3420 while (value_zero_p (p1->Constraint[i1][scat_dim]) &&
3421 (scat_dim < dim1))
3422 scat_dim++;
3424 if (value_notone_p (p1->Constraint[i1][scat_dim]))
3425 continue;
3426 else
3428 for (j1 = scat_dim + 1; j1 <= dim1; j1++)
3429 if (value_notzero_p (p1->Constraint[i1][j1]))
3430 break;
3432 if (j1 != dim1 + 1)
3433 continue;
3435 value_assign (scat_val,
3436 p1->Constraint[i1][dim1 + 1]);
3438 for (i2 = 0; i2 < nbc2; i2++)
3440 for (j2 = 0; j2 < scat_dim; j2++)
3441 if (value_notzero_p (p2->Constraint[i2][j2]))
3442 break;
3444 if ((j2 != scat_dim)
3446 value_notone_p (p2->Constraint[i2][scat_dim]))
3447 continue;
3449 for (j2 = scat_dim + 1; j2 < dim2; j2++)
3450 if (value_notzero_p (p2->Constraint[i2][j2]))
3451 break;
3453 if (j2 != dim2)
3454 continue;
3456 if (value_ne
3457 (p2->Constraint[i2][dim2 + 1], scat_val))
3459 value_clear_c (scat_val);
3460 return 1;
3466 value_clear_c (scat_val);
3467 return 0;
3472 * cloog_domain_list_lazy_same function:
3473 * This function returns 1 if two domains in the list are the same, 0 if it
3474 * is unable to decide.
3475 * - February 9th 2004: first version.
3478 cloog_domain_list_lazy_same (CloogDomainList * list)
3479 { /*int i=1, j=1 ; */
3480 CloogDomainList *current, *next;
3482 current = list;
3483 while (current != NULL)
3485 next = cloog_next_domain (current);
3486 /*j=i+1; */
3487 while (next != NULL)
3489 if (cloog_domain_lazy_equal (cloog_domain (current),
3490 cloog_domain (next)))
3491 { /*printf("Same domains: %d and %d\n",i,j) ; */
3492 return 1;
3494 /*j++ ; */
3495 next = cloog_next_domain (next);
3497 /*i++ ; */
3498 current = cloog_next_domain (current);
3501 return 0;
3505 * cloog_domain_cut_first function:
3506 * this function returns a CloogDomain structure with everything except the
3507 * first part of the polyhedra union of the input domain as domain. After a call
3508 * to this function, there remains in the CloogDomain structure provided as
3509 * input only the first part of the original polyhedra union.
3510 * - April 20th 2005: first version, extracted from different part of loop.c.
3512 CloogDomain *
3513 cloog_domain_cut_first (CloogDomain * domain)
3515 CloogDomain *rest;
3517 if (domain && cloog_domain_polyhedron (domain))
3519 if (!cloog_upol_next (cloog_domain_upol (domain)))
3520 return NULL;
3522 rest = cloog_new_domain (cloog_upol_next (cloog_domain_upol (domain)));
3523 cloog_upol_set_next (cloog_domain_upol (domain), NULL);
3525 else
3526 rest = NULL;
3528 return cloog_check_domain (rest);
3533 * cloog_domain_lazy_isscalar function:
3534 * this function returns 1 if the dimension 'dimension' in the domain 'domain'
3535 * is scalar, this means that the only constraint on this dimension must have
3536 * the shape "x.dimension + scalar = 0" with x an integral variable. This
3537 * function is lazy since we only accept x=1 (further calculations are easier
3538 * in this way).
3539 * - June 14th 2005: first version.
3540 * - June 21rd 2005: Adaptation for GMP.
3543 cloog_domain_lazy_isscalar (CloogDomain * domain, int dimension)
3545 int i, j;
3546 polyhedron p = cloog_domain_polyhedron (domain);
3547 int nbc = cloog_domain_nbconstraints (domain);
3548 int dim = cloog_domain_dim (domain);
3550 /* For each constraint... */
3551 for (i = 0; i < nbc; i++)
3552 { /* ...if it is concerned by the potentially scalar dimension... */
3553 if (value_notzero_p
3554 (p->Constraint[i][dimension + 1]))
3555 { /* ...check that the constraint has the shape "dimension + scalar = 0". */
3556 for (j = 0; j <= dimension; j++)
3557 if (value_notzero_p (p->Constraint[i][j]))
3558 return 0;
3560 if (value_notone_p
3561 (p->Constraint[i][dimension + 1]))
3562 return 0;
3564 for (j = dimension + 2; j < dim + 1; j++)
3565 if (value_notzero_p (p->Constraint[i][j]))
3566 return 0;
3570 return 1;
3575 * cloog_domain_scalar function:
3576 * when we call this function, we know that "dimension" is a scalar dimension,
3577 * this function finds the scalar value in "domain" and returns it in "value".
3578 * - June 30th 2005: first version.
3580 void
3581 cloog_domain_scalar (CloogDomain * domain, int dimension, Value * value)
3583 int i;
3584 polyhedron p = cloog_domain_polyhedron (domain);
3585 int nbc = cloog_domain_nbconstraints (domain);
3586 int dim = cloog_domain_dim (domain);
3588 /* For each constraint... */
3589 for (i = 0; i < nbc; i++)
3590 { /* ...if it is the equality defining the scalar dimension... */
3591 if (value_notzero_p
3592 (p->Constraint[i][dimension + 1])
3593 && value_zero_p (p->Constraint[i][0]))
3594 { /* ...Then send the scalar value. */
3595 value_assign (*value, p->Constraint[i][dim + 1]);
3596 value_oppose (*value, *value);
3597 return;
3601 /* We should have found a scalar value: if not, there is an error. */
3602 fprintf (stderr, "[CLooG]ERROR: dimension %d is not scalar as expected.\n",
3603 dimension);
3604 exit (0);
3609 * cloog_domain_erase_dimension function:
3610 * this function returns a CloogDomain structure builds from 'domain' where
3611 * we removed the dimension 'dimension' and every constraint considering this
3612 * dimension. This is not a projection ! Every data concerning the
3613 * considered dimension is simply erased.
3614 * - June 14th 2005: first version.
3615 * - June 21rd 2005: Adaptation for GMP.
3617 CloogDomain *
3618 cloog_domain_erase_dimension (CloogDomain * domain, int dimension)
3620 int i, j, mi, nb_dim, nbc;
3621 CloogMatrix *matrix;
3622 CloogDomain *erased;
3623 polyhedron p = cloog_domain_polyhedron (domain);
3625 nb_dim = cloog_domain_dim (domain);
3626 nbc = cloog_domain_nbconstraints (domain);
3628 /* The matrix is one column less and at least one constraint less. */
3629 matrix = cloog_matrix_alloc (nbc - 1, nb_dim + 1);
3631 /* mi is the constraint counter for the matrix. */
3632 mi = 0;
3633 for (i = 0; i < nbc; i++)
3634 if (value_zero_p (p->Constraint[i][dimension + 1]))
3636 for (j = 0; j <= dimension; j++)
3637 value_assign (matrix->p[mi][j],
3638 p->Constraint[i][j]);
3640 for (j = dimension + 2; j < nb_dim + 2; j++)
3641 value_assign (matrix->p[mi][j - 1],
3642 p->Constraint[i][j]);
3644 mi++;
3647 erased = cloog_domain_matrix2domain (matrix);
3648 cloog_matrix_free (matrix);
3650 return cloog_check_domain (erased);
3653 /* Number of polyhedra inside the union of disjoint polyhedra. */
3655 unsigned
3656 cloog_domain_nb_polyhedra (CloogDomain * domain)
3658 unsigned res = 0;
3659 polyhedra_union upol = cloog_domain_upol (domain);
3661 while (upol)
3663 res++;
3664 upol = cloog_upol_next (upol);
3667 return res;
3670 void
3671 cloog_domain_print_polyhedra (FILE * foo, CloogDomain * domain)
3673 polyhedra_union upol = cloog_domain_upol (domain);
3675 while (upol != NULL)
3677 CloogMatrix *matrix = cloog_upol_domain2matrix (upol);
3678 cloog_matrix_print (foo, matrix);
3679 cloog_matrix_free (matrix);
3680 upol = cloog_upol_next (upol);
3684 void
3685 debug_cloog_domain (CloogDomain *domain)
3687 cloog_domain_print_polyhedra (stderr, domain);
3690 void
3691 debug_cloog_matrix (CloogMatrix *m)
3693 cloog_matrix_print (stderr, m);
3696 void
3697 debug_value (Value v)
3699 value_print (stderr, VALUE_FMT, v);
3702 void
3703 debug_values (Value *p, int length)
3705 int i;
3706 for (i = 0; i < length; i++)
3707 debug_value (p[i]);
3710 polyhedra_union cloog_new_upol (polyhedron p)
3712 polyhedra_union ppl =
3713 (polyhedra_union) malloc (sizeof (struct polyhedra_union));
3714 ppl->_polyhedron = p;
3715 ppl->_next = NULL;
3716 return ppl;
3719 Vector *Vector_Alloc (unsigned length)
3721 unsigned i;
3722 Vector *vector = (Vector *) malloc (sizeof (Vector));
3724 vector->Size = length;
3725 vector->p = (Value *) malloc (length * sizeof (Value));
3727 for (i = 0; i < length; i++)
3728 value_init (vector->p[i]);
3730 return vector;
3733 polyhedron cloog_new_pol (int dim, int nrows)
3735 int i;
3736 polyhedron res = (polyhedron) malloc (sizeof (struct polyhedron));
3737 int ncolumns = dim + 2;
3738 int n = nrows * ncolumns;
3739 Value *p = (Value *) malloc (n * sizeof (Value));
3741 res->Dimension = dim;
3742 res->NbConstraints = nrows;
3743 res->Constraint = (Value **) malloc (nrows * sizeof (Value *));
3745 for (i = 0; i < n; ++i)
3746 value_init (p[i]);
3748 for (i = 0; i < nrows; i++, p += ncolumns)
3749 res->Constraint[i] = p;
3751 return res;