1 /******************************************************************************
2 * PIP : Parametric Integer Programming *
3 ******************************************************************************
5 * Copyright Paul Feautrier, 1988, 1993, 1994, 1996 *
7 * This is free software; you can redistribute it and/or modify it under the *
8 * terms of the GNU General Public License as published by the Free Software *
9 * Foundation; either version 2 of the License, or (at your option) any later *
12 * This software is distributed in the hope that it will be useful, but *
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
17 * You should have received a copy of the GNU General Public License along *
18 * with software; if not, write to the Free Software Foundation, Inc., *
19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
21 * Written by Paul Feautrier *
23 ******************************************************************************/
28 #include <piplib/piplib.h>
30 /* The routines in this file are used to build a Gomory cut from
31 a non-integral row of the problem tableau */
33 extern long int cross_product
, limit
;
37 /* mod(x,y) computes the remainder of x when divided by y. The difference
38 with x%y is that the result is guaranteed to be positive, which is not
39 always true for x%y */
49 /* this routine is useless at present */
51 int non_borne(tp
, nvar
, D
, bigparm
)
56 for(i
= 0; i
<nvar
; i
++)
59 {if(ff
& Unit
)return(True
);
60 if(Index(tp
, i
, bigparm
) != D
) return(True
);
68 /* integrer(.....) add a cut to the problem tableau, or return 0 when an
69 integral solution has been found, or -1 when no integral solution
72 Since integrer may add rows and columns to the problem tableau, its
73 arguments are pointers rather than values. If a cut is constructed,
74 ni increases by 1. If the cut is parametric, nparm increases by 1 and
78 int integrer(ptp
, pcontext
, D
, pnvar
, pnparm
, pni
, pnc
)
79 Tableau
**ptp
, **pcontext
;
80 int *pnvar
, *pnparm
, *pni
, *pnc
;
82 {int ncol
= *pnvar
+*pnparm
+1;
83 int nligne
= *pnvar
+ *pni
;
88 Entier coupure
[MAXCOL
];
91 int ok_var
, ok_const
, ok_parm
;
92 Entier discrp
[MAXPARM
], discrm
[MAXPARM
];
95 if(ncol
+1 >= MAXCOL
) {
96 fprintf(stderr
, "Too much variables : %d\n", ncol
);
100 /* search for a non-integral row */
101 for(i
= 0; i
<nvar
; i
++) {
104 /* If the common denominator of the row is 1
105 the row is integral */
107 if(ff
& Unit
)continue;
108 /* If the row is a Unit, it is integral */
110 /* Here a portential candidate has been found.
111 Build the cut by reducing each coefficient
112 modulo D, the common denominator */
114 for(j
= 0; j
<nvar
; j
++) {
115 x
= coupure
[j
] = mod(Index(*ptp
, i
, j
), D
);
116 if(x
> 0) ok_var
= True
;
118 /* Done for the coefficient of the variables. */
120 x
= coupure
[nvar
] = - mod(-Index(*ptp
, i
, nvar
), D
);
122 /* This is the constant term */
124 for(j
= nvar
+1; j
<ncol
; j
++) {
125 x
= coupure
[j
] = - mod(- Index(*ptp
, i
, j
), D
); /* (1) */
126 if(x
!= 0) ok_parm
= True
;
128 /* These are the parametric terms */
130 coupure
[ncol
] = D
; /* Just in case */
132 /* The question now is whether the cut is valid. The answer is given
133 by the following decision table:
135 ok_var ok_parm ok_const
137 F F F (a) continue, integral row
138 F F T (b) return -1, no solution
140 (c) if the <<constant>> part is not divisible
141 by D then bottom else ....
143 T F F (a) continue, integral row
144 T F T (d) constant cut
151 if(!ok_parm
&& !ok_const
) continue;
153 if(ok_var
) { /* case (d) */
154 if(nligne
>= (*ptp
)->height
) {
158 *ptp
= expanser(*ptp
, nvar
, ni
, ncol
, 0, dth
, 0);
160 /* The cut has a negative <<constant>> part */
161 Flag(*ptp
, nligne
) = Minus
;
162 Denom(*ptp
, nligne
) = D
;
164 for(j
= 0; j
<ncol
; j
++)
165 Index(*ptp
, nligne
, j
) = coupure
[j
];
166 /* A new row has been added to the problem tableau. */
170 else return -1; /* case (b) */
172 /* In cases (c) and (e), one has to introduce a new parameter and
173 introduce its defining inequalities into the context.
175 Let the cut be sum_{j=0}^{nvar-1} c_j x_j + c_{nvar} + (2)
176 sum_{j=0}^{nparm-1} c_{nvar + 1 + j} p_j >= 0. */
179 if(nparm
>= MAXPARM
) {
180 fprintf(stderr
, "Too much parameters : %d\n", *pnparm
);
183 /* Build the definition of the new parameter into the solution :
184 p_{nparm} = -(sum_{j=0}^{nparm-1} c_{nvar + 1 + j} p_j
186 The minus sign is there to compensate the one in (1) */
191 for(j
= 0; j
<nparm
; j
++) sol_val(-coupure
[j
+nvar
+1], UN
);
192 sol_val(-coupure
[*pnvar
], UN
);
193 sol_val(D
, UN
); /* The divisor */
195 /* The value of the new parameter is specified by applying the definition of
196 Euclidean division to (3) :
198 0<= - sum_{j=0}^{nparm-1} c_{nvar+1+j} p_j - c_{nvar} - D * p_{nparm} < D (4)
200 This formula gives two inequalities which are stored in the context */
202 for(j
= 0; j
<nparm
; j
++) {
203 x
= coupure
[j
+nvar
+1];
210 discrp
[(nparm
)+1] = -x
;
211 discrm
[(nparm
)+1] = x
+ D
-1;
212 if(nc
+2 > (*pcontext
)->height
|| nparm
+1 > (*pcontext
)->width
) {
215 dch
= 2 * dcw
+ *pni
;
216 *pcontext
= expanser(*pcontext
, 0, nc
, nparm
+1, 0, dch
, dcw
);
218 /* Flag(*pcontext, *pnc) = 0; Probably useless see line A */
220 /* Since a new parameter is to be added, the constant term has to be moved
221 right and a zero has to be inserted in all rows of the old context */
223 for(k
= 0; k
< nc
; k
++) {
224 Index(*pcontext
, k
, nparm
+1) = Index(*pcontext
, k
, nparm
);
225 Index(*pcontext
, k
, nparm
) = 0;
227 /* Now, insert the new rows */
229 for(j
= 0; j
<= nparm
+1; j
++) {
230 Index(*pcontext
, nc
, j
) = discrp
[j
];
231 Index(*pcontext
, nc
+1, j
) = discrm
[j
];
233 Flag(*pcontext
, nc
) = Unknown
; /* A */
234 Denom(*pcontext
, nc
) = UN
;
235 Flag(*pcontext
, nc
+1) = Unknown
;
236 Denom(*pcontext
, nc
+1) = UN
;
239 /* end of the construction of the new parameter */
241 if(ok_var
) { /* case (e) */
242 if(nligne
>= (*ptp
)->height
|| ncol
>= (*ptp
)->width
) {
247 *ptp
= expanser(*ptp
, nvar
, ni
, ncol
, 0, dth
, dtw
);
249 /* Zeroing out the new column seems to be useless
250 since <<expanser>> does it anyway */
252 /* The cut has a negative <<constant>> part */
253 Flag(*ptp
, nligne
) = Minus
;
254 Denom(*ptp
, nligne
) = D
;
256 for(j
= 0; j
<ncol
+1; j
++)
257 Index(*ptp
, nligne
, j
) = coupure
[j
];
258 /* A new row has been added to the problem tableau. */
263 /* The new parameter has already been defined as a
264 quotient. It remains to express that the
265 remainder of that division is zero */
267 sol_forme(nparm
+ 2);
268 for (j
= 0; j
< nparm
+1 ; j
++)
269 sol_val(discrm
[j
], UN
);
271 sol_nil(); /* No solution if the division is not even */
272 /* Add a new column */
273 if(ncol
+1 >= (*ptp
)-> width
) {
276 *ptp
= expanser(*ptp
, *pnvar
, *pni
, ncol
, 0, 0, dtw
);
278 /* The new column is zeroed out by <<expanser>> */
279 /* Let c be the coefficient of parameter p in the i row. In <<coupure>>,
280 this parameter has coefficient - mod(-c, D). In <<discrp>>, this same
281 parameter has coefficient mod(-c, D). The sum c + mod(-c, D) is obviously
284 for (j
= 0; j
<= nparm
; j
++)
285 Index(*ptp
, i
, j
+ nvar
+ 1) += discrp
[j
];
286 tab_display(*ptp
, stderr
);
290 /* The solution is integral. */