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