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 * Displays a openscop_relation_t structure (*relation) into a file (file,
79 * possibly stdout) in a way that trends to be understandable. It includes an
80 * indentation level (level) in order to work with others print_structure
82 * \param file File where informations are printed.
83 * \param relation The relation whose information have to be printed.
84 * \param 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 file File where informations are printed.
164 * \param 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 val The coefficient or constant value.
179 * \param first Pointer to a boolean set to 1 if the current value is the first
180 * of an expresion, 0 otherwise (this function may update it).
181 * \param cst A boolean set to 1 if the value is a constant, 0 otherwise.
182 * \param name String containing the name of the iterator or of the parameter.
183 * \return A string that contains the printing of a value.
187 openscop_relation_expression_element(openscop_int_t val
, int * first
, int cst
,
190 char * sval
, * body
, * temp
;
192 temp
= (char *)malloc(OPENSCOP_MAX_STRING
* sizeof(char));
193 body
= (char *)malloc(OPENSCOP_MAX_STRING
* sizeof(char));
194 sval
= (char *)malloc(OPENSCOP_MAX_STRING
* sizeof(char));
198 // statements for the 'normal' processing.
199 if (SCOPINT_notzero_p(val
) && (!cst
))
201 if ((*first
) || SCOPINT_neg_p(val
))
203 if (SCOPINT_one_p(val
)) // case 1
204 sprintf(sval
, "%s", name
);
207 if (SCOPINT_mone_p(val
)) // case -1
208 sprintf(sval
, "-%s", name
);
211 SCOPINT_sprint(sval
, OPENSCOP_FMT_TXT
, val
);
212 sprintf(temp
, "*%s", name
);
220 if (SCOPINT_one_p(val
))
221 sprintf(sval
, "+%s", name
);
225 SCOPINT_sprint(temp
, OPENSCOP_FMT_TXT
, val
);
227 sprintf(temp
, "*%s", name
);
236 if ((SCOPINT_zero_p(val
) && (*first
)) || SCOPINT_neg_p(val
))
237 SCOPINT_sprint(sval
, OPENSCOP_FMT_TXT
, val
);
238 if (SCOPINT_pos_p(val
))
242 SCOPINT_sprint(sval
, "+"OPENSCOP_FMT_TXT
, val
); // Block macro !
245 SCOPINT_sprint(sval
, OPENSCOP_FMT_TXT
, val
);
257 * openscop_relation_expression function:
258 * This function returns a string corresponding to an affine expression
259 * stored at the "row"^th row of the relation pointed by "relation".
260 * \param relation A set of linear expressions.
261 * \param row The row corresponding to the expression.
262 * \param nb_iterators The number of iterators for the considered statement.
263 * \param iterators An array containing iterator names for the statement.
264 * \param nb_parameters The number of parameters in the SCoP.
265 * \param parameters An array containing all parameters names.
266 * \return A string that contains the printing of an affine expression.
270 openscop_relation_expression(openscop_relation_p relation
, int row
,
271 int nb_iterators
, char ** iterators
,
272 int nb_parameters
, char ** parameters
)
275 char * sline
, * sval
;
277 sline
= (char *)malloc(OPENSCOP_MAX_STRING
* sizeof(char)) ;
280 // First the iterator part.
281 for (i
= 1; i
<= nb_iterators
; i
++)
283 sval
= openscop_relation_expression_element(relation
->m
[row
][i
],
284 &first
, 0, iterators
[i
-1]);
289 // Next the parameter part.
290 for (i
= nb_iterators
+ 1; i
<= nb_iterators
+ nb_parameters
; i
++)
292 sval
= openscop_relation_expression_element(relation
->m
[row
][i
], &first
, 0,
293 parameters
[i
- nb_iterators
- 1]);
298 // Finally the constant part (yes, I reused it).
299 sval
= openscop_relation_expression_element(relation
->m
[row
][i
],
309 * openscop_relation_get_array_id internal function:
310 * This function returns the array identifier when the relation provided
311 * as parameter corresponds to an access function.
312 * \param relation The access function.
313 * \return The accessed array identifier.
317 openscop_relation_get_array_id(openscop_relation_p relation
)
319 if (relation
== NULL
)
321 fprintf(stderr
, "[OpenScop] Error: cannot find nb_arrays "
322 "in a NULL relation.\n");
326 if (relation
->nb_local_dims
== OPENSCOP_UNDEFINED
)
328 // Matrix representation case.
329 if ((relation
->nb_rows
< 1) || (relation
->nb_columns
< 1))
331 fprintf(stderr
, "[OpenScop] Error: not enough rows or columns "
332 "to extract nb_arrays.\n");
335 return SCOPINT_get_si(relation
->m
[0][0]);
339 // Relation representation case.
340 if ((relation
->nb_rows
< 1) || (relation
->nb_columns
< 2))
342 fprintf(stderr
, "[OpenScop] Error: not enough rows or columns "
343 "to extract nb_arrays.\n");
346 // TODO: do something more general
347 return SCOPINT_get_si(relation
->m
[0][1]);
353 * openscop_relation_print_openscop function:
354 * This function prints the content of a openscop_relation_t structure
355 * (*relation) into a file (file, possibly stdout) in the OpenScop format.
356 * \param file File where informations are printed.
357 * \param relation The relation whose information have to be printed.
358 * \param type Semantics about this relation (domain, access...).
359 * \param nb_iterators The number of iterators for the considered statement.
360 * \param iterators An array containing iterator names for the statement.
361 * \param nb_parameters The number of parameters in the SCoP.
362 * \param parameters An array containing all parameters names.
363 * \param nb_arrays The number of arrays accessed in the SCoP.
364 * \param arrays An array containing all accessed array names.
367 openscop_relation_print_openscop(FILE * file
, openscop_relation_p relation
,
369 int nb_iterators
, char ** iterators
,
370 int nb_parameters
, char ** parameters
,
371 int nb_arrays
, char ** arrays
)
374 int generated_iterator_names
= 0;
375 int generated_parameter_names
= 0;
376 int generated_array_names
= 0;
380 openscop_relation_p r
;
382 if (relation
== NULL
)
384 fprintf(stderr
, "[OpenScop] Warning: asked to print a NULL relation.\n");
385 fprintf(file
, "# NULL relation\n");
389 // Generate names for comments if necessary.
390 if (((type
== OPENSCOP_TYPE_DOMAIN
) &&
391 (relation
->nb_output_dims
> nb_iterators
)) ||
392 (((type
== OPENSCOP_TYPE_SCATTERING
) ||
393 (type
== OPENSCOP_TYPE_ACCESS
)) &&
394 (relation
->nb_input_dims
> nb_iterators
)))
396 generated_iterator_names
= 1;
397 if (type
== OPENSCOP_TYPE_DOMAIN
)
398 nb_iterators
= relation
->nb_output_dims
;
400 nb_iterators
= relation
->nb_input_dims
;
402 iterators
= openscop_util_generate_names("i_", nb_iterators
);
405 if (relation
->nb_parameters
> nb_parameters
)
407 generated_parameter_names
= 1;
408 nb_parameters
= relation
->nb_parameters
;
409 parameters
= openscop_util_generate_names("P_", nb_parameters
);
412 if ((type
== OPENSCOP_TYPE_ACCESS
) &&
413 ((array_id
= openscop_relation_get_array_id(relation
)) > nb_arrays
))
415 generated_array_names
= 1;
416 arrays
= openscop_util_generate_names("A_", array_id
);
419 // Count the number of parts in the union and print it if it is not 1.
428 fprintf(file
, "# Union with %d parts\n%d\n", nb_parts
, nb_parts
);
430 // Print each part of the union.
431 for (part
= 1; part
<= nb_parts
; part
++)
434 fprintf(file
, "# Union part No.%d\n", part
);
435 if ((relation
->nb_output_dims
== OPENSCOP_UNDEFINED
) &&
436 (relation
->nb_input_dims
== OPENSCOP_UNDEFINED
) &&
437 (relation
->nb_local_dims
== OPENSCOP_UNDEFINED
) &&
438 (relation
->nb_parameters
== OPENSCOP_UNDEFINED
))
439 fprintf(file
, "%d %d\n", relation
->nb_rows
, relation
->nb_columns
);
441 fprintf(file
, "%d %d %d %d %d %d\n",
442 relation
->nb_rows
, relation
->nb_columns
,
443 relation
->nb_output_dims
, relation
->nb_input_dims
,
444 relation
->nb_local_dims
, relation
->nb_parameters
);
446 for (i
= 0; i
< relation
->nb_rows
; i
++)
448 for (j
= 0; j
< relation
->nb_columns
; j
++)
450 SCOPINT_print(file
, OPENSCOP_FMT
, relation
->m
[i
][j
]);
454 if (type
== OPENSCOP_TYPE_DOMAIN
)
456 expression
= openscop_relation_expression(relation
, i
,
457 nb_iterators
, iterators
,
458 nb_parameters
, parameters
);
459 fprintf(file
, " ## %s", expression
);
461 if (SCOPINT_zero_p(relation
->m
[i
][0]))
462 fprintf(file
, " == 0");
464 fprintf(file
, " >= 0");
467 if (type
== OPENSCOP_TYPE_SCATTERING
)
469 expression
= openscop_relation_expression(relation
, i
,
470 nb_iterators
, iterators
,
471 nb_parameters
, parameters
);
472 fprintf(file
, " ## %s", expression
);
476 if (type
== OPENSCOP_TYPE_ACCESS
)
478 if (SCOPINT_notzero_p(relation
->m
[i
][0]))
480 if (strncmp(arrays
[SCOPINT_get_si(relation
->m
[i
][0]) - 1],
481 OPENSCOP_FAKE_ARRAY
, strlen(OPENSCOP_FAKE_ARRAY
)))
482 fprintf(file
, " ## %s",
483 arrays
[SCOPINT_get_si(relation
->m
[i
][0]) - 1]);
487 expression
= openscop_relation_expression(relation
, k
,
488 nb_iterators
, iterators
,
489 nb_parameters
, parameters
);
490 fprintf(file
, "[%s]", expression
);
494 while ((k
< relation
->nb_rows
) &&
495 SCOPINT_zero_p(relation
->m
[k
][0]))
499 fprintf(file
, " ##");
504 relation
= relation
->next
;
507 if (generated_iterator_names
)
508 openscop_util_free_name_array(iterators
, nb_iterators
);
509 if (generated_parameter_names
)
510 openscop_util_free_name_array(parameters
, nb_parameters
);
511 if (generated_array_names
)
512 openscop_util_free_name_array(arrays
, nb_arrays
);
516 /*****************************************************************************
518 *****************************************************************************/
522 * openscop_relation_read function:
523 * This function reads a relation into a file (foo, posibly stdin) and
524 * returns a pointer this relation. In addition, it reads the arrays as
525 * comments at the end of the line.
526 * \param file The input stream.
527 * \return A pointer to the relation structure that has been read.
530 openscop_relation_read(FILE * foo
)
532 int i
, j
, k
, n
, read
= 0;
533 int nb_rows
, nb_columns
;
534 int nb_output_dims
, nb_input_dims
, nb_local_dims
, nb_parameters
;
535 int nb_union_parts
= 1;
536 int may_read_nb_union_parts
= 1;
537 int read_properties
= 1;
539 char * c
, s
[OPENSCOP_MAX_STRING
], str
[OPENSCOP_MAX_STRING
];
540 openscop_relation_p relation
, relation_union
= NULL
, previous
= NULL
;
541 openscop_int_t
* p
= NULL
;
543 // Read each part of the union (the number of parts may be updated inside)
544 for (k
= 0; k
< nb_union_parts
; k
++)
546 // Read the number of union parts or the properties of the union part
547 while (read_properties
)
551 // Read relation properties.
552 c
= openscop_util_skip_blank_and_comments(foo
, s
);
553 read
= sscanf(c
, " %d %d %d %d %d %d", &nb_rows
, &nb_columns
,
554 &nb_output_dims
, &nb_input_dims
,
555 &nb_local_dims
, &nb_parameters
);
557 if (((read
!= 1) && (read
!= 2) && (read
!= 6)) ||
558 ((read
== 1) && (may_read_nb_union_parts
!= 1)))
560 fprintf(stderr
, "[OpenScop] Error:: badly formated relation.\n");
565 // Only one number means a union and is the number of parts.
566 nb_union_parts
= nb_rows
;
567 if (nb_union_parts
< 1)
569 fprintf(stderr
, "[OpenScop] Error: negative nb of union parts.\n");
572 // Allow to read the properties of the first part of the union.
577 nb_output_dims
= OPENSCOP_UNDEFINED
;
578 nb_input_dims
= OPENSCOP_UNDEFINED
;
579 nb_local_dims
= OPENSCOP_UNDEFINED
;
580 nb_parameters
= OPENSCOP_UNDEFINED
;
583 may_read_nb_union_parts
= 0;
586 // Allocate the union part and fill its properties.
587 relation
= openscop_relation_malloc(nb_rows
, nb_columns
);
588 relation
->nb_output_dims
= nb_output_dims
;
589 relation
->nb_input_dims
= nb_input_dims
;
590 relation
->nb_local_dims
= nb_local_dims
;
591 relation
->nb_parameters
= nb_parameters
;
593 // Read the matrix of constraints.
594 if ((relation
->nb_rows
!= 0) && (relation
->nb_columns
!= 0))
597 for (i
= 0; i
< relation
->nb_rows
; i
++)
599 c
= openscop_util_skip_blank_and_comments(foo
, s
);
602 fprintf(stderr
, "[OpenScop] Error: not enough rows.\n");
606 for (j
= 0; j
< relation
->nb_columns
; j
++)
608 if (c
== NULL
|| *c
== '#' || *c
== '\n')
610 fprintf(stderr
, "[OpenScop] Error: not enough columns.\n");
613 if (sscanf(c
, "%s%n", str
, &n
) == 0)
615 fprintf(stderr
, "[OpenScop] Error: not enough rows.\n");
618 #if defined(OPENSCOP_INT_T_IS_MP)
620 sscanf(str
, "%lld", &val
);
621 mpz_set_si(*p
++, val
);
623 sscanf(str
, OPENSCOP_FMT_TXT
, p
++);
629 // Build the linked list of union parts.
632 relation_union
= relation
;
636 previous
->next
= relation
;
642 return relation_union
;
646 /*+***************************************************************************
647 * Memory allocation/deallocation function *
648 *****************************************************************************/
651 * openscop_relation_malloc function:
652 * This function allocates the memory space for a openscop_relation_t
653 * structure and sets its fields with default values. Then it returns a
654 * pointer to the allocated space.
655 * \param nb_rows The number of row of the relation to allocate.
656 * \param nb_columns The number of columns of the relation to allocate.
657 * \return A pointer to an empty relation with fields set to default values
658 * and a ready-to-use constraint matrix.
661 openscop_relation_malloc(int nb_rows
, int nb_columns
)
663 openscop_relation_p relation
;
664 openscop_int_t
** p
, * q
;
667 relation
= (openscop_relation_p
)malloc(sizeof(openscop_relation_t
));
668 if (relation
== NULL
)
670 fprintf(stderr
, "[OpenScop] Memory Overflow.\n");
674 relation
->nb_rows
= nb_rows
;
675 relation
->nb_columns
= nb_columns
;
676 relation
->nb_output_dims
= OPENSCOP_UNDEFINED
;
677 relation
->nb_input_dims
= OPENSCOP_UNDEFINED
;
678 relation
->nb_parameters
= OPENSCOP_UNDEFINED
;
679 relation
->nb_local_dims
= OPENSCOP_UNDEFINED
;
681 if ((nb_rows
== 0) || (nb_columns
== 0) ||
682 (nb_rows
== OPENSCOP_UNDEFINED
) || (nb_columns
== OPENSCOP_UNDEFINED
))
686 p
= (openscop_int_t
**)malloc(nb_rows
* sizeof(openscop_int_t
*));
689 fprintf(stderr
, "[OpenScop] Memory Overflow.\n");
692 q
= (openscop_int_t
*)malloc(nb_rows
*nb_columns
*sizeof(openscop_int_t
));
695 fprintf(stderr
, "[OpenScop] Memory Overflow.\n");
699 for (i
= 0; i
< nb_rows
; i
++)
702 for (j
= 0; j
< nb_columns
; j
++)
703 SCOPINT_init_set_si(*(q
+j
),0);
708 relation
->next
= NULL
;
715 * openscop_relation_free_inside function:
716 * This function frees the allocated memory for the inside of a
717 * openscop_relation_t structure, i.e. only m.
718 * \param relation The pointer to the relation we want to free.
721 openscop_relation_free_inside(openscop_relation_p relation
)
726 if (relation
== NULL
)
729 nb_elements
= relation
->nb_rows
* relation
->nb_columns
;
734 for (i
= 0; i
< nb_elements
; i
++)
737 if (relation
->m
!= NULL
)
740 free(relation
->m
[0]);
747 * openscop_relation_free function:
748 * This function frees the allocated memory for a openscop_relation_t
750 * \param relation The pointer to the relation we want to free.
753 openscop_relation_free(openscop_relation_p relation
)
755 openscop_relation_p tmp
;
757 if (relation
== NULL
)
760 while (relation
!= NULL
)
762 tmp
= relation
->next
;
763 openscop_relation_free_inside(relation
);
770 /*+***************************************************************************
771 * Processing functions *
772 *****************************************************************************/
776 * openscop_relation_is_matrix function:
777 * This function returns 1 if the relation provided as parameter corresponds
778 * to a "matrix" representation (see documentation), -1 if it is NULL and
779 * 0 in all other cases.
780 * \param relation The relation we want to know whether it is a matrix or not.
781 * \return 1 if the relation has "matrix" representation, -1 if it is NULL,
782 * 0 in all other cases.
785 openscop_relation_is_matrix(openscop_relation_p relation
)
787 if (relation
== NULL
)
790 // A relation has matrix representation if all nb_local_dims fields
791 // of all parts of the union is OPENSCOP_UNDEFINED.
792 while (relation
!= NULL
)
794 if (relation
->nb_local_dims
!= OPENSCOP_UNDEFINED
)
797 relation
= relation
->next
;
805 * openscop_relation_ncopy function:
806 * This functions builds and returns a "hard copy" (not a pointer copy) of a
807 * openscop_relation_t data structure such that the copy is restricted to the
808 * "n" first rows of the relation. This applies to all the parts in the case
809 * of a relation union.
810 * \param relation The pointer to the relation we want to copy.
811 * \param n The number of row of the relation we want to copy (the
812 * special value -1 means "all the rows").
813 * \return A pointer to the full copy of the relation union restricted to the
814 * first n rows of constraint matrix for each part of the union.
817 openscop_relation_ncopy(openscop_relation_p relation
, int n
)
820 int first
= 1, all_rows
= 0;
821 openscop_relation_p copy
= NULL
, node
, previous
= NULL
;
826 while (relation
!= NULL
)
829 n
= relation
->nb_rows
;
831 if (n
> relation
->nb_rows
)
833 fprintf(stderr
,"[OpenScop] Error: not enough rows in the relation\n");
837 node
= openscop_relation_malloc(n
, relation
->nb_columns
);
839 for (i
= 0; i
< n
; i
++)
840 for (j
= 0; j
< relation
->nb_columns
; j
++)
841 SCOPINT_assign(node
->m
[i
][j
], relation
->m
[i
][j
]);
851 previous
->next
= node
;
852 previous
= previous
->next
;
855 relation
= relation
->next
;
863 * openscop_relation_copy function:
864 * this function builds and returns a "hard copy" (not a pointer copy) of a
865 * openscop_relation_t data structure (the full union of relation).
866 * \param relation The pointer to the relation we want to copy.
867 * \return A pointer to the copy of the union of relations.
870 openscop_relation_copy(openscop_relation_p relation
)
872 if (relation
== NULL
)
875 return openscop_relation_ncopy(relation
, relation
->nb_rows
);
880 * openscop_relation_replace_vector function:
881 * this function replaces the "row"^th row of a relation "relation" with the
882 * vector "vector". It directly updates the relation union part pointed
883 * by "relation" and this part only.
884 * \param relation The relation we want to change a row.
885 * \param vector The vector that will replace a row of the relation.
886 * \param row The row of the relation to be replaced.
889 openscop_relation_replace_vector(openscop_relation_p relation
,
890 openscop_vector_p vector
, int row
)
894 if ((relation
== NULL
) || (vector
== NULL
) ||
895 (relation
->nb_columns
!= vector
->size
) ||
896 (row
>= relation
->nb_rows
) || (row
< 0))
898 fprintf(stderr
,"[OpenScop] Error: vector cannot replace relation row.\n");
902 for (i
= 0; i
< vector
->size
; i
++)
903 SCOPINT_assign(relation
->m
[row
][i
], vector
->v
[i
]);
908 * openscop_relation_add_vector function:
909 * this function adds the "row"^th row of a relation "relation" with the
910 * vector "vector". It directly updates the relation union part pointed
911 * by "relation" and this part only.
912 * \param relation The relation we want to change a row.
913 * \param vector The vector that will replace a row of the relation.
914 * \param row The row of the relation to be replaced.
917 openscop_relation_add_vector(openscop_relation_p relation
,
918 openscop_vector_p vector
,
923 if ((relation
== NULL
) || (vector
== NULL
) ||
924 (relation
->nb_columns
!= vector
->size
) ||
925 (row
>= relation
->nb_rows
) || (row
< 0))
927 fprintf(stderr
,"[OpenScop] Error: vector cannot be added to relation.\n");
931 if (SCOPINT_get_si(relation
->m
[row
][0]) == 0)
932 SCOPINT_assign(relation
->m
[row
][0], vector
->v
[0]);
933 for (i
= 1; i
< vector
->size
; i
++)
934 SCOPINT_addto(relation
->m
[row
][i
], relation
->m
[row
][i
], vector
->v
[i
]);
939 * openscop_relation_sub_vector function:
940 * this function substracts the vector "vector" to the "row"^th row of
941 * a relation "relation. It directly updates the relation union part pointed
942 * by "relation" and this part only.
943 * \param relation The relation we want to change a row.
944 * \param vector The vector that will be subtracted to a row of the relation.
945 * \param row The row of the relation to subtract the vector.
948 openscop_relation_sub_vector(openscop_relation_p relation
,
949 openscop_vector_p vector
,
954 if ((relation
== NULL
) || (vector
== NULL
) ||
955 (relation
->nb_columns
!= vector
->size
) ||
956 (row
>= relation
->nb_rows
) || (row
< 0))
958 fprintf(stderr
,"[OpenScop] Error: vector cannot be subtracted to row.\n");
962 if (SCOPINT_get_si(relation
->m
[row
][0]) == 0)
963 SCOPINT_assign(relation
->m
[row
][0], vector
->v
[0]);
964 for (i
= 1; i
< vector
->size
; i
++)
965 SCOPINT_subtract(relation
->m
[row
][i
], relation
->m
[row
][i
], vector
->v
[i
]);
970 * openscop_relation_insert_vector function:
971 * this function adds a new row corresponding to the vector "vector" to
972 * the relation "relation" by inserting it at the "row"^th row. It directly
973 * updates the relation union part pointed by "relation" and this part only.
974 * If "vector" (or "relation") is NULL, the relation is left unmodified.
975 * \param relation The relation we want to extend.
976 * \param vector The vector that will be added relation.
977 * \param row The row where to insert the vector.
980 openscop_relation_insert_vector(openscop_relation_p relation
,
981 openscop_vector_p vector
,
985 openscop_relation_p
new;
987 if ((vector
== NULL
) || (relation
== NULL
))
990 if ((relation
->nb_columns
!= vector
->size
) ||
991 (row
> relation
->nb_rows
) || (row
< 0))
993 fprintf(stderr
,"[OpenScop] Error: vector cannot be inserted.\n");
997 // We use a temporary relation just to reuse existing functions. Cleaner.
998 new = openscop_relation_malloc(relation
->nb_rows
+1, relation
->nb_columns
);
1000 for (i
= 0; i
< row
; i
++)
1001 for (j
= 0; j
< relation
->nb_columns
; j
++)
1002 SCOPINT_assign(new->m
[i
][j
], relation
->m
[i
][j
]);
1004 openscop_relation_replace_vector(new,vector
, row
);
1006 for (i
= row
+1; i
< relation
->nb_rows
; i
++)
1007 for (j
= 0; j
< relation
->nb_columns
; j
++)
1008 SCOPINT_assign(new->m
[i
][j
], relation
->m
[i
-1][j
]);
1010 openscop_relation_free_inside(relation
);
1012 // Replace the inside of relation.
1013 relation
->nb_rows
= new->nb_rows
;
1014 relation
->nb_columns
= new->nb_columns
;
1015 relation
->m
= new->m
;
1016 // Free the new "shell".
1022 * openscop_relation_from_vector function:
1023 * this function converts a vector "vector" to a relation with a single row
1024 * and returns a pointer to that relation.
1025 * \param vector The vector to convert to a relation.
1026 * \return A pointer to a relation resulting from the conversion of the vector.
1029 openscop_relation_from_vector(openscop_vector_p vector
)
1031 openscop_relation_p relation
;
1036 relation
= openscop_relation_malloc(1, vector
->size
);
1037 openscop_relation_replace_vector(relation
, vector
, 0);
1043 * openscop_relation_replace_relation function:
1044 * this function replaces some rows of a relation "r1" with the rows of
1045 * the relation "r2". It begins at the "row"^th row of "r1". It directly
1046 * updates the relation union part pointed by "r1" and this part only.
1047 * \param r1 The relation we want to change some rows.
1048 * \param r2 The relation containing the new rows.
1049 * \param row The first row of the relation r1 to be replaced.
1052 openscop_relation_replace_relation(openscop_relation_p r1
,
1053 openscop_relation_p r2
, int row
)
1057 if ((r1
== NULL
) || (r2
== NULL
) ||
1058 (r1
->nb_columns
!= r1
->nb_columns
) ||
1059 ((row
+ r2
->nb_rows
) > r1
->nb_rows
) || (row
< 0))
1061 fprintf(stderr
,"[OpenScop] Error: relation rows could not be replaced.\n");
1065 for (i
= 0; i
< r2
->nb_rows
; i
++)
1066 for (j
= 0; j
< r2
->nb_columns
; j
++)
1067 SCOPINT_assign(r1
->m
[i
+row
][j
], r2
->m
[i
][j
]);
1072 * openscop_relation_insert_relation function:
1073 * this function adds new rows corresponding to the relation "r1" to
1074 * the relation "r2" by inserting it at the "row"^th row. It directly
1075 * updates the relation union part pointed by "r1" and this part only.
1076 * If "r2" (or "r1") is NULL, the relation is left unmodified.
1077 * \param r1 The relation we want to extend.
1078 * \param r2 The relation to be inserted.
1079 * \param row The row where to insert the relation
1082 openscop_relation_insert_relation(openscop_relation_p r1
,
1083 openscop_relation_p r2
, int row
)
1086 openscop_relation_p
new;
1088 if ((r1
== NULL
) || (r2
== NULL
))
1091 if ((r1
->nb_columns
!= r2
->nb_columns
) ||
1092 (row
> r1
->nb_rows
) || (row
< 0))
1094 fprintf(stderr
,"[OpenScop] Error: relation cannot be inserted.\n");
1098 // We use a temporary relation just to reuse existing functions. Cleaner.
1099 new = openscop_relation_malloc(r1
->nb_rows
+r2
->nb_rows
, r1
->nb_columns
);
1101 for (i
= 0; i
< row
; i
++)
1102 for (j
= 0; j
< r1
->nb_columns
; j
++)
1103 SCOPINT_assign(new->m
[i
][j
], r1
->m
[i
][j
]);
1105 openscop_relation_replace_relation(new, r2
, row
);
1107 for (i
= row
+ r2
->nb_rows
; i
< r1
->nb_rows
; i
++)
1108 for (j
= 0; j
< r1
->nb_columns
; j
++)
1109 SCOPINT_assign(new->m
[i
][j
], r1
->m
[i
-r2
->nb_rows
][j
]);
1111 openscop_relation_free_inside(r1
);
1113 // Replace the inside of relation.
1114 r1
->nb_rows
= new->nb_rows
;
1115 r1
->nb_columns
= new->nb_columns
;
1118 // Free the new "container".
1124 * openscop_relation_concat function:
1125 * this function builds a new relation as the concatenation of the rows of
1126 * two other matrices sent as parameters.
1127 * \param r1 The first relation.
1128 * \param r2 The second relation.
1129 * \return A pointer to the relation resulting from the concatenation of
1133 openscop_relation_concat(openscop_relation_p r1
, openscop_relation_p r2
)
1135 openscop_relation_p
new;
1138 return openscop_relation_copy(r2
);
1141 return openscop_relation_copy(r1
);
1143 if (r1
->nb_columns
!= r2
->nb_columns
)
1145 fprintf(stderr
,"[OpenScop] Error: matrices cannot be concatenated\n");
1149 new = openscop_relation_malloc(r1
->nb_rows
+r2
->nb_rows
, r1
->nb_columns
);
1150 openscop_relation_replace_relation(new, r1
, 0);
1151 openscop_relation_replace_relation(new, r2
, r1
->nb_rows
);
1158 * openscop_relation_equal function:
1159 * this function returns true if the two matrices are the same, false
1161 * \param r1 The first relation.
1162 * \param r2 The second relation.
1163 * \return 1 if r1 and r2 are the same (content-wise), 0 otherwise.
1166 openscop_relation_equal(openscop_relation_p r1
, openscop_relation_p r2
)
1170 while ((r1
!= NULL
) && (r2
!= NULL
))
1175 if ((r1
->nb_rows
!= r2
->nb_rows
) || (r1
->nb_columns
!= r2
->nb_columns
))
1178 for (i
= 0; i
< r1
->nb_rows
; ++i
)
1179 for (j
= 0; j
< r1
->nb_columns
; ++j
)
1180 if (SCOPINT_ne(r1
->m
[i
][j
], r2
->m
[i
][j
]))
1187 if (((r1
== NULL
) && (r2
!= NULL
)) || ((r1
!= NULL
) && (r2
== NULL
)))
1195 * openscop_relation_check_property internal function:
1196 * This function checks whether an "actual" value is the same as an
1197 * "expected" value or not. If the expected value is set to
1198 * OPENSCOP_UNDEFINED, this function sets it to the "actual" value
1199 * and do not report a difference has been detected.
1200 * It returns 0 if a difference has been detected, 1 otherwise.
1201 * \param expected Pointer to the expected value (the value is modified if
1202 * it was set to OPENSCOP_UNDEFINED).
1203 * \param actual Value we want to check.
1204 * \return 0 if the values are not the same while the expected value was
1205 * not OPENSCOP_UNDEFINED, 1 otherwise.
1209 openscop_relation_check_property(int * expected
, int actual
)
1211 if (*expected
!= OPENSCOP_UNDEFINED
)
1212 { if ((actual
!= OPENSCOP_UNDEFINED
) &&
1213 (actual
!= *expected
))
1215 fprintf(stderr
, "[OpenScop] Warning: unexpected property.\n");
1227 * openscop_relation_check_nb_columns internal function:
1228 * This function checks that the number of columns of a relation is
1229 * corresponds to some expected properties (setting an expected property to
1230 * OPENSCOP_UNDEFINED makes this function unable to detect a problem).
1231 * It returns 0 if the number of columns seems incorrect or 1 if no problem
1232 * has been detected.
1233 * \param relation The relation we want to check the number of column.
1234 * \param expected_nb_output_dims Expected number of output dimensions.
1235 * \param expected_nb_input_dims Expected number of input dimensions.
1236 * \param expected_nb_parameters Expected number of parameters.
1237 * \return 0 if the number of columns seems incorrect, 1 otherwise.
1241 openscop_relation_check_nb_columns(openscop_relation_p relation
,
1242 int expected_nb_output_dims
,
1243 int expected_nb_input_dims
,
1244 int expected_nb_parameters
)
1246 int expected_nb_local_dims
, expected_nb_columns
;
1248 if ((expected_nb_output_dims
!= OPENSCOP_UNDEFINED
) &&
1249 (expected_nb_input_dims
!= OPENSCOP_UNDEFINED
) &&
1250 (expected_nb_parameters
!= OPENSCOP_UNDEFINED
))
1252 if (relation
->nb_local_dims
== OPENSCOP_UNDEFINED
)
1253 expected_nb_local_dims
= 0;
1255 expected_nb_local_dims
= relation
->nb_local_dims
;
1257 expected_nb_columns
= expected_nb_output_dims
+
1258 expected_nb_input_dims
+
1259 expected_nb_local_dims
+
1260 expected_nb_parameters
+
1263 if (expected_nb_columns
!= relation
->nb_columns
)
1265 fprintf(stderr
, "[OpenScop] Warning: unexpected number of columns.\n");
1275 * openscop_relation_integrity_check function:
1276 * This function checks that a relation is "well formed" according to some
1277 * expected properties (setting an expected value to OPENSCOP_UNDEFINED means
1278 * that we do not expect a specific value) and what the relation is supposed
1279 * to represent. It returns 0 if the check failed or 1 if no problem has been
1281 * \param relation The relation we want to check.
1282 * \param type Semantics about this relation (domain, access...).
1283 * \param expected_nb_output_dims Expected number of output dimensions.
1284 * \param expected_nb_input_dims Expected number of input dimensions.
1285 * \param expected_nb_parameters Expected number of parameters.
1286 * \return 0 if the integrity check fails, 1 otherwise.
1289 openscop_relation_integrity_check(openscop_relation_p relation
,
1291 int expected_nb_output_dims
,
1292 int expected_nb_input_dims
,
1293 int expected_nb_parameters
)
1297 // Check the NULL case.
1298 if (relation
== NULL
)
1300 if ((expected_nb_output_dims
!= OPENSCOP_UNDEFINED
) &&
1301 (expected_nb_input_dims
!= OPENSCOP_UNDEFINED
) &&
1302 (expected_nb_parameters
!= OPENSCOP_UNDEFINED
))
1304 fprintf(stderr
, "[OpenScop] Warning: NULL relation with "
1305 "some expected properties.\n");
1310 fprintf(stderr
, "[OpenScop] Warning: NULL relation.\n");
1315 // Check properties according to expected values (and if expected values
1316 // are undefined, define them with the first relation part properties).
1317 if (!openscop_relation_check_property(&expected_nb_output_dims
,
1318 relation
->nb_output_dims
) ||
1319 !openscop_relation_check_property(&expected_nb_input_dims
,
1320 relation
->nb_input_dims
) ||
1321 !openscop_relation_check_property(&expected_nb_parameters
,
1322 relation
->nb_parameters
))
1325 // Check that a domain has actually 0 input dimensions.
1326 if (((type
== OPENSCOP_TYPE_DOMAIN
) ||
1327 (type
== OPENSCOP_TYPE_CONTEXT
)) &&
1328 ((relation
->nb_input_dims
!= 0) &&
1329 (relation
->nb_input_dims
!= OPENSCOP_UNDEFINED
)))
1331 fprintf(stderr
, "[OpenScop] Warning: domain or context without 0 "
1332 "as number of input dimensions.\n");
1336 while (relation
!= NULL
)
1338 // Properties (except the number of local dimensions) should be the same
1340 if ((expected_nb_output_dims
!= relation
->nb_output_dims
) ||
1341 (expected_nb_input_dims
!= relation
->nb_input_dims
) ||
1342 (expected_nb_parameters
!= relation
->nb_parameters
))
1344 fprintf(stderr
, "[OpenScop] Warning: inconsistent properties.\n");
1348 // Check whether the number of columns is OK or not.
1349 if (!openscop_relation_check_nb_columns(relation
,
1350 expected_nb_output_dims
,
1351 expected_nb_input_dims
,
1352 expected_nb_parameters
))
1355 // The first column of a relation part should be made of 0 or 1 only,
1357 // - for the [0][0] element of an access function in "matrix"
1358 // representation which should be > 0 (array identifier),
1359 // and all other elements are 0.
1360 // - for scattering functions in "matrix" representation, the
1361 // first column is made only of 0.
1362 if ((relation
->nb_rows
> 0) && (relation
->nb_columns
> 0))
1365 if ((relation
->nb_local_dims
== OPENSCOP_UNDEFINED
) &&
1366 (type
== OPENSCOP_TYPE_ACCESS
))
1369 if (SCOPINT_get_si(relation
->m
[0][0]) <= 0)
1371 fprintf(stderr
, "[OpenScop] Warning: bad array identifier "
1372 "in access function.\n");
1377 for (i
= start
; i
< relation
->nb_rows
; i
++)
1379 if ((type
== OPENSCOP_TYPE_ACCESS
) &&
1380 (relation
->nb_local_dims
== OPENSCOP_UNDEFINED
))
1382 if (!SCOPINT_zero_p(relation
->m
[i
][0]))
1384 fprintf(stderr
, "[OpenScop] Warning: non-first element of the "
1385 "first column of an access function is not 0.\n");
1389 else if ((type
== OPENSCOP_TYPE_SCATTERING
) &&
1390 (relation
->nb_local_dims
== OPENSCOP_UNDEFINED
))
1392 if (!SCOPINT_zero_p(relation
->m
[i
][0]))
1394 fprintf(stderr
, "[OpenScop] Warning: first column of a "
1395 "scattering function not made of 0s.\n");
1401 if (!SCOPINT_zero_p(relation
->m
[i
][0]) &&
1402 !SCOPINT_one_p(relation
->m
[i
][0]))
1404 fprintf(stderr
, "[OpenScop] Warning: first column of a relation "
1405 "is not made of 0 or 1 only.\n");
1412 relation
= relation
->next
;