Switch from matrix to relation data structure
[openscop.git] / source / relation.c
blob6bf10d152c6f013878fc3aa99405bbb64add896c
2 /*+-----------------------------------------------------------------**
3 ** OpenScop Library **
4 **-----------------------------------------------------------------**
5 ** relation.c **
6 **-----------------------------------------------------------------**
7 ** First version: 30/04/2008 **
8 **-----------------------------------------------------------------**
11 *****************************************************************************
12 * OpenScop: Structures and formats for polyhedral tools to talk together *
13 *****************************************************************************
14 * ,___,,_,__,,__,,__,,__,,_,__,,_,__,,__,,___,_,__,,_,__, *
15 * / / / // // // // / / / // // / / // / /|,_, *
16 * / / / // // // // / / / // // / / // / / / /\ *
17 * |~~~|~|~~~|~~~|~~~|~~~|~|~~~|~|~~~|~~~|~~~|~|~~~|~|~~~|/_/ \ *
18 * | G |C| P | = | L | P |=| = |C| = | = | = |=| = |=| C |\ \ /\ *
19 * | R |l| o | = | e | l |=| = |a| = | = | = |=| = |=| L | \# \ /\ *
20 * | A |a| l | = | t | u |=| = |n| = | = | = |=| = |=| o | |\# \ \ *
21 * | P |n| l | = | s | t |=| = |d| = | = | = | | |=| o | | \# \ \ *
22 * | H | | y | | e | o | | = |l| | | = | | | | G | | \ \ \ *
23 * | I | | | | e | | | | | | | | | | | | | \ \ \ *
24 * | T | | | | | | | | | | | | | | | | | \ \ \ *
25 * | E | | | | | | | | | | | | | | | | | \ \ \ *
26 * | * |*| * | * | * | * |*| * |*| * | * | * |*| * |*| * | / \* \ \ *
27 * | O |p| e | n | S | c |o| p |-| L | i | b |r| a |r| y |/ \ \ / *
28 * '---'-'---'---'---'---'-'---'-'---'---'---'-'---'-'---' '--' *
29 * *
30 * Copyright (C) 2008 University Paris-Sud 11 and INRIA *
31 * *
32 * (3-clause BSD license) *
33 * Redistribution and use in source and binary forms, with or without *
34 * modification, are permitted provided that the following conditions *
35 * are met: *
36 * *
37 * 1. Redistributions of source code must retain the above copyright notice, *
38 * this list of conditions and the following disclaimer. *
39 * 2. Redistributions in binary form must reproduce the above copyright *
40 * notice, this list of conditions and the following disclaimer in the *
41 * documentation and/or other materials provided with the distribution. *
42 * 3. The name of the author may not be used to endorse or promote products *
43 * derived from this software without specific prior written permission. *
44 * *
45 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR *
46 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES *
47 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. *
48 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, *
49 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT *
50 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, *
51 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY *
52 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
53 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF *
54 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
55 * *
56 * OpenScop Library, a library to manipulate OpenScop formats and data *
57 * structures. Written by: *
58 * Cedric Bastoul <Cedric.Bastoul@u-psud.fr> and *
59 * Louis-Noel Pouchet <Louis-Noel.pouchet@inria.fr> *
60 * *
61 *****************************************************************************/
64 # include <stdlib.h>
65 # include <stdio.h>
66 # include <string.h>
67 # include <ctype.h>
68 # include <openscop/relation.h>
71 /*+***************************************************************************
72 * Structure display function *
73 *****************************************************************************/
76 /**
77 * openscop_relation_print_structure function:
78 * 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
81 * functions.
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.
86 void
87 openscop_relation_print_structure(FILE * file, openscop_relation_p relation,
88 int level)
90 int i, j, first = 1;
92 // Go to the right level.
93 for (j = 0; j < level; j++)
94 fprintf(file, "|\t");
96 if (relation != NULL)
97 fprintf(file,"+-- openscop_relation_t\n");
98 else
99 fprintf(file, "+-- NULL relation\n");
101 while (relation != NULL)
103 if (! first)
105 // Go to the right level.
106 for (j = 0; j < level; j++)
107 fprintf(file, "|\t");
108 fprintf(file, "| openscop_relation_t\n");
110 else
111 first = 0;
113 // A blank line
114 for(j = 0; j <= level; j++)
115 fprintf(file, "|\t");
116 fprintf(file, "%d %d %d %d %d %d\n",
117 relation->nb_rows, relation->nb_columns,
118 relation->nb_output_dims, relation->nb_input_dims,
119 relation->nb_local_dims, relation->nb_parameters);
121 // Display the relation.
122 for (i = 0; i < relation->nb_rows; i++)
124 for (j = 0; j <= level; j++)
125 fprintf(file, "|\t");
127 fprintf(file, "[ ");
129 for (j = 0; j < relation->nb_columns; j++)
131 SCOPINT_print(file, OPENSCOP_FMT, relation->m[i][j]);
132 fprintf(file, " ");
135 fprintf(file, "]\n");
138 relation = relation->next;
140 // Next line.
141 if (relation != NULL)
143 for (j = 0; j <= level; j++)
144 fprintf(file, "|\t");
145 fprintf(file, "|\n");
146 for (j = 0; j <= level; j++)
147 fprintf(file, "|\t");
148 fprintf(file, "V\n");
152 // The last line.
153 for (j = 0; j <= level; j++)
154 fprintf(file, "|\t");
155 fprintf(file, "\n");
160 * openscop_relation_print function:
161 * This function prints the content of a openscop_relation_t structure
162 * (*relation) into a file (file, possibly stdout).
163 * \param file File where informations are printed.
164 * \param relation The relation whose information have to be printed.
166 void
167 openscop_relation_print(FILE * file, openscop_relation_p relation)
169 openscop_relation_print_structure(file, relation, 0);
175 * openscop_relation_expression_element function:
176 * This function returns a string containing the printing of a value (possibly
177 * an iterator or a parameter with its coefficient or a constant).
178 * \param 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.
185 static
186 char *
187 openscop_relation_expression_element(openscop_int_t val, int * first, int cst,
188 char * name)
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));
195 body[0] = '\0';
196 sval[0] = '\0';
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);
205 else
207 if (SCOPINT_mone_p(val)) // case -1
208 sprintf(sval, "-%s", name);
209 else // default case
211 SCOPINT_sprint(sval, OPENSCOP_FMT_TXT, val);
212 sprintf(temp, "*%s", name);
213 strcat(sval, temp);
216 *first = 0;
218 else
220 if (SCOPINT_one_p(val))
221 sprintf(sval, "+%s", name);
222 else
224 sprintf(sval, "+");
225 SCOPINT_sprint(temp, OPENSCOP_FMT_TXT, val);
226 strcat(sval, temp);
227 sprintf(temp, "*%s", name);
228 strcat(sval, temp);
232 else
234 if (cst)
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))
240 if (!(*first))
242 SCOPINT_sprint(sval, "+"OPENSCOP_FMT_TXT, val); // Block macro !
244 else
245 SCOPINT_sprint(sval, OPENSCOP_FMT_TXT, val);
249 free(temp);
250 free(body);
252 return(sval);
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.
268 static
269 char *
270 openscop_relation_expression(openscop_relation_p relation, int row,
271 int nb_iterators, char ** iterators,
272 int nb_parameters, char ** parameters)
274 int i, first = 1;
275 char * sline, * sval;
277 sline = (char *)malloc(OPENSCOP_MAX_STRING * sizeof(char)) ;
278 sline[0] = '\0' ;
280 // First the iterator part.
281 for (i = 1; i <= nb_iterators; i++)
283 sval = openscop_relation_expression_element(relation->m[row][i],
284 &first, 0, iterators[i-1]);
285 strcat(sline, sval);
286 free(sval);
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]);
294 strcat(sline, sval);
295 free(sval);
298 // Finally the constant part (yes, I reused it).
299 sval = openscop_relation_expression_element(relation->m[row][i],
300 &first, 1, NULL);
301 strcat(sline, sval);
302 free(sval);
304 return sline;
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.
315 static
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");
323 exit(1);
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");
333 exit(1);
335 return SCOPINT_get_si(relation->m[0][0]);
337 else
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");
344 exit(1);
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.
366 void
367 openscop_relation_print_openscop(FILE * file, openscop_relation_p relation,
368 int type,
369 int nb_iterators, char ** iterators,
370 int nb_parameters, char ** parameters,
371 int nb_arrays, char ** arrays)
373 int i, j, k;
374 int generated_iterator_names = 0;
375 int generated_parameter_names = 0;
376 int generated_array_names = 0;
377 int part, nb_parts;
378 int array_id;
379 char * expression;
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");
386 return;
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;
399 else
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.
420 r = relation;
421 nb_parts = 0;
422 while (r != NULL)
424 nb_parts++;
425 r = r->next;
427 if (nb_parts > 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++)
433 if (nb_parts > 1)
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);
440 else
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]);
451 fprintf(file, " ");
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);
460 free(expression);
461 if (SCOPINT_zero_p(relation->m[i][0]))
462 fprintf(file, " == 0");
463 else
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);
473 free(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]);
484 k = i;
487 expression = openscop_relation_expression(relation, k,
488 nb_iterators, iterators,
489 nb_parameters, parameters);
490 fprintf(file, "[%s]", expression);
491 free(expression);
492 k++;
494 while ((k < relation->nb_rows) &&
495 SCOPINT_zero_p(relation->m[k][0]))
498 else
499 fprintf(file, " ##");
502 fprintf(file, "\n");
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 /*****************************************************************************
517 * Reading function *
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.
529 openscop_relation_p
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;
538 int first = 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)
549 read_properties = 0;
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");
561 exit(1);
563 if (read == 1)
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");
570 exit(1);
572 // Allow to read the properties of the first part of the union.
573 read_properties = 1;
575 if (read == 2)
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))
595 p = relation->m[0];
597 for (i = 0; i < relation->nb_rows; i++)
599 c = openscop_util_skip_blank_and_comments(foo, s);
600 if (c == NULL)
602 fprintf(stderr, "[OpenScop] Error: not enough rows.\n");
603 exit(1);
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");
611 exit(1);
613 if (sscanf(c, "%s%n", str, &n) == 0)
615 fprintf(stderr, "[OpenScop] Error: not enough rows.\n");
616 exit(1);
618 #if defined(OPENSCOP_INT_T_IS_MP)
619 long long val;
620 sscanf(str, "%lld", &val);
621 mpz_set_si(*p++, val);
622 #else
623 sscanf(str, OPENSCOP_FMT_TXT, p++);
624 #endif
625 c += n;
629 // Build the linked list of union parts.
630 if (first == 1)
632 relation_union = relation;
633 first = 0;
635 else
636 previous->next = relation;
638 previous = relation;
639 read_properties = 1;
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.
660 openscop_relation_p
661 openscop_relation_malloc(int nb_rows, int nb_columns)
663 openscop_relation_p relation;
664 openscop_int_t ** p, * q;
665 int i, j;
667 relation = (openscop_relation_p)malloc(sizeof(openscop_relation_t));
668 if (relation == NULL)
670 fprintf(stderr, "[OpenScop] Memory Overflow.\n");
671 exit(1);
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))
683 relation->m = NULL;
684 else
686 p = (openscop_int_t **)malloc(nb_rows * sizeof(openscop_int_t *));
687 if (p == NULL)
689 fprintf(stderr, "[OpenScop] Memory Overflow.\n");
690 exit(1);
692 q = (openscop_int_t *)malloc(nb_rows*nb_columns*sizeof(openscop_int_t));
693 if (q == NULL)
695 fprintf(stderr, "[OpenScop] Memory Overflow.\n");
696 exit(1);
698 relation->m = p;
699 for (i = 0; i < nb_rows; i++)
701 *p++ = q;
702 for (j = 0; j < nb_columns; j++)
703 SCOPINT_init_set_si(*(q+j),0);
704 q += nb_columns;
708 relation->next = NULL;
710 return relation;
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.
720 void
721 openscop_relation_free_inside(openscop_relation_p relation)
723 int i, nb_elements;
724 openscop_int_t * p;
726 if (relation == NULL)
727 return;
729 nb_elements = relation->nb_rows * relation->nb_columns;
731 if (nb_elements > 0)
732 p = relation->m[0];
734 for (i = 0; i < nb_elements; i++)
735 SCOPINT_clear(*p++);
737 if (relation->m != NULL)
739 if (nb_elements > 0)
740 free(relation->m[0]);
741 free(relation->m);
747 * openscop_relation_free function:
748 * This function frees the allocated memory for a openscop_relation_t
749 * structure.
750 * \param relation The pointer to the relation we want to free.
752 void
753 openscop_relation_free(openscop_relation_p relation)
755 openscop_relation_p tmp;
757 if (relation == NULL)
758 return;
760 while (relation != NULL)
762 tmp = relation->next;
763 openscop_relation_free_inside(relation);
764 free(relation);
765 relation = tmp;
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)
788 return -1;
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)
795 return 0;
797 relation = relation->next;
800 return 1;
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.
816 openscop_relation_p
817 openscop_relation_ncopy(openscop_relation_p relation, int n)
819 int i, j;
820 int first = 1, all_rows = 0;
821 openscop_relation_p copy = NULL, node, previous = NULL;
823 if (n == -1)
824 all_rows = 1;
826 while (relation != NULL)
828 if (all_rows)
829 n = relation->nb_rows;
831 if (n > relation->nb_rows)
833 fprintf(stderr,"[OpenScop] Error: not enough rows in the relation\n");
834 exit(1);
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]);
843 if (first)
845 first = 0;
846 copy = node;
847 previous = node;
849 else
851 previous->next = node;
852 previous = previous->next;
855 relation = relation->next;
858 return copy;
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.
869 openscop_relation_p
870 openscop_relation_copy(openscop_relation_p relation)
872 if (relation == NULL)
873 return 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.
888 void
889 openscop_relation_replace_vector(openscop_relation_p relation,
890 openscop_vector_p vector, int row)
892 int i;
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");
899 exit(1);
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.
916 void
917 openscop_relation_add_vector(openscop_relation_p relation,
918 openscop_vector_p vector,
919 int row)
921 int i;
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");
928 exit(1);
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.
947 void
948 openscop_relation_sub_vector(openscop_relation_p relation,
949 openscop_vector_p vector,
950 int row)
952 int i;
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");
959 exit(1);
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.
979 void
980 openscop_relation_insert_vector(openscop_relation_p relation,
981 openscop_vector_p vector,
982 int row)
984 int i, j;
985 openscop_relation_p new;
987 if ((vector == NULL) || (relation == NULL))
988 return;
990 if ((relation->nb_columns != vector->size) ||
991 (row > relation->nb_rows) || (row < 0))
993 fprintf(stderr,"[OpenScop] Error: vector cannot be inserted.\n");
994 exit(1);
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".
1017 free(new);
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.
1028 openscop_relation_p
1029 openscop_relation_from_vector(openscop_vector_p vector)
1031 openscop_relation_p relation;
1033 if (vector == NULL)
1034 return NULL;
1036 relation = openscop_relation_malloc(1, vector->size);
1037 openscop_relation_replace_vector(relation, vector, 0);
1038 return relation;
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.
1051 void
1052 openscop_relation_replace_relation(openscop_relation_p r1,
1053 openscop_relation_p r2, int row)
1055 int i, j;
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");
1062 exit(1);
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
1081 void
1082 openscop_relation_insert_relation(openscop_relation_p r1,
1083 openscop_relation_p r2, int row)
1085 int i, j;
1086 openscop_relation_p new;
1088 if ((r1 == NULL) || (r2 == NULL))
1089 return;
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");
1095 exit(1);
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;
1116 r1->m = new->m;
1118 // Free the new "container".
1119 free(new);
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
1130 * r1 and r2.
1132 openscop_relation_p
1133 openscop_relation_concat(openscop_relation_p r1, openscop_relation_p r2)
1135 openscop_relation_p new;
1137 if (r1 == NULL)
1138 return openscop_relation_copy(r2);
1140 if (r2 == NULL)
1141 return openscop_relation_copy(r1);
1143 if (r1->nb_columns != r2->nb_columns)
1145 fprintf(stderr,"[OpenScop] Error: matrices cannot be concatenated\n");
1146 exit(1);
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);
1153 return new;
1158 * openscop_relation_equal function:
1159 * this function returns true if the two matrices are the same, false
1160 * otherwise.
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)
1168 int i, j;
1170 while ((r1 != NULL) && (r2 != NULL))
1172 if (r1 == r2)
1173 return 1;
1175 if ((r1->nb_rows != r2->nb_rows) || (r1->nb_columns != r2->nb_columns))
1176 return 0;
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]))
1181 return 0;
1183 r1 = r1->next;
1184 r2 = r2->next;
1187 if (((r1 == NULL) && (r2 != NULL)) || ((r1 != NULL) && (r2 == NULL)))
1188 return 0;
1190 return 1;
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.
1207 static
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");
1216 return 0;
1219 else
1220 *expected = actual;
1222 return 1;
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.
1239 static
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;
1254 else
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");
1266 return 0;
1270 return 1;
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
1280 * detected.
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,
1290 int type,
1291 int expected_nb_output_dims,
1292 int expected_nb_input_dims,
1293 int expected_nb_parameters)
1295 int i, start;
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");
1306 return 0;
1308 else
1310 fprintf(stderr, "[OpenScop] Warning: NULL relation.\n");
1311 return 1;
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))
1323 return 0;
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");
1333 return 0;
1336 while (relation != NULL)
1338 // Properties (except the number of local dimensions) should be the same
1339 // in all parts.
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");
1345 return 0;
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))
1353 return 0;
1355 // The first column of a relation part should be made of 0 or 1 only,
1356 // except:
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))
1364 start = 0;
1365 if ((relation->nb_local_dims == OPENSCOP_UNDEFINED) &&
1366 (type == OPENSCOP_TYPE_ACCESS))
1368 start = 1;
1369 if (SCOPINT_get_si(relation->m[0][0]) <= 0)
1371 fprintf(stderr, "[OpenScop] Warning: bad array identifier "
1372 "in access function.\n");
1373 return 0;
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");
1386 return 0;
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");
1396 return 0;
1399 else
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");
1406 return 0;
1412 relation = relation->next;
1415 return 1;