1 /********************************************************/
2 /* Part of MultiPrecision PIP port by Zbigniew Chamski */
3 /* and Paul Feautrier. */
4 /* Based on straight PIP E.1 version 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 /********************************************************/
20 #include <piplib/piplib.h>
22 #define max(x,y) ((x) > (y)? (x) : (y))
24 extern long int cross_product
, limit
;
27 extern int profondeur
;
29 extern int compa_count
;
31 /* The function llog is replaced by mpz_sizeinbase. */
33 int chercher(Tableau
*p
, int masque
, int n
)
36 if(p
->row
[i
].flags
& masque
) break;
40 /* il est convenu que traiter ne doit modifier ni le tableau, ni le contexte;
41 le tableau peut grandir en cas de coupure (+1 en hauteur et +1 en largeur
42 si nparm != 0) et en cas de partage (+1 en hauteur)
43 (seulement si nparm != 0).
44 le contexte peut grandir en cas de coupure (+2 en hauteur et +1 en largeur)
45 (seulement si nparm !=0) et en cas de partage (+1 en hauteur)(nparm !=0).
46 On estime le nombre de coupures a llog(D) et le nombre de partages a
50 Tableau
*expanser(Tableau
*tp
, int virt
, int reel
, int ncol
,
51 int off
, int dh
, int dw
)
57 if(tp
== NULL
) return(NULL
);
58 rp
= tab_alloc(reel
+dh
, ncol
+dw
, virt
);
60 mpz_set(rp
->determinant
, tp
->determinant
);
61 pq
= (Entier
*) & (rp
->row
[virt
+reel
+dh
]);
62 for(i
= off
; i
<virt
+ reel
; i
++)
63 {ff
= Flag(rp
, i
) = Flag(tp
, i
-off
);
64 mpz_set(Denom(rp
, i
), Denom(tp
, i
-off
));
65 if(ff
& Unit
) rp
->row
[i
].objet
.unit
= tp
->row
[i
-off
].objet
.unit
;
67 rp
->row
[i
].objet
.val
= pq
;
69 pp
= tp
->row
[i
-off
].objet
.val
;
70 qq
= rp
->row
[i
].objet
.val
;
71 for(j
= 0; j
<ncol
; j
++) mpz_set(*qq
++, *pp
++);
77 int exam_coef(Tableau
*tp
, int nvar
, int ncol
, int bigparm
)
82 for(i
= 0; i
<tp
->height
; i
++)
87 x
= mpz_sgn(Index(tp
,i
, bigparm
));
97 p
= &(tp
->row
[i
].objet
.val
[nvar
+1]);
98 for(j
= nvar
+1; j
<ncol
; j
++){
101 else if (x
>0) fff
= Plus
;
103 if(fff
!= Zero
&& fff
!= ff
)
104 if(ff
== Zero
) ff
= fff
;
109 /* bug de'tecte' par [paf], 16/2/93 !
110 Si tous les coefficients des parame`tres sont ne'gatifs
111 et si le terme constant est nul, le signe est inconnu!!
112 On traite donc spe'cialement le terme constant. */
113 x
= mpz_sgn(Index(tp
, i
, nvar
));
115 else if(x
>0) fff
= Plus
;
117 /* ici on a le signe du terme constant */
119 /* le signe est inconnu si les coefficients sont positifs et
120 le terme constant ne'gatif */
121 case Plus
: if(fff
== Minus
) ff
= Unknown
; break;
122 /* si les coefficients sont tous nuls, le signe est celui
124 case Zero
: ff
= fff
; break;
125 /* le signe est inconnu si les coefficients sont ne'gatifs,
126 sauf si le terme constant est ‚galement n‚gatif. */
127 case Minus
: if(fff
!= Minus
) ff
= Unknown
; break;
128 /* enfin, il n'y a rien a` dire si le signe des coefficients est inconnu */
131 if(ff
== Minus
) return(i
);
137 void compa_test(Tableau
*tp
, Tableau
*context
,
138 int ni
, int nvar
, int nparm
, int nc
)
140 Entier discr
[MAXPARM
];
143 int cPlus
, cMinus
, isCritic
;
145 Tableau
*tPlus
, *tMinus
;
147 struct high_water_mark q
;
148 if(nparm
== 0) return;
149 if(nparm
>= MAXPARM
) {
150 fprintf(stdout
, "Too much parameters : %d\n", nparm
);
154 for(i
=0; i
<=nparm
; i
++)
157 for(i
= 0; i
<ni
+ nvar
; i
++)
159 if(ff
& (Critic
| Unknown
))
161 for(j
= 0; j
<nvar
; j
++) if(mpz_sgn(Index(tp
, i
, j
)) > 0)
166 for(j
= 0; j
<nparm
; j
++)mpz_set(discr
[j
], Index(tp
, i
, j
+nvar
+1));
167 mpz_set(discr
[nparm
], Index(tp
, i
, nvar
));
168 mpz_sub_ui(discr
[nparm
], discr
[nparm
], (isCritic
? 0 : 1));
169 tPlus
= expanser(context
, nparm
, nc
, nparm
+1, nparm
, 1, 0);
170 Flag(tPlus
, nparm
+nc
) = Unknown
;
171 for(j
= 0;j
<=nparm
; j
++)mpz_set(Index(tPlus
, nparm
+nc
, j
),discr
[j
]);
172 mpz_set(Denom(tPlus
, nparm
+nc
), UN
);
174 traiter(tPlus
, NULL
, True
, nparm
, 0, nc
+1, 0, -1);
175 cPlus
= is_not_Nil(p
);
177 fprintf(dump
, "\nThe positive case has been found ");
178 fprintf(dump
, cPlus
? "possible\n": "impossible\n");
183 for(j
= 0; j
<nparm
+1; j
++) mpz_neg(discr
[j
], discr
[j
]);
184 mpz_sub_ui(discr
[nparm
], discr
[nparm
], (isCritic
? 1 : 2));
185 tMinus
= expanser(context
, nparm
, nc
, nparm
+1, nparm
, 1, 0);
186 Flag(tMinus
, nparm
+nc
) = Unknown
;
187 for(j
=0;j
<=nparm
; j
++)mpz_set(Index(tMinus
, nparm
+nc
, j
),discr
[j
]);
188 mpz_set(Denom(tMinus
, nparm
+nc
), UN
);
189 traiter(tMinus
, NULL
, True
, nparm
, 0, nc
+1, 0, -1);
190 cMinus
= is_not_Nil(p
);
192 fprintf(dump
, "\nThe negative case has been found ");
193 fprintf(dump
, cMinus
? "possible\n": "impossible\n");
197 if (cPlus
&& cMinus
) {
198 Flag(tp
,i
) = isCritic
? Critic
: Unknown
;
205 Flag(tp
,i
) = cPlus
? Plus
: Zero
;
211 for(i
=0; i
<=nparm
; i
++)
217 Entier
*valeur(Tableau
*tp
, int i
, int j
)
219 if(Flag(tp
, i
) & Unit
)
220 return(tp
->row
[i
].objet
.unit
== j
? &Denom(tp
,i
) : &ZERO
);
221 else return(&Index(tp
, i
, j
));
224 void solution(Tableau
*tp
, int nvar
, int nparm
)
226 int ncol
= nvar
+ nparm
+ 1;
230 for(i
= 0; i
<nvar
; i
++)
232 for(j
= nvar
+1; j
<ncol
; j
++)
233 sol_val(*valeur(tp
, i
, j
), Denom(tp
,i
));
234 sol_val(*valeur(tp
, i
, nvar
), Denom(tp
,i
));
238 int choisir_piv(Tableau
*tp
, int pivi
, int nvar
, int nligne
)
241 Entier pivot
, foo
, x
, y
;
245 mpz_init(pivot
); mpz_init(foo
); mpz_init(x
); mpz_init(y
);
247 for(j
= 0; j
<nvar
; j
++){
248 mpz_set(foo
, Index(tp
, pivi
, j
));
249 if(mpz_sgn(foo
) <= 0) continue;
255 for(k
= 0; k
<nligne
; k
++){
256 mpz_mul(x
, pivot
, *valeur(tp
, k
, j
));
257 mpz_mul(y
, *valeur(tp
, k
, pivj
), foo
);
268 mpz_clear(pivot
); mpz_clear(foo
); mpz_clear(x
); mpz_clear(y
);
272 int pivoter(Tableau
*tp
, int pivi
, int nvar
,
273 int nparm
, int ni
, int iq
)
275 int ncol
= nvar
+ nparm
+ 1;
276 int nligne
= nvar
+ ni
;
278 Entier x
, y
, d
, gcd
, u
, dpiv
;
280 Entier pivot
, foo
, z
;
281 Entier ppivot
, dppiv
;
282 Entier
new[MAXCOL
], *p
, *q
;
288 fprintf(stdout
, "Too much variables\n");
291 if(0 > pivi
|| pivi
>= nligne
|| Flag(tp
, pivi
) == Unit
) {
292 fprintf(stdout
, "Syserr : pivoter : wrong pivot row\n");
296 pivj
= choisir_piv(tp
, pivi
, nvar
, nligne
);
297 if(pivj
< 0) return(-1);
299 fprintf(stdout
, "Syserr : pivoter : wrong pivot\n");
303 mpz_init(x
); mpz_init(y
); mpz_init(d
);
304 mpz_init(gcd
); mpz_init(u
); mpz_init(dpiv
);
305 mpz_init(lpiv
); mpz_init(pivot
); mpz_init(foo
);
306 mpz_init(z
); mpz_init(ppivot
); mpz_init(dppiv
);
308 for(i
=0; i
<ncol
; i
++)
311 mpz_set(pivot
, Index(tp
, pivi
, pivj
));
312 mpz_set(dpiv
, Denom(tp
, pivi
));
313 mpz_gcd(d
, pivot
, dpiv
);
314 mpz_divexact(ppivot
, pivot
, d
);
315 mpz_divexact(dppiv
, dpiv
, d
);
317 fprintf(dump
, "Pivot ");
318 mpz_out_str(dump
, 10, ppivot
);
320 mpz_out_str(dump
, 10, dppiv
);
322 fprintf(dump
, "%d x %d\n", pivi
, pivj
);
324 mpz_fdiv_qr(x
, y
, tp
->determinant
, dppiv
);
327 fprintf(stdout
, "Computation error\n");
328 if(verbose
>0) fflush(dump
);
331 mpz_mul(tp
->determinant
, x
, ppivot
);
334 fprintf(dump
, "determinant ");
335 mpz_out_str(dump
, 10, tp
->determinant
);
340 for(j
= 0; j
<ncol
; j
++)
342 mpz_set(new[j
], dpiv
);
344 mpz_neg(new[j
], Index(tp
, pivi
, j
));
345 for(k
= 0; k
<nligne
; k
++){
346 if(Flag(tp
,k
) & Unit
)continue;
347 if(k
== pivi
)continue;
348 /* foo = Index(tp, k, pivj) */
349 mpz_set(foo
, Index(tp
, k
, pivj
));
350 /* d = gcd(pivot, foo); */
351 mpz_gcd(d
, pivot
, foo
);
352 /* lpiv = pivot/d; */
353 mpz_divexact(lpiv
, pivot
, d
);
355 mpz_divexact(foo
, foo
, d
);
356 /* d = Denom(tp,k); */
357 mpz_set(d
, Denom(tp
,k
));
358 mpz_mul(gcd
, lpiv
, d
);
359 mpz_set(Denom(tp
, k
), gcd
);
360 p
= tp
->row
[k
].objet
.val
;
361 q
= tp
->row
[pivi
].objet
.val
;
362 for(j
= 0; j
<ncol
; j
++){
364 mpz_mul(z
, dpiv
, foo
);
366 mpz_mul(z
, *p
, lpiv
);
374 if(mpz_cmp_ui(gcd
, 1) != 0)
375 mpz_gcd(gcd
, gcd
, z
);
377 if(mpz_cmp_ui(gcd
, 1) != 0){
378 p
= tp
->row
[k
].objet
.val
;
379 for(j
= 0; j
<ncol
; j
++){
380 mpz_divexact(*p
, *p
, gcd
);
384 mpz_divexact(Denom(tp
,k
), Denom(tp
,k
), gcd
);
386 p
= tp
->row
[pivi
].objet
.val
;
387 for(k
= 0; k
<nligne
; k
++)
388 if((Flag(tp
, k
) & Unit
) && tp
->row
[k
].objet
.unit
== pivj
) break;
390 tp
->row
[k
].objet
.val
= p
;
391 for(j
= 0; j
<ncol
; j
++)
393 mpz_set(*p
++, new[j
]);
394 mpz_set(Denom(tp
, k
), pivot
);
395 Flag(tp
, pivi
) = Unit
| Zero
;
396 mpz_set(Denom(tp
, pivi
), UN
);
397 tp
->row
[pivi
].objet
.unit
= pivj
;
399 for(k
= 0; k
<nligne
; k
++){
401 if(ff
& Unit
) continue;
402 sgn_x
= mpz_sgn(Index(tp
, k
, pivj
));
403 if(sgn_x
< 0) fff
= Minus
;
404 else if(sgn_x
== 0) fff
= Zero
;
406 if(fff
!= Zero
&& fff
!= ff
)
407 if(ff
== Zero
) ff
= (fff
== Minus
? Unknown
: fff
);
413 fprintf(dump
, "just pivoted\n");
414 tab_display(tp
, dump
);
417 mpz_clear(x
); mpz_clear(y
); mpz_clear(d
); mpz_clear(gcd
);
418 mpz_clear(u
); mpz_clear(dpiv
); mpz_clear(lpiv
);
419 mpz_clear(pivot
); mpz_clear(foo
); mpz_clear(z
);
420 mpz_clear(ppivot
); mpz_clear(dppiv
);
422 for(i
=0; i
<ncol
; i
++)
428 /* dans cette version, "traiter" modifie ineq; par contre
429 le contexte est immediatement recopie' */
431 void traiter(tp
, ctxt
, iq
, nvar
, nparm
, ni
, nc
, bigparm
)
433 int iq
, nvar
, nparm
, ni
, nc
, bigparm
;
437 int pivi
, nligne
, ncol
;
438 struct high_water_mark x
;
441 double s
, t
, d
, smax
;
445 Entier discr
[MAXPARM
];
446 for(i
=0; i
<=MAXPARM
; i
++)
449 dcw
= mpz_sizeinbase(tp
->determinant
, 2);
454 context
= expanser(ctxt
, 0, nc
, nparm
+1, 0, dch
, dcw
);
456 sort the rows in increasing order of the largest coefficient
460 for(i
=nvar
; i
<nligne
; i
++){
461 if(Flag(tp
,i
) & Unit
) continue;
463 d
= mpz_get_d(Denom(tp
,i
));
464 for(j
=0; j
<nvar
; j
++){
465 t
= mpz_get_d(Index(tp
,i
,j
))/d
;
472 for(i
=nvar
; i
<nligne
; i
++){
473 if(Flag(tp
,i
) & Unit
) continue;
476 for(j
=i
; j
<nligne
; j
++){
477 if(Flag(tp
,j
) & Unit
) continue;
478 if(tp
->row
[j
].size
< s
){
484 temp
= tp
->row
[pivi
];
485 tp
->row
[pivi
] = tp
->row
[i
];
492 fprintf(dump
, "just sorted\n");
493 tab_display(tp
, dump
);
498 nligne
= nvar
+ni
; ncol
= nvar
+nparm
+1;
499 if(nligne
> tp
->height
|| ncol
> tp
->width
) {
500 fprintf(stdout
, "Syserr : traiter : tableau too small\n");
503 pivi
= chercher(tp
, Minus
, nligne
);
504 if(pivi
< nligne
) goto pirouette
; /* There is a negative row */
506 pivi
= exam_coef(tp
, nvar
, ncol
, bigparm
);
509 fprintf(dump
, "coefs examined\n");
510 tab_display(tp
, dump
);
514 if(pivi
< nligne
) goto pirouette
;
515 /* There is a row whose coefficients are negative */
516 compa_test(tp
, context
, ni
, nvar
, nparm
, nc
);
518 fprintf(dump
, "compatibility tested\n");
519 tab_display(tp
, dump
);
523 pivi
= chercher(tp
, Minus
, nligne
);
524 if(pivi
< nligne
) goto pirouette
;
525 /* The compatibility test has found a negative row */
526 pivi
= chercher(tp
, Critic
, nligne
);
527 if(pivi
>= nligne
)pivi
= chercher(tp
, Unknown
, nligne
);
528 /* Here, the problem tree splits */
532 struct high_water_mark q
;
533 if(nc
>= context
->height
) {
534 dcw
= mpz_sizeinbase(context
->determinant
,2);
536 context
= expanser(context
, 0, nc
, nparm
+1, 0, dch
, dcw
);
538 if(nparm
>= MAXPARM
) {
539 fprintf(stdout
, "Too much parameters : %d\n", nparm
);
544 fprintf(stdout
,"profondeur %d %lx\n", profondeur
, q
.top
);
545 ntp
= expanser(tp
, nvar
, ni
, ncol
, 0, 0, 0);
549 mpz_init_set_ui(com_dem
, 0);
550 for(j
= 0; j
<nparm
; j
++) {
551 mpz_set(discr
[j
], Index(tp
, pivi
, j
+ nvar
+1));
552 mpz_gcd(com_dem
, com_dem
, discr
[j
]);
554 mpz_set(discr
[nparm
], Index(tp
, pivi
, nvar
));
555 mpz_gcd(com_dem
, com_dem
, discr
[nparm
]);
556 for(j
= 0; j
<=nparm
; j
++) {
557 mpz_divexact(discr
[j
], discr
[j
], com_dem
);
558 mpz_set(Index(context
, nc
, j
), discr
[j
]);
559 sol_val(discr
[j
], UN
);
562 Flag(context
, nc
) = Unknown
;
563 mpz_set(Denom(context
, nc
), UN
);
564 Flag(ntp
, pivi
) = Plus
;
567 if(verbose
> 0) fflush(dump
);
568 traiter(ntp
, context
, iq
, nvar
, nparm
, ni
, nc
+1, bigparm
);
572 fprintf(stdout
, "descente %d %lx\n", profondeur
, tab_hwm().top
);
573 for(j
= 0; j
<nparm
; j
++)
574 mpz_neg(Index(context
, nc
, j
), Index(context
, nc
, j
));
575 mpz_add_ui(Index(context
, nc
, nparm
), Index(context
, nc
, nparm
), 1);
576 mpz_neg(Index(context
, nc
, nparm
), Index(context
, nc
, nparm
));
577 Flag(tp
, pivi
) = Minus
;
578 mpz_set(Denom(context
, nc
), UN
);
582 /* Here, all rows are positive. Do we need an integral solution? */
584 solution(tp
, nvar
, nparm
);
588 pivi
= integrer(&tp
, &context
, &nvar
, &nparm
, &ni
, &nc
);
589 if(pivi
> 0) goto pirouette
;
590 /* A cut has been inserted and is always negative */
591 /* Here, either there is an integral solution, */
592 if(pivi
== 0) solution(tp
, nvar
, nparm
);
593 /* or no solution exists */
597 /* Here, a negative row has been found. The call to <<pivoter>> executes
601 if(pivoter(tp
, pivi
, nvar
, nparm
, ni
, iq
) < 0) {
606 /* Danger : a premature return would induce memory leaks */
608 for(i
=0; i
<MAXPARM
; i
++)