1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2021 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not visit scipopt.org. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15
16 /**@file scip_var.c
17 * @ingroup OTHER_CFILES
18 * @brief public methods for SCIP variables
19 * @author Tobias Achterberg
20 * @author Timo Berthold
21 * @author Gerald Gamrath
22 * @author Leona Gottwald
23 * @author Stefan Heinz
24 * @author Gregor Hendel
25 * @author Thorsten Koch
26 * @author Alexander Martin
27 * @author Marc Pfetsch
28 * @author Michael Winkler
29 * @author Kati Wolter
30 *
31 * @todo check all SCIP_STAGE_* switches, and include the new stages TRANSFORMED and INITSOLVE
32 */
33
34 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
35
36 #include "blockmemshell/memory.h"
37 #include "lpi/lpi.h"
38 #include "scip/branch.h"
39 #include "scip/clock.h"
40 #include "scip/conflict.h"
41 #include "scip/debug.h"
42 #include "scip/history.h"
43 #include "scip/implics.h"
44 #include "scip/lp.h"
45 #include "scip/prob.h"
46 #include "scip/pub_cons.h"
47 #include "scip/pub_implics.h"
48 #include "scip/pub_lp.h"
49 #include "scip/pub_message.h"
50 #include "scip/pub_misc.h"
51 #include "scip/pub_tree.h"
52 #include "scip/pub_var.h"
53 #include "scip/relax.h"
54 #include "scip/scip_general.h"
55 #include "scip/scip_lp.h"
56 #include "scip/scip_mem.h"
57 #include "scip/scip_message.h"
58 #include "scip/scip_numerics.h"
59 #include "scip/scip_prob.h"
60 #include "scip/scip_probing.h"
61 #include "scip/scip_sol.h"
62 #include "scip/scip_solvingstats.h"
63 #include "scip/scip_tree.h"
64 #include "scip/scip_var.h"
65 #include "scip/set.h"
66 #include "scip/sol.h"
67 #include "scip/solve.h"
68 #include "scip/stat.h"
69 #include "scip/struct_lp.h"
70 #include "scip/struct_mem.h"
71 #include "scip/struct_primal.h"
72 #include "scip/struct_prob.h"
73 #include "scip/struct_scip.h"
74 #include "scip/struct_set.h"
75 #include "scip/struct_stat.h"
76 #include "scip/struct_tree.h"
77 #include "scip/struct_var.h"
78 #include "scip/tree.h"
79 #include "scip/var.h"
80 #include <ctype.h>
81
82
83 /** creates and captures problem variable; if variable is of integral type, fractional bounds are automatically rounded;
84 * an integer variable with bounds zero and one is automatically converted into a binary variable;
85 *
86 * @warning When doing column generation and the original problem is a maximization problem, notice that SCIP will
87 * transform the problem into a minimization problem by multiplying the objective function by -1. Thus, the
88 * original objective function value of variables created during the solving process has to be multiplied by
89 * -1, too.
90 *
91 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
92 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
93 *
94 * @pre This method can be called if @p scip is in one of the following stages:
95 * - \ref SCIP_STAGE_PROBLEM
96 * - \ref SCIP_STAGE_TRANSFORMING
97 * - \ref SCIP_STAGE_INITPRESOLVE
98 * - \ref SCIP_STAGE_PRESOLVING
99 * - \ref SCIP_STAGE_EXITPRESOLVE
100 * - \ref SCIP_STAGE_PRESOLVED
101 * - \ref SCIP_STAGE_SOLVING
102 *
103 * @note the variable gets captured, hence at one point you have to release it using the method SCIPreleaseVar()
104 */
SCIPcreateVar(SCIP * scip,SCIP_VAR ** var,const char * name,SCIP_Real lb,SCIP_Real ub,SCIP_Real obj,SCIP_VARTYPE vartype,SCIP_Bool initial,SCIP_Bool removable,SCIP_DECL_VARDELORIG ((* vardelorig)),SCIP_DECL_VARTRANS ((* vartrans)),SCIP_DECL_VARDELTRANS ((* vardeltrans)),SCIP_DECL_VARCOPY ((* varcopy)),SCIP_VARDATA * vardata)105 SCIP_RETCODE SCIPcreateVar(
106 SCIP* scip, /**< SCIP data structure */
107 SCIP_VAR** var, /**< pointer to variable object */
108 const char* name, /**< name of variable, or NULL for automatic name creation */
109 SCIP_Real lb, /**< lower bound of variable */
110 SCIP_Real ub, /**< upper bound of variable */
111 SCIP_Real obj, /**< objective function value */
112 SCIP_VARTYPE vartype, /**< type of variable */
113 SCIP_Bool initial, /**< should var's column be present in the initial root LP? */
114 SCIP_Bool removable, /**< is var's column removable from the LP (due to aging or cleanup)? */
115 SCIP_DECL_VARDELORIG ((*vardelorig)), /**< frees user data of original variable, or NULL */
116 SCIP_DECL_VARTRANS ((*vartrans)), /**< creates transformed user data by transforming original user data, or NULL */
117 SCIP_DECL_VARDELTRANS ((*vardeltrans)), /**< frees user data of transformed variable, or NULL */
118 SCIP_DECL_VARCOPY ((*varcopy)), /**< copies variable data if wanted to subscip, or NULL */
119 SCIP_VARDATA* vardata /**< user data for this specific variable */
120 )
121 {
122 assert(var != NULL);
123 assert(lb <= ub);
124
125 SCIP_CALL( SCIPcheckStage(scip, "SCIPcreateVar", FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
126
127 /* forbid infinite objective function values */
128 if( SCIPisInfinity(scip, REALABS(obj)) )
129 {
130 SCIPerrorMessage("invalid objective function value: value is infinite\n");
131 return SCIP_INVALIDDATA;
132 }
133
134 switch( scip->set->stage )
135 {
136 case SCIP_STAGE_PROBLEM:
137 SCIP_CALL( SCIPvarCreateOriginal(var, scip->mem->probmem, scip->set, scip->stat,
138 name, lb, ub, obj, vartype, initial, removable, vardelorig, vartrans, vardeltrans, varcopy, vardata) );
139 break;
140
141 case SCIP_STAGE_TRANSFORMING:
142 case SCIP_STAGE_INITPRESOLVE:
143 case SCIP_STAGE_PRESOLVING:
144 case SCIP_STAGE_EXITPRESOLVE:
145 case SCIP_STAGE_PRESOLVED:
146 case SCIP_STAGE_SOLVING:
147 SCIP_CALL( SCIPvarCreateTransformed(var, scip->mem->probmem, scip->set, scip->stat,
148 name, lb, ub, obj, vartype, initial, removable, vardelorig, vartrans, vardeltrans, varcopy, vardata) );
149 break;
150
151 default:
152 SCIPerrorMessage("invalid SCIP stage <%d>\n", scip->set->stage);
153 return SCIP_INVALIDCALL;
154 } /*lint !e788*/
155
156 return SCIP_OKAY;
157 }
158
159 /** creates and captures problem variable with optional callbacks and variable data set to NULL, which can be set
160 * afterwards using SCIPvarSetDelorigData(), SCIPvarSetTransData(),
161 * SCIPvarSetDeltransData(), SCIPvarSetCopy(), and SCIPvarSetData(); sets variable flags initial=TRUE
162 * and removable = FALSE, which can be adjusted by using SCIPvarSetInitial() and SCIPvarSetRemovable(), resp.;
163 * if variable is of integral type, fractional bounds are automatically rounded;
164 * an integer variable with bounds zero and one is automatically converted into a binary variable;
165 *
166 * @warning When doing column generation and the original problem is a maximization problem, notice that SCIP will
167 * transform the problem into a minimization problem by multiplying the objective function by -1. Thus, the
168 * original objective function value of variables created during the solving process has to be multiplied by
169 * -1, too.
170 *
171 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
172 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
173 *
174 * @pre This method can be called if @p scip is in one of the following stages:
175 * - \ref SCIP_STAGE_PROBLEM
176 * - \ref SCIP_STAGE_TRANSFORMING
177 * - \ref SCIP_STAGE_INITPRESOLVE
178 * - \ref SCIP_STAGE_PRESOLVING
179 * - \ref SCIP_STAGE_EXITPRESOLVE
180 * - \ref SCIP_STAGE_PRESOLVED
181 * - \ref SCIP_STAGE_SOLVING
182 *
183 * @note the variable gets captured, hence at one point you have to release it using the method SCIPreleaseVar()
184 */
SCIPcreateVarBasic(SCIP * scip,SCIP_VAR ** var,const char * name,SCIP_Real lb,SCIP_Real ub,SCIP_Real obj,SCIP_VARTYPE vartype)185 SCIP_RETCODE SCIPcreateVarBasic(
186 SCIP* scip, /**< SCIP data structure */
187 SCIP_VAR** var, /**< pointer to variable object */
188 const char* name, /**< name of variable, or NULL for automatic name creation */
189 SCIP_Real lb, /**< lower bound of variable */
190 SCIP_Real ub, /**< upper bound of variable */
191 SCIP_Real obj, /**< objective function value */
192 SCIP_VARTYPE vartype /**< type of variable */
193 )
194 {
195 SCIP_CALL( SCIPcheckStage(scip, "SCIPcreateVarBasic", FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
196
197 SCIP_CALL( SCIPcreateVar(scip, var, name, lb, ub, obj, vartype, TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) );
198
199 return SCIP_OKAY;
200 }
201
202 /** outputs the variable name to the file stream
203 *
204 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
205 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
206 *
207 * @pre This method can be called if @p scip is in one of the following stages:
208 * - \ref SCIP_STAGE_PROBLEM
209 * - \ref SCIP_STAGE_TRANSFORMING
210 * - \ref SCIP_STAGE_TRANSFORMED
211 * - \ref SCIP_STAGE_INITPRESOLVE
212 * - \ref SCIP_STAGE_PRESOLVING
213 * - \ref SCIP_STAGE_EXITPRESOLVE
214 * - \ref SCIP_STAGE_PRESOLVED
215 * - \ref SCIP_STAGE_INITSOLVE
216 * - \ref SCIP_STAGE_SOLVING
217 * - \ref SCIP_STAGE_SOLVED
218 * - \ref SCIP_STAGE_EXITSOLVE
219 * - \ref SCIP_STAGE_FREETRANS
220 */
SCIPwriteVarName(SCIP * scip,FILE * file,SCIP_VAR * var,SCIP_Bool type)221 SCIP_RETCODE SCIPwriteVarName(
222 SCIP* scip, /**< SCIP data structure */
223 FILE* file, /**< output file, or NULL for stdout */
224 SCIP_VAR* var, /**< variable to output */
225 SCIP_Bool type /**< should the variable type be also posted */
226 )
227 {
228 assert(scip != NULL);
229 assert(var != NULL);
230
231 SCIP_CALL( SCIPcheckStage(scip, "SCIPwriteVarName", FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE) );
232
233 /* print variable name */
234 if( SCIPvarIsNegated(var) )
235 {
236 SCIP_VAR* negatedvar;
237
238 SCIP_CALL( SCIPgetNegatedVar(scip, var, &negatedvar) );
239 SCIPinfoMessage(scip, file, "<~%s>", SCIPvarGetName(negatedvar));
240 }
241 else
242 {
243 SCIPinfoMessage(scip, file, "<%s>", SCIPvarGetName(var));
244 }
245
246 if( type )
247 {
248 /* print variable type */
249 SCIPinfoMessage(scip, file, "[%c]",
250 SCIPvarGetType(var) == SCIP_VARTYPE_BINARY ? SCIP_VARTYPE_BINARY_CHAR :
251 SCIPvarGetType(var) == SCIP_VARTYPE_INTEGER ? SCIP_VARTYPE_INTEGER_CHAR :
252 SCIPvarGetType(var) == SCIP_VARTYPE_IMPLINT ? SCIP_VARTYPE_IMPLINT_CHAR : SCIP_VARTYPE_CONTINUOUS_CHAR);
253 }
254
255 return SCIP_OKAY;
256 }
257
258 /** print the given list of variables to output stream separated by the given delimiter character;
259 *
260 * i. e. the variables x1, x2, ..., xn with given delimiter ',' are written as: \<x1\>, \<x2\>, ..., \<xn\>;
261 *
262 * the method SCIPparseVarsList() can parse such a string
263 *
264 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
265 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
266 *
267 * @pre This method can be called if @p scip is in one of the following stages:
268 * - \ref SCIP_STAGE_PROBLEM
269 * - \ref SCIP_STAGE_TRANSFORMING
270 * - \ref SCIP_STAGE_TRANSFORMED
271 * - \ref SCIP_STAGE_INITPRESOLVE
272 * - \ref SCIP_STAGE_PRESOLVING
273 * - \ref SCIP_STAGE_EXITPRESOLVE
274 * - \ref SCIP_STAGE_PRESOLVED
275 * - \ref SCIP_STAGE_INITSOLVE
276 * - \ref SCIP_STAGE_SOLVING
277 * - \ref SCIP_STAGE_SOLVED
278 * - \ref SCIP_STAGE_EXITSOLVE
279 * - \ref SCIP_STAGE_FREETRANS
280 *
281 * @note The printing process is done via the message handler system.
282 */
SCIPwriteVarsList(SCIP * scip,FILE * file,SCIP_VAR ** vars,int nvars,SCIP_Bool type,char delimiter)283 SCIP_RETCODE SCIPwriteVarsList(
284 SCIP* scip, /**< SCIP data structure */
285 FILE* file, /**< output file, or NULL for stdout */
286 SCIP_VAR** vars, /**< variable array to output */
287 int nvars, /**< number of variables */
288 SCIP_Bool type, /**< should the variable type be also posted */
289 char delimiter /**< character which is used for delimitation */
290 )
291 {
292 int v;
293
294 SCIP_CALL( SCIPcheckStage(scip, "SCIPwriteVarsList", FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE) );
295
296 for( v = 0; v < nvars; ++v )
297 {
298 if( v > 0 )
299 {
300 SCIPinfoMessage(scip, file, "%c", delimiter);
301 }
302
303 /* print variable name */
304 SCIP_CALL( SCIPwriteVarName(scip, file, vars[v], type) );
305 }
306
307 return SCIP_OKAY;
308 }
309
310 /** print the given variables and coefficients as linear sum in the following form
311 * c1 \<x1\> + c2 \<x2\> ... + cn \<xn\>
312 *
313 * This string can be parsed by the method SCIPparseVarsLinearsum().
314 *
315 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
316 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
317 *
318 * @pre This method can be called if @p scip is in one of the following stages:
319 * - \ref SCIP_STAGE_PROBLEM
320 * - \ref SCIP_STAGE_TRANSFORMING
321 * - \ref SCIP_STAGE_TRANSFORMED
322 * - \ref SCIP_STAGE_INITPRESOLVE
323 * - \ref SCIP_STAGE_PRESOLVING
324 * - \ref SCIP_STAGE_EXITPRESOLVE
325 * - \ref SCIP_STAGE_PRESOLVED
326 * - \ref SCIP_STAGE_INITSOLVE
327 * - \ref SCIP_STAGE_SOLVING
328 * - \ref SCIP_STAGE_SOLVED
329 * - \ref SCIP_STAGE_EXITSOLVE
330 * - \ref SCIP_STAGE_FREETRANS
331 *
332 * @note The printing process is done via the message handler system.
333 */
SCIPwriteVarsLinearsum(SCIP * scip,FILE * file,SCIP_VAR ** vars,SCIP_Real * vals,int nvars,SCIP_Bool type)334 SCIP_RETCODE SCIPwriteVarsLinearsum(
335 SCIP* scip, /**< SCIP data structure */
336 FILE* file, /**< output file, or NULL for stdout */
337 SCIP_VAR** vars, /**< variable array to output */
338 SCIP_Real* vals, /**< array of coefficients or NULL if all coefficients are 1.0 */
339 int nvars, /**< number of variables */
340 SCIP_Bool type /**< should the variable type be also posted */
341 )
342 {
343 int v;
344
345 SCIP_CALL( SCIPcheckStage(scip, "SCIPwriteVarsLinearsum", FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE) );
346
347 for( v = 0; v < nvars; ++v )
348 {
349 if( vals != NULL )
350 {
351 if( vals[v] == 1.0 )
352 {
353 if( v > 0 )
354 SCIPinfoMessage(scip, file, " +");
355 }
356 else if( vals[v] == -1.0 )
357 SCIPinfoMessage(scip, file, " -");
358 else
359 SCIPinfoMessage(scip, file, " %+.15g", vals[v]);
360 }
361 else if( nvars > 0 )
362 SCIPinfoMessage(scip, file, " +");
363
364 /* print variable name */
365 SCIP_CALL( SCIPwriteVarName(scip, file, vars[v], type) );
366 }
367
368 return SCIP_OKAY;
369 }
370
371 /** print the given monomials as polynomial in the following form
372 * c1 \<x11\>^e11 \<x12\>^e12 ... \<x1n\>^e1n + c2 \<x21\>^e21 \<x22\>^e22 ... + ... + cn \<xn1\>^en1 ...
373 *
374 * This string can be parsed by the method SCIPparseVarsPolynomial().
375 *
376 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
377 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
378 *
379 * @pre This method can be called if @p scip is in one of the following stages:
380 * - \ref SCIP_STAGE_PROBLEM
381 * - \ref SCIP_STAGE_TRANSFORMING
382 * - \ref SCIP_STAGE_TRANSFORMED
383 * - \ref SCIP_STAGE_INITPRESOLVE
384 * - \ref SCIP_STAGE_PRESOLVING
385 * - \ref SCIP_STAGE_EXITPRESOLVE
386 * - \ref SCIP_STAGE_PRESOLVED
387 * - \ref SCIP_STAGE_INITSOLVE
388 * - \ref SCIP_STAGE_SOLVING
389 * - \ref SCIP_STAGE_SOLVED
390 * - \ref SCIP_STAGE_EXITSOLVE
391 * - \ref SCIP_STAGE_FREETRANS
392 *
393 * @note The printing process is done via the message handler system.
394 */
SCIPwriteVarsPolynomial(SCIP * scip,FILE * file,SCIP_VAR *** monomialvars,SCIP_Real ** monomialexps,SCIP_Real * monomialcoefs,int * monomialnvars,int nmonomials,SCIP_Bool type)395 SCIP_RETCODE SCIPwriteVarsPolynomial(
396 SCIP* scip, /**< SCIP data structure */
397 FILE* file, /**< output file, or NULL for stdout */
398 SCIP_VAR*** monomialvars, /**< arrays with variables for each monomial */
399 SCIP_Real** monomialexps, /**< arrays with variable exponents, or NULL if always 1.0 */
400 SCIP_Real* monomialcoefs, /**< array with monomial coefficients */
401 int* monomialnvars, /**< array with number of variables for each monomial */
402 int nmonomials, /**< number of monomials */
403 SCIP_Bool type /**< should the variable type be also posted */
404 )
405 {
406 int i;
407 int v;
408
409 assert(scip != NULL);
410 assert(monomialvars != NULL || nmonomials == 0);
411 assert(monomialcoefs != NULL || nmonomials == 0);
412 assert(monomialnvars != NULL || nmonomials == 0);
413
414 SCIP_CALL( SCIPcheckStage(scip, "SCIPwriteVarsPolynomial", FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE) );
415
416 if( nmonomials == 0 )
417 {
418 SCIPinfoMessage(scip, file, " 0 ");
419 return SCIP_OKAY;
420 }
421
422 for( i = 0; i < nmonomials; ++i )
423 {
424 if( monomialcoefs[i] == 1.0 ) /*lint !e613*/
425 {
426 if( i > 0 )
427 SCIPinfoMessage(scip, file, " +");
428 }
429 else if( monomialcoefs[i] == -1.0 ) /*lint !e613*/
430 SCIPinfoMessage(scip, file, " -");
431 else
432 SCIPinfoMessage(scip, file, " %+.15g", monomialcoefs[i]); /*lint !e613*/
433
434 assert(monomialvars[i] != NULL || monomialnvars[i] == 0); /*lint !e613*/
435
436 for( v = 0; v < monomialnvars[i]; ++v ) /*lint !e613*/
437 {
438 SCIP_CALL( SCIPwriteVarName(scip, file, monomialvars[i][v], type) ); /*lint !e613*/
439 if( monomialexps != NULL && monomialexps[i] != NULL && monomialexps[i][v] != 1.0 )
440 {
441 SCIPinfoMessage(scip, file, "^%.15g", monomialexps[i][v]);
442 }
443 }
444 }
445
446 return SCIP_OKAY;
447 }
448
449 /** parses variable information (in cip format) out of a string; if the parsing process was successful a variable is
450 * created and captured; if variable is of integral type, fractional bounds are automatically rounded; an integer
451 * variable with bounds zero and one is automatically converted into a binary variable
452 *
453 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
454 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
455 *
456 * @pre This method can be called if @p scip is in one of the following stages:
457 * - \ref SCIP_STAGE_PROBLEM
458 * - \ref SCIP_STAGE_TRANSFORMING
459 * - \ref SCIP_STAGE_INITPRESOLVE
460 * - \ref SCIP_STAGE_PRESOLVING
461 * - \ref SCIP_STAGE_EXITPRESOLVE
462 * - \ref SCIP_STAGE_PRESOLVED
463 * - \ref SCIP_STAGE_SOLVING
464 */
SCIPparseVar(SCIP * scip,SCIP_VAR ** var,const char * str,SCIP_Bool initial,SCIP_Bool removable,SCIP_DECL_VARCOPY ((* varcopy)),SCIP_DECL_VARDELORIG ((* vardelorig)),SCIP_DECL_VARTRANS ((* vartrans)),SCIP_DECL_VARDELTRANS ((* vardeltrans)),SCIP_VARDATA * vardata,char ** endptr,SCIP_Bool * success)465 SCIP_RETCODE SCIPparseVar(
466 SCIP* scip, /**< SCIP data structure */
467 SCIP_VAR** var, /**< pointer to store the problem variable */
468 const char* str, /**< string to parse */
469 SCIP_Bool initial, /**< should var's column be present in the initial root LP? */
470 SCIP_Bool removable, /**< is var's column removable from the LP (due to aging or cleanup)? */
471 SCIP_DECL_VARCOPY ((*varcopy)), /**< copies variable data if wanted to subscip, or NULL */
472 SCIP_DECL_VARDELORIG ((*vardelorig)), /**< frees user data of original variable */
473 SCIP_DECL_VARTRANS ((*vartrans)), /**< creates transformed user data by transforming original user data */
474 SCIP_DECL_VARDELTRANS ((*vardeltrans)), /**< frees user data of transformed variable */
475 SCIP_VARDATA* vardata, /**< user data for this specific variable */
476 char** endptr, /**< pointer to store the final string position if successful */
477 SCIP_Bool* success /**< pointer store if the paring process was successful */
478 )
479 {
480 assert(var != NULL);
481
482 SCIP_CALL( SCIPcheckStage(scip, "SCIPparseVar", FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
483
484 switch( scip->set->stage )
485 {
486 case SCIP_STAGE_PROBLEM:
487 SCIP_CALL( SCIPvarParseOriginal(var, scip->mem->probmem, scip->set, scip->messagehdlr, scip->stat,
488 str, initial, removable, varcopy, vardelorig, vartrans, vardeltrans, vardata, endptr, success) );
489 break;
490
491 case SCIP_STAGE_TRANSFORMING:
492 case SCIP_STAGE_INITPRESOLVE:
493 case SCIP_STAGE_PRESOLVING:
494 case SCIP_STAGE_EXITPRESOLVE:
495 case SCIP_STAGE_PRESOLVED:
496 case SCIP_STAGE_SOLVING:
497 SCIP_CALL( SCIPvarParseTransformed(var, scip->mem->probmem, scip->set, scip->messagehdlr, scip->stat,
498 str, initial, removable, varcopy, vardelorig, vartrans, vardeltrans, vardata, endptr, success) );
499 break;
500
501 default:
502 SCIPerrorMessage("invalid SCIP stage <%d>\n", scip->set->stage);
503 return SCIP_INVALIDCALL;
504 } /*lint !e788*/
505
506 return SCIP_OKAY;
507 }
508
509 /** parses the given string for a variable name and stores the variable in the corresponding pointer if such a variable
510 * exits and returns the position where the parsing stopped
511 *
512 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
513 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
514 *
515 * @pre This method can be called if @p scip is in one of the following stages:
516 * - \ref SCIP_STAGE_PROBLEM
517 * - \ref SCIP_STAGE_TRANSFORMING
518 * - \ref SCIP_STAGE_INITPRESOLVE
519 * - \ref SCIP_STAGE_PRESOLVING
520 * - \ref SCIP_STAGE_EXITPRESOLVE
521 * - \ref SCIP_STAGE_PRESOLVED
522 * - \ref SCIP_STAGE_SOLVING
523 */
SCIPparseVarName(SCIP * scip,const char * str,SCIP_VAR ** var,char ** endptr)524 SCIP_RETCODE SCIPparseVarName(
525 SCIP* scip, /**< SCIP data structure */
526 const char* str, /**< string to parse */
527 SCIP_VAR** var, /**< pointer to store the problem variable, or NULL if it does not exit */
528 char** endptr /**< pointer to store the final string position if successful */
529 )
530 {
531 char varname[SCIP_MAXSTRLEN];
532
533 assert(str != NULL);
534 assert(var != NULL);
535 assert(endptr != NULL);
536
537 SCIP_CALL( SCIPcheckStage(scip, "SCIPparseVarName", FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
538
539 SCIPstrCopySection(str, '<', '>', varname, SCIP_MAXSTRLEN, endptr);
540 assert(*endptr != NULL);
541
542 if( *varname == '\0' )
543 {
544 SCIPerrorMessage("invalid variable name string given: could not find '<'\n");
545 return SCIP_INVALIDDATA;
546 }
547
548 /* check if we have a negated variable */
549 if( *varname == '~' )
550 {
551 SCIPdebugMsg(scip, "parsed negated variable name <%s>\n", &varname[1]);
552
553 /* search for the variable and ignore '~' */
554 (*var) = SCIPfindVar(scip, &varname[1]);
555
556 if( *var != NULL )
557 {
558 SCIP_CALL( SCIPgetNegatedVar(scip, *var, var) );
559 }
560 }
561 else
562 {
563 SCIPdebugMsg(scip, "parsed variable name <%s>\n", varname);
564
565 /* search for the variable */
566 (*var) = SCIPfindVar(scip, varname);
567 }
568
569 str = *endptr;
570
571 /* skip additional variable type marker */
572 if( *str == '[' && (str[1] == SCIP_VARTYPE_BINARY_CHAR || str[1] == SCIP_VARTYPE_INTEGER_CHAR ||
573 str[1] == SCIP_VARTYPE_IMPLINT_CHAR || str[1] == SCIP_VARTYPE_CONTINUOUS_CHAR ) && str[2] == ']' )
574 (*endptr) += 3;
575
576 return SCIP_OKAY;
577 }
578
579 /** parse the given string as variable list (here ',' is the delimiter)) (\<x1\>, \<x2\>, ..., \<xn\>) (see
580 * SCIPwriteVarsList() ); if it was successful, the pointer success is set to TRUE
581 *
582 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
583 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
584 *
585 * @pre This method can be called if @p scip is in one of the following stages:
586 * - \ref SCIP_STAGE_PROBLEM
587 * - \ref SCIP_STAGE_TRANSFORMING
588 * - \ref SCIP_STAGE_INITPRESOLVE
589 * - \ref SCIP_STAGE_PRESOLVING
590 * - \ref SCIP_STAGE_EXITPRESOLVE
591 * - \ref SCIP_STAGE_PRESOLVED
592 * - \ref SCIP_STAGE_SOLVING
593 *
594 * @note The pointer success in only set to FALSE in the case that a variable with a parsed variable name does not exist.
595 *
596 * @note If the number of (parsed) variables is greater than the available slots in the variable array, nothing happens
597 * except that the required size is stored in the corresponding integer; the reason for this approach is that we
598 * cannot reallocate memory, since we do not know how the memory has been allocated (e.g., by a C++ 'new' or SCIP
599 * memory functions).
600 */
SCIPparseVarsList(SCIP * scip,const char * str,SCIP_VAR ** vars,int * nvars,int varssize,int * requiredsize,char ** endptr,char delimiter,SCIP_Bool * success)601 SCIP_RETCODE SCIPparseVarsList(
602 SCIP* scip, /**< SCIP data structure */
603 const char* str, /**< string to parse */
604 SCIP_VAR** vars, /**< array to store the parsed variable */
605 int* nvars, /**< pointer to store number of parsed variables */
606 int varssize, /**< size of the variable array */
607 int* requiredsize, /**< pointer to store the required array size for the active variables */
608 char** endptr, /**< pointer to store the final string position if successful */
609 char delimiter, /**< character which is used for delimitation */
610 SCIP_Bool* success /**< pointer to store the whether the parsing was successful or not */
611 )
612 {
613 SCIP_VAR** tmpvars;
614 SCIP_VAR* var;
615 int ntmpvars = 0;
616 int v;
617
618 assert( nvars != NULL );
619 assert( requiredsize != NULL );
620 assert( endptr != NULL );
621 assert( success != NULL );
622
623 SCIP_CALL( SCIPcheckStage(scip, "SCIPparseVarsList", FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
624
625 /* allocate buffer memory for temporary storing the parsed variables */
626 SCIP_CALL( SCIPallocBufferArray(scip, &tmpvars, varssize) );
627
628 (*success) = TRUE;
629
630 do
631 {
632 *endptr = (char*)str;
633
634 /* parse variable name */
635 SCIP_CALL( SCIPparseVarName(scip, str, &var, endptr) );
636
637 if( var == NULL )
638 {
639 SCIPdebugMsg(scip, "variable with name <%s> does not exist\n", SCIPvarGetName(var));
640 (*success) = FALSE;
641 break;
642 }
643
644 /* store the variable in the tmp array */
645 if( ntmpvars < varssize )
646 tmpvars[ntmpvars] = var;
647
648 ntmpvars++;
649
650 str = *endptr;
651
652 while( isspace((unsigned char)*str) )
653 str++;
654 }
655 while( *str == delimiter );
656
657 *endptr = (char*)str;
658
659 /* if all variable name searches were successful and the variable array has enough slots, copy the collected variables */
660 if( (*success) && ntmpvars <= varssize )
661 {
662 for( v = 0; v < ntmpvars; ++v )
663 vars[v] = tmpvars[v];
664
665 (*nvars) = ntmpvars;
666 }
667 else
668 (*nvars) = 0;
669
670 (*requiredsize) = ntmpvars;
671
672 /* free buffer arrays */
673 SCIPfreeBufferArray(scip, &tmpvars);
674
675 return SCIP_OKAY;
676 }
677
678 /** parse the given string as linear sum of variables and coefficients (c1 \<x1\> + c2 \<x2\> + ... + cn \<xn\>)
679 * (see SCIPwriteVarsLinearsum() ); if it was successful, the pointer success is set to TRUE
680 *
681 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
682 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
683 *
684 * @pre This method can be called if @p scip is in one of the following stages:
685 * - \ref SCIP_STAGE_PROBLEM
686 * - \ref SCIP_STAGE_TRANSFORMING
687 * - \ref SCIP_STAGE_INITPRESOLVE
688 * - \ref SCIP_STAGE_PRESOLVING
689 * - \ref SCIP_STAGE_EXITPRESOLVE
690 * - \ref SCIP_STAGE_PRESOLVED
691 * - \ref SCIP_STAGE_SOLVING
692 *
693 * @note The pointer success in only set to FALSE in the case that a variable with a parsed variable name does not exist.
694 *
695 * @note If the number of (parsed) variables is greater than the available slots in the variable array, nothing happens
696 * except that the required size is stored in the corresponding integer; the reason for this approach is that we
697 * cannot reallocate memory, since we do not know how the memory has been allocated (e.g., by a C++ 'new' or SCIP
698 * memory functions).
699 */
SCIPparseVarsLinearsum(SCIP * scip,const char * str,SCIP_VAR ** vars,SCIP_Real * vals,int * nvars,int varssize,int * requiredsize,char ** endptr,SCIP_Bool * success)700 SCIP_RETCODE SCIPparseVarsLinearsum(
701 SCIP* scip, /**< SCIP data structure */
702 const char* str, /**< string to parse */
703 SCIP_VAR** vars, /**< array to store the parsed variables */
704 SCIP_Real* vals, /**< array to store the parsed coefficients */
705 int* nvars, /**< pointer to store number of parsed variables */
706 int varssize, /**< size of the variable array */
707 int* requiredsize, /**< pointer to store the required array size for the active variables */
708 char** endptr, /**< pointer to store the final string position if successful */
709 SCIP_Bool* success /**< pointer to store the whether the parsing was successful or not */
710 )
711 {
712 SCIP_VAR*** monomialvars;
713 SCIP_Real** monomialexps;
714 SCIP_Real* monomialcoefs;
715 int* monomialnvars;
716 int nmonomials;
717
718 SCIP_CALL( SCIPcheckStage(scip, "SCIPparseVarsLinearsum", FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
719
720 assert(scip != NULL);
721 assert(str != NULL);
722 assert(vars != NULL || varssize == 0);
723 assert(vals != NULL || varssize == 0);
724 assert(nvars != NULL);
725 assert(requiredsize != NULL);
726 assert(endptr != NULL);
727 assert(success != NULL);
728
729 *requiredsize = 0;
730
731 SCIP_CALL( SCIPparseVarsPolynomial(scip, str, &monomialvars, &monomialexps, &monomialcoefs, &monomialnvars, &nmonomials, endptr, success) );
732
733 if( !*success )
734 {
735 assert(nmonomials == 0); /* SCIPparseVarsPolynomial should have freed all buffers, so no need to call free here */
736 return SCIP_OKAY;
737 }
738
739 /* check if linear sum is just "0" */
740 if( nmonomials == 1 && monomialnvars[0] == 0 && monomialcoefs[0] == 0.0 )
741 {
742 *nvars = 0;
743 *requiredsize = 0;
744
745 SCIPfreeParseVarsPolynomialData(scip, &monomialvars, &monomialexps, &monomialcoefs, &monomialnvars, nmonomials);
746
747 return SCIP_OKAY;
748 }
749
750 *nvars = nmonomials;
751 *requiredsize = nmonomials;
752
753 /* if we have enough slots in the variables array, copy variables over */
754 if( varssize >= nmonomials )
755 {
756 int v;
757
758 for( v = 0; v < nmonomials; ++v )
759 {
760 if( monomialnvars[v] == 0 )
761 {
762 SCIPerrorMessage("constant in linear sum\n");
763 *success = FALSE;
764 break;
765 }
766 if( monomialnvars[v] > 1 || monomialexps[v][0] != 1.0 )
767 {
768 SCIPerrorMessage("nonlinear monomial in linear sum\n");
769 *success = FALSE;
770 break;
771 }
772 assert(monomialnvars[v] == 1);
773 assert(monomialvars[v][0] != NULL);
774 assert(monomialexps[v][0] == 1.0);
775
776 vars[v] = monomialvars[v][0]; /*lint !e613*/
777 vals[v] = monomialcoefs[v]; /*lint !e613*/
778 }
779 }
780
781 SCIPfreeParseVarsPolynomialData(scip, &monomialvars, &monomialexps, &monomialcoefs, &monomialnvars, nmonomials);
782
783 return SCIP_OKAY;
784 }
785
786 /** parse the given string as polynomial of variables and coefficients
787 * (c1 \<x11\>^e11 \<x12\>^e12 ... \<x1n\>^e1n + c2 \<x21\>^e21 \<x22\>^e22 ... + ... + cn \<xn1\>^en1 ...)
788 * (see SCIPwriteVarsPolynomial()); if it was successful, the pointer success is set to TRUE
789 *
790 * The user has to call SCIPfreeParseVarsPolynomialData(scip, monomialvars, monomialexps,
791 * monomialcoefs, monomialnvars, *nmonomials) short after SCIPparseVarsPolynomial to free all the
792 * allocated memory again. Do not keep the arrays created by SCIPparseVarsPolynomial around, since
793 * they use buffer memory that is intended for short term use only.
794 *
795 * Parsing is stopped at the end of string (indicated by the \\0-character) or when no more monomials
796 * are recognized.
797 *
798 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
799 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
800 *
801 * @pre This method can be called if @p scip is in one of the following stages:
802 * - \ref SCIP_STAGE_PROBLEM
803 * - \ref SCIP_STAGE_TRANSFORMING
804 * - \ref SCIP_STAGE_INITPRESOLVE
805 * - \ref SCIP_STAGE_PRESOLVING
806 * - \ref SCIP_STAGE_EXITPRESOLVE
807 * - \ref SCIP_STAGE_PRESOLVED
808 * - \ref SCIP_STAGE_SOLVING
809 */
SCIPparseVarsPolynomial(SCIP * scip,const char * str,SCIP_VAR **** monomialvars,SCIP_Real *** monomialexps,SCIP_Real ** monomialcoefs,int ** monomialnvars,int * nmonomials,char ** endptr,SCIP_Bool * success)810 SCIP_RETCODE SCIPparseVarsPolynomial(
811 SCIP* scip, /**< SCIP data structure */
812 const char* str, /**< string to parse */
813 SCIP_VAR**** monomialvars, /**< pointer to store arrays with variables for each monomial */
814 SCIP_Real*** monomialexps, /**< pointer to store arrays with variable exponents */
815 SCIP_Real** monomialcoefs, /**< pointer to store array with monomial coefficients */
816 int** monomialnvars, /**< pointer to store array with number of variables for each monomial */
817 int* nmonomials, /**< pointer to store number of parsed monomials */
818 char** endptr, /**< pointer to store the final string position if successful */
819 SCIP_Bool* success /**< pointer to store the whether the parsing was successful or not */
820 )
821 {
822 typedef enum
823 {
824 SCIPPARSEPOLYNOMIAL_STATE_BEGIN, /* we are at the beginning of a monomial */
825 SCIPPARSEPOLYNOMIAL_STATE_INTERMED, /* we are in between the factors of a monomial */
826 SCIPPARSEPOLYNOMIAL_STATE_COEF, /* we parse the coefficient of a monomial */
827 SCIPPARSEPOLYNOMIAL_STATE_VARS, /* we parse monomial variables */
828 SCIPPARSEPOLYNOMIAL_STATE_EXPONENT, /* we parse the exponent of a variable */
829 SCIPPARSEPOLYNOMIAL_STATE_END, /* we are at the end the polynomial */
830 SCIPPARSEPOLYNOMIAL_STATE_ERROR /* a parsing error occured */
831 } SCIPPARSEPOLYNOMIAL_STATES;
832
833 SCIPPARSEPOLYNOMIAL_STATES state;
834 int monomialssize;
835
836 /* data of currently parsed monomial */
837 int varssize;
838 int nvars;
839 SCIP_VAR** vars;
840 SCIP_Real* exponents;
841 SCIP_Real coef;
842
843 assert(scip != NULL);
844 assert(str != NULL);
845 assert(monomialvars != NULL);
846 assert(monomialexps != NULL);
847 assert(monomialnvars != NULL);
848 assert(monomialcoefs != NULL);
849 assert(nmonomials != NULL);
850 assert(endptr != NULL);
851 assert(success != NULL);
852
853 SCIP_CALL( SCIPcheckStage(scip, "SCIPparseVarsPolynomial", FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
854
855 *success = FALSE;
856 *nmonomials = 0;
857 monomialssize = 0;
858 *monomialvars = NULL;
859 *monomialexps = NULL;
860 *monomialcoefs = NULL;
861 *monomialnvars = NULL;
862
863 /* initialize state machine */
864 state = SCIPPARSEPOLYNOMIAL_STATE_BEGIN;
865 varssize = 0;
866 nvars = 0;
867 vars = NULL;
868 exponents = NULL;
869 coef = SCIP_INVALID;
870
871 SCIPdebugMsg(scip, "parsing polynomial from '%s'\n", str);
872
873 while( *str && state != SCIPPARSEPOLYNOMIAL_STATE_END && state != SCIPPARSEPOLYNOMIAL_STATE_ERROR )
874 {
875 /* skip white space */
876 while( isspace((unsigned char)*str) )
877 str++;
878
879 assert(state != SCIPPARSEPOLYNOMIAL_STATE_END);
880
881 switch( state )
882 {
883 case SCIPPARSEPOLYNOMIAL_STATE_BEGIN:
884 {
885 if( coef != SCIP_INVALID ) /*lint !e777*/
886 {
887 SCIPdebugMsg(scip, "push monomial with coefficient <%g> and <%d> vars\n", coef, nvars);
888 /* push previous monomial */
889 if( monomialssize <= *nmonomials )
890 {
891 monomialssize = SCIPcalcMemGrowSize(scip, *nmonomials+1);
892
893 SCIP_CALL( SCIPreallocBufferArray(scip, monomialvars, monomialssize) );
894 SCIP_CALL( SCIPreallocBufferArray(scip, monomialexps, monomialssize) );
895 SCIP_CALL( SCIPreallocBufferArray(scip, monomialnvars, monomialssize) );
896 SCIP_CALL( SCIPreallocBufferArray(scip, monomialcoefs, monomialssize) );
897 }
898
899 if( nvars > 0 )
900 {
901 SCIP_CALL( SCIPduplicateBufferArray(scip, &(*monomialvars)[*nmonomials], vars, nvars) ); /*lint !e866*/
902 SCIP_CALL( SCIPduplicateBufferArray(scip, &(*monomialexps)[*nmonomials], exponents, nvars) ); /*lint !e866*/
903 }
904 else
905 {
906 (*monomialvars)[*nmonomials] = NULL;
907 (*monomialexps)[*nmonomials] = NULL;
908 }
909 (*monomialcoefs)[*nmonomials] = coef;
910 (*monomialnvars)[*nmonomials] = nvars;
911 ++*nmonomials;
912
913 nvars = 0;
914 coef = SCIP_INVALID;
915 }
916
917 if( *str == '<' )
918 {
919 /* there seem to come a variable at the beginning of a monomial
920 * so assume the coefficient is 1.0
921 */
922 state = SCIPPARSEPOLYNOMIAL_STATE_VARS;
923 coef = 1.0;
924 }
925 else if( *str == '-' || *str == '+' || isdigit(*str) )
926 state = SCIPPARSEPOLYNOMIAL_STATE_COEF;
927 else
928 state = SCIPPARSEPOLYNOMIAL_STATE_END;
929
930 break;
931 }
932
933 case SCIPPARSEPOLYNOMIAL_STATE_INTERMED:
934 {
935 if( *str == '<' )
936 {
937 /* there seem to come another variable */
938 state = SCIPPARSEPOLYNOMIAL_STATE_VARS;
939 }
940 else if( *str == '-' || *str == '+' || isdigit(*str) )
941 {
942 /* there seem to come a coefficient, which means the next monomial */
943 state = SCIPPARSEPOLYNOMIAL_STATE_BEGIN;
944 }
945 else /* since we cannot detect the symbols we stop parsing the polynomial */
946 state = SCIPPARSEPOLYNOMIAL_STATE_END;
947
948 break;
949 }
950
951 case SCIPPARSEPOLYNOMIAL_STATE_COEF:
952 {
953 if( *str == '+' && !isdigit(str[1]) )
954 {
955 /* only a plus sign, without number */
956 coef = 1.0;
957 ++str;
958 }
959 else if( *str == '-' && !isdigit(str[1]) )
960 {
961 /* only a minus sign, without number */
962 coef = -1.0;
963 ++str;
964 }
965 else if( SCIPstrToRealValue(str, &coef, endptr) )
966 {
967 str = *endptr;
968 }
969 else
970 {
971 SCIPerrorMessage("could not parse number in the beginning of '%s'\n", str);
972 state = SCIPPARSEPOLYNOMIAL_STATE_ERROR;
973 break;
974 }
975
976 /* after the coefficient we go into the intermediate state, i.e., expecting next variables */
977 state = SCIPPARSEPOLYNOMIAL_STATE_INTERMED; /*lint !e838*/
978
979 break;
980 }
981
982 case SCIPPARSEPOLYNOMIAL_STATE_VARS:
983 {
984 SCIP_VAR* var;
985
986 assert(*str == '<');
987
988 /* parse variable name */
989 SCIP_CALL( SCIPparseVarName(scip, str, &var, endptr) );
990
991 /* check if variable name was parsed */
992 if( *endptr == str )
993 {
994 state = SCIPPARSEPOLYNOMIAL_STATE_END;
995 break;
996 }
997
998 if( var == NULL )
999 {
1000 SCIPerrorMessage("did not find variable in the beginning of %s\n", str);
1001 state = SCIPPARSEPOLYNOMIAL_STATE_ERROR;
1002 break;
1003 }
1004
1005 /* add variable to vars array */
1006 if( nvars + 1 > varssize )
1007 {
1008 varssize = SCIPcalcMemGrowSize(scip, nvars+1);
1009 SCIP_CALL( SCIPreallocBufferArray(scip, &vars, varssize) );
1010 SCIP_CALL( SCIPreallocBufferArray(scip, &exponents, varssize) );
1011 }
1012 assert(vars != NULL);
1013 assert(exponents != NULL);
1014
1015 vars[nvars] = var;
1016 exponents[nvars] = 1.0;
1017 ++nvars;
1018
1019 str = *endptr;
1020
1021 if( *str == '^' )
1022 state = SCIPPARSEPOLYNOMIAL_STATE_EXPONENT;
1023 else
1024 state = SCIPPARSEPOLYNOMIAL_STATE_INTERMED;
1025
1026 break;
1027 }
1028
1029 case SCIPPARSEPOLYNOMIAL_STATE_EXPONENT:
1030 {
1031 assert(*str == '^');
1032 assert(nvars > 0); /* we should be in a monomial that has already a variable */
1033 assert(exponents != NULL);
1034 ++str;
1035
1036 if( !SCIPstrToRealValue(str, &exponents[nvars-1], endptr) )
1037 {
1038 SCIPerrorMessage("could not parse number in the beginning of '%s'\n", str);
1039 state = SCIPPARSEPOLYNOMIAL_STATE_ERROR;
1040 break;
1041 }
1042 str = *endptr;
1043
1044 /* after the exponent we go into the intermediate state, i.e., expecting next variables */
1045 state = SCIPPARSEPOLYNOMIAL_STATE_INTERMED; /*lint !e838*/
1046 break;
1047 }
1048
1049 case SCIPPARSEPOLYNOMIAL_STATE_END:
1050 case SCIPPARSEPOLYNOMIAL_STATE_ERROR:
1051 default:
1052 SCIPerrorMessage("unexpected state\n");
1053 return SCIP_READERROR;
1054 }
1055 }
1056
1057 /* set end pointer */
1058 *endptr = (char*)str;
1059
1060 /* check state at end of string */
1061 switch( state )
1062 {
1063 case SCIPPARSEPOLYNOMIAL_STATE_BEGIN:
1064 case SCIPPARSEPOLYNOMIAL_STATE_END:
1065 case SCIPPARSEPOLYNOMIAL_STATE_INTERMED:
1066 {
1067 if( coef != SCIP_INVALID ) /*lint !e777*/
1068 {
1069 /* push last monomial */
1070 SCIPdebugMsg(scip, "push monomial with coefficient <%g> and <%d> vars\n", coef, nvars);
1071 if( monomialssize <= *nmonomials )
1072 {
1073 monomialssize = *nmonomials+1;
1074 SCIP_CALL( SCIPreallocBufferArray(scip, monomialvars, monomialssize) );
1075 SCIP_CALL( SCIPreallocBufferArray(scip, monomialexps, monomialssize) );
1076 SCIP_CALL( SCIPreallocBufferArray(scip, monomialnvars, monomialssize) );
1077 SCIP_CALL( SCIPreallocBufferArray(scip, monomialcoefs, monomialssize) );
1078 }
1079
1080 if( nvars > 0 )
1081 {
1082 /* shrink vars and exponents array to needed size and take over ownership */
1083 SCIP_CALL( SCIPreallocBufferArray(scip, &vars, nvars) );
1084 SCIP_CALL( SCIPreallocBufferArray(scip, &exponents, nvars) );
1085 (*monomialvars)[*nmonomials] = vars;
1086 (*monomialexps)[*nmonomials] = exponents;
1087 vars = NULL;
1088 exponents = NULL;
1089 }
1090 else
1091 {
1092 (*monomialvars)[*nmonomials] = NULL;
1093 (*monomialexps)[*nmonomials] = NULL;
1094 }
1095 (*monomialcoefs)[*nmonomials] = coef;
1096 (*monomialnvars)[*nmonomials] = nvars;
1097 ++*nmonomials;
1098 }
1099
1100 *success = TRUE;
1101 break;
1102 }
1103
1104 case SCIPPARSEPOLYNOMIAL_STATE_COEF:
1105 case SCIPPARSEPOLYNOMIAL_STATE_VARS:
1106 case SCIPPARSEPOLYNOMIAL_STATE_EXPONENT:
1107 {
1108 SCIPerrorMessage("unexpected parsing state at end of polynomial string\n");
1109 }
1110 /*lint -fallthrough*/
1111 case SCIPPARSEPOLYNOMIAL_STATE_ERROR:
1112 assert(!*success);
1113 break;
1114 }
1115
1116 /* free memory to store current monomial, if still existing */
1117 SCIPfreeBufferArrayNull(scip, &vars);
1118 SCIPfreeBufferArrayNull(scip, &exponents);
1119
1120 if( *success && *nmonomials > 0 )
1121 {
1122 /* shrink arrays to required size, so we do not need to keep monomialssize around */
1123 assert(*nmonomials <= monomialssize);
1124 SCIP_CALL( SCIPreallocBufferArray(scip, monomialvars, *nmonomials) );
1125 SCIP_CALL( SCIPreallocBufferArray(scip, monomialexps, *nmonomials) );
1126 SCIP_CALL( SCIPreallocBufferArray(scip, monomialnvars, *nmonomials) );
1127 SCIP_CALL( SCIPreallocBufferArray(scip, monomialcoefs, *nmonomials) );
1128
1129 /* SCIPwriteVarsPolynomial(scip, NULL, *monomialvars, *monomialexps, *monomialcoefs, *monomialnvars, *nmonomials, FALSE); */
1130 }
1131 else
1132 {
1133 /* in case of error, cleanup all data here */
1134 SCIPfreeParseVarsPolynomialData(scip, monomialvars, monomialexps, monomialcoefs, monomialnvars, *nmonomials);
1135 *nmonomials = 0;
1136 }
1137
1138 return SCIP_OKAY;
1139 }
1140
1141 /** frees memory allocated when parsing a polynomial from a string
1142 *
1143 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
1144 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
1145 *
1146 * @pre This method can be called if @p scip is in one of the following stages:
1147 * - \ref SCIP_STAGE_PROBLEM
1148 * - \ref SCIP_STAGE_TRANSFORMING
1149 * - \ref SCIP_STAGE_INITPRESOLVE
1150 * - \ref SCIP_STAGE_PRESOLVING
1151 * - \ref SCIP_STAGE_EXITPRESOLVE
1152 * - \ref SCIP_STAGE_PRESOLVED
1153 * - \ref SCIP_STAGE_SOLVING
1154 */
SCIPfreeParseVarsPolynomialData(SCIP * scip,SCIP_VAR **** monomialvars,SCIP_Real *** monomialexps,SCIP_Real ** monomialcoefs,int ** monomialnvars,int nmonomials)1155 void SCIPfreeParseVarsPolynomialData(
1156 SCIP* scip, /**< SCIP data structure */
1157 SCIP_VAR**** monomialvars, /**< pointer to store arrays with variables for each monomial */
1158 SCIP_Real*** monomialexps, /**< pointer to store arrays with variable exponents */
1159 SCIP_Real** monomialcoefs, /**< pointer to store array with monomial coefficients */
1160 int** monomialnvars, /**< pointer to store array with number of variables for each monomial */
1161 int nmonomials /**< pointer to store number of parsed monomials */
1162 )
1163 {
1164 int i;
1165
1166 assert(scip != NULL);
1167 assert(monomialvars != NULL);
1168 assert(monomialexps != NULL);
1169 assert(monomialcoefs != NULL);
1170 assert(monomialnvars != NULL);
1171 assert((*monomialvars != NULL) == (nmonomials > 0));
1172 assert((*monomialexps != NULL) == (nmonomials > 0));
1173 assert((*monomialcoefs != NULL) == (nmonomials > 0));
1174 assert((*monomialnvars != NULL) == (nmonomials > 0));
1175
1176 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPfreeParseVarsPolynomialData", FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
1177
1178 if( nmonomials == 0 )
1179 return;
1180
1181 for( i = nmonomials - 1; i >= 0; --i )
1182 {
1183 SCIPfreeBufferArrayNull(scip, &(*monomialexps)[i]);
1184 SCIPfreeBufferArrayNull(scip, &(*monomialvars)[i]);
1185 }
1186
1187 SCIPfreeBufferArray(scip, monomialcoefs);
1188 SCIPfreeBufferArray(scip, monomialnvars);
1189 SCIPfreeBufferArray(scip, monomialexps);
1190 SCIPfreeBufferArray(scip, monomialvars);
1191 }
1192
1193 /** increases usage counter of variable
1194 *
1195 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
1196 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
1197 *
1198 * @pre This method can be called if @p scip is in one of the following stages:
1199 * - \ref SCIP_STAGE_PROBLEM
1200 * - \ref SCIP_STAGE_TRANSFORMING
1201 * - \ref SCIP_STAGE_TRANSFORMED
1202 * - \ref SCIP_STAGE_INITPRESOLVE
1203 * - \ref SCIP_STAGE_PRESOLVING
1204 * - \ref SCIP_STAGE_EXITPRESOLVE
1205 * - \ref SCIP_STAGE_PRESOLVED
1206 * - \ref SCIP_STAGE_INITSOLVE
1207 * - \ref SCIP_STAGE_SOLVING
1208 * - \ref SCIP_STAGE_SOLVED
1209 * - \ref SCIP_STAGE_EXITSOLVE
1210 */
SCIPcaptureVar(SCIP * scip,SCIP_VAR * var)1211 SCIP_RETCODE SCIPcaptureVar(
1212 SCIP* scip, /**< SCIP data structure */
1213 SCIP_VAR* var /**< variable to capture */
1214 )
1215 {
1216 SCIP_CALL( SCIPcheckStage(scip, "SCIPcaptureVar", FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE) );
1217 assert(var->scip == scip);
1218
1219 SCIPvarCapture(var);
1220
1221 return SCIP_OKAY;
1222 }
1223
1224 /** decreases usage counter of variable, if the usage pointer reaches zero the variable gets freed
1225 *
1226 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
1227 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
1228 *
1229 * @pre This method can be called if @p scip is in one of the following stages:
1230 * - \ref SCIP_STAGE_PROBLEM
1231 * - \ref SCIP_STAGE_TRANSFORMING
1232 * - \ref SCIP_STAGE_TRANSFORMED
1233 * - \ref SCIP_STAGE_INITPRESOLVE
1234 * - \ref SCIP_STAGE_PRESOLVING
1235 * - \ref SCIP_STAGE_EXITPRESOLVE
1236 * - \ref SCIP_STAGE_PRESOLVED
1237 * - \ref SCIP_STAGE_INITSOLVE
1238 * - \ref SCIP_STAGE_SOLVING
1239 * - \ref SCIP_STAGE_SOLVED
1240 * - \ref SCIP_STAGE_EXITSOLVE
1241 * - \ref SCIP_STAGE_FREETRANS
1242 *
1243 * @note the pointer of the variable will be NULLed
1244 */
SCIPreleaseVar(SCIP * scip,SCIP_VAR ** var)1245 SCIP_RETCODE SCIPreleaseVar(
1246 SCIP* scip, /**< SCIP data structure */
1247 SCIP_VAR** var /**< pointer to variable */
1248 )
1249 {
1250 assert(var != NULL);
1251 assert(*var != NULL);
1252 assert((*var)->scip == scip);
1253
1254 SCIP_CALL( SCIPcheckStage(scip, "SCIPreleaseVar", FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE) );
1255
1256 switch( scip->set->stage )
1257 {
1258 case SCIP_STAGE_PROBLEM:
1259 SCIP_CALL( SCIPvarRelease(var, scip->mem->probmem, scip->set, scip->eventqueue, scip->lp) );
1260 return SCIP_OKAY;
1261
1262 case SCIP_STAGE_TRANSFORMING:
1263 case SCIP_STAGE_TRANSFORMED:
1264 case SCIP_STAGE_INITPRESOLVE:
1265 case SCIP_STAGE_PRESOLVING:
1266 case SCIP_STAGE_EXITPRESOLVE:
1267 case SCIP_STAGE_PRESOLVED:
1268 case SCIP_STAGE_INITSOLVE:
1269 case SCIP_STAGE_SOLVING:
1270 case SCIP_STAGE_SOLVED:
1271 case SCIP_STAGE_EXITSOLVE:
1272 case SCIP_STAGE_FREETRANS:
1273 if( !SCIPvarIsTransformed(*var) && (*var)->nuses == 1 )
1274 {
1275 SCIPerrorMessage("cannot release last use of original variable while the transformed problem exists\n");
1276 return SCIP_INVALIDCALL;
1277 }
1278 SCIP_CALL( SCIPvarRelease(var, scip->mem->probmem, scip->set, scip->eventqueue, scip->lp) );
1279 return SCIP_OKAY;
1280
1281 default:
1282 SCIPerrorMessage("invalid SCIP stage <%d>\n", scip->set->stage);
1283 return SCIP_INVALIDCALL;
1284 } /*lint !e788*/
1285 }
1286
1287 /** changes the name of a variable
1288 *
1289 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
1290 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
1291 *
1292 * @pre This method can only be called if @p scip is in stage \ref SCIP_STAGE_PROBLEM
1293 *
1294 * @note to get the current name of a variable, use SCIPvarGetName() from pub_var.h
1295 */
SCIPchgVarName(SCIP * scip,SCIP_VAR * var,const char * name)1296 SCIP_RETCODE SCIPchgVarName(
1297 SCIP* scip, /**< SCIP data structure */
1298 SCIP_VAR* var, /**< variable */
1299 const char* name /**< new name of constraint */
1300 )
1301 {
1302 SCIP_CALL( SCIPcheckStage(scip, "SCIPchgVarName", FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE) );
1303 assert( var->scip == scip );
1304
1305 if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
1306 {
1307 SCIPerrorMessage("variable names can only be changed in problem creation stage\n");
1308 SCIPABORT();
1309 return SCIP_INVALIDCALL; /*lint !e527*/
1310 }
1311
1312 /* remove variable's name from the namespace if the variable was already added */
1313 if( SCIPvarGetProbindex(var) != -1 )
1314 {
1315 SCIP_CALL( SCIPprobRemoveVarName(scip->origprob, var) );
1316 }
1317
1318 /* change variable name */
1319 SCIP_CALL( SCIPvarChgName(var, SCIPblkmem(scip), name) );
1320
1321 /* add variable's name to the namespace if the variable was already added */
1322 if( SCIPvarGetProbindex(var) != -1 )
1323 {
1324 SCIP_CALL( SCIPprobAddVarName(scip->origprob, var) );
1325 }
1326
1327 return SCIP_OKAY;
1328 }
1329
1330 /** gets and captures transformed variable of a given variable; if the variable is not yet transformed,
1331 * a new transformed variable for this variable is created
1332 *
1333 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
1334 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
1335 *
1336 * @pre This method can be called if @p scip is in one of the following stages:
1337 * - \ref SCIP_STAGE_TRANSFORMING
1338 * - \ref SCIP_STAGE_TRANSFORMED
1339 * - \ref SCIP_STAGE_INITPRESOLVE
1340 * - \ref SCIP_STAGE_PRESOLVING
1341 * - \ref SCIP_STAGE_EXITPRESOLVE
1342 * - \ref SCIP_STAGE_PRESOLVED
1343 * - \ref SCIP_STAGE_INITSOLVE
1344 * - \ref SCIP_STAGE_SOLVING
1345 */
SCIPtransformVar(SCIP * scip,SCIP_VAR * var,SCIP_VAR ** transvar)1346 SCIP_RETCODE SCIPtransformVar(
1347 SCIP* scip, /**< SCIP data structure */
1348 SCIP_VAR* var, /**< variable to get/create transformed variable for */
1349 SCIP_VAR** transvar /**< pointer to store the transformed variable */
1350 )
1351 {
1352 assert(transvar != NULL);
1353
1354 SCIP_CALL( SCIPcheckStage(scip, "SCIPtransformVar", FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
1355
1356 if( SCIPvarIsTransformed(var) )
1357 {
1358 *transvar = var;
1359 SCIPvarCapture(*transvar);
1360 }
1361 else
1362 {
1363 SCIP_CALL( SCIPvarTransform(var, scip->mem->probmem, scip->set, scip->stat, scip->origprob->objsense, transvar) );
1364 }
1365
1366 return SCIP_OKAY;
1367 }
1368
1369 /** gets and captures transformed variables for an array of variables;
1370 * if a variable of the array is not yet transformed, a new transformed variable for this variable is created;
1371 * it is possible to call this method with vars == transvars
1372 *
1373 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
1374 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
1375 *
1376 * @pre This method can be called if @p scip is in one of the following stages:
1377 * - \ref SCIP_STAGE_TRANSFORMING
1378 * - \ref SCIP_STAGE_TRANSFORMED
1379 * - \ref SCIP_STAGE_INITPRESOLVE
1380 * - \ref SCIP_STAGE_PRESOLVING
1381 * - \ref SCIP_STAGE_EXITPRESOLVE
1382 * - \ref SCIP_STAGE_PRESOLVED
1383 * - \ref SCIP_STAGE_INITSOLVE
1384 * - \ref SCIP_STAGE_SOLVING
1385 */
SCIPtransformVars(SCIP * scip,int nvars,SCIP_VAR ** vars,SCIP_VAR ** transvars)1386 SCIP_RETCODE SCIPtransformVars(
1387 SCIP* scip, /**< SCIP data structure */
1388 int nvars, /**< number of variables to get/create transformed variables for */
1389 SCIP_VAR** vars, /**< array with variables to get/create transformed variables for */
1390 SCIP_VAR** transvars /**< array to store the transformed variables */
1391 )
1392 {
1393 int v;
1394
1395 assert(nvars == 0 || vars != NULL);
1396 assert(nvars == 0 || transvars != NULL);
1397
1398 SCIP_CALL( SCIPcheckStage(scip, "SCIPtransformVars", FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
1399
1400 for( v = 0; v < nvars; ++v )
1401 {
1402 if( SCIPvarIsTransformed(vars[v]) )
1403 {
1404 transvars[v] = vars[v];
1405 SCIPvarCapture(transvars[v]);
1406 }
1407 else
1408 {
1409 SCIP_CALL( SCIPvarTransform(vars[v], scip->mem->probmem, scip->set, scip->stat, scip->origprob->objsense,
1410 &transvars[v]) );
1411 }
1412 }
1413
1414 return SCIP_OKAY;
1415 }
1416
1417 /** gets corresponding transformed variable of a given variable;
1418 * returns NULL as transvar, if transformed variable is not yet existing
1419 *
1420 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
1421 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
1422 *
1423 * @pre This method can be called if @p scip is in one of the following stages:
1424 * - \ref SCIP_STAGE_TRANSFORMING
1425 * - \ref SCIP_STAGE_TRANSFORMED
1426 * - \ref SCIP_STAGE_INITPRESOLVE
1427 * - \ref SCIP_STAGE_PRESOLVING
1428 * - \ref SCIP_STAGE_EXITPRESOLVE
1429 * - \ref SCIP_STAGE_PRESOLVED
1430 * - \ref SCIP_STAGE_INITSOLVE
1431 * - \ref SCIP_STAGE_SOLVING
1432 * - \ref SCIP_STAGE_SOLVED
1433 * - \ref SCIP_STAGE_EXITSOLVE
1434 * - \ref SCIP_STAGE_FREETRANS
1435 */
SCIPgetTransformedVar(SCIP * scip,SCIP_VAR * var,SCIP_VAR ** transvar)1436 SCIP_RETCODE SCIPgetTransformedVar(
1437 SCIP* scip, /**< SCIP data structure */
1438 SCIP_VAR* var, /**< variable to get transformed variable for */
1439 SCIP_VAR** transvar /**< pointer to store the transformed variable */
1440 )
1441 {
1442 assert(transvar != NULL);
1443
1444 SCIP_CALL( SCIPcheckStage(scip, "SCIPgetTransformedVar", FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE) );
1445
1446 if( SCIPvarIsTransformed(var) )
1447 *transvar = var;
1448 else
1449 {
1450 SCIP_CALL( SCIPvarGetTransformed(var, scip->mem->probmem, scip->set, scip->stat, transvar) );
1451 }
1452
1453 return SCIP_OKAY;
1454 }
1455
1456 /** gets corresponding transformed variables for an array of variables;
1457 * stores NULL in a transvars slot, if the transformed variable is not yet existing;
1458 * it is possible to call this method with vars == transvars, but remember that variables that are not
1459 * yet transformed will be replaced with NULL
1460 *
1461 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
1462 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
1463 *
1464 * @pre This method can be called if @p scip is in one of the following stages:
1465 * - \ref SCIP_STAGE_TRANSFORMING
1466 * - \ref SCIP_STAGE_TRANSFORMED
1467 * - \ref SCIP_STAGE_INITPRESOLVE
1468 * - \ref SCIP_STAGE_PRESOLVING
1469 * - \ref SCIP_STAGE_EXITPRESOLVE
1470 * - \ref SCIP_STAGE_PRESOLVED
1471 * - \ref SCIP_STAGE_INITSOLVE
1472 * - \ref SCIP_STAGE_SOLVING
1473 * - \ref SCIP_STAGE_SOLVED
1474 * - \ref SCIP_STAGE_EXITSOLVE
1475 * - \ref SCIP_STAGE_FREETRANS
1476 */
SCIPgetTransformedVars(SCIP * scip,int nvars,SCIP_VAR ** vars,SCIP_VAR ** transvars)1477 SCIP_RETCODE SCIPgetTransformedVars(
1478 SCIP* scip, /**< SCIP data structure */
1479 int nvars, /**< number of variables to get transformed variables for */
1480 SCIP_VAR** vars, /**< array with variables to get transformed variables for */
1481 SCIP_VAR** transvars /**< array to store the transformed variables */
1482 )
1483 {
1484 int v;
1485
1486 assert(nvars == 0 || vars != NULL);
1487 assert(nvars == 0 || transvars != NULL);
1488
1489 SCIP_CALL( SCIPcheckStage(scip, "SCIPgetTransformedVars", FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE) );
1490
1491 for( v = 0; v < nvars; ++v )
1492 {
1493 if( SCIPvarIsTransformed(vars[v]) )
1494 transvars[v] = vars[v];
1495 else
1496 {
1497 SCIP_CALL( SCIPvarGetTransformed(vars[v], scip->mem->probmem, scip->set, scip->stat, &transvars[v]) );
1498 }
1499 }
1500
1501 return SCIP_OKAY;
1502 }
1503
1504 /** gets negated variable x' = lb + ub - x of variable x; negated variable is created, if not yet existing;
1505 * in difference to \ref SCIPcreateVar, the negated variable must not be released (unless captured explicitly)
1506 *
1507 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
1508 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
1509 *
1510 * @pre This method can be called if @p scip is in one of the following stages:
1511 * - \ref SCIP_STAGE_PROBLEM
1512 * - \ref SCIP_STAGE_TRANSFORMING
1513 * - \ref SCIP_STAGE_TRANSFORMED
1514 * - \ref SCIP_STAGE_INITPRESOLVE
1515 * - \ref SCIP_STAGE_PRESOLVING
1516 * - \ref SCIP_STAGE_EXITPRESOLVE
1517 * - \ref SCIP_STAGE_PRESOLVED
1518 * - \ref SCIP_STAGE_INITSOLVE
1519 * - \ref SCIP_STAGE_SOLVING
1520 * - \ref SCIP_STAGE_SOLVED
1521 * - \ref SCIP_STAGE_EXITSOLVE
1522 * - \ref SCIP_STAGE_FREETRANS
1523 */
SCIPgetNegatedVar(SCIP * scip,SCIP_VAR * var,SCIP_VAR ** negvar)1524 SCIP_RETCODE SCIPgetNegatedVar(
1525 SCIP* scip, /**< SCIP data structure */
1526 SCIP_VAR* var, /**< variable to get negated variable for */
1527 SCIP_VAR** negvar /**< pointer to store the negated variable */
1528 )
1529 {
1530 SCIP_CALL( SCIPcheckStage(scip, "SCIPgetNegatedVar", FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE) );
1531 assert( var->scip == scip );
1532
1533 SCIP_CALL( SCIPvarNegate(var, scip->mem->probmem, scip->set, scip->stat, negvar) );
1534
1535 return SCIP_OKAY;
1536 }
1537
1538 /** gets negated variables x' = lb + ub - x of variables x; negated variables are created, if not yet existing
1539 *
1540 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
1541 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
1542 *
1543 * @pre This method can be called if @p scip is in one of the following stages:
1544 * - \ref SCIP_STAGE_PROBLEM
1545 * - \ref SCIP_STAGE_TRANSFORMING
1546 * - \ref SCIP_STAGE_TRANSFORMED
1547 * - \ref SCIP_STAGE_INITPRESOLVE
1548 * - \ref SCIP_STAGE_PRESOLVING
1549 * - \ref SCIP_STAGE_EXITPRESOLVE
1550 * - \ref SCIP_STAGE_PRESOLVED
1551 * - \ref SCIP_STAGE_INITSOLVE
1552 * - \ref SCIP_STAGE_SOLVING
1553 * - \ref SCIP_STAGE_SOLVED
1554 * - \ref SCIP_STAGE_EXITSOLVE
1555 * - \ref SCIP_STAGE_FREETRANS
1556 */
SCIPgetNegatedVars(SCIP * scip,int nvars,SCIP_VAR ** vars,SCIP_VAR ** negvars)1557 SCIP_RETCODE SCIPgetNegatedVars(
1558 SCIP* scip, /**< SCIP data structure */
1559 int nvars, /**< number of variables to get negated variables for */
1560 SCIP_VAR** vars, /**< array of variables to get negated variables for */
1561 SCIP_VAR** negvars /**< array to store the negated variables */
1562 )
1563 {
1564 int v;
1565
1566 SCIP_CALL( SCIPcheckStage(scip, "SCIPgetNegatedVars", FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE) );
1567
1568 for( v = 0; v < nvars; ++v )
1569 {
1570 SCIP_CALL( SCIPvarNegate(vars[v], scip->mem->probmem, scip->set, scip->stat, &(negvars[v])) );
1571 }
1572
1573 return SCIP_OKAY;
1574 }
1575
1576 /** gets a binary variable that is equal to the given binary variable, and that is either active, fixed, or
1577 * multi-aggregated, or the negated variable of an active, fixed, or multi-aggregated variable
1578 *
1579 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
1580 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
1581 *
1582 * @pre This method can be called if @p scip is in one of the following stages:
1583 * - \ref SCIP_STAGE_PROBLEM
1584 * - \ref SCIP_STAGE_TRANSFORMED
1585 * - \ref SCIP_STAGE_INITPRESOLVE
1586 * - \ref SCIP_STAGE_PRESOLVING
1587 * - \ref SCIP_STAGE_EXITPRESOLVE
1588 * - \ref SCIP_STAGE_PRESOLVED
1589 * - \ref SCIP_STAGE_INITSOLVE
1590 * - \ref SCIP_STAGE_SOLVING
1591 * - \ref SCIP_STAGE_SOLVED
1592 * - \ref SCIP_STAGE_EXITSOLVE
1593 */
SCIPgetBinvarRepresentative(SCIP * scip,SCIP_VAR * var,SCIP_VAR ** repvar,SCIP_Bool * negated)1594 SCIP_RETCODE SCIPgetBinvarRepresentative(
1595 SCIP* scip, /**< SCIP data structure */
1596 SCIP_VAR* var, /**< binary variable to get binary representative for */
1597 SCIP_VAR** repvar, /**< pointer to store the binary representative */
1598 SCIP_Bool* negated /**< pointer to store whether the negation of an active variable was returned */
1599 )
1600 {
1601 assert(scip != NULL);
1602 assert(var != NULL);
1603 assert(repvar != NULL);
1604 assert(negated != NULL);
1605 assert(var->scip == scip);
1606
1607 SCIP_CALL( SCIPcheckStage(scip, "SCIPgetBinvarRepresentative", FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE) );
1608
1609 /* get the active representative of the given variable */
1610 *repvar = var;
1611 *negated = FALSE;
1612 SCIP_CALL( SCIPvarGetProbvarBinary(repvar, negated) );
1613
1614 /* negate the representative, if it corresponds to the negation of the given variable */
1615 if( *negated )
1616 {
1617 SCIP_CALL( SCIPgetNegatedVar(scip, *repvar, repvar) );
1618 }
1619
1620 return SCIP_OKAY;
1621 }
1622
1623 /** gets binary variables that are equal to the given binary variables, and which are either active, fixed, or
1624 * multi-aggregated, or the negated variables of active, fixed, or multi-aggregated variables
1625 *
1626 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
1627 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
1628 *
1629 * @pre This method can be called if @p scip is in one of the following stages:
1630 * - \ref SCIP_STAGE_PROBLEM
1631 * - \ref SCIP_STAGE_TRANSFORMED
1632 * - \ref SCIP_STAGE_INITPRESOLVE
1633 * - \ref SCIP_STAGE_PRESOLVING
1634 * - \ref SCIP_STAGE_EXITPRESOLVE
1635 * - \ref SCIP_STAGE_PRESOLVED
1636 * - \ref SCIP_STAGE_INITSOLVE
1637 * - \ref SCIP_STAGE_SOLVING
1638 * - \ref SCIP_STAGE_SOLVED
1639 * - \ref SCIP_STAGE_EXITSOLVE
1640 */
SCIPgetBinvarRepresentatives(SCIP * scip,int nvars,SCIP_VAR ** vars,SCIP_VAR ** repvars,SCIP_Bool * negated)1641 SCIP_RETCODE SCIPgetBinvarRepresentatives(
1642 SCIP* scip, /**< SCIP data structure */
1643 int nvars, /**< number of binary variables to get representatives for */
1644 SCIP_VAR** vars, /**< binary variables to get binary representatives for */
1645 SCIP_VAR** repvars, /**< array to store the binary representatives */
1646 SCIP_Bool* negated /**< array to store whether the negation of an active variable was returned */
1647 )
1648 {
1649 int v;
1650
1651 assert(scip != NULL);
1652 assert(vars != NULL || nvars == 0);
1653 assert(repvars != NULL || nvars == 0);
1654 assert(negated != NULL || nvars == 0);
1655
1656 SCIP_CALL( SCIPcheckStage(scip, "SCIPgetBinvarRepresentatives", FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE) );
1657
1658 if( nvars == 0 )
1659 return SCIP_OKAY;
1660
1661 /* get the active representative of the given variable */
1662 BMScopyMemoryArray(repvars, vars, nvars);
1663 BMSclearMemoryArray(negated, nvars);
1664 SCIP_CALL( SCIPvarsGetProbvarBinary(&repvars, &negated, nvars) );
1665
1666 /* negate the representatives, if they correspond to the negation of the given variables */
1667 for( v = nvars - 1; v >= 0; --v )
1668 if( negated[v] )
1669 {
1670 SCIP_CALL( SCIPgetNegatedVar(scip, repvars[v], &(repvars[v])) );
1671 }
1672
1673 return SCIP_OKAY;
1674 }
1675
1676 /** flattens aggregation graph of multi-aggregated variable in order to avoid exponential recursion later on
1677 *
1678 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
1679 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
1680 *
1681 * @pre This method can be called if @p scip is in one of the following stages:
1682 * - \ref SCIP_STAGE_INITPRESOLVE
1683 * - \ref SCIP_STAGE_PRESOLVING
1684 * - \ref SCIP_STAGE_EXITPRESOLVE
1685 * - \ref SCIP_STAGE_PRESOLVED
1686 * - \ref SCIP_STAGE_INITSOLVE
1687 * - \ref SCIP_STAGE_SOLVING
1688 * - \ref SCIP_STAGE_SOLVED
1689 */
SCIPflattenVarAggregationGraph(SCIP * scip,SCIP_VAR * var)1690 SCIP_RETCODE SCIPflattenVarAggregationGraph(
1691 SCIP* scip, /**< SCIP data structure */
1692 SCIP_VAR* var /**< problem variable */
1693 )
1694 {
1695 assert( scip != NULL );
1696 assert( var != NULL );
1697 SCIP_CALL( SCIPcheckStage(scip, "SCIPflattenVarAggregationGraph", FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE) );
1698
1699 SCIP_CALL( SCIPvarFlattenAggregationGraph(var, scip->mem->probmem, scip->set, scip->eventqueue) );
1700
1701 return SCIP_OKAY;
1702 }
1703
1704 /** Transforms a given linear sum of variables, that is a_1*x_1 + ... + a_n*x_n + c into a corresponding linear sum of
1705 * active variables, that is b_1*y_1 + ... + b_m*y_m + d.
1706 *
1707 * If the number of needed active variables is greater than the available slots in the variable array, nothing happens
1708 * except that the required size is stored in the corresponding variable (requiredsize). Otherwise, the active variable
1709 * representation is stored in the variable array, scalar array and constant.
1710 *
1711 * The reason for this approach is that we cannot reallocate memory, since we do not know how the memory has been
1712 * allocated (e.g., by a C++ 'new' or SCIP functions).
1713 *
1714 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
1715 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
1716 *
1717 * @pre This method can be called if @p scip is in one of the following stages:
1718 * - \ref SCIP_STAGE_TRANSFORMED
1719 * - \ref SCIP_STAGE_INITPRESOLVE
1720 * - \ref SCIP_STAGE_PRESOLVING
1721 * - \ref SCIP_STAGE_EXITPRESOLVE
1722 * - \ref SCIP_STAGE_PRESOLVED
1723 * - \ref SCIP_STAGE_INITSOLVE
1724 * - \ref SCIP_STAGE_SOLVING
1725 * - \ref SCIP_STAGE_SOLVED
1726 * - \ref SCIP_STAGE_EXITSOLVE
1727 * - \ref SCIP_STAGE_FREETRANS
1728 *
1729 * @note The resulting linear sum is stored into the given variable array, scalar array, and constant. That means the
1730 * given entries are overwritten.
1731 *
1732 * @note That method can be used to convert a single variables into variable space of active variables. Therefore call
1733 * the method with the linear sum 1.0*x + 0.0.
1734 */
SCIPgetProbvarLinearSum(SCIP * scip,SCIP_VAR ** vars,SCIP_Real * scalars,int * nvars,int varssize,SCIP_Real * constant,int * requiredsize,SCIP_Bool mergemultiples)1735 SCIP_RETCODE SCIPgetProbvarLinearSum(
1736 SCIP* scip, /**< SCIP data structure */
1737 SCIP_VAR** vars, /**< variable array x_1, ..., x_n in the linear sum which will be
1738 * overwritten by the variable array y_1, ..., y_m in the linear sum
1739 * w.r.t. active variables */
1740 SCIP_Real* scalars, /**< scalars a_1, ..., a_n in linear sum which will be overwritten to the
1741 * scalars b_1, ..., b_m in the linear sum of the active variables */
1742 int* nvars, /**< pointer to number of variables in the linear sum which will be
1743 * overwritten by the number of variables in the linear sum corresponding
1744 * to the active variables */
1745 int varssize, /**< available slots in vars and scalars array which is needed to check if
1746 * the array are large enough for the linear sum w.r.t. active
1747 * variables */
1748 SCIP_Real* constant, /**< pointer to constant c in linear sum a_1*x_1 + ... + a_n*x_n + c which
1749 * will chnage to constant d in the linear sum b_1*y_1 + ... + b_m*y_m +
1750 * d w.r.t. the active variables */
1751 int* requiredsize, /**< pointer to store the required array size for the linear sum w.r.t. the
1752 * active variables */
1753 SCIP_Bool mergemultiples /**< should multiple occurrences of a var be replaced by a single coeff? */
1754 )
1755 {
1756 assert( scip != NULL );
1757 assert( nvars != NULL );
1758 assert( vars != NULL || *nvars == 0 );
1759 assert( scalars != NULL || *nvars == 0 );
1760 assert( constant != NULL );
1761 assert( requiredsize != NULL );
1762 assert( *nvars <= varssize );
1763
1764 SCIP_CALL( SCIPcheckStage(scip, "SCIPgetProbvarLinearSum", FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE) );
1765 SCIP_CALL( SCIPvarGetActiveRepresentatives(scip->set, vars, scalars, nvars, varssize, constant, requiredsize, mergemultiples) );
1766
1767 return SCIP_OKAY;
1768 }
1769
1770 /** transforms given variable, scalar and constant to the corresponding active, fixed, or
1771 * multi-aggregated variable, scalar and constant; if the variable resolves to a fixed variable,
1772 * "scalar" will be 0.0 and the value of the sum will be stored in "constant"; a multi-aggregation
1773 * with only one active variable (this can happen due to fixings after the multi-aggregation),
1774 * is treated like an aggregation; if the multi-aggregation constant is infinite, "scalar" will be 0.0
1775 *
1776 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
1777 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
1778 *
1779 * @pre This method can be called if @p scip is in one of the following stages:
1780 * - \ref SCIP_STAGE_TRANSFORMED
1781 * - \ref SCIP_STAGE_INITPRESOLVE
1782 * - \ref SCIP_STAGE_PRESOLVING
1783 * - \ref SCIP_STAGE_EXITPRESOLVE
1784 * - \ref SCIP_STAGE_PRESOLVED
1785 * - \ref SCIP_STAGE_INITSOLVE
1786 * - \ref SCIP_STAGE_SOLVING
1787 * - \ref SCIP_STAGE_SOLVED
1788 * - \ref SCIP_STAGE_EXITSOLVE
1789 * - \ref SCIP_STAGE_FREETRANS
1790 */
SCIPgetProbvarSum(SCIP * scip,SCIP_VAR ** var,SCIP_Real * scalar,SCIP_Real * constant)1791 SCIP_RETCODE SCIPgetProbvarSum(
1792 SCIP* scip, /**< SCIP data structure */
1793 SCIP_VAR** var, /**< pointer to problem variable x in sum a*x + c */
1794 SCIP_Real* scalar, /**< pointer to scalar a in sum a*x + c */
1795 SCIP_Real* constant /**< pointer to constant c in sum a*x + c */
1796 )
1797 {
1798 assert(scip != NULL);
1799 assert(var != NULL);
1800 assert(scalar != NULL);
1801 assert(constant != NULL);
1802
1803 SCIP_CALL( SCIPcheckStage(scip, "SCIPgetProbvarSum", FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE) );
1804 SCIP_CALL( SCIPvarGetProbvarSum(var, scip->set, scalar, constant) );
1805
1806 return SCIP_OKAY;
1807 }
1808
1809 /** return for given variables all their active counterparts; all active variables will be pairwise different
1810 * @note It does not hold that the first output variable is the active variable for the first input variable.
1811 *
1812 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
1813 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
1814 *
1815 * @pre This method can be called if @p scip is in one of the following stages:
1816 * - \ref SCIP_STAGE_TRANSFORMED
1817 * - \ref SCIP_STAGE_INITPRESOLVE
1818 * - \ref SCIP_STAGE_PRESOLVING
1819 * - \ref SCIP_STAGE_EXITPRESOLVE
1820 * - \ref SCIP_STAGE_PRESOLVED
1821 * - \ref SCIP_STAGE_INITSOLVE
1822 * - \ref SCIP_STAGE_SOLVING
1823 * - \ref SCIP_STAGE_SOLVED
1824 * - \ref SCIP_STAGE_EXITSOLVE
1825 * - \ref SCIP_STAGE_FREETRANS
1826 */
SCIPgetActiveVars(SCIP * scip,SCIP_VAR ** vars,int * nvars,int varssize,int * requiredsize)1827 SCIP_RETCODE SCIPgetActiveVars(
1828 SCIP* scip, /**< SCIP data structure */
1829 SCIP_VAR** vars, /**< variable array with given variables and as output all active
1830 * variables, if enough slots exist
1831 */
1832 int* nvars, /**< number of given variables, and as output number of active variables,
1833 * if enough slots exist
1834 */
1835 int varssize, /**< available slots in vars array */
1836 int* requiredsize /**< pointer to store the required array size for the active variables */
1837 )
1838 {
1839 assert(scip != NULL);
1840 assert(nvars != NULL);
1841 assert(vars != NULL || *nvars == 0);
1842 assert(varssize >= *nvars);
1843 assert(requiredsize != NULL);
1844
1845 SCIP_CALL( SCIPcheckStage(scip, "SCIPgetActiveVars", FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE) );
1846 SCIP_CALL( SCIPvarsGetActiveVars(scip->set, vars, nvars, varssize, requiredsize) );
1847
1848 return SCIP_OKAY;
1849 }
1850
1851 /** returns the reduced costs of the variable in the current node's LP relaxation;
1852 * the current node has to have a feasible LP.
1853 *
1854 * returns SCIP_INVALID if the variable is active but not in the current LP;
1855 * returns 0 if the variable has been aggregated out or fixed in presolving.
1856 *
1857 * @pre This method can only be called if @p scip is in stage \ref SCIP_STAGE_SOLVING
1858 *
1859 * @note The return value of this method should be used carefully if the dual feasibility check was explictely disabled.
1860 */
SCIPgetVarRedcost(SCIP * scip,SCIP_VAR * var)1861 SCIP_Real SCIPgetVarRedcost(
1862 SCIP* scip, /**< SCIP data structure */
1863 SCIP_VAR* var /**< variable to get reduced costs, should be a column in current node LP */
1864 )
1865 {
1866 assert( scip != NULL );
1867 assert( var != NULL );
1868 assert( var->scip == scip );
1869
1870 switch( SCIPvarGetStatus(var) )
1871 {
1872 case SCIP_VARSTATUS_ORIGINAL:
1873 if( var->data.original.transvar == NULL )
1874 return SCIP_INVALID;
1875 return SCIPgetVarRedcost(scip, var->data.original.transvar);
1876
1877 case SCIP_VARSTATUS_COLUMN:
1878 return SCIPgetColRedcost(scip, SCIPvarGetCol(var));
1879
1880 case SCIP_VARSTATUS_LOOSE:
1881 return SCIP_INVALID;
1882
1883 case SCIP_VARSTATUS_FIXED:
1884 case SCIP_VARSTATUS_AGGREGATED:
1885 case SCIP_VARSTATUS_MULTAGGR:
1886 case SCIP_VARSTATUS_NEGATED:
1887 return 0.0;
1888
1889 default:
1890 SCIPerrorMessage("unknown variable status\n");
1891 SCIPABORT();
1892 return 0.0; /*lint !e527*/
1893 }
1894 }
1895
1896 /** returns the implied reduced costs of the variable in the current node's LP relaxation;
1897 * the current node has to have a feasible LP.
1898 *
1899 * returns SCIP_INVALID if the variable is active but not in the current LP;
1900 * returns 0 if the variable has been aggregated out or fixed in presolving.
1901 *
1902 * @pre This method can only be called if @p scip is in stage \ref SCIP_STAGE_SOLVING
1903 *
1904 * @note The return value of this method should be used carefully if the dual feasibility check was explictely disabled.
1905 */
SCIPgetVarImplRedcost(SCIP * scip,SCIP_VAR * var,SCIP_Bool varfixing)1906 SCIP_Real SCIPgetVarImplRedcost(
1907 SCIP* scip, /**< SCIP data structure */
1908 SCIP_VAR* var, /**< variable to get reduced costs, should be a column in current node LP */
1909 SCIP_Bool varfixing /**< FALSE if for x == 0, TRUE for x == 1 */
1910 )
1911 {
1912 assert( scip != NULL );
1913 assert( var != NULL );
1914 assert( var->scip == scip );
1915
1916 switch( SCIPvarGetStatus(var) )
1917 {
1918 case SCIP_VARSTATUS_ORIGINAL:
1919 if( var->data.original.transvar == NULL )
1920 return SCIP_INVALID;
1921 return SCIPgetVarImplRedcost(scip, var->data.original.transvar, varfixing);
1922
1923 case SCIP_VARSTATUS_COLUMN:
1924 return SCIPvarGetImplRedcost(var, scip->set, varfixing, scip->stat, scip->transprob, scip->lp);
1925
1926 case SCIP_VARSTATUS_LOOSE:
1927 return SCIP_INVALID;
1928
1929 case SCIP_VARSTATUS_FIXED:
1930 case SCIP_VARSTATUS_AGGREGATED:
1931 case SCIP_VARSTATUS_MULTAGGR:
1932 case SCIP_VARSTATUS_NEGATED:
1933 return 0.0;
1934
1935 default:
1936 SCIPerrorMessage("unknown variable status\n");
1937 SCIPABORT();
1938 return 0.0; /*lint !e527*/
1939 }
1940 }
1941
1942
1943 /** returns the Farkas coefficient of the variable in the current node's LP relaxation;
1944 * the current node has to have an infeasible LP.
1945 *
1946 * returns SCIP_INVALID if the variable is active but not in the current LP;
1947 * returns 0 if the variable has been aggregated out or fixed in presolving.
1948 *
1949 * @pre This method can only be called if @p scip is in stage \ref SCIP_STAGE_SOLVING
1950 */
SCIPgetVarFarkasCoef(SCIP * scip,SCIP_VAR * var)1951 SCIP_Real SCIPgetVarFarkasCoef(
1952 SCIP* scip, /**< SCIP data structure */
1953 SCIP_VAR* var /**< variable to get reduced costs, should be a column in current node LP */
1954 )
1955 {
1956 assert(scip != NULL);
1957 assert(var != NULL);
1958 assert(var->scip == scip);
1959
1960 switch( SCIPvarGetStatus(var) )
1961 {
1962 case SCIP_VARSTATUS_ORIGINAL:
1963 if( var->data.original.transvar == NULL )
1964 return SCIP_INVALID;
1965 return SCIPgetVarFarkasCoef(scip,var->data.original.transvar);
1966
1967 case SCIP_VARSTATUS_COLUMN:
1968 return SCIPgetColFarkasCoef(scip,SCIPvarGetCol(var));
1969
1970 case SCIP_VARSTATUS_LOOSE:
1971 return SCIP_INVALID;
1972
1973 case SCIP_VARSTATUS_FIXED:
1974 case SCIP_VARSTATUS_AGGREGATED:
1975 case SCIP_VARSTATUS_MULTAGGR:
1976 case SCIP_VARSTATUS_NEGATED:
1977 return 0.0;
1978
1979 default:
1980 SCIPerrorMessage("unknown variable status\n");
1981 SCIPABORT();
1982 return 0.0; /*lint !e527*/
1983 }
1984 }
1985
1986 /** returns lower bound of variable directly before or after the bound change given by the bound change index
1987 * was applied
1988 */
SCIPgetVarLbAtIndex(SCIP * scip,SCIP_VAR * var,SCIP_BDCHGIDX * bdchgidx,SCIP_Bool after)1989 SCIP_Real SCIPgetVarLbAtIndex(
1990 SCIP* scip, /**< SCIP data structure */
1991 SCIP_VAR* var, /**< problem variable */
1992 SCIP_BDCHGIDX* bdchgidx, /**< bound change index representing time on path to current node */
1993 SCIP_Bool after /**< should the bound change with given index be included? */
1994 )
1995 {
1996 SCIP_VARSTATUS varstatus;
1997 SCIP_BDCHGINFO* bdchginfo;
1998 assert(var != NULL);
1999
2000 varstatus = SCIPvarGetStatus(var);
2001
2002 /* get bounds of attached variables */
2003 switch( varstatus )
2004 {
2005 case SCIP_VARSTATUS_ORIGINAL:
2006 assert(var->data.original.transvar != NULL);
2007 return SCIPgetVarLbAtIndex(scip, var->data.original.transvar, bdchgidx, after);
2008
2009 case SCIP_VARSTATUS_COLUMN:
2010 case SCIP_VARSTATUS_LOOSE:
2011 if( bdchgidx == NULL )
2012 return SCIPvarGetLbLocal(var);
2013 else
2014 {
2015 bdchginfo = SCIPvarGetLbchgInfo(var, bdchgidx, after);
2016 if( bdchginfo != NULL )
2017 return SCIPbdchginfoGetNewbound(bdchginfo);
2018 else
2019 return var->glbdom.lb;
2020 }
2021
2022 case SCIP_VARSTATUS_FIXED:
2023 return var->glbdom.lb;
2024
2025 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
2026 assert(var->data.aggregate.var != NULL);
2027 if( var->data.aggregate.scalar > 0.0 )
2028 {
2029 SCIP_Real lb;
2030
2031 lb = SCIPgetVarLbAtIndex(scip, var->data.aggregate.var, bdchgidx, after);
2032
2033 /* a > 0 -> get lower bound of y */
2034 if( SCIPisInfinity(scip, -lb) )
2035 return -SCIPinfinity(scip);
2036 else if( SCIPisInfinity(scip, lb) )
2037 return SCIPinfinity(scip);
2038 else
2039 return var->data.aggregate.scalar * lb + var->data.aggregate.constant;
2040 }
2041 else if( var->data.aggregate.scalar < 0.0 )
2042 {
2043 SCIP_Real ub;
2044
2045 ub = SCIPgetVarUbAtIndex(scip, var->data.aggregate.var, bdchgidx, after);
2046
2047 /* a < 0 -> get upper bound of y */
2048 if( SCIPisInfinity(scip, -ub) )
2049 return SCIPinfinity(scip);
2050 else if( SCIPisInfinity(scip, ub) )
2051 return -SCIPinfinity(scip);
2052 else
2053 return var->data.aggregate.scalar * ub + var->data.aggregate.constant;
2054 }
2055 else
2056 {
2057 SCIPerrorMessage("scalar is zero in aggregation\n");
2058 SCIPABORT();
2059 return SCIP_INVALID; /*lint !e527*/
2060 }
2061
2062 case SCIP_VARSTATUS_MULTAGGR:
2063 /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */
2064 if ( var->data.multaggr.nvars == 1 )
2065 {
2066 assert(var->data.multaggr.vars != NULL);
2067 assert(var->data.multaggr.scalars != NULL);
2068 assert(var->data.multaggr.vars[0] != NULL);
2069
2070 if( var->data.multaggr.scalars[0] > 0.0 )
2071 {
2072 SCIP_Real lb;
2073
2074 lb = SCIPgetVarLbAtIndex(scip, var->data.multaggr.vars[0], bdchgidx, after);
2075
2076 /* a > 0 -> get lower bound of y */
2077 if( SCIPisInfinity(scip, -lb) )
2078 return -SCIPinfinity(scip);
2079 else if( SCIPisInfinity(scip, lb) )
2080 return SCIPinfinity(scip);
2081 else
2082 return var->data.multaggr.scalars[0] * lb + var->data.multaggr.constant;
2083 }
2084 else if( var->data.multaggr.scalars[0] < 0.0 )
2085 {
2086 SCIP_Real ub;
2087
2088 ub = SCIPgetVarUbAtIndex(scip, var->data.multaggr.vars[0], bdchgidx, after);
2089
2090 /* a < 0 -> get upper bound of y */
2091 if( SCIPisInfinity(scip, -ub) )
2092 return SCIPinfinity(scip);
2093 else if( SCIPisInfinity(scip, ub) )
2094 return -SCIPinfinity(scip);
2095 else
2096 return var->data.multaggr.scalars[0] * ub + var->data.multaggr.constant;
2097 }
2098 else
2099 {
2100 SCIPerrorMessage("scalar is zero in multi-aggregation\n");
2101 SCIPABORT();
2102 return SCIP_INVALID; /*lint !e527*/
2103 }
2104 }
2105 SCIPerrorMessage("cannot get the bounds of a multi-aggregated variable.\n");
2106 SCIPABORT();
2107 return SCIP_INVALID; /*lint !e527*/
2108
2109 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
2110 assert(var->negatedvar != NULL);
2111 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
2112 assert(var->negatedvar->negatedvar == var);
2113 return var->data.negate.constant - SCIPgetVarUbAtIndex(scip, var->negatedvar, bdchgidx, after);
2114
2115 default:
2116 SCIPerrorMessage("unknown variable status\n");
2117 SCIPABORT();
2118 return SCIP_INVALID; /*lint !e527*/
2119 }
2120 }
2121
2122 /** returns upper bound of variable directly before or after the bound change given by the bound change index
2123 * was applied
2124 */
SCIPgetVarUbAtIndex(SCIP * scip,SCIP_VAR * var,SCIP_BDCHGIDX * bdchgidx,SCIP_Bool after)2125 SCIP_Real SCIPgetVarUbAtIndex(
2126 SCIP* scip, /**< SCIP data structure */
2127 SCIP_VAR* var, /**< problem variable */
2128 SCIP_BDCHGIDX* bdchgidx, /**< bound change index representing time on path to current node */
2129 SCIP_Bool after /**< should the bound change with given index be included? */
2130 )
2131 {
2132 SCIP_VARSTATUS varstatus;
2133 SCIP_BDCHGINFO* bdchginfo;
2134 assert(var != NULL);
2135
2136 varstatus = SCIPvarGetStatus(var);
2137
2138 /* get bounds of attached variables */
2139 switch( varstatus )
2140 {
2141 case SCIP_VARSTATUS_ORIGINAL:
2142 assert(var->data.original.transvar != NULL);
2143 return SCIPgetVarUbAtIndex(scip, var->data.original.transvar, bdchgidx, after);
2144
2145 case SCIP_VARSTATUS_COLUMN:
2146 case SCIP_VARSTATUS_LOOSE:
2147 if( bdchgidx == NULL )
2148 return SCIPvarGetUbLocal(var);
2149 else
2150 {
2151 bdchginfo = SCIPvarGetUbchgInfo(var, bdchgidx, after);
2152 if( bdchginfo != NULL )
2153 return SCIPbdchginfoGetNewbound(bdchginfo);
2154 else
2155 return var->glbdom.ub;
2156 }
2157
2158 case SCIP_VARSTATUS_FIXED:
2159 return var->glbdom.ub;
2160
2161 case SCIP_VARSTATUS_AGGREGATED: /* x = a*y + c -> y = (x-c)/a */
2162 assert(var->data.aggregate.var != NULL);
2163 if( var->data.aggregate.scalar > 0.0 )
2164 {
2165 SCIP_Real ub;
2166
2167 ub = SCIPgetVarUbAtIndex(scip, var->data.aggregate.var, bdchgidx, after);
2168
2169 /* a > 0 -> get lower bound of y */
2170 if( SCIPisInfinity(scip, -ub) )
2171 return -SCIPinfinity(scip);
2172 else if( SCIPisInfinity(scip, ub) )
2173 return SCIPinfinity(scip);
2174 else
2175 return var->data.aggregate.scalar * ub + var->data.aggregate.constant;
2176 }
2177 else if( var->data.aggregate.scalar < 0.0 )
2178 {
2179 SCIP_Real lb;
2180
2181 lb = SCIPgetVarLbAtIndex(scip, var->data.aggregate.var, bdchgidx, after);
2182
2183 /* a < 0 -> get upper bound of y */
2184 if ( SCIPisInfinity(scip, -lb) )
2185 return SCIPinfinity(scip);
2186 else if ( SCIPisInfinity(scip, lb) )
2187 return -SCIPinfinity(scip);
2188 else
2189 return var->data.aggregate.scalar * lb + var->data.aggregate.constant;
2190 }
2191 else
2192 {
2193 SCIPerrorMessage("scalar is zero in aggregation\n");
2194 SCIPABORT();
2195 return SCIP_INVALID; /*lint !e527*/
2196 }
2197
2198 case SCIP_VARSTATUS_MULTAGGR:
2199 /* handle multi-aggregated variables depending on one variable only (possibly caused by SCIPvarFlattenAggregationGraph()) */
2200 if ( var->data.multaggr.nvars == 1 )
2201 {
2202 assert(var->data.multaggr.vars != NULL);
2203 assert(var->data.multaggr.scalars != NULL);
2204 assert(var->data.multaggr.vars[0] != NULL);
2205
2206 if( var->data.multaggr.scalars[0] > 0.0 )
2207 {
2208 SCIP_Real ub;
2209
2210 ub = SCIPgetVarUbAtIndex(scip, var->data.multaggr.vars[0], bdchgidx, after);
2211
2212 /* a > 0 -> get lower bound of y */
2213 if ( SCIPisInfinity(scip, -ub) )
2214 return -SCIPinfinity(scip);
2215 else if ( SCIPisInfinity(scip, ub) )
2216 return SCIPinfinity(scip);
2217 else
2218 return var->data.multaggr.scalars[0] * ub + var->data.multaggr.constant;
2219 }
2220 else if( var->data.multaggr.scalars[0] < 0.0 )
2221 {
2222 SCIP_Real lb;
2223
2224 lb = SCIPgetVarLbAtIndex(scip, var->data.multaggr.vars[0], bdchgidx, after);
2225
2226 /* a < 0 -> get upper bound of y */
2227 if ( SCIPisInfinity(scip, -lb) )
2228 return SCIPinfinity(scip);
2229 else if ( SCIPisInfinity(scip, lb) )
2230 return -SCIPinfinity(scip);
2231 else
2232 return var->data.multaggr.scalars[0] * lb + var->data.multaggr.constant;
2233 }
2234 else
2235 {
2236 SCIPerrorMessage("scalar is zero in multi-aggregation\n");
2237 SCIPABORT();
2238 return SCIP_INVALID; /*lint !e527*/
2239 }
2240 }
2241 SCIPerrorMessage("cannot get the bounds of a multiple aggregated variable.\n");
2242 SCIPABORT();
2243 return SCIP_INVALID; /*lint !e527*/
2244
2245 case SCIP_VARSTATUS_NEGATED: /* x' = offset - x -> x = offset - x' */
2246 assert(var->negatedvar != NULL);
2247 assert(SCIPvarGetStatus(var->negatedvar) != SCIP_VARSTATUS_NEGATED);
2248 assert(var->negatedvar->negatedvar == var);
2249 return var->data.negate.constant - SCIPgetVarLbAtIndex(scip, var->negatedvar, bdchgidx, after);
2250
2251 default:
2252 SCIPerrorMessage("unknown variable status\n");
2253 SCIPABORT();
2254 return SCIP_INVALID; /*lint !e527*/
2255 }
2256 }
2257
2258 /** returns lower or upper bound of variable directly before or after the bound change given by the bound change index
2259 * was applied
2260 */
SCIPgetVarBdAtIndex(SCIP * scip,SCIP_VAR * var,SCIP_BOUNDTYPE boundtype,SCIP_BDCHGIDX * bdchgidx,SCIP_Bool after)2261 SCIP_Real SCIPgetVarBdAtIndex(
2262 SCIP* scip, /**< SCIP data structure */
2263 SCIP_VAR* var, /**< problem variable */
2264 SCIP_BOUNDTYPE boundtype, /**< type of bound: lower or upper bound */
2265 SCIP_BDCHGIDX* bdchgidx, /**< bound change index representing time on path to current node */
2266 SCIP_Bool after /**< should the bound change with given index be included? */
2267 )
2268 {
2269 if( boundtype == SCIP_BOUNDTYPE_LOWER )
2270 return SCIPgetVarLbAtIndex(scip, var, bdchgidx, after);
2271 else
2272 {
2273 assert(boundtype == SCIP_BOUNDTYPE_UPPER);
2274 return SCIPgetVarUbAtIndex(scip, var, bdchgidx, after);
2275 }
2276 }
2277
2278 /** returns whether the binary variable was fixed at the time given by the bound change index */
SCIPgetVarWasFixedAtIndex(SCIP * scip,SCIP_VAR * var,SCIP_BDCHGIDX * bdchgidx,SCIP_Bool after)2279 SCIP_Bool SCIPgetVarWasFixedAtIndex(
2280 SCIP* scip, /**< SCIP data structure */
2281 SCIP_VAR* var, /**< problem variable */
2282 SCIP_BDCHGIDX* bdchgidx, /**< bound change index representing time on path to current node */
2283 SCIP_Bool after /**< should the bound change with given index be included? */
2284 )
2285 {
2286 assert(var != NULL);
2287 assert(SCIPvarIsBinary(var));
2288
2289 /* check the current bounds first in order to decide at which bound change information we have to look
2290 * (which is expensive because we have to follow the aggregation tree to the active variable)
2291 */
2292 return ((SCIPvarGetLbLocal(var) > 0.5 && SCIPgetVarLbAtIndex(scip, var, bdchgidx, after) > 0.5)
2293 || (SCIPvarGetUbLocal(var) < 0.5 && SCIPgetVarUbAtIndex(scip, var, bdchgidx, after) < 0.5));
2294 }
2295
2296 /** gets solution value for variable in current node
2297 *
2298 * @return solution value for variable in current node
2299 *
2300 * @pre This method can be called if @p scip is in one of the following stages:
2301 * - \ref SCIP_STAGE_PRESOLVED
2302 * - \ref SCIP_STAGE_SOLVING
2303 */
SCIPgetVarSol(SCIP * scip,SCIP_VAR * var)2304 SCIP_Real SCIPgetVarSol(
2305 SCIP* scip, /**< SCIP data structure */
2306 SCIP_VAR* var /**< variable to get solution value for */
2307 )
2308 {
2309 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetVarSol", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
2310 assert( var->scip == scip );
2311
2312 return SCIPvarGetSol(var, SCIPtreeHasCurrentNodeLP(scip->tree));
2313 }
2314
2315 /** gets solution values of multiple variables in current node
2316 *
2317 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
2318 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
2319 *
2320 * @pre This method can be called if @p scip is in one of the following stages:
2321 * - \ref SCIP_STAGE_PRESOLVED
2322 * - \ref SCIP_STAGE_SOLVING
2323 */
SCIPgetVarSols(SCIP * scip,int nvars,SCIP_VAR ** vars,SCIP_Real * vals)2324 SCIP_RETCODE SCIPgetVarSols(
2325 SCIP* scip, /**< SCIP data structure */
2326 int nvars, /**< number of variables to get solution value for */
2327 SCIP_VAR** vars, /**< array with variables to get value for */
2328 SCIP_Real* vals /**< array to store solution values of variables */
2329 )
2330 {
2331 int v;
2332
2333 assert(nvars == 0 || vars != NULL);
2334 assert(nvars == 0 || vals != NULL);
2335
2336 SCIP_CALL( SCIPcheckStage(scip, "SCIPgetVarSols", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
2337
2338 if( SCIPtreeHasCurrentNodeLP(scip->tree) )
2339 {
2340 for( v = 0; v < nvars; ++v )
2341 vals[v] = SCIPvarGetLPSol(vars[v]);
2342 }
2343 else
2344 {
2345 for( v = 0; v < nvars; ++v )
2346 vals[v] = SCIPvarGetPseudoSol(vars[v]);
2347 }
2348
2349 return SCIP_OKAY;
2350 }
2351
2352 /** sets the solution value of all variables in the global relaxation solution to zero
2353 *
2354 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
2355 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
2356 *
2357 * @pre This method can be called if @p scip is in one of the following stages:
2358 * - \ref SCIP_STAGE_PRESOLVED
2359 * - \ref SCIP_STAGE_SOLVING
2360 */
SCIPclearRelaxSolVals(SCIP * scip,SCIP_RELAX * relax)2361 SCIP_RETCODE SCIPclearRelaxSolVals(
2362 SCIP* scip, /**< SCIP data structure */
2363 SCIP_RELAX* relax /**< relaxator data structure */
2364 )
2365 {
2366 SCIP_VAR** vars;
2367 int nvars;
2368 int v;
2369
2370 assert(scip != NULL);
2371
2372 SCIP_CALL( SCIPcheckStage(scip, "SCIPclearRelaxSolVals", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
2373
2374 /* update the responsible relax pointer */
2375 SCIPrelaxationSetSolRelax(scip->relaxation, relax);
2376
2377 /* the relaxation solution is already cleared */
2378 if( SCIPrelaxationIsSolZero(scip->relaxation) )
2379 return SCIP_OKAY;
2380
2381 SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
2382
2383 for( v = 0; v < nvars; v++ )
2384 {
2385 SCIP_CALL( SCIPvarSetRelaxSol(vars[v], scip->set, scip->relaxation, 0.0, FALSE) );
2386 }
2387
2388 SCIPrelaxationSetSolObj(scip->relaxation, 0.0);
2389 SCIPrelaxationSetSolZero(scip->relaxation, TRUE);
2390
2391 return SCIP_OKAY;
2392 }
2393
2394 /** sets the value of the given variable in the global relaxation solution;
2395 * this solution can be filled by the relaxation handlers and can be used by heuristics and for separation;
2396 * You can use SCIPclearRelaxSolVals() to set all values to zero, initially;
2397 * after setting all solution values, you have to call SCIPmarkRelaxSolValid()
2398 * to inform SCIP that the stored solution is valid
2399 *
2400 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
2401 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
2402 *
2403 * @pre This method can be called if @p scip is in one of the following stages:
2404 * - \ref SCIP_STAGE_PRESOLVED
2405 * - \ref SCIP_STAGE_SOLVING
2406 *
2407 * @note This method incrementally updates the objective value of the relaxation solution. If the whole solution
2408 * should be updated, using SCIPsetRelaxSolVals() instead or calling SCIPclearRelaxSolVals() before setting
2409 * the first value to reset the solution and the objective value to 0 may help the numerics.
2410 */
SCIPsetRelaxSolVal(SCIP * scip,SCIP_RELAX * relax,SCIP_VAR * var,SCIP_Real val)2411 SCIP_RETCODE SCIPsetRelaxSolVal(
2412 SCIP* scip, /**< SCIP data structure */
2413 SCIP_RELAX* relax, /**< relaxator data structure */
2414 SCIP_VAR* var, /**< variable to set value for */
2415 SCIP_Real val /**< solution value of variable */
2416 )
2417 {
2418 assert(scip != NULL);
2419
2420 SCIP_CALL( SCIPcheckStage(scip, "SCIPsetRelaxSolVal", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
2421
2422 SCIP_CALL( SCIPvarSetRelaxSol(var, scip->set, scip->relaxation, val, TRUE) );
2423
2424 if( val != 0.0 )
2425 SCIPrelaxationSetSolZero(scip->relaxation, FALSE);
2426 SCIPrelaxationSetSolValid(scip->relaxation, FALSE, FALSE);
2427 SCIPrelaxationSetSolRelax(scip->relaxation, relax);
2428
2429 return SCIP_OKAY;
2430 }
2431
2432 /** sets the values of the given variables in the global relaxation solution and informs SCIP about the validity
2433 * and whether the solution can be enforced via linear cuts;
2434 * this solution can be filled by the relaxation handlers and can be used by heuristics and for separation;
2435 * the solution is automatically cleared, s.t. all other variables get value 0.0
2436 *
2437 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
2438 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
2439 *
2440 * @pre This method can be called if @p scip is in one of the following stages:
2441 * - \ref SCIP_STAGE_PRESOLVED
2442 * - \ref SCIP_STAGE_SOLVING
2443 */
SCIPsetRelaxSolVals(SCIP * scip,SCIP_RELAX * relax,int nvars,SCIP_VAR ** vars,SCIP_Real * vals,SCIP_Bool includeslp)2444 SCIP_RETCODE SCIPsetRelaxSolVals(
2445 SCIP* scip, /**< SCIP data structure */
2446 SCIP_RELAX* relax, /**< relaxator data structure */
2447 int nvars, /**< number of variables to set relaxation solution value for */
2448 SCIP_VAR** vars, /**< array with variables to set value for */
2449 SCIP_Real* vals, /**< array with solution values of variables */
2450 SCIP_Bool includeslp /**< does the relaxator contain all cuts in the LP? */
2451 )
2452 {
2453 int v;
2454
2455 assert(scip != NULL);
2456 assert(nvars == 0 || vars != NULL);
2457 assert(nvars == 0 || vals != NULL);
2458
2459 SCIP_CALL( SCIPcheckStage(scip, "SCIPsetRelaxSolVals", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
2460
2461 SCIP_CALL( SCIPclearRelaxSolVals(scip, relax) );
2462
2463 for( v = 0; v < nvars; v++ )
2464 {
2465 SCIP_CALL( SCIPvarSetRelaxSol(vars[v], scip->set, scip->relaxation, vals[v], TRUE) );
2466 }
2467
2468 SCIPrelaxationSetSolZero(scip->relaxation, FALSE);
2469 SCIPrelaxationSetSolValid(scip->relaxation, TRUE, includeslp);
2470 SCIPrelaxationSetSolRelax(scip->relaxation, relax);
2471
2472 return SCIP_OKAY;
2473 }
2474
2475 /** sets the values of the variables in the global relaxation solution to the values in the given primal solution
2476 * and informs SCIP about the validity and whether the solution can be enforced via linear cuts;
2477 * the relaxation solution can be filled by the relaxation handlers and might be used by heuristics and for separation
2478 *
2479 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
2480 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
2481 *
2482 * @pre This method can be called if @p scip is in one of the following stages:
2483 * - \ref SCIP_STAGE_PRESOLVED
2484 * - \ref SCIP_STAGE_SOLVING
2485 */
SCIPsetRelaxSolValsSol(SCIP * scip,SCIP_RELAX * relax,SCIP_SOL * sol,SCIP_Bool includeslp)2486 SCIP_RETCODE SCIPsetRelaxSolValsSol(
2487 SCIP* scip, /**< SCIP data structure */
2488 SCIP_RELAX* relax, /**< relaxator data structure */
2489 SCIP_SOL* sol, /**< primal relaxation solution */
2490 SCIP_Bool includeslp /**< does the relaxator contain all cuts in the LP? */
2491 )
2492 {
2493 SCIP_VAR** vars;
2494 SCIP_Real* vals;
2495 int nvars;
2496 int v;
2497
2498 assert(scip != NULL);
2499
2500 SCIP_CALL( SCIPcheckStage(scip, "SCIPsetRelaxSolValsSol", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
2501
2502 SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
2503
2504 /* alloc buffer array for solution values of the variables and get the values */
2505 SCIP_CALL( SCIPallocBufferArray(scip, &vals, nvars) );
2506 SCIP_CALL( SCIPgetSolVals(scip, sol, nvars, vars, vals) );
2507
2508 SCIP_CALL( SCIPclearRelaxSolVals(scip, relax) );
2509
2510 for( v = 0; v < nvars; v++ )
2511 {
2512 SCIP_CALL( SCIPvarSetRelaxSol(vars[v], scip->set, scip->relaxation, vals[v], FALSE) );
2513 }
2514
2515 SCIPrelaxationSetSolObj(scip->relaxation, SCIPsolGetObj(sol, scip->set, scip->transprob, scip->origprob));
2516
2517 SCIPrelaxationSetSolZero(scip->relaxation, FALSE);
2518 SCIPrelaxationSetSolValid(scip->relaxation, TRUE, includeslp);
2519 SCIPrelaxationSetSolRelax(scip->relaxation, relax);
2520
2521 SCIPfreeBufferArray(scip, &vals);
2522
2523 return SCIP_OKAY;
2524 }
2525
2526 /** returns whether the relaxation solution is valid
2527 *
2528 * @return TRUE, if the relaxation solution is valid; FALSE, otherwise
2529 *
2530 * @pre This method can be called if @p scip is in one of the following stages:
2531 * - \ref SCIP_STAGE_PRESOLVED
2532 * - \ref SCIP_STAGE_SOLVING
2533 */
SCIPisRelaxSolValid(SCIP * scip)2534 SCIP_Bool SCIPisRelaxSolValid(
2535 SCIP* scip /**< SCIP data structure */
2536 )
2537 {
2538 assert(scip != NULL);
2539
2540 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPisRelaxSolValid", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
2541
2542 return SCIPrelaxationIsSolValid(scip->relaxation);
2543 }
2544
2545 /** informs SCIP that the relaxation solution is valid and whether the relaxation can be enforced through linear cuts
2546 *
2547 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
2548 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
2549 *
2550 * @pre This method can be called if @p scip is in one of the following stages:
2551 * - \ref SCIP_STAGE_PRESOLVED
2552 * - \ref SCIP_STAGE_SOLVING
2553 */
SCIPmarkRelaxSolValid(SCIP * scip,SCIP_RELAX * relax,SCIP_Bool includeslp)2554 SCIP_RETCODE SCIPmarkRelaxSolValid(
2555 SCIP* scip, /**< SCIP data structure */
2556 SCIP_RELAX* relax, /**< relaxator data structure that set the current relaxation solution */
2557 SCIP_Bool includeslp /**< does the relaxator contain all cuts in the LP? */
2558 )
2559 {
2560 assert(scip != NULL);
2561
2562 SCIP_CALL( SCIPcheckStage(scip, "SCIPmarkRelaxSolValid", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
2563
2564 SCIPrelaxationSetSolValid(scip->relaxation, TRUE, includeslp);
2565 SCIPrelaxationSetSolRelax(scip->relaxation, relax);
2566
2567 return SCIP_OKAY;
2568 }
2569
2570 /** informs SCIP, that the relaxation solution is invalid
2571 *
2572 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
2573 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
2574 *
2575 * @pre This method can be called if @p scip is in one of the following stages:
2576 * - \ref SCIP_STAGE_PRESOLVED
2577 * - \ref SCIP_STAGE_SOLVING
2578 */
SCIPmarkRelaxSolInvalid(SCIP * scip)2579 SCIP_RETCODE SCIPmarkRelaxSolInvalid(
2580 SCIP* scip /**< SCIP data structure */
2581 )
2582 {
2583 assert(scip != NULL);
2584
2585 SCIP_CALL( SCIPcheckStage(scip, "SCIPmarkRelaxSolInvalid", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
2586
2587 SCIPrelaxationSetSolValid(scip->relaxation, FALSE, FALSE);
2588
2589 return SCIP_OKAY;
2590 }
2591
2592 /** gets the relaxation solution value of the given variable
2593 *
2594 * @return the relaxation solution value of the given variable
2595 *
2596 * @pre This method can be called if @p scip is in one of the following stages:
2597 * - \ref SCIP_STAGE_PRESOLVED
2598 * - \ref SCIP_STAGE_SOLVING
2599 */
SCIPgetRelaxSolVal(SCIP * scip,SCIP_VAR * var)2600 SCIP_Real SCIPgetRelaxSolVal(
2601 SCIP* scip, /**< SCIP data structure */
2602 SCIP_VAR* var /**< variable to get value for */
2603 )
2604 {
2605 assert(scip != NULL);
2606 assert(var != NULL);
2607 assert(var->scip == scip);
2608
2609 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetRelaxSolVal", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
2610
2611 if( !SCIPrelaxationIsSolValid(scip->relaxation) )
2612 {
2613 SCIPerrorMessage("Relaxation Solution is not valid!\n");
2614 SCIPABORT();
2615 return SCIP_INVALID; /*lint !e527*/
2616 }
2617
2618 return SCIPvarGetRelaxSol(var, scip->set);
2619 }
2620
2621 /** gets the relaxation solution objective value
2622 *
2623 * @return the objective value of the relaxation solution
2624 *
2625 * @pre This method can be called if @p scip is in one of the following stages:
2626 * - \ref SCIP_STAGE_PRESOLVED
2627 * - \ref SCIP_STAGE_SOLVING
2628 */
SCIPgetRelaxSolObj(SCIP * scip)2629 SCIP_Real SCIPgetRelaxSolObj(
2630 SCIP* scip /**< SCIP data structure */
2631 )
2632 {
2633 assert(scip != NULL);
2634
2635 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetRelaxSolObj", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
2636
2637 if( !SCIPrelaxationIsSolValid(scip->relaxation) )
2638 {
2639 SCIPerrorMessage("Relaxation Solution is not valid!\n");
2640 SCIPABORT();
2641 return SCIP_INVALID; /*lint !e527*/
2642 }
2643
2644 return SCIPrelaxationGetSolObj(scip->relaxation);
2645 }
2646
2647 /** determine which branching direction should be evaluated first by strong branching
2648 *
2649 * @return TRUE iff strong branching should first evaluate the down child
2650 *
2651 */
SCIPisStrongbranchDownFirst(SCIP * scip,SCIP_VAR * var)2652 SCIP_Bool SCIPisStrongbranchDownFirst(
2653 SCIP* scip, /**< SCIP data structure */
2654 SCIP_VAR* var /**< variable to determine the branching direction on */
2655 )
2656 {
2657 switch( scip->set->branch_firstsbchild )
2658 {
2659 case 'u':
2660 return FALSE;
2661 case 'd':
2662 return TRUE;
2663 case 'a':
2664 return (SCIPvarGetNLocksDown(var) > SCIPvarGetNLocksUp(var));
2665 default:
2666 assert(scip->set->branch_firstsbchild == 'h');
2667 return (SCIPgetVarAvgCutoffs(scip, var, SCIP_BRANCHDIR_DOWNWARDS) > SCIPgetVarAvgCutoffs(scip, var, SCIP_BRANCHDIR_UPWARDS));
2668 }
2669 }
2670
2671 /** start strong branching - call before any strong branching
2672 *
2673 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
2674 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
2675 *
2676 * @pre This method can be called if @p scip is in one of the following stages:
2677 * - \ref SCIP_STAGE_PRESOLVED
2678 * - \ref SCIP_STAGE_SOLVING
2679 *
2680 * @note if propagation is enabled, strong branching is not done directly on the LP, but probing nodes are created
2681 * which allow to perform propagation but also creates some overhead
2682 */
SCIPstartStrongbranch(SCIP * scip,SCIP_Bool enablepropagation)2683 SCIP_RETCODE SCIPstartStrongbranch(
2684 SCIP* scip, /**< SCIP data structure */
2685 SCIP_Bool enablepropagation /**< should propagation be done before solving the strong branching LP? */
2686 )
2687 {
2688 assert( scip != NULL );
2689 SCIP_CALL( SCIPcheckStage(scip, "SCIPstartStrongbranch", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
2690
2691 assert(!SCIPinProbing(scip));
2692
2693 SCIPdebugMsg(scip, "starting strong branching mode%s: lpcount=%" SCIP_LONGINT_FORMAT "\n", enablepropagation ? " with propagation" : "", scip->stat->lpcount - scip->stat->nsbdivinglps);
2694
2695 /* start probing mode to allow propagation before solving the strong branching LPs; if no propagation should be done,
2696 * start the strong branching mode in the LP interface
2697 */
2698 if( enablepropagation )
2699 {
2700 if( SCIPtreeProbing(scip->tree) )
2701 {
2702 SCIPerrorMessage("cannot start strong branching with propagation while in probing mode\n");
2703 return SCIP_INVALIDCALL;
2704 }
2705
2706 if( scip->lp != NULL && SCIPlpDiving(scip->lp) )
2707 {
2708 SCIPerrorMessage("cannot start strong branching with propagation while in diving mode\n");
2709 return SCIP_INVALIDCALL;
2710 }
2711
2712 /* other then in SCIPstartProbing(), we do not disable collecting variable statistics during strong branching;
2713 * we cannot disable it, because the pseudo costs would not be updated, otherwise,
2714 * and reliability branching would end up doing strong branching all the time
2715 */
2716 SCIP_CALL( SCIPtreeStartProbing(scip->tree, scip->mem->probmem, scip->set, scip->lp, scip->relaxation, scip->transprob, TRUE) );
2717
2718 /* inform the LP that the current probing mode is used for strong branching */
2719 SCIPlpStartStrongbranchProbing(scip->lp);
2720 }
2721 else
2722 {
2723 SCIP_CALL( SCIPlpStartStrongbranch(scip->lp) );
2724 }
2725
2726 /* reset local strong branching info */
2727 scip->stat->lastsblpsolstats[0] = scip->stat->lastsblpsolstats[1] = SCIP_LPSOLSTAT_NOTSOLVED;
2728
2729 return SCIP_OKAY;
2730 }
2731
2732 /** end strong branching - call after any strong branching
2733 *
2734 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
2735 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
2736 *
2737 * @pre This method can be called if @p scip is in one of the following stages:
2738 * - \ref SCIP_STAGE_PRESOLVED
2739 * - \ref SCIP_STAGE_SOLVING
2740 */
SCIPendStrongbranch(SCIP * scip)2741 SCIP_RETCODE SCIPendStrongbranch(
2742 SCIP* scip /**< SCIP data structure */
2743 )
2744 {
2745 assert( scip != NULL );
2746
2747 SCIP_CALL( SCIPcheckStage(scip, "SCIPendStrongbranch", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
2748
2749 /* depending on whether the strong branching mode was started with propagation enabled or not, we end the strong
2750 * branching probing mode or the LP strong branching mode
2751 */
2752 if( SCIPtreeProbing(scip->tree) )
2753 {
2754 SCIP_NODE* node;
2755 SCIP_DOMCHG* domchg;
2756 SCIP_VAR** boundchgvars;
2757 SCIP_Real* bounds;
2758 SCIP_BOUNDTYPE* boundtypes;
2759 int nboundchgs;
2760 int nbnds;
2761 int i;
2762
2763 /* collect all bound changes deducted during probing, which were applied at the probing root and apply them to the
2764 * focusnode
2765 */
2766 node = SCIPgetCurrentNode(scip);
2767 assert(SCIPnodeGetType(node) == SCIP_NODETYPE_PROBINGNODE);
2768 assert(SCIPgetProbingDepth(scip) == 0);
2769
2770 domchg = SCIPnodeGetDomchg(node);
2771 nboundchgs = SCIPdomchgGetNBoundchgs(domchg);
2772
2773 SCIP_CALL( SCIPallocBufferArray(scip, &boundchgvars, nboundchgs) );
2774 SCIP_CALL( SCIPallocBufferArray(scip, &bounds, nboundchgs) );
2775 SCIP_CALL( SCIPallocBufferArray(scip, &boundtypes, nboundchgs) );
2776
2777 for( i = 0, nbnds = 0; i < nboundchgs; ++i )
2778 {
2779 SCIP_BOUNDCHG* boundchg;
2780
2781 boundchg = SCIPdomchgGetBoundchg(domchg, i);
2782
2783 /* ignore redundant bound changes */
2784 if( SCIPboundchgIsRedundant(boundchg) )
2785 continue;
2786
2787 boundchgvars[nbnds] = SCIPboundchgGetVar(boundchg);
2788 bounds[nbnds] = SCIPboundchgGetNewbound(boundchg);
2789 boundtypes[nbnds] = SCIPboundchgGetBoundtype(boundchg);
2790 ++nbnds;
2791 }
2792
2793 SCIPdebugMsg(scip, "ending strong branching with probing: %d bound changes collected\n", nbnds);
2794
2795 /* inform the LP that the probing mode is not used for strong branching anymore */
2796 SCIPlpEndStrongbranchProbing(scip->lp);
2797
2798 /* switch back from probing to normal operation mode and restore variables and constraints to focus node */
2799 SCIP_CALL( SCIPtreeEndProbing(scip->tree, scip->reopt, scip->mem->probmem, scip->set, scip->messagehdlr, scip->stat,
2800 scip->transprob, scip->origprob, scip->lp, scip->relaxation, scip->primal,
2801 scip->branchcand, scip->eventqueue, scip->eventfilter, scip->cliquetable) );
2802
2803 /* apply the collected bound changes */
2804 for( i = 0; i < nbnds; ++i )
2805 {
2806 if( boundtypes[i] == SCIP_BOUNDTYPE_LOWER )
2807 {
2808 SCIPdebugMsg(scip, "apply probing lower bound change <%s> >= %.9g\n", SCIPvarGetName(boundchgvars[i]), bounds[i]);
2809 SCIP_CALL( SCIPchgVarLb(scip, boundchgvars[i], bounds[i]) );
2810 }
2811 else
2812 {
2813 SCIPdebugMsg(scip, "apply probing upper bound change <%s> <= %.9g\n", SCIPvarGetName(boundchgvars[i]), bounds[i]);
2814 SCIP_CALL( SCIPchgVarUb(scip, boundchgvars[i], bounds[i]) );
2815 }
2816 }
2817
2818 SCIPfreeBufferArray(scip, &boundtypes);
2819 SCIPfreeBufferArray(scip, &bounds);
2820 SCIPfreeBufferArray(scip, &boundchgvars);
2821 }
2822 else
2823 {
2824 SCIPdebugMsg(scip, "ending strong branching\n");
2825
2826 SCIP_CALL( SCIPlpEndStrongbranch(scip->lp) );
2827 }
2828
2829 return SCIP_OKAY;
2830 }
2831
2832 /** analyze the strong branching for the given variable; that includes conflict analysis for infeasible branches and
2833 * storing of root reduced cost information
2834 */
2835 static
analyzeStrongbranch(SCIP * scip,SCIP_VAR * var,SCIP_Bool * downinf,SCIP_Bool * upinf,SCIP_Bool * downconflict,SCIP_Bool * upconflict)2836 SCIP_RETCODE analyzeStrongbranch(
2837 SCIP* scip, /**< SCIP data structure */
2838 SCIP_VAR* var, /**< variable to analyze */
2839 SCIP_Bool* downinf, /**< pointer to store whether the downwards branch is infeasible, or NULL */
2840 SCIP_Bool* upinf, /**< pointer to store whether the upwards branch is infeasible, or NULL */
2841 SCIP_Bool* downconflict, /**< pointer to store whether a conflict constraint was created for an
2842 * infeasible downwards branch, or NULL */
2843 SCIP_Bool* upconflict /**< pointer to store whether a conflict constraint was created for an
2844 * infeasible upwards branch, or NULL */
2845 )
2846 {
2847 SCIP_COL* col;
2848 SCIP_Bool downcutoff;
2849 SCIP_Bool upcutoff;
2850
2851 col = SCIPvarGetCol(var);
2852 assert(col != NULL);
2853
2854 downcutoff = col->sbdownvalid && SCIPsetIsGE(scip->set, col->sbdown, scip->lp->cutoffbound);
2855 upcutoff = col->sbupvalid && SCIPsetIsGE(scip->set, col->sbup, scip->lp->cutoffbound);
2856
2857 if( downinf != NULL )
2858 *downinf = downcutoff;
2859 if( upinf != NULL )
2860 *upinf = upcutoff;
2861
2862 /* analyze infeasible strong branching sub problems:
2863 * because the strong branching's bound change is necessary for infeasibility, it cannot be undone;
2864 * therefore, infeasible strong branchings on non-binary variables will not produce a valid conflict constraint
2865 */
2866 if( scip->set->conf_enable && scip->set->conf_usesb && scip->set->nconflicthdlrs > 0
2867 && SCIPvarIsBinary(var) && SCIPtreeGetCurrentDepth(scip->tree) > 0 )
2868 {
2869 if( (downcutoff && SCIPsetFeasCeil(scip->set, col->primsol-1.0) >= col->lb - 0.5)
2870 || (upcutoff && SCIPsetFeasFloor(scip->set, col->primsol+1.0) <= col->ub + 0.5) )
2871 {
2872 assert(downconflict != NULL);
2873 assert(upconflict != NULL);
2874 SCIP_CALL( SCIPconflictAnalyzeStrongbranch(scip->conflict, scip->conflictstore, scip->mem->probmem, scip->set, scip->stat,
2875 scip->transprob, scip->origprob, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventqueue, scip->cliquetable, col, downconflict, upconflict) );
2876 }
2877 }
2878
2879 /* the strong branching results can be used to strengthen the root reduced cost information which is used for example
2880 * to propagate against the cutoff bound
2881 *
2882 * @note Ignore the results if the LP solution of the down (up) branch LP is smaller which should not happened by
2883 * theory but can arise due to numerical issues.
2884 */
2885 if( SCIPtreeGetCurrentDepth(scip->tree) == 0 && SCIPvarIsBinary(var) && SCIPlpIsDualReliable(scip->lp) )
2886 {
2887 SCIP_Real lpobjval;
2888
2889 assert(SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL);
2890
2891 lpobjval = SCIPlpGetObjval(scip->lp, scip->set, scip->transprob);
2892
2893 if( col->sbdownvalid && SCIPsetFeasCeil(scip->set, col->primsol-1.0) >= col->lb - 0.5 && lpobjval < col->sbdown )
2894 SCIPvarUpdateBestRootSol(var, scip->set, SCIPvarGetUbGlobal(var), -(col->sbdown - lpobjval), lpobjval);
2895 if( col->sbupvalid && SCIPsetFeasFloor(scip->set, col->primsol+1.0) <= col->ub + 0.5 && lpobjval < col->sbup )
2896 SCIPvarUpdateBestRootSol(var, scip->set, SCIPvarGetLbGlobal(var), col->sbup - lpobjval, lpobjval);
2897 }
2898
2899 return SCIP_OKAY;
2900 }
2901
2902 /** gets strong branching information on column variable with fractional value
2903 *
2904 * Before calling this method, the strong branching mode must have been activated by calling SCIPstartStrongbranch();
2905 * after strong branching was done for all candidate variables, the strong branching mode must be ended by
2906 * SCIPendStrongbranch(). Since this method does not apply domain propagation before strongbranching,
2907 * propagation should not be enabled in the SCIPstartStrongbranch() call.
2908 *
2909 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
2910 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
2911 *
2912 * @pre This method can be called if @p scip is in one of the following stages:
2913 * - \ref SCIP_STAGE_PRESOLVED
2914 * - \ref SCIP_STAGE_SOLVING
2915 */
SCIPgetVarStrongbranchFrac(SCIP * scip,SCIP_VAR * var,int itlim,SCIP_Bool idempotent,SCIP_Real * down,SCIP_Real * up,SCIP_Bool * downvalid,SCIP_Bool * upvalid,SCIP_Bool * downinf,SCIP_Bool * upinf,SCIP_Bool * downconflict,SCIP_Bool * upconflict,SCIP_Bool * lperror)2916 SCIP_RETCODE SCIPgetVarStrongbranchFrac(
2917 SCIP* scip, /**< SCIP data structure */
2918 SCIP_VAR* var, /**< variable to get strong branching values for */
2919 int itlim, /**< iteration limit for strong branchings */
2920 SCIP_Bool idempotent, /**< should scip's state remain the same after the call (statistics, column states...), or should it be updated ? */
2921 SCIP_Real* down, /**< stores dual bound after branching column down */
2922 SCIP_Real* up, /**< stores dual bound after branching column up */
2923 SCIP_Bool* downvalid, /**< stores whether the returned down value is a valid dual bound, or NULL;
2924 * otherwise, it can only be used as an estimate value */
2925 SCIP_Bool* upvalid, /**< stores whether the returned up value is a valid dual bound, or NULL;
2926 * otherwise, it can only be used as an estimate value */
2927 SCIP_Bool* downinf, /**< pointer to store whether the downwards branch is infeasible, or NULL */
2928 SCIP_Bool* upinf, /**< pointer to store whether the upwards branch is infeasible, or NULL */
2929 SCIP_Bool* downconflict, /**< pointer to store whether a conflict constraint was created for an
2930 * infeasible downwards branch, or NULL */
2931 SCIP_Bool* upconflict, /**< pointer to store whether a conflict constraint was created for an
2932 * infeasible upwards branch, or NULL */
2933 SCIP_Bool* lperror /**< pointer to store whether an unresolved LP error occurred or the
2934 * solving process should be stopped (e.g., due to a time limit) */
2935 )
2936 {
2937 SCIP_COL* col;
2938 SCIP_Real localdown;
2939 SCIP_Real localup;
2940 SCIP_Bool localdownvalid;
2941 SCIP_Bool localupvalid;
2942
2943 assert(scip != NULL);
2944 assert(var != NULL);
2945 assert(lperror != NULL);
2946 assert(!SCIPtreeProbing(scip->tree)); /* we should not be in strong branching with propagation mode */
2947 assert(var->scip == scip);
2948
2949 SCIP_CALL( SCIPcheckStage(scip, "SCIPgetVarStrongbranchFrac", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
2950
2951 if( downvalid != NULL )
2952 *downvalid = FALSE;
2953 if( upvalid != NULL )
2954 *upvalid = FALSE;
2955 if( downinf != NULL )
2956 *downinf = FALSE;
2957 if( upinf != NULL )
2958 *upinf = FALSE;
2959 if( downconflict != NULL )
2960 *downconflict = FALSE;
2961 if( upconflict != NULL )
2962 *upconflict = FALSE;
2963
2964 if( SCIPvarGetStatus(var) != SCIP_VARSTATUS_COLUMN )
2965 {
2966 SCIPerrorMessage("cannot get strong branching information on non-COLUMN variable <%s>\n", SCIPvarGetName(var));
2967 return SCIP_INVALIDDATA;
2968 }
2969
2970 col = SCIPvarGetCol(var);
2971 assert(col != NULL);
2972
2973 if( !SCIPcolIsInLP(col) )
2974 {
2975 SCIPerrorMessage("cannot get strong branching information on variable <%s> not in current LP\n", SCIPvarGetName(var));
2976 return SCIP_INVALIDDATA;
2977 }
2978
2979 /* check if the solving process should be aborted */
2980 if( SCIPsolveIsStopped(scip->set, scip->stat, FALSE) )
2981 {
2982 /* mark this as if the LP failed */
2983 *lperror = TRUE;
2984 return SCIP_OKAY;
2985 }
2986
2987 /* call strong branching for column with fractional value */
2988 SCIP_CALL( SCIPcolGetStrongbranch(col, FALSE, scip->set, scip->stat, scip->transprob, scip->lp, itlim, !idempotent, !idempotent,
2989 &localdown, &localup, &localdownvalid, &localupvalid, lperror) );
2990
2991 /* check, if the branchings are infeasible; in exact solving mode, we cannot trust the strong branching enough to
2992 * declare the sub nodes infeasible
2993 */
2994 if( !(*lperror) && SCIPprobAllColsInLP(scip->transprob, scip->set, scip->lp) && !scip->set->misc_exactsolve )
2995 {
2996 if( !idempotent ) /*lint !e774*/
2997 {
2998 SCIP_CALL( analyzeStrongbranch(scip, var, downinf, upinf, downconflict, upconflict) );
2999 }
3000 else
3001 {
3002 if( downinf != NULL )
3003 *downinf = localdownvalid && SCIPsetIsGE(scip->set, localdown, scip->lp->cutoffbound);
3004 if( upinf != NULL )
3005 *upinf = localupvalid && SCIPsetIsGE(scip->set, localup, scip->lp->cutoffbound);
3006 }
3007 }
3008
3009 if( down != NULL )
3010 *down = localdown;
3011 if( up != NULL )
3012 *up = localup;
3013 if( downvalid != NULL )
3014 *downvalid = localdownvalid;
3015 if( upvalid != NULL )
3016 *upvalid = localupvalid;
3017
3018 return SCIP_OKAY;
3019 }
3020
3021 /** create, solve, and evaluate a single strong branching child (for strong branching with propagation) */
3022 static
performStrongbranchWithPropagation(SCIP * scip,SCIP_VAR * var,SCIP_Bool down,SCIP_Bool firstchild,SCIP_Bool propagate,SCIP_Real newbound,int itlim,int maxproprounds,SCIP_Real * value,SCIP_Bool * valid,SCIP_Longint * ndomreductions,SCIP_Bool * conflict,SCIP_Bool * lperror,SCIP_VAR ** vars,int nvars,SCIP_Real * newlbs,SCIP_Real * newubs,SCIP_Bool * foundsol,SCIP_Bool * cutoff)3023 SCIP_RETCODE performStrongbranchWithPropagation(
3024 SCIP* scip, /**< SCIP data structure */
3025 SCIP_VAR* var, /**< variable to get strong branching values for */
3026 SCIP_Bool down, /**< do we regard the down child? */
3027 SCIP_Bool firstchild, /**< is this the first of the two strong branching children? */
3028 SCIP_Bool propagate, /**< should domain propagation be performed? */
3029 SCIP_Real newbound, /**< new bound to apply at the strong branching child */
3030 int itlim, /**< iteration limit for strong branchings */
3031 int maxproprounds, /**< maximum number of propagation rounds (-1: no limit, -2: parameter
3032 * settings) */
3033 SCIP_Real* value, /**< stores dual bound for strong branching child */
3034 SCIP_Bool* valid, /**< stores whether the returned value is a valid dual bound, or NULL;
3035 * otherwise, it can only be used as an estimate value */
3036 SCIP_Longint* ndomreductions, /**< pointer to store the number of domain reductions found, or NULL */
3037 SCIP_Bool* conflict, /**< pointer to store whether a conflict constraint was created for an
3038 * infeasible strong branching child, or NULL */
3039 SCIP_Bool* lperror, /**< pointer to store whether an unresolved LP error occurred or the
3040 * solving process should be stopped (e.g., due to a time limit) */
3041 SCIP_VAR** vars, /**< active problem variables */
3042 int nvars, /**< number of active problem variables */
3043 SCIP_Real* newlbs, /**< array to store valid lower bounds for all active variables, or NULL */
3044 SCIP_Real* newubs, /**< array to store valid upper bounds for all active variables, or NULL */
3045 SCIP_Bool* foundsol, /**< pointer to store whether a primal solution was found during strong branching */
3046 SCIP_Bool* cutoff /**< pointer to store whether the strong branching child is infeasible */
3047 )
3048 {
3049 SCIP_Longint ndomreds;
3050
3051 assert(value != NULL);
3052 assert(foundsol != NULL);
3053 assert(cutoff != NULL);
3054 assert(lperror != NULL);
3055 assert(valid != NULL ? !(*valid) : TRUE);
3056
3057 *foundsol = FALSE;
3058 *cutoff = FALSE;
3059 *lperror = FALSE;
3060
3061 /* check whether the strong branching child is already infeasible due to the bound change */
3062 if( down )
3063 {
3064 /* the down branch is infeasible due to the branching bound change; since this means that solval is not within the
3065 * bounds, this should only happen if previous strong branching calls on other variables detected bound changes which
3066 * are valid for and were already applied at the probing root
3067 */
3068 if( newbound < SCIPvarGetLbLocal(var) - 0.5 )
3069 {
3070 *value = SCIPinfinity(scip);
3071
3072 if( valid != NULL )
3073 *valid = TRUE;
3074
3075 /* bound changes are applied in SCIPendStrongbranch(), which can be seen as a conflict constraint */
3076 if( conflict != NULL )
3077 *conflict = TRUE;
3078
3079 *cutoff = TRUE;
3080
3081 return SCIP_OKAY;
3082 }
3083 }
3084 else
3085 {
3086 /* the up branch is infeasible due to the branching bound change; since this means that solval is not within the
3087 * bounds, this should only happen if previous strong branching calls on other variables detected bound changes which
3088 * are valid for and were already applied at the probing root
3089 */
3090 if( newbound > SCIPvarGetUbLocal(var) + 0.5 )
3091 {
3092 *value = SCIPinfinity(scip);
3093
3094 if( valid != NULL )
3095 *valid = TRUE;
3096
3097 /* bound changes are applied in SCIPendStrongbranch(), which can be seen as a conflict constraint */
3098 if( conflict != NULL )
3099 *conflict = TRUE;
3100
3101 *cutoff = TRUE;
3102
3103 return SCIP_OKAY;
3104 }
3105 }
3106
3107 /* we need to ensure that we can create at least one new probing node without exceeding the maximal tree depth */
3108 if( SCIP_MAXTREEDEPTH > SCIPtreeGetProbingDepth(scip->tree) )
3109 {
3110 /* create a new probing node for the strong branching child and apply the new bound for the variable */
3111 SCIP_CALL( SCIPnewProbingNode(scip) );
3112
3113 if( down )
3114 {
3115 assert(SCIPisGE(scip, newbound, SCIPvarGetLbLocal(var)));
3116 if( SCIPisLT(scip, newbound, SCIPvarGetUbLocal(var)) )
3117 {
3118 SCIP_CALL( SCIPchgVarUbProbing(scip, var, newbound) );
3119 }
3120 }
3121 else
3122 {
3123 assert(SCIPisLE(scip, newbound, SCIPvarGetUbLocal(var)));
3124 if( SCIPisGT(scip, newbound, SCIPvarGetLbLocal(var)) )
3125 {
3126 SCIP_CALL( SCIPchgVarLbProbing(scip, var, newbound) );
3127 }
3128 }
3129 }
3130 else
3131 {
3132 if( valid != NULL )
3133 *valid = FALSE;
3134
3135 *cutoff = FALSE;
3136
3137 if( conflict != NULL )
3138 *conflict = FALSE;
3139
3140 return SCIP_OKAY;
3141 }
3142
3143 /* propagate domains at the probing node */
3144 if( propagate )
3145 {
3146 /* start time measuring */
3147 SCIPclockStart(scip->stat->strongpropclock, scip->set);
3148
3149 ndomreds = 0;
3150 SCIP_CALL( SCIPpropagateProbing(scip, maxproprounds, cutoff, &ndomreds) );
3151
3152 /* store number of domain reductions in strong branching */
3153 if( down )
3154 SCIPstatAdd(scip->stat, scip->set, nsbdowndomchgs, ndomreds);
3155 else
3156 SCIPstatAdd(scip->stat, scip->set, nsbupdomchgs, ndomreds);
3157
3158 if( ndomreductions != NULL )
3159 *ndomreductions = ndomreds;
3160
3161 /* stop time measuring */
3162 SCIPclockStop(scip->stat->strongpropclock, scip->set);
3163
3164 if( *cutoff )
3165 {
3166 *value = SCIPinfinity(scip);
3167
3168 if( valid != NULL )
3169 *valid = TRUE;
3170
3171 SCIPdebugMsg(scip, "%s branch of var <%s> detected infeasible during propagation\n",
3172 down ? "down" : "up", SCIPvarGetName(var));
3173 }
3174 }
3175
3176 /* if propagation did not already detect infeasibility, solve the probing LP */
3177 if( !(*cutoff) )
3178 {
3179 SCIP_CALL( SCIPsolveProbingLP(scip, itlim, lperror, cutoff) );
3180 assert(SCIPisLPRelax(scip));
3181
3182 if( *cutoff )
3183 {
3184 assert(!(*lperror));
3185
3186 *value = SCIPinfinity(scip);
3187
3188 if( valid != NULL )
3189 *valid = TRUE;
3190
3191 SCIPdebugMsg(scip, "%s branch of var <%s> detected infeasible in LP solving: status=%d\n",
3192 down ? "down" : "up", SCIPvarGetName(var), SCIPgetLPSolstat(scip));
3193 }
3194 else if( !(*lperror) )
3195 {
3196 /* save the lp solution status */
3197 scip->stat->lastsblpsolstats[down ? 0 : 1] = SCIPgetLPSolstat(scip);
3198
3199 switch( SCIPgetLPSolstat(scip) )
3200 {
3201 case SCIP_LPSOLSTAT_OPTIMAL:
3202 {
3203 *value = SCIPgetLPObjval(scip);
3204 assert(SCIPisLT(scip, *value, SCIPgetCutoffbound(scip)));
3205
3206 SCIPdebugMsg(scip, "probing LP solved to optimality, objective value: %16.9g\n", *value);
3207
3208 if( valid != NULL )
3209 *valid = TRUE;
3210
3211 /* check the strong branching LP solution for feasibility */
3212 SCIP_CALL( SCIPtryStrongbranchLPSol(scip, foundsol, cutoff) );
3213 break;
3214 }
3215 case SCIP_LPSOLSTAT_ITERLIMIT:
3216 ++scip->stat->nsbtimesiterlimhit;
3217 /*lint -fallthrough*/
3218 case SCIP_LPSOLSTAT_TIMELIMIT:
3219 {
3220 /* use LP value as estimate */
3221 SCIP_LPI* lpi;
3222 SCIP_Real objval;
3223 SCIP_Real looseobjval;
3224
3225 SCIPdebugMsg(scip, "probing LP hit %s limit\n", SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_ITERLIMIT ? "iteration" : "time");
3226
3227 /* we access the LPI directly, because when a time limit was hit, we cannot access objective value and dual
3228 * feasibility using the SCIPlp... methods; we should try to avoid direct calls to the LPI, but this is rather
3229 * uncritical here, because we are immediately after the SCIPsolveProbingLP() call, because we access the LPI
3230 * read-only, and we check SCIPlpiWasSolved() first
3231 */
3232 SCIP_CALL( SCIPgetLPI(scip, &lpi) );
3233
3234 if( SCIPlpiWasSolved(lpi) )
3235 {
3236 SCIP_CALL( SCIPlpiGetObjval(lpi, &objval) );
3237 looseobjval = SCIPlpGetLooseObjval(scip->lp, scip->set, scip->transprob);
3238
3239 /* the infinity value in the LPI should not be smaller than SCIP's infinity value */
3240 assert(!SCIPlpiIsInfinity(lpi, objval) || SCIPisInfinity(scip, objval));
3241
3242 /* we use SCIP's infinity value here because a value larger than this is counted as infeasible by SCIP */
3243 if( SCIPisInfinity(scip, objval) )
3244 *value = SCIPinfinity(scip);
3245 else if( SCIPisInfinity(scip, -looseobjval) )
3246 *value = -SCIPinfinity(scip);
3247 else
3248 *value = objval + looseobjval;
3249
3250 if( SCIPlpiIsDualFeasible(lpi) )
3251 {
3252 if( valid != NULL )
3253 *valid = TRUE;
3254
3255 if( SCIPisGE(scip, *value, SCIPgetCutoffbound(scip)) )
3256 *cutoff = TRUE;
3257 }
3258 }
3259 break;
3260 }
3261 case SCIP_LPSOLSTAT_ERROR:
3262 case SCIP_LPSOLSTAT_UNBOUNDEDRAY:
3263 *lperror = TRUE;
3264 break;
3265 case SCIP_LPSOLSTAT_NOTSOLVED: /* should only be the case for *cutoff = TRUE or *lperror = TRUE */
3266 case SCIP_LPSOLSTAT_OBJLIMIT: /* in this case, *cutoff should be TRUE and we should not get here */
3267 case SCIP_LPSOLSTAT_INFEASIBLE: /* in this case, *cutoff should be TRUE and we should not get here */
3268 default:
3269 SCIPerrorMessage("invalid LP solution status <%d>\n", SCIPgetLPSolstat(scip));
3270 return SCIP_INVALIDDATA;
3271 } /*lint !e788*/
3272 }
3273
3274 /* If columns are missing in the LP, the cutoff flag may be wrong. Therefore, we need to set it and the valid pointer
3275 * to false here.
3276 */
3277 if( (*cutoff) && !SCIPallColsInLP(scip) )
3278 {
3279 *cutoff = FALSE;
3280 }
3281
3282 #ifndef NDEBUG
3283 if( *lperror )
3284 {
3285 SCIPdebugMsg(scip, "error during strong branching probing LP solving: status=%d\n", SCIPgetLPSolstat(scip));
3286 }
3287 #endif
3288 }
3289
3290 /* if the subproblem was feasible, we store the local bounds of the variables after propagation and (possibly)
3291 * conflict analysis
3292 * @todo do this after propagation? should be able to get valid bounds more often, but they might be weaker
3293 */
3294 if( !(*cutoff) && newlbs != NULL)
3295 {
3296 int v;
3297
3298 assert(newubs != NULL);
3299
3300 /* initialize the newlbs and newubs to the current local bounds */
3301 if( firstchild )
3302 {
3303 for( v = 0; v < nvars; ++v )
3304 {
3305 newlbs[v] = SCIPvarGetLbLocal(vars[v]);
3306 newubs[v] = SCIPvarGetUbLocal(vars[v]);
3307 }
3308 }
3309 /* update newlbs and newubs: take the weaker of the already stored bounds and the current local bounds */
3310 else
3311 {
3312 for( v = 0; v < nvars; ++v )
3313 {
3314 SCIP_Real lb = SCIPvarGetLbLocal(vars[v]);
3315 SCIP_Real ub = SCIPvarGetUbLocal(vars[v]);
3316
3317 newlbs[v] = MIN(newlbs[v], lb);
3318 newubs[v] = MAX(newubs[v], ub);
3319 }
3320 }
3321 }
3322
3323 /* revert all changes at the probing node */
3324 SCIP_CALL( SCIPbacktrackProbing(scip, 0) );
3325
3326 return SCIP_OKAY;
3327 }
3328
3329 /** gets strong branching information with previous domain propagation on column variable
3330 *
3331 * Before calling this method, the strong branching mode must have been activated by calling SCIPstartStrongbranch();
3332 * after strong branching was done for all candidate variables, the strong branching mode must be ended by
3333 * SCIPendStrongbranch(). Since this method applies domain propagation before strongbranching, propagation has to be be
3334 * enabled in the SCIPstartStrongbranch() call.
3335 *
3336 * Before solving the strong branching LP, domain propagation can be performed. The number of propagation rounds
3337 * can be specified by the parameter @p maxproprounds.
3338 *
3339 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
3340 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
3341 *
3342 * @pre This method can be called if @p scip is in one of the following stages:
3343 * - \ref SCIP_STAGE_PRESOLVED
3344 * - \ref SCIP_STAGE_SOLVING
3345 *
3346 * @warning When using this method, LP banching candidates and solution values must be copied beforehand, because
3347 * they are updated w.r.t. the strong branching LP solution.
3348 */
SCIPgetVarStrongbranchWithPropagation(SCIP * scip,SCIP_VAR * var,SCIP_Real solval,SCIP_Real lpobjval,int itlim,int maxproprounds,SCIP_Real * down,SCIP_Real * up,SCIP_Bool * downvalid,SCIP_Bool * upvalid,SCIP_Longint * ndomredsdown,SCIP_Longint * ndomredsup,SCIP_Bool * downinf,SCIP_Bool * upinf,SCIP_Bool * downconflict,SCIP_Bool * upconflict,SCIP_Bool * lperror,SCIP_Real * newlbs,SCIP_Real * newubs)3349 SCIP_RETCODE SCIPgetVarStrongbranchWithPropagation(
3350 SCIP* scip, /**< SCIP data structure */
3351 SCIP_VAR* var, /**< variable to get strong branching values for */
3352 SCIP_Real solval, /**< value of the variable in the current LP solution */
3353 SCIP_Real lpobjval, /**< LP objective value of the current LP solution */
3354 int itlim, /**< iteration limit for strong branchings */
3355 int maxproprounds, /**< maximum number of propagation rounds (-1: no limit, -2: parameter
3356 * settings) */
3357 SCIP_Real* down, /**< stores dual bound after branching column down */
3358 SCIP_Real* up, /**< stores dual bound after branching column up */
3359 SCIP_Bool* downvalid, /**< stores whether the returned down value is a valid dual bound, or NULL;
3360 * otherwise, it can only be used as an estimate value */
3361 SCIP_Bool* upvalid, /**< stores whether the returned up value is a valid dual bound, or NULL;
3362 * otherwise, it can only be used as an estimate value */
3363 SCIP_Longint* ndomredsdown, /**< pointer to store the number of domain reductions down, or NULL */
3364 SCIP_Longint* ndomredsup, /**< pointer to store the number of domain reductions up, or NULL */
3365 SCIP_Bool* downinf, /**< pointer to store whether the downwards branch is infeasible, or NULL */
3366 SCIP_Bool* upinf, /**< pointer to store whether the upwards branch is infeasible, or NULL */
3367 SCIP_Bool* downconflict, /**< pointer to store whether a conflict constraint was created for an
3368 * infeasible downwards branch, or NULL */
3369 SCIP_Bool* upconflict, /**< pointer to store whether a conflict constraint was created for an
3370 * infeasible upwards branch, or NULL */
3371 SCIP_Bool* lperror, /**< pointer to store whether an unresolved LP error occurred or the
3372 * solving process should be stopped (e.g., due to a time limit) */
3373 SCIP_Real* newlbs, /**< array to store valid lower bounds for all active variables, or NULL */
3374 SCIP_Real* newubs /**< array to store valid upper bounds for all active variables, or NULL */
3375 )
3376 {
3377 SCIP_COL* col;
3378 SCIP_VAR** vars;
3379 SCIP_Longint oldniters;
3380 SCIP_Real newub;
3381 SCIP_Real newlb;
3382 SCIP_Bool propagate;
3383 SCIP_Bool cutoff;
3384 SCIP_Bool downchild;
3385 SCIP_Bool firstchild;
3386 SCIP_Bool foundsol;
3387 SCIP_Bool downvalidlocal;
3388 SCIP_Bool upvalidlocal;
3389 SCIP_Bool allcolsinlp;
3390 SCIP_Bool enabledconflict;
3391 int oldnconflicts;
3392 int nvars;
3393
3394 assert(scip != NULL);
3395 assert(var != NULL);
3396 assert(SCIPvarIsIntegral(var));
3397 assert(down != NULL);
3398 assert(up != NULL);
3399 assert(lperror != NULL);
3400 assert((newlbs != NULL) == (newubs != NULL));
3401 assert(SCIPinProbing(scip));
3402 assert(var->scip == scip);
3403
3404 SCIP_CALL( SCIPcheckStage(scip, "SCIPgetVarStrongbranchWithPropagation", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
3405
3406 /* check whether propagation should be performed */
3407 propagate = (maxproprounds != 0 && maxproprounds != -3);
3408
3409 /* Check, if all existing columns are in LP.
3410 * If this is not the case, we may still return that the up and down dual bounds are valid, because the branching
3411 * rule should not apply them otherwise.
3412 * However, we must not set the downinf or upinf pointers to TRUE based on the dual bound, because we cannot
3413 * guarantee that this node can be cut off.
3414 */
3415 allcolsinlp = SCIPallColsInLP(scip);
3416
3417 /* if maxproprounds is -2, change it to 0, which for the following calls means using the parameter settings */
3418 if( maxproprounds == -2 )
3419 maxproprounds = 0;
3420
3421 *down = lpobjval;
3422 *up = lpobjval;
3423 if( downvalid != NULL )
3424 *downvalid = FALSE;
3425 if( upvalid != NULL )
3426 *upvalid = FALSE;
3427 if( downinf != NULL )
3428 *downinf = FALSE;
3429 if( upinf != NULL )
3430 *upinf = FALSE;
3431 if( downconflict != NULL )
3432 *downconflict = FALSE;
3433 if( upconflict != NULL )
3434 *upconflict = FALSE;
3435 if( ndomredsdown != NULL )
3436 *ndomredsdown = 0;
3437 if( ndomredsup != NULL )
3438 *ndomredsup = 0;
3439
3440 *lperror = FALSE;
3441
3442 vars = SCIPgetVars(scip);
3443 nvars = SCIPgetNVars(scip);
3444
3445 scip->stat->lastsblpsolstats[0] = scip->stat->lastsblpsolstats[1] = SCIP_LPSOLSTAT_NOTSOLVED;
3446
3447 /* check if the solving process should be aborted */
3448 if( SCIPsolveIsStopped(scip->set, scip->stat, FALSE) )
3449 {
3450 /* mark this as if the LP failed */
3451 *lperror = TRUE;
3452 return SCIP_OKAY;
3453 }
3454
3455 if( SCIPvarGetStatus(var) != SCIP_VARSTATUS_COLUMN )
3456 {
3457 SCIPerrorMessage("cannot get strong branching information on non-COLUMN variable <%s>\n", SCIPvarGetName(var));
3458 return SCIP_INVALIDDATA;
3459 }
3460
3461 col = SCIPvarGetCol(var);
3462 assert(col != NULL);
3463
3464 if( !SCIPcolIsInLP(col) )
3465 {
3466 SCIPerrorMessage("cannot get strong branching information on variable <%s> not in current LP\n", SCIPvarGetName(var));
3467 return SCIP_INVALIDDATA;
3468 }
3469
3470 newlb = SCIPfeasFloor(scip, solval + 1.0);
3471 newub = SCIPfeasCeil(scip, solval - 1.0);
3472
3473 SCIPdebugMsg(scip, "strong branching on var <%s>: solval=%g, lb=%g, ub=%g\n", SCIPvarGetName(var), solval,
3474 SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
3475
3476 /* the up branch is infeasible due to the branching bound change; since this means that solval is not within the
3477 * bounds, this should only happen if previous strong branching calls on other variables detected bound changes which
3478 * are valid for and were already applied at the probing root
3479 */
3480 if( newlb > SCIPvarGetUbLocal(var) + 0.5 )
3481 {
3482 *up = SCIPinfinity(scip);
3483
3484 if( upinf != NULL )
3485 *upinf = TRUE;
3486
3487 if( upvalid != NULL )
3488 *upvalid = TRUE;
3489
3490 /* bound changes are applied in SCIPendStrongbranch(), which can be seen as a conflict constraint */
3491 if( upconflict != NULL )
3492 *upconflict = TRUE;
3493
3494 SCIPcolSetStrongbranchData(col, scip->set, scip->stat, scip->lp, lpobjval, solval,
3495 *down, *up, FALSE, TRUE, 0LL, INT_MAX);
3496
3497 /* we do not regard the down branch; its valid pointer stays set to FALSE */
3498 return SCIP_OKAY;
3499 }
3500
3501 /* the down branch is infeasible due to the branching bound change; since this means that solval is not within the
3502 * bounds, this should only happen if previous strong branching calls on other variables detected bound changes which
3503 * are valid for and were already applied at the probing root
3504 */
3505 if( newub < SCIPvarGetLbLocal(var) - 0.5 )
3506 {
3507 *down = SCIPinfinity(scip);
3508
3509 if( downinf != NULL )
3510 *downinf = TRUE;
3511
3512 if( downvalid != NULL )
3513 *downvalid = TRUE;
3514
3515 /* bound changes are applied in SCIPendStrongbranch(), which can be seen as a conflict constraint */
3516 if( downconflict != NULL )
3517 *downconflict = TRUE;
3518
3519 SCIPcolSetStrongbranchData(col, scip->set, scip->stat, scip->lp, lpobjval, solval,
3520 *down, *up, TRUE, FALSE, 0LL, INT_MAX);
3521
3522 /* we do not regard the up branch; its valid pointer stays set to FALSE */
3523 return SCIP_OKAY;
3524 }
3525
3526 /* We now do strong branching by creating the two potential child nodes as probing nodes and solving them one after
3527 * the other. We will stop when the first child is detected infeasible, saving the effort we would need for the
3528 * second child. Since empirically, the up child tends to be infeasible more often, we do strongbranching first on
3529 * the up branch.
3530 */
3531 oldniters = scip->stat->nsbdivinglpiterations;
3532 firstchild = TRUE;
3533 cutoff = FALSE;
3534
3535 /* switch conflict analysis according to usesb parameter */
3536 enabledconflict = scip->set->conf_enable;
3537 scip->set->conf_enable = (scip->set->conf_enable && scip->set->conf_usesb);
3538
3539 /* @todo: decide the branch to look at first based on the cutoffs in previous calls? */
3540 downchild = SCIPisStrongbranchDownFirst(scip, var);
3541
3542 downvalidlocal = FALSE;
3543 upvalidlocal = FALSE;
3544
3545 do
3546 {
3547 oldnconflicts = SCIPconflictGetNConflicts(scip->conflict);
3548
3549 if( downchild )
3550 {
3551 SCIP_CALL( performStrongbranchWithPropagation(scip, var, downchild, firstchild, propagate, newub, itlim, maxproprounds,
3552 down, &downvalidlocal, ndomredsdown, downconflict, lperror, vars, nvars, newlbs, newubs, &foundsol, &cutoff) );
3553
3554 /* check whether a new solutions rendered the previous child infeasible */
3555 if( foundsol && !firstchild && allcolsinlp )
3556 {
3557 if( SCIPisGE(scip, *up, SCIPgetCutoffbound(scip)) )
3558 {
3559 if( upinf != NULL )
3560 *upinf = TRUE;
3561 }
3562 }
3563
3564 /* check for infeasibility */
3565 if( cutoff )
3566 {
3567 if( downinf != NULL )
3568 *downinf = TRUE;
3569
3570 if( downconflict != NULL &&
3571 (SCIPvarGetLbLocal(var) > newub + 0.5 || SCIPconflictGetNConflicts(scip->conflict) > oldnconflicts) )
3572 {
3573 *downconflict = TRUE;
3574 }
3575
3576 if( !scip->set->branch_forceall )
3577 {
3578 /* if this is the first call, we do not regard the up branch, its valid pointer is initially set to FALSE */
3579 break;
3580 }
3581 }
3582 }
3583 else
3584 {
3585 SCIP_CALL( performStrongbranchWithPropagation(scip, var, downchild, firstchild, propagate, newlb, itlim, maxproprounds,
3586 up, &upvalidlocal, ndomredsup, upconflict, lperror, vars, nvars, newlbs, newubs, &foundsol, &cutoff) );
3587
3588 /* check whether a new solutions rendered the previous child infeasible */
3589 if( foundsol && !firstchild && allcolsinlp )
3590 {
3591 if( SCIPisGE(scip, *down, SCIPgetCutoffbound(scip)) )
3592 {
3593 if( downinf != NULL )
3594 *downinf = TRUE;
3595 }
3596 }
3597
3598 /* check for infeasibility */
3599 if( cutoff )
3600 {
3601 if( upinf != NULL )
3602 *upinf = TRUE;
3603
3604 assert(upinf == NULL || (*upinf) == TRUE);
3605
3606 if( upconflict != NULL &&
3607 (SCIPvarGetUbLocal(var) < newlb - 0.5 || SCIPconflictGetNConflicts(scip->conflict) > oldnconflicts) )
3608 {
3609 *upconflict = TRUE;
3610 }
3611
3612 if( !scip->set->branch_forceall )
3613 {
3614 /* if this is the first call, we do not regard the down branch, its valid pointer is initially set to FALSE */
3615 break;
3616 }
3617 }
3618 }
3619
3620 downchild = !downchild;
3621 firstchild = !firstchild;
3622 }
3623 while( !firstchild );
3624
3625 /* set strong branching information in column */
3626 if( *lperror )
3627 {
3628 SCIPcolInvalidateStrongbranchData(col, scip->set, scip->stat, scip->lp);
3629 }
3630 else
3631 {
3632 SCIPcolSetStrongbranchData(col, scip->set, scip->stat, scip->lp, lpobjval, solval,
3633 *down, *up, downvalidlocal, upvalidlocal, scip->stat->nsbdivinglpiterations - oldniters, itlim);
3634 }
3635
3636 if( downvalid != NULL )
3637 *downvalid = downvalidlocal;
3638 if( upvalid != NULL )
3639 *upvalid = upvalidlocal;
3640
3641 scip->set->conf_enable = enabledconflict;
3642
3643 return SCIP_OKAY; /*lint !e438*/
3644 }
3645
3646 /** gets strong branching information on column variable x with integral LP solution value (val); that is, the down branch
3647 * is (val -1.0) and the up brach ins (val +1.0)
3648 *
3649 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
3650 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
3651 *
3652 * @pre This method can be called if @p scip is in one of the following stages:
3653 * - \ref SCIP_STAGE_PRESOLVED
3654 * - \ref SCIP_STAGE_SOLVING
3655 *
3656 * @note If the integral LP solution value is the lower or upper bound of the variable, the corresponding branch will be
3657 * marked as infeasible. That is, the valid pointer and the infeasible pointer are set to TRUE.
3658 */
SCIPgetVarStrongbranchInt(SCIP * scip,SCIP_VAR * var,int itlim,SCIP_Bool idempotent,SCIP_Real * down,SCIP_Real * up,SCIP_Bool * downvalid,SCIP_Bool * upvalid,SCIP_Bool * downinf,SCIP_Bool * upinf,SCIP_Bool * downconflict,SCIP_Bool * upconflict,SCIP_Bool * lperror)3659 SCIP_RETCODE SCIPgetVarStrongbranchInt(
3660 SCIP* scip, /**< SCIP data structure */
3661 SCIP_VAR* var, /**< variable to get strong branching values for */
3662 int itlim, /**< iteration limit for strong branchings */
3663 SCIP_Bool idempotent, /**< should scip's state remain the same after the call (statistics, column states...), or should it be updated ? */
3664 SCIP_Real* down, /**< stores dual bound after branching column down */
3665 SCIP_Real* up, /**< stores dual bound after branching column up */
3666 SCIP_Bool* downvalid, /**< stores whether the returned down value is a valid dual bound, or NULL;
3667 * otherwise, it can only be used as an estimate value */
3668 SCIP_Bool* upvalid, /**< stores whether the returned up value is a valid dual bound, or NULL;
3669 * otherwise, it can only be used as an estimate value */
3670 SCIP_Bool* downinf, /**< pointer to store whether the downwards branch is infeasible, or NULL */
3671 SCIP_Bool* upinf, /**< pointer to store whether the upwards branch is infeasible, or NULL */
3672 SCIP_Bool* downconflict, /**< pointer to store whether a conflict constraint was created for an
3673 * infeasible downwards branch, or NULL */
3674 SCIP_Bool* upconflict, /**< pointer to store whether a conflict constraint was created for an
3675 * infeasible upwards branch, or NULL */
3676 SCIP_Bool* lperror /**< pointer to store whether an unresolved LP error occurred or the
3677 * solving process should be stopped (e.g., due to a time limit) */
3678 )
3679 {
3680 SCIP_COL* col;
3681 SCIP_Real localdown;
3682 SCIP_Real localup;
3683 SCIP_Bool localdownvalid;
3684 SCIP_Bool localupvalid;
3685
3686 SCIP_CALL( SCIPcheckStage(scip, "SCIPgetVarStrongbranchInt", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
3687
3688 assert(lperror != NULL);
3689 assert(var->scip == scip);
3690
3691 if( downvalid != NULL )
3692 *downvalid = FALSE;
3693 if( upvalid != NULL )
3694 *upvalid = FALSE;
3695 if( downinf != NULL )
3696 *downinf = FALSE;
3697 if( upinf != NULL )
3698 *upinf = FALSE;
3699 if( downconflict != NULL )
3700 *downconflict = FALSE;
3701 if( upconflict != NULL )
3702 *upconflict = FALSE;
3703
3704 if( SCIPvarGetStatus(var) != SCIP_VARSTATUS_COLUMN )
3705 {
3706 SCIPerrorMessage("cannot get strong branching information on non-COLUMN variable <%s>\n", SCIPvarGetName(var));
3707 return SCIP_INVALIDDATA;
3708 }
3709
3710 col = SCIPvarGetCol(var);
3711 assert(col != NULL);
3712
3713 if( !SCIPcolIsInLP(col) )
3714 {
3715 SCIPerrorMessage("cannot get strong branching information on variable <%s> not in current LP\n", SCIPvarGetName(var));
3716 return SCIP_INVALIDDATA;
3717 }
3718
3719 /* check if the solving process should be aborted */
3720 if( SCIPsolveIsStopped(scip->set, scip->stat, FALSE) )
3721 {
3722 /* mark this as if the LP failed */
3723 *lperror = TRUE;
3724 return SCIP_OKAY;
3725 }
3726
3727 /* call strong branching for column */
3728 SCIP_CALL( SCIPcolGetStrongbranch(col, TRUE, scip->set, scip->stat, scip->transprob, scip->lp, itlim, !idempotent, !idempotent,
3729 &localdown, &localup, &localdownvalid, &localupvalid, lperror) );
3730
3731 /* check, if the branchings are infeasible; in exact solving mode, we cannot trust the strong branching enough to
3732 * declare the sub nodes infeasible
3733 */
3734 if( !(*lperror) && SCIPprobAllColsInLP(scip->transprob, scip->set, scip->lp) && !scip->set->misc_exactsolve )
3735 {
3736 if( !idempotent ) /*lint !e774*/
3737 {
3738 SCIP_CALL( analyzeStrongbranch(scip, var, downinf, upinf, downconflict, upconflict) );
3739 }
3740 else
3741 {
3742 if( downinf != NULL )
3743 *downinf = localdownvalid && SCIPsetIsGE(scip->set, localdown, scip->lp->cutoffbound);
3744 if( upinf != NULL )
3745 *upinf = localupvalid && SCIPsetIsGE(scip->set, localup, scip->lp->cutoffbound);
3746 }
3747 }
3748
3749 if( down != NULL )
3750 *down = localdown;
3751 if( up != NULL )
3752 *up = localup;
3753 if( downvalid != NULL )
3754 *downvalid = localdownvalid;
3755 if( upvalid != NULL )
3756 *upvalid = localupvalid;
3757
3758 return SCIP_OKAY;
3759 }
3760
3761 /** gets strong branching information on column variables with fractional values
3762 *
3763 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
3764 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
3765 *
3766 * @pre This method can be called if @p scip is in one of the following stages:
3767 * - \ref SCIP_STAGE_PRESOLVED
3768 * - \ref SCIP_STAGE_SOLVING
3769 */
SCIPgetVarsStrongbranchesFrac(SCIP * scip,SCIP_VAR ** vars,int nvars,int itlim,SCIP_Real * down,SCIP_Real * up,SCIP_Bool * downvalid,SCIP_Bool * upvalid,SCIP_Bool * downinf,SCIP_Bool * upinf,SCIP_Bool * downconflict,SCIP_Bool * upconflict,SCIP_Bool * lperror)3770 SCIP_RETCODE SCIPgetVarsStrongbranchesFrac(
3771 SCIP* scip, /**< SCIP data structure */
3772 SCIP_VAR** vars, /**< variables to get strong branching values for */
3773 int nvars, /**< number of variables */
3774 int itlim, /**< iteration limit for strong branchings */
3775 SCIP_Real* down, /**< stores dual bounds after branching variables down */
3776 SCIP_Real* up, /**< stores dual bounds after branching variables up */
3777 SCIP_Bool* downvalid, /**< stores whether the returned down values are valid dual bounds, or NULL;
3778 * otherwise, they can only be used as an estimate value */
3779 SCIP_Bool* upvalid, /**< stores whether the returned up values are valid dual bounds, or NULL;
3780 * otherwise, they can only be used as an estimate value */
3781 SCIP_Bool* downinf, /**< array to store whether the downward branches are infeasible, or NULL */
3782 SCIP_Bool* upinf, /**< array to store whether the upward branches are infeasible, or NULL */
3783 SCIP_Bool* downconflict, /**< array to store whether conflict constraints were created for
3784 * infeasible downward branches, or NULL */
3785 SCIP_Bool* upconflict, /**< array to store whether conflict constraints were created for
3786 * infeasible upward branches, or NULL */
3787 SCIP_Bool* lperror /**< pointer to store whether an unresolved LP error occurred or the
3788 * solving process should be stopped (e.g., due to a time limit) */
3789 )
3790 {
3791 SCIP_COL** cols;
3792 int j;
3793
3794 SCIP_CALL( SCIPcheckStage(scip, "SCIPgetVarsStrongbranchesFrac", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
3795
3796 assert( lperror != NULL );
3797 assert( vars != NULL );
3798
3799 /* set up data */
3800 cols = NULL;
3801 SCIP_CALL( SCIPallocBufferArray(scip, &cols, nvars) );
3802 assert(cols != NULL);
3803 for( j = 0; j < nvars; ++j )
3804 {
3805 SCIP_VAR* var;
3806 SCIP_COL* col;
3807
3808 if( downvalid != NULL )
3809 downvalid[j] = FALSE;
3810 if( upvalid != NULL )
3811 upvalid[j] = FALSE;
3812 if( downinf != NULL )
3813 downinf[j] = FALSE;
3814 if( upinf != NULL )
3815 upinf[j] = FALSE;
3816 if( downconflict != NULL )
3817 downconflict[j] = FALSE;
3818 if( upconflict != NULL )
3819 upconflict[j] = FALSE;
3820
3821 var = vars[j];
3822 assert( var != NULL );
3823 if( SCIPvarGetStatus(var) != SCIP_VARSTATUS_COLUMN )
3824 {
3825 SCIPerrorMessage("cannot get strong branching information on non-COLUMN variable <%s>\n", SCIPvarGetName(var));
3826 SCIPfreeBufferArray(scip, &cols);
3827 return SCIP_INVALIDDATA;
3828 }
3829
3830 col = SCIPvarGetCol(var);
3831 assert(col != NULL);
3832 cols[j] = col;
3833
3834 if( !SCIPcolIsInLP(col) )
3835 {
3836 SCIPerrorMessage("cannot get strong branching information on variable <%s> not in current LP\n", SCIPvarGetName(var));
3837 SCIPfreeBufferArray(scip, &cols);
3838 return SCIP_INVALIDDATA;
3839 }
3840 }
3841
3842 /* check if the solving process should be aborted */
3843 if( SCIPsolveIsStopped(scip->set, scip->stat, FALSE) )
3844 {
3845 /* mark this as if the LP failed */
3846 *lperror = TRUE;
3847 }
3848 else
3849 {
3850 /* call strong branching for columns with fractional value */
3851 SCIP_CALL( SCIPcolGetStrongbranches(cols, nvars, FALSE, scip->set, scip->stat, scip->transprob, scip->lp, itlim,
3852 down, up, downvalid, upvalid, lperror) );
3853
3854 /* check, if the branchings are infeasible; in exact solving mode, we cannot trust the strong branching enough to
3855 * declare the sub nodes infeasible
3856 */
3857 if( !(*lperror) && SCIPprobAllColsInLP(scip->transprob, scip->set, scip->lp) && !scip->set->misc_exactsolve )
3858 {
3859 for( j = 0; j < nvars; ++j )
3860 {
3861 SCIP_CALL( analyzeStrongbranch(scip, vars[j], (downinf != NULL) ? (&(downinf[j])) : NULL,
3862 (upinf != NULL) ? (&(upinf[j])) : NULL, (downconflict != NULL) ? (&(downconflict[j])) : NULL,
3863 (upconflict != NULL) ? (&(upconflict[j])) : NULL) );
3864 }
3865 }
3866 }
3867 SCIPfreeBufferArray(scip, &cols);
3868
3869 return SCIP_OKAY;
3870 }
3871
3872 /** gets strong branching information on column variables with integral values
3873 *
3874 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
3875 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
3876 *
3877 * @pre This method can be called if @p scip is in one of the following stages:
3878 * - \ref SCIP_STAGE_PRESOLVED
3879 * - \ref SCIP_STAGE_SOLVING
3880 */
SCIPgetVarsStrongbranchesInt(SCIP * scip,SCIP_VAR ** vars,int nvars,int itlim,SCIP_Real * down,SCIP_Real * up,SCIP_Bool * downvalid,SCIP_Bool * upvalid,SCIP_Bool * downinf,SCIP_Bool * upinf,SCIP_Bool * downconflict,SCIP_Bool * upconflict,SCIP_Bool * lperror)3881 SCIP_RETCODE SCIPgetVarsStrongbranchesInt(
3882 SCIP* scip, /**< SCIP data structure */
3883 SCIP_VAR** vars, /**< variables to get strong branching values for */
3884 int nvars, /**< number of variables */
3885 int itlim, /**< iteration limit for strong branchings */
3886 SCIP_Real* down, /**< stores dual bounds after branching variables down */
3887 SCIP_Real* up, /**< stores dual bounds after branching variables up */
3888 SCIP_Bool* downvalid, /**< stores whether the returned down values are valid dual bounds, or NULL;
3889 * otherwise, they can only be used as an estimate value */
3890 SCIP_Bool* upvalid, /**< stores whether the returned up values are valid dual bounds, or NULL;
3891 * otherwise, they can only be used as an estimate value */
3892 SCIP_Bool* downinf, /**< array to store whether the downward branches are infeasible, or NULL */
3893 SCIP_Bool* upinf, /**< array to store whether the upward branches are infeasible, or NULL */
3894 SCIP_Bool* downconflict, /**< array to store whether conflict constraints were created for
3895 * infeasible downward branches, or NULL */
3896 SCIP_Bool* upconflict, /**< array to store whether conflict constraints were created for
3897 * infeasible upward branches, or NULL */
3898 SCIP_Bool* lperror /**< pointer to store whether an unresolved LP error occurred or the
3899 * solving process should be stopped (e.g., due to a time limit) */
3900 )
3901 {
3902 SCIP_COL** cols;
3903 int j;
3904
3905 assert(lperror != NULL);
3906
3907 SCIP_CALL( SCIPcheckStage(scip, "SCIPgetVarsStrongbranchesInt", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
3908
3909 assert( vars != NULL );
3910
3911 /* set up data */
3912 cols = NULL;
3913 SCIP_CALL( SCIPallocBufferArray(scip, &cols, nvars) );
3914 assert(cols != NULL);
3915 for( j = 0; j < nvars; ++j )
3916 {
3917 SCIP_VAR* var;
3918 SCIP_COL* col;
3919
3920 if( downvalid != NULL )
3921 downvalid[j] = FALSE;
3922 if( upvalid != NULL )
3923 upvalid[j] = FALSE;
3924 if( downinf != NULL )
3925 downinf[j] = FALSE;
3926 if( upinf != NULL )
3927 upinf[j] = FALSE;
3928 if( downconflict != NULL )
3929 downconflict[j] = FALSE;
3930 if( upconflict != NULL )
3931 upconflict[j] = FALSE;
3932
3933 var = vars[j];
3934 assert( var != NULL );
3935 if( SCIPvarGetStatus(var) != SCIP_VARSTATUS_COLUMN )
3936 {
3937 SCIPerrorMessage("cannot get strong branching information on non-COLUMN variable <%s>\n", SCIPvarGetName(var));
3938 SCIPfreeBufferArray(scip, &cols);
3939 return SCIP_INVALIDDATA;
3940 }
3941
3942 col = SCIPvarGetCol(var);
3943 assert(col != NULL);
3944 cols[j] = col;
3945
3946 if( !SCIPcolIsInLP(col) )
3947 {
3948 SCIPerrorMessage("cannot get strong branching information on variable <%s> not in current LP\n", SCIPvarGetName(var));
3949 SCIPfreeBufferArray(scip, &cols);
3950 return SCIP_INVALIDDATA;
3951 }
3952 }
3953
3954 /* check if the solving process should be aborted */
3955 if( SCIPsolveIsStopped(scip->set, scip->stat, FALSE) )
3956 {
3957 /* mark this as if the LP failed */
3958 *lperror = TRUE;
3959 }
3960 else
3961 {
3962 /* call strong branching for columns */
3963 SCIP_CALL( SCIPcolGetStrongbranches(cols, nvars, TRUE, scip->set, scip->stat, scip->transprob, scip->lp, itlim,
3964 down, up, downvalid, upvalid, lperror) );
3965
3966 /* check, if the branchings are infeasible; in exact solving mode, we cannot trust the strong branching enough to
3967 * declare the sub nodes infeasible
3968 */
3969 if( !(*lperror) && SCIPprobAllColsInLP(scip->transprob, scip->set, scip->lp) && !scip->set->misc_exactsolve )
3970 {
3971 for( j = 0; j < nvars; ++j )
3972 {
3973 SCIP_CALL( analyzeStrongbranch(scip, vars[j], (downinf != NULL) ? (&(downinf[j])) : NULL,
3974 (upinf != NULL) ? (&(upinf[j])) : NULL, (downconflict != NULL) ? (&(downconflict[j])) : NULL,
3975 (upconflict != NULL) ? (&(upconflict[j])) : NULL) );
3976 }
3977 }
3978 }
3979 SCIPfreeBufferArray(scip, &cols);
3980
3981 return SCIP_OKAY;
3982 }
3983
3984 /** get LP solution status of last strong branching call (currently only works for strong branching with propagation) */
SCIPgetLastStrongbranchLPSolStat(SCIP * scip,SCIP_BRANCHDIR branchdir)3985 SCIP_LPSOLSTAT SCIPgetLastStrongbranchLPSolStat(
3986 SCIP* scip, /**< SCIP data structure */
3987 SCIP_BRANCHDIR branchdir /**< branching direction for which LP solution status is requested */
3988 )
3989 {
3990 assert(NULL != scip);
3991 assert(branchdir == SCIP_BRANCHDIR_DOWNWARDS || branchdir == SCIP_BRANCHDIR_UPWARDS);
3992
3993 return scip->stat->lastsblpsolstats[branchdir == SCIP_BRANCHDIR_DOWNWARDS ? 0 : 1];
3994 }
3995
3996 /** gets strong branching information on COLUMN variable of the last SCIPgetVarStrongbranch() call;
3997 * returns values of SCIP_INVALID, if strong branching was not yet called on the given variable;
3998 * keep in mind, that the returned old values may have nothing to do with the current LP solution
3999 *
4000 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
4001 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
4002 *
4003 * @pre This method can be called if @p scip is in one of the following stages:
4004 * - \ref SCIP_STAGE_SOLVING
4005 * - \ref SCIP_STAGE_SOLVED
4006 */
SCIPgetVarStrongbranchLast(SCIP * scip,SCIP_VAR * var,SCIP_Real * down,SCIP_Real * up,SCIP_Bool * downvalid,SCIP_Bool * upvalid,SCIP_Real * solval,SCIP_Real * lpobjval)4007 SCIP_RETCODE SCIPgetVarStrongbranchLast(
4008 SCIP* scip, /**< SCIP data structure */
4009 SCIP_VAR* var, /**< variable to get last strong branching values for */
4010 SCIP_Real* down, /**< stores dual bound after branching column down */
4011 SCIP_Real* up, /**< stores dual bound after branching column up */
4012 SCIP_Bool* downvalid, /**< stores whether the returned down value is a valid dual bound, or NULL;
4013 * otherwise, it can only be used as an estimate value */
4014 SCIP_Bool* upvalid, /**< stores whether the returned up value is a valid dual bound, or NULL;
4015 * otherwise, it can only be used as an estimate value */
4016 SCIP_Real* solval, /**< stores LP solution value of variable at the last strong branching call, or NULL */
4017 SCIP_Real* lpobjval /**< stores LP objective value at last strong branching call, or NULL */
4018 )
4019 {
4020 SCIP_CALL( SCIPcheckStage(scip, "SCIPgetVarStrongbranchLast", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE) );
4021
4022 if( SCIPvarGetStatus(var) != SCIP_VARSTATUS_COLUMN )
4023 {
4024 SCIPerrorMessage("cannot get strong branching information on non-COLUMN variable\n");
4025 return SCIP_INVALIDDATA;
4026 }
4027
4028 SCIPcolGetStrongbranchLast(SCIPvarGetCol(var), down, up, downvalid, upvalid, solval, lpobjval);
4029
4030 return SCIP_OKAY;
4031 }
4032
4033 /** sets strong branching information for a column variable
4034 *
4035 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
4036 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
4037 *
4038 * @pre This method can be called if @p scip is in one of the following stages:
4039 * - \ref SCIP_STAGE_SOLVING
4040 */
SCIPsetVarStrongbranchData(SCIP * scip,SCIP_VAR * var,SCIP_Real lpobjval,SCIP_Real primsol,SCIP_Real down,SCIP_Real up,SCIP_Bool downvalid,SCIP_Bool upvalid,SCIP_Longint iter,int itlim)4041 SCIP_RETCODE SCIPsetVarStrongbranchData(
4042 SCIP* scip, /**< SCIP data structure */
4043 SCIP_VAR* var, /**< variable to set last strong branching values for */
4044 SCIP_Real lpobjval, /**< objective value of the current LP */
4045 SCIP_Real primsol, /**< primal solution value of the column in the current LP */
4046 SCIP_Real down, /**< dual bound after branching column down */
4047 SCIP_Real up, /**< dual bound after branching column up */
4048 SCIP_Bool downvalid, /**< is the returned down value a valid dual bound? */
4049 SCIP_Bool upvalid, /**< is the returned up value a valid dual bound? */
4050 SCIP_Longint iter, /**< total number of strong branching iterations */
4051 int itlim /**< iteration limit applied to the strong branching call */
4052 )
4053 {
4054 SCIP_CALL( SCIPcheckStage(scip, "SCIPsetVarStrongbranchData", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
4055
4056 if( SCIPvarGetStatus(var) != SCIP_VARSTATUS_COLUMN )
4057 {
4058 SCIPerrorMessage("cannot set strong branching information on non-COLUMN variable\n");
4059 return SCIP_INVALIDDATA;
4060 }
4061
4062 SCIPcolSetStrongbranchData(SCIPvarGetCol(var), scip->set, scip->stat, scip->lp, lpobjval, primsol,
4063 down, up, downvalid, upvalid, iter, itlim);
4064
4065 return SCIP_OKAY;
4066 }
4067
4068 /** rounds the current solution and tries it afterwards; if feasible, adds it to storage
4069 *
4070 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
4071 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
4072 *
4073 * @pre This method can be called if @p scip is in one of the following stages:
4074 * - \ref SCIP_STAGE_SOLVING
4075 */
SCIPtryStrongbranchLPSol(SCIP * scip,SCIP_Bool * foundsol,SCIP_Bool * cutoff)4076 SCIP_RETCODE SCIPtryStrongbranchLPSol(
4077 SCIP* scip, /**< SCIP data structure */
4078 SCIP_Bool* foundsol, /**< stores whether solution was feasible and good enough to keep */
4079 SCIP_Bool* cutoff /**< stores whether solution was cutoff due to exceeding the cutoffbound */
4080 )
4081 {
4082 assert(scip != NULL);
4083 assert(foundsol != NULL);
4084 assert(cutoff != NULL);
4085
4086 SCIP_CALL( SCIPcheckStage(scip, "SCIPtryStrongbranchLPSol", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
4087
4088 if( scip->set->branch_checksbsol )
4089 {
4090 SCIP_SOL* sol;
4091 SCIP_Bool rounded = TRUE;
4092 SCIP_Real value = SCIPgetLPObjval(scip);
4093 SCIP_Longint oldnbestsolsfound = scip->primal->nbestsolsfound;
4094
4095 /* start clock for strong branching solutions */
4096 SCIPclockStart(scip->stat->sbsoltime, scip->set);
4097
4098 SCIP_CALL( SCIPcreateLPSol(scip, &sol, NULL) );
4099 SCIPsolSetStrongbranching(sol);
4100
4101 /* try to round the strong branching solution */
4102 if( scip->set->branch_roundsbsol )
4103 {
4104 SCIP_CALL( SCIProundSol(scip, sol, &rounded) );
4105 }
4106
4107 /* check the solution for feasibility if rounding worked well (or was not tried) */
4108 if( rounded )
4109 {
4110 SCIP_CALL( SCIPtrySolFree(scip, &sol, FALSE, FALSE, FALSE, TRUE, FALSE, foundsol) );
4111 }
4112 else
4113 {
4114 SCIP_CALL( SCIPfreeSol(scip, &sol) );
4115 }
4116
4117 if( *foundsol )
4118 {
4119 SCIPdebugMsg(scip, "found new solution in strong branching\n");
4120
4121 scip->stat->nsbsolsfound++;
4122
4123 if( scip->primal->nbestsolsfound != oldnbestsolsfound )
4124 {
4125 scip->stat->nsbbestsolsfound++;
4126 }
4127
4128 if( SCIPisGE(scip, value, SCIPgetCutoffbound(scip)) )
4129 *cutoff = TRUE;
4130 }
4131
4132 /* stop clock for strong branching solutions */
4133 SCIPclockStop(scip->stat->sbsoltime, scip->set);
4134 }
4135 return SCIP_OKAY;
4136 }
4137
4138
4139 /** gets node number of the last node in current branch and bound run, where strong branching was used on the
4140 * given variable, or -1 if strong branching was never applied to the variable in current run
4141 *
4142 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
4143 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
4144 *
4145 * @pre This method can be called if @p scip is in one of the following stages:
4146 * - \ref SCIP_STAGE_TRANSFORMING
4147 * - \ref SCIP_STAGE_TRANSFORMED
4148 * - \ref SCIP_STAGE_INITPRESOLVE
4149 * - \ref SCIP_STAGE_PRESOLVING
4150 * - \ref SCIP_STAGE_EXITPRESOLVE
4151 * - \ref SCIP_STAGE_PRESOLVED
4152 * - \ref SCIP_STAGE_INITSOLVE
4153 * - \ref SCIP_STAGE_SOLVING
4154 * - \ref SCIP_STAGE_SOLVED
4155 * - \ref SCIP_STAGE_EXITSOLVE
4156 */
SCIPgetVarStrongbranchNode(SCIP * scip,SCIP_VAR * var)4157 SCIP_Longint SCIPgetVarStrongbranchNode(
4158 SCIP* scip, /**< SCIP data structure */
4159 SCIP_VAR* var /**< variable to get last strong branching node for */
4160 )
4161 {
4162 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetVarStrongbranchNode", FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE) );
4163
4164 assert( var->scip == scip );
4165
4166 if( SCIPvarGetStatus(var) != SCIP_VARSTATUS_COLUMN )
4167 return -1;
4168
4169 return SCIPcolGetStrongbranchNode(SCIPvarGetCol(var));
4170 }
4171
4172 /** if strong branching was already applied on the variable at the current node, returns the number of LPs solved after
4173 * the LP where the strong branching on this variable was applied;
4174 * if strong branching was not yet applied on the variable at the current node, returns INT_MAX
4175 *
4176 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
4177 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
4178 *
4179 * @pre This method can be called if @p scip is in one of the following stages:
4180 * - \ref SCIP_STAGE_TRANSFORMING
4181 * - \ref SCIP_STAGE_TRANSFORMED
4182 * - \ref SCIP_STAGE_INITPRESOLVE
4183 * - \ref SCIP_STAGE_PRESOLVING
4184 * - \ref SCIP_STAGE_EXITPRESOLVE
4185 * - \ref SCIP_STAGE_PRESOLVED
4186 * - \ref SCIP_STAGE_INITSOLVE
4187 * - \ref SCIP_STAGE_SOLVING
4188 * - \ref SCIP_STAGE_SOLVED
4189 * - \ref SCIP_STAGE_EXITSOLVE
4190 */
SCIPgetVarStrongbranchLPAge(SCIP * scip,SCIP_VAR * var)4191 SCIP_Longint SCIPgetVarStrongbranchLPAge(
4192 SCIP* scip, /**< SCIP data structure */
4193 SCIP_VAR* var /**< variable to get strong branching LP age for */
4194 )
4195 {
4196 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetVarStrongbranchLPAge", FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE) );
4197
4198 assert( var->scip == scip );
4199
4200 if( SCIPvarGetStatus(var) != SCIP_VARSTATUS_COLUMN )
4201 return SCIP_LONGINT_MAX;
4202
4203 return SCIPcolGetStrongbranchLPAge(SCIPvarGetCol(var), scip->stat);
4204 }
4205
4206 /** gets number of times, strong branching was applied in current run on the given variable
4207 *
4208 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
4209 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
4210 *
4211 * @pre This method can be called if @p scip is in one of the following stages:
4212 * - \ref SCIP_STAGE_TRANSFORMING
4213 * - \ref SCIP_STAGE_TRANSFORMED
4214 * - \ref SCIP_STAGE_INITPRESOLVE
4215 * - \ref SCIP_STAGE_PRESOLVING
4216 * - \ref SCIP_STAGE_EXITPRESOLVE
4217 * - \ref SCIP_STAGE_PRESOLVED
4218 * - \ref SCIP_STAGE_INITSOLVE
4219 * - \ref SCIP_STAGE_SOLVING
4220 * - \ref SCIP_STAGE_SOLVED
4221 * - \ref SCIP_STAGE_EXITSOLVE
4222 */
SCIPgetVarNStrongbranchs(SCIP * scip,SCIP_VAR * var)4223 int SCIPgetVarNStrongbranchs(
4224 SCIP* scip, /**< SCIP data structure */
4225 SCIP_VAR* var /**< variable to get last strong branching node for */
4226 )
4227 {
4228 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetVarNStrongbranchs", FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE) );
4229
4230 assert( var->scip == scip );
4231
4232 if( SCIPvarGetStatus(var) != SCIP_VARSTATUS_COLUMN )
4233 return 0;
4234
4235 return SCIPcolGetNStrongbranchs(SCIPvarGetCol(var));
4236 }
4237
4238 /** adds given values to lock numbers of type @p locktype of variable for rounding
4239 *
4240 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
4241 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
4242 *
4243 * @pre This method can be called if @p scip is in one of the following stages:
4244 * - \ref SCIP_STAGE_PROBLEM
4245 * - \ref SCIP_STAGE_TRANSFORMING
4246 * - \ref SCIP_STAGE_TRANSFORMED
4247 * - \ref SCIP_STAGE_INITPRESOLVE
4248 * - \ref SCIP_STAGE_PRESOLVING
4249 * - \ref SCIP_STAGE_EXITPRESOLVE
4250 * - \ref SCIP_STAGE_PRESOLVED
4251 * - \ref SCIP_STAGE_INITSOLVE
4252 * - \ref SCIP_STAGE_SOLVING
4253 * - \ref SCIP_STAGE_EXITSOLVE
4254 * - \ref SCIP_STAGE_FREETRANS
4255 */
SCIPaddVarLocksType(SCIP * scip,SCIP_VAR * var,SCIP_LOCKTYPE locktype,int nlocksdown,int nlocksup)4256 SCIP_RETCODE SCIPaddVarLocksType(
4257 SCIP* scip, /**< SCIP data structure */
4258 SCIP_VAR* var, /**< problem variable */
4259 SCIP_LOCKTYPE locktype, /**< type of the variable locks */
4260 int nlocksdown, /**< modification in number of rounding down locks */
4261 int nlocksup /**< modification in number of rounding up locks */
4262 )
4263 {
4264 SCIP_CALL( SCIPcheckStage(scip, "SCIPaddVarLocksType", FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE) );
4265
4266 assert( var->scip == scip );
4267
4268 switch( scip->set->stage )
4269 {
4270 case SCIP_STAGE_PROBLEM:
4271 assert(!SCIPvarIsTransformed(var));
4272 /*lint -fallthrough*/
4273 case SCIP_STAGE_TRANSFORMING:
4274 case SCIP_STAGE_TRANSFORMED:
4275 case SCIP_STAGE_INITPRESOLVE:
4276 case SCIP_STAGE_PRESOLVING:
4277 case SCIP_STAGE_EXITPRESOLVE:
4278 case SCIP_STAGE_PRESOLVED:
4279 case SCIP_STAGE_INITSOLVE:
4280 case SCIP_STAGE_SOLVING:
4281 case SCIP_STAGE_EXITSOLVE:
4282 case SCIP_STAGE_FREETRANS:
4283 SCIP_CALL( SCIPvarAddLocks(var, scip->mem->probmem, scip->set, scip->eventqueue, locktype, nlocksdown, nlocksup) );
4284 return SCIP_OKAY;
4285
4286 default:
4287 SCIPerrorMessage("invalid SCIP stage <%d>\n", scip->set->stage);
4288 return SCIP_INVALIDCALL;
4289 } /*lint !e788*/
4290 }
4291
4292 /** adds given values to lock numbers of variable for rounding
4293 *
4294 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
4295 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
4296 *
4297 * @pre This method can be called if @p scip is in one of the following stages:
4298 * - \ref SCIP_STAGE_PROBLEM
4299 * - \ref SCIP_STAGE_TRANSFORMING
4300 * - \ref SCIP_STAGE_TRANSFORMED
4301 * - \ref SCIP_STAGE_INITPRESOLVE
4302 * - \ref SCIP_STAGE_PRESOLVING
4303 * - \ref SCIP_STAGE_EXITPRESOLVE
4304 * - \ref SCIP_STAGE_PRESOLVED
4305 * - \ref SCIP_STAGE_INITSOLVE
4306 * - \ref SCIP_STAGE_SOLVING
4307 * - \ref SCIP_STAGE_EXITSOLVE
4308 * - \ref SCIP_STAGE_FREETRANS
4309 *
4310 * @note This method will always add variable locks of type model
4311 *
4312 * @note It is recommented to use SCIPaddVarLocksType()
4313 */
SCIPaddVarLocks(SCIP * scip,SCIP_VAR * var,int nlocksdown,int nlocksup)4314 SCIP_RETCODE SCIPaddVarLocks(
4315 SCIP* scip, /**< SCIP data structure */
4316 SCIP_VAR* var, /**< problem variable */
4317 int nlocksdown, /**< modification in number of rounding down locks */
4318 int nlocksup /**< modification in number of rounding up locks */
4319 )
4320 {
4321 SCIP_CALL( SCIPcheckStage(scip, "SCIPaddVarLocks", FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE) );
4322
4323 SCIP_CALL( SCIPaddVarLocksType(scip, var, SCIP_LOCKTYPE_MODEL, nlocksdown, nlocksup) );
4324
4325 return SCIP_OKAY;
4326 }
4327
4328 /** add locks of variable with respect to the lock status of the constraint and its negation;
4329 * this method should be called whenever the lock status of a variable in a constraint changes, for example if
4330 * the coefficient of the variable changed its sign or if the left or right hand sides of the constraint were
4331 * added or removed
4332 *
4333 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
4334 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
4335 *
4336 * @pre This method can be called if @p scip is in one of the following stages:
4337 * - \ref SCIP_STAGE_PROBLEM
4338 * - \ref SCIP_STAGE_TRANSFORMING
4339 * - \ref SCIP_STAGE_INITPRESOLVE
4340 * - \ref SCIP_STAGE_PRESOLVING
4341 * - \ref SCIP_STAGE_EXITPRESOLVE
4342 * - \ref SCIP_STAGE_INITSOLVE
4343 * - \ref SCIP_STAGE_SOLVING
4344 * - \ref SCIP_STAGE_EXITSOLVE
4345 * - \ref SCIP_STAGE_FREETRANS
4346 */
SCIPlockVarCons(SCIP * scip,SCIP_VAR * var,SCIP_CONS * cons,SCIP_Bool lockdown,SCIP_Bool lockup)4347 SCIP_RETCODE SCIPlockVarCons(
4348 SCIP* scip, /**< SCIP data structure */
4349 SCIP_VAR* var, /**< problem variable */
4350 SCIP_CONS* cons, /**< constraint */
4351 SCIP_Bool lockdown, /**< should the rounding be locked in downwards direction? */
4352 SCIP_Bool lockup /**< should the rounding be locked in upwards direction? */
4353 )
4354 {
4355 int nlocksdown[NLOCKTYPES];
4356 int nlocksup[NLOCKTYPES];
4357 int i;
4358
4359 SCIP_CALL( SCIPcheckStage(scip, "SCIPlockVarCons", FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE) );
4360
4361 assert( var->scip == scip );
4362
4363 for( i = 0; i < NLOCKTYPES; i++ )
4364 {
4365 nlocksdown[i] = 0;
4366 nlocksup[i] = 0;
4367
4368 if( SCIPconsIsLockedTypePos(cons, (SCIP_LOCKTYPE) i) )
4369 {
4370 if( lockdown )
4371 ++nlocksdown[i];
4372 if( lockup )
4373 ++nlocksup[i];
4374 }
4375 if( SCIPconsIsLockedTypeNeg(cons, (SCIP_LOCKTYPE) i) )
4376 {
4377 if( lockdown )
4378 ++nlocksup[i];
4379 if( lockup )
4380 ++nlocksdown[i];
4381 }
4382 }
4383
4384 switch( scip->set->stage )
4385 {
4386 case SCIP_STAGE_PROBLEM:
4387 assert(!SCIPvarIsTransformed(var));
4388 /*lint -fallthrough*/
4389 case SCIP_STAGE_TRANSFORMING:
4390 case SCIP_STAGE_TRANSFORMED:
4391 case SCIP_STAGE_INITPRESOLVE:
4392 case SCIP_STAGE_PRESOLVING:
4393 case SCIP_STAGE_EXITPRESOLVE:
4394 case SCIP_STAGE_INITSOLVE:
4395 case SCIP_STAGE_SOLVING:
4396 case SCIP_STAGE_EXITSOLVE:
4397 case SCIP_STAGE_FREETRANS:
4398 for( i = 0; i < NLOCKTYPES; i++ )
4399 {
4400 if( nlocksdown[i] == 0 && nlocksup[i] == 0 )
4401 continue;
4402
4403 SCIP_CALL( SCIPvarAddLocks(var, scip->mem->probmem, scip->set, scip->eventqueue, (SCIP_LOCKTYPE) i, nlocksdown[i], nlocksup[i]) );
4404 }
4405 return SCIP_OKAY;
4406
4407 default:
4408 SCIPerrorMessage("invalid SCIP stage <%d>\n", scip->set->stage);
4409 return SCIP_INVALIDCALL;
4410 } /*lint !e788*/
4411 }
4412
4413 /** remove locks of type @p locktype of variable with respect to the lock status of the constraint and its negation;
4414 * this method should be called whenever the lock status of a variable in a constraint changes, for example if
4415 * the coefficient of the variable changed its sign or if the left or right hand sides of the constraint were
4416 * added or removed
4417 *
4418 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
4419 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
4420 *
4421 * @pre This method can be called if @p scip is in one of the following stages:
4422 * - \ref SCIP_STAGE_PROBLEM
4423 * - \ref SCIP_STAGE_TRANSFORMING
4424 * - \ref SCIP_STAGE_INITPRESOLVE
4425 * - \ref SCIP_STAGE_PRESOLVING
4426 * - \ref SCIP_STAGE_EXITPRESOLVE
4427 * - \ref SCIP_STAGE_INITSOLVE
4428 * - \ref SCIP_STAGE_SOLVING
4429 * - \ref SCIP_STAGE_EXITSOLVE
4430 * - \ref SCIP_STAGE_FREETRANS
4431 */
SCIPunlockVarCons(SCIP * scip,SCIP_VAR * var,SCIP_CONS * cons,SCIP_Bool lockdown,SCIP_Bool lockup)4432 SCIP_RETCODE SCIPunlockVarCons(
4433 SCIP* scip, /**< SCIP data structure */
4434 SCIP_VAR* var, /**< problem variable */
4435 SCIP_CONS* cons, /**< constraint */
4436 SCIP_Bool lockdown, /**< should the rounding be unlocked in downwards direction? */
4437 SCIP_Bool lockup /**< should the rounding be unlocked in upwards direction? */
4438 )
4439 {
4440 int nlocksdown[NLOCKTYPES];
4441 int nlocksup[NLOCKTYPES];
4442 int i;
4443
4444 SCIP_CALL( SCIPcheckStage(scip, "SCIPunlockVarCons", FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE) );
4445
4446 assert( var->scip == scip );
4447
4448 for( i = 0; i < NLOCKTYPES; i++ )
4449 {
4450 nlocksdown[i] = 0;
4451 nlocksup[i] = 0;
4452
4453 if( SCIPconsIsLockedTypePos(cons, (SCIP_LOCKTYPE) i) )
4454 {
4455 if( lockdown )
4456 ++nlocksdown[i];
4457 if( lockup )
4458 ++nlocksup[i];
4459 }
4460 if( SCIPconsIsLockedTypeNeg(cons, (SCIP_LOCKTYPE) i) )
4461 {
4462 if( lockdown )
4463 ++nlocksup[i];
4464 if( lockup )
4465 ++nlocksdown[i];
4466 }
4467 }
4468 switch( scip->set->stage )
4469 {
4470 case SCIP_STAGE_PROBLEM:
4471 assert(!SCIPvarIsTransformed(var));
4472 /*lint -fallthrough*/
4473 case SCIP_STAGE_TRANSFORMING:
4474 case SCIP_STAGE_INITPRESOLVE:
4475 case SCIP_STAGE_PRESOLVING:
4476 case SCIP_STAGE_EXITPRESOLVE:
4477 case SCIP_STAGE_INITSOLVE:
4478 case SCIP_STAGE_SOLVING:
4479 case SCIP_STAGE_EXITSOLVE:
4480 case SCIP_STAGE_FREETRANS:
4481 for( i = 0; i < NLOCKTYPES; i++ )
4482 {
4483 if( nlocksdown[i] == 0 && nlocksup[i] == 0 )
4484 continue;
4485
4486 SCIP_CALL( SCIPvarAddLocks(var, scip->mem->probmem, scip->set, scip->eventqueue, (SCIP_LOCKTYPE) i, -nlocksdown[i], -nlocksup[i]) );
4487 }
4488 return SCIP_OKAY;
4489
4490 default:
4491 SCIPerrorMessage("invalid SCIP stage <%d>\n", scip->set->stage);
4492 return SCIP_INVALIDCALL;
4493 } /*lint !e788*/
4494 }
4495
4496 /** changes variable's objective value
4497 *
4498 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
4499 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
4500 *
4501 * @pre This method can be called if @p scip is in one of the following stages:
4502 * - \ref SCIP_STAGE_PROBLEM
4503 * - \ref SCIP_STAGE_TRANSFORMING
4504 * - \ref SCIP_STAGE_PRESOLVING
4505 * - \ref SCIP_STAGE_PRESOLVED
4506 */
SCIPchgVarObj(SCIP * scip,SCIP_VAR * var,SCIP_Real newobj)4507 SCIP_RETCODE SCIPchgVarObj(
4508 SCIP* scip, /**< SCIP data structure */
4509 SCIP_VAR* var, /**< variable to change the objective value for */
4510 SCIP_Real newobj /**< new objective value */
4511 )
4512 {
4513 SCIP_CALL( SCIPcheckStage(scip, "SCIPchgVarObj", FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE) );
4514
4515 assert( var->scip == scip );
4516
4517 /* forbid infinite objective values */
4518 if( SCIPisInfinity(scip, REALABS(newobj)) )
4519 {
4520 SCIPerrorMessage("invalid objective value: objective value is infinite\n");
4521 return SCIP_INVALIDDATA;
4522 }
4523
4524 switch( scip->set->stage )
4525 {
4526 case SCIP_STAGE_PROBLEM:
4527 assert(!SCIPvarIsTransformed(var));
4528 SCIP_CALL( SCIPvarChgObj(var, scip->mem->probmem, scip->set, scip->origprob, scip->primal, scip->lp, scip->eventqueue, newobj) );
4529 return SCIP_OKAY;
4530
4531 case SCIP_STAGE_TRANSFORMED:
4532 case SCIP_STAGE_TRANSFORMING:
4533 case SCIP_STAGE_PRESOLVING:
4534 case SCIP_STAGE_PRESOLVED:
4535 SCIP_CALL( SCIPvarChgObj(var, scip->mem->probmem, scip->set, scip->transprob, scip->primal, scip->lp, scip->eventqueue, newobj) );
4536 return SCIP_OKAY;
4537
4538 default:
4539 SCIPerrorMessage("invalid SCIP stage <%d>\n", scip->set->stage);
4540 return SCIP_INVALIDCALL;
4541 } /*lint !e788*/
4542 }
4543
4544 /** adds value to variable's objective value
4545 *
4546 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
4547 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
4548 *
4549 * @pre This method can be called if @p scip is in one of the following stages:
4550 * - \ref SCIP_STAGE_PROBLEM
4551 * - \ref SCIP_STAGE_TRANSFORMING
4552 * - \ref SCIP_STAGE_PRESOLVING
4553 * - \ref SCIP_STAGE_EXITPRESOLVE
4554 * - \ref SCIP_STAGE_PRESOLVED
4555 */
SCIPaddVarObj(SCIP * scip,SCIP_VAR * var,SCIP_Real addobj)4556 SCIP_RETCODE SCIPaddVarObj(
4557 SCIP* scip, /**< SCIP data structure */
4558 SCIP_VAR* var, /**< variable to change the objective value for */
4559 SCIP_Real addobj /**< additional objective value */
4560 )
4561 {
4562 SCIP_CALL( SCIPcheckStage(scip, "SCIPaddVarObj", FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE) );
4563
4564 assert( var->scip == scip );
4565
4566 switch( scip->set->stage )
4567 {
4568 case SCIP_STAGE_PROBLEM:
4569 assert(!SCIPvarIsTransformed(var));
4570 SCIP_CALL( SCIPvarAddObj(var, scip->mem->probmem, scip->set, scip->stat, scip->transprob, scip->origprob, scip->primal,
4571 scip->tree, scip->reopt, scip->lp, scip->eventfilter, scip->eventqueue, addobj) );
4572 return SCIP_OKAY;
4573
4574 case SCIP_STAGE_TRANSFORMING:
4575 case SCIP_STAGE_PRESOLVING:
4576 case SCIP_STAGE_EXITPRESOLVE:
4577 case SCIP_STAGE_PRESOLVED:
4578 SCIP_CALL( SCIPvarAddObj(var, scip->mem->probmem, scip->set, scip->stat, scip->transprob, scip->origprob, scip->primal,
4579 scip->tree, scip->reopt, scip->lp, scip->eventfilter, scip->eventqueue, addobj) );
4580 return SCIP_OKAY;
4581
4582 default:
4583 SCIPerrorMessage("invalid SCIP stage <%d>\n", scip->set->stage);
4584 return SCIP_INVALIDCALL;
4585 } /*lint !e788*/
4586 }
4587
4588 /** returns the adjusted (i.e. rounded, if the given variable is of integral type) lower bound value;
4589 * does not change the bounds of the variable
4590 *
4591 * @return adjusted lower bound for the given variable; the bound of the variable is not changed
4592 *
4593 * @pre This method can be called if @p scip is in one of the following stages:
4594 * - \ref SCIP_STAGE_PROBLEM
4595 * - \ref SCIP_STAGE_TRANSFORMING
4596 * - \ref SCIP_STAGE_TRANSFORMED
4597 * - \ref SCIP_STAGE_INITPRESOLVE
4598 * - \ref SCIP_STAGE_PRESOLVING
4599 * - \ref SCIP_STAGE_EXITPRESOLVE
4600 * - \ref SCIP_STAGE_PRESOLVED
4601 * - \ref SCIP_STAGE_INITSOLVE
4602 * - \ref SCIP_STAGE_SOLVING
4603 * - \ref SCIP_STAGE_SOLVED
4604 * - \ref SCIP_STAGE_EXITSOLVE
4605 * - \ref SCIP_STAGE_FREETRANS
4606 */
SCIPadjustedVarLb(SCIP * scip,SCIP_VAR * var,SCIP_Real lb)4607 SCIP_Real SCIPadjustedVarLb(
4608 SCIP* scip, /**< SCIP data structure */
4609 SCIP_VAR* var, /**< variable to adjust the bound for */
4610 SCIP_Real lb /**< lower bound value to adjust */
4611 )
4612 {
4613 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPadjustedVarLb", FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE) );
4614
4615 SCIPvarAdjustLb(var, scip->set, &lb);
4616
4617 return lb;
4618 }
4619
4620 /** returns the adjusted (i.e. rounded, if the given variable is of integral type) upper bound value;
4621 * does not change the bounds of the variable
4622 *
4623 * @return adjusted upper bound for the given variable; the bound of the variable is not changed
4624 *
4625 * @pre This method can be called if @p scip is in one of the following stages:
4626 * - \ref SCIP_STAGE_PROBLEM
4627 * - \ref SCIP_STAGE_TRANSFORMING
4628 * - \ref SCIP_STAGE_TRANSFORMED
4629 * - \ref SCIP_STAGE_INITPRESOLVE
4630 * - \ref SCIP_STAGE_PRESOLVING
4631 * - \ref SCIP_STAGE_EXITPRESOLVE
4632 * - \ref SCIP_STAGE_PRESOLVED
4633 * - \ref SCIP_STAGE_INITSOLVE
4634 * - \ref SCIP_STAGE_SOLVING
4635 * - \ref SCIP_STAGE_SOLVED
4636 * - \ref SCIP_STAGE_EXITSOLVE
4637 * - \ref SCIP_STAGE_FREETRANS
4638 */
SCIPadjustedVarUb(SCIP * scip,SCIP_VAR * var,SCIP_Real ub)4639 SCIP_Real SCIPadjustedVarUb(
4640 SCIP* scip, /**< SCIP data structure */
4641 SCIP_VAR* var, /**< variable to adjust the bound for */
4642 SCIP_Real ub /**< upper bound value to adjust */
4643 )
4644 {
4645 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPadjustedVarUb", FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE) );
4646
4647 SCIPvarAdjustUb(var, scip->set, &ub);
4648
4649 return ub;
4650 }
4651
4652 /** depending on SCIP's stage, changes lower bound of variable in the problem, in preprocessing, or in current node;
4653 * if possible, adjusts bound to integral value; doesn't store any inference information in the bound change, such
4654 * that in conflict analysis, this change is treated like a branching decision
4655 *
4656 * @warning If SCIP is in presolving stage, it can happen that the internal variable array (which can be accessed via
4657 * SCIPgetVars()) gets resorted.
4658 *
4659 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
4660 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
4661 *
4662 * @pre This method can be called if @p scip is in one of the following stages:
4663 * - \ref SCIP_STAGE_PROBLEM
4664 * - \ref SCIP_STAGE_TRANSFORMING
4665 * - \ref SCIP_STAGE_PRESOLVING
4666 * - \ref SCIP_STAGE_SOLVING
4667 *
4668 * @note During presolving, an integer variable whose bound changes to {0,1} is upgraded to a binary variable.
4669 */
SCIPchgVarLb(SCIP * scip,SCIP_VAR * var,SCIP_Real newbound)4670 SCIP_RETCODE SCIPchgVarLb(
4671 SCIP* scip, /**< SCIP data structure */
4672 SCIP_VAR* var, /**< variable to change the bound for */
4673 SCIP_Real newbound /**< new value for bound */
4674 )
4675 {
4676 SCIP_CALL( SCIPcheckStage(scip, "SCIPchgVarLb", FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
4677
4678 SCIPvarAdjustLb(var, scip->set, &newbound);
4679
4680 /* ignore tightenings of lower bounds to +infinity during solving process */
4681 if( SCIPisInfinity(scip, newbound) && SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
4682 {
4683 #ifndef NDEBUG
4684 SCIPwarningMessage(scip, "ignore lower bound tightening for %s from %e to +infinity\n", SCIPvarGetName(var),
4685 SCIPvarGetLbLocal(var));
4686 #endif
4687 return SCIP_OKAY;
4688 }
4689
4690 switch( scip->set->stage )
4691 {
4692 case SCIP_STAGE_PROBLEM:
4693 assert(!SCIPvarIsTransformed(var));
4694 SCIP_CALL( SCIPvarChgLbGlobal(var, scip->mem->probmem, scip->set, scip->stat, scip->lp,
4695 scip->branchcand, scip->eventqueue, scip->cliquetable, newbound) );
4696 SCIP_CALL( SCIPvarChgLbLocal(var, scip->mem->probmem, scip->set, scip->stat, scip->lp,
4697 scip->branchcand, scip->eventqueue, newbound) );
4698 SCIP_CALL( SCIPvarChgLbOriginal(var, scip->set, newbound) );
4699 break;
4700
4701 case SCIP_STAGE_TRANSFORMING:
4702 case SCIP_STAGE_PRESOLVED:
4703 SCIP_CALL( SCIPvarChgLbGlobal(var, scip->mem->probmem, scip->set, scip->stat, scip->lp,
4704 scip->branchcand, scip->eventqueue, scip->cliquetable, newbound) );
4705 break;
4706
4707 case SCIP_STAGE_PRESOLVING:
4708 if( !SCIPinProbing(scip) )
4709 {
4710 assert(SCIPtreeGetCurrentDepth(scip->tree) == 0);
4711 assert(scip->tree->root == SCIPtreeGetCurrentNode(scip->tree));
4712
4713 SCIP_CALL( SCIPnodeAddBoundchg(scip->tree->root, scip->mem->probmem, scip->set, scip->stat, scip->transprob,
4714 scip->origprob, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventqueue, scip->cliquetable,
4715 var, newbound, SCIP_BOUNDTYPE_LOWER, FALSE) );
4716
4717 if( (SCIP_VARTYPE)var->vartype == SCIP_VARTYPE_INTEGER && SCIPvarIsBinary(var) )
4718 {
4719 SCIP_Bool infeasible;
4720
4721 SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_BINARY, &infeasible) );
4722 assert(!infeasible);
4723 }
4724 break;
4725 }
4726 /*lint -fallthrough*/
4727 case SCIP_STAGE_SOLVING:
4728 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetCurrentNode(scip->tree), scip->mem->probmem, scip->set, scip->stat,
4729 scip->transprob, scip->origprob, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventqueue,
4730 scip->cliquetable, var, newbound,
4731 SCIP_BOUNDTYPE_LOWER, FALSE) );
4732 break;
4733
4734 default:
4735 SCIPerrorMessage("invalid SCIP stage <%d>\n", scip->set->stage);
4736 return SCIP_INVALIDCALL;
4737 } /*lint !e788*/
4738
4739 return SCIP_OKAY;
4740 }
4741
4742 /** depending on SCIP's stage, changes upper bound of variable in the problem, in preprocessing, or in current node;
4743 * if possible, adjusts bound to integral value; doesn't store any inference information in the bound change, such
4744 * that in conflict analysis, this change is treated like a branching decision
4745 *
4746 * @warning If SCIP is in presolving stage, it can happen that the internal variable array (which can be accessed via
4747 * SCIPgetVars()) gets resorted.
4748 *
4749 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
4750 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
4751 *
4752 * @pre This method can be called if @p scip is in one of the following stages:
4753 * - \ref SCIP_STAGE_PROBLEM
4754 * - \ref SCIP_STAGE_TRANSFORMING
4755 * - \ref SCIP_STAGE_PRESOLVING
4756 * - \ref SCIP_STAGE_SOLVING
4757 *
4758 * @note During presolving, an integer variable whose bound changes to {0,1} is upgraded to a binary variable.
4759 */
SCIPchgVarUb(SCIP * scip,SCIP_VAR * var,SCIP_Real newbound)4760 SCIP_RETCODE SCIPchgVarUb(
4761 SCIP* scip, /**< SCIP data structure */
4762 SCIP_VAR* var, /**< variable to change the bound for */
4763 SCIP_Real newbound /**< new value for bound */
4764 )
4765 {
4766 SCIP_CALL( SCIPcheckStage(scip, "SCIPchgVarUb", FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
4767
4768 SCIPvarAdjustUb(var, scip->set, &newbound);
4769
4770 /* ignore tightenings of upper bounds to -infinity during solving process */
4771 if( SCIPisInfinity(scip, -newbound) && SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
4772 {
4773 #ifndef NDEBUG
4774 SCIPwarningMessage(scip, "ignore upper bound tightening for %s from %e to -infinity\n", SCIPvarGetName(var),
4775 SCIPvarGetUbLocal(var));
4776 #endif
4777 return SCIP_OKAY;
4778 }
4779
4780 switch( scip->set->stage )
4781 {
4782 case SCIP_STAGE_PROBLEM:
4783 assert(!SCIPvarIsTransformed(var));
4784 SCIP_CALL( SCIPvarChgUbGlobal(var, scip->mem->probmem, scip->set, scip->stat, scip->lp,
4785 scip->branchcand, scip->eventqueue, scip->cliquetable, newbound) );
4786 SCIP_CALL( SCIPvarChgUbLocal(var, scip->mem->probmem, scip->set, scip->stat, scip->lp,
4787 scip->branchcand, scip->eventqueue, newbound) );
4788 SCIP_CALL( SCIPvarChgUbOriginal(var, scip->set, newbound) );
4789 break;
4790
4791 case SCIP_STAGE_TRANSFORMING:
4792 case SCIP_STAGE_PRESOLVED:
4793 SCIP_CALL( SCIPvarChgUbGlobal(var, scip->mem->probmem, scip->set, scip->stat, scip->lp,
4794 scip->branchcand, scip->eventqueue, scip->cliquetable, newbound) );
4795 break;
4796
4797 case SCIP_STAGE_PRESOLVING:
4798 if( !SCIPinProbing(scip) )
4799 {
4800 assert(SCIPtreeGetCurrentDepth(scip->tree) == 0);
4801 assert(scip->tree->root == SCIPtreeGetCurrentNode(scip->tree));
4802
4803 SCIP_CALL( SCIPnodeAddBoundchg(scip->tree->root, scip->mem->probmem, scip->set, scip->stat, scip->transprob,
4804 scip->origprob, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventqueue,
4805 scip->cliquetable, var, newbound, SCIP_BOUNDTYPE_UPPER, FALSE) );
4806
4807 if( (SCIP_VARTYPE)var->vartype == SCIP_VARTYPE_INTEGER && SCIPvarIsBinary(var) )
4808 {
4809 SCIP_Bool infeasible;
4810
4811 SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_BINARY, &infeasible) );
4812 assert(!infeasible);
4813 }
4814 break;
4815 }
4816 /*lint -fallthrough*/
4817 case SCIP_STAGE_SOLVING:
4818 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetCurrentNode(scip->tree), scip->mem->probmem, scip->set, scip->stat,
4819 scip->transprob, scip->origprob, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventqueue,
4820 scip->cliquetable, var, newbound, SCIP_BOUNDTYPE_UPPER, FALSE) );
4821 break;
4822
4823 default:
4824 SCIPerrorMessage("invalid SCIP stage <%d>\n", scip->set->stage);
4825 return SCIP_INVALIDCALL;
4826 } /*lint !e788*/
4827
4828 return SCIP_OKAY;
4829 }
4830
4831 /** changes lower bound of variable in the given node; if possible, adjust bound to integral value; doesn't store any
4832 * inference information in the bound change, such that in conflict analysis, this change is treated like a branching
4833 * decision
4834 *
4835 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
4836 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
4837 *
4838 * @pre This method can only be called if @p scip is in stage \ref SCIP_STAGE_SOLVING
4839 */
SCIPchgVarLbNode(SCIP * scip,SCIP_NODE * node,SCIP_VAR * var,SCIP_Real newbound)4840 SCIP_RETCODE SCIPchgVarLbNode(
4841 SCIP* scip, /**< SCIP data structure */
4842 SCIP_NODE* node, /**< node to change bound at, or NULL for current node */
4843 SCIP_VAR* var, /**< variable to change the bound for */
4844 SCIP_Real newbound /**< new value for bound */
4845 )
4846 {
4847 SCIP_CALL( SCIPcheckStage(scip, "SCIPchgVarLbNode", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
4848
4849 if( node == NULL )
4850 {
4851 SCIP_CALL( SCIPchgVarLb(scip, var, newbound) );
4852 }
4853 else
4854 {
4855 SCIPvarAdjustLb(var, scip->set, &newbound);
4856
4857 /* ignore tightenings of lower bounds to +infinity during solving process */
4858 if( SCIPisInfinity(scip, newbound) && SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
4859 {
4860 #ifndef NDEBUG
4861 SCIPwarningMessage(scip, "ignore lower bound tightening for %s from %e to +infinity\n", SCIPvarGetName(var),
4862 SCIPvarGetLbLocal(var));
4863 #endif
4864 return SCIP_OKAY;
4865 }
4866
4867 SCIP_CALL( SCIPnodeAddBoundchg(node, scip->mem->probmem, scip->set, scip->stat, scip->transprob, scip->origprob,
4868 scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventqueue, scip->cliquetable, var, newbound,
4869 SCIP_BOUNDTYPE_LOWER, FALSE) );
4870 }
4871
4872 return SCIP_OKAY;
4873 }
4874
4875 /** changes upper bound of variable in the given node; if possible, adjust bound to integral value; doesn't store any
4876 * inference information in the bound change, such that in conflict analysis, this change is treated like a branching
4877 * decision
4878 *
4879 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
4880 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
4881 *
4882 * @pre This method can only be called if @p scip is in stage \ref SCIP_STAGE_SOLVING
4883 */
SCIPchgVarUbNode(SCIP * scip,SCIP_NODE * node,SCIP_VAR * var,SCIP_Real newbound)4884 SCIP_RETCODE SCIPchgVarUbNode(
4885 SCIP* scip, /**< SCIP data structure */
4886 SCIP_NODE* node, /**< node to change bound at, or NULL for current node */
4887 SCIP_VAR* var, /**< variable to change the bound for */
4888 SCIP_Real newbound /**< new value for bound */
4889 )
4890 {
4891 SCIP_CALL( SCIPcheckStage(scip, "SCIPchgVarUbNode", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
4892
4893 if( node == NULL )
4894 {
4895 SCIP_CALL( SCIPchgVarUb(scip, var, newbound) );
4896 }
4897 else
4898 {
4899 SCIPvarAdjustUb(var, scip->set, &newbound);
4900
4901 /* ignore tightenings of upper bounds to -infinity during solving process */
4902 if( SCIPisInfinity(scip, -newbound) && SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
4903 {
4904 #ifndef NDEBUG
4905 SCIPwarningMessage(scip, "ignore upper bound tightening for %s from %e to -infinity\n", SCIPvarGetName(var),
4906 SCIPvarGetUbLocal(var));
4907 #endif
4908 return SCIP_OKAY;
4909 }
4910
4911 SCIP_CALL( SCIPnodeAddBoundchg(node, scip->mem->probmem, scip->set, scip->stat, scip->transprob, scip->origprob,
4912 scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventqueue, scip->cliquetable, var, newbound,
4913 SCIP_BOUNDTYPE_UPPER, FALSE) );
4914 }
4915
4916 return SCIP_OKAY;
4917 }
4918
4919 /** changes global lower bound of variable; if possible, adjust bound to integral value; also tightens the local bound,
4920 * if the global bound is better than the local bound
4921 *
4922 * @warning If SCIP is in presolving stage, it can happen that the internal variable array (which can be accessed via
4923 * SCIPgetVars()) gets resorted.
4924 *
4925 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
4926 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
4927 *
4928 * @pre This method can be called if @p scip is in one of the following stages:
4929 * - \ref SCIP_STAGE_PROBLEM
4930 * - \ref SCIP_STAGE_TRANSFORMING
4931 * - \ref SCIP_STAGE_PRESOLVING
4932 * - \ref SCIP_STAGE_SOLVING
4933 *
4934 * @note During presolving, an integer variable whose bound changes to {0,1} is upgraded to a binary variable.
4935 */
SCIPchgVarLbGlobal(SCIP * scip,SCIP_VAR * var,SCIP_Real newbound)4936 SCIP_RETCODE SCIPchgVarLbGlobal(
4937 SCIP* scip, /**< SCIP data structure */
4938 SCIP_VAR* var, /**< variable to change the bound for */
4939 SCIP_Real newbound /**< new value for bound */
4940 )
4941 {
4942 SCIP_CALL( SCIPcheckStage(scip, "SCIPchgVarLbGlobal", FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
4943
4944 SCIPvarAdjustLb(var, scip->set, &newbound);
4945
4946 /* ignore tightenings of lower bounds to +infinity during solving process */
4947 if( SCIPisInfinity(scip, newbound) && SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
4948 {
4949 #ifndef NDEBUG
4950 SCIPwarningMessage(scip, "ignore lower bound tightening for %s from %e to +infinity\n", SCIPvarGetName(var),
4951 SCIPvarGetLbLocal(var));
4952 #endif
4953 return SCIP_OKAY;
4954 }
4955
4956 switch( scip->set->stage )
4957 {
4958 case SCIP_STAGE_PROBLEM:
4959 assert(!SCIPvarIsTransformed(var));
4960 SCIP_CALL( SCIPvarChgLbGlobal(var, scip->mem->probmem, scip->set, scip->stat, scip->lp,
4961 scip->branchcand, scip->eventqueue, scip->cliquetable, newbound) );
4962 SCIP_CALL( SCIPvarChgLbLocal(var, scip->mem->probmem, scip->set, scip->stat, scip->lp,
4963 scip->branchcand, scip->eventqueue, newbound) );
4964 SCIP_CALL( SCIPvarChgLbOriginal(var, scip->set, newbound) );
4965 break;
4966
4967 case SCIP_STAGE_TRANSFORMING:
4968 SCIP_CALL( SCIPvarChgLbGlobal(var, scip->mem->probmem, scip->set, scip->stat, scip->lp,
4969 scip->branchcand, scip->eventqueue, scip->cliquetable, newbound) );
4970 break;
4971
4972 case SCIP_STAGE_PRESOLVING:
4973 if( !SCIPinProbing(scip) )
4974 {
4975 assert(SCIPtreeGetCurrentDepth(scip->tree) == 0);
4976 assert(scip->tree->root == SCIPtreeGetCurrentNode(scip->tree));
4977
4978 SCIP_CALL( SCIPnodeAddBoundchg(scip->tree->root, scip->mem->probmem, scip->set, scip->stat, scip->transprob,
4979 scip->origprob, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventqueue, scip->cliquetable, var, newbound,
4980 SCIP_BOUNDTYPE_LOWER, FALSE) );
4981
4982 if( (SCIP_VARTYPE)var->vartype == SCIP_VARTYPE_INTEGER && SCIPvarIsBinary(var) )
4983 {
4984 SCIP_Bool infeasible;
4985
4986 SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_BINARY, &infeasible) );
4987 assert(!infeasible);
4988 }
4989 break;
4990 }
4991 /*lint -fallthrough*/
4992 case SCIP_STAGE_SOLVING:
4993 SCIP_CALL( SCIPnodeAddBoundchg(scip->tree->root, scip->mem->probmem, scip->set, scip->stat, scip->transprob,
4994 scip->origprob, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventqueue, scip->cliquetable, var, newbound,
4995 SCIP_BOUNDTYPE_LOWER, FALSE) );
4996 break;
4997
4998 default:
4999 SCIPerrorMessage("invalid SCIP stage <%d>\n", scip->set->stage);
5000 return SCIP_INVALIDCALL;
5001 } /*lint !e788*/
5002
5003 return SCIP_OKAY;
5004 }
5005
5006 /** changes global upper bound of variable; if possible, adjust bound to integral value; also tightens the local bound,
5007 * if the global bound is better than the local bound
5008 *
5009 * @warning If SCIP is in presolving stage, it can happen that the internal variable array (which can be accessed via
5010 * SCIPgetVars()) gets resorted.
5011 *
5012 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
5013 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
5014 *
5015 * @pre This method can be called if @p scip is in one of the following stages:
5016 * - \ref SCIP_STAGE_PROBLEM
5017 * - \ref SCIP_STAGE_TRANSFORMING
5018 * - \ref SCIP_STAGE_PRESOLVING
5019 * - \ref SCIP_STAGE_SOLVING
5020 *
5021 * @note During presolving, an integer variable whose bound changes to {0,1} is upgraded to a binary variable.
5022 */
SCIPchgVarUbGlobal(SCIP * scip,SCIP_VAR * var,SCIP_Real newbound)5023 SCIP_RETCODE SCIPchgVarUbGlobal(
5024 SCIP* scip, /**< SCIP data structure */
5025 SCIP_VAR* var, /**< variable to change the bound for */
5026 SCIP_Real newbound /**< new value for bound */
5027 )
5028 {
5029 SCIP_CALL( SCIPcheckStage(scip, "SCIPchgVarUbGlobal", FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
5030
5031 SCIPvarAdjustUb(var, scip->set, &newbound);
5032
5033 /* ignore tightenings of upper bounds to -infinity during solving process */
5034 if( SCIPisInfinity(scip, -newbound) && SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
5035 {
5036 #ifndef NDEBUG
5037 SCIPwarningMessage(scip, "ignore upper bound tightening for %s from %e to -infinity\n", SCIPvarGetName(var),
5038 SCIPvarGetUbLocal(var));
5039 #endif
5040 return SCIP_OKAY;
5041 }
5042
5043 switch( scip->set->stage )
5044 {
5045 case SCIP_STAGE_PROBLEM:
5046 assert(!SCIPvarIsTransformed(var));
5047 SCIP_CALL( SCIPvarChgUbGlobal(var, scip->mem->probmem, scip->set, scip->stat, scip->lp,
5048 scip->branchcand, scip->eventqueue, scip->cliquetable, newbound) );
5049 SCIP_CALL( SCIPvarChgUbLocal(var, scip->mem->probmem, scip->set, scip->stat, scip->lp,
5050 scip->branchcand, scip->eventqueue, newbound) );
5051 SCIP_CALL( SCIPvarChgUbOriginal(var, scip->set, newbound) );
5052 break;
5053
5054 case SCIP_STAGE_TRANSFORMING:
5055 SCIP_CALL( SCIPvarChgUbGlobal(var, scip->mem->probmem, scip->set, scip->stat, scip->lp,
5056 scip->branchcand, scip->eventqueue, scip->cliquetable, newbound) );
5057 break;
5058
5059 case SCIP_STAGE_PRESOLVING:
5060 if( !SCIPinProbing(scip) )
5061 {
5062 assert(SCIPtreeGetCurrentDepth(scip->tree) == 0);
5063 assert(scip->tree->root == SCIPtreeGetCurrentNode(scip->tree));
5064
5065 SCIP_CALL( SCIPnodeAddBoundchg(scip->tree->root, scip->mem->probmem, scip->set, scip->stat, scip->transprob,
5066 scip->origprob, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventqueue, scip->cliquetable, var, newbound,
5067 SCIP_BOUNDTYPE_UPPER, FALSE) );
5068
5069 if( (SCIP_VARTYPE)var->vartype == SCIP_VARTYPE_INTEGER && SCIPvarIsBinary(var) )
5070 {
5071 SCIP_Bool infeasible;
5072
5073 SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_BINARY, &infeasible) );
5074 assert(!infeasible);
5075 }
5076 break;
5077 }
5078 /*lint -fallthrough*/
5079 case SCIP_STAGE_SOLVING:
5080 SCIP_CALL( SCIPnodeAddBoundchg(scip->tree->root, scip->mem->probmem, scip->set, scip->stat, scip->transprob,
5081 scip->origprob, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventqueue, scip->cliquetable, var, newbound,
5082 SCIP_BOUNDTYPE_UPPER, FALSE) );
5083 break;
5084
5085 default:
5086 SCIPerrorMessage("invalid SCIP stage <%d>\n", scip->set->stage);
5087 return SCIP_INVALIDCALL;
5088 } /*lint !e788*/
5089
5090 return SCIP_OKAY;
5091 }
5092
5093 /** changes lazy lower bound of the variable, this is only possible if the variable is not in the LP yet
5094 *
5095 * lazy bounds are bounds, that are enforced by constraints and the objective function; hence, these bounds do not need
5096 * to be put into the LP explicitly.
5097 *
5098 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
5099 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
5100 *
5101 * @pre This method can be called if @p scip is in one of the following stages:
5102 * - \ref SCIP_STAGE_PROBLEM
5103 * - \ref SCIP_STAGE_TRANSFORMING
5104 * - \ref SCIP_STAGE_TRANSFORMED
5105 * - \ref SCIP_STAGE_PRESOLVING
5106 * - \ref SCIP_STAGE_SOLVING
5107 *
5108 * @note lazy bounds are useful for branch-and-price since the corresponding variable bounds are not part of the LP
5109 */
SCIPchgVarLbLazy(SCIP * scip,SCIP_VAR * var,SCIP_Real lazylb)5110 SCIP_RETCODE SCIPchgVarLbLazy(
5111 SCIP* scip, /**< SCIP data structure */
5112 SCIP_VAR* var, /**< problem variable */
5113 SCIP_Real lazylb /**< the lazy lower bound to be set */
5114 )
5115 {
5116 assert(scip != NULL);
5117 assert(var != NULL);
5118
5119 SCIP_CALL( SCIPcheckStage(scip, "SCIPchgVarLbLazy", FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
5120
5121 SCIP_CALL( SCIPvarChgLbLazy(var, scip->set, lazylb) );
5122
5123 return SCIP_OKAY;
5124 }
5125
5126 /** changes lazy upper bound of the variable, this is only possible if the variable is not in the LP yet
5127 *
5128 * lazy bounds are bounds, that are enforced by constraints and the objective function; hence, these bounds do not need
5129 * to be put into the LP explicitly.
5130 *
5131 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
5132 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
5133 *
5134 * @pre This method can be called if @p scip is in one of the following stages:
5135 * - \ref SCIP_STAGE_PROBLEM
5136 * - \ref SCIP_STAGE_TRANSFORMING
5137 * - \ref SCIP_STAGE_TRANSFORMED
5138 * - \ref SCIP_STAGE_PRESOLVING
5139 * - \ref SCIP_STAGE_SOLVING
5140 *
5141 * @note lazy bounds are useful for branch-and-price since the corresponding variable bounds are not part of the LP
5142 */
SCIPchgVarUbLazy(SCIP * scip,SCIP_VAR * var,SCIP_Real lazyub)5143 SCIP_RETCODE SCIPchgVarUbLazy(
5144 SCIP* scip, /**< SCIP data structure */
5145 SCIP_VAR* var, /**< problem variable */
5146 SCIP_Real lazyub /**< the lazy lower bound to be set */
5147 )
5148 {
5149 assert(scip != NULL);
5150 assert(var != NULL);
5151
5152 SCIP_CALL( SCIPcheckStage(scip, "SCIPchgVarUbLazy", FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
5153
5154 SCIP_CALL( SCIPvarChgUbLazy(var, scip->set, lazyub) );
5155
5156 return SCIP_OKAY;
5157 }
5158
5159 /** changes lower bound of variable in preprocessing or in the current node, if the new bound is tighter
5160 * (w.r.t. bound strengthening epsilon) than the current bound; if possible, adjusts bound to integral value;
5161 * doesn't store any inference information in the bound change, such that in conflict analysis, this change
5162 * is treated like a branching decision
5163 *
5164 * @warning If SCIP is in presolving stage, it can happen that the internal variable array (which can be accessed via
5165 * SCIPgetVars()) gets resorted.
5166 *
5167 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
5168 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
5169 *
5170 * @pre This method can be called if @p scip is in one of the following stages:
5171 * - \ref SCIP_STAGE_PROBLEM
5172 * - \ref SCIP_STAGE_PRESOLVING
5173 * - \ref SCIP_STAGE_SOLVING
5174 *
5175 * @note During presolving, an integer variable whose bound changes to {0,1} is upgraded to a binary variable.
5176 */
SCIPtightenVarLb(SCIP * scip,SCIP_VAR * var,SCIP_Real newbound,SCIP_Bool force,SCIP_Bool * infeasible,SCIP_Bool * tightened)5177 SCIP_RETCODE SCIPtightenVarLb(
5178 SCIP* scip, /**< SCIP data structure */
5179 SCIP_VAR* var, /**< variable to change the bound for */
5180 SCIP_Real newbound, /**< new value for bound */
5181 SCIP_Bool force, /**< force tightening even if below bound strengthening tolerance */
5182 SCIP_Bool* infeasible, /**< pointer to store whether the new domain is empty */
5183 SCIP_Bool* tightened /**< pointer to store whether the bound was tightened, or NULL */
5184 )
5185 {
5186 SCIP_Real lb;
5187 SCIP_Real ub;
5188
5189 assert(infeasible != NULL);
5190
5191 SCIP_CALL( SCIPcheckStage(scip, "SCIPtightenVarLb", FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
5192 /** @todo if needed provide pending local/global bound changes that will be flushed after leaving diving mode (as in struct_tree.h) */
5193 assert(SCIPgetStage(scip) == SCIP_STAGE_PROBLEM || !SCIPinDive(scip));
5194
5195 *infeasible = FALSE;
5196 if( tightened != NULL )
5197 *tightened = FALSE;
5198
5199 SCIPvarAdjustLb(var, scip->set, &newbound);
5200
5201 /* ignore tightenings of lower bounds to +infinity during solving process */
5202 if( SCIPisInfinity(scip, newbound) && SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
5203 {
5204 #ifndef NDEBUG
5205 SCIPwarningMessage(scip, "ignore lower bound tightening for %s from %e to +infinity\n", SCIPvarGetName(var),
5206 SCIPvarGetLbLocal(var));
5207 #endif
5208 return SCIP_OKAY;
5209 }
5210
5211 /* get current bounds */
5212 lb = SCIPcomputeVarLbLocal(scip, var);
5213 ub = SCIPcomputeVarUbLocal(scip, var);
5214 assert(SCIPsetIsLE(scip->set, lb, ub));
5215
5216 if( SCIPsetIsFeasGT(scip->set, newbound, ub) )
5217 {
5218 *infeasible = TRUE;
5219 return SCIP_OKAY;
5220 }
5221 newbound = MIN(newbound, ub);
5222
5223 if( (force && SCIPsetIsLE(scip->set, newbound, lb)) || (!force && !SCIPsetIsLbBetter(scip->set, newbound, lb, ub)) )
5224 return SCIP_OKAY;
5225
5226 switch( scip->set->stage )
5227 {
5228 case SCIP_STAGE_PROBLEM:
5229 assert(!SCIPvarIsTransformed(var));
5230 SCIP_CALL( SCIPvarChgLbGlobal(var, scip->mem->probmem, scip->set, scip->stat, scip->lp,
5231 scip->branchcand, scip->eventqueue, scip->cliquetable, newbound) );
5232 SCIP_CALL( SCIPvarChgLbLocal(var, scip->mem->probmem, scip->set, scip->stat, scip->lp,
5233 scip->branchcand, scip->eventqueue, newbound) );
5234 SCIP_CALL( SCIPvarChgLbOriginal(var, scip->set, newbound) );
5235 break;
5236 case SCIP_STAGE_TRANSFORMED:
5237 SCIP_CALL( SCIPvarChgLbGlobal(var, scip->mem->probmem, scip->set, scip->stat, scip->lp,
5238 scip->branchcand, scip->eventqueue, scip->cliquetable, newbound) );
5239 break;
5240 case SCIP_STAGE_PRESOLVING:
5241 if( !SCIPinProbing(scip) )
5242 {
5243 assert(SCIPtreeGetCurrentDepth(scip->tree) == 0);
5244 assert(scip->tree->root == SCIPtreeGetCurrentNode(scip->tree));
5245
5246 SCIP_CALL( SCIPnodeAddBoundchg(scip->tree->root, scip->mem->probmem, scip->set, scip->stat, scip->transprob,
5247 scip->origprob, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventqueue, scip->cliquetable, var, newbound,
5248 SCIP_BOUNDTYPE_LOWER, FALSE) );
5249
5250 if( (SCIP_VARTYPE)var->vartype == SCIP_VARTYPE_INTEGER && SCIPvarIsBinary(var) )
5251 {
5252 SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_BINARY, infeasible) );
5253 assert(!(*infeasible));
5254 }
5255 break;
5256 }
5257 /*lint -fallthrough*/
5258 case SCIP_STAGE_SOLVING:
5259 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetCurrentNode(scip->tree), scip->mem->probmem, scip->set, scip->stat,
5260 scip->transprob, scip->origprob, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventqueue, scip->cliquetable,
5261 var, newbound, SCIP_BOUNDTYPE_LOWER, FALSE) );
5262 break;
5263
5264 default:
5265 SCIPerrorMessage("invalid SCIP stage <%d>\n", scip->set->stage);
5266 return SCIP_INVALIDCALL;
5267 } /*lint !e788*/
5268
5269 /* check whether the lower bound improved */
5270 if( tightened != NULL && lb < SCIPcomputeVarLbLocal(scip, var) )
5271 *tightened = TRUE;
5272
5273 return SCIP_OKAY;
5274 }
5275
5276 /** changes upper bound of variable in preprocessing or in the current node, if the new bound is tighter
5277 * (w.r.t. bound strengthening epsilon) than the current bound; if possible, adjusts bound to integral value;
5278 * doesn't store any inference information in the bound change, such that in conflict analysis, this change
5279 * is treated like a branching decision
5280 *
5281 * @warning If SCIP is in presolving stage, it can happen that the internal variable array (which can be accessed via
5282 * SCIPgetVars()) gets resorted.
5283 *
5284 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
5285 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
5286 *
5287 * @pre This method can be called if @p scip is in one of the following stages:
5288 * - \ref SCIP_STAGE_PROBLEM
5289 * - \ref SCIP_STAGE_PRESOLVING
5290 * - \ref SCIP_STAGE_SOLVING
5291 *
5292 * @note During presolving, an integer variable whose bound changes to {0,1} is upgraded to a binary variable.
5293 */
SCIPtightenVarUb(SCIP * scip,SCIP_VAR * var,SCIP_Real newbound,SCIP_Bool force,SCIP_Bool * infeasible,SCIP_Bool * tightened)5294 SCIP_RETCODE SCIPtightenVarUb(
5295 SCIP* scip, /**< SCIP data structure */
5296 SCIP_VAR* var, /**< variable to change the bound for */
5297 SCIP_Real newbound, /**< new value for bound */
5298 SCIP_Bool force, /**< force tightening even if below bound strengthening tolerance */
5299 SCIP_Bool* infeasible, /**< pointer to store whether the new domain is empty */
5300 SCIP_Bool* tightened /**< pointer to store whether the bound was tightened, or NULL */
5301 )
5302 {
5303 SCIP_Real lb;
5304 SCIP_Real ub;
5305
5306 assert(infeasible != NULL);
5307 SCIP_CALL( SCIPcheckStage(scip, "SCIPtightenVarUb", FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
5308
5309 /** @todo if needed provide pending local/global bound changes that will be flushed after leaving diving mode (as in struct_tree.h) */
5310 assert(SCIPgetStage(scip) == SCIP_STAGE_PROBLEM || !SCIPinDive(scip));
5311
5312 *infeasible = FALSE;
5313 if( tightened != NULL )
5314 *tightened = FALSE;
5315
5316 SCIPvarAdjustUb(var, scip->set, &newbound);
5317
5318 /* ignore tightenings of upper bounds to -infinity during solving process */
5319 if( SCIPisInfinity(scip, -newbound) && SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
5320 {
5321 #ifndef NDEBUG
5322 SCIPwarningMessage(scip, "ignore upper bound tightening for %s from %e to -infinity\n", SCIPvarGetName(var),
5323 SCIPvarGetUbLocal(var));
5324 #endif
5325 return SCIP_OKAY;
5326 }
5327
5328 /* get current bounds */
5329 lb = SCIPcomputeVarLbLocal(scip, var);
5330 ub = SCIPcomputeVarUbLocal(scip, var);
5331 assert(SCIPsetIsLE(scip->set, lb, ub));
5332
5333 if( SCIPsetIsFeasLT(scip->set, newbound, lb) )
5334 {
5335 *infeasible = TRUE;
5336 return SCIP_OKAY;
5337 }
5338 newbound = MAX(newbound, lb);
5339
5340 if( (force && SCIPsetIsGE(scip->set, newbound, ub)) || (!force && !SCIPsetIsUbBetter(scip->set, newbound, lb, ub)) )
5341 return SCIP_OKAY;
5342
5343 switch( scip->set->stage )
5344 {
5345 case SCIP_STAGE_PROBLEM:
5346 assert(!SCIPvarIsTransformed(var));
5347 SCIP_CALL( SCIPvarChgUbGlobal(var, scip->mem->probmem, scip->set, scip->stat, scip->lp,
5348 scip->branchcand, scip->eventqueue, scip->cliquetable, newbound) );
5349 SCIP_CALL( SCIPvarChgUbLocal(var, scip->mem->probmem, scip->set, scip->stat, scip->lp,
5350 scip->branchcand, scip->eventqueue, newbound) );
5351 SCIP_CALL( SCIPvarChgUbOriginal(var, scip->set, newbound) );
5352 break;
5353 case SCIP_STAGE_TRANSFORMED:
5354 SCIP_CALL( SCIPvarChgUbGlobal(var, scip->mem->probmem, scip->set, scip->stat, scip->lp,
5355 scip->branchcand, scip->eventqueue, scip->cliquetable, newbound) );
5356 break;
5357 case SCIP_STAGE_PRESOLVING:
5358 if( !SCIPinProbing(scip) )
5359 {
5360 assert(SCIPtreeGetCurrentDepth(scip->tree) == 0);
5361 assert(scip->tree->root == SCIPtreeGetCurrentNode(scip->tree));
5362
5363 SCIP_CALL( SCIPnodeAddBoundchg(scip->tree->root, scip->mem->probmem, scip->set, scip->stat, scip->transprob,
5364 scip->origprob, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventqueue, scip->cliquetable, var, newbound,
5365 SCIP_BOUNDTYPE_UPPER, FALSE) );
5366
5367 if( (SCIP_VARTYPE)var->vartype == SCIP_VARTYPE_INTEGER && SCIPvarIsBinary(var) )
5368 {
5369 SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_BINARY, infeasible) );
5370 assert(!(*infeasible));
5371 }
5372 break;
5373 }
5374 /*lint -fallthrough*/
5375 case SCIP_STAGE_SOLVING:
5376 SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetCurrentNode(scip->tree), scip->mem->probmem, scip->set, scip->stat,
5377 scip->transprob, scip->origprob, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventqueue,
5378 scip->cliquetable, var, newbound, SCIP_BOUNDTYPE_UPPER, FALSE) );
5379 break;
5380
5381 default:
5382 SCIPerrorMessage("invalid SCIP stage <%d>\n", scip->set->stage);
5383 return SCIP_INVALIDCALL;
5384 } /*lint !e788*/
5385
5386 /* check whether the upper bound improved */
5387 if( tightened != NULL && ub > SCIPcomputeVarUbLocal(scip, var) )
5388 *tightened = TRUE;
5389
5390 return SCIP_OKAY;
5391 }
5392
5393 /** fixes variable in preprocessing or in the current node, if the new bound is tighter (w.r.t. bound strengthening
5394 * epsilon) than the current bound; if possible, adjusts bound to integral value; the given inference constraint is
5395 * stored, such that the conflict analysis is able to find out the reason for the deduction of the bound change
5396 *
5397 * @note In presolving stage when not in probing mode the variable will be fixed directly, otherwise this method
5398 * changes first the lowerbound by calling SCIPinferVarLbCons and second the upperbound by calling
5399 * SCIPinferVarUbCons
5400 *
5401 * @note If SCIP is in presolving stage, it can happen that the internal variable array (which get be accessed via
5402 * SCIPgetVars()) gets resorted.
5403 *
5404 * @note During presolving, an integer variable which bound changes to {0,1} is upgraded to a binary variable.
5405 */
SCIPinferVarFixCons(SCIP * scip,SCIP_VAR * var,SCIP_Real fixedval,SCIP_CONS * infercons,int inferinfo,SCIP_Bool force,SCIP_Bool * infeasible,SCIP_Bool * tightened)5406 SCIP_RETCODE SCIPinferVarFixCons(
5407 SCIP* scip, /**< SCIP data structure */
5408 SCIP_VAR* var, /**< variable to change the bound for */
5409 SCIP_Real fixedval, /**< new value for fixation */
5410 SCIP_CONS* infercons, /**< constraint that deduced the bound change */
5411 int inferinfo, /**< user information for inference to help resolving the conflict */
5412 SCIP_Bool force, /**< force tightening even if below bound strengthening tolerance */
5413 SCIP_Bool* infeasible, /**< pointer to store whether the bound change is infeasible */
5414 SCIP_Bool* tightened /**< pointer to store whether the bound was tightened, or NULL */
5415 )
5416 {
5417 assert(scip != NULL);
5418 assert(var != NULL);
5419 assert(infeasible != NULL);
5420
5421 SCIP_CALL( SCIPcheckStage(scip, "SCIPinferVarFixCons", FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
5422
5423 if( tightened != NULL )
5424 *tightened = FALSE;
5425
5426 /* in presolving case we take the shortcut to directly fix the variables */
5427 if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && SCIPtreeGetCurrentDepth(scip->tree) == 0 )
5428 {
5429 SCIP_Bool fixed;
5430
5431 SCIP_CALL( SCIPvarFix(var, scip->mem->probmem, scip->set, scip->stat, scip->transprob, scip->origprob,
5432 scip->primal, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventfilter,
5433 scip->eventqueue, scip->cliquetable, fixedval, infeasible, &fixed) );
5434
5435 if( tightened != NULL )
5436 *tightened = fixed;
5437 }
5438 /* otherwise we use the lb and ub methods */
5439 else
5440 {
5441 SCIP_Bool lbtightened;
5442
5443 SCIP_CALL( SCIPinferVarLbCons(scip, var, fixedval, infercons, inferinfo, force, infeasible, &lbtightened) );
5444
5445 if( ! (*infeasible) )
5446 {
5447 SCIP_CALL( SCIPinferVarUbCons(scip, var, fixedval, infercons, inferinfo, force, infeasible, tightened) );
5448
5449 if( tightened != NULL )
5450 *tightened |= lbtightened;
5451 }
5452 }
5453
5454 return SCIP_OKAY;
5455 }
5456
5457 /** changes lower bound of variable in preprocessing or in the current node, if the new bound is tighter
5458 * (w.r.t. bound strengthening epsilon) than the current bound; if possible, adjusts bound to integral value;
5459 * the given inference constraint is stored, such that the conflict analysis is able to find out the reason
5460 * for the deduction of the bound change
5461 *
5462 * @warning If SCIP is in presolving stage, it can happen that the internal variable array (which can be accessed via
5463 * SCIPgetVars()) gets resorted.
5464 *
5465 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
5466 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
5467 *
5468 * @pre This method can be called if @p scip is in one of the following stages:
5469 * - \ref SCIP_STAGE_PROBLEM
5470 * - \ref SCIP_STAGE_PRESOLVING
5471 * - \ref SCIP_STAGE_SOLVING
5472 *
5473 * @note During presolving, an integer variable whose bound changes to {0,1} is upgraded to a binary variable.
5474 */
SCIPinferVarLbCons(SCIP * scip,SCIP_VAR * var,SCIP_Real newbound,SCIP_CONS * infercons,int inferinfo,SCIP_Bool force,SCIP_Bool * infeasible,SCIP_Bool * tightened)5475 SCIP_RETCODE SCIPinferVarLbCons(
5476 SCIP* scip, /**< SCIP data structure */
5477 SCIP_VAR* var, /**< variable to change the bound for */
5478 SCIP_Real newbound, /**< new value for bound */
5479 SCIP_CONS* infercons, /**< constraint that deduced the bound change */
5480 int inferinfo, /**< user information for inference to help resolving the conflict */
5481 SCIP_Bool force, /**< force tightening even if below bound strengthening tolerance */
5482 SCIP_Bool* infeasible, /**< pointer to store whether the bound change is infeasible */
5483 SCIP_Bool* tightened /**< pointer to store whether the bound was tightened, or NULL */
5484 )
5485 {
5486 SCIP_Real lb;
5487 SCIP_Real ub;
5488
5489 assert(infeasible != NULL);
5490
5491 SCIP_CALL( SCIPcheckStage(scip, "SCIPinferVarLbCons", FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
5492
5493 *infeasible = FALSE;
5494 if( tightened != NULL )
5495 *tightened = FALSE;
5496
5497 SCIPvarAdjustLb(var, scip->set, &newbound);
5498
5499 /* ignore tightenings of lower bounds to +infinity during solving process */
5500 if( SCIPisInfinity(scip, newbound) && SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
5501 {
5502 #ifndef NDEBUG
5503 SCIPwarningMessage(scip, "ignore lower bound tightening for %s from %e to +infinity\n", SCIPvarGetName(var),
5504 SCIPvarGetLbLocal(var));
5505 #endif
5506 return SCIP_OKAY;
5507 }
5508
5509 /* get current bounds */
5510 lb = SCIPvarGetLbLocal(var);
5511 ub = SCIPvarGetUbLocal(var);
5512 assert(SCIPsetIsLE(scip->set, lb, ub));
5513
5514 if( SCIPsetIsFeasGT(scip->set, newbound, ub) )
5515 {
5516 *infeasible = TRUE;
5517 return SCIP_OKAY;
5518 }
5519 newbound = MIN(newbound, ub);
5520
5521 if( (force && SCIPsetIsLE(scip->set, newbound, lb)) || (!force && !SCIPsetIsLbBetter(scip->set, newbound, lb, ub)) )
5522 return SCIP_OKAY;
5523
5524 switch( scip->set->stage )
5525 {
5526 case SCIP_STAGE_PROBLEM:
5527 assert(!SCIPvarIsTransformed(var));
5528 SCIP_CALL( SCIPvarChgLbGlobal(var, scip->mem->probmem, scip->set, scip->stat, scip->lp,
5529 scip->branchcand, scip->eventqueue, scip->cliquetable, newbound) );
5530 SCIP_CALL( SCIPvarChgLbLocal(var, scip->mem->probmem, scip->set, scip->stat, scip->lp,
5531 scip->branchcand, scip->eventqueue, newbound) );
5532 SCIP_CALL( SCIPvarChgLbOriginal(var, scip->set, newbound) );
5533 break;
5534
5535 case SCIP_STAGE_PRESOLVING:
5536 if( !SCIPinProbing(scip) )
5537 {
5538 assert(SCIPtreeGetCurrentDepth(scip->tree) == 0);
5539 assert(scip->tree->root == SCIPtreeGetCurrentNode(scip->tree));
5540
5541 SCIP_CALL( SCIPnodeAddBoundchg(scip->tree->root, scip->mem->probmem, scip->set, scip->stat, scip->transprob,
5542 scip->origprob, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventqueue, scip->cliquetable, var, newbound,
5543 SCIP_BOUNDTYPE_LOWER, FALSE) );
5544
5545 if( (SCIP_VARTYPE)var->vartype == SCIP_VARTYPE_INTEGER && SCIPvarIsBinary(var) )
5546 {
5547 SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_BINARY, infeasible) );
5548 assert(!(*infeasible));
5549 }
5550 break;
5551 }
5552 /*lint -fallthrough*/
5553 case SCIP_STAGE_SOLVING:
5554 SCIP_CALL( SCIPnodeAddBoundinfer(SCIPtreeGetCurrentNode(scip->tree), scip->mem->probmem, scip->set, scip->stat,
5555 scip->transprob, scip->origprob, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventqueue,
5556 scip->cliquetable, var, newbound, SCIP_BOUNDTYPE_LOWER, infercons, NULL, inferinfo, FALSE) );
5557 break;
5558
5559 default:
5560 SCIPerrorMessage("invalid SCIP stage <%d>\n", scip->set->stage);
5561 return SCIP_INVALIDCALL;
5562 } /*lint !e788*/
5563
5564 /* check whether the lower bound improved */
5565 if( tightened != NULL && lb < SCIPcomputeVarLbLocal(scip, var) )
5566 *tightened = TRUE;
5567
5568 return SCIP_OKAY;
5569 }
5570
5571 /** changes upper bound of variable in preprocessing or in the current node, if the new bound is tighter
5572 * (w.r.t. bound strengthening epsilon) than the current bound; if possible, adjusts bound to integral value;
5573 * the given inference constraint is stored, such that the conflict analysis is able to find out the reason
5574 * for the deduction of the bound change
5575 *
5576 * @warning If SCIP is in presolving stage, it can happen that the internal variable array (which can be accessed via
5577 * SCIPgetVars()) gets resorted.
5578 *
5579 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
5580 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
5581 *
5582 * @pre This method can be called if @p scip is in one of the following stages:
5583 * - \ref SCIP_STAGE_PROBLEM
5584 * - \ref SCIP_STAGE_PRESOLVING
5585 * - \ref SCIP_STAGE_SOLVING
5586 *
5587 * @note During presolving, an integer variable whose bound changes to {0,1} is upgraded to a binary variable.
5588 */
SCIPinferVarUbCons(SCIP * scip,SCIP_VAR * var,SCIP_Real newbound,SCIP_CONS * infercons,int inferinfo,SCIP_Bool force,SCIP_Bool * infeasible,SCIP_Bool * tightened)5589 SCIP_RETCODE SCIPinferVarUbCons(
5590 SCIP* scip, /**< SCIP data structure */
5591 SCIP_VAR* var, /**< variable to change the bound for */
5592 SCIP_Real newbound, /**< new value for bound */
5593 SCIP_CONS* infercons, /**< constraint that deduced the bound change */
5594 int inferinfo, /**< user information for inference to help resolving the conflict */
5595 SCIP_Bool force, /**< force tightening even if below bound strengthening tolerance */
5596 SCIP_Bool* infeasible, /**< pointer to store whether the bound change is infeasible */
5597 SCIP_Bool* tightened /**< pointer to store whether the bound was tightened, or NULL */
5598 )
5599 {
5600 SCIP_Real lb;
5601 SCIP_Real ub;
5602
5603 assert(infeasible != NULL);
5604
5605 SCIP_CALL( SCIPcheckStage(scip, "SCIPinferVarUbCons", FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
5606
5607 *infeasible = FALSE;
5608 if( tightened != NULL )
5609 *tightened = FALSE;
5610
5611 SCIPvarAdjustUb(var, scip->set, &newbound);
5612
5613 /* ignore tightenings of upper bounds to -infinity during solving process */
5614 if( SCIPisInfinity(scip, -newbound) && SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
5615 {
5616 #ifndef NDEBUG
5617 SCIPwarningMessage(scip, "ignore upper bound tightening for %s from %e to -infinity\n", SCIPvarGetName(var),
5618 SCIPvarGetUbLocal(var));
5619 #endif
5620 return SCIP_OKAY;
5621 }
5622
5623 /* get current bounds */
5624 lb = SCIPvarGetLbLocal(var);
5625 ub = SCIPvarGetUbLocal(var);
5626 assert(SCIPsetIsLE(scip->set, lb, ub));
5627
5628 if( SCIPsetIsFeasLT(scip->set, newbound, lb) )
5629 {
5630 *infeasible = TRUE;
5631 return SCIP_OKAY;
5632 }
5633 newbound = MAX(newbound, lb);
5634
5635 if( (force && SCIPsetIsGE(scip->set, newbound, ub)) || (!force && !SCIPsetIsUbBetter(scip->set, newbound, lb, ub)) )
5636 return SCIP_OKAY;
5637
5638 switch( scip->set->stage )
5639 {
5640 case SCIP_STAGE_PROBLEM:
5641 assert(!SCIPvarIsTransformed(var));
5642 SCIP_CALL( SCIPvarChgUbGlobal(var, scip->mem->probmem, scip->set, scip->stat, scip->lp,
5643 scip->branchcand, scip->eventqueue, scip->cliquetable, newbound) );
5644 SCIP_CALL( SCIPvarChgUbLocal(var, scip->mem->probmem, scip->set, scip->stat, scip->lp,
5645 scip->branchcand, scip->eventqueue, newbound) );
5646 SCIP_CALL( SCIPvarChgUbOriginal(var, scip->set, newbound) );
5647 break;
5648
5649 case SCIP_STAGE_PRESOLVING:
5650 if( !SCIPinProbing(scip) )
5651 {
5652 assert(SCIPtreeGetCurrentDepth(scip->tree) == 0);
5653 assert(scip->tree->root == SCIPtreeGetCurrentNode(scip->tree));
5654
5655 SCIP_CALL( SCIPnodeAddBoundchg(scip->tree->root, scip->mem->probmem, scip->set, scip->stat, scip->transprob,
5656 scip->origprob, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventqueue, scip->cliquetable, var, newbound,
5657 SCIP_BOUNDTYPE_UPPER, FALSE) );
5658
5659 if( (SCIP_VARTYPE)var->vartype == SCIP_VARTYPE_INTEGER && SCIPvarIsBinary(var) )
5660 {
5661 SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_BINARY, infeasible) );
5662 assert(!(*infeasible));
5663 }
5664 break;
5665 }
5666 /*lint -fallthrough*/
5667 case SCIP_STAGE_SOLVING:
5668 SCIP_CALL( SCIPnodeAddBoundinfer(SCIPtreeGetCurrentNode(scip->tree), scip->mem->probmem, scip->set, scip->stat,
5669 scip->transprob, scip->origprob, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventqueue,
5670 scip->cliquetable, var, newbound, SCIP_BOUNDTYPE_UPPER, infercons, NULL, inferinfo, FALSE) );
5671 break;
5672
5673 default:
5674 SCIPerrorMessage("invalid SCIP stage <%d>\n", scip->set->stage);
5675 return SCIP_INVALIDCALL;
5676 } /*lint !e788*/
5677
5678 /* check whether the upper bound improved */
5679 if( tightened != NULL && ub > SCIPcomputeVarUbLocal(scip, var) )
5680 *tightened = TRUE;
5681
5682 return SCIP_OKAY;
5683 }
5684
5685 /** depending on SCIP's stage, fixes binary variable in the problem, in preprocessing, or in current node;
5686 * the given inference constraint is stored, such that the conflict analysis is able to find out the reason for the
5687 * deduction of the fixing
5688 *
5689 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
5690 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
5691 *
5692 * @pre This method can be called if @p scip is in one of the following stages:
5693 * - \ref SCIP_STAGE_PROBLEM
5694 * - \ref SCIP_STAGE_PRESOLVING
5695 * - \ref SCIP_STAGE_SOLVING
5696 */
SCIPinferBinvarCons(SCIP * scip,SCIP_VAR * var,SCIP_Bool fixedval,SCIP_CONS * infercons,int inferinfo,SCIP_Bool * infeasible,SCIP_Bool * tightened)5697 SCIP_RETCODE SCIPinferBinvarCons(
5698 SCIP* scip, /**< SCIP data structure */
5699 SCIP_VAR* var, /**< binary variable to fix */
5700 SCIP_Bool fixedval, /**< value to fix binary variable to */
5701 SCIP_CONS* infercons, /**< constraint that deduced the fixing */
5702 int inferinfo, /**< user information for inference to help resolving the conflict */
5703 SCIP_Bool* infeasible, /**< pointer to store whether the fixing is infeasible */
5704 SCIP_Bool* tightened /**< pointer to store whether the fixing tightened the local bounds, or NULL */
5705 )
5706 {
5707 SCIP_Real lb;
5708 SCIP_Real ub;
5709
5710 assert(SCIPvarIsBinary(var));
5711 assert(fixedval == TRUE || fixedval == FALSE);
5712 assert(infeasible != NULL);
5713
5714 SCIP_CALL( SCIPcheckStage(scip, "SCIPinferBinvarCons", FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
5715
5716 *infeasible = FALSE;
5717 if( tightened != NULL )
5718 *tightened = FALSE;
5719
5720 /* get current bounds */
5721 lb = SCIPvarGetLbLocal(var);
5722 ub = SCIPvarGetUbLocal(var);
5723 assert(SCIPsetIsEQ(scip->set, lb, 0.0) || SCIPsetIsEQ(scip->set, lb, 1.0));
5724 assert(SCIPsetIsEQ(scip->set, ub, 0.0) || SCIPsetIsEQ(scip->set, ub, 1.0));
5725 assert(SCIPsetIsLE(scip->set, lb, ub));
5726
5727 /* check, if variable is already fixed */
5728 if( (lb > 0.5) || (ub < 0.5) )
5729 {
5730 *infeasible = (fixedval == (lb < 0.5));
5731
5732 return SCIP_OKAY;
5733 }
5734
5735 /* apply the fixing */
5736 switch( scip->set->stage )
5737 {
5738 case SCIP_STAGE_PROBLEM:
5739 assert(!SCIPvarIsTransformed(var));
5740 if( fixedval == TRUE )
5741 {
5742 SCIP_CALL( SCIPchgVarLb(scip, var, 1.0) );
5743 }
5744 else
5745 {
5746 SCIP_CALL( SCIPchgVarUb(scip, var, 0.0) );
5747 }
5748 break;
5749
5750 case SCIP_STAGE_PRESOLVING:
5751 if( SCIPtreeGetCurrentDepth(scip->tree) == 0 )
5752 {
5753 SCIP_Bool fixed;
5754
5755 SCIP_CALL( SCIPvarFix(var, scip->mem->probmem, scip->set, scip->stat, scip->transprob, scip->origprob,
5756 scip->primal, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventfilter, scip->eventqueue,
5757 scip->cliquetable, (SCIP_Real)fixedval, infeasible, &fixed) );
5758 break;
5759 }
5760 /*lint -fallthrough*/
5761 case SCIP_STAGE_SOLVING:
5762 if( fixedval == TRUE )
5763 {
5764 SCIP_CALL( SCIPnodeAddBoundinfer(SCIPtreeGetCurrentNode(scip->tree), scip->mem->probmem, scip->set, scip->stat,
5765 scip->transprob, scip->origprob, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventqueue,
5766 scip->cliquetable, var, 1.0, SCIP_BOUNDTYPE_LOWER, infercons, NULL, inferinfo, FALSE) );
5767 }
5768 else
5769 {
5770 SCIP_CALL( SCIPnodeAddBoundinfer(SCIPtreeGetCurrentNode(scip->tree), scip->mem->probmem, scip->set, scip->stat,
5771 scip->transprob, scip->origprob, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventqueue,
5772 scip->cliquetable, var, 0.0, SCIP_BOUNDTYPE_UPPER, infercons, NULL, inferinfo, FALSE) );
5773 }
5774 break;
5775
5776 default:
5777 SCIPerrorMessage("invalid SCIP stage <%d>\n", scip->set->stage);
5778 return SCIP_INVALIDCALL;
5779 } /*lint !e788*/
5780
5781 if( tightened != NULL )
5782 *tightened = TRUE;
5783
5784 return SCIP_OKAY;
5785 }
5786
5787 /** fixes variable in preprocessing or in the current node, if the new bound is tighter (w.r.t. bound strengthening
5788 * epsilon) than the current bound; if possible, adjusts bound to integral value; the given inference constraint is
5789 * stored, such that the conflict analysis is able to find out the reason for the deduction of the bound change
5790 *
5791 * @note In presolving stage when not in probing mode the variable will be fixed directly, otherwise this method
5792 * changes first the lowerbound by calling SCIPinferVarLbProp and second the upperbound by calling
5793 * SCIPinferVarUbProp
5794 *
5795 * @note If SCIP is in presolving stage, it can happen that the internal variable array (which get be accessed via
5796 * SCIPgetVars()) gets resorted.
5797 *
5798 * @note During presolving, an integer variable which bound changes to {0,1} is upgraded to a binary variable.
5799 */
SCIPinferVarFixProp(SCIP * scip,SCIP_VAR * var,SCIP_Real fixedval,SCIP_PROP * inferprop,int inferinfo,SCIP_Bool force,SCIP_Bool * infeasible,SCIP_Bool * tightened)5800 SCIP_RETCODE SCIPinferVarFixProp(
5801 SCIP* scip, /**< SCIP data structure */
5802 SCIP_VAR* var, /**< variable to change the bound for */
5803 SCIP_Real fixedval, /**< new value for fixation */
5804 SCIP_PROP* inferprop, /**< propagator that deduced the bound change */
5805 int inferinfo, /**< user information for inference to help resolving the conflict */
5806 SCIP_Bool force, /**< force tightening even if below bound strengthening tolerance */
5807 SCIP_Bool* infeasible, /**< pointer to store whether the bound change is infeasible */
5808 SCIP_Bool* tightened /**< pointer to store whether the bound was tightened, or NULL */
5809 )
5810 {
5811 assert(scip != NULL);
5812 assert(var != NULL);
5813 assert(infeasible != NULL);
5814
5815 SCIP_CALL( SCIPcheckStage(scip, "SCIPinferVarFixProp", FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
5816
5817 if( tightened != NULL )
5818 *tightened = FALSE;
5819
5820 /* in presolving case we take the shortcut to directly fix the variables */
5821 if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && SCIPtreeGetCurrentDepth(scip->tree) == 0 )
5822 {
5823 SCIP_Bool fixed;
5824
5825 SCIP_CALL( SCIPvarFix(var, scip->mem->probmem, scip->set, scip->stat, scip->transprob, scip->origprob,
5826 scip->primal, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventfilter, scip->eventqueue,
5827 scip->cliquetable, fixedval, infeasible, &fixed) );
5828
5829 if( tightened != NULL )
5830 *tightened = fixed;
5831 }
5832 /* otherwise we use the lb and ub methods */
5833 else
5834 {
5835 SCIP_Bool lbtightened;
5836
5837 SCIP_CALL( SCIPinferVarLbProp(scip, var, fixedval, inferprop, inferinfo, force, infeasible, &lbtightened) );
5838
5839 if( ! (*infeasible) )
5840 {
5841 SCIP_CALL( SCIPinferVarUbProp(scip, var, fixedval, inferprop, inferinfo, force, infeasible, tightened) );
5842
5843 if( tightened != NULL )
5844 *tightened |= lbtightened;
5845 }
5846 }
5847
5848 return SCIP_OKAY;
5849 }
5850
5851 /** changes lower bound of variable in preprocessing or in the current node, if the new bound is tighter
5852 * (w.r.t. bound strengthening epsilon) than the current bound; if possible, adjusts bound to integral value;
5853 * the given inference propagator is stored, such that the conflict analysis is able to find out the reason
5854 * for the deduction of the bound change
5855 *
5856 * @warning If SCIP is in presolving stage, it can happen that the internal variable array (which can be accessed via
5857 * SCIPgetVars()) gets resorted.
5858 *
5859 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
5860 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
5861 *
5862 * @pre This method can be called if @p scip is in one of the following stages:
5863 * - \ref SCIP_STAGE_PROBLEM
5864 * - \ref SCIP_STAGE_PRESOLVING
5865 * - \ref SCIP_STAGE_SOLVING
5866 *
5867 * @note During presolving, an integer variable whose bound changes to {0,1} is upgraded to a binary variable.
5868 */
SCIPinferVarLbProp(SCIP * scip,SCIP_VAR * var,SCIP_Real newbound,SCIP_PROP * inferprop,int inferinfo,SCIP_Bool force,SCIP_Bool * infeasible,SCIP_Bool * tightened)5869 SCIP_RETCODE SCIPinferVarLbProp(
5870 SCIP* scip, /**< SCIP data structure */
5871 SCIP_VAR* var, /**< variable to change the bound for */
5872 SCIP_Real newbound, /**< new value for bound */
5873 SCIP_PROP* inferprop, /**< propagator that deduced the bound change */
5874 int inferinfo, /**< user information for inference to help resolving the conflict */
5875 SCIP_Bool force, /**< force tightening even if below bound strengthening tolerance */
5876 SCIP_Bool* infeasible, /**< pointer to store whether the bound change is infeasible */
5877 SCIP_Bool* tightened /**< pointer to store whether the bound was tightened, or NULL */
5878 )
5879 {
5880 SCIP_Real lb;
5881 SCIP_Real ub;
5882
5883 assert(infeasible != NULL);
5884
5885 SCIP_CALL( SCIPcheckStage(scip, "SCIPinferVarLbProp", FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
5886
5887 *infeasible = FALSE;
5888 if( tightened != NULL )
5889 *tightened = FALSE;
5890
5891 SCIPvarAdjustLb(var, scip->set, &newbound);
5892
5893 /* ignore tightenings of lower bounds to +infinity during solving process */
5894 if( SCIPisInfinity(scip, newbound) && SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
5895 {
5896 #ifndef NDEBUG
5897 SCIPwarningMessage(scip, "ignore lower bound tightening for %s from %e to +infinity\n", SCIPvarGetName(var),
5898 SCIPvarGetLbLocal(var));
5899 #endif
5900 return SCIP_OKAY;
5901 }
5902
5903 /* get current bounds */
5904 lb = SCIPvarGetLbLocal(var);
5905 ub = SCIPvarGetUbLocal(var);
5906 assert(SCIPsetIsLE(scip->set, lb, ub));
5907
5908 if( SCIPsetIsFeasGT(scip->set, newbound, ub) )
5909 {
5910 *infeasible = TRUE;
5911 return SCIP_OKAY;
5912 }
5913 newbound = MIN(newbound, ub);
5914
5915 if( (!force && !SCIPsetIsLbBetter(scip->set, newbound, lb, ub))
5916 || SCIPsetIsLE(scip->set, newbound, lb) )
5917 return SCIP_OKAY;
5918
5919 switch( scip->set->stage )
5920 {
5921 case SCIP_STAGE_PROBLEM:
5922 assert(!SCIPvarIsTransformed(var));
5923 SCIP_CALL( SCIPvarChgLbGlobal(var, scip->mem->probmem, scip->set, scip->stat, scip->lp,
5924 scip->branchcand, scip->eventqueue, scip->cliquetable, newbound) );
5925 SCIP_CALL( SCIPvarChgLbLocal(var, scip->mem->probmem, scip->set, scip->stat, scip->lp,
5926 scip->branchcand, scip->eventqueue, newbound) );
5927 SCIP_CALL( SCIPvarChgLbOriginal(var, scip->set, newbound) );
5928 break;
5929
5930 case SCIP_STAGE_PRESOLVING:
5931 if( !SCIPinProbing(scip) )
5932 {
5933 assert(SCIPtreeGetCurrentDepth(scip->tree) == 0);
5934 assert(scip->tree->root == SCIPtreeGetCurrentNode(scip->tree));
5935
5936 SCIP_CALL( SCIPnodeAddBoundchg(scip->tree->root, scip->mem->probmem, scip->set, scip->stat, scip->transprob,
5937 scip->origprob, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventqueue, scip->cliquetable, var, newbound,
5938 SCIP_BOUNDTYPE_LOWER, FALSE) );
5939
5940 if( (SCIP_VARTYPE)var->vartype == SCIP_VARTYPE_INTEGER && SCIPvarIsBinary(var) )
5941 {
5942 SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_BINARY, infeasible) );
5943 assert(!(*infeasible));
5944 }
5945 break;
5946 }
5947 /*lint -fallthrough*/
5948 case SCIP_STAGE_SOLVING:
5949 SCIP_CALL( SCIPnodeAddBoundinfer(SCIPtreeGetCurrentNode(scip->tree), scip->mem->probmem, scip->set, scip->stat,
5950 scip->transprob, scip->origprob, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventqueue,
5951 scip->cliquetable, var, newbound, SCIP_BOUNDTYPE_LOWER, NULL, inferprop, inferinfo, FALSE) );
5952 break;
5953
5954 default:
5955 SCIPerrorMessage("invalid SCIP stage <%d>\n", scip->set->stage);
5956 return SCIP_INVALIDCALL;
5957 } /*lint !e788*/
5958
5959 /* check whether the lower bound improved */
5960 if( tightened != NULL && lb < SCIPcomputeVarLbLocal(scip, var) )
5961 *tightened = TRUE;
5962
5963 return SCIP_OKAY;
5964 }
5965
5966 /** changes upper bound of variable in preprocessing or in the current node, if the new bound is tighter
5967 * (w.r.t. bound strengthening epsilon) than the current bound; if possible, adjusts bound to integral value;
5968 * the given inference propagator is stored, such that the conflict analysis is able to find out the reason
5969 * for the deduction of the bound change
5970 *
5971 * @warning If SCIP is in presolving stage, it can happen that the internal variable array (which can be accessed via
5972 * SCIPgetVars()) gets resorted.
5973 *
5974 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
5975 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
5976 *
5977 * @pre This method can be called if @p scip is in one of the following stages:
5978 * - \ref SCIP_STAGE_PROBLEM
5979 * - \ref SCIP_STAGE_PRESOLVING
5980 * - \ref SCIP_STAGE_SOLVING
5981 *
5982 * @note During presolving, an integer variable whose bound changes to {0,1} is upgraded to a binary variable.
5983 */
SCIPinferVarUbProp(SCIP * scip,SCIP_VAR * var,SCIP_Real newbound,SCIP_PROP * inferprop,int inferinfo,SCIP_Bool force,SCIP_Bool * infeasible,SCIP_Bool * tightened)5984 SCIP_RETCODE SCIPinferVarUbProp(
5985 SCIP* scip, /**< SCIP data structure */
5986 SCIP_VAR* var, /**< variable to change the bound for */
5987 SCIP_Real newbound, /**< new value for bound */
5988 SCIP_PROP* inferprop, /**< propagator that deduced the bound change */
5989 int inferinfo, /**< user information for inference to help resolving the conflict */
5990 SCIP_Bool force, /**< force tightening even if below bound strengthening tolerance */
5991 SCIP_Bool* infeasible, /**< pointer to store whether the bound change is infeasible */
5992 SCIP_Bool* tightened /**< pointer to store whether the bound was tightened, or NULL */
5993 )
5994 {
5995 SCIP_Real lb;
5996 SCIP_Real ub;
5997
5998 assert(infeasible != NULL);
5999
6000 SCIP_CALL( SCIPcheckStage(scip, "SCIPinferVarUbProp", FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
6001
6002 *infeasible = FALSE;
6003 if( tightened != NULL )
6004 *tightened = FALSE;
6005
6006 SCIPvarAdjustUb(var, scip->set, &newbound);
6007
6008 /* ignore tightenings of upper bounds to -infinity during solving process */
6009 if( SCIPisInfinity(scip, -newbound) && SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
6010 {
6011 #ifndef NDEBUG
6012 SCIPwarningMessage(scip, "ignore upper bound tightening for %s from %e to -infinity\n", SCIPvarGetName(var),
6013 SCIPvarGetUbLocal(var));
6014 #endif
6015 return SCIP_OKAY;
6016 }
6017
6018 /* get current bounds */
6019 lb = SCIPvarGetLbLocal(var);
6020 ub = SCIPvarGetUbLocal(var);
6021 assert(SCIPsetIsLE(scip->set, lb, ub));
6022
6023 if( SCIPsetIsFeasLT(scip->set, newbound, lb) )
6024 {
6025 *infeasible = TRUE;
6026 return SCIP_OKAY;
6027 }
6028 newbound = MAX(newbound, lb);
6029
6030 if( (!force && !SCIPsetIsUbBetter(scip->set, newbound, lb, ub))
6031 || SCIPsetIsGE(scip->set, newbound, ub) )
6032 return SCIP_OKAY;
6033
6034 switch( scip->set->stage )
6035 {
6036 case SCIP_STAGE_PROBLEM:
6037 assert(!SCIPvarIsTransformed(var));
6038 SCIP_CALL( SCIPvarChgUbGlobal(var, scip->mem->probmem, scip->set, scip->stat, scip->lp,
6039 scip->branchcand, scip->eventqueue, scip->cliquetable, newbound) );
6040 SCIP_CALL( SCIPvarChgUbLocal(var, scip->mem->probmem, scip->set, scip->stat, scip->lp,
6041 scip->branchcand, scip->eventqueue, newbound) );
6042 SCIP_CALL( SCIPvarChgUbOriginal(var, scip->set, newbound) );
6043 break;
6044
6045 case SCIP_STAGE_PRESOLVING:
6046 if( !SCIPinProbing(scip) )
6047 {
6048 assert(SCIPtreeGetCurrentDepth(scip->tree) == 0);
6049 assert(scip->tree->root == SCIPtreeGetCurrentNode(scip->tree));
6050
6051 SCIP_CALL( SCIPnodeAddBoundchg(scip->tree->root, scip->mem->probmem, scip->set, scip->stat, scip->transprob,
6052 scip->origprob, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventqueue, scip->cliquetable, var, newbound,
6053 SCIP_BOUNDTYPE_UPPER, FALSE) );
6054
6055 if( (SCIP_VARTYPE)var->vartype == SCIP_VARTYPE_INTEGER && SCIPvarIsBinary(var) )
6056 {
6057 SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_BINARY, infeasible) );
6058 assert(!(*infeasible));
6059 }
6060 break;
6061 }
6062 /*lint -fallthrough*/
6063 case SCIP_STAGE_SOLVING:
6064 SCIP_CALL( SCIPnodeAddBoundinfer(SCIPtreeGetCurrentNode(scip->tree), scip->mem->probmem, scip->set, scip->stat,
6065 scip->transprob, scip->origprob, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventqueue,
6066 scip->cliquetable, var, newbound, SCIP_BOUNDTYPE_UPPER, NULL, inferprop, inferinfo, FALSE) );
6067 break;
6068
6069 default:
6070 SCIPerrorMessage("invalid SCIP stage <%d>\n", scip->set->stage);
6071 return SCIP_INVALIDCALL;
6072 } /*lint !e788*/
6073
6074 /* check whether the upper bound improved */
6075 if( tightened != NULL && ub > SCIPcomputeVarUbLocal(scip, var) )
6076 *tightened = TRUE;
6077
6078 return SCIP_OKAY;
6079 }
6080
6081 /** depending on SCIP's stage, fixes binary variable in the problem, in preprocessing, or in current node;
6082 * the given inference propagator is stored, such that the conflict analysis is able to find out the reason for the
6083 * deduction of the fixing
6084 *
6085 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
6086 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
6087 *
6088 * @pre This method can be called if @p scip is in one of the following stages:
6089 * - \ref SCIP_STAGE_PROBLEM
6090 * - \ref SCIP_STAGE_PRESOLVING
6091 * - \ref SCIP_STAGE_PRESOLVED
6092 * - \ref SCIP_STAGE_SOLVING
6093 */
SCIPinferBinvarProp(SCIP * scip,SCIP_VAR * var,SCIP_Bool fixedval,SCIP_PROP * inferprop,int inferinfo,SCIP_Bool * infeasible,SCIP_Bool * tightened)6094 SCIP_RETCODE SCIPinferBinvarProp(
6095 SCIP* scip, /**< SCIP data structure */
6096 SCIP_VAR* var, /**< binary variable to fix */
6097 SCIP_Bool fixedval, /**< value to fix binary variable to */
6098 SCIP_PROP* inferprop, /**< propagator that deduced the fixing */
6099 int inferinfo, /**< user information for inference to help resolving the conflict */
6100 SCIP_Bool* infeasible, /**< pointer to store whether the fixing is infeasible */
6101 SCIP_Bool* tightened /**< pointer to store whether the fixing tightened the local bounds, or NULL */
6102 )
6103 {
6104 SCIP_Real lb;
6105 SCIP_Real ub;
6106
6107 assert(SCIPvarIsBinary(var));
6108 assert(fixedval == TRUE || fixedval == FALSE);
6109 assert(infeasible != NULL);
6110
6111 SCIP_CALL( SCIPcheckStage(scip, "SCIPinferBinvarProp", FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
6112
6113 *infeasible = FALSE;
6114 if( tightened != NULL )
6115 *tightened = FALSE;
6116
6117 /* get current bounds */
6118 lb = SCIPvarGetLbLocal(var);
6119 ub = SCIPvarGetUbLocal(var);
6120 assert(SCIPsetIsEQ(scip->set, lb, 0.0) || SCIPsetIsEQ(scip->set, lb, 1.0));
6121 assert(SCIPsetIsEQ(scip->set, ub, 0.0) || SCIPsetIsEQ(scip->set, ub, 1.0));
6122 assert(SCIPsetIsLE(scip->set, lb, ub));
6123
6124 /* check, if variable is already fixed */
6125 if( (lb > 0.5) || (ub < 0.5) )
6126 {
6127 *infeasible = (fixedval == (lb < 0.5));
6128
6129 return SCIP_OKAY;
6130 }
6131
6132 /* apply the fixing */
6133 switch( scip->set->stage )
6134 {
6135 case SCIP_STAGE_PROBLEM:
6136 assert(!SCIPvarIsTransformed(var));
6137 if( fixedval == TRUE )
6138 {
6139 SCIP_CALL( SCIPchgVarLb(scip, var, 1.0) );
6140 }
6141 else
6142 {
6143 SCIP_CALL( SCIPchgVarUb(scip, var, 0.0) );
6144 }
6145 break;
6146
6147 case SCIP_STAGE_PRESOLVING:
6148 if( SCIPtreeGetCurrentDepth(scip->tree) == 0 )
6149 {
6150 SCIP_Bool fixed;
6151
6152 SCIP_CALL( SCIPvarFix(var, scip->mem->probmem, scip->set, scip->stat, scip->transprob, scip->origprob,
6153 scip->primal, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventfilter, scip->eventqueue,
6154 scip->cliquetable, (SCIP_Real)fixedval, infeasible, &fixed) );
6155 break;
6156 }
6157 /*lint -fallthrough*/
6158 case SCIP_STAGE_SOLVING:
6159 if( fixedval == TRUE )
6160 {
6161 SCIP_CALL( SCIPnodeAddBoundinfer(SCIPtreeGetCurrentNode(scip->tree), scip->mem->probmem, scip->set, scip->stat,
6162 scip->transprob, scip->origprob, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventqueue, scip->cliquetable, var, 1.0,
6163 SCIP_BOUNDTYPE_LOWER, NULL, inferprop, inferinfo, FALSE) );
6164 }
6165 else
6166 {
6167 SCIP_CALL( SCIPnodeAddBoundinfer(SCIPtreeGetCurrentNode(scip->tree), scip->mem->probmem, scip->set, scip->stat,
6168 scip->transprob, scip->origprob, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventqueue, scip->cliquetable, var, 0.0,
6169 SCIP_BOUNDTYPE_UPPER, NULL, inferprop, inferinfo, FALSE) );
6170 }
6171 break;
6172
6173 default:
6174 SCIPerrorMessage("invalid SCIP stage <%d>\n", scip->set->stage);
6175 return SCIP_INVALIDCALL;
6176 } /*lint !e788*/
6177
6178 if( tightened != NULL )
6179 *tightened = TRUE;
6180
6181 return SCIP_OKAY;
6182 }
6183
6184 /** changes global lower bound of variable in preprocessing or in the current node, if the new bound is tighter
6185 * (w.r.t. bound strengthening epsilon) than the current global bound; if possible, adjusts bound to integral value;
6186 * also tightens the local bound, if the global bound is better than the local bound
6187 *
6188 * @warning If SCIP is in presolving stage, it can happen that the internal variable array (which can be accessed via
6189 * SCIPgetVars()) gets resorted.
6190 *
6191 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
6192 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
6193 *
6194 * @pre This method can be called if @p scip is in one of the following stages:
6195 * - \ref SCIP_STAGE_PROBLEM
6196 * - \ref SCIP_STAGE_TRANSFORMING
6197 * - \ref SCIP_STAGE_PRESOLVING
6198 * - \ref SCIP_STAGE_SOLVING
6199 *
6200 * @note During presolving, an integer variable whose bound changes to {0,1} is upgraded to a binary variable.
6201 */
SCIPtightenVarLbGlobal(SCIP * scip,SCIP_VAR * var,SCIP_Real newbound,SCIP_Bool force,SCIP_Bool * infeasible,SCIP_Bool * tightened)6202 SCIP_RETCODE SCIPtightenVarLbGlobal(
6203 SCIP* scip, /**< SCIP data structure */
6204 SCIP_VAR* var, /**< variable to change the bound for */
6205 SCIP_Real newbound, /**< new value for bound */
6206 SCIP_Bool force, /**< force tightening even if below bound strengthening tolerance */
6207 SCIP_Bool* infeasible, /**< pointer to store whether the new domain is empty */
6208 SCIP_Bool* tightened /**< pointer to store whether the bound was tightened, or NULL */
6209 )
6210 {
6211 SCIP_Real lb;
6212 SCIP_Real ub;
6213
6214 assert(infeasible != NULL);
6215
6216 SCIP_CALL( SCIPcheckStage(scip, "SCIPtightenVarLbGlobal", FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
6217
6218 *infeasible = FALSE;
6219 if( tightened != NULL )
6220 *tightened = FALSE;
6221
6222 SCIPvarAdjustLb(var, scip->set, &newbound);
6223
6224 /* ignore tightenings of lower bounds to +infinity during solving process */
6225 if( SCIPisInfinity(scip, newbound) && SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
6226 {
6227 #ifndef NDEBUG
6228 SCIPwarningMessage(scip, "ignore lower bound tightening for %s from %e to +infinity\n", SCIPvarGetName(var),
6229 SCIPvarGetLbLocal(var));
6230 #endif
6231 return SCIP_OKAY;
6232 }
6233
6234 /* get current bounds */
6235 lb = SCIPvarGetLbGlobal(var);
6236 ub = SCIPvarGetUbGlobal(var);
6237 assert(scip->set->stage == SCIP_STAGE_PROBLEM || SCIPsetIsLE(scip->set, lb, ub));
6238
6239 if( SCIPsetIsFeasGT(scip->set, newbound, ub) )
6240 {
6241 *infeasible = TRUE;
6242 return SCIP_OKAY;
6243 }
6244 newbound = MIN(newbound, ub);
6245
6246 /* bound changes of less than epsilon are ignored by SCIPvarChgLb or raise an assert in SCIPnodeAddBoundinfer,
6247 * so don't apply them even if force is set
6248 */
6249 if( SCIPsetIsEQ(scip->set, lb, newbound) || (!force && !SCIPsetIsLbBetter(scip->set, newbound, lb, ub)) )
6250 return SCIP_OKAY;
6251
6252 switch( scip->set->stage )
6253 {
6254 case SCIP_STAGE_PROBLEM:
6255 assert(!SCIPvarIsTransformed(var));
6256 SCIP_CALL( SCIPvarChgLbGlobal(var, scip->mem->probmem, scip->set, scip->stat, scip->lp,
6257 scip->branchcand, scip->eventqueue, scip->cliquetable, newbound) );
6258 SCIP_CALL( SCIPvarChgLbLocal(var, scip->mem->probmem, scip->set, scip->stat, scip->lp,
6259 scip->branchcand, scip->eventqueue, newbound) );
6260 SCIP_CALL( SCIPvarChgLbOriginal(var, scip->set, newbound) );
6261 break;
6262
6263 case SCIP_STAGE_TRANSFORMING:
6264 SCIP_CALL( SCIPvarChgLbGlobal(var, scip->mem->probmem, scip->set, scip->stat, scip->lp,
6265 scip->branchcand, scip->eventqueue, scip->cliquetable, newbound) );
6266 break;
6267
6268 case SCIP_STAGE_PRESOLVING:
6269 if( !SCIPinProbing(scip) )
6270 {
6271 assert(SCIPtreeGetCurrentDepth(scip->tree) == 0);
6272 assert(scip->tree->root == SCIPtreeGetCurrentNode(scip->tree));
6273
6274 SCIP_CALL( SCIPnodeAddBoundchg(scip->tree->root, scip->mem->probmem, scip->set, scip->stat, scip->transprob,
6275 scip->origprob, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventqueue, scip->cliquetable, var, newbound,
6276 SCIP_BOUNDTYPE_LOWER, FALSE) );
6277
6278 if( (SCIP_VARTYPE)var->vartype == SCIP_VARTYPE_INTEGER && SCIPvarIsBinary(var) )
6279 {
6280 SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_BINARY, infeasible) );
6281 assert(!(*infeasible));
6282 }
6283 break;
6284 }
6285 /*lint -fallthrough*/
6286 case SCIP_STAGE_SOLVING:
6287 SCIP_CALL( SCIPnodeAddBoundchg(scip->tree->root, scip->mem->probmem, scip->set, scip->stat, scip->transprob,
6288 scip->origprob, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventqueue, scip->cliquetable, var, newbound,
6289 SCIP_BOUNDTYPE_LOWER, FALSE) );
6290 break;
6291
6292 default:
6293 SCIPerrorMessage("invalid SCIP stage <%d>\n", scip->set->stage);
6294 return SCIP_INVALIDCALL;
6295 } /*lint !e788*/
6296
6297 /* coverity: unreachable code */
6298 if( tightened != NULL && lb < SCIPcomputeVarLbGlobal(scip, var) )
6299 *tightened = TRUE;
6300
6301 return SCIP_OKAY;
6302 }
6303
6304 /** changes global upper bound of variable in preprocessing or in the current node, if the new bound is tighter
6305 * (w.r.t. bound strengthening epsilon) than the current global bound; if possible, adjusts bound to integral value;
6306 * also tightens the local bound, if the global bound is better than the local bound
6307 *
6308 * @warning If SCIP is in presolving stage, it can happen that the internal variable array (which can be accessed via
6309 * SCIPgetVars()) gets resorted.
6310 *
6311 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
6312 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
6313 *
6314 * @pre This method can be called if @p scip is in one of the following stages:
6315 * - \ref SCIP_STAGE_PROBLEM
6316 * - \ref SCIP_STAGE_TRANSFORMING
6317 * - \ref SCIP_STAGE_PRESOLVING
6318 * - \ref SCIP_STAGE_SOLVING
6319 *
6320 * @note During presolving, an integer variable whose bound changes to {0,1} is upgraded to a binary variable.
6321 */
SCIPtightenVarUbGlobal(SCIP * scip,SCIP_VAR * var,SCIP_Real newbound,SCIP_Bool force,SCIP_Bool * infeasible,SCIP_Bool * tightened)6322 SCIP_RETCODE SCIPtightenVarUbGlobal(
6323 SCIP* scip, /**< SCIP data structure */
6324 SCIP_VAR* var, /**< variable to change the bound for */
6325 SCIP_Real newbound, /**< new value for bound */
6326 SCIP_Bool force, /**< force tightening even if below bound strengthening tolerance */
6327 SCIP_Bool* infeasible, /**< pointer to store whether the new domain is empty */
6328 SCIP_Bool* tightened /**< pointer to store whether the bound was tightened, or NULL */
6329 )
6330 {
6331 SCIP_Real lb;
6332 SCIP_Real ub;
6333
6334 assert(infeasible != NULL);
6335
6336 SCIP_CALL( SCIPcheckStage(scip, "SCIPtightenVarUbGlobal", FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
6337
6338 *infeasible = FALSE;
6339 if( tightened != NULL )
6340 *tightened = FALSE;
6341
6342 SCIPvarAdjustUb(var, scip->set, &newbound);
6343
6344 /* ignore tightenings of upper bounds to -infinity during solving process */
6345 if( SCIPisInfinity(scip, -newbound) && SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
6346 {
6347 #ifndef NDEBUG
6348 SCIPwarningMessage(scip, "ignore upper bound tightening for %s from %e to -infinity\n", SCIPvarGetName(var),
6349 SCIPvarGetUbLocal(var));
6350 #endif
6351 return SCIP_OKAY;
6352 }
6353
6354 /* get current bounds */
6355 lb = SCIPvarGetLbGlobal(var);
6356 ub = SCIPvarGetUbGlobal(var);
6357 assert(scip->set->stage == SCIP_STAGE_PROBLEM || SCIPsetIsLE(scip->set, lb, ub));
6358
6359 if( SCIPsetIsFeasLT(scip->set, newbound, lb) )
6360 {
6361 *infeasible = TRUE;
6362 return SCIP_OKAY;
6363 }
6364 newbound = MAX(newbound, lb);
6365
6366 /* bound changes of less than epsilon are ignored by SCIPvarChgUb or raise an assert in SCIPnodeAddBoundinfer,
6367 * so don't apply them even if force is set
6368 */
6369 if( SCIPsetIsEQ(scip->set, ub, newbound) || (!force && !SCIPsetIsUbBetter(scip->set, newbound, lb, ub)) )
6370 return SCIP_OKAY;
6371
6372 switch( scip->set->stage )
6373 {
6374 case SCIP_STAGE_PROBLEM:
6375 assert(!SCIPvarIsTransformed(var));
6376 SCIP_CALL( SCIPvarChgUbGlobal(var, scip->mem->probmem, scip->set, scip->stat, scip->lp,
6377 scip->branchcand, scip->eventqueue, scip->cliquetable, newbound) );
6378 SCIP_CALL( SCIPvarChgUbLocal(var, scip->mem->probmem, scip->set, scip->stat, scip->lp,
6379 scip->branchcand, scip->eventqueue, newbound) );
6380 SCIP_CALL( SCIPvarChgUbOriginal(var, scip->set, newbound) );
6381 break;
6382
6383 case SCIP_STAGE_TRANSFORMING:
6384 SCIP_CALL( SCIPvarChgUbGlobal(var, scip->mem->probmem, scip->set, scip->stat, scip->lp,
6385 scip->branchcand, scip->eventqueue, scip->cliquetable, newbound) );
6386 break;
6387
6388 case SCIP_STAGE_PRESOLVING:
6389 if( !SCIPinProbing(scip) )
6390 {
6391 assert(SCIPtreeGetCurrentDepth(scip->tree) == 0);
6392 assert(scip->tree->root == SCIPtreeGetCurrentNode(scip->tree));
6393
6394 SCIP_CALL( SCIPnodeAddBoundchg(scip->tree->root, scip->mem->probmem, scip->set, scip->stat, scip->transprob,
6395 scip->origprob, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventqueue, scip->cliquetable, var, newbound,
6396 SCIP_BOUNDTYPE_UPPER, FALSE) );
6397
6398 if( (SCIP_VARTYPE)var->vartype == SCIP_VARTYPE_INTEGER && SCIPvarIsBinary(var) )
6399 {
6400 SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_BINARY, infeasible) );
6401 assert(!(*infeasible));
6402 }
6403 break;
6404 }
6405 /*lint -fallthrough*/
6406 case SCIP_STAGE_SOLVING:
6407 SCIP_CALL( SCIPnodeAddBoundchg(scip->tree->root, scip->mem->probmem, scip->set, scip->stat, scip->transprob,
6408 scip->origprob, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventqueue, scip->cliquetable, var, newbound,
6409 SCIP_BOUNDTYPE_UPPER, FALSE) );
6410 break;
6411
6412 default:
6413 SCIPerrorMessage("invalid SCIP stage <%d>\n", scip->set->stage);
6414 return SCIP_INVALIDCALL;
6415 } /*lint !e788*/
6416
6417 /* coverity: unreachable code */
6418 if( tightened != NULL && ub > SCIPcomputeVarUbGlobal(scip, var) )
6419 *tightened = TRUE;
6420
6421 return SCIP_OKAY;
6422 }
6423
6424 /* some simple variable functions implemented as defines */
6425 #undef SCIPcomputeVarLbGlobal
6426 #undef SCIPcomputeVarUbGlobal
6427 #undef SCIPcomputeVarLbLocal
6428 #undef SCIPcomputeVarUbLocal
6429
6430 /** for a multi-aggregated variable, returns the global lower bound computed by adding the global bounds from all aggregation variables
6431 *
6432 * This global bound may be tighter than the one given by SCIPvarGetLbGlobal, since the latter is not updated if bounds of aggregation variables are changing
6433 * calling this function for a non-multi-aggregated variable results in a call to SCIPvarGetLbGlobal.
6434 *
6435 * @return the global lower bound computed by adding the global bounds from all aggregation variables
6436 */
SCIPcomputeVarLbGlobal(SCIP * scip,SCIP_VAR * var)6437 SCIP_Real SCIPcomputeVarLbGlobal(
6438 SCIP* scip, /**< SCIP data structure */
6439 SCIP_VAR* var /**< variable to compute the bound for */
6440 )
6441 {
6442 assert(scip != NULL);
6443 assert(var != NULL);
6444
6445 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR )
6446 return SCIPvarGetMultaggrLbGlobal(var, scip->set);
6447 else
6448 return SCIPvarGetLbGlobal(var);
6449 }
6450
6451 /** for a multi-aggregated variable, returns the global upper bound computed by adding the global bounds from all aggregation variables
6452 *
6453 * This global bound may be tighter than the one given by SCIPvarGetUbGlobal, since the latter is not updated if bounds of aggregation variables are changing
6454 * calling this function for a non-multi-aggregated variable results in a call to SCIPvarGetUbGlobal
6455 *
6456 * @return the global upper bound computed by adding the global bounds from all aggregation variables
6457 */
SCIPcomputeVarUbGlobal(SCIP * scip,SCIP_VAR * var)6458 SCIP_Real SCIPcomputeVarUbGlobal(
6459 SCIP* scip, /**< SCIP data structure */
6460 SCIP_VAR* var /**< variable to compute the bound for */
6461 )
6462 {
6463 assert(scip != NULL);
6464 assert(var != NULL);
6465
6466 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR )
6467 return SCIPvarGetMultaggrUbGlobal(var, scip->set);
6468 else
6469 return SCIPvarGetUbGlobal(var);
6470 }
6471
6472 /** for a multi-aggregated variable, returns the local lower bound computed by adding the local bounds from all aggregation variables
6473 *
6474 * This local bound may be tighter than the one given by SCIPvarGetLbLocal, since the latter is not updated if bounds of aggregation variables are changing
6475 * calling this function for a non-multi-aggregated variable results in a call to SCIPvarGetLbLocal.
6476 *
6477 * @return the local lower bound computed by adding the global bounds from all aggregation variables
6478 */
SCIPcomputeVarLbLocal(SCIP * scip,SCIP_VAR * var)6479 SCIP_Real SCIPcomputeVarLbLocal(
6480 SCIP* scip, /**< SCIP data structure */
6481 SCIP_VAR* var /**< variable to compute the bound for */
6482 )
6483 {
6484 assert(scip != NULL);
6485 assert(var != NULL);
6486
6487 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR )
6488 return SCIPvarGetMultaggrLbLocal(var, scip->set);
6489 else
6490 return SCIPvarGetLbLocal(var);
6491 }
6492
6493 /** for a multi-aggregated variable, returns the local upper bound computed by adding the local bounds from all aggregation variables
6494 *
6495 * This local bound may be tighter than the one given by SCIPvarGetUbLocal, since the latter is not updated if bounds of aggregation variables are changing
6496 * calling this function for a non-multi-aggregated variable results in a call to SCIPvarGetUbLocal.
6497 *
6498 * @return the local upper bound computed by adding the global bounds from all aggregation variables
6499 */
SCIPcomputeVarUbLocal(SCIP * scip,SCIP_VAR * var)6500 SCIP_Real SCIPcomputeVarUbLocal(
6501 SCIP* scip, /**< SCIP data structure */
6502 SCIP_VAR* var /**< variable to compute the bound for */
6503 )
6504 {
6505 assert(scip != NULL);
6506 assert(var != NULL);
6507
6508 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR )
6509 return SCIPvarGetMultaggrUbLocal(var, scip->set);
6510 else
6511 return SCIPvarGetUbLocal(var);
6512 }
6513
6514 /** for a multi-aggregated variable, gives the global lower bound computed by adding the global bounds from all
6515 * aggregation variables, this global bound may be tighter than the one given by SCIPvarGetLbGlobal, since the latter is
6516 * not updated if bounds of aggregation variables are changing
6517 *
6518 * calling this function for a non-multi-aggregated variable is not allowed
6519 */
SCIPgetVarMultaggrLbGlobal(SCIP * scip,SCIP_VAR * var)6520 SCIP_Real SCIPgetVarMultaggrLbGlobal(
6521 SCIP* scip, /**< SCIP data structure */
6522 SCIP_VAR* var /**< variable to compute the bound for */
6523 )
6524 {
6525 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
6526 return SCIPvarGetMultaggrLbGlobal(var, scip->set);
6527 }
6528
6529 /** for a multi-aggregated variable, gives the global upper bound computed by adding the global bounds from all
6530 * aggregation variables, this upper bound may be tighter than the one given by SCIPvarGetUbGlobal, since the latter is
6531 * not updated if bounds of aggregation variables are changing
6532 *
6533 * calling this function for a non-multi-aggregated variable is not allowed
6534 */
SCIPgetVarMultaggrUbGlobal(SCIP * scip,SCIP_VAR * var)6535 SCIP_Real SCIPgetVarMultaggrUbGlobal(
6536 SCIP* scip, /**< SCIP data structure */
6537 SCIP_VAR* var /**< variable to compute the bound for */
6538 )
6539 {
6540 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
6541 return SCIPvarGetMultaggrUbGlobal(var, scip->set);
6542 }
6543
6544 /** for a multi-aggregated variable, gives the local lower bound computed by adding the local bounds from all
6545 * aggregation variables, this lower bound may be tighter than the one given by SCIPvarGetLbLocal, since the latter is
6546 * not updated if bounds of aggregation variables are changing
6547 *
6548 * calling this function for a non-multi-aggregated variable is not allowed
6549 */
SCIPgetVarMultaggrLbLocal(SCIP * scip,SCIP_VAR * var)6550 SCIP_Real SCIPgetVarMultaggrLbLocal(
6551 SCIP* scip, /**< SCIP data structure */
6552 SCIP_VAR* var /**< variable to compute the bound for */
6553 )
6554 {
6555 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
6556 return SCIPvarGetMultaggrLbLocal(var, scip->set);
6557 }
6558
6559 /** for a multi-aggregated variable, gives the local upper bound computed by adding the local bounds from all
6560 * aggregation variables, this upper bound may be tighter than the one given by SCIPvarGetUbLocal, since the latter is
6561 * not updated if bounds of aggregation variables are changing
6562 *
6563 * calling this function for a non-multi-aggregated variable is not allowed
6564 */
SCIPgetVarMultaggrUbLocal(SCIP * scip,SCIP_VAR * var)6565 SCIP_Real SCIPgetVarMultaggrUbLocal(
6566 SCIP* scip, /**< SCIP data structure */
6567 SCIP_VAR* var /**< variable to compute the bound for */
6568 )
6569 {
6570 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
6571 return SCIPvarGetMultaggrUbLocal(var, scip->set);
6572 }
6573
6574 /** returns solution value and index of variable lower bound that is closest to the variable's value in the given primal
6575 * solution or current LP solution if no primal solution is given; returns an index of -1 if no variable lower bound is
6576 * available
6577 *
6578 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
6579 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
6580 *
6581 * @pre This method can only be called if @p scip is in stage \ref SCIP_STAGE_SOLVING
6582 */
SCIPgetVarClosestVlb(SCIP * scip,SCIP_VAR * var,SCIP_SOL * sol,SCIP_Real * closestvlb,int * closestvlbidx)6583 SCIP_RETCODE SCIPgetVarClosestVlb(
6584 SCIP* scip, /**< SCIP data structure */
6585 SCIP_VAR* var, /**< active problem variable */
6586 SCIP_SOL* sol, /**< primal solution, or NULL for LP solution */
6587 SCIP_Real* closestvlb, /**< pointer to store the value of the closest variable lower bound */
6588 int* closestvlbidx /**< pointer to store the index of the closest variable lower bound */
6589 )
6590 {
6591 SCIP_CALL( SCIPcheckStage(scip, "SCIPgetVarClosestVlb", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
6592
6593 SCIPvarGetClosestVlb(var, sol, scip->set, scip->stat, closestvlb, closestvlbidx);
6594
6595 return SCIP_OKAY;
6596 }
6597
6598 /** returns solution value and index of variable upper bound that is closest to the variable's value in the given primal solution;
6599 * or current LP solution if no primal solution is given; returns an index of -1 if no variable upper bound is available
6600 *
6601 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
6602 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
6603 *
6604 * @pre This method can only be called if @p scip is in stage \ref SCIP_STAGE_SOLVING
6605 */
SCIPgetVarClosestVub(SCIP * scip,SCIP_VAR * var,SCIP_SOL * sol,SCIP_Real * closestvub,int * closestvubidx)6606 SCIP_RETCODE SCIPgetVarClosestVub(
6607 SCIP* scip, /**< SCIP data structure */
6608 SCIP_VAR* var, /**< active problem variable */
6609 SCIP_SOL* sol, /**< primal solution, or NULL for LP solution */
6610 SCIP_Real* closestvub, /**< pointer to store the value of the closest variable lower bound */
6611 int* closestvubidx /**< pointer to store the index of the closest variable lower bound */
6612 )
6613 {
6614 SCIP_CALL( SCIPcheckStage(scip, "SCIPgetVarClosestVub", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
6615
6616 SCIPvarGetClosestVub(var, sol, scip->set, scip->stat, closestvub, closestvubidx);
6617
6618 return SCIP_OKAY;
6619 }
6620
6621 /** informs variable x about a globally valid variable lower bound x >= b*z + d with integer variable z;
6622 * if z is binary, the corresponding valid implication for z is also added;
6623 * if z is non-continuous and 1/b not too small, the corresponding valid upper/lower bound
6624 * z <= (x-d)/b or z >= (x-d)/b (depending on the sign of of b) is added, too;
6625 * improves the global bounds of the variable and the vlb variable if possible
6626 *
6627 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
6628 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
6629 *
6630 * @pre This method can be called if @p scip is in one of the following stages:
6631 * - \ref SCIP_STAGE_PRESOLVING
6632 * - \ref SCIP_STAGE_PRESOLVED
6633 * - \ref SCIP_STAGE_SOLVING
6634 */
SCIPaddVarVlb(SCIP * scip,SCIP_VAR * var,SCIP_VAR * vlbvar,SCIP_Real vlbcoef,SCIP_Real vlbconstant,SCIP_Bool * infeasible,int * nbdchgs)6635 SCIP_RETCODE SCIPaddVarVlb(
6636 SCIP* scip, /**< SCIP data structure */
6637 SCIP_VAR* var, /**< problem variable */
6638 SCIP_VAR* vlbvar, /**< variable z in x >= b*z + d */
6639 SCIP_Real vlbcoef, /**< coefficient b in x >= b*z + d */
6640 SCIP_Real vlbconstant, /**< constant d in x >= b*z + d */
6641 SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */
6642 int* nbdchgs /**< pointer to store the number of performed bound changes, or NULL */
6643 )
6644 {
6645 int nlocalbdchgs;
6646
6647 SCIP_CALL( SCIPcheckStage(scip, "SCIPaddVarVlb", FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
6648
6649 SCIP_CALL( SCIPvarAddVlb(var, scip->mem->probmem, scip->set, scip->stat, scip->transprob, scip->origprob, scip->tree,
6650 scip->reopt, scip->lp, scip->cliquetable, scip->branchcand, scip->eventqueue, vlbvar, vlbcoef, vlbconstant,
6651 TRUE, infeasible, &nlocalbdchgs) );
6652
6653 *nbdchgs = nlocalbdchgs;
6654
6655 /* if x is not continuous we add a variable bound for z; do not add it if cofficient would be too small or we already
6656 * detected infeasibility
6657 */
6658 if( !(*infeasible) && SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS && !SCIPisZero(scip, 1.0/vlbcoef) )
6659 {
6660 if( vlbcoef > 0.0 )
6661 {
6662 /* if b > 0, we have a variable upper bound: x >= b*z + d => z <= (x-d)/b */
6663 SCIP_CALL( SCIPvarAddVub(vlbvar, scip->mem->probmem, scip->set, scip->stat, scip->transprob, scip->origprob,
6664 scip->tree, scip->reopt, scip->lp, scip->cliquetable, scip->branchcand, scip->eventqueue, var, 1.0/vlbcoef,
6665 -vlbconstant/vlbcoef, TRUE, infeasible, &nlocalbdchgs) );
6666 }
6667 else
6668 {
6669 /* if b < 0, we have a variable lower bound: x >= b*z + d => z >= (x-d)/b */
6670 SCIP_CALL( SCIPvarAddVlb(vlbvar, scip->mem->probmem, scip->set, scip->stat, scip->transprob, scip->origprob,
6671 scip->tree, scip->reopt, scip->lp, scip->cliquetable, scip->branchcand, scip->eventqueue, var, 1.0/vlbcoef,
6672 -vlbconstant/vlbcoef, TRUE, infeasible, &nlocalbdchgs) );
6673 }
6674 *nbdchgs += nlocalbdchgs;
6675 }
6676
6677 return SCIP_OKAY;
6678 }
6679
6680 /** informs variable x about a globally valid variable upper bound x <= b*z + d with integer variable z;
6681 * if z is binary, the corresponding valid implication for z is also added;
6682 * if z is non-continuous and 1/b not too small, the corresponding valid lower/upper bound
6683 * z >= (x-d)/b or z <= (x-d)/b (depending on the sign of of b) is added, too;
6684 * improves the global bounds of the variable and the vlb variable if possible
6685 *
6686 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
6687 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
6688 *
6689 * @pre This method can be called if @p scip is in one of the following stages:
6690 * - \ref SCIP_STAGE_PRESOLVING
6691 * - \ref SCIP_STAGE_PRESOLVED
6692 * - \ref SCIP_STAGE_SOLVING
6693 */
SCIPaddVarVub(SCIP * scip,SCIP_VAR * var,SCIP_VAR * vubvar,SCIP_Real vubcoef,SCIP_Real vubconstant,SCIP_Bool * infeasible,int * nbdchgs)6694 SCIP_RETCODE SCIPaddVarVub(
6695 SCIP* scip, /**< SCIP data structure */
6696 SCIP_VAR* var, /**< problem variable */
6697 SCIP_VAR* vubvar, /**< variable z in x <= b*z + d */
6698 SCIP_Real vubcoef, /**< coefficient b in x <= b*z + d */
6699 SCIP_Real vubconstant, /**< constant d in x <= b*z + d */
6700 SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */
6701 int* nbdchgs /**< pointer to store the number of performed bound changes, or NULL */
6702 )
6703 {
6704 int nlocalbdchgs;
6705
6706 SCIP_CALL( SCIPcheckStage(scip, "SCIPaddVarVub", FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
6707
6708 SCIP_CALL( SCIPvarAddVub(var, scip->mem->probmem, scip->set, scip->stat, scip->transprob, scip->origprob, scip->tree,
6709 scip->reopt, scip->lp, scip->cliquetable, scip->branchcand, scip->eventqueue, vubvar, vubcoef, vubconstant, TRUE,
6710 infeasible, &nlocalbdchgs) );
6711
6712 *nbdchgs = nlocalbdchgs;
6713
6714 /* if x is not continuous we add a variable bound for z; do not add it if cofficient would be too small or we already
6715 * detected infeasibility
6716 */
6717 if( !(*infeasible) && SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS && !SCIPisZero(scip, 1.0/vubcoef) )
6718 {
6719 if( vubcoef > 0.0 )
6720 {
6721 /* if b < 0, we have a variable lower bound: x >= b*z + d => z >= (x-d)/b */
6722 SCIP_CALL( SCIPvarAddVlb(vubvar, scip->mem->probmem, scip->set, scip->stat, scip->transprob, scip->origprob,
6723 scip->tree, scip->reopt, scip->lp, scip->cliquetable, scip->branchcand, scip->eventqueue, var, 1.0/vubcoef,
6724 -vubconstant/vubcoef, TRUE, infeasible, &nlocalbdchgs) );
6725 }
6726 else
6727 {
6728 /* if b > 0, we have a variable upper bound: x >= b*z + d => z <= (x-d)/b */
6729 SCIP_CALL( SCIPvarAddVub(vubvar, scip->mem->probmem, scip->set, scip->stat, scip->transprob, scip->origprob,
6730 scip->tree, scip->reopt, scip->lp, scip->cliquetable, scip->branchcand, scip->eventqueue, var, 1.0/vubcoef,
6731 -vubconstant/vubcoef, TRUE, infeasible, &nlocalbdchgs) );
6732 }
6733 *nbdchgs += nlocalbdchgs;
6734 }
6735
6736 return SCIP_OKAY;
6737 }
6738
6739 /** informs binary variable x about a globally valid implication: x == 0 or x == 1 ==> y <= b or y >= b;
6740 * also adds the corresponding implication or variable bound to the implied variable;
6741 * if the implication is conflicting, the variable is fixed to the opposite value;
6742 * if the variable is already fixed to the given value, the implication is performed immediately;
6743 * if the implication is redundant with respect to the variables' global bounds, it is ignored
6744 *
6745 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
6746 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
6747 *
6748 * @pre This method can be called if @p scip is in one of the following stages:
6749 * - \ref SCIP_STAGE_TRANSFORMED
6750 * - \ref SCIP_STAGE_PRESOLVING
6751 * - \ref SCIP_STAGE_PRESOLVED
6752 * - \ref SCIP_STAGE_SOLVING
6753 */
SCIPaddVarImplication(SCIP * scip,SCIP_VAR * var,SCIP_Bool varfixing,SCIP_VAR * implvar,SCIP_BOUNDTYPE impltype,SCIP_Real implbound,SCIP_Bool * infeasible,int * nbdchgs)6754 SCIP_RETCODE SCIPaddVarImplication(
6755 SCIP* scip, /**< SCIP data structure */
6756 SCIP_VAR* var, /**< problem variable */
6757 SCIP_Bool varfixing, /**< FALSE if y should be added in implications for x == 0, TRUE for x == 1 */
6758 SCIP_VAR* implvar, /**< variable y in implication y <= b or y >= b */
6759 SCIP_BOUNDTYPE impltype, /**< type of implication y <= b (SCIP_BOUNDTYPE_UPPER)
6760 * or y >= b (SCIP_BOUNDTYPE_LOWER) */
6761 SCIP_Real implbound, /**< bound b in implication y <= b or y >= b */
6762 SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */
6763 int* nbdchgs /**< pointer to store the number of performed bound changes, or NULL */
6764 )
6765 {
6766 SCIP_VAR* implprobvar;
6767
6768 SCIP_CALL( SCIPcheckStage(scip, "SCIPaddVarImplication", FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
6769
6770 assert(infeasible != NULL);
6771 *infeasible = FALSE;
6772
6773 if ( nbdchgs != NULL )
6774 *nbdchgs = 0;
6775
6776 if( !SCIPvarIsBinary(var) )
6777 {
6778 SCIPerrorMessage("can't add implication for nonbinary variable\n");
6779 return SCIP_INVALIDDATA;
6780 }
6781
6782 implprobvar = SCIPvarGetProbvar(implvar);
6783 /* transform implication containing two binary variables to a clique; the condition ensures that the active representative
6784 * of implvar is actually binary
6785 */
6786 if( SCIPvarIsBinary(implvar) && (SCIPvarIsActive(implvar) || (implprobvar != NULL && SCIPvarIsBinary(implprobvar))) )
6787 {
6788 assert(SCIPisFeasEQ(scip, implbound, 1.0) || SCIPisFeasZero(scip, implbound));
6789 assert((impltype == SCIP_BOUNDTYPE_UPPER) == SCIPisFeasZero(scip, implbound));
6790
6791 /* only add clique if implication is not redundant with respect to global bounds of the implication variable */
6792 if( (impltype == SCIP_BOUNDTYPE_LOWER && SCIPvarGetLbGlobal(implvar) < 0.5) ||
6793 (impltype == SCIP_BOUNDTYPE_UPPER && SCIPvarGetUbGlobal(implvar) > 0.5) )
6794 {
6795 SCIP_VAR* vars[2];
6796 SCIP_Bool vals[2];
6797
6798 vars[0] = var;
6799 vars[1] = implvar;
6800 vals[0] = varfixing;
6801 vals[1] = (impltype == SCIP_BOUNDTYPE_UPPER);
6802
6803 SCIP_CALL( SCIPaddClique(scip, vars, vals, 2, FALSE, infeasible, nbdchgs) );
6804 }
6805
6806 return SCIP_OKAY;
6807 }
6808
6809 /* the implication graph can only handle 'real' binary (SCIP_VARTYPE_BINARY) variables, therefore we transform the
6810 * implication in variable bounds, (lowerbound of y will be abbreviated by lby, upperbound equivlaent) the follwing
6811 * four cases are:
6812 *
6813 * 1. (x >= 1 => y >= b) => y >= (b - lby) * x + lby
6814 * 2. (x >= 1 => y <= b) => y <= (b - uby) * x + uby
6815 * 3. (x <= 0 => y >= b) => y >= (lby - b) * x + b
6816 * 4. (x <= 0 => y <= b) => y <= (uby - b) * x + b
6817 */
6818 if( SCIPvarGetType(var) != SCIP_VARTYPE_BINARY )
6819 {
6820 SCIP_Real lby;
6821 SCIP_Real uby;
6822
6823 lby = SCIPvarGetLbGlobal(implvar);
6824 uby = SCIPvarGetUbGlobal(implvar);
6825
6826 if( varfixing == TRUE )
6827 {
6828 if( impltype == SCIP_BOUNDTYPE_LOWER )
6829 {
6830 /* we return if the lower bound is infinity */
6831 if( SCIPisInfinity(scip, -lby) )
6832 return SCIP_OKAY;
6833
6834 SCIP_CALL( SCIPvarAddVlb(implvar, scip->mem->probmem, scip->set, scip->stat, scip->transprob, scip->origprob,
6835 scip->tree, scip->reopt, scip->lp, scip->cliquetable, scip->branchcand, scip->eventqueue, var,
6836 implbound - lby, lby, TRUE, infeasible, nbdchgs) );
6837 }
6838 else
6839 {
6840 /* we return if the upper bound is infinity */
6841 if( SCIPisInfinity(scip, uby) )
6842 return SCIP_OKAY;
6843
6844 SCIP_CALL( SCIPvarAddVub(implvar, scip->mem->probmem, scip->set, scip->stat, scip->transprob, scip->origprob,
6845 scip->tree, scip->reopt, scip->lp, scip->cliquetable, scip->branchcand, scip->eventqueue, var,
6846 implbound - uby, uby, TRUE, infeasible, nbdchgs) );
6847 }
6848 }
6849 else
6850 {
6851 if( impltype == SCIP_BOUNDTYPE_LOWER )
6852 {
6853 /* we return if the lower bound is infinity */
6854 if( SCIPisInfinity(scip, -lby) )
6855 return SCIP_OKAY;
6856
6857 SCIP_CALL( SCIPvarAddVlb(implvar, scip->mem->probmem, scip->set, scip->stat, scip->transprob, scip->origprob,
6858 scip->tree, scip->reopt, scip->lp, scip->cliquetable, scip->branchcand, scip->eventqueue, var,
6859 lby - implbound, implbound, TRUE, infeasible, nbdchgs) );
6860 }
6861 else
6862 {
6863 /* we return if the upper bound is infinity */
6864 if( SCIPisInfinity(scip, uby) )
6865 return SCIP_OKAY;
6866
6867 SCIP_CALL( SCIPvarAddVub(implvar, scip->mem->probmem, scip->set, scip->stat, scip->transprob, scip->origprob,
6868 scip->tree, scip->reopt, scip->lp, scip->cliquetable, scip->branchcand, scip->eventqueue, var,
6869 uby - implbound, implbound, TRUE, infeasible, nbdchgs) );
6870 }
6871 }
6872 }
6873 else
6874 {
6875 SCIP_CALL( SCIPvarAddImplic(var, scip->mem->probmem, scip->set, scip->stat, scip->transprob, scip->origprob,
6876 scip->tree, scip->reopt, scip->lp, scip->cliquetable, scip->branchcand, scip->eventqueue, varfixing, implvar, impltype,
6877 implbound, TRUE, infeasible, nbdchgs) );
6878 }
6879
6880 return SCIP_OKAY;
6881 }
6882
6883 /** adds a clique information to SCIP, stating that at most one of the given binary variables can be set to 1;
6884 * if a variable appears twice in the same clique, the corresponding implications are performed
6885 *
6886 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
6887 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
6888 *
6889 * @pre This method can be called if @p scip is in one of the following stages:
6890 * - \ref SCIP_STAGE_TRANSFORMED
6891 * - \ref SCIP_STAGE_PRESOLVING
6892 * - \ref SCIP_STAGE_PRESOLVED
6893 * - \ref SCIP_STAGE_SOLVING
6894 */
SCIPaddClique(SCIP * scip,SCIP_VAR ** vars,SCIP_Bool * values,int nvars,SCIP_Bool isequation,SCIP_Bool * infeasible,int * nbdchgs)6895 SCIP_RETCODE SCIPaddClique(
6896 SCIP* scip, /**< SCIP data structure */
6897 SCIP_VAR** vars, /**< binary variables in the clique from which at most one can be set to 1 */
6898 SCIP_Bool* values, /**< values of the variables in the clique; NULL to use TRUE for all vars */
6899 int nvars, /**< number of variables in the clique */
6900 SCIP_Bool isequation, /**< is the clique an equation or an inequality? */
6901 SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */
6902 int* nbdchgs /**< pointer to store the number of performed bound changes, or NULL */
6903 )
6904 {
6905 SCIP_CALL( SCIPcheckStage(scip, "SCIPaddClique", FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
6906
6907 *infeasible = FALSE;
6908 if( nbdchgs != NULL )
6909 *nbdchgs = 0;
6910
6911 if( nvars > 1 )
6912 {
6913 /* add the clique to the clique table */
6914 SCIP_CALL( SCIPcliquetableAdd(scip->cliquetable, scip->mem->probmem, scip->set, scip->stat, scip->transprob,
6915 scip->origprob, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventqueue, vars, values, nvars, isequation,
6916 infeasible, nbdchgs) );
6917 }
6918
6919 return SCIP_OKAY;
6920 }
6921
6922 /** relabels the given labels in-place in an increasing fashion: the first seen label is 0, the next label 1, etc...
6923 *
6924 * @note every label equal to -1 is treated as a previously unseen, unique label and gets a new ordered label.
6925 */
6926 static
relabelOrderConsistent(SCIP * const scip,int * labels,int const nlabels,int * nclasses)6927 SCIP_RETCODE relabelOrderConsistent(
6928 SCIP*const scip, /**< SCIP data structure */
6929 int* labels, /**< current labels that will be overwritten */
6930 int const nlabels, /**< number of variables in the clique */
6931 int* nclasses /**< pointer to store the total number of distinct labels */
6932 )
6933 {
6934 SCIP_HASHMAP* classidx2newlabel;
6935
6936 int classidx;
6937 int i;
6938
6939 SCIP_CALL( SCIPhashmapCreate(&classidx2newlabel, SCIPblkmem(scip), nlabels) );
6940
6941 classidx = 0;
6942
6943 /* loop over labels to create local class indices that obey the variable order */
6944 for( i = 0; i < nlabels; ++i )
6945 {
6946 int currentlabel = labels[i];
6947 int localclassidx;
6948
6949 /* labels equal to -1 are stored as singleton classes */
6950 if( currentlabel == -1 )
6951 {
6952 ++classidx;
6953 localclassidx = classidx;
6954 }
6955 else
6956 {
6957 assert(currentlabel >= 0);
6958 /* look up the class index image in the hash map; if it is not stored yet, new class index is created and stored */
6959 if( !SCIPhashmapExists(classidx2newlabel, (void*)(size_t)currentlabel) )
6960 {
6961 ++classidx;
6962 localclassidx = classidx;
6963 SCIP_CALL( SCIPhashmapInsertInt(classidx2newlabel, (void*)(size_t)currentlabel, classidx) ); /*lint !e571*/
6964 }
6965 else
6966 {
6967 localclassidx = SCIPhashmapGetImageInt(classidx2newlabel, (void*)(size_t)currentlabel); /*lint !e571*/
6968 }
6969 }
6970 assert(localclassidx - 1 >= 0);
6971 assert(localclassidx - 1 <= i);
6972
6973 /* indices start with zero, but we have an offset of 1 because we cannot store 0 in a hashmap */
6974 labels[i] = localclassidx - 1;
6975 }
6976
6977 assert(classidx > 0);
6978 assert(classidx <= nlabels);
6979 *nclasses = classidx;
6980
6981 SCIPhashmapFree(&classidx2newlabel);
6982
6983 return SCIP_OKAY;
6984 }
6985
6986 /** sort the variables w.r.t. the given labels; thereby ensure the current order of the variables with the same label. */
6987 static
labelSortStable(SCIP * scip,SCIP_VAR ** vars,int * classlabels,SCIP_VAR ** sortedvars,int * sortedindices,int * classesstartposs,int nvars,int nclasses)6988 SCIP_RETCODE labelSortStable(
6989 SCIP* scip, /**< SCIP data structure */
6990 SCIP_VAR** vars, /**< variable array */
6991 int* classlabels, /**< array that contains a class label for every variable */
6992 SCIP_VAR** sortedvars, /**< array to store variables after stable sorting */
6993 int* sortedindices, /**< array to store indices of sorted variables in the original vars array */
6994 int* classesstartposs, /**< starting position array for each label class (must have size nclasses + 1) */
6995 int nvars, /**< size of the vars arrays */
6996 int nclasses /**< number of label classes */
6997 )
6998 {
6999 SCIP_VAR*** varpointers;
7000 int** indexpointers;
7001 int* classcount;
7002
7003 int nextpos;
7004 int c;
7005 int v;
7006
7007 assert(scip != NULL);
7008 assert(vars != NULL);
7009 assert(sortedindices != NULL);
7010 assert(classesstartposs != NULL);
7011
7012 assert(nvars == 0 || vars != NULL);
7013
7014 if( nvars == 0 )
7015 return SCIP_OKAY;
7016
7017 assert(classlabels != NULL);
7018 assert(nclasses > 0);
7019
7020 /* we first count all class cardinalities and allocate temporary memory for a bucket sort */
7021 SCIP_CALL( SCIPallocBufferArray(scip, &classcount, nclasses) );
7022 BMSclearMemoryArray(classcount, nclasses);
7023
7024 /* first we count for each class the number of elements */
7025 for( v = nvars - 1; v >= 0; --v )
7026 {
7027 assert(0 <= classlabels[v] && classlabels[v] < nclasses);
7028 ++(classcount[classlabels[v]]);
7029 }
7030
7031 #ifndef NDEBUG
7032 BMSclearMemoryArray(sortedvars, nvars);
7033 BMSclearMemoryArray(sortedindices, nvars);
7034 #endif
7035 SCIP_CALL( SCIPallocBufferArray(scip, &varpointers, nclasses) );
7036 SCIP_CALL( SCIPallocBufferArray(scip, &indexpointers, nclasses) );
7037
7038 nextpos = 0;
7039 /* now we initialize all start pointers for each class, so they will be ordered */
7040 for( c = 0; c < nclasses; ++c )
7041 {
7042 /* to reach the goal that all variables of each class will be standing next to each other we will initialize the
7043 * starting pointers for each class by adding the cardinality of each class to the last class starting pointer
7044 * e.g. class1 has 4 elements and class2 has 3 elements then the starting pointer for class1 will be the pointer
7045 * to sortedvars[0], the starting pointer to class2 will be the pointer to sortedvars[4] and to class3 it will be
7046 * the pointer to sortedvars[7]
7047 */
7048 varpointers[c] = (SCIP_VAR**) (sortedvars + nextpos);
7049 indexpointers[c] = (int*) (sortedindices + nextpos);
7050 classesstartposs[c] = nextpos;
7051 assert(classcount[c] > 0);
7052 nextpos += classcount[c];
7053 assert(nextpos > 0);
7054 }
7055 assert(nextpos == nvars);
7056 classesstartposs[c] = nextpos;
7057
7058 /* now we copy all variables to the right order */
7059 for( v = 0; v < nvars; ++v )
7060 {
7061 /* copy variable itself to the right position */
7062 *(varpointers[classlabels[v]]) = vars[v]; /*lint !e613*/
7063 ++(varpointers[classlabels[v]]);
7064
7065 /* copy index */
7066 *(indexpointers[classlabels[v]]) = v;
7067 ++(indexpointers[classlabels[v]]);
7068 }
7069
7070 /* in debug mode, we ensure the correctness of the mapping */
7071 #ifndef NDEBUG
7072 for( v = 0; v < nvars; ++v )
7073 {
7074 assert(sortedvars[v] != NULL);
7075 assert(sortedindices[v] >= 0);
7076
7077 /* assert that the sorted indices map back to the correct variable in the original order */
7078 assert(vars[sortedindices[v]] == sortedvars[v]);
7079 }
7080 #endif
7081
7082 /* free temporary memory */
7083 SCIPfreeBufferArray(scip, &indexpointers);
7084 SCIPfreeBufferArray(scip, &varpointers);
7085 SCIPfreeBufferArray(scip, &classcount);
7086
7087 return SCIP_OKAY;
7088 }
7089
7090
7091 /* calculate clique partition for a maximal amount of comparisons on variables due to expensive algorithm
7092 * @todo: check for a good value, maybe it's better to check parts of variables
7093 */
7094 #define MAXNCLIQUEVARSCOMP 1000000
7095
7096 /** calculates a partition of the given set of binary variables into cliques;
7097 * afterwards the output array contains one value for each variable, such that two variables got the same value iff they
7098 * were assigned to the same clique;
7099 * the first variable is always assigned to clique 0, and a variable can only be assigned to clique i if at least one of
7100 * the preceding variables was assigned to clique i-1;
7101 * for each clique at most 1 variables can be set to TRUE in a feasible solution;
7102 *
7103 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
7104 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
7105 *
7106 * @pre This method can be called if @p scip is in one of the following stages:
7107 * - \ref SCIP_STAGE_INITPRESOLVE
7108 * - \ref SCIP_STAGE_PRESOLVING
7109 * - \ref SCIP_STAGE_EXITPRESOLVE
7110 * - \ref SCIP_STAGE_PRESOLVED
7111 * - \ref SCIP_STAGE_SOLVING
7112 */
7113 static
calcCliquePartitionGreedy(SCIP * const scip,SCIP_VAR ** const vars,SCIP_Bool * const values,int const nvars,int * const cliquepartition,int * const ncliques)7114 SCIP_RETCODE calcCliquePartitionGreedy(
7115 SCIP*const scip, /**< SCIP data structure */
7116 SCIP_VAR**const vars, /**< binary variables in the clique from which at most one can be set to 1 */
7117 SCIP_Bool*const values, /**< clique value (TRUE or FALSE) for each variable in the clique */
7118 int const nvars, /**< number of variables in the array */
7119 int*const cliquepartition, /**< array of length nvars to store the clique partition */
7120 int*const ncliques /**< pointer to store the number of cliques actually contained in the partition */
7121 )
7122 {
7123 SCIP_VAR** cliquevars;
7124 SCIP_Bool* cliquevalues;
7125 int i;
7126 int maxncliquevarscomp;
7127 int ncliquevars;
7128
7129 /* allocate temporary memory for storing the variables of the current clique */
7130 SCIP_CALL( SCIPsetAllocBufferArray(scip->set, &cliquevars, nvars) );
7131 SCIP_CALL( SCIPsetAllocBufferArray(scip->set, &cliquevalues, nvars) );
7132
7133 /* initialize the cliquepartition array with -1 */
7134 for( i = nvars - 1; i >= 0; --i )
7135 cliquepartition[i] = -1;
7136
7137 maxncliquevarscomp = (int) MIN(nvars * (SCIP_Longint)nvars, MAXNCLIQUEVARSCOMP);
7138 /* calculate the clique partition */
7139 *ncliques = 0;
7140 for( i = 0; i < nvars; ++i )
7141 {
7142 if( cliquepartition[i] == -1 )
7143 {
7144 int j;
7145
7146 /* variable starts a new clique */
7147 cliquepartition[i] = *ncliques;
7148 cliquevars[0] = vars[i];
7149 cliquevalues[0] = values[i];
7150 ncliquevars = 1;
7151
7152 /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique */
7153 if( SCIPvarIsActive(vars[i]) && SCIPvarGetNCliques(vars[i], values[i]) > 0 )
7154 {
7155 /* greedily fill up the clique */
7156 for( j = i+1; j < nvars; ++j )
7157 {
7158 /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique */
7159 if( cliquepartition[j] == -1 && SCIPvarIsActive(vars[j]) )
7160 {
7161 int k;
7162
7163 /* check if every variable in the current clique can be extended by tmpvars[j] */
7164 for( k = ncliquevars - 1; k >= 0; --k )
7165 {
7166 if( !SCIPvarsHaveCommonClique(vars[j], values[j], cliquevars[k], cliquevalues[k], FALSE) )
7167 break;
7168 }
7169
7170 if( k == -1 )
7171 {
7172 /* put the variable into the same clique */
7173 cliquepartition[j] = cliquepartition[i];
7174 cliquevars[ncliquevars] = vars[j];
7175 cliquevalues[ncliquevars] = values[j];
7176 ++ncliquevars;
7177 }
7178 }
7179 }
7180 }
7181
7182 /* this clique is finished */
7183 ++(*ncliques);
7184 }
7185 assert(cliquepartition[i] >= 0 && cliquepartition[i] < i+1);
7186
7187 /* break if we reached the maximal number of comparisons */
7188 if( i * nvars > maxncliquevarscomp )
7189 break;
7190 }
7191 /* if we had to many variables fill up the cliquepartition and put each variable in a separate clique */
7192 for( ; i < nvars; ++i )
7193 {
7194 if( cliquepartition[i] == -1 )
7195 {
7196 cliquepartition[i] = *ncliques;
7197 ++(*ncliques);
7198 }
7199 }
7200
7201 SCIPsetFreeBufferArray(scip->set, &cliquevalues);
7202 SCIPsetFreeBufferArray(scip->set, &cliquevars);
7203
7204 return SCIP_OKAY;
7205 }
7206
7207 /** calculates a partition of the given set of binary variables into cliques; takes into account independent clique components
7208 *
7209 * The algorithm performs the following steps:
7210 * - recomputes connected components of the clique table, if necessary
7211 * - computes a clique partition for every connected component greedily.
7212 * - relabels the resulting clique partition such that it satisfies the description below
7213 *
7214 * afterwards the output array contains one value for each variable, such that two variables got the same value iff they
7215 * were assigned to the same clique;
7216 * the first variable is always assigned to clique 0, and a variable can only be assigned to clique i if at least one of
7217 * the preceding variables was assigned to clique i-1;
7218 * for each clique at most 1 variables can be set to TRUE in a feasible solution;
7219 *
7220 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
7221 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
7222 *
7223 * @pre This method can be called if @p scip is in one of the following stages:
7224 * - \ref SCIP_STAGE_INITPRESOLVE
7225 * - \ref SCIP_STAGE_PRESOLVING
7226 * - \ref SCIP_STAGE_EXITPRESOLVE
7227 * - \ref SCIP_STAGE_PRESOLVED
7228 * - \ref SCIP_STAGE_SOLVING
7229 */
SCIPcalcCliquePartition(SCIP * const scip,SCIP_VAR ** const vars,int const nvars,int * const cliquepartition,int * const ncliques)7230 SCIP_RETCODE SCIPcalcCliquePartition(
7231 SCIP*const scip, /**< SCIP data structure */
7232 SCIP_VAR**const vars, /**< binary variables in the clique from which at most one can be set to 1 */
7233 int const nvars, /**< number of variables in the clique */
7234 int*const cliquepartition, /**< array of length nvars to store the clique partition */
7235 int*const ncliques /**< pointer to store the number of cliques actually contained in the partition */
7236 )
7237 {
7238 SCIP_VAR** tmpvars;
7239
7240 SCIP_VAR** sortedtmpvars;
7241 SCIP_Bool* tmpvalues;
7242 SCIP_Bool* sortedtmpvalues;
7243 int* componentlabels;
7244 int* sortedindices;
7245 int* componentstartposs;
7246 int i;
7247 int c;
7248
7249 int ncomponents;
7250
7251 assert(scip != NULL);
7252 assert(nvars == 0 || vars != NULL);
7253 assert(nvars == 0 || cliquepartition != NULL);
7254 assert(ncliques != NULL);
7255
7256 SCIP_CALL( SCIPcheckStage(scip, "SCIPcalcCliquePartition", FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
7257
7258 if( nvars == 0 )
7259 {
7260 *ncliques = 0;
7261 return SCIP_OKAY;
7262 }
7263
7264 /* early abort if no cliques are present */
7265 if( SCIPgetNCliques(scip) == 0 )
7266 {
7267 for( i = 0; i < nvars; ++i )
7268 cliquepartition[i] = i;
7269
7270 *ncliques = nvars;
7271
7272 return SCIP_OKAY;
7273 }
7274
7275 SCIP_CALL( SCIPsetAllocBufferArray(scip->set, &tmpvalues, nvars) );
7276 SCIP_CALL( SCIPsetDuplicateBufferArray(scip->set, &tmpvars, vars, nvars) );
7277 SCIP_CALL( SCIPsetAllocBufferArray(scip->set, &componentlabels, nvars) );
7278 SCIP_CALL( SCIPsetAllocBufferArray(scip->set, &sortedindices, nvars) );
7279
7280 /* initialize the tmpvalues array */
7281 for( i = nvars - 1; i >= 0; --i )
7282 {
7283 tmpvalues[i] = TRUE;
7284 cliquepartition[i] = -1;
7285 }
7286
7287 /* get corresponding active problem variables */
7288 SCIP_CALL( SCIPvarsGetProbvarBinary(&tmpvars, &tmpvalues, nvars) );
7289
7290 ncomponents = -1;
7291
7292 /* update clique components if necessary */
7293 if( SCIPcliquetableNeedsComponentUpdate(scip->cliquetable) )
7294 {
7295 SCIP_VAR** allvars;
7296 int nallbinvars;
7297 int nallintvars;
7298 int nallimplvars;
7299
7300 SCIP_CALL( SCIPgetVarsData(scip, &allvars, NULL, &nallbinvars, &nallintvars, &nallimplvars, NULL) );
7301
7302 SCIP_CALL( SCIPcliquetableComputeCliqueComponents(scip->cliquetable, scip->set, SCIPblkmem(scip), allvars, nallbinvars, nallintvars, nallimplvars) );
7303 }
7304
7305 assert(!SCIPcliquetableNeedsComponentUpdate(scip->cliquetable));
7306
7307 /* store the global clique component labels */
7308 for( i = 0; i < nvars; ++i )
7309 {
7310 if( SCIPvarIsActive(tmpvars[i]) )
7311 componentlabels[i] = SCIPcliquetableGetVarComponentIdx(scip->cliquetable, tmpvars[i]);
7312 else
7313 componentlabels[i] = -1;
7314 }
7315
7316 /* relabel component labels order consistent as prerequisite for a stable sort */
7317 SCIP_CALL( relabelOrderConsistent(scip, componentlabels, nvars, &ncomponents) );
7318 assert(ncomponents >= 1);
7319 assert(ncomponents <= nvars);
7320
7321 /* allocate storage array for the starting positions of the components */
7322 SCIP_CALL( SCIPsetAllocBufferArray(scip->set, &componentstartposs, ncomponents + 1) );
7323
7324 /* stable sort the variables w.r.t. the component labels so that we can restrict the quadratic algorithm to the components */
7325 if( ncomponents > 1 )
7326 {
7327 SCIP_CALL( SCIPsetAllocBufferArray(scip->set, &sortedtmpvars, nvars) );
7328 SCIP_CALL( SCIPsetAllocBufferArray(scip->set, &sortedtmpvalues, nvars) );
7329 SCIP_CALL( labelSortStable(scip, tmpvars, componentlabels, sortedtmpvars, sortedindices, componentstartposs, nvars, ncomponents) );
7330
7331 /* reassign the tmpvalues with respect to the sorting */
7332 for( i = 0; i < nvars; ++i )
7333 {
7334 assert(tmpvars[sortedindices[i]] == sortedtmpvars[i]);
7335 sortedtmpvalues[i] = tmpvalues[sortedindices[i]];
7336 }
7337 }
7338 else
7339 {
7340 /* if we have only one large connected component, skip the stable sorting and prepare the data differently */
7341 sortedtmpvars = tmpvars;
7342 sortedtmpvalues = tmpvalues;
7343 componentstartposs[0] = 0;
7344 componentstartposs[1] = nvars;
7345
7346 /* sorted indices are the identity */
7347 for( i = 0; i < nvars; ++i )
7348 sortedindices[i] = i;
7349 }
7350
7351 *ncliques = 0;
7352 /* calculate a greedy clique partition for each connected component */
7353 for( c = 0; c < ncomponents; ++c )
7354 {
7355 int* localcliquepartition;
7356 int nlocalcliques;
7357 int ncomponentvars;
7358 int l;
7359
7360 /* extract the number of variables in this connected component */
7361 ncomponentvars = componentstartposs[c + 1] - componentstartposs[c];
7362 nlocalcliques = 0;
7363
7364 /* allocate necessary memory to hold the intermediate component clique partition */
7365 SCIP_CALL( SCIPsetAllocBufferArray(scip->set, &localcliquepartition, ncomponentvars) );
7366
7367 /* call greedy clique algorithm for all component variables */
7368 SCIP_CALL( calcCliquePartitionGreedy(scip, &(sortedtmpvars[componentstartposs[c]]), &(sortedtmpvalues[componentstartposs[c]]),
7369 ncomponentvars, localcliquepartition, &nlocalcliques) );
7370
7371 assert(nlocalcliques >= 1);
7372 assert(nlocalcliques <= ncomponentvars);
7373
7374 /* store the obtained clique partition with an offset of ncliques for the original variables */
7375 for( l = componentstartposs[c]; l < componentstartposs[c + 1]; ++l )
7376 {
7377 int origvaridx = sortedindices[l];
7378 assert(cliquepartition[origvaridx] == -1);
7379 assert(localcliquepartition[l - componentstartposs[c]] <= l - componentstartposs[c]);
7380 cliquepartition[origvaridx] = localcliquepartition[l - componentstartposs[c]] + (*ncliques);
7381 }
7382 *ncliques += nlocalcliques;
7383
7384 /* free the local clique partition */
7385 SCIPsetFreeBufferArray(scip->set, &localcliquepartition);
7386 }
7387
7388 /* except in the two trivial cases, we have to ensure the order consistency of the partition indices */
7389 if( ncomponents > 1 && ncomponents < nvars )
7390 {
7391 int partitionsize;
7392 SCIP_CALL( relabelOrderConsistent(scip, cliquepartition, nvars, &partitionsize) );
7393
7394 assert(partitionsize == *ncliques);
7395 }
7396
7397 if( ncomponents > 1 )
7398 {
7399 SCIPsetFreeBufferArray(scip->set, &sortedtmpvalues);
7400 SCIPsetFreeBufferArray(scip->set, &sortedtmpvars);
7401 }
7402
7403 /* use the greedy algorithm as a whole to verify the result on small number of variables */
7404 #ifdef SCIP_DISABLED_CODE
7405 {
7406 int* debugcliquepartition;
7407 int ndebugcliques;
7408
7409 SCIP_CALL( SCIPsetAllocBufferArray(scip->set, &debugcliquepartition, nvars) );
7410
7411 /* call greedy clique algorithm for all component variables */
7412 SCIP_CALL( calcCliquePartitionGreedy(scip, tmpvars, tmpvalues, nvars, debugcliquepartition, &ndebugcliques) );
7413
7414 /* loop and compare the traditional greedy clique with */
7415 for( i = 0; i < nvars; ++i )
7416 assert(i * nvars > MAXNCLIQUEVARSCOMP || cliquepartition[i] == debugcliquepartition[i]);
7417
7418 SCIPsetFreeBufferArray(scip->set, &debugcliquepartition);
7419 }
7420 #endif
7421
7422 /* free temporary memory */
7423 SCIPsetFreeBufferArray(scip->set, &componentstartposs);
7424 SCIPsetFreeBufferArray(scip->set, &sortedindices);
7425 SCIPsetFreeBufferArray(scip->set, &componentlabels);
7426 SCIPsetFreeBufferArray(scip->set, &tmpvars);
7427 SCIPsetFreeBufferArray(scip->set, &tmpvalues);
7428
7429 return SCIP_OKAY;
7430 }
7431
7432 /** calculates a partition of the given set of binary variables into negated cliques;
7433 * afterwards the output array contains one value for each variable, such that two variables got the same value iff they
7434 * were assigned to the same negated clique;
7435 * the first variable is always assigned to clique 0 and a variable can only be assigned to clique i if at least one of
7436 * the preceding variables was assigned to clique i-1;
7437 * for each clique with n_c variables at least n_c-1 variables can be set to TRUE in a feasible solution;
7438 *
7439 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
7440 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
7441 *
7442 * @pre This method can be called if @p scip is in one of the following stages:
7443 * - \ref SCIP_STAGE_INITPRESOLVE
7444 * - \ref SCIP_STAGE_PRESOLVING
7445 * - \ref SCIP_STAGE_EXITPRESOLVE
7446 * - \ref SCIP_STAGE_PRESOLVED
7447 * - \ref SCIP_STAGE_SOLVING
7448 */
SCIPcalcNegatedCliquePartition(SCIP * const scip,SCIP_VAR ** const vars,int const nvars,int * const cliquepartition,int * const ncliques)7449 SCIP_RETCODE SCIPcalcNegatedCliquePartition(
7450 SCIP*const scip, /**< SCIP data structure */
7451 SCIP_VAR**const vars, /**< binary variables in the clique from which at most one can be set to 1 */
7452 int const nvars, /**< number of variables in the clique */
7453 int*const cliquepartition, /**< array of length nvars to store the clique partition */
7454 int*const ncliques /**< pointer to store the number of cliques actually contained in the partition */
7455 )
7456 {
7457 SCIP_VAR** negvars;
7458 int v;
7459
7460 assert(scip != NULL);
7461 assert(cliquepartition != NULL || nvars == 0);
7462 assert(ncliques != NULL);
7463
7464 if( nvars == 0 )
7465 {
7466 *ncliques = 0;
7467 return SCIP_OKAY;
7468 }
7469 assert(vars != NULL);
7470
7471 /* allocate temporary memory */
7472 SCIP_CALL( SCIPsetAllocBufferArray(scip->set, &negvars, nvars) );
7473
7474 /* get all negated variables */
7475 for( v = nvars - 1; v >= 0; --v )
7476 {
7477 SCIP_CALL( SCIPgetNegatedVar(scip, vars[v], &(negvars[v])) );
7478 }
7479
7480 /* calculate cliques on negated variables, which are "negated" cliques on normal variables array */
7481 SCIP_CALL( SCIPcalcCliquePartition( scip, negvars, nvars, cliquepartition, ncliques) );
7482
7483 /* free temporary memory */
7484 SCIPsetFreeBufferArray(scip->set, &negvars);
7485
7486 return SCIP_OKAY;
7487 }
7488
7489
7490 /** force SCIP to clean up all cliques; cliques do not get automatically cleaned up after presolving. Use
7491 * this method to prevent inactive variables in cliques when retrieved via SCIPgetCliques()
7492 *
7493 * @return SCIP_OKAY if everything worked, otherwise a suitable error code is passed
7494 *
7495 * @pre This method can be called if @p scip is in one of the following stages:
7496 * - \ref SCIP_STAGE_TRANSFORMED
7497 * - \ref SCIP_STAGE_INITPRESOLVE
7498 * - \ref SCIP_STAGE_PRESOLVING
7499 * - \ref SCIP_STAGE_EXITPRESOLVE
7500 * - \ref SCIP_STAGE_PRESOLVED
7501 * - \ref SCIP_STAGE_INITSOLVE
7502 * - \ref SCIP_STAGE_SOLVING
7503 * - \ref SCIP_STAGE_SOLVED
7504 * - \ref SCIP_STAGE_EXITSOLVE
7505 */
SCIPcleanupCliques(SCIP * scip,SCIP_Bool * infeasible)7506 SCIP_RETCODE SCIPcleanupCliques(
7507 SCIP* scip, /**< SCIP data structure */
7508 SCIP_Bool* infeasible /**< pointer to store if cleanup detected infeasibility */
7509 )
7510 {
7511 int nlocalbdchgs;
7512 SCIP_Bool globalinfeasibility;
7513
7514 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPcleanupCliques", FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE) );
7515
7516 globalinfeasibility = FALSE;
7517 nlocalbdchgs = 0;
7518 SCIP_CALL( SCIPcliquetableCleanup(scip->cliquetable, scip->mem->probmem, scip->set, scip->stat, scip->transprob,
7519 scip->origprob, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventqueue, &nlocalbdchgs,
7520 &globalinfeasibility) );
7521
7522 if( infeasible != NULL )
7523 *infeasible = globalinfeasibility;
7524
7525 if( globalinfeasibility )
7526 scip->stat->status = SCIP_STATUS_INFEASIBLE;
7527
7528 return SCIP_OKAY;
7529 }
7530
7531 /** gets the number of cliques in the clique table
7532 *
7533 * @return number of cliques in the clique table
7534 *
7535 * @note cliques do not get automatically cleaned up after presolving. Use SCIPcleanupCliques()
7536 * to prevent inactive variables in cliques when retrieved via SCIPgetCliques(). This might reduce the number of cliques
7537 *
7538 * @pre This method can be called if @p scip is in one of the following stages:
7539 * - \ref SCIP_STAGE_TRANSFORMED
7540 * - \ref SCIP_STAGE_INITPRESOLVE
7541 * - \ref SCIP_STAGE_PRESOLVING
7542 * - \ref SCIP_STAGE_EXITPRESOLVE
7543 * - \ref SCIP_STAGE_PRESOLVED
7544 * - \ref SCIP_STAGE_INITSOLVE
7545 * - \ref SCIP_STAGE_SOLVING
7546 * - \ref SCIP_STAGE_SOLVED
7547 * - \ref SCIP_STAGE_EXITSOLVE
7548 */
SCIPgetNCliques(SCIP * scip)7549 int SCIPgetNCliques(
7550 SCIP* scip /**< SCIP data structure */
7551 )
7552 {
7553 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetNCliques", FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE) );
7554
7555 return SCIPcliquetableGetNCliques(scip->cliquetable);
7556 }
7557
7558 /** gets the number of cliques created so far by the cliquetable
7559 *
7560 * @return number of cliques created so far by the cliquetable
7561 *
7562 * @note cliques do not get automatically cleaned up after presolving. Use SCIPcleanupCliques()
7563 * to prevent inactive variables in cliques when retrieved via SCIPgetCliques(). This might reduce the number of cliques
7564 *
7565 * @pre This method can be called if @p scip is in one of the following stages:
7566 * - \ref SCIP_STAGE_TRANSFORMED
7567 * - \ref SCIP_STAGE_INITPRESOLVE
7568 * - \ref SCIP_STAGE_PRESOLVING
7569 * - \ref SCIP_STAGE_EXITPRESOLVE
7570 * - \ref SCIP_STAGE_PRESOLVED
7571 * - \ref SCIP_STAGE_INITSOLVE
7572 * - \ref SCIP_STAGE_SOLVING
7573 * - \ref SCIP_STAGE_SOLVED
7574 * - \ref SCIP_STAGE_EXITSOLVE
7575 */
SCIPgetNCliquesCreated(SCIP * scip)7576 int SCIPgetNCliquesCreated(
7577 SCIP* scip /**< SCIP data structure */
7578 )
7579 {
7580 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetNCliquesCreated", FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE) );
7581
7582 return SCIPcliquetableGetNCliquesCreated(scip->cliquetable);
7583 }
7584
7585 /** gets the array of cliques in the clique table
7586 *
7587 * @return array of cliques in the clique table
7588 *
7589 * @note cliques do not get automatically cleaned up after presolving. Use SCIPcleanupCliques()
7590 * to prevent inactive variables in cliques when retrieved via SCIPgetCliques(). This might reduce the number of cliques
7591 *
7592 * @pre This method can be called if @p scip is in one of the following stages:
7593 * - \ref SCIP_STAGE_TRANSFORMED
7594 * - \ref SCIP_STAGE_INITPRESOLVE
7595 * - \ref SCIP_STAGE_PRESOLVING
7596 * - \ref SCIP_STAGE_EXITPRESOLVE
7597 * - \ref SCIP_STAGE_PRESOLVED
7598 * - \ref SCIP_STAGE_INITSOLVE
7599 * - \ref SCIP_STAGE_SOLVING
7600 * - \ref SCIP_STAGE_SOLVED
7601 * - \ref SCIP_STAGE_EXITSOLVE
7602 */
SCIPgetCliques(SCIP * scip)7603 SCIP_CLIQUE** SCIPgetCliques(
7604 SCIP* scip /**< SCIP data structure */
7605 )
7606 {
7607 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetCliques", FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE) );
7608
7609 return SCIPcliquetableGetCliques(scip->cliquetable);
7610 }
7611
7612 /** returns whether there is a clique that contains both given variable/value pairs;
7613 * the variables must be active binary variables;
7614 * if regardimplics is FALSE, only the cliques in the clique table are looked at;
7615 * if regardimplics is TRUE, both the cliques and the implications of the implication graph are regarded
7616 *
7617 * @return TRUE, if there is a clique that contains both variable/clique pairs; FALSE, otherwise
7618 *
7619 * @pre This method can be called if @p scip is in one of the following stages:
7620 * - \ref SCIP_STAGE_TRANSFORMED
7621 * - \ref SCIP_STAGE_INITPRESOLVE
7622 * - \ref SCIP_STAGE_PRESOLVING
7623 * - \ref SCIP_STAGE_EXITPRESOLVE
7624 * - \ref SCIP_STAGE_PRESOLVED
7625 * - \ref SCIP_STAGE_INITSOLVE
7626 * - \ref SCIP_STAGE_SOLVING
7627 * - \ref SCIP_STAGE_SOLVED
7628 * - \ref SCIP_STAGE_EXITSOLVE
7629 *
7630 * @note a variable with it's negated variable are NOT! in a clique
7631 * @note a variable with itself are in a clique
7632 */
SCIPhaveVarsCommonClique(SCIP * scip,SCIP_VAR * var1,SCIP_Bool value1,SCIP_VAR * var2,SCIP_Bool value2,SCIP_Bool regardimplics)7633 SCIP_Bool SCIPhaveVarsCommonClique(
7634 SCIP* scip, /**< SCIP data structure */
7635 SCIP_VAR* var1, /**< first variable */
7636 SCIP_Bool value1, /**< value of first variable */
7637 SCIP_VAR* var2, /**< second variable */
7638 SCIP_Bool value2, /**< value of second variable */
7639 SCIP_Bool regardimplics /**< should the implication graph also be searched for a clique? */
7640 )
7641 {
7642 assert(scip != NULL);
7643 assert(var1 != NULL);
7644 assert(var2 != NULL);
7645 assert(SCIPvarIsActive(var1));
7646 assert(SCIPvarIsActive(var2));
7647 assert(SCIPvarIsBinary(var1));
7648 assert(SCIPvarIsBinary(var2));
7649
7650 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPhaveVarsCommonClique", FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE) );
7651
7652 /* if both variables together have more cliques then actual cliques exist, then they have a common clique (in debug
7653 * mode we check this for correctness), otherwise we need to call the pairwise comparison method for these variables
7654 */
7655 #ifndef NDEBUG
7656 assert((SCIPvarGetNCliques(var1, value1) + SCIPvarGetNCliques(var2, value2) > SCIPcliquetableGetNCliques(scip->cliquetable)) ? SCIPvarsHaveCommonClique(var1, value1, var2, value2, FALSE) : TRUE);
7657 #endif
7658
7659 return (SCIPvarGetNCliques(var1, value1) + SCIPvarGetNCliques(var2, value2) > SCIPcliquetableGetNCliques(scip->cliquetable)
7660 || SCIPvarsHaveCommonClique(var1, value1, var2, value2, regardimplics));
7661 }
7662
7663 /** writes the clique graph to a gml file
7664 *
7665 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
7666 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
7667 *
7668 * @pre This method can be called if @p scip is in one of the following stages:
7669 * - \ref SCIP_STAGE_TRANSFORMED
7670 * - \ref SCIP_STAGE_INITPRESOLVE
7671 * - \ref SCIP_STAGE_PRESOLVING
7672 * - \ref SCIP_STAGE_EXITPRESOLVE
7673 * - \ref SCIP_STAGE_PRESOLVED
7674 * - \ref SCIP_STAGE_INITSOLVE
7675 * - \ref SCIP_STAGE_SOLVING
7676 * - \ref SCIP_STAGE_SOLVED
7677 * - \ref SCIP_STAGE_EXITSOLVE
7678 *
7679 * @note there can be duplicated arcs in the output file
7680 *
7681 * If @p writenodeweights is true, only nodes corresponding to variables that have a fractional value and only edges
7682 * between such nodes are written.
7683 */
SCIPwriteCliqueGraph(SCIP * scip,const char * fname,SCIP_Bool writenodeweights)7684 SCIP_RETCODE SCIPwriteCliqueGraph(
7685 SCIP* scip, /**< SCIP data structure */
7686 const char* fname, /**< name of file */
7687 SCIP_Bool writenodeweights /**< should we write weights of nodes? */
7688 )
7689 {
7690 FILE* gmlfile;
7691 SCIP_HASHMAP* nodehashmap;
7692 SCIP_CLIQUE** cliques;
7693 SCIP_VAR** clqvars;
7694 SCIP_VAR** allvars;
7695 SCIP_Bool* clqvalues;
7696 char nodename[SCIP_MAXSTRLEN];
7697 int nallvars;
7698 int nbinvars;
7699 int nintvars;
7700 int nimplvars;
7701 int ncliques;
7702 int c;
7703 int v1;
7704 int v2;
7705 int id1;
7706 int id2;
7707
7708 assert(scip != NULL);
7709 assert(fname != NULL);
7710
7711 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPwriteCliqueGraph", FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE) );
7712
7713 /* get all active variables */
7714 SCIP_CALL( SCIPgetVarsData(scip, &allvars, &nallvars, &nbinvars, &nintvars, &nimplvars, NULL) );
7715
7716 /* no possible variables for cliques exist */
7717 if( nbinvars + nimplvars == 0 )
7718 return SCIP_OKAY;
7719
7720 ncliques = SCIPgetNCliques(scip);
7721
7722 /* no cliques and do not wont to check for binary implications */
7723 if( ncliques == 0 )
7724 return SCIP_OKAY;
7725
7726 /* open gml file */
7727 gmlfile = fopen(fname, "w");
7728
7729 if( gmlfile == NULL )
7730 {
7731 SCIPerrorMessage("cannot open graph file <%s>\n", fname);
7732 SCIPABORT();
7733 return SCIP_INVALIDDATA; /*lint !e527*/
7734 }
7735
7736 /* create the hash map */
7737 SCIP_CALL_FINALLY( SCIPhashmapCreate(&nodehashmap, SCIPblkmem(scip), nbinvars+nimplvars), fclose(gmlfile) );
7738
7739 /* write starting of gml file */
7740 SCIPgmlWriteOpening(gmlfile, TRUE);
7741
7742 cliques = SCIPgetCliques(scip);
7743
7744 /* write nodes and arcs for all cliques */
7745 for( c = ncliques - 1; c >= 0; --c )
7746 {
7747 clqvalues = SCIPcliqueGetValues(cliques[c]);
7748 clqvars = SCIPcliqueGetVars(cliques[c]);
7749
7750 for( v1 = SCIPcliqueGetNVars(cliques[c]) - 1; v1 >= 0; --v1 )
7751 {
7752 id1 = clqvalues[v1] ? SCIPvarGetProbindex(clqvars[v1]) : (nallvars + SCIPvarGetProbindex(clqvars[v1]));
7753
7754 /* if corresponding node was not added yet, add it */
7755 if( !SCIPhashmapExists(nodehashmap, (void*)(size_t)id1) )
7756 {
7757 assert(id1 >= 0);
7758 SCIP_CALL_FINALLY( SCIPhashmapInsertInt(nodehashmap, (void*)(size_t)id1, 1), fclose(gmlfile) ); /*lint !e571*/
7759
7760 (void) SCIPsnprintf(nodename, SCIP_MAXSTRLEN, "%s%s", (id1 >= nallvars ? "~" : ""), SCIPvarGetName(clqvars[v1]));
7761
7762 /* write new gml node for new variable */
7763 if ( writenodeweights )
7764 {
7765 if ( ! SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, NULL, clqvars[v1])) )
7766 SCIPgmlWriteNodeWeight(gmlfile, (unsigned int)id1, nodename, NULL, NULL, NULL, SCIPgetSolVal(scip, NULL, clqvars[v1]));
7767 }
7768 else
7769 {
7770 SCIPgmlWriteNode(gmlfile, (unsigned int)id1, nodename, NULL, NULL, NULL);
7771 }
7772 }
7773
7774 for( v2 = SCIPcliqueGetNVars(cliques[c]) - 1; v2 >= 0; --v2 )
7775 {
7776 if( v1 == v2 )
7777 continue;
7778
7779 id2 = clqvalues[v2] ? SCIPvarGetProbindex(clqvars[v2]) : (nallvars + SCIPvarGetProbindex(clqvars[v2]));
7780
7781 /* if corresponding node was not added yet, add it */
7782 if( !SCIPhashmapExists(nodehashmap, (void*)(size_t)id2) )
7783 {
7784 assert(id2 >= 0);
7785 SCIP_CALL_FINALLY( SCIPhashmapInsertInt(nodehashmap, (void*)(size_t)id2, 1), fclose(gmlfile) ); /*lint !e571*/
7786
7787 (void) SCIPsnprintf(nodename, SCIP_MAXSTRLEN, "%s%s", (id2 >= nallvars ? "~" : ""), SCIPvarGetName(clqvars[v2]));
7788
7789 /* write new gml node for new variable */
7790 if ( writenodeweights )
7791 {
7792 if ( ! SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, NULL, clqvars[v2])) )
7793 SCIPgmlWriteNodeWeight(gmlfile, (unsigned int)id2, nodename, NULL, NULL, NULL, SCIPgetSolVal(scip, NULL, clqvars[v2]));
7794 }
7795 else
7796 {
7797 SCIPgmlWriteNode(gmlfile, (unsigned int)id2, nodename, NULL, NULL, NULL);
7798 }
7799 }
7800
7801 /* write gml arc between resultant and operand */
7802 if ( ! writenodeweights || ! SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, NULL, clqvars[v2])) )
7803 SCIPgmlWriteArc(gmlfile, (unsigned int)id1, (unsigned int)id2, NULL, NULL);
7804 }
7805 }
7806 }
7807
7808 /* free the hash map */
7809 SCIPhashmapFree(&nodehashmap);
7810
7811 SCIPgmlWriteClosing(gmlfile);
7812 fclose(gmlfile);
7813
7814 return SCIP_OKAY;
7815 }
7816
7817 /** Removes (irrelevant) variable from all its global structures, i.e. cliques, implications and variable bounds.
7818 * This is an advanced method which should be used with care.
7819 *
7820 * @return SCIP_OKAY if everything worked, otherwise a suitable error code is passed
7821 *
7822 * @pre This method can be called if @p scip is in one of the following stages:
7823 * - \ref SCIP_STAGE_TRANSFORMED
7824 * - \ref SCIP_STAGE_INITPRESOLVE
7825 * - \ref SCIP_STAGE_PRESOLVING
7826 * - \ref SCIP_STAGE_EXITPRESOLVE
7827 * - \ref SCIP_STAGE_PRESOLVED
7828 * - \ref SCIP_STAGE_INITSOLVE
7829 * - \ref SCIP_STAGE_SOLVING
7830 * - \ref SCIP_STAGE_SOLVED
7831 * - \ref SCIP_STAGE_EXITSOLVE
7832 */
SCIPremoveVarFromGlobalStructures(SCIP * scip,SCIP_VAR * var)7833 SCIP_RETCODE SCIPremoveVarFromGlobalStructures(
7834 SCIP* scip, /**< SCIP data structure */
7835 SCIP_VAR* var /**< variable to remove from global structures */
7836 )
7837 {
7838 assert(scip != NULL);
7839
7840 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPremoveVarFromGlobalStructures", FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE) );
7841
7842 /* mark the variable as deletable from global structures - This is necessary for the delayed clean up of cliques */
7843 SCIPvarMarkDeleteGlobalStructures(var);
7844
7845 /* remove variable from all its cliques, implications, and variable bounds */
7846 SCIP_CALL( SCIPvarRemoveCliquesImplicsVbs(var, SCIPblkmem(scip), scip->cliquetable, scip->set, TRUE, FALSE, TRUE) );
7847
7848 return SCIP_OKAY;
7849 }
7850
7851 /** sets the branch factor of the variable; this value can be used in the branching methods to scale the score
7852 * values of the variables; higher factor leads to a higher probability that this variable is chosen for branching
7853 *
7854 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
7855 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
7856 *
7857 * @pre This method can be called if @p scip is in one of the following stages:
7858 * - \ref SCIP_STAGE_PROBLEM
7859 * - \ref SCIP_STAGE_TRANSFORMING
7860 * - \ref SCIP_STAGE_TRANSFORMED
7861 * - \ref SCIP_STAGE_INITPRESOLVE
7862 * - \ref SCIP_STAGE_PRESOLVING
7863 * - \ref SCIP_STAGE_EXITPRESOLVE
7864 * - \ref SCIP_STAGE_PRESOLVED
7865 * - \ref SCIP_STAGE_SOLVING
7866 */
SCIPchgVarBranchFactor(SCIP * scip,SCIP_VAR * var,SCIP_Real branchfactor)7867 SCIP_RETCODE SCIPchgVarBranchFactor(
7868 SCIP* scip, /**< SCIP data structure */
7869 SCIP_VAR* var, /**< problem variable */
7870 SCIP_Real branchfactor /**< factor to weigh variable's branching score with */
7871 )
7872 {
7873 SCIP_CALL( SCIPcheckStage(scip, "SCIPchgVarBranchFactor", FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
7874
7875 SCIP_CALL( SCIPvarChgBranchFactor(var, scip->set, branchfactor) );
7876
7877 return SCIP_OKAY;
7878 }
7879
7880 /** scales the branch factor of the variable with the given value
7881 *
7882 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
7883 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
7884 *
7885 * @pre This method can be called if @p scip is in one of the following stages:
7886 * - \ref SCIP_STAGE_PROBLEM
7887 * - \ref SCIP_STAGE_TRANSFORMING
7888 * - \ref SCIP_STAGE_TRANSFORMED
7889 * - \ref SCIP_STAGE_INITPRESOLVE
7890 * - \ref SCIP_STAGE_PRESOLVING
7891 * - \ref SCIP_STAGE_EXITPRESOLVE
7892 * - \ref SCIP_STAGE_PRESOLVED
7893 * - \ref SCIP_STAGE_SOLVING
7894 */
SCIPscaleVarBranchFactor(SCIP * scip,SCIP_VAR * var,SCIP_Real scale)7895 SCIP_RETCODE SCIPscaleVarBranchFactor(
7896 SCIP* scip, /**< SCIP data structure */
7897 SCIP_VAR* var, /**< problem variable */
7898 SCIP_Real scale /**< factor to scale variable's branching factor with */
7899 )
7900 {
7901 SCIP_CALL( SCIPcheckStage(scip, "SCIPscaleVarBranchFactor", FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
7902
7903 SCIP_CALL( SCIPvarChgBranchFactor(var, scip->set, scale * SCIPvarGetBranchFactor(var)) );
7904
7905 return SCIP_OKAY;
7906 }
7907
7908 /** adds the given value to the branch factor of the variable
7909 *
7910 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
7911 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
7912 *
7913 * @pre This method can be called if @p scip is in one of the following stages:
7914 * - \ref SCIP_STAGE_PROBLEM
7915 * - \ref SCIP_STAGE_TRANSFORMING
7916 * - \ref SCIP_STAGE_TRANSFORMED
7917 * - \ref SCIP_STAGE_INITPRESOLVE
7918 * - \ref SCIP_STAGE_PRESOLVING
7919 * - \ref SCIP_STAGE_EXITPRESOLVE
7920 * - \ref SCIP_STAGE_PRESOLVED
7921 * - \ref SCIP_STAGE_SOLVING
7922 */
SCIPaddVarBranchFactor(SCIP * scip,SCIP_VAR * var,SCIP_Real addfactor)7923 SCIP_RETCODE SCIPaddVarBranchFactor(
7924 SCIP* scip, /**< SCIP data structure */
7925 SCIP_VAR* var, /**< problem variable */
7926 SCIP_Real addfactor /**< value to add to the branch factor of the variable */
7927 )
7928 {
7929 SCIP_CALL( SCIPcheckStage(scip, "SCIPaddVarBranchFactor", FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
7930
7931 SCIP_CALL( SCIPvarChgBranchFactor(var, scip->set, addfactor + SCIPvarGetBranchFactor(var)) );
7932
7933 return SCIP_OKAY;
7934 }
7935
7936 /** sets the branch priority of the variable; variables with higher branch priority are always preferred to variables
7937 * with lower priority in selection of branching variable
7938 *
7939 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
7940 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
7941 *
7942 * @pre This method can be called if @p scip is in one of the following stages:
7943 * - \ref SCIP_STAGE_PROBLEM
7944 * - \ref SCIP_STAGE_TRANSFORMING
7945 * - \ref SCIP_STAGE_TRANSFORMED
7946 * - \ref SCIP_STAGE_INITPRESOLVE
7947 * - \ref SCIP_STAGE_PRESOLVING
7948 * - \ref SCIP_STAGE_EXITPRESOLVE
7949 * - \ref SCIP_STAGE_PRESOLVED
7950 * - \ref SCIP_STAGE_SOLVING
7951 *
7952 * @note the default branching priority is 0
7953 */
SCIPchgVarBranchPriority(SCIP * scip,SCIP_VAR * var,int branchpriority)7954 SCIP_RETCODE SCIPchgVarBranchPriority(
7955 SCIP* scip, /**< SCIP data structure */
7956 SCIP_VAR* var, /**< problem variable */
7957 int branchpriority /**< branch priority of the variable */
7958 )
7959 {
7960 SCIP_CALL( SCIPcheckStage(scip, "SCIPchgVarBranchPriority", FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
7961
7962 assert( var->scip == scip );
7963
7964 if( SCIPisTransformed(scip) )
7965 {
7966 assert(scip->branchcand != NULL);
7967
7968 /* inform the pseudo branch candidates that the branch priority changes and change the branch priority */
7969 SCIP_CALL( SCIPbranchcandUpdateVarBranchPriority(scip->branchcand, scip->set, var, branchpriority) );
7970 }
7971 else
7972 {
7973 /* change the branching priority of the variable */
7974 SCIP_CALL( SCIPvarChgBranchPriority(var, branchpriority) );
7975 }
7976
7977 return SCIP_OKAY;
7978 }
7979
7980 /** changes the branch priority of the variable to the given value, if it is larger than the current priority
7981 *
7982 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
7983 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
7984 *
7985 * @pre This method can be called if @p scip is in one of the following stages:
7986 * - \ref SCIP_STAGE_PROBLEM
7987 * - \ref SCIP_STAGE_TRANSFORMING
7988 * - \ref SCIP_STAGE_TRANSFORMED
7989 * - \ref SCIP_STAGE_INITPRESOLVE
7990 * - \ref SCIP_STAGE_PRESOLVING
7991 * - \ref SCIP_STAGE_EXITPRESOLVE
7992 * - \ref SCIP_STAGE_PRESOLVED
7993 * - \ref SCIP_STAGE_SOLVING
7994 */
SCIPupdateVarBranchPriority(SCIP * scip,SCIP_VAR * var,int branchpriority)7995 SCIP_RETCODE SCIPupdateVarBranchPriority(
7996 SCIP* scip, /**< SCIP data structure */
7997 SCIP_VAR* var, /**< problem variable */
7998 int branchpriority /**< new branch priority of the variable, if it is larger than current priority */
7999 )
8000 {
8001 SCIP_CALL( SCIPcheckStage(scip, "SCIPupdateVarBranchPriority", FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
8002
8003 assert( var->scip == scip );
8004
8005 if( branchpriority > SCIPvarGetBranchPriority(var) )
8006 {
8007 SCIP_CALL( SCIPvarChgBranchPriority(var, branchpriority) );
8008 }
8009
8010 return SCIP_OKAY;
8011 }
8012
8013 /** adds the given value to the branch priority of the variable
8014 *
8015 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
8016 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
8017 *
8018 * @pre This method can be called if @p scip is in one of the following stages:
8019 * - \ref SCIP_STAGE_PROBLEM
8020 * - \ref SCIP_STAGE_TRANSFORMING
8021 * - \ref SCIP_STAGE_TRANSFORMED
8022 * - \ref SCIP_STAGE_INITPRESOLVE
8023 * - \ref SCIP_STAGE_PRESOLVING
8024 * - \ref SCIP_STAGE_EXITPRESOLVE
8025 * - \ref SCIP_STAGE_PRESOLVED
8026 * - \ref SCIP_STAGE_SOLVING
8027 */
SCIPaddVarBranchPriority(SCIP * scip,SCIP_VAR * var,int addpriority)8028 SCIP_RETCODE SCIPaddVarBranchPriority(
8029 SCIP* scip, /**< SCIP data structure */
8030 SCIP_VAR* var, /**< problem variable */
8031 int addpriority /**< value to add to the branch priority of the variable */
8032 )
8033 {
8034 SCIP_CALL( SCIPcheckStage(scip, "SCIPaddVarBranchPriority", FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
8035
8036 assert( var->scip == scip );
8037
8038 SCIP_CALL( SCIPvarChgBranchPriority(var, addpriority + SCIPvarGetBranchPriority(var)) );
8039
8040 return SCIP_OKAY;
8041 }
8042
8043 /** sets the branch direction of the variable (-1: prefer downwards branch, 0: automatic selection, +1: prefer upwards
8044 * branch)
8045 *
8046 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
8047 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
8048 *
8049 * @pre This method can be called if @p scip is in one of the following stages:
8050 * - \ref SCIP_STAGE_PROBLEM
8051 * - \ref SCIP_STAGE_TRANSFORMING
8052 * - \ref SCIP_STAGE_TRANSFORMED
8053 * - \ref SCIP_STAGE_INITPRESOLVE
8054 * - \ref SCIP_STAGE_PRESOLVING
8055 * - \ref SCIP_STAGE_EXITPRESOLVE
8056 * - \ref SCIP_STAGE_PRESOLVED
8057 * - \ref SCIP_STAGE_SOLVING
8058 */
SCIPchgVarBranchDirection(SCIP * scip,SCIP_VAR * var,SCIP_BRANCHDIR branchdirection)8059 SCIP_RETCODE SCIPchgVarBranchDirection(
8060 SCIP* scip, /**< SCIP data structure */
8061 SCIP_VAR* var, /**< problem variable */
8062 SCIP_BRANCHDIR branchdirection /**< preferred branch direction of the variable (downwards, upwards, auto) */
8063 )
8064 {
8065 SCIP_CALL( SCIPcheckStage(scip, "SCIPchgVarBranchDirection", FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
8066
8067 assert( var->scip == scip );
8068
8069 SCIP_CALL( SCIPvarChgBranchDirection(var, branchdirection) );
8070
8071 return SCIP_OKAY;
8072 }
8073
8074 /** tightens the variable bounds due to a new variable type */
8075 static
tightenBounds(SCIP * scip,SCIP_VAR * var,SCIP_VARTYPE vartype,SCIP_Bool * infeasible)8076 SCIP_RETCODE tightenBounds(
8077 SCIP* scip, /**< SCIP data structure */
8078 SCIP_VAR* var, /**< variable to change the bound for */
8079 SCIP_VARTYPE vartype, /**< new type of variable */
8080 SCIP_Bool* infeasible /**< pointer to store whether an infeasibility was detected (, due to
8081 * integrality condition of the new variable type) */
8082 )
8083 {
8084 assert(scip != NULL);
8085 assert(SCIPgetStage(scip) == SCIP_STAGE_PROBLEM || SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING);
8086 assert(scip->set->stage == SCIP_STAGE_PROBLEM || SCIPvarIsTransformed(var));
8087 assert(var->scip == scip);
8088
8089 *infeasible = FALSE;
8090
8091 /* adjusts bounds if the variable type changed form continuous to non-continuous (integral) */
8092 if( SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS && vartype != SCIP_VARTYPE_CONTINUOUS )
8093 {
8094 SCIP_Bool tightened;
8095
8096 /* we adjust variable bounds to integers first, since otherwise a later bound tightening with a fractional old
8097 * bound may give an assert because SCIP expects non-continuous variables to have non-fractional bounds
8098 *
8099 * we adjust bounds with a fractionality within [eps,feastol] only if the resulting bound change is a bound
8100 * tightening, because relaxing bounds may not be allowed
8101 */
8102 if( !SCIPisFeasIntegral(scip, SCIPvarGetLbGlobal(var)) ||
8103 (!SCIPisIntegral(scip, SCIPvarGetLbGlobal(var)) && SCIPvarGetLbGlobal(var) < SCIPfeasCeil(scip, SCIPvarGetLbGlobal(var))) ||
8104 (!SCIPsetIsEQ(scip->set, SCIPvarGetLbGlobal(var), SCIPfeasCeil(scip, SCIPvarGetLbGlobal(var))) &&
8105 SCIPvarGetLbGlobal(var) < SCIPfeasCeil(scip, SCIPvarGetLbGlobal(var)))
8106 )
8107 {
8108 SCIP_CALL( SCIPtightenVarLbGlobal(scip, var, SCIPfeasCeil(scip, SCIPvarGetLbGlobal(var)), TRUE, infeasible, &tightened) );
8109 if( *infeasible )
8110 return SCIP_OKAY;
8111
8112 /* the only reason for not applying a forced boundchange is when the new bound is reduced because the variables upper bound is below the new bound
8113 * in a concrete case, lb == ub == 100.99999001; even though within feastol of 101, the lower bound cannot be tighented to 101 due to the upper bound
8114 */
8115 assert(tightened || SCIPisFeasLE(scip, SCIPvarGetUbGlobal(var), SCIPfeasCeil(scip, SCIPvarGetLbGlobal(var))));
8116 }
8117 if( !SCIPisFeasIntegral(scip, SCIPvarGetUbGlobal(var)) ||
8118 (!SCIPisIntegral(scip, SCIPvarGetUbGlobal(var)) && SCIPvarGetUbGlobal(var) > SCIPfeasFloor(scip, SCIPvarGetUbGlobal(var)))
8119 )
8120 {
8121 SCIP_CALL( SCIPtightenVarUbGlobal(scip, var, SCIPfeasFloor(scip, SCIPvarGetUbGlobal(var)), TRUE, infeasible, &tightened) );
8122 if( *infeasible )
8123 return SCIP_OKAY;
8124
8125 assert(tightened || SCIPisFeasGE(scip, SCIPvarGetLbGlobal(var), SCIPfeasFloor(scip, SCIPvarGetUbGlobal(var))));
8126 }
8127 }
8128
8129 return SCIP_OKAY;
8130 }
8131
8132 /** changes type of variable in the problem;
8133 *
8134 * @warning This type change might change the variable array returned from SCIPgetVars() and SCIPgetVarsData();
8135 *
8136 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
8137 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
8138 *
8139 * @pre This method can be called if @p scip is in one of the following stages:
8140 * - \ref SCIP_STAGE_PROBLEM
8141 * - \ref SCIP_STAGE_TRANSFORMING
8142 * - \ref SCIP_STAGE_PRESOLVING
8143 *
8144 * @note If SCIP is already beyond the SCIP_STAGE_PROBLEM and a original variable is passed, the variable type of the
8145 * corresponding transformed variable is changed; the type of the original variable does not change
8146 *
8147 * @note If the type changes from a continuous variable to a non-continuous variable the bounds of the variable get
8148 * adjusted w.r.t. to integrality information
8149 */
SCIPchgVarType(SCIP * scip,SCIP_VAR * var,SCIP_VARTYPE vartype,SCIP_Bool * infeasible)8150 SCIP_RETCODE SCIPchgVarType(
8151 SCIP* scip, /**< SCIP data structure */
8152 SCIP_VAR* var, /**< variable to change the bound for */
8153 SCIP_VARTYPE vartype, /**< new type of variable */
8154 SCIP_Bool* infeasible /**< pointer to store whether an infeasibility was detected (, due to
8155 * integrality condition of the new variable type) */
8156 )
8157 {
8158 SCIP_CALL( SCIPcheckStage(scip, "SCIPchgVarType", FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE) );
8159
8160 assert(var != NULL);
8161 assert(var->scip == scip);
8162
8163 if( SCIPvarIsNegated(var) )
8164 {
8165 SCIPdebugMsg(scip, "upgrading type of negated variable <%s> from %d to %d\n", SCIPvarGetName(var), SCIPvarGetType(var), vartype);
8166 var = SCIPvarGetNegationVar(var);
8167 }
8168 #ifndef NDEBUG
8169 else
8170 {
8171 if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM )
8172 {
8173 SCIPdebugMsg(scip, "upgrading type of variable <%s> from %d to %d\n", SCIPvarGetName(var), SCIPvarGetType(var), vartype);
8174 }
8175 }
8176 #endif
8177
8178 /* change variable type */
8179 switch( scip->set->stage )
8180 {
8181 case SCIP_STAGE_PROBLEM:
8182 assert(!SCIPvarIsTransformed(var));
8183
8184 /* first adjust the variable due to new integrality information */
8185 SCIP_CALL( tightenBounds(scip, var, vartype, infeasible) );
8186
8187 /* second change variable type */
8188 if( SCIPvarGetProbindex(var) >= 0 )
8189 {
8190 SCIP_CALL( SCIPprobChgVarType(scip->origprob, scip->mem->probmem, scip->set, scip->primal, scip->lp,
8191 scip->branchcand, scip->eventqueue, scip->cliquetable, var, vartype) );
8192 }
8193 else
8194 {
8195 SCIP_CALL( SCIPvarChgType(var, scip->mem->probmem, scip->set, scip->primal, scip->lp,
8196 scip->eventqueue, vartype) );
8197 }
8198 break;
8199
8200 case SCIP_STAGE_PRESOLVING:
8201 if( !SCIPvarIsTransformed(var) )
8202 {
8203 SCIP_VAR* transvar;
8204
8205 SCIP_CALL( SCIPgetTransformedVar(scip, var, &transvar) );
8206 assert(transvar != NULL);
8207
8208 /* recall method with transformed variable */
8209 SCIP_CALL( SCIPchgVarType(scip, transvar, vartype, infeasible) );
8210 return SCIP_OKAY;
8211 }
8212
8213 /* first adjust the variable due to new integrality information */
8214 SCIP_CALL( tightenBounds(scip, var, vartype, infeasible) );
8215
8216 /* second change variable type */
8217 if( SCIPvarGetProbindex(var) >= 0 )
8218 {
8219 SCIP_CALL( SCIPprobChgVarType(scip->transprob, scip->mem->probmem, scip->set, scip->primal, scip->lp,
8220 scip->branchcand, scip->eventqueue, scip->cliquetable, var, vartype) );
8221 }
8222 else
8223 {
8224 SCIP_CALL( SCIPvarChgType(var, scip->mem->probmem, scip->set, scip->primal, scip->lp,
8225 scip->eventqueue, vartype) );
8226 }
8227 break;
8228
8229 default:
8230 SCIPerrorMessage("invalid SCIP stage <%d>\n", scip->set->stage);
8231 return SCIP_INVALIDCALL;
8232 } /*lint !e788*/
8233
8234 return SCIP_OKAY;
8235 }
8236
8237 /** in problem creation and solving stage, both bounds of the variable are set to the given value;
8238 * in presolving stage, the variable is converted into a fixed variable, and bounds are changed respectively;
8239 * conversion into a fixed variable changes the vars array returned from SCIPgetVars() and SCIPgetVarsData(),
8240 * and also renders arrays returned from the SCIPvarGetImpl...() methods invalid
8241 *
8242 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
8243 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
8244 *
8245 * @pre This method can be called if @p scip is in one of the following stages:
8246 * - \ref SCIP_STAGE_PROBLEM
8247 * - \ref SCIP_STAGE_PRESOLVING
8248 * - \ref SCIP_STAGE_SOLVING
8249 */
SCIPfixVar(SCIP * scip,SCIP_VAR * var,SCIP_Real fixedval,SCIP_Bool * infeasible,SCIP_Bool * fixed)8250 SCIP_RETCODE SCIPfixVar(
8251 SCIP* scip, /**< SCIP data structure */
8252 SCIP_VAR* var, /**< variable to fix */
8253 SCIP_Real fixedval, /**< value to fix variable to */
8254 SCIP_Bool* infeasible, /**< pointer to store whether the fixing is infeasible */
8255 SCIP_Bool* fixed /**< pointer to store whether the fixing was performed (variable was unfixed) */
8256 )
8257 {
8258 assert(var != NULL);
8259 assert(infeasible != NULL);
8260 assert(fixed != NULL);
8261
8262 SCIP_CALL( SCIPcheckStage(scip, "SCIPfixVar", FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
8263
8264 *infeasible = FALSE;
8265 *fixed = FALSE;
8266
8267 /* in the problem creation stage, modify the bounds as requested, independently from the current bounds */
8268 if( scip->set->stage != SCIP_STAGE_PROBLEM )
8269 {
8270 if( (SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS && !SCIPsetIsFeasIntegral(scip->set, fixedval))
8271 || SCIPsetIsFeasLT(scip->set, fixedval, SCIPvarGetLbLocal(var))
8272 || SCIPsetIsFeasGT(scip->set, fixedval, SCIPvarGetUbLocal(var)) )
8273 {
8274 *infeasible = TRUE;
8275 return SCIP_OKAY;
8276 }
8277 else if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED )
8278 {
8279 *infeasible = !SCIPsetIsFeasEQ(scip->set, fixedval, SCIPvarGetLbLocal(var));
8280 return SCIP_OKAY;
8281 }
8282 }
8283 else
8284 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL);
8285
8286 switch( scip->set->stage )
8287 {
8288 case SCIP_STAGE_PROBLEM:
8289 /* in the problem creation stage, modify the bounds as requested, independently from the current bounds;
8290 * we have to make sure, that the order of the bound changes does not intermediately produce an invalid
8291 * interval lb > ub
8292 */
8293 if( fixedval <= SCIPvarGetLbLocal(var) )
8294 {
8295 SCIP_CALL( SCIPchgVarLb(scip, var, fixedval) );
8296 SCIP_CALL( SCIPchgVarUb(scip, var, fixedval) );
8297 *fixed = TRUE;
8298 }
8299 else
8300 {
8301 SCIP_CALL( SCIPchgVarUb(scip, var, fixedval) );
8302 SCIP_CALL( SCIPchgVarLb(scip, var, fixedval) );
8303 *fixed = TRUE;
8304 }
8305 return SCIP_OKAY;
8306
8307 case SCIP_STAGE_PRESOLVING:
8308 if( SCIPtreeGetCurrentDepth(scip->tree) == 0 )
8309 {
8310 SCIP_CALL( SCIPvarFix(var, scip->mem->probmem, scip->set, scip->stat, scip->transprob, scip->origprob,
8311 scip->primal, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventfilter, scip->eventqueue,
8312 scip->cliquetable, fixedval, infeasible, fixed) );
8313 return SCIP_OKAY;
8314 }
8315 /*lint -fallthrough*/
8316 case SCIP_STAGE_SOLVING:
8317 if( SCIPsetIsFeasGT(scip->set, fixedval, SCIPvarGetLbLocal(var)) )
8318 {
8319 if( SCIPsetIsFeasGT(scip->set, fixedval, SCIPvarGetUbLocal(var)) )
8320 {
8321 *infeasible = TRUE;
8322 return SCIP_OKAY;
8323 }
8324 else
8325 {
8326 SCIP_CALL( SCIPchgVarLb(scip, var, fixedval) );
8327 *fixed = TRUE;
8328 }
8329 }
8330 if( SCIPsetIsFeasLT(scip->set, fixedval, SCIPvarGetUbLocal(var)) )
8331 {
8332 if( SCIPsetIsFeasLT(scip->set, fixedval, SCIPvarGetLbLocal(var)) )
8333 {
8334 *infeasible = TRUE;
8335 return SCIP_OKAY;
8336 }
8337 else
8338 {
8339 SCIP_CALL( SCIPchgVarUb(scip, var, fixedval) );
8340 *fixed = TRUE;
8341 }
8342 }
8343 return SCIP_OKAY;
8344
8345 default:
8346 SCIPerrorMessage("invalid SCIP stage <%d>\n", scip->set->stage);
8347 return SCIP_INVALIDCALL;
8348 } /*lint !e788*/
8349 }
8350
8351 /** From a given equality a*x + b*y == c, aggregates one of the variables and removes it from the set of
8352 * active problem variables. This changes the vars array returned from SCIPgetVars() and SCIPgetVarsData(),
8353 * and also renders the arrays returned from the SCIPvarGetImpl...() methods for the two variables invalid.
8354 * In the first step, the equality is transformed into an equality with active problem variables
8355 * a'*x' + b'*y' == c'. If x' == y', this leads to the detection of redundancy if a' == -b' and c' == 0,
8356 * of infeasibility, if a' == -b' and c' != 0, or to a variable fixing x' == c'/(a'+b') (and possible
8357 * infeasibility) otherwise.
8358 * In the second step, the variable to be aggregated is chosen among x' and y', prefering a less strict variable
8359 * type as aggregation variable (i.e. continuous variables are preferred over implicit integers, implicit integers
8360 * over integers, and integers over binaries). If none of the variables is continuous, it is tried to find an integer
8361 * aggregation (i.e. integral coefficients a'' and b'', such that a''*x' + b''*y' == c''). This can lead to
8362 * the detection of infeasibility (e.g. if c'' is fractional), or to a rejection of the aggregation (denoted by
8363 * aggregated == FALSE), if the resulting integer coefficients are too large and thus numerically instable.
8364 *
8365 * The output flags have the following meaning:
8366 * - infeasible: the problem is infeasible
8367 * - redundant: the equality can be deleted from the constraint set
8368 * - aggregated: the aggregation was successfully performed (the variables were not aggregated before)
8369 *
8370 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
8371 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
8372 *
8373 * @pre This method can only be called if @p scip is in stage \ref SCIP_STAGE_PRESOLVING
8374 */
SCIPaggregateVars(SCIP * scip,SCIP_VAR * varx,SCIP_VAR * vary,SCIP_Real scalarx,SCIP_Real scalary,SCIP_Real rhs,SCIP_Bool * infeasible,SCIP_Bool * redundant,SCIP_Bool * aggregated)8375 SCIP_RETCODE SCIPaggregateVars(
8376 SCIP* scip, /**< SCIP data structure */
8377 SCIP_VAR* varx, /**< variable x in equality a*x + b*y == c */
8378 SCIP_VAR* vary, /**< variable y in equality a*x + b*y == c */
8379 SCIP_Real scalarx, /**< multiplier a in equality a*x + b*y == c */
8380 SCIP_Real scalary, /**< multiplier b in equality a*x + b*y == c */
8381 SCIP_Real rhs, /**< right hand side c in equality a*x + b*y == c */
8382 SCIP_Bool* infeasible, /**< pointer to store whether the aggregation is infeasible */
8383 SCIP_Bool* redundant, /**< pointer to store whether the equality is (now) redundant */
8384 SCIP_Bool* aggregated /**< pointer to store whether the aggregation was successful */
8385 )
8386 {
8387 SCIP_Real constantx;
8388 SCIP_Real constanty;
8389
8390 assert(infeasible != NULL);
8391 assert(redundant != NULL);
8392 assert(aggregated != NULL);
8393
8394 SCIP_CALL( SCIPcheckStage(scip, "SCIPaggregateVars", FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE) );
8395
8396 *infeasible = FALSE;
8397 *redundant = FALSE;
8398 *aggregated = FALSE;
8399
8400 if( SCIPtreeProbing(scip->tree) )
8401 {
8402 SCIPerrorMessage("cannot aggregate variables during probing\n");
8403 return SCIP_INVALIDCALL;
8404 }
8405 assert(SCIPtreeGetCurrentDepth(scip->tree) == 0);
8406
8407 /* do not perform aggregation if it is globally deactivated */
8408 if( scip->set->presol_donotaggr )
8409 return SCIP_OKAY;
8410
8411 /* get the corresponding equality in active problem variable space:
8412 * transform both expressions "a*x + 0" and "b*y + 0" into problem variable space
8413 */
8414 constantx = 0.0;
8415 constanty = 0.0;
8416 SCIP_CALL( SCIPvarGetProbvarSum(&varx, scip->set, &scalarx, &constantx) );
8417 SCIP_CALL( SCIPvarGetProbvarSum(&vary, scip->set, &scalary, &constanty) );
8418
8419 /* we cannot aggregate multi-aggregated variables */
8420 if( SCIPvarGetStatus(varx) == SCIP_VARSTATUS_MULTAGGR || SCIPvarGetStatus(vary) == SCIP_VARSTATUS_MULTAGGR )
8421 return SCIP_OKAY;
8422
8423 /* move the constant to the right hand side to acquire the form "a'*x' + b'*y' == c'" */
8424 rhs -= (constantx + constanty);
8425
8426 /* if a scalar is zero, treat the variable as fixed-to-zero variable */
8427 if( SCIPsetIsZero(scip->set, scalarx) )
8428 varx = NULL;
8429 if( SCIPsetIsZero(scip->set, scalary) )
8430 vary = NULL;
8431
8432 /* capture the special cases that less than two variables are left, due to resolutions to a fixed variable or
8433 * to the same active variable
8434 */
8435 if( varx == NULL && vary == NULL )
8436 {
8437 /* both variables were resolved to fixed variables */
8438 *infeasible = !SCIPsetIsZero(scip->set, rhs);
8439 *redundant = TRUE;
8440 }
8441 else if( varx == NULL )
8442 {
8443 assert(SCIPsetIsZero(scip->set, scalarx));
8444 assert(!SCIPsetIsZero(scip->set, scalary));
8445
8446 /* variable x was resolved to fixed variable: variable y can be fixed to c'/b' */
8447 SCIP_CALL( SCIPvarFix(vary, scip->mem->probmem, scip->set, scip->stat, scip->transprob, scip->origprob,
8448 scip->primal, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventfilter, scip->eventqueue,
8449 scip->cliquetable, rhs/scalary, infeasible, aggregated) );
8450 *redundant = TRUE;
8451 }
8452 else if( vary == NULL )
8453 {
8454 assert(SCIPsetIsZero(scip->set, scalary));
8455 assert(!SCIPsetIsZero(scip->set, scalarx));
8456
8457 /* variable y was resolved to fixed variable: variable x can be fixed to c'/a' */
8458 SCIP_CALL( SCIPvarFix(varx, scip->mem->probmem, scip->set, scip->stat, scip->transprob, scip->origprob,
8459 scip->primal, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventfilter, scip->eventqueue,
8460 scip->cliquetable, rhs/scalarx, infeasible, aggregated) );
8461 *redundant = TRUE;
8462 }
8463 else if( varx == vary )
8464 {
8465 /* both variables were resolved to the same active problem variable: this variable can be fixed */
8466 scalarx += scalary;
8467 if( SCIPsetIsZero(scip->set, scalarx) )
8468 {
8469 /* left hand side of equality is zero: equality is potentially infeasible */
8470 *infeasible = !SCIPsetIsZero(scip->set, rhs);
8471 }
8472 else
8473 {
8474 /* sum of scalars is not zero: fix variable x' == y' to c'/(a'+b') */
8475 SCIP_CALL( SCIPvarFix(varx, scip->mem->probmem, scip->set, scip->stat, scip->transprob, scip->origprob,
8476 scip->primal, scip->tree, scip->reopt, scip->lp, scip->branchcand, scip->eventfilter, scip->eventqueue,
8477 scip->cliquetable, rhs/scalarx, infeasible, aggregated) );
8478 }
8479 *redundant = TRUE;
8480 }
8481 else
8482 {
8483 /* both variables are different active problem variables, and both scalars are non-zero: try to aggregate them */
8484 SCIP_CALL( SCIPvarTryAggregateVars(scip->set, scip->mem->probmem, scip->stat, scip->transprob, scip->origprob,
8485 scip->primal, scip->tree, scip->reopt, scip->lp, scip->cliquetable, scip->branchcand, scip->eventfilter,
8486 scip->eventqueue, varx, vary, scalarx, scalary, rhs, infeasible, aggregated) );
8487 *redundant = *aggregated;
8488 }
8489
8490 return SCIP_OKAY;
8491 }
8492
8493 /** converts variable into multi-aggregated variable; this changes the variable array returned from
8494 * SCIPgetVars() and SCIPgetVarsData();
8495 *
8496 * @warning The integrality condition is not checked anymore on the multi-aggregated variable. You must not
8497 * multi-aggregate an integer variable without being sure, that integrality on the aggregation variables
8498 * implies integrality on the aggregated variable.
8499 *
8500 * The output flags have the following meaning:
8501 * - infeasible: the problem is infeasible
8502 * - aggregated: the aggregation was successfully performed (the variables were not aggregated before)
8503 *
8504 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
8505 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
8506 *
8507 * @pre This method can only be called if @p scip is in stage \ref SCIP_STAGE_PRESOLVING
8508 */
SCIPmultiaggregateVar(SCIP * scip,SCIP_VAR * var,int naggvars,SCIP_VAR ** aggvars,SCIP_Real * scalars,SCIP_Real constant,SCIP_Bool * infeasible,SCIP_Bool * aggregated)8509 SCIP_RETCODE SCIPmultiaggregateVar(
8510 SCIP* scip, /**< SCIP data structure */
8511 SCIP_VAR* var, /**< variable x to aggregate */
8512 int naggvars, /**< number n of variables in aggregation x = a_1*y_1 + ... + a_n*y_n + c */
8513 SCIP_VAR** aggvars, /**< variables y_i in aggregation x = a_1*y_1 + ... + a_n*y_n + c */
8514 SCIP_Real* scalars, /**< multipliers a_i in aggregation x = a_1*y_1 + ... + a_n*y_n + c */
8515 SCIP_Real constant, /**< constant shift c in aggregation x = a_1*y_1 + ... + a_n*y_n + c */
8516 SCIP_Bool* infeasible, /**< pointer to store whether the aggregation is infeasible */
8517 SCIP_Bool* aggregated /**< pointer to store whether the aggregation was successful */
8518 )
8519 {
8520 SCIP_CALL( SCIPcheckStage(scip, "SCIPmultiaggregateVar", FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE) );
8521
8522 assert(var->scip == scip);
8523
8524 if( SCIPtreeProbing(scip->tree) )
8525 {
8526 SCIPerrorMessage("cannot multi-aggregate variables during probing\n");
8527 return SCIP_INVALIDCALL;
8528 }
8529 assert(SCIPtreeGetCurrentDepth(scip->tree) == 0);
8530
8531 SCIP_CALL( SCIPvarMultiaggregate(var, scip->mem->probmem, scip->set, scip->stat, scip->transprob, scip->origprob,
8532 scip->primal, scip->tree, scip->reopt, scip->lp, scip->cliquetable, scip->branchcand, scip->eventfilter,
8533 scip->eventqueue, naggvars, aggvars, scalars, constant, infeasible, aggregated) );
8534
8535 return SCIP_OKAY;
8536 }
8537
8538 /** returns whether aggregation of variables is not allowed */
SCIPdoNotAggr(SCIP * scip)8539 SCIP_Bool SCIPdoNotAggr(
8540 SCIP* scip /**< SCIP data structure */
8541 )
8542 {
8543 assert(scip != NULL);
8544
8545 return scip->set->presol_donotaggr;
8546 }
8547
8548 /** returns whether multi-aggregation is disabled */
SCIPdoNotMultaggr(SCIP * scip)8549 SCIP_Bool SCIPdoNotMultaggr(
8550 SCIP* scip /**< SCIP data structure */
8551 )
8552 {
8553 assert(scip != NULL);
8554
8555 return scip->set->presol_donotmultaggr;
8556 }
8557
8558 /** returns whether variable is not allowed to be multi-aggregated */
SCIPdoNotMultaggrVar(SCIP * scip,SCIP_VAR * var)8559 SCIP_Bool SCIPdoNotMultaggrVar(
8560 SCIP* scip, /**< SCIP data structure */
8561 SCIP_VAR* var /**< variable x to aggregate */
8562 )
8563 {
8564 assert(scip != NULL);
8565 assert(var != NULL);
8566 assert(var->scip == scip);
8567
8568 return scip->set->presol_donotmultaggr || SCIPvarDoNotMultaggr(var);
8569 }
8570
8571 /** returns whether dual reductions are allowed during propagation and presolving
8572 *
8573 * @deprecated Please use SCIPallowStrongDualReds()
8574 */
SCIPallowDualReds(SCIP * scip)8575 SCIP_Bool SCIPallowDualReds(
8576 SCIP* scip /**< SCIP data structure */
8577 )
8578 {
8579 assert(scip != NULL);
8580
8581 return !scip->set->reopt_enable && scip->set->misc_allowstrongdualreds;
8582 }
8583
8584 /** returns whether strong dual reductions are allowed during propagation and presolving
8585 *
8586 * @note A reduction is called strong dual, if it may discard feasible/optimal solutions, but leaves at least one
8587 * optimal solution intact. Often such reductions are based on analyzing the objective function and variable
8588 * locks.
8589 */
SCIPallowStrongDualReds(SCIP * scip)8590 SCIP_Bool SCIPallowStrongDualReds(
8591 SCIP* scip /**< SCIP data structure */
8592 )
8593 {
8594 assert(scip != NULL);
8595
8596 return !scip->set->reopt_enable && scip->set->misc_allowstrongdualreds;
8597 }
8598
8599 /** returns whether propagation w.r.t. current objective is allowed
8600 *
8601 * @deprecated Please use SCIPallowWeakDualReds()
8602 */
SCIPallowObjProp(SCIP * scip)8603 SCIP_Bool SCIPallowObjProp(
8604 SCIP* scip /**< SCIP data structure */
8605 )
8606 {
8607 assert(scip != NULL);
8608
8609 return !scip->set->reopt_enable && scip->set->misc_allowweakdualreds;
8610 }
8611
8612 /** returns whether weak dual reductions are allowed during propagation and presolving
8613 *
8614 * @note A reduction is called weak dual, if it may discard feasible solutions, but leaves at all optimal solutions
8615 * intact. Often such reductions are based on analyzing the objective function, reduced costs, and/or dual LPs.
8616 */
SCIPallowWeakDualReds(SCIP * scip)8617 SCIP_Bool SCIPallowWeakDualReds(
8618 SCIP* scip /**< SCIP data structure */
8619 )
8620 {
8621 assert(scip != NULL);
8622
8623 return !scip->set->reopt_enable && scip->set->misc_allowweakdualreds;
8624 }
8625
8626 /** marks the variable that it must not be multi-aggregated
8627 *
8628 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
8629 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
8630 *
8631 * @pre This method can be called if @p scip is in one of the following stages:
8632 * - \ref SCIP_STAGE_INIT
8633 * - \ref SCIP_STAGE_PROBLEM
8634 * - \ref SCIP_STAGE_TRANSFORMING
8635 * - \ref SCIP_STAGE_TRANSFORMED
8636 * - \ref SCIP_STAGE_INITPRESOLVE
8637 * - \ref SCIP_STAGE_PRESOLVING
8638 * - \ref SCIP_STAGE_EXITPRESOLVE
8639 *
8640 * @note There exists no "unmark" method since it has to be ensured that if a plugin requires that a variable is not
8641 * multi-aggregated that this is will be the case.
8642 */
SCIPmarkDoNotMultaggrVar(SCIP * scip,SCIP_VAR * var)8643 SCIP_RETCODE SCIPmarkDoNotMultaggrVar(
8644 SCIP* scip, /**< SCIP data structure */
8645 SCIP_VAR* var /**< variable to delete */
8646 )
8647 {
8648 assert(scip != NULL);
8649 assert(var != NULL);
8650 assert(var->scip == scip);
8651
8652 SCIP_CALL( SCIPcheckStage(scip, "SCIPmarkDoNotMultaggrVar", TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE) );
8653
8654 SCIP_CALL( SCIPvarMarkDoNotMultaggr(var) );
8655
8656 return SCIP_OKAY;
8657 }
8658
8659 /** enables the collection of statistics for a variable
8660 *
8661 * @pre This method can be called if @p scip is in one of the following stages:
8662 * - \ref SCIP_STAGE_PROBLEM
8663 * - \ref SCIP_STAGE_INITPRESOLVE
8664 * - \ref SCIP_STAGE_PRESOLVING
8665 * - \ref SCIP_STAGE_EXITPRESOLVE
8666 * - \ref SCIP_STAGE_SOLVING
8667 * - \ref SCIP_STAGE_SOLVED
8668 */
SCIPenableVarHistory(SCIP * scip)8669 void SCIPenableVarHistory(
8670 SCIP* scip /**< SCIP data structure */
8671 )
8672 {
8673 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPenableVarHistory", FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE) );
8674
8675 SCIPstatEnableVarHistory(scip->stat);
8676 }
8677
8678 /** disables the collection of any statistic for a variable
8679 *
8680 * @pre This method can be called if @p scip is in one of the following stages:
8681 * - \ref SCIP_STAGE_PROBLEM
8682 * - \ref SCIP_STAGE_INITPRESOLVE
8683 * - \ref SCIP_STAGE_PRESOLVING
8684 * - \ref SCIP_STAGE_EXITPRESOLVE
8685 * - \ref SCIP_STAGE_SOLVING
8686 * - \ref SCIP_STAGE_SOLVED
8687 */
SCIPdisableVarHistory(SCIP * scip)8688 void SCIPdisableVarHistory(
8689 SCIP* scip /**< SCIP data structure */
8690 )
8691 {
8692 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPdisableVarHistory", FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE) );
8693
8694 SCIPstatDisableVarHistory(scip->stat);
8695 }
8696
8697 /** updates the pseudo costs of the given variable and the global pseudo costs after a change of "solvaldelta" in the
8698 * variable's solution value and resulting change of "objdelta" in the in the LP's objective value;
8699 * the update is ignored, if the objective value difference is infinite
8700 *
8701 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
8702 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
8703 *
8704 * @pre This method can be called if @p scip is in one of the following stages:
8705 * - \ref SCIP_STAGE_SOLVING
8706 * - \ref SCIP_STAGE_SOLVED
8707 */
SCIPupdateVarPseudocost(SCIP * scip,SCIP_VAR * var,SCIP_Real solvaldelta,SCIP_Real objdelta,SCIP_Real weight)8708 SCIP_RETCODE SCIPupdateVarPseudocost(
8709 SCIP* scip, /**< SCIP data structure */
8710 SCIP_VAR* var, /**< problem variable */
8711 SCIP_Real solvaldelta, /**< difference of variable's new LP value - old LP value */
8712 SCIP_Real objdelta, /**< difference of new LP's objective value - old LP's objective value */
8713 SCIP_Real weight /**< weight in (0,1] of this update in pseudo cost sum */
8714 )
8715 {
8716 SCIP_CALL( SCIPcheckStage(scip, "SCIPupdateVarPseudocost", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE) );
8717
8718 if( !SCIPsetIsInfinity(scip->set, 2*objdelta) ) /* differences infinity - eps should also be treated as infinity */
8719 {
8720 if( scip->set->branch_divingpscost || (!scip->lp->diving && !SCIPtreeProbing(scip->tree)) )
8721 {
8722 SCIP_CALL( SCIPvarUpdatePseudocost(var, scip->set, scip->stat, solvaldelta, objdelta, weight) );
8723 }
8724 }
8725
8726 return SCIP_OKAY;
8727 }
8728
8729 /** gets the variable's pseudo cost value for the given change of the variable's LP value
8730 *
8731 * @return the variable's pseudo cost value for the given change of the variable's LP value
8732 *
8733 * @pre This method can be called if @p scip is in one of the following stages:
8734 * - \ref SCIP_STAGE_INITPRESOLVE
8735 * - \ref SCIP_STAGE_PRESOLVING
8736 * - \ref SCIP_STAGE_EXITPRESOLVE
8737 * - \ref SCIP_STAGE_PRESOLVED
8738 * - \ref SCIP_STAGE_INITSOLVE
8739 * - \ref SCIP_STAGE_SOLVING
8740 * - \ref SCIP_STAGE_SOLVED
8741 */
SCIPgetVarPseudocostVal(SCIP * scip,SCIP_VAR * var,SCIP_Real solvaldelta)8742 SCIP_Real SCIPgetVarPseudocostVal(
8743 SCIP* scip, /**< SCIP data structure */
8744 SCIP_VAR* var, /**< problem variable */
8745 SCIP_Real solvaldelta /**< difference of variable's new LP value - old LP value */
8746 )
8747 {
8748 assert( var->scip == scip );
8749
8750 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetVarPseudocostVal", FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE) );
8751
8752 return SCIPvarGetPseudocost(var, scip->stat, solvaldelta);
8753 }
8754
8755 /** gets the variable's pseudo cost value for the given change of the variable's LP value,
8756 * only using the pseudo cost information of the current run
8757 *
8758 * @return the variable's pseudo cost value for the given change of the variable's LP value,
8759 * only using the pseudo cost information of the current run
8760 *
8761 * @pre This method can be called if @p scip is in one of the following stages:
8762 * - \ref SCIP_STAGE_INITPRESOLVE
8763 * - \ref SCIP_STAGE_PRESOLVING
8764 * - \ref SCIP_STAGE_EXITPRESOLVE
8765 * - \ref SCIP_STAGE_PRESOLVED
8766 * - \ref SCIP_STAGE_INITSOLVE
8767 * - \ref SCIP_STAGE_SOLVING
8768 * - \ref SCIP_STAGE_SOLVED
8769 */
SCIPgetVarPseudocostValCurrentRun(SCIP * scip,SCIP_VAR * var,SCIP_Real solvaldelta)8770 SCIP_Real SCIPgetVarPseudocostValCurrentRun(
8771 SCIP* scip, /**< SCIP data structure */
8772 SCIP_VAR* var, /**< problem variable */
8773 SCIP_Real solvaldelta /**< difference of variable's new LP value - old LP value */
8774 )
8775 {
8776 assert( var->scip == scip );
8777
8778 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetVarPseudocostValCurrentRun", FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE) );
8779
8780 return SCIPvarGetPseudocostCurrentRun(var, scip->stat, solvaldelta);
8781 }
8782
8783 /** gets the variable's pseudo cost value for the given direction
8784 *
8785 * @return the variable's pseudo cost value for the given direction
8786 *
8787 * @pre This method can be called if @p scip is in one of the following stages:
8788 * - \ref SCIP_STAGE_INITPRESOLVE
8789 * - \ref SCIP_STAGE_PRESOLVING
8790 * - \ref SCIP_STAGE_EXITPRESOLVE
8791 * - \ref SCIP_STAGE_PRESOLVED
8792 * - \ref SCIP_STAGE_INITSOLVE
8793 * - \ref SCIP_STAGE_SOLVING
8794 * - \ref SCIP_STAGE_SOLVED
8795 */
SCIPgetVarPseudocost(SCIP * scip,SCIP_VAR * var,SCIP_BRANCHDIR dir)8796 SCIP_Real SCIPgetVarPseudocost(
8797 SCIP* scip, /**< SCIP data structure */
8798 SCIP_VAR* var, /**< problem variable */
8799 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
8800 )
8801 {
8802 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetVarPseudocost", FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE) );
8803 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
8804 assert(var->scip == scip);
8805
8806 return SCIPvarGetPseudocost(var, scip->stat, dir == SCIP_BRANCHDIR_DOWNWARDS ? -1.0 : 1.0);
8807 }
8808
8809 /** gets the variable's pseudo cost value for the given direction,
8810 * only using the pseudo cost information of the current run
8811 *
8812 * @return the variable's pseudo cost value for the given direction,
8813 * only using the pseudo cost information of the current run
8814 *
8815 * @pre This method can be called if @p scip is in one of the following stages:
8816 * - \ref SCIP_STAGE_INITPRESOLVE
8817 * - \ref SCIP_STAGE_PRESOLVING
8818 * - \ref SCIP_STAGE_EXITPRESOLVE
8819 * - \ref SCIP_STAGE_PRESOLVED
8820 * - \ref SCIP_STAGE_INITSOLVE
8821 * - \ref SCIP_STAGE_SOLVING
8822 * - \ref SCIP_STAGE_SOLVED
8823 */
SCIPgetVarPseudocostCurrentRun(SCIP * scip,SCIP_VAR * var,SCIP_BRANCHDIR dir)8824 SCIP_Real SCIPgetVarPseudocostCurrentRun(
8825 SCIP* scip, /**< SCIP data structure */
8826 SCIP_VAR* var, /**< problem variable */
8827 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
8828 )
8829 {
8830 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetVarPseudocostCurrentRun", FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE) );
8831 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
8832 assert(var->scip == scip);
8833
8834 return SCIPvarGetPseudocostCurrentRun(var, scip->stat, dir == SCIP_BRANCHDIR_DOWNWARDS ? -1.0 : 1.0);
8835 }
8836
8837 /** gets the variable's (possible fractional) number of pseudo cost updates for the given direction
8838 *
8839 * @return the variable's (possible fractional) number of pseudo cost updates for the given direction
8840 *
8841 * @pre This method can be called if @p scip is in one of the following stages:
8842 * - \ref SCIP_STAGE_INITPRESOLVE
8843 * - \ref SCIP_STAGE_PRESOLVING
8844 * - \ref SCIP_STAGE_EXITPRESOLVE
8845 * - \ref SCIP_STAGE_PRESOLVED
8846 * - \ref SCIP_STAGE_INITSOLVE
8847 * - \ref SCIP_STAGE_SOLVING
8848 * - \ref SCIP_STAGE_SOLVED
8849 */
SCIPgetVarPseudocostCount(SCIP * scip,SCIP_VAR * var,SCIP_BRANCHDIR dir)8850 SCIP_Real SCIPgetVarPseudocostCount(
8851 SCIP* scip, /**< SCIP data structure */
8852 SCIP_VAR* var, /**< problem variable */
8853 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
8854 )
8855 {
8856 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetVarPseudocostCount", FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE) );
8857 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
8858 assert(var->scip == scip);
8859
8860 return SCIPvarGetPseudocostCount(var, dir);
8861 }
8862
8863 /** gets the variable's (possible fractional) number of pseudo cost updates for the given direction,
8864 * only using the pseudo cost information of the current run
8865 *
8866 * @return the variable's (possible fractional) number of pseudo cost updates for the given direction,
8867 * only using the pseudo cost information of the current run
8868 *
8869 * @pre This method can be called if @p scip is in one of the following stages:
8870 * - \ref SCIP_STAGE_INITPRESOLVE
8871 * - \ref SCIP_STAGE_PRESOLVING
8872 * - \ref SCIP_STAGE_EXITPRESOLVE
8873 * - \ref SCIP_STAGE_PRESOLVED
8874 * - \ref SCIP_STAGE_INITSOLVE
8875 * - \ref SCIP_STAGE_SOLVING
8876 * - \ref SCIP_STAGE_SOLVED
8877 */
SCIPgetVarPseudocostCountCurrentRun(SCIP * scip,SCIP_VAR * var,SCIP_BRANCHDIR dir)8878 SCIP_Real SCIPgetVarPseudocostCountCurrentRun(
8879 SCIP* scip, /**< SCIP data structure */
8880 SCIP_VAR* var, /**< problem variable */
8881 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
8882 )
8883 {
8884 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetVarPseudocostCountCurrentRun", FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE) );
8885 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
8886 assert(var->scip == scip);
8887
8888 return SCIPvarGetPseudocostCountCurrentRun(var, dir);
8889 }
8890
8891 /** get pseudo cost variance of the variable, either for entire solve or only for current branch and bound run
8892 *
8893 * @return returns the (corrected) variance of pseudo code information collected so far.
8894 *
8895 * @pre This method can be called if @p scip is in one of the following stages:
8896 * - \ref SCIP_STAGE_INITPRESOLVE
8897 * - \ref SCIP_STAGE_PRESOLVING
8898 * - \ref SCIP_STAGE_EXITPRESOLVE
8899 * - \ref SCIP_STAGE_PRESOLVED
8900 * - \ref SCIP_STAGE_INITSOLVE
8901 * - \ref SCIP_STAGE_SOLVING
8902 * - \ref SCIP_STAGE_SOLVED
8903 */
SCIPgetVarPseudocostVariance(SCIP * scip,SCIP_VAR * var,SCIP_BRANCHDIR dir,SCIP_Bool onlycurrentrun)8904 SCIP_Real SCIPgetVarPseudocostVariance(
8905 SCIP* scip, /**< SCIP data structure */
8906 SCIP_VAR* var, /**< problem variable */
8907 SCIP_BRANCHDIR dir, /**< branching direction (downwards, or upwards) */
8908 SCIP_Bool onlycurrentrun /**< only for pseudo costs of current branch and bound run */
8909 )
8910 {
8911 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetVarPseudocostVariance", FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE) );
8912 assert(dir == SCIP_BRANCHDIR_DOWNWARDS || dir == SCIP_BRANCHDIR_UPWARDS);
8913 assert(var->scip == scip);
8914
8915 return SCIPvarGetPseudocostVariance(var, dir, onlycurrentrun);
8916 }
8917
8918 /** calculates a confidence bound for this variable under the assumption of normally distributed pseudo costs
8919 *
8920 * The confidence bound \f$ \theta \geq 0\f$ denotes the interval borders \f$ [X - \theta, \ X + \theta]\f$, which contains
8921 * the true pseudo costs of the variable, i.e., the expected value of the normal distribution, with a probability
8922 * of 2 * clevel - 1.
8923 *
8924 * @return value of confidence bound for this variable
8925 */
SCIPcalculatePscostConfidenceBound(SCIP * scip,SCIP_VAR * var,SCIP_BRANCHDIR dir,SCIP_Bool onlycurrentrun,SCIP_CONFIDENCELEVEL clevel)8926 SCIP_Real SCIPcalculatePscostConfidenceBound(
8927 SCIP* scip, /**< SCIP data structure */
8928 SCIP_VAR* var, /**< variable in question */
8929 SCIP_BRANCHDIR dir, /**< the branching direction for the confidence bound */
8930 SCIP_Bool onlycurrentrun, /**< should only the current run be taken into account */
8931 SCIP_CONFIDENCELEVEL clevel /**< confidence level for the interval */
8932 )
8933 {
8934 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPcalculatePscostConfidenceBound", FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE) );
8935
8936 return SCIPvarCalcPscostConfidenceBound(var, scip->set, dir, onlycurrentrun, clevel);
8937 }
8938
8939 /** check if variable pseudo-costs have a significant difference in location. The significance depends on
8940 * the choice of \p clevel and on the kind of tested hypothesis. The one-sided hypothesis, which
8941 * should be rejected, is that fracy * mu_y >= fracx * mu_x, where mu_y and mu_x denote the
8942 * unknown location means of the underlying pseudo-cost distributions of x and y.
8943 *
8944 * This method is applied best if variable x has a better pseudo-cost score than y. The method hypothesizes that y were actually
8945 * better than x (despite the current information), meaning that y can be expected to yield branching
8946 * decisions as least as good as x in the long run. If the method returns TRUE, the current history information is
8947 * sufficient to safely rely on the alternative hypothesis that x yields indeed a better branching score (on average)
8948 * than y.
8949 *
8950 * @note The order of x and y matters for the one-sided hypothesis
8951 *
8952 * @note set \p onesided to FALSE if you are not sure which variable is better. The hypothesis tested then reads
8953 * fracy * mu_y == fracx * mu_x vs the alternative hypothesis fracy * mu_y != fracx * mu_x.
8954 *
8955 * @return TRUE if the hypothesis can be safely rejected at the given confidence level
8956 */
SCIPsignificantVarPscostDifference(SCIP * scip,SCIP_VAR * varx,SCIP_Real fracx,SCIP_VAR * vary,SCIP_Real fracy,SCIP_BRANCHDIR dir,SCIP_CONFIDENCELEVEL clevel,SCIP_Bool onesided)8957 SCIP_Bool SCIPsignificantVarPscostDifference(
8958 SCIP* scip, /**< SCIP data structure */
8959 SCIP_VAR* varx, /**< variable x */
8960 SCIP_Real fracx, /**< the fractionality of variable x */
8961 SCIP_VAR* vary, /**< variable y */
8962 SCIP_Real fracy, /**< the fractionality of variable y */
8963 SCIP_BRANCHDIR dir, /**< branching direction */
8964 SCIP_CONFIDENCELEVEL clevel, /**< confidence level for rejecting hypothesis */
8965 SCIP_Bool onesided /**< should a one-sided hypothesis y >= x be tested? */
8966 )
8967 {
8968 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPsignificantVarPscostDifference", FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE) );
8969
8970 return SCIPvarSignificantPscostDifference(scip->set, scip->stat, varx, fracx, vary, fracy, dir, clevel, onesided);
8971 }
8972
8973 /** tests at a given confidence level whether the variable pseudo-costs only have a small probability to
8974 * exceed a \p threshold. This is useful to determine if past observations provide enough evidence
8975 * to skip an expensive strong-branching step if there is already a candidate that has been proven to yield an improvement
8976 * of at least \p threshold.
8977 *
8978 * @note use \p clevel to adjust the level of confidence. For SCIP_CONFIDENCELEVEL_MIN, the method returns TRUE if
8979 * the estimated probability to exceed \p threshold is less than 25 %.
8980 *
8981 * @see SCIP_Confidencelevel for a list of available levels. The used probability limits refer to the one-sided levels
8982 * of confidence.
8983 *
8984 * @return TRUE if the variable pseudo-cost probabilistic model is likely to be smaller than \p threshold
8985 * at the given confidence level \p clevel.
8986 */
SCIPpscostThresholdProbabilityTest(SCIP * scip,SCIP_VAR * var,SCIP_Real frac,SCIP_Real threshold,SCIP_BRANCHDIR dir,SCIP_CONFIDENCELEVEL clevel)8987 SCIP_Bool SCIPpscostThresholdProbabilityTest(
8988 SCIP* scip, /**< SCIP data structure */
8989 SCIP_VAR* var, /**< variable x */
8990 SCIP_Real frac, /**< the fractionality of variable x */
8991 SCIP_Real threshold, /**< the threshold to test against */
8992 SCIP_BRANCHDIR dir, /**< branching direction */
8993 SCIP_CONFIDENCELEVEL clevel /**< confidence level for rejecting hypothesis */
8994 )
8995 {
8996 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPpscostThresholdProbabilityTest", FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE) );
8997
8998 return SCIPvarPscostThresholdProbabilityTest(scip->set, scip->stat, var, frac, threshold, dir, clevel);
8999 }
9000
9001 /** check if the current pseudo cost relative error in a direction violates the given threshold. The Relative
9002 * Error is calculated at a specific confidence level
9003 *
9004 * @return TRUE if relative error in variable pseudo costs is smaller than \p threshold
9005 */
SCIPisVarPscostRelerrorReliable(SCIP * scip,SCIP_VAR * var,SCIP_Real threshold,SCIP_CONFIDENCELEVEL clevel)9006 SCIP_Bool SCIPisVarPscostRelerrorReliable(
9007 SCIP* scip, /**< SCIP data structure */
9008 SCIP_VAR* var, /**< variable in question */
9009 SCIP_Real threshold, /**< threshold for relative errors to be considered reliable (enough) */
9010 SCIP_CONFIDENCELEVEL clevel /**< a given confidence level */
9011 )
9012 {
9013 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPisVarPscostRelerrorReliable", FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE) );
9014
9015 return SCIPvarIsPscostRelerrorReliable(var, scip->set, scip->stat, threshold, clevel);
9016 }
9017
9018 /** gets the variable's pseudo cost score value for the given LP solution value
9019 *
9020 * @return the variable's pseudo cost score value for the given LP solution value
9021 *
9022 * @pre This method can be called if @p scip is in one of the following stages:
9023 * - \ref SCIP_STAGE_INITPRESOLVE
9024 * - \ref SCIP_STAGE_PRESOLVING
9025 * - \ref SCIP_STAGE_EXITPRESOLVE
9026 * - \ref SCIP_STAGE_PRESOLVED
9027 * - \ref SCIP_STAGE_INITSOLVE
9028 * - \ref SCIP_STAGE_SOLVING
9029 * - \ref SCIP_STAGE_SOLVED
9030 */
SCIPgetVarPseudocostScore(SCIP * scip,SCIP_VAR * var,SCIP_Real solval)9031 SCIP_Real SCIPgetVarPseudocostScore(
9032 SCIP* scip, /**< SCIP data structure */
9033 SCIP_VAR* var, /**< problem variable */
9034 SCIP_Real solval /**< variable's LP solution value */
9035 )
9036 {
9037 SCIP_Real downsol;
9038 SCIP_Real upsol;
9039 SCIP_Real pscostdown;
9040 SCIP_Real pscostup;
9041
9042 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetVarPseudocostScore", FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE) );
9043
9044 assert( var->scip == scip );
9045
9046 downsol = SCIPsetFeasCeil(scip->set, solval-1.0);
9047 upsol = SCIPsetFeasFloor(scip->set, solval+1.0);
9048 pscostdown = SCIPvarGetPseudocost(var, scip->stat, downsol-solval);
9049 pscostup = SCIPvarGetPseudocost(var, scip->stat, upsol-solval);
9050
9051 return SCIPbranchGetScore(scip->set, var, pscostdown, pscostup);
9052 }
9053
9054 /** gets the variable's pseudo cost score value for the given LP solution value,
9055 * only using the pseudo cost information of the current run
9056 *
9057 * @return the variable's pseudo cost score value for the given LP solution value,
9058 * only using the pseudo cost information of the current run
9059 *
9060 * @pre This method can be called if @p scip is in one of the following stages:
9061 * - \ref SCIP_STAGE_INITPRESOLVE
9062 * - \ref SCIP_STAGE_PRESOLVING
9063 * - \ref SCIP_STAGE_EXITPRESOLVE
9064 * - \ref SCIP_STAGE_PRESOLVED
9065 * - \ref SCIP_STAGE_INITSOLVE
9066 * - \ref SCIP_STAGE_SOLVING
9067 * - \ref SCIP_STAGE_SOLVED
9068 */
SCIPgetVarPseudocostScoreCurrentRun(SCIP * scip,SCIP_VAR * var,SCIP_Real solval)9069 SCIP_Real SCIPgetVarPseudocostScoreCurrentRun(
9070 SCIP* scip, /**< SCIP data structure */
9071 SCIP_VAR* var, /**< problem variable */
9072 SCIP_Real solval /**< variable's LP solution value */
9073 )
9074 {
9075 SCIP_Real downsol;
9076 SCIP_Real upsol;
9077 SCIP_Real pscostdown;
9078 SCIP_Real pscostup;
9079
9080 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetVarPseudocostScoreCurrentRun", FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE) );
9081
9082 assert( var->scip == scip );
9083
9084 downsol = SCIPsetFeasCeil(scip->set, solval-1.0);
9085 upsol = SCIPsetFeasFloor(scip->set, solval+1.0);
9086 pscostdown = SCIPvarGetPseudocostCurrentRun(var, scip->stat, downsol-solval);
9087 pscostup = SCIPvarGetPseudocostCurrentRun(var, scip->stat, upsol-solval);
9088
9089 return SCIPbranchGetScore(scip->set, var, pscostdown, pscostup);
9090 }
9091
9092 /** returns the variable's VSIDS value
9093 *
9094 * @return the variable's VSIDS value
9095 *
9096 * @pre This method can be called if @p scip is in one of the following stages:
9097 * - \ref SCIP_STAGE_INITPRESOLVE
9098 * - \ref SCIP_STAGE_PRESOLVING
9099 * - \ref SCIP_STAGE_EXITPRESOLVE
9100 * - \ref SCIP_STAGE_PRESOLVED
9101 * - \ref SCIP_STAGE_INITSOLVE
9102 * - \ref SCIP_STAGE_SOLVING
9103 * - \ref SCIP_STAGE_SOLVED
9104 */
SCIPgetVarVSIDS(SCIP * scip,SCIP_VAR * var,SCIP_BRANCHDIR dir)9105 SCIP_Real SCIPgetVarVSIDS(
9106 SCIP* scip, /**< SCIP data structure */
9107 SCIP_VAR* var, /**< problem variable */
9108 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
9109 )
9110 {
9111 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetVarVSIDS", FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE) );
9112
9113 assert( var->scip == scip );
9114
9115 if( dir != SCIP_BRANCHDIR_DOWNWARDS && dir != SCIP_BRANCHDIR_UPWARDS )
9116 {
9117 SCIPerrorMessage("invalid branching direction %d when asking for VSIDS value\n", dir);
9118 return SCIP_INVALID;
9119 }
9120
9121 return SCIPvarGetVSIDS(var, scip->stat, dir);
9122 }
9123
9124 /** returns the variable's VSIDS value only using conflicts of the current run
9125 *
9126 * @return the variable's VSIDS value only using conflicts of the current run
9127 *
9128 * @pre This method can be called if @p scip is in one of the following stages:
9129 * - \ref SCIP_STAGE_INITPRESOLVE
9130 * - \ref SCIP_STAGE_PRESOLVING
9131 * - \ref SCIP_STAGE_EXITPRESOLVE
9132 * - \ref SCIP_STAGE_PRESOLVED
9133 * - \ref SCIP_STAGE_INITSOLVE
9134 * - \ref SCIP_STAGE_SOLVING
9135 * - \ref SCIP_STAGE_SOLVED
9136 */
SCIPgetVarVSIDSCurrentRun(SCIP * scip,SCIP_VAR * var,SCIP_BRANCHDIR dir)9137 SCIP_Real SCIPgetVarVSIDSCurrentRun(
9138 SCIP* scip, /**< SCIP data structure */
9139 SCIP_VAR* var, /**< problem variable */
9140 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
9141 )
9142 {
9143 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetVarVSIDSCurrentRun", FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE) );
9144
9145 assert( var->scip == scip );
9146
9147 if( dir != SCIP_BRANCHDIR_DOWNWARDS && dir != SCIP_BRANCHDIR_UPWARDS )
9148 {
9149 SCIPerrorMessage("invalid branching direction %d when asking for VSIDS value\n", dir);
9150 return SCIP_INVALID;
9151 }
9152
9153 return SCIPvarGetVSIDSCurrentRun(var, scip->stat, dir);
9154 }
9155
9156 /** returns the variable's conflict score value
9157 *
9158 * @return the variable's conflict score value
9159 *
9160 * @pre This method can be called if @p scip is in one of the following stages:
9161 * - \ref SCIP_STAGE_INITPRESOLVE
9162 * - \ref SCIP_STAGE_PRESOLVING
9163 * - \ref SCIP_STAGE_EXITPRESOLVE
9164 * - \ref SCIP_STAGE_PRESOLVED
9165 * - \ref SCIP_STAGE_INITSOLVE
9166 * - \ref SCIP_STAGE_SOLVING
9167 * - \ref SCIP_STAGE_SOLVED
9168 */
SCIPgetVarConflictScore(SCIP * scip,SCIP_VAR * var)9169 SCIP_Real SCIPgetVarConflictScore(
9170 SCIP* scip, /**< SCIP data structure */
9171 SCIP_VAR* var /**< problem variable */
9172 )
9173 {
9174 SCIP_Real downscore;
9175 SCIP_Real upscore;
9176
9177 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetVarConflictScore", FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE) );
9178
9179 assert( var->scip == scip );
9180
9181 downscore = SCIPvarGetVSIDS(var, scip->stat, SCIP_BRANCHDIR_DOWNWARDS);
9182 upscore = SCIPvarGetVSIDS(var, scip->stat, SCIP_BRANCHDIR_UPWARDS);
9183
9184 return SCIPbranchGetScore(scip->set, var, downscore, upscore);
9185 }
9186
9187 /** returns the variable's conflict score value only using conflicts of the current run
9188 *
9189 * @return the variable's conflict score value only using conflicts of the current run
9190 *
9191 * @pre This method can be called if @p scip is in one of the following stages:
9192 * - \ref SCIP_STAGE_INITPRESOLVE
9193 * - \ref SCIP_STAGE_PRESOLVING
9194 * - \ref SCIP_STAGE_EXITPRESOLVE
9195 * - \ref SCIP_STAGE_PRESOLVED
9196 * - \ref SCIP_STAGE_INITSOLVE
9197 * - \ref SCIP_STAGE_SOLVING
9198 * - \ref SCIP_STAGE_SOLVED
9199 */
SCIPgetVarConflictScoreCurrentRun(SCIP * scip,SCIP_VAR * var)9200 SCIP_Real SCIPgetVarConflictScoreCurrentRun(
9201 SCIP* scip, /**< SCIP data structure */
9202 SCIP_VAR* var /**< problem variable */
9203 )
9204 {
9205 SCIP_Real downscore;
9206 SCIP_Real upscore;
9207
9208 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetVarConflictScoreCurrentRun", FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE) );
9209
9210 assert( var->scip == scip );
9211
9212 downscore = SCIPvarGetVSIDSCurrentRun(var, scip->stat, SCIP_BRANCHDIR_DOWNWARDS);
9213 upscore = SCIPvarGetVSIDSCurrentRun(var, scip->stat, SCIP_BRANCHDIR_UPWARDS);
9214
9215 return SCIPbranchGetScore(scip->set, var, downscore, upscore);
9216 }
9217
9218 /** returns the variable's conflict length score
9219 *
9220 * @return the variable's conflict length score
9221 *
9222 * @pre This method can be called if @p scip is in one of the following stages:
9223 * - \ref SCIP_STAGE_INITPRESOLVE
9224 * - \ref SCIP_STAGE_PRESOLVING
9225 * - \ref SCIP_STAGE_EXITPRESOLVE
9226 * - \ref SCIP_STAGE_PRESOLVED
9227 * - \ref SCIP_STAGE_INITSOLVE
9228 * - \ref SCIP_STAGE_SOLVING
9229 * - \ref SCIP_STAGE_SOLVED
9230 */
SCIPgetVarConflictlengthScore(SCIP * scip,SCIP_VAR * var)9231 SCIP_Real SCIPgetVarConflictlengthScore(
9232 SCIP* scip, /**< SCIP data structure */
9233 SCIP_VAR* var /**< problem variable */
9234 )
9235 {
9236 SCIP_Real downscore;
9237 SCIP_Real upscore;
9238
9239 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetVarConflictlengthScore", FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE) );
9240
9241 assert( var->scip == scip );
9242
9243 downscore = SCIPvarGetAvgConflictlength(var, SCIP_BRANCHDIR_DOWNWARDS);
9244 upscore = SCIPvarGetAvgConflictlength(var, SCIP_BRANCHDIR_UPWARDS);
9245
9246 return SCIPbranchGetScore(scip->set, var, downscore, upscore);
9247 }
9248
9249 /** returns the variable's conflict length score only using conflicts of the current run
9250 *
9251 * @return the variable's conflict length score only using conflicts of the current run
9252 *
9253 * @pre This method can be called if @p scip is in one of the following stages:
9254 * - \ref SCIP_STAGE_INITPRESOLVE
9255 * - \ref SCIP_STAGE_PRESOLVING
9256 * - \ref SCIP_STAGE_EXITPRESOLVE
9257 * - \ref SCIP_STAGE_PRESOLVED
9258 * - \ref SCIP_STAGE_INITSOLVE
9259 * - \ref SCIP_STAGE_SOLVING
9260 * - \ref SCIP_STAGE_SOLVED
9261 */
SCIPgetVarConflictlengthScoreCurrentRun(SCIP * scip,SCIP_VAR * var)9262 SCIP_Real SCIPgetVarConflictlengthScoreCurrentRun(
9263 SCIP* scip, /**< SCIP data structure */
9264 SCIP_VAR* var /**< problem variable */
9265 )
9266 {
9267 SCIP_Real downscore;
9268 SCIP_Real upscore;
9269
9270 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetVarConflictlengthScoreCurrentRun", FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE) );
9271
9272 assert( var->scip == scip );
9273
9274 downscore = SCIPvarGetAvgConflictlengthCurrentRun(var, SCIP_BRANCHDIR_DOWNWARDS);
9275 upscore = SCIPvarGetAvgConflictlengthCurrentRun(var, SCIP_BRANCHDIR_UPWARDS);
9276
9277 return SCIPbranchGetScore(scip->set, var, downscore, upscore);
9278 }
9279
9280 /** returns the variable's average conflict length
9281 *
9282 * @return the variable's average conflict length
9283 *
9284 * @pre This method can be called if @p scip is in one of the following stages:
9285 * - \ref SCIP_STAGE_INITPRESOLVE
9286 * - \ref SCIP_STAGE_PRESOLVING
9287 * - \ref SCIP_STAGE_EXITPRESOLVE
9288 * - \ref SCIP_STAGE_PRESOLVED
9289 * - \ref SCIP_STAGE_INITSOLVE
9290 * - \ref SCIP_STAGE_SOLVING
9291 * - \ref SCIP_STAGE_SOLVED
9292 */
SCIPgetVarAvgConflictlength(SCIP * scip,SCIP_VAR * var,SCIP_BRANCHDIR dir)9293 SCIP_Real SCIPgetVarAvgConflictlength(
9294 SCIP* scip, /**< SCIP data structure */
9295 SCIP_VAR* var, /**< problem variable */
9296 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
9297 )
9298 {
9299 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetVarAvgConflictlength", FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE) );
9300
9301 assert( var->scip == scip );
9302
9303 return SCIPvarGetAvgConflictlength(var, dir);
9304 }
9305
9306 /** returns the variable's average conflict length only using conflicts of the current run
9307 *
9308 * @return the variable's average conflict length only using conflicts of the current run
9309 *
9310 * @pre This method can be called if @p scip is in one of the following stages:
9311 * - \ref SCIP_STAGE_INITPRESOLVE
9312 * - \ref SCIP_STAGE_PRESOLVING
9313 * - \ref SCIP_STAGE_EXITPRESOLVE
9314 * - \ref SCIP_STAGE_PRESOLVED
9315 * - \ref SCIP_STAGE_INITSOLVE
9316 * - \ref SCIP_STAGE_SOLVING
9317 * - \ref SCIP_STAGE_SOLVED
9318 */
SCIPgetVarAvgConflictlengthCurrentRun(SCIP * scip,SCIP_VAR * var,SCIP_BRANCHDIR dir)9319 SCIP_Real SCIPgetVarAvgConflictlengthCurrentRun(
9320 SCIP* scip, /**< SCIP data structure */
9321 SCIP_VAR* var, /**< problem variable */
9322 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
9323 )
9324 {
9325 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetVarAvgConflictlengthCurrentRun", FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE) );
9326
9327 assert( var->scip == scip );
9328
9329 return SCIPvarGetAvgConflictlengthCurrentRun(var, dir);
9330 }
9331
9332 /** returns the average number of inferences found after branching on the variable in given direction;
9333 * if branching on the variable in the given direction was yet evaluated, the average number of inferences
9334 * over all variables for branching in the given direction is returned
9335 *
9336 * @return the average number of inferences found after branching on the variable in given direction
9337 *
9338 * @pre This method can be called if @p scip is in one of the following stages:
9339 * - \ref SCIP_STAGE_INITPRESOLVE
9340 * - \ref SCIP_STAGE_PRESOLVING
9341 * - \ref SCIP_STAGE_EXITPRESOLVE
9342 * - \ref SCIP_STAGE_PRESOLVED
9343 * - \ref SCIP_STAGE_INITSOLVE
9344 * - \ref SCIP_STAGE_SOLVING
9345 * - \ref SCIP_STAGE_SOLVED
9346 */
SCIPgetVarAvgInferences(SCIP * scip,SCIP_VAR * var,SCIP_BRANCHDIR dir)9347 SCIP_Real SCIPgetVarAvgInferences(
9348 SCIP* scip, /**< SCIP data structure */
9349 SCIP_VAR* var, /**< problem variable */
9350 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
9351 )
9352 {
9353 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetVarAvgInferences", FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE) );
9354
9355 assert( var->scip == scip );
9356
9357 return SCIPvarGetAvgInferences(var, scip->stat, dir);
9358 }
9359
9360 /** returns the average number of inferences found after branching on the variable in given direction in the current run;
9361 * if branching on the variable in the given direction was yet evaluated, the average number of inferences
9362 * over all variables for branching in the given direction is returned
9363 *
9364 * @return the average number of inferences found after branching on the variable in given direction in the current run
9365 *
9366 * @pre This method can be called if @p scip is in one of the following stages:
9367 * - \ref SCIP_STAGE_INITPRESOLVE
9368 * - \ref SCIP_STAGE_PRESOLVING
9369 * - \ref SCIP_STAGE_EXITPRESOLVE
9370 * - \ref SCIP_STAGE_PRESOLVED
9371 * - \ref SCIP_STAGE_INITSOLVE
9372 * - \ref SCIP_STAGE_SOLVING
9373 * - \ref SCIP_STAGE_SOLVED
9374 */
SCIPgetVarAvgInferencesCurrentRun(SCIP * scip,SCIP_VAR * var,SCIP_BRANCHDIR dir)9375 SCIP_Real SCIPgetVarAvgInferencesCurrentRun(
9376 SCIP* scip, /**< SCIP data structure */
9377 SCIP_VAR* var, /**< problem variable */
9378 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
9379 )
9380 {
9381 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetVarAvgInferencesCurrentRun", FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE) );
9382
9383 assert( var->scip == scip );
9384
9385 return SCIPvarGetAvgInferencesCurrentRun(var, scip->stat, dir);
9386 }
9387
9388 /** returns the variable's average inference score value
9389 *
9390 * @return the variable's average inference score value
9391 *
9392 * @pre This method can be called if @p scip is in one of the following stages:
9393 * - \ref SCIP_STAGE_INITPRESOLVE
9394 * - \ref SCIP_STAGE_PRESOLVING
9395 * - \ref SCIP_STAGE_EXITPRESOLVE
9396 * - \ref SCIP_STAGE_PRESOLVED
9397 * - \ref SCIP_STAGE_INITSOLVE
9398 * - \ref SCIP_STAGE_SOLVING
9399 * - \ref SCIP_STAGE_SOLVED
9400 */
SCIPgetVarAvgInferenceScore(SCIP * scip,SCIP_VAR * var)9401 SCIP_Real SCIPgetVarAvgInferenceScore(
9402 SCIP* scip, /**< SCIP data structure */
9403 SCIP_VAR* var /**< problem variable */
9404 )
9405 {
9406 SCIP_Real inferdown;
9407 SCIP_Real inferup;
9408
9409 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetVarAvgInferenceScore", FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE) );
9410
9411 assert( var->scip == scip );
9412
9413 inferdown = SCIPvarGetAvgInferences(var, scip->stat, SCIP_BRANCHDIR_DOWNWARDS);
9414 inferup = SCIPvarGetAvgInferences(var, scip->stat, SCIP_BRANCHDIR_UPWARDS);
9415
9416 return SCIPbranchGetScore(scip->set, var, inferdown, inferup);
9417 }
9418
9419 /** returns the variable's average inference score value only using inferences of the current run
9420 *
9421 * @return the variable's average inference score value only using inferences of the current run
9422 *
9423 * @pre This method can be called if @p scip is in one of the following stages:
9424 * - \ref SCIP_STAGE_INITPRESOLVE
9425 * - \ref SCIP_STAGE_PRESOLVING
9426 * - \ref SCIP_STAGE_EXITPRESOLVE
9427 * - \ref SCIP_STAGE_PRESOLVED
9428 * - \ref SCIP_STAGE_INITSOLVE
9429 * - \ref SCIP_STAGE_SOLVING
9430 * - \ref SCIP_STAGE_SOLVED
9431 */
SCIPgetVarAvgInferenceScoreCurrentRun(SCIP * scip,SCIP_VAR * var)9432 SCIP_Real SCIPgetVarAvgInferenceScoreCurrentRun(
9433 SCIP* scip, /**< SCIP data structure */
9434 SCIP_VAR* var /**< problem variable */
9435 )
9436 {
9437 SCIP_Real inferdown;
9438 SCIP_Real inferup;
9439
9440 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetVarAvgInferenceScoreCurrentRun", FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE) );
9441
9442 assert( var->scip == scip );
9443
9444 inferdown = SCIPvarGetAvgInferencesCurrentRun(var, scip->stat, SCIP_BRANCHDIR_DOWNWARDS);
9445 inferup = SCIPvarGetAvgInferencesCurrentRun(var, scip->stat, SCIP_BRANCHDIR_UPWARDS);
9446
9447 return SCIPbranchGetScore(scip->set, var, inferdown, inferup);
9448 }
9449
9450 /** initializes the upwards and downwards pseudocosts, conflict scores, conflict lengths, inference scores, cutoff scores
9451 * of a variable to the given values
9452 *
9453 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
9454 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
9455 *
9456 * @pre This method can be called if @p scip is in one of the following stages:
9457 * - \ref SCIP_STAGE_TRANSFORMED
9458 * - \ref SCIP_STAGE_INITPRESOLVE
9459 * - \ref SCIP_STAGE_PRESOLVING
9460 * - \ref SCIP_STAGE_EXITPRESOLVE
9461 * - \ref SCIP_STAGE_PRESOLVED
9462 * - \ref SCIP_STAGE_INITSOLVE
9463 * - \ref SCIP_STAGE_SOLVING
9464 */
SCIPinitVarBranchStats(SCIP * scip,SCIP_VAR * var,SCIP_Real downpscost,SCIP_Real uppscost,SCIP_Real downvsids,SCIP_Real upvsids,SCIP_Real downconflen,SCIP_Real upconflen,SCIP_Real downinfer,SCIP_Real upinfer,SCIP_Real downcutoff,SCIP_Real upcutoff)9465 SCIP_RETCODE SCIPinitVarBranchStats(
9466 SCIP* scip, /**< SCIP data structure */
9467 SCIP_VAR* var, /**< variable which should be initialized */
9468 SCIP_Real downpscost, /**< value to which pseudocosts for downwards branching should be initialized */
9469 SCIP_Real uppscost, /**< value to which pseudocosts for upwards branching should be initialized */
9470 SCIP_Real downvsids, /**< value to which VSIDS score for downwards branching should be initialized */
9471 SCIP_Real upvsids, /**< value to which VSIDS score for upwards branching should be initialized */
9472 SCIP_Real downconflen, /**< value to which conflict length score for downwards branching should be initialized */
9473 SCIP_Real upconflen, /**< value to which conflict length score for upwards branching should be initialized */
9474 SCIP_Real downinfer, /**< value to which inference counter for downwards branching should be initialized */
9475 SCIP_Real upinfer, /**< value to which inference counter for upwards branching should be initialized */
9476 SCIP_Real downcutoff, /**< value to which cutoff counter for downwards branching should be initialized */
9477 SCIP_Real upcutoff /**< value to which cutoff counter for upwards branching should be initialized */
9478 )
9479 {
9480 SCIP_CALL( SCIPcheckStage(scip, "SCIPinitVarBranchStats", FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
9481
9482 assert(downpscost >= 0.0 && uppscost >= 0.0);
9483 assert(downvsids >= 0.0 && upvsids >= 0.0);
9484 assert(downconflen >= 0.0 && upconflen >= 0.0);
9485 assert(downinfer >= 0.0 && upinfer >= 0.0);
9486 assert(downcutoff >= 0.0 && upcutoff >= 0.0);
9487
9488 if( !SCIPisFeasZero(scip, downpscost) || !SCIPisFeasZero(scip, downvsids)
9489 || !SCIPisFeasZero(scip, downinfer) || !SCIPisFeasZero(scip, downcutoff) )
9490 {
9491 SCIP_CALL( SCIPvarIncNBranchings(var, NULL, NULL, scip->stat, SCIP_BRANCHDIR_DOWNWARDS, SCIP_UNKNOWN, 1) );
9492 SCIP_CALL( SCIPvarUpdatePseudocost(var, scip->set, scip->stat, -1.0, downpscost, 1.0) );
9493 SCIP_CALL( SCIPvarIncInferenceSum(var, NULL, NULL, scip->stat, SCIP_BRANCHDIR_DOWNWARDS, SCIP_UNKNOWN, downinfer) );
9494 SCIP_CALL( SCIPvarIncVSIDS(var, NULL, scip->set, scip->stat, SCIP_BRANCHDIR_DOWNWARDS, SCIP_UNKNOWN, downvsids) );
9495 SCIP_CALL( SCIPvarIncCutoffSum(var, NULL, NULL, scip->stat, SCIP_BRANCHDIR_DOWNWARDS, SCIP_UNKNOWN, downcutoff) );
9496 }
9497
9498 if( !SCIPisFeasZero(scip, downconflen) )
9499 {
9500 SCIP_CALL( SCIPvarIncNActiveConflicts(var, NULL, NULL, scip->stat, SCIP_BRANCHDIR_DOWNWARDS, SCIP_UNKNOWN, downconflen) );
9501 }
9502
9503 if( !SCIPisFeasZero(scip, uppscost) || !SCIPisFeasZero(scip, upvsids)
9504 || !SCIPisFeasZero(scip, upinfer) || !SCIPisFeasZero(scip, upcutoff) )
9505 {
9506 SCIP_CALL( SCIPvarIncNBranchings(var, NULL, NULL, scip->stat, SCIP_BRANCHDIR_UPWARDS, SCIP_UNKNOWN, 1) );
9507 SCIP_CALL( SCIPvarUpdatePseudocost(var, scip->set, scip->stat, 1.0, uppscost, 1.0) );
9508 SCIP_CALL( SCIPvarIncInferenceSum(var, NULL, NULL, scip->stat, SCIP_BRANCHDIR_UPWARDS, SCIP_UNKNOWN, upinfer) );
9509 SCIP_CALL( SCIPvarIncVSIDS(var, NULL, scip->set, scip->stat, SCIP_BRANCHDIR_UPWARDS, SCIP_UNKNOWN, upvsids) );
9510 SCIP_CALL( SCIPvarIncCutoffSum(var, NULL, NULL, scip->stat, SCIP_BRANCHDIR_UPWARDS, SCIP_UNKNOWN, upcutoff) );
9511 }
9512
9513 if( !SCIPisFeasZero(scip, upconflen) )
9514 {
9515 SCIP_CALL( SCIPvarIncNActiveConflicts(var, NULL, NULL, scip->stat, SCIP_BRANCHDIR_UPWARDS, SCIP_UNKNOWN, upconflen) );
9516 }
9517
9518 return SCIP_OKAY;
9519 }
9520
9521 /** initializes the upwards and downwards conflict scores, conflict lengths, inference scores, cutoff scores of a
9522 * variable w.r.t. a value by the given values (SCIP_VALUEHISTORY)
9523 *
9524 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
9525 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
9526 *
9527 * @pre This method can be called if @p scip is in one of the following stages:
9528 * - \ref SCIP_STAGE_TRANSFORMED
9529 * - \ref SCIP_STAGE_INITPRESOLVE
9530 * - \ref SCIP_STAGE_PRESOLVING
9531 * - \ref SCIP_STAGE_EXITPRESOLVE
9532 * - \ref SCIP_STAGE_PRESOLVED
9533 * - \ref SCIP_STAGE_INITSOLVE
9534 * - \ref SCIP_STAGE_SOLVING
9535 */
SCIPinitVarValueBranchStats(SCIP * scip,SCIP_VAR * var,SCIP_Real value,SCIP_Real downvsids,SCIP_Real upvsids,SCIP_Real downconflen,SCIP_Real upconflen,SCIP_Real downinfer,SCIP_Real upinfer,SCIP_Real downcutoff,SCIP_Real upcutoff)9536 SCIP_RETCODE SCIPinitVarValueBranchStats(
9537 SCIP* scip, /**< SCIP data structure */
9538 SCIP_VAR* var, /**< variable which should be initialized */
9539 SCIP_Real value, /**< domain value, or SCIP_UNKNOWN */
9540 SCIP_Real downvsids, /**< value to which VSIDS score for downwards branching should be initialized */
9541 SCIP_Real upvsids, /**< value to which VSIDS score for upwards branching should be initialized */
9542 SCIP_Real downconflen, /**< value to which conflict length score for downwards branching should be initialized */
9543 SCIP_Real upconflen, /**< value to which conflict length score for upwards branching should be initialized */
9544 SCIP_Real downinfer, /**< value to which inference counter for downwards branching should be initialized */
9545 SCIP_Real upinfer, /**< value to which inference counter for upwards branching should be initialized */
9546 SCIP_Real downcutoff, /**< value to which cutoff counter for downwards branching should be initialized */
9547 SCIP_Real upcutoff /**< value to which cutoff counter for upwards branching should be initialized */
9548 )
9549 {
9550 SCIP_CALL( SCIPcheckStage(scip, "SCIPinitVarValueBranchStats", FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
9551
9552 assert(downvsids >= 0.0 && upvsids >= 0.0);
9553 assert(downconflen >= 0.0 && upconflen >= 0.0);
9554 assert(downinfer >= 0.0 && upinfer >= 0.0);
9555 assert(downcutoff >= 0.0 && upcutoff >= 0.0);
9556
9557 if( !SCIPisFeasZero(scip, downvsids) || !SCIPisFeasZero(scip, downinfer) || !SCIPisFeasZero(scip, downcutoff) )
9558 {
9559 SCIP_CALL( SCIPvarIncNBranchings(var, SCIPblkmem(scip), scip->set, scip->stat, SCIP_BRANCHDIR_DOWNWARDS, value, 1) );
9560 SCIP_CALL( SCIPvarIncInferenceSum(var, SCIPblkmem(scip), scip->set, scip->stat, SCIP_BRANCHDIR_DOWNWARDS, value, downinfer) );
9561 SCIP_CALL( SCIPvarIncVSIDS(var, SCIPblkmem(scip), scip->set, scip->stat, SCIP_BRANCHDIR_DOWNWARDS, value, downvsids) );
9562 SCIP_CALL( SCIPvarIncCutoffSum(var, SCIPblkmem(scip), scip->set, scip->stat, SCIP_BRANCHDIR_DOWNWARDS, value, downcutoff) );
9563 }
9564
9565 if( !SCIPisFeasZero(scip, downconflen) )
9566 {
9567 SCIP_CALL( SCIPvarIncNActiveConflicts(var, SCIPblkmem(scip), scip->set, scip->stat, SCIP_BRANCHDIR_DOWNWARDS, value, downconflen) );
9568 }
9569
9570 if( !SCIPisFeasZero(scip, upvsids) || !SCIPisFeasZero(scip, upinfer) || !SCIPisFeasZero(scip, upcutoff) )
9571 {
9572 SCIP_CALL( SCIPvarIncNBranchings(var, SCIPblkmem(scip), scip->set, scip->stat, SCIP_BRANCHDIR_UPWARDS, value, 1) );
9573 SCIP_CALL( SCIPvarIncInferenceSum(var, SCIPblkmem(scip), scip->set, scip->stat, SCIP_BRANCHDIR_UPWARDS, value, upinfer) );
9574 SCIP_CALL( SCIPvarIncVSIDS(var, SCIPblkmem(scip), scip->set, scip->stat, SCIP_BRANCHDIR_UPWARDS, value, upvsids) );
9575 SCIP_CALL( SCIPvarIncCutoffSum(var, SCIPblkmem(scip), scip->set, scip->stat, SCIP_BRANCHDIR_UPWARDS, value, upcutoff) );
9576 }
9577
9578 if( !SCIPisFeasZero(scip, upconflen) )
9579 {
9580 SCIP_CALL( SCIPvarIncNActiveConflicts(var, SCIPblkmem(scip), scip->set, scip->stat, SCIP_BRANCHDIR_UPWARDS, value, upconflen) );
9581 }
9582
9583 return SCIP_OKAY;
9584 }
9585
9586 /** returns the average number of cutoffs found after branching on the variable in given direction;
9587 * if branching on the variable in the given direction was yet evaluated, the average number of cutoffs
9588 * over all variables for branching in the given direction is returned
9589 *
9590 * @return the average number of cutoffs found after branching on the variable in given direction
9591 *
9592 * @pre This method can be called if @p scip is in one of the following stages:
9593 * - \ref SCIP_STAGE_INITPRESOLVE
9594 * - \ref SCIP_STAGE_PRESOLVING
9595 * - \ref SCIP_STAGE_EXITPRESOLVE
9596 * - \ref SCIP_STAGE_PRESOLVED
9597 * - \ref SCIP_STAGE_INITSOLVE
9598 * - \ref SCIP_STAGE_SOLVING
9599 * - \ref SCIP_STAGE_SOLVED
9600 */
SCIPgetVarAvgCutoffs(SCIP * scip,SCIP_VAR * var,SCIP_BRANCHDIR dir)9601 SCIP_Real SCIPgetVarAvgCutoffs(
9602 SCIP* scip, /**< SCIP data structure */
9603 SCIP_VAR* var, /**< problem variable */
9604 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
9605 )
9606 {
9607 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetVarAvgCutoffs", FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE) );
9608
9609 assert( var->scip == scip );
9610
9611 return SCIPvarGetAvgCutoffs(var, scip->stat, dir);
9612 }
9613
9614 /** returns the average number of cutoffs found after branching on the variable in given direction in the current run;
9615 * if branching on the variable in the given direction was yet evaluated, the average number of cutoffs
9616 * over all variables for branching in the given direction is returned
9617 *
9618 * @return the average number of cutoffs found after branching on the variable in given direction in the current run
9619 *
9620 * @pre This method can be called if @p scip is in one of the following stages:
9621 * - \ref SCIP_STAGE_INITPRESOLVE
9622 * - \ref SCIP_STAGE_PRESOLVING
9623 * - \ref SCIP_STAGE_EXITPRESOLVE
9624 * - \ref SCIP_STAGE_PRESOLVED
9625 * - \ref SCIP_STAGE_INITSOLVE
9626 * - \ref SCIP_STAGE_SOLVING
9627 * - \ref SCIP_STAGE_SOLVED
9628 */
SCIPgetVarAvgCutoffsCurrentRun(SCIP * scip,SCIP_VAR * var,SCIP_BRANCHDIR dir)9629 SCIP_Real SCIPgetVarAvgCutoffsCurrentRun(
9630 SCIP* scip, /**< SCIP data structure */
9631 SCIP_VAR* var, /**< problem variable */
9632 SCIP_BRANCHDIR dir /**< branching direction (downwards, or upwards) */
9633 )
9634 {
9635 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetVarAvgCutoffsCurrentRun", FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE) );
9636
9637 assert( var->scip == scip );
9638
9639 return SCIPvarGetAvgCutoffsCurrentRun(var, scip->stat, dir);
9640 }
9641
9642 /** returns the variable's average cutoff score value
9643 *
9644 * @return the variable's average cutoff score value
9645 *
9646 * @pre This method can be called if @p scip is in one of the following stages:
9647 * - \ref SCIP_STAGE_INITPRESOLVE
9648 * - \ref SCIP_STAGE_PRESOLVING
9649 * - \ref SCIP_STAGE_EXITPRESOLVE
9650 * - \ref SCIP_STAGE_PRESOLVED
9651 * - \ref SCIP_STAGE_INITSOLVE
9652 * - \ref SCIP_STAGE_SOLVING
9653 * - \ref SCIP_STAGE_SOLVED
9654 */
SCIPgetVarAvgCutoffScore(SCIP * scip,SCIP_VAR * var)9655 SCIP_Real SCIPgetVarAvgCutoffScore(
9656 SCIP* scip, /**< SCIP data structure */
9657 SCIP_VAR* var /**< problem variable */
9658 )
9659 {
9660 SCIP_Real cutoffdown;
9661 SCIP_Real cutoffup;
9662
9663 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetVarAvgCutoffScore", FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE) );
9664
9665 assert( var->scip == scip );
9666
9667 cutoffdown = SCIPvarGetAvgCutoffs(var, scip->stat, SCIP_BRANCHDIR_DOWNWARDS);
9668 cutoffup = SCIPvarGetAvgCutoffs(var, scip->stat, SCIP_BRANCHDIR_UPWARDS);
9669
9670 return SCIPbranchGetScore(scip->set, var, cutoffdown, cutoffup);
9671 }
9672
9673 /** returns the variable's average cutoff score value, only using cutoffs of the current run
9674 *
9675 * @return the variable's average cutoff score value, only using cutoffs of the current run
9676 *
9677 * @pre This method can be called if @p scip is in one of the following stages:
9678 * - \ref SCIP_STAGE_INITPRESOLVE
9679 * - \ref SCIP_STAGE_PRESOLVING
9680 * - \ref SCIP_STAGE_EXITPRESOLVE
9681 * - \ref SCIP_STAGE_PRESOLVED
9682 * - \ref SCIP_STAGE_INITSOLVE
9683 * - \ref SCIP_STAGE_SOLVING
9684 * - \ref SCIP_STAGE_SOLVED
9685 */
SCIPgetVarAvgCutoffScoreCurrentRun(SCIP * scip,SCIP_VAR * var)9686 SCIP_Real SCIPgetVarAvgCutoffScoreCurrentRun(
9687 SCIP* scip, /**< SCIP data structure */
9688 SCIP_VAR* var /**< problem variable */
9689 )
9690 {
9691 SCIP_Real cutoffdown;
9692 SCIP_Real cutoffup;
9693
9694 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetVarAvgCutoffScoreCurrentRun", FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE) );
9695
9696 assert( var->scip == scip );
9697
9698 cutoffdown = SCIPvarGetAvgCutoffsCurrentRun(var, scip->stat, SCIP_BRANCHDIR_DOWNWARDS);
9699 cutoffup = SCIPvarGetAvgCutoffsCurrentRun(var, scip->stat, SCIP_BRANCHDIR_UPWARDS);
9700
9701 return SCIPbranchGetScore(scip->set, var, cutoffdown, cutoffup);
9702 }
9703
9704 /** returns the variable's average inference/cutoff score value, weighting the cutoffs of the variable with the given
9705 * factor
9706 *
9707 * @return the variable's average inference/cutoff score value
9708 *
9709 * @pre This method can be called if @p scip is in one of the following stages:
9710 * - \ref SCIP_STAGE_INITPRESOLVE
9711 * - \ref SCIP_STAGE_PRESOLVING
9712 * - \ref SCIP_STAGE_EXITPRESOLVE
9713 * - \ref SCIP_STAGE_PRESOLVED
9714 * - \ref SCIP_STAGE_INITSOLVE
9715 * - \ref SCIP_STAGE_SOLVING
9716 * - \ref SCIP_STAGE_SOLVED
9717 */
SCIPgetVarAvgInferenceCutoffScore(SCIP * scip,SCIP_VAR * var,SCIP_Real cutoffweight)9718 SCIP_Real SCIPgetVarAvgInferenceCutoffScore(
9719 SCIP* scip, /**< SCIP data structure */
9720 SCIP_VAR* var, /**< problem variable */
9721 SCIP_Real cutoffweight /**< factor to weigh average number of cutoffs in branching score */
9722 )
9723 {
9724 SCIP_Real avginferdown;
9725 SCIP_Real avginferup;
9726 SCIP_Real avginfer;
9727 SCIP_Real inferdown;
9728 SCIP_Real inferup;
9729 SCIP_Real cutoffdown;
9730 SCIP_Real cutoffup;
9731
9732 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetVarAvgInferenceCutoffScore", FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE) );
9733
9734 assert( var->scip == scip );
9735
9736 avginferdown = SCIPhistoryGetAvgInferences(scip->stat->glbhistory, SCIP_BRANCHDIR_DOWNWARDS);
9737 avginferup = SCIPhistoryGetAvgInferences(scip->stat->glbhistory, SCIP_BRANCHDIR_UPWARDS);
9738 avginfer = (avginferdown + avginferup)/2.0;
9739 inferdown = SCIPvarGetAvgInferences(var, scip->stat, SCIP_BRANCHDIR_DOWNWARDS);
9740 inferup = SCIPvarGetAvgInferences(var, scip->stat, SCIP_BRANCHDIR_UPWARDS);
9741 cutoffdown = SCIPvarGetAvgCutoffs(var, scip->stat, SCIP_BRANCHDIR_DOWNWARDS);
9742 cutoffup = SCIPvarGetAvgCutoffs(var, scip->stat, SCIP_BRANCHDIR_UPWARDS);
9743
9744 return SCIPbranchGetScore(scip->set, var,
9745 inferdown + cutoffweight * avginfer * cutoffdown, inferup + cutoffweight * avginfer * cutoffup);
9746 }
9747
9748 /** returns the variable's average inference/cutoff score value, weighting the cutoffs of the variable with the given
9749 * factor, only using inferences and cutoffs of the current run
9750 *
9751 * @return the variable's average inference/cutoff score value, only using inferences and cutoffs of the current run
9752 *
9753 * @pre This method can be called if @p scip is in one of the following stages:
9754 * - \ref SCIP_STAGE_INITPRESOLVE
9755 * - \ref SCIP_STAGE_PRESOLVING
9756 * - \ref SCIP_STAGE_EXITPRESOLVE
9757 * - \ref SCIP_STAGE_PRESOLVED
9758 * - \ref SCIP_STAGE_INITSOLVE
9759 * - \ref SCIP_STAGE_SOLVING
9760 * - \ref SCIP_STAGE_SOLVED
9761 */
SCIPgetVarAvgInferenceCutoffScoreCurrentRun(SCIP * scip,SCIP_VAR * var,SCIP_Real cutoffweight)9762 SCIP_Real SCIPgetVarAvgInferenceCutoffScoreCurrentRun(
9763 SCIP* scip, /**< SCIP data structure */
9764 SCIP_VAR* var, /**< problem variable */
9765 SCIP_Real cutoffweight /**< factor to weigh average number of cutoffs in branching score */
9766 )
9767 {
9768 SCIP_Real avginferdown;
9769 SCIP_Real avginferup;
9770 SCIP_Real avginfer;
9771 SCIP_Real inferdown;
9772 SCIP_Real inferup;
9773 SCIP_Real cutoffdown;
9774 SCIP_Real cutoffup;
9775
9776 SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetVarAvgInferenceCutoffScoreCurrentRun", FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE) );
9777
9778 assert( var->scip == scip );
9779
9780 avginferdown = SCIPhistoryGetAvgInferences(scip->stat->glbhistorycrun, SCIP_BRANCHDIR_DOWNWARDS);
9781 avginferup = SCIPhistoryGetAvgInferences(scip->stat->glbhistorycrun, SCIP_BRANCHDIR_UPWARDS);
9782 avginfer = (avginferdown + avginferup)/2.0;
9783 inferdown = SCIPvarGetAvgInferencesCurrentRun(var, scip->stat, SCIP_BRANCHDIR_DOWNWARDS);
9784 inferup = SCIPvarGetAvgInferencesCurrentRun(var, scip->stat, SCIP_BRANCHDIR_UPWARDS);
9785 cutoffdown = SCIPvarGetAvgCutoffsCurrentRun(var, scip->stat, SCIP_BRANCHDIR_DOWNWARDS);
9786 cutoffup = SCIPvarGetAvgCutoffsCurrentRun(var, scip->stat, SCIP_BRANCHDIR_UPWARDS);
9787
9788 return SCIPbranchGetScore(scip->set, var,
9789 inferdown + cutoffweight * avginfer * cutoffdown, inferup + cutoffweight * avginfer * cutoffup);
9790 }
9791
9792 /** outputs variable information to file stream via the message system
9793 *
9794 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
9795 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
9796 *
9797 * @pre This method can be called if @p scip is in one of the following stages:
9798 * - \ref SCIP_STAGE_PROBLEM
9799 * - \ref SCIP_STAGE_TRANSFORMING
9800 * - \ref SCIP_STAGE_TRANSFORMED
9801 * - \ref SCIP_STAGE_INITPRESOLVE
9802 * - \ref SCIP_STAGE_PRESOLVING
9803 * - \ref SCIP_STAGE_EXITPRESOLVE
9804 * - \ref SCIP_STAGE_PRESOLVED
9805 * - \ref SCIP_STAGE_INITSOLVE
9806 * - \ref SCIP_STAGE_SOLVING
9807 * - \ref SCIP_STAGE_SOLVED
9808 * - \ref SCIP_STAGE_EXITSOLVE
9809 * - \ref SCIP_STAGE_FREETRANS
9810 *
9811 * @note If the message handler is set to a NULL pointer nothing will be printed
9812 */
SCIPprintVar(SCIP * scip,SCIP_VAR * var,FILE * file)9813 SCIP_RETCODE SCIPprintVar(
9814 SCIP* scip, /**< SCIP data structure */
9815 SCIP_VAR* var, /**< problem variable */
9816 FILE* file /**< output file (or NULL for standard output) */
9817 )
9818 {
9819 SCIP_CALL( SCIPcheckStage(scip, "SCIPprintVar", FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE) );
9820
9821 SCIP_CALL( SCIPvarPrint(var, scip->set, scip->messagehdlr, file) );
9822
9823 return SCIP_OKAY;
9824 }
9825