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 prob.c
17 * @ingroup OTHER_CFILES
18 * @brief Methods and datastructures for storing and manipulating the main problem
19 * @author Tobias Achterberg
20 */
21
22 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
23
24 #include "scip/branch.h"
25 #include "scip/conflictstore.h"
26 #include "scip/cons.h"
27 #include "scip/event.h"
28 #include "scip/lp.h"
29 #include "scip/primal.h"
30 #include "scip/prob.h"
31 #include "scip/pub_cons.h"
32 #include "scip/pub_lp.h"
33 #include "scip/pub_message.h"
34 #include "scip/pub_misc.h"
35 #include "scip/pub_misc_sort.h"
36 #include "scip/pub_var.h"
37 #include "scip/set.h"
38 #include "scip/stat.h"
39 #include "scip/struct_cons.h"
40 #include "scip/struct_lp.h"
41 #include "scip/struct_prob.h"
42 #include "scip/struct_set.h"
43 #include "scip/struct_stat.h"
44 #include "scip/struct_var.h"
45 #include "scip/var.h"
46 #include <string.h>
47
48
49 #define OBJSCALE_MAXDNOM 1000000LL /**< maximal denominator in objective integral scaling */
50 #define OBJSCALE_MAXSCALE 1000000.0 /**< maximal scalar to reach objective integrality */
51 #define OBJSCALE_MAXFINALSCALE 1000.0 /**< maximal final value to apply as scaling */
52
53
54
55 /*
56 * dymanic memory arrays
57 */
58
59 /** resizes vars array to be able to store at least num entries */
60 static
probEnsureVarsMem(SCIP_PROB * prob,SCIP_SET * set,int num)61 SCIP_RETCODE probEnsureVarsMem(
62 SCIP_PROB* prob, /**< problem data */
63 SCIP_SET* set, /**< global SCIP settings */
64 int num /**< minimal number of slots in array */
65 )
66 {
67 assert(prob != NULL);
68 assert(set != NULL);
69
70 if( num > prob->varssize )
71 {
72 int newsize;
73
74 newsize = SCIPsetCalcMemGrowSize(set, num);
75 SCIP_ALLOC( BMSreallocMemoryArray(&prob->vars, newsize) );
76 prob->varssize = newsize;
77 }
78 assert(num <= prob->varssize);
79
80 return SCIP_OKAY;
81 }
82
83 /** resizes fixedvars array to be able to store at least num entries */
84 static
probEnsureFixedvarsMem(SCIP_PROB * prob,SCIP_SET * set,int num)85 SCIP_RETCODE probEnsureFixedvarsMem(
86 SCIP_PROB* prob, /**< problem data */
87 SCIP_SET* set, /**< global SCIP settings */
88 int num /**< minimal number of slots in array */
89 )
90 {
91 assert(prob != NULL);
92 assert(set != NULL);
93
94 if( num > prob->fixedvarssize )
95 {
96 int newsize;
97
98 newsize = SCIPsetCalcMemGrowSize(set, num);
99 SCIP_ALLOC( BMSreallocMemoryArray(&prob->fixedvars, newsize) );
100 prob->fixedvarssize = newsize;
101 }
102 assert(num <= prob->fixedvarssize);
103
104 return SCIP_OKAY;
105 }
106
107 /** resizes deletedvars array to be able to store at least num entries */
108 static
probEnsureDeletedvarsMem(SCIP_PROB * prob,SCIP_SET * set,int num)109 SCIP_RETCODE probEnsureDeletedvarsMem(
110 SCIP_PROB* prob, /**< problem data */
111 SCIP_SET* set, /**< global SCIP settings */
112 int num /**< minimal number of slots in array */
113 )
114 {
115 assert(prob != NULL);
116 assert(set != NULL);
117
118 if( num > prob->deletedvarssize )
119 {
120 int newsize;
121
122 newsize = SCIPsetCalcMemGrowSize(set, num);
123 SCIP_ALLOC( BMSreallocMemoryArray(&prob->deletedvars, newsize) );
124 prob->deletedvarssize = newsize;
125 }
126 assert(num <= prob->deletedvarssize);
127
128 return SCIP_OKAY;
129 }
130
131 /** resizes conss array to be able to store at least num entries */
132 static
probEnsureConssMem(SCIP_PROB * prob,SCIP_SET * set,int num)133 SCIP_RETCODE probEnsureConssMem(
134 SCIP_PROB* prob, /**< problem data */
135 SCIP_SET* set, /**< global SCIP settings */
136 int num /**< minimal number of slots in array */
137 )
138 {
139 assert(prob != NULL);
140 assert(set != NULL);
141
142 if( num > prob->consssize )
143 {
144 int newsize;
145
146 newsize = SCIPsetCalcMemGrowSize(set, num);
147 SCIP_ALLOC( BMSreallocMemoryArray(&prob->conss, newsize) );
148 prob->consssize = newsize;
149 }
150 assert(num <= prob->consssize);
151
152 return SCIP_OKAY;
153 }
154
155 /** returns whether the constraint has a name */
156 static
consHasName(SCIP_CONS * cons)157 SCIP_Bool consHasName(
158 SCIP_CONS* cons /**< constraint */
159 )
160 {
161 const char* name;
162
163 name = SCIPconsGetName(cons);
164
165 return (name != NULL && name[0] != '\0');
166 }
167
168 /** returns whether the variable has a name */
169 static
varHasName(SCIP_VAR * var)170 SCIP_Bool varHasName(
171 SCIP_VAR* var /**< variable */
172 )
173 {
174 const char* name;
175
176 name = SCIPvarGetName(var);
177
178 return (name != NULL && name[0] != '\0');
179 }
180
181
182
183 /*
184 * problem creation
185 */
186
187 /** creates problem data structure by copying the source problem
188 *
189 * If the problem type requires the use of variable pricers, these pricers should be activated with calls
190 * to SCIPactivatePricer(). These pricers are automatically deactivated, when the problem is freed.
191 */
SCIPprobCopy(SCIP_PROB ** prob,BMS_BLKMEM * blkmem,SCIP_SET * set,const char * name,SCIP * sourcescip,SCIP_PROB * sourceprob,SCIP_HASHMAP * varmap,SCIP_HASHMAP * consmap,SCIP_Bool global)192 SCIP_RETCODE SCIPprobCopy(
193 SCIP_PROB** prob, /**< pointer to problem data structure */
194 BMS_BLKMEM* blkmem, /**< block memory */
195 SCIP_SET* set, /**< global SCIP settings */
196 const char* name, /**< problem name */
197 SCIP* sourcescip, /**< source SCIP data structure */
198 SCIP_PROB* sourceprob, /**< source problem structure */
199 SCIP_HASHMAP* varmap, /**< a hashmap to store the mapping of source variables corresponding
200 * target variables */
201 SCIP_HASHMAP* consmap, /**< a hashmap to store the mapping of source constraints to the corresponding
202 * target constraints */
203 SCIP_Bool global /**< create a global or a local copy? */
204 )
205 {
206 SCIP_PROBDATA* targetdata = NULL;
207 SCIP_RESULT result = SCIP_DIDNOTRUN;
208
209 assert(prob != NULL);
210 assert(set != NULL);
211 assert(blkmem != NULL);
212 assert(sourcescip != NULL);
213 assert(sourceprob != NULL);
214 assert(varmap != NULL);
215 assert(consmap != NULL);
216
217 /* create problem and initialize callbacks with NULL */
218 SCIP_CALL( SCIPprobCreate(prob, blkmem, set, name, NULL, NULL, NULL, NULL, NULL, NULL, NULL, FALSE) );
219
220 /* call user copy callback method */
221 if( sourceprob->probdata != NULL && sourceprob->probcopy != NULL )
222 {
223 SCIP_CALL( sourceprob->probcopy(set->scip, sourcescip, sourceprob->probdata, varmap, consmap, &targetdata, global, &result) );
224
225 /* evaluate result */
226 if( result != SCIP_DIDNOTRUN && result != SCIP_SUCCESS )
227 {
228 SCIPerrorMessage("probdata copying method returned invalid result <%d>\n", result);
229 return SCIP_INVALIDRESULT;
230 }
231
232 assert(targetdata == NULL || result == SCIP_SUCCESS);
233
234 /* if copying was successful, add data and callbacks */
235 if( result == SCIP_SUCCESS )
236 {
237 assert( targetdata != NULL );
238 (*prob)->probdelorig = sourceprob->probdelorig;
239 (*prob)->probtrans = sourceprob->probtrans;
240 (*prob)->probdeltrans = sourceprob->probdeltrans;
241 (*prob)->probinitsol = sourceprob->probinitsol;
242 (*prob)->probexitsol = sourceprob->probexitsol;
243 (*prob)->probcopy = sourceprob->probcopy;
244 (*prob)->probdata = targetdata;
245 }
246 }
247
248 return SCIP_OKAY;
249 }
250
251 /** creates problem data structure
252 * If the problem type requires the use of variable pricers, these pricers should be activated with calls
253 * to SCIPactivatePricer(). These pricers are automatically deactivated, when the problem is freed.
254 */
SCIPprobCreate(SCIP_PROB ** prob,BMS_BLKMEM * blkmem,SCIP_SET * set,const char * name,SCIP_DECL_PROBDELORIG ((* probdelorig)),SCIP_DECL_PROBTRANS ((* probtrans)),SCIP_DECL_PROBDELTRANS ((* probdeltrans)),SCIP_DECL_PROBINITSOL ((* probinitsol)),SCIP_DECL_PROBEXITSOL ((* probexitsol)),SCIP_DECL_PROBCOPY ((* probcopy)),SCIP_PROBDATA * probdata,SCIP_Bool transformed)255 SCIP_RETCODE SCIPprobCreate(
256 SCIP_PROB** prob, /**< pointer to problem data structure */
257 BMS_BLKMEM* blkmem, /**< block memory */
258 SCIP_SET* set, /**< global SCIP settings */
259 const char* name, /**< problem name */
260 SCIP_DECL_PROBDELORIG ((*probdelorig)), /**< frees user data of original problem */
261 SCIP_DECL_PROBTRANS ((*probtrans)), /**< creates user data of transformed problem by transforming original user data */
262 SCIP_DECL_PROBDELTRANS((*probdeltrans)), /**< frees user data of transformed problem */
263 SCIP_DECL_PROBINITSOL ((*probinitsol)), /**< solving process initialization method of transformed data */
264 SCIP_DECL_PROBEXITSOL ((*probexitsol)), /**< solving process deinitialization method of transformed data */
265 SCIP_DECL_PROBCOPY ((*probcopy)), /**< copies user data if you want to copy it to a subscip, or NULL */
266 SCIP_PROBDATA* probdata, /**< user problem data set by the reader */
267 SCIP_Bool transformed /**< is this the transformed problem? */
268 )
269 {
270 assert(prob != NULL);
271
272 SCIP_ALLOC( BMSallocMemory(prob) );
273 SCIP_ALLOC( BMSduplicateMemoryArray(&(*prob)->name, name, strlen(name)+1) );
274
275 (*prob)->probdata = probdata;
276 (*prob)->probcopy = probcopy;
277 (*prob)->probdelorig = probdelorig;
278 (*prob)->probtrans = probtrans;
279 (*prob)->probdeltrans = probdeltrans;
280 (*prob)->probinitsol = probinitsol;
281 (*prob)->probexitsol = probexitsol;
282 if( set->misc_usevartable )
283 {
284 SCIP_CALL( SCIPhashtableCreate(&(*prob)->varnames, blkmem,
285 (set->misc_usesmalltables ? SCIP_HASHSIZE_NAMES_SMALL : SCIP_HASHSIZE_NAMES),
286 SCIPhashGetKeyVar, SCIPhashKeyEqString, SCIPhashKeyValString, NULL) );
287 }
288 else
289 (*prob)->varnames = NULL;
290 (*prob)->vars = NULL;
291 (*prob)->varssize = 0;
292 (*prob)->nvars = 0;
293 (*prob)->nbinvars = 0;
294 (*prob)->nintvars = 0;
295 (*prob)->nimplvars = 0;
296 (*prob)->ncontvars = 0;
297 (*prob)->ncolvars = 0;
298 (*prob)->fixedvars = NULL;
299 (*prob)->fixedvarssize = 0;
300 (*prob)->nfixedvars = 0;
301 (*prob)->deletedvars = NULL;
302 (*prob)->deletedvarssize = 0;
303 (*prob)->ndeletedvars = 0;
304 (*prob)->nobjvars = 0;
305 if( set->misc_useconstable )
306 {
307 SCIP_CALL( SCIPhashtableCreate(&(*prob)->consnames, blkmem,
308 (set->misc_usesmalltables ? SCIP_HASHSIZE_NAMES_SMALL : SCIP_HASHSIZE_NAMES),
309 SCIPhashGetKeyCons, SCIPhashKeyEqString, SCIPhashKeyValString, NULL) );
310 }
311 else
312 (*prob)->consnames = NULL;
313 (*prob)->conss = NULL;
314 (*prob)->consssize = 0;
315 (*prob)->nconss = 0;
316 (*prob)->maxnconss = 0;
317 (*prob)->startnvars = 0;
318 (*prob)->startnconss = 0;
319 (*prob)->objsense = SCIP_OBJSENSE_MINIMIZE;
320 (*prob)->objoffset = 0.0;
321 (*prob)->objscale = 1.0;
322 (*prob)->objlim = SCIP_INVALID;
323 (*prob)->dualbound = SCIP_INVALID;
324 (*prob)->objisintegral = FALSE;
325 (*prob)->transformed = transformed;
326 (*prob)->nlpenabled = FALSE;
327 (*prob)->permuted = FALSE;
328 (*prob)->conscompression = FALSE;
329
330 return SCIP_OKAY;
331 }
332
333 /** sets callback to free user data of original problem */
SCIPprobSetDelorig(SCIP_PROB * prob,SCIP_DECL_PROBDELORIG ((* probdelorig)))334 void SCIPprobSetDelorig(
335 SCIP_PROB* prob, /**< problem */
336 SCIP_DECL_PROBDELORIG ((*probdelorig)) /**< frees user data of original problem */
337 )
338 {
339 assert(prob != NULL);
340
341 prob->probdelorig = probdelorig;
342 }
343
344 /** sets callback to create user data of transformed problem by transforming original user data */
SCIPprobSetTrans(SCIP_PROB * prob,SCIP_DECL_PROBTRANS ((* probtrans)))345 void SCIPprobSetTrans(
346 SCIP_PROB* prob, /**< problem */
347 SCIP_DECL_PROBTRANS ((*probtrans)) /**< creates user data of transformed problem by transforming original user data */
348 )
349 {
350 assert(prob != NULL);
351
352 prob->probtrans = probtrans;
353 }
354
355 /** sets callback to free user data of transformed problem */
SCIPprobSetDeltrans(SCIP_PROB * prob,SCIP_DECL_PROBDELTRANS ((* probdeltrans)))356 void SCIPprobSetDeltrans(
357 SCIP_PROB* prob, /**< problem */
358 SCIP_DECL_PROBDELTRANS((*probdeltrans)) /**< frees user data of transformed problem */
359 )
360 {
361 assert(prob != NULL);
362
363 prob->probdeltrans = probdeltrans;
364 }
365
366 /** sets solving process initialization callback of transformed data */
SCIPprobSetInitsol(SCIP_PROB * prob,SCIP_DECL_PROBINITSOL ((* probinitsol)))367 void SCIPprobSetInitsol(
368 SCIP_PROB* prob, /**< problem */
369 SCIP_DECL_PROBINITSOL ((*probinitsol)) /**< solving process initialization callback of transformed data */
370 )
371 {
372 assert(prob != NULL);
373
374 prob->probinitsol= probinitsol;
375 }
376
377 /** sets solving process deinitialization callback of transformed data */
SCIPprobSetExitsol(SCIP_PROB * prob,SCIP_DECL_PROBEXITSOL ((* probexitsol)))378 void SCIPprobSetExitsol(
379 SCIP_PROB* prob, /**< problem */
380 SCIP_DECL_PROBEXITSOL ((*probexitsol)) /**< solving process deinitialization callback of transformed data */
381 )
382 {
383 assert(prob != NULL);
384
385 prob->probexitsol= probexitsol;
386 }
387
388 /** sets callback to copy user data to copy it to a subscip, or NULL */
SCIPprobSetCopy(SCIP_PROB * prob,SCIP_DECL_PROBCOPY ((* probcopy)))389 void SCIPprobSetCopy(
390 SCIP_PROB* prob, /**< problem */
391 SCIP_DECL_PROBCOPY ((*probcopy)) /**< copies user data if you want to copy it to a subscip, or NULL */
392 )
393 {
394 assert(prob != NULL);
395
396 prob->probcopy= probcopy;
397 }
398
399 /** frees problem data structure */
SCIPprobFree(SCIP_PROB ** prob,SCIP_MESSAGEHDLR * messagehdlr,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp)400 SCIP_RETCODE SCIPprobFree(
401 SCIP_PROB** prob, /**< pointer to problem data structure */
402 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
403 BMS_BLKMEM* blkmem, /**< block memory buffer */
404 SCIP_SET* set, /**< global SCIP settings */
405 SCIP_STAT* stat, /**< dynamic problem statistics */
406 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
407 SCIP_LP* lp /**< current LP data (or NULL, if it's the original problem) */
408 )
409 {
410 int v;
411 #ifndef NDEBUG
412 SCIP_Bool unreleasedvar = FALSE;
413 #endif
414
415 assert(prob != NULL);
416 assert(*prob != NULL);
417 assert(set != NULL);
418
419 /* remove all constraints from the problem */
420 while( (*prob)->nconss > 0 )
421 {
422 /*@todo for debug mode it even might sense, to sort them downwards after their arraypos */
423 assert((*prob)->conss != NULL);
424 SCIP_CALL( SCIPprobDelCons(*prob, blkmem, set, stat, (*prob)->conss[(*prob)->nconss - 1]) );
425 }
426
427 if( (*prob)->transformed )
428 {
429 int h;
430
431 /* unlock variables for all constraint handlers that don't need constraints */
432 for( h = 0; h < set->nconshdlrs; ++h )
433 {
434 if( !SCIPconshdlrNeedsCons(set->conshdlrs[h]) )
435 {
436 SCIP_CALL( SCIPconshdlrUnlockVars(set->conshdlrs[h], set) );
437 }
438 }
439 }
440
441 /* free constraint array */
442 BMSfreeMemoryArrayNull(&(*prob)->conss);
443
444 /* free user problem data */
445 if( (*prob)->transformed )
446 {
447 if( (*prob)->probdeltrans != NULL )
448 {
449 SCIP_CALL( (*prob)->probdeltrans(set->scip, &(*prob)->probdata) );
450 }
451 }
452 else
453 {
454 if( (*prob)->probdelorig != NULL )
455 {
456 SCIP_CALL( (*prob)->probdelorig(set->scip, &(*prob)->probdata) );
457 }
458 }
459
460 /* release problem variables */
461 for( v = (*prob)->nvars - 1; v >= 0; --v )
462 {
463 assert(SCIPvarGetProbindex((*prob)->vars[v]) >= 0);
464
465 if( SCIPvarGetNUses((*prob)->vars[v]) > 1 )
466 {
467 SCIPmessageFPrintWarning(messagehdlr, "%s variable <%s> not released when freeing SCIP.\n",
468 (*prob)->transformed ? "Transformed" : "Original", SCIPvarGetName((*prob)->vars[v]));
469 #ifndef NDEBUG
470 unreleasedvar = TRUE;
471 #endif
472 }
473
474 SCIP_CALL( SCIPvarRemove((*prob)->vars[v], blkmem, NULL, set, TRUE) );
475 SCIP_CALL( SCIPvarRelease(&(*prob)->vars[v], blkmem, set, eventqueue, lp) );
476 }
477 BMSfreeMemoryArrayNull(&(*prob)->vars);
478
479 /* release fixed problem variables */
480 for( v = (*prob)->nfixedvars - 1; v >= 0; --v )
481 {
482 assert(SCIPvarGetProbindex((*prob)->fixedvars[v]) == -1);
483
484 if( SCIPvarGetNUses((*prob)->fixedvars[v]) > 1 )
485 {
486 SCIPmessageFPrintWarning(messagehdlr, "%s variable <%s> not released when freeing SCIP.\n",
487 (*prob)->transformed ? "Transformed" : "Original", SCIPvarGetName((*prob)->fixedvars[v]));
488 #ifndef NDEBUG
489 unreleasedvar = TRUE;
490 #endif
491 }
492
493 SCIP_CALL( SCIPvarRelease(&(*prob)->fixedvars[v], blkmem, set, eventqueue, lp) );
494 }
495 BMSfreeMemoryArrayNull(&(*prob)->fixedvars);
496
497 assert(! unreleasedvar);
498
499 /* free deleted problem variables array */
500 BMSfreeMemoryArrayNull(&(*prob)->deletedvars);
501
502 /* free hash tables for names */
503 if( (*prob)->varnames != NULL )
504 {
505 SCIPhashtableFree(&(*prob)->varnames);
506 }
507 if( (*prob)->consnames != NULL )
508 {
509 SCIPhashtableFree(&(*prob)->consnames);
510 }
511 BMSfreeMemoryArray(&(*prob)->name);
512 BMSfreeMemory(prob);
513
514 return SCIP_OKAY;
515 }
516
517 /** transform problem data into normalized form */
SCIPprobTransform(SCIP_PROB * source,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PRIMAL * primal,SCIP_TREE * tree,SCIP_REOPT * reopt,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_EVENTFILTER * eventfilter,SCIP_EVENTQUEUE * eventqueue,SCIP_CONFLICTSTORE * conflictstore,SCIP_PROB ** target)518 SCIP_RETCODE SCIPprobTransform(
519 SCIP_PROB* source, /**< problem to transform */
520 BMS_BLKMEM* blkmem, /**< block memory buffer */
521 SCIP_SET* set, /**< global SCIP settings */
522 SCIP_STAT* stat, /**< problem statistics */
523 SCIP_PRIMAL* primal, /**< primal data */
524 SCIP_TREE* tree, /**< branch and bound tree */
525 SCIP_REOPT* reopt, /**< reoptimization data structure */
526 SCIP_LP* lp, /**< current LP data */
527 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
528 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
529 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
530 SCIP_CONFLICTSTORE* conflictstore, /**< conflict store */
531 SCIP_PROB** target /**< pointer to target problem data structure */
532 )
533 {
534 SCIP_VAR* targetvar;
535 SCIP_CONS* targetcons;
536 char transname[SCIP_MAXSTRLEN];
537 int v;
538 int c;
539 int h;
540
541 assert(set != NULL);
542 assert(source != NULL);
543 assert(blkmem != NULL);
544 assert(target != NULL);
545
546 SCIPsetDebugMsg(set, "transform problem: original has %d variables\n", source->nvars);
547
548 /* create target problem data (probdelorig and probtrans are not needed, probdata is set later) */
549 (void) SCIPsnprintf(transname, SCIP_MAXSTRLEN, "t_%s", source->name);
550 SCIP_CALL( SCIPprobCreate(target, blkmem, set, transname, source->probdelorig, source->probtrans, source->probdeltrans,
551 source->probinitsol, source->probexitsol, source->probcopy, NULL, TRUE) );
552 SCIPprobSetObjsense(*target, source->objsense);
553
554 /* transform objective limit */
555 if( source->objlim < SCIP_INVALID )
556 SCIPprobSetObjlim(*target, source->objlim);
557
558 /* transform dual bound */
559 if( source->dualbound < SCIP_INVALID )
560 SCIPprobSetDualbound(*target, source->dualbound);
561
562 /* transform and copy all variables to target problem */
563 SCIP_CALL( probEnsureVarsMem(*target, set, source->nvars) );
564 for( v = 0; v < source->nvars; ++v )
565 {
566 SCIP_CALL( SCIPvarTransform(source->vars[v], blkmem, set, stat, source->objsense, &targetvar) );
567 SCIP_CALL( SCIPprobAddVar(*target, blkmem, set, lp, branchcand, eventfilter, eventqueue, targetvar) );
568 SCIP_CALL( SCIPvarRelease(&targetvar, blkmem, set, eventqueue, NULL) );
569 }
570 assert((*target)->nvars == source->nvars);
571 assert((*target)->nobjvars == SCIPprobGetNObjVars(*target, set));
572
573 /* call user data transformation */
574 if( source->probtrans != NULL )
575 {
576 SCIP_CALL( source->probtrans(set->scip, source->probdata, &(*target)->probdata) );
577 }
578 else
579 (*target)->probdata = source->probdata;
580
581 /* transform and copy all constraints to target problem */
582 for( c = 0; c < source->nconss; ++c )
583 {
584 SCIP_CALL( SCIPconsTransform(source->conss[c], blkmem, set, &targetcons) );
585 SCIP_CALL( SCIPprobAddCons(*target, set, stat, targetcons) );
586 SCIP_CALL( SCIPconsRelease(&targetcons, blkmem, set) );
587 }
588
589 /* lock variables for all constraint handlers that don't need constraints */
590 for( h = 0; h < set->nconshdlrs; ++h )
591 {
592 if( !SCIPconshdlrNeedsCons(set->conshdlrs[h]) )
593 {
594 SCIP_CALL( SCIPconshdlrLockVars(set->conshdlrs[h], set) );
595 }
596 }
597
598 /* objective value is always integral, iff original objective value is always integral and shift is integral */
599 (*target)->objisintegral = source->objisintegral && SCIPsetIsIntegral(set, (*target)->objoffset);
600
601 /* check, whether objective value is always integral by inspecting the problem, if it is the case adjust the
602 * cutoff bound if primal solution is already known
603 */
604 SCIP_CALL( SCIPprobCheckObjIntegral(*target, source, blkmem, set, stat, primal, tree, reopt, lp, eventfilter, eventqueue) );
605
606 /* copy the nlpenabled flag */
607 (*target)->nlpenabled = source->nlpenabled;
608
609 /* mark the transformed problem to be permuted iff the source problem is permuted */
610 (*target)->permuted = source->permuted;
611
612 /* transform the conflict pool */
613 SCIP_CALL( SCIPconflictstoreTransform(conflictstore, blkmem, set, stat, tree, *target, reopt) );
614
615 return SCIP_OKAY;
616 }
617
618 /** resets the global and local bounds of original variables in original problem to their original values */
SCIPprobResetBounds(SCIP_PROB * prob,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat)619 SCIP_RETCODE SCIPprobResetBounds(
620 SCIP_PROB* prob, /**< original problem data */
621 BMS_BLKMEM* blkmem, /**< block memory */
622 SCIP_SET* set, /**< global SCIP settings */
623 SCIP_STAT* stat /**< problem statistics */
624 )
625 {
626 int v;
627
628 assert(prob != NULL);
629 assert(prob->nfixedvars == 0);
630
631 for( v = 0; v < prob->nvars; ++v )
632 {
633 SCIP_CALL( SCIPvarResetBounds(prob->vars[v], blkmem, set, stat) );
634 }
635
636 return SCIP_OKAY;
637 }
638
639 /** (Re)Sort the variables, which appear in the four categories (binary, integer, implicit, continuous) after presolve
640 * with respect to their original index (within their categories). Adjust the problem index afterwards which is
641 * supposed to reflect the position in the variable array. This additional (re)sorting is supposed to get more robust
642 * against the order presolving fixed variables. (We also reobtain a possible block structure induced by the user
643 * model)
644 */
SCIPprobResortVars(SCIP_PROB * prob)645 void SCIPprobResortVars(
646 SCIP_PROB* prob /**< problem data */
647 )
648 {
649 SCIP_VAR** vars;
650 int nbinvars;
651 int nintvars;
652 int nimplvars;
653 int ncontvars;
654 int nvars;
655 int v;
656
657 vars = prob->vars;
658 nvars = prob->nvars;
659 nbinvars = prob->nbinvars;
660 nintvars = prob->nintvars;
661 nimplvars = prob->nimplvars;
662 ncontvars = prob->ncontvars;
663
664 if( nvars == 0 )
665 return;
666
667 assert(vars != NULL);
668 assert(nbinvars + nintvars + nimplvars + ncontvars == nvars);
669
670 SCIPdebugMessage("entering sorting with respect to original block structure! \n");
671
672 /* sort binaries */
673 if( nbinvars > 0 )
674 SCIPsortPtr((void**)vars, SCIPvarComp, nbinvars);
675
676 /* sort integers */
677 if( nintvars > 0 )
678 SCIPsortPtr((void**)&vars[nbinvars], SCIPvarComp, nintvars);
679
680 /* sort implicit variables */
681 if( nimplvars > 0 )
682 SCIPsortPtr((void**)&vars[nbinvars + nintvars], SCIPvarComp, nimplvars);
683
684 /* sort continuous variables*/
685 if( ncontvars > 0 )
686 SCIPsortPtr((void**)&vars[nbinvars + nintvars + nimplvars], SCIPvarComp, ncontvars);
687
688 /* after sorting, the problem index of each variable has to be adjusted */
689 for( v = 0; v < nvars; ++v )
690 {
691 vars[v]->probindex = v;
692 SCIPdebugMessage("Variable: Problem index <%d>, original index <%d> \n", vars[v]->probindex, vars[v]->index);
693 }
694 }
695
696
697
698 /*
699 * problem modification
700 */
701
702 /** sets user problem data */
SCIPprobSetData(SCIP_PROB * prob,SCIP_PROBDATA * probdata)703 void SCIPprobSetData(
704 SCIP_PROB* prob, /**< problem */
705 SCIP_PROBDATA* probdata /**< user problem data to use */
706 )
707 {
708 assert(prob != NULL);
709
710 prob->probdata = probdata;
711 }
712
713 /** inserts variable at the correct position in vars array, depending on its type */
714 static
probInsertVar(SCIP_PROB * prob,SCIP_VAR * var)715 void probInsertVar(
716 SCIP_PROB* prob, /**< problem data */
717 SCIP_VAR* var /**< variable to insert */
718 )
719 {
720 int insertpos;
721 int intstart;
722 int implstart;
723 int contstart;
724
725 assert(prob != NULL);
726 assert(prob->vars != NULL);
727 assert(prob->nvars < prob->varssize);
728 assert(var != NULL);
729 assert(SCIPvarGetProbindex(var) == -1);
730 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL
731 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE
732 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
733 /* original variables cannot go into transformed problem and transformed variables cannot go into original problem */
734 assert((SCIPvarGetStatus(var) != SCIP_VARSTATUS_ORIGINAL) == prob->transformed);
735
736 /* insert variable in array */
737 insertpos = prob->nvars;
738 intstart = prob->nbinvars;
739 implstart = intstart + prob->nintvars;
740 contstart = implstart + prob->nimplvars;
741
742 if( SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS )
743 prob->ncontvars++;
744 else
745 {
746 if( insertpos > contstart )
747 {
748 prob->vars[insertpos] = prob->vars[contstart];
749 SCIPvarSetProbindex(prob->vars[insertpos], insertpos);
750 insertpos = contstart;
751 }
752 assert(insertpos == contstart);
753
754 if( SCIPvarGetType(var) == SCIP_VARTYPE_IMPLINT )
755 prob->nimplvars++;
756 else
757 {
758 if( insertpos > implstart )
759 {
760 prob->vars[insertpos] = prob->vars[implstart];
761 SCIPvarSetProbindex(prob->vars[insertpos], insertpos);
762 insertpos = implstart;
763 }
764 assert(insertpos == implstart);
765
766 if( SCIPvarGetType(var) == SCIP_VARTYPE_INTEGER )
767 prob->nintvars++;
768 else
769 {
770 assert(SCIPvarGetType(var) == SCIP_VARTYPE_BINARY);
771 if( insertpos > intstart )
772 {
773 prob->vars[insertpos] = prob->vars[intstart];
774 SCIPvarSetProbindex(prob->vars[insertpos], insertpos);
775 insertpos = intstart;
776 }
777 assert(insertpos == intstart);
778
779 prob->nbinvars++;
780 }
781 }
782 }
783 prob->nvars++;
784
785 assert(prob->nvars == prob->nbinvars + prob->nintvars + prob->nimplvars + prob->ncontvars);
786 assert((SCIPvarGetType(var) == SCIP_VARTYPE_BINARY && insertpos == prob->nbinvars - 1)
787 || (SCIPvarGetType(var) == SCIP_VARTYPE_INTEGER && insertpos == prob->nbinvars + prob->nintvars - 1)
788 || (SCIPvarGetType(var) == SCIP_VARTYPE_IMPLINT && insertpos == prob->nbinvars + prob->nintvars + prob->nimplvars - 1)
789 || (SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS
790 && insertpos == prob->nbinvars + prob->nintvars + prob->nimplvars + prob->ncontvars - 1));
791
792 prob->vars[insertpos] = var;
793 SCIPvarSetProbindex(var, insertpos);
794
795 /* update number of column variables in problem */
796 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN )
797 prob->ncolvars++;
798 assert(0 <= prob->ncolvars && prob->ncolvars <= prob->nvars);
799 }
800
801 /** removes variable from vars array */
802 static
probRemoveVar(SCIP_PROB * prob,BMS_BLKMEM * blkmem,SCIP_CLIQUETABLE * cliquetable,SCIP_SET * set,SCIP_VAR * var)803 SCIP_RETCODE probRemoveVar(
804 SCIP_PROB* prob, /**< problem data */
805 BMS_BLKMEM* blkmem, /**< block memory */
806 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
807 SCIP_SET* set, /**< global SCIP settings */
808 SCIP_VAR* var /**< variable to remove */
809 )
810 {
811 int freepos;
812 int intstart;
813 int implstart;
814 int contstart;
815
816 assert(prob != NULL);
817 assert(var != NULL);
818 assert(SCIPvarGetProbindex(var) >= 0);
819 assert(prob->vars != NULL);
820 assert(prob->vars[SCIPvarGetProbindex(var)] == var);
821
822 intstart = prob->nbinvars;
823 implstart = intstart + prob->nintvars;
824 contstart = implstart + prob->nimplvars;
825
826 switch( SCIPvarGetType(var) )
827 {
828 case SCIP_VARTYPE_BINARY:
829 assert(0 <= SCIPvarGetProbindex(var) && SCIPvarGetProbindex(var) < intstart);
830 prob->nbinvars--;
831 break;
832 case SCIP_VARTYPE_INTEGER:
833 assert(intstart <= SCIPvarGetProbindex(var) && SCIPvarGetProbindex(var) < implstart);
834 prob->nintvars--;
835 break;
836 case SCIP_VARTYPE_IMPLINT:
837 assert(implstart <= SCIPvarGetProbindex(var) && SCIPvarGetProbindex(var) < contstart);
838 prob->nimplvars--;
839 break;
840 case SCIP_VARTYPE_CONTINUOUS:
841 assert(contstart <= SCIPvarGetProbindex(var) && SCIPvarGetProbindex(var) < prob->nvars);
842 prob->ncontvars--;
843 break;
844 default:
845 SCIPerrorMessage("unknown variable type\n");
846 SCIPABORT();
847 return SCIP_INVALIDDATA; /*lint !e527*/
848 }
849
850 /* move last binary, last integer, last implicit, and last continuous variable forward to fill the free slot */
851 freepos = SCIPvarGetProbindex(var);
852 if( freepos < intstart-1 )
853 {
854 /* move last binary variable to free slot */
855 prob->vars[freepos] = prob->vars[intstart-1];
856 SCIPvarSetProbindex(prob->vars[freepos], freepos);
857 freepos = intstart-1;
858 }
859 if( freepos < implstart-1 )
860 {
861 /* move last integer variable to free slot */
862 prob->vars[freepos] = prob->vars[implstart-1];
863 SCIPvarSetProbindex(prob->vars[freepos], freepos);
864 freepos = implstart-1;
865 }
866 if( freepos < contstart-1 )
867 {
868 /* move last implicit integer variable to free slot */
869 prob->vars[freepos] = prob->vars[contstart-1];
870 SCIPvarSetProbindex(prob->vars[freepos], freepos);
871 freepos = contstart-1;
872 }
873 if( freepos < prob->nvars-1 )
874 {
875 /* move last implicit integer variable to free slot */
876 prob->vars[freepos] = prob->vars[prob->nvars-1];
877 SCIPvarSetProbindex(prob->vars[freepos], freepos);
878 freepos = prob->nvars-1;
879 }
880 assert(freepos == prob->nvars-1);
881
882 prob->nvars--;
883 assert(prob->nvars == prob->nbinvars + prob->nintvars + prob->nimplvars + prob->ncontvars);
884
885 /* update number of column variables in problem */
886 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN )
887 prob->ncolvars--;
888 assert(0 <= prob->ncolvars && prob->ncolvars <= prob->nvars);
889
890 /* inform the variable that it is no longer in the problem; if necessary, delete it from the implication graph */
891 SCIP_CALL( SCIPvarRemove(var, blkmem, cliquetable, set, FALSE) );
892
893 return SCIP_OKAY;
894 }
895
896 /** adds variable's name to the namespace */
SCIPprobAddVarName(SCIP_PROB * prob,SCIP_VAR * var)897 SCIP_RETCODE SCIPprobAddVarName(
898 SCIP_PROB* prob, /**< problem data */
899 SCIP_VAR* var /**< variable */
900 )
901 {
902 assert(SCIPvarGetProbindex(var) != -1);
903
904 if( varHasName(var) && prob->varnames != NULL )
905 {
906 SCIP_CALL( SCIPhashtableInsert(prob->varnames, (void*)var) );
907 }
908
909 return SCIP_OKAY;
910 }
911
912 /** removes variable's name from the namespace */
SCIPprobRemoveVarName(SCIP_PROB * prob,SCIP_VAR * var)913 SCIP_RETCODE SCIPprobRemoveVarName(
914 SCIP_PROB* prob, /**< problem data */
915 SCIP_VAR* var /**< variable */
916 )
917 {
918 if( varHasName(var) && prob->varnames != NULL )
919 {
920 assert(SCIPhashtableExists(prob->varnames, (void*)var));
921 SCIP_CALL( SCIPhashtableRemove(prob->varnames, (void*)var) );
922 }
923
924 return SCIP_OKAY;
925 }
926
927 /** adds variable to the problem and captures it */
SCIPprobAddVar(SCIP_PROB * prob,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_EVENTFILTER * eventfilter,SCIP_EVENTQUEUE * eventqueue,SCIP_VAR * var)928 SCIP_RETCODE SCIPprobAddVar(
929 SCIP_PROB* prob, /**< problem data */
930 BMS_BLKMEM* blkmem, /**< block memory buffers */
931 SCIP_SET* set, /**< global SCIP settings */
932 SCIP_LP* lp, /**< current LP data */
933 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
934 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
935 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
936 SCIP_VAR* var /**< variable to add */
937 )
938 {
939 assert(prob != NULL);
940 assert(set != NULL);
941 assert(var != NULL);
942 assert(SCIPvarGetProbindex(var) == -1);
943 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL
944 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE
945 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
946 /* original variables cannot go into transformed problem and transformed variables cannot go into original problem */
947 assert((SCIPvarGetStatus(var) != SCIP_VARSTATUS_ORIGINAL) == prob->transformed);
948
949 #ifndef NDEBUG
950 /* check if we add this variables to the same scip, where we created it */
951 if( var->scip != set->scip )
952 {
953 SCIPerrorMessage("variable belongs to a different scip instance\n");
954 return SCIP_INVALIDDATA;
955 }
956 #endif
957
958 /* capture variable */
959 SCIPvarCapture(var);
960
961 /* allocate additional memory */
962 SCIP_CALL( probEnsureVarsMem(prob, set, prob->nvars+1) );
963
964 /* insert variable in vars array and mark it to be in problem */
965 probInsertVar(prob, var);
966
967 /* add variable's name to the namespace */
968 SCIP_CALL( SCIPprobAddVarName(prob, var) );
969
970 /* update branching candidates and pseudo and loose objective value in the LP */
971 if( SCIPvarGetStatus(var) != SCIP_VARSTATUS_ORIGINAL )
972 {
973 SCIP_CALL( SCIPbranchcandUpdateVar(branchcand, set, var) );
974 SCIP_CALL( SCIPlpUpdateAddVar(lp, set, var) );
975 }
976
977 SCIPsetDebugMsg(set, "added variable <%s> to problem (%d variables: %d binary, %d integer, %d implicit, %d continuous)\n",
978 SCIPvarGetName(var), prob->nvars, prob->nbinvars, prob->nintvars, prob->nimplvars, prob->ncontvars);
979
980 if( prob->transformed )
981 {
982 SCIP_EVENT* event;
983
984 /* issue VARADDED event */
985 SCIP_CALL( SCIPeventCreateVarAdded(&event, blkmem, var) );
986 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, eventfilter, &event) );
987
988 /* update the number of variables with non-zero objective coefficient */
989 SCIPprobUpdateNObjVars(prob, set, 0.0, SCIPvarGetObj(var));
990
991 /* SCIP assumes that the status of objisintegral does not change after transformation. Thus, the objective of all
992 * new variables beyond that stage has to be compatible. */
993 assert( SCIPsetGetStage(set) == SCIP_STAGE_TRANSFORMING || ! prob->objisintegral || SCIPsetIsZero(set, SCIPvarGetObj(var)) ||
994 ( SCIPvarIsIntegral(var) && SCIPsetIsIntegral(set, SCIPvarGetObj(var)) ) );
995 }
996
997 return SCIP_OKAY;
998 }
999
1000 /** marks variable to be removed from the problem; however, the variable is NOT removed from the constraints */
SCIPprobDelVar(SCIP_PROB * prob,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_VAR * var,SCIP_Bool * deleted)1001 SCIP_RETCODE SCIPprobDelVar(
1002 SCIP_PROB* prob, /**< problem data */
1003 BMS_BLKMEM* blkmem, /**< block memory */
1004 SCIP_SET* set, /**< global SCIP settings */
1005 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1006 SCIP_VAR* var, /**< problem variable */
1007 SCIP_Bool* deleted /**< pointer to store whether marking variable to be deleted was successful */
1008 )
1009 {
1010 assert(prob != NULL);
1011 assert(set != NULL);
1012 assert(var != NULL);
1013 assert(deleted != NULL);
1014 assert(SCIPvarGetProbindex(var) != -1);
1015 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL
1016 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE
1017 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
1018
1019 *deleted = FALSE;
1020
1021 /* don't remove variables that are not in the problem */
1022 /**@todo what about negated variables? should the negation variable be removed instead? */
1023 if( SCIPvarGetProbindex(var) == -1 )
1024 return SCIP_OKAY;
1025
1026 /* don't remove the direct counterpart of an original variable from the transformed problem, because otherwise
1027 * operations on the original variables would be applied to a NULL pointer
1028 */
1029 if( SCIPvarIsTransformedOrigvar(var) )
1030 return SCIP_OKAY;
1031
1032 assert(SCIPvarGetNegatedVar(var) == NULL);
1033
1034 SCIPsetDebugMsg(set, "deleting variable <%s> from problem (%d variables: %d binary, %d integer, %d implicit, %d continuous)\n",
1035 SCIPvarGetName(var), prob->nvars, prob->nbinvars, prob->nintvars, prob->nimplvars, prob->ncontvars);
1036
1037 /* mark variable to be deleted from the problem */
1038 SCIPvarMarkDeleted(var);
1039
1040 if( prob->transformed )
1041 {
1042 SCIP_EVENT* event;
1043
1044 assert(eventqueue != NULL);
1045
1046 /* issue VARDELETED event */
1047 SCIP_CALL( SCIPeventCreateVarDeleted(&event, blkmem, var) );
1048 SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, NULL, &event) );
1049 }
1050
1051 /* remember that the variable should be deleted from the problem in SCIPprobPerformVarDeletions() */
1052 SCIP_CALL( probEnsureDeletedvarsMem(prob, set, prob->ndeletedvars+1) );
1053 prob->deletedvars[prob->ndeletedvars] = var;
1054 prob->ndeletedvars++;
1055
1056 *deleted = TRUE;
1057
1058 return SCIP_OKAY;
1059 }
1060
1061 /** actually removes the deleted variables from the problem and releases them */
SCIPprobPerformVarDeletions(SCIP_PROB * prob,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_EVENTQUEUE * eventqueue,SCIP_CLIQUETABLE * cliquetable,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand)1062 SCIP_RETCODE SCIPprobPerformVarDeletions(
1063 SCIP_PROB* prob, /**< problem data */
1064 BMS_BLKMEM* blkmem, /**< block memory */
1065 SCIP_SET* set, /**< global SCIP settings */
1066 SCIP_STAT* stat, /**< dynamic problem statistics */
1067 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1068 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
1069 SCIP_LP* lp, /**< current LP data (may be NULL) */
1070 SCIP_BRANCHCAND* branchcand /**< branching candidate storage */
1071 )
1072 {
1073 int i;
1074
1075 assert(prob != NULL);
1076 assert(set != NULL);
1077
1078 /* delete variables from the constraints;
1079 * do this only in solving stage, in presolving, it is already handled by the constraint handlers
1080 */
1081 if( SCIPsetGetStage(set) == SCIP_STAGE_SOLVING )
1082 {
1083 for( i = 0; i < set->nconshdlrs; ++i )
1084 {
1085 SCIP_CALL( SCIPconshdlrDelVars(set->conshdlrs[i], blkmem, set, stat) );
1086 }
1087 }
1088
1089 for( i = 0; i < prob->ndeletedvars; ++i )
1090 {
1091 SCIP_VAR* var;
1092
1093 var = prob->deletedvars[i];
1094
1095 /* don't delete the variable, if it was fixed or aggregated in the meantime */
1096 if( SCIPvarGetProbindex(var) >= 0 )
1097 {
1098 SCIPsetDebugMsg(set, "perform deletion of <%s> [%p]\n", SCIPvarGetName(var), (void*)var);
1099
1100 /* convert column variable back into loose variable, free LP column */
1101 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN )
1102 {
1103 SCIP_CALL( SCIPvarLoose(var, blkmem, set, eventqueue, prob, lp) );
1104 }
1105
1106 /* update branching candidates and pseudo and loose objective value in the LP */
1107 if( SCIPvarGetStatus(var) != SCIP_VARSTATUS_ORIGINAL )
1108 {
1109 SCIP_CALL( SCIPlpUpdateDelVar(lp, set, var) );
1110 SCIP_CALL( SCIPbranchcandRemoveVar(branchcand, var) );
1111 }
1112
1113 /* remove variable's name from the namespace */
1114 SCIP_CALL( SCIPprobRemoveVarName(prob, var) );
1115
1116 /* remove variable from vars array and mark it to be not in problem */
1117 SCIP_CALL( probRemoveVar(prob, blkmem, cliquetable, set, var) );
1118
1119 /* update the number of variables with non-zero objective coefficient */
1120 if( prob->transformed )
1121 SCIPprobUpdateNObjVars(prob, set, SCIPvarGetObj(var), 0.0);
1122
1123 /* release variable */
1124 SCIP_CALL( SCIPvarRelease(&prob->deletedvars[i], blkmem, set, eventqueue, lp) );
1125 }
1126 }
1127 prob->ndeletedvars = 0;
1128
1129 return SCIP_OKAY;
1130 }
1131
1132 /** changes the type of a variable in the problem */
SCIPprobChgVarType(SCIP_PROB * prob,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_PRIMAL * primal,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_EVENTQUEUE * eventqueue,SCIP_CLIQUETABLE * cliquetable,SCIP_VAR * var,SCIP_VARTYPE vartype)1133 SCIP_RETCODE SCIPprobChgVarType(
1134 SCIP_PROB* prob, /**< problem data */
1135 BMS_BLKMEM* blkmem, /**< block memory */
1136 SCIP_SET* set, /**< global SCIP settings */
1137 SCIP_PRIMAL* primal, /**< primal data */
1138 SCIP_LP* lp, /**< current LP data */
1139 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
1140 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1141 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
1142 SCIP_VAR* var, /**< variable to add */
1143 SCIP_VARTYPE vartype /**< new type of variable */
1144 )
1145 {
1146 assert(prob != NULL);
1147 assert(var != NULL);
1148 assert(SCIPvarGetProbindex(var) >= 0);
1149 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL
1150 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE
1151 || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
1152 assert(branchcand != NULL || SCIPvarGetStatus(var) == SCIP_VARSTATUS_ORIGINAL);
1153
1154 if( SCIPvarGetType(var) == vartype )
1155 return SCIP_OKAY;
1156
1157 /* temporarily remove variable from branching candidates */
1158 if( branchcand != NULL )
1159 {
1160 SCIP_CALL( SCIPbranchcandRemoveVar(branchcand, var) );
1161 }
1162
1163 /* temporarily remove variable from problem */
1164 SCIP_CALL( probRemoveVar(prob, blkmem, cliquetable, set, var) );
1165
1166 /* change the type of the variable */
1167 SCIP_CALL( SCIPvarChgType(var, blkmem, set, primal, lp, eventqueue, vartype) );
1168
1169 /* reinsert variable into problem */
1170 probInsertVar(prob, var);
1171
1172 /* update branching candidates */
1173 if( branchcand != NULL )
1174 {
1175 SCIP_CALL( SCIPbranchcandUpdateVar(branchcand, set, var) );
1176 }
1177
1178 return SCIP_OKAY;
1179 }
1180
1181 /** informs problem, that the given loose problem variable changed its status */
SCIPprobVarChangedStatus(SCIP_PROB * prob,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_BRANCHCAND * branchcand,SCIP_CLIQUETABLE * cliquetable,SCIP_VAR * var)1182 SCIP_RETCODE SCIPprobVarChangedStatus(
1183 SCIP_PROB* prob, /**< problem data */
1184 BMS_BLKMEM* blkmem, /**< block memory */
1185 SCIP_SET* set, /**< global SCIP settings */
1186 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
1187 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
1188 SCIP_VAR* var /**< problem variable */
1189 )
1190 {
1191 assert(prob != NULL);
1192 assert(var != NULL);
1193 assert(SCIPvarGetProbindex(var) != -1);
1194
1195 /* get current status of variable */
1196 switch( SCIPvarGetStatus(var) )
1197 {
1198 case SCIP_VARSTATUS_ORIGINAL:
1199 SCIPerrorMessage("variables cannot switch to ORIGINAL status\n");
1200 return SCIP_INVALIDDATA;
1201
1202 case SCIP_VARSTATUS_LOOSE:
1203 /* variable switched from column to loose */
1204 prob->ncolvars--;
1205 break;
1206
1207 case SCIP_VARSTATUS_COLUMN:
1208 /* variable switched from non-column to column */
1209 prob->ncolvars++;
1210 break;
1211
1212 case SCIP_VARSTATUS_FIXED:
1213 case SCIP_VARSTATUS_AGGREGATED:
1214 case SCIP_VARSTATUS_MULTAGGR:
1215 case SCIP_VARSTATUS_NEGATED:
1216 /* variable switched from unfixed to fixed (if it was fixed before, probindex would have been -1) */
1217
1218 /* remove variable from problem */
1219 SCIP_CALL( probRemoveVar(prob, blkmem, cliquetable, set, var) );
1220
1221 /* insert variable in fixedvars array */
1222 SCIP_CALL( probEnsureFixedvarsMem(prob, set, prob->nfixedvars+1) );
1223 prob->fixedvars[prob->nfixedvars] = var;
1224 prob->nfixedvars++;
1225
1226 /* update branching candidates */
1227 SCIP_CALL( SCIPbranchcandUpdateVar(branchcand, set, var) );
1228 break;
1229
1230 default:
1231 SCIPerrorMessage("invalid variable status <%d>\n", SCIPvarGetStatus(var));
1232 return SCIP_INVALIDDATA;
1233 }
1234 assert(0 <= prob->ncolvars && prob->ncolvars <= prob->nvars);
1235
1236 return SCIP_OKAY;
1237 }
1238
1239 /** adds constraint's name to the namespace */
SCIPprobAddConsName(SCIP_PROB * prob,SCIP_CONS * cons)1240 SCIP_RETCODE SCIPprobAddConsName(
1241 SCIP_PROB* prob, /**< problem data */
1242 SCIP_CONS* cons /**< constraint */
1243 )
1244 {
1245 /* add constraint's name to the namespace */
1246 if( consHasName(cons) && prob->consnames != NULL )
1247 {
1248 SCIP_CALL( SCIPhashtableInsert(prob->consnames, (void*)cons) );
1249 }
1250
1251 return SCIP_OKAY;
1252 }
1253
1254 /** remove constraint's name from the namespace */
SCIPprobRemoveConsName(SCIP_PROB * prob,SCIP_CONS * cons)1255 SCIP_RETCODE SCIPprobRemoveConsName(
1256 SCIP_PROB* prob, /**< problem data */
1257 SCIP_CONS* cons /**< constraint */
1258 )
1259 {
1260 /* remove constraint's name from the namespace */
1261 if( consHasName(cons) && prob->consnames != NULL )
1262 {
1263 SCIP_CONS* currentcons;
1264 currentcons = (SCIP_CONS*)SCIPhashtableRetrieve(prob->consnames, (void*)(cons->name));
1265 if( currentcons == cons )
1266 {
1267 SCIP_CALL( SCIPhashtableRemove(prob->consnames, (void*)cons) );
1268 }
1269 }
1270
1271 return SCIP_OKAY;
1272 }
1273
1274 /** adds constraint to the problem and captures it;
1275 * a local constraint is automatically upgraded into a global constraint
1276 */
SCIPprobAddCons(SCIP_PROB * prob,SCIP_SET * set,SCIP_STAT * stat,SCIP_CONS * cons)1277 SCIP_RETCODE SCIPprobAddCons(
1278 SCIP_PROB* prob, /**< problem data */
1279 SCIP_SET* set, /**< global SCIP settings */
1280 SCIP_STAT* stat, /**< dynamic problem statistics */
1281 SCIP_CONS* cons /**< constraint to add */
1282 )
1283 {
1284 assert(prob != NULL);
1285 assert(cons != NULL);
1286 assert(cons->addconssetchg == NULL);
1287 assert(cons->addarraypos == -1);
1288
1289 #ifndef NDEBUG
1290 /* check if we add this constraint to the same scip, where we create the constraint */
1291 if( cons->scip != set->scip )
1292 {
1293 SCIPerrorMessage("constraint belongs to different scip instance\n");
1294 return SCIP_INVALIDDATA;
1295 }
1296 #endif
1297 SCIPsetDebugMsg(set, "adding constraint <%s> to global problem -> %d constraints\n",
1298 SCIPconsGetName(cons), prob->nconss+1);
1299
1300 /* mark the constraint as problem constraint, and remember the constraint's position */
1301 cons->addconssetchg = NULL;
1302 cons->addarraypos = prob->nconss;
1303
1304 /* add the constraint to the problem's constraint array */
1305 SCIP_CALL( probEnsureConssMem(prob, set, prob->nconss+1) );
1306 prob->conss[prob->nconss] = cons;
1307 prob->nconss++;
1308 prob->maxnconss = MAX(prob->maxnconss, prob->nconss);
1309 stat->nactiveconssadded++;
1310
1311 /* undelete constraint, if it was globally deleted in the past */
1312 cons->deleted = FALSE;
1313
1314 /* mark constraint to be globally valid */
1315 SCIPconsSetLocal(cons, FALSE);
1316
1317 /* capture constraint */
1318 SCIPconsCapture(cons);
1319
1320 /* add constraint's name to the namespace */
1321 SCIP_CALL( SCIPprobAddConsName(prob, cons) );
1322
1323 /* if the problem is the transformed problem, activate and lock constraint */
1324 if( prob->transformed )
1325 {
1326 /* activate constraint */
1327 if( !SCIPconsIsActive(cons) )
1328 {
1329 SCIP_CALL( SCIPconsActivate(cons, set, stat, -1, (stat->nnodes <= 1)) );
1330 }
1331
1332 /* if constraint is a check-constraint, lock roundings of constraint's variables */
1333 if( SCIPconsIsChecked(cons) )
1334 {
1335 SCIP_CALL( SCIPconsAddLocks(cons, set, SCIP_LOCKTYPE_MODEL, +1, 0) );
1336 }
1337 }
1338
1339 return SCIP_OKAY;
1340 }
1341
1342 /** releases and removes constraint from the problem; if the user has not captured the constraint for his own use, the
1343 * constraint may be invalid after the call
1344 */
SCIPprobDelCons(SCIP_PROB * prob,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_CONS * cons)1345 SCIP_RETCODE SCIPprobDelCons(
1346 SCIP_PROB* prob, /**< problem data */
1347 BMS_BLKMEM* blkmem, /**< block memory */
1348 SCIP_SET* set, /**< global SCIP settings */
1349 SCIP_STAT* stat, /**< dynamic problem statistics */
1350 SCIP_CONS* cons /**< constraint to remove */
1351 )
1352 {
1353 int arraypos;
1354
1355 assert(prob != NULL);
1356 assert(blkmem != NULL);
1357 assert(cons != NULL);
1358 assert(cons->addconssetchg == NULL);
1359 assert(0 <= cons->addarraypos && cons->addarraypos < prob->nconss);
1360 assert(prob->conss != NULL);
1361 assert(prob->conss[cons->addarraypos] == cons);
1362
1363 /* if the problem is the transformed problem, deactivate and unlock constraint */
1364 if( prob->transformed )
1365 {
1366 /* if constraint is a check-constraint, unlock roundings of constraint's variables */
1367 if( SCIPconsIsChecked(cons) )
1368 {
1369 SCIP_CALL( SCIPconsAddLocks(cons, set, SCIP_LOCKTYPE_MODEL, -1, 0) );
1370 }
1371
1372 /* deactivate constraint, if it is currently active */
1373 if( cons->active && !cons->updatedeactivate )
1374 {
1375 SCIP_CALL( SCIPconsDeactivate(cons, set, stat) );
1376 }
1377 }
1378 assert(!cons->active || cons->updatedeactivate);
1379 assert(!cons->enabled || cons->updatedeactivate);
1380
1381 /* remove constraint's name from the namespace */
1382 SCIP_CALL( SCIPprobRemoveConsName(prob, cons) );
1383
1384 /* remove the constraint from the problem's constraint array */
1385 arraypos = cons->addarraypos;
1386 prob->conss[arraypos] = prob->conss[prob->nconss-1];
1387 assert(prob->conss[arraypos] != NULL);
1388 assert(prob->conss[arraypos]->addconssetchg == NULL);
1389 prob->conss[arraypos]->addarraypos = arraypos;
1390 prob->nconss--;
1391
1392 /* mark the constraint to be no longer in the problem */
1393 cons->addarraypos = -1;
1394
1395 /* release constraint */
1396 SCIP_CALL( SCIPconsRelease(&cons, blkmem, set) );
1397
1398 return SCIP_OKAY;
1399 }
1400
1401 /** remembers the current number of constraints in the problem's internal data structure
1402 * - resets maximum number of constraints to current number of constraints
1403 * - remembers current number of constraints as starting number of constraints
1404 */
SCIPprobMarkNConss(SCIP_PROB * prob)1405 void SCIPprobMarkNConss(
1406 SCIP_PROB* prob /**< problem data */
1407 )
1408 {
1409 assert(prob != NULL);
1410
1411 /* remember number of constraints for statistic */
1412 prob->maxnconss = prob->nconss;
1413 prob->startnvars = prob->nvars;
1414 prob->startnconss = prob->nconss;
1415 }
1416
1417 /** sets objective sense: minimization or maximization */
SCIPprobSetObjsense(SCIP_PROB * prob,SCIP_OBJSENSE objsense)1418 void SCIPprobSetObjsense(
1419 SCIP_PROB* prob, /**< problem data */
1420 SCIP_OBJSENSE objsense /**< new objective sense */
1421 )
1422 {
1423 assert(prob != NULL);
1424 assert(prob->objsense == SCIP_OBJSENSE_MAXIMIZE || prob->objsense == SCIP_OBJSENSE_MINIMIZE);
1425 assert(objsense == SCIP_OBJSENSE_MAXIMIZE || objsense == SCIP_OBJSENSE_MINIMIZE);
1426
1427 prob->objsense = objsense;
1428 }
1429
1430 /** adds value to objective offset */
SCIPprobAddObjoffset(SCIP_PROB * prob,SCIP_Real addval)1431 void SCIPprobAddObjoffset(
1432 SCIP_PROB* prob, /**< problem data */
1433 SCIP_Real addval /**< value to add to objective offset */
1434 )
1435 {
1436 assert(prob != NULL);
1437 assert(prob->transformed);
1438
1439 SCIPdebugMessage("adding %g to objective offset %g: new offset = %g\n", addval, prob->objoffset, prob->objoffset + addval);
1440 prob->objoffset += addval;
1441 }
1442
1443 /** sets the dual bound on objective function */
SCIPprobSetDualbound(SCIP_PROB * prob,SCIP_Real dualbound)1444 void SCIPprobSetDualbound(
1445 SCIP_PROB* prob, /**< problem data */
1446 SCIP_Real dualbound /**< external dual bound */
1447 )
1448 {
1449 assert(prob != NULL);
1450
1451 prob->dualbound = dualbound;
1452 }
1453
1454 /** sets limit on objective function, such that only solutions better than this limit are accepted */
SCIPprobSetObjlim(SCIP_PROB * prob,SCIP_Real objlim)1455 void SCIPprobSetObjlim(
1456 SCIP_PROB* prob, /**< problem data */
1457 SCIP_Real objlim /**< external objective limit */
1458 )
1459 {
1460 assert(prob != NULL);
1461
1462 prob->objlim = objlim;
1463 }
1464
1465 /** informs the problem, that its objective value is always integral in every feasible solution */
SCIPprobSetObjIntegral(SCIP_PROB * prob)1466 void SCIPprobSetObjIntegral(
1467 SCIP_PROB* prob /**< problem data */
1468 )
1469 {
1470 assert(prob != NULL);
1471
1472 prob->objisintegral = TRUE;
1473 }
1474
1475 /** sets integral objective value flag, if all variables with non-zero objective values are integral and have
1476 * integral objective value and also updates the cutoff bound if primal solution is already known
1477 */
SCIPprobCheckObjIntegral(SCIP_PROB * transprob,SCIP_PROB * origprob,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PRIMAL * primal,SCIP_TREE * tree,SCIP_REOPT * reopt,SCIP_LP * lp,SCIP_EVENTFILTER * eventfilter,SCIP_EVENTQUEUE * eventqueue)1478 SCIP_RETCODE SCIPprobCheckObjIntegral(
1479 SCIP_PROB* transprob, /**< tranformed problem data */
1480 SCIP_PROB* origprob, /**< original problem data */
1481 BMS_BLKMEM* blkmem, /**< block memory */
1482 SCIP_SET* set, /**< global SCIP settings */
1483 SCIP_STAT* stat, /**< problem statistics data */
1484 SCIP_PRIMAL* primal, /**< primal data */
1485 SCIP_TREE* tree, /**< branch and bound tree */
1486 SCIP_REOPT* reopt, /**< reoptimization data structure */
1487 SCIP_LP* lp, /**< current LP data */
1488 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
1489 SCIP_EVENTQUEUE* eventqueue /**< event queue */
1490 )
1491 {
1492 SCIP_Real obj;
1493 int v;
1494
1495 assert(transprob != NULL);
1496 assert(origprob != NULL);
1497
1498 /* if we know already, that the objective value is integral, nothing has to be done */
1499 if( transprob->objisintegral )
1500 return SCIP_OKAY;
1501
1502 /* if there exist unknown variables, we cannot conclude that the objective value is always integral */
1503 if( set->nactivepricers != 0 || set->nactivebenders != 0 )
1504 return SCIP_OKAY;
1505
1506 /* if the objective value offset is fractional, the value itself is possibly fractional */
1507 if( !SCIPsetIsIntegral(set, transprob->objoffset) )
1508 return SCIP_OKAY;
1509
1510 /* scan through the variables */
1511 for( v = 0; v < transprob->nvars; ++v )
1512 {
1513 /* get objective value of variable */
1514 obj = SCIPvarGetObj(transprob->vars[v]);
1515
1516 /* check, if objective value is non-zero */
1517 if( !SCIPsetIsZero(set, obj) )
1518 {
1519 /* if variable's objective value is fractional, the problem's objective value may also be fractional */
1520 if( !SCIPsetIsIntegral(set, obj) )
1521 break;
1522
1523 /* if variable with non-zero objective value is continuous, the problem's objective value may be fractional */
1524 if( SCIPvarGetType(transprob->vars[v]) == SCIP_VARTYPE_CONTINUOUS )
1525 break;
1526 }
1527 }
1528
1529 /* objective value is integral, if the variable loop scanned all variables */
1530 if( v == transprob->nvars )
1531 {
1532 transprob->objisintegral = TRUE;
1533
1534 /* update upper bound and cutoff bound in primal data structure due to new internality information */
1535 SCIP_CALL( SCIPprimalUpdateObjoffset(primal, blkmem, set, stat, eventfilter, eventqueue, transprob, origprob, tree, reopt, lp) );
1536 }
1537
1538 return SCIP_OKAY;
1539 }
1540
1541 /** update the number of variables with non-zero objective coefficient */
SCIPprobUpdateNObjVars(SCIP_PROB * prob,SCIP_SET * set,SCIP_Real oldobj,SCIP_Real newobj)1542 void SCIPprobUpdateNObjVars(
1543 SCIP_PROB* prob, /**< problem data */
1544 SCIP_SET* set, /**< global SCIP settings */
1545 SCIP_Real oldobj, /**< old objective value for variable */
1546 SCIP_Real newobj /**< new objective value for variable */
1547 )
1548 {
1549 assert(prob->transformed);
1550
1551 if( !SCIPsetIsZero(set, oldobj) )
1552 prob->nobjvars--;
1553
1554 if( !SCIPsetIsZero(set, newobj) )
1555 prob->nobjvars++;
1556 }
1557
1558 /** update the dual bound if its better as the current one */
SCIPprobUpdateDualbound(SCIP_PROB * prob,SCIP_Real newbound)1559 void SCIPprobUpdateDualbound(
1560 SCIP_PROB* prob, /**< problem data */
1561 SCIP_Real newbound /**< new dual bound for the node (if it's tighter than the old one) */
1562 )
1563 {
1564 if( prob->dualbound == SCIP_INVALID ) /*lint !e777*/
1565 SCIPprobSetDualbound(prob, newbound);
1566 else
1567 {
1568 switch( prob->objsense )
1569 {
1570 case SCIP_OBJSENSE_MINIMIZE:
1571 prob->dualbound = MAX(newbound, prob->dualbound);
1572 break;
1573
1574 case SCIP_OBJSENSE_MAXIMIZE:
1575 prob->dualbound = MIN(newbound, prob->dualbound);
1576 break;
1577
1578 default:
1579 SCIPerrorMessage("invalid objective sense <%d>\n", prob->objsense);
1580 SCIPABORT();
1581 }
1582 }
1583 }
1584
1585 /** invalidates the dual bound */
SCIPprobInvalidateDualbound(SCIP_PROB * prob)1586 void SCIPprobInvalidateDualbound(
1587 SCIP_PROB* prob /**< problem data */
1588 )
1589 {
1590 assert(prob != NULL);
1591
1592 prob->dualbound = SCIP_INVALID;
1593 }
1594
1595 /** if possible, scales objective function such that it is integral with gcd = 1 */
SCIPprobScaleObj(SCIP_PROB * transprob,SCIP_PROB * origprob,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PRIMAL * primal,SCIP_TREE * tree,SCIP_REOPT * reopt,SCIP_LP * lp,SCIP_EVENTFILTER * eventfilter,SCIP_EVENTQUEUE * eventqueue)1596 SCIP_RETCODE SCIPprobScaleObj(
1597 SCIP_PROB* transprob, /**< tranformed problem data */
1598 SCIP_PROB* origprob, /**< original problem data */
1599 BMS_BLKMEM* blkmem, /**< block memory */
1600 SCIP_SET* set, /**< global SCIP settings */
1601 SCIP_STAT* stat, /**< problem statistics data */
1602 SCIP_PRIMAL* primal, /**< primal data */
1603 SCIP_TREE* tree, /**< branch and bound tree */
1604 SCIP_REOPT* reopt, /**< reoptimization data structure */
1605 SCIP_LP* lp, /**< current LP data */
1606 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
1607 SCIP_EVENTQUEUE* eventqueue /**< event queue */
1608 )
1609 {
1610 int v;
1611 int nints;
1612
1613 assert(transprob != NULL);
1614 assert(set != NULL);
1615
1616 /* do not change objective if there are pricers involved */
1617 if( set->nactivepricers != 0 || set->nactivebenders != 0 || !set->misc_scaleobj )
1618 return SCIP_OKAY;
1619
1620 nints = transprob->nvars - transprob->ncontvars;
1621
1622 /* scan through the continuous variables */
1623 for( v = nints; v < transprob->nvars; ++v )
1624 {
1625 SCIP_Real obj;
1626
1627 /* get objective value of variable; it it is non-zero, no scaling can be applied */
1628 obj = SCIPvarGetObj(transprob->vars[v]);
1629 if( !SCIPsetIsZero(set, obj) )
1630 break;
1631 }
1632
1633 /* only continue if all continuous variables have obj = 0 */
1634 if( v == transprob->nvars )
1635 {
1636 SCIP_Real* objvals;
1637 SCIP_Real intscalar;
1638 SCIP_Bool success;
1639
1640 /* get temporary memory */
1641 SCIP_CALL( SCIPsetAllocBufferArray(set, &objvals, nints) );
1642
1643 /* get objective values of integer variables */
1644 for( v = 0; v < nints; ++v )
1645 objvals[v] = SCIPvarGetObj(transprob->vars[v]);
1646
1647 /* calculate integral scalar */
1648 SCIP_CALL( SCIPcalcIntegralScalar(objvals, nints, -SCIPsetEpsilon(set), +SCIPsetEpsilon(set), OBJSCALE_MAXDNOM, OBJSCALE_MAXSCALE,
1649 &intscalar, &success) );
1650
1651 SCIPsetDebugMsg(set, "integral objective scalar: success=%u, intscalar=%g\n", success, intscalar);
1652
1653 if( success )
1654 {
1655 SCIP_Longint gcd;
1656
1657 assert(intscalar > 0.0);
1658
1659 /* calculate gcd of resulting integral coefficients */
1660 gcd = 0;
1661 for( v = 0; v < nints && gcd != 1; ++v )
1662 {
1663 SCIP_Longint absobj;
1664
1665 /* if absobj exceeds maximum SCIP_Longint value, return */
1666 if( REALABS(objvals[v]) * intscalar + 0.5 > (SCIP_Real)SCIP_LONGINT_MAX )
1667 {
1668 SCIPsetFreeBufferArray(set, &objvals);
1669 return SCIP_OKAY;
1670 }
1671
1672 absobj = (SCIP_Longint)(REALABS(objvals[v]) * intscalar + 0.5);
1673 if( gcd == 0 )
1674 gcd = absobj;
1675 else if( absobj > 0 )
1676 gcd = SCIPcalcGreComDiv(gcd, absobj);
1677 }
1678 if( gcd != 0 )
1679 intscalar /= gcd;
1680 SCIPsetDebugMsg(set, "integral objective scalar: gcd=%" SCIP_LONGINT_FORMAT ", intscalar=%g\n", gcd, intscalar);
1681
1682 /* only apply scaling if the final scalar is small enough */
1683 if( intscalar <= OBJSCALE_MAXFINALSCALE )
1684 {
1685 /* apply scaling */
1686 if( !SCIPsetIsEQ(set, intscalar, 1.0) )
1687 {
1688 /* calculate scaled objective values */
1689 for( v = 0; v < nints; ++v )
1690 {
1691 SCIP_Real newobj;
1692
1693 /* check if new obj is really integral */
1694 newobj = intscalar * SCIPvarGetObj(transprob->vars[v]);
1695 if( !SCIPsetIsFeasIntegral(set, newobj) )
1696 break;
1697 objvals[v] = SCIPsetFeasFloor(set, newobj);
1698 }
1699
1700 /* change the variables' objective values and adjust objscale and objoffset */
1701 if( v == nints )
1702 {
1703 for( v = 0; v < nints; ++v )
1704 {
1705 SCIPsetDebugMsg(set, " -> var <%s>: newobj = %.6f\n", SCIPvarGetName(transprob->vars[v]), objvals[v]);
1706 SCIP_CALL( SCIPvarChgObj(transprob->vars[v], blkmem, set, transprob, primal, lp, eventqueue, objvals[v]) );
1707 }
1708 transprob->objoffset *= intscalar;
1709 transprob->objscale /= intscalar;
1710 transprob->objisintegral = TRUE;
1711 SCIPsetDebugMsg(set, "integral objective scalar: objscale=%g\n", transprob->objscale);
1712
1713 /* update upperbound and cutoffbound in primal data structure */
1714 SCIP_CALL( SCIPprimalUpdateObjoffset(primal, blkmem, set, stat, eventfilter, eventqueue, transprob, origprob, tree, reopt, lp) );
1715 }
1716 }
1717 }
1718 }
1719
1720 /* free temporary memory */
1721 SCIPsetFreeBufferArray(set, &objvals);
1722 }
1723
1724 return SCIP_OKAY;
1725 }
1726
1727 /** remembers the current solution as root solution in the problem variables */
SCIPprobStoreRootSol(SCIP_PROB * prob,SCIP_SET * set,SCIP_STAT * stat,SCIP_LP * lp,SCIP_Bool roothaslp)1728 void SCIPprobStoreRootSol(
1729 SCIP_PROB* prob, /**< problem data */
1730 SCIP_SET* set, /**< global SCIP settings */
1731 SCIP_STAT* stat, /**< SCIP statistics */
1732 SCIP_LP* lp, /**< current LP data */
1733 SCIP_Bool roothaslp /**< is the root solution from LP? */
1734 )
1735 {
1736 int v;
1737
1738 assert(prob != NULL);
1739 assert(prob->transformed);
1740
1741 if( roothaslp )
1742 {
1743 for( v = 0; v < prob->nvars; ++v )
1744 SCIPvarStoreRootSol(prob->vars[v], roothaslp);
1745
1746 SCIPlpSetRootLPIsRelax(lp, SCIPlpIsRelax(lp));
1747 SCIPlpStoreRootObjval(lp, set, prob);
1748
1749 /* compute root LP best-estimate */
1750 SCIPstatComputeRootLPBestEstimate(stat, set, SCIPlpGetColumnObjval(lp), prob->vars, prob->nbinvars + prob->nintvars + prob->nimplvars);
1751 }
1752 }
1753
1754 /** remembers the best solution w.r.t. root reduced cost propagation as root solution in the problem variables */
SCIPprobUpdateBestRootSol(SCIP_PROB * prob,SCIP_SET * set,SCIP_STAT * stat,SCIP_LP * lp)1755 void SCIPprobUpdateBestRootSol(
1756 SCIP_PROB* prob, /**< problem data */
1757 SCIP_SET* set, /**< global SCIP settings */
1758 SCIP_STAT* stat, /**< problem statistics */
1759 SCIP_LP* lp /**< current LP data */
1760 )
1761 {
1762 SCIP_Real rootlpobjval;
1763 int v;
1764
1765 assert(prob != NULL);
1766 assert(lp != NULL);
1767 assert(prob->transformed);
1768 assert(lp->lpsolstat == SCIP_LPSOLSTAT_OPTIMAL);
1769
1770 /* in case we have a zero objective fucntion, we skip the root reduced cost update */
1771 if( SCIPprobGetNObjVars(prob, set) == 0 )
1772 return;
1773
1774 if( !SCIPlpIsDualReliable(lp) )
1775 return;
1776
1777 SCIPsetDebugMsg(set, "update root reduced costs\n");
1778
1779 /* compute current root LP objective value */
1780 rootlpobjval = SCIPlpGetObjval(lp, set, prob);
1781 assert(rootlpobjval != SCIP_INVALID); /*lint !e777*/
1782
1783 for( v = 0; v < prob->nvars; ++v )
1784 {
1785 SCIP_VAR* var;
1786 SCIP_COL* col;
1787 SCIP_Real rootsol = 0.0;
1788 SCIP_Real rootredcost = 0.0;
1789
1790 var = prob->vars[v];
1791 assert(var != NULL);
1792
1793 /* check if the variable is part of the LP */
1794 if( SCIPvarGetStatus(var) != SCIP_VARSTATUS_COLUMN )
1795 continue;
1796
1797 col = SCIPvarGetCol(var);
1798 assert(col != NULL);
1799
1800 assert(SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_OPTIMAL);
1801
1802 if( !SCIPvarIsBinary(var) )
1803 {
1804 rootsol = SCIPvarGetSol(var, TRUE);
1805 rootredcost = SCIPcolGetRedcost(col, stat, lp);
1806 }
1807 else
1808 {
1809 SCIP_Real primsol;
1810 SCIP_BASESTAT basestat;
1811 SCIP_Bool lpissolbasic;
1812
1813 basestat = SCIPcolGetBasisStatus(col);
1814 lpissolbasic = SCIPlpIsSolBasic(lp);
1815 primsol = SCIPcolGetPrimsol(col);
1816
1817 if( (lpissolbasic && (basestat == SCIP_BASESTAT_LOWER || basestat == SCIP_BASESTAT_UPPER)) ||
1818 (!lpissolbasic && (SCIPsetIsFeasEQ(set, SCIPvarGetLbLocal(var), primsol) ||
1819 SCIPsetIsFeasEQ(set, SCIPvarGetUbLocal(var), primsol))) )
1820 {
1821 SCIP_Real lbrootredcost;
1822 SCIP_Real ubrootredcost;
1823
1824 /* get reduced cost if the variable gets fixed to zero */
1825 lbrootredcost = SCIPvarGetImplRedcost(var, set, FALSE, stat, prob, lp);
1826 assert( !SCIPsetIsDualfeasPositive(set, lbrootredcost)
1827 || SCIPsetIsFeasEQ(set, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)));
1828
1829 /* get reduced cost if the variable gets fixed to one */
1830 ubrootredcost = SCIPvarGetImplRedcost(var, set, TRUE, stat, prob, lp);
1831 assert( !SCIPsetIsDualfeasNegative(set, ubrootredcost)
1832 || SCIPsetIsFeasEQ(set, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)));
1833
1834 if( -lbrootredcost > ubrootredcost )
1835 {
1836 rootredcost = lbrootredcost;
1837 rootsol = 1.0;
1838 }
1839 else
1840 {
1841 rootredcost = ubrootredcost;
1842 rootsol = 0.0;
1843 }
1844 }
1845 }
1846
1847 /* update the current solution as best root solution in the problem variables if it is better */
1848 SCIPvarUpdateBestRootSol(var, set, rootsol, rootredcost, rootlpobjval);
1849 }
1850 }
1851
1852 /** informs problem, that the presolving process was finished, and updates all internal data structures */ /*lint -e715*/
SCIPprobExitPresolve(SCIP_PROB * prob,SCIP_SET * set)1853 SCIP_RETCODE SCIPprobExitPresolve(
1854 SCIP_PROB* prob, /**< problem data */
1855 SCIP_SET* set /**< global SCIP settings */
1856 )
1857 { /*lint --e{715}*/
1858 return SCIP_OKAY;
1859 }
1860
1861 /** initializes problem for branch and bound process and resets all constraint's ages and histories of current run */
SCIPprobInitSolve(SCIP_PROB * prob,SCIP_SET * set)1862 SCIP_RETCODE SCIPprobInitSolve(
1863 SCIP_PROB* prob, /**< problem data */
1864 SCIP_SET* set /**< global SCIP settings */
1865 )
1866 {
1867 int c;
1868 int v;
1869
1870 assert(prob != NULL);
1871 assert(prob->transformed);
1872 assert(set != NULL);
1873
1874 /* reset constraint's ages */
1875 for( c = 0; c < prob->nconss; ++c )
1876 {
1877 SCIP_CALL( SCIPconsResetAge(prob->conss[c], set) );
1878 }
1879
1880 /* initialize variables for solving */
1881 for( v = 0; v < prob->nvars; ++v )
1882 SCIPvarInitSolve(prob->vars[v]);
1883
1884 /* call user data function */
1885 if( prob->probinitsol != NULL )
1886 {
1887 SCIP_CALL( prob->probinitsol(set->scip, prob->probdata) );
1888 }
1889
1890 /* assert that the counter for variables with nonzero objective is correct */
1891 assert(prob->nobjvars == SCIPprobGetNObjVars(prob, set));
1892
1893 return SCIP_OKAY;
1894 }
1895
1896 /** deinitializes problem after branch and bound process, and converts all COLUMN variables back into LOOSE variables */
SCIPprobExitSolve(SCIP_PROB * prob,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp,SCIP_Bool restart)1897 SCIP_RETCODE SCIPprobExitSolve(
1898 SCIP_PROB* prob, /**< problem data */
1899 BMS_BLKMEM* blkmem, /**< block memory */
1900 SCIP_SET* set, /**< global SCIP settings */
1901 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1902 SCIP_LP* lp, /**< current LP data */
1903 SCIP_Bool restart /**< was this exit solve call triggered by a restart? */
1904 )
1905 {
1906 SCIP_VAR* var;
1907 int v;
1908
1909 assert(prob != NULL);
1910 assert(prob->transformed);
1911 assert(set != NULL);
1912
1913 /* call user data function */
1914 if( prob->probexitsol != NULL )
1915 {
1916 SCIP_CALL( prob->probexitsol(set->scip, prob->probdata, restart) );
1917 }
1918
1919 /* convert all COLUMN variables back into LOOSE variables */
1920 if( prob->ncolvars > 0 )
1921 {
1922 for( v = 0; v < prob->nvars; ++v )
1923 {
1924 var = prob->vars[v];
1925 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN )
1926 {
1927 SCIP_CALL( SCIPvarLoose(var, blkmem, set, eventqueue, prob, lp) );
1928 }
1929
1930 /* invalidate root reduced cost, root reduced solution, and root LP objective value for each variable */
1931 SCIPvarSetBestRootSol(var, 0.0, 0.0, SCIP_INVALID);
1932 }
1933 }
1934 assert(prob->ncolvars == 0);
1935
1936 return SCIP_OKAY;
1937 }
1938
1939
1940
1941
1942 /*
1943 * problem information
1944 */
1945
1946 /** sets problem name */
SCIPprobSetName(SCIP_PROB * prob,const char * name)1947 SCIP_RETCODE SCIPprobSetName(
1948 SCIP_PROB* prob, /**< problem data */
1949 const char* name /**< name to be set */
1950 )
1951 {
1952 assert(prob != NULL);
1953
1954 BMSfreeMemoryArray(&(prob->name));
1955 SCIP_ALLOC( BMSduplicateMemoryArray(&(prob->name), name, strlen(name)+1) );
1956
1957 return SCIP_OKAY;
1958 }
1959
1960 /** returns the number of implicit binary variables, meaning variable of vartype != SCIP_VARTYPE_BINARY and !=
1961 * SCIP_VARTYPE_CONTINUOUS but with global bounds [0,1]
1962 *
1963 * @note this number needs to be computed, because it cannot be updated like the other counters for binary and integer
1964 * variables, each time the variable type changes(, we would need to update this counter each time a global bound
1965 * changes), even at the end of presolving this cannot be computed, because some variable can change to an
1966 * implicit binary status
1967 */
SCIPprobGetNImplBinVars(SCIP_PROB * prob)1968 int SCIPprobGetNImplBinVars(
1969 SCIP_PROB* prob /**< problem data */
1970 )
1971 {
1972 int v;
1973 int nimplbinvars = 0;
1974
1975 for( v = prob->nbinvars + prob->nintvars + prob->nimplvars - 1; v >= prob->nbinvars; --v )
1976 {
1977 if( SCIPvarIsBinary(prob->vars[v]) )
1978 ++nimplbinvars;
1979 }
1980
1981 return nimplbinvars;
1982 }
1983
1984 /** returns the number of variables with non-zero objective coefficient */
SCIPprobGetNObjVars(SCIP_PROB * prob,SCIP_SET * set)1985 int SCIPprobGetNObjVars(
1986 SCIP_PROB* prob, /**< problem data */
1987 SCIP_SET* set /**< global SCIP settings */
1988 )
1989 {
1990 if( prob->transformed )
1991 {
1992 /* this is much too expensive, to check it in each debug run */
1993 #ifdef SCIP_MORE_DEBUG
1994 int nobjvars;
1995 int v;
1996
1997 nobjvars = 0;
1998
1999 for( v = prob->nvars - 1; v >= 0; --v )
2000 {
2001 if( !SCIPsetIsZero(set, SCIPvarGetObj(prob->vars[v])) )
2002 nobjvars++;
2003 }
2004
2005 /* check that the internal count is correct */
2006 assert(prob->nobjvars == nobjvars);
2007 #endif
2008 return prob->nobjvars;
2009 }
2010 else
2011 {
2012 int nobjvars;
2013 int v;
2014
2015 nobjvars = 0;
2016
2017 for( v = prob->nvars - 1; v >= 0; --v )
2018 {
2019 if( !SCIPsetIsZero(set, SCIPvarGetObj(prob->vars[v])) )
2020 nobjvars++;
2021 }
2022 return nobjvars;
2023 }
2024 }
2025
2026 /** returns the minimal absolute non-zero objective coefficient
2027 *
2028 * @note currently, this is only used for statistics and printed after the solving process. if this information is
2029 * needed during the (pre)solving process this should be implemented more efficiently, e.g., updating the minimal
2030 * absolute non-zero coefficient every time an objective coefficient has changed.
2031 */
SCIPprobGetAbsMinObjCoef(SCIP_PROB * prob,SCIP_SET * set)2032 SCIP_Real SCIPprobGetAbsMinObjCoef(
2033 SCIP_PROB* prob, /**< problem data */
2034 SCIP_SET* set /**< global SCIP settings */
2035 )
2036 {
2037 SCIP_Real absmin;
2038 int v;
2039
2040 absmin = SCIPsetInfinity(set);
2041
2042 for( v = 0; v < prob->nvars; v++ )
2043 {
2044 SCIP_Real objcoef = SCIPvarGetObj(prob->vars[v]);
2045
2046 if( !SCIPsetIsZero(set, objcoef) && SCIPsetIsLT(set, REALABS(objcoef), absmin) )
2047 absmin = REALABS(objcoef);
2048 }
2049
2050 return absmin;
2051 }
2052
2053 /** returns the maximal absolute non-zero objective coefficient
2054 *
2055 * @note currently, this is only used for statistics and printed after the solving process. if this information is
2056 * needed during the (pre)solving process this should be implemented more efficiently, e.g., updating the maximal
2057 * absolute non-zero coefficient every time an objective coefficient has changed.
2058 */
SCIPprobGetAbsMaxObjCoef(SCIP_PROB * prob,SCIP_SET * set)2059 SCIP_Real SCIPprobGetAbsMaxObjCoef(
2060 SCIP_PROB* prob, /**< problem data */
2061 SCIP_SET* set /**< global SCIP settings */
2062 )
2063 {
2064 SCIP_Real absmax;
2065 int v;
2066
2067 absmax = -SCIPsetInfinity(set);
2068
2069 for( v = 0; v < prob->nvars; v++ )
2070 {
2071 SCIP_Real objcoef = SCIPvarGetObj(prob->vars[v]);
2072
2073 if( !SCIPsetIsZero(set, objcoef) && SCIPsetIsGT(set, REALABS(objcoef), absmax) )
2074 absmax = REALABS(objcoef);
2075 }
2076
2077 return absmax;
2078 }
2079
2080
2081 /** returns the external value of the given internal objective value */
SCIPprobExternObjval(SCIP_PROB * transprob,SCIP_PROB * origprob,SCIP_SET * set,SCIP_Real objval)2082 SCIP_Real SCIPprobExternObjval(
2083 SCIP_PROB* transprob, /**< tranformed problem data */
2084 SCIP_PROB* origprob, /**< original problem data */
2085 SCIP_SET* set, /**< global SCIP settings */
2086 SCIP_Real objval /**< internal objective value */
2087 )
2088 {
2089 assert(set != NULL);
2090 assert(origprob != NULL);
2091 assert(transprob != NULL);
2092 assert(transprob->transformed);
2093 assert(transprob->objscale > 0.0);
2094
2095 if( SCIPsetIsInfinity(set, objval) )
2096 return (SCIP_Real)transprob->objsense * SCIPsetInfinity(set);
2097 else if( SCIPsetIsInfinity(set, -objval) )
2098 return -(SCIP_Real)transprob->objsense * SCIPsetInfinity(set);
2099 else
2100 return (SCIP_Real)transprob->objsense * transprob->objscale * (objval + transprob->objoffset) + origprob->objoffset;
2101 }
2102
2103 /** returns the internal value of the given external objective value */
SCIPprobInternObjval(SCIP_PROB * transprob,SCIP_PROB * origprob,SCIP_SET * set,SCIP_Real objval)2104 SCIP_Real SCIPprobInternObjval(
2105 SCIP_PROB* transprob, /**< tranformed problem data */
2106 SCIP_PROB* origprob, /**< original problem data */
2107 SCIP_SET* set, /**< global SCIP settings */
2108 SCIP_Real objval /**< external objective value */
2109 )
2110 {
2111 assert(set != NULL);
2112 assert(origprob != NULL);
2113 assert(transprob != NULL);
2114 assert(transprob->transformed);
2115 assert(transprob->objscale > 0.0);
2116
2117 if( SCIPsetIsInfinity(set, objval) )
2118 return (SCIP_Real)transprob->objsense * SCIPsetInfinity(set);
2119 else if( SCIPsetIsInfinity(set, -objval) )
2120 return -(SCIP_Real)transprob->objsense * SCIPsetInfinity(set);
2121 else
2122 return (SCIP_Real)transprob->objsense * (objval - origprob->objoffset)/transprob->objscale - transprob->objoffset;
2123 }
2124
2125 /** returns variable of the problem with given name */
SCIPprobFindVar(SCIP_PROB * prob,const char * name)2126 SCIP_VAR* SCIPprobFindVar(
2127 SCIP_PROB* prob, /**< problem data */
2128 const char* name /**< name of variable to find */
2129 )
2130 {
2131 assert(prob != NULL);
2132 assert(name != NULL);
2133
2134 if( prob->varnames == NULL )
2135 {
2136 SCIPerrorMessage("Cannot find variable if variable-names hashtable was disabled (due to parameter <misc/usevartable>)\n");
2137 SCIPABORT();/*lint --e{527}*/ /* only in debug mode */
2138 return NULL;
2139 }
2140
2141 return (SCIP_VAR*)(SCIPhashtableRetrieve(prob->varnames, (char*)name));
2142 }
2143
2144 /** returns constraint of the problem with given name */
SCIPprobFindCons(SCIP_PROB * prob,const char * name)2145 SCIP_CONS* SCIPprobFindCons(
2146 SCIP_PROB* prob, /**< problem data */
2147 const char* name /**< name of variable to find */
2148 )
2149 {
2150 assert(prob != NULL);
2151 assert(name != NULL);
2152
2153 if( prob->consnames == NULL )
2154 {
2155 SCIPerrorMessage("Cannot find constraint if constraint-names hashtable was disabled (due to parameter <misc/useconstable>)\n");
2156 SCIPABORT();/*lint --e{527}*/ /* only in debug mode */
2157 return NULL;
2158 }
2159
2160 return (SCIP_CONS*)(SCIPhashtableRetrieve(prob->consnames, (char*)name));
2161 }
2162
2163 /** displays current pseudo solution */
SCIPprobPrintPseudoSol(SCIP_PROB * prob,SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr)2164 void SCIPprobPrintPseudoSol(
2165 SCIP_PROB* prob, /**< problem data */
2166 SCIP_SET* set, /**< global SCIP settings */
2167 SCIP_MESSAGEHDLR* messagehdlr /**< message handler */
2168 )
2169 {
2170 SCIP_VAR* var;
2171 SCIP_Real solval;
2172 int v;
2173
2174 for( v = 0; v < prob->nvars; ++v )
2175 {
2176 var = prob->vars[v];
2177 assert(var != NULL);
2178 solval = SCIPvarGetPseudoSol(var);
2179 if( !SCIPsetIsZero(set, solval) )
2180 SCIPmessagePrintInfo(messagehdlr, " <%s>=%.15g", SCIPvarGetName(var), solval);
2181 }
2182 SCIPmessagePrintInfo(messagehdlr, "\n");
2183 }
2184
2185 /** outputs problem statistics */
SCIPprobPrintStatistics(SCIP_PROB * prob,SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr,FILE * file)2186 void SCIPprobPrintStatistics(
2187 SCIP_PROB* prob, /**< problem data */
2188 SCIP_SET* set, /**< global SCIP settings */
2189 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
2190 FILE* file /**< output file (or NULL for standard output) */
2191 )
2192 {
2193 assert(prob != NULL);
2194
2195 SCIPmessageFPrintInfo(messagehdlr, file, " Problem name : %s\n", prob->name);
2196 SCIPmessageFPrintInfo(messagehdlr, file, " Variables : %d (%d binary, %d integer, %d implicit integer, %d continuous)\n",
2197 prob->nvars, prob->nbinvars, prob->nintvars, prob->nimplvars, prob->ncontvars);
2198 SCIPmessageFPrintInfo(messagehdlr, file, " Constraints : %d initial, %d maximal\n", prob->startnconss, prob->maxnconss);
2199 SCIPmessageFPrintInfo(messagehdlr, file, " Objective : %s, %d non-zeros (abs.min = %g, abs.max = %g)\n",
2200 !prob->transformed ? (prob->objsense == SCIP_OBJSENSE_MINIMIZE ? "minimize" : "maximize") : "minimize",
2201 SCIPprobGetNObjVars(prob, set), SCIPprobGetAbsMinObjCoef(prob, set), SCIPprobGetAbsMaxObjCoef(prob, set));
2202 }
2203
2204
2205 #ifndef NDEBUG
2206
2207 /* In debug mode, the following methods are implemented as function calls to ensure
2208 * type validity.
2209 * In optimized mode, the methods are implemented as defines to improve performance.
2210 * However, we want to have them in the library anyways, so we have to undef the defines.
2211 */
2212
2213 #undef SCIPprobIsPermuted
2214 #undef SCIPprobMarkPermuted
2215 #undef SCIPprobIsTransformed
2216 #undef SCIPprobIsObjIntegral
2217 #undef SCIPprobAllColsInLP
2218 #undef SCIPprobGetObjlim
2219 #undef SCIPprobGetData
2220 #undef SCIPprobGetName
2221 #undef SCIPprobGetNVars
2222 #undef SCIPprobGetNBinVars
2223 #undef SCIPprobGetNIntVars
2224 #undef SCIPprobGetNImplVars
2225 #undef SCIPprobGetNContVars
2226 #undef SCIPprobGetNConss
2227 #undef SCIPprobGetVars
2228 #undef SCIPprobGetObjoffset
2229 #undef SCIPisConsCompressedEnabled
2230 #undef SCIPprobEnableConsCompression
2231
2232 /** is the problem permuted */
SCIPprobIsPermuted(SCIP_PROB * prob)2233 SCIP_Bool SCIPprobIsPermuted(
2234 SCIP_PROB* prob
2235 )
2236 {
2237 assert(prob != NULL);
2238
2239 return prob->permuted;
2240 }
2241
2242 /** mark the problem as permuted */
SCIPprobMarkPermuted(SCIP_PROB * prob)2243 void SCIPprobMarkPermuted(
2244 SCIP_PROB* prob
2245 )
2246 {
2247 assert(prob != NULL);
2248
2249 prob->permuted = TRUE;
2250 }
2251
2252 /** is the problem data transformed */
SCIPprobIsTransformed(SCIP_PROB * prob)2253 SCIP_Bool SCIPprobIsTransformed(
2254 SCIP_PROB* prob /**< problem data */
2255 )
2256 {
2257 assert(prob != NULL);
2258
2259 return prob->transformed;
2260 }
2261
2262 /** returns whether the objective value is known to be integral in every feasible solution */
SCIPprobIsObjIntegral(SCIP_PROB * prob)2263 SCIP_Bool SCIPprobIsObjIntegral(
2264 SCIP_PROB* prob /**< problem data */
2265 )
2266 {
2267 assert(prob != NULL);
2268
2269 return prob->objisintegral;
2270 }
2271
2272 /** returns TRUE iff all columns, i.e. every variable with non-empty column w.r.t. all ever created rows, are present
2273 * in the LP, and FALSE, if there are additional already existing columns, that may be added to the LP in pricing
2274 */
SCIPprobAllColsInLP(SCIP_PROB * prob,SCIP_SET * set,SCIP_LP * lp)2275 SCIP_Bool SCIPprobAllColsInLP(
2276 SCIP_PROB* prob, /**< problem data */
2277 SCIP_SET* set, /**< global SCIP settings */
2278 SCIP_LP* lp /**< current LP data */
2279 )
2280 {
2281 assert(SCIPlpGetNCols(lp) <= prob->ncolvars && prob->ncolvars <= prob->nvars);
2282
2283 return (SCIPlpGetNCols(lp) == prob->ncolvars && set->nactivepricers == 0);
2284 }
2285
2286 /** gets limit on objective function in external space */
SCIPprobGetObjlim(SCIP_PROB * prob,SCIP_SET * set)2287 SCIP_Real SCIPprobGetObjlim(
2288 SCIP_PROB* prob, /**< problem data */
2289 SCIP_SET* set /**< global SCIP settings */
2290 )
2291 {
2292 assert(prob != NULL);
2293 assert(set != NULL);
2294
2295 return prob->objlim >= SCIP_INVALID ? (SCIP_Real)(prob->objsense) * SCIPsetInfinity(set) : prob->objlim;
2296 }
2297
2298 /** gets user problem data */
SCIPprobGetData(SCIP_PROB * prob)2299 SCIP_PROBDATA* SCIPprobGetData(
2300 SCIP_PROB* prob /**< problem */
2301 )
2302 {
2303 assert(prob != NULL);
2304
2305 return prob->probdata;
2306 }
2307
2308 /** gets problem name */
SCIPprobGetName(SCIP_PROB * prob)2309 const char* SCIPprobGetName(
2310 SCIP_PROB* prob /**< problem data */
2311 )
2312 {
2313 assert(prob != NULL);
2314 return prob->name;
2315 }
2316
2317 /** gets number of problem variables */
SCIPprobGetNVars(SCIP_PROB * prob)2318 int SCIPprobGetNVars(
2319 SCIP_PROB* prob /**< problem data */
2320 )
2321 {
2322 assert(prob != NULL);
2323 return prob->nvars;
2324 }
2325
2326 /** gets number of binary problem variables */
SCIPprobGetNBinVars(SCIP_PROB * prob)2327 int SCIPprobGetNBinVars(
2328 SCIP_PROB* prob /**< problem data */
2329 )
2330 {
2331 assert(prob != NULL);
2332 return prob->nbinvars;
2333 }
2334
2335 /** gets number of integer problem variables */
SCIPprobGetNIntVars(SCIP_PROB * prob)2336 int SCIPprobGetNIntVars(
2337 SCIP_PROB* prob /**< problem data */
2338 )
2339 {
2340 assert(prob != NULL);
2341 return prob->nintvars;
2342 }
2343
2344 /** gets number of implicit integer problem variables */
SCIPprobGetNImplVars(SCIP_PROB * prob)2345 int SCIPprobGetNImplVars(
2346 SCIP_PROB* prob /**< problem data */
2347 )
2348 {
2349 assert(prob != NULL);
2350 return prob->nimplvars;
2351 }
2352
2353 /** gets number of continuous problem variables */
SCIPprobGetNContVars(SCIP_PROB * prob)2354 int SCIPprobGetNContVars(
2355 SCIP_PROB* prob /**< problem data */
2356 )
2357 {
2358 assert(prob != NULL);
2359 return prob->ncontvars;
2360 }
2361
2362 /** gets problem variables */
SCIPprobGetVars(SCIP_PROB * prob)2363 SCIP_VAR** SCIPprobGetVars(
2364 SCIP_PROB* prob /**< problem data */
2365 )
2366 {
2367 assert(prob != NULL);
2368 return prob->vars;
2369 }
2370
2371 /** gets number of problem constraints */
SCIPprobGetNConss(SCIP_PROB * prob)2372 int SCIPprobGetNConss(
2373 SCIP_PROB* prob /**< problem data */
2374 )
2375 {
2376 assert(prob != NULL);
2377 return prob->nconss;
2378 }
2379
2380 /** gets the objective offset */
SCIPprobGetObjoffset(SCIP_PROB * prob)2381 SCIP_Real SCIPprobGetObjoffset(
2382 SCIP_PROB* prob /**< problem data */
2383 )
2384 {
2385 assert(prob != NULL);
2386 return prob->objoffset;
2387 }
2388
2389 /** gets the objective scalar */
SCIPprobGetObjscale(SCIP_PROB * prob)2390 SCIP_Real SCIPprobGetObjscale(
2391 SCIP_PROB* prob /**< problem data */
2392 )
2393 {
2394 assert(prob != NULL);
2395 return prob->objscale;
2396 }
2397
2398 /** is constraint compression enabled for this problem? */
SCIPprobIsConsCompressionEnabled(SCIP_PROB * prob)2399 SCIP_Bool SCIPprobIsConsCompressionEnabled(
2400 SCIP_PROB* prob /**< problem data */
2401 )
2402 {
2403 assert(prob != NULL);
2404
2405 return prob->conscompression;
2406 }
2407
2408 /** enable problem compression, i.e., constraints can reduce memory size by removing fixed variables during creation */
SCIPprobEnableConsCompression(SCIP_PROB * prob)2409 void SCIPprobEnableConsCompression(
2410 SCIP_PROB* prob /**< problem data */
2411 )
2412 {
2413 assert(prob != NULL);
2414
2415 prob->conscompression = TRUE;
2416 }
2417
2418 #endif
2419