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_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.
87 openscop_relation_print_structure(FILE * file
, openscop_relation_p relation
,
92 // Go to the right level.
93 for (j
= 0; j
< level
; j
++)
97 fprintf(file
, "+-- openscop_relation_t\n");
99 fprintf(file
, "+-- NULL relation\n");
101 while (relation
!= NULL
)
105 // Go to the right level.
106 for (j
= 0; j
< level
; j
++)
107 fprintf(file
, "|\t");
108 fprintf(file
, "| openscop_relation_t\n");
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");
129 for (j
= 0; j
< relation
->nb_columns
; j
++)
131 SCOPINT_print(file
, OPENSCOP_FMT
, relation
->m
[i
][j
]);
135 fprintf(file
, "]\n");
138 relation
= relation
->next
;
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");
153 for (j
= 0; j
<= level
; j
++)
154 fprintf(file
, "|\t");
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.
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,
183 * \param[in] name String containing the name of the element.
184 * \return A string that contains the printing of a value.
188 openscop_relation_expression_element(openscop_int_t val
, int * first
, int cst
,
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));
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
);
208 if (SCOPINT_mone_p(val
)) // case -1
209 sprintf(sval
, "-%s", name
);
212 SCOPINT_sprint(sval
, OPENSCOP_FMT_TXT
, val
);
213 sprintf(temp
, "*%s", name
);
221 if (SCOPINT_one_p(val
))
222 sprintf(sval
, "+%s", name
);
226 SCOPINT_sprint(temp
, OPENSCOP_FMT_TXT
, val
);
228 sprintf(temp
, "*%s", name
);
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
))
243 SCOPINT_sprint(sval
, "+"OPENSCOP_FMT_TXT
, val
); // Block macro !
246 SCOPINT_sprint(sval
, OPENSCOP_FMT_TXT
, val
);
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.
271 openscop_relation_expression(openscop_relation_p relation
, int row
,
272 openscop_names_p names
)
275 char * sline
, * sval
;
277 sline
= (char *)malloc(OPENSCOP_MAX_STRING
* sizeof(char)) ;
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]);
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]);
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
;
304 sval
= openscop_relation_expression_element(relation
->m
[row
][i
], &first
, 0,
305 names
->parameters
[i
- names
->nb_iterators
- names
->nb_localdims
- 1]);
310 // Finally the constant part (yes, I reused it).
311 sval
= openscop_relation_expression_element(relation
->m
[row
][i
],
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.
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");
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");
347 return SCOPINT_get_si(relation
->m
[0][0]);
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");
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.
377 openscop_relation_print_openscop(FILE * file
, openscop_relation_p relation
,
378 int type
, openscop_names_p names
)
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");
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.
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
++)
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
);
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
]);
430 if (type
== OPENSCOP_TYPE_DOMAIN
)
432 expression
= openscop_relation_expression(relation
, i
, names
);
433 fprintf(file
, " ## %s", expression
);
435 if (SCOPINT_zero_p(relation
->m
[i
][0]))
436 fprintf(file
, " == 0");
438 fprintf(file
, " >= 0");
441 if (type
== OPENSCOP_TYPE_SCATTERING
)
443 expression
= openscop_relation_expression(relation
, i
, names
);
444 fprintf(file
, " ## %s", 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]);
460 expression
= openscop_relation_expression(relation
, k
, names
);
461 fprintf(file
, "[%s]", expression
);
465 while ((k
< relation
->nb_rows
) &&
466 SCOPINT_zero_p(relation
->m
[k
][0]))
470 fprintf(file
, " ##");
475 relation
= relation
->next
;
480 /*****************************************************************************
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.
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;
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
)
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");
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");
535 // Allow to read the properties of the first part of the union.
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))
560 for (i
= 0; i
< relation
->nb_rows
; i
++)
562 c
= openscop_util_skip_blank_and_comments(foo
, s
);
565 fprintf(stderr
, "[OpenScop] Error: not enough rows.\n");
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");
576 if (sscanf(c
, "%s%n", str
, &n
) == 0)
578 fprintf(stderr
, "[OpenScop] Error: not enough rows.\n");
581 #if defined(OPENSCOP_INT_T_IS_MP)
583 if (sscanf(str
, "%lld", &val
) == 0)
585 fprintf(stderr
, "[OpenScop] Error: failed to read an integer.\n");
588 mpz_set_si(*p
++, val
);
590 if (sscanf(str
, OPENSCOP_FMT_TXT
, p
++) == 0)
592 fprintf(stderr
, "[OpenScop] Error: failed to read an integer.\n");
600 // Build the linked list of union parts.
603 relation_union
= relation
;
607 previous
->next
= relation
;
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.
633 openscop_relation_malloc(int nb_rows
, int nb_columns
)
635 openscop_relation_p relation
;
636 openscop_int_t
** p
, * q
;
639 relation
= (openscop_relation_p
)malloc(sizeof(openscop_relation_t
));
640 if (relation
== NULL
)
642 fprintf(stderr
, "[OpenScop] Error: memory Overflow.\n");
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
))
658 p
= (openscop_int_t
**)malloc(nb_rows
* sizeof(openscop_int_t
*));
661 fprintf(stderr
, "[OpenScop] Error: memory Overflow.\n");
664 q
= (openscop_int_t
*)malloc(nb_rows
*nb_columns
*sizeof(openscop_int_t
));
667 fprintf(stderr
, "[OpenScop] Error: memory Overflow.\n");
671 for (i
= 0; i
< nb_rows
; i
++)
674 for (j
= 0; j
< nb_columns
; j
++)
675 SCOPINT_init_set_si(*(q
+j
),0);
680 relation
->next
= NULL
;
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.
693 openscop_relation_free_inside(openscop_relation_p relation
)
698 if (relation
== NULL
)
701 nb_elements
= relation
->nb_rows
* relation
->nb_columns
;
706 for (i
= 0; i
< nb_elements
; i
++)
709 if (relation
->m
!= NULL
)
712 free(relation
->m
[0]);
719 * openscop_relation_free function:
720 * this function frees the allocated memory for a openscop_relation_t
722 * \param[in] relation The pointer to the relation we want to free.
725 openscop_relation_free(openscop_relation_p relation
)
727 openscop_relation_p tmp
;
729 if (relation
== NULL
)
732 while (relation
!= NULL
)
734 tmp
= relation
->next
;
735 openscop_relation_free_inside(relation
);
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
)
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
)
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.
789 openscop_relation_ncopy(openscop_relation_p relation
, int n
)
792 int first
= 1, all_rows
= 0;
793 openscop_relation_p copy
= NULL
, node
, previous
= NULL
;
798 while (relation
!= NULL
)
801 n
= relation
->nb_rows
;
803 if (n
> relation
->nb_rows
)
805 fprintf(stderr
,"[OpenScop] Error: not enough rows in the relation\n");
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
]);
827 previous
->next
= node
;
828 previous
= previous
->next
;
831 relation
= relation
->next
;
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.
846 openscop_relation_copy(openscop_relation_p relation
)
848 if (relation
== 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.
865 openscop_relation_replace_vector(openscop_relation_p relation
,
866 openscop_vector_p vector
, int row
)
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");
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.
893 openscop_relation_add_vector(openscop_relation_p relation
,
894 openscop_vector_p vector
,
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");
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.
924 openscop_relation_sub_vector(openscop_relation_p relation
,
925 openscop_vector_p vector
,
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");
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.
956 openscop_relation_insert_vector(openscop_relation_p relation
,
957 openscop_vector_p vector
,
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.
976 openscop_relation_from_vector(openscop_vector_p vector
)
978 openscop_relation_p relation
;
983 relation
= openscop_relation_malloc(1, vector
->size
);
984 openscop_relation_replace_vector(relation
, vector
, 0);
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.
999 openscop_relation_replace_relation(openscop_relation_p r1
,
1000 openscop_relation_p r2
, int row
)
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");
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
1029 openscop_relation_insert_relation(openscop_relation_p r1
,
1030 openscop_relation_p r2
, int row
)
1033 openscop_relation_p temp
;
1035 if ((r1
== NULL
) || (r2
== NULL
))
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");
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
;
1064 // Free the temp "shell".
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.
1081 openscop_relation_concat(openscop_relation_p r1
, openscop_relation_p r2
)
1083 openscop_relation_p
new;
1086 return openscop_relation_copy(r2
);
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");
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
);
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
)
1124 while ((r1
!= NULL
) && (r2
!= NULL
))
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
))
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
]))
1146 if (((r1
== NULL
) && (r2
!= NULL
)) || ((r1
!= NULL
) && (r2
== NULL
)))
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.
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");
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.
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;
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");
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.
1246 openscop_relation_consistency_check(openscop_relation_p r
)
1253 if (r
->nb_local_dims
== OPENSCOP_UNDEFINED
)
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
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
,
1282 int expected_nb_output_dims
,
1283 int expected_nb_input_dims
,
1284 int expected_nb_parameters
)
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");
1301 fprintf(stderr
, "[OpenScop] Warning: NULL relation.\n");
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");
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");
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");
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
))
1345 while (relation
!= NULL
)
1347 // Properties (except the number of local dimensions) should be the same
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");
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
))
1364 // The first column of a relation part should be made of 0 or 1 only,
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))
1374 if ((relation
->nb_local_dims
== OPENSCOP_UNDEFINED
) &&
1375 (type
== OPENSCOP_TYPE_ACCESS
))
1378 if (SCOPINT_get_si(relation
->m
[0][0]) <= 0)
1380 fprintf(stderr
, "[OpenScop] Warning: bad array identifier "
1381 "in access function.\n");
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");
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");
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");
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
;
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.
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
))
1451 copy1
= openscop_relation_copy(r1
);
1452 copy2
= openscop_relation_copy(r2
);
1454 if ((r1
!= NULL
) && (r2
== NULL
))
1457 if ((r1
== NULL
) && (r2
!= NULL
))
1461 while (tmp
->next
!= NULL
)