Merge with debug branch
[openscop.git] / source / relation.c
blobe525268e1f7b262670e1c4e100d6fcfd7e89f6cc
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_print_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_print_type(FILE * file, openscop_relation_p relation) {
86 if (relation != NULL) {
87 switch (relation->type) {
88 case OPENSCOP_UNDEFINED: {
89 printf("\n");
90 break;
92 case OPENSCOP_TYPE_DOMAIN: {
93 printf("(domain)\n");
94 break;
96 case OPENSCOP_TYPE_SCATTERING: {
97 printf("(scattering)\n");
98 break;
100 case OPENSCOP_TYPE_ACCESS: {
101 printf("(access)\n");
102 break;
104 default: {
105 printf("(unknown type: %d)\n", relation->type);
106 break;
114 * openscop_relation_print_structure function:
115 * this function displays a openscop_relation_t structure (*relation) into a
116 * file (file, possibly stdout) in a way that trends to be understandable.
117 * It includes an indentation level (level) in order to work with others
118 * print_structure functions.
119 * \param[in] file File where informations are printed.
120 * \param[in] relation The relation whose information has to be printed.
121 * \param[in] level Number of spaces before printing, for each line.
123 void openscop_relation_print_structure(FILE * file,
124 openscop_relation_p relation,
125 int level) {
126 int i, j, first = 1;
128 // Go to the right level.
129 for (j = 0; j < level; j++)
130 fprintf(file, "|\t");
132 if (relation != NULL) {
133 fprintf(file, "+-- openscop_relation_t ");
134 openscop_relation_print_type(file, relation);
136 else {
137 fprintf(file, "+-- NULL relation\n");
140 while (relation != NULL) {
141 if (! first) {
142 // Go to the right level.
143 for (j = 0; j < level; j++)
144 fprintf(file, "|\t");
145 fprintf(file, "| openscop_relation_t ");
146 openscop_relation_print_type(file, relation);
148 else
149 first = 0;
151 // A blank line
152 for(j = 0; j <= level; j++)
153 fprintf(file, "|\t");
154 fprintf(file, "%d %d %d %d %d %d\n",
155 relation->nb_rows, relation->nb_columns,
156 relation->nb_output_dims, relation->nb_input_dims,
157 relation->nb_local_dims, relation->nb_parameters);
159 // Display the relation.
160 for (i = 0; i < relation->nb_rows; i++) {
161 for (j = 0; j <= level; j++)
162 fprintf(file, "|\t");
164 fprintf(file, "[ ");
166 for (j = 0; j < relation->nb_columns; j++) {
167 SCOPINT_print(file, OPENSCOP_FMT, relation->m[i][j]);
168 fprintf(file, " ");
171 fprintf(file, "]\n");
174 relation = relation->next;
176 // Next line.
177 if (relation != NULL) {
178 for (j = 0; j <= level; j++)
179 fprintf(file, "|\t");
180 fprintf(file, "|\n");
181 for (j = 0; j <= level; j++)
182 fprintf(file, "|\t");
183 fprintf(file, "V\n");
187 // The last line.
188 for (j = 0; j <= level; j++)
189 fprintf(file, "|\t");
190 fprintf(file, "\n");
195 * openscop_relation_print function:
196 * this function prints the content of a openscop_relation_t structure
197 * (*relation) into a file (file, possibly stdout).
198 * \param[in] file File where informations are printed.
199 * \param[in] relation The relation whose information have to be printed.
201 void openscop_relation_print(FILE * file, openscop_relation_p relation) {
202 openscop_relation_print_structure(file, relation, 0);
208 * openscop_relation_expression_element function:
209 * this function returns a string containing the printing of a value (possibly
210 * an iterator or a parameter with its coefficient or a constant).
211 * \param[in] val The coefficient or constant value.
212 * \param[in,out] first Pointer to a boolean set to 1 if the current value is
213 * the first of an expresion, 0 otherwise (maybe updated).
214 * \param[in] cst A boolean set to 1 if the value is a constant,
215 * 0 otherwise.
216 * \param[in] name String containing the name of the element.
217 * \return A string that contains the printing of a value.
219 static
220 char * openscop_relation_expression_element(openscop_int_t val, int * first,
221 int cst, char * name) {
222 char * temp = (char *)malloc(OPENSCOP_MAX_STRING * sizeof(char));
223 char * body = (char *)malloc(OPENSCOP_MAX_STRING * sizeof(char));
224 char * sval = (char *)malloc(OPENSCOP_MAX_STRING * sizeof(char));
226 body[0] = '\0';
227 sval[0] = '\0';
229 // statements for the 'normal' processing.
230 if (SCOPINT_notzero_p(val) && (!cst)) {
231 if ((*first) || SCOPINT_neg_p(val)) {
232 if (SCOPINT_one_p(val)) { // case 1
233 sprintf(sval, "%s", name);
235 else {
236 if (SCOPINT_mone_p(val)) { // case -1
237 sprintf(sval, "-%s", name);
239 else { // default case
240 SCOPINT_sprint(sval, OPENSCOP_FMT_TXT, val);
241 sprintf(temp, "*%s", name);
242 strcat(sval, temp);
245 *first = 0;
247 else {
248 if (SCOPINT_one_p(val)) {
249 sprintf(sval, "+%s", name);
251 else {
252 sprintf(sval, "+");
253 SCOPINT_sprint(temp, OPENSCOP_FMT_TXT, val);
254 strcat(sval, temp);
255 sprintf(temp, "*%s", name);
256 strcat(sval, temp);
260 else {
261 if (cst) {
262 if ((SCOPINT_zero_p(val) && (*first)) || SCOPINT_neg_p(val))
263 SCOPINT_sprint(sval, OPENSCOP_FMT_TXT, val);
264 if (SCOPINT_pos_p(val)) {
265 if (!(*first)) {
266 SCOPINT_sprint(sval, "+"OPENSCOP_FMT_TXT, val); // Block macro !
268 else {
269 SCOPINT_sprint(sval, OPENSCOP_FMT_TXT, val);
274 free(temp);
275 free(body);
277 return(sval);
282 * openscop_relation_expression function:
283 * this function returns a string corresponding to an affine expression
284 * stored at the "row"^th row of the relation pointed by "relation".
285 * \param[in] relation A set of linear expressions.
286 * \param[in] row The row corresponding to the expression.
287 * \param[in] names The textual names of the various elements. Is is
288 * important that names->nb_parameters is exact if the
289 * matrix representation is used. Set to NULL if
290 * printing comments is not needed.
291 * \return A string that contains the printing of an affine expression.
293 char * openscop_relation_expression(openscop_relation_p relation,
294 int row, openscop_names_p names) {
295 int i, first = 1;
296 char * sval;
297 char * sline = (char *)malloc(OPENSCOP_MAX_STRING * sizeof(char));
298 sline[0] = '\0';
300 // First the iterator part.
301 for (i = 1; i <= names->nb_iterators; i++) {
302 sval = openscop_relation_expression_element(
303 relation->m[row][i], &first, 0, names->iterators[i-1]);
304 strcat(sline, sval);
305 free(sval);
308 // Next the local dims part.
309 for (i = names->nb_iterators + 1;
310 i <= names->nb_iterators + names->nb_localdims; i++) {
311 sval = openscop_relation_expression_element(
312 relation->m[row][i], &first, 0,
313 names->localdims[i - names->nb_iterators - 1]);
314 strcat(sline, sval);
315 free(sval);
318 // Next the parameter part.
319 for (i = names->nb_iterators + names->nb_localdims + 1;
320 i <= names->nb_iterators + names->nb_localdims + names->nb_parameters;
321 i++) {
322 sval = openscop_relation_expression_element(
323 relation->m[row][i], &first, 0,
324 names->parameters[i - names->nb_iterators - names->nb_localdims - 1]);
325 strcat(sline, sval);
326 free(sval);
329 // Finally the constant part (yes, I reused it).
330 sval = openscop_relation_expression_element(relation->m[row][i],
331 &first, 1, NULL);
332 strcat(sline, sval);
333 free(sval);
335 return sline;
340 * openscop_relation_get_array_id internal function:
341 * this function returns the array identifier when the relation provided
342 * as parameter corresponds to an access function.
343 * \param[in] relation The access function.
344 * \return The accessed array identifier.
346 static
347 int openscop_relation_get_array_id(openscop_relation_p relation) {
348 if (relation == NULL) {
349 fprintf(stderr, "[OpenScop] Error: cannot find nb_arrays "
350 "in a NULL relation.\n");
351 exit(1);
354 if (openscop_relation_is_matrix(relation)) {
355 // Matrix representation case.
356 if ((relation->nb_rows < 1) || (relation->nb_columns < 1)) {
357 fprintf(stderr, "[OpenScop] Error: not enough rows or columns "
358 "to extract nb_arrays.\n");
359 exit(1);
361 return SCOPINT_get_si(relation->m[0][0]);
363 else {
364 // Relation representation case.
365 if ((relation->nb_rows < 1) || (relation->nb_columns < 2)) {
366 fprintf(stderr, "[OpenScop] Error: not enough rows or columns "
367 "to extract nb_arrays.\n");
368 exit(1);
370 // TODO: do something more general
371 return SCOPINT_get_si(relation->m[0][relation->nb_columns - 1]);
377 * openscop_relation_print_openscop function:
378 * this function prints the content of a openscop_relation_t structure
379 * (*relation) into a file (file, possibly stdout) in the OpenScop format.
380 * \param[in] file File where informations are printed.
381 * \param[in] relation The relation whose information has to be printed.
382 * \param[in] names The textual names of the various elements. Is is
383 * important that names->nb_parameters is exact if the
384 * matrix representation is used. Set to NULL if printing
385 * comments is not needed.
387 void openscop_relation_print_openscop(FILE * file,
388 openscop_relation_p relation,
389 openscop_names_p names) {
390 int i, j, k;
391 int part, nb_parts;
392 int type = relation->type;
393 char * expression;
394 openscop_relation_p r;
396 if (relation == NULL) {
397 fprintf(stderr, "[OpenScop] Warning: asked to print a NULL relation.\n");
398 fprintf(file, "# NULL relation\n");
399 return;
402 // TODO: check whether there are enough names or not, if not, set to NULL.
403 // (or generate them temporarily ?)
404 // Check whether there is exactly the right number of names. If not, the
405 // comments will not be printed.
408 switch (relation->type) {
409 // In the case of an undefined relation, we do not print comments.
410 case OPENSCOP_UNDEFINED: {
411 names = NULL;
412 break;
414 // In the case of a domain, check for iterator and parameter names.
415 case OPENSCOP_TYPE_DOMAIN: {
416 if (openscop_relation_is_matrix(relation)) {
427 // TODO: check whether there are too many names or not, if yes, set to NULL.
428 // (or remove them temporarily ?)
429 // TODO: if names are not textual, set to NULL.
431 // Count the number of parts in the union and print it if it is not 1.
432 r = relation;
433 nb_parts = 0;
434 while (r != NULL) {
435 nb_parts++;
436 r = r->next;
438 if (nb_parts > 1)
439 fprintf(file, "# Union with %d parts\n%d\n", nb_parts, nb_parts);
441 // Print each part of the union.
442 for (part = 1; part <= nb_parts; part++) {
443 if (nb_parts > 1)
444 fprintf(file, "# Union part No.%d\n", part);
445 if ((relation->nb_output_dims == OPENSCOP_UNDEFINED) &&
446 (relation->nb_input_dims == OPENSCOP_UNDEFINED) &&
447 (relation->nb_local_dims == OPENSCOP_UNDEFINED) &&
448 (relation->nb_parameters == OPENSCOP_UNDEFINED))
449 fprintf(file, "%d %d\n", relation->nb_rows, relation->nb_columns);
450 else
451 fprintf(file, "%d %d %d %d %d %d\n",
452 relation->nb_rows, relation->nb_columns,
453 relation->nb_output_dims, relation->nb_input_dims,
454 relation->nb_local_dims, relation->nb_parameters);
456 for (i = 0; i < relation->nb_rows; i++) {
457 for (j = 0; j < relation->nb_columns; j++) {
458 SCOPINT_print(file, OPENSCOP_FMT, relation->m[i][j]);
459 fprintf(file, " ");
462 if (type == OPENSCOP_TYPE_DOMAIN) {
463 expression = openscop_relation_expression(relation, i, names);
464 fprintf(file, " ## %s", expression);
465 free(expression);
466 if (SCOPINT_zero_p(relation->m[i][0]))
467 fprintf(file, " == 0");
468 else
469 fprintf(file, " >= 0");
472 if (type == OPENSCOP_TYPE_SCATTERING) {
473 expression = openscop_relation_expression(relation, i, names);
474 fprintf(file, " ## %s", expression);
475 free(expression);
478 if (type == OPENSCOP_TYPE_ACCESS) {
479 //TODO: works only for matrix: use openscop_relation_get_array_id
480 if (SCOPINT_notzero_p(relation->m[i][0])) {
481 if (strncmp(names->arrays[SCOPINT_get_si(relation->m[i][0]) - 1],
482 OPENSCOP_FAKE_ARRAY, strlen(OPENSCOP_FAKE_ARRAY)))
483 fprintf(file, " ## %s",
484 names->arrays[SCOPINT_get_si(relation->m[i][0]) - 1]);
485 k = i;
486 do {
487 expression = openscop_relation_expression(relation, k, names);
488 fprintf(file, "[%s]", expression);
489 free(expression);
490 k++;
492 while ((k < relation->nb_rows) &&
493 SCOPINT_zero_p(relation->m[k][0]));
495 else {
496 fprintf(file, " ##");
500 fprintf(file, "\n");
502 relation = relation->next;
507 /*****************************************************************************
508 * Reading function *
509 *****************************************************************************/
513 * openscop_relation_read function:
514 * this function reads a relation into a file (foo, posibly stdin) and
515 * returns a pointer this relation.
516 * \param[in] file The input stream.
517 * \return A pointer to the relation structure that has been read.
519 openscop_relation_p openscop_relation_read(FILE * foo) {
520 int i, j, k, n, read = 0;
521 int nb_rows, nb_columns;
522 int nb_output_dims, nb_input_dims, nb_local_dims, nb_parameters;
523 int nb_union_parts = 1;
524 int may_read_nb_union_parts = 1;
525 int read_properties = 1;
526 int first = 1;
527 char * c, s[OPENSCOP_MAX_STRING], str[OPENSCOP_MAX_STRING];
528 openscop_relation_p relation, relation_union = NULL, previous = NULL;
529 openscop_int_t * p = NULL;
531 // Read each part of the union (the number of parts may be updated inside)
532 for (k = 0; k < nb_union_parts; k++) {
533 // Read the number of union parts or the properties of the union part
534 while (read_properties) {
535 read_properties = 0;
537 // Read relation properties.
538 c = openscop_util_skip_blank_and_comments(foo, s);
539 read = sscanf(c, " %d %d %d %d %d %d", &nb_rows, &nb_columns,
540 &nb_output_dims, &nb_input_dims,
541 &nb_local_dims, &nb_parameters);
543 if (((read != 1) && (read != 2) && (read != 6)) ||
544 ((read == 1) && (may_read_nb_union_parts != 1))) {
545 fprintf(stderr, "[OpenScop] Error: badly formated relation.\n");
546 exit(1);
549 if (read == 1) {
550 // Only one number means a union and is the number of parts.
551 nb_union_parts = nb_rows;
552 if (nb_union_parts < 1) {
553 fprintf(stderr, "[OpenScop] Error: negative nb of union parts.\n");
554 exit(1);
556 // Allow to read the properties of the first part of the union.
557 read_properties = 1;
560 if (read == 2) {
561 nb_output_dims = OPENSCOP_UNDEFINED;
562 nb_input_dims = OPENSCOP_UNDEFINED;
563 nb_local_dims = OPENSCOP_UNDEFINED;
564 nb_parameters = OPENSCOP_UNDEFINED;
567 may_read_nb_union_parts = 0;
570 // Allocate the union part and fill its properties.
571 relation = openscop_relation_malloc(nb_rows, nb_columns);
572 relation->nb_output_dims = nb_output_dims;
573 relation->nb_input_dims = nb_input_dims;
574 relation->nb_local_dims = nb_local_dims;
575 relation->nb_parameters = nb_parameters;
577 // Read the matrix of constraints.
578 if ((relation->nb_rows != 0) && (relation->nb_columns != 0))
579 p = relation->m[0];
581 for (i = 0; i < relation->nb_rows; i++) {
582 c = openscop_util_skip_blank_and_comments(foo, s);
583 if (c == NULL) {
584 fprintf(stderr, "[OpenScop] Error: not enough rows.\n");
585 exit(1);
588 for (j = 0; j < relation->nb_columns; j++) {
589 if (c == NULL || *c == '#' || *c == '\n') {
590 fprintf(stderr, "[OpenScop] Error: not enough columns.\n");
591 exit(1);
593 if (sscanf(c, "%s%n", str, &n) == 0) {
594 fprintf(stderr, "[OpenScop] Error: not enough rows.\n");
595 exit(1);
597 #if defined(OPENSCOP_INT_T_IS_MP)
598 long long val;
599 if (sscanf(str, "%lld", &val) == 0) {
600 fprintf(stderr, "[OpenScop] Error: failed to read an integer.\n");
601 exit(1);
603 mpz_set_si(*p++, val);
604 #else
605 if (sscanf(str, OPENSCOP_FMT_TXT, p++) == 0) {
606 fprintf(stderr, "[OpenScop] Error: failed to read an integer.\n");
607 exit(1);
609 #endif
610 c += n;
614 // Build the linked list of union parts.
615 if (first == 1) {
616 relation_union = relation;
617 first = 0;
619 else {
620 previous->next = relation;
623 previous = relation;
624 read_properties = 1;
627 return relation_union;
631 /*+***************************************************************************
632 * Memory allocation/deallocation function *
633 *****************************************************************************/
637 * openscop_relation_malloc function:
638 * this function allocates the memory space for a openscop_relation_t
639 * structure and sets its fields with default values. Then it returns a
640 * pointer to the allocated space.
641 * \param[in] nb_rows The number of row of the relation to allocate.
642 * \param[in] nb_columns The number of columns of the relation to allocate.
643 * \return A pointer to an empty relation with fields set to default values
644 * and a ready-to-use constraint matrix.
646 openscop_relation_p openscop_relation_malloc(int nb_rows, int nb_columns) {
647 openscop_relation_p relation;
648 openscop_int_t ** p, * q;
649 int i, j;
651 relation = (openscop_relation_p)malloc(sizeof(openscop_relation_t));
652 if (relation == NULL) {
653 fprintf(stderr, "[OpenScop] Error: memory Overflow.\n");
654 exit(1);
657 relation->type = OPENSCOP_UNDEFINED;
658 relation->nb_rows = nb_rows;
659 relation->nb_columns = nb_columns;
660 relation->nb_output_dims = OPENSCOP_UNDEFINED;
661 relation->nb_input_dims = OPENSCOP_UNDEFINED;
662 relation->nb_parameters = OPENSCOP_UNDEFINED;
663 relation->nb_local_dims = OPENSCOP_UNDEFINED;
665 if ((nb_rows == 0) || (nb_columns == 0) ||
666 (nb_rows == OPENSCOP_UNDEFINED) || (nb_columns == OPENSCOP_UNDEFINED)) {
667 relation->m = NULL;
669 else {
670 p = (openscop_int_t **)malloc(nb_rows * sizeof(openscop_int_t *));
671 if (p == NULL) {
672 fprintf(stderr, "[OpenScop] Error: memory Overflow.\n");
673 exit(1);
675 q = (openscop_int_t *)malloc(nb_rows*nb_columns*sizeof(openscop_int_t));
676 if (q == NULL) {
677 fprintf(stderr, "[OpenScop] Error: memory Overflow.\n");
678 exit(1);
680 relation->m = p;
681 for (i = 0; i < nb_rows; i++) {
682 *p++ = q;
683 for (j = 0; j < nb_columns; j++)
684 SCOPINT_init_set_si(*(q+j),0);
685 q += nb_columns;
689 relation->next = NULL;
691 return relation;
696 * openscop_relation_free_inside function:
697 * this function frees the allocated memory for the inside of a
698 * openscop_relation_t structure, i.e. only m.
699 * \param[in] relation The pointer to the relation we want to free internals.
701 void openscop_relation_free_inside(openscop_relation_p relation) {
702 int i, nb_elements;
703 openscop_int_t * p;
705 if (relation == NULL)
706 return;
708 nb_elements = relation->nb_rows * relation->nb_columns;
710 if (nb_elements > 0)
711 p = relation->m[0];
713 for (i = 0; i < nb_elements; i++)
714 SCOPINT_clear(*p++);
716 if (relation->m != NULL) {
717 if (nb_elements > 0)
718 free(relation->m[0]);
719 free(relation->m);
725 * openscop_relation_free function:
726 * this function frees the allocated memory for a openscop_relation_t
727 * structure.
728 * \param[in] relation The pointer to the relation we want to free.
730 void openscop_relation_free(openscop_relation_p relation) {
731 openscop_relation_p tmp;
733 if (relation == NULL)
734 return;
736 while (relation != NULL) {
737 tmp = relation->next;
738 openscop_relation_free_inside(relation);
739 free(relation);
740 relation = tmp;
745 /*+***************************************************************************
746 * Processing functions *
747 *****************************************************************************/
751 * openscop_relation_is_matrix function:
752 * this function returns 1 if the relation provided as parameter corresponds
753 * to a "matrix" representation (see documentation), -1 if it is NULL and
754 * 0 in all other cases.
755 * \param[in] relation The relation we want to know if it is a matrix or not.
756 * \return 1 if the relation has "matrix" representation, -1 if it is NULL,
757 * 0 in all other cases.
759 int openscop_relation_is_matrix(openscop_relation_p relation) {
760 if (relation == NULL)
761 return -1;
763 // A relation has matrix representation if all nb_local_dims fields
764 // of all parts of the union is OPENSCOP_UNDEFINED.
765 while (relation != NULL) {
766 if (relation->nb_local_dims != OPENSCOP_UNDEFINED)
767 return 0;
769 relation = relation->next;
772 return 1;
777 * openscop_relation_ncopy function:
778 * this functions builds and returns a "hard copy" (not a pointer copy) of a
779 * openscop_relation_t data structure such that the copy is restricted to the
780 * "n" first rows of the relation. This applies to all the parts in the case
781 * of a relation union.
782 * \param[in] relation The pointer to the relation we want to copy.
783 * \param[in] n The number of row of the relation we want to copy (the
784 * special value -1 means "all the rows").
785 * \return A pointer to the full copy of the relation union restricted to the
786 * first n rows of constraint matrix for each part of the union.
788 openscop_relation_p openscop_relation_ncopy(openscop_relation_p relation,
789 int n) {
790 int i, j;
791 int first = 1, all_rows = 0;
792 openscop_relation_p copy = NULL, node, previous = NULL;
794 if (n == -1)
795 all_rows = 1;
797 while (relation != NULL) {
798 if (all_rows)
799 n = relation->nb_rows;
801 if (n > relation->nb_rows) {
802 fprintf(stderr,"[OpenScop] Error: not enough rows in the relation\n");
803 exit(1);
806 node = openscop_relation_malloc(n, relation->nb_columns);
807 node->type = relation->type;
808 node->nb_output_dims = relation->nb_output_dims;
809 node->nb_input_dims = relation->nb_input_dims;
810 node->nb_local_dims = relation->nb_local_dims;
811 node->nb_parameters = relation->nb_parameters;
813 for (i = 0; i < n; i++)
814 for (j = 0; j < relation->nb_columns; j++)
815 SCOPINT_assign(node->m[i][j], relation->m[i][j]);
817 if (first) {
818 first = 0;
819 copy = node;
820 previous = node;
822 else {
823 previous->next = node;
824 previous = previous->next;
827 relation = relation->next;
830 return copy;
835 * openscop_relation_copy function:
836 * this function builds and returns a "hard copy" (not a pointer copy) of an
837 * openscop_relation_t data structure (the full union of relation).
838 * \param[in] relation The pointer to the relation we want to copy.
839 * \return A pointer to the copy of the union of relations.
841 openscop_relation_p openscop_relation_copy(openscop_relation_p relation) {
842 if (relation == NULL)
843 return NULL;
845 return openscop_relation_ncopy(relation, -1);
850 * openscop_relation_replace_vector function:
851 * this function replaces the "row"^th row of a relation "relation" with the
852 * vector "vector". It directly updates the relation union part pointed
853 * by "relation" and this part only.
854 * \param[in,out] relation The relation we want to replace a row.
855 * \param[in] vector The vector that will replace a row of the relation.
856 * \param[in] row The row of the relation to be replaced.
858 void openscop_relation_replace_vector(openscop_relation_p relation,
859 openscop_vector_p vector, int row) {
860 int i;
862 if ((relation == NULL) || (vector == NULL) ||
863 (relation->nb_columns != vector->size) ||
864 (row >= relation->nb_rows) || (row < 0)) {
865 fprintf(stderr,"[OpenScop] Error: vector cannot replace relation row.\n");
866 exit(1);
869 for (i = 0; i < vector->size; i++)
870 SCOPINT_assign(relation->m[row][i], vector->v[i]);
875 * openscop_relation_add_vector function:
876 * this function adds (meaning, +) a vector to the "row"^th row of a
877 * relation "relation". It directly updates the relation union part pointed
878 * by "relation" and this part only.
879 * \param[in,out] relation The relation we want to add a vector to a row.
880 * \param[in] vector The vector that will replace a row of the relation.
881 * \param[in] row The row of the relation to be replaced.
883 void openscop_relation_add_vector(openscop_relation_p relation,
884 openscop_vector_p vector, int row) {
885 int i;
887 if ((relation == NULL) || (vector == NULL) ||
888 (relation->nb_columns != vector->size) ||
889 (row >= relation->nb_rows) || (row < 0)) {
890 fprintf(stderr,"[OpenScop] Error: vector cannot be added to relation.\n");
891 exit(1);
894 if (SCOPINT_get_si(relation->m[row][0]) == 0)
895 SCOPINT_assign(relation->m[row][0], vector->v[0]);
897 for (i = 1; i < vector->size; i++)
898 SCOPINT_addto(relation->m[row][i], relation->m[row][i], vector->v[i]);
903 * openscop_relation_sub_vector function:
904 * this function subtracts the vector "vector" to the "row"^th row of
905 * a relation "relation. It directly updates the relation union part pointed
906 * by "relation" and this part only.
907 * \param[in,out] relation The relation where to subtract a vector to a row.
908 * \param[in] vector The vector to subtract to a relation row.
909 * \param[in] row The row of the relation to subtract the vector.
911 void openscop_relation_sub_vector(openscop_relation_p relation,
912 openscop_vector_p vector, int row) {
913 int i;
915 if ((relation == NULL) || (vector == NULL) ||
916 (relation->nb_columns != vector->size) ||
917 (row >= relation->nb_rows) || (row < 0)) {
918 fprintf(stderr,"[OpenScop] Error: vector cannot be subtracted to row.\n");
919 exit(1);
922 if (SCOPINT_get_si(relation->m[row][0]) == 0)
923 SCOPINT_assign(relation->m[row][0], vector->v[0]);
925 for (i = 1; i < vector->size; i++)
926 SCOPINT_subtract(relation->m[row][i], relation->m[row][i], vector->v[i]);
931 * openscop_relation_insert_vector function:
932 * this function inserts a new row corresponding to the vector "vector" to
933 * the relation "relation" by inserting it at the "row"^th row. It directly
934 * updates the relation union part pointed by "relation" and this part only.
935 * If "vector" (or "relation") is NULL, the relation is left unmodified.
936 * \param[in,out] relation The relation we want to extend.
937 * \param[in] vector The vector that will be added relation.
938 * \param[in] row The row where to insert the vector.
940 void openscop_relation_insert_vector(openscop_relation_p relation,
941 openscop_vector_p vector, int row) {
942 openscop_relation_p temp;
944 temp = openscop_relation_from_vector(vector);
945 openscop_relation_insert_relation(relation, temp, row);
946 openscop_relation_free(temp);
951 * openscop_relation_from_vector function:
952 * this function converts a vector "vector" to a relation with a single row
953 * and returns a pointer to that relation.
954 * \param[in] vector The vector to convert to a relation.
955 * \return A pointer to a relation resulting from the vector conversion.
957 openscop_relation_p openscop_relation_from_vector(openscop_vector_p vector) {
958 openscop_relation_p relation;
960 if (vector == NULL)
961 return NULL;
963 relation = openscop_relation_malloc(1, vector->size);
964 openscop_relation_replace_vector(relation, vector, 0);
965 return relation;
970 * openscop_relation_replace_relation function:
971 * this function replaces some rows of a relation "r1" with the rows of
972 * the relation "r2". It begins at the "row"^th row of "r1". It directly
973 * updates the relation union part pointed by "r1" and this part only.
974 * \param[in,out] r1 The relation we want to change some rows.
975 * \param[in] r2 The relation containing the new rows.
976 * \param[in] row The first row of the relation r1 to be replaced.
978 void openscop_relation_replace_relation(openscop_relation_p r1,
979 openscop_relation_p r2, int row) {
980 int i, j;
982 if ((r1 == NULL) || (r2 == NULL) ||
983 (r1->nb_columns != r1->nb_columns) ||
984 ((row + r2->nb_rows) > r1->nb_rows) || (row < 0)) {
985 fprintf(stderr,"[OpenScop] Error: relation rows could not be replaced.\n");
986 exit(1);
989 for (i = 0; i < r2->nb_rows; i++)
990 for (j = 0; j < r2->nb_columns; j++)
991 SCOPINT_assign(r1->m[i+row][j], r2->m[i][j]);
996 * openscop_relation_insert_relation function:
997 * this function adds new rows corresponding to the relation "r1" to
998 * the relation "r2" by inserting it at the "row"^th row. It directly
999 * updates the relation union part pointed by "r1" and this part only.
1000 * If "r2" (or "r1") is NULL, the relation is left unmodified.
1001 * \param[in,out] r1 The relation we want to extend.
1002 * \param[in] r2 The relation to be inserted.
1003 * \param[in] row The row where to insert the relation
1005 void openscop_relation_insert_relation(openscop_relation_p r1,
1006 openscop_relation_p r2, int row) {
1007 int i, j;
1008 openscop_relation_p temp;
1010 if ((r1 == NULL) || (r2 == NULL))
1011 return;
1013 if ((r1->nb_columns != r2->nb_columns) ||
1014 (row > r1->nb_rows) || (row < 0)) {
1015 fprintf(stderr,"[OpenScop] Error: constraints cannot be inserted.\n");
1016 exit(1);
1019 // We use a temporary relation just to reuse existing functions. Cleaner.
1020 temp = openscop_relation_malloc(r1->nb_rows+r2->nb_rows, r1->nb_columns);
1022 for (i = 0; i < row; i++)
1023 for (j = 0; j < r1->nb_columns; j++)
1024 SCOPINT_assign(temp->m[i][j], r1->m[i][j]);
1026 openscop_relation_replace_relation(temp, r2, row);
1028 for (i = row + r2->nb_rows; i < r2->nb_rows + r1->nb_rows; i++)
1029 for (j = 0; j < r1->nb_columns; j++)
1030 SCOPINT_assign(temp->m[i][j], r1->m[i-r2->nb_rows][j]);
1032 openscop_relation_free_inside(r1);
1034 // Replace the inside of relation.
1035 r1->nb_rows = temp->nb_rows;
1036 r1->m = temp->m;
1038 // Free the temp "shell".
1039 free(temp);
1044 * openscop_relation_concat function:
1045 * this function builds a new relation from two relations sent as
1046 * parameters. The new set of constraints is built as the concatenation
1047 * of the rows of the first elements of the two relation unions r1 and r2.
1048 * This means, there is no next field in the result.
1049 * \param[in] r1 The first relation.
1050 * \param[in] r2 The second relation.
1051 * \return A pointer to the relation resulting from the concatenation of
1052 * the first elements of r1 and r2.
1054 openscop_relation_p openscop_relation_concat(openscop_relation_p r1,
1055 openscop_relation_p r2) {
1056 openscop_relation_p new;
1058 if (r1 == NULL)
1059 return openscop_relation_copy(r2);
1061 if (r2 == NULL)
1062 return openscop_relation_copy(r1);
1064 if (r1->nb_columns != r2->nb_columns) {
1065 fprintf(stderr, "[OpenScop] Error: incompatible sizes "
1066 "for concatenation.\n");
1067 exit(1);
1069 if (r1->next || r2->next) {
1070 fprintf(stderr, "[OpenScop] Warning: relation concatenation is done "
1071 "on the first elements only.\n");
1074 new = openscop_relation_malloc(r1->nb_rows+r2->nb_rows, r1->nb_columns);
1075 openscop_relation_replace_relation(new, r1, 0);
1076 openscop_relation_replace_relation(new, r2, r1->nb_rows);
1078 return new;
1083 * openscop_relation_equal function:
1084 * this function returns true if the two relations provided as parameters
1085 * are the same, false otherwise.
1086 * \param[in] r1 The first relation.
1087 * \param[in] r2 The second relation.
1088 * \return 1 if r1 and r2 are the same (content-wise), 0 otherwise.
1090 int openscop_relation_equal(openscop_relation_p r1, openscop_relation_p r2) {
1091 int i, j;
1093 while ((r1 != NULL) && (r2 != NULL)) {
1094 if (r1 == r2)
1095 return 1;
1097 if ((r1->type != r2->type) ||
1098 (r1->nb_rows != r2->nb_rows) ||
1099 (r1->nb_columns != r2->nb_columns) ||
1100 (r1->nb_output_dims != r2->nb_output_dims) ||
1101 (r1->nb_input_dims != r2->nb_input_dims) ||
1102 (r1->nb_local_dims != r2->nb_local_dims) ||
1103 (r1->nb_parameters != r2->nb_parameters))
1104 return 0;
1106 for (i = 0; i < r1->nb_rows; ++i)
1107 for (j = 0; j < r1->nb_columns; ++j)
1108 if (SCOPINT_ne(r1->m[i][j], r2->m[i][j]))
1109 return 0;
1111 r1 = r1->next;
1112 r2 = r2->next;
1115 if (((r1 == NULL) && (r2 != NULL)) || ((r1 != NULL) && (r2 == NULL)))
1116 return 0;
1118 return 1;
1123 * openscop_relation_check_property internal function:
1124 * This function checks whether an "actual" value is the same as an
1125 * "expected" value or not. If the expected value is set to
1126 * OPENSCOP_UNDEFINED, this function sets it to the "actual" value
1127 * and do not report a difference has been detected.
1128 * It returns 0 if a difference has been detected, 1 otherwise.
1129 * \param[in,out] expected Pointer to the expected value (the value is
1130 * modified if it was set to OPENSCOP_UNDEFINED).
1131 * \param[in] actual Value we want to check.
1132 * \return 0 if the values are not the same while the expected value was
1133 * not OPENSCOP_UNDEFINED, 1 otherwise.
1135 static
1136 int openscop_relation_check_property(int * expected, int actual) {
1137 if (*expected != OPENSCOP_UNDEFINED) {
1138 if ((actual != OPENSCOP_UNDEFINED) &&
1139 (actual != *expected)) {
1140 fprintf(stderr, "[OpenScop] Warning: unexpected property.\n");
1141 return 0;
1144 else {
1145 *expected = actual;
1148 return 1;
1153 * openscop_relation_check_nb_columns internal function:
1154 * This function checks that the number of columns of a relation
1155 * corresponds to some expected properties (setting an expected property to
1156 * OPENSCOP_UNDEFINED makes this function unable to detect a problem).
1157 * It returns 0 if the number of columns seems incorrect or 1 if no problem
1158 * has been detected.
1159 * \param[in] relation The relation we want to check the number of columns.
1160 * \param[in] expected_nb_output_dims Expected number of output dimensions.
1161 * \param[in] expected_nb_input_dims Expected number of input dimensions.
1162 * \param[in] expected_nb_parameters Expected number of parameters.
1163 * \return 0 if the number of columns seems incorrect, 1 otherwise.
1165 static
1166 int openscop_relation_check_nb_columns(openscop_relation_p relation,
1167 int expected_nb_output_dims,
1168 int expected_nb_input_dims,
1169 int expected_nb_parameters) {
1170 int expected_nb_local_dims, expected_nb_columns;
1172 if ((expected_nb_output_dims != OPENSCOP_UNDEFINED) &&
1173 (expected_nb_input_dims != OPENSCOP_UNDEFINED) &&
1174 (expected_nb_parameters != OPENSCOP_UNDEFINED)) {
1176 if (relation->nb_local_dims == OPENSCOP_UNDEFINED)
1177 expected_nb_local_dims = 0;
1178 else
1179 expected_nb_local_dims = relation->nb_local_dims;
1181 expected_nb_columns = expected_nb_output_dims +
1182 expected_nb_input_dims +
1183 expected_nb_local_dims +
1184 expected_nb_parameters +
1187 if (expected_nb_columns != relation->nb_columns) {
1188 fprintf(stderr, "[OpenScop] Warning: unexpected number of columns.\n");
1189 return 0;
1193 return 1;
1198 * openscop_relation_consistency_check function:
1199 * this function checks that each part of an union of relations use the same
1200 * representation type (either matrix or relation representation). It returns
1201 * 1 if it is the case, 0 otherwise.
1202 * \param[in] r The relation to check for representation consistency.
1203 * \return 0 if the representation consistency check fails, 1 if it succeeds.
1205 static
1206 int openscop_relation_consistency_check(openscop_relation_p r) {
1207 int matrix = 0;
1208 int relation = 0;
1210 while (r != NULL) {
1211 if (r->nb_local_dims == OPENSCOP_UNDEFINED)
1212 matrix = 1;
1213 else
1214 relation = 1;
1216 r = r->next;
1219 return (matrix == relation) ? 0 : 1;
1224 * openscop_relation_integrity_check function:
1225 * this function checks that a relation is "well formed" according to some
1226 * expected properties (setting an expected value to OPENSCOP_UNDEFINED means
1227 * that we do not expect a specific value) and what the relation is supposed
1228 * to represent. It returns 0 if the check failed or 1 if no problem has been
1229 * detected.
1230 * \param[in] relation The relation we want to check.
1231 * \param[in] type Semantics about this relation (domain, access...).
1232 * \param[in] expected_nb_output_dims Expected number of output dimensions.
1233 * \param[in] expected_nb_input_dims Expected number of input dimensions.
1234 * \param[in] expected_nb_parameters Expected number of parameters.
1235 * \return 0 if the integrity check fails, 1 otherwise.
1237 int openscop_relation_integrity_check(openscop_relation_p relation,
1238 int type,
1239 int expected_nb_output_dims,
1240 int expected_nb_input_dims,
1241 int expected_nb_parameters) {
1242 int i, is_matrix, nb_array_id, row_id = -1;
1243 openscop_int_t array_id, tmp;
1245 // Check the NULL case.
1246 if (relation == NULL) {
1247 if ((expected_nb_output_dims != OPENSCOP_UNDEFINED) &&
1248 (expected_nb_input_dims != OPENSCOP_UNDEFINED) &&
1249 (expected_nb_parameters != OPENSCOP_UNDEFINED)) {
1250 fprintf(stderr, "[OpenScop] Warning: NULL relation with "
1251 "some expected properties.\n");
1252 return 0;
1254 else {
1255 fprintf(stderr, "[OpenScop] Warning: integrity check of a NULL "
1256 "relation.\n");
1257 return 1;
1261 // Check the relation is using either matrix or relation representation.
1262 if (!openscop_relation_consistency_check(relation)) {
1263 fprintf(stderr, "[OpenScop] Warning: inconsistent representation "
1264 "(both matrix and relation).\n");
1265 return 0;
1267 is_matrix = openscop_relation_is_matrix(relation);
1269 // Check that a context has actually 0 or an undefined #output dimensions.
1270 if ((type == OPENSCOP_TYPE_CONTEXT) &&
1271 ((relation->nb_output_dims != 0) &&
1272 (relation->nb_output_dims != OPENSCOP_UNDEFINED))) {
1273 fprintf(stderr, "[OpenScop] Warning: context without 0 "
1274 "as number of output dimensions.\n");
1275 return 0;
1278 // Check that a domain has actually 0 or an undefined #input dimensions.
1279 if (((type == OPENSCOP_TYPE_DOMAIN) ||
1280 (type == OPENSCOP_TYPE_CONTEXT)) &&
1281 ((relation->nb_input_dims != 0) &&
1282 (relation->nb_input_dims != OPENSCOP_UNDEFINED))) {
1283 fprintf(stderr, "[OpenScop] Warning: domain or context without 0 "
1284 "as number of input dimensions.\n");
1285 return 0;
1288 // Check properties according to expected values (and if expected values
1289 // are undefined, define them with the first relation part properties).
1290 if (!openscop_relation_check_property(&expected_nb_output_dims,
1291 relation->nb_output_dims) ||
1292 !openscop_relation_check_property(&expected_nb_input_dims,
1293 relation->nb_input_dims) ||
1294 !openscop_relation_check_property(&expected_nb_parameters,
1295 relation->nb_parameters))
1296 return 0;
1298 while (relation != NULL) {
1299 // Properties (except the number of local dimensions) should be the same
1300 // in all parts.
1301 if ((expected_nb_output_dims != relation->nb_output_dims) ||
1302 (expected_nb_input_dims != relation->nb_input_dims) ||
1303 (expected_nb_parameters != relation->nb_parameters)) {
1304 fprintf(stderr, "[OpenScop] Warning: inconsistent properties.\n");
1305 return 0;
1308 // Check whether the number of columns is OK or not.
1309 if (!openscop_relation_check_nb_columns(relation,
1310 expected_nb_output_dims,
1311 expected_nb_input_dims,
1312 expected_nb_parameters))
1313 return 0;
1315 // Check the first column. The first column of a relation part
1316 // should be made of 0 or 1 only, except:
1317 // - for the [0][0] element of an access function in "matrix"
1318 // representation (array identifier),
1319 // - for scattering functions in "matrix" representation, the
1320 // first column is made only of 0.
1321 if ((relation->nb_rows > 0) && (relation->nb_columns > 0)) {
1322 for (i = 0; i < relation->nb_rows; i++) {
1323 if (!((i == 0) && (type == OPENSCOP_TYPE_ACCESS) && is_matrix)) {
1324 if ((type == OPENSCOP_TYPE_SCATTERING) && is_matrix) {
1325 if (!SCOPINT_zero_p(relation->m[i][0])) {
1326 fprintf(stderr, "[OpenScop] Warning: first column of a "
1327 "scattering function not made of 0s.\n");
1328 return 0;
1331 else {
1332 if (!SCOPINT_zero_p(relation->m[i][0]) &&
1333 !SCOPINT_one_p(relation->m[i][0])) {
1334 fprintf(stderr, "[OpenScop] Warning: first column of a "
1335 "relation is not strictly made of 0 or 1.\n");
1336 return 0;
1343 // Array accesses must provide the array identifier.
1344 if (type == OPENSCOP_TYPE_ACCESS) {
1346 // There should be room to store the array identifier.
1347 if ((relation->nb_rows == 0) ||
1348 (is_matrix && (relation->nb_columns < 2)) ||
1349 (!is_matrix && (relation->nb_columns < 3))) {
1350 fprintf(stderr, "[OpenScop] Warning: no array identifier in "
1351 "an access function.\n");
1352 return 0;
1355 // In matrix format, the array identifier is in m[0][0] and it should
1356 // be greater than 0.
1357 if (is_matrix && SCOPINT_get_si(relation->m[0][0]) <= 0) {
1358 fprintf(stderr, "[OpenScop] Warning: negative or 0 identifier "
1359 "in access function.\n");
1360 return 0;
1363 // In relation format, array identifiers are
1364 // m[i][#columns -1] / m[i][1], with i the only row
1365 // where m[i][1] is not 0.
1366 // - check there is exactly one row such that m[i][1] is not 0,
1367 // - check the whole ith row if full of 0 except m[i][1] and the id,
1368 // - check that (m[i][#columns -1] % m[i][1]) == 0,
1369 // - check that (-m[i][#columns -1] / m[i][1]) > 0.
1370 if (!is_matrix) {
1371 nb_array_id = 0;
1372 for (i = 0; i < relation->nb_rows; i++) {
1373 if (!SCOPINT_zero_p(relation->m[i][1])) {
1374 nb_array_id ++;
1375 row_id = i;
1378 if (nb_array_id == 0) {
1379 fprintf(stderr, "[OpenScop] Warning: no array identifier in "
1380 "an access function.\n");
1381 return 0;
1383 if (nb_array_id > 1) {
1384 fprintf(stderr, "[OpenScop] Warning: several array identification "
1385 "rows in one access function.\n");
1386 return 0;
1388 for (i = 0; i < relation->nb_columns - 1; i++) {
1389 if ((i != 1) && !SCOPINT_zero_p(relation->m[row_id][i])) {
1390 fprintf(stderr, "[OpenScop] Warning: non integer array "
1391 "identifier.\n");
1392 return 0;
1395 if (!SCOPINT_divisible(relation->m[row_id][relation->nb_columns - 1],
1396 relation->m[row_id][1])) {
1397 fprintf(stderr, "[OpenScop] Warning: rational array identifier.\n");
1398 return 0;
1400 SCOPINT_init(array_id);
1401 SCOPINT_init(tmp);
1402 SCOPINT_oppose(tmp, relation->m[row_id][relation->nb_columns - 1]);
1403 SCOPINT_fdiv(array_id, tmp, relation->m[row_id][1]);
1404 if (!SCOPINT_pos_p(array_id)) {
1405 SCOPINT_clear(array_id);
1406 SCOPINT_clear(tmp);
1407 fprintf(stderr, "[OpenScop] Warning: negative or 0 identifier "
1408 "in access function.\n");
1409 return 0;
1411 SCOPINT_clear(array_id);
1412 SCOPINT_clear(tmp);
1416 relation = relation->next;
1419 return 1;
1424 * openscop_relation_union function:
1425 * this function builds a new relation from two relations provided
1426 * as parameters. The new relation is built as an union of the
1427 * two relations: the list of constraint sets are linked together.
1428 * \param[in] r1 The first relation.
1429 * \param[in] r2 The second relation.
1430 * \return A new relation corresponding to the union of r1 and r2.
1432 openscop_relation_p openscop_relation_union(openscop_relation_p r1,
1433 openscop_relation_p r2) {
1434 openscop_relation_p copy1, copy2, tmp;
1436 if ((r1 == NULL) && (r2 == NULL))
1437 return NULL;
1439 copy1 = openscop_relation_copy(r1);
1440 copy2 = openscop_relation_copy(r2);
1442 if ((r1 != NULL) && (r2 == NULL))
1443 return copy1;
1445 if ((r1 == NULL) && (r2 != NULL))
1446 return copy2;
1448 tmp = copy1;
1449 while (tmp->next != NULL)
1450 tmp = tmp->next;
1452 tmp->next = copy2;
1453 return copy1;
1457 /**
1458 * openscop_relation_set_type function:
1459 * this function sets the type of each relation union part in the relation
1460 * to the one provided as parameter.
1461 * \param relation The relation to set the type.
1462 * \param type The type.
1464 void openscop_relation_set_type(openscop_relation_p relation, int type) {
1466 while (relation != NULL) {
1467 relation->type = type;
1468 relation = relation->next;