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(Tableau
**ptp
, Tableau
**pcontext
,
147 int *pnvar
, int *pnparm
, int *pni
, int *pnc
)
148 {int ncol
= *pnvar
+*pnparm
+1;
149 int nligne
= *pnvar
+ *pni
;
154 Entier coupure
[MAXCOL
];
157 int ok_var
, ok_const
, ok_parm
;
158 Entier discrp
[MAXPARM
], discrm
[MAXPARM
];
162 Entier t
, delta
, tau
, lambda
;
164 #if defined(LINEAR_VALUE_IS_MP)
165 for(i
=0; i
<=ncol
; i
++)
166 mpz_init(coupure
[i
]);
168 for(i
=0; i
<=nparm
+1; i
++){
173 mpz_init(x
); mpz_init(d
); mpz_init(D
);
174 mpz_init(t
); mpz_init(delta
); mpz_init(tau
); mpz_init(lambda
);
178 if(ncol
+1 >= MAXCOL
) {
179 fprintf(stderr
, "Too much variables : %d\n", ncol
);
183 /* search for a non-integral row */
184 for(i
= 0; i
<nvar
; i
++) {
185 #if defined(LINEAR_VALUE_IS_MP)
186 mpz_set(D
, Denom(*ptp
, i
));
187 if(mpz_cmp_ui(D
, 1) == 0) continue;
192 /* If the common denominator of the row is 1
193 the row is integral */
195 if(ff
& Unit
)continue;
196 /* If the row is a Unit, it is integral */
198 /* Here a portential candidate has been found.
199 Build the cut by reducing each coefficient
200 modulo D, the common denominator */
202 for(j
= 0; j
<nvar
; j
++) {
203 #if defined(LINEAR_VALUE_IS_MP)
204 mpz_fdiv_r(x
, Index(*ptp
, i
, j
), D
);
205 mpz_set(coupure
[j
], x
);
207 x
= coupure
[j
] = mod(Index(*ptp
, i
, j
), D
);
209 if(x
> 0) ok_var
= Pip_True
;
211 /* Done for the coefficient of the variables. */
213 #if defined(LINEAR_VALUE_IS_MP)
214 mpz_neg(x
, Index(*ptp
, i
, nvar
));
217 mpz_set(coupure
[nvar
], x
);
218 ok_const
= mpz_cmp_ui(x
, 0);
220 x
= coupure
[nvar
] = - mod(-Index(*ptp
, i
, nvar
), D
);
223 /* This is the constant term */
225 for(j
= nvar
+1; j
<ncol
; j
++) {
226 value_oppose(x
, Index(*ptp
, i
, j
));
227 value_pmodulus(x
, x
, D
);
228 value_oppose(coupure
[j
], x
);
229 if (value_notzero_p(coupure
[j
]))
232 /* These are the parametric terms */
234 #if defined(LINEAR_VALUE_IS_MP)
235 mpz_set(coupure
[ncol
], D
);
237 coupure
[ncol
] = D
; /* Just in case */
240 /* The question now is whether the cut is valid. The answer is given
241 by the following decision table:
243 ok_var ok_parm ok_const
245 F F F (a) continue, integral row
246 F F T (b) return -1, no solution
248 (c) if the <<constant>> part is not divisible
249 by D then bottom else ....
251 T F F (a) continue, integral row
252 T F T (d) constant cut
259 if(!ok_parm
&& !ok_const
) continue;
261 if(ok_var
) { /* case (d) */
262 if(nligne
>= (*ptp
)->height
) {
264 #if defined(LINEAR_VALUE_IS_MP)
265 d
= mpz_sizeinbase(D
, 2);
270 *ptp
= expanser(*ptp
, nvar
, ni
, ncol
, 0, dth
, 0);
272 /* Find the deepest cut*/
274 #if defined(LINEAR_VALUE_IS_MP)
275 mpz_neg(t
, coupure
[nvar
]);
276 mpz_gcd(delta
, t
, D
);
277 mpz_divexact(tau
, t
, delta
);
278 mpz_divexact(d
, D
, delta
);
280 bezout(t
, tau
, d
, &lambda
);
281 mpz_gcd(t
, lambda
, D
);
282 while(mpz_cmp_ui(t
, 1) != 0){
283 mpz_add(lambda
, lambda
, d
);
284 mpz_gcd(t
, lambda
, D
);
286 for(j
=0; j
<nvar
; j
++){
287 mpz_mul(t
, lambda
, coupure
[j
]);
288 mpz_fdiv_r(coupure
[j
], t
, D
);
290 mpz_mul(t
, coupure
[nvar
], lambda
);
293 mpz_neg(coupure
[nvar
], t
);
299 bezout(d
-1, tau
, d
, &lambda
);
300 while(pgcd(lambda
, D
) != 1)
302 for(j
=0; j
<nvar
; j
++)
303 coupure
[j
] = mod(lambda
*coupure
[j
], D
);
304 coupure
[nvar
] = -mod(-lambda
*coupure
[nvar
], D
);
307 /* The cut has a negative <<constant>> part */
308 Flag(*ptp
, nligne
) = Minus
;
309 #if defined(LINEAR_VALUE_IS_MP)
310 mpz_set(Denom(*ptp
, nligne
), D
);
312 Denom(*ptp
, nligne
) = D
;
315 for(j
= 0; j
<ncol
; j
++)
316 #if defined(LINEAR_VALUE_IS_MP)
317 mpz_set(Index(*ptp
, nligne
, j
), coupure
[j
]);
319 Index(*ptp
, nligne
, j
) = coupure
[j
];
321 /* A new row has been added to the problem tableau. */
324 fprintf(dump
, "just cut ");
326 fprintf(dump
, "Bezout multiplier ");
327 #if defined(LINEAR_VALUE_IS_MP)
328 mpz_out_str(dump
, 10, lambda
);
330 fprintf(dump
, FORMAT
, lambda
);
335 for(i
=0; i
<nvar
; i
++){
336 if(Flag(*ptp
, i
) & Unit
){
337 #if defined(LINEAR_VALUE_IS_MP)
340 sprintf(compose
+k
, "0 ");
345 #if defined(LINEAR_VALUE_IS_MP)
346 k
+= mpz_out_str(dump
, 10, Index(*ptp
, i
, nvar
));
349 k
+= mpz_out_str(dump
, 10, Denom(*ptp
, i
));
357 sprintf(compose
+k
, FORMAT
, Index(*ptp
, i
, nvar
));
359 sprintf(compose
+k
, "/");
361 sprintf(compose
+k
, FORMAT
, Denom(*ptp
, i
));
363 sprintf(compose
+k
, " ");
366 fputs(compose
, dump
);
373 fputs(compose
, dump
);
376 if(verbose
> 2) tab_display(*ptp
, dump
);
377 #if defined(LINEAR_VALUE_IS_MP)
384 #if defined(LINEAR_VALUE_IS_MP)
391 /* In cases (c) and (e), one has to introduce a new parameter and
392 introduce its defining inequalities into the context.
394 Let the cut be sum_{j=0}^{nvar-1} c_j x_j + c_{nvar} + (2)
395 sum_{j=0}^{nparm-1} c_{nvar + 1 + j} p_j >= 0. */
398 if(nparm
>= MAXPARM
) {
399 fprintf(stderr
, "Too much parameters : %d\n", *pnparm
);
402 /* Build the definition of the new parameter into the solution :
403 p_{nparm} = -(sum_{j=0}^{nparm-1} c_{nvar + 1 + j} p_j
405 The minus sign is there to compensate the one in (1) */
410 for(j
= 0; j
<nparm
; j
++)
411 #if defined(LINEAR_VALUE_IS_MP)
412 { mpz_neg(x
, coupure
[j
+nvar
+1]);
415 mpz_neg(x
, coupure
[*pnvar
]);
418 sol_val(-coupure
[j
+nvar
+1], UN
); /* loop body. */
419 sol_val(-coupure
[*pnvar
], UN
);
421 sol_val(D
, UN
); /* The divisor */
423 /* The value of the new parameter is specified by applying the definition of
424 Euclidean division to (3) :
426 0<= - sum_{j=0}^{nparm-1} c_{nvar+1+j} p_j - c_{nvar} - D * p_{nparm} < D (4)
428 This formula gives two inequalities which are stored in the context */
430 for(j
= 0; j
<nparm
; j
++) {
431 #if defined(LINEAR_VALUE_IS_MP)
432 mpz_set(x
, coupure
[j
+nvar
+1]);
433 mpz_neg(discrp
[j
], x
);
434 mpz_set(discrm
[j
], x
);
436 x
= coupure
[j
+nvar
+1];
441 #if defined(LINEAR_VALUE_IS_MP)
442 mpz_neg(discrp
[nparm
], D
);
443 mpz_set(discrm
[nparm
], D
);
444 mpz_set(x
, coupure
[nvar
]);
445 mpz_neg(discrp
[nparm
+1], x
);
447 mpz_add(discrm
[nparm
+1], x
, D
);
452 discrp
[(nparm
)+1] = -x
;
453 discrm
[(nparm
)+1] = x
+ D
-1;
455 if(nc
+2 > (*pcontext
)->height
|| nparm
+1 > (*pcontext
)->width
) {
457 #if defined(LINEAR_VALUE_IS_MP)
458 dcw
= mpz_sizeinbase(D
, 2);
462 dch
= 2 * dcw
+ *pni
;
463 *pcontext
= expanser(*pcontext
, 0, nc
, nparm
+1, 0, dch
, dcw
);
465 /* Flag(*pcontext, *pnc) = 0; Probably useless see line A */
467 /* Since a new parameter is to be added, the constant term has to be moved
468 right and a zero has to be inserted in all rows of the old context */
470 for(k
= 0; k
< nc
; k
++) {
471 #if defined(LINEAR_VALUE_IS_MP)
472 mpz_set(Index(*pcontext
, k
, nparm
+1), Index(*pcontext
, k
, nparm
));
473 mpz_set_ui(Index(*pcontext
, k
, nparm
), 0);
475 Index(*pcontext
, k
, nparm
+1) = Index(*pcontext
, k
, nparm
);
476 Index(*pcontext
, k
, nparm
) = 0;
479 /* Now, insert the new rows */
481 for(j
= 0; j
<= nparm
+1; j
++) {
482 #if defined(LINEAR_VALUE_IS_MP)
483 mpz_set(Index(*pcontext
, nc
, j
), discrp
[j
]);
484 mpz_set(Index(*pcontext
, nc
+1, j
), discrm
[j
]);
486 Index(*pcontext
, nc
, j
) = discrp
[j
];
487 Index(*pcontext
, nc
+1, j
) = discrm
[j
];
490 Flag(*pcontext
, nc
) = Unknown
; /* A */
491 Flag(*pcontext
, nc
+1) = Unknown
;
492 #if defined(LINEAR_VALUE_IS_MP)
493 mpz_set(Denom(*pcontext
, nc
), UN
);
494 mpz_set(Denom(*pcontext
, nc
+1), UN
);
496 Denom(*pcontext
, nc
) = UN
;
497 Denom(*pcontext
, nc
+1) = UN
;
502 fprintf(dump
, "enlarged context %d x %d\n", *pnparm
, *pnc
);
505 /* end of the construction of the new parameter */
507 if(ok_var
) { /* case (e) */
508 if(nligne
>= (*ptp
)->height
|| ncol
>= (*ptp
)->width
) {
510 #if defined(LINEAR_VALUE_IS_MP)
511 d
= mpz_sizeinbase(D
, 2);
517 *ptp
= expanser(*ptp
, nvar
, ni
, ncol
, 0, dth
, dtw
);
519 /* Zeroing out the new column seems to be useless
520 since <<expanser>> does it anyway */
522 /* The cut has a negative <<constant>> part */
523 Flag(*ptp
, nligne
) = Minus
;
524 #if defined(LINEAR_VALUE_IS_MP)
525 mpz_set(Denom(*ptp
, nligne
), D
);
527 Denom(*ptp
, nligne
) = D
;
530 for(j
= 0; j
<ncol
+1; j
++)
531 #if defined(LINEAR_VALUE_IS_MP)
532 mpz_set(Index(*ptp
, nligne
, j
), coupure
[j
]);
534 Index(*ptp
, nligne
, j
) = coupure
[j
];
536 /* A new row has been added to the problem tableau. */
538 #if defined(LINEAR_VALUE_IS_MP)
545 /* The new parameter has already been defined as a
546 quotient. It remains to express that the
547 remainder of that division is zero */
549 sol_forme(nparm
+ 2);
550 for (j
= 0; j
< nparm
+1 ; j
++)
551 sol_val(discrm
[j
], UN
);
552 #if defined(LINEAR_VALUE_IS_MP)
558 sol_nil(); /* No solution if the division is not even */
559 /* Add a new column */
560 if(ncol
+1 >= (*ptp
)-> width
) {
562 #if defined(LINEAR_VALUE_IS_MP)
563 dtw
= mpz_sizeinbase(D
, 2);
567 *ptp
= expanser(*ptp
, *pnvar
, *pni
, ncol
, 0, 0, dtw
);
569 /* The new column is zeroed out by <<expanser>> */
570 /* Let c be the coefficient of parameter p in the i row. In <<coupure>>,
571 this parameter has coefficient - mod(-c, D). In <<discrp>>, this same
572 parameter has coefficient mod(-c, D). The sum c + mod(-c, D) is obviously
575 for (j
= 0; j
<= nparm
; j
++)
576 #if defined(LINEAR_VALUE_IS_MP)
577 mpz_add(Index(*ptp
, i
, j
+ nvar
+ 1),
578 Index(*ptp
, i
, j
+ nvar
+ 1), discrp
[j
]);
580 Index(*ptp
, i
, j
+ nvar
+ 1) += discrp
[j
];
582 tab_display(*ptp
, stderr
);
586 /* The solution is integral. */
587 #if defined(LINEAR_VALUE_IS_MP)
590 for(i
=0; i
<= ncol
; i
++)
591 mpz_clear(coupure
[i
]);
592 for(i
=0; i
<= nparm
+1; i
++){
593 mpz_clear(discrp
[i
]);
594 mpz_clear(discrm
[i
]);
596 mpz_clear(x
); mpz_clear(d
); mpz_clear(D
);
597 mpz_clear(t
); mpz_clear(tau
); mpz_clear(lambda
); mpz_clear(delta
);