Merge branch 'osl_strings_add_strings+osl_generic_nclone' of https://github.com/Haere...
[openscop.git] / source / relation.c
blob5b7f7cc19f524f2b98aebc11975de1b9b64f3ad0
2 /*+-----------------------------------------------------------------**
3 ** OpenScop Library **
4 **-----------------------------------------------------------------**
5 ** relation.c **
6 **-----------------------------------------------------------------**
7 ** First version: 30/04/2008 **
8 **-----------------------------------------------------------------**
11 *****************************************************************************
12 * OpenScop: Structures and formats for polyhedral tools to talk together *
13 *****************************************************************************
14 * ,___,,_,__,,__,,__,,__,,_,__,,_,__,,__,,___,_,__,,_,__, *
15 * / / / // // // // / / / // // / / // / /|,_, *
16 * / / / // // // // / / / // // / / // / / / /\ *
17 * |~~~|~|~~~|~~~|~~~|~~~|~|~~~|~|~~~|~~~|~~~|~|~~~|~|~~~|/_/ \ *
18 * | G |C| P | = | L | P |=| = |C| = | = | = |=| = |=| C |\ \ /\ *
19 * | R |l| o | = | e | l |=| = |a| = | = | = |=| = |=| L | \# \ /\ *
20 * | A |a| l | = | t | u |=| = |n| = | = | = |=| = |=| o | |\# \ \ *
21 * | P |n| l | = | s | t |=| = |d| = | = | = | | |=| o | | \# \ \ *
22 * | H | | y | | e | o | | = |l| | | = | | | | G | | \ \ \ *
23 * | I | | | | e | | | | | | | | | | | | | \ \ \ *
24 * | T | | | | | | | | | | | | | | | | | \ \ \ *
25 * | E | | | | | | | | | | | | | | | | | \ \ \ *
26 * | * |*| * | * | * | * |*| * |*| * | * | * |*| * |*| * | / \* \ \ *
27 * | O |p| e | n | S | c |o| p |-| L | i | b |r| a |r| y |/ \ \ / *
28 * '---'-'---'---'---'---'-'---'-'---'---'---'-'---'-'---' '--' *
29 * *
30 * Copyright (C) 2008 University Paris-Sud 11 and INRIA *
31 * *
32 * (3-clause BSD license) *
33 * Redistribution and use in source and binary forms, with or without *
34 * modification, are permitted provided that the following conditions *
35 * are met: *
36 * *
37 * 1. Redistributions of source code must retain the above copyright notice, *
38 * this list of conditions and the following disclaimer. *
39 * 2. Redistributions in binary form must reproduce the above copyright *
40 * notice, this list of conditions and the following disclaimer in the *
41 * documentation and/or other materials provided with the distribution. *
42 * 3. The name of the author may not be used to endorse or promote products *
43 * derived from this software without specific prior written permission. *
44 * *
45 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR *
46 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES *
47 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. *
48 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, *
49 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT *
50 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, *
51 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY *
52 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
53 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF *
54 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
55 * *
56 * OpenScop Library, a library to manipulate OpenScop formats and data *
57 * structures. Written by: *
58 * Cedric Bastoul <Cedric.Bastoul@u-psud.fr> and *
59 * Louis-Noel Pouchet <Louis-Noel.pouchet@inria.fr> *
60 * *
61 *****************************************************************************/
64 #include <stdlib.h>
65 #include <stdio.h>
66 #include <string.h>
67 #include <ctype.h>
69 #include <osl/macros.h>
70 #include <osl/int.h>
71 #include <osl/util.h>
72 #include <osl/vector.h>
73 #include <osl/strings.h>
74 #include <osl/names.h>
75 #include <osl/relation.h>
78 /*+***************************************************************************
79 * Structure display function *
80 *****************************************************************************/
83 /**
84 * osl_relation_sprint_type function:
85 * this function prints the textual type of an osl_relation_t structure into
86 * a string, according to the OpenScop specification, and returns that string.
87 * \param[in] relation The relation whose type has to be printed.
88 * \return A string containing the relation type.
90 static
91 char * osl_relation_sprint_type(osl_relation_p relation) {
92 char * string = NULL;
94 OSL_malloc(string, char *, OSL_MAX_STRING * sizeof(char));
95 string[0] = '\0';
97 if (relation != NULL) {
98 switch (relation->type) {
99 case OSL_UNDEFINED: {
100 snprintf(string, OSL_MAX_STRING, OSL_STRING_UNDEFINED);
101 break;
103 case OSL_TYPE_CONTEXT: {
104 snprintf(string, OSL_MAX_STRING, OSL_STRING_CONTEXT);
105 break;
107 case OSL_TYPE_DOMAIN: {
108 snprintf(string, OSL_MAX_STRING, OSL_STRING_DOMAIN);
109 break;
111 case OSL_TYPE_SCATTERING: {
112 snprintf(string, OSL_MAX_STRING, OSL_STRING_SCATTERING);
113 break;
115 case OSL_TYPE_READ: {
116 snprintf(string, OSL_MAX_STRING, OSL_STRING_READ);
117 break;
119 case OSL_TYPE_WRITE: {
120 snprintf(string, OSL_MAX_STRING, OSL_STRING_WRITE);
121 break;
123 case OSL_TYPE_MAY_WRITE: {
124 snprintf(string, OSL_MAX_STRING, OSL_STRING_MAY_WRITE);
125 break;
127 default: {
128 OSL_warning("unknown relation type, "
129 "replaced with "OSL_STRING_UNDEFINED);
130 snprintf(string, OSL_MAX_STRING, OSL_STRING_UNDEFINED);
135 return string;
140 * osl_relation_print_type function:
141 * this function displays the textual type of an osl_relation_t structure into
142 * a file (file, possibly stdout), according to the OpenScop specification.
143 * \param[in] file File where informations are printed.
144 * \param[in] relation The relation whose type has to be printed.
146 static
147 void osl_relation_print_type(FILE * file, osl_relation_p relation) {
148 char * string = osl_relation_sprint_type(relation);
149 fprintf(file, "%s", string);
150 free(string);
155 * osl_relation_idump function:
156 * this function displays a osl_relation_t structure (*relation) into a
157 * file (file, possibly stdout) in a way that trends to be understandable.
158 * It includes an indentation level (level) in order to work with others
159 * idump functions.
160 * \param[in] file File where informations are printed.
161 * \param[in] relation The relation whose information has to be printed.
162 * \param[in] level Number of spaces before printing, for each line.
164 void osl_relation_idump(FILE * file, osl_relation_p relation, int level) {
165 int i, j, first = 1;
167 // Go to the right level.
168 for (j = 0; j < level; j++)
169 fprintf(file, "|\t");
171 if (relation != NULL) {
172 fprintf(file, "+-- osl_relation_t (");
173 osl_relation_print_type(file, relation);
174 fprintf(file, ", ");
175 osl_int_dump_precision(file, relation->precision);
176 fprintf(file, ")\n");
178 else {
179 fprintf(file, "+-- NULL relation\n");
182 while (relation != NULL) {
183 if (! first) {
184 // Go to the right level.
185 for (j = 0; j < level; j++)
186 fprintf(file, "|\t");
187 fprintf(file, "| osl_relation_t (");
188 osl_relation_print_type(file, relation);
189 fprintf(file, ", ");
190 osl_int_dump_precision(file, relation->precision);
191 fprintf(file, ")\n");
193 else
194 first = 0;
196 // A blank line
197 for(j = 0; j <= level; j++)
198 fprintf(file, "|\t");
199 fprintf(file, "%d %d %d %d %d %d\n",
200 relation->nb_rows, relation->nb_columns,
201 relation->nb_output_dims, relation->nb_input_dims,
202 relation->nb_local_dims, relation->nb_parameters);
204 // Display the relation.
205 for (i = 0; i < relation->nb_rows; i++) {
206 for (j = 0; j <= level; j++)
207 fprintf(file, "|\t");
209 fprintf(file, "[ ");
211 for (j = 0; j < relation->nb_columns; j++) {
212 osl_int_print(file, relation->precision, relation->m[i][j]);
213 fprintf(file, " ");
216 fprintf(file, "]\n");
219 relation = relation->next;
221 // Next line.
222 if (relation != NULL) {
223 for (j = 0; j <= level; j++)
224 fprintf(file, "|\t");
225 fprintf(file, "|\n");
226 for (j = 0; j <= level; j++)
227 fprintf(file, "|\t");
228 fprintf(file, "V\n");
232 // The last line.
233 for (j = 0; j <= level; j++)
234 fprintf(file, "|\t");
235 fprintf(file, "\n");
240 * osl_relation_dump function:
241 * this function prints the content of a osl_relation_t structure
242 * (*relation) into a file (file, possibly stdout).
243 * \param[in] file File where informations are printed.
244 * \param[in] relation The relation whose information have to be printed.
246 void osl_relation_dump(FILE * file, osl_relation_p relation) {
247 osl_relation_idump(file, relation, 0);
252 * osl_relation_expression_element function:
253 * this function returns a string containing the printing of a value (e.g.,
254 * an iterator with its coefficient or a constant).
255 * \param[in] val Coefficient or constant value.
256 * \param[in] precision The precision of the value.
257 * \param[in,out] first Pointer to a boolean set to 1 if the current value
258 * is the first of an expresion, 0 otherwise (maybe
259 * updated).
260 * \param[in] cst A boolean set to 1 if the value is a constant,
261 * 0 otherwise.
262 * \param[in] name String containing the name of the element.
263 * \return A string that contains the printing of a value.
265 static
266 char * osl_relation_expression_element(osl_int_t val,
267 int precision, int * first,
268 int cst, char * name) {
269 char * temp, * body, * sval;
271 OSL_malloc(temp, char *, OSL_MAX_STRING * sizeof(char));
272 OSL_malloc(body, char *, OSL_MAX_STRING * sizeof(char));
273 OSL_malloc(sval, char *, OSL_MAX_STRING * sizeof(char));
275 body[0] = '\0';
276 sval[0] = '\0';
278 // statements for the 'normal' processing.
279 if (!osl_int_zero(precision, val) && (!cst)) {
280 if ((*first) || osl_int_neg(precision, val)) {
281 if (osl_int_one(precision, val)) { // case 1
282 sprintf(sval, "%s", name);
284 else {
285 if (osl_int_mone(precision, val)) { // case -1
286 sprintf(sval, "-%s", name);
288 else { // default case
289 osl_int_sprint_txt(sval, precision, val);
290 sprintf(temp, "*%s", name);
291 strcat(sval, temp);
294 *first = 0;
296 else {
297 if (osl_int_one(precision, val)) {
298 sprintf(sval, "+%s", name);
300 else {
301 sprintf(sval, "+");
302 osl_int_sprint_txt(temp, precision, val);
303 strcat(sval, temp);
304 sprintf(temp, "*%s", name);
305 strcat(sval, temp);
309 else {
310 if (cst) {
311 if ((osl_int_zero(precision, val) && (*first)) ||
312 (osl_int_neg(precision, val)))
313 osl_int_sprint_txt(sval, precision, val);
314 if (osl_int_pos(precision, val)) {
315 if (!(*first)) {
316 sprintf(sval, "+");
317 osl_int_sprint_txt(temp, precision, val);
318 strcat(sval, temp);
320 else {
321 osl_int_sprint_txt(sval, precision, val);
326 free(temp);
327 free(body);
329 return(sval);
334 * osl_relation_strings function:
335 * this function creates a NULL-terminated array of strings from an
336 * osl_names_t structure in such a way that the ith string is the "name"
337 * corresponding to the ith column of the constraint matrix.
338 * \param[in] relation The relation for which we need an array of names.
339 * \param[in] names The set of names for each element.
340 * \return An array of strings with one string per constraint matrix column.
342 static
343 char ** osl_relation_strings(osl_relation_p relation, osl_names_p names) {
344 char ** strings;
345 char temp[OSL_MAX_STRING];
346 int i, offset;
348 if ((relation == NULL) || (names == NULL)) {
349 OSL_debug("no names or relation to build the name array");
350 return NULL;
353 OSL_malloc(strings, char **, (relation->nb_columns + 1)*sizeof(char *));
354 strings[relation->nb_columns] = NULL;
356 // 1. Equality/inequality marker.
357 OSL_strdup(strings[0], "e/i");
358 offset = 1;
360 // 2. Output dimensions.
361 if (osl_relation_is_access(relation)) {
362 // The first output dimension is the array name.
363 OSL_strdup(strings[offset], "Arr");
364 // The other ones are the array dimensions [1]...[n]
365 for (i = offset + 1; i < relation->nb_output_dims + offset; i++) {
366 sprintf(temp, "[%d]", i - 1);
367 OSL_strdup(strings[i], temp);
370 else
371 if ((relation->type == OSL_TYPE_DOMAIN) ||
372 (relation->type == OSL_TYPE_CONTEXT)) {
373 for (i = offset; i < relation->nb_output_dims + offset; i++) {
374 OSL_strdup(strings[i], names->iterators->string[i - offset]);
377 else {
378 for (i = offset; i < relation->nb_output_dims + offset; i++) {
379 OSL_strdup(strings[i], names->scatt_dims->string[i - offset]);
382 offset += relation->nb_output_dims;
384 // 3. Input dimensions.
385 for (i = offset; i < relation->nb_input_dims + offset; i++)
386 OSL_strdup(strings[i], names->iterators->string[i - offset]);
387 offset += relation->nb_input_dims;
389 // 4. Local dimensions.
390 for (i = offset; i < relation->nb_local_dims + offset; i++)
391 OSL_strdup(strings[i], names->local_dims->string[i - offset]);
392 offset += relation->nb_local_dims;
394 // 5. Parameters.
395 for (i = offset; i < relation->nb_parameters + offset; i++)
396 OSL_strdup(strings[i], names->parameters->string[i - offset]);
397 offset += relation->nb_parameters;
399 // 6. Scalar.
400 OSL_strdup(strings[offset], "1");
402 return strings;
407 * osl_relation_subexpression function:
408 * this function returns a string corresponding to an affine (sub-)expression
409 * stored at the "row"^th row of the relation pointed by "relation" between
410 * the start and stop columns. Optionally it may oppose the whole expression.
411 * \param[in] relation A set of linear expressions.
412 * \param[in] row The row corresponding to the expression.
413 * \param[in] start The first column for the expression (inclusive).
414 * \param[in] stop The last column for the expression (inclusive).
415 * \param[in] oppose Boolean set to 1 to negate the expression, 0 otherwise.
416 * \param[in] strings Array of textual names of the various elements.
417 * \return A string that contains the printing of an affine (sub-)expression.
419 static
420 char * osl_relation_subexpression(osl_relation_p relation,
421 int row, int start, int stop, int oppose,
422 char ** strings) {
423 int i, first = 1, constant;
424 char * sval;
425 char * sline;
427 OSL_malloc(sline, char *, OSL_MAX_STRING * sizeof(char));
428 sline[0] = '\0';
430 // Create the expression. The constant is a special case.
431 for (i = start; i <= stop; i++) {
432 if (oppose) {
433 osl_int_oppose(relation->precision,
434 &relation->m[row][i], relation->m[row][i]);
437 if (i == relation->nb_columns - 1)
438 constant = 1;
439 else
440 constant = 0;
442 sval = osl_relation_expression_element(relation->m[row][i],
443 relation->precision, &first, constant, strings[i]);
445 if (oppose) {
446 osl_int_oppose(relation->precision,
447 &relation->m[row][i], relation->m[row][i]);
449 strcat(sline, sval);
450 free(sval);
453 return sline;
458 * osl_relation_expression function:
459 * this function returns a string corresponding to an affine expression
460 * stored at the "row"^th row of the relation pointed by "relation".
461 * \param[in] relation A set of linear expressions.
462 * \param[in] row The row corresponding to the expression.
463 * \param[in] strings Array of textual names of the various elements.
464 * \return A string that contains the printing of an affine expression.
466 char * osl_relation_expression(osl_relation_p relation,
467 int row, char ** strings) {
469 return osl_relation_subexpression(relation, row,
470 1, relation->nb_columns - 1, 0,
471 strings);
476 * osl_relation_is_simple_output function:
477 * this function returns 1 or -1 if a given constraint row of a relation
478 * corresponds to an output, 0 otherwise. We call a simple output an equality
479 * constraint where exactly one output coefficient is not 0 and is either
480 * 1 (in this case the function returns 1) or -1 (in this case the function
481 * returns -1).
482 * \param[in] relation The relation to test for simple output.
483 * \param[in] row The row corresponding to the constraint to test.
484 * \return 1 or -1 if the row is a simple output, 0 otherwise.
486 static
487 int osl_relation_is_simple_output(osl_relation_p relation, int row) {
488 int i;
489 int first = 1;
490 int sign = 0;
492 if ((relation == NULL) ||
493 (relation->m == NULL) ||
494 (relation->nb_output_dims == 0))
495 return 0;
497 if ((row < 0) || (row > relation->nb_rows))
498 OSL_error("the specified row does not exist in the relation");
500 // The constraint must be an equality.
501 if (!osl_int_zero(relation->precision, relation->m[row][0]))
502 return 0;
504 // Check the output part has one and only one non-zero +1 or -1 coefficient.
505 first = 1;
506 for (i = 1; i <= relation->nb_output_dims; i++) {
507 if (!osl_int_zero(relation->precision, relation->m[row][i])) {
508 if (first)
509 first = 0;
510 else
511 return 0;
513 if (osl_int_one(relation->precision, relation->m[row][i]))
514 sign = 1;
515 else if (osl_int_mone(relation->precision, relation->m[row][i]))
516 sign = -1;
517 else
518 return 0;
522 return sign;
527 * osl_relation_sprint_comment function:
528 * this function prints into a string a comment corresponding to a constraint
529 * of a relation, according to its type, then it returns this string. This
530 * function does not check that printing the comment is possible (i.e., are
531 * there enough names ?), hence it is the responsibility of the user to ensure
532 * he/she can call this function safely.
533 * \param[in] relation The relation for which a comment has to be printed.
534 * \param[in] row The constrain row for which a comment has to be printed.
535 * \param[in] strings Array of textual names of the various elements.
536 * \param[in] arrays Array of textual identifiers of the arrays.
537 * \return A string which contains the comment for the row.
539 static
540 char * osl_relation_sprint_comment(osl_relation_p relation, int row,
541 char ** strings, char ** arrays) {
542 int sign;
543 int high_water_mark = OSL_MAX_STRING;
544 char * string = NULL;
545 char * expression;
546 char buffer[OSL_MAX_STRING];
548 OSL_malloc(string, char *, high_water_mark * sizeof(char));
549 string[0] = '\0';
551 if ((relation == NULL) || (strings == NULL)) {
552 OSL_debug("no relation or names while asked to print a comment");
553 return string;
556 if ((sign = osl_relation_is_simple_output(relation, row))) {
557 // First case : output == expression.
559 expression = osl_relation_subexpression(relation, row,
560 1, relation->nb_output_dims,
561 sign < 0,
562 strings);
563 snprintf(buffer, OSL_MAX_STRING, " ## %s", expression);
564 osl_util_safe_strcat(&string, buffer, &high_water_mark);
565 free(expression);
567 // We don't print the right hand side if it's an array identifier.
568 if (!osl_relation_is_access(relation) ||
569 osl_int_zero(relation->precision, relation->m[row][1])) {
570 expression = osl_relation_subexpression(relation, row,
571 relation->nb_output_dims + 1,
572 relation->nb_columns - 1,
573 sign > 0,
574 strings);
575 snprintf(buffer, OSL_MAX_STRING, " == %s", expression);
576 osl_util_safe_strcat(&string, buffer, &high_water_mark);
577 free(expression);
579 else {
580 snprintf(buffer, OSL_MAX_STRING, " == %s",
581 arrays[osl_relation_get_array_id(relation) - 1]);
582 osl_util_safe_strcat(&string, buffer, &high_water_mark);
585 else {
586 // Second case : general case.
588 expression = osl_relation_expression(relation, row, strings);
589 snprintf(buffer, OSL_MAX_STRING, " ## %s", expression);
590 osl_util_safe_strcat(&string, buffer, &high_water_mark);
591 free(expression);
593 if (osl_int_zero(relation->precision, relation->m[row][0]))
594 snprintf(buffer, OSL_MAX_STRING, " == 0");
595 else
596 snprintf(buffer, OSL_MAX_STRING, " >= 0");
597 osl_util_safe_strcat(&string, buffer, &high_water_mark);
600 return string;
605 * osl_relation_column_string function:
606 * this function returns an OpenScop comment string showing all column
607 * names. It is designed to nicely fit a constraint matrix that would be
608 * printed just below this line.
609 * \param[in] relation The relation related to the comment line to build.
610 * \param[in] strings Array of textual names of the various elements.
611 * \return A fancy comment string with all the dimension names.
613 static
614 char * osl_relation_column_string(osl_relation_p relation, char ** strings) {
615 int i, j;
616 int index_output_dims;
617 int index_input_dims;
618 int index_local_dims;
619 int index_parameters;
620 int index_scalar;
621 int space, length, left, right;
622 char * scolumn;
623 char temp[OSL_MAX_STRING];
625 OSL_malloc(scolumn, char *, OSL_MAX_STRING);
627 index_output_dims = 1;
628 index_input_dims = index_output_dims + relation->nb_output_dims;
629 index_local_dims = index_input_dims + relation->nb_input_dims;
630 index_parameters = index_local_dims + relation->nb_local_dims;
631 index_scalar = index_parameters + relation->nb_parameters;
633 // 1. The comment part.
634 sprintf(scolumn, "#");
635 for (j = 0; j < (OSL_FMT_LENGTH - 1)/2 - 1; j++)
636 strcat(scolumn, " ");
638 i = 0;
639 while (strings[i] != NULL) {
640 space = OSL_FMT_LENGTH;
641 length = (space > (int)strlen(strings[i])) ? (int)strlen(strings[i]) : space;
642 right = (space - length + (OSL_FMT_LENGTH % 2)) / 2;
643 left = space - length - right;
645 // 2. Spaces before the name
646 for (j = 0; j < left; j++)
647 strcat(scolumn, " ");
649 // 3. The (abbreviated) name
650 for (j = 0; j < length - 1; j++) {
651 sprintf(temp, "%c", strings[i][j]);
652 strcat(scolumn, temp);
654 if (length >= (int)strlen(strings[i]))
655 sprintf(temp, "%c", strings[i][j]);
656 else
657 sprintf(temp, ".");
658 strcat(scolumn, temp);
660 // 4. Spaces after the name
661 for (j = 0; j < right; j++)
662 strcat(scolumn, " ");
664 i++;
665 if ((i == index_output_dims) ||
666 (i == index_input_dims) ||
667 (i == index_local_dims) ||
668 (i == index_parameters) ||
669 (i == index_scalar))
670 strcat(scolumn, "|");
671 else
672 strcat(scolumn, " ");
674 strcat(scolumn, "\n");
676 return scolumn;
681 * osl_relation_column_string_scoplib function:
682 * this function returns an OpenScop comment string showing all column
683 * names. It is designed to nicely fit a constraint matrix that would be
684 * printed just below this line.
685 * \param[in] relation The relation related to the comment line to build.
686 * \param[in] strings Array of textual names of the various elements.
687 * \return A fancy comment string with all the dimension names.
689 static
690 char * osl_relation_column_string_scoplib(osl_relation_p relation,
691 char ** strings) {
692 int i, j;
693 int index_output_dims;
694 int index_input_dims;
695 int index_local_dims;
696 int index_parameters;
697 int index_scalar;
698 int space, length, left, right;
699 char * scolumn;
700 char temp[OSL_MAX_STRING];
702 OSL_malloc(scolumn, char *, OSL_MAX_STRING);
704 index_output_dims = 1;
705 index_input_dims = index_output_dims + relation->nb_output_dims;
706 index_local_dims = index_input_dims + relation->nb_input_dims;
707 index_parameters = index_local_dims + relation->nb_local_dims;
708 index_scalar = index_parameters + relation->nb_parameters;
710 // 1. The comment part.
711 sprintf(scolumn, "#");
712 for (j = 0; j < (OSL_FMT_LENGTH - 1)/2 - 1; j++)
713 strcat(scolumn, " ");
715 i = 0;
716 while (strings[i] != NULL) {
718 if (i == 0 ||
719 (relation->type != OSL_TYPE_DOMAIN && i >= index_input_dims) ||
720 (relation->type == OSL_TYPE_DOMAIN && i <= index_output_dims) ||
721 i >= index_parameters) {
722 space = OSL_FMT_LENGTH;
723 length = (space > (int)strlen(strings[i])) ? (int)strlen(strings[i]) : space;
724 right = (space - length + (OSL_FMT_LENGTH % 2)) / 2;
725 left = space - length - right;
727 // 2. Spaces before the name
728 for (j = 0; j < left; j++)
729 strcat(scolumn, " ");
731 // 3. The (abbreviated) name
732 for (j = 0; j < length - 1; j++) {
733 sprintf(temp, "%c", strings[i][j]);
734 strcat(scolumn, temp);
736 if (length >= (int)strlen(strings[i]))
737 sprintf(temp, "%c", strings[i][j]);
738 else
739 sprintf(temp, ".");
740 strcat(scolumn, temp);
742 // 4. Spaces after the name
743 for (j = 0; j < right; j++)
744 strcat(scolumn, " ");
746 if ((i == index_output_dims-1) ||
747 (i == index_input_dims-1) ||
748 (i == index_local_dims-1) ||
749 (i == index_parameters-1) ||
750 (i == index_scalar-1))
751 strcat(scolumn, "|");
752 else
753 strcat(scolumn, " ");
756 i++;
758 strcat(scolumn, "\n");
760 return scolumn;
765 * osl_relation_names function:
766 * this function generates as set of names for all the dimensions
767 * involved in a given relation.
768 * \param[in] relation The relation we have to generate names for.
769 * \return A set of generated names for the input relation dimensions.
771 static
772 osl_names_p osl_relation_names(osl_relation_p relation) {
773 int nb_parameters = OSL_UNDEFINED;
774 int nb_iterators = OSL_UNDEFINED;
775 int nb_scattdims = OSL_UNDEFINED;
776 int nb_localdims = OSL_UNDEFINED;
777 int array_id = OSL_UNDEFINED;
779 osl_relation_get_attributes(relation, &nb_parameters, &nb_iterators,
780 &nb_scattdims, &nb_localdims, &array_id);
782 return osl_names_generate("P", nb_parameters,
783 "i", nb_iterators,
784 "c", nb_scattdims,
785 "l", nb_localdims,
786 "A", array_id);
791 * osl_relation_nb_components function:
792 * this function returns the number of component in the union of relations
793 * provided as parameter.
794 * \param[in] relation The input union of relations.
795 * \return The number of components in the input union of relations.
797 int osl_relation_nb_components(osl_relation_p relation) {
798 int nb_components = 0;
800 while (relation != NULL) {
801 nb_components++;
802 relation = relation->next;
805 return nb_components;
810 * osl_relation_spprint_polylib function:
811 * this function pretty-prints the content of an osl_relation_t structure
812 * (*relation) into a string in the extended polylib format, and returns this
813 * string. This format is the same as OpenScop's, minus the type.
814 * \param[in] relation The relation whose information has to be printed.
815 * \param[in] names The names of the constraint columns for comments.
816 * \return A string containing the relation pretty-printing.
818 char * osl_relation_spprint_polylib(osl_relation_p relation,
819 osl_names_p names) {
820 int i, j;
821 int part, nb_parts;
822 int generated_names = 0;
823 int high_water_mark = OSL_MAX_STRING;
824 char * string = NULL;
825 char buffer[OSL_MAX_STRING];
826 char ** name_array = NULL;
827 char * scolumn;
828 char * comment;
830 if (relation == NULL)
831 return osl_util_strdup("# NULL relation\n");
833 OSL_malloc(string, char *, high_water_mark * sizeof(char));
834 string[0] = '\0';
836 // Generates the names for the comments if necessary.
837 if (names == NULL) {
838 generated_names = 1;
839 names = osl_relation_names(relation);
842 nb_parts = osl_relation_nb_components(relation);
844 if (nb_parts > 1) {
845 snprintf(buffer, OSL_MAX_STRING, "# Union with %d parts\n%d\n",
846 nb_parts, nb_parts);
847 osl_util_safe_strcat(&string, buffer, &high_water_mark);
850 // Print each part of the union.
851 for (part = 1; part <= nb_parts; part++) {
852 // Prepare the array of strings for comments.
853 name_array = osl_relation_strings(relation, names);
855 if (nb_parts > 1) {
856 snprintf(buffer, OSL_MAX_STRING, "# Union part No.%d\n", part);
857 osl_util_safe_strcat(&string, buffer, &high_water_mark);
860 snprintf(buffer, OSL_MAX_STRING, "%d %d %d %d %d %d\n",
861 relation->nb_rows, relation->nb_columns,
862 relation->nb_output_dims, relation->nb_input_dims,
863 relation->nb_local_dims, relation->nb_parameters);
864 osl_util_safe_strcat(&string, buffer, &high_water_mark);
866 if (relation->nb_rows > 0) {
867 scolumn = osl_relation_column_string(relation, name_array);
868 snprintf(buffer, OSL_MAX_STRING, "%s", scolumn);
869 osl_util_safe_strcat(&string, buffer, &high_water_mark);
870 free(scolumn);
873 for (i = 0; i < relation->nb_rows; i++) {
874 for (j = 0; j < relation->nb_columns; j++) {
875 osl_int_sprint(buffer, relation->precision, relation->m[i][j]);
876 osl_util_safe_strcat(&string, buffer, &high_water_mark);
877 snprintf(buffer, OSL_MAX_STRING, " ");
878 osl_util_safe_strcat(&string, buffer, &high_water_mark);
881 if (name_array != NULL) {
882 comment = osl_relation_sprint_comment(relation, i, name_array,
883 names->arrays->string);
884 osl_util_safe_strcat(&string, comment, &high_water_mark);
885 free(comment);
887 snprintf(buffer, OSL_MAX_STRING, "\n");
888 osl_util_safe_strcat(&string, buffer, &high_water_mark);
891 // Free the array of strings.
892 if (name_array != NULL) {
893 for (i = 0; i < relation->nb_columns; i++)
894 free(name_array[i]);
895 free(name_array);
898 relation = relation->next;
901 if (generated_names)
902 osl_names_free(names);
904 return string;
909 * osl_relation_spprint_polylib_scoplib function:
910 * this function pretty-prints the content of an osl_relation_t structure
911 * (*relation) into a string in the extended polylib format, and returns this
912 * string.
913 * \param[in] relation The relation whose information has to be printed.
914 * \param[in] names The names of the constraint columns for comments.
915 * \param[in] print_nth_part Print the value of `n' (used for domain union)
916 * \param[in] add_fakeiter
917 * \return A string containing the relation pretty-printing.
919 char * osl_relation_spprint_polylib_scoplib(osl_relation_p relation,
920 osl_names_p names,
921 int print_nth_part,
922 int add_fakeiter) {
923 int i, j;
924 int part, nb_parts;
925 int generated_names = 0;
926 int is_access_array;
927 int high_water_mark = OSL_MAX_STRING;
928 int start_row; // for removing the first line in the access matrix
929 int index_output_dims;
930 int index_input_dims;
931 int index_params;
932 char * string = NULL;
933 char buffer[OSL_MAX_STRING];
934 char ** name_array = NULL;
935 char * scolumn;
936 char * comment;
938 if (relation == NULL)
939 return osl_util_strdup("# NULL relation\n");
941 OSL_malloc(string, char *, high_water_mark * sizeof(char));
942 string[0] = '\0';
944 // Generates the names for the comments if necessary.
945 if (names == NULL) {
946 generated_names = 1;
947 names = osl_relation_names(relation);
950 nb_parts = osl_relation_nb_components(relation);
951 if (nb_parts > 1) {
952 snprintf(buffer, OSL_MAX_STRING, "# Union with %d parts\n%d\n",
953 nb_parts, nb_parts);
954 osl_util_safe_strcat(&string, buffer, &high_water_mark);
957 is_access_array = (relation->type == OSL_TYPE_READ ||
958 relation->type == OSL_TYPE_WRITE ? 1 : 0);
960 // Print each part of the union.
962 for (part = 1; part <= nb_parts; part++) {
964 index_output_dims = 1;
965 index_input_dims = index_output_dims + relation->nb_output_dims;
966 index_params = index_input_dims + relation->nb_input_dims;
968 // Prepare the array of strings for comments.
969 name_array = osl_relation_strings(relation, names);
971 if (nb_parts > 1) {
972 snprintf(buffer, OSL_MAX_STRING, "# Union part No.%d\n", part);
973 osl_util_safe_strcat(&string, buffer, &high_water_mark);
976 if (print_nth_part) {
977 snprintf(buffer, OSL_MAX_STRING, "%d\n", part);
978 osl_util_safe_strcat(&string, buffer, &high_water_mark);
981 // Don't print the array size for access array
982 // (the total size is printed in osl_relation_list_pprint_access_array_scoplib)
983 if (!is_access_array) {
985 // Print array size
986 if (relation->type == OSL_TYPE_DOMAIN) {
988 if (add_fakeiter) {
990 snprintf(buffer, OSL_MAX_STRING, "%d %d\n",
991 relation->nb_rows+1, relation->nb_columns -
992 relation->nb_input_dims + 1);
993 osl_util_safe_strcat(&string, buffer, &high_water_mark);
995 // add the fakeiter line
996 snprintf(buffer, OSL_MAX_STRING, " 0 ");
997 osl_util_safe_strcat(&string, buffer, &high_water_mark);
998 snprintf(buffer, OSL_MAX_STRING, " 1 "); // fakeiter
999 osl_util_safe_strcat(&string, buffer, &high_water_mark);
1001 for (i = 0 ; i < relation->nb_parameters ; i++) {
1002 snprintf(buffer, OSL_MAX_STRING, " 0 ");
1003 osl_util_safe_strcat(&string, buffer, &high_water_mark);
1006 snprintf(buffer, OSL_MAX_STRING, " 0 ## fakeiter == 0\n");
1007 osl_util_safe_strcat(&string, buffer, &high_water_mark);
1009 } else {
1010 snprintf(buffer, OSL_MAX_STRING, "%d %d\n",
1011 relation->nb_rows, relation->nb_columns -
1012 relation->nb_input_dims);
1013 osl_util_safe_strcat(&string, buffer, &high_water_mark);
1016 } else { // SCATTERING
1018 if (add_fakeiter) {
1019 snprintf(buffer, OSL_MAX_STRING, "%d %d\n",
1020 relation->nb_rows+2, relation->nb_columns -
1021 relation->nb_output_dims + 1);
1022 osl_util_safe_strcat(&string, buffer, &high_water_mark);
1023 } else {
1024 snprintf(buffer, OSL_MAX_STRING, "%d %d\n",
1025 relation->nb_rows, relation->nb_columns -
1026 relation->nb_output_dims);
1027 osl_util_safe_strcat(&string, buffer, &high_water_mark);
1031 // Print column names in comment
1032 if (relation->nb_rows > 0) {
1033 scolumn = osl_relation_column_string_scoplib(relation, name_array);
1034 snprintf(buffer, OSL_MAX_STRING, "%s", scolumn);
1035 osl_util_safe_strcat(&string, buffer, &high_water_mark);
1036 free(scolumn);
1039 start_row = 0;
1041 } else {
1043 if (relation->nb_rows == 1) // for non array variables
1044 start_row = 0;
1045 else // Remove the 'Arr' line
1046 start_row = 1;
1049 // Print the array
1050 for (i = start_row; i < relation->nb_rows; i++) {
1052 // First column
1053 if (!is_access_array) {
1054 // array index name for scoplib
1055 osl_int_sprint(buffer, relation->precision, relation->m[i][0]);
1056 osl_util_safe_strcat(&string, buffer, &high_water_mark);
1057 snprintf(buffer, OSL_MAX_STRING, " ");
1058 osl_util_safe_strcat(&string, buffer, &high_water_mark);
1060 } else {
1061 // The first column represents the array index name in openscop
1062 if (i == start_row)
1063 osl_int_sprint(buffer, relation->precision,
1064 relation->m[0][relation->nb_columns-1]);
1065 else
1066 snprintf(buffer, OSL_MAX_STRING, " 0 ");
1068 osl_util_safe_strcat(&string, buffer, &high_water_mark);
1069 snprintf(buffer, OSL_MAX_STRING, " ");
1070 osl_util_safe_strcat(&string, buffer, &high_water_mark);
1073 // Rest of the array
1074 if (relation->type == OSL_TYPE_DOMAIN) {
1076 for (j = 1; j < index_input_dims; j++) {
1077 osl_int_sprint(buffer, relation->precision, relation->m[i][j]);
1078 osl_util_safe_strcat(&string, buffer, &high_water_mark);
1079 snprintf(buffer, OSL_MAX_STRING, " ");
1080 osl_util_safe_strcat(&string, buffer, &high_water_mark);
1083 // Jmp input_dims
1084 for (j = index_params; j < relation->nb_columns; j++) {
1085 osl_int_sprint(buffer, relation->precision, relation->m[i][j]);
1086 osl_util_safe_strcat(&string, buffer, &high_water_mark);
1087 snprintf(buffer, OSL_MAX_STRING, " ");
1088 osl_util_safe_strcat(&string, buffer, &high_water_mark);
1091 } else {
1093 // Jmp output_dims
1094 for (j = index_input_dims; j < index_params; j++) {
1095 if (is_access_array && relation->nb_rows == 1 &&
1096 j == relation->nb_columns-1) {
1097 snprintf(buffer, OSL_MAX_STRING, " 0 ");
1098 osl_util_safe_strcat(&string, buffer, &high_water_mark);
1099 } else {
1100 osl_int_sprint(buffer, relation->precision, relation->m[i][j]);
1101 osl_util_safe_strcat(&string, buffer, &high_water_mark);
1102 snprintf(buffer, OSL_MAX_STRING, " ");
1103 osl_util_safe_strcat(&string, buffer, &high_water_mark);
1107 if (add_fakeiter) {
1108 snprintf(buffer, OSL_MAX_STRING, " 0 ");
1109 osl_util_safe_strcat(&string, buffer, &high_water_mark);
1112 for (; j < relation->nb_columns; j++) {
1113 if (is_access_array && relation->nb_rows == 1 &&
1114 j == relation->nb_columns-1) {
1115 snprintf(buffer, OSL_MAX_STRING, " 0 ");
1116 osl_util_safe_strcat(&string, buffer, &high_water_mark);
1117 } else {
1118 osl_int_sprint(buffer, relation->precision, relation->m[i][j]);
1119 osl_util_safe_strcat(&string, buffer, &high_water_mark);
1120 snprintf(buffer, OSL_MAX_STRING, " ");
1121 osl_util_safe_strcat(&string, buffer, &high_water_mark);
1126 // equation in comment
1127 if (name_array != NULL) {
1128 comment = osl_relation_sprint_comment(relation, i, name_array,
1129 names->arrays->string);
1130 osl_util_safe_strcat(&string, comment, &high_water_mark);
1131 free(comment);
1132 snprintf(buffer, OSL_MAX_STRING, "\n");
1133 osl_util_safe_strcat(&string, buffer, &high_water_mark);
1136 // add the lines in the scattering if we need the fakeiter
1137 if (relation->nb_rows > 0 && add_fakeiter &&
1138 relation->type == OSL_TYPE_SCATTERING) {
1140 for (i = 0 ; i < 2 ; i++) {
1141 for (j = 0; j < relation->nb_columns; j++) {
1142 if (j == index_output_dims && i == 0)
1143 snprintf(buffer, OSL_MAX_STRING, " 1 "); // fakeiter
1144 else
1145 snprintf(buffer, OSL_MAX_STRING, " 0 ");
1146 osl_util_safe_strcat(&string, buffer, &high_water_mark);
1148 snprintf(buffer, OSL_MAX_STRING, "\n");
1149 osl_util_safe_strcat(&string, buffer, &high_water_mark);
1155 // Free the array of strings.
1156 if (name_array != NULL) {
1157 for (i = 0; i < relation->nb_columns; i++)
1158 free(name_array[i]);
1159 free(name_array);
1162 relation = relation->next;
1165 if (generated_names)
1166 osl_names_free(names);
1168 return string;
1173 * osl_relation_spprint function:
1174 * this function pretty-prints the content of an osl_relation_t structure
1175 * (*relation) into a string in the OpenScop format, and returns this string.
1176 * \param[in] relation The relation whose information has to be printed.
1177 * \param[in] names The names of the constraint columns for comments.
1178 * \return A string
1180 char * osl_relation_spprint(osl_relation_p relation, osl_names_p names) {
1181 int high_water_mark = OSL_MAX_STRING;
1182 char * string = NULL;
1183 char * temp;
1184 char buffer[OSL_MAX_STRING];
1185 OSL_malloc(string, char *, high_water_mark * sizeof(char));
1186 string[0] = '\0';
1188 if (osl_relation_nb_components(relation) > 0) {
1189 temp = osl_relation_sprint_type(relation);
1190 osl_util_safe_strcat(&string, temp, &high_water_mark);
1191 free(temp);
1193 snprintf(buffer, OSL_MAX_STRING, "\n");
1194 osl_util_safe_strcat(&string, buffer, &high_water_mark);
1196 temp = osl_relation_spprint_polylib(relation, names);
1197 osl_util_safe_strcat(&string, temp, &high_water_mark);
1198 free(temp);
1201 return string;
1206 * osl_relation_spprint_scoplib function:
1207 * this function pretty-prints the content of an osl_relation_t structure
1208 * (*relation) into a string in the SCoPLib format, and returns this string.
1209 * \param[in] relation The relation whose information has to be printed.
1210 * \param[in] names The names of the constraint columns for comments.
1211 * \param[in] print_nth_part Print the value of `n' (used for domain union)
1212 * \param[in] add_fakeiter
1213 * \return A string
1215 char * osl_relation_spprint_scoplib(osl_relation_p relation, osl_names_p names,
1216 int print_nth_part, int add_fakeiter) {
1217 int high_water_mark = OSL_MAX_STRING;
1218 char * string = NULL;
1219 char * temp;
1220 OSL_malloc(string, char *, high_water_mark * sizeof(char));
1221 string[0] = '\0';
1223 if (relation) {
1224 temp = osl_relation_spprint_polylib_scoplib(relation, names,
1225 print_nth_part, add_fakeiter);
1226 osl_util_safe_strcat(&string, temp, &high_water_mark);
1227 free(temp);
1230 return string;
1235 * osl_relation_pprint function:
1236 * this function pretty-prints the content of an osl_relation_t structure
1237 * (*relation) into a file (file, possibly stdout) in the OpenScop format.
1238 * \param[in] file File where informations are printed.
1239 * \param[in] relation The relation whose information has to be printed.
1240 * \param[in] names The names of the constraint columns for comments.
1242 void osl_relation_pprint(FILE * file, osl_relation_p relation,
1243 osl_names_p names) {
1244 char * string = osl_relation_spprint(relation, names);
1245 fprintf(file, "%s", string);
1246 free(string);
1251 * osl_relation_pprint_scoplib function:
1252 * this function pretty-prints the content of an osl_relation_t structure
1253 * (*relation) into a file (file, possibly stdout) in the SCoPLibformat.
1254 * \param[in] file File where informations are printed.
1255 * \param[in] relation The relation whose information has to be printed.
1256 * \param[in] names The names of the constraint columns for comments.
1257 * \param[in] print_nth_part
1258 * \param[in] add_fakeiter
1260 void osl_relation_pprint_scoplib(FILE * file, osl_relation_p relation,
1261 osl_names_p names, int print_nth_part,
1262 int add_fakeiter) {
1263 char * string = osl_relation_spprint_scoplib(relation, names,
1264 print_nth_part, add_fakeiter);
1265 fprintf(file, "%s", string);
1266 free(string);
1271 * osl_relation_sprint function:
1272 * this function prints the content of an osl_relation_t structure
1273 * (*relation) into a string (returned) in the OpenScop textual format.
1274 * \param[in] relation The relation structure to print.
1275 * \return A string containing the OpenScop dump of the relation structure.
1277 char * osl_relation_sprint(osl_relation_p relation) {
1279 return osl_relation_spprint(relation, NULL);
1284 * osl_relation_print function:
1285 * this function prints the content of an osl_relation_t structure
1286 * (*relation) into a file (file, possibly stdout) in the OpenScop format.
1287 * \param[in] file File where informations are printed.
1288 * \param[in] relation The relation whose information has to be printed.
1290 void osl_relation_print(FILE * file, osl_relation_p relation) {
1292 osl_relation_pprint(file, relation, NULL);
1296 /*****************************************************************************
1297 * Reading function *
1298 *****************************************************************************/
1302 * osl_relation_read_type function:
1303 * this function reads a textual relation type on the input 'file' or the
1304 * input string 'str' depending on which one is not NULL (exactly
1305 * one of them must not be NULL). It returns its integer counterpart.
1306 * \param[in] file The file where to read a relation type (if not NULL).
1307 * \param[in,out] str The string where to read a relation type (if not NULL).
1308 * This pointer is updated to reflect the read and points
1309 * after the tag in the input string.
1310 * \return The relation type.
1312 static
1313 int osl_relation_read_type(FILE * file, char ** str) {
1314 int type;
1315 osl_strings_p strings;
1317 if ((file != NULL && str != NULL) || (file == NULL && str == NULL))
1318 OSL_error("one and only one of the two parameters can be non-NULL");
1320 if (file != NULL)
1321 strings = osl_strings_read(file);
1322 else
1323 strings = osl_strings_sread(str);
1325 if (osl_strings_size(strings) > 1) {
1326 OSL_warning("uninterpreted information (after the relation type)");
1328 if (osl_strings_size(strings) == 0)
1329 OSL_error("no relation type");
1331 if (!strcmp(strings->string[0], OSL_STRING_UNDEFINED)) {
1332 type = OSL_UNDEFINED;
1333 goto return_type;
1336 if (!strcmp(strings->string[0], OSL_STRING_CONTEXT)) {
1337 type = OSL_TYPE_CONTEXT;
1338 goto return_type;
1341 if (!strcmp(strings->string[0], OSL_STRING_DOMAIN)) {
1342 type = OSL_TYPE_DOMAIN;
1343 goto return_type;
1346 if (!strcmp(strings->string[0], OSL_STRING_SCATTERING)) {
1347 type = OSL_TYPE_SCATTERING;
1348 goto return_type;
1351 if (!strcmp(strings->string[0], OSL_STRING_READ)) {
1352 type = OSL_TYPE_READ;
1353 goto return_type;
1356 if (!strcmp(strings->string[0], OSL_STRING_WRITE)) {
1357 type = OSL_TYPE_WRITE;
1358 goto return_type;
1361 if (!strcmp(strings->string[0], OSL_STRING_MAY_WRITE)) {
1362 type = OSL_TYPE_MAY_WRITE;
1363 goto return_type;
1366 OSL_error("relation type not supported");
1368 return_type:
1369 osl_strings_free(strings);
1370 return type;
1375 * osl_relation_pread function ("precision read"):
1376 * this function reads a relation into a file (foo, posibly stdin) and
1377 * returns a pointer this relation.
1378 * \param[in] foo The input stream.
1379 * \param[in] precision The precision of the relation elements.
1380 * \return A pointer to the relation structure that has been read.
1382 osl_relation_p osl_relation_pread(FILE * foo, int precision) {
1383 int i, j, k, n, read = 0;
1384 int nb_rows, nb_columns;
1385 int nb_output_dims, nb_input_dims, nb_local_dims, nb_parameters;
1386 int nb_union_parts = 1;
1387 int may_read_nb_union_parts = 1;
1388 int read_attributes = 1;
1389 int first = 1;
1390 int type;
1391 char * c, s[OSL_MAX_STRING], str[OSL_MAX_STRING], *tmp;
1392 osl_relation_p relation, relation_union = NULL, previous = NULL;
1394 type = osl_relation_read_type(foo, NULL);
1396 // Read each part of the union (the number of parts may be updated inside)
1397 for (k = 0; k < nb_union_parts; k++) {
1398 // Read the number of union parts or the attributes of the union part
1399 while (read_attributes) {
1400 read_attributes = 0;
1402 // Read relation attributes.
1403 c = osl_util_skip_blank_and_comments(foo, s);
1404 read = sscanf(c, " %d %d %d %d %d %d", &nb_rows, &nb_columns,
1405 &nb_output_dims, &nb_input_dims,
1406 &nb_local_dims, &nb_parameters);
1408 if (((read != 1) && (read != 6)) ||
1409 ((read == 1) && (may_read_nb_union_parts != 1)))
1410 OSL_error("not 1 or 6 integers on the first relation line");
1412 if (read == 1) {
1413 // Only one number means a union and is the number of parts.
1414 nb_union_parts = nb_rows;
1415 if (nb_union_parts < 1)
1416 OSL_error("negative nb of union parts");
1418 // Allow to read the properties of the first part of the union.
1419 read_attributes = 1;
1422 may_read_nb_union_parts = 0;
1425 // Allocate the union part and fill its properties.
1426 relation = osl_relation_pmalloc(precision, nb_rows, nb_columns);
1427 relation->type = type;
1428 relation->nb_output_dims = nb_output_dims;
1429 relation->nb_input_dims = nb_input_dims;
1430 relation->nb_local_dims = nb_local_dims;
1431 relation->nb_parameters = nb_parameters;
1433 // Read the matrix of constraints.
1434 for (i = 0; i < relation->nb_rows; i++) {
1435 c = osl_util_skip_blank_and_comments(foo, s);
1436 if (c == NULL)
1437 OSL_error("not enough rows");
1439 for (j = 0; j < relation->nb_columns; j++) {
1440 if (c == NULL || *c == '#' || *c == '\n')
1441 OSL_error("not enough columns");
1442 if (sscanf(c, "%s%n", str, &n) == 0)
1443 OSL_error("not enough rows");
1445 // TODO: remove this tmp (sread updates the pointer).
1446 tmp = str;
1447 osl_int_sread(&tmp, precision, &relation->m[i][j]);
1448 c += n;
1452 // Build the linked list of union parts.
1453 if (first == 1) {
1454 relation_union = relation;
1455 first = 0;
1457 else {
1458 previous->next = relation;
1461 previous = relation;
1462 read_attributes = 1;
1465 return relation_union;
1469 * osl_relation_psread function ("precision read"):
1470 * this function is equivalent to osl_relation_psread_polylib() except that
1471 * it reads an the type of the relation before reading the rest of the
1472 * input.
1473 * \see{osl_relation_psread_polylib}
1475 osl_relation_p osl_relation_psread(char ** input, int precision) {
1476 int type;
1477 osl_relation_p relation;
1479 type = osl_relation_read_type(NULL, input);
1480 relation = osl_relation_psread_polylib(input, precision);
1481 relation->type = type;
1483 return relation;
1487 * osl_relation_psread_polylib function ("precision read"):
1488 * this function reads a relation from a string complying to the Extended
1489 * PolyLib textual format and returns a pointer this relation. The input
1490 * parameter is updated to the position in the input string this function
1491 * reach right after reading the generic structure.
1492 * \param[in,out] input The input string where to find a relation.
1493 * Updated to the position after what has been read.
1494 * \param[in] precision The precision of the relation elements.
1495 * \return A pointer to the relation structure that has been read.
1497 osl_relation_p osl_relation_psread_polylib(char ** input, int precision) {
1498 int i, j, k, n, read = 0;
1499 int nb_rows, nb_columns;
1500 int nb_output_dims, nb_input_dims, nb_local_dims, nb_parameters;
1501 int nb_union_parts = 1;
1502 int may_read_nb_union_parts = 1;
1503 int read_attributes = 1;
1504 int first = 1;
1505 char str[OSL_MAX_STRING], *tmp;
1506 osl_relation_p relation, relation_union = NULL, previous = NULL;
1508 // Read each part of the union (the number of parts may be updated inside)
1509 for (k = 0; k < nb_union_parts; k++) {
1510 // Read the number of union parts or the attributes of the union part
1511 while (read_attributes) {
1512 read_attributes = 0;
1513 // Read relation attributes.
1514 osl_util_sskip_blank_and_comments(input);
1515 // make a copy of the first line
1516 tmp = *input;
1517 while ((*tmp != '\0') && (*tmp != '\n'))
1518 tmp++;
1519 strncpy(str, *input, sizeof(char) * (tmp-*input));
1520 str[(tmp-*input)] = '\0';
1522 read = sscanf(str, " %d %d %d %d %d %d",
1523 &nb_rows, &nb_columns,
1524 &nb_output_dims, &nb_input_dims,
1525 &nb_local_dims, &nb_parameters);
1526 *input = tmp;
1528 if (((read != 1) && (read != 6)) ||
1529 ((read == 1) && (may_read_nb_union_parts != 1)))
1530 OSL_error("not 1 or 6 integers on the first relation line");
1532 if (read == 1) {
1533 // Only one number means a union and is the number of parts.
1534 nb_union_parts = nb_rows;
1535 if (nb_union_parts < 1)
1536 OSL_error("negative nb of union parts");
1538 // Allow to read the properties of the first part of the union.
1539 read_attributes = 1;
1542 may_read_nb_union_parts = 0;
1545 // Allocate the union part and fill its properties.
1546 relation = osl_relation_pmalloc(precision, nb_rows, nb_columns);
1547 relation->nb_output_dims = nb_output_dims;
1548 relation->nb_input_dims = nb_input_dims;
1549 relation->nb_local_dims = nb_local_dims;
1550 relation->nb_parameters = nb_parameters;
1552 // Read the matrix of constraints.
1553 for (i = 0; i < relation->nb_rows; i++) {
1554 osl_util_sskip_blank_and_comments(input);
1555 if (!(*input))
1556 OSL_error("not enough rows");
1558 for (j = 0; j < relation->nb_columns; j++) {
1559 if (*input == NULL || **input == '#' || **input == '\n')
1560 OSL_error("not enough columns");
1561 if (sscanf(*input, "%s%n", str, &n) == 0)
1562 OSL_error("not enough rows");
1564 // TODO: remove this tmp (sread updates the pointer).
1565 tmp = str;
1566 osl_int_sread(&tmp, precision, &relation->m[i][j]);
1567 *input += n;
1571 // Build the linked list of union parts.
1572 if (first == 1) {
1573 relation_union = relation;
1574 first = 0;
1576 else {
1577 previous->next = relation;
1580 previous = relation;
1581 read_attributes = 1;
1584 return relation_union;
1589 * osl_relation_sread function:
1590 * this function is equivalent to osl_relation_psread() except that
1591 * the precision corresponds to the precision environment variable or
1592 * to the highest available precision if it is not defined.
1593 * \see{osl_relation_psread}
1595 osl_relation_p osl_relation_sread(char ** input) {
1596 int precision = osl_util_get_precision();
1597 return osl_relation_psread(input, precision);
1601 * osl_relation_sread function:
1602 * this function is equivalent to osl_relation_psread_polylib() except that
1603 * the precision corresponds to the precision environment variable or
1604 * to the highest available precision if it is not defined.
1605 * \see{osl_relation_posread_polylib}
1607 osl_relation_p osl_relation_sread_polylib(char ** input) {
1608 int precision = osl_util_get_precision();
1609 return osl_relation_psread_polylib(input, precision);
1614 * osl_relation_read function:
1615 * this function is equivalent to osl_relation_pread() except that
1616 * the precision corresponds to the precision environment variable or
1617 * to the highest available precision if it is not defined.
1618 * \see{osl_relation_pread}
1620 osl_relation_p osl_relation_read(FILE * foo) {
1621 int precision = osl_util_get_precision();
1622 return osl_relation_pread(foo, precision);
1626 /*+***************************************************************************
1627 * Memory allocation/deallocation function *
1628 *****************************************************************************/
1632 * osl_relation_pmalloc function:
1633 * (precision malloc) this function allocates the memory space for an
1634 * osl_relation_t structure and sets its fields with default values.
1635 * Then it returns a pointer to the allocated space.
1636 * \param[in] precision The precision of the constraint matrix.
1637 * \param[in] nb_rows The number of row of the relation to allocate.
1638 * \param[in] nb_columns The number of columns of the relation to allocate.
1639 * \return A pointer to an empty relation with fields set to default values
1640 * and a ready-to-use constraint matrix.
1642 osl_relation_p osl_relation_pmalloc(int precision,
1643 int nb_rows, int nb_columns) {
1644 osl_relation_p relation;
1645 osl_int_t ** p, * q;
1646 int i, j;
1648 if ((precision != OSL_PRECISION_SP) &&
1649 (precision != OSL_PRECISION_DP) &&
1650 (precision != OSL_PRECISION_MP))
1651 OSL_error("unknown precision");
1653 if ((nb_rows < 0) || (nb_columns < 0))
1654 OSL_error("negative sizes");
1656 OSL_malloc(relation, osl_relation_p, sizeof(osl_relation_t));
1657 relation->type = OSL_UNDEFINED;
1658 relation->nb_rows = nb_rows;
1659 relation->nb_columns = nb_columns;
1660 relation->nb_output_dims = OSL_UNDEFINED;
1661 relation->nb_input_dims = OSL_UNDEFINED;
1662 relation->nb_parameters = OSL_UNDEFINED;
1663 relation->nb_local_dims = OSL_UNDEFINED;
1664 relation->precision = precision;
1666 if ((nb_rows == 0) || (nb_columns == 0) ||
1667 (nb_rows == OSL_UNDEFINED) || (nb_columns == OSL_UNDEFINED)) {
1668 relation->m = NULL;
1670 else {
1671 OSL_malloc(p, osl_int_t**, nb_rows * sizeof(osl_int_t*));
1672 OSL_malloc(q, osl_int_t*, nb_rows * nb_columns * sizeof(osl_int_t));
1673 relation->m = p;
1674 for (i = 0; i < nb_rows; i++) {
1675 relation->m[i] = q + i * nb_columns ;
1676 for (j = 0; j < nb_columns; j++)
1677 osl_int_init_set_si(precision, &relation->m[i][j], 0);
1681 relation->next = NULL;
1683 return relation;
1688 * osl_relation_malloc function:
1689 * this function is equivalent to osl_relation_pmalloc() except that
1690 * the precision corresponds to the precision environment variable or
1691 * to the highest available precision if it is not defined.
1692 * \see{osl_relation_pmalloc}
1694 osl_relation_p osl_relation_malloc(int nb_rows, int nb_columns) {
1695 int precision = osl_util_get_precision();
1696 return osl_relation_pmalloc(precision, nb_rows, nb_columns);
1701 * osl_relation_free_inside function:
1702 * this function frees the allocated memory for the inside of a
1703 * osl_relation_t structure, i.e. only m.
1704 * \param[in] relation The pointer to the relation we want to free internals.
1706 void osl_relation_free_inside(osl_relation_p relation) {
1707 int i, nb_elements;
1709 if (relation == NULL)
1710 return;
1712 nb_elements = relation->nb_rows * relation->nb_columns;
1714 for (i = 0; i < nb_elements; i++)
1715 osl_int_clear(relation->precision, &relation->m[0][i]);
1717 if (relation->m != NULL) {
1718 if (nb_elements > 0)
1719 free(relation->m[0]);
1720 free(relation->m);
1726 * osl_relation_free function:
1727 * this function frees the allocated memory for an osl_relation_t
1728 * structure.
1729 * \param[in] relation The pointer to the relation we want to free.
1731 void osl_relation_free(osl_relation_p relation) {
1732 osl_relation_p tmp;
1734 while (relation != NULL) {
1735 tmp = relation->next;
1736 osl_relation_free_inside(relation);
1737 free(relation);
1738 relation = tmp;
1743 /*+***************************************************************************
1744 * Processing functions *
1745 *****************************************************************************/
1749 * osl_relation_nclone function:
1750 * this functions builds and returns a "hard copy" (not a pointer copy) of the
1751 * first n parts of a relation union.
1752 * \param[in] relation The pointer to the relation we want to clone.
1753 * \param[in] n The number of union parts of the relation we want to
1754 * clone (the special value -1 means "all the parts").
1755 * \return A pointer to the clone of the relation union restricted to the
1756 * first n parts of the relation union.
1758 osl_relation_p osl_relation_nclone(osl_relation_p relation, int n) {
1759 int i, j, k;
1760 int first = 1, nb_components, nb_parts;
1761 osl_relation_p clone = NULL, node, previous = NULL;
1763 nb_components = osl_relation_nb_components(relation);
1764 nb_parts = (n == -1) ? nb_components : n;
1765 if (nb_components < nb_parts)
1766 OSL_error("not enough union parts to clone");
1768 for (k = 0; k < nb_parts; k++) {
1769 node = osl_relation_pmalloc(relation->precision,
1770 relation->nb_rows, relation->nb_columns);
1771 node->type = relation->type;
1772 node->nb_output_dims = relation->nb_output_dims;
1773 node->nb_input_dims = relation->nb_input_dims;
1774 node->nb_local_dims = relation->nb_local_dims;
1775 node->nb_parameters = relation->nb_parameters;
1777 for (i = 0; i < relation->nb_rows; i++)
1778 for (j = 0; j < relation->nb_columns; j++)
1779 osl_int_assign(relation->precision,
1780 &node->m[i][j], relation->m[i][j]);
1782 if (first) {
1783 first = 0;
1784 clone = node;
1785 previous = node;
1787 else {
1788 previous->next = node;
1789 previous = previous->next;
1792 relation = relation->next;
1795 return clone;
1800 * osl_relation_clone_nconstraints function:
1801 * this functions builds and returns a "hard copy" (not a pointer copy) of a
1802 * osl_relation_t data structure such that the clone is restricted to the
1803 * "n" first rows of the relation. This applies to all the parts in the case
1804 * of a relation union.
1805 * \param[in] relation The pointer to the relation we want to clone.
1806 * \param[in] n The number of row of the relation we want to clone (the
1807 * special value -1 means "all the rows").
1808 * \return A pointer to the clone of the relation union restricted to the
1809 * first n rows of constraint matrix for each part of the union.
1811 osl_relation_p osl_relation_clone_nconstraints(osl_relation_p relation,
1812 int n) {
1813 int i, j;
1814 int first = 1, all_rows = 0;
1815 osl_relation_p clone = NULL, node, previous = NULL;
1817 if (n == -1)
1818 all_rows = 1;
1820 while (relation != NULL) {
1821 if (all_rows)
1822 n = relation->nb_rows;
1824 if (n > relation->nb_rows)
1825 OSL_error("not enough rows to clone in the relation");
1827 node = osl_relation_pmalloc(relation->precision, n, relation->nb_columns);
1828 node->type = relation->type;
1829 node->nb_output_dims = relation->nb_output_dims;
1830 node->nb_input_dims = relation->nb_input_dims;
1831 node->nb_local_dims = relation->nb_local_dims;
1832 node->nb_parameters = relation->nb_parameters;
1834 for (i = 0; i < n; i++)
1835 for (j = 0; j < relation->nb_columns; j++)
1836 osl_int_assign(relation->precision,
1837 &node->m[i][j], relation->m[i][j]);
1839 if (first) {
1840 first = 0;
1841 clone = node;
1842 previous = node;
1844 else {
1845 previous->next = node;
1846 previous = previous->next;
1849 relation = relation->next;
1852 return clone;
1857 * osl_relation_clone function:
1858 * this function builds and returns a "hard copy" (not a pointer copy) of an
1859 * osl_relation_t data structure (the full union of relation).
1860 * \param[in] relation The pointer to the relation we want to clone.
1861 * \return A pointer to the clone of the union of relations.
1863 osl_relation_p osl_relation_clone(osl_relation_p relation) {
1864 if (relation == NULL)
1865 return NULL;
1867 return osl_relation_nclone(relation, -1);
1872 * osl_relation_add function:
1873 * this function adds a relation (union) at the end of the relation (union)
1874 * pointed by r1. No new relation is created: this functions links the two
1875 * input unions. If the first relation is NULL, it is set to the
1876 * second relation.
1877 * \param[in,out] r1 Pointer to the first relation (union).
1878 * \param[in] r2 The second relation (union).
1880 void osl_relation_add(osl_relation_p *r1, osl_relation_p r2) {
1881 while (*r1 != NULL)
1882 r1 = &((*r1)->next);
1884 *r1 = r2;
1889 * osl_relation_union function:
1890 * this function builds a new relation from two relations provided
1891 * as parameters. The new relation is built as an union of the
1892 * two relations: the list of constraint sets are linked together.
1893 * \param[in] r1 The first relation.
1894 * \param[in] r2 The second relation.
1895 * \return A new relation corresponding to the union of r1 and r2.
1897 osl_relation_p osl_relation_union(osl_relation_p r1,
1898 osl_relation_p r2) {
1899 osl_relation_p copy1, copy2;
1901 if ((r1 == NULL) && (r2 == NULL))
1902 return NULL;
1904 copy1 = osl_relation_clone(r1);
1905 copy2 = osl_relation_clone(r2);
1906 osl_relation_add(&copy1, copy2);
1908 return copy1;
1913 * osl_relation_replace_vector function:
1914 * this function replaces the "row"^th row of a relation "relation" with the
1915 * vector "vector". It directly updates the relation union part pointed
1916 * by "relation" and this part only.
1917 * \param[in,out] relation The relation we want to replace a row.
1918 * \param[in] vector The vector that will replace a row of the relation.
1919 * \param[in] row The row of the relation to be replaced.
1921 void osl_relation_replace_vector(osl_relation_p relation,
1922 osl_vector_p vector, int row) {
1923 int i;
1925 if ((relation == NULL) || (vector == NULL) ||
1926 (relation->precision != vector->precision) ||
1927 (relation->nb_columns != vector->size) ||
1928 (row >= relation->nb_rows) || (row < 0))
1929 OSL_error("vector cannot replace relation row");
1931 for (i = 0; i < vector->size; i++)
1932 osl_int_assign(relation->precision, &relation->m[row][i], vector->v[i]);
1937 * osl_relation_add_vector function:
1938 * this function adds (meaning, +) a vector to the "row"^th row of a
1939 * relation "relation". It directly updates the relation union part pointed
1940 * by "relation" and this part only.
1941 * \param[in,out] relation The relation we want to add a vector to a row.
1942 * \param[in] vector The vector that will replace a row of the relation.
1943 * \param[in] row The row of the relation to add the vector.
1945 void osl_relation_add_vector(osl_relation_p relation,
1946 osl_vector_p vector, int row) {
1947 int i;
1949 if ((relation == NULL) || (vector == NULL) ||
1950 (relation->precision != vector->precision) ||
1951 (relation->nb_columns != vector->size) ||
1952 (row >= relation->nb_rows) || (row < 0))
1953 OSL_error("vector cannot be added to relation");
1955 if (osl_int_get_si(relation->precision, relation->m[row][0]) == 0)
1956 osl_int_assign(relation->precision, &relation->m[row][0], vector->v[0]);
1958 for (i = 1; i < vector->size; i++)
1959 osl_int_add(relation->precision,
1960 &relation->m[row][i], relation->m[row][i], vector->v[i]);
1965 * osl_relation_sub_vector function:
1966 * this function subtracts the vector "vector" to the "row"^th row of
1967 * a relation "relation. It directly updates the relation union part pointed
1968 * by "relation" and this part only.
1969 * \param[in,out] relation The relation where to subtract a vector to a row.
1970 * \param[in] vector The vector to subtract to a relation row.
1971 * \param[in] row The row of the relation to subtract the vector.
1973 void osl_relation_sub_vector(osl_relation_p relation,
1974 osl_vector_p vector, int row) {
1975 int i;
1977 if ((relation == NULL) || (vector == NULL) ||
1978 (relation->precision != vector->precision) ||
1979 (relation->nb_columns != vector->size) ||
1980 (row >= relation->nb_rows) || (row < 0))
1981 OSL_error("vector cannot be subtracted to row");
1983 if (osl_int_get_si(relation->precision, relation->m[row][0]) == 0)
1984 osl_int_assign(relation->precision, &relation->m[row][0], vector->v[0]);
1986 for (i = 1; i < vector->size; i++)
1987 osl_int_sub(relation->precision,
1988 &relation->m[row][i], relation->m[row][i], vector->v[i]);
1993 * osl_relation_insert_vector function:
1994 * this function inserts a new row corresponding to the vector "vector" to
1995 * the relation "relation" by inserting it at the "row"^th row of
1996 * "relation" (-1 is a shortcut to insert the vector after the constraints
1997 * of the relation). It directly updates the relation union part pointed
1998 * by "relation" and this part only. If "vector" (or "relation") is NULL,
1999 * the relation is left unmodified.
2000 * \param[in,out] relation The relation we want to extend.
2001 * \param[in] vector The vector that will be added relation.
2002 * \param[in] row The row where to insert the vector (-1 to
2003 * insert it after the relation constraints).
2005 void osl_relation_insert_vector(osl_relation_p relation,
2006 osl_vector_p vector, int row) {
2007 osl_relation_p temp;
2009 temp = osl_relation_from_vector(vector);
2010 osl_relation_insert_constraints(relation, temp, row);
2011 osl_relation_free(temp);
2016 * osl_relation_concat_vector function:
2017 * this function builds a new relation from one relation and a vector sent as
2018 * parameters. The new set of constraints is built as the concatenation
2019 * of the rows of the first part of the relation and of the vector
2020 * constraint. This means, there is no next field in the result.
2021 * \param[in] r The input relation.
2022 * \param[in] v The input vector.
2023 * \return A pointer to the relation resulting from the concatenation of
2024 * the constraints of the relation and of the vector.
2026 osl_relation_p osl_relation_concat_vector(osl_relation_p relation,
2027 osl_vector_p vector) {
2028 osl_relation_p new, temp;
2030 temp = osl_relation_from_vector(vector);
2031 new = osl_relation_concat_constraints(relation, temp);
2032 osl_relation_free(temp);
2033 return new;
2038 * osl_relation_insert_blank_row function:
2039 * this function inserts a new row filled with zeros o an existing relation
2040 * union part (it only affects the first union part).
2041 * \param[in,out] relation The relation to add a row in.
2042 * \param[in] row The row where to insert the blank row.
2044 void osl_relation_insert_blank_row(osl_relation_p relation, int row) {
2045 osl_vector_p vector;
2047 if (relation != NULL) {
2048 vector = osl_vector_pmalloc(relation->precision, relation->nb_columns);
2049 osl_relation_insert_vector(relation, vector, row);
2050 osl_vector_free(vector);
2056 * osl_relation_insert_blank_column function:
2057 * this function inserts a new column filled with zeros to an existing
2058 * relation union part (it only affects the first union part). WARNING:
2059 * this function does not update the relation attributes.
2060 * \param[in,out] relation The relation to add a column in.
2061 * \param[in] column The column where to insert the blank column.
2063 void osl_relation_insert_blank_column(osl_relation_p relation, int column) {
2065 int i, j;
2066 osl_relation_p temp;
2068 if (relation == NULL)
2069 return;
2071 if ((column < 0) || (column > relation->nb_columns))
2072 OSL_error("bad column number");
2074 // We use a temporary relation just to reuse existing functions. Cleaner.
2075 temp = osl_relation_pmalloc(relation->precision,
2076 relation->nb_rows, relation->nb_columns + 1);
2078 for (i = 0; i < relation->nb_rows; i++) {
2079 for (j = 0; j < column; j++)
2080 osl_int_assign(relation->precision, &temp->m[i][j], relation->m[i][j]);
2082 for (j = column; j < relation->nb_columns; j++)
2083 osl_int_assign(relation->precision, &temp->m[i][j+1], relation->m[i][j]);
2086 osl_relation_free_inside(relation);
2088 // Replace the inside of relation.
2089 relation->nb_columns = temp->nb_columns;
2090 relation->m = temp->m;
2092 // Free the temp "shell".
2093 free(temp);
2098 * osl_relation_from_vector function:
2099 * this function converts a vector "vector" to a relation with a single row
2100 * and returns a pointer to that relation.
2101 * \param[in] vector The vector to convert to a relation.
2102 * \return A pointer to a relation resulting from the vector conversion.
2104 osl_relation_p osl_relation_from_vector(osl_vector_p vector) {
2105 osl_relation_p relation;
2107 if (vector == NULL)
2108 return NULL;
2110 relation = osl_relation_pmalloc(vector->precision, 1, vector->size);
2111 osl_relation_replace_vector(relation, vector, 0);
2112 return relation;
2117 * osl_relation_replace_constraints function:
2118 * this function replaces some rows of a relation "r1" with the rows of
2119 * the relation "r2". It begins at the "row"^th row of "r1". It directly
2120 * updates the relation union part pointed by "r1" and this part only.
2121 * \param[in,out] r1 The relation we want to change some rows.
2122 * \param[in] r2 The relation containing the new rows.
2123 * \param[in] row The first row of the relation r1 to be replaced.
2125 void osl_relation_replace_constraints(osl_relation_p r1,
2126 osl_relation_p r2, int row) {
2127 int i, j;
2129 if ((r1 == NULL) || (r2 == NULL) ||
2130 (r1->precision != r2->precision) ||
2131 (r1->nb_columns != r1->nb_columns) ||
2132 ((row + r2->nb_rows) > r1->nb_rows) || (row < 0))
2133 OSL_error("relation rows could not be replaced");
2135 for (i = 0; i < r2->nb_rows; i++)
2136 for (j = 0; j < r2->nb_columns; j++)
2137 osl_int_assign(r1->precision, &r1->m[i+row][j], r2->m[i][j]);
2142 * osl_relation_insert_constraints function:
2143 * this function inserts the rows of the relation "r2" to the relation
2144 * "r1", starting from the "row"^th row of "r1" (-1 is a
2145 * shortcut to insert the "r2" constraints after the constraints of r1).
2146 * It directly updates the relation union part pointed by "r1" and this
2147 * part only. If "r2" (or "r1") is NULL, the relation is left unmodified.
2148 * \param[in,out] r1 The relation we want to extend.
2149 * \param[in] r2 The relation to be inserted.
2150 * \param[in] row The row where to insert the constraints (-1 to
2151 * insert them after those of "r1").
2153 void osl_relation_insert_constraints(osl_relation_p r1,
2154 osl_relation_p r2, int row) {
2155 int i, j;
2156 osl_relation_p temp;
2158 if ((r1 == NULL) || (r2 == NULL))
2159 return;
2161 if (row == -1)
2162 row = r1->nb_rows;
2164 if ((r1->nb_columns != r2->nb_columns) ||
2165 (r1->precision != r2->precision) ||
2166 (row > r1->nb_rows) || (row < 0))
2167 OSL_error("constraints cannot be inserted");
2169 // We use a temporary relation just to reuse existing functions. Cleaner.
2170 temp = osl_relation_pmalloc(r1->precision,
2171 r1->nb_rows + r2->nb_rows, r1->nb_columns);
2173 for (i = 0; i < row; i++)
2174 for (j = 0; j < r1->nb_columns; j++)
2175 osl_int_assign(r1->precision, &temp->m[i][j], r1->m[i][j]);
2177 osl_relation_replace_constraints(temp, r2, row);
2179 for (i = row + r2->nb_rows; i < r2->nb_rows + r1->nb_rows; i++)
2180 for (j = 0; j < r1->nb_columns; j++)
2181 osl_int_assign(r1->precision, &temp->m[i][j], r1->m[i-r2->nb_rows][j]);
2183 osl_relation_free_inside(r1);
2185 // Replace the inside of relation.
2186 r1->nb_rows = temp->nb_rows;
2187 r1->m = temp->m;
2189 // Free the temp "shell".
2190 free(temp);
2195 * osl_relation_swap_constraints function:
2196 * this function swaps two constraints (i.e., rows) of the relation matrix.
2197 * This function updates the relation directly.
2198 * \param[in,out] relation The relation to swap two rows (modified).
2199 * \param[in] c1 The row corresponding to the first constraint.
2200 * \param[in] c2 The row corresponding to the second constraint.
2202 void osl_relation_swap_constraints(osl_relation_p relation, int c1, int c2) {
2203 int i;
2205 if ((relation == NULL) || (c1 == c2))
2206 return;
2208 if ((c1 >= relation->nb_rows) || (c1 < 0) ||
2209 (c2 >= relation->nb_rows) || (c2 < 0))
2210 OSL_error("bad constraint rows");
2212 for (i = 0; i < relation->nb_columns; i++)
2213 osl_int_swap(relation->precision,
2214 &relation->m[c1][i], &relation->m[c2][i]);
2219 * osl_relation_remove_row function:
2220 * this function removes a given row to the relation "r". It directly
2221 * updates the relation union part pointed by "r" and this part only.
2222 * \param[in,out] r The relation to remove a row.
2223 * \param[in] row The row number to remove.
2225 void osl_relation_remove_row(osl_relation_p r, int row) {
2226 int i, j;
2227 osl_relation_p temp;
2229 if (r == NULL)
2230 return;
2232 if ((row < 0) || (row >= r->nb_rows))
2233 OSL_error("bad row number");
2235 // We use a temporary relation just to reuse existing functions. Cleaner.
2236 temp = osl_relation_pmalloc(r->precision,
2237 r->nb_rows - 1, r->nb_columns);
2239 for (i = 0; i < row; i++)
2240 for (j = 0; j < r->nb_columns; j++)
2241 osl_int_assign(r->precision, &temp->m[i][j], r->m[i][j]);
2243 for (i = row + 1; i < r->nb_rows; i++)
2244 for (j = 0; j < r->nb_columns; j++)
2245 osl_int_assign(r->precision, &temp->m[i - 1][j], r->m[i][j]);
2247 osl_relation_free_inside(r);
2249 // Replace the inside of relation.
2250 r->nb_rows = temp->nb_rows;
2251 r->m = temp->m;
2253 // Free the temp "shell".
2254 free(temp);
2259 * osl_relation_remove_column function:
2260 * this function removes a given column to the relation "r". It directly
2261 * updates the relation union part pointed by "r" and this part only.
2262 * \param[in,out] r The relation to remove a column.
2263 * \param[in] column The column number to remove.
2265 void osl_relation_remove_column(osl_relation_p r, int column) {
2266 int i, j;
2267 osl_relation_p temp;
2269 if (r == NULL)
2270 return;
2272 if ((column < 0) || (column >= r->nb_columns))
2273 OSL_error("bad column number");
2275 // We use a temporary relation just to reuse existing functions. Cleaner.
2276 temp = osl_relation_pmalloc(r->precision,
2277 r->nb_rows, r->nb_columns - 1);
2279 for (i = 0; i < r->nb_rows; i++) {
2280 for (j = 0; j < column; j++)
2281 osl_int_assign(r->precision, &temp->m[i][j], r->m[i][j]);
2283 for (j = column + 1; j < r->nb_columns; j++)
2284 osl_int_assign(r->precision, &temp->m[i][j - 1], r->m[i][j]);
2287 osl_relation_free_inside(r);
2289 // Replace the inside of relation.
2290 r->nb_columns = temp->nb_columns;
2291 r->m = temp->m;
2293 // Free the temp "shell".
2294 free(temp);
2299 * osl_relation_insert_columns function:
2300 * this function inserts new columns to an existing relation union part (it
2301 * only affects the first union part). The columns are copied out from the
2302 * matrix of an input relation which must have the convenient number of rows.
2303 * All columns of the input matrix are copied. WARNING: this function does not
2304 * update the relation attributes of the modified matrix.
2305 * \param[in,out] relation The relation to add columns in.
2306 * \param[in] insert The relation containing the columns to add.
2307 * \param[in] column The column where to insert the new columns.
2309 void osl_relation_insert_columns(osl_relation_p relation,
2310 osl_relation_p insert, int column) {
2311 int i, j;
2312 osl_relation_p temp;
2314 if ((relation == NULL) || (insert == NULL))
2315 return;
2317 if ((relation->precision != insert->precision) ||
2318 (relation->nb_rows != insert->nb_rows) ||
2319 (column < 0) || (column > relation->nb_columns))
2320 OSL_error("columns cannot be inserted");
2322 // We use a temporary relation just to reuse existing functions. Cleaner.
2323 temp = osl_relation_pmalloc(relation->precision, relation->nb_rows,
2324 relation->nb_columns + insert->nb_columns);
2326 for (i = 0; i < relation->nb_rows; i++) {
2327 for (j = 0; j < column; j++)
2328 osl_int_assign(relation->precision, &temp->m[i][j], relation->m[i][j]);
2330 for (j = column; j < column + insert->nb_columns; j++)
2331 osl_int_assign(relation->precision,
2332 &temp->m[i][j], insert->m[i][j - column]);
2334 for (j = column + insert->nb_columns;
2335 j < insert->nb_columns + relation->nb_columns; j++)
2336 osl_int_assign(relation->precision,
2337 &temp->m[i][j], relation->m[i][j - insert->nb_columns]);
2340 osl_relation_free_inside(relation);
2342 // Replace the inside of relation.
2343 relation->nb_columns = temp->nb_columns;
2344 relation->m = temp->m;
2346 // Free the temp "shell".
2347 free(temp);
2352 * osl_relation_concat_constraints function:
2353 * this function builds a new relation from two relations sent as
2354 * parameters. The new set of constraints is built as the concatenation
2355 * of the rows of the first elements of the two relation unions r1 and r2.
2356 * This means, there is no next field in the result.
2357 * \param[in] r1 The first relation.
2358 * \param[in] r2 The second relation.
2359 * \return A pointer to the relation resulting from the concatenation of
2360 * the first elements of r1 and r2.
2362 osl_relation_p osl_relation_concat_constraints(
2363 osl_relation_p r1,
2364 osl_relation_p r2) {
2365 osl_relation_p new;
2367 if (r1 == NULL)
2368 return osl_relation_clone(r2);
2370 if (r2 == NULL)
2371 return osl_relation_clone(r1);
2373 if (r1->nb_columns != r2->nb_columns)
2374 OSL_error("incompatible sizes for concatenation");
2376 if (r1->next || r2->next)
2377 OSL_warning("relation concatenation is done on the first elements "
2378 "of union only");
2380 new = osl_relation_pmalloc(r1->precision,
2381 r1->nb_rows + r2->nb_rows, r1->nb_columns);
2382 osl_relation_replace_constraints(new, r1, 0);
2383 osl_relation_replace_constraints(new, r2, r1->nb_rows);
2385 return new;
2390 * osl_relation_part_equal function:
2391 * this function returns true if the two relations parts provided as
2392 * parameters are the same, false otherwise. In the case of relation
2393 * unions, only the first part of the two relations are tested.
2394 * \param[in] r1 The first relation.
2395 * \param[in] r2 The second relation.
2396 * \return 1 if r1 and r2 are the same (content-wise), 0 otherwise.
2398 int osl_relation_part_equal(osl_relation_p r1, osl_relation_p r2) {
2399 int i, j;
2401 if (r1 == r2)
2402 return 1;
2404 if (((r1 == NULL) && (r2 != NULL)) ||
2405 ((r1 != NULL) && (r2 == NULL)))
2406 return 0;
2408 if ((r1->type != r2->type) ||
2409 (r1->precision != r2->precision) ||
2410 (r1->nb_rows != r2->nb_rows) ||
2411 (r1->nb_columns != r2->nb_columns) ||
2412 (r1->nb_output_dims != r2->nb_output_dims) ||
2413 (r1->nb_input_dims != r2->nb_input_dims) ||
2414 (r1->nb_local_dims != r2->nb_local_dims) ||
2415 (r1->nb_parameters != r2->nb_parameters))
2416 return 0;
2418 for (i = 0; i < r1->nb_rows; ++i)
2419 for (j = 0; j < r1->nb_columns; ++j)
2420 if (osl_int_ne(r1->precision, r1->m[i][j], r2->m[i][j]))
2421 return 0;
2423 return 1;
2428 * osl_relation_equal function:
2429 * this function returns true if the two relations provided as parameters
2430 * are the same, false otherwise.
2431 * \param[in] r1 The first relation.
2432 * \param[in] r2 The second relation.
2433 * \return 1 if r1 and r2 are the same (content-wise), 0 otherwise.
2435 int osl_relation_equal(osl_relation_p r1, osl_relation_p r2) {
2436 while ((r1 != NULL) && (r2 != NULL)) {
2437 if (!osl_relation_part_equal(r1, r2))
2438 return 0;
2440 r1 = r1->next;
2441 r2 = r2->next;
2444 if (((r1 == NULL) && (r2 != NULL)) || ((r1 != NULL) && (r2 == NULL)))
2445 return 0;
2447 return 1;
2452 * osl_relation_check_attribute internal function:
2453 * This function checks whether an "actual" value is the same as an
2454 * "expected" value or not. If the expected value is set to
2455 * OSL_UNDEFINED, this function sets it to the "actual" value
2456 * and do not report a difference has been detected.
2457 * It returns 0 if a difference has been detected, 1 otherwise.
2458 * \param[in,out] expected Pointer to the expected value (the value is
2459 * modified if it was set to OSL_UNDEFINED).
2460 * \param[in] actual Value we want to check.
2461 * \return 0 if the values are not the same while the expected value was
2462 * not OSL_UNDEFINED, 1 otherwise.
2464 static
2465 int osl_relation_check_attribute(int * expected, int actual) {
2466 if (*expected != OSL_UNDEFINED) {
2467 if ((actual != OSL_UNDEFINED) &&
2468 (actual != *expected)) {
2469 OSL_warning("unexpected atribute");
2470 return 0;
2473 else {
2474 *expected = actual;
2477 return 1;
2482 * osl_relation_check_nb_columns internal function:
2483 * This function checks that the number of columns of a relation
2484 * corresponds to some expected properties (setting an expected property to
2485 * OSL_UNDEFINED makes this function unable to detect a problem).
2486 * It returns 0 if the number of columns seems incorrect or 1 if no problem
2487 * has been detected.
2488 * \param[in] relation The relation we want to check the number of columns.
2489 * \param[in] expected_nb_output_dims Expected number of output dimensions.
2490 * \param[in] expected_nb_input_dims Expected number of input dimensions.
2491 * \param[in] expected_nb_parameters Expected number of parameters.
2492 * \return 0 if the number of columns seems incorrect, 1 otherwise.
2494 static
2495 int osl_relation_check_nb_columns(osl_relation_p relation,
2496 int expected_nb_output_dims,
2497 int expected_nb_input_dims,
2498 int expected_nb_parameters) {
2499 int expected_nb_local_dims, expected_nb_columns;
2501 if ((expected_nb_output_dims != OSL_UNDEFINED) &&
2502 (expected_nb_input_dims != OSL_UNDEFINED) &&
2503 (expected_nb_parameters != OSL_UNDEFINED)) {
2505 if (relation->nb_local_dims == OSL_UNDEFINED)
2506 expected_nb_local_dims = 0;
2507 else
2508 expected_nb_local_dims = relation->nb_local_dims;
2510 expected_nb_columns = expected_nb_output_dims +
2511 expected_nb_input_dims +
2512 expected_nb_local_dims +
2513 expected_nb_parameters +
2516 if (expected_nb_columns != relation->nb_columns) {
2517 OSL_warning("unexpected number of columns");
2518 return 0;
2522 return 1;
2527 * osl_relation_integrity_check function:
2528 * this function checks that a relation is "well formed" according to some
2529 * expected properties (setting an expected value to OSL_UNDEFINED means
2530 * that we do not expect a specific value) and what the relation is supposed
2531 * to represent. It returns 0 if the check failed or 1 if no problem has been
2532 * detected.
2533 * \param[in] relation The relation we want to check.
2534 * \param[in] expected_type Semantics about this relation (domain, access...).
2535 * \param[in] expected_nb_output_dims Expected number of output dimensions.
2536 * \param[in] expected_nb_input_dims Expected number of input dimensions.
2537 * \param[in] expected_nb_parameters Expected number of parameters.
2538 * \return 0 if the integrity check fails, 1 otherwise.
2540 int osl_relation_integrity_check(osl_relation_p relation,
2541 int expected_type,
2542 int expected_nb_output_dims,
2543 int expected_nb_input_dims,
2544 int expected_nb_parameters) {
2545 int i;
2547 // Check the NULL case.
2548 if (relation == NULL) {
2549 if ((expected_nb_output_dims != OSL_UNDEFINED) ||
2550 (expected_nb_input_dims != OSL_UNDEFINED) ||
2551 (expected_nb_parameters != OSL_UNDEFINED)) {
2552 OSL_debug("NULL relation with some expected attibutes");
2553 //return 0;
2556 return 1;
2559 // Check the type.
2560 if (((expected_type != OSL_TYPE_ACCESS) &&
2561 (expected_type != relation->type)) ||
2562 ((expected_type == OSL_TYPE_ACCESS) &&
2563 (!osl_relation_is_access(relation)))) {
2564 OSL_warning("wrong type");
2565 osl_relation_dump(stderr, relation);
2566 return 0;
2569 // Check that relations have no undefined atributes.
2570 if ((relation->nb_output_dims == OSL_UNDEFINED) ||
2571 (relation->nb_input_dims == OSL_UNDEFINED) ||
2572 (relation->nb_local_dims == OSL_UNDEFINED) ||
2573 (relation->nb_parameters == OSL_UNDEFINED)) {
2574 OSL_warning("all attributes should be defined");
2575 osl_relation_dump(stderr, relation);
2576 return 0;
2579 // Check that a context has actually 0 output dimensions.
2580 if ((relation->type == OSL_TYPE_CONTEXT) &&
2581 (relation->nb_output_dims != 0)) {
2582 OSL_warning("context without 0 as number of output dimensions");
2583 osl_relation_dump(stderr, relation);
2584 return 0;
2587 // Check that a domain or a context has actually 0 input dimensions.
2588 if (((relation->type == OSL_TYPE_DOMAIN) ||
2589 (relation->type == OSL_TYPE_CONTEXT)) &&
2590 (relation->nb_input_dims != 0)) {
2591 OSL_warning("domain or context without 0 input dimensions");
2592 osl_relation_dump(stderr, relation);
2593 return 0;
2596 // Check properties according to expected values (and if expected values
2597 // are undefined, define them with the first relation part properties).
2598 if (!osl_relation_check_attribute(&expected_nb_output_dims,
2599 relation->nb_output_dims) ||
2600 !osl_relation_check_attribute(&expected_nb_input_dims,
2601 relation->nb_input_dims) ||
2602 !osl_relation_check_attribute(&expected_nb_parameters,
2603 relation->nb_parameters)) {
2604 osl_relation_dump(stderr, relation);
2605 return 0;
2608 while (relation != NULL) {
2610 // Attributes (except the number of local dimensions) should be the same
2611 // in all parts of the union.
2612 if ((expected_nb_output_dims != relation->nb_output_dims) ||
2613 (expected_nb_input_dims != relation->nb_input_dims) ||
2614 (expected_nb_parameters != relation->nb_parameters)) {
2615 OSL_warning("inconsistent attributes");
2616 osl_relation_dump(stderr, relation);
2617 return 0;
2620 // Check whether the number of columns is OK or not.
2621 if (!osl_relation_check_nb_columns(relation,
2622 expected_nb_output_dims,
2623 expected_nb_input_dims,
2624 expected_nb_parameters)) {
2625 osl_relation_dump(stderr, relation);
2626 return 0;
2629 // Check the first column. The first column of a relation part should be
2630 // made of 0 or 1 only.
2631 if ((relation->nb_rows > 0) && (relation->nb_columns > 0)) {
2632 for (i = 0; i < relation->nb_rows; i++) {
2633 if (!osl_int_zero(relation->precision, relation->m[i][0]) &&
2634 !osl_int_one(relation->precision, relation->m[i][0])) {
2635 OSL_warning("first column of a relation is not "
2636 "strictly made of 0 or 1");
2637 osl_relation_dump(stderr, relation);
2638 return 0;
2643 // Array accesses must provide the array identifier.
2644 if ((osl_relation_is_access(relation)) &&
2645 (osl_relation_get_array_id(relation) == OSL_UNDEFINED)) {
2646 osl_relation_dump(stderr, relation);
2647 return 0;
2650 relation = relation->next;
2653 return 1;
2658 * osl_relation_set_attributes_one function:
2659 * this functions sets the attributes of a relation part provided as a
2660 * parameter. It updates the relation directly.
2661 * \param[in,out] relation The relation (union part) to set the attributes.
2662 * \param[in] nb_output_dims Number of output dimensions.
2663 * \param[in] nb_input_dims Number of input dimensions.
2664 * \param[in] nb_local_dims Number of local dimensions.
2665 * \param[in] nb_parameters Number of parameters.
2667 void osl_relation_set_attributes_one(osl_relation_p relation,
2668 int nb_output_dims, int nb_input_dims,
2669 int nb_local_dims, int nb_parameters) {
2670 if (relation != NULL) {
2671 relation->nb_output_dims = nb_output_dims;
2672 relation->nb_input_dims = nb_input_dims;
2673 relation->nb_local_dims = nb_local_dims;
2674 relation->nb_parameters = nb_parameters;
2680 * osl_relation_set_attributes function:
2681 * this functions sets the attributes of a relation (union) provided
2682 * as a parameter. It updates the relation directly.
2683 * \param[in,out] relation The relation (union) to set the attributes.
2684 * \param[in] nb_output_dims Number of output dimensions.
2685 * \param[in] nb_input_dims Number of input dimensions.
2686 * \param[in] nb_local_dims Number of local dimensions.
2687 * \param[in] nb_parameters Number of parameters.
2689 void osl_relation_set_attributes(osl_relation_p relation,
2690 int nb_output_dims, int nb_input_dims,
2691 int nb_local_dims, int nb_parameters) {
2692 while (relation != NULL) {
2693 osl_relation_set_attributes_one(relation,
2694 nb_output_dims, nb_input_dims,
2695 nb_local_dims, nb_parameters);
2696 relation = relation->next;
2701 /**
2702 * osl_relation_set_type function:
2703 * this function sets the type of each relation union part in the relation
2704 * to the one provided as parameter.
2705 * \param relation The relation to set the type.
2706 * \param type The type.
2708 void osl_relation_set_type(osl_relation_p relation, int type) {
2710 while (relation != NULL) {
2711 relation->type = type;
2712 relation = relation->next;
2718 * osl_relation_get_array_id function:
2719 * this function returns the array identifier in a relation with access type
2720 * It returns OSL_UNDEFINED if it is not able to find it (in particular
2721 * if there are irregularities in the relation).
2722 * \param[in] relation The relation where to find an array identifier.
2723 * \return The array identifier in the relation or OSL_UNDEFINED.
2725 int osl_relation_get_array_id(osl_relation_p relation) {
2726 int i;
2727 int first = 1;
2728 int array_id = OSL_UNDEFINED;
2729 int reference_array_id = OSL_UNDEFINED;
2730 int nb_array_id;
2731 int row_id = 0;
2732 int precision;
2734 if (relation == NULL)
2735 return OSL_UNDEFINED;
2737 if (!osl_relation_is_access(relation)) {
2738 OSL_warning("asked for an array id of non-array relation");
2739 return OSL_UNDEFINED;
2742 while (relation != NULL) {
2743 precision = relation->precision;
2745 // There should be room to store the array identifier.
2746 if ((relation->nb_rows < 1) ||
2747 (relation->nb_columns < 3)) {
2748 OSL_warning("no array identifier in an access function");
2749 return OSL_UNDEFINED;
2752 // Array identifiers are m[i][#columns -1] / m[i][1], with i the only row
2753 // where m[i][1] is not 0.
2754 // - check there is exactly one row such that m[i][1] is not 0,
2755 // - check the whole ith row if full of 0 except m[i][1] and the id,
2756 // - check that (m[i][#columns -1] % m[i][1]) == 0,
2757 // - check that (-m[i][#columns -1] / m[i][1]) > 0.
2758 nb_array_id = 0;
2759 for (i = 0; i < relation->nb_rows; i++) {
2760 if (!osl_int_zero(precision, relation->m[i][1])) {
2761 nb_array_id ++;
2762 row_id = i;
2765 if (nb_array_id == 0) {
2766 OSL_warning("no array identifier in an access function");
2767 return OSL_UNDEFINED;
2769 if (nb_array_id > 1) {
2770 OSL_warning("several array identifiers in one access function");
2771 return OSL_UNDEFINED;
2773 for (i = 0; i < relation->nb_columns - 1; i++) {
2774 if ((i != 1) && !osl_int_zero(precision, relation->m[row_id][i])) {
2775 OSL_warning("non integer array identifier");
2776 return OSL_UNDEFINED;
2779 if (!osl_int_divisible(precision,
2780 relation->m[row_id][relation->nb_columns - 1],
2781 relation->m[row_id][1])) {
2782 OSL_warning("rational array identifier");
2783 return OSL_UNDEFINED;
2785 array_id = -osl_int_get_si(precision,
2786 relation->m[row_id][relation->nb_columns - 1]);
2787 array_id /= osl_int_get_si(precision, relation->m[row_id][1]);
2788 if (array_id <= 0) {
2789 OSL_warning("negative or 0 identifier in access function");
2790 return OSL_UNDEFINED;
2793 // Unions of accesses are allowed, but they should refer at the same array.
2794 if (first) {
2795 reference_array_id = array_id;
2796 first = 0;
2798 else {
2799 if (reference_array_id != array_id) {
2800 OSL_warning("inconsistency of array identifiers in an "
2801 "union of access relations");
2802 return OSL_UNDEFINED;
2806 relation = relation->next;
2809 return array_id;
2814 * osl_relation_is_access function:
2815 * this function returns 1 if the relation corresponds to an access relation,
2816 * whatever its precise type (read, write etc.), 0 otherwise.
2817 * \param relation The relation to check wheter it is an access relation or not.
2818 * \return 1 if the relation is an access relation, 0 otherwise.
2820 int osl_relation_is_access(osl_relation_p relation) {
2822 if (relation == NULL)
2823 return 0;
2825 if ((relation->type == OSL_TYPE_ACCESS) ||
2826 (relation->type == OSL_TYPE_READ) ||
2827 (relation->type == OSL_TYPE_WRITE) ||
2828 (relation->type == OSL_TYPE_MAY_WRITE))
2829 return 1;
2831 return 0;
2836 * osl_relation_get_attributes function:
2837 * this function returns, through its parameters, the maximum values of the
2838 * relation attributes (nb_iterators, nb_parameters etc), depending on its
2839 * type. HOWEVER, it updates the parameter value iff the attribute is greater
2840 * than the input parameter value. Hence it may be used to get the
2841 * attributes as well as to find the maximum attributes for several relations.
2842 * The array identifier 0 is used when there is no array identifier (AND this
2843 * is OK), OSL_UNDEFINED is used to report it is impossible to provide the
2844 * property while it should. This function is not intended for checking, the
2845 * input relation should be correct.
2846 * \param[in] relation The relation to extract attribute values.
2847 * \param[in,out] nb_parameters Number of parameter attribute.
2848 * \param[in,out] nb_iterators Number of iterators attribute.
2849 * \param[in,out] nb_scattdims Number of scattering dimensions attribute.
2850 * \param[in,out] nb_localdims Number of local dimensions attribute.
2851 * \param[in,out] array_id Maximum array identifier attribute.
2853 void osl_relation_get_attributes(osl_relation_p relation,
2854 int * nb_parameters,
2855 int * nb_iterators,
2856 int * nb_scattdims,
2857 int * nb_localdims,
2858 int * array_id) {
2859 int type;
2860 int local_nb_parameters = OSL_UNDEFINED;
2861 int local_nb_iterators = OSL_UNDEFINED;
2862 int local_nb_scattdims = OSL_UNDEFINED;
2863 int local_nb_localdims = OSL_UNDEFINED;
2864 int local_array_id = OSL_UNDEFINED;
2866 while (relation != NULL) {
2867 if (osl_relation_is_access(relation))
2868 type = OSL_TYPE_ACCESS;
2869 else
2870 type = relation->type;
2872 // There is some redundancy but I believe the code is cleaner this way.
2873 switch (type) {
2874 case OSL_TYPE_CONTEXT:
2875 local_nb_parameters = relation->nb_parameters;
2876 local_nb_iterators = 0;
2877 local_nb_scattdims = 0;
2878 local_nb_localdims = relation->nb_local_dims;
2879 local_array_id = 0;
2880 break;
2882 case OSL_TYPE_DOMAIN:
2883 local_nb_parameters = relation->nb_parameters;
2884 local_nb_iterators = relation->nb_output_dims;
2885 local_nb_scattdims = 0;
2886 local_nb_localdims = relation->nb_local_dims;
2887 local_array_id = 0;
2888 break;
2890 case OSL_TYPE_SCATTERING:
2891 local_nb_parameters = relation->nb_parameters;
2892 local_nb_iterators = relation->nb_input_dims;
2893 local_nb_scattdims = relation->nb_output_dims;
2894 local_nb_localdims = relation->nb_local_dims;
2895 local_array_id = 0;
2896 break;
2898 case OSL_TYPE_ACCESS:
2899 local_nb_parameters = relation->nb_parameters;
2900 local_nb_iterators = relation->nb_input_dims;
2901 local_nb_scattdims = 0;
2902 local_nb_localdims = relation->nb_local_dims;
2903 local_array_id = osl_relation_get_array_id(relation);
2904 break;
2906 default:
2907 local_nb_parameters = relation->nb_parameters;
2908 local_nb_iterators = relation->nb_input_dims;
2909 local_nb_scattdims = relation->nb_output_dims;
2910 local_nb_localdims = relation->nb_local_dims;
2911 local_array_id = 0;
2914 // Update.
2915 *nb_parameters = OSL_max(*nb_parameters, local_nb_parameters);
2916 *nb_iterators = OSL_max(*nb_iterators, local_nb_iterators);
2917 *nb_scattdims = OSL_max(*nb_scattdims, local_nb_scattdims);
2918 *nb_localdims = OSL_max(*nb_localdims, local_nb_localdims);
2919 *array_id = OSL_max(*array_id, local_array_id);
2920 relation = relation->next;
2926 * osl_relation_extend_output function:
2927 * this function extends the number of output dimensions of a given relation. It
2928 * returns a copy of the input relation with a number of output dimensions
2929 * extended to "dim" for all its union components. The new output dimensions
2930 * are simply set equal to 0. The extended number of dimensions must be higher
2931 * than or equal to the original one (an error will be raised otherwise).
2932 * \param[in] relation The input relation to extend.
2933 * \param[in] dim The number of output dimension to reach.
2934 * \return A new relation: "relation" extended to "dim" output dims.
2936 osl_relation_p osl_relation_extend_output(osl_relation_p relation, int dim) {
2937 int i, j;
2938 int first = 1;
2939 int offset;
2940 int precision = relation->precision;
2941 osl_relation_p extended = NULL, node, previous = NULL;
2943 while (relation != NULL) {
2944 if (relation->nb_output_dims > dim)
2945 OSL_error("Number of output dims is greater than required extension");
2946 offset = dim - relation->nb_output_dims;
2948 node = osl_relation_pmalloc(precision,
2949 relation->nb_rows + offset,
2950 relation->nb_columns + offset);
2952 node->type = relation->type;
2953 node->nb_output_dims = OSL_max(relation->nb_output_dims, dim);
2954 node->nb_input_dims = relation->nb_input_dims;
2955 node->nb_local_dims = relation->nb_local_dims;
2956 node->nb_parameters = relation->nb_parameters;
2958 // Copy of the original relation with some 0 columns for the new dimensions
2959 // Note that we use the fact that the matrix is initialized with zeros.
2960 for (i = 0; i < relation->nb_rows; i++) {
2961 for (j = 0; j <= relation->nb_output_dims; j++)
2962 osl_int_assign(precision, &node->m[i][j], relation->m[i][j]);
2964 for (j = relation->nb_output_dims + offset + 1;
2965 j < relation->nb_columns + offset; j++)
2966 osl_int_assign(precision, &node->m[i][j], relation->m[i][j - offset]);
2969 // New rows dedicated to the new dimensions
2970 for (i = relation->nb_rows; i < relation->nb_rows + offset; i++) {
2971 for (j = 0; j < relation->nb_columns + offset; j++) {
2972 if ((i - relation->nb_rows) == (j - relation->nb_output_dims - 1))
2973 osl_int_set_si(precision, &node->m[i][j], -1);
2977 if (first) {
2978 first = 0;
2979 extended = node;
2980 previous = node;
2982 else {
2983 previous->next = node;
2984 previous = previous->next;
2987 relation = relation->next;
2990 return extended;
2995 * osl_relation_interface function:
2996 * this function creates an interface structure corresponding to the relation
2997 * and returns it.
2998 * \return An interface structure for the relation structure.
3000 osl_interface_p osl_relation_interface() {
3001 osl_interface_p interface = osl_interface_malloc();
3003 OSL_strdup(interface->URI, OSL_URI_RELATION);
3004 interface->idump = (osl_idump_f)osl_relation_idump;
3005 interface->sprint = (osl_sprint_f)osl_relation_sprint;
3006 interface->sread = (osl_sread_f)osl_relation_sread;
3007 interface->malloc = (osl_malloc_f)osl_relation_malloc;
3008 interface->free = (osl_free_f)osl_relation_free;
3009 interface->clone = (osl_clone_f)osl_relation_clone;
3010 interface->equal = (osl_equal_f)osl_relation_equal;
3012 return interface;
3017 * osl_relation_set_precision function:
3018 * this function changes the precision of the osl_relation
3019 * \param[in] precision Precision wanted for the relation
3020 * \param[in,out] r A osl relation to change the precision
3022 void osl_relation_set_precision(int const precision, osl_relation_p r) {
3023 while (r != NULL) {
3024 if (precision != r->precision) {
3025 size_t i;
3026 size_t j;
3027 for (i = 0; i < (size_t)r->nb_rows; ++i) {
3028 for (j = 0; j < (size_t)r->nb_columns; ++j) {
3029 osl_int_set_precision(r->precision, precision, &r->m[i][j]);
3032 r->precision = precision;
3034 r = r->next;
3040 * osl_relation_set_same_precision function:
3041 * this function gets the highest precision of the relations
3042 * and set this precision to the other relation if necessary
3043 * \param[in,out] a A osl relation to change the precision if necessary
3044 * \param[in,out] b A osl relation to change the precision if necessary
3046 void osl_relation_set_same_precision(osl_relation_p a, osl_relation_p b) {
3047 if (a != NULL && b != NULL && a->precision != b->precision) {
3048 if (a->precision == OSL_PRECISION_MP || b->precision == OSL_PRECISION_MP) {
3049 osl_relation_set_precision(OSL_PRECISION_MP, a);
3050 osl_relation_set_precision(OSL_PRECISION_MP, b);
3052 else if (a->precision == OSL_PRECISION_DP || b->precision == OSL_PRECISION_DP) {
3053 osl_relation_set_precision(OSL_PRECISION_DP, a);
3054 osl_relation_set_precision(OSL_PRECISION_DP, b);