OpenScop  0.9.0
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(osl_int_t 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) && (!cst)) {
00280     if ((*first) || osl_int_neg(precision, val)) {
00281       if (osl_int_one(precision, val)) {         // case 1
00282         sprintf(sval, "%s", name);
00283       }
00284       else {
00285         if (osl_int_mone(precision, val)) {      // case -1
00286           sprintf(sval, "-%s", name);
00287         }
00288         else {                                      // default case
00289           osl_int_sprint_txt(sval, precision, val);
00290           sprintf(temp, "*%s", name);
00291           strcat(sval, temp);
00292         }
00293       }
00294       *first = 0;
00295     }
00296     else {
00297       if (osl_int_one(precision, val)) {
00298         sprintf(sval, "+%s", name);
00299       }
00300       else {
00301         sprintf(sval, "+");
00302         osl_int_sprint_txt(temp, precision, val);
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) && (*first)) ||
00312           (osl_int_neg(precision, val)))
00313         osl_int_sprint_txt(sval, precision, val);
00314       if (osl_int_pos(precision, val)) {
00315         if (!(*first)) {
00316           sprintf(sval, "+");
00317           osl_int_sprint_txt(temp, precision, val);
00318           strcat(sval, temp);
00319         }
00320         else {
00321           osl_int_sprint_txt(sval, precision, val);
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;
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     OSL_strdup(strings[offset], "Arr");
00364     // The other ones are the array dimensions [1]...[n]
00365     for (i = offset + 1; i < relation->nb_output_dims + offset; i++) {
00366       sprintf(temp, "[%d]", i - 1);
00367       OSL_strdup(strings[i], temp);
00368     }
00369   }
00370   else
00371   if ((relation->type == OSL_TYPE_DOMAIN) ||
00372       (relation->type == OSL_TYPE_CONTEXT)) {
00373     for (i = offset; i < relation->nb_output_dims + offset; i++) {
00374       OSL_strdup(strings[i], names->iterators->string[i - offset]);
00375     }
00376   }
00377   else {
00378     for (i = offset; i < relation->nb_output_dims + offset; i++) {
00379       OSL_strdup(strings[i], names->scatt_dims->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(relation->m[row][i],
00443         relation->precision, &first, constant, strings[i]);
00444     
00445     if (oppose) {
00446       osl_int_oppose(relation->precision,
00447                      &relation->m[row][i], relation->m[row][i]);
00448     }
00449     strcat(sline, sval);
00450     free(sval);
00451   }
00452 
00453   return sline;
00454 }
00455 
00456 
00466 char * osl_relation_expression(osl_relation_p relation,
00467                                int row, char ** strings) {
00468 
00469   return osl_relation_subexpression(relation, row,
00470                                     1, relation->nb_columns - 1, 0,
00471                                     strings);
00472 }
00473 
00474 
00486 static
00487 int osl_relation_is_simple_output(osl_relation_p relation, int row) {
00488   int i;
00489   int first = 1;
00490   int sign  = 0;
00491 
00492   if ((relation == NULL) ||
00493       (relation->m == NULL) ||
00494       (relation->nb_output_dims == 0))
00495     return 0;
00496 
00497   if ((row < 0) || (row > relation->nb_rows))
00498     OSL_error("the specified row does not exist in the relation");
00499 
00500   // The constraint must be an equality.
00501   if (!osl_int_zero(relation->precision, relation->m[row][0]))
00502     return 0;
00503 
00504   // Check the output part has one and only one non-zero +1 or -1 coefficient.
00505   first = 1;
00506   for (i = 1; i <= relation->nb_output_dims; i++) {
00507     if (!osl_int_zero(relation->precision, relation->m[row][i])) {
00508       if (first)
00509         first = 0;
00510       else
00511         return 0;
00512 
00513       if (osl_int_one(relation->precision, relation->m[row][i]))
00514         sign = 1;
00515       else if (osl_int_mone(relation->precision, relation->m[row][i]))
00516         sign = -1;
00517       else
00518         return 0;
00519     }
00520   }
00521 
00522   return sign;
00523 }
00524 
00525 
00539 static
00540 char * osl_relation_sprint_comment(osl_relation_p relation, int row,
00541                                    char ** strings, char ** arrays) {
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     else {
00580       snprintf(buffer, OSL_MAX_STRING, " == %s",
00581                arrays[osl_relation_get_array_id(relation) - 1]);
00582       osl_util_safe_strcat(&string, buffer, &high_water_mark);
00583     }
00584   }
00585   else {
00586     // Second case : general case.
00587     
00588     expression = osl_relation_expression(relation, row, strings);
00589     snprintf(buffer, OSL_MAX_STRING, "   ## %s", expression);
00590     osl_util_safe_strcat(&string, buffer, &high_water_mark);
00591     free(expression);
00592     
00593     if (osl_int_zero(relation->precision, relation->m[row][0]))
00594       snprintf(buffer, OSL_MAX_STRING, " == 0");
00595     else
00596       snprintf(buffer, OSL_MAX_STRING, " >= 0");
00597     osl_util_safe_strcat(&string, buffer, &high_water_mark);
00598   }
00599 
00600   return string;
00601 }
00602 
00603 
00613 static
00614 char * osl_relation_column_string(osl_relation_p relation, char ** strings) {
00615   int i, j;
00616   int index_output_dims;
00617   int index_input_dims;
00618   int index_local_dims;
00619   int index_parameters;
00620   int index_scalar;
00621   int space, length, left, right;
00622   char * scolumn;
00623   char temp[OSL_MAX_STRING];
00624 
00625   OSL_malloc(scolumn, char *, OSL_MAX_STRING);
00626  
00627   index_output_dims = 1;
00628   index_input_dims  = index_output_dims + relation->nb_output_dims;
00629   index_local_dims  = index_input_dims  + relation->nb_input_dims;
00630   index_parameters  = index_local_dims  + relation->nb_local_dims;
00631   index_scalar      = index_parameters  + relation->nb_parameters;
00632 
00633   // 1. The comment part.
00634   sprintf(scolumn, "#");
00635   for (j = 0; j < (OSL_FMT_LENGTH - 1)/2 - 1; j++)
00636     strcat(scolumn, " ");
00637 
00638   i = 0;
00639   while (strings[i] != NULL) {
00640     space  = OSL_FMT_LENGTH;
00641     length = (space > (int)strlen(strings[i])) ? (int)strlen(strings[i]) : space;
00642     right  = (space - length + (OSL_FMT_LENGTH % 2)) / 2;
00643     left   = space - length - right;
00644 
00645     // 2. Spaces before the name
00646     for (j = 0; j < left; j++)
00647       strcat(scolumn, " ");
00648 
00649     // 3. The (abbreviated) name
00650     for (j = 0; j < length - 1; j++) {
00651       sprintf(temp, "%c", strings[i][j]);
00652       strcat(scolumn, temp);
00653     }
00654     if (length >= (int)strlen(strings[i]))
00655       sprintf(temp, "%c", strings[i][j]);
00656     else 
00657       sprintf(temp, ".");
00658     strcat(scolumn, temp);
00659 
00660     // 4. Spaces after the name
00661     for (j = 0; j < right; j++)
00662       strcat(scolumn, " ");
00663     
00664     i++;
00665     if ((i == index_output_dims) ||
00666         (i == index_input_dims)  ||
00667         (i == index_local_dims)  ||
00668         (i == index_parameters)  ||
00669         (i == index_scalar))
00670       strcat(scolumn, "|");
00671     else
00672       strcat(scolumn, " ");
00673   }
00674   strcat(scolumn, "\n");
00675 
00676   return scolumn;
00677 }
00678 
00679 
00689 static
00690 char * osl_relation_column_string_scoplib(osl_relation_p relation,
00691                                           char ** strings) {
00692   int i, j;
00693   int index_output_dims;
00694   int index_input_dims;
00695   int index_local_dims;
00696   int index_parameters;
00697   int index_scalar;
00698   int space, length, left, right;
00699   char * scolumn;
00700   char temp[OSL_MAX_STRING];
00701 
00702   OSL_malloc(scolumn, char *, OSL_MAX_STRING);
00703  
00704   index_output_dims = 1;
00705   index_input_dims  = index_output_dims + relation->nb_output_dims;
00706   index_local_dims  = index_input_dims  + relation->nb_input_dims;
00707   index_parameters  = index_local_dims  + relation->nb_local_dims;
00708   index_scalar      = index_parameters  + relation->nb_parameters;
00709 
00710   // 1. The comment part.
00711   sprintf(scolumn, "#");
00712   for (j = 0; j < (OSL_FMT_LENGTH - 1)/2 - 1; j++)
00713     strcat(scolumn, " ");
00714 
00715   i = 0;
00716   while (strings[i] != NULL) {
00717     
00718     if (i == 0 || 
00719         (relation->type != OSL_TYPE_DOMAIN && i >= index_input_dims) ||
00720         (relation->type == OSL_TYPE_DOMAIN && i <= index_output_dims) ||
00721         i >= index_parameters) {
00722       space  = OSL_FMT_LENGTH;
00723       length = (space > (int)strlen(strings[i])) ? (int)strlen(strings[i]) : space;
00724       right  = (space - length + (OSL_FMT_LENGTH % 2)) / 2;
00725       left   = space - length - right;
00726 
00727       // 2. Spaces before the name
00728       for (j = 0; j < left; j++)
00729         strcat(scolumn, " ");
00730 
00731       // 3. The (abbreviated) name
00732       for (j = 0; j < length - 1; j++) {
00733         sprintf(temp, "%c", strings[i][j]);
00734         strcat(scolumn, temp);
00735       }
00736       if (length >= (int)strlen(strings[i]))
00737         sprintf(temp, "%c", strings[i][j]);
00738       else 
00739         sprintf(temp, ".");
00740       strcat(scolumn, temp);
00741 
00742       // 4. Spaces after the name
00743       for (j = 0; j < right; j++)
00744         strcat(scolumn, " ");
00745         
00746       if ((i == index_output_dims-1) ||
00747           (i == index_input_dims-1)  ||
00748           (i == index_local_dims-1)  ||
00749           (i == index_parameters-1)  ||
00750           (i == index_scalar-1))
00751         strcat(scolumn, "|");
00752       else
00753         strcat(scolumn, " ");
00754     }
00755     
00756     i++;
00757   }
00758   strcat(scolumn, "\n");
00759 
00760   return scolumn;
00761 }
00762 
00763 
00771 static
00772 osl_names_p osl_relation_names(osl_relation_p relation) {
00773   int nb_parameters = OSL_UNDEFINED;
00774   int nb_iterators  = OSL_UNDEFINED;
00775   int nb_scattdims  = OSL_UNDEFINED;
00776   int nb_localdims  = OSL_UNDEFINED;
00777   int array_id      = OSL_UNDEFINED;
00778 
00779   osl_relation_get_attributes(relation, &nb_parameters, &nb_iterators,
00780                               &nb_scattdims, &nb_localdims, &array_id);
00781   
00782   return osl_names_generate("P", nb_parameters,
00783                             "i", nb_iterators,
00784                             "c", nb_scattdims,
00785                             "l", nb_localdims,
00786                             "A", array_id);
00787 }
00788 
00789 
00797 int osl_relation_nb_components(osl_relation_p relation) {
00798   int nb_components = 0;
00799   
00800   while (relation != NULL) {
00801     nb_components++;
00802     relation = relation->next;
00803   }
00804 
00805   return nb_components;
00806 }
00807 
00808 
00818 char * osl_relation_spprint_polylib(osl_relation_p relation,
00819                                     osl_names_p names) {
00820   int i, j;
00821   int part, nb_parts;
00822   int generated_names = 0;
00823   int high_water_mark = OSL_MAX_STRING;
00824   char * string = NULL;
00825   char buffer[OSL_MAX_STRING];
00826   char ** name_array = NULL;
00827   char * scolumn;
00828   char * comment;
00829 
00830   if (relation == NULL)
00831     return osl_util_strdup("# NULL relation\n");
00832 
00833   OSL_malloc(string, char *, high_water_mark * sizeof(char));
00834   string[0] = '\0';
00835 
00836   // Generates the names for the comments if necessary.
00837   if (names == NULL) {
00838     generated_names = 1;
00839     names = osl_relation_names(relation);
00840   }
00841 
00842   nb_parts = osl_relation_nb_components(relation);
00843 
00844   if (nb_parts > 1) {
00845     snprintf(buffer, OSL_MAX_STRING, "# Union with %d parts\n%d\n",
00846              nb_parts, nb_parts);
00847     osl_util_safe_strcat(&string, buffer, &high_water_mark);
00848   }
00849 
00850   // Print each part of the union.
00851   for (part = 1; part <= nb_parts; part++) {
00852     // Prepare the array of strings for comments.
00853     name_array = osl_relation_strings(relation, names);
00854 
00855     if (nb_parts > 1) {
00856       snprintf(buffer, OSL_MAX_STRING, "# Union part No.%d\n", part);
00857       osl_util_safe_strcat(&string, buffer, &high_water_mark);
00858     }
00859 
00860     snprintf(buffer, OSL_MAX_STRING, "%d %d %d %d %d %d\n",
00861              relation->nb_rows,        relation->nb_columns,
00862              relation->nb_output_dims, relation->nb_input_dims,
00863              relation->nb_local_dims,  relation->nb_parameters);
00864     osl_util_safe_strcat(&string, buffer, &high_water_mark);
00865 
00866     if (relation->nb_rows > 0) {
00867       scolumn = osl_relation_column_string(relation, name_array);
00868       snprintf(buffer, OSL_MAX_STRING, "%s", scolumn);
00869       osl_util_safe_strcat(&string, buffer, &high_water_mark);
00870       free(scolumn);
00871     }
00872 
00873     for (i = 0; i < relation->nb_rows; i++) {
00874       for (j = 0; j < relation->nb_columns; j++) {
00875         osl_int_sprint(buffer, relation->precision, relation->m[i][j]);
00876         osl_util_safe_strcat(&string, buffer, &high_water_mark);
00877         snprintf(buffer, OSL_MAX_STRING, " ");
00878         osl_util_safe_strcat(&string, buffer, &high_water_mark);
00879       }
00880 
00881       if (name_array != NULL) {
00882         comment = osl_relation_sprint_comment(relation, i, name_array,
00883                                               names->arrays->string);
00884         osl_util_safe_strcat(&string, comment, &high_water_mark);
00885         free(comment);
00886       }
00887       snprintf(buffer, OSL_MAX_STRING, "\n");
00888       osl_util_safe_strcat(&string, buffer, &high_water_mark);
00889     }
00890 
00891     // Free the array of strings.
00892     if (name_array != NULL) {
00893       for (i = 0; i < relation->nb_columns; i++)
00894         free(name_array[i]);
00895       free(name_array);
00896     }
00897 
00898     relation = relation->next;
00899   }
00900   
00901   if (generated_names)
00902     osl_names_free(names);
00903 
00904   return string;
00905 }
00906 
00907 
00919 char * osl_relation_spprint_polylib_scoplib(osl_relation_p relation,
00920                                             osl_names_p names,
00921                                             int print_nth_part,
00922                                             int add_fakeiter) {
00923   int i, j;
00924   int part, nb_parts;
00925   int generated_names = 0;
00926   int is_access_array;
00927   int high_water_mark = OSL_MAX_STRING;
00928   int start_row; // for removing the first line in the access matrix
00929   int index_output_dims;
00930   int index_input_dims;
00931   int index_params;
00932   char * string = NULL;
00933   char buffer[OSL_MAX_STRING];
00934   char ** name_array = NULL;
00935   char * scolumn;
00936   char * comment;
00937 
00938   if (relation == NULL)
00939     return osl_util_strdup("# NULL relation\n");
00940 
00941   OSL_malloc(string, char *, high_water_mark * sizeof(char));
00942   string[0] = '\0';
00943 
00944   // Generates the names for the comments if necessary.
00945   if (names == NULL) {
00946     generated_names = 1;
00947     names = osl_relation_names(relation);
00948   }
00949 
00950   nb_parts = osl_relation_nb_components(relation);
00951   if (nb_parts > 1) {
00952     snprintf(buffer, OSL_MAX_STRING, "# Union with %d parts\n%d\n",
00953              nb_parts, nb_parts);
00954     osl_util_safe_strcat(&string, buffer, &high_water_mark);
00955   }
00956   
00957   is_access_array = (relation->type == OSL_TYPE_READ ||
00958                      relation->type == OSL_TYPE_WRITE ? 1 : 0);
00959     
00960   // Print each part of the union.
00961 
00962   for (part = 1; part <= nb_parts; part++) {
00963     
00964     index_output_dims = 1;
00965     index_input_dims  = index_output_dims + relation->nb_output_dims;
00966     index_params      = index_input_dims + relation->nb_input_dims;
00967     
00968     // Prepare the array of strings for comments.
00969     name_array = osl_relation_strings(relation, names);
00970 
00971     if (nb_parts > 1) {
00972       snprintf(buffer, OSL_MAX_STRING, "# Union part No.%d\n", part);
00973       osl_util_safe_strcat(&string, buffer, &high_water_mark);
00974     }
00975     
00976     if (print_nth_part) {
00977       snprintf(buffer, OSL_MAX_STRING, "%d\n", part);
00978       osl_util_safe_strcat(&string, buffer, &high_water_mark);
00979     }
00980     
00981     // Don't print the array size for access array
00982     // (the total size is printed in osl_relation_list_pprint_access_array_scoplib)
00983     if (!is_access_array) {
00984       
00985       // Print array size
00986       if (relation->type == OSL_TYPE_DOMAIN) {
00987         
00988         if (add_fakeiter) {
00989           
00990           snprintf(buffer, OSL_MAX_STRING, "%d %d\n",
00991                    relation->nb_rows+1, relation->nb_columns - 
00992                                       relation->nb_input_dims + 1);
00993           osl_util_safe_strcat(&string, buffer, &high_water_mark);
00994           
00995           // add the fakeiter line
00996           snprintf(buffer, OSL_MAX_STRING, "   0 ");
00997           osl_util_safe_strcat(&string, buffer, &high_water_mark);
00998           snprintf(buffer, OSL_MAX_STRING, "   1 "); // fakeiter
00999           osl_util_safe_strcat(&string, buffer, &high_water_mark);
01000           
01001           for (i = 0 ; i < relation->nb_parameters ; i++) {
01002             snprintf(buffer, OSL_MAX_STRING, "   0 ");
01003             osl_util_safe_strcat(&string, buffer, &high_water_mark);
01004           }
01005           
01006           snprintf(buffer, OSL_MAX_STRING, "    0  ## fakeiter == 0\n");
01007           osl_util_safe_strcat(&string, buffer, &high_water_mark);
01008           
01009         } else {
01010           snprintf(buffer, OSL_MAX_STRING, "%d %d\n",
01011                    relation->nb_rows, relation->nb_columns - 
01012                                       relation->nb_input_dims);
01013           osl_util_safe_strcat(&string, buffer, &high_water_mark);
01014         }
01015         
01016       } else { // SCATTERING
01017         
01018         if (add_fakeiter) {
01019           snprintf(buffer, OSL_MAX_STRING, "%d %d\n",
01020                    relation->nb_rows+2, relation->nb_columns - 
01021                                      relation->nb_output_dims + 1);
01022           osl_util_safe_strcat(&string, buffer, &high_water_mark);
01023         } else {
01024           snprintf(buffer, OSL_MAX_STRING, "%d %d\n",
01025                    relation->nb_rows, relation->nb_columns - 
01026                                      relation->nb_output_dims);
01027           osl_util_safe_strcat(&string, buffer, &high_water_mark);
01028         }
01029       }
01030       
01031       // Print column names in comment
01032       if (relation->nb_rows > 0) {
01033         scolumn = osl_relation_column_string_scoplib(relation, name_array);
01034         snprintf(buffer, OSL_MAX_STRING, "%s", scolumn);
01035         osl_util_safe_strcat(&string, buffer, &high_water_mark);
01036         free(scolumn);
01037       }
01038       
01039       start_row = 0;
01040       
01041     } else {
01042       
01043       if (relation->nb_rows == 1) // for non array variables
01044         start_row = 0;
01045       else // Remove the 'Arr' line
01046         start_row = 1;
01047     }
01048     
01049     // Print the array
01050     for (i = start_row; i < relation->nb_rows; i++) {
01051       
01052       // First column
01053       if (!is_access_array) {
01054         // array index name for scoplib
01055         osl_int_sprint(buffer, relation->precision, relation->m[i][0]);
01056         osl_util_safe_strcat(&string, buffer, &high_water_mark);
01057         snprintf(buffer, OSL_MAX_STRING, " ");
01058         osl_util_safe_strcat(&string, buffer, &high_water_mark);
01059         
01060       } else {
01061         // The first column represents the array index name in openscop
01062         if (i == start_row)
01063           osl_int_sprint(buffer, relation->precision,
01064                          relation->m[0][relation->nb_columns-1]);
01065         else
01066           snprintf(buffer, OSL_MAX_STRING, "   0 ");
01067           
01068         osl_util_safe_strcat(&string, buffer, &high_water_mark);
01069         snprintf(buffer, OSL_MAX_STRING, " ");
01070         osl_util_safe_strcat(&string, buffer, &high_water_mark);
01071       }
01072       
01073       // Rest of the array
01074       if (relation->type == OSL_TYPE_DOMAIN) {
01075       
01076         for (j = 1; j < index_input_dims; j++) {
01077           osl_int_sprint(buffer, relation->precision, relation->m[i][j]);
01078           osl_util_safe_strcat(&string, buffer, &high_water_mark);
01079           snprintf(buffer, OSL_MAX_STRING, " ");
01080           osl_util_safe_strcat(&string, buffer, &high_water_mark);
01081         }
01082         
01083         // Jmp input_dims
01084         for (j = index_params; j < relation->nb_columns; j++) {
01085           osl_int_sprint(buffer, relation->precision, relation->m[i][j]);
01086           osl_util_safe_strcat(&string, buffer, &high_water_mark);
01087           snprintf(buffer, OSL_MAX_STRING, " ");
01088           osl_util_safe_strcat(&string, buffer, &high_water_mark);
01089         }
01090         
01091       } else {
01092 
01093         // Jmp output_dims
01094         for (j = index_input_dims; j < index_params; j++) {
01095           if (is_access_array && relation->nb_rows == 1 &&
01096               j == relation->nb_columns-1) {
01097             snprintf(buffer, OSL_MAX_STRING, "   0 ");
01098             osl_util_safe_strcat(&string, buffer, &high_water_mark);
01099           } else {
01100             osl_int_sprint(buffer, relation->precision, relation->m[i][j]);
01101             osl_util_safe_strcat(&string, buffer, &high_water_mark);
01102             snprintf(buffer, OSL_MAX_STRING, " ");
01103             osl_util_safe_strcat(&string, buffer, &high_water_mark);
01104           }
01105         }
01106         
01107         if (add_fakeiter) {
01108           snprintf(buffer, OSL_MAX_STRING, "   0 ");
01109           osl_util_safe_strcat(&string, buffer, &high_water_mark);
01110         }
01111         
01112         for (; j < relation->nb_columns; j++) {
01113           if (is_access_array && relation->nb_rows == 1 &&
01114               j == relation->nb_columns-1) {
01115             snprintf(buffer, OSL_MAX_STRING, "  0 ");
01116             osl_util_safe_strcat(&string, buffer, &high_water_mark);
01117           } else {
01118             osl_int_sprint(buffer, relation->precision, relation->m[i][j]);
01119             osl_util_safe_strcat(&string, buffer, &high_water_mark);
01120             snprintf(buffer, OSL_MAX_STRING, " ");
01121             osl_util_safe_strcat(&string, buffer, &high_water_mark);
01122           }
01123         }
01124       }
01125       
01126       // equation in comment
01127       if (name_array != NULL) {
01128         comment = osl_relation_sprint_comment(relation, i, name_array,
01129                                               names->arrays->string);
01130         osl_util_safe_strcat(&string, comment, &high_water_mark);
01131         free(comment);
01132         snprintf(buffer, OSL_MAX_STRING, "\n");
01133         osl_util_safe_strcat(&string, buffer, &high_water_mark);
01134       }
01135       
01136       // add the lines in the scattering if we need the fakeiter
01137       if (relation->nb_rows > 0 && add_fakeiter &&
01138           relation->type == OSL_TYPE_SCATTERING) {
01139           
01140         for (i = 0 ; i < 2 ; i++) {
01141           for (j = 0; j < relation->nb_columns; j++) {
01142             if (j == index_output_dims && i == 0)
01143               snprintf(buffer, OSL_MAX_STRING, "   1 "); // fakeiter
01144             else
01145               snprintf(buffer, OSL_MAX_STRING, "   0 ");
01146             osl_util_safe_strcat(&string, buffer, &high_water_mark);
01147           }
01148           snprintf(buffer, OSL_MAX_STRING, "\n");
01149           osl_util_safe_strcat(&string, buffer, &high_water_mark);
01150         }
01151       }
01152       
01153     }
01154 
01155     // Free the array of strings.
01156     if (name_array != NULL) {
01157       for (i = 0; i < relation->nb_columns; i++)
01158         free(name_array[i]);
01159       free(name_array);
01160     }
01161     
01162     relation = relation->next;
01163   }
01164   
01165   if (generated_names)
01166     osl_names_free(names);
01167 
01168   return string;
01169 }
01170 
01171 
01180 char * osl_relation_spprint(osl_relation_p relation, osl_names_p names) {
01181   int high_water_mark = OSL_MAX_STRING;
01182   char * string = NULL;
01183   char * temp;
01184   char buffer[OSL_MAX_STRING];
01185   OSL_malloc(string, char *, high_water_mark * sizeof(char));
01186   string[0] = '\0';
01187 
01188   if (osl_relation_nb_components(relation) > 0) {
01189     temp = osl_relation_sprint_type(relation);
01190     osl_util_safe_strcat(&string, temp, &high_water_mark);
01191     free(temp);
01192     
01193     snprintf(buffer, OSL_MAX_STRING, "\n");
01194     osl_util_safe_strcat(&string, buffer, &high_water_mark);
01195 
01196     temp = osl_relation_spprint_polylib(relation, names);
01197     osl_util_safe_strcat(&string, temp, &high_water_mark);
01198     free(temp);
01199   }
01200 
01201   return string;
01202 }
01203 
01204 
01215 char * osl_relation_spprint_scoplib(osl_relation_p relation, osl_names_p names,
01216                                     int print_nth_part, int add_fakeiter) {
01217   int high_water_mark = OSL_MAX_STRING;
01218   char * string = NULL;
01219   char * temp;
01220   OSL_malloc(string, char *, high_water_mark * sizeof(char));
01221   string[0] = '\0';
01222 
01223   if (relation) {
01224     temp = osl_relation_spprint_polylib_scoplib(relation, names,
01225                                                 print_nth_part, add_fakeiter);
01226     osl_util_safe_strcat(&string, temp, &high_water_mark);
01227     free(temp);
01228   }
01229 
01230   return string;
01231 }
01232 
01233 
01242 void osl_relation_pprint(FILE * file, osl_relation_p relation,
01243                          osl_names_p names) {
01244   char * string = osl_relation_spprint(relation, names);
01245   fprintf(file, "%s", string);
01246   free(string);
01247 }
01248 
01249 
01260 void osl_relation_pprint_scoplib(FILE * file, osl_relation_p relation,
01261                                  osl_names_p names, int print_nth_part,
01262                                  int add_fakeiter) {
01263   char * string = osl_relation_spprint_scoplib(relation, names,
01264                                                print_nth_part, add_fakeiter);
01265   fprintf(file, "%s", string);
01266   free(string);
01267 }
01268 
01269 
01277 char * osl_relation_sprint(osl_relation_p relation) {
01278 
01279   return osl_relation_spprint(relation, NULL);
01280 }
01281 
01282 
01290 void osl_relation_print(FILE * file, osl_relation_p relation) {
01291 
01292   osl_relation_pprint(file, relation, NULL);
01293 }
01294 
01295 
01296 /*****************************************************************************
01297  *                               Reading function                            *
01298  *****************************************************************************/
01299 
01300 
01312 static
01313 int osl_relation_read_type(FILE * file, char ** str) {
01314   int type;
01315   osl_strings_p strings;
01316   
01317   if ((file != NULL && str != NULL) || (file == NULL && str == NULL))
01318     OSL_error("one and only one of the two parameters can be non-NULL");
01319 
01320   if (file != NULL)
01321     strings = osl_strings_read(file);
01322   else
01323     strings = osl_strings_sread(str);
01324   
01325   if (osl_strings_size(strings) > 1) {
01326     OSL_warning("uninterpreted information (after the relation type)");
01327   }
01328   if (osl_strings_size(strings) == 0)
01329     OSL_error("no relation type");
01330  
01331   if (!strcmp(strings->string[0], OSL_STRING_UNDEFINED)) {
01332     type = OSL_UNDEFINED;
01333     goto return_type;
01334   }
01335 
01336   if (!strcmp(strings->string[0], OSL_STRING_CONTEXT)) {
01337     type = OSL_TYPE_CONTEXT; 
01338     goto return_type;
01339   }
01340 
01341   if (!strcmp(strings->string[0], OSL_STRING_DOMAIN)) {
01342     type = OSL_TYPE_DOMAIN; 
01343     goto return_type;
01344   }
01345 
01346   if (!strcmp(strings->string[0], OSL_STRING_SCATTERING)) {
01347     type = OSL_TYPE_SCATTERING; 
01348     goto return_type;
01349   }
01350 
01351   if (!strcmp(strings->string[0], OSL_STRING_READ)) {
01352     type = OSL_TYPE_READ; 
01353     goto return_type;
01354   }
01355 
01356   if (!strcmp(strings->string[0], OSL_STRING_WRITE)) {
01357     type = OSL_TYPE_WRITE; 
01358     goto return_type;
01359   }
01360 
01361   if (!strcmp(strings->string[0], OSL_STRING_MAY_WRITE)) {
01362     type = OSL_TYPE_MAY_WRITE; 
01363     goto return_type;
01364   }
01365 
01366   OSL_error("relation type not supported");
01367 
01368 return_type:
01369   osl_strings_free(strings);
01370   return type;
01371 }
01372 
01373 
01382 osl_relation_p osl_relation_pread(FILE * foo, int precision) {
01383   int i, j, k, n, read = 0;
01384   int nb_rows, nb_columns;
01385   int nb_output_dims, nb_input_dims, nb_local_dims, nb_parameters;
01386   int nb_union_parts = 1;
01387   int may_read_nb_union_parts = 1;
01388   int read_attributes = 1;
01389   int first = 1;
01390   int type;
01391   char * c, s[OSL_MAX_STRING], str[OSL_MAX_STRING], *tmp;
01392   osl_relation_p relation, relation_union = NULL, previous = NULL;
01393 
01394   type = osl_relation_read_type(foo, NULL);
01395 
01396   // Read each part of the union (the number of parts may be updated inside)
01397   for (k = 0; k < nb_union_parts; k++) {
01398     // Read the number of union parts or the attributes of the union part
01399     while (read_attributes) {
01400       read_attributes = 0;
01401 
01402       // Read relation attributes.
01403       c = osl_util_skip_blank_and_comments(foo, s);
01404       read = sscanf(c, " %d %d %d %d %d %d", &nb_rows, &nb_columns,
01405                                              &nb_output_dims, &nb_input_dims,
01406                                              &nb_local_dims, &nb_parameters);
01407     
01408       if (((read != 1) && (read != 6)) ||
01409           ((read == 1) && (may_read_nb_union_parts != 1)))
01410         OSL_error("not 1 or 6 integers on the first relation line");
01411 
01412       if (read == 1) {
01413         // Only one number means a union and is the number of parts.
01414         nb_union_parts = nb_rows;
01415         if (nb_union_parts < 1)
01416           OSL_error("negative nb of union parts");
01417         
01418         // Allow to read the properties of the first part of the union.
01419         read_attributes = 1;
01420       }
01421 
01422       may_read_nb_union_parts = 0;
01423     }
01424 
01425     // Allocate the union part and fill its properties.
01426     relation = osl_relation_pmalloc(precision, nb_rows, nb_columns);
01427     relation->type           = type;
01428     relation->nb_output_dims = nb_output_dims;
01429     relation->nb_input_dims  = nb_input_dims;
01430     relation->nb_local_dims  = nb_local_dims;
01431     relation->nb_parameters  = nb_parameters;
01432 
01433     // Read the matrix of constraints.
01434     for (i = 0; i < relation->nb_rows; i++) {
01435       c = osl_util_skip_blank_and_comments(foo, s);
01436       if (c == NULL)
01437         OSL_error("not enough rows");
01438 
01439       for (j = 0; j < relation->nb_columns; j++) {
01440         if (c == NULL || *c == '#' || *c == '\n')
01441           OSL_error("not enough columns");
01442         if (sscanf(c, "%s%n", str, &n) == 0)
01443           OSL_error("not enough rows");
01444 
01445         // TODO: remove this tmp (sread updates the pointer).
01446         tmp = str;
01447         osl_int_sread(&tmp, precision, &relation->m[i][j]);
01448         c += n;
01449       }
01450     }
01451     
01452     // Build the linked list of union parts.
01453     if (first == 1) {
01454       relation_union = relation;
01455       first = 0;
01456     }
01457     else {
01458       previous->next = relation;
01459     }
01460 
01461     previous = relation;
01462     read_attributes = 1;
01463   }
01464 
01465   return relation_union;
01466 }
01467 
01468 
01480 osl_relation_p osl_relation_psread(char ** input, int precision) {
01481   int i, j, k, n, read = 0;
01482   int nb_rows, nb_columns;
01483   int nb_output_dims, nb_input_dims, nb_local_dims, nb_parameters;
01484   int nb_union_parts = 1;
01485   int may_read_nb_union_parts = 1;
01486   int read_attributes = 1;
01487   int first = 1;
01488   int type;
01489   char str[OSL_MAX_STRING], *tmp;
01490   osl_relation_p relation, relation_union = NULL, previous = NULL;
01491 
01492   type = osl_relation_read_type(NULL, input);
01493 
01494   // Read each part of the union (the number of parts may be updated inside)
01495   for (k = 0; k < nb_union_parts; k++) {
01496     // Read the number of union parts or the attributes of the union part
01497     while (read_attributes) {
01498       read_attributes = 0;
01499 
01500       // Read relation attributes.
01501       osl_util_sskip_blank_and_comments(input);
01502       
01503       read = sscanf(*input, " %d %d %d %d %d %d%n",
01504           &nb_rows, &nb_columns,
01505           &nb_output_dims, &nb_input_dims,
01506           &nb_local_dims, &nb_parameters, &n);
01507       *input += n;
01508 
01509       if (((read != 1) && (read != 6)) ||
01510           ((read == 1) && (may_read_nb_union_parts != 1)))
01511         OSL_error("not 1 or 6 integers on the first relation line");
01512 
01513       if (read == 1) {
01514         // Only one number means a union and is the number of parts.
01515         nb_union_parts = nb_rows;
01516         if (nb_union_parts < 1)
01517           OSL_error("negative nb of union parts");
01518         
01519         // Allow to read the properties of the first part of the union.
01520         read_attributes = 1;
01521       }
01522 
01523       may_read_nb_union_parts = 0;
01524     }
01525 
01526     // Allocate the union part and fill its properties.
01527     relation = osl_relation_pmalloc(precision, nb_rows, nb_columns);
01528     relation->type           = type;
01529     relation->nb_output_dims = nb_output_dims;
01530     relation->nb_input_dims  = nb_input_dims;
01531     relation->nb_local_dims  = nb_local_dims;
01532     relation->nb_parameters  = nb_parameters;
01533 
01534     // Read the matrix of constraints.
01535     for (i = 0; i < relation->nb_rows; i++) {
01536       osl_util_sskip_blank_and_comments(input);
01537       if (!(*input))
01538         OSL_error("not enough rows");
01539 
01540       for (j = 0; j < relation->nb_columns; j++) {
01541         if (*input == NULL || **input == '#' || **input == '\n')
01542           OSL_error("not enough columns");
01543         if (sscanf(*input, "%s%n", str, &n) == 0)
01544           OSL_error("not enough rows");
01545 
01546         // TODO: remove this tmp (sread updates the pointer).
01547         tmp = str;
01548         osl_int_sread(&tmp, precision, &relation->m[i][j]);
01549         *input += n;
01550       }
01551     }
01552     
01553     // Build the linked list of union parts.
01554     if (first == 1) {
01555       relation_union = relation;
01556       first = 0;
01557     }
01558     else {
01559       previous->next = relation;
01560     }
01561 
01562     previous = relation;
01563     read_attributes = 1;
01564   }
01565 
01566   return relation_union;
01567 }
01568 
01569 
01577 osl_relation_p osl_relation_sread(char ** input) {
01578   int precision = osl_util_get_precision();
01579   return osl_relation_psread(input, precision);
01580 }
01581 
01582 
01590 osl_relation_p osl_relation_read(FILE * foo) {
01591   int precision = osl_util_get_precision();
01592   return osl_relation_pread(foo, precision);
01593 }
01594 
01595 
01596 /*+***************************************************************************
01597  *                    Memory allocation/deallocation function                *
01598  *****************************************************************************/
01599 
01600 
01612 osl_relation_p osl_relation_pmalloc(int precision,
01613                                     int nb_rows, int nb_columns) {
01614   osl_relation_p relation;
01615   osl_int_t ** p, * q;
01616   int i, j;
01617 
01618   if ((precision != OSL_PRECISION_SP) &&
01619       (precision != OSL_PRECISION_DP) &&
01620       (precision != OSL_PRECISION_MP))
01621     OSL_error("unknown precision");
01622 
01623   if ((nb_rows < 0) || (nb_columns < 0))
01624     OSL_error("negative sizes");
01625 
01626   OSL_malloc(relation, osl_relation_p, sizeof(osl_relation_t));
01627   relation->type           = OSL_UNDEFINED;
01628   relation->nb_rows        = nb_rows;
01629   relation->nb_columns     = nb_columns;
01630   relation->nb_output_dims = OSL_UNDEFINED;
01631   relation->nb_input_dims  = OSL_UNDEFINED;
01632   relation->nb_parameters  = OSL_UNDEFINED;
01633   relation->nb_local_dims  = OSL_UNDEFINED;
01634   relation->precision      = precision;
01635   
01636   if ((nb_rows == 0) || (nb_columns == 0) ||
01637       (nb_rows == OSL_UNDEFINED) || (nb_columns == OSL_UNDEFINED)) {
01638     relation->m = NULL;
01639   } 
01640   else {
01641     OSL_malloc(p, osl_int_t**, nb_rows * sizeof(osl_int_t*));
01642     OSL_malloc(q, osl_int_t*, nb_rows * nb_columns * sizeof(osl_int_t));
01643     relation->m = p;
01644     for (i = 0; i < nb_rows; i++) {
01645       relation->m[i] = q + i * nb_columns ;
01646       for (j = 0; j < nb_columns; j++)
01647         osl_int_init_set_si(precision, &relation->m[i][j], 0);
01648     }
01649   }
01650  
01651   relation->next = NULL;
01652 
01653   return relation;
01654 }
01655 
01656 
01664 osl_relation_p osl_relation_malloc(int nb_rows, int nb_columns) {
01665   int precision = osl_util_get_precision();
01666   return osl_relation_pmalloc(precision, nb_rows, nb_columns);
01667 }
01668 
01669 
01676 void osl_relation_free_inside(osl_relation_p relation) {
01677   int i, nb_elements;
01678 
01679   if (relation == NULL)
01680     return;
01681 
01682   nb_elements = relation->nb_rows * relation->nb_columns;
01683   
01684   for (i = 0; i < nb_elements; i++)
01685     osl_int_clear(relation->precision, &relation->m[0][i]);
01686 
01687   if (relation->m != NULL) {
01688     if (nb_elements > 0)
01689       free(relation->m[0]);
01690     free(relation->m);
01691   }
01692 }
01693 
01694 
01701 void osl_relation_free(osl_relation_p relation) {
01702   osl_relation_p tmp;
01703   
01704   while (relation != NULL) {
01705     tmp = relation->next;
01706     osl_relation_free_inside(relation);
01707     free(relation);
01708     relation = tmp;
01709   }
01710 }
01711 
01712 
01713 /*+***************************************************************************
01714  *                            Processing functions                           *
01715  *****************************************************************************/
01716 
01717 
01728 osl_relation_p osl_relation_nclone(osl_relation_p relation, int n) {
01729   int i, j, k;
01730   int first = 1, nb_components, nb_parts;
01731   osl_relation_p clone = NULL, node, previous = NULL;
01732 
01733   nb_components = osl_relation_nb_components(relation);
01734   nb_parts = (n == -1) ? nb_components : n;
01735   if (nb_components < nb_parts)
01736     OSL_error("not enough union parts to clone");
01737 
01738   for (k = 0; k < nb_parts; k++) {
01739     node = osl_relation_pmalloc(relation->precision,
01740                                 relation->nb_rows, relation->nb_columns);
01741     node->type           = relation->type;
01742     node->nb_output_dims = relation->nb_output_dims;
01743     node->nb_input_dims  = relation->nb_input_dims;
01744     node->nb_local_dims  = relation->nb_local_dims;
01745     node->nb_parameters  = relation->nb_parameters;
01746 
01747     for (i = 0; i < relation->nb_rows; i++)
01748       for (j = 0; j < relation->nb_columns; j++)
01749         osl_int_assign(relation->precision,
01750                        &node->m[i][j], relation->m[i][j]);
01751   
01752     if (first) {
01753       first = 0;
01754       clone = node;
01755       previous = node;
01756     }
01757     else {
01758       previous->next = node;
01759       previous = previous->next;
01760     }
01761 
01762     relation = relation->next;
01763   }
01764 
01765   return clone;
01766 }
01767 
01768 
01781 osl_relation_p osl_relation_clone_nconstraints(osl_relation_p relation,
01782                                                int n) {
01783   int i, j;
01784   int first = 1, all_rows = 0;
01785   osl_relation_p clone = NULL, node, previous = NULL;
01786 
01787   if (n == -1)
01788     all_rows = 1;
01789 
01790   while (relation != NULL) {
01791     if (all_rows)
01792       n = relation->nb_rows;
01793 
01794     if (n > relation->nb_rows)
01795       OSL_error("not enough rows to clone in the relation");
01796 
01797     node = osl_relation_pmalloc(relation->precision, n, relation->nb_columns);
01798     node->type           = relation->type;
01799     node->nb_output_dims = relation->nb_output_dims;
01800     node->nb_input_dims  = relation->nb_input_dims;
01801     node->nb_local_dims  = relation->nb_local_dims;
01802     node->nb_parameters  = relation->nb_parameters;
01803 
01804     for (i = 0; i < n; i++)
01805       for (j = 0; j < relation->nb_columns; j++)
01806         osl_int_assign(relation->precision,
01807                        &node->m[i][j], relation->m[i][j]);
01808   
01809     if (first) {
01810       first = 0;
01811       clone = node;
01812       previous = node;
01813     }
01814     else {
01815       previous->next = node;
01816       previous = previous->next;
01817     }
01818 
01819     relation = relation->next;
01820   }
01821 
01822   return clone;
01823 }
01824 
01825 
01833 osl_relation_p osl_relation_clone(osl_relation_p relation) {
01834   if (relation == NULL)
01835     return NULL;
01836 
01837   return osl_relation_nclone(relation, -1);
01838 }
01839 
01840 
01850 void osl_relation_add(osl_relation_p *r1, osl_relation_p r2) {
01851   while (*r1 != NULL)
01852     r1 = &((*r1)->next);
01853 
01854   *r1 = r2;
01855 }
01856 
01857 
01867 osl_relation_p osl_relation_union(osl_relation_p r1,
01868                                   osl_relation_p r2) {
01869   osl_relation_p copy1, copy2;
01870   
01871   if ((r1 == NULL) && (r2 == NULL))
01872     return NULL;
01873   
01874   copy1 = osl_relation_clone(r1);
01875   copy2 = osl_relation_clone(r2);
01876   osl_relation_add(&copy1, copy2);
01877   
01878   return copy1;
01879 }
01880 
01881 
01891 void osl_relation_replace_vector(osl_relation_p relation,
01892                                  osl_vector_p vector, int row) {
01893   int i;
01894 
01895   if ((relation == NULL) || (vector == NULL)     ||
01896       (relation->precision != vector->precision) ||
01897       (relation->nb_columns != vector->size)     ||
01898       (row >= relation->nb_rows) || (row < 0))
01899     OSL_error("vector cannot replace relation row");
01900 
01901   for (i = 0; i < vector->size; i++)
01902     osl_int_assign(relation->precision, &relation->m[row][i], vector->v[i]);
01903 }
01904 
01905 
01915 void osl_relation_add_vector(osl_relation_p relation,
01916                              osl_vector_p vector, int row) {
01917   int i;
01918 
01919   if ((relation == NULL) || (vector == NULL)     ||
01920       (relation->precision != vector->precision) ||
01921       (relation->nb_columns != vector->size)     ||
01922       (row >= relation->nb_rows) || (row < 0))
01923     OSL_error("vector cannot be added to relation");
01924 
01925   if (osl_int_get_si(relation->precision, relation->m[row][0]) == 0)
01926     osl_int_assign(relation->precision, &relation->m[row][0], vector->v[0]);
01927 
01928   for (i = 1; i < vector->size; i++)
01929     osl_int_add(relation->precision,
01930                 &relation->m[row][i], relation->m[row][i], vector->v[i]);
01931 }
01932 
01933 
01943 void osl_relation_sub_vector(osl_relation_p relation,
01944                              osl_vector_p vector, int row) {
01945   int i;
01946 
01947   if ((relation == NULL) || (vector == NULL)     ||
01948       (relation->precision != vector->precision) ||
01949       (relation->nb_columns != vector->size)     ||
01950       (row >= relation->nb_rows) || (row < 0))
01951     OSL_error("vector cannot be subtracted to row");
01952 
01953   if (osl_int_get_si(relation->precision, relation->m[row][0]) == 0)
01954     osl_int_assign(relation->precision, &relation->m[row][0], vector->v[0]);
01955 
01956   for (i = 1; i < vector->size; i++)
01957     osl_int_sub(relation->precision,
01958                 &relation->m[row][i], relation->m[row][i], vector->v[i]);
01959 }
01960 
01961 
01975 void osl_relation_insert_vector(osl_relation_p relation,
01976                                 osl_vector_p vector, int row) {
01977   osl_relation_p temp;
01978 
01979   temp = osl_relation_from_vector(vector);
01980   osl_relation_insert_constraints(relation, temp, row);
01981   osl_relation_free(temp);
01982 }
01983 
01984 
01996 osl_relation_p osl_relation_concat_vector(osl_relation_p relation,
01997                                           osl_vector_p vector) {
01998   osl_relation_p new, temp;
01999 
02000   temp = osl_relation_from_vector(vector);
02001   new = osl_relation_concat_constraints(relation, temp);
02002   osl_relation_free(temp);
02003   return new;
02004 }
02005 
02006 
02014 void osl_relation_insert_blank_row(osl_relation_p relation, int row) {
02015   osl_vector_p vector;
02016 
02017   if (relation != NULL) {
02018     vector = osl_vector_pmalloc(relation->precision, relation->nb_columns);
02019     osl_relation_insert_vector(relation, vector, row);
02020     osl_vector_free(vector);
02021   }
02022 }
02023 
02024 
02033 void osl_relation_insert_blank_column(osl_relation_p relation, int column) {
02034 
02035   int i, j;
02036   osl_relation_p temp;
02037 
02038   if (relation == NULL)
02039     return;
02040 
02041   if ((column < 0) || (column > relation->nb_columns))
02042     OSL_error("bad column number");
02043 
02044   // We use a temporary relation just to reuse existing functions. Cleaner.
02045   temp = osl_relation_pmalloc(relation->precision,
02046                               relation->nb_rows, relation->nb_columns + 1);
02047 
02048   for (i = 0; i < relation->nb_rows; i++) {
02049     for (j = 0; j < column; j++)
02050       osl_int_assign(relation->precision, &temp->m[i][j], relation->m[i][j]);
02051 
02052     for (j = column; j < relation->nb_columns; j++)
02053       osl_int_assign(relation->precision, &temp->m[i][j+1], relation->m[i][j]);
02054   }
02055 
02056   osl_relation_free_inside(relation);
02057 
02058   // Replace the inside of relation.
02059   relation->nb_columns = temp->nb_columns;
02060   relation->m = temp->m;
02061 
02062   // Free the temp "shell".
02063   free(temp);
02064 }
02065 
02066 
02074 osl_relation_p osl_relation_from_vector(osl_vector_p vector) {
02075   osl_relation_p relation;
02076 
02077   if (vector == NULL)
02078     return NULL;
02079 
02080   relation = osl_relation_pmalloc(vector->precision, 1, vector->size);
02081   osl_relation_replace_vector(relation, vector, 0);
02082   return relation;
02083 }
02084 
02085 
02095 void osl_relation_replace_constraints(osl_relation_p r1,
02096                                       osl_relation_p r2, int row) {
02097   int i, j;
02098 
02099   if ((r1 == NULL) || (r2 == NULL)       ||
02100       (r1->precision != r2->precision)   ||
02101       (r1->nb_columns != r1->nb_columns) ||
02102       ((row + r2->nb_rows) > r1->nb_rows) || (row < 0))
02103     OSL_error("relation rows could not be replaced");
02104 
02105   for (i = 0; i < r2->nb_rows; i++)
02106     for (j = 0; j < r2->nb_columns; j++)
02107       osl_int_assign(r1->precision, &r1->m[i+row][j], r2->m[i][j]);
02108 }
02109 
02110 
02123 void osl_relation_insert_constraints(osl_relation_p r1,
02124                                      osl_relation_p r2, int row) {
02125   int i, j;
02126   osl_relation_p temp;
02127 
02128   if ((r1 == NULL) || (r2 == NULL))
02129     return;
02130 
02131   if (row == -1)
02132     row = r1->nb_rows;
02133 
02134   if ((r1->nb_columns != r2->nb_columns) ||
02135       (r1->precision != r2->precision)   ||
02136       (row > r1->nb_rows) || (row < 0))
02137     OSL_error("constraints cannot be inserted");
02138 
02139   // We use a temporary relation just to reuse existing functions. Cleaner.
02140   temp = osl_relation_pmalloc(r1->precision,
02141                               r1->nb_rows + r2->nb_rows, r1->nb_columns);
02142 
02143   for (i = 0; i < row; i++)
02144     for (j = 0; j < r1->nb_columns; j++)
02145       osl_int_assign(r1->precision, &temp->m[i][j], r1->m[i][j]);
02146 
02147   osl_relation_replace_constraints(temp, r2, row);
02148 
02149   for (i = row + r2->nb_rows; i < r2->nb_rows + r1->nb_rows; i++)
02150     for (j = 0; j < r1->nb_columns; j++)
02151       osl_int_assign(r1->precision, &temp->m[i][j], r1->m[i-r2->nb_rows][j]);
02152 
02153   osl_relation_free_inside(r1);
02154 
02155   // Replace the inside of relation.
02156   r1->nb_rows = temp->nb_rows;
02157   r1->m = temp->m;
02158 
02159   // Free the temp "shell".
02160   free(temp);
02161 }
02162 
02163 
02172 void osl_relation_swap_constraints(osl_relation_p relation, int c1, int c2) {
02173   int i;
02174     
02175   if ((relation == NULL) || (c1 == c2))
02176     return;
02177 
02178   if ((c1 >= relation->nb_rows) || (c1 < 0) ||
02179       (c2 >= relation->nb_rows) || (c2 < 0))
02180     OSL_error("bad constraint rows");
02181 
02182   for (i = 0; i < relation->nb_columns; i++)
02183     osl_int_swap(relation->precision,
02184                  &relation->m[c1][i], &relation->m[c2][i]);
02185 }
02186 
02187 
02195 void osl_relation_remove_row(osl_relation_p r, int row) {
02196   int i, j;
02197   osl_relation_p temp;
02198 
02199   if (r == NULL)
02200     return;
02201 
02202   if ((row < 0) || (row >= r->nb_rows))
02203     OSL_error("bad row number");
02204 
02205   // We use a temporary relation just to reuse existing functions. Cleaner.
02206   temp = osl_relation_pmalloc(r->precision,
02207                               r->nb_rows - 1, r->nb_columns);
02208 
02209   for (i = 0; i < row; i++)
02210     for (j = 0; j < r->nb_columns; j++)
02211       osl_int_assign(r->precision, &temp->m[i][j], r->m[i][j]);
02212 
02213   for (i = row + 1; i < r->nb_rows; i++)
02214     for (j = 0; j < r->nb_columns; j++)
02215       osl_int_assign(r->precision, &temp->m[i - 1][j], r->m[i][j]);
02216 
02217   osl_relation_free_inside(r);
02218 
02219   // Replace the inside of relation.
02220   r->nb_rows = temp->nb_rows;
02221   r->m = temp->m;
02222 
02223   // Free the temp "shell".
02224   free(temp);
02225 }
02226 
02227 
02235 void osl_relation_remove_column(osl_relation_p r, int column) {
02236   int i, j;
02237   osl_relation_p temp;
02238 
02239   if (r == NULL)
02240     return;
02241 
02242   if ((column < 0) || (column >= r->nb_columns))
02243     OSL_error("bad column number");
02244 
02245   // We use a temporary relation just to reuse existing functions. Cleaner.
02246   temp = osl_relation_pmalloc(r->precision,
02247                               r->nb_rows, r->nb_columns - 1);
02248 
02249   for (i = 0; i < r->nb_rows; i++) {
02250     for (j = 0; j < column; j++)
02251       osl_int_assign(r->precision, &temp->m[i][j], r->m[i][j]);
02252 
02253     for (j = column + 1; j < r->nb_columns; j++)
02254       osl_int_assign(r->precision, &temp->m[i][j - 1], r->m[i][j]);
02255   }
02256 
02257   osl_relation_free_inside(r);
02258 
02259   // Replace the inside of relation.
02260   r->nb_columns = temp->nb_columns;
02261   r->m = temp->m;
02262 
02263   // Free the temp "shell".
02264   free(temp);
02265 }
02266 
02267 
02279 void osl_relation_insert_columns(osl_relation_p relation,
02280                                  osl_relation_p insert, int column) {
02281   int i, j;
02282   osl_relation_p temp;
02283 
02284   if ((relation == NULL) || (insert == NULL))
02285     return;
02286 
02287   if ((relation->precision != insert->precision) ||
02288       (relation->nb_rows   != insert->nb_rows)   ||
02289       (column < 0) || (column > relation->nb_columns))
02290     OSL_error("columns cannot be inserted");
02291 
02292   // We use a temporary relation just to reuse existing functions. Cleaner.
02293   temp = osl_relation_pmalloc(relation->precision, relation->nb_rows,
02294                               relation->nb_columns + insert->nb_columns);
02295 
02296   for (i = 0; i < relation->nb_rows; i++) {
02297     for (j = 0; j < column; j++)
02298       osl_int_assign(relation->precision, &temp->m[i][j], relation->m[i][j]);
02299 
02300     for (j = column; j < column + insert->nb_columns; j++)
02301       osl_int_assign(relation->precision,
02302                      &temp->m[i][j], insert->m[i][j - column]);
02303 
02304     for (j = column + insert->nb_columns;
02305          j < insert->nb_columns + relation->nb_columns; j++)
02306       osl_int_assign(relation->precision,
02307                      &temp->m[i][j], relation->m[i][j - insert->nb_columns]);
02308   }
02309 
02310   osl_relation_free_inside(relation);
02311 
02312   // Replace the inside of relation.
02313   relation->nb_columns = temp->nb_columns;
02314   relation->m = temp->m;
02315 
02316   // Free the temp "shell".
02317   free(temp);
02318 }
02319 
02320 
02332 osl_relation_p osl_relation_concat_constraints(
02333     osl_relation_p r1,
02334     osl_relation_p r2) {
02335   osl_relation_p new;
02336 
02337   if (r1 == NULL)
02338     return osl_relation_clone(r2);
02339 
02340   if (r2 == NULL)
02341     return osl_relation_clone(r1);
02342 
02343   if (r1->nb_columns != r2->nb_columns)
02344     OSL_error("incompatible sizes for concatenation");
02345   
02346   if (r1->next || r2->next)
02347     OSL_warning("relation concatenation is done on the first elements "
02348                 "of union only");
02349 
02350   new = osl_relation_pmalloc(r1->precision,
02351                              r1->nb_rows + r2->nb_rows, r1->nb_columns);
02352   osl_relation_replace_constraints(new, r1, 0);
02353   osl_relation_replace_constraints(new, r2, r1->nb_rows);
02354 
02355   return new;
02356 }
02357 
02358 
02368 int osl_relation_part_equal(osl_relation_p r1, osl_relation_p r2) {
02369   int i, j;
02370 
02371   if (r1 == r2)
02372     return 1;
02373 
02374   if (((r1 == NULL) && (r2 != NULL)) ||
02375       ((r1 != NULL) && (r2 == NULL)))
02376     return 0;
02377 
02378   if ((r1->type           != r2->type)           ||
02379       (r1->precision      != r2->precision)      ||
02380       (r1->nb_rows        != r2->nb_rows)        ||
02381       (r1->nb_columns     != r2->nb_columns)     ||
02382       (r1->nb_output_dims != r2->nb_output_dims) ||
02383       (r1->nb_input_dims  != r2->nb_input_dims)  ||
02384       (r1->nb_local_dims  != r2->nb_local_dims)  ||
02385       (r1->nb_parameters  != r2->nb_parameters))
02386     return 0;
02387 
02388   for (i = 0; i < r1->nb_rows; ++i)
02389     for (j = 0; j < r1->nb_columns; ++j)
02390       if (osl_int_ne(r1->precision, r1->m[i][j], r2->m[i][j]))
02391         return 0;
02392 
02393   return 1;
02394 }
02395 
02396 
02405 int osl_relation_equal(osl_relation_p r1, osl_relation_p r2) {
02406   while ((r1 != NULL) && (r2 != NULL)) {
02407     if (!osl_relation_part_equal(r1, r2))
02408       return 0;
02409 
02410     r1 = r1->next;
02411     r2 = r2->next;
02412   }
02413   
02414   if (((r1 == NULL) && (r2 != NULL)) || ((r1 != NULL) && (r2 == NULL)))
02415     return 0;
02416   
02417   return 1;
02418 }
02419 
02420 
02434 static
02435 int osl_relation_check_attribute(int * expected, int actual) {
02436   if (*expected != OSL_UNDEFINED) { 
02437     if ((actual != OSL_UNDEFINED) &&
02438         (actual != *expected)) {
02439       OSL_warning("unexpected atribute");
02440       return 0;
02441     }
02442   }
02443   else {
02444     *expected = actual;
02445   }
02446 
02447   return 1;
02448 }
02449 
02450 
02464 static
02465 int osl_relation_check_nb_columns(osl_relation_p relation,
02466                                   int expected_nb_output_dims,
02467                                   int expected_nb_input_dims,
02468                                   int expected_nb_parameters) {
02469   int expected_nb_local_dims, expected_nb_columns;
02470   
02471   if ((expected_nb_output_dims != OSL_UNDEFINED) &&
02472       (expected_nb_input_dims  != OSL_UNDEFINED) &&
02473       (expected_nb_parameters  != OSL_UNDEFINED)) {
02474     
02475     if (relation->nb_local_dims == OSL_UNDEFINED)
02476       expected_nb_local_dims = 0;
02477     else
02478       expected_nb_local_dims = relation->nb_local_dims;
02479 
02480     expected_nb_columns = expected_nb_output_dims +
02481                           expected_nb_input_dims  +
02482                           expected_nb_local_dims  +
02483                           expected_nb_parameters  +
02484                           2;
02485     
02486     if (expected_nb_columns != relation->nb_columns) {
02487       OSL_warning("unexpected number of columns");
02488       return 0;
02489     }
02490   }
02491 
02492   return 1;
02493 }
02494 
02495 
02510 int osl_relation_integrity_check(osl_relation_p relation,
02511                                  int expected_type,
02512                                  int expected_nb_output_dims,
02513                                  int expected_nb_input_dims,
02514                                  int expected_nb_parameters) {
02515   int i;
02516 
02517   // Check the NULL case.
02518   if (relation == NULL) {
02519     if ((expected_nb_output_dims != OSL_UNDEFINED) ||
02520         (expected_nb_input_dims  != OSL_UNDEFINED) ||
02521         (expected_nb_parameters  != OSL_UNDEFINED)) {
02522       OSL_debug("NULL relation with some expected attibutes");
02523       //return 0;
02524     }
02525 
02526     return 1;
02527   }
02528 
02529   // Check the type.
02530   if (((expected_type != OSL_TYPE_ACCESS) &&
02531        (expected_type != relation->type)) ||
02532       ((expected_type == OSL_TYPE_ACCESS) &&
02533        (!osl_relation_is_access(relation)))) {
02534     OSL_warning("wrong type");
02535     osl_relation_dump(stderr, relation);
02536     return 0;
02537   }
02538 
02539   // Check that relations have no undefined atributes.
02540   if ((relation->nb_output_dims == OSL_UNDEFINED) ||
02541       (relation->nb_input_dims  == OSL_UNDEFINED) ||
02542       (relation->nb_local_dims  == OSL_UNDEFINED) ||
02543       (relation->nb_parameters  == OSL_UNDEFINED)) {
02544     OSL_warning("all attributes should be defined");
02545     osl_relation_dump(stderr, relation);
02546     return 0;
02547   }
02548 
02549   // Check that a context has actually 0 output dimensions.
02550   if ((relation->type == OSL_TYPE_CONTEXT) &&
02551       (relation->nb_output_dims != 0)) {
02552     OSL_warning("context without 0 as number of output dimensions");
02553     osl_relation_dump(stderr, relation);
02554     return 0;
02555   }
02556 
02557   // Check that a domain or a context has actually 0 input dimensions.
02558   if (((relation->type == OSL_TYPE_DOMAIN) ||
02559        (relation->type == OSL_TYPE_CONTEXT)) &&
02560       (relation->nb_input_dims != 0)) {
02561     OSL_warning("domain or context without 0 input dimensions");
02562     osl_relation_dump(stderr, relation);
02563     return 0;
02564   }
02565 
02566   // Check properties according to expected values (and if expected values
02567   // are undefined, define them with the first relation part properties).
02568   if (!osl_relation_check_attribute(&expected_nb_output_dims,
02569                                     relation->nb_output_dims) ||
02570       !osl_relation_check_attribute(&expected_nb_input_dims,
02571                                     relation->nb_input_dims)  ||
02572       !osl_relation_check_attribute(&expected_nb_parameters,
02573                                     relation->nb_parameters)) {
02574     osl_relation_dump(stderr, relation);
02575     return 0;
02576   }
02577 
02578   while (relation != NULL) {
02579 
02580     // Attributes (except the number of local dimensions) should be the same
02581     // in all parts of the union.
02582     if ((expected_nb_output_dims != relation->nb_output_dims) ||
02583         (expected_nb_input_dims  != relation->nb_input_dims)  ||
02584         (expected_nb_parameters  != relation->nb_parameters)) {
02585       OSL_warning("inconsistent attributes");
02586       osl_relation_dump(stderr, relation);
02587       return 0;
02588     }
02589    
02590     // Check whether the number of columns is OK or not.
02591     if (!osl_relation_check_nb_columns(relation,
02592                                        expected_nb_output_dims,
02593                                        expected_nb_input_dims,
02594                                        expected_nb_parameters)) {
02595       osl_relation_dump(stderr, relation);
02596       return 0;
02597     }
02598 
02599     // Check the first column. The first column of a relation part should be
02600     // made of 0 or 1 only.
02601     if ((relation->nb_rows > 0) && (relation->nb_columns > 0)) {
02602       for (i = 0; i < relation->nb_rows; i++) {
02603         if (!osl_int_zero(relation->precision, relation->m[i][0]) &&
02604             !osl_int_one(relation->precision, relation->m[i][0])) {
02605           OSL_warning("first column of a relation is not "
02606                            "strictly made of 0 or 1");
02607           osl_relation_dump(stderr, relation);
02608           return 0;
02609         }
02610       }
02611     }
02612 
02613     // Array accesses must provide the array identifier.
02614     if ((osl_relation_is_access(relation)) &&
02615         (osl_relation_get_array_id(relation) == OSL_UNDEFINED)) {
02616       osl_relation_dump(stderr, relation);
02617       return 0;
02618     }
02619 
02620     relation = relation->next;
02621   }
02622 
02623   return 1;
02624 }
02625 
02626 
02637 void osl_relation_set_attributes_one(osl_relation_p relation,
02638                                      int nb_output_dims, int nb_input_dims,
02639                                      int nb_local_dims,  int nb_parameters) {
02640   if (relation != NULL) {
02641     relation->nb_output_dims = nb_output_dims;
02642     relation->nb_input_dims  = nb_input_dims;
02643     relation->nb_local_dims  = nb_local_dims;
02644     relation->nb_parameters  = nb_parameters;
02645   }
02646 }
02647 
02648 
02659 void osl_relation_set_attributes(osl_relation_p relation,
02660                                  int nb_output_dims, int nb_input_dims,
02661                                  int nb_local_dims,  int nb_parameters) {
02662   while (relation != NULL) {
02663     osl_relation_set_attributes_one(relation,
02664                                     nb_output_dims, nb_input_dims,
02665                                     nb_local_dims,  nb_parameters);
02666     relation = relation->next;
02667   }
02668 }
02669 
02670 
02678 void osl_relation_set_type(osl_relation_p relation, int type) {
02679 
02680   while (relation != NULL) {
02681     relation->type = type;
02682     relation = relation->next;
02683   }
02684 }
02685 
02686 
02695 int osl_relation_get_array_id(osl_relation_p relation) {
02696   int i;
02697   int first = 1;
02698   int array_id = OSL_UNDEFINED;
02699   int reference_array_id = OSL_UNDEFINED;
02700   int nb_array_id;
02701   int row_id = 0;
02702   int precision;
02703 
02704   if (relation == NULL)
02705     return OSL_UNDEFINED;
02706   
02707   if (!osl_relation_is_access(relation)) {
02708     OSL_warning("asked for an array id of non-array relation");
02709     return OSL_UNDEFINED;
02710   }
02711   
02712   while (relation != NULL) {
02713     precision = relation->precision;
02714 
02715     // There should be room to store the array identifier.
02716     if ((relation->nb_rows < 1) ||
02717         (relation->nb_columns < 3)) {
02718       OSL_warning("no array identifier in an access function");
02719       return OSL_UNDEFINED;
02720     }
02721 
02722     // Array identifiers are m[i][#columns -1] / m[i][1], with i the only row
02723     // where m[i][1] is not 0.
02724     // - check there is exactly one row such that m[i][1] is not 0,
02725     // - check the whole ith row if full of 0 except m[i][1] and the id,
02726     // - check that (m[i][#columns -1] % m[i][1]) == 0,
02727     // - check that (-m[i][#columns -1] / m[i][1]) > 0.
02728     nb_array_id = 0;
02729     for (i = 0; i < relation->nb_rows; i++) {
02730       if (!osl_int_zero(precision, relation->m[i][1])) {
02731         nb_array_id ++;
02732         row_id = i;
02733       }
02734     }
02735     if (nb_array_id == 0) {
02736       OSL_warning("no array identifier in an access function");
02737       return OSL_UNDEFINED;
02738     }
02739     if (nb_array_id > 1) {
02740       OSL_warning("several array identifiers in one access function");
02741       return OSL_UNDEFINED;
02742     }
02743     for (i = 0; i < relation->nb_columns - 1; i++) {
02744       if ((i != 1) && !osl_int_zero(precision, relation->m[row_id][i])) {
02745         OSL_warning("non integer array identifier");
02746         return OSL_UNDEFINED;
02747       }
02748     }
02749     if (!osl_int_divisible(precision,
02750                            relation->m[row_id][relation->nb_columns - 1],
02751                            relation->m[row_id][1])) {
02752       OSL_warning("rational array identifier");
02753       return OSL_UNDEFINED;
02754     }
02755     array_id = -osl_int_get_si(precision,
02756                                relation->m[row_id][relation->nb_columns - 1]);
02757     array_id /= osl_int_get_si(precision, relation->m[row_id][1]);
02758     if (array_id <= 0) {
02759       OSL_warning("negative or 0 identifier in access function");
02760       return OSL_UNDEFINED;
02761     }
02762 
02763     // Unions of accesses are allowed, but they should refer at the same array.
02764     if (first) {
02765       reference_array_id = array_id;
02766       first = 0;
02767     }
02768     else {
02769       if (reference_array_id != array_id) {
02770         OSL_warning("inconsistency of array identifiers in an "
02771                     "union of access relations");
02772         return OSL_UNDEFINED;
02773       }
02774     }
02775     
02776     relation = relation->next;
02777   }
02778 
02779   return array_id;
02780 }
02781 
02782 
02790 int osl_relation_is_access(osl_relation_p relation) {
02791 
02792   if (relation == NULL)
02793     return 0;
02794   
02795   if ((relation->type == OSL_TYPE_ACCESS)    ||
02796       (relation->type == OSL_TYPE_READ)      ||
02797       (relation->type == OSL_TYPE_WRITE)     ||
02798       (relation->type == OSL_TYPE_MAY_WRITE))
02799     return 1;
02800 
02801   return 0;
02802 }
02803 
02804 
02823 void osl_relation_get_attributes(osl_relation_p relation,
02824                                  int * nb_parameters,
02825                                  int * nb_iterators,
02826                                  int * nb_scattdims,
02827                                  int * nb_localdims,
02828                                  int * array_id) {
02829   int type;
02830   int local_nb_parameters = OSL_UNDEFINED;
02831   int local_nb_iterators  = OSL_UNDEFINED;
02832   int local_nb_scattdims  = OSL_UNDEFINED;
02833   int local_nb_localdims  = OSL_UNDEFINED;
02834   int local_array_id      = OSL_UNDEFINED;
02835 
02836   while (relation != NULL) {
02837     if (osl_relation_is_access(relation))
02838       type = OSL_TYPE_ACCESS;
02839     else
02840       type = relation->type;
02841 
02842     // There is some redundancy but I believe the code is cleaner this way.
02843     switch (type) {
02844       case OSL_TYPE_CONTEXT:
02845         local_nb_parameters = relation->nb_parameters;
02846         local_nb_iterators  = 0;
02847         local_nb_scattdims  = 0;
02848         local_nb_localdims  = relation->nb_local_dims;
02849         local_array_id      = 0;
02850         break;
02851 
02852       case OSL_TYPE_DOMAIN:
02853         local_nb_parameters = relation->nb_parameters;
02854         local_nb_iterators  = relation->nb_output_dims;
02855         local_nb_scattdims  = 0;
02856         local_nb_localdims  = relation->nb_local_dims;
02857         local_array_id      = 0;
02858         break;
02859 
02860       case OSL_TYPE_SCATTERING:
02861         local_nb_parameters = relation->nb_parameters;
02862         local_nb_iterators  = relation->nb_input_dims;
02863         local_nb_scattdims  = relation->nb_output_dims;
02864         local_nb_localdims  = relation->nb_local_dims;
02865         local_array_id      = 0;
02866         break;
02867 
02868       case OSL_TYPE_ACCESS:
02869         local_nb_parameters = relation->nb_parameters;
02870         local_nb_iterators  = relation->nb_input_dims;
02871         local_nb_scattdims  = 0;
02872         local_nb_localdims  = relation->nb_local_dims;
02873         local_array_id      = osl_relation_get_array_id(relation);
02874         break;
02875 
02876       default:
02877         local_nb_parameters = relation->nb_parameters;
02878         local_nb_iterators  = relation->nb_input_dims;
02879         local_nb_scattdims  = relation->nb_output_dims;
02880         local_nb_localdims  = relation->nb_local_dims;
02881         local_array_id      = 0;
02882     }
02883 
02884     // Update.
02885     *nb_parameters = OSL_max(*nb_parameters, local_nb_parameters);
02886     *nb_iterators  = OSL_max(*nb_iterators,  local_nb_iterators);
02887     *nb_scattdims  = OSL_max(*nb_scattdims,  local_nb_scattdims);
02888     *nb_localdims  = OSL_max(*nb_localdims,  local_nb_localdims);
02889     *array_id      = OSL_max(*array_id,      local_array_id);
02890     relation = relation->next;
02891   }
02892 }
02893 
02894 
02906 osl_relation_p osl_relation_extend_output(osl_relation_p relation, int dim) {
02907   int i, j;
02908   int first = 1;
02909   int offset;
02910   int precision = relation->precision;
02911   osl_relation_p extended = NULL, node, previous = NULL;
02912 
02913   while (relation != NULL) {
02914     if (relation->nb_output_dims > dim)
02915       OSL_error("Number of output dims is greater than required extension");
02916     offset = dim - relation->nb_output_dims;
02917     
02918     node = osl_relation_pmalloc(precision,
02919                                 relation->nb_rows + offset,
02920                                 relation->nb_columns + offset);
02921     
02922     node->type           = relation->type;
02923     node->nb_output_dims = OSL_max(relation->nb_output_dims, dim);
02924     node->nb_input_dims  = relation->nb_input_dims;
02925     node->nb_local_dims  = relation->nb_local_dims;
02926     node->nb_parameters  = relation->nb_parameters;
02927 
02928     // Copy of the original relation with some 0 columns for the new dimensions
02929     // Note that we use the fact that the matrix is initialized with zeros.
02930     for (i = 0; i < relation->nb_rows; i++) {
02931       for (j = 0; j <= relation->nb_output_dims; j++)
02932         osl_int_assign(precision, &node->m[i][j], relation->m[i][j]);
02933 
02934       for (j = relation->nb_output_dims + offset + 1;
02935            j < relation->nb_columns + offset; j++)
02936         osl_int_assign(precision, &node->m[i][j], relation->m[i][j - offset]);
02937     }
02938 
02939     // New rows dedicated to the new dimensions
02940     for (i = relation->nb_rows; i < relation->nb_rows + offset; i++) {
02941       for (j = 0; j < relation->nb_columns + offset; j++) {
02942         if ((i - relation->nb_rows) == (j - relation->nb_output_dims - 1))
02943           osl_int_set_si(precision, &node->m[i][j], -1);
02944       }
02945     }
02946 
02947     if (first) {
02948       first = 0;
02949       extended = node;
02950       previous = node;
02951     }
02952     else {
02953       previous->next = node;
02954       previous = previous->next;
02955     }
02956 
02957     relation = relation->next;
02958   }
02959   
02960   return extended;
02961 }
02962 
02963 
02970 osl_interface_p osl_relation_interface() {
02971   osl_interface_p interface = osl_interface_malloc();
02972   
02973   OSL_strdup(interface->URI, OSL_URI_RELATION);
02974   interface->idump  = (osl_idump_f)osl_relation_idump;
02975   interface->sprint = (osl_sprint_f)osl_relation_sprint;
02976   interface->sread  = (osl_sread_f)osl_relation_sread;
02977   interface->malloc = (osl_malloc_f)osl_relation_malloc;
02978   interface->free   = (osl_free_f)osl_relation_free;
02979   interface->clone  = (osl_clone_f)osl_relation_clone;
02980   interface->equal  = (osl_equal_f)osl_relation_equal;
02981 
02982   return interface;
02983 }