Relation type also in the textual representation
[openscop.git] / source / relation.c
blob3615b7c686921fc41883e37a88be0dfccfb14142
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>
68 # include <openscop/relation.h>
71 /*+***************************************************************************
72 * Structure display function *
73 *****************************************************************************/
76 /**
77 * openscop_relation_dump_type function:
78 * this function displays the type of an openscop_relation_t structure into
79 * a file (file, possibly stdout).
80 * \param[in] file File where informations are printed.
81 * \param[in] relation The relation whose type has to be printed.
83 static
84 void openscop_relation_dump_type(FILE * file, openscop_relation_p relation) {
86 if (relation != NULL) {
87 switch (relation->type) {
88 case OPENSCOP_UNDEFINED: {
89 fprintf(file, "(undefined)\n");
90 break;
92 case OPENSCOP_TYPE_CONTEXT: {
93 fprintf(file, "(context)\n");
94 break;
96 case OPENSCOP_TYPE_DOMAIN: {
97 fprintf(file, "(domain)\n");
98 break;
100 case OPENSCOP_TYPE_SCATTERING: {
101 fprintf(file, "(scattering)\n");
102 break;
104 case OPENSCOP_TYPE_READ: {
105 fprintf(file, "(read access)\n");
106 break;
108 case OPENSCOP_TYPE_WRITE: {
109 fprintf(file, "(write access)\n");
110 break;
112 case OPENSCOP_TYPE_RDWR: {
113 fprintf(file, "(read-write access)\n");
114 break;
116 case OPENSCOP_TYPE_MAY_READ: {
117 fprintf(file, "(may read access)\n");
118 break;
120 case OPENSCOP_TYPE_MAY_WRITE: {
121 fprintf(file, "(may write access)\n");
122 break;
124 case OPENSCOP_TYPE_MAY_RDWR: {
125 fprintf(file, "(may read-write access)\n");
126 break;
128 default: {
129 fprintf(file, "(unknown type: %d)\n", relation->type);
130 break;
138 * openscop_relation_print_type function:
139 * this function displays the textual type of an openscop_relation_t structure
140 * into a file (file, possibly stdout), accoding to the OpenScop specification.
141 * \param[in] file File where informations are printed.
142 * \param[in] relation The relation whose type has to be printed.
144 static
145 void openscop_relation_print_type(FILE * file, openscop_relation_p relation) {
147 if (relation != NULL) {
148 switch (relation->type) {
149 case OPENSCOP_UNDEFINED: {
150 fprintf(file, OPENSCOP_STRING_UNDEFINED"\n");
151 break;
153 case OPENSCOP_TYPE_CONTEXT: {
154 fprintf(file, OPENSCOP_STRING_CONTEXT"\n");
155 break;
157 case OPENSCOP_TYPE_DOMAIN: {
158 fprintf(file, OPENSCOP_STRING_DOMAIN"\n");
159 break;
161 case OPENSCOP_TYPE_SCATTERING: {
162 fprintf(file, OPENSCOP_STRING_SCATTERING"\n");
163 break;
165 case OPENSCOP_TYPE_READ: {
166 fprintf(file, OPENSCOP_STRING_READ"\n");
167 break;
169 case OPENSCOP_TYPE_WRITE: {
170 fprintf(file, OPENSCOP_STRING_WRITE"\n");
171 break;
173 case OPENSCOP_TYPE_RDWR: {
174 fprintf(file, OPENSCOP_STRING_RDWR"\n");
175 break;
177 case OPENSCOP_TYPE_MAY_READ: {
178 fprintf(file, OPENSCOP_STRING_MAY_READ"\n");
179 break;
181 case OPENSCOP_TYPE_MAY_WRITE: {
182 fprintf(file, OPENSCOP_STRING_MAY_WRITE"\n");
183 break;
185 case OPENSCOP_TYPE_MAY_RDWR: {
186 fprintf(file, OPENSCOP_STRING_MAY_RDWR"\n");
187 break;
189 default: {
190 fprintf(stderr, "[OpenScop] Warning: unknown relation type (%d) "
191 "replaced with "OPENSCOP_STRING_UNDEFINED".\n",
192 relation->type);
193 fprintf(file, OPENSCOP_STRING_UNDEFINED"\n");
201 * openscop_relation_print_structure function:
202 * this function displays a openscop_relation_t structure (*relation) into a
203 * file (file, possibly stdout) in a way that trends to be understandable.
204 * It includes an indentation level (level) in order to work with others
205 * print_structure functions.
206 * \param[in] file File where informations are printed.
207 * \param[in] relation The relation whose information has to be printed.
208 * \param[in] level Number of spaces before printing, for each line.
210 void openscop_relation_print_structure(FILE * file,
211 openscop_relation_p relation,
212 int level) {
213 int i, j, first = 1;
215 // Go to the right level.
216 for (j = 0; j < level; j++)
217 fprintf(file, "|\t");
219 if (relation != NULL) {
220 fprintf(file, "+-- openscop_relation_t ");
221 openscop_relation_dump_type(file, relation);
223 else {
224 fprintf(file, "+-- NULL relation\n");
227 while (relation != NULL) {
228 if (! first) {
229 // Go to the right level.
230 for (j = 0; j < level; j++)
231 fprintf(file, "|\t");
232 fprintf(file, "| openscop_relation_t ");
233 openscop_relation_dump_type(file, relation);
235 else
236 first = 0;
238 // A blank line
239 for(j = 0; j <= level; j++)
240 fprintf(file, "|\t");
241 fprintf(file, "%d %d %d %d %d %d\n",
242 relation->nb_rows, relation->nb_columns,
243 relation->nb_output_dims, relation->nb_input_dims,
244 relation->nb_local_dims, relation->nb_parameters);
246 // Display the relation.
247 for (i = 0; i < relation->nb_rows; i++) {
248 for (j = 0; j <= level; j++)
249 fprintf(file, "|\t");
251 fprintf(file, "[ ");
253 for (j = 0; j < relation->nb_columns; j++) {
254 SCOPINT_print(file, OPENSCOP_FMT, relation->m[i][j]);
255 fprintf(file, " ");
258 fprintf(file, "]\n");
261 relation = relation->next;
263 // Next line.
264 if (relation != NULL) {
265 for (j = 0; j <= level; j++)
266 fprintf(file, "|\t");
267 fprintf(file, "|\n");
268 for (j = 0; j <= level; j++)
269 fprintf(file, "|\t");
270 fprintf(file, "V\n");
274 // The last line.
275 for (j = 0; j <= level; j++)
276 fprintf(file, "|\t");
277 fprintf(file, "\n");
282 * openscop_relation_print function:
283 * this function prints the content of a openscop_relation_t structure
284 * (*relation) into a file (file, possibly stdout).
285 * \param[in] file File where informations are printed.
286 * \param[in] relation The relation whose information have to be printed.
288 void openscop_relation_print(FILE * file, openscop_relation_p relation) {
289 openscop_relation_print_structure(file, relation, 0);
295 * openscop_relation_expression_element function:
296 * this function returns a string containing the printing of a value (possibly
297 * an iterator or a parameter with its coefficient or a constant).
298 * \param[in] val The coefficient or constant value.
299 * \param[in,out] first Pointer to a boolean set to 1 if the current value is
300 * the first of an expresion, 0 otherwise (maybe updated).
301 * \param[in] cst A boolean set to 1 if the value is a constant,
302 * 0 otherwise.
303 * \param[in] name String containing the name of the element.
304 * \return A string that contains the printing of a value.
306 static
307 char * openscop_relation_expression_element(openscop_int_t val, int * first,
308 int cst, char * name) {
309 char * temp = (char *)malloc(OPENSCOP_MAX_STRING * sizeof(char));
310 char * body = (char *)malloc(OPENSCOP_MAX_STRING * sizeof(char));
311 char * sval = (char *)malloc(OPENSCOP_MAX_STRING * sizeof(char));
313 body[0] = '\0';
314 sval[0] = '\0';
316 // statements for the 'normal' processing.
317 if (SCOPINT_notzero_p(val) && (!cst)) {
318 if ((*first) || SCOPINT_neg_p(val)) {
319 if (SCOPINT_one_p(val)) { // case 1
320 sprintf(sval, "%s", name);
322 else {
323 if (SCOPINT_mone_p(val)) { // case -1
324 sprintf(sval, "-%s", name);
326 else { // default case
327 SCOPINT_sprint(sval, OPENSCOP_FMT_TXT, val);
328 sprintf(temp, "*%s", name);
329 strcat(sval, temp);
332 *first = 0;
334 else {
335 if (SCOPINT_one_p(val)) {
336 sprintf(sval, "+%s", name);
338 else {
339 sprintf(sval, "+");
340 SCOPINT_sprint(temp, OPENSCOP_FMT_TXT, val);
341 strcat(sval, temp);
342 sprintf(temp, "*%s", name);
343 strcat(sval, temp);
347 else {
348 if (cst) {
349 if ((SCOPINT_zero_p(val) && (*first)) || SCOPINT_neg_p(val))
350 SCOPINT_sprint(sval, OPENSCOP_FMT_TXT, val);
351 if (SCOPINT_pos_p(val)) {
352 if (!(*first)) {
353 SCOPINT_sprint(sval, "+"OPENSCOP_FMT_TXT, val); // Block macro !
355 else {
356 SCOPINT_sprint(sval, OPENSCOP_FMT_TXT, val);
361 free(temp);
362 free(body);
364 return(sval);
369 * openscop_relation_expression function:
370 * this function returns a string corresponding to an affine expression
371 * stored at the "row"^th row of the relation pointed by "relation".
372 * \param[in] relation A set of linear expressions.
373 * \param[in] row The row corresponding to the expression.
374 * \param[in] names The textual names of the various elements. Is is
375 * important that names->nb_parameters is exact if the
376 * matrix representation is used. Set to NULL if
377 * printing comments is not needed.
378 * \return A string that contains the printing of an affine expression.
380 char * openscop_relation_expression(openscop_relation_p relation,
381 int row, openscop_names_p names) {
382 int i, first = 1;
383 char * sval;
384 char * sline = (char *)malloc(OPENSCOP_MAX_STRING * sizeof(char));
385 sline[0] = '\0';
387 // First the iterator part.
388 for (i = 1; i <= names->nb_iterators; i++) {
389 sval = openscop_relation_expression_element(
390 relation->m[row][i], &first, 0, names->iterators[i-1]);
391 strcat(sline, sval);
392 free(sval);
395 // Next the local dims part.
396 for (i = names->nb_iterators + 1;
397 i <= names->nb_iterators + names->nb_localdims; i++) {
398 sval = openscop_relation_expression_element(
399 relation->m[row][i], &first, 0,
400 names->localdims[i - names->nb_iterators - 1]);
401 strcat(sline, sval);
402 free(sval);
405 // Next the parameter part.
406 for (i = names->nb_iterators + names->nb_localdims + 1;
407 i <= names->nb_iterators + names->nb_localdims + names->nb_parameters;
408 i++) {
409 sval = openscop_relation_expression_element(
410 relation->m[row][i], &first, 0,
411 names->parameters[i - names->nb_iterators - names->nb_localdims - 1]);
412 strcat(sline, sval);
413 free(sval);
416 // Finally the constant part (yes, I reused it).
417 sval = openscop_relation_expression_element(relation->m[row][i],
418 &first, 1, NULL);
419 strcat(sline, sval);
420 free(sval);
422 return sline;
427 * openscop_relation_is_access function:
428 * this function returns 1 if the relation corresponds to an access relation,
429 * whatever its precise type (read, write etc.), 0 otherwise.
430 * \param relation The relation to check wheter it is an access relation or not.
431 * \return 1 if the relation is an access relation, 0 otherwise.
433 static
434 int openscop_relation_is_access(openscop_relation_p relation) {
436 if ((relation->type == OPENSCOP_TYPE_ACCESS) ||
437 (relation->type == OPENSCOP_TYPE_READ) ||
438 (relation->type == OPENSCOP_TYPE_WRITE) ||
439 (relation->type == OPENSCOP_TYPE_RDWR) ||
440 (relation->type == OPENSCOP_TYPE_MAY_READ) ||
441 (relation->type == OPENSCOP_TYPE_MAY_WRITE) ||
442 (relation->type == OPENSCOP_TYPE_MAY_RDWR))
443 return 1;
445 return 0;
450 * openscop_relation_properties function:
451 * this function returns, through its parameters, the values of every possible
452 * "property" (nb_iterators, nb_parameters etc) of a relation, depending on
453 * its value, its representation and its type. The array identifier 0 is used
454 * when there is no array identifier (AND this is OK), OPENSCOP_UNDEFINED is
455 * used to report it is impossible to provide the property while it should.
456 * This function is not intended for checking, the input relation should be
457 * correct. The parameter nb_parameters is an input in matrix representation.
458 * \param[in] relation The relation to extract property values.
459 * \param[in,out] nb_parameters Number of parameter property.
460 * \param[out] nb_iterators Number of iterators property.
461 * \param[out] nb_scattdims Number of scattering dimensions property.
462 * \param[out] nb_localdims Number of local dimensions property.
463 * \param[out] array_id Array identifier property.
465 static
466 void openscop_relation_properties(openscop_relation_p relation,
467 int * nb_parameters,
468 int * nb_iterators,
469 int * nb_scattdims,
470 int * nb_localdims,
471 int * array_id) {
473 int is_matrix = openscop_relation_is_matrix(relation);
474 int type;
476 if (!is_matrix)
477 *nb_parameters = OPENSCOP_UNDEFINED;
478 *nb_iterators = OPENSCOP_UNDEFINED;
479 *nb_scattdims = OPENSCOP_UNDEFINED;
480 *nb_localdims = OPENSCOP_UNDEFINED;
481 *array_id = OPENSCOP_UNDEFINED;
483 if (relation == NULL)
484 return;
486 if (openscop_relation_is_access(relation))
487 type = OPENSCOP_TYPE_ACCESS;
488 else
489 type = relation->type;
491 // There is some redundancy but I believe the code is cleaner this way.
492 switch (type) {
493 case OPENSCOP_TYPE_CONTEXT: {
494 if (is_matrix) {
495 *nb_parameters = *nb_parameters;
496 *nb_iterators = 0;
497 *nb_scattdims = 0;
498 *nb_localdims = 0;
499 *array_id = 0;
501 else {
502 *nb_parameters = relation->nb_parameters;
503 *nb_iterators = 0;
504 *nb_scattdims = 0;
505 *nb_localdims = relation->nb_local_dims;
506 *array_id = 0;
508 break;
510 case OPENSCOP_TYPE_DOMAIN: {
511 if (is_matrix) {
512 *nb_parameters = *nb_parameters;
513 *nb_iterators = relation->nb_columns - *nb_parameters - 2;
514 *nb_scattdims = 0;
515 *nb_localdims = 0;
516 *array_id = 0;
518 else {
519 *nb_parameters = relation->nb_parameters;
520 *nb_iterators = relation->nb_output_dims;
521 *nb_scattdims = 0;
522 *nb_localdims = relation->nb_local_dims;
523 *array_id = 0;
525 break;
527 case OPENSCOP_TYPE_SCATTERING: {
528 if (is_matrix) {
529 *nb_parameters = *nb_parameters;
530 *nb_iterators = relation->nb_columns - *nb_parameters - 2;
531 *nb_scattdims = relation->nb_rows;
532 *nb_localdims = 0;
533 *array_id = 0;
535 else {
536 *nb_parameters = relation->nb_parameters;
537 *nb_iterators = relation->nb_input_dims;
538 *nb_scattdims = relation->nb_output_dims;
539 *nb_localdims = relation->nb_local_dims;
540 *array_id = 0;
542 break;
544 case OPENSCOP_TYPE_ACCESS: {
545 if (is_matrix) {
546 *nb_parameters = *nb_parameters;
547 *nb_iterators = relation->nb_columns - *nb_parameters - 2;
548 *nb_scattdims = 0;
549 *nb_localdims = 0;
550 *array_id = openscop_relation_get_array_id(relation);
552 else {
553 *nb_parameters = relation->nb_parameters;
554 *nb_iterators = relation->nb_input_dims;
555 *nb_scattdims = 0;
556 *nb_localdims = relation->nb_local_dims;
557 *array_id = openscop_relation_get_array_id(relation);
559 break;
566 * openscop_relation_printable_comments function:
567 * this function returns 1 if we can print safely the comments for the
568 * relation provided as parameter (in the OpenScop file), 0 otherwise.
569 * \param[in] relation The relation we want to know if we can print comments.
570 * \param[in] names The names used for comment printing.
571 * \return 1 if we can print the comments safely, 0 otherwise.
573 static
574 int openscop_relation_printable_comments(openscop_relation_p relation,
575 openscop_names_p names) {
576 int nb_parameters;
577 int nb_iterators;
578 int nb_scattdims;
579 int nb_localdims;
580 int array_id;
582 if ((relation == NULL) || (names == NULL))
583 return 0;
585 // TODO: remove this !!!
586 // Temporarily deactivate comments for relations, to finish OpenScop
587 // RFC first.
588 if (openscop_relation_is_matrix(relation))
589 return 0;
591 // We cannot print comments if the names are not textual.
592 if (names->textual != 1)
593 return 0;
595 // We cannot print comments if the relation is not of one known type.
596 if (!(relation->type == OPENSCOP_TYPE_DOMAIN) &&
597 !(relation->type == OPENSCOP_TYPE_SCATTERING) &&
598 !(relation->type == OPENSCOP_TYPE_ACCESS))
599 return 0;
601 // We cannot print comments if we are not sure we have enough names.
602 nb_parameters = names->nb_parameters;
603 openscop_relation_properties(relation, &nb_parameters, &nb_iterators,
604 &nb_scattdims, &nb_localdims, &array_id);
606 if ((nb_parameters == OPENSCOP_UNDEFINED) ||
607 (nb_iterators == OPENSCOP_UNDEFINED) ||
608 (nb_scattdims == OPENSCOP_UNDEFINED) ||
609 (nb_localdims == OPENSCOP_UNDEFINED) ||
610 (array_id == OPENSCOP_UNDEFINED) ||
611 (nb_parameters > names->nb_parameters) ||
612 (nb_iterators > names->nb_iterators) ||
613 (nb_scattdims > names->nb_scattdims) ||
614 (nb_localdims > names->nb_localdims) ||
615 (array_id > names->nb_arrays)) {
617 fprintf(stderr, "[OpenScop] Warning: something is wrong with the names or "
618 "an array identifier, printing comments deactivated.\n");
619 return 0;
622 return 1;
627 * openscop_relation_print_comment function:
628 * this function prints a comment corresponding to a constraint of a relation,
629 * according to its type and representation. This function does not check that
630 * printing the comment is possible (i.e., are there enough names ?), hence it
631 * is the responsibility of the user to ensure he/she can call this function
632 * safely.
633 * \param[in] file File where informations are printed.
634 * \param[in] relation The relation for which a comment has to be printed.
635 * \param[in] row The constrain row for which a comment has to be printed.
636 * \param[in] names The textual names of the various elements. Is is
637 * important that names->nb_parameters is exact if the
638 * matrix representation is used.
640 static
641 void openscop_relation_print_comment(FILE * file,
642 openscop_relation_p relation, int row,
643 openscop_names_p names) {
644 int k;
645 int type;
646 char * expression;
648 if (openscop_relation_is_access(relation))
649 type = OPENSCOP_TYPE_ACCESS;
650 else
651 type = relation->type;
653 switch (type) {
654 case OPENSCOP_TYPE_DOMAIN: {
655 expression = openscop_relation_expression(relation, row, names);
656 fprintf(file, " ## %s", expression);
657 free(expression);
658 if (SCOPINT_zero_p(relation->m[row][0]))
659 fprintf(file, " == 0");
660 else
661 fprintf(file, " >= 0");
662 break;
664 case OPENSCOP_TYPE_SCATTERING: {
665 expression = openscop_relation_expression(relation, row, names);
666 fprintf(file, " ## %s", expression);
667 free(expression);
668 break;
670 case OPENSCOP_TYPE_ACCESS: {
671 //TODO: works only for matrix: use openscop_relation_get_array_id
672 if (SCOPINT_notzero_p(relation->m[row][0])) {
673 if (strncmp(names->arrays[SCOPINT_get_si(relation->m[row][0]) - 1],
674 OPENSCOP_FAKE_ARRAY, strlen(OPENSCOP_FAKE_ARRAY)))
675 fprintf(file, " ## %s",
676 names->arrays[SCOPINT_get_si(relation->m[row][0]) - 1]);
677 k = row;
678 do {
679 expression = openscop_relation_expression(relation, k, names);
680 fprintf(file, "[%s]", expression);
681 free(expression);
682 k++;
684 while ((k < relation->nb_rows) &&
685 SCOPINT_zero_p(relation->m[k][0]));
687 else {
688 fprintf(file, " ##");
696 * openscop_relation_print_openscop function:
697 * this function prints the content of a openscop_relation_t structure
698 * (*relation) into a file (file, possibly stdout) in the OpenScop format.
699 * \param[in] file File where informations are printed.
700 * \param[in] relation The relation whose information has to be printed.
701 * \param[in] names The textual names of the various elements. Is is
702 * important that names->nb_parameters is exact if the
703 * matrix representation is used. Set to NULL if printing
704 * comments is not needed.
706 void openscop_relation_print_openscop(FILE * file,
707 openscop_relation_p relation,
708 openscop_names_p names) {
709 int i, j;
710 int part, nb_parts;
711 int printable_comments;
712 openscop_relation_p r;
714 if (relation == NULL) {
715 fprintf(stderr, "[OpenScop] Warning: asked to print a NULL relation.\n");
716 fprintf(file, "# NULL relation\n");
717 return;
720 printable_comments = openscop_relation_printable_comments(relation, names);
722 // Count the number of parts in the union and print it if it is not 1.
723 r = relation;
724 nb_parts = 0;
725 while (r != NULL) {
726 nb_parts++;
727 r = r->next;
730 if (nb_parts > 0)
731 openscop_relation_print_type(file, relation);
733 if (nb_parts > 1)
734 fprintf(file, "# Union with %d parts\n%d\n", nb_parts, nb_parts);
736 // Print each part of the union.
737 for (part = 1; part <= nb_parts; part++) {
738 if (nb_parts > 1)
739 fprintf(file, "# Union part No.%d\n", part);
740 if ((relation->nb_output_dims == OPENSCOP_UNDEFINED) &&
741 (relation->nb_input_dims == OPENSCOP_UNDEFINED) &&
742 (relation->nb_local_dims == OPENSCOP_UNDEFINED) &&
743 (relation->nb_parameters == OPENSCOP_UNDEFINED))
744 fprintf(file, "%d %d\n", relation->nb_rows, relation->nb_columns);
745 else
746 fprintf(file, "%d %d %d %d %d %d\n",
747 relation->nb_rows, relation->nb_columns,
748 relation->nb_output_dims, relation->nb_input_dims,
749 relation->nb_local_dims, relation->nb_parameters);
751 for (i = 0; i < relation->nb_rows; i++) {
752 for (j = 0; j < relation->nb_columns; j++) {
753 SCOPINT_print(file, OPENSCOP_FMT, relation->m[i][j]);
754 fprintf(file, " ");
757 if (printable_comments)
758 openscop_relation_print_comment(file, relation, i, names);
760 fprintf(file, "\n");
762 relation = relation->next;
767 /*****************************************************************************
768 * Reading function *
769 *****************************************************************************/
773 * openscop_relation_read_type function:
774 * this function reads a textual relation type and returns its integer
775 * counterpart.
776 * \param[in] file The input stream.
777 * \return The relation type.
779 static
780 int openscop_relation_read_type(FILE * file) {
781 int nb_strings;
782 int type;
783 char ** strings;
785 strings = openscop_util_strings_read(file, &nb_strings);
786 if (nb_strings > 1) {
787 fprintf(stderr, "[OpenScop] Warning: uninterpreted information "
788 "(after relation type).\n");
790 if (nb_strings == 0) {
791 fprintf(stderr, "[OpenScop] Error: no relation type.\n");
792 exit(1);
795 if (!strcmp(strings[0], OPENSCOP_STRING_UNDEFINED)) {
796 type = OPENSCOP_UNDEFINED;
797 goto return_type;
800 if (!strcmp(strings[0], OPENSCOP_STRING_CONTEXT)) {
801 type = OPENSCOP_TYPE_CONTEXT;
802 goto return_type;
805 if (!strcmp(strings[0], OPENSCOP_STRING_DOMAIN)) {
806 type = OPENSCOP_TYPE_DOMAIN;
807 goto return_type;
810 if (!strcmp(strings[0], OPENSCOP_STRING_SCATTERING)) {
811 type = OPENSCOP_TYPE_SCATTERING;
812 goto return_type;
815 if (!strcmp(strings[0], OPENSCOP_STRING_READ)) {
816 type = OPENSCOP_TYPE_READ;
817 goto return_type;
820 if (!strcmp(strings[0], OPENSCOP_STRING_WRITE)) {
821 type = OPENSCOP_TYPE_WRITE;
822 goto return_type;
825 if (!strcmp(strings[0], OPENSCOP_STRING_RDWR)) {
826 type = OPENSCOP_TYPE_RDWR;
827 goto return_type;
830 if (!strcmp(strings[0], OPENSCOP_STRING_MAY_READ)) {
831 type = OPENSCOP_TYPE_MAY_READ;
832 goto return_type;
835 if (!strcmp(strings[0], OPENSCOP_STRING_MAY_WRITE)) {
836 type = OPENSCOP_TYPE_MAY_WRITE;
837 goto return_type;
840 if (!strcmp(strings[0], OPENSCOP_STRING_MAY_RDWR)) {
841 type = OPENSCOP_TYPE_CONTEXT;
842 goto return_type;
845 fprintf(stderr, "[OpenScop] Error: relation type not supported "
846 "(%s).\n", strings[0]);
847 exit(1);
849 return_type:
850 openscop_util_strings_free(strings, nb_strings);
851 return type;
856 * openscop_relation_read function:
857 * this function reads a relation into a file (foo, posibly stdin) and
858 * returns a pointer this relation.
859 * \param[in] file The input stream.
860 * \return A pointer to the relation structure that has been read.
862 openscop_relation_p openscop_relation_read(FILE * foo) {
863 int i, j, k, n, read = 0;
864 int nb_rows, nb_columns;
865 int nb_output_dims, nb_input_dims, nb_local_dims, nb_parameters;
866 int nb_union_parts = 1;
867 int may_read_nb_union_parts = 1;
868 int read_properties = 1;
869 int first = 1;
870 int type;
871 char * c, s[OPENSCOP_MAX_STRING], str[OPENSCOP_MAX_STRING];
872 openscop_relation_p relation, relation_union = NULL, previous = NULL;
873 openscop_int_t * p = NULL;
875 type = openscop_relation_read_type(foo);
877 // Read each part of the union (the number of parts may be updated inside)
878 for (k = 0; k < nb_union_parts; k++) {
879 // Read the number of union parts or the properties of the union part
880 while (read_properties) {
881 read_properties = 0;
883 // Read relation properties.
884 c = openscop_util_skip_blank_and_comments(foo, s);
885 read = sscanf(c, " %d %d %d %d %d %d", &nb_rows, &nb_columns,
886 &nb_output_dims, &nb_input_dims,
887 &nb_local_dims, &nb_parameters);
889 if (((read != 1) && (read != 2) && (read != 6)) ||
890 ((read == 1) && (may_read_nb_union_parts != 1))) {
891 fprintf(stderr, "[OpenScop] Error: badly formated relation.\n");
892 exit(1);
895 if (read == 1) {
896 // Only one number means a union and is the number of parts.
897 nb_union_parts = nb_rows;
898 if (nb_union_parts < 1) {
899 fprintf(stderr, "[OpenScop] Error: negative nb of union parts.\n");
900 exit(1);
902 // Allow to read the properties of the first part of the union.
903 read_properties = 1;
906 if (read == 2) {
907 nb_output_dims = OPENSCOP_UNDEFINED;
908 nb_input_dims = OPENSCOP_UNDEFINED;
909 nb_local_dims = OPENSCOP_UNDEFINED;
910 nb_parameters = OPENSCOP_UNDEFINED;
913 may_read_nb_union_parts = 0;
916 // Allocate the union part and fill its properties.
917 relation = openscop_relation_malloc(nb_rows, nb_columns);
918 relation->type = type;
919 relation->nb_output_dims = nb_output_dims;
920 relation->nb_input_dims = nb_input_dims;
921 relation->nb_local_dims = nb_local_dims;
922 relation->nb_parameters = nb_parameters;
924 // Read the matrix of constraints.
925 if ((relation->nb_rows != 0) && (relation->nb_columns != 0))
926 p = relation->m[0];
928 for (i = 0; i < relation->nb_rows; i++) {
929 c = openscop_util_skip_blank_and_comments(foo, s);
930 if (c == NULL) {
931 fprintf(stderr, "[OpenScop] Error: not enough rows.\n");
932 exit(1);
935 for (j = 0; j < relation->nb_columns; j++) {
936 if (c == NULL || *c == '#' || *c == '\n') {
937 fprintf(stderr, "[OpenScop] Error: not enough columns.\n");
938 exit(1);
940 if (sscanf(c, "%s%n", str, &n) == 0) {
941 fprintf(stderr, "[OpenScop] Error: not enough rows.\n");
942 exit(1);
944 #if defined(OPENSCOP_INT_T_IS_MP)
945 long long val;
946 if (sscanf(str, "%lld", &val) == 0) {
947 fprintf(stderr, "[OpenScop] Error: failed to read an integer.\n");
948 exit(1);
950 mpz_set_si(*p++, val);
951 #else
952 if (sscanf(str, OPENSCOP_FMT_TXT, p++) == 0) {
953 fprintf(stderr, "[OpenScop] Error: failed to read an integer.\n");
954 exit(1);
956 #endif
957 c += n;
961 // Build the linked list of union parts.
962 if (first == 1) {
963 relation_union = relation;
964 first = 0;
966 else {
967 previous->next = relation;
970 previous = relation;
971 read_properties = 1;
974 return relation_union;
978 /*+***************************************************************************
979 * Memory allocation/deallocation function *
980 *****************************************************************************/
984 * openscop_relation_malloc function:
985 * this function allocates the memory space for a openscop_relation_t
986 * structure and sets its fields with default values. Then it returns a
987 * pointer to the allocated space.
988 * \param[in] nb_rows The number of row of the relation to allocate.
989 * \param[in] nb_columns The number of columns of the relation to allocate.
990 * \return A pointer to an empty relation with fields set to default values
991 * and a ready-to-use constraint matrix.
993 openscop_relation_p openscop_relation_malloc(int nb_rows, int nb_columns) {
994 openscop_relation_p relation;
995 openscop_int_t ** p, * q;
996 int i, j;
998 relation = (openscop_relation_p)malloc(sizeof(openscop_relation_t));
999 if (relation == NULL) {
1000 fprintf(stderr, "[OpenScop] Error: memory Overflow.\n");
1001 exit(1);
1004 relation->type = OPENSCOP_UNDEFINED;
1005 relation->nb_rows = nb_rows;
1006 relation->nb_columns = nb_columns;
1007 relation->nb_output_dims = OPENSCOP_UNDEFINED;
1008 relation->nb_input_dims = OPENSCOP_UNDEFINED;
1009 relation->nb_parameters = OPENSCOP_UNDEFINED;
1010 relation->nb_local_dims = OPENSCOP_UNDEFINED;
1012 if ((nb_rows == 0) || (nb_columns == 0) ||
1013 (nb_rows == OPENSCOP_UNDEFINED) || (nb_columns == OPENSCOP_UNDEFINED)) {
1014 relation->m = NULL;
1016 else {
1017 p = (openscop_int_t **)malloc(nb_rows * sizeof(openscop_int_t *));
1018 if (p == NULL) {
1019 fprintf(stderr, "[OpenScop] Error: memory Overflow.\n");
1020 exit(1);
1022 q = (openscop_int_t *)malloc(nb_rows*nb_columns*sizeof(openscop_int_t));
1023 if (q == NULL) {
1024 fprintf(stderr, "[OpenScop] Error: memory Overflow.\n");
1025 exit(1);
1027 relation->m = p;
1028 for (i = 0; i < nb_rows; i++) {
1029 *p++ = q;
1030 for (j = 0; j < nb_columns; j++)
1031 SCOPINT_init_set_si(*(q+j),0);
1032 q += nb_columns;
1036 relation->next = NULL;
1038 return relation;
1043 * openscop_relation_free_inside function:
1044 * this function frees the allocated memory for the inside of a
1045 * openscop_relation_t structure, i.e. only m.
1046 * \param[in] relation The pointer to the relation we want to free internals.
1048 void openscop_relation_free_inside(openscop_relation_p relation) {
1049 int i, nb_elements;
1050 openscop_int_t * p;
1052 if (relation == NULL)
1053 return;
1055 nb_elements = relation->nb_rows * relation->nb_columns;
1057 if (nb_elements > 0)
1058 p = relation->m[0];
1060 for (i = 0; i < nb_elements; i++)
1061 SCOPINT_clear(*p++);
1063 if (relation->m != NULL) {
1064 if (nb_elements > 0)
1065 free(relation->m[0]);
1066 free(relation->m);
1072 * openscop_relation_free function:
1073 * this function frees the allocated memory for a openscop_relation_t
1074 * structure.
1075 * \param[in] relation The pointer to the relation we want to free.
1077 void openscop_relation_free(openscop_relation_p relation) {
1078 openscop_relation_p tmp;
1080 if (relation == NULL)
1081 return;
1083 while (relation != NULL) {
1084 tmp = relation->next;
1085 openscop_relation_free_inside(relation);
1086 free(relation);
1087 relation = tmp;
1092 /*+***************************************************************************
1093 * Processing functions *
1094 *****************************************************************************/
1098 * openscop_relation_is_matrix function:
1099 * this function returns 1 if the relation provided as parameter corresponds
1100 * to a "matrix" representation (see documentation), -1 if it is NULL and
1101 * 0 in all other cases.
1102 * \param[in] relation The relation we want to know if it is a matrix or not.
1103 * \return 1 if the relation has "matrix" representation, -1 if it is NULL,
1104 * 0 in all other cases.
1106 int openscop_relation_is_matrix(openscop_relation_p relation) {
1107 if (relation == NULL)
1108 return -1;
1110 // A relation has matrix representation if all nb_local_dims fields
1111 // of all parts of the union is OPENSCOP_UNDEFINED.
1112 while (relation != NULL) {
1113 if (relation->nb_local_dims != OPENSCOP_UNDEFINED)
1114 return 0;
1116 relation = relation->next;
1119 return 1;
1124 * openscop_relation_ncopy function:
1125 * this functions builds and returns a "hard copy" (not a pointer copy) of a
1126 * openscop_relation_t data structure such that the copy is restricted to the
1127 * "n" first rows of the relation. This applies to all the parts in the case
1128 * of a relation union.
1129 * \param[in] relation The pointer to the relation we want to copy.
1130 * \param[in] n The number of row of the relation we want to copy (the
1131 * special value -1 means "all the rows").
1132 * \return A pointer to the full copy of the relation union restricted to the
1133 * first n rows of constraint matrix for each part of the union.
1135 openscop_relation_p openscop_relation_ncopy(openscop_relation_p relation,
1136 int n) {
1137 int i, j;
1138 int first = 1, all_rows = 0;
1139 openscop_relation_p copy = NULL, node, previous = NULL;
1141 if (n == -1)
1142 all_rows = 1;
1144 while (relation != NULL) {
1145 if (all_rows)
1146 n = relation->nb_rows;
1148 if (n > relation->nb_rows) {
1149 fprintf(stderr,"[OpenScop] Error: not enough rows in the relation\n");
1150 exit(1);
1153 node = openscop_relation_malloc(n, relation->nb_columns);
1154 node->type = relation->type;
1155 node->nb_output_dims = relation->nb_output_dims;
1156 node->nb_input_dims = relation->nb_input_dims;
1157 node->nb_local_dims = relation->nb_local_dims;
1158 node->nb_parameters = relation->nb_parameters;
1160 for (i = 0; i < n; i++)
1161 for (j = 0; j < relation->nb_columns; j++)
1162 SCOPINT_assign(node->m[i][j], relation->m[i][j]);
1164 if (first) {
1165 first = 0;
1166 copy = node;
1167 previous = node;
1169 else {
1170 previous->next = node;
1171 previous = previous->next;
1174 relation = relation->next;
1177 return copy;
1182 * openscop_relation_copy function:
1183 * this function builds and returns a "hard copy" (not a pointer copy) of an
1184 * openscop_relation_t data structure (the full union of relation).
1185 * \param[in] relation The pointer to the relation we want to copy.
1186 * \return A pointer to the copy of the union of relations.
1188 openscop_relation_p openscop_relation_copy(openscop_relation_p relation) {
1189 if (relation == NULL)
1190 return NULL;
1192 return openscop_relation_ncopy(relation, -1);
1197 * openscop_relation_replace_vector function:
1198 * this function replaces the "row"^th row of a relation "relation" with the
1199 * vector "vector". It directly updates the relation union part pointed
1200 * by "relation" and this part only.
1201 * \param[in,out] relation The relation we want to replace a row.
1202 * \param[in] vector The vector that will replace a row of the relation.
1203 * \param[in] row The row of the relation to be replaced.
1205 void openscop_relation_replace_vector(openscop_relation_p relation,
1206 openscop_vector_p vector, int row) {
1207 int i;
1209 if ((relation == NULL) || (vector == NULL) ||
1210 (relation->nb_columns != vector->size) ||
1211 (row >= relation->nb_rows) || (row < 0)) {
1212 fprintf(stderr,"[OpenScop] Error: vector cannot replace relation row.\n");
1213 exit(1);
1216 for (i = 0; i < vector->size; i++)
1217 SCOPINT_assign(relation->m[row][i], vector->v[i]);
1222 * openscop_relation_add_vector function:
1223 * this function adds (meaning, +) a vector to the "row"^th row of a
1224 * relation "relation". It directly updates the relation union part pointed
1225 * by "relation" and this part only.
1226 * \param[in,out] relation The relation we want to add a vector to a row.
1227 * \param[in] vector The vector that will replace a row of the relation.
1228 * \param[in] row The row of the relation to be replaced.
1230 void openscop_relation_add_vector(openscop_relation_p relation,
1231 openscop_vector_p vector, int row) {
1232 int i;
1234 if ((relation == NULL) || (vector == NULL) ||
1235 (relation->nb_columns != vector->size) ||
1236 (row >= relation->nb_rows) || (row < 0)) {
1237 fprintf(stderr,"[OpenScop] Error: vector cannot be added to relation.\n");
1238 exit(1);
1241 if (SCOPINT_get_si(relation->m[row][0]) == 0)
1242 SCOPINT_assign(relation->m[row][0], vector->v[0]);
1244 for (i = 1; i < vector->size; i++)
1245 SCOPINT_addto(relation->m[row][i], relation->m[row][i], vector->v[i]);
1250 * openscop_relation_sub_vector function:
1251 * this function subtracts the vector "vector" to the "row"^th row of
1252 * a relation "relation. It directly updates the relation union part pointed
1253 * by "relation" and this part only.
1254 * \param[in,out] relation The relation where to subtract a vector to a row.
1255 * \param[in] vector The vector to subtract to a relation row.
1256 * \param[in] row The row of the relation to subtract the vector.
1258 void openscop_relation_sub_vector(openscop_relation_p relation,
1259 openscop_vector_p vector, int row) {
1260 int i;
1262 if ((relation == NULL) || (vector == NULL) ||
1263 (relation->nb_columns != vector->size) ||
1264 (row >= relation->nb_rows) || (row < 0)) {
1265 fprintf(stderr,"[OpenScop] Error: vector cannot be subtracted to row.\n");
1266 exit(1);
1269 if (SCOPINT_get_si(relation->m[row][0]) == 0)
1270 SCOPINT_assign(relation->m[row][0], vector->v[0]);
1272 for (i = 1; i < vector->size; i++)
1273 SCOPINT_subtract(relation->m[row][i], relation->m[row][i], vector->v[i]);
1278 * openscop_relation_insert_vector function:
1279 * this function inserts a new row corresponding to the vector "vector" to
1280 * the relation "relation" by inserting it at the "row"^th row. It directly
1281 * updates the relation union part pointed by "relation" and this part only.
1282 * If "vector" (or "relation") is NULL, the relation is left unmodified.
1283 * \param[in,out] relation The relation we want to extend.
1284 * \param[in] vector The vector that will be added relation.
1285 * \param[in] row The row where to insert the vector.
1287 void openscop_relation_insert_vector(openscop_relation_p relation,
1288 openscop_vector_p vector, int row) {
1289 openscop_relation_p temp;
1291 temp = openscop_relation_from_vector(vector);
1292 openscop_relation_insert_relation(relation, temp, row);
1293 openscop_relation_free(temp);
1298 * openscop_relation_from_vector function:
1299 * this function converts a vector "vector" to a relation with a single row
1300 * and returns a pointer to that relation.
1301 * \param[in] vector The vector to convert to a relation.
1302 * \return A pointer to a relation resulting from the vector conversion.
1304 openscop_relation_p openscop_relation_from_vector(openscop_vector_p vector) {
1305 openscop_relation_p relation;
1307 if (vector == NULL)
1308 return NULL;
1310 relation = openscop_relation_malloc(1, vector->size);
1311 openscop_relation_replace_vector(relation, vector, 0);
1312 return relation;
1317 * openscop_relation_replace_relation function:
1318 * this function replaces some rows of a relation "r1" with the rows of
1319 * the relation "r2". It begins at the "row"^th row of "r1". It directly
1320 * updates the relation union part pointed by "r1" and this part only.
1321 * \param[in,out] r1 The relation we want to change some rows.
1322 * \param[in] r2 The relation containing the new rows.
1323 * \param[in] row The first row of the relation r1 to be replaced.
1325 void openscop_relation_replace_relation(openscop_relation_p r1,
1326 openscop_relation_p r2, int row) {
1327 int i, j;
1329 if ((r1 == NULL) || (r2 == NULL) ||
1330 (r1->nb_columns != r1->nb_columns) ||
1331 ((row + r2->nb_rows) > r1->nb_rows) || (row < 0)) {
1332 fprintf(stderr,"[OpenScop] Error: relation rows could not be replaced.\n");
1333 exit(1);
1336 for (i = 0; i < r2->nb_rows; i++)
1337 for (j = 0; j < r2->nb_columns; j++)
1338 SCOPINT_assign(r1->m[i+row][j], r2->m[i][j]);
1343 * openscop_relation_insert_relation function:
1344 * this function adds new rows corresponding to the relation "r1" to
1345 * the relation "r2" by inserting it at the "row"^th row. It directly
1346 * updates the relation union part pointed by "r1" and this part only.
1347 * If "r2" (or "r1") is NULL, the relation is left unmodified.
1348 * \param[in,out] r1 The relation we want to extend.
1349 * \param[in] r2 The relation to be inserted.
1350 * \param[in] row The row where to insert the relation
1352 void openscop_relation_insert_relation(openscop_relation_p r1,
1353 openscop_relation_p r2, int row) {
1354 int i, j;
1355 openscop_relation_p temp;
1357 if ((r1 == NULL) || (r2 == NULL))
1358 return;
1360 if ((r1->nb_columns != r2->nb_columns) ||
1361 (row > r1->nb_rows) || (row < 0)) {
1362 fprintf(stderr,"[OpenScop] Error: constraints cannot be inserted.\n");
1363 exit(1);
1366 // We use a temporary relation just to reuse existing functions. Cleaner.
1367 temp = openscop_relation_malloc(r1->nb_rows+r2->nb_rows, r1->nb_columns);
1369 for (i = 0; i < row; i++)
1370 for (j = 0; j < r1->nb_columns; j++)
1371 SCOPINT_assign(temp->m[i][j], r1->m[i][j]);
1373 openscop_relation_replace_relation(temp, r2, row);
1375 for (i = row + r2->nb_rows; i < r2->nb_rows + r1->nb_rows; i++)
1376 for (j = 0; j < r1->nb_columns; j++)
1377 SCOPINT_assign(temp->m[i][j], r1->m[i-r2->nb_rows][j]);
1379 openscop_relation_free_inside(r1);
1381 // Replace the inside of relation.
1382 r1->nb_rows = temp->nb_rows;
1383 r1->m = temp->m;
1385 // Free the temp "shell".
1386 free(temp);
1391 * openscop_relation_concat function:
1392 * this function builds a new relation from two relations sent as
1393 * parameters. The new set of constraints is built as the concatenation
1394 * of the rows of the first elements of the two relation unions r1 and r2.
1395 * This means, there is no next field in the result.
1396 * \param[in] r1 The first relation.
1397 * \param[in] r2 The second relation.
1398 * \return A pointer to the relation resulting from the concatenation of
1399 * the first elements of r1 and r2.
1401 openscop_relation_p openscop_relation_concat(openscop_relation_p r1,
1402 openscop_relation_p r2) {
1403 openscop_relation_p new;
1405 if (r1 == NULL)
1406 return openscop_relation_copy(r2);
1408 if (r2 == NULL)
1409 return openscop_relation_copy(r1);
1411 if (r1->nb_columns != r2->nb_columns) {
1412 fprintf(stderr, "[OpenScop] Error: incompatible sizes "
1413 "for concatenation.\n");
1414 exit(1);
1416 if (r1->next || r2->next) {
1417 fprintf(stderr, "[OpenScop] Warning: relation concatenation is done "
1418 "on the first elements only.\n");
1421 new = openscop_relation_malloc(r1->nb_rows+r2->nb_rows, r1->nb_columns);
1422 openscop_relation_replace_relation(new, r1, 0);
1423 openscop_relation_replace_relation(new, r2, r1->nb_rows);
1425 return new;
1430 * openscop_relation_equal function:
1431 * this function returns true if the two relations provided as parameters
1432 * are the same, false otherwise.
1433 * \param[in] r1 The first relation.
1434 * \param[in] r2 The second relation.
1435 * \return 1 if r1 and r2 are the same (content-wise), 0 otherwise.
1437 int openscop_relation_equal(openscop_relation_p r1, openscop_relation_p r2) {
1438 int i, j;
1440 while ((r1 != NULL) && (r2 != NULL)) {
1441 if (r1 == r2)
1442 return 1;
1444 if ((r1->type != r2->type) ||
1445 (r1->nb_rows != r2->nb_rows) ||
1446 (r1->nb_columns != r2->nb_columns) ||
1447 (r1->nb_output_dims != r2->nb_output_dims) ||
1448 (r1->nb_input_dims != r2->nb_input_dims) ||
1449 (r1->nb_local_dims != r2->nb_local_dims) ||
1450 (r1->nb_parameters != r2->nb_parameters))
1451 return 0;
1453 for (i = 0; i < r1->nb_rows; ++i)
1454 for (j = 0; j < r1->nb_columns; ++j)
1455 if (SCOPINT_ne(r1->m[i][j], r2->m[i][j]))
1456 return 0;
1458 r1 = r1->next;
1459 r2 = r2->next;
1462 if (((r1 == NULL) && (r2 != NULL)) || ((r1 != NULL) && (r2 == NULL)))
1463 return 0;
1465 return 1;
1470 * openscop_relation_check_property internal function:
1471 * This function checks whether an "actual" value is the same as an
1472 * "expected" value or not. If the expected value is set to
1473 * OPENSCOP_UNDEFINED, this function sets it to the "actual" value
1474 * and do not report a difference has been detected.
1475 * It returns 0 if a difference has been detected, 1 otherwise.
1476 * \param[in,out] expected Pointer to the expected value (the value is
1477 * modified if it was set to OPENSCOP_UNDEFINED).
1478 * \param[in] actual Value we want to check.
1479 * \return 0 if the values are not the same while the expected value was
1480 * not OPENSCOP_UNDEFINED, 1 otherwise.
1482 static
1483 int openscop_relation_check_property(int * expected, int actual) {
1484 if (*expected != OPENSCOP_UNDEFINED) {
1485 if ((actual != OPENSCOP_UNDEFINED) &&
1486 (actual != *expected)) {
1487 fprintf(stderr, "[OpenScop] Warning: unexpected property.\n");
1488 return 0;
1491 else {
1492 *expected = actual;
1495 return 1;
1500 * openscop_relation_check_nb_columns internal function:
1501 * This function checks that the number of columns of a relation
1502 * corresponds to some expected properties (setting an expected property to
1503 * OPENSCOP_UNDEFINED makes this function unable to detect a problem).
1504 * It returns 0 if the number of columns seems incorrect or 1 if no problem
1505 * has been detected.
1506 * \param[in] relation The relation we want to check the number of columns.
1507 * \param[in] expected_nb_output_dims Expected number of output dimensions.
1508 * \param[in] expected_nb_input_dims Expected number of input dimensions.
1509 * \param[in] expected_nb_parameters Expected number of parameters.
1510 * \return 0 if the number of columns seems incorrect, 1 otherwise.
1512 static
1513 int openscop_relation_check_nb_columns(openscop_relation_p relation,
1514 int expected_nb_output_dims,
1515 int expected_nb_input_dims,
1516 int expected_nb_parameters) {
1517 int expected_nb_local_dims, expected_nb_columns;
1519 if ((expected_nb_output_dims != OPENSCOP_UNDEFINED) &&
1520 (expected_nb_input_dims != OPENSCOP_UNDEFINED) &&
1521 (expected_nb_parameters != OPENSCOP_UNDEFINED)) {
1523 if (relation->nb_local_dims == OPENSCOP_UNDEFINED)
1524 expected_nb_local_dims = 0;
1525 else
1526 expected_nb_local_dims = relation->nb_local_dims;
1528 expected_nb_columns = expected_nb_output_dims +
1529 expected_nb_input_dims +
1530 expected_nb_local_dims +
1531 expected_nb_parameters +
1534 if (expected_nb_columns != relation->nb_columns) {
1535 fprintf(stderr, "[OpenScop] Warning: unexpected number of columns.\n");
1536 return 0;
1540 return 1;
1545 * openscop_relation_format_consistency function:
1546 * this function checks that each part of an union of relations use the same
1547 * representation type (either matrix or relation representation). It returns
1548 * 1 if it is the case, 0 otherwise.
1549 * \param[in] r The relation to check for representation consistency.
1550 * \return 0 if the representation consistency check fails, 1 if it succeeds.
1552 static
1553 int openscop_relation_format_consistency(openscop_relation_p r) {
1554 int matrix = 0;
1555 int relation = 0;
1557 while (r != NULL) {
1558 if (r->nb_local_dims == OPENSCOP_UNDEFINED)
1559 matrix = 1;
1560 else
1561 relation = 1;
1563 r = r->next;
1566 return (matrix == relation) ? 0 : 1;
1571 * openscop_relation_integrity_check function:
1572 * this function checks that a relation is "well formed" according to some
1573 * expected properties (setting an expected value to OPENSCOP_UNDEFINED means
1574 * that we do not expect a specific value) and what the relation is supposed
1575 * to represent. It returns 0 if the check failed or 1 if no problem has been
1576 * detected.
1577 * \param[in] relation The relation we want to check.
1578 * \param[in] type Semantics about this relation (domain, access...).
1579 * \param[in] expected_nb_output_dims Expected number of output dimensions.
1580 * \param[in] expected_nb_input_dims Expected number of input dimensions.
1581 * \param[in] expected_nb_parameters Expected number of parameters.
1582 * \return 0 if the integrity check fails, 1 otherwise.
1584 int openscop_relation_integrity_check(openscop_relation_p relation,
1585 int expected_type,
1586 int expected_nb_output_dims,
1587 int expected_nb_input_dims,
1588 int expected_nb_parameters) {
1589 int i, is_matrix;
1591 // Check the NULL case.
1592 if (relation == NULL) {
1593 if ((expected_nb_output_dims != OPENSCOP_UNDEFINED) ||
1594 (expected_nb_input_dims != OPENSCOP_UNDEFINED) ||
1595 (expected_nb_parameters != OPENSCOP_UNDEFINED)) {
1596 fprintf(stderr, "[OpenScop] Warning: NULL relation with "
1597 "some expected properties.\n");
1598 return 0;
1601 return 1;
1604 // Check the type.
1605 if (((expected_type != OPENSCOP_TYPE_ACCESS) &&
1606 (expected_type != relation->type)) ||
1607 ((expected_type == OPENSCOP_TYPE_ACCESS) &&
1608 (!openscop_relation_is_access(relation)))) {
1609 fprintf(stderr, "[OpenScop] Warning: wrong type.\n");
1610 return 0;
1613 // Check the relation is using either matrix or relation representation.
1614 if (!openscop_relation_format_consistency(relation)) {
1615 fprintf(stderr, "[OpenScop] Warning: inconsistent representation "
1616 "(both matrix and relation).\n");
1617 return 0;
1620 is_matrix = openscop_relation_is_matrix(relation);
1622 // Check that relations have no undefined properties.
1623 if (!is_matrix &&
1624 ((relation->nb_output_dims == OPENSCOP_UNDEFINED) ||
1625 (relation->nb_input_dims == OPENSCOP_UNDEFINED) ||
1626 (relation->nb_local_dims == OPENSCOP_UNDEFINED) ||
1627 (relation->nb_parameters == OPENSCOP_UNDEFINED))) {
1628 fprintf(stderr, "[OpenScop] Warning: undefined property for a "
1629 "relation representation.\n");
1630 return 0;
1633 // Check that a context has actually 0 or an undefined #output dimensions.
1634 if ((relation->type == OPENSCOP_TYPE_CONTEXT) &&
1635 (relation->nb_output_dims != 0) &&
1636 (relation->nb_output_dims != OPENSCOP_UNDEFINED)) {
1637 fprintf(stderr, "[OpenScop] Warning: context without 0 "
1638 "as number of output dimensions.\n");
1639 openscop_relation_print(stdout, relation);
1640 return 0;
1643 // Check that a domain has actually 0 or an undefined #input dimensions.
1644 if (((relation->type == OPENSCOP_TYPE_DOMAIN) ||
1645 (relation->type == OPENSCOP_TYPE_CONTEXT)) &&
1646 (relation->nb_input_dims != 0) &&
1647 (relation->nb_input_dims != OPENSCOP_UNDEFINED)) {
1648 fprintf(stderr, "[OpenScop] Warning: domain or context without 0 "
1649 "as number of input dimensions.\n");
1650 return 0;
1653 // Check properties according to expected values (and if expected values
1654 // are undefined, define them with the first relation part properties).
1655 if (!openscop_relation_check_property(&expected_nb_output_dims,
1656 relation->nb_output_dims) ||
1657 !openscop_relation_check_property(&expected_nb_input_dims,
1658 relation->nb_input_dims) ||
1659 !openscop_relation_check_property(&expected_nb_parameters,
1660 relation->nb_parameters))
1661 return 0;
1663 while (relation != NULL) {
1665 // Properties (except the number of local dimensions) should be the same
1666 // in all parts.
1667 if ((expected_nb_output_dims != relation->nb_output_dims) ||
1668 (expected_nb_input_dims != relation->nb_input_dims) ||
1669 (expected_nb_parameters != relation->nb_parameters)) {
1670 fprintf(stderr, "[OpenScop] Warning: inconsistent properties.\n");
1671 return 0;
1674 // Check whether the number of columns is OK or not.
1675 if (!openscop_relation_check_nb_columns(relation,
1676 expected_nb_output_dims,
1677 expected_nb_input_dims,
1678 expected_nb_parameters))
1679 return 0;
1681 // Check the first column. The first column of a relation part should be
1682 // made of 0 or 1 only, except for scattering and access relations in
1683 // "matrix" representation, the first column is made only of 0.
1684 if ((relation->nb_rows > 0) && (relation->nb_columns > 0)) {
1685 for (i = 0; i < relation->nb_rows; i++) {
1686 if (is_matrix &&
1687 ((openscop_relation_is_access(relation)) ||
1688 (relation->type == OPENSCOP_TYPE_SCATTERING))) {
1689 if (!SCOPINT_zero_p(relation->m[i][0])) {
1690 fprintf(stderr, "[OpenScop] Warning: first column of a scattering "
1691 "or access function not made of 0s.\n");
1692 openscop_relation_print(stdout, relation);
1693 return 0;
1696 else {
1697 if (!SCOPINT_zero_p(relation->m[i][0]) &&
1698 !SCOPINT_one_p(relation->m[i][0])) {
1699 fprintf(stderr, "[OpenScop] Warning: first column of a "
1700 "relation is not strictly made of 0 or 1.\n");
1701 return 0;
1707 // Array accesses must provide the array identifier.
1708 if ((openscop_relation_is_access(relation)) &&
1709 (openscop_relation_get_array_id(relation) == OPENSCOP_UNDEFINED))
1710 return 0;
1712 relation = relation->next;
1715 return 1;
1720 * openscop_relation_union function:
1721 * this function builds a new relation from two relations provided
1722 * as parameters. The new relation is built as an union of the
1723 * two relations: the list of constraint sets are linked together.
1724 * \param[in] r1 The first relation.
1725 * \param[in] r2 The second relation.
1726 * \return A new relation corresponding to the union of r1 and r2.
1728 openscop_relation_p openscop_relation_union(openscop_relation_p r1,
1729 openscop_relation_p r2) {
1730 openscop_relation_p copy1, copy2, tmp;
1732 if ((r1 == NULL) && (r2 == NULL))
1733 return NULL;
1735 copy1 = openscop_relation_copy(r1);
1736 copy2 = openscop_relation_copy(r2);
1738 if ((r1 != NULL) && (r2 == NULL))
1739 return copy1;
1741 if ((r1 == NULL) && (r2 != NULL))
1742 return copy2;
1744 tmp = copy1;
1745 while (tmp->next != NULL)
1746 tmp = tmp->next;
1748 tmp->next = copy2;
1749 return copy1;
1753 /**
1754 * openscop_relation_set_type function:
1755 * this function sets the type of each relation union part in the relation
1756 * to the one provided as parameter.
1757 * \param relation The relation to set the type.
1758 * \param type The type.
1760 void openscop_relation_set_type(openscop_relation_p relation, int type) {
1762 while (relation != NULL) {
1763 relation->type = type;
1764 relation = relation->next;
1770 * openscop_relation_get_array_id function:
1771 * this function returns the array identifier in a relation with access type
1772 * It returns OPENSCOP_UNDEFINED if it is not able to find it (in particular
1773 * if there are irregularities in the relation).
1774 * \param[in] relation The relation where to find an array identifier.
1775 * \return The array identifier in the relation or OPENSCOP_UNDEFINED.
1777 int openscop_relation_get_array_id(openscop_relation_p relation) {
1778 int i;
1779 int first = 1;
1780 int is_matrix = openscop_relation_is_matrix(relation);
1781 int array_id = OPENSCOP_UNDEFINED;
1782 int reference_array_id = OPENSCOP_UNDEFINED;
1783 int nb_array_id;
1784 int row_id = 0;
1786 if (relation == NULL)
1787 return OPENSCOP_UNDEFINED;
1789 if (!openscop_relation_is_access(relation)) {
1790 fprintf(stderr, "[OpenScop] Warning: asked array id of non-array "
1791 "relation.\n");
1792 return OPENSCOP_UNDEFINED;
1795 while (relation != NULL) {
1796 // There should be room to store the array identifier.
1797 if ((relation->nb_rows < 1) ||
1798 (is_matrix && (relation->nb_columns < 2)) ||
1799 (!is_matrix && (relation->nb_columns < 3))) {
1800 fprintf(stderr, "[OpenScop] Warning: no array identifier in "
1801 "an access function.\n");
1802 return OPENSCOP_UNDEFINED;
1805 if (is_matrix) {
1806 // In matrix format, the array identifier is the last element of the
1807 // first row (m[0][#columns -1]), it should be greater than 0 and be
1808 // the only non-zero element in the row.
1809 for (i = 0; i < relation->nb_columns - 1; i++) {
1810 if (!SCOPINT_zero_p(relation->m[0][i])) {
1811 fprintf(stderr, "[OpenScop] Warning: non integer array "
1812 "identifier.\n");
1813 return OPENSCOP_UNDEFINED;
1816 array_id = SCOPINT_get_si(relation->m[0][relation->nb_columns - 1]);
1817 if (array_id <= 0) {
1818 fprintf(stderr, "[OpenScop] Warning: negative or 0 identifier "
1819 "in access function.\n");
1820 return OPENSCOP_UNDEFINED;
1823 else {
1824 // In relation format, array identifiers are
1825 // m[i][#columns -1] / m[i][1], with i the only row
1826 // where m[i][1] is not 0.
1827 // - check there is exactly one row such that m[i][1] is not 0,
1828 // - check the whole ith row if full of 0 except m[i][1] and the id,
1829 // - check that (m[i][#columns -1] % m[i][1]) == 0,
1830 // - check that (-m[i][#columns -1] / m[i][1]) > 0.
1831 nb_array_id = 0;
1832 for (i = 0; i < relation->nb_rows; i++) {
1833 if (!SCOPINT_zero_p(relation->m[i][1])) {
1834 nb_array_id ++;
1835 row_id = i;
1838 if (nb_array_id == 0) {
1839 fprintf(stderr, "[OpenScop] Warning: no array identifier in "
1840 "an access function.\n");
1841 return OPENSCOP_UNDEFINED;
1843 if (nb_array_id > 1) {
1844 fprintf(stderr, "[OpenScop] Warning: several array identification "
1845 "rows in one access function.\n");
1846 return OPENSCOP_UNDEFINED;
1848 for (i = 0; i < relation->nb_columns - 1; i++) {
1849 if ((i != 1) && !SCOPINT_zero_p(relation->m[row_id][i])) {
1850 fprintf(stderr, "[OpenScop] Warning: non integer array "
1851 "identifier.\n");
1852 return OPENSCOP_UNDEFINED;
1855 if (!SCOPINT_divisible(relation->m[row_id][relation->nb_columns - 1],
1856 relation->m[row_id][1])) {
1857 fprintf(stderr, "[OpenScop] Warning: rational array identifier.\n");
1858 return OPENSCOP_UNDEFINED;
1860 array_id = -SCOPINT_get_si(relation->m[row_id][relation->nb_columns-1]);
1861 array_id /= SCOPINT_get_si(relation->m[row_id][1]);
1862 if (array_id <= 0) {
1863 fprintf(stderr, "[OpenScop] Warning: negative or 0 identifier "
1864 "in access function.\n");
1865 return OPENSCOP_UNDEFINED;
1869 // Unions of accesses are allowed, but they should refer the same array.
1870 if (first) {
1871 reference_array_id = array_id;
1872 first = 0;
1874 else {
1875 if (reference_array_id != array_id) {
1876 fprintf(stderr, "[OpenScop] Warning: inconsistency of array "
1877 "identifiers in an union of access relations.\n");
1878 return OPENSCOP_UNDEFINED;
1882 relation = relation->next;
1885 return array_id;