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 *****************************************************************************/
32 /* The routines in this file are used to build a Gomory cut from
33 a non-integral row of the problem tableau */
35 extern long int cross_product
, limit
;
37 extern int deepest_cut
;
41 /* mod(x,y) computes the remainder of x when divided by y. The difference
42 with x%y is that the result is guaranteed to be positive, which is not
43 always true for x%y. This function is replaced by mpz_fdiv_r for MP. */
45 #if !defined(LINEAR_VALUE_IS_MP)
55 /* this routine is useless at present */
57 int non_borne(tp
, nvar
, D
, bigparm
)
62 for(i
= 0; i
<nvar
; i
++)
65 {if(ff
& Unit
)return(Pip_True
);
66 if(Index(tp
, i
, bigparm
) != D
) return(Pip_True
);
72 /* This routine solve for z in the equation z.y = x (mod delta), provided
73 y and delta are mutually prime. Remember that for multiple precision
74 operation, the responsibility of creating and destroying <<z>> is the
77 void bezout(Entier x
, Entier y
, Entier delta
, Entier
*z
){
78 Entier a
, b
, c
, d
, e
, f
, u
, v
, q
, r
;
79 #if defined(LINEAR_VALUE_IS_MP)
80 mpz_init(a
); mpz_init(b
); mpz_init(c
); mpz_init(d
);
81 mpz_init(e
); mpz_init(f
); mpz_init(u
); mpz_init(v
);
82 mpz_init(q
); mpz_init(r
);
83 mpz_set_ui(a
, 1); mpz_set_ui(b
, 0); mpz_set_ui(c
, 0);
84 mpz_set_ui(d
, 1); mpz_set(u
, y
); mpz_set(v
, delta
);
86 a
= 1; b
= 0; c
= 0; d
= 1;
90 #if defined(LINEAR_VALUE_IS_MP)
91 mpz_fdiv_qr(q
, r
, u
, v
);
92 if(mpz_cmp_ui(r
, 0) == 0) break;
117 #if defined(LINEAR_VALUE_IS_MP)
118 if(mpz_cmp_ui(v
, 1) != 0)
122 mpz_mod(*z
, a
, delta
);
124 mpz_clear(a
); mpz_clear(b
); mpz_clear(c
); mpz_clear(d
);
125 mpz_clear(e
); mpz_clear(f
); mpz_clear(u
); mpz_clear(v
);
126 mpz_clear(q
); mpz_clear(r
);
129 if(v
!= 1) *z
= 0; /* y and delta are not mutually prime */
130 else *z
= mod(c
*x
, delta
);
136 /* integrer(.....) add a cut to the problem tableau, or return 0 when an
137 integral solution has been found, or -1 when no integral solution
140 Since integrer may add rows and columns to the problem tableau, its
141 arguments are pointers rather than values. If a cut is constructed,
142 ni increases by 1. If the cut is parametric, nparm increases by 1 and
146 int integrer(ptp
, pcontext
, pnvar
, pnparm
, pni
, pnc
)
147 Tableau
**ptp
, **pcontext
;
148 int *pnvar
, *pnparm
, *pni
, *pnc
;
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 defined(LINEAR_VALUE_IS_MP)
166 for(i
=0; i
<=ncol
; i
++)
167 mpz_init(coupure
[i
]);
169 for(i
=0; i
<=nparm
+1; i
++){
174 mpz_init(x
); mpz_init(d
); mpz_init(D
);
175 mpz_init(t
); mpz_init(delta
); mpz_init(tau
); mpz_init(lambda
);
179 if(ncol
+1 >= MAXCOL
) {
180 fprintf(stderr
, "Too much variables : %d\n", ncol
);
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
);
210 if(x
> 0) ok_var
= Pip_True
;
212 /* Done for the coefficient of the variables. */
214 #if defined(LINEAR_VALUE_IS_MP)
215 mpz_neg(x
, Index(*ptp
, i
, nvar
));
218 mpz_set(coupure
[nvar
], x
);
219 ok_const
= mpz_cmp_ui(x
, 0);
221 x
= coupure
[nvar
] = - mod(-Index(*ptp
, i
, nvar
), D
);
224 /* This is the constant term */
226 for(j
= nvar
+1; j
<ncol
; j
++) {
227 #if defined(LINEAR_VALUE_IS_MP)
228 mpz_neg(x
, Index(*ptp
, i
, j
));
231 mpz_set(coupure
[j
], x
);
232 if(mpz_cmp_ui(x
, 0) != 0) ok_parm
= Pip_True
;
234 x
= coupure
[j
] = - mod(- Index(*ptp
, i
, j
), D
); /* (1) */
235 if(x
!= 0) ok_parm
= Pip_True
;
238 /* These are the parametric terms */
240 #if defined(LINEAR_VALUE_IS_MP)
241 mpz_set(coupure
[ncol
], D
);
243 coupure
[ncol
] = D
; /* Just in case */
246 /* The question now is whether the cut is valid. The answer is given
247 by the following decision table:
249 ok_var ok_parm ok_const
251 F F F (a) continue, integral row
252 F F T (b) return -1, no solution
254 (c) if the <<constant>> part is not divisible
255 by D then bottom else ....
257 T F F (a) continue, integral row
258 T F T (d) constant cut
265 if(!ok_parm
&& !ok_const
) continue;
267 if(ok_var
) { /* case (d) */
268 if(nligne
>= (*ptp
)->height
) {
270 #if defined(LINEAR_VALUE_IS_MP)
271 d
= mpz_sizeinbase(D
, 2);
276 *ptp
= expanser(*ptp
, nvar
, ni
, ncol
, 0, dth
, 0);
278 /* Find the deepest cut*/
280 #if defined(LINEAR_VALUE_IS_MP)
281 mpz_neg(t
, coupure
[nvar
]);
282 mpz_gcd(delta
, t
, D
);
283 mpz_divexact(tau
, t
, delta
);
284 mpz_divexact(d
, D
, delta
);
286 bezout(t
, tau
, d
, &lambda
);
287 mpz_gcd(t
, lambda
, D
);
288 while(mpz_cmp_ui(t
, 1) != 0){
289 mpz_add(lambda
, lambda
, d
);
290 mpz_gcd(t
, lambda
, D
);
292 for(j
=0; j
<nvar
; j
++){
293 mpz_mul(t
, lambda
, coupure
[j
]);
294 mpz_fdiv_r(coupure
[j
], t
, D
);
296 mpz_mul(t
, coupure
[nvar
], lambda
);
299 mpz_neg(coupure
[nvar
], t
);
305 bezout(d
-1, tau
, d
, &lambda
);
306 while(pgcd(lambda
, D
) != 1)
308 for(j
=0; j
<nvar
; j
++)
309 coupure
[j
] = mod(lambda
*coupure
[j
], D
);
310 coupure
[nvar
] = -mod(-lambda
*coupure
[nvar
], D
);
313 /* The cut has a negative <<constant>> part */
314 Flag(*ptp
, nligne
) = Minus
;
315 #if defined(LINEAR_VALUE_IS_MP)
316 mpz_set(Denom(*ptp
, nligne
), D
);
318 Denom(*ptp
, nligne
) = D
;
321 for(j
= 0; j
<ncol
; j
++)
322 #if defined(LINEAR_VALUE_IS_MP)
323 mpz_set(Index(*ptp
, nligne
, j
), coupure
[j
]);
325 Index(*ptp
, nligne
, j
) = coupure
[j
];
327 /* A new row has been added to the problem tableau. */
330 fprintf(dump
, "just cut ");
332 fprintf(dump
, "Bezout multiplier ");
333 #if defined(LINEAR_VALUE_IS_MP)
334 mpz_out_str(dump
, 10, lambda
);
336 fprintf(dump
, FORMAT
, lambda
);
341 for(i
=0; i
<nvar
; i
++){
342 if(Flag(*ptp
, i
) & Unit
){
343 #if defined(LINEAR_VALUE_IS_MP)
346 sprintf(compose
+k
, "0 ");
351 #if defined(LINEAR_VALUE_IS_MP)
352 k
+= mpz_out_str(dump
, 10, Index(*ptp
, i
, nvar
));
355 k
+= mpz_out_str(dump
, 10, Denom(*ptp
, i
));
363 sprintf(compose
+k
, FORMAT
, Index(*ptp
, i
, nvar
));
365 sprintf(compose
+k
, "/");
367 sprintf(compose
+k
, FORMAT
, Denom(*ptp
, i
));
369 sprintf(compose
+k
, " ");
372 fputs(compose
, dump
);
379 fputs(compose
, dump
);
382 if(verbose
> 2) tab_display(*ptp
, dump
);
383 #if defined(LINEAR_VALUE_IS_MP)
390 #if defined(LINEAR_VALUE_IS_MP)
397 /* In cases (c) and (e), one has to introduce a new parameter and
398 introduce its defining inequalities into the context.
400 Let the cut be sum_{j=0}^{nvar-1} c_j x_j + c_{nvar} + (2)
401 sum_{j=0}^{nparm-1} c_{nvar + 1 + j} p_j >= 0. */
404 if(nparm
>= MAXPARM
) {
405 fprintf(stderr
, "Too much parameters : %d\n", *pnparm
);
408 /* Build the definition of the new parameter into the solution :
409 p_{nparm} = -(sum_{j=0}^{nparm-1} c_{nvar + 1 + j} p_j
411 The minus sign is there to compensate the one in (1) */
416 for(j
= 0; j
<nparm
; j
++)
417 #if defined(LINEAR_VALUE_IS_MP)
418 { mpz_neg(x
, coupure
[j
+nvar
+1]);
421 mpz_neg(x
, coupure
[*pnvar
]);
424 sol_val(-coupure
[j
+nvar
+1], UN
); /* loop body. */
425 sol_val(-coupure
[*pnvar
], UN
);
427 sol_val(D
, UN
); /* The divisor */
429 /* The value of the new parameter is specified by applying the definition of
430 Euclidean division to (3) :
432 0<= - sum_{j=0}^{nparm-1} c_{nvar+1+j} p_j - c_{nvar} - D * p_{nparm} < D (4)
434 This formula gives two inequalities which are stored in the context */
436 for(j
= 0; j
<nparm
; j
++) {
437 #if defined(LINEAR_VALUE_IS_MP)
438 mpz_set(x
, coupure
[j
+nvar
+1]);
439 mpz_neg(discrp
[j
], x
);
440 mpz_set(discrm
[j
], x
);
442 x
= coupure
[j
+nvar
+1];
447 #if defined(LINEAR_VALUE_IS_MP)
448 mpz_neg(discrp
[nparm
], D
);
449 mpz_set(discrm
[nparm
], D
);
450 mpz_set(x
, coupure
[nvar
]);
451 mpz_neg(discrp
[nparm
+1], x
);
453 mpz_add(discrm
[nparm
+1], x
, D
);
458 discrp
[(nparm
)+1] = -x
;
459 discrm
[(nparm
)+1] = x
+ D
-1;
461 if(nc
+2 > (*pcontext
)->height
|| nparm
+1 > (*pcontext
)->width
) {
463 #if defined(LINEAR_VALUE_IS_MP)
464 dcw
= mpz_sizeinbase(D
, 2);
468 dch
= 2 * dcw
+ *pni
;
469 *pcontext
= expanser(*pcontext
, 0, nc
, nparm
+1, 0, dch
, dcw
);
471 /* Flag(*pcontext, *pnc) = 0; Probably useless see line A */
473 /* Since a new parameter is to be added, the constant term has to be moved
474 right and a zero has to be inserted in all rows of the old context */
476 for(k
= 0; k
< nc
; k
++) {
477 #if defined(LINEAR_VALUE_IS_MP)
478 mpz_set(Index(*pcontext
, k
, nparm
+1), Index(*pcontext
, k
, nparm
));
479 mpz_set_ui(Index(*pcontext
, k
, nparm
), 0);
481 Index(*pcontext
, k
, nparm
+1) = Index(*pcontext
, k
, nparm
);
482 Index(*pcontext
, k
, nparm
) = 0;
485 /* Now, insert the new rows */
487 for(j
= 0; j
<= nparm
+1; j
++) {
488 #if defined(LINEAR_VALUE_IS_MP)
489 mpz_set(Index(*pcontext
, nc
, j
), discrp
[j
]);
490 mpz_set(Index(*pcontext
, nc
+1, j
), discrm
[j
]);
492 Index(*pcontext
, nc
, j
) = discrp
[j
];
493 Index(*pcontext
, nc
+1, j
) = discrm
[j
];
496 Flag(*pcontext
, nc
) = Unknown
; /* A */
497 Flag(*pcontext
, nc
+1) = Unknown
;
498 #if defined(LINEAR_VALUE_IS_MP)
499 mpz_set(Denom(*pcontext
, nc
), UN
);
500 mpz_set(Denom(*pcontext
, nc
+1), UN
);
502 Denom(*pcontext
, nc
) = UN
;
503 Denom(*pcontext
, nc
+1) = UN
;
508 fprintf(dump
, "enlarged context %d x %d\n", *pnparm
, *pnc
);
511 /* end of the construction of the new parameter */
513 if(ok_var
) { /* case (e) */
514 if(nligne
>= (*ptp
)->height
|| ncol
>= (*ptp
)->width
) {
516 #if defined(LINEAR_VALUE_IS_MP)
517 d
= mpz_sizeinbase(D
, 2);
523 *ptp
= expanser(*ptp
, nvar
, ni
, ncol
, 0, dth
, dtw
);
525 /* Zeroing out the new column seems to be useless
526 since <<expanser>> does it anyway */
528 /* The cut has a negative <<constant>> part */
529 Flag(*ptp
, nligne
) = Minus
;
530 #if defined(LINEAR_VALUE_IS_MP)
531 mpz_set(Denom(*ptp
, nligne
), D
);
533 Denom(*ptp
, nligne
) = D
;
536 for(j
= 0; j
<ncol
+1; j
++)
537 #if defined(LINEAR_VALUE_IS_MP)
538 mpz_set(Index(*ptp
, nligne
, j
), coupure
[j
]);
540 Index(*ptp
, nligne
, j
) = coupure
[j
];
542 /* A new row has been added to the problem tableau. */
544 #if defined(LINEAR_VALUE_IS_MP)
551 /* The new parameter has already been defined as a
552 quotient. It remains to express that the
553 remainder of that division is zero */
555 sol_forme(nparm
+ 2);
556 for (j
= 0; j
< nparm
+1 ; j
++)
557 sol_val(discrm
[j
], UN
);
558 #if defined(LINEAR_VALUE_IS_MP)
564 sol_nil(); /* No solution if the division is not even */
565 /* Add a new column */
566 if(ncol
+1 >= (*ptp
)-> width
) {
568 #if defined(LINEAR_VALUE_IS_MP)
569 dtw
= mpz_sizeinbase(D
, 2);
573 *ptp
= expanser(*ptp
, *pnvar
, *pni
, ncol
, 0, 0, dtw
);
575 /* The new column is zeroed out by <<expanser>> */
576 /* Let c be the coefficient of parameter p in the i row. In <<coupure>>,
577 this parameter has coefficient - mod(-c, D). In <<discrp>>, this same
578 parameter has coefficient mod(-c, D). The sum c + mod(-c, D) is obviously
581 for (j
= 0; j
<= nparm
; j
++)
582 #if defined(LINEAR_VALUE_IS_MP)
583 mpz_add(Index(*ptp
, i
, j
+ nvar
+ 1),
584 Index(*ptp
, i
, j
+ nvar
+ 1), discrp
[j
]);
586 Index(*ptp
, i
, j
+ nvar
+ 1) += discrp
[j
];
588 tab_display(*ptp
, stderr
);
592 /* The solution is integral. */
593 #if defined(LINEAR_VALUE_IS_MP)
596 for(i
=0; i
<= ncol
; i
++)
597 mpz_clear(coupure
[i
]);
598 for(i
=0; i
<= nparm
+1; i
++){
599 mpz_clear(discrp
[i
]);
600 mpz_clear(discrm
[i
]);
602 mpz_clear(x
); mpz_clear(d
); mpz_clear(D
);
603 mpz_clear(t
); mpz_clear(tau
); mpz_clear(lambda
); mpz_clear(delta
);