1 /******************************************************************************
2 * PIP : Parametric Integer Programming *
3 ******************************************************************************
5 ******************************************************************************
7 * Copyright Paul Feautrier, 1988, 1993, 1994, 1996, 2002 *
9 * This is free software; you can redistribute it and/or modify it under the *
10 * terms of the GNU General Public License as published by the Free Software *
11 * Foundation; either version 2 of the License, or (at your option) any later *
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 General Public License along *
20 * with software; if not, write to the Free Software Foundation, Inc., *
21 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
23 * Written by Paul Feautrier and Cedric Bastoul *
25 ******************************************************************************/
31 #include <piplib/piplib.h>
33 extern long int cross_product
, limit
;
39 Entier param1
, param2
;
52 struct S sol_space
[SOL_SIZE
];
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
);
82 if(p
<0 || p
>=SOL_SIZE
)
83 {fprintf(stderr
, "Syserr : sol_reset : Memory allocation error\n");
86 #if defined(LINEAR_VALUE_IS_MP)
87 for(i
=p
; i
<sol_free
; i
++){
88 mpz_clear(sol_space
[i
].param1
);
89 mpz_clear(sol_space
[i
].param2
);
95 struct S
*sol_alloc(void)
97 r
= sol_space
+ sol_free
;
99 #if defined(LINEAR_VALUE_IS_MP)
100 mpz_init_set_si(r
->param1
,0);
101 mpz_init_set_si(r
->param2
,0);
103 r
->param1
= r
->param2
= 0;
106 if(sol_free
>= SOL_SIZE
)
107 {fprintf(stderr
, "The solution is too complex! : sol\n");
119 {fprintf(dump
, "\nNil");
124 void sol_error(int c
)
129 #if defined(LINEAR_VALUE_IS_MP)
130 mpz_set_si(r
->param1
, c
);
135 fprintf(dump
, "Erreur %d\n", c
);
143 return(sol_space
[p
].flags
!= Nil
);
152 fprintf(dump
, "\nIf ");
162 #if defined(LINEAR_VALUE_IS_MP)
163 mpz_set_si(r
->param1
, n
);
168 fprintf(dump
, "\nList %d ", n
);
179 #if defined(LINEAR_VALUE_IS_MP)
180 mpz_set_ui(r
-> param1
, l
);
185 fprintf(dump
, "\nForme %d ", l
);
196 #if defined(LINEAR_VALUE_IS_MP)
197 mpz_set_ui(r
-> param1
, k
);
202 fprintf(dump
, "New %d ", k
);
213 fprintf(dump
, "Div ");
224 #if defined(LINEAR_VALUE_IS_MP)
225 mpz_set(r
-> param1
, n
);
226 mpz_set(r
-> param2
, d
);
232 fprintf(dump
, "val(");
233 #if defined(LINEAR_VALUE_IS_MP)
234 mpz_out_str(dump
, 10, n
);
236 mpz_out_str(dump
, 10, d
);
238 fprintf(dump
, FORMAT
, n
);
240 fprintf(dump
, FORMAT
, d
);
249 /* a` partir d'un point de la solution, sauter un objet
250 bien forme' ainsi qu'un e'ventuel New et pointer sur l'objet
255 if(sol_space
[i
].flags
!= New
) return i
;
256 i
= skip(i
+1); /* sauter le Div */
259 /* au lancement, i indexe une cellule qui est la te^te d'un objet.
260 la valeur retourne'e est la te^te de l'objet qui suit. Les
261 objets de type New sont e'limine's */
265 while((f
= sol_space
[i
].flags
) == Free
|| f
== Error
) i
++;
266 switch (sol_space
[i
].flags
) {
267 case Nil
: case Val
: i
++; break;
268 case New
: i
= skip_New(i
); break;
269 case If
: i
= skip(i
+1); /* sauter le pre'dicat */
270 i
= skip(i
); /* sauter le vrai */
271 i
= skip(i
); break; /* sauter le faux */
272 case List
: case Form
:
273 #if defined(LINEAR_VALUE_IS_MP)
274 n
= mpz_get_si(sol_space
[i
].param1
);
276 n
= sol_space
[i
].param1
;
279 while(n
--) i
= skip(i
);
281 case Div
: i
= skip(i
+1); /* sauter la forme */
282 i
= skip(i
); /* sauter le diviseur */
284 default : fprintf(stderr
,
285 "Syserr : skip : unknown %d\n", sol_space
[i
].flags
);
289 /* simplification de la solution : e'limination des constructions
290 (if p () ()). N'est en service qu'en pre'sence de l'option -z */
292 void sol_simplify(int i
)
294 if(sol_space
[i
].flags
== If
) {
295 j
= skip(i
+1); /* j : debut de la partie vraie */
296 k
= skip(j
); /* k : debut de la partie fausse */
299 if(sol_space
[j
].flags
== Nil
&& sol_space
[k
].flags
== Nil
) {
300 sol_space
[i
].flags
= Nil
;
301 if(k
>= sol_free
- 1) sol_free
= i
+1;
302 else for(l
= i
+1; l
<=k
; l
++) sol_space
[l
].flags
= Free
;
307 /* e'dition de la solution */
309 int sol_edit(FILE *foo
, int i
)
313 #if defined(LINEAR_VALUE_IS_MP)
321 if(p
->flags
== Free
) {
326 if(p
->flags
== New
) {
327 #if defined(LINEAR_VALUE_IS_MP)
328 n
= mpz_get_si(p
->param1
);
332 fprintf(foo
, "(newparm %d ", n
);
333 if(verbose
>0)fprintf(dump
, "(newparm %d ", n
);
334 i
= sol_edit(foo
, ++i
);
337 if(verbose
>0)fprintf(dump
, ")\n");
343 case Nil
: fprintf(foo
, "()\n");
344 if(verbose
>0)fprintf(dump
, "()\n");
347 #if defined(LINEAR_VALUE_IS_MP)
348 fprintf(foo
, "Error %d\n", mpz_get_si(p
->param1
));
350 fprintf(dump
, "Error %d\n", mpz_get_si(p
->param1
));
352 fprintf(foo
, "Error %d\n", p
->param1
);
354 fprintf(dump
, "Error %d\n", p
->param1
);
357 case If
: fprintf(foo
, "(if ");
358 if(verbose
>0)fprintf(dump
, "(if ");
359 i
= sol_edit(foo
, ++i
);
360 i
= sol_edit(foo
, i
);
361 i
= sol_edit(foo
, i
);
363 if(verbose
>0)fprintf(dump
, ")\n");
365 case List
: fprintf(foo
, "(list ");
366 if(verbose
>0)fprintf(dump
, "(list ");
367 #if defined(LINEAR_VALUE_IS_MP)
368 n
= mpz_get_si(p
->param1
);
373 while(n
--) i
= sol_edit(foo
, i
);
375 if(verbose
>0)fprintf(dump
, ")\n");
377 case Form
: fprintf(foo
, "#[");
378 if(verbose
>0)fprintf(dump
, "#[");
379 #if defined(LINEAR_VALUE_IS_MP)
380 n
= mpz_get_si(p
->param1
);
384 for(j
= 0; j
<n
; j
++){
386 #if defined(LINEAR_VALUE_IS_MP)
387 mpz_set(N
, p
->param1
); mpz_set(D
, p
->param2
);
389 if(mpz_cmp(d
, D
) == 0){
391 mpz_divexact(N
, N
, d
);
392 mpz_out_str(foo
, 10, N
);
395 mpz_out_str(dump
, 10, N
);
399 mpz_divexact(N
, N
, d
);
400 mpz_divexact(D
, D
, d
);
402 mpz_out_str(foo
, 10, N
);
404 mpz_out_str(foo
, 10, D
);
407 mpz_out_str(dump
, 10, N
);
409 mpz_out_str(dump
, 10, D
);
413 N
= p
->param1
; D
= p
->param2
;
417 fprintf(foo
, FORMAT
, N
/d
);
420 fprintf(dump
, FORMAT
, N
/d
);
425 fprintf(foo
,FORMAT
,N
/d
);
427 fprintf(foo
,FORMAT
, D
/d
);
430 fprintf(dump
,FORMAT
,N
/d
);
432 fprintf(dump
,FORMAT
, D
/d
);
438 if(verbose
>0)fprintf(dump
, "]\n");
441 case Div
: fprintf(foo
, "(div ");
442 if(verbose
>0)fprintf(dump
, "(div ");
443 i
= sol_edit(foo
, ++i
);
444 i
= sol_edit(foo
, i
);
446 if(verbose
>0)fprintf(dump
, ")\n");
449 #if defined(LINEAR_VALUE_IS_MP)
450 mpz_set(N
, p
->param1
); mpz_set(D
, p
->param2
);
452 if(mpz_cmp(d
, D
) == 0){
453 mpz_divexact(N
, N
, d
);
455 mpz_out_str(foo
, 10, N
);
458 mpz_out_str(dump
, 10, N
);
462 mpz_divexact(N
, N
, d
);
463 mpz_divexact(D
, D
, d
);
465 mpz_out_str(foo
, 10, N
);
467 mpz_out_str(foo
, 10, D
);
470 mpz_out_str(dump
, 10, N
);
472 mpz_out_str(dump
, 10, D
);
476 N
= p
->param1
; D
= p
->param2
;
478 if(d
== D
){putc(' ', foo
);
479 fprintf(foo
, FORMAT
, N
/d
);
482 fprintf(dump
, FORMAT
, N
/d
);
486 fprintf(foo
, FORMAT
, N
/d
);
488 fprintf(foo
, FORMAT
, D
/d
);
491 fprintf(dump
, FORMAT
, N
/d
);
493 fprintf(dump
, FORMAT
, D
/d
);
499 default : fprintf(foo
, "Inconnu : sol\n");
500 if(verbose
>0)fprintf(dump
, "Inconnu : sol\n");
502 #if defined(LINEAR_VALUE_IS_MP)
511 /* Fonction sol_vector_edit :
512 * Cette fonction a pour but de placer les informations correspondant
513 * a un Vector dans la grammaire dans une structure de type PipVector. Elle
514 * prend en parametre un pointeur vers une case memoire contenant le
515 * numero de cellule du tableau sol_space a partir de laquelle on doit
516 * commencer la lecture des informations. Elle retourne un pointeur vers
517 * une structure de type PipVector contenant les informations de ce Vector.
518 * Premiere version : Ced. 20 juillet 2001.
520 PipVector
* sol_vector_edit(int * i
)
526 #if defined(LINEAR_VALUE_IS_MP)
532 vector
= (PipVector
*)malloc(sizeof(PipVector
)) ;
534 { fprintf(stderr
, "Memory Overflow.\n") ;
537 p
= sol_space
+ (*i
) ;
538 #if defined(LINEAR_VALUE_IS_MP)
539 n
= mpz_get_si(p
->param1
) ;
543 vector
->nb_elements
= n
;
544 vector
->the_vector
= (Entier
*)malloc(sizeof(Entier
)*n
) ;
545 if (vector
->the_vector
== NULL
)
546 { fprintf(stderr
, "Memory Overflow.\n") ;
549 vector
->the_deno
= (Entier
*)malloc(sizeof(Entier
)*n
) ;
550 if (vector
->the_deno
== NULL
)
551 { fprintf(stderr
, "Memory Overflow.\n") ;
558 #if defined(LINEAR_VALUE_IS_MP)
559 mpz_set(N
,p
->param1
) ;
560 mpz_set(D
,p
->param2
) ;
562 mpz_init(vector
->the_vector
[j
]) ;
563 mpz_divexact(vector
->the_vector
[j
],N
,d
) ;
564 mpz_init(vector
->the_deno
[j
]) ;
565 if (mpz_cmp(d
, D
) == 0)
566 mpz_set(vector
->the_deno
[j
],UN
) ;
568 mpz_divexact(vector
->the_deno
[j
],D
,d
) ;
573 vector
->the_vector
[j
] = N
/d
;
575 vector
->the_deno
[j
] = UN
;
577 vector
->the_deno
[j
] = D
/d
;
582 #if defined(LINEAR_VALUE_IS_MP)
592 /* Fonction sol_newparm_edit :
593 * Cette fonction a pour but de placer les informations correspondant
594 * a un Newparm dans la grammaire dans une structure de type PipNewparm. Elle
595 * prend en parametre un pointeur vers une case memoire contenant le
596 * numero de cellule du tableau sol_space a partir de laquelle on doit
597 * commencer la lecture des informations. Elle retourne un pointeur vers
598 * une structure de type PipNewparm contenant les informations de ce Newparm.
599 * Premiere version : Ced. 18 octobre 2001.
601 PipNewparm
* sol_newparm_edit(int * i
)
603 PipNewparm
* newparm
, * newparm_new
, * newparm_now
;
605 /* On place p au lieu de lecture. */
606 p
= sol_space
+ (*i
) ;
607 /* On passe le New et le Div pour aller a Form et lire le VECTOR. */
610 newparm
= (PipNewparm
*)malloc(sizeof(PipNewparm
)) ;
612 { fprintf(stderr
, "Memory Overflow.\n") ;
615 newparm
->vector
= sol_vector_edit(i
) ;
616 #if defined(LINEAR_VALUE_IS_MP)
617 newparm
->rank
= mpz_get_si(p
->param1
) ;
618 /* On met p a jour pour lire le denominateur (un Val de param2 UN). */
619 p
= sol_space
+ (*i
) ;
620 mpz_init_set(newparm
->deno
,p
->param1
) ;
622 newparm
->rank
= p
->param1
;
623 p
= sol_space
+ (*i
) ;
624 newparm
->deno
= p
->param1
;
626 newparm
->next
= NULL
;
628 newparm_now
= newparm
;
630 { fprintf(dump
,"\n(newparm ") ;
631 fprintf(dump
,FORMAT
,newparm
->rank
) ;
632 fprintf(dump
," (div ") ;
633 pip_vector_print(dump
,newparm
->vector
) ;
635 #if defined(LINEAR_VALUE_IS_MP)
636 mpz_out_str(dump
,10,newparm
->deno
) ;
638 fprintf(dump
,FORMAT
,newparm
->deno
) ;
643 /* On passe aux elements suivants. */
645 p
= sol_space
+ (*i
) ;
646 while (p
->flags
== New
)
648 newparm_new
= (PipNewparm
*)malloc(sizeof(PipNewparm
)) ;
649 if (newparm_new
== NULL
)
650 { fprintf(stderr
, "Memory Overflow.\n") ;
653 newparm_new
->vector
= sol_vector_edit(i
) ;
654 #if defined(LINEAR_VALUE_IS_MP)
655 newparm_new
->rank
= mpz_get_si(p
->param1
) ;
656 p
= sol_space
+ (*i
) ;
657 mpz_init_set(newparm_new
->deno
,p
->param1
) ;
659 newparm_new
->rank
= p
->param1
;
660 p
= sol_space
+ (*i
) ;
661 newparm_new
->deno
= p
->param1
;
663 newparm_new
->next
= NULL
;
665 newparm_now
->next
= newparm_new
;
666 newparm_now
= newparm_now
->next
;
668 { fprintf(dump
,"\n(newparm ") ;
669 fprintf(dump
,FORMAT
,newparm_new
->rank
) ;
670 fprintf(dump
," (div ") ;
671 pip_vector_print(dump
,newparm_new
->vector
) ;
673 #if defined(LINEAR_VALUE_IS_MP)
674 mpz_out_str(dump
,10,newparm_new
->deno
) ;
676 fprintf(dump
,FORMAT
,newparm_new
->deno
) ;
681 p
= sol_space
+ (*i
) ;
687 /* Fonction sol_list_edit :
688 * Cette fonction a pour but de placer les informations correspondant
689 * a une List dans la grammaire dans une structure de type PipList. Elle
690 * prend en parametre un pointeur vers une case memoire contenant le
691 * numero de cellule du tableau sol_space a partir de laquelle on doit
692 * commencer la lecture des informations. Elle retourne un pointeur vers
693 * une structure de type PipList contenant les informations de cette List.
694 * Premiere version : Ced. 18 octobre 2001.
696 PipList
* sol_list_edit(int * i
, int nb_elements
)
697 { PipList
* list
, * list_new
, * list_now
;
699 /* Pour le premier element. */
700 list
= (PipList
*)malloc(sizeof(PipList
)) ;
702 { fprintf(stderr
, "Memory Overflow.\n") ;
705 list
->vector
= sol_vector_edit(i
) ;
710 { fprintf(dump
,"\n(list ") ;
711 pip_vector_print(dump
,list
->vector
) ;
715 /* Pour les elements suivants. */
716 while (nb_elements
--)
717 { list_new
= (PipList
*)malloc(sizeof(PipList
)) ;
718 if (list_new
== NULL
)
719 { fprintf(stderr
, "Memory Overflow.\n") ;
722 list_new
->vector
= sol_vector_edit(i
) ;
723 list_new
->next
= NULL
;
726 { fprintf(dump
,"\n") ;
727 pip_vector_print(dump
,list_new
->vector
) ;
729 list_now
->next
= list_new
;
730 list_now
= list_now
->next
;
733 fprintf(dump
,"\n)") ;
739 /* Fonction sol_quast_edit :
740 * Cette fonction a pour but de placer les informations de la solution
741 * (qui sont contenues dans le tableau sol_space) dans une structure de
742 * type PipQuast en vue d'une utilisation directe de la solution par une
743 * application exterieure. Elle prend en parametre un pointeur vers une
744 * case memoire contenant le numero de cellule du tableau sol_space
745 * a partir de laquelle on doit commencer la lecture des informations. Elle
746 * recoit aussi l'adresse du PipQuast qui l'a appelle (pour le champ father).
747 * Elle retourne un pointeur vers une structure de type PipQuast qui
748 * contient toutes les informations sur la solution (sous forme d'arbre).
749 * Remarques : cette fonction lit les informations comme elles doivent
750 * se presenter a la fin du traitement. Elle respecte scrupuleusement
751 * la grammaire attendue et n'accepte de passer des cellules a Free
752 * qu'entre une des trois grandes formes (if, list ou suite de newparm).
753 * 20 juillet 2001 : Premiere version, Ced.
754 * 31 juillet 2001 : Ajout du traitement de l'option verbose = code*2 :0(
755 * 18 octobre 2001 : Grands changements dus a l'eclatement de la structure
756 * PipVector en PipVector, PipNewparm et PipList, et
757 * eclatement de la fonction avec sol_newparm_edit et
760 PipQuast
* sol_quast_edit(int * i
, PipQuast
* father
)
763 PipQuast
* solution
;
764 PipList
* list_new
, * list_now
;
765 PipNewparm
* newparm_new
, * newparm_now
;
767 /* On place p au lieu de lecture. */
768 p
= sol_space
+ (*i
) ;
769 /* En cas d'utilisation de l'option de simplification, une plage de
770 * structures S peut avoir les flags a Free. On doit alors les passer.
772 while (p
->flags
== Free
)
777 solution
= (PipQuast
*)malloc(sizeof(PipQuast
)) ;
778 if (solution
== NULL
)
779 { fprintf(stderr
, "Memory Overflow.\n") ;
782 solution
->newparm
= NULL
;
783 solution
->list
= NULL
;
784 solution
->condition
= NULL
;
785 solution
->next_then
= NULL
;
786 solution
->next_else
= NULL
;
787 solution
->father
= father
;
789 /* On peut commencer par une chaine de nouveaux parametres... */
791 { solution
->newparm
= sol_newparm_edit(i
) ;
792 p
= sol_space
+ (*i
) ;
795 /* ...ensuite soit par une liste (vide ou non) soit par un if. */
796 (*i
)++ ; /* Factorise de List, Nil et If. */
799 #if defined(LINEAR_VALUE_IS_MP)
800 if ((nb_elements
= mpz_get_si(p
->param1
)) != 0)
802 if ((nb_elements
= p
->param1
) != 0)
804 solution
->list
= sol_list_edit(i
,nb_elements
) ;
806 case Nil
: if (verbose
)
807 fprintf(dump
,"\n()") ;
809 case If
: solution
->condition
= sol_vector_edit(i
) ;
811 { fprintf(dump
,"\n(if ") ;
812 pip_vector_print(dump
,solution
->condition
) ;
814 solution
->next_then
= sol_quast_edit(i
,solution
) ;
815 solution
->next_else
= sol_quast_edit(i
,solution
) ;
817 fprintf(dump
,"\n)") ;
819 default : fprintf(stderr
,"\nAie !!! Flag %d inattendu.\n",p
->flags
) ;
821 fprintf(dump
,"\nAie !!! Flag %d inattendu.\n",p
->flags
) ;