Fix integrity check for context
[openscop.git] / source / relation.c
blob2997c14058ce838a3ecff87103c3c435fa92ad07
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_structure function:
78 * this function displays a openscop_relation_t structure (*relation) into a
79 * file (file, possibly stdout) in a way that trends to be understandable.
80 * It includes an indentation level (level) in order to work with others
81 * print_structure functions.
82 * \param[in] file File where informations are printed.
83 * \param[in] relation The relation whose information have to be printed.
84 * \param[in] level Number of spaces before printing, for each line.
86 void
87 openscop_relation_print_structure(FILE * file, openscop_relation_p relation,
88 int level)
90 int i, j, first = 1;
92 // Go to the right level.
93 for (j = 0; j < level; j++)
94 fprintf(file, "|\t");
96 if (relation != NULL)
97 fprintf(file, "+-- openscop_relation_t\n");
98 else
99 fprintf(file, "+-- NULL relation\n");
101 while (relation != NULL)
103 if (! first)
105 // Go to the right level.
106 for (j = 0; j < level; j++)
107 fprintf(file, "|\t");
108 fprintf(file, "| openscop_relation_t\n");
110 else
111 first = 0;
113 // A blank line
114 for(j = 0; j <= level; j++)
115 fprintf(file, "|\t");
116 fprintf(file, "%d %d %d %d %d %d\n",
117 relation->nb_rows, relation->nb_columns,
118 relation->nb_output_dims, relation->nb_input_dims,
119 relation->nb_local_dims, relation->nb_parameters);
121 // Display the relation.
122 for (i = 0; i < relation->nb_rows; i++)
124 for (j = 0; j <= level; j++)
125 fprintf(file, "|\t");
127 fprintf(file, "[ ");
129 for (j = 0; j < relation->nb_columns; j++)
131 SCOPINT_print(file, OPENSCOP_FMT, relation->m[i][j]);
132 fprintf(file, " ");
135 fprintf(file, "]\n");
138 relation = relation->next;
140 // Next line.
141 if (relation != NULL)
143 for (j = 0; j <= level; j++)
144 fprintf(file, "|\t");
145 fprintf(file, "|\n");
146 for (j = 0; j <= level; j++)
147 fprintf(file, "|\t");
148 fprintf(file, "V\n");
152 // The last line.
153 for (j = 0; j <= level; j++)
154 fprintf(file, "|\t");
155 fprintf(file, "\n");
160 * openscop_relation_print function:
161 * this function prints the content of a openscop_relation_t structure
162 * (*relation) into a file (file, possibly stdout).
163 * \param[in] file File where informations are printed.
164 * \param[in] relation The relation whose information have to be printed.
166 void
167 openscop_relation_print(FILE * file, openscop_relation_p relation)
169 openscop_relation_print_structure(file, relation, 0);
175 * openscop_relation_expression_element function:
176 * this function returns a string containing the printing of a value (possibly
177 * an iterator or a parameter with its coefficient or a constant).
178 * \param[in] val The coefficient or constant value.
179 * \param[in,out] first Pointer to a boolean set to 1 if the current value is
180 * the first of an expresion, 0 otherwise (maybe updated).
181 * \param[in] cst A boolean set to 1 if the value is a constant,
182 * 0 otherwise.
183 * \param[in] name String containing the name of the element.
184 * \return A string that contains the printing of a value.
186 static
187 char *
188 openscop_relation_expression_element(openscop_int_t val, int * first, int cst,
189 char * name)
191 char * sval, * body, * temp;
193 temp = (char *)malloc(OPENSCOP_MAX_STRING * sizeof(char));
194 body = (char *)malloc(OPENSCOP_MAX_STRING * sizeof(char));
195 sval = (char *)malloc(OPENSCOP_MAX_STRING * sizeof(char));
196 body[0] = '\0';
197 sval[0] = '\0';
199 // statements for the 'normal' processing.
200 if (SCOPINT_notzero_p(val) && (!cst))
202 if ((*first) || SCOPINT_neg_p(val))
204 if (SCOPINT_one_p(val)) // case 1
205 sprintf(sval, "%s", name);
206 else
208 if (SCOPINT_mone_p(val)) // case -1
209 sprintf(sval, "-%s", name);
210 else // default case
212 SCOPINT_sprint(sval, OPENSCOP_FMT_TXT, val);
213 sprintf(temp, "*%s", name);
214 strcat(sval, temp);
217 *first = 0;
219 else
221 if (SCOPINT_one_p(val))
222 sprintf(sval, "+%s", name);
223 else
225 sprintf(sval, "+");
226 SCOPINT_sprint(temp, OPENSCOP_FMT_TXT, val);
227 strcat(sval, temp);
228 sprintf(temp, "*%s", name);
229 strcat(sval, temp);
233 else
235 if (cst)
237 if ((SCOPINT_zero_p(val) && (*first)) || SCOPINT_neg_p(val))
238 SCOPINT_sprint(sval, OPENSCOP_FMT_TXT, val);
239 if (SCOPINT_pos_p(val))
241 if (!(*first))
243 SCOPINT_sprint(sval, "+"OPENSCOP_FMT_TXT, val); // Block macro !
245 else
246 SCOPINT_sprint(sval, OPENSCOP_FMT_TXT, val);
250 free(temp);
251 free(body);
253 return(sval);
258 * openscop_relation_expression function:
259 * this function returns a string corresponding to an affine expression
260 * stored at the "row"^th row of the relation pointed by "relation".
261 * \param[in] relation A set of linear expressions.
262 * \param[in] row The row corresponding to the expression.
263 * \param[in] names The textual names of the various elements. Is is
264 * important that names->nb_parameters is exact if the
265 * matrix representation is used. Set to NULL if
266 * printing comments is not needed.
267 * \return A string that contains the printing of an affine expression.
269 static
270 char *
271 openscop_relation_expression(openscop_relation_p relation, int row,
272 openscop_names_p names)
274 int i, first = 1;
275 char * sline, * sval;
277 sline = (char *)malloc(OPENSCOP_MAX_STRING * sizeof(char)) ;
278 sline[0] = '\0' ;
280 // First the iterator part.
281 for (i = 1; i <= names->nb_iterators; i++)
283 sval = openscop_relation_expression_element(relation->m[row][i],
284 &first, 0, names->iterators[i-1]);
285 strcat(sline, sval);
286 free(sval);
289 // Next the local dims part.
290 for (i = names->nb_iterators + 1;
291 i <= names->nb_iterators + names->nb_localdims; i++)
293 sval = openscop_relation_expression_element(relation->m[row][i], &first, 0,
294 names->localdims[i - names->nb_iterators - 1]);
295 strcat(sline, sval);
296 free(sval);
299 // Next the parameter part.
300 for (i = names->nb_iterators + names->nb_localdims + 1;
301 i <= names->nb_iterators + names->nb_localdims + names->nb_parameters;
302 i++)
304 sval = openscop_relation_expression_element(relation->m[row][i], &first, 0,
305 names->parameters[i - names->nb_iterators - names->nb_localdims - 1]);
306 strcat(sline, sval);
307 free(sval);
310 // Finally the constant part (yes, I reused it).
311 sval = openscop_relation_expression_element(relation->m[row][i],
312 &first, 1, NULL);
313 strcat(sline, sval);
314 free(sval);
316 return sline;
321 * openscop_relation_get_array_id internal function:
322 * this function returns the array identifier when the relation provided
323 * as parameter corresponds to an access function.
324 * \param[in] relation The access function.
325 * \return The accessed array identifier.
327 static
329 openscop_relation_get_array_id(openscop_relation_p relation)
331 if (relation == NULL)
333 fprintf(stderr, "[OpenScop] Error: cannot find nb_arrays "
334 "in a NULL relation.\n");
335 exit(1);
338 if (relation->nb_local_dims == OPENSCOP_UNDEFINED)
340 // Matrix representation case.
341 if ((relation->nb_rows < 1) || (relation->nb_columns < 1))
343 fprintf(stderr, "[OpenScop] Error: not enough rows or columns "
344 "to extract nb_arrays.\n");
345 exit(1);
347 return SCOPINT_get_si(relation->m[0][0]);
349 else
351 // Relation representation case.
352 if ((relation->nb_rows < 1) || (relation->nb_columns < 2))
354 fprintf(stderr, "[OpenScop] Error: not enough rows or columns "
355 "to extract nb_arrays.\n");
356 exit(1);
358 // TODO: do something more general
359 return SCOPINT_get_si(relation->m[0][relation->nb_columns - 1]);
365 * openscop_relation_print_openscop function:
366 * this function prints the content of a openscop_relation_t structure
367 * (*relation) into a file (file, possibly stdout) in the OpenScop format.
368 * \param[in] file File where informations are printed.
369 * \param[in] relation The relation whose information has to be printed.
370 * \param[in] type Semantics about this relation (domain, access...).
371 * \param[in] names The textual names of the various elements. Is is
372 * important that names->nb_parameters is exact if the
373 * matrix representation is used. Set to NULL if printing
374 * comments is not needed.
376 void
377 openscop_relation_print_openscop(FILE * file, openscop_relation_p relation,
378 int type, openscop_names_p names)
380 int i, j, k;
381 int part, nb_parts;
382 char * expression;
383 openscop_relation_p r;
385 if (relation == NULL)
387 fprintf(stderr, "[OpenScop] Warning: asked to print a NULL relation.\n");
388 fprintf(file, "# NULL relation\n");
389 return;
392 // TODO: check whether there are enough names or not, if not set to NULL.
393 // TODO: if names are not textual, set to NULL.
395 // Count the number of parts in the union and print it if it is not 1.
396 r = relation;
397 nb_parts = 0;
398 while (r != NULL)
400 nb_parts++;
401 r = r->next;
403 if (nb_parts > 1)
404 fprintf(file, "# Union with %d parts\n%d\n", nb_parts, nb_parts);
406 // Print each part of the union.
407 for (part = 1; part <= nb_parts; part++)
409 if (nb_parts > 1)
410 fprintf(file, "# Union part No.%d\n", part);
411 if ((relation->nb_output_dims == OPENSCOP_UNDEFINED) &&
412 (relation->nb_input_dims == OPENSCOP_UNDEFINED) &&
413 (relation->nb_local_dims == OPENSCOP_UNDEFINED) &&
414 (relation->nb_parameters == OPENSCOP_UNDEFINED))
415 fprintf(file, "%d %d\n", relation->nb_rows, relation->nb_columns);
416 else
417 fprintf(file, "%d %d %d %d %d %d\n",
418 relation->nb_rows, relation->nb_columns,
419 relation->nb_output_dims, relation->nb_input_dims,
420 relation->nb_local_dims, relation->nb_parameters);
422 for (i = 0; i < relation->nb_rows; i++)
424 for (j = 0; j < relation->nb_columns; j++)
426 SCOPINT_print(file, OPENSCOP_FMT, relation->m[i][j]);
427 fprintf(file, " ");
430 if (type == OPENSCOP_TYPE_DOMAIN)
432 expression = openscop_relation_expression(relation, i, names);
433 fprintf(file, " ## %s", expression);
434 free(expression);
435 if (SCOPINT_zero_p(relation->m[i][0]))
436 fprintf(file, " == 0");
437 else
438 fprintf(file, " >= 0");
441 if (type == OPENSCOP_TYPE_SCATTERING)
443 expression = openscop_relation_expression(relation, i, names);
444 fprintf(file, " ## %s", expression);
445 free(expression);
448 if (type == OPENSCOP_TYPE_ACCESS)
450 //TODO: works only for matrix: use openscop_relation_get_array_id
451 if (SCOPINT_notzero_p(relation->m[i][0]))
453 if (strncmp(names->arrays[SCOPINT_get_si(relation->m[i][0]) - 1],
454 OPENSCOP_FAKE_ARRAY, strlen(OPENSCOP_FAKE_ARRAY)))
455 fprintf(file, " ## %s",
456 names->arrays[SCOPINT_get_si(relation->m[i][0]) - 1]);
457 k = i;
460 expression = openscop_relation_expression(relation, k, names);
461 fprintf(file, "[%s]", expression);
462 free(expression);
463 k++;
465 while ((k < relation->nb_rows) &&
466 SCOPINT_zero_p(relation->m[k][0]))
469 else
470 fprintf(file, " ##");
473 fprintf(file, "\n");
475 relation = relation->next;
480 /*****************************************************************************
481 * Reading function *
482 *****************************************************************************/
486 * openscop_relation_read function:
487 * this function reads a relation into a file (foo, posibly stdin) and
488 * returns a pointer this relation.
489 * \param[in] file The input stream.
490 * \return A pointer to the relation structure that has been read.
492 openscop_relation_p
493 openscop_relation_read(FILE * foo)
495 int i, j, k, n, read = 0;
496 int nb_rows, nb_columns;
497 int nb_output_dims, nb_input_dims, nb_local_dims, nb_parameters;
498 int nb_union_parts = 1;
499 int may_read_nb_union_parts = 1;
500 int read_properties = 1;
501 int first = 1;
502 char * c, s[OPENSCOP_MAX_STRING], str[OPENSCOP_MAX_STRING];
503 openscop_relation_p relation, relation_union = NULL, previous = NULL;
504 openscop_int_t * p = NULL;
506 // Read each part of the union (the number of parts may be updated inside)
507 for (k = 0; k < nb_union_parts; k++)
509 // Read the number of union parts or the properties of the union part
510 while (read_properties)
512 read_properties = 0;
514 // Read relation properties.
515 c = openscop_util_skip_blank_and_comments(foo, s);
516 read = sscanf(c, " %d %d %d %d %d %d", &nb_rows, &nb_columns,
517 &nb_output_dims, &nb_input_dims,
518 &nb_local_dims, &nb_parameters);
520 if (((read != 1) && (read != 2) && (read != 6)) ||
521 ((read == 1) && (may_read_nb_union_parts != 1)))
523 fprintf(stderr, "[OpenScop] Error:: badly formated relation.\n");
524 exit(1);
526 if (read == 1)
528 // Only one number means a union and is the number of parts.
529 nb_union_parts = nb_rows;
530 if (nb_union_parts < 1)
532 fprintf(stderr, "[OpenScop] Error: negative nb of union parts.\n");
533 exit(1);
535 // Allow to read the properties of the first part of the union.
536 read_properties = 1;
538 if (read == 2)
540 nb_output_dims = OPENSCOP_UNDEFINED;
541 nb_input_dims = OPENSCOP_UNDEFINED;
542 nb_local_dims = OPENSCOP_UNDEFINED;
543 nb_parameters = OPENSCOP_UNDEFINED;
546 may_read_nb_union_parts = 0;
549 // Allocate the union part and fill its properties.
550 relation = openscop_relation_malloc(nb_rows, nb_columns);
551 relation->nb_output_dims = nb_output_dims;
552 relation->nb_input_dims = nb_input_dims;
553 relation->nb_local_dims = nb_local_dims;
554 relation->nb_parameters = nb_parameters;
556 // Read the matrix of constraints.
557 if ((relation->nb_rows != 0) && (relation->nb_columns != 0))
558 p = relation->m[0];
560 for (i = 0; i < relation->nb_rows; i++)
562 c = openscop_util_skip_blank_and_comments(foo, s);
563 if (c == NULL)
565 fprintf(stderr, "[OpenScop] Error: not enough rows.\n");
566 exit(1);
569 for (j = 0; j < relation->nb_columns; j++)
571 if (c == NULL || *c == '#' || *c == '\n')
573 fprintf(stderr, "[OpenScop] Error: not enough columns.\n");
574 exit(1);
576 if (sscanf(c, "%s%n", str, &n) == 0)
578 fprintf(stderr, "[OpenScop] Error: not enough rows.\n");
579 exit(1);
581 #if defined(OPENSCOP_INT_T_IS_MP)
582 long long val;
583 if (sscanf(str, "%lld", &val) == 0)
585 fprintf(stderr, "[OpenScop] Error: failed to read an integer.\n");
586 exit(1);
588 mpz_set_si(*p++, val);
589 #else
590 if (sscanf(str, OPENSCOP_FMT_TXT, p++) == 0)
592 fprintf(stderr, "[OpenScop] Error: failed to read an integer.\n");
593 exit(1);
595 #endif
596 c += n;
600 // Build the linked list of union parts.
601 if (first == 1)
603 relation_union = relation;
604 first = 0;
606 else
607 previous->next = relation;
609 previous = relation;
610 read_properties = 1;
613 return relation_union;
617 /*+***************************************************************************
618 * Memory allocation/deallocation function *
619 *****************************************************************************/
623 * openscop_relation_malloc function:
624 * this function allocates the memory space for a openscop_relation_t
625 * structure and sets its fields with default values. Then it returns a
626 * pointer to the allocated space.
627 * \param[in] nb_rows The number of row of the relation to allocate.
628 * \param[in] nb_columns The number of columns of the relation to allocate.
629 * \return A pointer to an empty relation with fields set to default values
630 * and a ready-to-use constraint matrix.
632 openscop_relation_p
633 openscop_relation_malloc(int nb_rows, int nb_columns)
635 openscop_relation_p relation;
636 openscop_int_t ** p, * q;
637 int i, j;
639 relation = (openscop_relation_p)malloc(sizeof(openscop_relation_t));
640 if (relation == NULL)
642 fprintf(stderr, "[OpenScop] Error: memory Overflow.\n");
643 exit(1);
646 relation->nb_rows = nb_rows;
647 relation->nb_columns = nb_columns;
648 relation->nb_output_dims = OPENSCOP_UNDEFINED;
649 relation->nb_input_dims = OPENSCOP_UNDEFINED;
650 relation->nb_parameters = OPENSCOP_UNDEFINED;
651 relation->nb_local_dims = OPENSCOP_UNDEFINED;
653 if ((nb_rows == 0) || (nb_columns == 0) ||
654 (nb_rows == OPENSCOP_UNDEFINED) || (nb_columns == OPENSCOP_UNDEFINED))
655 relation->m = NULL;
656 else
658 p = (openscop_int_t **)malloc(nb_rows * sizeof(openscop_int_t *));
659 if (p == NULL)
661 fprintf(stderr, "[OpenScop] Error: memory Overflow.\n");
662 exit(1);
664 q = (openscop_int_t *)malloc(nb_rows*nb_columns*sizeof(openscop_int_t));
665 if (q == NULL)
667 fprintf(stderr, "[OpenScop] Error: memory Overflow.\n");
668 exit(1);
670 relation->m = p;
671 for (i = 0; i < nb_rows; i++)
673 *p++ = q;
674 for (j = 0; j < nb_columns; j++)
675 SCOPINT_init_set_si(*(q+j),0);
676 q += nb_columns;
680 relation->next = NULL;
682 return relation;
687 * openscop_relation_free_inside function:
688 * this function frees the allocated memory for the inside of a
689 * openscop_relation_t structure, i.e. only m.
690 * \param[in] relation The pointer to the relation we want to free internals.
692 void
693 openscop_relation_free_inside(openscop_relation_p relation)
695 int i, nb_elements;
696 openscop_int_t * p;
698 if (relation == NULL)
699 return;
701 nb_elements = relation->nb_rows * relation->nb_columns;
703 if (nb_elements > 0)
704 p = relation->m[0];
706 for (i = 0; i < nb_elements; i++)
707 SCOPINT_clear(*p++);
709 if (relation->m != NULL)
711 if (nb_elements > 0)
712 free(relation->m[0]);
713 free(relation->m);
719 * openscop_relation_free function:
720 * this function frees the allocated memory for a openscop_relation_t
721 * structure.
722 * \param[in] relation The pointer to the relation we want to free.
724 void
725 openscop_relation_free(openscop_relation_p relation)
727 openscop_relation_p tmp;
729 if (relation == NULL)
730 return;
732 while (relation != NULL)
734 tmp = relation->next;
735 openscop_relation_free_inside(relation);
736 free(relation);
737 relation = tmp;
742 /*+***************************************************************************
743 * Processing functions *
744 *****************************************************************************/
748 * openscop_relation_is_matrix function:
749 * this function returns 1 if the relation provided as parameter corresponds
750 * to a "matrix" representation (see documentation), -1 if it is NULL and
751 * 0 in all other cases.
752 * \param[in] relation The relation we want to know if it is a matrix or not.
753 * \return 1 if the relation has "matrix" representation, -1 if it is NULL,
754 * 0 in all other cases.
757 openscop_relation_is_matrix(openscop_relation_p relation)
759 if (relation == NULL)
760 return -1;
762 // A relation has matrix representation if all nb_local_dims fields
763 // of all parts of the union is OPENSCOP_UNDEFINED.
764 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
789 openscop_relation_ncopy(openscop_relation_p relation, int n)
791 int i, j;
792 int first = 1, all_rows = 0;
793 openscop_relation_p copy = NULL, node, previous = NULL;
795 if (n == -1)
796 all_rows = 1;
798 while (relation != NULL)
800 if (all_rows)
801 n = relation->nb_rows;
803 if (n > relation->nb_rows)
805 fprintf(stderr,"[OpenScop] Error: not enough rows in the relation\n");
806 exit(1);
809 node = openscop_relation_malloc(n, relation->nb_columns);
810 node->nb_output_dims = relation->nb_output_dims;
811 node->nb_input_dims = relation->nb_input_dims;
812 node->nb_local_dims = relation->nb_local_dims;
813 node->nb_parameters = relation->nb_parameters;
815 for (i = 0; i < n; i++)
816 for (j = 0; j < relation->nb_columns; j++)
817 SCOPINT_assign(node->m[i][j], relation->m[i][j]);
819 if (first)
821 first = 0;
822 copy = node;
823 previous = node;
825 else
827 previous->next = node;
828 previous = previous->next;
831 relation = relation->next;
834 return copy;
839 * openscop_relation_copy function:
840 * this function builds and returns a "hard copy" (not a pointer copy) of an
841 * openscop_relation_t data structure (the full union of relation).
842 * \param[in] relation The pointer to the relation we want to copy.
843 * \return A pointer to the copy of the union of relations.
845 openscop_relation_p
846 openscop_relation_copy(openscop_relation_p relation)
848 if (relation == NULL)
849 return NULL;
851 return openscop_relation_ncopy(relation, -1);
856 * openscop_relation_replace_vector function:
857 * this function replaces the "row"^th row of a relation "relation" with the
858 * vector "vector". It directly updates the relation union part pointed
859 * by "relation" and this part only.
860 * \param[in,out] relation The relation we want to replace a row.
861 * \param[in] vector The vector that will replace a row of the relation.
862 * \param[in] row The row of the relation to be replaced.
864 void
865 openscop_relation_replace_vector(openscop_relation_p relation,
866 openscop_vector_p vector, int row)
868 int i;
870 if ((relation == NULL) || (vector == NULL) ||
871 (relation->nb_columns != vector->size) ||
872 (row >= relation->nb_rows) || (row < 0))
874 fprintf(stderr,"[OpenScop] Error: vector cannot replace relation row.\n");
875 exit(1);
878 for (i = 0; i < vector->size; i++)
879 SCOPINT_assign(relation->m[row][i], vector->v[i]);
884 * openscop_relation_add_vector function:
885 * this function adds (meaning, +) a vector to the "row"^th row of a
886 * relation "relation". It directly updates the relation union part pointed
887 * by "relation" and this part only.
888 * \param[in,out] relation The relation we want to add a vector to a row.
889 * \param[in] vector The vector that will replace a row of the relation.
890 * \param[in] row The row of the relation to be replaced.
892 void
893 openscop_relation_add_vector(openscop_relation_p relation,
894 openscop_vector_p vector,
895 int row)
897 int i;
899 if ((relation == NULL) || (vector == NULL) ||
900 (relation->nb_columns != vector->size) ||
901 (row >= relation->nb_rows) || (row < 0))
903 fprintf(stderr,"[OpenScop] Error: vector cannot be added to relation.\n");
904 exit(1);
907 if (SCOPINT_get_si(relation->m[row][0]) == 0)
908 SCOPINT_assign(relation->m[row][0], vector->v[0]);
909 for (i = 1; i < vector->size; i++)
910 SCOPINT_addto(relation->m[row][i], relation->m[row][i], vector->v[i]);
915 * openscop_relation_sub_vector function:
916 * this function subtracts the vector "vector" to the "row"^th row of
917 * a relation "relation. It directly updates the relation union part pointed
918 * by "relation" and this part only.
919 * \param[in,out] relation The relation where to subtract a vector to a row.
920 * \param[in] vector The vector to subtract to a relation row.
921 * \param[in] row The row of the relation to subtract the vector.
923 void
924 openscop_relation_sub_vector(openscop_relation_p relation,
925 openscop_vector_p vector,
926 int row)
928 int i;
930 if ((relation == NULL) || (vector == NULL) ||
931 (relation->nb_columns != vector->size) ||
932 (row >= relation->nb_rows) || (row < 0))
934 fprintf(stderr,"[OpenScop] Error: vector cannot be subtracted to row.\n");
935 exit(1);
938 if (SCOPINT_get_si(relation->m[row][0]) == 0)
939 SCOPINT_assign(relation->m[row][0], vector->v[0]);
940 for (i = 1; i < vector->size; i++)
941 SCOPINT_subtract(relation->m[row][i], relation->m[row][i], vector->v[i]);
946 * openscop_relation_insert_vector function:
947 * this function inserts a new row corresponding to the vector "vector" to
948 * the relation "relation" by inserting it at the "row"^th row. It directly
949 * updates the relation union part pointed by "relation" and this part only.
950 * If "vector" (or "relation") is NULL, the relation is left unmodified.
951 * \param[in,out] relation The relation we want to extend.
952 * \param[in] vector The vector that will be added relation.
953 * \param[in] row The row where to insert the vector.
955 void
956 openscop_relation_insert_vector(openscop_relation_p relation,
957 openscop_vector_p vector,
958 int row)
960 openscop_relation_p temp;
962 temp = openscop_relation_from_vector(vector);
963 openscop_relation_insert_relation(relation, temp, row);
964 openscop_relation_free(temp);
969 * openscop_relation_from_vector function:
970 * this function converts a vector "vector" to a relation with a single row
971 * and returns a pointer to that relation.
972 * \param[in] vector The vector to convert to a relation.
973 * \return A pointer to a relation resulting from the vector conversion.
975 openscop_relation_p
976 openscop_relation_from_vector(openscop_vector_p vector)
978 openscop_relation_p relation;
980 if (vector == NULL)
981 return NULL;
983 relation = openscop_relation_malloc(1, vector->size);
984 openscop_relation_replace_vector(relation, vector, 0);
985 return relation;
990 * openscop_relation_replace_relation function:
991 * this function replaces some rows of a relation "r1" with the rows of
992 * the relation "r2". It begins at the "row"^th row of "r1". It directly
993 * updates the relation union part pointed by "r1" and this part only.
994 * \param[in,out] r1 The relation we want to change some rows.
995 * \param[in] r2 The relation containing the new rows.
996 * \param[in] row The first row of the relation r1 to be replaced.
998 void
999 openscop_relation_replace_relation(openscop_relation_p r1,
1000 openscop_relation_p r2, int row)
1002 int i, j;
1004 if ((r1 == NULL) || (r2 == NULL) ||
1005 (r1->nb_columns != r1->nb_columns) ||
1006 ((row + r2->nb_rows) > r1->nb_rows) || (row < 0))
1008 fprintf(stderr,"[OpenScop] Error: relation rows could not be replaced.\n");
1009 exit(1);
1012 for (i = 0; i < r2->nb_rows; i++)
1013 for (j = 0; j < r2->nb_columns; j++)
1014 SCOPINT_assign(r1->m[i+row][j], r2->m[i][j]);
1019 * openscop_relation_insert_relation function:
1020 * this function adds new rows corresponding to the relation "r1" to
1021 * the relation "r2" by inserting it at the "row"^th row. It directly
1022 * updates the relation union part pointed by "r1" and this part only.
1023 * If "r2" (or "r1") is NULL, the relation is left unmodified.
1024 * \param[in,out] r1 The relation we want to extend.
1025 * \param[in] r2 The relation to be inserted.
1026 * \param[in] row The row where to insert the relation
1028 void
1029 openscop_relation_insert_relation(openscop_relation_p r1,
1030 openscop_relation_p r2, int row)
1032 int i, j;
1033 openscop_relation_p temp;
1035 if ((r1 == NULL) || (r2 == NULL))
1036 return;
1038 if ((r1->nb_columns != r2->nb_columns) ||
1039 (row > r1->nb_rows) || (row < 0))
1041 fprintf(stderr,"[OpenScop] Error: constraints cannot be inserted.\n");
1042 exit(1);
1045 // We use a temporary relation just to reuse existing functions. Cleaner.
1046 temp = openscop_relation_malloc(r1->nb_rows+r2->nb_rows, r1->nb_columns);
1048 for (i = 0; i < row; i++)
1049 for (j = 0; j < r1->nb_columns; j++)
1050 SCOPINT_assign(temp->m[i][j], r1->m[i][j]);
1052 openscop_relation_replace_relation(temp, r2, row);
1054 for (i = row + r2->nb_rows; i < r2->nb_rows + r1->nb_rows; i++)
1055 for (j = 0; j < r1->nb_columns; j++)
1056 SCOPINT_assign(temp->m[i][j], r1->m[i-r2->nb_rows][j]);
1058 openscop_relation_free_inside(r1);
1060 // Replace the inside of relation.
1061 r1->nb_rows = temp->nb_rows;
1062 r1->m = temp->m;
1064 // Free the temp "shell".
1065 free(temp);
1070 * openscop_relation_concat function:
1071 * this function builds a new relation from two relations sent as
1072 * parameters. The new set of constraints is built as the concatenation
1073 * of the rows of the first elements of the two relation unions r1 and r2.
1074 * This means, there is no next field in the result.
1075 * \param[in] r1 The first relation.
1076 * \param[in] r2 The second relation.
1077 * \return A pointer to the relation resulting from the concatenation of
1078 * the first elements of r1 and r2.
1080 openscop_relation_p
1081 openscop_relation_concat(openscop_relation_p r1, openscop_relation_p r2)
1083 openscop_relation_p new;
1085 if (r1 == NULL)
1086 return openscop_relation_copy(r2);
1088 if (r2 == NULL)
1089 return openscop_relation_copy(r1);
1091 if (r1->nb_columns != r2->nb_columns)
1093 fprintf(stderr, "[OpenScop] Error: incompatible sizes "
1094 "for concatenation.\n");
1095 exit(1);
1097 if (r1->next || r2->next)
1099 fprintf(stderr, "[OpenScop] Warning: relation concatenation is done "
1100 "on the first elements only.\n");
1103 new = openscop_relation_malloc(r1->nb_rows+r2->nb_rows, r1->nb_columns);
1104 openscop_relation_replace_relation(new, r1, 0);
1105 openscop_relation_replace_relation(new, r2, r1->nb_rows);
1107 return new;
1112 * openscop_relation_equal function:
1113 * this function returns true if the two relations provided as parameters
1114 * are the same, false otherwise.
1115 * \param[in] r1 The first relation.
1116 * \param[in] r2 The second relation.
1117 * \return 1 if r1 and r2 are the same (content-wise), 0 otherwise.
1120 openscop_relation_equal(openscop_relation_p r1, openscop_relation_p r2)
1122 int i, j;
1124 while ((r1 != NULL) && (r2 != NULL))
1126 if (r1 == r2)
1127 return 1;
1129 if ((r1->nb_rows != r2->nb_rows) ||
1130 (r1->nb_columns != r2->nb_columns) ||
1131 (r1->nb_output_dims != r2->nb_output_dims) ||
1132 (r1->nb_input_dims != r2->nb_input_dims) ||
1133 (r1->nb_local_dims != r2->nb_local_dims) ||
1134 (r1->nb_parameters != r2->nb_parameters))
1135 return 0;
1137 for (i = 0; i < r1->nb_rows; ++i)
1138 for (j = 0; j < r1->nb_columns; ++j)
1139 if (SCOPINT_ne(r1->m[i][j], r2->m[i][j]))
1140 return 0;
1142 r1 = r1->next;
1143 r2 = r2->next;
1146 if (((r1 == NULL) && (r2 != NULL)) || ((r1 != NULL) && (r2 == NULL)))
1147 return 0;
1149 return 1;
1154 * openscop_relation_check_property internal function:
1155 * This function checks whether an "actual" value is the same as an
1156 * "expected" value or not. If the expected value is set to
1157 * OPENSCOP_UNDEFINED, this function sets it to the "actual" value
1158 * and do not report a difference has been detected.
1159 * It returns 0 if a difference has been detected, 1 otherwise.
1160 * \param[in,out] expected Pointer to the expected value (the value is
1161 * modified if it was set to OPENSCOP_UNDEFINED).
1162 * \param[in] actual Value we want to check.
1163 * \return 0 if the values are not the same while the expected value was
1164 * not OPENSCOP_UNDEFINED, 1 otherwise.
1166 static
1168 openscop_relation_check_property(int * expected, int actual)
1170 if (*expected != OPENSCOP_UNDEFINED)
1172 if ((actual != OPENSCOP_UNDEFINED) &&
1173 (actual != *expected))
1175 fprintf(stderr, "[OpenScop] Warning: unexpected property.\n");
1176 return 0;
1179 else
1181 *expected = actual;
1184 return 1;
1189 * openscop_relation_check_nb_columns internal function:
1190 * This function checks that the number of columns of a relation
1191 * corresponds to some expected properties (setting an expected property to
1192 * OPENSCOP_UNDEFINED makes this function unable to detect a problem).
1193 * It returns 0 if the number of columns seems incorrect or 1 if no problem
1194 * has been detected.
1195 * \param[in] relation The relation we want to check the number of columns.
1196 * \param[in] expected_nb_output_dims Expected number of output dimensions.
1197 * \param[in] expected_nb_input_dims Expected number of input dimensions.
1198 * \param[in] expected_nb_parameters Expected number of parameters.
1199 * \return 0 if the number of columns seems incorrect, 1 otherwise.
1201 static
1203 openscop_relation_check_nb_columns(openscop_relation_p relation,
1204 int expected_nb_output_dims,
1205 int expected_nb_input_dims,
1206 int expected_nb_parameters)
1208 int expected_nb_local_dims, expected_nb_columns;
1210 if ((expected_nb_output_dims != OPENSCOP_UNDEFINED) &&
1211 (expected_nb_input_dims != OPENSCOP_UNDEFINED) &&
1212 (expected_nb_parameters != OPENSCOP_UNDEFINED))
1214 if (relation->nb_local_dims == OPENSCOP_UNDEFINED)
1215 expected_nb_local_dims = 0;
1216 else
1217 expected_nb_local_dims = relation->nb_local_dims;
1219 expected_nb_columns = expected_nb_output_dims +
1220 expected_nb_input_dims +
1221 expected_nb_local_dims +
1222 expected_nb_parameters +
1225 if (expected_nb_columns != relation->nb_columns)
1227 fprintf(stderr, "[OpenScop] Warning: unexpected number of columns.\n");
1228 return 0;
1232 return 1;
1237 * openscop_relation_consistency_check function:
1238 * this function checks that each part of an union of relations use the same
1239 * representation type (either matrix or relation representation). It returns
1240 * 1 if it is the case, 0 otherwise.
1241 * \param[in] r The relation to check for representation consistency.
1242 * \return 0 if the representation consistency check fails, 1 if it succeeds.
1244 static
1246 openscop_relation_consistency_check(openscop_relation_p r)
1248 int matrix = 0;
1249 int relation = 0;
1251 while (r != NULL)
1253 if (r->nb_local_dims == OPENSCOP_UNDEFINED)
1254 matrix = 1;
1255 else
1256 relation = 1;
1258 r = r->next;
1261 return (matrix == relation) ? 0 : 1;
1266 * openscop_relation_integrity_check function:
1267 * this function checks that a relation is "well formed" according to some
1268 * expected properties (setting an expected value to OPENSCOP_UNDEFINED means
1269 * that we do not expect a specific value) and what the relation is supposed
1270 * to represent. It returns 0 if the check failed or 1 if no problem has been
1271 * detected.
1272 * \param[in] relation The relation we want to check.
1273 * \param[in] type Semantics about this relation (domain, access...).
1274 * \param[in] expected_nb_output_dims Expected number of output dimensions.
1275 * \param[in] expected_nb_input_dims Expected number of input dimensions.
1276 * \param[in] expected_nb_parameters Expected number of parameters.
1277 * \return 0 if the integrity check fails, 1 otherwise.
1280 openscop_relation_integrity_check(openscop_relation_p relation,
1281 int type,
1282 int expected_nb_output_dims,
1283 int expected_nb_input_dims,
1284 int expected_nb_parameters)
1286 int i, start;
1288 // Check the NULL case.
1289 if (relation == NULL)
1291 if ((expected_nb_output_dims != OPENSCOP_UNDEFINED) &&
1292 (expected_nb_input_dims != OPENSCOP_UNDEFINED) &&
1293 (expected_nb_parameters != OPENSCOP_UNDEFINED))
1295 fprintf(stderr, "[OpenScop] Warning: NULL relation with "
1296 "some expected properties.\n");
1297 return 0;
1299 else
1301 fprintf(stderr, "[OpenScop] Warning: NULL relation.\n");
1302 return 1;
1306 // Check the relation is using either matrix or relation representation.
1307 if (!openscop_relation_consistency_check(relation))
1309 fprintf(stderr, "[OpenScop] Warning: inconsistent representation "
1310 "(both matrix and relation).\n");
1311 return 0;
1314 // Check that a context has actually 0 or an undefined #output dimensions.
1315 if ((type == OPENSCOP_TYPE_CONTEXT) &&
1316 ((relation->nb_output_dims != 0) &&
1317 (relation->nb_output_dims != OPENSCOP_UNDEFINED)))
1319 fprintf(stderr, "[OpenScop] Warning: context without 0 "
1320 "as number of output dimensions.\n");
1321 return 0;
1324 // Check that a domain has actually 0 or an undefined #input dimensions.
1325 if (((type == OPENSCOP_TYPE_DOMAIN) ||
1326 (type == OPENSCOP_TYPE_CONTEXT)) &&
1327 ((relation->nb_input_dims != 0) &&
1328 (relation->nb_input_dims != OPENSCOP_UNDEFINED)))
1330 fprintf(stderr, "[OpenScop] Warning: domain or context without 0 "
1331 "as number of input dimensions.\n");
1332 return 0;
1335 // Check properties according to expected values (and if expected values
1336 // are undefined, define them with the first relation part properties).
1337 if (!openscop_relation_check_property(&expected_nb_output_dims,
1338 relation->nb_output_dims) ||
1339 !openscop_relation_check_property(&expected_nb_input_dims,
1340 relation->nb_input_dims) ||
1341 !openscop_relation_check_property(&expected_nb_parameters,
1342 relation->nb_parameters))
1343 return 0;
1345 while (relation != NULL)
1347 // Properties (except the number of local dimensions) should be the same
1348 // in all parts.
1349 if ((expected_nb_output_dims != relation->nb_output_dims) ||
1350 (expected_nb_input_dims != relation->nb_input_dims) ||
1351 (expected_nb_parameters != relation->nb_parameters))
1353 fprintf(stderr, "[OpenScop] Warning: inconsistent properties.\n");
1354 return 0;
1357 // Check whether the number of columns is OK or not.
1358 if (!openscop_relation_check_nb_columns(relation,
1359 expected_nb_output_dims,
1360 expected_nb_input_dims,
1361 expected_nb_parameters))
1362 return 0;
1364 // The first column of a relation part should be made of 0 or 1 only,
1365 // except:
1366 // - for the [0][0] element of an access function in "matrix"
1367 // representation which should be > 0 (array identifier),
1368 // and all other elements are 0.
1369 // - for scattering functions in "matrix" representation, the
1370 // first column is made only of 0.
1371 if ((relation->nb_rows > 0) && (relation->nb_columns > 0))
1373 start = 0;
1374 if ((relation->nb_local_dims == OPENSCOP_UNDEFINED) &&
1375 (type == OPENSCOP_TYPE_ACCESS))
1377 start = 1;
1378 if (SCOPINT_get_si(relation->m[0][0]) <= 0)
1380 fprintf(stderr, "[OpenScop] Warning: bad array identifier "
1381 "in access function.\n");
1382 return 0;
1386 for (i = start; i < relation->nb_rows; i++)
1388 if ((type == OPENSCOP_TYPE_ACCESS) &&
1389 (openscop_relation_is_matrix(relation)))
1391 if (!SCOPINT_zero_p(relation->m[i][0]))
1393 fprintf(stderr, "[OpenScop] Warning: non-first element of the "
1394 "first column of an access function is not 0.\n");
1395 return 0;
1398 else if ((type == OPENSCOP_TYPE_SCATTERING) &&
1399 (openscop_relation_is_matrix(relation)))
1401 if (!SCOPINT_zero_p(relation->m[i][0]))
1403 fprintf(stderr, "[OpenScop] Warning: first column of a "
1404 "scattering function not made of 0s.\n");
1405 return 0;
1408 else
1410 if (!SCOPINT_zero_p(relation->m[i][0]) &&
1411 !SCOPINT_one_p(relation->m[i][0]))
1413 fprintf(stderr, "[OpenScop] Warning: first column of a relation "
1414 "is not made of 0 or 1 only.\n");
1415 return 0;
1421 // TODO: in relation format, array identifiers are
1422 // m[i][#columns -1] / m[i][1], with i the only row
1423 // where m[i][1] is not 0.
1424 // - check there is exactly one row such that m[i][1] is not 0,
1425 // - check that (m[i][#columns -1] % m[i][1]) == 0.
1427 relation = relation->next;
1430 return 1;
1435 * openscop_relation_union function:
1436 * this function builds a new relation from two relations provided
1437 * as parameters. The new relation is built as an union of the
1438 * two relations: the list of constraint sets are linked together.
1439 * \param[in] r1 The first relation.
1440 * \param[in] r2 The second relation.
1441 * \return A new relation corresponding to the union of r1 and r2.
1443 openscop_relation_p
1444 openscop_relation_union(openscop_relation_p r1, openscop_relation_p r2)
1446 openscop_relation_p copy1, copy2, tmp;
1448 if ((r1 == NULL) && (r2 == NULL))
1449 return NULL;
1451 copy1 = openscop_relation_copy(r1);
1452 copy2 = openscop_relation_copy(r2);
1454 if ((r1 != NULL) && (r2 == NULL))
1455 return copy1;
1457 if ((r1 == NULL) && (r2 != NULL))
1458 return copy2;
1460 tmp = copy1;
1461 while (tmp->next != NULL)
1462 tmp = tmp->next;
1464 tmp->next = copy2;
1465 return copy1;