OpenScop 0.8.1

relation.c

Go to the documentation of this file.
00001 
00002     /*+-----------------------------------------------------------------**
00003      **                       OpenScop Library                          **
00004      **-----------------------------------------------------------------**
00005      **                           relation.c                            **
00006      **-----------------------------------------------------------------**
00007      **                   First version: 30/04/2008                     **
00008      **-----------------------------------------------------------------**
00009 
00010  
00011  *****************************************************************************
00012  * OpenScop: Structures and formats for polyhedral tools to talk together    *
00013  *****************************************************************************
00014  *    ,___,,_,__,,__,,__,,__,,_,__,,_,__,,__,,___,_,__,,_,__,                *
00015  *    /   / /  //  //  //  // /   / /  //  //   / /  // /  /|,_,             *
00016  *   /   / /  //  //  //  // /   / /  //  //   / /  // /  / / /\             *
00017  *  |~~~|~|~~~|~~~|~~~|~~~|~|~~~|~|~~~|~~~|~~~|~|~~~|~|~~~|/_/  \            *
00018  *  | G |C| P | = | L | P |=| = |C| = | = | = |=| = |=| C |\  \ /\           *
00019  *  | R |l| o | = | e | l |=| = |a| = | = | = |=| = |=| L | \# \ /\          *
00020  *  | A |a| l | = | t | u |=| = |n| = | = | = |=| = |=| o | |\# \  \         *
00021  *  | P |n| l | = | s | t |=| = |d| = | = | = | |   |=| o | | \# \  \        *
00022  *  | H | | y |   | e | o | | = |l|   |   | = | |   | | G | |  \  \  \       *
00023  *  | I | |   |   | e |   | |   | |   |   |   | |   | |   | |   \  \  \      *
00024  *  | T | |   |   |   |   | |   | |   |   |   | |   | |   | |    \  \  \     *
00025  *  | E | |   |   |   |   | |   | |   |   |   | |   | |   | |     \  \  \    *
00026  *  | * |*| * | * | * | * |*| * |*| * | * | * |*| * |*| * | /      \* \  \   *
00027  *  | O |p| e | n | S | c |o| p |-| L | i | b |r| a |r| y |/        \  \ /   *
00028  *  '---'-'---'---'---'---'-'---'-'---'---'---'-'---'-'---'          '--'    *
00029  *                                                                           *
00030  * Copyright (C) 2008 University Paris-Sud 11 and INRIA                      *
00031  *                                                                           *
00032  * (3-clause BSD license)                                                    *
00033  * Redistribution and use in source  and binary forms, with or without       *
00034  * modification, are permitted provided that the following conditions        *
00035  * are met:                                                                  *
00036  *                                                                           *
00037  * 1. Redistributions of source code must retain the above copyright notice, *
00038  *    this list of conditions and the following disclaimer.                  *
00039  * 2. Redistributions in binary form must reproduce the above copyright      *
00040  *    notice, this list of conditions and the following disclaimer in the    *
00041  *    documentation and/or other materials provided with the distribution.   *
00042  * 3. The name of the author may not be used to endorse or promote products  *
00043  *    derived from this software without specific prior written permission.  *
00044  *                                                                           *
00045  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR      *
00046  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES *
00047  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.   *
00048  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,          *
00049  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT  *
00050  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, *
00051  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY     *
00052  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT       *
00053  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF  *
00054  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.         *
00055  *                                                                           *
00056  * OpenScop Library, a library to manipulate OpenScop formats and data       *
00057  * structures. Written by:                                                   *
00058  * Cedric Bastoul     <Cedric.Bastoul@u-psud.fr> and                         *
00059  * Louis-Noel Pouchet <Louis-Noel.pouchet@inria.fr>                          *
00060  *                                                                           *
00061  *****************************************************************************/
00062 
00063 
00064 #include <stdlib.h>
00065 #include <stdio.h>
00066 #include <string.h>
00067 #include <ctype.h>
00068 
00069 #include <osl/macros.h>
00070 #include <osl/int.h>
00071 #include <osl/util.h>
00072 #include <osl/vector.h>
00073 #include <osl/strings.h>
00074 #include <osl/names.h>
00075 #include <osl/relation.h>
00076 
00077 
00078 /*+***************************************************************************
00079  *                          Structure display function                       *
00080  *****************************************************************************/
00081 
00082 
00090 static
00091 char * osl_relation_sprint_type(osl_relation_p relation) {
00092   char * string = NULL;
00093   
00094   OSL_malloc(string, char *, OSL_MAX_STRING * sizeof(char));
00095   string[0] = '\0';
00096 
00097   if (relation != NULL) {
00098     switch (relation->type) {
00099       case OSL_UNDEFINED: {
00100         snprintf(string, OSL_MAX_STRING, OSL_STRING_UNDEFINED);
00101         break;
00102       }
00103       case OSL_TYPE_CONTEXT: {
00104         snprintf(string, OSL_MAX_STRING, OSL_STRING_CONTEXT);
00105         break;
00106       }
00107       case OSL_TYPE_DOMAIN: {
00108         snprintf(string, OSL_MAX_STRING, OSL_STRING_DOMAIN);
00109         break;
00110       }
00111       case OSL_TYPE_SCATTERING: {
00112         snprintf(string, OSL_MAX_STRING, OSL_STRING_SCATTERING);
00113         break;
00114       }
00115       case OSL_TYPE_READ: {
00116         snprintf(string, OSL_MAX_STRING, OSL_STRING_READ);
00117         break;
00118       }
00119       case OSL_TYPE_WRITE: {
00120         snprintf(string, OSL_MAX_STRING, OSL_STRING_WRITE);
00121         break;
00122       }
00123       case OSL_TYPE_MAY_WRITE: {
00124         snprintf(string, OSL_MAX_STRING, OSL_STRING_MAY_WRITE);
00125         break;
00126       }
00127       default: {
00128         OSL_warning("unknown relation type, "
00129                     "replaced with "OSL_STRING_UNDEFINED);
00130         snprintf(string, OSL_MAX_STRING, OSL_STRING_UNDEFINED);
00131       }
00132     }
00133   }
00134 
00135   return string;
00136 }
00137 
00138 
00146 static
00147 void osl_relation_print_type(FILE * file, osl_relation_p relation) {
00148   char * string = osl_relation_sprint_type(relation);
00149   fprintf(file, "%s", string);
00150   free(string);
00151 }
00152 
00153 
00164 void osl_relation_idump(FILE * file, osl_relation_p relation, int level) {
00165   int i, j, first = 1;
00166 
00167   // Go to the right level.
00168   for (j = 0; j < level; j++)
00169     fprintf(file, "|\t");
00170 
00171   if (relation != NULL) {
00172     fprintf(file, "+-- osl_relation_t (");
00173     osl_relation_print_type(file, relation);
00174     fprintf(file, ", ");
00175     osl_int_dump_precision(file, relation->precision);
00176     fprintf(file, ")\n");
00177   }
00178   else {
00179     fprintf(file, "+-- NULL relation\n");
00180   }
00181 
00182   while (relation != NULL) {
00183     if (! first) {
00184       // Go to the right level.
00185       for (j = 0; j < level; j++)
00186         fprintf(file, "|\t");
00187       fprintf(file, "|   osl_relation_t (");
00188       osl_relation_print_type(file, relation);
00189       fprintf(file, ", ");
00190       osl_int_dump_precision(file, relation->precision);
00191       fprintf(file, ")\n");
00192     }
00193     else
00194       first = 0;
00195 
00196     // A blank line
00197     for(j = 0; j <= level; j++)
00198       fprintf(file, "|\t");
00199     fprintf(file, "%d %d %d %d %d %d\n",
00200             relation->nb_rows,        relation->nb_columns,
00201             relation->nb_output_dims, relation->nb_input_dims,
00202             relation->nb_local_dims,  relation->nb_parameters);
00203 
00204     // Display the relation.
00205     for (i = 0; i < relation->nb_rows; i++) {
00206       for (j = 0; j <= level; j++)
00207         fprintf(file, "|\t");
00208 
00209       fprintf(file, "[ ");
00210 
00211       for (j = 0; j < relation->nb_columns; j++) {
00212         osl_int_print(file, relation->precision, relation->m[i], j);
00213         fprintf(file, " ");
00214       }
00215 
00216       fprintf(file, "]\n");
00217     }
00218 
00219     relation = relation->next;
00220 
00221     // Next line.
00222     if (relation != NULL) {
00223       for (j = 0; j <= level; j++)
00224         fprintf(file, "|\t");
00225       fprintf(file, "|\n");
00226       for (j = 0; j <= level; j++)
00227         fprintf(file, "|\t");
00228       fprintf(file, "V\n");
00229     }
00230   }
00231 
00232   // The last line.
00233   for (j = 0; j <= level; j++)
00234     fprintf(file, "|\t");
00235   fprintf(file, "\n");
00236 }
00237 
00238 
00246 void osl_relation_dump(FILE * file, osl_relation_p relation) {
00247   osl_relation_idump(file, relation, 0);
00248 }
00249 
00250 
00265 static
00266 char * osl_relation_expression_element(void * val,
00267                                        int precision, int * first,
00268                                        int cst, char * name) {
00269   char * temp, * body, * sval;
00270  
00271   OSL_malloc(temp, char *, OSL_MAX_STRING * sizeof(char));
00272   OSL_malloc(body, char *, OSL_MAX_STRING * sizeof(char));
00273   OSL_malloc(sval, char *, OSL_MAX_STRING * sizeof(char));
00274 
00275   body[0] = '\0';
00276   sval[0] = '\0';
00277 
00278   // statements for the 'normal' processing.
00279   if (!osl_int_zero(precision, val, 0) && (!cst)) {
00280     if ((*first) || osl_int_neg(precision, val, 0)) {
00281       if (osl_int_one(precision, val, 0)) {         // case 1
00282         sprintf(sval, "%s", name);
00283       }
00284       else {
00285         if (osl_int_mone(precision, val, 0)) {      // case -1
00286           sprintf(sval, "-%s", name);
00287         }
00288         else {                                      // default case
00289           osl_int_sprint(sval, precision, val, 0);
00290           sprintf(temp, "*%s", name);
00291           strcat(sval, temp);
00292         }
00293       }
00294       *first = 0;
00295     }
00296     else {
00297       if (osl_int_one(precision, val, 0)) {
00298         sprintf(sval, "+%s", name);
00299       }
00300       else {
00301         sprintf(sval, "+");
00302         osl_int_sprint_txt(temp, precision, val, 0);
00303         strcat(sval, temp);
00304         sprintf(temp, "*%s", name);
00305         strcat(sval, temp);
00306       }
00307     }
00308   }
00309   else {
00310     if (cst) {
00311       if ((osl_int_zero(precision, val, 0) && (*first)) ||
00312           (osl_int_neg(precision, val, 0)))
00313         osl_int_sprint_txt(sval, precision, val, 0);
00314       if (osl_int_pos(precision, val, 0)) {
00315         if (!(*first)) {
00316           sprintf(sval, "+");
00317           osl_int_sprint_txt(temp, precision, val, 0);
00318           strcat(sval, temp);
00319         }
00320         else {
00321           osl_int_sprint_txt(sval, precision, val, 0);
00322         }
00323       }
00324     }
00325   }
00326   free(temp);
00327   free(body);
00328 
00329   return(sval);
00330 }
00331 
00332 
00342 static
00343 char ** osl_relation_strings(osl_relation_p relation, osl_names_p names) {
00344   char ** strings;
00345   char temp[OSL_MAX_STRING];
00346   int i, offset, array_id;
00347   
00348   if ((relation == NULL) || (names == NULL)) {
00349     OSL_debug("no names or relation to build the name array");
00350     return NULL;
00351   }
00352 
00353   OSL_malloc(strings, char **, (relation->nb_columns + 1)*sizeof(char *));
00354   strings[relation->nb_columns] = NULL;
00355 
00356   // 1. Equality/inequality marker.
00357   OSL_strdup(strings[0], "e/i");
00358   offset = 1;
00359 
00360   // 2. Output dimensions.
00361   if (osl_relation_is_access(relation)) {
00362     // The first output dimension is the array name.
00363     array_id  = osl_relation_get_array_id(relation);
00364     OSL_strdup(strings[offset], names->arrays->string[array_id - 1]);
00365     // The other ones are the array dimensions [1]...[n]
00366     for (i = offset + 1; i < relation->nb_output_dims + offset; i++) {
00367       sprintf(temp, "[%d]", i - 1);
00368       OSL_strdup(strings[i], temp);
00369     }
00370   }
00371   else
00372   if (relation->type == OSL_TYPE_SCATTERING) {
00373     for (i = offset; i < relation->nb_output_dims + offset; i++) {
00374       OSL_strdup(strings[i], names->scatt_dims->string[i - offset]);
00375     }
00376   }
00377   else {
00378     for (i = offset; i < relation->nb_output_dims + offset; i++) {
00379       OSL_strdup(strings[i], names->iterators->string[i - offset]);
00380     }
00381   }
00382   offset += relation->nb_output_dims;
00383 
00384   // 3. Input dimensions.
00385   for (i = offset; i < relation->nb_input_dims + offset; i++)
00386     OSL_strdup(strings[i], names->iterators->string[i - offset]);
00387   offset += relation->nb_input_dims;
00388 
00389   // 4. Local dimensions.
00390   for (i = offset; i < relation->nb_local_dims + offset; i++)
00391     OSL_strdup(strings[i], names->local_dims->string[i - offset]);
00392   offset += relation->nb_local_dims;
00393 
00394   // 5. Parameters.
00395   for (i = offset; i < relation->nb_parameters + offset; i++)
00396     OSL_strdup(strings[i], names->parameters->string[i - offset]);
00397   offset += relation->nb_parameters;
00398 
00399   // 6. Scalar.
00400   OSL_strdup(strings[offset], "1");
00401 
00402   return strings;
00403 }
00404 
00405 
00419 static
00420 char * osl_relation_subexpression(osl_relation_p relation,
00421                                   int row, int start, int stop, int oppose,
00422                                   char ** strings) {
00423   int i, first = 1, constant;
00424   char * sval;
00425   char * sline;
00426   
00427   OSL_malloc(sline, char *, OSL_MAX_STRING * sizeof(char));
00428   sline[0] = '\0';
00429 
00430   // Create the expression. The constant is a special case.
00431   for (i = start; i <= stop; i++) {
00432     if (oppose) {
00433       osl_int_oppose(relation->precision,
00434                      relation->m[row], i, relation->m[row], i);
00435     }
00436 
00437     if (i == relation->nb_columns - 1)
00438       constant = 1;
00439     else
00440       constant = 0;
00441 
00442     sval = osl_relation_expression_element(
00443         osl_int_address(relation->precision, relation->m[row], i),
00444         relation->precision, &first, constant, strings[i]);
00445     
00446     if (oppose) {
00447       osl_int_oppose(relation->precision,
00448                      relation->m[row], i, relation->m[row], i);
00449     }
00450     strcat(sline, sval);
00451     free(sval);
00452   }
00453 
00454   return sline;
00455 }
00456 
00457 
00467 char * osl_relation_expression(osl_relation_p relation,
00468                                int row, char ** strings) {
00469 
00470   return osl_relation_subexpression(relation, row,
00471                                     1, relation->nb_columns - 1, 0,
00472                                     strings);
00473 }
00474 
00475 
00487 static
00488 int osl_relation_is_simple_output(osl_relation_p relation, int row) {
00489   int i;
00490   int first = 1;
00491   int sign  = 0;
00492 
00493   if ((relation == NULL) ||
00494       (relation->m == NULL) ||
00495       (relation->nb_output_dims == 0))
00496     return 0;
00497 
00498   if ((row < 0) || (row > relation->nb_rows))
00499     OSL_error("the specified row does not exist in the relation");
00500 
00501   // The constraint must be an equality.
00502   if (!osl_int_zero(relation->precision, relation->m[row], 0))
00503     return 0;
00504 
00505   // Check the output part has one and only one non-zero +1 or -1 coefficient.
00506   first = 1;
00507   for (i = 1; i <= relation->nb_output_dims; i++) {
00508     if (!osl_int_zero(relation->precision, relation->m[row], i)) {
00509       if (first)
00510         first = 0;
00511       else
00512         return 0;
00513 
00514       if (osl_int_one(relation->precision, relation->m[row], i))
00515         sign = 1;
00516       else if (osl_int_mone(relation->precision, relation->m[row], i))
00517         sign = -1;
00518       else
00519         return 0;
00520     }
00521   }
00522 
00523   return sign;
00524 }
00525 
00526 
00539 static
00540 char * osl_relation_sprint_comment(osl_relation_p relation,
00541                                    int row, char ** strings) {
00542   int sign;
00543   int high_water_mark = OSL_MAX_STRING;
00544   char * string = NULL;
00545   char * expression;
00546   char buffer[OSL_MAX_STRING];
00547 
00548   OSL_malloc(string, char *, high_water_mark * sizeof(char));
00549   string[0] = '\0';
00550   
00551   if ((relation == NULL) || (strings == NULL)) {
00552     OSL_debug("no relation or names while asked to print a comment");
00553     return string;
00554   }
00555   
00556   if ((sign = osl_relation_is_simple_output(relation, row))) {
00557     // First case : output == expression.
00558 
00559     expression = osl_relation_subexpression(relation, row,
00560                                             1, relation->nb_output_dims,
00561                                             sign < 0,
00562                                             strings);
00563     snprintf(buffer, OSL_MAX_STRING, "   ## %s", expression);
00564     osl_util_safe_strcat(&string, buffer, &high_water_mark);
00565     free(expression);
00566     
00567     // We don't print the right hand side if it's an array identifier.
00568     if (!osl_relation_is_access(relation) ||
00569         osl_int_zero(relation->precision, relation->m[row], 1)) {
00570       expression = osl_relation_subexpression(relation, row,
00571                                               relation->nb_output_dims + 1,
00572                                               relation->nb_columns - 1,
00573                                               sign > 0,
00574                                               strings);
00575       snprintf(buffer, OSL_MAX_STRING, " == %s", expression);
00576       osl_util_safe_strcat(&string, buffer, &high_water_mark);
00577       free(expression);
00578     }
00579   }
00580   else {
00581     // Second case : general case.
00582     
00583     expression = osl_relation_expression(relation, row, strings);
00584     snprintf(buffer, OSL_MAX_STRING, "   ## %s", expression);
00585     osl_util_safe_strcat(&string, buffer, &high_water_mark);
00586     free(expression);
00587     
00588     if (osl_int_zero(relation->precision, relation->m[row], 0))
00589       snprintf(buffer, OSL_MAX_STRING, " == 0");
00590     else
00591       snprintf(buffer, OSL_MAX_STRING, " >= 0");
00592     osl_util_safe_strcat(&string, buffer, &high_water_mark);
00593   }
00594 
00595   return string;
00596 }
00597 
00598 
00608 static
00609 char * osl_relation_column_string(osl_relation_p relation, char ** strings) {
00610   int i, j;
00611   int index_output_dims;
00612   int index_input_dims;
00613   int index_local_dims;
00614   int index_parameters;
00615   int index_scalar;
00616   int space, length, left, right;
00617   char * scolumn;
00618   char temp[OSL_MAX_STRING];
00619 
00620   OSL_malloc(scolumn, char *, OSL_MAX_STRING);
00621  
00622   index_output_dims = 1;
00623   index_input_dims  = index_output_dims + relation->nb_output_dims;
00624   index_local_dims  = index_input_dims  + relation->nb_input_dims;
00625   index_parameters  = index_local_dims  + relation->nb_local_dims;
00626   index_scalar      = index_parameters  + relation->nb_parameters;
00627 
00628   // 1. The comment part.
00629   sprintf(scolumn, "#");
00630   for (j = 0; j < (OSL_FMT_LENGTH - 1)/2 - 1; j++)
00631     strcat(scolumn, " ");
00632 
00633   i = 0;
00634   while (strings[i] != NULL) {
00635     space  = OSL_FMT_LENGTH;
00636     length = (space > strlen(strings[i])) ? strlen(strings[i]) : space;
00637     right  = (space - length + (OSL_FMT_LENGTH % 2)) / 2;
00638     left   = space - length - right;
00639 
00640     // 2. Spaces before the name
00641     for (j = 0; j < left; j++)
00642       strcat(scolumn, " ");
00643 
00644     // 3. The (abbreviated) name
00645     for (j = 0; j < length - 1; j++) {
00646       sprintf(temp, "%c", strings[i][j]);
00647       strcat(scolumn, temp);
00648     }
00649     if (length >= strlen(strings[i]))
00650       sprintf(temp, "%c", strings[i][j]);
00651     else 
00652       sprintf(temp, ".");
00653     strcat(scolumn, temp);
00654 
00655     // 4. Spaces after the name
00656     for (j = 0; j < right; j++)
00657       strcat(scolumn, " ");
00658     
00659     i++;
00660     if ((i == index_output_dims) ||
00661         (i == index_input_dims)  ||
00662         (i == index_local_dims)  ||
00663         (i == index_parameters)  ||
00664         (i == index_scalar))
00665       strcat(scolumn, "|");
00666     else
00667       strcat(scolumn, " ");
00668   }
00669   strcat(scolumn, "\n");
00670 
00671   return scolumn;
00672 }
00673 
00674 
00682 static
00683 osl_names_p osl_relation_names(osl_relation_p relation) {
00684   int nb_parameters = OSL_UNDEFINED;
00685   int nb_iterators  = OSL_UNDEFINED;
00686   int nb_scattdims  = OSL_UNDEFINED;
00687   int nb_localdims  = OSL_UNDEFINED;
00688   int array_id      = OSL_UNDEFINED;
00689 
00690   osl_relation_get_attributes(relation, &nb_parameters, &nb_iterators,
00691                               &nb_scattdims, &nb_localdims, &array_id);
00692   
00693   return osl_names_generate("P", nb_parameters,
00694                             "i", nb_iterators,
00695                             "c", nb_scattdims,
00696                             "l", nb_localdims,
00697                             "A", array_id);
00698 }
00699 
00700 
00708 int osl_relation_nb_components(osl_relation_p relation) {
00709   int nb_components = 0;
00710   
00711   while (relation != NULL) {
00712     nb_components++;
00713     relation = relation->next;
00714   }
00715 
00716   return nb_components;
00717 }
00718 
00719 
00729 char * osl_relation_spprint_polylib(osl_relation_p relation,
00730                                     osl_names_p names) {
00731   int i, j;
00732   int part, nb_parts;
00733   int generated_names = 0;
00734   int high_water_mark = OSL_MAX_STRING;
00735   char * string = NULL;
00736   char buffer[OSL_MAX_STRING];
00737   char ** name_array = NULL;
00738   char * scolumn;
00739   char * comment;
00740 
00741   if (relation == NULL)
00742     return strdup("# NULL relation\n");
00743 
00744   OSL_malloc(string, char *, high_water_mark * sizeof(char));
00745   string[0] = '\0';
00746 
00747   // Generates the names for the comments if necessary.
00748   if (names == NULL) {
00749     generated_names = 1;
00750     names = osl_relation_names(relation);
00751   }
00752 
00753   nb_parts = osl_relation_nb_components(relation);
00754 
00755   if (nb_parts > 1) {
00756     snprintf(buffer, OSL_MAX_STRING, "# Union with %d parts\n%d\n",
00757              nb_parts, nb_parts);
00758     osl_util_safe_strcat(&string, buffer, &high_water_mark);
00759   }
00760 
00761   // Print each part of the union.
00762   for (part = 1; part <= nb_parts; part++) {
00763     // Prepare the array of strings for comments.
00764     name_array = osl_relation_strings(relation, names);
00765 
00766     if (nb_parts > 1) {
00767       snprintf(buffer, OSL_MAX_STRING, "# Union part No.%d\n", part);
00768       osl_util_safe_strcat(&string, buffer, &high_water_mark);
00769     }
00770 
00771     snprintf(buffer, OSL_MAX_STRING, "%d %d %d %d %d %d\n",
00772              relation->nb_rows,        relation->nb_columns,
00773              relation->nb_output_dims, relation->nb_input_dims,
00774              relation->nb_local_dims,  relation->nb_parameters);
00775     osl_util_safe_strcat(&string, buffer, &high_water_mark);
00776 
00777     if (relation->nb_rows > 0) {
00778       scolumn = osl_relation_column_string(relation, name_array);
00779       snprintf(buffer, OSL_MAX_STRING, "%s", scolumn);
00780       osl_util_safe_strcat(&string, buffer, &high_water_mark);
00781       free(scolumn);
00782     }
00783 
00784     for (i = 0; i < relation->nb_rows; i++) {
00785       for (j = 0; j < relation->nb_columns; j++) {
00786         osl_int_sprint(buffer, relation->precision, relation->m[i], j);
00787         osl_util_safe_strcat(&string, buffer, &high_water_mark);
00788         snprintf(buffer, OSL_MAX_STRING, " ");
00789         osl_util_safe_strcat(&string, buffer, &high_water_mark);
00790       }
00791 
00792       if (name_array != NULL) {
00793         comment = osl_relation_sprint_comment(relation, i, name_array);
00794         osl_util_safe_strcat(&string, comment, &high_water_mark);
00795         free(comment);
00796       }
00797       snprintf(buffer, OSL_MAX_STRING, "\n");
00798       osl_util_safe_strcat(&string, buffer, &high_water_mark);
00799     }
00800 
00801     // Free the array of strings.
00802     if (name_array != NULL) {
00803       for (i = 0; i < relation->nb_columns; i++)
00804         free(name_array[i]);
00805       free(name_array);
00806     }
00807 
00808     relation = relation->next;
00809   }
00810   
00811   if (generated_names)
00812     osl_names_free(names);
00813 
00814   return string;
00815 }
00816 
00817 
00826 char * osl_relation_spprint(osl_relation_p relation, osl_names_p names) {
00827   int high_water_mark = OSL_MAX_STRING;
00828   char * string = NULL;
00829   char * temp;
00830   char buffer[OSL_MAX_STRING];
00831   OSL_malloc(string, char *, high_water_mark * sizeof(char));
00832   string[0] = '\0';
00833 
00834   if (osl_relation_nb_components(relation) > 0) {
00835     temp = osl_relation_sprint_type(relation);
00836     osl_util_safe_strcat(&string, temp, &high_water_mark);
00837     free(temp);
00838     
00839     snprintf(buffer, OSL_MAX_STRING, "\n");
00840     osl_util_safe_strcat(&string, buffer, &high_water_mark);
00841 
00842     temp = osl_relation_spprint_polylib(relation, names);
00843     osl_util_safe_strcat(&string, temp, &high_water_mark);
00844     free(temp);
00845   }
00846 
00847   return string;
00848 }
00849 
00850 
00859 void osl_relation_pprint(FILE * file, osl_relation_p relation,
00860                          osl_names_p names) {
00861   char * string = osl_relation_spprint(relation, names);
00862   fprintf(file, "%s", string);
00863   free(string);
00864 }
00865 
00866 
00874 void osl_relation_print(FILE * file, osl_relation_p relation) {
00875 
00876   osl_relation_pprint(file, relation, NULL);
00877 }
00878 
00879 
00880 /*****************************************************************************
00881  *                               Reading function                            *
00882  *****************************************************************************/
00883 
00884 
00892 static
00893 int osl_relation_read_type(FILE * file) {
00894   int type;
00895   osl_strings_p strings;
00896   
00897   strings = osl_strings_read(file);
00898   if (osl_strings_size(strings) > 1) {
00899     OSL_warning("uninterpreted information (after the relation type)");
00900   }
00901   if (osl_strings_size(strings) == 0)
00902     OSL_error("no relation type");
00903  
00904   if (!strcmp(strings->string[0], OSL_STRING_UNDEFINED)) {
00905     type = OSL_UNDEFINED;
00906     goto return_type;
00907   }
00908 
00909   if (!strcmp(strings->string[0], OSL_STRING_CONTEXT)) {
00910     type = OSL_TYPE_CONTEXT; 
00911     goto return_type;
00912   }
00913 
00914   if (!strcmp(strings->string[0], OSL_STRING_DOMAIN)) {
00915     type = OSL_TYPE_DOMAIN; 
00916     goto return_type;
00917   }
00918 
00919   if (!strcmp(strings->string[0], OSL_STRING_SCATTERING)) {
00920     type = OSL_TYPE_SCATTERING; 
00921     goto return_type;
00922   }
00923 
00924   if (!strcmp(strings->string[0], OSL_STRING_READ)) {
00925     type = OSL_TYPE_READ; 
00926     goto return_type;
00927   }
00928 
00929   if (!strcmp(strings->string[0], OSL_STRING_WRITE)) {
00930     type = OSL_TYPE_WRITE; 
00931     goto return_type;
00932   }
00933 
00934   if (!strcmp(strings->string[0], OSL_STRING_MAY_WRITE)) {
00935     type = OSL_TYPE_MAY_WRITE; 
00936     goto return_type;
00937   }
00938 
00939   OSL_error("relation type not supported");
00940 
00941 return_type:
00942   osl_strings_free(strings);
00943   return type;
00944 }
00945 
00946 
00956 osl_relation_p osl_relation_pread(FILE * foo, int precision) {
00957   int i, j, k, n, read = 0;
00958   int nb_rows, nb_columns;
00959   int nb_output_dims, nb_input_dims, nb_local_dims, nb_parameters;
00960   int nb_union_parts = 1;
00961   int may_read_nb_union_parts = 1;
00962   int read_attributes = 1;
00963   int first = 1;
00964   int type;
00965   char * c, s[OSL_MAX_STRING], str[OSL_MAX_STRING], *tmp;
00966   osl_relation_p relation, relation_union = NULL, previous = NULL;
00967 
00968   type = osl_relation_read_type(foo);
00969 
00970   // Read each part of the union (the number of parts may be updated inside)
00971   for (k = 0; k < nb_union_parts; k++) {
00972     // Read the number of union parts or the attributes of the union part
00973     while (read_attributes) {
00974       read_attributes = 0;
00975 
00976       // Read relation attributes.
00977       c = osl_util_skip_blank_and_comments(foo, s);
00978       read = sscanf(c, " %d %d %d %d %d %d", &nb_rows, &nb_columns,
00979                                              &nb_output_dims, &nb_input_dims,
00980                                              &nb_local_dims, &nb_parameters);
00981     
00982       if (((read != 1) && (read != 6)) ||
00983           ((read == 1) && (may_read_nb_union_parts != 1)))
00984         OSL_error("not 1 or 6 integers on the first relation line");
00985 
00986       if (read == 1) {
00987         // Only one number means a union and is the number of parts.
00988         nb_union_parts = nb_rows;
00989         if (nb_union_parts < 1)
00990           OSL_error("negative nb of union parts");
00991         
00992         // Allow to read the properties of the first part of the union.
00993         read_attributes = 1;
00994       }
00995 
00996       may_read_nb_union_parts = 0;
00997     }
00998 
00999     // Allocate the union part and fill its properties.
01000     relation = osl_relation_pmalloc(precision, nb_rows, nb_columns);
01001     relation->type           = type;
01002     relation->nb_output_dims = nb_output_dims;
01003     relation->nb_input_dims  = nb_input_dims;
01004     relation->nb_local_dims  = nb_local_dims;
01005     relation->nb_parameters  = nb_parameters;
01006 
01007     // Read the matrix of constraints.
01008     for (i = 0; i < relation->nb_rows; i++) {
01009       c = osl_util_skip_blank_and_comments(foo, s);
01010       if (c == NULL)
01011         OSL_error("not enough rows");
01012 
01013       for (j = 0; j < relation->nb_columns; j++) {
01014         if (c == NULL || *c == '#' || *c == '\n')
01015           OSL_error("not enough columns");
01016         if (sscanf(c, "%s%n", str, &n) == 0)
01017           OSL_error("not enough rows");
01018 
01019         // TODO: remove this tmp (sread updates the pointer).
01020         tmp = str;
01021         osl_int_sread(&tmp, precision, relation->m[i], j);
01022         c += n;
01023       }
01024     }
01025     
01026     // Build the linked list of union parts.
01027     if (first == 1) {
01028       relation_union = relation;
01029       first = 0;
01030     }
01031     else {
01032       previous->next = relation;
01033     }
01034 
01035     previous = relation;
01036     read_attributes = 1;
01037   }
01038 
01039   return relation_union;
01040 }
01041 
01042 
01050 osl_relation_p osl_relation_read(FILE * foo) {
01051   int precision = osl_util_get_precision();
01052   return osl_relation_pread(foo, precision);
01053 }
01054 
01055 
01056 /*+***************************************************************************
01057  *                    Memory allocation/deallocation function                *
01058  *****************************************************************************/
01059 
01060 
01072 osl_relation_p osl_relation_pmalloc(int precision,
01073                                     int nb_rows, int nb_columns) {
01074   osl_relation_p relation;
01075   void ** p, * q;
01076   int i, j;
01077 
01078   OSL_malloc(relation, osl_relation_p, sizeof(osl_relation_t));
01079   relation->type           = OSL_UNDEFINED;
01080   relation->nb_rows        = nb_rows;
01081   relation->nb_columns     = nb_columns;
01082   relation->nb_output_dims = OSL_UNDEFINED;
01083   relation->nb_input_dims  = OSL_UNDEFINED;
01084   relation->nb_parameters  = OSL_UNDEFINED;
01085   relation->nb_local_dims  = OSL_UNDEFINED;
01086   relation->precision      = precision;
01087   
01088   if ((nb_rows == 0) || (nb_columns == 0) ||
01089       (nb_rows == OSL_UNDEFINED) || (nb_columns == OSL_UNDEFINED)) {
01090     relation->m = NULL;
01091   } 
01092   else {
01093     OSL_malloc(p, void **, nb_rows * sizeof(void *));
01094     OSL_malloc(q, void *,
01095                     nb_rows * nb_columns * osl_int_sizeof(precision));
01096     relation->m = p;
01097     for (i = 0; i < nb_rows; i++) {
01098       relation->m[i] = osl_int_address(precision, q, i * nb_columns);
01099       for (j = 0; j < nb_columns; j++)
01100         osl_int_init_set_si(precision, relation->m[i], j, 0);
01101     }
01102   }
01103  
01104   relation->next = NULL;
01105 
01106   return relation;
01107 }
01108 
01109 
01117 osl_relation_p osl_relation_malloc(int nb_rows, int nb_columns) {
01118   int precision = osl_util_get_precision();
01119   return osl_relation_pmalloc(precision, nb_rows, nb_columns);
01120 }
01121 
01122 
01129 void osl_relation_free_inside(osl_relation_p relation) {
01130   int i, nb_elements;
01131   void * p;
01132 
01133   if (relation == NULL)
01134     return;
01135 
01136   nb_elements = relation->nb_rows * relation->nb_columns;
01137   
01138   if (nb_elements > 0)
01139     p = relation->m[0];
01140   
01141   for (i = 0; i < nb_elements; i++)
01142     osl_int_clear(relation->precision, p, i);
01143 
01144   if (relation->m != NULL) {
01145     if (nb_elements > 0)
01146       free(relation->m[0]);
01147     free(relation->m);
01148   }
01149 }
01150 
01151 
01158 void osl_relation_free(osl_relation_p relation) {
01159   osl_relation_p tmp;
01160   
01161   if (relation == NULL)
01162     return;
01163 
01164   while (relation != NULL) {
01165     tmp = relation->next;
01166     osl_relation_free_inside(relation);
01167     free(relation);
01168     relation = tmp;
01169   }
01170 }
01171 
01172 
01173 /*+***************************************************************************
01174  *                            Processing functions                           *
01175  *****************************************************************************/
01176 
01177 
01190 osl_relation_p osl_relation_nclone(osl_relation_p relation, int n) {
01191   int i, j;
01192   int first = 1, all_rows = 0;
01193   osl_relation_p clone = NULL, node, previous = NULL;
01194 
01195   if (n == -1)
01196     all_rows = 1;
01197 
01198   while (relation != NULL) {
01199     if (all_rows)
01200       n = relation->nb_rows;
01201 
01202     if (n > relation->nb_rows)
01203       OSL_error("not enough rows to clone in the relation");
01204 
01205     node = osl_relation_pmalloc(relation->precision, n, relation->nb_columns);
01206     node->type           = relation->type;
01207     node->nb_output_dims = relation->nb_output_dims;
01208     node->nb_input_dims  = relation->nb_input_dims;
01209     node->nb_local_dims  = relation->nb_local_dims;
01210     node->nb_parameters  = relation->nb_parameters;
01211 
01212     for (i = 0; i < n; i++)
01213       for (j = 0; j < relation->nb_columns; j++)
01214         osl_int_assign(relation->precision, node->m[i], j, relation->m[i], j);
01215   
01216     if (first) {
01217       first = 0;
01218       clone = node;
01219       previous = node;
01220     }
01221     else {
01222       previous->next = node;
01223       previous = previous->next;
01224     }
01225 
01226     relation = relation->next;
01227   }
01228 
01229   return clone;
01230 }
01231 
01232 
01240 osl_relation_p osl_relation_clone(osl_relation_p relation) {
01241   if (relation == NULL)
01242     return NULL;
01243 
01244   return osl_relation_nclone(relation, -1);
01245 }
01246 
01247 
01257 void osl_relation_replace_vector(osl_relation_p relation,
01258                                  osl_vector_p vector, int row) {
01259   int i;
01260 
01261   if ((relation == NULL) || (vector == NULL)     ||
01262       (relation->precision != vector->precision) ||
01263       (relation->nb_columns != vector->size)     ||
01264       (row >= relation->nb_rows) || (row < 0))
01265     OSL_error("vector cannot replace relation row");
01266 
01267   for (i = 0; i < vector->size; i++)
01268     osl_int_assign(relation->precision, relation->m[row], i, vector->v, i);
01269 }
01270 
01271 
01281 void osl_relation_add_vector(osl_relation_p relation,
01282                              osl_vector_p vector, int row) {
01283   int i;
01284 
01285   if ((relation == NULL) || (vector == NULL)     ||
01286       (relation->precision != vector->precision) ||
01287       (relation->nb_columns != vector->size)     ||
01288       (row >= relation->nb_rows) || (row < 0))
01289     OSL_error("vector cannot be added to relation");
01290 
01291   if (osl_int_get_si(relation->precision, relation->m[row], 0) == 0)
01292     osl_int_assign(relation->precision, relation->m[row], 0, vector->v, 0);
01293 
01294   for (i = 1; i < vector->size; i++)
01295     osl_int_add(relation->precision,
01296                 relation->m[row], i, relation->m[row], i, vector->v, i);
01297 }
01298 
01299 
01309 void osl_relation_sub_vector(osl_relation_p relation,
01310                              osl_vector_p vector, int row) {
01311   int i;
01312 
01313   if ((relation == NULL) || (vector == NULL)     ||
01314       (relation->precision != vector->precision) ||
01315       (relation->nb_columns != vector->size)     ||
01316       (row >= relation->nb_rows) || (row < 0))
01317     OSL_error("vector cannot be subtracted to row");
01318 
01319   if (osl_int_get_si(relation->precision, relation->m[row], 0) == 0)
01320     osl_int_assign(relation->precision, relation->m[row], 0, vector->v, 0);
01321 
01322   for (i = 1; i < vector->size; i++)
01323     osl_int_sub(relation->precision,
01324                 relation->m[row], i, relation->m[row], i, vector->v, i);
01325 }
01326 
01327 
01338 void osl_relation_insert_vector(osl_relation_p relation,
01339                                 osl_vector_p vector, int row) {
01340   osl_relation_p temp;
01341 
01342   temp = osl_relation_from_vector(vector);
01343   osl_relation_insert_constraints(relation, temp, row);
01344   osl_relation_free(temp);
01345 }
01346 
01347 
01355 void osl_relation_insert_blank_row(osl_relation_p relation, int row) {
01356   osl_vector_p vector;
01357 
01358   if (relation != NULL) {
01359     vector = osl_vector_pmalloc(relation->precision, relation->nb_columns);
01360     osl_relation_insert_vector(relation, vector, row);
01361     osl_vector_free(vector);
01362   }
01363 }
01364 
01365 
01374 void osl_relation_insert_blank_column(osl_relation_p relation, int column) {
01375 
01376   int i, j;
01377   osl_relation_p temp;
01378 
01379   if (relation == NULL)
01380     return;
01381 
01382   if ((column < 0) || (column > relation->nb_columns))
01383     OSL_error("bad column number");
01384 
01385   // We use a temporary relation just to reuse existing functions. Cleaner.
01386   temp = osl_relation_pmalloc(relation->precision,
01387                               relation->nb_rows, relation->nb_columns + 1);
01388 
01389   for (i = 0; i < relation->nb_rows; i++) {
01390     for (j = 0; j < column; j++)
01391       osl_int_assign(relation->precision, temp->m[i], j, relation->m[i], j);
01392 
01393     for (j = column; j < relation->nb_columns; j++)
01394       osl_int_assign(relation->precision, temp->m[i], j+1, relation->m[i], j);
01395   }
01396 
01397   osl_relation_free_inside(relation);
01398 
01399   // Replace the inside of relation.
01400   relation->nb_columns = temp->nb_columns;
01401   relation->m = temp->m;
01402 
01403   // Free the temp "shell".
01404   free(temp);
01405 }
01406 
01407 
01415 osl_relation_p osl_relation_from_vector(osl_vector_p vector) {
01416   osl_relation_p relation;
01417 
01418   if (vector == NULL)
01419     return NULL;
01420 
01421   relation = osl_relation_pmalloc(vector->precision, 1, vector->size);
01422   osl_relation_replace_vector(relation, vector, 0);
01423   return relation;
01424 }
01425 
01426 
01436 void osl_relation_replace_constraints(osl_relation_p r1,
01437                                       osl_relation_p r2, int row) {
01438   int i, j;
01439 
01440   if ((r1 == NULL) || (r2 == NULL)       ||
01441       (r1->precision != r2->precision)   ||
01442       (r1->nb_columns != r1->nb_columns) ||
01443       ((row + r2->nb_rows) > r1->nb_rows) || (row < 0))
01444     OSL_error("relation rows could not be replaced");
01445 
01446   for (i = 0; i < r2->nb_rows; i++)
01447     for (j = 0; j < r2->nb_columns; j++)
01448       osl_int_assign(r1->precision, r1->m[i+row], j, r2->m[i], j);
01449 }
01450 
01451 
01462 void osl_relation_insert_constraints(osl_relation_p r1,
01463                                      osl_relation_p r2, int row) {
01464   int i, j;
01465   osl_relation_p temp;
01466 
01467   if ((r1 == NULL) || (r2 == NULL))
01468     return;
01469 
01470   if ((r1->nb_columns != r2->nb_columns) ||
01471       (r1->precision != r2->precision)   ||
01472       (row > r1->nb_rows) || (row < 0))
01473     OSL_error("constraints cannot be inserted");
01474 
01475   // We use a temporary relation just to reuse existing functions. Cleaner.
01476   temp = osl_relation_pmalloc(r1->precision,
01477                               r1->nb_rows + r2->nb_rows, r1->nb_columns);
01478 
01479   for (i = 0; i < row; i++)
01480     for (j = 0; j < r1->nb_columns; j++)
01481       osl_int_assign(r1->precision, temp->m[i], j, r1->m[i], j);
01482 
01483   osl_relation_replace_constraints(temp, r2, row);
01484 
01485   for (i = row + r2->nb_rows; i < r2->nb_rows + r1->nb_rows; i++)
01486     for (j = 0; j < r1->nb_columns; j++)
01487       osl_int_assign(r1->precision, temp->m[i], j, r1->m[i-r2->nb_rows], j);
01488 
01489   osl_relation_free_inside(r1);
01490 
01491   // Replace the inside of relation.
01492   r1->nb_rows = temp->nb_rows;
01493   r1->m = temp->m;
01494 
01495   // Free the temp "shell".
01496   free(temp);
01497 }
01498 
01499 
01511 void osl_relation_insert_columns(osl_relation_p relation,
01512                                  osl_relation_p insert, int column) {
01513   int i, j;
01514   osl_relation_p temp;
01515 
01516   if ((relation == NULL) || (insert == NULL))
01517     return;
01518 
01519   if ((relation->precision != insert->precision) ||
01520       (relation->nb_rows   != insert->nb_rows)   ||
01521       (column < 0) || (column > relation->nb_columns))
01522     OSL_error("columns cannot be inserted");
01523 
01524   // We use a temporary relation just to reuse existing functions. Cleaner.
01525   temp = osl_relation_pmalloc(relation->precision, relation->nb_rows,
01526                               relation->nb_columns + insert->nb_columns);
01527 
01528   for (i = 0; i < relation->nb_rows; i++) {
01529     for (j = 0; j < column; j++)
01530       osl_int_assign(relation->precision, temp->m[i], j, relation->m[i], j);
01531 
01532     for (j = column; j < column + insert->nb_columns; j++)
01533       osl_int_assign(relation->precision,
01534                      temp->m[i], j, insert->m[i], j - column);
01535 
01536     for (j = column + insert->nb_columns;
01537          j < insert->nb_columns + relation->nb_columns; j++)
01538       osl_int_assign(relation->precision,
01539                      temp->m[i], j, relation->m[i], j - insert->nb_columns);
01540   }
01541 
01542   osl_relation_free_inside(relation);
01543 
01544   // Replace the inside of relation.
01545   relation->nb_columns = temp->nb_columns;
01546   relation->m = temp->m;
01547 
01548   // Free the temp "shell".
01549   free(temp);
01550 }
01551 
01552 
01564 osl_relation_p osl_relation_concat_constraints(
01565     osl_relation_p r1,
01566     osl_relation_p r2) {
01567   osl_relation_p new;
01568 
01569   if (r1 == NULL)
01570     return osl_relation_clone(r2);
01571 
01572   if (r2 == NULL)
01573     return osl_relation_clone(r1);
01574 
01575   if (r1->nb_columns != r2->nb_columns)
01576     OSL_error("incompatible sizes for concatenation");
01577   
01578   if (r1->next || r2->next)
01579     OSL_warning("relation concatenation is done on the first elements "
01580                      "of union only");
01581 
01582   new = osl_relation_pmalloc(r1->precision,
01583                              r1->nb_rows + r2->nb_rows, r1->nb_columns);
01584   osl_relation_replace_constraints(new, r1, 0);
01585   osl_relation_replace_constraints(new, r2, r1->nb_rows);
01586 
01587   return new;
01588 }
01589 
01590 
01599 int osl_relation_equal(osl_relation_p r1, osl_relation_p r2) {
01600   int i, j;
01601 
01602   while ((r1 != NULL) && (r2 != NULL)) {
01603     if (r1 == r2)
01604       return 1;
01605 
01606     if ((r1->type           != r2->type)           ||
01607         (r1->precision      != r2->precision)      ||
01608         (r1->nb_rows        != r2->nb_rows)        ||
01609         (r1->nb_columns     != r2->nb_columns)     ||
01610         (r1->nb_output_dims != r2->nb_output_dims) ||
01611         (r1->nb_input_dims  != r2->nb_input_dims)  ||
01612         (r1->nb_local_dims  != r2->nb_local_dims)  ||
01613         (r1->nb_parameters  != r2->nb_parameters))
01614       return 0;
01615 
01616     for (i = 0; i < r1->nb_rows; ++i)
01617       for (j = 0; j < r1->nb_columns; ++j)
01618         if (osl_int_ne(r1->precision, r1->m[i], j, r2->m[i], j))
01619           return 0;
01620 
01621     r1 = r1->next;
01622     r2 = r2->next;
01623   }
01624   
01625   if (((r1 == NULL) && (r2 != NULL)) || ((r1 != NULL) && (r2 == NULL)))
01626     return 0;
01627   
01628   return 1;
01629 }
01630 
01631 
01645 static
01646 int osl_relation_check_attribute(int * expected, int actual) {
01647   if (*expected != OSL_UNDEFINED) { 
01648     if ((actual != OSL_UNDEFINED) &&
01649         (actual != *expected)) {
01650       OSL_warning("unexpected atribute");
01651       return 0;
01652     }
01653   }
01654   else {
01655     *expected = actual;
01656   }
01657 
01658   return 1;
01659 }
01660 
01661 
01675 static
01676 int osl_relation_check_nb_columns(osl_relation_p relation,
01677                                   int expected_nb_output_dims,
01678                                   int expected_nb_input_dims,
01679                                   int expected_nb_parameters) {
01680   int expected_nb_local_dims, expected_nb_columns;
01681   
01682   if ((expected_nb_output_dims != OSL_UNDEFINED) &&
01683       (expected_nb_input_dims  != OSL_UNDEFINED) &&
01684       (expected_nb_parameters  != OSL_UNDEFINED)) {
01685     
01686     if (relation->nb_local_dims == OSL_UNDEFINED)
01687       expected_nb_local_dims = 0;
01688     else
01689       expected_nb_local_dims = relation->nb_local_dims;
01690 
01691     expected_nb_columns = expected_nb_output_dims +
01692                           expected_nb_input_dims  +
01693                           expected_nb_local_dims  +
01694                           expected_nb_parameters  +
01695                           2;
01696     
01697     if (expected_nb_columns != relation->nb_columns) {
01698       OSL_warning("unexpected number of columns");
01699       return 0;
01700     }
01701   }
01702 
01703   return 1;
01704 }
01705 
01706 
01721 int osl_relation_integrity_check(osl_relation_p relation,
01722                                  int expected_type,
01723                                  int expected_nb_output_dims,
01724                                  int expected_nb_input_dims,
01725                                  int expected_nb_parameters) {
01726   int i;
01727 
01728   // Check the NULL case.
01729   if (relation == NULL) {
01730     if ((expected_nb_output_dims != OSL_UNDEFINED) ||
01731         (expected_nb_input_dims  != OSL_UNDEFINED) ||
01732         (expected_nb_parameters  != OSL_UNDEFINED)) {
01733       OSL_debug("NULL relation with some expected attibutes");
01734       //return 0;
01735     }
01736 
01737     return 1;
01738   }
01739 
01740   // Check the type.
01741   if (((expected_type != OSL_TYPE_ACCESS) &&
01742        (expected_type != relation->type)) ||
01743       ((expected_type == OSL_TYPE_ACCESS) &&
01744        (!osl_relation_is_access(relation)))) {
01745     OSL_warning("wrong type");
01746     osl_relation_dump(stderr, relation);
01747     return 0;
01748   }
01749 
01750   // Check that relations have no undefined atributes.
01751   if ((relation->nb_output_dims == OSL_UNDEFINED) ||
01752       (relation->nb_input_dims  == OSL_UNDEFINED) ||
01753       (relation->nb_local_dims  == OSL_UNDEFINED) ||
01754       (relation->nb_parameters  == OSL_UNDEFINED)) {
01755     OSL_warning("all attributes should be defined");
01756     osl_relation_dump(stderr, relation);
01757     return 0;
01758   }
01759 
01760   // Check that a context has actually 0 output dimensions.
01761   if ((relation->type == OSL_TYPE_CONTEXT) &&
01762       (relation->nb_output_dims != 0)) {
01763     OSL_warning("context without 0 as number of output dimensions");
01764     osl_relation_dump(stderr, relation);
01765     return 0;
01766   }
01767 
01768   // Check that a domain or a context has actually 0 input dimensions.
01769   if (((relation->type == OSL_TYPE_DOMAIN) ||
01770        (relation->type == OSL_TYPE_CONTEXT)) &&
01771       (relation->nb_input_dims != 0)) {
01772     OSL_warning("domain or context without 0 input dimensions");
01773     osl_relation_dump(stderr, relation);
01774     return 0;
01775   }
01776 
01777   // Check properties according to expected values (and if expected values
01778   // are undefined, define them with the first relation part properties).
01779   if (!osl_relation_check_attribute(&expected_nb_output_dims,
01780                                     relation->nb_output_dims) ||
01781       !osl_relation_check_attribute(&expected_nb_input_dims,
01782                                     relation->nb_input_dims)  ||
01783       !osl_relation_check_attribute(&expected_nb_parameters,
01784                                     relation->nb_parameters)) {
01785     osl_relation_dump(stderr, relation);
01786     return 0;
01787   }
01788 
01789   while (relation != NULL) {
01790 
01791     // Attributes (except the number of local dimensions) should be the same
01792     // in all parts of the union.
01793     if ((expected_nb_output_dims != relation->nb_output_dims) ||
01794         (expected_nb_input_dims  != relation->nb_input_dims)  ||
01795         (expected_nb_parameters  != relation->nb_parameters)) {
01796       OSL_warning("inconsistent attributes");
01797       osl_relation_dump(stderr, relation);
01798       return 0;
01799     }
01800    
01801     // Check whether the number of columns is OK or not.
01802     if (!osl_relation_check_nb_columns(relation,
01803                                        expected_nb_output_dims,
01804                                        expected_nb_input_dims,
01805                                        expected_nb_parameters)) {
01806       osl_relation_dump(stderr, relation);
01807       return 0;
01808     }
01809 
01810     // Check the first column. The first column of a relation part should be
01811     // made of 0 or 1 only.
01812     if ((relation->nb_rows > 0) && (relation->nb_columns > 0)) {
01813       for (i = 0; i < relation->nb_rows; i++) {
01814         if (!osl_int_zero(relation->precision, relation->m[i], 0) &&
01815             !osl_int_one(relation->precision, relation->m[i], 0)) {
01816           OSL_warning("first column of a relation is not "
01817                            "strictly made of 0 or 1");
01818           osl_relation_dump(stderr, relation);
01819           return 0;
01820         }
01821       }
01822     }
01823 
01824     // Array accesses must provide the array identifier.
01825     if ((osl_relation_is_access(relation)) &&
01826         (osl_relation_get_array_id(relation) == OSL_UNDEFINED)) {
01827       osl_relation_dump(stderr, relation);
01828       return 0;
01829     }
01830 
01831     relation = relation->next;
01832   }
01833 
01834   return 1;
01835 }
01836 
01837 
01847 osl_relation_p osl_relation_union(osl_relation_p r1,
01848                                   osl_relation_p r2) {
01849   osl_relation_p copy1, copy2, tmp;
01850   
01851   if ((r1 == NULL) && (r2 == NULL))
01852     return NULL;
01853   
01854   copy1 = osl_relation_clone(r1);
01855   copy2 = osl_relation_clone(r2);
01856 
01857   if ((r1 != NULL) && (r2 == NULL))
01858     return copy1;
01859     
01860   if ((r1 == NULL) && (r2 != NULL))
01861     return copy2;
01862 
01863   tmp = copy1;
01864   while (tmp->next != NULL)
01865     tmp = tmp->next;
01866 
01867   tmp->next = copy2;
01868   return copy1;
01869 }
01870 
01871 
01882 void osl_relation_set_attributes(osl_relation_p relation,
01883                                  int nb_output_dims, int nb_input_dims,
01884                                  int nb_local_dims,  int nb_parameters) {
01885   if (relation != NULL) {
01886     relation->nb_output_dims = nb_output_dims;
01887     relation->nb_input_dims  = nb_input_dims;
01888     relation->nb_local_dims  = nb_local_dims;
01889     relation->nb_parameters  = nb_parameters;
01890   }
01891 }
01892 
01893 
01901 void osl_relation_set_type(osl_relation_p relation, int type) {
01902 
01903   while (relation != NULL) {
01904     relation->type = type;
01905     relation = relation->next;
01906   }
01907 }
01908 
01909 
01918 int osl_relation_get_array_id(osl_relation_p relation) {
01919   int i;
01920   int first = 1;
01921   int array_id = OSL_UNDEFINED;
01922   int reference_array_id = OSL_UNDEFINED;
01923   int nb_array_id;
01924   int row_id = 0;
01925   int precision;
01926 
01927   if (relation == NULL)
01928     return OSL_UNDEFINED;
01929   
01930   if (!osl_relation_is_access(relation)) {
01931     OSL_warning("asked for an array id of non-array relation");
01932     return OSL_UNDEFINED;
01933   }
01934   
01935   while (relation != NULL) {
01936     precision = relation->precision;
01937 
01938     // There should be room to store the array identifier.
01939     if ((relation->nb_rows < 1) ||
01940         (relation->nb_columns < 3)) {
01941       OSL_warning("no array identifier in an access function");
01942       return OSL_UNDEFINED;
01943     }
01944 
01945     // Array identifiers are m[i][#columns -1] / m[i][1], with i the only row
01946     // where m[i][1] is not 0.
01947     // - check there is exactly one row such that m[i][1] is not 0,
01948     // - check the whole ith row if full of 0 except m[i][1] and the id,
01949     // - check that (m[i][#columns -1] % m[i][1]) == 0,
01950     // - check that (-m[i][#columns -1] / m[i][1]) > 0.
01951     nb_array_id = 0;
01952     for (i = 0; i < relation->nb_rows; i++) {
01953       if (!osl_int_zero(precision, relation->m[i], 1)) {
01954         nb_array_id ++;
01955         row_id = i;
01956       }
01957     }
01958     if (nb_array_id == 0) {
01959       OSL_warning("no array identifier in an access function");
01960       return OSL_UNDEFINED;
01961     }
01962     if (nb_array_id > 1) {
01963       OSL_warning("several array identifiers in one access function");
01964       return OSL_UNDEFINED;
01965     }
01966     for (i = 0; i < relation->nb_columns - 1; i++) {
01967       if ((i != 1) && !osl_int_zero(precision, relation->m[row_id], i)) {
01968         OSL_warning("non integer array identifier");
01969         return OSL_UNDEFINED;
01970       }
01971     }
01972     if (!osl_int_divisible(precision,
01973                            relation->m[row_id], relation->nb_columns - 1,
01974                            relation->m[row_id], 1)) {
01975       OSL_warning("rational array identifier");
01976       return OSL_UNDEFINED;
01977     }
01978     array_id = -osl_int_get_si(precision,
01979                                relation->m[row_id],
01980                                relation->nb_columns - 1);
01981     array_id /= osl_int_get_si(precision, relation->m[row_id], 1);
01982     if (array_id <= 0) {
01983       OSL_warning("negative or 0 identifier in access function");
01984       return OSL_UNDEFINED;
01985     }
01986 
01987     // Unions of accesses are allowed, but they should refer at the same array.
01988     if (first) {
01989       reference_array_id = array_id;
01990       first = 0;
01991     }
01992     else {
01993       if (reference_array_id != array_id) {
01994         OSL_warning("inconsistency of array identifiers in an "
01995                     "union of access relations");
01996         return OSL_UNDEFINED;
01997       }
01998     }
01999     
02000     relation = relation->next;
02001   }
02002 
02003   return array_id;
02004 }
02005 
02006 
02014 int osl_relation_is_access(osl_relation_p relation) {
02015 
02016   if (relation == NULL)
02017     return 0;
02018   
02019   if ((relation->type == OSL_TYPE_ACCESS)    ||
02020       (relation->type == OSL_TYPE_READ)      ||
02021       (relation->type == OSL_TYPE_WRITE)     ||
02022       (relation->type == OSL_TYPE_MAY_WRITE))
02023     return 1;
02024 
02025   return 0;
02026 }
02027 
02028 
02047 void osl_relation_get_attributes(osl_relation_p relation,
02048                                  int * nb_parameters,
02049                                  int * nb_iterators,
02050                                  int * nb_scattdims,
02051                                  int * nb_localdims,
02052                                  int * array_id) {
02053   int type;
02054   int local_nb_parameters = OSL_UNDEFINED;
02055   int local_nb_iterators  = OSL_UNDEFINED;
02056   int local_nb_scattdims  = OSL_UNDEFINED;
02057   int local_nb_localdims  = OSL_UNDEFINED;
02058   int local_array_id      = OSL_UNDEFINED;
02059 
02060   while (relation != NULL) {
02061     if (osl_relation_is_access(relation))
02062       type = OSL_TYPE_ACCESS;
02063     else
02064       type = relation->type;
02065 
02066     // There is some redundancy but I believe the code is cleaner this way.
02067     switch (type) {
02068       case OSL_TYPE_CONTEXT:
02069         local_nb_parameters = relation->nb_parameters;
02070         local_nb_iterators  = 0;
02071         local_nb_scattdims  = 0;
02072         local_nb_localdims  = relation->nb_local_dims;
02073         local_array_id      = 0;
02074         break;
02075 
02076       case OSL_TYPE_DOMAIN:
02077         local_nb_parameters = relation->nb_parameters;
02078         local_nb_iterators  = relation->nb_output_dims;
02079         local_nb_scattdims  = 0;
02080         local_nb_localdims  = relation->nb_local_dims;
02081         local_array_id      = 0;
02082         break;
02083 
02084       case OSL_TYPE_SCATTERING:
02085         local_nb_parameters = relation->nb_parameters;
02086         local_nb_iterators  = relation->nb_input_dims;
02087         local_nb_scattdims  = relation->nb_output_dims;
02088         local_nb_localdims  = relation->nb_local_dims;
02089         local_array_id      = 0;
02090         break;
02091 
02092       case OSL_TYPE_ACCESS:
02093         local_nb_parameters = relation->nb_parameters;
02094         local_nb_iterators  = relation->nb_input_dims;
02095         local_nb_scattdims  = 0;
02096         local_nb_localdims  = relation->nb_local_dims;
02097         local_array_id      = osl_relation_get_array_id(relation);
02098         break;
02099     }
02100 
02101     // Update.
02102     *nb_parameters = OSL_max(*nb_parameters, local_nb_parameters);
02103     *nb_iterators  = OSL_max(*nb_iterators,  local_nb_iterators);
02104     *nb_scattdims  = OSL_max(*nb_scattdims,  local_nb_scattdims);
02105     *nb_localdims  = OSL_max(*nb_localdims,  local_nb_localdims);
02106     *array_id      = OSL_max(*array_id,      local_array_id);
02107     relation = relation->next;
02108   }
02109 }
02110 
02111 
02123 osl_relation_p osl_relation_extend_output(osl_relation_p relation, int dim) {
02124   int i, j;
02125   int first = 1;
02126   int offset;
02127   osl_relation_p extended = NULL, node, previous = NULL;
02128 
02129   while (relation != NULL) {
02130     if (relation->nb_output_dims > dim)
02131       OSL_error("Number of output dims is greater than required extension");
02132     offset = dim - relation->nb_output_dims;
02133     
02134     node = osl_relation_pmalloc(relation->precision,
02135                                 relation->nb_rows + offset,
02136                                 relation->nb_columns + offset);
02137     
02138     node->type           = relation->type;
02139     node->nb_output_dims = OSL_max(relation->nb_output_dims, dim);
02140     node->nb_input_dims  = relation->nb_input_dims;
02141     node->nb_local_dims  = relation->nb_local_dims;
02142     node->nb_parameters  = relation->nb_parameters;
02143 
02144     // Copy of the original relation with some 0 columns for the new dimensions
02145     // Note that we use the fact that the matrix is initialized with zeros.
02146     for (i = 0; i < relation->nb_rows; i++) {
02147       for (j = 0; j <= relation->nb_output_dims; j++)
02148         osl_int_assign(relation->precision, node->m[i], j, relation->m[i], j);
02149 
02150       for (j = relation->nb_output_dims + offset + 1;
02151            j < relation->nb_columns + offset; j++)
02152         osl_int_assign(relation->precision,
02153                        node->m[i], j, relation->m[i], j - offset);
02154     }
02155 
02156     // New rows dedicated to the new dimensions
02157     for (i = relation->nb_rows; i < relation->nb_rows + offset; i++) {
02158       for (j = 0; j < relation->nb_columns + offset; j++) {
02159         if ((i - relation->nb_rows) == (j - relation->nb_output_dims - 1))
02160           osl_int_set_si(relation->precision, node->m[i], j, -1);
02161       }
02162     }
02163 
02164     if (first) {
02165       first = 0;
02166       extended = node;
02167       previous = node;
02168     }
02169     else {
02170       previous->next = node;
02171       previous = previous->next;
02172     }
02173 
02174     relation = relation->next;
02175   }
02176   
02177   return extended;
02178 }
02179