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 *
25 *****************************************************************************/
33 /* The routines in this file are used to build a Gomory cut from
34 a non-integral row of the problem tableau */
36 extern long int cross_product
, limit
;
38 extern int deepest_cut
;
42 /* mod(x,y) computes the remainder of x when divided by y. The difference
43 with x%y is that the result is guaranteed to be positive, which is not
44 always true for x%y. This function is replaced by mpz_fdiv_r for MP. */
46 #if !defined(LINEAR_VALUE_IS_MP)
56 /* this routine is useless at present */
58 int non_borne(tp
, nvar
, D
, bigparm
)
63 for(i
= 0; i
<nvar
; i
++)
66 {if(ff
& Unit
)return(Pip_True
);
67 if(Index(tp
, i
, bigparm
) != D
) return(Pip_True
);
73 /* This routine solve for z in the equation z.y = x (mod delta), provided
74 y and delta are mutually prime. Remember that for multiple precision
75 operation, the responsibility of creating and destroying <<z>> is the
78 void bezout(Entier x
, Entier y
, Entier delta
, Entier
*z
){
79 Entier a
, b
, c
, d
, e
, f
, u
, v
, q
, r
;
80 #if defined(LINEAR_VALUE_IS_MP)
81 mpz_init(a
); mpz_init(b
); mpz_init(c
); mpz_init(d
);
82 mpz_init(e
); mpz_init(f
); mpz_init(u
); mpz_init(v
);
83 mpz_init(q
); mpz_init(r
);
84 mpz_set_ui(a
, 1); mpz_set_ui(b
, 0); mpz_set_ui(c
, 0);
85 mpz_set_ui(d
, 1); mpz_set(u
, y
); mpz_set(v
, delta
);
87 a
= 1; b
= 0; c
= 0; d
= 1;
91 #if defined(LINEAR_VALUE_IS_MP)
92 mpz_fdiv_qr(q
, r
, u
, v
);
93 if(mpz_cmp_ui(r
, 0) == 0) break;
118 #if defined(LINEAR_VALUE_IS_MP)
119 if(mpz_cmp_ui(v
, 1) != 0)
123 mpz_mod(*z
, a
, delta
);
125 mpz_clear(a
); mpz_clear(b
); mpz_clear(c
); mpz_clear(d
);
126 mpz_clear(e
); mpz_clear(f
); mpz_clear(u
); mpz_clear(v
);
127 mpz_clear(q
); mpz_clear(r
);
130 if(v
!= 1) *z
= 0; /* y and delta are not mutually prime */
131 else *z
= mod(c
*x
, delta
);
137 /* integrer(.....) add a cut to the problem tableau, or return 0 when an
138 integral solution has been found, or -1 when no integral solution
141 Since integrer may add rows and columns to the problem tableau, its
142 arguments are pointers rather than values. If a cut is constructed,
143 ni increases by 1. If the cut is parametric, nparm increases by 1 and
147 int integrer(Tableau
**ptp
, Tableau
**pcontext
,
148 int *pnvar
, int *pnparm
, int *pni
, int *pnc
, int bigparm
)
149 {int ncol
= *pnvar
+*pnparm
+1;
150 int nligne
= *pnvar
+ *pni
;
155 Entier coupure
[MAXCOL
];
158 int ok_var
, ok_const
, ok_parm
;
159 Entier discrp
[MAXPARM
], discrm
[MAXPARM
];
163 Entier t
, delta
, tau
, lambda
;
165 if (ncol
>= MAXCOL
) {
166 fprintf(stderr
, "Too many variables: %d\n", ncol
);
170 #if defined(LINEAR_VALUE_IS_MP)
171 for(i
=0; i
<=ncol
; i
++)
172 mpz_init(coupure
[i
]);
174 for(i
=0; i
<=nparm
+1; i
++){
179 mpz_init(x
); mpz_init(d
); mpz_init(D
);
180 mpz_init(t
); mpz_init(delta
); mpz_init(tau
); mpz_init(lambda
);
184 /* search for a non-integral row */
185 for(i
= 0; i
<nvar
; i
++) {
186 #if defined(LINEAR_VALUE_IS_MP)
187 mpz_set(D
, Denom(*ptp
, i
));
188 if(mpz_cmp_ui(D
, 1) == 0) continue;
193 /* If the common denominator of the row is 1
194 the row is integral */
196 if(ff
& Unit
)continue;
197 /* If the row is a Unit, it is integral */
199 /* Here a portential candidate has been found.
200 Build the cut by reducing each coefficient
201 modulo D, the common denominator */
203 for(j
= 0; j
<nvar
; j
++) {
204 #if defined(LINEAR_VALUE_IS_MP)
205 mpz_fdiv_r(x
, Index(*ptp
, i
, j
), D
);
206 mpz_set(coupure
[j
], x
);
208 x
= coupure
[j
] = mod(Index(*ptp
, i
, j
), D
);
213 /* Done for the coefficient of the variables. */
215 #if defined(LINEAR_VALUE_IS_MP)
216 mpz_neg(x
, Index(*ptp
, i
, nvar
));
219 mpz_set(coupure
[nvar
], x
);
220 ok_const
= mpz_cmp_ui(x
, 0);
222 x
= coupure
[nvar
] = - mod(-Index(*ptp
, i
, nvar
), D
);
225 /* This is the constant term */
227 for(j
= nvar
+1; j
<ncol
; j
++) {
228 /* We assume that the big parameter is divisible by any number. */
230 entier_set_si(coupure
[j
], 0);
233 entier_oppose(x
, Index(*ptp
, i
, j
));
234 entier_pmodulus(x
, x
, D
);
235 entier_oppose(coupure
[j
], x
);
236 if (entier_notzero_p(coupure
[j
]))
239 /* These are the parametric terms */
241 #if defined(LINEAR_VALUE_IS_MP)
242 mpz_set(coupure
[ncol
], D
);
244 coupure
[ncol
] = D
; /* Just in case */
247 /* The question now is whether the cut is valid. The answer is given
248 by the following decision table:
250 ok_var ok_parm ok_const
252 F F F (a) continue, integral row
253 F F T (b) return -1, no solution
255 (c) if the <<constant>> part is not divisible
256 by D then bottom else ....
258 T F F (a) continue, integral row
259 T F T (d) constant cut
266 if(!ok_parm
&& !ok_const
) continue;
268 if(ok_var
) { /* case (d) */
269 if(nligne
>= (*ptp
)->height
) {
271 #if defined(LINEAR_VALUE_IS_MP)
272 d
= mpz_sizeinbase(D
, 2);
277 *ptp
= expanser(*ptp
, nvar
, ni
, ncol
, 0, dth
, 0);
279 /* Find the deepest cut*/
281 #if defined(LINEAR_VALUE_IS_MP)
282 mpz_neg(t
, coupure
[nvar
]);
283 mpz_gcd(delta
, t
, D
);
284 mpz_divexact(tau
, t
, delta
);
285 mpz_divexact(d
, D
, delta
);
287 bezout(t
, tau
, d
, &lambda
);
288 mpz_gcd(t
, lambda
, D
);
289 while(mpz_cmp_ui(t
, 1) != 0){
290 mpz_add(lambda
, lambda
, d
);
291 mpz_gcd(t
, lambda
, D
);
293 for(j
=0; j
<nvar
; j
++){
294 mpz_mul(t
, lambda
, coupure
[j
]);
295 mpz_fdiv_r(coupure
[j
], t
, D
);
297 mpz_mul(t
, coupure
[nvar
], lambda
);
300 mpz_neg(coupure
[nvar
], t
);
306 bezout(d
-1, tau
, d
, &lambda
);
307 while(pgcd(lambda
, D
) != 1)
309 for(j
=0; j
<nvar
; j
++)
310 coupure
[j
] = mod(lambda
*coupure
[j
], D
);
311 coupure
[nvar
] = -mod(-lambda
*coupure
[nvar
], D
);
314 /* The cut has a negative <<constant>> part */
315 Flag(*ptp
, nligne
) = Minus
;
316 #if defined(LINEAR_VALUE_IS_MP)
317 mpz_set(Denom(*ptp
, nligne
), D
);
319 Denom(*ptp
, nligne
) = D
;
322 for(j
= 0; j
<ncol
; j
++)
323 #if defined(LINEAR_VALUE_IS_MP)
324 mpz_set(Index(*ptp
, nligne
, j
), coupure
[j
]);
326 Index(*ptp
, nligne
, j
) = coupure
[j
];
328 /* A new row has been added to the problem tableau. */
331 fprintf(dump
, "just cut ");
333 fprintf(dump
, "Bezout multiplier ");
334 #if defined(LINEAR_VALUE_IS_MP)
335 mpz_out_str(dump
, 10, lambda
);
337 fprintf(dump
, FORMAT
, lambda
);
342 for(i
=0; i
<nvar
; i
++){
343 if(Flag(*ptp
, i
) & Unit
){
344 #if defined(LINEAR_VALUE_IS_MP)
347 sprintf(compose
+k
, "0 ");
352 #if defined(LINEAR_VALUE_IS_MP)
353 k
+= mpz_out_str(dump
, 10, Index(*ptp
, i
, nvar
));
356 k
+= mpz_out_str(dump
, 10, Denom(*ptp
, i
));
364 sprintf(compose
+k
, FORMAT
, Index(*ptp
, i
, nvar
));
366 sprintf(compose
+k
, "/");
368 sprintf(compose
+k
, FORMAT
, Denom(*ptp
, i
));
370 sprintf(compose
+k
, " ");
373 fputs(compose
, dump
);
380 fputs(compose
, dump
);
383 if(verbose
> 2) tab_display(*ptp
, dump
);
386 else { /* case (b) */
390 /* In case (e), one has to introduce a new parameter and
391 introduce its defining inequalities into the context.
393 Let the cut be sum_{j=0}^{nvar-1} c_j x_j + c_{nvar} + (2)
394 sum_{j=0}^{nparm-1} c_{nvar + 1 + j} p_j >= 0. */
397 if(nparm
>= MAXPARM
) {
398 fprintf(stderr
, "Too much parameters : %d\n", *pnparm
);
401 /* Build the definition of the new parameter into the solution :
402 p_{nparm} = -(sum_{j=0}^{nparm-1} c_{nvar + 1 + j} p_j
404 The minus sign is there to compensate the one in (1) */
409 for(j
= 0; j
<nparm
; j
++)
410 #if defined(LINEAR_VALUE_IS_MP)
411 { mpz_neg(x
, coupure
[j
+nvar
+1]);
414 mpz_neg(x
, coupure
[*pnvar
]);
417 sol_val(-coupure
[j
+nvar
+1], UN
); /* loop body. */
418 sol_val(-coupure
[*pnvar
], UN
);
420 sol_val(D
, UN
); /* The divisor */
422 /* The value of the new parameter is specified by applying the definition of
423 Euclidean division to (3) :
425 0<= - sum_{j=0}^{nparm-1} c_{nvar+1+j} p_j - c_{nvar} - D * p_{nparm} < D (4)
427 This formula gives two inequalities which are stored in the context */
429 for(j
= 0; j
<nparm
; j
++) {
430 #if defined(LINEAR_VALUE_IS_MP)
431 mpz_set(x
, coupure
[j
+nvar
+1]);
432 mpz_neg(discrp
[j
], x
);
433 mpz_set(discrm
[j
], x
);
435 x
= coupure
[j
+nvar
+1];
440 #if defined(LINEAR_VALUE_IS_MP)
441 mpz_neg(discrp
[nparm
], D
);
442 mpz_set(discrm
[nparm
], D
);
443 mpz_set(x
, coupure
[nvar
]);
444 mpz_neg(discrp
[nparm
+1], x
);
446 mpz_add(discrm
[nparm
+1], x
, D
);
451 discrp
[(nparm
)+1] = -x
;
452 discrm
[(nparm
)+1] = x
+ D
-1;
454 if (nc
+2 > (*pcontext
)->height
|| nparm
+1+1 > (*pcontext
)->width
) {
456 #if defined(LINEAR_VALUE_IS_MP)
457 dcw
= mpz_sizeinbase(D
, 2);
461 dch
= 2 * dcw
+ *pni
;
462 *pcontext
= expanser(*pcontext
, 0, nc
, nparm
+1, 0, dch
, dcw
);
464 /* Flag(*pcontext, *pnc) = 0; Probably useless see line A */
466 /* Since a new parameter is to be added, the constant term has to be moved
467 right and a zero has to be inserted in all rows of the old context */
469 for(k
= 0; k
< nc
; k
++) {
470 #if defined(LINEAR_VALUE_IS_MP)
471 mpz_set(Index(*pcontext
, k
, nparm
+1), Index(*pcontext
, k
, nparm
));
472 mpz_set_ui(Index(*pcontext
, k
, nparm
), 0);
474 Index(*pcontext
, k
, nparm
+1) = Index(*pcontext
, k
, nparm
);
475 Index(*pcontext
, k
, nparm
) = 0;
478 /* Now, insert the new rows */
480 for(j
= 0; j
<= nparm
+1; j
++) {
481 #if defined(LINEAR_VALUE_IS_MP)
482 mpz_set(Index(*pcontext
, nc
, j
), discrp
[j
]);
483 mpz_set(Index(*pcontext
, nc
+1, j
), discrm
[j
]);
485 Index(*pcontext
, nc
, j
) = discrp
[j
];
486 Index(*pcontext
, nc
+1, j
) = discrm
[j
];
489 Flag(*pcontext
, nc
) = Unknown
; /* A */
490 Flag(*pcontext
, nc
+1) = Unknown
;
491 #if defined(LINEAR_VALUE_IS_MP)
492 mpz_set(Denom(*pcontext
, nc
), UN
);
493 mpz_set(Denom(*pcontext
, nc
+1), UN
);
495 Denom(*pcontext
, nc
) = UN
;
496 Denom(*pcontext
, nc
+1) = UN
;
501 fprintf(dump
, "enlarged context %d x %d\n", *pnparm
, *pnc
);
504 /* end of the construction of the new parameter */
507 if(nligne
>= (*ptp
)->height
|| ncol
>= (*ptp
)->width
) {
509 #if defined(LINEAR_VALUE_IS_MP)
510 d
= mpz_sizeinbase(D
, 2);
516 *ptp
= expanser(*ptp
, nvar
, ni
, ncol
, 0, dth
, dtw
);
518 /* Zeroing out the new column seems to be useless
519 since <<expanser>> does it anyway */
521 /* The cut has a negative <<constant>> part */
522 Flag(*ptp
, nligne
) = Minus
;
523 #if defined(LINEAR_VALUE_IS_MP)
524 mpz_set(Denom(*ptp
, nligne
), D
);
526 Denom(*ptp
, nligne
) = D
;
529 for(j
= 0; j
<ncol
+1; j
++)
530 #if defined(LINEAR_VALUE_IS_MP)
531 mpz_set(Index(*ptp
, nligne
, j
), coupure
[j
]);
533 Index(*ptp
, nligne
, j
) = coupure
[j
];
535 /* A new row has been added to the problem tableau. */
539 /* The solution is integral. */
542 for(i
=0; i
<= ncol
; i
++)
543 entier_clear(coupure
[i
]);
544 for(i
=0; i
<= nparm
+1; i
++){
545 entier_clear(discrp
[i
]);
546 entier_clear(discrm
[i
]);
548 entier_clear(x
); entier_clear(d
); entier_clear(D
);
549 entier_clear(t
); entier_clear(tau
); entier_clear(lambda
); entier_clear(delta
);