1 /******************************************************************************
2 * PIP : Parametric Integer Programming *
3 ******************************************************************************
5 ******************************************************************************
7 * Copyright Paul Feautrier, 1988, 1993, 1994, 1996, 2002 *
9 * This library is free software; you can redistribute it and/or modify it *
10 * under the terms of the GNU Lesser General Public License as published by *
11 * the Free Software Foundation; either version 2.1 of the License, or (at *
12 * your option) any later version. *
14 * This software is distributed in the hope that it will be useful, but *
15 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
16 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
19 * You should have received a copy of the GNU Lesser General Public License *
20 * along with this library; if not, write to the Free Software Foundation, *
21 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
23 * Written by Paul Feautrier and Cedric Bastoul *
25 ******************************************************************************/
33 extern long int cross_product
, limit
;
39 Entier param1
, param2
;
55 #if !defined(LINEAR_VALUE_IS_MP)
56 Entier
mod(Entier
, Entier
);
58 Entier
pgcd(Entier x
, Entier y
)
65 return(x
>= 0? x
: -x
);
72 sol_space
= (struct S
*)malloc(SOL_SIZE
*sizeof(struct S
)) ;
88 if(p
<0 || p
>=SOL_SIZE
)
89 {fprintf(stderr
, "Syserr : sol_reset : Memory allocation error\n");
92 #if defined(LINEAR_VALUE_IS_MP)
93 for(i
=p
; i
<sol_free
; i
++){
94 mpz_clear(sol_space
[i
].param1
);
95 mpz_clear(sol_space
[i
].param2
);
101 struct S
*sol_alloc(void)
103 r
= sol_space
+ sol_free
;
105 #if defined(LINEAR_VALUE_IS_MP)
106 mpz_init_set_si(r
->param1
,0);
107 mpz_init_set_si(r
->param2
,0);
109 r
->param1
= r
->param2
= 0;
112 if(sol_free
>= SOL_SIZE
)
113 {fprintf(stderr
, "The solution is too complex! : sol\n");
125 {fprintf(dump
, "\nNil");
130 void sol_error(int c
)
135 #if defined(LINEAR_VALUE_IS_MP)
136 mpz_set_si(r
->param1
, c
);
141 fprintf(dump
, "Erreur %d\n", c
);
149 return(sol_space
[p
].flags
!= Nil
);
158 fprintf(dump
, "\nIf ");
168 #if defined(LINEAR_VALUE_IS_MP)
169 mpz_set_si(r
->param1
, n
);
174 fprintf(dump
, "\nList %d ", n
);
185 #if defined(LINEAR_VALUE_IS_MP)
186 mpz_set_ui(r
-> param1
, l
);
191 fprintf(dump
, "\nForme %d ", l
);
202 #if defined(LINEAR_VALUE_IS_MP)
203 mpz_set_ui(r
-> param1
, k
);
208 fprintf(dump
, "New %d ", k
);
219 fprintf(dump
, "Div ");
230 #if defined(LINEAR_VALUE_IS_MP)
231 mpz_set(r
-> param1
, n
);
232 mpz_set(r
-> param2
, d
);
238 fprintf(dump
, "val(");
239 #if defined(LINEAR_VALUE_IS_MP)
240 mpz_out_str(dump
, 10, n
);
242 mpz_out_str(dump
, 10, d
);
244 fprintf(dump
, FORMAT
, n
);
246 fprintf(dump
, FORMAT
, d
);
255 /* a` partir d'un point de la solution, sauter un objet
256 bien forme' ainsi qu'un e'ventuel New et pointer sur l'objet
261 if(sol_space
[i
].flags
!= New
) return i
;
262 i
= skip(i
+1); /* sauter le Div */
265 /* au lancement, i indexe une cellule qui est la te^te d'un objet.
266 la valeur retourne'e est la te^te de l'objet qui suit. Les
267 objets de type New sont e'limine's */
271 while((f
= sol_space
[i
].flags
) == Free
|| f
== Error
) i
++;
272 switch (sol_space
[i
].flags
) {
273 case Nil
: case Val
: i
++; break;
274 case New
: i
= skip_New(i
); break;
275 case If
: i
= skip(i
+1); /* sauter le pre'dicat */
276 i
= skip(i
); /* sauter le vrai */
277 i
= skip(i
); break; /* sauter le faux */
278 case List
: case Form
:
279 #if defined(LINEAR_VALUE_IS_MP)
280 n
= mpz_get_si(sol_space
[i
].param1
);
282 n
= sol_space
[i
].param1
;
285 while(n
--) i
= skip(i
);
287 case Div
: i
= skip(i
+1); /* sauter la forme */
288 i
= skip(i
); /* sauter le diviseur */
290 default : fprintf(stderr
,
291 "Syserr : skip : unknown %d\n", sol_space
[i
].flags
);
295 /* simplification de la solution : e'limination des constructions
296 (if p () ()). N'est en service qu'en pre'sence de l'option -z */
298 void sol_simplify(int i
)
300 if(sol_space
[i
].flags
== If
) {
301 j
= skip(i
+1); /* j : debut de la partie vraie */
302 k
= skip(j
); /* k : debut de la partie fausse */
305 if(sol_space
[j
].flags
== Nil
&& sol_space
[k
].flags
== Nil
) {
306 sol_space
[i
].flags
= Nil
;
307 if (k
>= sol_free
- 1)
309 else for(l
= i
+1; l
<=k
; l
++) sol_space
[l
].flags
= Free
;
314 /* e'dition de la solution */
316 int sol_edit(FILE *foo
, int i
)
320 #if defined(LINEAR_VALUE_IS_MP)
328 if(p
->flags
== Free
) {
333 if(p
->flags
== New
) {
334 #if defined(LINEAR_VALUE_IS_MP)
335 n
= mpz_get_si(p
->param1
);
339 fprintf(foo
, "(newparm %d ", n
);
340 if(verbose
>0)fprintf(dump
, "(newparm %d ", n
);
341 i
= sol_edit(foo
, ++i
);
344 if(verbose
>0)fprintf(dump
, ")\n");
350 case Nil
: fprintf(foo
, "()\n");
351 if(verbose
>0)fprintf(dump
, "()\n");
354 #if defined(LINEAR_VALUE_IS_MP)
355 fprintf(foo
, "Error %d\n", mpz_get_si(p
->param1
));
357 fprintf(dump
, "Error %d\n", mpz_get_si(p
->param1
));
359 fprintf(foo
, "Error %d\n", p
->param1
);
361 fprintf(dump
, "Error %d\n", p
->param1
);
364 case If
: fprintf(foo
, "(if ");
365 if(verbose
>0)fprintf(dump
, "(if ");
366 i
= sol_edit(foo
, ++i
);
367 i
= sol_edit(foo
, i
);
368 i
= sol_edit(foo
, i
);
370 if(verbose
>0)fprintf(dump
, ")\n");
372 case List
: fprintf(foo
, "(list ");
373 if(verbose
>0)fprintf(dump
, "(list ");
374 #if defined(LINEAR_VALUE_IS_MP)
375 n
= mpz_get_si(p
->param1
);
380 while(n
--) i
= sol_edit(foo
, i
);
382 if(verbose
>0)fprintf(dump
, ")\n");
384 case Form
: fprintf(foo
, "#[");
385 if(verbose
>0)fprintf(dump
, "#[");
386 #if defined(LINEAR_VALUE_IS_MP)
387 n
= mpz_get_si(p
->param1
);
391 for(j
= 0; j
<n
; j
++){
393 #if defined(LINEAR_VALUE_IS_MP)
394 mpz_set(N
, p
->param1
); mpz_set(D
, p
->param2
);
396 if(mpz_cmp(d
, D
) == 0){
398 mpz_divexact(N
, N
, d
);
399 mpz_out_str(foo
, 10, N
);
402 mpz_out_str(dump
, 10, N
);
406 mpz_divexact(N
, N
, d
);
407 mpz_divexact(D
, D
, d
);
409 mpz_out_str(foo
, 10, N
);
411 mpz_out_str(foo
, 10, D
);
414 mpz_out_str(dump
, 10, N
);
416 mpz_out_str(dump
, 10, D
);
420 N
= p
->param1
; D
= p
->param2
;
424 fprintf(foo
, FORMAT
, N
/d
);
427 fprintf(dump
, FORMAT
, N
/d
);
432 fprintf(foo
,FORMAT
,N
/d
);
434 fprintf(foo
,FORMAT
, D
/d
);
437 fprintf(dump
,FORMAT
,N
/d
);
439 fprintf(dump
,FORMAT
, D
/d
);
445 if(verbose
>0)fprintf(dump
, "]\n");
448 case Div
: fprintf(foo
, "(div ");
449 if(verbose
>0)fprintf(dump
, "(div ");
450 i
= sol_edit(foo
, ++i
);
451 i
= sol_edit(foo
, i
);
453 if(verbose
>0)fprintf(dump
, ")\n");
456 #if defined(LINEAR_VALUE_IS_MP)
457 mpz_set(N
, p
->param1
); mpz_set(D
, p
->param2
);
459 if(mpz_cmp(d
, D
) == 0){
460 mpz_divexact(N
, N
, d
);
462 mpz_out_str(foo
, 10, N
);
465 mpz_out_str(dump
, 10, N
);
469 mpz_divexact(N
, N
, d
);
470 mpz_divexact(D
, D
, d
);
472 mpz_out_str(foo
, 10, N
);
474 mpz_out_str(foo
, 10, D
);
477 mpz_out_str(dump
, 10, N
);
479 mpz_out_str(dump
, 10, D
);
483 N
= p
->param1
; D
= p
->param2
;
485 if(d
== D
){putc(' ', foo
);
486 fprintf(foo
, FORMAT
, N
/d
);
489 fprintf(dump
, FORMAT
, N
/d
);
493 fprintf(foo
, FORMAT
, N
/d
);
495 fprintf(foo
, FORMAT
, D
/d
);
498 fprintf(dump
, FORMAT
, N
/d
);
500 fprintf(dump
, FORMAT
, D
/d
);
506 default : fprintf(foo
, "Inconnu : sol\n");
507 if(verbose
>0)fprintf(dump
, "Inconnu : sol\n");
509 #if defined(LINEAR_VALUE_IS_MP)
518 /* Fonction sol_vector_edit :
519 * Cette fonction a pour but de placer les informations correspondant
520 * a un Vector dans la grammaire dans une structure de type PipVector. Elle
521 * prend en parametre un pointeur vers une case memoire contenant le
522 * numero de cellule du tableau sol_space a partir de laquelle on doit
523 * commencer la lecture des informations. Elle retourne un pointeur vers
524 * une structure de type PipVector contenant les informations de ce Vector.
525 * Premiere version : Ced. 20 juillet 2001.
527 PipVector
* sol_vector_edit(int *i
, int Bg
, int Urs_p
, int flags
)
528 { int j
, k
, n
, unbounded
= 0, first_urs
;
537 vector
= (PipVector
*)malloc(sizeof(PipVector
)) ;
539 { fprintf(stderr
, "Memory Overflow.\n") ;
542 p
= sol_space
+ (*i
) ;
543 n
= ENTIER_TO_INT(p
->param1
);
544 if (flags
& SOL_REMOVE
)
547 first_urs
= Urs_p
+ (Bg
>= 0);
548 vector
->nb_elements
= n
;
549 vector
->the_vector
= (Entier
*)malloc(sizeof(Entier
)*n
) ;
550 if (vector
->the_vector
== NULL
)
551 { fprintf(stderr
, "Memory Overflow.\n") ;
554 vector
->the_deno
= (Entier
*)malloc(sizeof(Entier
)*n
) ;
555 if (vector
->the_deno
== NULL
)
556 { fprintf(stderr
, "Memory Overflow.\n") ;
560 for (j
=0, k
=0; k
< n
; j
++) {
564 entier_assign(N
, p
->param1
);
565 entier_assign(D
, p
->param2
);
568 if ((flags
& SOL_SHIFT
) && j
== Bg
) {
569 entier_subtract(N
, N
, D
); /* subtract 1 */
570 if (entier_notzero_p(N
))
574 if ((flags
& SOL_REMOVE
) && j
== Bg
)
577 if (first_urs
<= j
&& j
< first_urs
+Urs_p
)
580 entier_init(vector
->the_vector
[k
]);
581 entier_divexact(vector
->the_vector
[k
], N
, d
);
582 if (flags
& SOL_NEGATE
)
583 entier_oppose(vector
->the_vector
[k
], vector
->the_vector
[k
]);
584 entier_init(vector
->the_deno
[k
]);
586 entier_assign(vector
->the_deno
[k
], UN
);
588 entier_divexact(vector
->the_deno
[k
], D
, d
);
592 for (k
=0; k
< n
; k
++)
593 entier_assign(vector
->the_deno
[k
], ZERO
);
604 /* Fonction sol_newparm_edit :
605 * Cette fonction a pour but de placer les informations correspondant
606 * a un Newparm dans la grammaire dans une structure de type PipNewparm. Elle
607 * prend en parametre un pointeur vers une case memoire contenant le
608 * numero de cellule du tableau sol_space a partir de laquelle on doit
609 * commencer la lecture des informations. Elle retourne un pointeur vers
610 * une structure de type PipNewparm contenant les informations de ce Newparm.
611 * Premiere version : Ced. 18 octobre 2001.
613 PipNewparm
* sol_newparm_edit(int *i
, int Bg
, int Urs_p
, int flags
)
615 PipNewparm
* newparm
, * newparm_first
= NULL
, * newparm_now
= NULL
;
617 /* On place p au lieu de lecture. */
618 p
= sol_space
+ (*i
) ;
621 /* On passe le New et le Div pour aller a Form et lire le VECTOR. */
624 newparm
= (PipNewparm
*)malloc(sizeof(PipNewparm
)) ;
626 { fprintf(stderr
, "Memory Overflow.\n") ;
629 newparm
->vector
= sol_vector_edit(i
, Bg
, Urs_p
, flags
);
630 newparm
->rank
= ENTIER_TO_INT(p
->param1
);
631 /* On met p a jour pour lire le denominateur (un Val de param2 UN). */
632 p
= sol_space
+ (*i
) ;
633 entier_init_set(newparm
->deno
, p
->param1
);
634 if (flags
& SOL_REMOVE
)
636 newparm
->rank
-= Urs_p
;
637 newparm
->next
= NULL
;
640 newparm_now
->next
= newparm
;
642 newparm_first
= newparm
;
643 newparm_now
= newparm
;
645 { fprintf(dump
,"\n(newparm ") ;
646 fprintf(dump
,FORMAT
,newparm
->rank
) ;
647 fprintf(dump
," (div ") ;
648 pip_vector_print(dump
,newparm
->vector
) ;
650 #if defined(LINEAR_VALUE_IS_MP)
651 mpz_out_str(dump
,10,newparm
->deno
) ;
653 fprintf(dump
,FORMAT
,newparm
->deno
) ;
658 /* On passe aux elements suivants. */
660 p
= sol_space
+ (*i
) ;
661 } while (p
->flags
== New
);
663 return newparm_first
;
667 /* Fonction sol_list_edit :
668 * Cette fonction a pour but de placer les informations correspondant
669 * a une List dans la grammaire dans une structure de type PipList. Elle
670 * prend en parametre un pointeur vers une case memoire contenant le
671 * numero de cellule du tableau sol_space a partir de laquelle on doit
672 * commencer la lecture des informations. Elle retourne un pointeur vers
673 * une structure de type PipList contenant les informations de cette List.
674 * Premiere version : Ced. 18 octobre 2001.
675 * 16 novembre 2005 : Ced. Prise en compte du cas 0 éléments, avant impossible.
677 PipList
* sol_list_edit(int *i
, int nb_elements
, int Bg
, int Urs_p
, int flags
)
678 { PipList
* list
, * list_new
, * list_now
;
680 /* Pour le premier element. */
681 list
= (PipList
*)malloc(sizeof(PipList
)) ;
683 { fprintf(stderr
, "Memory Overflow.\n") ;
688 if (nb_elements
== 0)
689 { list
->vector
= NULL
;
693 list
->vector
= sol_vector_edit(i
, Bg
, Urs_p
, flags
);
697 { fprintf(dump
,"\n(list ") ;
698 pip_vector_print(dump
,list
->vector
) ;
702 /* Pour les elements suivants. */
703 while (nb_elements
--)
704 { list_new
= (PipList
*)malloc(sizeof(PipList
)) ;
705 if (list_new
== NULL
)
706 { fprintf(stderr
, "Memory Overflow.\n") ;
709 list_new
->vector
= sol_vector_edit(i
, Bg
, Urs_p
, flags
);
710 list_new
->next
= NULL
;
713 { fprintf(dump
,"\n") ;
714 pip_vector_print(dump
,list_new
->vector
) ;
716 list_now
->next
= list_new
;
717 list_now
= list_now
->next
;
720 fprintf(dump
,"\n)") ;
726 /* Fonction sol_quast_edit :
727 * Cette fonction a pour but de placer les informations de la solution
728 * (qui sont contenues dans le tableau sol_space) dans une structure de
729 * type PipQuast en vue d'une utilisation directe de la solution par une
730 * application exterieure. Elle prend en parametre un pointeur vers une
731 * case memoire contenant le numero de cellule du tableau sol_space
732 * a partir de laquelle on doit commencer la lecture des informations. Elle
733 * recoit aussi l'adresse du PipQuast qui l'a appelle (pour le champ father).
734 * Elle retourne un pointeur vers une structure de type PipQuast qui
735 * contient toutes les informations sur la solution (sous forme d'arbre).
736 * Remarques : cette fonction lit les informations comme elles doivent
737 * se presenter a la fin du traitement. Elle respecte scrupuleusement
738 * la grammaire attendue et n'accepte de passer des cellules a Free
739 * qu'entre une des trois grandes formes (if, list ou suite de newparm).
740 * 20 juillet 2001 : Premiere version, Ced.
741 * 31 juillet 2001 : Ajout du traitement de l'option verbose = code*2 :0(
742 * 18 octobre 2001 : Grands changements dus a l'eclatement de la structure
743 * PipVector en PipVector, PipNewparm et PipList, et
744 * eclatement de la fonction avec sol_newparm_edit et
746 * 16 novembre 2005 : (debug) Même si une liste est vide il faut la créer pour
747 * afficher plus tard le (list), repéré par Sven Verdoolaege.
749 PipQuast
*sol_quast_edit(int *i
, PipQuast
*father
, int Bg
, int Urs_p
, int flags
)
752 PipQuast
* solution
;
753 PipList
* list_new
, * list_now
;
754 PipNewparm
* newparm_new
, * newparm_now
;
756 /* On place p au lieu de lecture. */
757 p
= sol_space
+ (*i
) ;
758 /* En cas d'utilisation de l'option de simplification, une plage de
759 * structures S peut avoir les flags a Free. On doit alors les passer.
761 while (p
->flags
== Free
)
766 solution
= (PipQuast
*)malloc(sizeof(PipQuast
)) ;
767 if (solution
== NULL
)
768 { fprintf(stderr
, "Memory Overflow.\n") ;
771 solution
->newparm
= NULL
;
772 solution
->list
= NULL
;
773 solution
->condition
= NULL
;
774 solution
->next_then
= NULL
;
775 solution
->next_else
= NULL
;
776 solution
->father
= father
;
778 /* On peut commencer par une chaine de nouveaux parametres... */
780 { solution
->newparm
= sol_newparm_edit(i
, Bg
, Urs_p
, flags
& SOL_REMOVE
);
781 p
= sol_space
+ (*i
) ;
784 /* ...ensuite soit par une liste (vide ou non) soit par un if. */
785 (*i
)++ ; /* Factorise de List, Nil et If. */
788 #if defined(LINEAR_VALUE_IS_MP)
789 nb_elements
= mpz_get_si(p
->param1
) ;
791 nb_elements
= p
->param1
;
793 solution
->list
= sol_list_edit(i
, nb_elements
, Bg
, Urs_p
, flags
);
794 if (flags
& SOL_DUAL
)
795 solution
->next_then
= sol_quast_edit(i
, solution
, Bg
, Urs_p
, 0);
797 case Nil
: if (verbose
> 0)
798 fprintf(dump
,"\n()") ;
800 case If
: solution
->condition
=
801 sol_vector_edit(i
, Bg
, Urs_p
, flags
& SOL_REMOVE
);
803 { fprintf(dump
,"\n(if ") ;
804 pip_vector_print(dump
,solution
->condition
) ;
806 solution
->next_then
= sol_quast_edit(i
, solution
, Bg
, Urs_p
, flags
);
807 solution
->next_else
= sol_quast_edit(i
, solution
, Bg
, Urs_p
, flags
);
809 fprintf(dump
,"\n)") ;
811 default : fprintf(stderr
,"\nAie !!! Flag %d inattendu.\n",p
->flags
) ;
813 fprintf(dump
,"\nAie !!! Flag %d inattendu.\n",p
->flags
) ;