Clan  0.8.0
relation.c
Go to the documentation of this file.
00001 
00002    /*+------- <| --------------------------------------------------------**
00003     **         A                     Clan                                **
00004     **---     /.\   -----------------------------------------------------**
00005     **   <|  [""M#                 relation.c                              **
00006     **-   A   | #   -----------------------------------------------------**
00007     **   /.\ [""M#         First version: 30/04/2008                     **
00008     **- [""M# | #  U"U#U  -----------------------------------------------**
00009          | #  | #  \ .:/
00010          | #  | #___| #
00011  ******  | "--'     .-"  ******************************************************
00012  *     |"-"-"-"-"-#-#-##   Clan : the Chunky Loop Analyzer (experimental)     *
00013  ****  |     # ## ######  *****************************************************
00014  *      \       .::::'/                                                       *
00015  *       \      ::::'/     Copyright (C) 2008 University Paris-Sud 11         *
00016  *     :8a|    # # ##                                                         *
00017  *     ::88a      ###      This is free software; you can redistribute it     *
00018  *    ::::888a  8a ##::.   and/or modify it under the terms of the GNU Lesser *
00019  *  ::::::::888a88a[]:::   General Public License as published by the Free    *
00020  *::8:::::::::SUNDOGa8a::. Software Foundation, either version 2.1 of the     *
00021  *::::::::8::::888:Y8888:: License, or (at your option) any later version.    *
00022  *::::':::88::::888::Y88a::::::::::::...                                      *
00023  *::'::..    .   .....   ..   ...  .                                          *
00024  * This software is distributed in the hope that it will be useful, but       *
00025  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
00026  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License   *
00027  * for more details.                                                          *
00028  *                                                                            *
00029  * You should have received a copy of the GNU Lesser General Public License   *
00030  * along with software; if not, write to the Free Software Foundation, Inc.,  *
00031  * 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA                     *
00032  *                                                                            *
00033  * Clan, the Chunky Loop Analyzer                                             *
00034  * Written by Cedric Bastoul, Cedric.Bastoul@u-psud.fr                        *
00035  *                                                                            *
00036  ******************************************************************************/
00037 
00038 
00039 #include <stdlib.h>
00040 #include <stdio.h>
00041 #include <string.h>
00042 #include <ctype.h>
00043 
00044 #include <osl/macros.h>
00045 #include <osl/int.h>
00046 #include <osl/relation.h>
00047 #include <clan/macros.h>
00048 #include <clan/options.h>
00049 #include <clan/relation.h>
00050 
00051 int clan_parser_nb_ld(void);
00052 void clan_parser_add_ld(void);
00053 
00054 
00055 /*+****************************************************************************
00056  *                            Processing functions                            *
00057  ******************************************************************************/
00058 
00059 
00071 void clan_relation_tag_array(osl_relation_p relation, int array) {
00072   if (relation == NULL)
00073     CLAN_error("relation cannot be array-tagged");
00074 
00075   osl_relation_insert_blank_row(relation, 0);
00076   osl_relation_insert_blank_column(relation, 1);
00077   osl_int_set_si(relation->precision, &relation->m[0][1], -1);
00078   osl_int_set_si(relation->precision,
00079                  &relation->m[0][relation->nb_columns - 1], array);
00080   relation->nb_output_dims++;
00081 }
00082 
00083 
00093 osl_relation_p clan_relation_build_context(int nb_parameters,
00094                                            clan_options_p options) {
00095   int i;
00096   osl_relation_p context = NULL;
00097 
00098   if (options->bounded_context) {
00099     context = osl_relation_pmalloc(options->precision,
00100                                    nb_parameters, nb_parameters + 2);
00101     for (i = 0; i < nb_parameters; i++) {
00102       osl_int_set_si(options->precision, &context->m[i][0], 1);
00103       osl_int_set_si(options->precision, &context->m[i][i + 1], 1);
00104       osl_int_set_si(options->precision,
00105                      &context->m[i][context->nb_columns - 1], 1);
00106     }
00107   } else {
00108     context = osl_relation_pmalloc(options->precision, 0, nb_parameters + 2);
00109   }
00110   osl_relation_set_type(context, OSL_TYPE_CONTEXT);
00111   osl_relation_set_attributes(context, 0, 0, 0, nb_parameters);
00112   return context;
00113 }
00114 
00115 
00133 osl_relation_p clan_relation_scattering(int* vector, int depth,
00134                                         int precision) {
00135   int i, j, nb_rows, nb_columns;
00136   int beta_col, alpha_col;
00137   osl_relation_p scattering;
00138 
00139   nb_rows    = (2 * depth + 1);
00140   nb_columns = (2 * depth + 1) + (depth) + (CLAN_MAX_PARAMETERS) + 2;
00141   scattering = osl_relation_pmalloc(precision, nb_rows, nb_columns);
00142   osl_relation_set_type(scattering, OSL_TYPE_SCATTERING);
00143   osl_relation_set_attributes(scattering, 2 * depth + 1, depth, 0,
00144                               CLAN_MAX_PARAMETERS);  
00145   
00146   // The output dimension identity
00147   for (i = 0; i < 2 * depth + 1; i++)
00148     osl_int_set_si(precision, &scattering->m[i][i + 1], -1);
00149 
00150   // The beta and alpha.
00151   j = 0;
00152   beta_col = nb_columns - 1;
00153   for (i = 0; i < depth; i++) {
00154     alpha_col = (2 * depth + 1) + i + 1;
00155     osl_int_set_si(precision, &scattering->m[j][beta_col], vector[j]);
00156     osl_int_set_si(precision, &scattering->m[j+1][alpha_col], vector[j+1]);
00157     j += 2;
00158   }
00159   osl_int_set_si(precision, &scattering->m[nb_rows-1][beta_col], vector[j]);
00160 
00161   return scattering;
00162 }
00163 
00164 
00175 void clan_relation_new_output_vector(osl_relation_p relation,
00176                                      osl_vector_p vector) {
00177   int i, new_col, new_row;
00178 
00179   if (relation == NULL)
00180     CLAN_error("cannot add a new output dimension to a NULL relation");
00181   else if (vector == NULL)
00182     CLAN_error("cannot add a NULL expression of an output dimension");
00183   else if (relation->precision != vector->precision)
00184     CLAN_error("incompatible precisions");
00185 
00186   if (relation->nb_output_dims == OSL_UNDEFINED)
00187     new_col = 1;
00188   else
00189     new_col = relation->nb_output_dims + 1;
00190   new_row = relation->nb_rows;
00191 
00192   if ((relation->nb_columns - (new_col - 1)) != vector->size)
00193     CLAN_error("incompatible sizes");
00194   else if (!osl_int_zero(vector->precision, vector->v[0]))
00195     CLAN_error("the output dimension expression should be an equality");
00196 
00197   // Prepare the space for the new output dimension and the vector.
00198   osl_relation_insert_blank_column(relation, new_col);
00199   osl_relation_insert_blank_row(relation, new_row);
00200   relation->nb_output_dims = new_col;
00201 
00202   // Insert the new output dimension.
00203   osl_int_set_si(relation->precision, &relation->m[new_row][new_col], -1);
00204   for (i = 1; i < vector->size; i++)
00205     osl_int_assign(relation->precision,
00206                    &relation->m[new_row][new_col + i], vector->v[i]);
00207 }
00208 
00209 
00220 void clan_relation_new_output_scalar(osl_relation_p relation, int scalar) {
00221   int new_col, new_row;
00222   
00223   if (relation == NULL)
00224     CLAN_error("cannot add a new output dimension to a NULL relation");
00225 
00226   if (relation->nb_output_dims == OSL_UNDEFINED)
00227     new_col = 1;
00228   else
00229     new_col = relation->nb_output_dims + 1;
00230   new_row = relation->nb_rows;
00231 
00232   // Prepare the space for the new output dimension and the vector.
00233   osl_relation_insert_blank_column(relation, new_col);
00234   osl_relation_insert_blank_row(relation, new_row);
00235   relation->nb_output_dims = new_col;
00236 
00237   // Insert the new output dimension.
00238   osl_int_set_si(relation->precision, &relation->m[new_row][new_col], -1);
00239   osl_int_set_si(relation->precision,
00240                  &relation->m[new_row][relation->nb_columns - 1], scalar);
00241 }
00242 
00243 
00253 void clan_relation_compact(osl_relation_p relation, 
00254                            int nb_parameters) {
00255   int i, j, nb_columns;
00256   int nb_output_dims, nb_input_dims, nb_local_dims, nb_out_in_loc;
00257   osl_relation_p compacted;
00258 
00259   while (relation != NULL) {
00260     nb_output_dims = relation->nb_output_dims;
00261     nb_input_dims  = relation->nb_input_dims;
00262     nb_local_dims  = relation->nb_local_dims;
00263     nb_out_in_loc  = nb_output_dims + nb_input_dims + nb_local_dims;
00264 
00265     nb_columns = nb_out_in_loc  + nb_parameters + 2;
00266     compacted = osl_relation_pmalloc(relation->precision,
00267                                      relation->nb_rows, nb_columns);
00268 
00269     for (i = 0; i < relation->nb_rows; i++) {
00270       // We copy the equ/inequ tag, the output and input coefficients.
00271       for (j = 0; j <= nb_output_dims + nb_input_dims; j++)
00272         osl_int_assign(relation->precision,
00273                        &compacted->m[i][j], relation->m[i][j]);
00274 
00275       // Then we copy the local dimension coefficients.
00276       for (j = 0; j < nb_local_dims; j++)
00277         osl_int_assign(relation->precision,
00278             &compacted->m[i][nb_output_dims + nb_input_dims + 1 + j],
00279             relation->m[i][CLAN_MAX_DEPTH + 1 + j]);
00280 
00281       // Then we copy the parameter coefficients.
00282       for (j = 0; j < nb_parameters; j++)
00283         osl_int_assign(relation->precision,
00284             &compacted->m[i][j + nb_out_in_loc + 1],
00285             relation->m[i][relation->nb_columns - CLAN_MAX_PARAMETERS -1 + j]);
00286 
00287       // Lastly the scalar coefficient.
00288       osl_int_assign(relation->precision,
00289           &compacted->m[i][nb_columns - 1],
00290           relation->m[i][relation->nb_columns - 1]);
00291     }
00292 
00293     osl_relation_free_inside(relation);
00294 
00295     // Replace the inside of relation.
00296     relation->nb_rows       = compacted->nb_rows;
00297     relation->nb_columns    = compacted->nb_columns;
00298     relation->m             = compacted->m;
00299     relation->nb_parameters = nb_parameters;
00300 
00301     // Free the compacted "container".
00302     free(compacted);
00303 
00304     relation = relation->next;
00305   }
00306 }
00307 
00308 
00332 osl_relation_p clan_relation_greater(osl_relation_p min, osl_relation_p max,
00333                                      int strict) {
00334   int imin, imax, j, precision;
00335   int a, b;
00336   osl_relation_p r;
00337   osl_int_t b_min, a_max;
00338 
00339   if ((min == NULL) || (max == NULL) || (strict < 0) || (strict > 1) ||
00340       (min->nb_columns != max->nb_columns))
00341     CLAN_error("cannot compose relations");
00342   
00343   precision = min->precision;
00344   osl_int_init(precision, &a_max);
00345   osl_int_init(precision, &b_min);
00346   r = osl_relation_pmalloc(precision,
00347                            min->nb_rows * max->nb_rows, min->nb_columns);
00348   
00349   // For each row of min
00350   for (imin = 0; imin < min->nb_rows; imin++) {
00351     // For each row of max
00352     // We have a couple min/a >= max/b to translate to b*min - a*max >= 0
00353     //      or a couple min/a > max/b  to translate to b*min - a*max - 1 >= 0
00354     // TODO: here a and b are > 0, this may be generalized to avoid a
00355     //       problem if the grammar is updated. Plus it's debatable to use
00356     //       b*min - a*max -a*b >= 0 in the second case. 
00357     
00358     // -1. Find a
00359     a = osl_int_get_si(precision, min->m[imin][0]);
00360     a = (a == 0) ? 1 : a;
00361 
00362     for (imax = 0; imax < max->nb_rows; imax++) {
00363       // -2. Find b
00364       b = osl_int_get_si(precision, max->m[imax][0]);
00365       b = (b == 0) ? 1 : b;
00366 
00367       // -3. Compute b*min - a*max to the new relation.
00368       for (j = 1; j < max->nb_columns; j++) {
00369         // -3.1. Compute b*min
00370         osl_int_mul_si(precision, &b_min, min->m[imin][j], b);
00371         
00372         // -3.2. Compute a*max
00373         osl_int_mul_si(precision, &a_max, max->m[imax][j], a);
00374         
00375         // -3.3. Compute b*min - a*max
00376         osl_int_sub(precision,
00377                     &r->m[imin * max->nb_rows + imax][j], b_min, a_max);
00378       }
00379 
00380       // -4. Add -1 if the condition is min/a > max/b, add 0 otherwise.
00381       osl_int_add_si(precision,
00382                      &r->m[imin * max->nb_rows + imax][max->nb_columns - 1],
00383                      r->m[imin * max->nb_rows + imax][max->nb_columns - 1],
00384                      -strict);
00385       // -5. Set the equality/inequality marker to inequality.
00386       osl_int_set_si(precision, &r->m[imin * max->nb_rows + imax][0], 1);
00387     }
00388   }
00389   
00390   osl_int_clear(precision, &a_max);
00391   osl_int_clear(precision, &b_min);
00392   return r;
00393 }
00394 
00395 
00404 static 
00405 void clan_relation_negate_inequality(osl_relation_p relation, int row) {
00406   int i;
00407   
00408   // Oppose all constraint elements.
00409   for (i = 1; i < relation->nb_columns; i++)
00410     osl_int_oppose(relation->precision,
00411                    &relation->m[row][i], relation->m[row][i]);
00412   
00413   // The constant term - 1.
00414   osl_int_decrement(relation->precision,
00415                     &relation->m[row][relation->nb_columns - 1],
00416                     relation->m[row][relation->nb_columns - 1]);
00417 }
00418 
00419 
00429 static
00430 osl_relation_p clan_relation_extract_constraint(osl_relation_p relation,
00431                                                 int row) {
00432   int i, precision = relation->precision;
00433   osl_relation_p constraint;
00434   
00435   constraint = osl_relation_pmalloc(precision, 1, relation->nb_columns);
00436   constraint->type           = relation->type;
00437   constraint->nb_output_dims = relation->nb_output_dims;
00438   constraint->nb_input_dims  = relation->nb_input_dims;
00439   constraint->nb_local_dims  = relation->nb_local_dims;
00440   constraint->nb_parameters  = relation->nb_parameters;
00441 
00442   for (i = 0; i < relation->nb_columns; i++)
00443     osl_int_assign(precision, &constraint->m[0][i], relation->m[row][i]);
00444 
00445   return constraint;
00446 }
00447 
00448 
00458 static
00459 int clan_relation_is_equality(osl_relation_p relation, int row) {
00460 
00461   return (osl_int_zero(relation->precision, relation->m[row][0])) ? 1 : 0;
00462 }
00463 
00464 
00474 static
00475 void clan_relation_tag_inequality(osl_relation_p relation, int row) {
00476   if ((relation == NULL) || (relation->nb_rows < row))
00477     CLAN_error("the constraint cannot be inquality-tagged");
00478   osl_int_set_si(relation->precision, &relation->m[row][0], 1);
00479 }
00480 
00481 
00491 static
00492 void clan_relation_tag_equality(osl_relation_p relation, int row) {
00493   if ((relation == NULL) || (relation->nb_rows < row))
00494     CLAN_error("the constraint cannot be equality-tagged");
00495   osl_int_set_si(relation->precision, &relation->m[row][0], 0);
00496 }
00497 
00498 
00507 static
00508 osl_relation_p clan_relation_constraint_not(osl_relation_p relation, int row) {
00509   osl_relation_p tmp, tmp_eq = NULL;
00510   
00511   if (row > relation->nb_rows)
00512     return NULL;
00513 
00514   // Extract the constraint.
00515   tmp = clan_relation_extract_constraint(relation, row);
00516 
00517   // Negate it (inequality-style): a >= 0 becomes a < 0, i.e., -a - 1 >= 0.
00518   clan_relation_negate_inequality(tmp, 0);
00519 
00520   // If the constraint is an equality we need to build an union.
00521   // a == 0 becomes a > 0 || a < 0, i.e., a - 1 >= 0 || -a - 1 >= 0.
00522   if (clan_relation_is_equality(relation, row)) {
00523     
00524     tmp_eq = clan_relation_extract_constraint(relation, row);
00525     osl_int_decrement(relation->precision,
00526                       &tmp_eq->m[0][tmp_eq->nb_columns - 1],
00527                       tmp_eq->m[0][tmp_eq->nb_columns - 1]);
00528 
00529     // Set the two constraints as inequalities and build the union.
00530     clan_relation_tag_inequality(tmp, 0);
00531     clan_relation_tag_inequality(tmp_eq, 0);
00532     tmp->next = tmp_eq;
00533   }
00534 
00535   return tmp;
00536 }
00537 
00538 
00545 osl_relation_p clan_relation_not(osl_relation_p relation) {
00546   int i;
00547   osl_relation_p not_constraint;
00548   osl_relation_p not = NULL, part;
00549   
00550   while (relation != NULL) {
00551     // Build the negation of one relation union part.
00552     part = NULL;
00553     for (i = 0; i < relation->nb_rows; i++) {
00554       not_constraint = clan_relation_constraint_not(relation, i);
00555       osl_relation_add(&part, not_constraint);
00556     }
00557 
00558     // AND it to the previously negated parts.
00559     if (not == NULL) {
00560       not = part;
00561     } else {
00562       clan_relation_and(not, part);
00563       osl_relation_free(part);
00564     }
00565     relation = relation->next;
00566   } 
00567 
00568   return not;
00569 }
00570 
00571 
00580 void clan_relation_and(osl_relation_p dest, osl_relation_p src) {
00581   osl_relation_p next_dest,
00582                  next_src,
00583                  dup_dest,
00584                  next_mem = NULL;
00585   
00586   // initializing
00587   next_src = src;
00588   next_dest = dest;
00589   dup_dest = osl_relation_clone(dest);
00590   if (dest == NULL || src == NULL)
00591     return;
00592 
00593   // For each union
00594   while (next_src != NULL) {
00595     // Add in each unions
00596     while(next_dest != NULL) {
00597       osl_relation_insert_constraints(next_dest, next_src, next_dest->nb_rows);
00598       next_mem = next_dest;
00599       next_dest = next_dest->next;
00600     }
00601     if (next_src->next != NULL)
00602       next_mem->next = osl_relation_clone(dup_dest);
00603     else
00604       next_mem->next = NULL;
00605 
00606     // Next union
00607     next_src = next_src->next;
00608     next_dest = next_mem->next;
00609   }
00610   osl_relation_free(dup_dest);
00611 }
00612 
00613 
00621 int clan_relation_existential(osl_relation_p relation) {
00622   int i, j;
00623 
00624   while (relation != NULL) {
00625     for (i = 0; i < relation->nb_rows; i++) {
00626       for (j = CLAN_MAX_DEPTH + 1;
00627            j < CLAN_MAX_DEPTH + CLAN_MAX_LOCAL_DIMS + 1;
00628            j++) {
00629         if (!osl_int_zero(relation->precision, relation->m[i][j]))
00630           return 1;
00631       }
00632     }
00633     relation = relation->next;
00634   }
00635 
00636   return 0;
00637 }
00638 
00639 
00647 void clan_relation_oppose_row(osl_relation_p r, int row) {
00648   int i;
00649   
00650   if (r == NULL)
00651     return;
00652 
00653   if ((row < 0) || (row >= r->nb_rows))
00654     CLAN_error("bad row number");
00655 
00656   for (i = 1; i < r->nb_columns; i++)
00657     osl_int_oppose(r->precision, &r->m[row][i], r->m[row][i]);
00658 }
00659 
00660 
00675 static
00676 void clan_relation_extract_bounding(osl_relation_p r,
00677                                     osl_relation_p* bound,
00678                                     osl_relation_p* notbound,
00679                                     int depth, int lower) {
00680   int i, precision;
00681   osl_relation_p constraint;
00682 
00683   if (r == NULL)
00684     return;
00685 
00686   if ((depth < 1) || (depth > CLAN_MAX_DEPTH))
00687     CLAN_error("bad depth");
00688 
00689   if ((lower < 0) || (lower > 1))
00690     CLAN_error("lower parameter must be 0 or 1");
00691 
00692   // Create two empty sets bound and notbound.
00693   precision = r->precision;
00694   *bound = osl_relation_pmalloc(precision, 0, r->nb_columns);
00695   osl_relation_set_attributes(*bound,
00696                               r->nb_output_dims,
00697                               r->nb_input_dims,
00698                               r->nb_local_dims,
00699                               r->nb_parameters);
00700   *notbound = osl_relation_pmalloc(precision, 0, r->nb_columns);
00701   osl_relation_set_attributes(*notbound,
00702                               r->nb_output_dims,
00703                               r->nb_input_dims,
00704                               r->nb_local_dims,
00705                               r->nb_parameters);
00706 
00707   // For each constraint in r...
00708   for (i = 0; i < r->nb_rows; i++) {
00709     constraint = clan_relation_extract_constraint(r, i);
00710 
00711     if (osl_int_zero(precision, constraint->m[0][depth])) {
00712       // If it does not involve the loop iterator => notbound set.
00713       osl_relation_insert_constraints(*notbound, constraint, -1);
00714     } else if (osl_int_zero(precision, constraint->m[0][0])) {
00715       // If this is an equality, separate it into two inequalities, then
00716       // put one in bound and the other one in notbound conveniently.
00717       osl_int_set_si(precision, &constraint->m[0][0], 1);
00718       osl_relation_insert_constraints(*bound, constraint, -1);
00719       osl_relation_insert_constraints(*notbound, constraint, -1);
00720       if ((lower && osl_int_pos(precision, constraint->m[0][depth])) ||
00721           (!lower && osl_int_neg(precision, constraint->m[0][depth]))) {
00722         clan_relation_oppose_row(*notbound, (*notbound)->nb_rows - 1);
00723       } else {
00724         clan_relation_oppose_row(*bound, (*bound)->nb_rows - 1);
00725       }
00726     } else {
00727       // If it is an inequality, drive it to the right set.
00728       if ((lower && osl_int_pos(precision, constraint->m[0][depth])) ||
00729           (!lower && osl_int_neg(precision, constraint->m[0][depth]))) {
00730         osl_relation_insert_constraints(*bound, constraint, -1);
00731       } else {
00732         osl_relation_insert_constraints(*notbound, constraint, -1);
00733       }
00734     }
00735     osl_relation_free(constraint);
00736   }
00737 }
00738 
00739 
00753 static
00754 void clan_relation_to_expressions(osl_relation_p r, int depth) {
00755   int i, coef, mark;
00756 
00757   for (i = 0; i < r->nb_rows; i++) {
00758     mark = osl_int_get_si(r->precision, r->m[i][0]);
00759     coef = osl_int_get_si(r->precision, r->m[i][depth]);
00760     if ((mark != 1) || (coef == 0))
00761       CLAN_error("you found a bug");
00762 
00763     if (coef > 1)
00764       clan_relation_oppose_row(r, i);
00765     
00766     coef = (coef > 0) ? coef : -coef;
00767     if (coef > 1)
00768       osl_int_set_si(r->precision, &r->m[i][0], coef);
00769     else
00770       osl_int_set_si(r->precision, &r->m[i][0], 0);
00771     osl_int_set_si(r->precision, &r->m[i][depth], 0);
00772   }
00773 }
00774 
00775 
00788 osl_relation_p clan_relation_stride(osl_relation_p r, int depth, int stride) {
00789   int i, lower, precision;
00790   osl_relation_p contribution;
00791   osl_relation_p constraint;
00792   osl_relation_p bound, notbound;
00793   osl_relation_p part;
00794   osl_relation_p full = NULL;
00795 
00796   if (depth < 1)
00797     CLAN_error("invalid loop depth");
00798   else if (stride == 0)
00799     CLAN_error("unsupported zero stride");
00800 
00801   precision = r->precision;
00802   lower = (stride > 0) ? 1 : 0;
00803   stride = (stride > 0) ? stride : -stride;
00804 
00805   // Each part of the relation union will provide independent contribution.
00806   while (r != NULL) {
00807     part = NULL;
00808 
00809     // Separate the bounding constraints (bound) which are impacted by the
00810     // stride from others (notbound) which will be reinjected later.
00811     clan_relation_extract_bounding(r, &bound, &notbound, depth, lower);
00812   
00813     // Change the bounding constraints to a set of linear expressions
00814     // to make it easy to manipulate them through existing functions.
00815     clan_relation_to_expressions(bound, depth);
00816   
00817     // Each bound constraint contributes along with the stride.
00818     for (i = 0; i < bound->nb_rows; i++) {
00819       // -1. Extract the contributing constraint c.
00820       constraint = clan_relation_extract_constraint(bound, i);
00821 
00822       // -2. For every constaint before c, ensure the comparison at step 3
00823       //     will be strictly greater, by adding 1: since the different
00824       //     sets must be disjoint, we don't want a >= b then b >= a but
00825       //     a >= b then b > a to avoid a == b to be in both sets.
00826       //     (Resp. adding -1 for the upper case.)
00827       if (i > 0) {
00828         if (lower) {
00829           osl_int_add_si(precision,
00830                          &bound->m[i - 1][bound->nb_columns - 1],
00831                          bound->m[i - 1][bound->nb_columns - 1], 1);
00832         } else {
00833           osl_int_add_si(precision,
00834                          &bound->m[i - 1][bound->nb_columns - 1],
00835                          bound->m[i - 1][bound->nb_columns - 1], -1);
00836         }
00837       }
00838 
00839       // -3. Compute c > a && c > b && c >= c && c >= d ...
00840       //     We remove the c >= c row which corresponds to a trivial 0 >= 0.
00841       //     (Resp. c < a && c <b && c <= c && c <=d ... for the upper case.)
00842       if (lower)
00843         contribution = clan_relation_greater(constraint, bound, 0);
00844       else
00845         contribution = clan_relation_greater(bound, constraint, 0);
00846       osl_relation_remove_row(contribution, i);
00847 
00848       // -4. The iterator i of the current depth is i >= c.
00849       //     (Resp. c <= i for the upper case.)
00850       //     * 4.1 Put c at the end of the constraint set.
00851       osl_relation_insert_constraints(contribution, constraint, -1);
00852       //     * 4.2 Oppose so we have -c.
00853       //           (Resp. do nothing so we have c for the upper case.)
00854       if (lower) {
00855         clan_relation_oppose_row(contribution, contribution->nb_rows - 1);
00856       }
00857       //     * 4.3 Put the loop iterator so we have i - c.
00858       //           (Resp. -i + c for the upper case.)
00859       if (lower) {
00860         osl_int_set_si(precision,
00861                        &contribution->m[contribution->nb_rows - 1][depth], 1);
00862       } else {
00863         osl_int_set_si(precision,
00864                        &contribution->m[contribution->nb_rows - 1][depth], -1);
00865       }
00866       //     * 4.4 Set the inequality marker so we have i - c >= 0.
00867       //           (Resp. -i + c >= 0 for the upper case.)
00868       osl_int_set_si(precision,
00869                      &contribution->m[contribution->nb_rows - 1][0], 1);
00870     
00871       // -5. Add the contribution of the stride (same for lower and upper).
00872       //     * 5.1 Put c at the end of the constraint set.
00873       osl_relation_insert_constraints(contribution, constraint, -1);
00874       //     * 5.2 Put the opposed loop iterator so we have -i + c.
00875       osl_int_set_si(precision,
00876                      &contribution->m[contribution->nb_rows - 1][depth], -1);
00877       //     * 5.3 Put stride * local dimension so we have -i + c + stride*ld.
00878       //           The equality marker is set so we have i == c + stride*ld.
00879       osl_int_set_si(precision,
00880           &contribution->m[contribution->nb_rows - 1]
00881                           [CLAN_MAX_DEPTH + 1 + clan_parser_nb_ld()], stride);
00882     
00883       osl_relation_free(constraint);
00884       osl_relation_add(&part, contribution);
00885     }
00886 
00887     // Re-inject notbound constraints
00888     clan_relation_and(notbound, part);
00889     osl_relation_free(bound);
00890     osl_relation_free(part);
00891     osl_relation_add(&full, notbound);
00892     r = r->next;
00893   }
00894   clan_parser_add_ld();
00895 
00896   return full;
00897 }
00898 
00899 
00913 static
00914 void clan_relation_gaussian_elimination(osl_relation_p relation,
00915                                         int pivot_row, int pivot_column) {
00916   int i, j, same_sign, precision, identical;
00917   osl_int_p temp, pivot_coef, current_coef;
00918   
00919   if (relation == NULL)
00920     return;
00921 
00922   precision = relation->precision;
00923 
00924   if (relation->next != NULL)
00925     OSL_debug("gaussian elimination works only on the first part of unions");
00926 
00927   if ((pivot_row    >= relation->nb_rows)    || (pivot_row    < 0) ||
00928       (pivot_column >= relation->nb_columns) || (pivot_column < 0))
00929     OSL_error("bad pivot position");
00930 
00931   if (osl_int_zero(precision, relation->m[pivot_row][pivot_column]))
00932     OSL_error("pivot value is 0");
00933 
00934   if (!osl_int_zero(precision, relation->m[pivot_row][0]))
00935     OSL_warning("pivot not in an equality: non equivalent simplified relation");
00936 
00937   // Achieve the gaussian elimination.
00938   // TODO: (ndCedric) investigate the impact of converting i > 0 to i - 1 >= 0.
00939   //       When we multiply with some coefficients, like here, we may run into
00940   //       trouble. For instance, let us suppose we want to simplify N > i
00941   //       knowing that 2i = N. If we keep the >, we end up with N > 0. If we
00942   //       translate to >=, we end up with N >= 2 which is not quite the same.
00943   temp = osl_int_malloc(precision);
00944   pivot_coef = osl_int_malloc(precision);
00945   current_coef = osl_int_malloc(precision);
00946   for (i = 0; i < relation->nb_rows; i++) {
00947     // Do not eliminate if:
00948     // - The current element to eliminate is the pivot,
00949     // - The current element to eliminate is already zero,
00950     // - The pivot lies in an inequality and the element in an equality,
00951     // - The pivot and the current element are described with inequalities and
00952     //   their coefficients have the same sign (impossible to eliminate).
00953     same_sign = (osl_int_neg(precision, relation->m[pivot_row][pivot_column])&&
00954                  osl_int_neg(precision, relation->m[i][pivot_column])) ||
00955                 (osl_int_pos(precision, relation->m[pivot_row][pivot_column])&&
00956                  osl_int_pos(precision, relation->m[i][pivot_column]));
00957     if ((i != pivot_row) &&
00958         (!osl_int_zero(precision, relation->m[i][pivot_column])) &&
00959         (osl_int_zero(precision, relation->m[pivot_row][0]) ||
00960          !osl_int_zero(precision, relation->m[i][0]))) {
00961       if (osl_int_zero(precision, relation->m[pivot_row][0]) ||
00962           osl_int_zero(precision, relation->m[i][0]) || !same_sign) {
00963         // Set the values of coefficients for the pivot and the current rows:
00964         // - if the pivot and the current element do not have the same sign,
00965         //   ensure that only an equality can be multiplied by a negative coef,
00966         // - if the signs are different, use positive coefficients.
00967         osl_int_assign(precision,
00968             pivot_coef, relation->m[pivot_row][pivot_column]);
00969         osl_int_assign(precision,
00970             current_coef, relation->m[i][pivot_column]);
00971         if (same_sign) {
00972           if (osl_int_zero(precision, relation->m[pivot_row][0])) {
00973             osl_int_oppose(precision, current_coef, *current_coef);
00974           } else {
00975             osl_int_oppose(precision, pivot_coef, *pivot_coef);
00976           }
00977         } else {
00978           osl_int_abs(precision, pivot_coef, *pivot_coef);
00979           osl_int_abs(precision, current_coef, *current_coef);
00980         }
00981 
00982         // element = pivot_coef * element + current_coef * pivot_row_element
00983         for (j = 1; j < relation->nb_columns; j++) {
00984           osl_int_mul(precision,
00985               temp, *current_coef, relation->m[pivot_row][j]);
00986           osl_int_mul(precision,
00987               &relation->m[i][j], *pivot_coef, relation->m[i][j]);
00988           osl_int_add(precision,
00989               &relation->m[i][j], relation->m[i][j], *temp); 
00990         }
00991       } else {
00992         // In the case of two inequalities of the same sign, check whether they
00993         // are identical and if yes, zero the current row.
00994         identical = 1;
00995           for (j = 1; j < relation->nb_columns; j++) {
00996             if (osl_int_ne(precision,
00997                            relation->m[i][j], relation->m[pivot_row][j])) {
00998             identical = 0;
00999             break;
01000           }
01001         }
01002         if (identical) {
01003           for (j = 1; j < relation->nb_columns; j++)
01004             osl_int_sub(precision, &relation->m[i][j],
01005                         relation->m[i][j], relation->m[i][j]);
01006         }
01007       }
01008     }
01009   }
01010   osl_int_free(precision, temp);
01011   osl_int_free(precision, pivot_coef);
01012   osl_int_free(precision, current_coef);
01013 }
01014 
01015 
01023 static
01024 void clan_relation_simplify_parts(osl_relation_p relation) {
01025   osl_relation_p test, temp;
01026 
01027   test = relation->next;
01028   while (relation != NULL) {
01029     while (test != NULL) {
01030       if (osl_relation_part_equal(relation, test)) {
01031         temp = test;
01032         test = test->next;
01033         if (relation->next == temp)
01034           relation->next = test;
01035         temp->next = NULL;
01036         osl_relation_free(temp);
01037       } else {
01038         test = test->next;
01039       }
01040     }
01041     relation = relation->next;
01042   }
01043 }
01044 
01045 
01054 void clan_relation_simplify(osl_relation_p relation) {
01055   int i, j, k, to_eliminate, offset;
01056   osl_relation_p gauss, reference_gauss, reference = relation;
01057 
01058   gauss = osl_relation_clone(relation);
01059   reference_gauss = gauss;
01060   while (relation != NULL) {
01061     // First, try to eliminate columns elements by pivoting.
01062     for (j = 1; j < gauss->nb_columns; j++) {
01063       // Try to find a pivot, hence such that:
01064       // - the pivot is not 0,
01065       // - the constraint including the pivot is an equality,
01066       // - there is no non-zero element in the row before the pivot.
01067       
01068       //printf("j = %d\n", j);
01069       //osl_relation_dump(stdout, gauss);
01070       for (i = 0; i < gauss->nb_rows; i++) {
01071         if (!osl_int_zero(gauss->precision, gauss->m[i][j]) &&
01072             osl_int_zero(gauss->precision, gauss->m[i][0])) {
01073           to_eliminate = 1;
01074           for (k = 1; k < j; k++)
01075             if (!osl_int_zero(gauss->precision, gauss->m[i][k]))
01076               to_eliminate = 0;
01077           if (to_eliminate)
01078             clan_relation_gaussian_elimination(gauss, i, j);
01079         }
01080       }
01081       //osl_relation_dump(stdout, gauss);
01082     }
01083     
01084     // Second, remove trivially duplicated rows.
01085     for (i = 0; i < gauss->nb_rows; i++) {
01086       for (k = i + 1; k < gauss->nb_rows; k++) {
01087         to_eliminate = 1;
01088         for (j = 1; j < gauss->nb_columns; j++) {
01089           if (osl_int_ne(gauss->precision, gauss->m[i][j], gauss->m[k][j])) {
01090             to_eliminate = 0;
01091             break;
01092           }
01093         }
01094         if (to_eliminate) {
01095           for (j = 1; j < gauss->nb_columns; j++)
01096             osl_int_sub(gauss->precision, &gauss->m[k][j],
01097                 gauss->m[k][j], gauss->m[k][j]);
01098         }
01099       }
01100     }
01101 
01102     // Third, remove positive constant >= 0 constraints (e.g., 42 >= 0)
01103     for (i = 0; i < gauss->nb_rows; i++) {
01104       if (osl_int_pos(gauss->precision, gauss->m[i][gauss->nb_columns - 1]) &&
01105           !osl_int_zero(gauss->precision, gauss->m[i][0])) {
01106         to_eliminate = 1;
01107         for (j = 1; j < gauss->nb_columns - 1; j++) {
01108           if (!osl_int_zero(gauss->precision, gauss->m[i][j])) {
01109             to_eliminate = 0;
01110             break;
01111           }
01112         }
01113         if (to_eliminate)
01114           osl_int_sub(gauss->precision,
01115                       &gauss->m[i][gauss->nb_columns - 1],
01116                       gauss->m[i][gauss->nb_columns - 1],
01117                       gauss->m[i][gauss->nb_columns - 1]);
01118       }
01119     }
01120 
01121     // Remove the rows in the original relation which correspond to
01122     // zero-rows in the gauss relation since they are redundant.
01123     offset = 0;
01124     for (i = 0; i < gauss->nb_rows; i++) {
01125       to_eliminate = 1;
01126       for (j = 1; j < gauss->nb_columns; j++) {
01127         if (!osl_int_zero(gauss->precision, gauss->m[i][j])) {
01128           to_eliminate = 0;
01129           break;
01130         }
01131       }
01132       if (to_eliminate) {
01133         osl_relation_remove_row(relation, i - offset);
01134         offset++;
01135       }
01136     }
01137 
01138     gauss    = gauss->next;
01139     relation = relation->next;
01140   }
01141   osl_relation_free(reference_gauss);
01142   clan_relation_simplify_parts(reference);
01143 }
01144 
01145 
01162 void clan_relation_loop_context(osl_relation_p condition,
01163                                 osl_relation_p initialization,
01164                                 int depth) {
01165   int i, j;
01166   osl_relation_p contextual = NULL, temp, first_condition, new_condition;
01167 
01168   if ((condition == NULL) || (initialization == NULL))
01169     return;
01170 
01171   if (initialization->next != NULL)
01172     OSL_error("cannot compute the loop context for an initialization union");
01173 
01174   if (initialization->nb_columns != condition->nb_columns)
01175     OSL_error("imcompatible number of columns");
01176 
01177   for (i = 0; i < initialization->nb_rows; i++)
01178     if (osl_int_zero(initialization->precision, initialization->m[i][0]))
01179       OSL_error("no equality is allowed in the initialization relation");
01180   
01181   first_condition = condition;
01182   // For each possible initial value (e.g., in the case of a max):
01183   for (i = 0; i < initialization->nb_rows; i++) {
01184     condition = first_condition;
01185     // For each union part of the condition
01186     while (condition != NULL) {
01187       // Build the loop context (i.e. the loop condition where the
01188       // iterator is replaced by its initial value).
01189       temp = osl_relation_nclone(condition, 1);
01190       osl_relation_insert_blank_row(temp, 0);
01191       for (j = 0; j < temp->nb_columns; j++)
01192         osl_int_assign(temp->precision,
01193                        &temp->m[0][j], initialization->m[i][j]);
01194       clan_relation_tag_equality(temp, 0);
01195       clan_relation_gaussian_elimination(temp, 0, depth);
01196       osl_relation_remove_row(temp, 0);
01197       
01198       // Intersect the union part of the condition with its loop context.
01199       new_condition = osl_relation_nclone(condition, 1);
01200       osl_relation_insert_constraints(new_condition, temp, -1);
01201 
01202       osl_relation_free(temp);
01203       osl_relation_add(&contextual, new_condition);
01204       condition = condition->next;
01205     }
01206   }
01207 
01208   condition = first_condition;
01209   osl_relation_free_inside(condition);
01210   osl_relation_free(condition->next);
01211   
01212   // Replace the inside of condition.
01213   condition->nb_rows = contextual->nb_rows;
01214   condition->m = contextual->m;
01215   condition->next = contextual->next;
01216 
01217   // Free the contextual "shell".
01218   free(contextual);
01219 }