2 /*+-----------------------------------------------------------------**
4 **-----------------------------------------------------------------**
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 * '---'-'---'---'---'---'-'---'-'---'---'---'-'---'-'---' '--' *
30 * Copyright (C) 2008 University Paris-Sud 11 and INRIA *
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 *
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. *
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. *
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> *
61 *****************************************************************************/
68 # include <openscop/relation.h>
71 /*+***************************************************************************
72 * Structure display function *
73 *****************************************************************************/
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.
84 void openscop_relation_print_type(FILE * file
, openscop_relation_p relation
) {
86 if (relation
!= NULL
) {
87 switch (relation
->type
) {
88 case OPENSCOP_UNDEFINED
: {
92 case OPENSCOP_TYPE_DOMAIN
: {
96 case OPENSCOP_TYPE_SCATTERING
: {
97 printf("(scattering)\n");
100 case OPENSCOP_TYPE_ACCESS
: {
101 printf("(access)\n");
105 printf("(unknown type: %d)\n", relation
->type
);
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
,
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
);
137 fprintf(file
, "+-- NULL relation\n");
140 while (relation
!= NULL
) {
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
);
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");
166 for (j
= 0; j
< relation
->nb_columns
; j
++) {
167 SCOPINT_print(file
, OPENSCOP_FMT
, relation
->m
[i
][j
]);
171 fprintf(file
, "]\n");
174 relation
= relation
->next
;
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");
188 for (j
= 0; j
<= level
; j
++)
189 fprintf(file
, "|\t");
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,
216 * \param[in] name String containing the name of the element.
217 * \return A string that contains the printing of a value.
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));
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
);
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
);
248 if (SCOPINT_one_p(val
)) {
249 sprintf(sval
, "+%s", name
);
253 SCOPINT_sprint(temp
, OPENSCOP_FMT_TXT
, val
);
255 sprintf(temp
, "*%s", name
);
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
)) {
266 SCOPINT_sprint(sval
, "+"OPENSCOP_FMT_TXT
, val
); // Block macro !
269 SCOPINT_sprint(sval
, OPENSCOP_FMT_TXT
, val
);
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
) {
297 char * sline
= (char *)malloc(OPENSCOP_MAX_STRING
* sizeof(char));
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]);
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]);
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
;
322 sval
= openscop_relation_expression_element(
323 relation
->m
[row
][i
], &first
, 0,
324 names
->parameters
[i
- names
->nb_iterators
- names
->nb_localdims
- 1]);
329 // Finally the constant part (yes, I reused it).
330 sval
= openscop_relation_expression_element(relation
->m
[row
][i
],
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.
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");
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");
361 return SCOPINT_get_si(relation
->m
[0][0]);
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");
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
) {
392 int type
= relation
->type
;
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");
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: {
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.
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
++) {
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
);
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
]);
462 if (type
== OPENSCOP_TYPE_DOMAIN
) {
463 expression
= openscop_relation_expression(relation
, i
, names
);
464 fprintf(file
, " ## %s", expression
);
466 if (SCOPINT_zero_p(relation
->m
[i
][0]))
467 fprintf(file
, " == 0");
469 fprintf(file
, " >= 0");
472 if (type
== OPENSCOP_TYPE_SCATTERING
) {
473 expression
= openscop_relation_expression(relation
, i
, names
);
474 fprintf(file
, " ## %s", 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]);
487 expression
= openscop_relation_expression(relation
, k
, names
);
488 fprintf(file
, "[%s]", expression
);
492 while ((k
< relation
->nb_rows
) &&
493 SCOPINT_zero_p(relation
->m
[k
][0]));
496 fprintf(file
, " ##");
502 relation
= relation
->next
;
507 /*****************************************************************************
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;
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
) {
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");
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");
556 // Allow to read the properties of the first part of the union.
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))
581 for (i
= 0; i
< relation
->nb_rows
; i
++) {
582 c
= openscop_util_skip_blank_and_comments(foo
, s
);
584 fprintf(stderr
, "[OpenScop] Error: not enough rows.\n");
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");
593 if (sscanf(c
, "%s%n", str
, &n
) == 0) {
594 fprintf(stderr
, "[OpenScop] Error: not enough rows.\n");
597 #if defined(OPENSCOP_INT_T_IS_MP)
599 if (sscanf(str
, "%lld", &val
) == 0) {
600 fprintf(stderr
, "[OpenScop] Error: failed to read an integer.\n");
603 mpz_set_si(*p
++, val
);
605 if (sscanf(str
, OPENSCOP_FMT_TXT
, p
++) == 0) {
606 fprintf(stderr
, "[OpenScop] Error: failed to read an integer.\n");
614 // Build the linked list of union parts.
616 relation_union
= relation
;
620 previous
->next
= relation
;
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
;
651 relation
= (openscop_relation_p
)malloc(sizeof(openscop_relation_t
));
652 if (relation
== NULL
) {
653 fprintf(stderr
, "[OpenScop] Error: memory Overflow.\n");
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
)) {
670 p
= (openscop_int_t
**)malloc(nb_rows
* sizeof(openscop_int_t
*));
672 fprintf(stderr
, "[OpenScop] Error: memory Overflow.\n");
675 q
= (openscop_int_t
*)malloc(nb_rows
*nb_columns
*sizeof(openscop_int_t
));
677 fprintf(stderr
, "[OpenScop] Error: memory Overflow.\n");
681 for (i
= 0; i
< nb_rows
; i
++) {
683 for (j
= 0; j
< nb_columns
; j
++)
684 SCOPINT_init_set_si(*(q
+j
),0);
689 relation
->next
= NULL
;
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
) {
705 if (relation
== NULL
)
708 nb_elements
= relation
->nb_rows
* relation
->nb_columns
;
713 for (i
= 0; i
< nb_elements
; i
++)
716 if (relation
->m
!= NULL
) {
718 free(relation
->m
[0]);
725 * openscop_relation_free function:
726 * this function frees the allocated memory for a openscop_relation_t
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
)
736 while (relation
!= NULL
) {
737 tmp
= relation
->next
;
738 openscop_relation_free_inside(relation
);
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
)
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
)
769 relation
= relation
->next
;
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
,
791 int first
= 1, all_rows
= 0;
792 openscop_relation_p copy
= NULL
, node
, previous
= NULL
;
797 while (relation
!= NULL
) {
799 n
= relation
->nb_rows
;
801 if (n
> relation
->nb_rows
) {
802 fprintf(stderr
,"[OpenScop] Error: not enough rows in the relation\n");
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
]);
823 previous
->next
= node
;
824 previous
= previous
->next
;
827 relation
= relation
->next
;
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
)
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
) {
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");
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
) {
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");
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
) {
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");
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
;
963 relation
= openscop_relation_malloc(1, vector
->size
);
964 openscop_relation_replace_vector(relation
, vector
, 0);
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
) {
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");
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
) {
1008 openscop_relation_p temp
;
1010 if ((r1
== NULL
) || (r2
== NULL
))
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");
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
;
1038 // Free the temp "shell".
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;
1059 return openscop_relation_copy(r2
);
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");
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
);
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
) {
1093 while ((r1
!= NULL
) && (r2
!= NULL
)) {
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
))
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
]))
1115 if (((r1
== NULL
) && (r2
!= NULL
)) || ((r1
!= NULL
) && (r2
== NULL
)))
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.
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");
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.
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;
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");
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.
1206 int openscop_relation_consistency_check(openscop_relation_p r
) {
1211 if (r
->nb_local_dims
== OPENSCOP_UNDEFINED
)
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
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
,
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");
1255 fprintf(stderr
, "[OpenScop] Warning: integrity check of a NULL "
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");
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");
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");
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
))
1298 while (relation
!= NULL
) {
1299 // Properties (except the number of local dimensions) should be the same
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");
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
))
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");
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");
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");
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");
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.
1372 for (i
= 0; i
< relation
->nb_rows
; i
++) {
1373 if (!SCOPINT_zero_p(relation
->m
[i
][1])) {
1378 if (nb_array_id
== 0) {
1379 fprintf(stderr
, "[OpenScop] Warning: no array identifier in "
1380 "an access function.\n");
1383 if (nb_array_id
> 1) {
1384 fprintf(stderr
, "[OpenScop] Warning: several array identification "
1385 "rows in one access function.\n");
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 "
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");
1400 SCOPINT_init(array_id
);
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
);
1407 fprintf(stderr
, "[OpenScop] Warning: negative or 0 identifier "
1408 "in access function.\n");
1411 SCOPINT_clear(array_id
);
1416 relation
= relation
->next
;
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
))
1439 copy1
= openscop_relation_copy(r1
);
1440 copy2
= openscop_relation_copy(r2
);
1442 if ((r1
!= NULL
) && (r2
== NULL
))
1445 if ((r1
== NULL
) && (r2
!= NULL
))
1449 while (tmp
->next
!= NULL
)
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
;