1 /********************************************************/
2 /* Part of MultiPrecision PIP port (C) Zbigniew Chamski */
3 /* and Paul Feautrier. */
4 /* Based on straight PIP version E.1 by Paul Feautrier */
5 /* (<Paul.Feautrier@inria.fr>) */
7 /* and a previous port (C) Zbigniew CHAMSKI, 1993. */
8 /* (Zbigniew.Chamski@philips.com) */
10 /* Copying subject to the terms and conditions of the */
11 /* GNU General Public License. */
13 /* Send questions, bug reports and fixes to: */
14 /* <Paul.Feautrier@inria.fr> */
15 /********************************************************/
21 #include <piplib/piplib.h>
23 extern long int cross_product
, limit
;
29 Entier param1
, param2
;
32 /* In some cases, param1 and param2 are used to store small integers.
33 These integers are nevertheless converted to bignums in the
34 interest of simplicity. Since the handling of the solution is
35 a negligible part of the algorithm, the corresponding overhead is
50 struct S sol_space
[SOL_SIZE
];
53 /* pgcd has been removed and replaced by mpz_gcd
69 if(p
<0 || p
>=SOL_SIZE
)
70 {fprintf(stdout
, "Syserr : sol_reset : Memory allocation error\n");
73 for(i
=p
; i
<sol_free
; i
++){
74 mpz_clear(sol_space
[i
].param1
);
75 mpz_clear(sol_space
[i
].param2
);
80 struct S
*sol_alloc(void)
82 r
= sol_space
+ sol_free
;
87 if(sol_free
>= SOL_SIZE
)
88 {fprintf(stdout
, "The solution is too complex! : sol\n");
100 {fprintf(dump
, "\nNil");
105 void sol_error(int c
)
110 mpz_set_si(r
->param1
, c
);
112 fprintf(dump
, "Erreur %d\n", c
);
120 return(sol_space
[p
].flags
!= Nil
);
129 fprintf(dump
, "\nIf ");
139 mpz_set_si(r
->param1
, n
);
141 fprintf(dump
, "\nList %d ", n
);
152 mpz_set_ui(r
-> param1
, l
);
154 fprintf(dump
, "\nForme %d ", l
);
164 fprintf(dump
, "New %d ", k
);
169 mpz_set_ui(r
-> param1
, k
);
178 fprintf(dump
, "Div ");
190 mpz_set(r
-> param1
, n
);
191 mpz_set(r
-> param2
, d
);
194 mpz_out_str(dump
, 10, n
);
196 mpz_out_str(dump
, 10, d
);
203 /* a` partir d'un point de la solution, sauter un objet
204 bien forme' ainsi qu'un e'ventuel New et pointer sur l'objet
209 if(sol_space
[i
].flags
!= New
) return i
;
210 i
= skip(i
+1); /* sauter le Div */
213 /* au lancement, i indexe une cellule qui est la te^te d'un objet.
214 la valeur retourne'e est la te^te de l'objet qui suit. Les
215 objets de type New sont e'limine's */
219 while((f
= sol_space
[i
].flags
) == Free
|| f
== Error
) i
++;
220 switch (sol_space
[i
].flags
) {
221 case Nil
: case Val
: i
++; break;
222 case New
: i
= skip_New(i
); break;
223 case If
: i
= skip(i
+1); /* sauter le pre'dicat */
224 i
= skip(i
); /* sauter le vrai */
225 i
= skip(i
); break; /* sauter le faux */
226 case List
: case Form
: n
= mpz_get_si(sol_space
[i
].param1
);
228 while(n
--) i
= skip(i
);
230 case Div
: i
= skip(i
+1); /* sauter la forme */
231 i
= skip(i
); /* sauter le diviseur */
233 default : fprintf(stdout
,
234 "Syserr : skip : unknown %d\n", sol_space
[i
].flags
);
238 /* simplification de la solution : e'limination des constructions
239 (if p () ()). N'est en service qu'en pre'sence de l'option -z */
241 void sol_simplify(int i
)
243 if(sol_space
[i
].flags
== If
) {
244 j
= skip(i
+1); /* j : de'but de la partie vraie */
245 k
= skip(j
); /* k : de'but de la partie fausse */
248 if(sol_space
[j
].flags
== Nil
&& sol_space
[k
].flags
== Nil
) {
249 sol_space
[i
].flags
= Nil
;
250 if(k
>= sol_free
- 1) sol_free
= i
+1;
251 else for(l
= i
+1; l
<=k
; l
++) sol_space
[l
].flags
= Free
;
256 /* e'dition de la solution */
258 int sol_edit(FILE *foo
, int i
)
267 if(p
->flags
== Free
) {
272 if(p
->flags
== New
) {
273 n
= mpz_get_si(p
->param1
);
274 fprintf(foo
, "(newparm %d ", n
);
275 if(verbose
>0)fprintf(dump
, "(newparm %d ", n
);
276 i
= sol_edit(foo
, ++i
);
279 if(verbose
>0)fprintf(dump
, ")\n");
286 case Nil
: fprintf(foo
, "()\n");
287 if(verbose
>0)fprintf(dump
, "()\n");
289 case Error
: n
= mpz_get_si(p
->param1
);
290 fprintf(foo
, "Error %d\n", n
);
291 if(verbose
>0)fprintf(dump
, "Error %d\n", n
);
293 case If
: fprintf(foo
, "(if ");
294 if(verbose
>0)fprintf(dump
, "(if ");
295 i
= sol_edit(foo
, ++i
);
296 i
= sol_edit(foo
, i
);
297 i
= sol_edit(foo
, i
);
299 if(verbose
>0)fprintf(dump
, ")\n");
301 case List
: fprintf(foo
, "(list ");
302 if(verbose
>0)fprintf(dump
, "(list ");
303 n
= mpz_get_si(p
->param1
);
305 while(n
--) i
= sol_edit(foo
, i
);
307 if(verbose
>0)fprintf(dump
, ")\n");
309 case Form
: fprintf(foo
, "#[");
310 if(verbose
>0)fprintf(dump
, "#[");
311 n
= mpz_get_si(p
->param1
);
312 for(j
= 0; j
<n
; j
++){
314 mpz_set(N
, p
->param1
); mpz_set(D
, p
->param2
);
316 if(mpz_cmp(d
, D
) == 0){
318 mpz_divexact(N
, N
, d
);
319 mpz_out_str(foo
, 10, N
);
322 mpz_out_str(dump
, 10, N
);
326 mpz_divexact(N
, N
, d
);
327 mpz_divexact(D
, D
, d
);
329 mpz_out_str(foo
, 10, N
);
331 mpz_out_str(foo
, 10, D
);
334 mpz_out_str(dump
, 10, N
);
336 mpz_out_str(dump
, 10, D
);
345 case Div
: fprintf(foo
, "(div ");
346 if(verbose
>0)fprintf(dump
, "(div ");
347 i
= sol_edit(foo
, ++i
);
348 i
= sol_edit(foo
, i
);
350 if(verbose
>0)fprintf(dump
, ")\n");
352 case Val
: mpz_set(N
, p
->param1
); mpz_set(D
, p
->param2
);
354 if(mpz_cmp(d
, D
) == 0){
355 mpz_divexact(N
, N
, d
);
357 mpz_out_str(foo
, 10, N
);
360 mpz_out_str(dump
, 10, N
);
364 mpz_divexact(N
, N
, d
);
365 mpz_divexact(D
, D
, d
);
367 mpz_out_str(foo
, 10, N
);
369 mpz_out_str(foo
, 10, D
);
372 mpz_out_str(dump
, 10, N
);
374 mpz_out_str(dump
, 10, D
);
379 default : fprintf(foo
, "Inconnu : sol\n");
380 if(verbose
>0)fprintf(dump
, "Inconnu : sol\n");
392 /* Fonction sol_vector_edit :
393 * Cette fonction a pour but de placer les informations correspondant
394 * a un Vector dans la grammaire dans une structure de type PipVector. Elle
395 * prend en parametre un pointeur vers une case memoire contenant le
396 * numero de cellule du tableau sol_space a partir de laquelle on doit
397 * commencer la lecture des informations. Elle retourne un pointeur vers
398 * une structure de type PipVector contenant les informations de ce Vector.
399 * Premiere version : Ced. 20 juillet 2001.
400 * 24 octobre 2002 : Premiere version MP.
402 PipVector
* sol_vector_edit(int * i
)
412 vector
= (PipVector
*)malloc(sizeof(PipVector
)) ;
414 { fprintf(stderr
, "Memory Overflow.\n") ;
417 p
= sol_space
+ (*i
) ;
418 n
= mpz_get_si(p
->param1
) ;
419 vector
->nb_elements
= n
;
420 vector
->the_vector
= (Entier
*)malloc(sizeof(Entier
)*n
) ;
421 if (vector
->the_vector
== NULL
)
422 { fprintf(stderr
, "Memory Overflow.\n") ;
425 vector
->the_deno
= (Entier
*)malloc(sizeof(Entier
)*n
) ;
426 if (vector
->the_deno
== NULL
)
427 { fprintf(stderr
, "Memory Overflow.\n") ;
434 mpz_set(N
,p
->param1
) ;
435 mpz_set(D
,p
->param2
) ;
438 mpz_init(vector
->the_vector
[j
]) ;
439 mpz_divexact(vector
->the_vector
[j
],N
,d
) ;
441 mpz_init(vector
->the_deno
[j
]) ;
442 if (mpz_cmp(d
, D
) == 0)
443 mpz_set(vector
->the_deno
[j
],UN
) ;
445 mpz_divexact(vector
->the_deno
[j
],D
,d
) ;
456 /* Fonction sol_newparm_edit :
457 * Cette fonction a pour but de placer les informations correspondant
458 * a un Newparm dans la grammaire dans une structure de type PipNewparm. Elle
459 * prend en parametre un pointeur vers une case memoire contenant le
460 * numero de cellule du tableau sol_space a partir de laquelle on doit
461 * commencer la lecture des informations. Elle retourne un pointeur vers
462 * une structure de type PipNewparm contenant les informations de ce Newparm.
463 * Premiere version : Ced. 18 octobre 2001.
464 * 24 octobre 2002 : Premiere version MP.
466 PipNewparm
* sol_newparm_edit(int * i
)
468 PipNewparm
* newparm
, * newparm_new
, * newparm_now
;
470 /* On place p au lieu de lecture. */
471 p
= sol_space
+ (*i
) ;
472 /* On passe le New et le Div pour aller a Form et lire le VECTOR. */
475 newparm
= (PipNewparm
*)malloc(sizeof(PipNewparm
)) ;
477 { fprintf(stderr
, "Memory Overflow.\n") ;
480 newparm
->vector
= sol_vector_edit(i
) ;
481 newparm
->rank
= mpz_get_si(p
->param1
) ;
482 /* On met p a jour pour lire le denominateur (un Val de param2 UN). */
483 p
= sol_space
+ (*i
) ;
484 mpz_init_set(newparm
->deno
,p
->param1
) ;
485 newparm
->next
= NULL
;
487 newparm_now
= newparm
;
489 { fprintf(dump
,"\n(newparm ") ;
490 fprintf(dump
,"%d",newparm
->rank
) ;
491 fprintf(dump
," (div ") ;
492 pip_vector_print(dump
,newparm
->vector
) ;
494 mpz_out_str(dump
,10,newparm
->deno
) ;
498 /* On passe aux elements suivants. */
500 p
= sol_space
+ (*i
) ;
501 while (p
->flags
== New
)
503 newparm_new
= (PipNewparm
*)malloc(sizeof(PipNewparm
)) ;
504 if (newparm_new
== NULL
)
505 { fprintf(stderr
, "Memory Overflow.\n") ;
508 newparm_new
->vector
= sol_vector_edit(i
) ;
509 newparm_new
->rank
= mpz_get_si(p
->param1
) ;
510 p
= sol_space
+ (*i
) ;
511 mpz_init_set(newparm_new
->deno
,p
->param1
) ;
512 newparm_new
->next
= NULL
;
514 newparm_now
->next
= newparm_new
;
515 newparm_now
= newparm_now
->next
;
517 { fprintf(dump
,"\n(newparm ") ;
518 fprintf(dump
,"%d",newparm_new
->rank
) ;
519 fprintf(dump
," (div ") ;
520 pip_vector_print(dump
,newparm_new
->vector
) ;
522 mpz_out_str(dump
,10,newparm_new
->deno
) ;
526 p
= sol_space
+ (*i
) ;
532 /* Fonction sol_list_edit :
533 * Cette fonction a pour but de placer les informations correspondant
534 * a une List dans la grammaire dans une structure de type PipList. Elle
535 * prend en parametre un pointeur vers une case memoire contenant le
536 * numero de cellule du tableau sol_space a partir de laquelle on doit
537 * commencer la lecture des informations. Elle retourne un pointeur vers
538 * une structure de type PipList contenant les informations de cette List.
539 * Premiere version : Ced. 18 octobre 2001.
541 PipList
* sol_list_edit(int * i
, int nb_elements
)
542 { PipList
* list
, * list_new
, * list_now
;
544 /* Pour le premier element. */
545 list
= (PipList
*)malloc(sizeof(PipList
)) ;
547 { fprintf(stderr
, "Memory Overflow.\n") ;
550 list
->vector
= sol_vector_edit(i
) ;
555 { fprintf(dump
,"\n(list ") ;
556 pip_vector_print(dump
,list
->vector
) ;
560 /* Pour les elements suivants. */
561 while (nb_elements
--)
562 { list_new
= (PipList
*)malloc(sizeof(PipList
)) ;
563 if (list_new
== NULL
)
564 { fprintf(stderr
, "Memory Overflow.\n") ;
567 list_new
->vector
= sol_vector_edit(i
) ;
568 list_new
->next
= NULL
;
571 { fprintf(dump
,"\n") ;
572 pip_vector_print(dump
,list_new
->vector
) ;
574 list_now
->next
= list_new
;
575 list_now
= list_now
->next
;
578 fprintf(dump
,"\n)") ;
584 /* Fonction sol_quast_edit :
585 * Cette fonction a pour but de placer les informations de la solution
586 * (qui sont contenues dans le tableau sol_space) dans une structure de
587 * type PipQuast en vue d'une utilisation directe de la solution par une
588 * application exterieure. Elle prend en parametre un pointeur vers une
589 * case memoire contenant le numero de cellule du tableau sol_space
590 * a partir de laquelle on doit commencer la lecture des informations. Elle
591 * recoit aussi l'adresse du PipQuast qui l'a appelle (pour le champ father).
592 * Elle retourne un pointeur vers une structure de type PipQuast qui
593 * contient toutes les informations sur la solution (sous forme d'arbre).
594 * Remarques : cette fonction lit les informations comme elles doivent
595 * se presenter a la fin du traitement. Elle respecte scrupuleusement
596 * la grammaire attendue et n'accepte de passer des cellules a Free
597 * qu'entre une des trois grandes formes (if, list ou suite de newparm).
598 * 20 juillet 2001 : Premiere version, Ced.
599 * 31 juillet 2001 : Ajout du traitement de l'option verbose = code*2 :0(
600 * 18 octobre 2001 : Grands changements dus a l'eclatement de la structure
601 * PipVector en PipVector, PipNewparm et PipList, et
602 * eclatement de la fonction avec sol_newparm_edit et
604 * 24 octobre 2002 : Premiere version MP.
606 PipQuast
* sol_quast_edit(int * i
, PipQuast
* father
)
609 PipQuast
* solution
;
610 PipList
* list_new
, * list_now
;
611 PipNewparm
* newparm_new
, * newparm_now
;
613 /* On place p au lieu de lecture. */
614 p
= sol_space
+ (*i
) ;
615 /* En cas d'utilisation de l'option de simplification, une plage de
616 * structures S peut avoir les flags a Free. On doit alors les passer.
618 while (p
->flags
== Free
)
623 solution
= (PipQuast
*)malloc(sizeof(PipQuast
)) ;
624 if (solution
== NULL
)
625 { fprintf(stderr
, "Memory Overflow.\n") ;
628 solution
->newparm
= NULL
;
629 solution
->list
= NULL
;
630 solution
->condition
= NULL
;
631 solution
->next_then
= NULL
;
632 solution
->next_else
= NULL
;
633 solution
->father
= father
;
635 /* On peut commencer par une chaine de nouveaux parametres... */
637 { solution
->newparm
= sol_newparm_edit(i
) ;
638 p
= sol_space
+ (*i
) ;
641 /* ...ensuite soit par une liste (vide ou non) soit par un if. */
642 (*i
)++ ; /* Factorise de List, Nil et If. */
644 { case List
: if ((nb_elements
= mpz_get_si(p
->param1
)) != 0)
645 solution
->list
= sol_list_edit(i
,nb_elements
) ;
647 case Nil
: if (verbose
)
648 fprintf(dump
,"\n()") ;
650 case If
: solution
->condition
= sol_vector_edit(i
) ;
652 { fprintf(dump
,"\n(if ") ;
653 pip_vector_print(dump
,solution
->condition
) ;
655 solution
->next_then
= sol_quast_edit(i
,solution
) ;
656 solution
->next_else
= sol_quast_edit(i
,solution
) ;
658 fprintf(dump
,"\n)") ;
660 default : fprintf(stderr
,"\nAie !!! Flag %d inattendu.\n",p
->flags
) ;
662 fprintf(dump
,"\nAie !!! Flag %d inattendu.\n",p
->flags
) ;