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   lp.c
17  * @ingroup OTHER_CFILES
18  * @brief  LP management methods and data structures
19  * @author Tobias Achterberg
20  * @author Timo Berthold
21  * @author Marc Pfetsch
22  * @author Kati Wolter
23  * @author Gerald Gamrath
24  *
25  *  In LP management, we have to differ between the current LP and the SCIP_LP
26  *  stored in the LP solver. All LP methods affect the current LP only.
27  *  Before solving the current LP with the LP solver or setting an LP state,
28  *  the LP solvers data has to be updated to the current LP with a call to
29  *  lpFlush().
30  */
31 
32 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
33 
34 
35 #include "lpi/lpi.h"
36 #include "scip/clock.h"
37 #include "scip/cons.h"
38 #include "scip/event.h"
39 #include "scip/intervalarith.h"
40 #include "scip/lp.h"
41 #include "scip/misc.h"
42 #include "scip/prob.h"
43 #include "scip/pub_lp.h"
44 #include "scip/pub_message.h"
45 #include "scip/pub_misc.h"
46 #include "scip/pub_misc_sort.h"
47 #include "scip/pub_var.h"
48 #include "scip/set.h"
49 #include "scip/sol.h"
50 #include "scip/solve.h"
51 #include "scip/stat.h"
52 #include "scip/struct_event.h"
53 #include "scip/struct_lp.h"
54 #include "scip/struct_prob.h"
55 #include "scip/struct_set.h"
56 #include "scip/struct_stat.h"
57 #include "scip/struct_var.h"
58 #include "scip/var.h"
59 #include <string.h>
60 
61 
62 
63 /*
64  * debug messages
65  */
66 
67 #ifdef SCIP_DEBUG
68 /** method is to print in row in case SCIP_DEBUG is defined */
69 static
debugRowPrint(SCIP_SET * set,SCIP_ROW * row)70 void debugRowPrint(
71    SCIP_SET*             set,                /**< global SCIP settings */
72    SCIP_ROW*             row                 /**< LP row */
73    )
74 {
75    int i;
76 
77    assert(row != NULL);
78 
79    /* print row name */
80    if( row->name != NULL && row->name[0] != '\0' )
81    {
82       SCIPsetDebugMsgPrint(set, "%s: ", row->name);
83    }
84 
85    /* print left hand side */
86    SCIPsetDebugMsgPrint(set, "%.15g <= ", row->lhs);
87 
88    /* print coefficients */
89    if( row->len == 0 )
90    {
91       SCIPsetDebugMsgPrint(set, "0 ");
92    }
93    for( i = 0; i < row->len; ++i )
94    {
95       assert(row->cols[i] != NULL);
96       assert(row->cols[i]->var != NULL);
97       assert(SCIPvarGetName(row->cols[i]->var) != NULL);
98       assert(SCIPvarGetStatus(row->cols[i]->var) == SCIP_VARSTATUS_COLUMN);
99       SCIPsetDebugMsgPrint(set, "%+.15g<%s> ", row->vals[i], SCIPvarGetName(row->cols[i]->var));
100    }
101 
102    /* print constant */
103    if( REALABS(row->constant) > SCIP_DEFAULT_EPSILON )
104    {
105       SCIPsetDebugMsgPrint(set, "%+.15g ", row->constant);
106    }
107 
108    /* print right hand side */
109    SCIPsetDebugMsgPrint(set, "<= %.15g\n", row->rhs);
110 }
111 #else
112 #define debugRowPrint(x,y) /**/
113 #endif
114 
115 #ifdef SCIP_DEBUG
116 /** method to output column if SCIP_DEBUG is define */
117 static
debugColPrint(SCIP_SET * set,SCIP_COL * col)118 void debugColPrint(
119    SCIP_SET*             set,                /**< global SCIP settings */
120    SCIP_COL*             col                 /**< LP column */
121    )
122 {
123    int r;
124 
125    assert(col != NULL);
126    assert(col->var != NULL);
127 
128    /* print bounds */
129    SCIPsetDebugMsgPrint(set, "(obj: %.15g) [%.15g,%.15g], ", col->obj, col->lb, col->ub);
130 
131    /* print coefficients */
132    if( col->len == 0 )
133    {
134       SCIPsetDebugMsgPrint(set, "<empty>");
135    }
136    for( r = 0; r < col->len; ++r )
137    {
138       assert(col->rows[r] != NULL);
139       assert(col->rows[r]->name != NULL);
140       SCIPsetDebugMsgPrint(set, "%+.15g<%s> ", col->vals[r], col->rows[r]->name);
141    }
142    SCIPsetDebugMsgPrint(set, "\n");
143 }
144 #else
145 #define debugColPrint(x,y) /**/
146 #endif
147 
148 /*
149  * memory growing methods for dynamically allocated arrays
150  */
151 
152 /** ensures, that chgcols array can store at least num entries */
153 static
ensureChgcolsSize(SCIP_LP * lp,SCIP_SET * set,int num)154 SCIP_RETCODE ensureChgcolsSize(
155    SCIP_LP*              lp,                 /**< current LP data */
156    SCIP_SET*             set,                /**< global SCIP settings */
157    int                   num                 /**< minimum number of entries to store */
158    )
159 {
160    assert(lp->nchgcols <= lp->chgcolssize);
161 
162    if( num > lp->chgcolssize )
163    {
164       int newsize;
165 
166       newsize = SCIPsetCalcMemGrowSize(set, num);
167       SCIP_ALLOC( BMSreallocMemoryArray(&lp->chgcols, newsize) );
168       lp->chgcolssize = newsize;
169    }
170    assert(num <= lp->chgcolssize);
171 
172    return SCIP_OKAY;
173 }
174 
175 /** ensures, that chgrows array can store at least num entries */
176 static
ensureChgrowsSize(SCIP_LP * lp,SCIP_SET * set,int num)177 SCIP_RETCODE ensureChgrowsSize(
178    SCIP_LP*              lp,                 /**< current LP data */
179    SCIP_SET*             set,                /**< global SCIP settings */
180    int                   num                 /**< minimum number of entries to store */
181    )
182 {
183    assert(lp->nchgrows <= lp->chgrowssize);
184 
185    if( num > lp->chgrowssize )
186    {
187       int newsize;
188 
189       newsize = SCIPsetCalcMemGrowSize(set, num);
190       SCIP_ALLOC( BMSreallocMemoryArray(&lp->chgrows, newsize) );
191       lp->chgrowssize = newsize;
192    }
193    assert(num <= lp->chgrowssize);
194 
195    return SCIP_OKAY;
196 }
197 
198 /** ensures, that lpicols array can store at least num entries */
199 static
ensureLpicolsSize(SCIP_LP * lp,SCIP_SET * set,int num)200 SCIP_RETCODE ensureLpicolsSize(
201    SCIP_LP*              lp,                 /**< current LP data */
202    SCIP_SET*             set,                /**< global SCIP settings */
203    int                   num                 /**< minimum number of entries to store */
204    )
205 {
206    assert(lp->nlpicols <= lp->lpicolssize);
207 
208    if( num > lp->lpicolssize )
209    {
210       int newsize;
211 
212       newsize = SCIPsetCalcMemGrowSize(set, num);
213       SCIP_ALLOC( BMSreallocMemoryArray(&lp->lpicols, newsize) );
214       lp->lpicolssize = newsize;
215    }
216    assert(num <= lp->lpicolssize);
217 
218    return SCIP_OKAY;
219 }
220 
221 /** ensures, that lpirows array can store at least num entries */
222 static
ensureLpirowsSize(SCIP_LP * lp,SCIP_SET * set,int num)223 SCIP_RETCODE ensureLpirowsSize(
224    SCIP_LP*              lp,                 /**< current LP data */
225    SCIP_SET*             set,                /**< global SCIP settings */
226    int                   num                 /**< minimum number of entries to store */
227    )
228 {
229    assert(lp->nlpirows <= lp->lpirowssize);
230 
231    if( num > lp->lpirowssize )
232    {
233       int newsize;
234 
235       newsize = SCIPsetCalcMemGrowSize(set, num);
236       SCIP_ALLOC( BMSreallocMemoryArray(&lp->lpirows, newsize) );
237       lp->lpirowssize = newsize;
238    }
239    assert(num <= lp->lpirowssize);
240 
241    return SCIP_OKAY;
242 }
243 
244 /** ensures, that cols array can store at least num entries */
245 static
ensureColsSize(SCIP_LP * lp,SCIP_SET * set,int num)246 SCIP_RETCODE ensureColsSize(
247    SCIP_LP*              lp,                 /**< current LP data */
248    SCIP_SET*             set,                /**< global SCIP settings */
249    int                   num                 /**< minimum number of entries to store */
250    )
251 {
252    assert(lp->ncols <= lp->colssize);
253 
254    if( num > lp->colssize )
255    {
256       int newsize;
257 
258       newsize = SCIPsetCalcMemGrowSize(set, num);
259       SCIP_ALLOC( BMSreallocMemoryArray(&lp->cols, newsize) );
260       lp->colssize = newsize;
261    }
262    assert(num <= lp->colssize);
263 
264    return SCIP_OKAY;
265 }
266 
267 /** ensures, that soldirection array can store at least num entries */
268 static
ensureSoldirectionSize(SCIP_LP * lp,int num)269 SCIP_RETCODE ensureSoldirectionSize(
270    SCIP_LP*              lp,                 /**< current LP data */
271    int                   num                 /**< minimum number of entries to store */
272    )
273 {
274    if( num > lp->soldirectionsize )
275    {
276       BMSfreeMemoryArrayNull(&lp->soldirection);
277       SCIP_ALLOC( BMSallocMemoryArray(&lp->soldirection, num) );
278 
279       lp->soldirectionsize = num;
280    }
281 
282    assert(num <= lp->soldirectionsize);
283 
284    return SCIP_OKAY;
285 }
286 
287 /** ensures, that lazy cols array can store at least num entries */
288 static
ensureLazycolsSize(SCIP_LP * lp,SCIP_SET * set,int num)289 SCIP_RETCODE ensureLazycolsSize(
290    SCIP_LP*              lp,                 /**< current LP data */
291    SCIP_SET*             set,                /**< global SCIP settings */
292    int                   num                 /**< minimum number of entries to store */
293    )
294 {
295    assert(lp->nlazycols <= lp->lazycolssize);
296 
297    if( num > lp->lazycolssize )
298    {
299       int newsize;
300 
301       newsize = SCIPsetCalcMemGrowSize(set, num);
302       SCIP_ALLOC( BMSreallocMemoryArray(&lp->lazycols, newsize) );
303       lp->lazycolssize = newsize;
304    }
305    assert(num <= lp->lazycolssize);
306 
307    return SCIP_OKAY;
308 }
309 
310 /** ensures, that rows array can store at least num entries */
311 static
ensureRowsSize(SCIP_LP * lp,SCIP_SET * set,int num)312 SCIP_RETCODE ensureRowsSize(
313    SCIP_LP*              lp,                 /**< current LP data */
314    SCIP_SET*             set,                /**< global SCIP settings */
315    int                   num                 /**< minimum number of entries to store */
316    )
317 {
318    assert(lp->nrows <= lp->rowssize);
319 
320    if( num > lp->rowssize )
321    {
322       int newsize;
323 
324       newsize = SCIPsetCalcMemGrowSize(set, num);
325       SCIP_ALLOC( BMSreallocMemoryArray(&lp->rows, newsize) );
326       lp->rowssize = newsize;
327    }
328    assert(num <= lp->rowssize);
329 
330    return SCIP_OKAY;
331 }
332 
333 /** ensures, that row array of column can store at least num entries */
334 static
colEnsureSize(SCIP_COL * col,BMS_BLKMEM * blkmem,SCIP_SET * set,int num)335 SCIP_RETCODE colEnsureSize(
336    SCIP_COL*             col,                /**< LP column */
337    BMS_BLKMEM*           blkmem,             /**< block memory */
338    SCIP_SET*             set,                /**< global SCIP settings */
339    int                   num                 /**< minimum number of entries to store */
340    )
341 {
342    assert(col != NULL);
343    assert(col->len <= col->size);
344 
345    if( num > col->size )
346    {
347       int newsize;
348 
349       newsize = SCIPsetCalcMemGrowSize(set, num);
350       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &col->rows, col->size, newsize) );
351       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &col->vals, col->size, newsize) );
352       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &col->linkpos, col->size, newsize) );
353       col->size = newsize;
354    }
355    assert(num <= col->size);
356 
357    return SCIP_OKAY;
358 }
359 
360 /** save current LP values dependent on the solution */
361 static
lpStoreSolVals(SCIP_LP * lp,SCIP_STAT * stat,BMS_BLKMEM * blkmem)362 SCIP_RETCODE lpStoreSolVals(
363    SCIP_LP*              lp,                 /**< LP data */
364    SCIP_STAT*            stat,               /**< problem statistics */
365    BMS_BLKMEM*           blkmem              /**< block memory */
366    )
367 {
368    SCIP_LPSOLVALS* storedsolvals;
369 
370    assert(lp != NULL);
371    assert(stat != NULL);
372    assert(blkmem != NULL);
373 
374    /* allocate memory for storage */
375    if( lp->storedsolvals == NULL )
376    {
377       SCIP_ALLOC( BMSallocMemory(&lp->storedsolvals) );
378    }
379    storedsolvals = lp->storedsolvals;
380 
381    /* store values */
382    storedsolvals->lpsolstat = lp->lpsolstat;
383    storedsolvals->lpobjval = lp->lpobjval;
384    storedsolvals->primalfeasible = lp->primalfeasible;
385    storedsolvals->primalchecked = lp->primalchecked;
386    storedsolvals->dualfeasible = lp->dualfeasible;
387    storedsolvals->dualchecked = lp->dualchecked;
388    storedsolvals->solisbasic = lp->solisbasic;
389    storedsolvals->lpissolved = lp->solved;
390 
391    return SCIP_OKAY;
392 }
393 
394 /** restore LP solution values in column */
395 static
lpRestoreSolVals(SCIP_LP * lp,BMS_BLKMEM * blkmem,SCIP_Longint validlp)396 SCIP_RETCODE lpRestoreSolVals(
397    SCIP_LP*              lp,                 /**< LP data */
398    BMS_BLKMEM*           blkmem,             /**< block memory */
399    SCIP_Longint          validlp             /**< number of lp for which restored values are valid */
400    )
401 {
402    SCIP_LPSOLVALS* storedsolvals;
403 
404    assert(lp != NULL);
405    assert(blkmem != NULL);
406 
407    /* if stored values are available, restore them */
408    storedsolvals = lp->storedsolvals;
409    if( storedsolvals != NULL )
410    {
411       lp->solved = storedsolvals->lpissolved;
412       lp->validsollp = validlp;
413 
414       lp->lpsolstat = storedsolvals->lpsolstat;
415       lp->lpobjval = storedsolvals->lpobjval;
416       lp->primalfeasible = storedsolvals->primalfeasible;
417       lp->primalchecked = storedsolvals->primalchecked;
418       lp->dualfeasible = storedsolvals->dualfeasible;
419       lp->dualchecked = storedsolvals->dualchecked;
420       lp->solisbasic = storedsolvals->solisbasic;
421 
422       /* solution values are stored only for LPs solved to optimality or unboundedness */
423       assert(lp->lpsolstat == SCIP_LPSOLSTAT_OPTIMAL ||
424          lp->lpsolstat == SCIP_LPSOLSTAT_UNBOUNDEDRAY ||
425          lp->storedsolvals->lpsolstat == SCIP_LPSOLSTAT_OBJLIMIT ||
426          lp->storedsolvals->lpsolstat == SCIP_LPSOLSTAT_ITERLIMIT ||
427          lp->storedsolvals->lpsolstat == SCIP_LPSOLSTAT_TIMELIMIT ||
428          lp->storedsolvals->lpsolstat == SCIP_LPSOLSTAT_INFEASIBLE ||
429          lp->validsollp == -1);
430    }
431    /* no values available, mark LP as unsolved */
432    else
433    {
434       lp->solved = FALSE;
435       lp->validsollp = -1;
436 
437       lp->lpsolstat = SCIP_LPSOLSTAT_NOTSOLVED;
438       lp->lpobjval = SCIP_INVALID;
439       lp->primalfeasible = FALSE;
440       lp->primalchecked = FALSE;
441       lp->dualfeasible = FALSE;
442       lp->dualchecked = FALSE;
443       lp->solisbasic = FALSE;
444       lp->validfarkaslp = -1;
445    }
446 
447    lp->validdegeneracylp = -1;
448 
449    /* intentionally keep storage space allocated */
450 
451    return SCIP_OKAY;
452 }
453 
454 /** save current LP solution values stored in each column */
455 static
colStoreSolVals(SCIP_COL * col,BMS_BLKMEM * blkmem)456 SCIP_RETCODE colStoreSolVals(
457    SCIP_COL*             col,                /**< LP column */
458    BMS_BLKMEM*           blkmem              /**< block memory */
459    )
460 {
461    SCIP_COLSOLVALS* storedsolvals;
462 
463    assert(col != NULL);
464    assert(blkmem != NULL);
465 
466    /* allocate memory for storage */
467    if( col->storedsolvals == NULL )
468    {
469       SCIP_ALLOC( BMSallocBlockMemory(blkmem, &col->storedsolvals) );
470    }
471    storedsolvals = col->storedsolvals;
472 
473    /* store values */
474    storedsolvals->primsol = col->primsol;
475    storedsolvals->redcost = col->redcost;
476    storedsolvals->basisstatus = col->basisstatus; /*lint !e641 !e732*/
477 
478    return SCIP_OKAY;
479 }
480 
481 /** restore LP solution values in column */
482 static
colRestoreSolVals(SCIP_COL * col,BMS_BLKMEM * blkmem,SCIP_Longint validlp,SCIP_Bool freebuffer)483 SCIP_RETCODE colRestoreSolVals(
484    SCIP_COL*             col,                /**< LP column */
485    BMS_BLKMEM*           blkmem,             /**< block memory */
486    SCIP_Longint          validlp,            /**< number of lp for which restored values are valid */
487    SCIP_Bool             freebuffer          /**< should buffer for LP solution values be freed? */
488    )
489 {
490    SCIP_COLSOLVALS* storedsolvals;
491 
492    assert(col != NULL);
493    assert(blkmem != NULL);
494 
495    /* if stored values are available, restore them */
496    storedsolvals = col->storedsolvals;
497    if( storedsolvals != NULL )
498    {
499       col->primsol = storedsolvals->primsol;
500       col->redcost = storedsolvals->redcost;
501       col->validredcostlp = validlp;
502       col->basisstatus = storedsolvals->basisstatus; /*lint !e641 !e732*/
503 
504       /* we do not save the farkas coefficient, since it can be recomputed; thus, we invalidate it here */
505       col->validfarkaslp = -1;
506    }
507    /* if the column was created after performing the storage (possibly during probing), we treat it as implicitly zero;
508     * we make sure to invalidate the reduced cost and farkas coefficient, which are not available
509     */
510    else
511    {
512       col->primsol = 0.0;
513       col->validredcostlp = -1;
514       col->validfarkaslp = -1;
515       col->basisstatus = SCIP_BASESTAT_ZERO; /*lint !e641*/
516    }
517 
518    /* free memory */
519    if( freebuffer )
520    {
521       BMSfreeBlockMemoryNull(blkmem, &col->storedsolvals);
522       assert(col->storedsolvals == NULL);
523    }
524 
525    return SCIP_OKAY;
526 }
527 
528 /** save current LP solution values stored in each column */
529 static
rowStoreSolVals(SCIP_ROW * row,BMS_BLKMEM * blkmem,SCIP_Bool infeasible)530 SCIP_RETCODE rowStoreSolVals(
531    SCIP_ROW*             row,                /**< LP row */
532    BMS_BLKMEM*           blkmem,             /**< block memory */
533    SCIP_Bool             infeasible          /**< is the solution infeasible? */
534    )
535 {
536    SCIP_ROWSOLVALS* storedsolvals;
537 
538    assert(row != NULL);
539    assert(blkmem != NULL);
540 
541    /* allocate memory for storage */
542    if( row->storedsolvals == NULL )
543    {
544       SCIP_ALLOC( BMSallocBlockMemory(blkmem, &row->storedsolvals) );
545    }
546    storedsolvals = row->storedsolvals;
547 
548    /* store values */
549    if ( infeasible )
550    {
551       storedsolvals->dualsol = row->dualfarkas;
552       storedsolvals->activity = SCIP_INVALID;
553       storedsolvals->basisstatus = SCIP_BASESTAT_BASIC;  /*lint !e641*/
554    }
555    else
556    {
557       storedsolvals->dualsol = row->dualsol;
558       storedsolvals->activity = row->activity;
559       storedsolvals->basisstatus = row->basisstatus; /*lint !e641 !e732*/
560    }
561 
562    return SCIP_OKAY;
563 }
564 
565 /** restore LP solution values in row */
566 static
rowRestoreSolVals(SCIP_ROW * row,BMS_BLKMEM * blkmem,SCIP_Longint validlp,SCIP_Bool freebuffer,SCIP_Bool infeasible)567 SCIP_RETCODE rowRestoreSolVals(
568    SCIP_ROW*             row,                /**< LP column */
569    BMS_BLKMEM*           blkmem,             /**< block memory */
570    SCIP_Longint          validlp,            /**< number of lp for which restored values are valid */
571    SCIP_Bool             freebuffer,         /**< should buffer for LP solution values be freed? */
572    SCIP_Bool             infeasible          /**< is the solution infeasible? */
573    )
574 {
575    SCIP_ROWSOLVALS* storedsolvals;
576 
577    assert(row != NULL);
578    assert(blkmem != NULL);
579 
580    /* if stored values are available, restore them */
581    storedsolvals = row->storedsolvals;
582    if( storedsolvals != NULL )
583    {
584       if ( infeasible )
585          row->dualfarkas = storedsolvals->dualsol;
586       else
587          row->dualsol = storedsolvals->dualsol;
588       row->activity = storedsolvals->activity;
589       row->validactivitylp = validlp;
590       row->basisstatus = storedsolvals->basisstatus; /*lint !e641 !e732*/
591    }
592    /* if the row was created after performing the storage (possibly during probing), we treat it as basic;
593     * we make sure to invalidate the reduced cost and farkas coefficient, which are not available
594     */
595    else
596    {
597       row->dualsol = 0.0;
598       row->dualfarkas = 0.0;
599       row->activity = SCIP_INVALID;
600       row->validactivitylp = -1;
601       row->basisstatus = SCIP_BASESTAT_BASIC; /*lint !e641*/
602    }
603 
604    /* free memory */
605    if( freebuffer )
606    {
607       BMSfreeBlockMemoryNull(blkmem, &row->storedsolvals);
608       assert(row->storedsolvals == NULL);
609    }
610 
611    return SCIP_OKAY;
612 }
613 
614 /** ensures, that column array of row can store at least num entries */
SCIProwEnsureSize(SCIP_ROW * row,BMS_BLKMEM * blkmem,SCIP_SET * set,int num)615 SCIP_RETCODE SCIProwEnsureSize(
616    SCIP_ROW*             row,                /**< LP row */
617    BMS_BLKMEM*           blkmem,             /**< block memory */
618    SCIP_SET*             set,                /**< global SCIP settings */
619    int                   num                 /**< minimum number of entries to store */
620    )
621 {
622    assert(row != NULL);
623    assert(row->len <= row->size);
624 
625    if( num > row->size )
626    {
627       int newsize;
628 
629       newsize = SCIPsetCalcMemGrowSize(set, num);
630       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &row->cols, row->size, newsize) );
631       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &row->cols_index, row->size, newsize) );
632       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &row->vals, row->size, newsize) );
633       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &row->linkpos, row->size, newsize) );
634       row->size = newsize;
635    }
636    assert(num <= row->size);
637 
638    return SCIP_OKAY;
639 }
640 
641 
642 #ifdef SCIP_MORE_DEBUG /* enable this to check the sortings within rows (for debugging, very slow!) */
643 static SCIP_Bool msgdisp_checkrow = FALSE;
644 
645 static
checkRow(SCIP_ROW * row)646 void checkRow(
647    SCIP_ROW*             row
648    )
649 {
650    int i;
651 
652    if( !msgdisp_checkrow )
653    {
654       printf("LP ROW CHECKING ACTIVATED! THIS IS VERY SLOW!\n");
655       msgdisp_checkrow = TRUE;
656    }
657 
658    /* validate sorting of LP part of row */
659    if( row->lpcolssorted && row->nlpcols > 0)
660    {
661       assert(row->cols_index[0] == row->cols[0]->index);
662       for( i = 1; i < row->nlpcols; ++i )
663       {
664          assert(row->cols_index[i] == row->cols[i]->index);
665          assert(row->cols_index[i] >= row->cols_index[i-1]);
666       }
667    }
668 
669    /* validate sorting of non-LP part of row */
670    if( row->nonlpcolssorted && row->len > row->nlpcols )
671    {
672       assert(row->cols_index[row->nlpcols] == row->cols[row->nlpcols]->index);
673       for( i = row->nlpcols + 1; i < row->len; ++i )
674       {
675          assert(row->cols_index[i] == row->cols[i]->index);
676          assert(row->cols_index[i] >= row->cols_index[i-1]);
677       }
678    }
679 }
680 #else
681 #define checkRow(row) /**/
682 #endif
683 
684 #ifdef SCIP_MORE_DEBUG /* enable this to check norms of rows (for debugging, very slow!) */
685 static
checkRowSqrnorm(SCIP_ROW * row)686 void checkRowSqrnorm(
687    SCIP_ROW*             row
688    )
689 {
690    SCIP_COL** cols;
691    SCIP_Real sqrnorm;
692    int c;
693 
694    cols = row->cols;
695    assert(cols != NULL || row->len == 0);
696 
697    sqrnorm = 0.0;
698 
699    for( c = row->len - 1; c >= 0; --c )
700    {
701       if( cols[c]->lppos >= 0 )
702          sqrnorm += SQR(row->vals[c]);
703    }
704 
705    assert(ABS(sqrnorm - row->sqrnorm) < 1e-06 * MAX(1.0,sqrnorm));
706 }
707 
708 static
checkRowSumnorm(SCIP_ROW * row)709 void checkRowSumnorm(
710    SCIP_ROW*             row
711    )
712 {
713    SCIP_COL** cols;
714    SCIP_Real sumnorm;
715    int c;
716 
717    cols = row->cols;
718    assert(cols != NULL || row->len == 0);
719 
720    sumnorm = 0.0;
721 
722    for( c = row->len - 1; c >= 0; --c )
723    {
724       if( cols[c]->lppos >= 0 )
725          sumnorm += REALABS(row->vals[c]);
726    }
727 
728    assert(ABS(sumnorm - row->sumnorm) < 1e-06 * MAX(1.0,sumnorm));
729 }
730 
731 static
checkRowObjprod(SCIP_ROW * row)732 void checkRowObjprod(
733    SCIP_ROW*             row
734    )
735 {
736    SCIP_COL** cols;
737    SCIP_Real objprod;
738    int c;
739 
740    cols = row->cols;
741    assert(cols != NULL || row->len == 0);
742 
743    objprod = 0.0;
744 
745    for( c = row->len - 1; c >= 0; --c )
746    {
747       if( cols[c]->lppos >= 0 )
748          objprod += row->vals[c] * cols[c]->unchangedobj;
749    }
750 
751    assert(ABS(objprod - row->objprod) < 1e-06 * MAX(1.0,objprod));
752 }
753 #else
754 #define checkRowSqrnorm(row) /**/
755 #define checkRowSumnorm(row) /**/
756 #define checkRowObjprod(row) /**/
757 #endif
758 
759 /*
760  * Local methods for pseudo and loose objective values
761  */
762 
763 /* recompute the loose objective value from scratch, if it was marked to be unreliable before */
764 static
recomputeLooseObjectiveValue(SCIP_LP * lp,SCIP_SET * set,SCIP_PROB * prob)765 void recomputeLooseObjectiveValue(
766    SCIP_LP*              lp,                 /**< current LP data */
767    SCIP_SET*             set,                /**< global SCIP settings */
768    SCIP_PROB*            prob                /**< problem data */
769    )
770 {
771    SCIP_VAR** vars;
772    SCIP_Real obj;
773    int nvars;
774    int v;
775 
776    assert(lp != NULL);
777    assert(set != NULL);
778    assert(prob != NULL);
779    assert(!lp->looseobjvalid);
780 
781    vars = prob->vars;
782    nvars = prob->nvars;
783    lp->looseobjval = 0.0;
784 
785    /* iterate over all variables in the problem */
786    for( v = 0; v < nvars; ++v )
787    {
788       if( SCIPvarGetStatus(vars[v]) == SCIP_VARSTATUS_LOOSE )
789       {
790          obj = SCIPvarGetObj(vars[v]);
791 
792          /* we are only interested in variables with a finite impact, because the infinity counters should be correct */
793          if( SCIPsetIsPositive(set, obj) && !SCIPsetIsInfinity(set, -SCIPvarGetLbLocal(vars[v])) )
794             lp->looseobjval += obj * SCIPvarGetLbLocal(vars[v]);
795          else if( SCIPsetIsNegative(set, obj) && !SCIPsetIsInfinity(set, SCIPvarGetUbLocal(vars[v])) )
796             lp->looseobjval += obj * SCIPvarGetUbLocal(vars[v]);
797       }
798    }
799 
800    /* the recomputed value is reliable */
801    lp->rellooseobjval = lp->looseobjval;
802    lp->looseobjvalid = TRUE;
803 }
804 
805 /* recompute the pseudo solution value from scratch, if it was marked to be unreliable before */
806 static
recomputePseudoObjectiveValue(SCIP_LP * lp,SCIP_SET * set,SCIP_PROB * prob)807 void recomputePseudoObjectiveValue(
808    SCIP_LP*              lp,                 /**< current LP data */
809    SCIP_SET*             set,                /**< global SCIP settings */
810    SCIP_PROB*            prob                /**< problem data */
811    )
812 {
813    SCIP_VAR** vars;
814    int nvars;
815    int v;
816 
817    assert(lp != NULL);
818    assert(set != NULL);
819    assert(prob != NULL);
820    assert(!lp->pseudoobjvalid);
821 
822    vars = prob->vars;
823    nvars = prob->nvars;
824    lp->pseudoobjval = 0.0;
825 
826    /* iterate over all variables in the problem */
827    for( v = 0; v < nvars; ++v )
828    {
829       /* we are only interested in variables with a finite impact, because the infinity counters should be correct */
830       if( SCIPsetIsPositive(set, SCIPvarGetObj(vars[v])) &&
831          !SCIPsetIsInfinity(set, -SCIPvarGetLbLocal(vars[v])) )
832       {
833          lp->pseudoobjval += SCIPvarGetObj(vars[v]) * SCIPvarGetLbLocal(vars[v]);
834       }
835       else if( SCIPsetIsNegative(set, SCIPvarGetObj(vars[v])) &&
836          !SCIPsetIsInfinity(set, SCIPvarGetUbLocal(vars[v])) )
837       {
838          lp->pseudoobjval += SCIPvarGetObj(vars[v]) * SCIPvarGetUbLocal(vars[v]);
839       }
840    }
841 
842    /* the recomputed value is reliable */
843    lp->relpseudoobjval = lp->pseudoobjval;
844    lp->pseudoobjvalid = TRUE;
845 }
846 
847 /* recompute the global pseudo solution value from scratch, if it was marked to be unreliable before */
848 static
recomputeGlbPseudoObjectiveValue(SCIP_LP * lp,SCIP_SET * set,SCIP_PROB * prob)849 void recomputeGlbPseudoObjectiveValue(
850    SCIP_LP*              lp,                 /**< current LP data */
851    SCIP_SET*             set,                /**< global SCIP settings */
852    SCIP_PROB*            prob                /**< problem data */
853    )
854 {
855    SCIP_VAR** vars;
856    int nvars;
857    int v;
858 
859    assert(lp != NULL);
860    assert(set != NULL);
861    assert(prob != NULL);
862    assert(!lp->glbpseudoobjvalid);
863 
864    vars = prob->vars;
865    nvars = prob->nvars;
866    lp->glbpseudoobjval = 0.0;
867 
868    /* iterate over all variables in the problem */
869    for( v = 0; v < nvars; ++v )
870    {
871       /* we are only interested in variables with a finite impact, because the infinity counters should be correct */
872       if( SCIPsetIsPositive(set, SCIPvarGetObj(vars[v])) &&
873          !SCIPsetIsInfinity(set, -SCIPvarGetLbGlobal(vars[v])) )
874       {
875          lp->glbpseudoobjval += SCIPvarGetObj(vars[v]) * SCIPvarGetLbGlobal(vars[v]);
876       }
877       else if( SCIPsetIsNegative(set, SCIPvarGetObj(vars[v])) &&
878          !SCIPsetIsInfinity(set, SCIPvarGetUbGlobal(vars[v])) )
879       {
880          lp->glbpseudoobjval += SCIPvarGetObj(vars[v]) * SCIPvarGetUbGlobal(vars[v]);
881       }
882    }
883 
884    /* the recomputed value is reliable */
885    lp->relglbpseudoobjval = lp->glbpseudoobjval;
886    lp->glbpseudoobjvalid = TRUE;
887 }
888 
889 /** gets finite part of objective value of current LP that results from LOOSE variables only */
890 static
getFiniteLooseObjval(SCIP_LP * lp,SCIP_SET * set,SCIP_PROB * prob)891 SCIP_Real getFiniteLooseObjval(
892    SCIP_LP*              lp,                 /**< current LP data */
893    SCIP_SET*             set,                /**< global SCIP settings */
894    SCIP_PROB*            prob                /**< problem data */
895    )
896 {
897    assert(lp != NULL);
898    assert(set != NULL);
899    assert(prob != NULL);
900    assert((lp->nloosevars > 0) || (lp->looseobjvalinf == 0 && lp->looseobjval == 0.0));
901    assert(lp->flushed);
902    assert(lp->looseobjvalinf == 0);
903 
904    /* recalculate the loose objective value, if needed */
905    if( !lp->looseobjvalid )
906       recomputeLooseObjectiveValue(lp, set, prob);
907 
908    return lp->looseobjval;
909 }
910 
911 /** gets finite part of pseudo objective value of current LP */
912 static
getFinitePseudoObjval(SCIP_LP * lp,SCIP_SET * set,SCIP_PROB * prob)913 SCIP_Real getFinitePseudoObjval(
914    SCIP_LP*              lp,                 /**< current LP data */
915    SCIP_SET*             set,                /**< global SCIP settings */
916    SCIP_PROB*            prob                /**< problem data */
917    )
918 {
919    assert(lp != NULL);
920    assert(set != NULL);
921    assert(prob != NULL);
922 
923    /* recalculate the pseudo objective value, if needed */
924    if( !lp->pseudoobjvalid )
925       recomputePseudoObjectiveValue(lp, set, prob);
926 
927    return lp->pseudoobjval;
928 }
929 
930 /*
931  * Sorting and searching rows and columns
932  */
933 
934 
935 /** comparison method for sorting rows by non-decreasing index */
SCIP_DECL_SORTPTRCOMP(SCIProwComp)936 SCIP_DECL_SORTPTRCOMP(SCIProwComp)
937 {
938    assert(elem1 != NULL);
939    assert(elem2 != NULL);
940 
941    if( ((SCIP_ROW*)elem1)->index < ((SCIP_ROW*)elem2)->index )
942       return -1;
943    else if( ((SCIP_ROW*)elem1)->index > ((SCIP_ROW*)elem2)->index )
944       return +1;
945    else
946    {
947       assert(SCIProwGetIndex((SCIP_ROW*)(elem1)) == SCIProwGetIndex(((SCIP_ROW*)elem2)));
948       return 0;
949    }
950 }
951 
952 
953 /** sorts column entries of linked rows currently in the LP such that lower row indices precede higher ones */
954 static
colSortLP(SCIP_COL * col)955 void colSortLP(
956    SCIP_COL*             col                 /**< column to be sorted */
957    )
958 {
959    int i;
960 
961    assert(col != NULL);
962 
963    /* check, if column is already sorted in the LP part */
964    if( col->lprowssorted )
965       return;
966 
967    /* sort coefficients */
968    SCIPsortPtrRealInt((void**)col->rows, col->vals, col->linkpos, SCIProwComp, col->nlprows );
969 
970    /* update links */
971    for( i = 0; i < col->nlprows; ++i )
972    {
973       if( col->linkpos[i] >= 0 )
974       {
975          assert(col->rows[i]->cols[col->linkpos[i]] == col);
976          assert(col->rows[i]->linkpos[col->linkpos[i]] >= 0);
977          col->rows[i]->linkpos[col->linkpos[i]] = i;
978       }
979    }
980 
981    col->lprowssorted = TRUE;
982 }
983 
984 /** sorts column entries of unlinked rows or rows currently not in the LP such that lower row indices precede higher
985  *  ones
986  */
987 static
colSortNonLP(SCIP_COL * col)988 void colSortNonLP(
989    SCIP_COL*             col                 /**< column to be sorted */
990    )
991 {
992    int i;
993 
994    assert(col != NULL);
995 
996    /* check, if column is already sorted in the non-LP part */
997    if( col->nonlprowssorted )
998       return;
999 
1000    /* sort coefficients */
1001    SCIPsortPtrRealInt((void**)(&(col->rows[col->nlprows])), &(col->vals[col->nlprows]), &(col->linkpos[col->nlprows]), SCIProwComp, col->len - col->nlprows);
1002 
1003    /* update links */
1004    for( i = col->nlprows; i < col->len; ++i )
1005    {
1006       if( col->linkpos[i] >= 0 )
1007       {
1008          assert(col->rows[i]->cols[col->linkpos[i]] == col);
1009          assert(col->rows[i]->linkpos[col->linkpos[i]] >= 0);
1010          col->rows[i]->linkpos[col->linkpos[i]] = i;
1011       }
1012    }
1013 
1014    col->nonlprowssorted = TRUE;
1015 }
1016 
1017 /** sorts row entries of linked columns currently in the LP such that lower column indices precede higher ones */
1018 static
rowSortLP(SCIP_ROW * row)1019 void rowSortLP(
1020    SCIP_ROW*             row                 /**< row to be sorted */
1021    )
1022 {
1023    int i;
1024 
1025    assert(row != NULL);
1026 
1027    /* check, if row is already sorted in the LP part, or if the sorting should be delayed */
1028    if( row->lpcolssorted || row->delaysort )
1029       return;
1030 
1031    /* sort coefficients */
1032    SCIPsortIntPtrIntReal(row->cols_index, (void**)row->cols, row->linkpos, row->vals, row->nlpcols);
1033 
1034    /* update links */
1035    for( i = 0; i < row->nlpcols; ++i )
1036    {
1037       if( row->linkpos[i] >= 0 )
1038       {
1039          assert(row->cols[i]->rows[row->linkpos[i]] == row);
1040          assert(row->cols[i]->linkpos[row->linkpos[i]] >= 0);
1041          row->cols[i]->linkpos[row->linkpos[i]] = i;
1042       }
1043    }
1044 
1045    row->lpcolssorted = TRUE;
1046 }
1047 
1048 /** sorts row entries of unlinked columns or columns currently not in the LP such that lower column indices precede
1049  *  higher ones
1050  */
1051 static
rowSortNonLP(SCIP_ROW * row)1052 void rowSortNonLP(
1053    SCIP_ROW*             row                 /**< row to be sorted */
1054    )
1055 {
1056    int i;
1057 
1058    assert(row != NULL);
1059 
1060    checkRow(row);
1061 
1062    /* check, if row is already sorted in the non-LP part, or if the sorting should be delayed */
1063    if( row->nonlpcolssorted || row->delaysort )
1064       return;
1065 
1066    /* sort coefficients */
1067    SCIPsortIntPtrIntReal(&(row->cols_index[row->nlpcols]), (void**)(&(row->cols[row->nlpcols])), &(row->linkpos[row->nlpcols]), &(row->vals[row->nlpcols]), row->len - row->nlpcols);
1068 
1069    /* update links */
1070    for( i = row->nlpcols; i < row->len; ++i )
1071    {
1072       if( row->linkpos[i] >= 0 )
1073       {
1074          assert(row->cols[i]->rows[row->linkpos[i]] == row);
1075          assert(row->cols[i]->linkpos[row->linkpos[i]] >= 0);
1076          row->cols[i]->linkpos[row->linkpos[i]] = i;
1077       }
1078    }
1079 
1080    checkRow(row);
1081 
1082    row->nonlpcolssorted = TRUE;
1083 }
1084 
1085 /** searches coefficient in part of the column, returns position in col vector or -1 if not found */
1086 static
colSearchCoefPart(SCIP_COL * col,const SCIP_ROW * row,int minpos,int maxpos)1087 int colSearchCoefPart(
1088    SCIP_COL*             col,                /**< column to be searched in */
1089    const SCIP_ROW*       row,                /**< coefficient to be searched for */
1090    int                   minpos,             /**< first position of search range */
1091    int                   maxpos              /**< last position of search range */
1092    )
1093 {
1094    int pos;
1095    int idx;
1096    int searchidx;
1097 
1098    assert(col != NULL);
1099    assert(row != NULL);
1100 
1101    /* binary search */
1102    searchidx = row->index;
1103    while(minpos <= maxpos)
1104    {
1105       pos = (minpos + maxpos)/2;
1106       assert(0 <= pos && pos < col->len);
1107       assert(col->rows[pos] != NULL);
1108       assert((pos < col->nlprows) == (col->rows[pos]->lppos >= 0 && col->linkpos[pos] >= 0));
1109       idx = col->rows[pos]->index;
1110       if( searchidx == idx )
1111          return pos;
1112       else if( searchidx < idx )
1113          maxpos = pos-1;
1114       else
1115          minpos = pos+1;
1116    }
1117 
1118    return -1;
1119 }
1120 
1121 /** searches coefficient in column, returns position in col vector or -1 if not found */
1122 static
colSearchCoef(SCIP_COL * col,const SCIP_ROW * row)1123 int colSearchCoef(
1124    SCIP_COL*             col,                /**< column to be searched in */
1125    const SCIP_ROW*       row                 /**< coefficient to be searched for */
1126    )
1127 {
1128    int pos;
1129 
1130    assert(col != NULL);
1131    assert(row != NULL);
1132 
1133    pos = -1;
1134 
1135    /* search in the linked LP rows */
1136    if( row->lppos >= 0 )
1137    {
1138       /* column has to be sorted, such that binary search works */
1139       colSortLP(col);
1140       assert(col->lprowssorted);
1141 
1142       pos = colSearchCoefPart(col, row, 0, col->nlprows-1);
1143       if( pos >= 0 )
1144          return pos;
1145    }
1146 
1147    /* search in the non-LP/unlinked rows */
1148    if( row->lppos == -1 || col->nunlinked > 0 )
1149    {
1150       /* column has to be sorted, such that binary search works */
1151       colSortNonLP(col);
1152       assert(col->nonlprowssorted);
1153 
1154       pos = colSearchCoefPart(col, row, col->nlprows, col->len-1);
1155    }
1156 
1157    return pos;
1158 }
1159 
1160 /** searches coefficient in part of the row, returns position in col vector or -1 if not found */
1161 static
rowSearchCoefPart(SCIP_ROW * row,const SCIP_COL * col,int minpos,int maxpos)1162 int rowSearchCoefPart(
1163    SCIP_ROW*             row,                /**< row to be searched in */
1164    const SCIP_COL*       col,                /**< coefficient to be searched for */
1165    int                   minpos,             /**< first position of search range */
1166    int                   maxpos              /**< last position of search range */
1167    )
1168 {
1169    int pos;
1170    int idx;
1171    int searchidx;
1172 
1173    assert(row != NULL);
1174    assert(col != NULL);
1175 
1176    /* binary search */
1177    searchidx = col->index;
1178    while(minpos <= maxpos)
1179    {
1180       pos = (minpos + maxpos)/2;
1181       assert(0 <= pos && pos < row->len);
1182       assert(row->cols[pos] != NULL);
1183       assert((pos < row->nlpcols) == (row->cols[pos]->lppos >= 0 && row->linkpos[pos] >= 0));
1184       assert(row->cols_index[pos] == row->cols[pos]->index);
1185       idx = row->cols_index[pos];
1186       if( searchidx == idx )
1187          return pos;
1188       else if( searchidx < idx )
1189          maxpos = pos-1;
1190       else
1191          minpos = pos+1;
1192    }
1193 
1194    return -1;
1195 }
1196 
1197 /** searches coefficient in row, returns position in row vector or -1 if not found;
1198  *  if the sorting of the row is delayed, returns -1
1199  */
1200 static
rowSearchCoef(SCIP_ROW * row,const SCIP_COL * col)1201 int rowSearchCoef(
1202    SCIP_ROW*             row,                /**< row to be searched in */
1203    const SCIP_COL*       col                 /**< coefficient to be searched for */
1204    )
1205 {
1206    int pos;
1207 
1208    assert(row != NULL);
1209    assert(col != NULL);
1210 
1211    if( row->delaysort )
1212       return -1;
1213 
1214    pos = -1;
1215 
1216    /* search in the linked LP columns */
1217    if( col->lppos >= 0 )
1218    {
1219       /* row has to be sorted, such that binary search works */
1220       rowSortLP(row);
1221       assert(row->lpcolssorted);
1222 
1223       pos = rowSearchCoefPart(row, col, 0, row->nlpcols-1);
1224    }
1225 
1226    /* search in the non-LP/unlinked columns */
1227    if( pos == -1 && (col->lppos == -1 || row->nunlinked > 0) )
1228    {
1229       /* row has to be sorted, such that binary search works */
1230       rowSortNonLP(row);
1231       assert(row->nonlpcolssorted);
1232 
1233       pos = rowSearchCoefPart(row, col, row->nlpcols, row->len-1);
1234    }
1235 
1236 #ifndef NDEBUG
1237    /* validate result */
1238    assert(-1 <= pos && pos < row->len);
1239    if( pos >= 0 )
1240       assert(row->cols[pos] == col);
1241    else
1242    {
1243       int i;
1244       for( i = 0; i < row->len; ++i )
1245          assert(row->cols[i] != col);
1246    }
1247 #endif
1248 
1249    return pos;
1250 }
1251 
1252 /** moves a coefficient in a column to a different place, and updates all corresponding data structures */
1253 static
colMoveCoef(SCIP_COL * col,int oldpos,int newpos)1254 void colMoveCoef(
1255    SCIP_COL*             col,                /**< LP column */
1256    int                   oldpos,             /**< old position of coefficient */
1257    int                   newpos              /**< new position of coefficient */
1258    )
1259 {
1260    assert(col != NULL);
1261    assert(0 <= oldpos && oldpos < col->len);
1262    assert(0 <= newpos && newpos < col->len);
1263    assert(col->rows[oldpos] != NULL);
1264 
1265    if( oldpos == newpos )
1266       return;
1267 
1268    col->rows[newpos] = col->rows[oldpos];
1269    col->vals[newpos] = col->vals[oldpos];
1270    col->linkpos[newpos] = col->linkpos[oldpos];
1271 
1272    /* update link position in row */
1273    if( col->linkpos[newpos] >= 0 )
1274    {
1275       assert(col->rows[newpos]->cols[col->linkpos[newpos]] == col);
1276       assert(col->rows[newpos]->linkpos[col->linkpos[newpos]] == oldpos);
1277 
1278       col->rows[newpos]->linkpos[col->linkpos[newpos]] = newpos;
1279    }
1280 
1281    /* update sorted flags */
1282    if( col->rows[newpos]->lppos >= 0 && col->linkpos[newpos] >= 0 )
1283       col->lprowssorted = FALSE;
1284    else
1285       col->nonlprowssorted = FALSE;
1286 }
1287 
1288 /** swaps two coefficients in a column, and updates all corresponding data structures */
1289 static
colSwapCoefs(SCIP_COL * col,int pos1,int pos2)1290 void colSwapCoefs(
1291    SCIP_COL*             col,                /**< LP column */
1292    int                   pos1,               /**< position of first coefficient */
1293    int                   pos2                /**< position of second coefficient */
1294    )
1295 {
1296    SCIP_ROW* tmprow;
1297    SCIP_Real tmpval;
1298    int tmplinkpos;
1299 
1300    assert(col != NULL);
1301    assert(0 <= pos1 && pos1 < col->len);
1302    assert(0 <= pos2 && pos2 < col->len);
1303    assert(col->rows[pos1] != NULL);
1304 
1305    if( pos1 == pos2 )
1306       return;
1307 
1308    /* swap coefficients */
1309    tmprow = col->rows[pos2];
1310    tmpval = col->vals[pos2];
1311    tmplinkpos = col->linkpos[pos2];
1312 
1313    col->rows[pos2] = col->rows[pos1];
1314    col->vals[pos2] = col->vals[pos1];
1315    col->linkpos[pos2] = col->linkpos[pos1];
1316 
1317    col->rows[pos1] = tmprow;
1318    col->vals[pos1] = tmpval;
1319    col->linkpos[pos1] = tmplinkpos;
1320 
1321    /* update link position in rows */
1322    if( col->linkpos[pos1] >= 0 )
1323    {
1324       assert(col->rows[pos1]->cols[col->linkpos[pos1]] == col);
1325       assert(col->rows[pos1]->linkpos[col->linkpos[pos1]] == pos2);
1326 
1327       col->rows[pos1]->linkpos[col->linkpos[pos1]] = pos1;
1328    }
1329    if( col->linkpos[pos2] >= 0 )
1330    {
1331       assert(col->rows[pos2]->cols[col->linkpos[pos2]] == col);
1332       assert(col->rows[pos2]->linkpos[col->linkpos[pos2]] == pos1);
1333 
1334       col->rows[pos2]->linkpos[col->linkpos[pos2]] = pos2;
1335    }
1336 
1337    /* update sorted flags */
1338    if( col->rows[pos1]->lppos >= 0 && col->linkpos[pos1] >= 0 )
1339       col->lprowssorted = FALSE;
1340    else
1341       col->nonlprowssorted = FALSE;
1342    if( col->rows[pos2]->lppos >= 0 && col->linkpos[pos2] >= 0 )
1343       col->lprowssorted = FALSE;
1344    else
1345       col->nonlprowssorted = FALSE;
1346 }
1347 
1348 /** moves a coefficient in a row to a different place, and updates all corresponding data structures */
1349 static
rowMoveCoef(SCIP_ROW * row,int oldpos,int newpos)1350 void rowMoveCoef(
1351    SCIP_ROW*             row,                /**< LP row */
1352    int                   oldpos,             /**< old position of coefficient */
1353    int                   newpos              /**< new position of coefficient */
1354    )
1355 {
1356    assert(row != NULL);
1357    assert(0 <= oldpos && oldpos < row->len);
1358    assert(0 <= newpos && newpos < row->len);
1359    assert(row->cols[oldpos] != NULL);
1360 
1361    if( oldpos == newpos )
1362       return;
1363 
1364    row->cols[newpos] = row->cols[oldpos];
1365    row->cols_index[newpos] = row->cols_index[oldpos];
1366    row->vals[newpos] = row->vals[oldpos];
1367    row->linkpos[newpos] = row->linkpos[oldpos];
1368 
1369    /* update link position in column */
1370    if( row->linkpos[newpos] >= 0 )
1371    {
1372       assert(row->cols[newpos]->rows[row->linkpos[newpos]] == row);
1373       assert(row->cols[newpos]->linkpos[row->linkpos[newpos]] == oldpos);
1374 
1375       row->cols[newpos]->linkpos[row->linkpos[newpos]] = newpos;
1376    }
1377 
1378    /* update sorted flags */
1379    if( row->cols[newpos]->lppos >= 0 && row->linkpos[newpos] >= 0 )
1380       row->lpcolssorted = FALSE;
1381    else
1382       row->nonlpcolssorted = FALSE;
1383 }
1384 
1385 /** swaps two coefficients in a row, and updates all corresponding data structures */
1386 static
rowSwapCoefs(SCIP_ROW * row,int pos1,int pos2)1387 void rowSwapCoefs(
1388    SCIP_ROW*             row,                /**< LP row */
1389    int                   pos1,               /**< position of first coefficient */
1390    int                   pos2                /**< position of second coefficient */
1391    )
1392 {
1393    SCIP_COL* tmpcol;
1394    SCIP_Real tmpval;
1395    int tmpindex;
1396    int tmplinkpos;
1397 
1398    assert(row != NULL);
1399    assert(0 <= pos1 && pos1 < row->len);
1400    assert(0 <= pos2 && pos2 < row->len);
1401    assert(row->cols[pos1] != NULL);
1402    assert(row->cols[pos1]->index == row->cols_index[pos1]);
1403 
1404    if( pos1 == pos2 )
1405       return;
1406 
1407    /* swap coefficients */
1408    tmpcol = row->cols[pos2];
1409    tmpindex = row->cols_index[pos2];
1410    tmpval = row->vals[pos2];
1411    tmplinkpos = row->linkpos[pos2];
1412 
1413    row->cols[pos2] = row->cols[pos1];
1414    row->cols_index[pos2] = row->cols_index[pos1];
1415    row->vals[pos2] = row->vals[pos1];
1416    row->linkpos[pos2] = row->linkpos[pos1];
1417 
1418    row->cols[pos1] = tmpcol;
1419    row->cols_index[pos1] = tmpindex;
1420    row->vals[pos1] = tmpval;
1421    row->linkpos[pos1] = tmplinkpos;
1422 
1423    /* update link position in columns */
1424    if( row->linkpos[pos1] >= 0 )
1425    {
1426       assert(row->cols[pos1]->rows[row->linkpos[pos1]] == row);
1427       assert(row->cols[pos1]->linkpos[row->linkpos[pos1]] == pos2);
1428 
1429       row->cols[pos1]->linkpos[row->linkpos[pos1]] = pos1;
1430    }
1431    if( row->linkpos[pos2] >= 0 )
1432    {
1433       assert(row->cols[pos2]->rows[row->linkpos[pos2]] == row);
1434       assert(row->cols[pos2]->linkpos[row->linkpos[pos2]] == pos1);
1435 
1436       row->cols[pos2]->linkpos[row->linkpos[pos2]] = pos2;
1437    }
1438 
1439    /* update sorted flags */
1440    if( row->cols[pos1]->lppos >= 0 && row->linkpos[pos1] >= 0 )
1441       row->lpcolssorted = FALSE;
1442    else
1443       row->nonlpcolssorted = FALSE;
1444    if( row->cols[pos2]->lppos >= 0 && row->linkpos[pos2] >= 0 )
1445       row->lpcolssorted = FALSE;
1446    else
1447       row->nonlpcolssorted = FALSE;
1448 }
1449 
1450 /** issues a ROWCOEFCHANGED event on the given row */
1451 static
rowEventCoefChanged(SCIP_ROW * row,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_COL * col,SCIP_Real oldval,SCIP_Real newval)1452 SCIP_RETCODE rowEventCoefChanged(
1453    SCIP_ROW*             row,                /**< row which coefficient has changed */
1454    BMS_BLKMEM*           blkmem,             /**< block memory */
1455    SCIP_SET*             set,                /**< global SCIP settings */
1456    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
1457    SCIP_COL*             col,                /**< the column which coefficient has changed */
1458    SCIP_Real             oldval,             /**< old value of the coefficient */
1459    SCIP_Real             newval              /**< new value of the coefficient */
1460    )
1461 {
1462    assert(row != NULL);
1463    assert(row->eventfilter != NULL);
1464    assert(col != NULL);
1465 
1466    /* check, if the row is being tracked for coefficient changes
1467     * if so, issue ROWCOEFCHANGED event
1468     */
1469    if( (row->eventfilter->len > 0 && (row->eventfilter->eventmask & SCIP_EVENTTYPE_ROWCOEFCHANGED) != 0) )
1470    {
1471       SCIP_EVENT* event;
1472 
1473       SCIP_CALL( SCIPeventCreateRowCoefChanged(&event, blkmem, row, col, oldval, newval) );
1474       SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, row->eventfilter, &event) );
1475    }
1476 
1477    return SCIP_OKAY;
1478 }
1479 
1480 /** issues a ROWCONSTCHANGED event on the given row */
1481 static
rowEventConstantChanged(SCIP_ROW * row,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_Real oldval,SCIP_Real newval)1482 SCIP_RETCODE rowEventConstantChanged(
1483    SCIP_ROW*             row,                /**< row which coefficient has changed */
1484    BMS_BLKMEM*           blkmem,             /**< block memory */
1485    SCIP_SET*             set,                /**< global SCIP settings */
1486    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
1487    SCIP_Real             oldval,             /**< old value of the constant */
1488    SCIP_Real             newval              /**< new value of the constant */
1489    )
1490 {
1491    assert(row != NULL);
1492    assert(row->eventfilter != NULL);
1493 
1494    /* check, if the row is being tracked for coefficient changes
1495     * if so, issue ROWCONSTCHANGED event
1496     */
1497    if( (row->eventfilter->len > 0 && (row->eventfilter->eventmask & SCIP_EVENTTYPE_ROWCONSTCHANGED)) )
1498    {
1499       SCIP_EVENT* event;
1500 
1501       SCIP_CALL( SCIPeventCreateRowConstChanged(&event, blkmem, row, oldval, newval) );
1502       SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, row->eventfilter, &event) );
1503    }
1504 
1505    return SCIP_OKAY;
1506 }
1507 
1508 /** issues a ROWSIDECHANGED event on the given row */
1509 static
rowEventSideChanged(SCIP_ROW * row,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_SIDETYPE side,SCIP_Real oldval,SCIP_Real newval)1510 SCIP_RETCODE rowEventSideChanged(
1511    SCIP_ROW*             row,                /**< row which coefficient has changed */
1512    BMS_BLKMEM*           blkmem,             /**< block memory */
1513    SCIP_SET*             set,                /**< global SCIP settings */
1514    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
1515    SCIP_SIDETYPE         side,               /**< the side that has changed */
1516    SCIP_Real             oldval,             /**< old value of side */
1517    SCIP_Real             newval              /**< new value of side */
1518    )
1519 {
1520    assert(row != NULL);
1521    assert(row->eventfilter != NULL);
1522 
1523    /* check, if the row is being tracked for coefficient changes
1524     * if so, issue ROWSIDECHANGED event
1525     */
1526    if( (row->eventfilter->len > 0 && !(row->eventfilter->eventmask & SCIP_EVENTTYPE_ROWSIDECHANGED)) )
1527    {
1528       SCIP_EVENT* event;
1529 
1530       SCIP_CALL( SCIPeventCreateRowSideChanged(&event, blkmem, row, side, oldval, newval) );
1531       SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, row->eventfilter, &event) );
1532    }
1533 
1534    return SCIP_OKAY;
1535 }
1536 
1537 #ifdef SCIP_MORE_DEBUG /* enable this to check links between columns and rows in LP data structure (for debugging, very slow!) */
1538 
1539 #ifdef NDEBUG
1540 #define ASSERT(x) do { if( !(x) ) abort(); } while( FALSE )
1541 #else
1542 #define ASSERT(x) assert(x)
1543 #endif
1544 
1545 static SCIP_Bool msgdisp_checklinks = FALSE;
1546 
1547 
1548 static
checkLinks(SCIP_LP * lp)1549 void checkLinks(
1550    SCIP_LP*              lp                  /**< current LP data */
1551    )
1552 {
1553    SCIP_COL* col;
1554    SCIP_ROW* row;
1555    int i;
1556    int j;
1557 
1558    ASSERT(lp != NULL);
1559 
1560    if( !msgdisp_checklinks )
1561    {
1562       printf("LP LINK CHECKING ACTIVATED! THIS IS VERY SLOW!\n");
1563       msgdisp_checklinks = TRUE;
1564    }
1565 
1566    for( i = 0; i < lp->ncols; ++i )
1567    {
1568       col = lp->cols[i];
1569       ASSERT(col != NULL);
1570       ASSERT(!lp->flushed || col->lppos >= 0 || col->primsol == 0.0);
1571       ASSERT(!lp->flushed || col->lppos >= 0 || col->farkascoef == 0.0);
1572       ASSERT(col->nlprows <= col->len);
1573       ASSERT(col->lppos == -1 || col->lppos >= lp->lpifirstchgcol || col->nunlinked == 0);
1574 
1575       for( j = 0; j < col->len; ++j )
1576       {
1577          row = col->rows[j];
1578          ASSERT(row != NULL);
1579          ASSERT(!lp->flushed || col->lppos == -1 || col->linkpos[j] >= 0);
1580          ASSERT(col->linkpos[j] == -1 || row->cols[col->linkpos[j]] == col);
1581          ASSERT(col->linkpos[j] == -1 || EPSEQ(row->vals[col->linkpos[j]], col->vals[j], 1e-6));
1582          ASSERT((j < col->nlprows) == (col->linkpos[j] >= 0 && row->lppos >= 0));
1583       }
1584    }
1585 
1586    for( i = 0; i < lp->nrows; ++i )
1587    {
1588       row = lp->rows[i];
1589       ASSERT(row != NULL);
1590       ASSERT(!lp->flushed || row->lppos >= 0 || row->dualsol == 0.0);
1591       ASSERT(!lp->flushed || row->lppos >= 0 || row->dualfarkas == 0.0);
1592       ASSERT(row->nlpcols <= row->len);
1593       ASSERT(row->lppos == -1 || row->lppos >= lp->lpifirstchgrow || row->nunlinked == 0);
1594 
1595       for( j = 0; j < row->len; ++j )
1596       {
1597          col = row->cols[j];
1598          ASSERT(col != NULL);
1599          ASSERT(!lp->flushed || row->lppos == -1 || row->linkpos[j] >= 0);
1600          ASSERT(row->linkpos[j] == -1 || col->rows[row->linkpos[j]] == row);
1601          ASSERT(row->linkpos[j] == -1 || EPSEQ(col->vals[row->linkpos[j]], row->vals[j], 1e-6));
1602          ASSERT((j < row->nlpcols) == (row->linkpos[j] >= 0 && col->lppos >= 0));
1603       }
1604    }
1605 }
1606 
1607 #undef ASSERT
1608 
1609 #else
1610 #define checkLinks(lp) /**/
1611 #endif
1612 
1613 /*
1614  * Changing announcements
1615  */
1616 
1617 /** announces, that the given coefficient in the constraint matrix changed */
1618 static
coefChanged(SCIP_ROW * row,SCIP_COL * col,SCIP_LP * lp)1619 void coefChanged(
1620    SCIP_ROW*             row,                /**< LP row */
1621    SCIP_COL*             col,                /**< LP col */
1622    SCIP_LP*              lp                  /**< current LP data */
1623    )
1624 {
1625    assert(row != NULL);
1626    assert(col != NULL);
1627    assert(lp != NULL);
1628 
1629    if( row->lpipos >= 0 && col->lpipos >= 0 )
1630    {
1631       assert(row->lpipos < lp->nlpirows);
1632       assert(col->lpipos < lp->nlpicols);
1633 
1634       /* we have to remember the change only in the row or in the column,
1635        * because the readdition of one vector would change the other automatically.
1636        */
1637       if( row->lpipos >= lp->lpifirstchgrow )
1638          row->coefchanged = TRUE;
1639       else if( col->lpipos >= lp->lpifirstchgcol )
1640          col->coefchanged = TRUE;
1641       else if( lp->lpifirstchgrow - row->lpipos <= lp->lpifirstchgcol - col->lpipos )
1642       {
1643          row->coefchanged = TRUE;
1644          lp->lpifirstchgrow = row->lpipos;
1645       }
1646       else
1647       {
1648          col->coefchanged = TRUE;
1649          lp->lpifirstchgcol = col->lpipos;
1650       }
1651 
1652       /* mark the current LP unflushed */
1653       lp->flushed = FALSE;
1654    }
1655 
1656    row->pseudoactivity = SCIP_INVALID;
1657    row->minactivity = SCIP_INVALID;
1658    row->maxactivity = SCIP_INVALID;
1659    row->validpsactivitydomchg = -1;
1660    row->validactivitybdsdomchg = -1;
1661 }
1662 
1663 
1664 
1665 /*
1666  * local column changing methods
1667  */
1668 
1669 /* forward declaration for colAddCoef() */
1670 static
1671 SCIP_RETCODE rowAddCoef(
1672    SCIP_ROW*             row,                /**< LP row */
1673    BMS_BLKMEM*           blkmem,             /**< block memory */
1674    SCIP_SET*             set,                /**< global SCIP settings */
1675    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
1676    SCIP_LP*              lp,                 /**< current LP data */
1677    SCIP_COL*             col,                /**< LP column */
1678    SCIP_Real             val,                /**< value of coefficient */
1679    int                   linkpos             /**< position of row in the column's row array, or -1 */
1680    );
1681 
1682 /** adds a previously non existing coefficient to an LP column */
1683 static
colAddCoef(SCIP_COL * col,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp,SCIP_ROW * row,SCIP_Real val,int linkpos)1684 SCIP_RETCODE colAddCoef(
1685    SCIP_COL*             col,                /**< LP column */
1686    BMS_BLKMEM*           blkmem,             /**< block memory */
1687    SCIP_SET*             set,                /**< global SCIP settings */
1688    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
1689    SCIP_LP*              lp,                 /**< current LP data */
1690    SCIP_ROW*             row,                /**< LP row */
1691    SCIP_Real             val,                /**< value of coefficient */
1692    int                   linkpos             /**< position of column in the row's col array, or -1 */
1693    )
1694 {
1695    int pos;
1696 
1697    assert(blkmem != NULL);
1698    assert(col != NULL);
1699    assert(col->nlprows <= col->len);
1700    assert(col->var != NULL);
1701    assert(row != NULL);
1702    assert(!SCIPsetIsZero(set, val));
1703    /*assert(colSearchCoef(col, row) == -1);*/ /* this assert would lead to slight differences in the solution process */
1704 
1705    SCIP_CALL( colEnsureSize(col, blkmem, set, col->len+1) );
1706    assert(col->rows != NULL);
1707    assert(col->vals != NULL);
1708    assert(col->linkpos != NULL);
1709 
1710    pos = col->len;
1711    col->len++;
1712 
1713    /* if the row is in current LP and is linked to the column, we have to insert it at the end of the linked LP rows
1714     * part of the column's arrays
1715     */
1716    if( row->lppos >= 0 && linkpos >= 0 )
1717    {
1718       /* move the first non-LP/not linked row to the end */
1719       if( col->nlprows < pos )
1720       {
1721          colMoveCoef(col, col->nlprows, pos);
1722          pos = col->nlprows;
1723       }
1724       col->nlprows++;
1725    }
1726 
1727    /* in case the coefficient is integral w.r.t. numerics we explicitly round the coefficient to an integral value */
1728    val = SCIPsetIsIntegral(set, val) ? SCIPsetRound(set, val) : val;
1729 
1730    /* insert the row at the correct position and update the links */
1731    col->rows[pos] = row;
1732    col->vals[pos] = val;
1733    col->linkpos[pos] = linkpos;
1734    if( linkpos == -1 )
1735    {
1736       col->nunlinked++;
1737 
1738       /* if the column is in current LP, we have to link it to the row, because otherwise, the primal information
1739        * of the row is not complete
1740        */
1741       if( col->lppos >= 0 )
1742       {
1743          /* this call might swap the current row with the first non-LP/not linked row, s.t. insertion position
1744           * has to be updated
1745           */
1746          SCIP_CALL( rowAddCoef(row, blkmem, set, eventqueue, lp, col, val, pos) );
1747          if( row->lppos >= 0 )
1748             pos = col->nlprows-1;
1749          linkpos = col->linkpos[pos];
1750 
1751          assert(0 <= linkpos && linkpos < row->len);
1752          assert(row->cols[linkpos] == col);
1753          assert(col->rows[pos] == row);
1754          assert(col->rows[pos]->cols[col->linkpos[pos]] == col);
1755          assert(col->rows[pos]->linkpos[col->linkpos[pos]] == pos);
1756       }
1757    }
1758    else
1759    {
1760       assert(row->linkpos[linkpos] == -1);
1761       assert(row->nunlinked > 0);
1762       row->linkpos[linkpos] = pos;
1763       row->nunlinked--;
1764 
1765       /* if the column is in current LP, now both conditions, row->cols[linkpos]->lppos >= 0 and row->linkpos[linkpos] >= 0
1766        * hold, so we have to move the column to the linked LP-cols part of the row's cols array
1767        */
1768       if( col->lppos >= 0 )
1769       {
1770          row->nlpcols++;
1771          rowSwapCoefs(row, linkpos, row->nlpcols-1);
1772 
1773          /* if no swap was necessary, mark nonlpcols to be unsorted */
1774          if( linkpos == row->nlpcols-1 )
1775             row->lpcolssorted = FALSE;
1776       }
1777    }
1778 
1779    /* update the sorted flags */
1780    if( row->lppos >= 0 && linkpos >= 0 )
1781    {
1782       assert(col->nlprows >= 1);
1783       assert(col->rows[col->nlprows-1] == row);
1784       if( col->nlprows > 1 )
1785          col->lprowssorted = col->lprowssorted && (col->rows[col->nlprows-2]->index < row->index);
1786    }
1787    else
1788    {
1789       assert(col->len - col->nlprows >= 1);
1790       assert(col->rows[col->len-1] == row);
1791       if( col->len - col->nlprows > 1 )
1792          col->nonlprowssorted = col->nonlprowssorted && (col->rows[col->len-2]->index < row->index);
1793    }
1794 
1795    coefChanged(row, col, lp);
1796 
1797    SCIPsetDebugMsg(set, "added coefficient %g * <%s> at position %d (%d/%d) to column <%s> (nunlinked=%d)\n",
1798       val, row->name, pos, col->nlprows, col->len, SCIPvarGetName(col->var), col->nunlinked);
1799 
1800    return SCIP_OKAY;
1801 }
1802 
1803 /** deletes coefficient at given position from column */
1804 static
colDelCoefPos(SCIP_COL * col,SCIP_SET * set,SCIP_LP * lp,int pos)1805 SCIP_RETCODE colDelCoefPos(
1806    SCIP_COL*             col,                /**< column to be changed */
1807    SCIP_SET*             set,                /**< global SCIP settings */
1808    SCIP_LP*              lp,                 /**< current LP data */
1809    int                   pos                 /**< position in column vector to delete */
1810    )
1811 {
1812    SCIP_ROW* row;
1813 
1814    assert(col != NULL);
1815    assert(col->var != NULL);
1816    assert(set != NULL);
1817    assert(0 <= pos && pos < col->len);
1818    assert(col->rows[pos] != NULL);
1819    assert(col->linkpos[pos] == -1 || col->rows[pos]->cols[col->linkpos[pos]] == col);
1820    assert((pos < col->nlprows) == (col->linkpos[pos] >= 0 && col->rows[pos]->lppos >= 0));
1821 
1822    row = col->rows[pos];
1823    assert((row->lppos >= 0) == (pos < col->nlprows));
1824 
1825    /*SCIPsetDebugMsg(set, "deleting coefficient %g * <%s> at position %d from column <%s>\n",
1826      col->vals[pos], row->name, pos, SCIPvarGetName(col->var));*/
1827 
1828    if( col->linkpos[pos] == -1 )
1829       col->nunlinked--;
1830 
1831    /* if row is a linked LP row, move last linked LP coefficient to position of empty slot (deleted coefficient) */
1832    if( pos < col->nlprows )
1833    {
1834       colMoveCoef(col, col->nlprows-1, pos);
1835       col->nlprows--;
1836       pos = col->nlprows;
1837    }
1838 
1839    /* move last coefficient to position of empty slot */
1840    colMoveCoef(col, col->len-1, pos);
1841    col->len--;
1842 
1843    coefChanged(row, col, lp);
1844 
1845    return SCIP_OKAY;
1846 }
1847 
1848 /** changes a coefficient at given position of an LP column */
1849 static
colChgCoefPos(SCIP_COL * col,SCIP_SET * set,SCIP_LP * lp,int pos,SCIP_Real val)1850 SCIP_RETCODE colChgCoefPos(
1851    SCIP_COL*             col,                /**< LP column */
1852    SCIP_SET*             set,                /**< global SCIP settings */
1853    SCIP_LP*              lp,                 /**< current LP data */
1854    int                   pos,                /**< position in column vector to change */
1855    SCIP_Real             val                 /**< value of coefficient */
1856    )
1857 {
1858    assert(col != NULL);
1859    assert(col->var != NULL);
1860    assert(0 <= pos && pos < col->len);
1861    assert(col->rows[pos] != NULL);
1862    assert(col->linkpos[pos] == -1 || col->rows[pos]->cols[col->linkpos[pos]] == col);
1863 
1864    /*debugMsg(scip, "changing coefficient %g * <%s> at position %d of column <%s> to %g\n",
1865      col->vals[pos], col->rows[pos]->name, pos, SCIPvarGetName(col->var), val);*/
1866 
1867    /* in case the coefficient is integral w.r.t. numerics we explicitly round the coefficient to an integral value */
1868    val = SCIPsetIsIntegral(set, val) ? SCIPsetRound(set, val) : val;
1869 
1870    if( SCIPsetIsZero(set, val) )
1871    {
1872       /* delete existing coefficient */
1873       SCIP_CALL( colDelCoefPos(col, set, lp, pos) );
1874    }
1875    else if( !SCIPsetIsEQ(set, col->vals[pos], val) )
1876    {
1877       /* change existing coefficient */
1878       col->vals[pos] = val;
1879       coefChanged(col->rows[pos], col, lp);
1880    }
1881 
1882    return SCIP_OKAY;
1883 }
1884 
1885 
1886 
1887 
1888 /*
1889  * local row changing methods
1890  */
1891 
1892 /** update row norms after addition of coefficient */
1893 static
rowAddNorms(SCIP_ROW * row,SCIP_SET * set,SCIP_COL * col,SCIP_Real val,SCIP_Bool updateidxvals)1894 void rowAddNorms(
1895    SCIP_ROW*             row,                /**< LP row */
1896    SCIP_SET*             set,                /**< global SCIP settings */
1897    SCIP_COL*             col,                /**< column of added coefficient */
1898    SCIP_Real             val,                /**< value of added coefficient */
1899    SCIP_Bool             updateidxvals       /**< update min/max idx and min/max val? */
1900    )
1901 {
1902    SCIP_Real absval;
1903 
1904    assert(row != NULL);
1905    assert(row->nummaxval >= 0);
1906    assert(row->numminval >= 0);
1907    assert(set != NULL);
1908    assert(col != NULL);
1909 
1910    absval = REALABS(val);
1911    assert(!SCIPsetIsZero(set, absval));
1912 
1913    /* Euclidean norm, sum norm, and objective function scalar product only take LP columns into account */
1914    if( col->lppos >= 0 )
1915    {
1916       /* update squared Euclidean norm and sum norm */
1917       row->sqrnorm += SQR(absval);
1918       row->sumnorm += absval;
1919 
1920       /* update objective function scalar product */
1921       row->objprod += val * col->unchangedobj;
1922    }
1923 
1924    if( updateidxvals )
1925    {
1926       /* update min/maxidx */
1927       row->minidx = MIN(row->minidx, col->index);
1928       row->maxidx = MAX(row->maxidx, col->index);
1929 
1930       /* update maximal and minimal non-zero value */
1931       if( row->nummaxval > 0 )
1932       {
1933          if( SCIPsetIsGT(set, absval, row->maxval) )
1934          {
1935             row->maxval = absval;
1936             row->nummaxval = 1;
1937          }
1938          else if( SCIPsetIsGE(set, absval, row->maxval) )
1939          {
1940             /* make sure the maxval is always exactly the same */
1941             row->maxval = MAX(absval, row->maxval);
1942             row->nummaxval++;
1943          }
1944       }
1945       if( row->numminval > 0 )
1946       {
1947          if( SCIPsetIsLT(set, absval, row->minval) )
1948          {
1949             row->minval = absval;
1950             row->numminval = 1;
1951          }
1952          else if( SCIPsetIsLE(set, absval, row->minval) )
1953          {
1954             /* make sure the minval is always exactly the same */
1955             row->minval = MIN(absval, row->minval);
1956             row->numminval++;
1957          }
1958       }
1959    }
1960    else
1961    {
1962       assert(row->minidx <= col->index);
1963       assert(row->maxidx >= col->index);
1964       assert(row->numminval <= 0 || absval >= row->minval);
1965       assert(row->nummaxval <= 0 || absval <= row->maxval);
1966    }
1967 }
1968 
1969 /** update row norms after deletion of coefficient */
1970 static
rowDelNorms(SCIP_ROW * row,SCIP_SET * set,SCIP_COL * col,SCIP_Real val,SCIP_Bool forcenormupdate,SCIP_Bool updateindex,SCIP_Bool updateval)1971 void rowDelNorms(
1972    SCIP_ROW*             row,                /**< LP row */
1973    SCIP_SET*             set,                /**< global SCIP settings */
1974    SCIP_COL*             col,                /**< column of deleted coefficient */
1975    SCIP_Real             val,                /**< value of deleted coefficient */
1976    SCIP_Bool             forcenormupdate,    /**< should the norms be updated even if lppos of column is -1? */
1977    SCIP_Bool             updateindex,        /**< should the minimal/maximal column index of row be updated? */
1978    SCIP_Bool             updateval           /**< should the minimal/maximal value of row be updated? */
1979    )
1980 {
1981    SCIP_Real absval;
1982 
1983    assert(row != NULL);
1984    assert(row->nummaxval >= 0);
1985    assert(row->numminval >= 0);
1986    assert(set != NULL);
1987    assert(col != NULL);
1988 
1989    absval = REALABS(val);
1990    assert(!SCIPsetIsZero(set, absval));
1991    assert(row->nummaxval == 0 || row->maxval >= absval);
1992    assert(row->numminval == 0 || row->minval <= absval);
1993 
1994    /* update min/maxidx validity */
1995    if( updateindex && (col->index == row->minidx || col->index == row->maxidx) )
1996       row->validminmaxidx = FALSE;
1997 
1998    /* Euclidean norm, sum norm, and objective function scalar product only take LP columns into account */
1999    if( forcenormupdate || col->lppos >= 0 )
2000    {
2001       /* update squared Euclidean norm and sum norm */
2002       row->sqrnorm -= SQR(absval);
2003       row->sqrnorm = MAX(row->sqrnorm, 0.0);
2004       row->sumnorm -= absval;
2005       row->sumnorm = MAX(row->sumnorm, 0.0);
2006 
2007       /* update objective function scalar product */
2008       row->objprod -= val * col->unchangedobj;
2009    }
2010 
2011    if( updateval )
2012    {
2013       /* update maximal and minimal non-zero value */
2014       if( row->nummaxval > 0 )
2015       {
2016          if( SCIPsetIsGE(set, absval, row->maxval) )
2017             row->nummaxval--;
2018       }
2019       if( row->numminval > 0 )
2020       {
2021          if( SCIPsetIsLE(set, absval, row->minval) )
2022             row->numminval--;
2023       }
2024    }
2025 }
2026 
2027 /** adds a previously non existing coefficient to an LP row */
2028 static
rowAddCoef(SCIP_ROW * row,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp,SCIP_COL * col,SCIP_Real val,int linkpos)2029 SCIP_RETCODE rowAddCoef(
2030    SCIP_ROW*             row,                /**< LP row */
2031    BMS_BLKMEM*           blkmem,             /**< block memory */
2032    SCIP_SET*             set,                /**< global SCIP settings */
2033    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
2034    SCIP_LP*              lp,                 /**< current LP data */
2035    SCIP_COL*             col,                /**< LP column */
2036    SCIP_Real             val,                /**< value of coefficient */
2037    int                   linkpos             /**< position of row in the column's row array, or -1 */
2038    )
2039 {
2040    int pos;
2041 
2042    assert(row != NULL);
2043    assert(row->nlpcols <= row->len);
2044    assert(blkmem != NULL);
2045    assert(col != NULL);
2046    assert(col->var != NULL);
2047    assert(col->var_probindex == SCIPvarGetProbindex(col->var));
2048    assert(!SCIPsetIsZero(set, val));
2049    /*assert(rowSearchCoef(row, col) == -1);*/ /* this assert would lead to slight differences in the solution process */
2050 
2051    if( row->nlocks > 0 )
2052    {
2053       SCIPerrorMessage("cannot add a coefficient to the locked unmodifiable row <%s>\n", row->name);
2054       return SCIP_INVALIDDATA;
2055    }
2056 
2057    SCIP_CALL( SCIProwEnsureSize(row, blkmem, set, row->len+1) );
2058    assert(row->cols != NULL);
2059    assert(row->vals != NULL);
2060 
2061    pos = row->len;
2062    row->len++;
2063 
2064    /* if the column is in current LP and is linked to the row, we have to insert it at the end of the linked LP columns
2065     * part of the row's arrays
2066     */
2067    if( col->lppos >= 0 && linkpos >= 0 )
2068    {
2069       /* move the first non-LP/not linked column to the end */
2070       if( row->nlpcols < pos )
2071       {
2072          rowMoveCoef(row, row->nlpcols, pos);
2073          pos = row->nlpcols;
2074       }
2075       row->nlpcols++;
2076    }
2077 
2078    /* in case the coefficient is integral w.r.t. numerics we explicitly round the coefficient to an integral value */
2079    val = SCIPsetIsIntegral(set, val) ? SCIPsetRound(set, val) : val;
2080 
2081    /* insert the column at the correct position and update the links */
2082    row->cols[pos] = col;
2083    row->cols_index[pos] = col->index;
2084    row->vals[pos] = val;
2085    row->linkpos[pos] = linkpos;
2086    row->integral = row->integral && SCIPcolIsIntegral(col) && SCIPsetIsIntegral(set, val);
2087    if( linkpos == -1 )
2088    {
2089       row->nunlinked++;
2090 
2091       /* if the row is in current LP, we have to link it to the column, because otherwise, the dual information
2092        * of the column is not complete
2093        */
2094       if( row->lppos >= 0 )
2095       {
2096          /* this call might swap the current column with the first non-LP/not linked column, s.t. insertion position
2097           * has to be updated
2098           */
2099          SCIP_CALL( colAddCoef(col, blkmem, set, eventqueue, lp, row, val, pos) );
2100          if( col->lppos >= 0 )
2101             pos = row->nlpcols-1;
2102          linkpos = row->linkpos[pos];
2103 
2104          assert(0 <= linkpos && linkpos < col->len);
2105          assert(col->rows[linkpos] == row);
2106          assert(row->cols[pos] == col);
2107          assert(row->cols[pos]->rows[row->linkpos[pos]] == row);
2108          assert(row->cols[pos]->linkpos[row->linkpos[pos]] == pos);
2109       }
2110    }
2111    else
2112    {
2113       assert(col->linkpos[linkpos] == -1);
2114       assert(col->nunlinked > 0);
2115       col->linkpos[linkpos] = pos;
2116       col->nunlinked--;
2117 
2118       /* if the row is in current LP, now both conditions, col->rows[linkpos]->lppos >= 0 and col->linkpos[linkpos] >= 0
2119        * hold, so we have to move the row to the linked LP-rows part of the column's rows array
2120        */
2121       if( row->lppos >= 0 )
2122       {
2123          col->nlprows++;
2124          colSwapCoefs(col, linkpos, col->nlprows-1);
2125 
2126          /* if no swap was necessary, mark lprows to be unsorted */
2127          if( linkpos == col->nlprows-1 )
2128             col->lprowssorted = FALSE;
2129       }
2130    }
2131 
2132    /* update the sorted flags */
2133    if( col->lppos >= 0 && linkpos >= 0 )
2134    {
2135       assert(row->nlpcols >= 1);
2136       assert(row->cols[row->nlpcols-1] == col);
2137       if( row->nlpcols > 1 )
2138       {
2139          assert(row->cols_index[row->nlpcols-2] == row->cols[row->nlpcols-2]->index);
2140          row->lpcolssorted = row->lpcolssorted && (row->cols_index[row->nlpcols-2] < col->index);
2141       }
2142    }
2143    else
2144    {
2145       assert(row->len - row->nlpcols >= 1);
2146       assert(row->cols[row->len-1] == col);
2147       if( row->len - row->nlpcols > 1 )
2148       {
2149          assert(row->cols_index[row->len-2] == row->cols[row->len-2]->index);
2150          row->nonlpcolssorted = row->nonlpcolssorted && (row->cols_index[row->len-2] < col->index);
2151       }
2152    }
2153 
2154    /* update row norm */
2155    rowAddNorms(row, set, col, val, TRUE);
2156 
2157    coefChanged(row, col, lp);
2158 
2159    SCIPsetDebugMsg(set, "added coefficient %g * <%s> at position %d (%d/%d) to row <%s> (nunlinked=%d)\n",
2160       val, SCIPvarGetName(col->var), pos, row->nlpcols, row->len, row->name, row->nunlinked);
2161 
2162    /* issue row coefficient changed event */
2163    SCIP_CALL( rowEventCoefChanged(row, blkmem, set, eventqueue, col, 0.0, val) );
2164 
2165    return SCIP_OKAY;
2166 }
2167 
2168 /** deletes coefficient at given position from row */
2169 static
rowDelCoefPos(SCIP_ROW * row,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp,int pos)2170 SCIP_RETCODE rowDelCoefPos(
2171    SCIP_ROW*             row,                /**< row to be changed */
2172    BMS_BLKMEM*           blkmem,             /**< block memory */
2173    SCIP_SET*             set,                /**< global SCIP settings */
2174    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
2175    SCIP_LP*              lp,                 /**< current LP data */
2176    int                   pos                 /**< position in row vector to delete */
2177    )
2178 {
2179    SCIP_COL* col;
2180    SCIP_Real val;
2181 
2182    assert(row != NULL);
2183    assert(set != NULL);
2184    assert(0 <= pos && pos < row->len);
2185    assert(row->cols[pos] != NULL);
2186    assert((pos < row->nlpcols) == (row->linkpos[pos] >= 0 && row->cols[pos]->lppos >= 0));
2187 
2188    col = row->cols[pos];
2189    val = row->vals[pos];
2190    assert((pos < row->nlpcols) == (col->lppos >= 0 && row->linkpos[pos] >= 0));
2191 
2192    /*SCIPsetDebugMsg(set, "deleting coefficient %g * <%s> at position %d from row <%s>\n",
2193      val, SCIPvarGetName(col->var), pos, row->name);*/
2194 
2195    if( row->nlocks > 0 )
2196    {
2197       SCIPerrorMessage("cannot delete a coefficient from the locked unmodifiable row <%s>\n", row->name);
2198       return SCIP_INVALIDDATA;
2199    }
2200 
2201    if( row->linkpos[pos] == -1 )
2202       row->nunlinked--;
2203 
2204    /* if column is a linked LP column, move last linked LP coefficient to position of empty slot (deleted coefficient) */
2205    if( pos < row->nlpcols )
2206    {
2207       rowMoveCoef(row, row->nlpcols-1, pos);
2208       assert(!row->lpcolssorted);
2209       row->nlpcols--;
2210       pos = row->nlpcols;
2211    }
2212 
2213    /* move last coefficient to position of empty slot */
2214    rowMoveCoef(row, row->len-1, pos);
2215    row->len--;
2216 
2217    /* update norms */
2218    rowDelNorms(row, set, col, val, FALSE, TRUE, TRUE);
2219 
2220    coefChanged(row, col, lp);
2221 
2222    /* issue row coefficient changed event */
2223    SCIP_CALL( rowEventCoefChanged(row, blkmem, set, eventqueue, col, val, 0.0) );
2224 
2225    return SCIP_OKAY;
2226 }
2227 
2228 /** changes a coefficient at given position of an LP row */
2229 static
rowChgCoefPos(SCIP_ROW * row,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp,int pos,SCIP_Real val)2230 SCIP_RETCODE rowChgCoefPos(
2231    SCIP_ROW*             row,                /**< LP row */
2232    BMS_BLKMEM*           blkmem,             /**< block memory */
2233    SCIP_SET*             set,                /**< global SCIP settings */
2234    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
2235    SCIP_LP*              lp,                 /**< current LP data */
2236    int                   pos,                /**< position in row vector to change */
2237    SCIP_Real             val                 /**< value of coefficient */
2238    )
2239 {
2240    SCIP_COL* col;
2241 
2242    assert(row != NULL);
2243    assert(0 <= pos && pos < row->len);
2244 
2245    /*SCIPsetDebugMsg(set, "changing coefficient %g * <%s> at position %d of row <%s> to %g\n",
2246      row->vals[pos], SCIPvarGetName(row->cols[pos]->var), pos, row->name, val);*/
2247 
2248    if( row->nlocks > 0 )
2249    {
2250       SCIPerrorMessage("cannot change a coefficient of the locked unmodifiable row <%s>\n", row->name);
2251       return SCIP_INVALIDDATA;
2252    }
2253 
2254    /* in case the coefficient is integral w.r.t. numerics we explicitly round the coefficient to an integral value */
2255    val = SCIPsetIsIntegral(set, val) ? SCIPsetRound(set, val) : val;
2256    col = row->cols[pos];
2257    assert(row->cols[pos] != NULL);
2258 
2259    if( SCIPsetIsZero(set, val) )
2260    {
2261       /* delete existing coefficient */
2262       SCIP_CALL( rowDelCoefPos(row, blkmem, set, eventqueue, lp, pos) );
2263    }
2264    else if( !SCIPsetIsEQ(set, row->vals[pos], val) )
2265    {
2266       SCIP_Real oldval;
2267 
2268       oldval = row->vals[pos];
2269 
2270       /* change existing coefficient */
2271       rowDelNorms(row, set, col, row->vals[pos], FALSE, FALSE, TRUE);
2272       row->vals[pos] = val;
2273       row->integral = row->integral && SCIPcolIsIntegral(col) && SCIPsetIsIntegral(set, val);
2274       rowAddNorms(row, set, col, row->vals[pos], TRUE);
2275       coefChanged(row, col, lp);
2276 
2277       /* issue row coefficient changed event */
2278       SCIP_CALL( rowEventCoefChanged(row, blkmem, set, eventqueue, col, oldval, val) );
2279    }
2280 
2281    return SCIP_OKAY;
2282 }
2283 
2284 /** notifies LP row, that its sides were changed */
2285 static
rowSideChanged(SCIP_ROW * row,SCIP_SET * set,SCIP_LP * lp,SCIP_SIDETYPE sidetype)2286 SCIP_RETCODE rowSideChanged(
2287    SCIP_ROW*             row,                /**< LP row */
2288    SCIP_SET*             set,                /**< global SCIP settings */
2289    SCIP_LP*              lp,                 /**< current LP data */
2290    SCIP_SIDETYPE         sidetype            /**< type of side: left or right hand side */
2291    )
2292 {
2293    assert(row != NULL);
2294    assert(lp != NULL);
2295 
2296    if( row->lpipos >= 0 )
2297    {
2298       /* insert row in the chgrows list (if not already there) */
2299       if( !row->lhschanged && !row->rhschanged )
2300       {
2301          SCIP_CALL( ensureChgrowsSize(lp, set, lp->nchgrows+1) );
2302          lp->chgrows[lp->nchgrows] = row;
2303          lp->nchgrows++;
2304       }
2305 
2306       /* mark side change in the row */
2307       switch( sidetype )
2308       {
2309       case SCIP_SIDETYPE_LEFT:
2310          row->lhschanged = TRUE;
2311          break;
2312       case SCIP_SIDETYPE_RIGHT:
2313          row->rhschanged = TRUE;
2314          break;
2315       default:
2316          SCIPerrorMessage("unknown row side type\n");
2317          SCIPABORT();
2318          return SCIP_INVALIDDATA;  /*lint !e527*/
2319       }
2320 
2321       /* mark the current LP unflushed */
2322       lp->flushed = FALSE;
2323 
2324       assert(lp->nchgrows > 0);
2325    }
2326 
2327    return SCIP_OKAY;
2328 }
2329 
2330 
2331 
2332 
2333 /*
2334  * double linked coefficient matrix methods
2335  */
2336 
2337 /** insert column coefficients in corresponding rows */
2338 static
colLink(SCIP_COL * col,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp)2339 SCIP_RETCODE colLink(
2340    SCIP_COL*             col,                /**< column data */
2341    BMS_BLKMEM*           blkmem,             /**< block memory */
2342    SCIP_SET*             set,                /**< global SCIP settings */
2343    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
2344    SCIP_LP*              lp                  /**< current LP data */
2345    )
2346 {
2347    int i;
2348 
2349    assert(col != NULL);
2350    assert(col->var != NULL);
2351    assert(blkmem != NULL);
2352    assert(set != NULL);
2353    assert(lp != NULL);
2354 
2355    if( col->nunlinked > 0 )
2356    {
2357       SCIPsetDebugMsg(set, "linking column <%s>\n", SCIPvarGetName(col->var));
2358 
2359       /* unlinked rows can only be in the non-LP/unlinked rows part of the rows array */
2360       for( i = col->nlprows; i < col->len; ++i )
2361       {
2362          assert(!SCIPsetIsZero(set, col->vals[i]));
2363          if( col->linkpos[i] == -1 )
2364          {
2365             /* this call might swap the current row with the first non-LP/not linked row, but this is of no harm */
2366             SCIP_CALL( rowAddCoef(col->rows[i], blkmem, set, eventqueue, lp, col, col->vals[i], i) );
2367          }
2368          assert(col->rows[i]->cols[col->linkpos[i]] == col);
2369          assert(col->rows[i]->linkpos[col->linkpos[i]] == i);
2370          assert(col->nlprows == 0 || col->rows[col->nlprows-1]->cols[col->linkpos[col->nlprows-1]] == col);
2371          assert(col->nlprows == 0 || col->rows[col->nlprows-1]->linkpos[col->linkpos[col->nlprows-1]] == col->nlprows-1);
2372       }
2373    }
2374    assert(col->nunlinked == 0);
2375 
2376    checkLinks(lp);
2377 
2378    return SCIP_OKAY;
2379 }
2380 
2381 /** removes column coefficients from corresponding rows */
2382 static
colUnlink(SCIP_COL * col,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp)2383 SCIP_RETCODE colUnlink(
2384    SCIP_COL*             col,                /**< column data */
2385    BMS_BLKMEM*           blkmem,             /**< block memory */
2386    SCIP_SET*             set,                /**< global SCIP settings */
2387    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
2388    SCIP_LP*              lp                  /**< current LP data */
2389    )
2390 {
2391    int i;
2392 
2393    assert(col != NULL);
2394    assert(col->var != NULL);
2395    assert(blkmem != NULL);
2396    assert(set != NULL);
2397    assert(lp != NULL);
2398 
2399    if( col->nunlinked < col->len )
2400    {
2401       SCIPsetDebugMsg(set, "unlinking column <%s>\n", SCIPvarGetName(col->var));
2402       for( i = 0; i < col->len; ++i )
2403       {
2404          if( col->linkpos[i] >= 0 )
2405          {
2406             assert(col->rows[i]->cols[col->linkpos[i]] == col);
2407             SCIP_CALL( rowDelCoefPos(col->rows[i], blkmem, set, eventqueue, lp, col->linkpos[i]) );
2408             col->linkpos[i] = -1;
2409             col->nunlinked++;
2410          }
2411       }
2412    }
2413    assert(col->nunlinked == col->len);
2414 
2415    checkLinks(lp);
2416 
2417    return SCIP_OKAY;
2418 }
2419 
2420 /** insert row coefficients in corresponding columns */
2421 static
rowLink(SCIP_ROW * row,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp)2422 SCIP_RETCODE rowLink(
2423    SCIP_ROW*             row,                /**< row data */
2424    BMS_BLKMEM*           blkmem,             /**< block memory */
2425    SCIP_SET*             set,                /**< global SCIP settings */
2426    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
2427    SCIP_LP*              lp                  /**< current LP data */
2428    )
2429 {
2430    int i;
2431 
2432    assert(row != NULL);
2433    assert(blkmem != NULL);
2434    assert(set != NULL);
2435    assert(lp != NULL);
2436 
2437    if( row->nunlinked > 0 )
2438    {
2439       SCIPsetDebugMsg(set, "linking row <%s>\n", row->name);
2440 
2441       /* unlinked columns can only be in the non-LP/unlinked columns part of the cols array */
2442       for( i = row->nlpcols; i < row->len; ++i )
2443       {
2444          assert(!SCIPsetIsZero(set, row->vals[i]));
2445          if( row->linkpos[i] == -1 )
2446          {
2447             /* this call might swap the current column with the first non-LP/not linked column, but this is of no harm */
2448             SCIP_CALL( colAddCoef(row->cols[i], blkmem, set, eventqueue, lp, row, row->vals[i], i) );
2449          }
2450          assert(row->cols[i]->rows[row->linkpos[i]] == row);
2451          assert(row->cols[i]->linkpos[row->linkpos[i]] == i);
2452          assert(row->nlpcols == 0 || row->cols[row->nlpcols-1]->rows[row->linkpos[row->nlpcols-1]] == row);
2453          assert(row->nlpcols == 0 || row->cols[row->nlpcols-1]->linkpos[row->linkpos[row->nlpcols-1]] == row->nlpcols-1);
2454       }
2455    }
2456    assert(row->nunlinked == 0);
2457 
2458    checkLinks(lp);
2459 
2460    return SCIP_OKAY;
2461 }
2462 
2463 /** removes row coefficients from corresponding columns */
2464 static
rowUnlink(SCIP_ROW * row,SCIP_SET * set,SCIP_LP * lp)2465 SCIP_RETCODE rowUnlink(
2466    SCIP_ROW*             row,                /**< row data */
2467    SCIP_SET*             set,                /**< global SCIP settings */
2468    SCIP_LP*              lp                  /**< current LP data */
2469    )
2470 {
2471    int i;
2472 
2473    assert(row != NULL);
2474    assert(set != NULL);
2475    assert(lp != NULL);
2476 
2477    if( row->nunlinked < row->len )
2478    {
2479       SCIPsetDebugMsg(set, "unlinking row <%s>\n", row->name);
2480       for( i = 0; i < row->len; ++i )
2481       {
2482          if( row->linkpos[i] >= 0 )
2483          {
2484             assert(row->cols[i]->rows[row->linkpos[i]] == row);
2485             SCIP_CALL( colDelCoefPos(row->cols[i], set, lp, row->linkpos[i]) );
2486             row->nunlinked++;
2487          }
2488       }
2489    }
2490    assert(row->nunlinked == row->len);
2491 
2492    return SCIP_OKAY;
2493 }
2494 
2495 
2496 
2497 
2498 /*
2499  * local LP parameter methods
2500  */
2501 
2502 /** sets parameter of type int in LP solver, ignoring unknown parameters */
2503 static
lpSetIntpar(SCIP_LP * lp,SCIP_LPPARAM lpparam,int value,SCIP_Bool * success)2504 SCIP_RETCODE lpSetIntpar(
2505    SCIP_LP*              lp,                 /**< current LP data */
2506    SCIP_LPPARAM          lpparam,            /**< LP parameter */
2507    int                   value,              /**< value to set parameter to */
2508    SCIP_Bool*            success             /**< pointer to store whether the parameter was successfully changed */
2509    )
2510 {
2511    SCIP_RETCODE retcode;
2512 
2513    assert(lp != NULL);
2514    assert(success != NULL);
2515 
2516    retcode = SCIPlpiSetIntpar(lp->lpi, lpparam, value);
2517 
2518    /* check, if parameter is unknown */
2519    if( retcode == SCIP_PARAMETERUNKNOWN )
2520    {
2521       *success = FALSE;
2522       return SCIP_OKAY;
2523    }
2524    *success = TRUE;
2525 
2526    return retcode;
2527 }
2528 
2529 /** sets parameter of type SCIP_Bool in LP solver, ignoring unknown parameters */
2530 static
lpSetBoolpar(SCIP_LP * lp,SCIP_LPPARAM lpparam,SCIP_Bool value,SCIP_Bool * success)2531 SCIP_RETCODE lpSetBoolpar(
2532    SCIP_LP*              lp,                 /**< current LP data */
2533    SCIP_LPPARAM          lpparam,            /**< LP parameter */
2534    SCIP_Bool             value,              /**< value to set parameter to */
2535    SCIP_Bool*            success             /**< pointer to store whether the parameter was successfully changed */
2536    )
2537 {
2538    return lpSetIntpar(lp, lpparam, (int)value, success);
2539 }
2540 
2541 /** sets parameter of type SCIP_Real in LP solver, ignoring unknown parameters */
2542 static
lpSetRealpar(SCIP_LP * lp,SCIP_LPPARAM lpparam,SCIP_Real value,SCIP_Bool * success)2543 SCIP_RETCODE lpSetRealpar(
2544    SCIP_LP*              lp,                 /**< current LP data */
2545    SCIP_LPPARAM          lpparam,            /**< LP parameter */
2546    SCIP_Real             value,              /**< value to set parameter to */
2547    SCIP_Bool*            success             /**< pointer to store whether the parameter was successfully changed */
2548    )
2549 {
2550    SCIP_RETCODE retcode;
2551 
2552    assert(lp != NULL);
2553    assert(success != NULL);
2554 
2555    retcode = SCIPlpiSetRealpar(lp->lpi, lpparam, value);
2556 
2557    /* check, if parameter is unknown */
2558    if( retcode == SCIP_PARAMETERUNKNOWN )
2559    {
2560       *success = FALSE;
2561       return SCIP_OKAY;
2562    }
2563    *success = TRUE;
2564 
2565    return retcode;
2566 }
2567 
2568 #ifndef NDEBUG
2569 /** checks, that parameter of type int in LP solver has the given value, ignoring unknown parameters */
2570 static
lpCheckIntpar(SCIP_LP * lp,SCIP_LPPARAM lpparam,int value)2571 SCIP_RETCODE lpCheckIntpar(
2572    SCIP_LP*              lp,                 /**< current LP data */
2573    SCIP_LPPARAM          lpparam,            /**< LP parameter */
2574    int                   value               /**< value parameter should have */
2575    )
2576 {
2577    SCIP_RETCODE retcode;
2578    int lpivalue;
2579 
2580    assert(lp != NULL);
2581 
2582    retcode = SCIPlpiGetIntpar(lp->lpi, lpparam, &lpivalue);
2583 
2584    /* ignore unknown parameter error */
2585    if( retcode == SCIP_PARAMETERUNKNOWN )
2586       return SCIP_OKAY;
2587 
2588    /* check value */
2589    assert(lpivalue == value);
2590 
2591    return retcode;
2592 }
2593 
2594 /** checks, that parameter of type SCIP_Bool in LP solver has the given value, ignoring unknown parameters */
2595 static
lpCheckBoolpar(SCIP_LP * lp,SCIP_LPPARAM lpparam,SCIP_Bool value)2596 SCIP_RETCODE lpCheckBoolpar(
2597    SCIP_LP*              lp,                 /**< current LP data */
2598    SCIP_LPPARAM          lpparam,            /**< LP parameter */
2599    SCIP_Bool             value               /**< value parameter should have */
2600    )
2601 {
2602    return lpCheckIntpar(lp, lpparam, (int)value);
2603 }
2604 
2605 /** checks, that parameter of type SCIP_Real in LP solver has the given value, ignoring unknown parameters */
2606 static
lpCheckRealpar(SCIP_LP * lp,SCIP_LPPARAM lpparam,SCIP_Real value)2607 SCIP_RETCODE lpCheckRealpar(
2608    SCIP_LP*              lp,                 /**< current LP data */
2609    SCIP_LPPARAM          lpparam,            /**< LP parameter */
2610    SCIP_Real             value               /**< value parameter should have */
2611    )
2612 {
2613    SCIP_RETCODE retcode;
2614    SCIP_Real lpivalue;
2615 
2616    assert(lp != NULL);
2617 
2618    retcode = SCIPlpiGetRealpar(lp->lpi, lpparam, &lpivalue);
2619 
2620    /* ignore unknown parameter error */
2621    if( retcode == SCIP_PARAMETERUNKNOWN )
2622       return SCIP_OKAY;
2623 
2624    /* check value */
2625    assert(lpivalue == value); /*lint !e777*/
2626 
2627    return retcode;
2628 }
2629 #else
2630 #define lpCheckIntpar(lp, lpparam, value) SCIP_OKAY
2631 #define lpCheckBoolpar(lp, lpparam, value) SCIP_OKAY
2632 #define lpCheckRealpar(lp, lpparam, value) SCIP_OKAY
2633 #endif
2634 
2635 /** should the objective limit of the LP solver be disabled */
2636 #define lpCutoffDisabled(set) (set->lp_disablecutoff == 1 || (set->nactivepricers > 0 && set->lp_disablecutoff == 2))
2637 
2638 /** sets the objective limit of the LP solver
2639  *
2640  *  Note that we are always minimizing.
2641  */
2642 static
lpSetObjlim(SCIP_LP * lp,SCIP_SET * set,SCIP_Real objlim,SCIP_Bool * success)2643 SCIP_RETCODE lpSetObjlim(
2644    SCIP_LP*              lp,                 /**< current LP data */
2645    SCIP_SET*             set,                /**< global SCIP settings */
2646    SCIP_Real             objlim,             /**< new objective limit */
2647    SCIP_Bool*            success             /**< pointer to store whether the parameter was actually changed */
2648    )
2649 {
2650    assert(lp != NULL);
2651    assert(set != NULL);
2652    assert(success != NULL);
2653 
2654    *success = FALSE;
2655 
2656    /* We disabled the objective limit in the LP solver or we want so solve exactly and thus cannot rely on the LP
2657     * solver's objective limit handling, so we return here and do not apply the objective limit. */
2658    if( lpCutoffDisabled(set) || set->misc_exactsolve )
2659       return SCIP_OKAY;
2660 
2661    /* convert SCIP infinity value to lp-solver infinity value if necessary */
2662    if( SCIPsetIsInfinity(set, objlim) )
2663       objlim = SCIPlpiInfinity(lp->lpi);
2664 
2665    SCIP_CALL( lpCheckRealpar(lp, SCIP_LPPAR_OBJLIM, lp->lpiobjlim) );
2666 
2667    if( objlim != lp->lpiobjlim ) /*lint !e777*/
2668    {
2669       SCIP_CALL( lpSetRealpar(lp, SCIP_LPPAR_OBJLIM, objlim, success) );
2670       if( *success )
2671       {
2672          SCIP_Real actualobjlim;
2673 
2674          /* check whether the parameter was actually changed or already was at the boundary of the LP solver's parameter range */
2675          SCIP_CALL( SCIPlpiGetRealpar(lp->lpi, SCIP_LPPAR_OBJLIM, &actualobjlim) );
2676          if( actualobjlim != lp->lpiobjlim ) /*lint !e777*/
2677          {
2678             /* mark the current solution invalid */
2679             lp->solved = FALSE;
2680             lp->primalfeasible = FALSE;
2681             lp->primalchecked = FALSE;
2682             lp->lpobjval = SCIP_INVALID;
2683             lp->lpsolstat = SCIP_LPSOLSTAT_NOTSOLVED;
2684          }
2685          lp->lpiobjlim = actualobjlim;
2686       }
2687    }
2688 
2689    return SCIP_OKAY;
2690 }
2691 
2692 /** sets the feasibility tolerance of the LP solver */
2693 static
lpSetFeastol(SCIP_LP * lp,SCIP_Real feastol,SCIP_Bool * success)2694 SCIP_RETCODE lpSetFeastol(
2695    SCIP_LP*              lp,                 /**< current LP data */
2696    SCIP_Real             feastol,            /**< new feasibility tolerance */
2697    SCIP_Bool*            success             /**< pointer to store whether the parameter was actually changed */
2698    )
2699 {
2700    assert(lp != NULL);
2701    assert(feastol >= 0.0);
2702    assert(success != NULL);
2703 
2704    SCIP_CALL( lpCheckRealpar(lp, SCIP_LPPAR_FEASTOL, lp->lpifeastol) );
2705 
2706    if( feastol != lp->lpifeastol ) /*lint !e777*/
2707    {
2708       SCIP_CALL( lpSetRealpar(lp, SCIP_LPPAR_FEASTOL, feastol, success) );
2709       if( *success )
2710       {
2711          SCIP_Real actualfeastol;
2712 
2713          /* check whether the parameter was actually changed or already was at the boundary of the LP solver's parameter range */
2714          SCIP_CALL( SCIPlpiGetRealpar(lp->lpi, SCIP_LPPAR_FEASTOL, &actualfeastol) );
2715          if( lp->nrows > 0 && actualfeastol < lp->lpifeastol )
2716          {
2717             /* mark the current solution invalid */
2718             lp->solved = FALSE;
2719             lp->primalfeasible = FALSE;
2720             lp->primalchecked = FALSE;
2721             lp->lpobjval = SCIP_INVALID;
2722             lp->lpsolstat = SCIP_LPSOLSTAT_NOTSOLVED;
2723          }
2724          else
2725             *success = FALSE;
2726          lp->lpifeastol = actualfeastol;
2727       }
2728    }
2729    else
2730       *success = FALSE;
2731 
2732    return SCIP_OKAY;
2733 }
2734 
2735 /** sets the reduced costs feasibility tolerance of the LP solver */
2736 static
lpSetDualfeastol(SCIP_LP * lp,SCIP_Real dualfeastol,SCIP_Bool * success)2737 SCIP_RETCODE lpSetDualfeastol(
2738    SCIP_LP*              lp,                 /**< current LP data */
2739    SCIP_Real             dualfeastol,        /**< new reduced costs feasibility tolerance */
2740    SCIP_Bool*            success             /**< pointer to store whether the parameter was actually changed */
2741    )
2742 {
2743    assert(lp != NULL);
2744    assert(dualfeastol >= 0.0);
2745    assert(success != NULL);
2746 
2747    SCIP_CALL( lpCheckRealpar(lp, SCIP_LPPAR_DUALFEASTOL, lp->lpidualfeastol) );
2748 
2749    if( dualfeastol != lp->lpidualfeastol ) /*lint !e777*/
2750    {
2751       SCIP_CALL( lpSetRealpar(lp, SCIP_LPPAR_DUALFEASTOL, dualfeastol, success) );
2752       if( *success )
2753       {
2754          SCIP_Real actualdualfeastol;
2755 
2756          /* check whether the parameter was actually changed or already was at the boundary of the LP solver's parameter range */
2757          SCIP_CALL( SCIPlpiGetRealpar(lp->lpi, SCIP_LPPAR_DUALFEASTOL, &actualdualfeastol) );
2758          if( lp->nrows > 0 && actualdualfeastol < lp->lpidualfeastol )
2759          {
2760             /* mark the current solution invalid */
2761             lp->solved = FALSE;
2762             lp->dualfeasible = FALSE;
2763             lp->dualchecked = FALSE;
2764             lp->lpobjval = SCIP_INVALID;
2765             lp->lpsolstat = SCIP_LPSOLSTAT_NOTSOLVED;
2766          }
2767          else
2768             *success = FALSE;
2769          lp->lpidualfeastol = actualdualfeastol;
2770       }
2771    }
2772    else
2773       *success = FALSE;
2774 
2775    return SCIP_OKAY;
2776 }
2777 
2778 /** sets the convergence tolerance used in barrier algorithm of the LP solver */
2779 static
lpSetBarrierconvtol(SCIP_LP * lp,SCIP_Real barrierconvtol,SCIP_Bool * success)2780 SCIP_RETCODE lpSetBarrierconvtol(
2781    SCIP_LP*              lp,                 /**< current LP data */
2782    SCIP_Real             barrierconvtol,     /**< new convergence tolerance used in barrier algorithm */
2783    SCIP_Bool*            success             /**< pointer to store whether the parameter was actually changed */
2784    )
2785 {
2786    assert(lp != NULL);
2787    assert(barrierconvtol >= 0.0);
2788    assert(success != NULL);
2789 
2790    SCIP_CALL( lpCheckRealpar(lp, SCIP_LPPAR_BARRIERCONVTOL, lp->lpibarrierconvtol) );
2791 
2792    if( barrierconvtol != lp->lpibarrierconvtol ) /*lint !e777*/
2793    {
2794       SCIP_CALL( lpSetRealpar(lp, SCIP_LPPAR_BARRIERCONVTOL, barrierconvtol, success) );
2795       if( *success )
2796       {
2797          SCIP_Real actualbarrierconvtol;
2798 
2799          /* check whether the parameter was actually changed or already was at the boundary of the LP solver's parameter range */
2800          SCIP_CALL( SCIPlpiGetRealpar(lp->lpi, SCIP_LPPAR_BARRIERCONVTOL, &actualbarrierconvtol) );
2801          if( lp->nrows > 0 && actualbarrierconvtol < lp->lpibarrierconvtol
2802             && (lp->lastlpalgo == SCIP_LPALGO_BARRIER || lp->lastlpalgo == SCIP_LPALGO_BARRIERCROSSOVER) )
2803          {
2804             /* mark the current solution invalid */
2805             lp->solved = FALSE;
2806             lp->dualfeasible = FALSE;
2807             lp->dualchecked = FALSE;
2808             lp->lpobjval = SCIP_INVALID;
2809             lp->lpsolstat = SCIP_LPSOLSTAT_NOTSOLVED;
2810          }
2811          else
2812             *success = FALSE;
2813          lp->lpibarrierconvtol = actualbarrierconvtol;
2814       }
2815    }
2816    else
2817       *success = FALSE;
2818 
2819    return SCIP_OKAY;
2820 }
2821 
2822 /** sets the FROMSCRATCH setting of the LP solver */
2823 static
lpSetFromscratch(SCIP_LP * lp,SCIP_Bool fromscratch,SCIP_Bool * success)2824 SCIP_RETCODE lpSetFromscratch(
2825    SCIP_LP*              lp,                 /**< current LP data */
2826    SCIP_Bool             fromscratch,        /**< new FROMSCRATCH setting */
2827    SCIP_Bool*            success             /**< pointer to store whether the parameter was successfully changed */
2828    )
2829 {
2830    assert(lp != NULL);
2831    assert(success != NULL);
2832 
2833    SCIP_CALL( lpCheckBoolpar(lp, SCIP_LPPAR_FROMSCRATCH, lp->lpifromscratch) );
2834 
2835    if( fromscratch != lp->lpifromscratch )
2836    {
2837       SCIP_CALL( lpSetBoolpar(lp, SCIP_LPPAR_FROMSCRATCH, fromscratch, success) );
2838       if( *success )
2839          lp->lpifromscratch = fromscratch;
2840    }
2841    else
2842       *success = FALSE;
2843 
2844    return SCIP_OKAY;
2845 }
2846 
2847 /** sets the FASTMIP setting of the LP solver */
2848 static
lpSetFastmip(SCIP_LP * lp,int fastmip,SCIP_Bool * success)2849 SCIP_RETCODE lpSetFastmip(
2850    SCIP_LP*              lp,                 /**< current LP data */
2851    int                   fastmip,            /**< new FASTMIP setting */
2852    SCIP_Bool*            success             /**< pointer to store whether the parameter was successfully changed */
2853    )
2854 {
2855    assert(lp != NULL);
2856    assert(success != NULL);
2857    assert(0 <= fastmip && fastmip <= 1);
2858 
2859    SCIP_CALL( lpCheckIntpar(lp, SCIP_LPPAR_FASTMIP, lp->lpifastmip) );
2860 
2861    if( fastmip != lp->lpifastmip )
2862    {
2863       SCIP_CALL( lpSetIntpar(lp, SCIP_LPPAR_FASTMIP, fastmip, success) );
2864       if( *success )
2865       {
2866          lp->lpifastmip = fastmip;
2867          lp->solved = FALSE;
2868          /* We might only set lp->solved to false if fastmip is turned off, since the latter should be the more
2869           * demanding setting; however, in the current code, this should have not effect. */
2870       }
2871    }
2872    else
2873       *success = FALSE;
2874 
2875    return SCIP_OKAY;
2876 }
2877 
2878 /** sets the SCALING setting of the LP solver */
2879 static
lpSetScaling(SCIP_LP * lp,int scaling,SCIP_Bool * success)2880 SCIP_RETCODE lpSetScaling(
2881    SCIP_LP*              lp,                 /**< current LP data */
2882    int                   scaling,            /**< new SCALING setting */
2883    SCIP_Bool*            success             /**< pointer to store whether the parameter was successfully changed */
2884    )
2885 {
2886    assert(lp != NULL);
2887    assert(success != NULL);
2888 
2889    SCIP_CALL( lpCheckIntpar(lp, SCIP_LPPAR_SCALING, lp->lpiscaling) );
2890 
2891    if( scaling != lp->lpiscaling )
2892    {
2893       SCIP_CALL( lpSetIntpar(lp, SCIP_LPPAR_SCALING, scaling, success) );
2894       if( *success )
2895          lp->lpiscaling = scaling;
2896    }
2897    else
2898       *success = FALSE;
2899 
2900    return SCIP_OKAY;
2901 }
2902 
2903 /** sets the number of THREADS  of the LP solver */
2904 static
lpSetThreads(SCIP_LP * lp,int threads,SCIP_Bool * success)2905 SCIP_RETCODE lpSetThreads(
2906    SCIP_LP*              lp,                 /**< current LP data */
2907    int                   threads,            /**< new number of threads used to solve the LP */
2908    SCIP_Bool*            success             /**< pointer to store whether the parameter was successfully changed */
2909    )
2910 {
2911    assert(lp != NULL);
2912    assert(success != NULL);
2913 
2914    SCIP_CALL( lpCheckIntpar(lp, SCIP_LPPAR_THREADS, lp->lpithreads) );
2915 
2916    if( threads != lp->lpithreads )
2917    {
2918       SCIP_CALL( lpSetIntpar(lp, SCIP_LPPAR_THREADS, threads, success) );
2919       if( *success )
2920          lp->lpithreads = threads;
2921    }
2922    else
2923       *success = FALSE;
2924 
2925    return SCIP_OKAY;
2926 }
2927 
2928 /** sets the PRESOLVING setting of the LP solver */
2929 static
lpSetPresolving(SCIP_LP * lp,SCIP_Bool presolving,SCIP_Bool * success)2930 SCIP_RETCODE lpSetPresolving(
2931    SCIP_LP*              lp,                 /**< current LP data */
2932    SCIP_Bool             presolving,         /**< new PRESOLVING setting */
2933    SCIP_Bool*            success             /**< pointer to store whether the parameter was successfully changed */
2934    )
2935 {
2936    assert(lp != NULL);
2937    assert(success != NULL);
2938 
2939    SCIP_CALL( lpCheckBoolpar(lp, SCIP_LPPAR_PRESOLVING, lp->lpipresolving) );
2940 
2941    if( presolving != lp->lpipresolving )
2942    {
2943       SCIP_CALL( lpSetBoolpar(lp, SCIP_LPPAR_PRESOLVING, presolving, success) );
2944       if( *success )
2945          lp->lpipresolving = presolving;
2946    }
2947    else
2948       *success = FALSE;
2949 
2950    return SCIP_OKAY;
2951 }
2952 
2953 /** sets the ROWREPSWITCH setting of the LP solver */
2954 static
lpSetRowrepswitch(SCIP_LP * lp,SCIP_Real rowrepswitch,SCIP_Bool * success)2955 SCIP_RETCODE lpSetRowrepswitch(
2956    SCIP_LP*              lp,                 /**< current LP data */
2957    SCIP_Real             rowrepswitch,       /**< new ROWREPSWITCH value */
2958    SCIP_Bool*            success             /**< pointer to store whether the parameter was successfully changed */
2959    )
2960 {
2961    assert(lp != NULL);
2962    assert(success != NULL);
2963 
2964    SCIP_CALL( lpCheckRealpar(lp, SCIP_LPPAR_ROWREPSWITCH, lp->lpirowrepswitch) );
2965 
2966    if( rowrepswitch != lp->lpirowrepswitch )  /*lint !e777*/
2967    {
2968       SCIP_CALL( lpSetRealpar(lp, SCIP_LPPAR_ROWREPSWITCH, rowrepswitch, success) );
2969       if( *success )
2970          lp->lpirowrepswitch = rowrepswitch;
2971    }
2972    else
2973       *success = FALSE;
2974 
2975    return SCIP_OKAY;
2976 }
2977 
2978 /** sets the iteration limit of the LP solver */
2979 static
lpSetIterationLimit(SCIP_LP * lp,int itlim)2980 SCIP_RETCODE lpSetIterationLimit(
2981    SCIP_LP*              lp,                 /**< current LP data */
2982    int                   itlim               /**< maximal number of LP iterations to perform, or -1 for no limit */
2983    )
2984 {
2985    SCIP_Bool success;
2986 
2987    assert(lp != NULL);
2988    assert(itlim >= -1);
2989 
2990    if( itlim == -1 )
2991       itlim = INT_MAX;
2992 
2993    SCIP_CALL( lpCheckIntpar(lp, SCIP_LPPAR_LPITLIM, lp->lpiitlim) );
2994 
2995    if( itlim != lp->lpiitlim )
2996    {
2997       SCIP_CALL( lpSetIntpar(lp, SCIP_LPPAR_LPITLIM, itlim, &success) );
2998       if( success )
2999       {
3000          if( itlim > lp->lpiitlim )
3001          {
3002             /* mark the current solution invalid */
3003             lp->solved = FALSE;
3004             lp->lpobjval = SCIP_INVALID;
3005             lp->lpsolstat = SCIP_LPSOLSTAT_NOTSOLVED;
3006          }
3007          lp->lpiitlim = itlim;
3008       }
3009    }
3010 
3011    return SCIP_OKAY;
3012 }
3013 
3014 /** sets the pricing strategy of the LP solver */
3015 static
lpSetPricing(SCIP_LP * lp,SCIP_PRICING pricing)3016 SCIP_RETCODE lpSetPricing(
3017    SCIP_LP*              lp,                 /**< current LP data */
3018    SCIP_PRICING          pricing             /**< pricing strategy */
3019    )
3020 {
3021    SCIP_Bool success;
3022 
3023    assert(lp != NULL);
3024 
3025    SCIP_CALL( lpCheckIntpar(lp, SCIP_LPPAR_PRICING, (int)lp->lpipricing) );
3026 
3027    if( pricing != lp->lpipricing )
3028    {
3029       SCIP_CALL( lpSetIntpar(lp, SCIP_LPPAR_PRICING, (int)pricing, &success) );
3030       if( success )
3031          lp->lpipricing = pricing;
3032    }
3033 
3034    return SCIP_OKAY;
3035 }
3036 
3037 /** sets the pricing strategy of the LP solver (given the character representation of the strategy) */
3038 static
lpSetPricingChar(SCIP_LP * lp,char pricingchar)3039 SCIP_RETCODE lpSetPricingChar(
3040    SCIP_LP*              lp,                 /**< current LP data */
3041    char                  pricingchar         /**< character representing the pricing strategy */
3042    )
3043 {
3044    SCIP_PRICING pricing;
3045 
3046    switch( pricingchar )
3047    {
3048    case 'l':
3049       pricing = SCIP_PRICING_LPIDEFAULT;
3050       break;
3051    case 'a':
3052       pricing = SCIP_PRICING_AUTO;
3053       break;
3054    case 'f':
3055       pricing = SCIP_PRICING_FULL;
3056       break;
3057    case 'p':
3058       pricing = SCIP_PRICING_PARTIAL;
3059       break;
3060    case 's':
3061       pricing = SCIP_PRICING_STEEP;
3062       break;
3063    case 'q':
3064       pricing = SCIP_PRICING_STEEPQSTART;
3065       break;
3066    case 'd':
3067       pricing = SCIP_PRICING_DEVEX;
3068       break;
3069    default:
3070       SCIPerrorMessage("invalid LP pricing parameter <%c>\n", pricingchar);
3071       return SCIP_INVALIDDATA;
3072    }
3073 
3074    SCIP_CALL( lpSetPricing(lp, pricing) );
3075 
3076    return SCIP_OKAY;
3077 }
3078 
3079 /** sets the verbosity of the LP solver */
3080 static
lpSetLPInfo(SCIP_LP * lp,SCIP_Bool lpinfo)3081 SCIP_RETCODE lpSetLPInfo(
3082    SCIP_LP*              lp,                 /**< current LP data */
3083    SCIP_Bool             lpinfo              /**< should the LP solver display status messages? */
3084    )
3085 {
3086    SCIP_Bool success;
3087 
3088    assert(lp != NULL);
3089 
3090    SCIP_CALL( lpCheckBoolpar(lp, SCIP_LPPAR_LPINFO, lp->lpilpinfo) );
3091 
3092    if( lpinfo != lp->lpilpinfo )
3093    {
3094       SCIP_CALL( lpSetBoolpar(lp, SCIP_LPPAR_LPINFO, lpinfo, &success) );
3095       if( success )
3096          lp->lpilpinfo = lpinfo;
3097    }
3098 
3099    return SCIP_OKAY;
3100 }
3101 
3102 /** sets the CONDITIONLIMIT setting of the LP solver */
3103 static
lpSetConditionLimit(SCIP_LP * lp,SCIP_Real condlimit,SCIP_Bool * success)3104 SCIP_RETCODE lpSetConditionLimit(
3105    SCIP_LP*              lp,                 /**< current LP data */
3106    SCIP_Real             condlimit,          /**< new CONDITIONLIMIT value */
3107    SCIP_Bool*            success             /**< pointer to store whether the parameter was successfully changed */
3108    )
3109 {
3110    assert(lp != NULL);
3111    assert(success != NULL);
3112 
3113    SCIP_CALL( lpCheckRealpar(lp, SCIP_LPPAR_CONDITIONLIMIT, lp->lpiconditionlimit) );
3114 
3115    if( condlimit != lp->lpiconditionlimit )  /*lint !e777*/
3116    {
3117       SCIP_CALL( lpSetRealpar(lp, SCIP_LPPAR_CONDITIONLIMIT, condlimit, success) );
3118       if( *success )
3119          lp->lpiconditionlimit = condlimit;
3120    }
3121    else
3122       *success = FALSE;
3123 
3124    return SCIP_OKAY;
3125 }
3126 
3127 /** sets the MARKOWITZ setting of the LP solver */
3128 static
lpSetMarkowitz(SCIP_LP * lp,SCIP_Real threshhold,SCIP_Bool * success)3129 SCIP_RETCODE lpSetMarkowitz(
3130    SCIP_LP*              lp,                 /**< current LP data */
3131    SCIP_Real             threshhold,         /**< new MARKOWITZ value */
3132    SCIP_Bool*            success             /**< pointer to store whether the parameter was successfully changed */
3133    )
3134 {
3135    assert(lp != NULL);
3136    assert(success != NULL);
3137 
3138    SCIP_CALL( lpCheckRealpar(lp, SCIP_LPPAR_MARKOWITZ, lp->lpimarkowitz) );
3139 
3140    if( threshhold != lp->lpimarkowitz )  /*lint !e777*/
3141    {
3142       SCIP_CALL( lpSetRealpar(lp, SCIP_LPPAR_MARKOWITZ, threshhold, success) );
3143       if( *success )
3144          lp->lpimarkowitz = threshhold;
3145    }
3146    else
3147       *success = FALSE;
3148 
3149    return SCIP_OKAY;
3150 }
3151 
3152 /** sets the type of timer of the LP solver */
3153 static
lpSetTiming(SCIP_LP * lp,SCIP_CLOCKTYPE timing,SCIP_Bool enabled,SCIP_Bool * success)3154 SCIP_RETCODE lpSetTiming(
3155    SCIP_LP*              lp,                 /**< current LP data */
3156    SCIP_CLOCKTYPE        timing,             /**< new timing value */
3157    SCIP_Bool             enabled,            /**< is timing enabled? */
3158    SCIP_Bool*            success             /**< pointer to store whether the parameter was successfully changed */
3159    )
3160 {
3161    int lptiming;
3162 
3163    assert(lp != NULL);
3164    assert(success != NULL);
3165    assert((int) SCIP_CLOCKTYPE_CPU == 1 && (int) SCIP_CLOCKTYPE_WALL == 2); /*lint !e506*/
3166 
3167    SCIP_CALL( lpCheckIntpar(lp, SCIP_LPPAR_TIMING, lp->lpitiming) );
3168 
3169    if( !enabled )
3170       lptiming = 0;
3171    else
3172       lptiming = (int) timing;
3173 
3174    if( lptiming != lp->lpitiming )  /*lint !e777*/
3175    {
3176       SCIP_CALL( lpSetIntpar(lp, SCIP_LPPAR_TIMING, lptiming, success) );
3177       if( *success )
3178          lp->lpitiming = lptiming;
3179    }
3180    else
3181       *success = FALSE;
3182 
3183    return SCIP_OKAY;
3184 }
3185 
3186 /** sets the initial random seed of the LP solver */
3187 static
lpSetRandomseed(SCIP_LP * lp,int randomseed,SCIP_Bool * success)3188 SCIP_RETCODE lpSetRandomseed(
3189    SCIP_LP*              lp,                 /**< current LP data */
3190    int                   randomseed,         /**< new initial random seed */
3191    SCIP_Bool*            success             /**< pointer to store whether the parameter was successfully changed */
3192    )
3193 {
3194    assert(lp != NULL);
3195    assert(success != NULL);
3196 
3197    /* we don't check this parameter because SoPlex will always return its current random seed, not the initial one */
3198 
3199    if( randomseed == 0 )
3200    {
3201       lp->lpirandomseed = randomseed;
3202       *success = TRUE;
3203    }
3204    else if( randomseed != lp->lpirandomseed )  /*lint !e777*/
3205    {
3206       SCIP_CALL( lpSetIntpar(lp, SCIP_LPPAR_RANDOMSEED, randomseed, success) );
3207       if( *success )
3208          lp->lpirandomseed = randomseed;
3209    }
3210    else
3211       *success = FALSE;
3212 
3213    return SCIP_OKAY;
3214 }
3215 
3216 /** sets the LP solution polishing method */
3217 static
lpSetSolutionPolishing(SCIP_LP * lp,SCIP_Bool polishing,SCIP_Bool * success)3218 SCIP_RETCODE lpSetSolutionPolishing(
3219    SCIP_LP*              lp,                 /**< current LP data */
3220    SCIP_Bool             polishing,          /**< LP solution polishing activated (0: disabled, 1: enabled) */
3221    SCIP_Bool*            success             /**< pointer to store whether the parameter was successfully changed */
3222    )
3223 {
3224    assert(lp != NULL);
3225    assert(success != NULL);
3226 
3227    if( polishing != lp->lpisolutionpolishing )
3228    {
3229       SCIP_CALL( lpSetIntpar(lp, SCIP_LPPAR_POLISHING, (polishing ? 1 : 0), success) );
3230       if( *success )
3231          lp->lpisolutionpolishing = polishing;
3232    }
3233    else
3234       *success = FALSE;
3235 
3236    return SCIP_OKAY;
3237 }
3238 
3239 /** sets the LP refactorization interval */
3240 static
lpSetRefactorInterval(SCIP_LP * lp,int refactor,SCIP_Bool * success)3241 SCIP_RETCODE lpSetRefactorInterval(
3242    SCIP_LP*              lp,                 /**< current LP data */
3243    int                   refactor,           /**< LP refactorization interval (0: automatic) */
3244    SCIP_Bool*            success             /**< pointer to store whether the parameter was successfully changed */
3245    )
3246 {
3247    assert(lp != NULL);
3248    assert(success != NULL);
3249 
3250    if( refactor != lp->lpirefactorinterval )
3251    {
3252       SCIP_CALL( lpSetIntpar(lp, SCIP_LPPAR_REFACTOR, refactor, success) );
3253       if( *success )
3254          lp->lpirefactorinterval = refactor;
3255    }
3256    else
3257       *success = FALSE;
3258 
3259    return SCIP_OKAY;
3260 }
3261 
3262 
3263 /*
3264  * Column methods
3265  */
3266 
3267 /** creates an LP column */
SCIPcolCreate(SCIP_COL ** col,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_VAR * var,int len,SCIP_ROW ** rows,SCIP_Real * vals,SCIP_Bool removable)3268 SCIP_RETCODE SCIPcolCreate(
3269    SCIP_COL**            col,                /**< pointer to column data */
3270    BMS_BLKMEM*           blkmem,             /**< block memory */
3271    SCIP_SET*             set,                /**< global SCIP settings */
3272    SCIP_STAT*            stat,               /**< problem statistics */
3273    SCIP_VAR*             var,                /**< variable, this column represents */
3274    int                   len,                /**< number of nonzeros in the column */
3275    SCIP_ROW**            rows,               /**< array with rows of column entries */
3276    SCIP_Real*            vals,               /**< array with coefficients of column entries */
3277    SCIP_Bool             removable           /**< should the column be removed from the LP due to aging or cleanup? */
3278    )
3279 {
3280    int i;
3281 
3282    assert(col != NULL);
3283    assert(blkmem != NULL);
3284    assert(set != NULL);
3285    assert(stat != NULL);
3286    assert(var != NULL);
3287    assert(len >= 0);
3288    assert(len == 0 || (rows != NULL && vals != NULL));
3289 
3290    SCIP_ALLOC( BMSallocBlockMemory(blkmem, col) );
3291 
3292    if( len > 0 )
3293    {
3294       SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*col)->rows, rows, len) );
3295       SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*col)->vals, vals, len) );
3296       SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*col)->linkpos, len) );
3297 
3298       for( i = 0; i < len; ++i )
3299       {
3300          assert(rows[i] != NULL);
3301          assert(!SCIPsetIsZero(set, vals[i]));
3302          (*col)->linkpos[i] = -1;
3303       }
3304    }
3305    else
3306    {
3307       (*col)->rows = NULL;
3308       (*col)->vals = NULL;
3309       (*col)->linkpos = NULL;
3310    }
3311 
3312    (*col)->var = var;
3313    (*col)->obj = SCIPvarGetObj(var);
3314    (*col)->unchangedobj = SCIPvarGetUnchangedObj(var);
3315    (*col)->lb = SCIPvarGetLbLocal(var);
3316    (*col)->ub = SCIPvarGetUbLocal(var);
3317    (*col)->flushedobj = 0.0;
3318    (*col)->flushedlb = 0.0;
3319    (*col)->flushedub = 0.0;
3320    (*col)->index = stat->ncolidx;
3321    SCIPstatIncrement(stat, set, ncolidx);
3322    (*col)->size = len;
3323    (*col)->len = len;
3324    (*col)->nlprows = 0;
3325    (*col)->nunlinked = len;
3326    (*col)->lppos = -1;
3327    (*col)->lpipos = -1;
3328    (*col)->lpdepth = -1;
3329    (*col)->primsol = 0.0;
3330    (*col)->redcost = SCIP_INVALID;
3331    (*col)->farkascoef = SCIP_INVALID;
3332    (*col)->minprimsol = (*col)->ub;
3333    (*col)->maxprimsol = (*col)->lb;
3334    (*col)->sbdown = SCIP_INVALID;
3335    (*col)->sbup = SCIP_INVALID;
3336    (*col)->sbsolval  = SCIP_INVALID;
3337    (*col)->sblpobjval = SCIP_INVALID;
3338    (*col)->sbnode = -1;
3339    (*col)->validredcostlp = -1;
3340    (*col)->validfarkaslp = -1;
3341    (*col)->validsblp = -1;
3342    (*col)->sbitlim = -1;
3343    (*col)->nsbcalls = 0;
3344    (*col)->age = 0;
3345    (*col)->obsoletenode = -1;
3346    (*col)->var_probindex = SCIPvarGetProbindex(var);
3347    (*col)->basisstatus = SCIP_BASESTAT_ZERO; /*lint !e641*/
3348    (*col)->lprowssorted = TRUE;
3349    (*col)->nonlprowssorted = (len <= 1);
3350    (*col)->objchanged = FALSE;
3351    (*col)->lbchanged = FALSE;
3352    (*col)->ubchanged = FALSE;
3353    (*col)->coefchanged = FALSE;
3354    (*col)->integral = SCIPvarIsIntegral(var);
3355    (*col)->removable = removable;
3356    (*col)->sbdownvalid = FALSE;
3357    (*col)->sbupvalid = FALSE;
3358    (*col)->lazylb = SCIPvarGetLbLazy(var);
3359    (*col)->lazyub = SCIPvarGetUbLazy(var);
3360    (*col)->storedsolvals = NULL;
3361 
3362    return SCIP_OKAY;
3363 }
3364 
3365 /** frees an LP column */
SCIPcolFree(SCIP_COL ** col,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp)3366 SCIP_RETCODE SCIPcolFree(
3367    SCIP_COL**            col,                /**< pointer to LP column */
3368    BMS_BLKMEM*           blkmem,             /**< block memory */
3369    SCIP_SET*             set,                /**< global SCIP settings */
3370    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
3371    SCIP_LP*              lp                  /**< current LP data */
3372    )
3373 {
3374    assert(blkmem != NULL);
3375    assert(col != NULL);
3376    assert(*col != NULL);
3377    assert((*col)->var != NULL);
3378    assert(SCIPvarGetStatus((*col)->var) == SCIP_VARSTATUS_COLUMN);
3379    assert(&(*col)->var->data.col == col); /* SCIPcolFree() has to be called from SCIPvarFree() */
3380    assert((*col)->lppos == -1);
3381    assert((*col)->lpipos == -1);
3382 
3383    /* remove column indices from corresponding rows */
3384    SCIP_CALL( colUnlink(*col, blkmem, set, eventqueue, lp) );
3385 
3386    BMSfreeBlockMemoryNull(blkmem, &(*col)->storedsolvals);
3387    BMSfreeBlockMemoryArrayNull(blkmem, &(*col)->rows, (*col)->size);
3388    BMSfreeBlockMemoryArrayNull(blkmem, &(*col)->vals, (*col)->size);
3389    BMSfreeBlockMemoryArrayNull(blkmem, &(*col)->linkpos, (*col)->size);
3390    BMSfreeBlockMemory(blkmem, col);
3391 
3392    return SCIP_OKAY;
3393 }
3394 
3395 /** output column to file stream */
SCIPcolPrint(SCIP_COL * col,SCIP_MESSAGEHDLR * messagehdlr,FILE * file)3396 void SCIPcolPrint(
3397    SCIP_COL*             col,                /**< LP column */
3398    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
3399    FILE*                 file                /**< output file (or NULL for standard output) */
3400    )
3401 {
3402    int r;
3403 
3404    assert(col != NULL);
3405    assert(col->var != NULL);
3406 
3407    /* print bounds */
3408    SCIPmessageFPrintInfo(messagehdlr, file, "(obj: %.15g) [%.15g,%.15g], ", col->obj, col->lb, col->ub);
3409 
3410    /* print coefficients */
3411    if( col->len == 0 )
3412       SCIPmessageFPrintInfo(messagehdlr, file, "<empty>");
3413    for( r = 0; r < col->len; ++r )
3414    {
3415       assert(col->rows[r] != NULL);
3416       assert(col->rows[r]->name != NULL);
3417       SCIPmessageFPrintInfo(messagehdlr, file, "%+.15g<%s> ", col->vals[r], col->rows[r]->name);
3418    }
3419    SCIPmessageFPrintInfo(messagehdlr, file, "\n");
3420 }
3421 
3422 /** sorts column entries such that LP rows precede non-LP rows and inside both parts lower row indices precede higher ones
3423  */
SCIPcolSort(SCIP_COL * col)3424 void SCIPcolSort(
3425    SCIP_COL*             col                 /**< column to be sorted */
3426    )
3427 {
3428    /* sort LP rows */
3429    colSortLP(col);
3430 
3431    /* sort non-LP rows */
3432    colSortNonLP(col);
3433 }
3434 
3435 /** adds a previously non existing coefficient to an LP column */
SCIPcolAddCoef(SCIP_COL * col,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp,SCIP_ROW * row,SCIP_Real val)3436 SCIP_RETCODE SCIPcolAddCoef(
3437    SCIP_COL*             col,                /**< LP column */
3438    BMS_BLKMEM*           blkmem,             /**< block memory */
3439    SCIP_SET*             set,                /**< global SCIP settings */
3440    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
3441    SCIP_LP*              lp,                 /**< current LP data */
3442    SCIP_ROW*             row,                /**< LP row */
3443    SCIP_Real             val                 /**< value of coefficient */
3444    )
3445 {
3446    assert(lp != NULL);
3447    assert(!lp->diving);
3448 
3449    SCIP_CALL( colAddCoef(col, blkmem, set, eventqueue, lp, row, val, -1) );
3450 
3451    checkLinks(lp);
3452 
3453    return SCIP_OKAY;
3454 }
3455 
3456 /** deletes existing coefficient from column */
SCIPcolDelCoef(SCIP_COL * col,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp,SCIP_ROW * row)3457 SCIP_RETCODE SCIPcolDelCoef(
3458    SCIP_COL*             col,                /**< column to be changed */
3459    BMS_BLKMEM*           blkmem,             /**< block memory */
3460    SCIP_SET*             set,                /**< global SCIP settings */
3461    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
3462    SCIP_LP*              lp,                 /**< current LP data */
3463    SCIP_ROW*             row                 /**< coefficient to be deleted */
3464    )
3465 {
3466    int pos;
3467 
3468    assert(col != NULL);
3469    assert(col->var != NULL);
3470    assert(lp != NULL);
3471    assert(!lp->diving);
3472    assert(row != NULL);
3473 
3474    /* search the position of the row in the column's row vector */
3475    pos = colSearchCoef(col, row);
3476    if( pos == -1 )
3477    {
3478       SCIPerrorMessage("coefficient for row <%s> doesn't exist in column <%s>\n", row->name, SCIPvarGetName(col->var));
3479       return SCIP_INVALIDDATA;
3480    }
3481    assert(0 <= pos && pos < col->len);
3482    assert(col->rows[pos] == row);
3483 
3484    /* if row knows of the column, remove the column from the row's col vector */
3485    if( col->linkpos[pos] >= 0 )
3486    {
3487       assert(row->cols[col->linkpos[pos]] == col);
3488       assert(row->cols_index[col->linkpos[pos]] == col->index);
3489       assert(SCIPsetIsEQ(set, row->vals[col->linkpos[pos]], col->vals[pos]));
3490       SCIP_CALL( rowDelCoefPos(row, blkmem, set, eventqueue, lp, col->linkpos[pos]) );
3491    }
3492 
3493    /* delete the row from the column's row vector */
3494    SCIP_CALL( colDelCoefPos(col, set, lp, pos) );
3495 
3496    checkLinks(lp);
3497 
3498    return SCIP_OKAY;
3499 }
3500 
3501 /** changes or adds a coefficient to an LP column */
SCIPcolChgCoef(SCIP_COL * col,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp,SCIP_ROW * row,SCIP_Real val)3502 SCIP_RETCODE SCIPcolChgCoef(
3503    SCIP_COL*             col,                /**< LP column */
3504    BMS_BLKMEM*           blkmem,             /**< block memory */
3505    SCIP_SET*             set,                /**< global SCIP settings */
3506    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
3507    SCIP_LP*              lp,                 /**< current LP data */
3508    SCIP_ROW*             row,                /**< LP row */
3509    SCIP_Real             val                 /**< value of coefficient */
3510    )
3511 {
3512    int pos;
3513 
3514    assert(col != NULL);
3515    assert(lp != NULL);
3516    assert(!lp->diving);
3517    assert(row != NULL);
3518 
3519    /* search the position of the row in the column's row vector */
3520    pos = colSearchCoef(col, row);
3521 
3522    /* check, if row already exists in the column's row vector */
3523    if( pos == -1 )
3524    {
3525       /* add previously not existing coefficient */
3526       SCIP_CALL( colAddCoef(col, blkmem, set, eventqueue, lp, row, val, -1) );
3527    }
3528    else
3529    {
3530       /* modify already existing coefficient */
3531       assert(0 <= pos && pos < col->len);
3532       assert(col->rows[pos] == row);
3533 
3534       /* if row knows of the column, change the corresponding coefficient in the row */
3535       if( col->linkpos[pos] >= 0 )
3536       {
3537          assert(row->cols[col->linkpos[pos]] == col);
3538          assert(row->cols_index[col->linkpos[pos]] == col->index);
3539          assert(SCIPsetIsEQ(set, row->vals[col->linkpos[pos]], col->vals[pos]));
3540          SCIP_CALL( rowChgCoefPos(row, blkmem, set, eventqueue, lp, col->linkpos[pos], val) );
3541       }
3542 
3543       /* change the coefficient in the column */
3544       SCIP_CALL( colChgCoefPos(col, set, lp, pos, val) );
3545    }
3546 
3547    checkLinks(lp);
3548 
3549    return SCIP_OKAY;
3550 }
3551 
3552 /** increases value of an existing or non-existing coefficient in an LP column */
SCIPcolIncCoef(SCIP_COL * col,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp,SCIP_ROW * row,SCIP_Real incval)3553 SCIP_RETCODE SCIPcolIncCoef(
3554    SCIP_COL*             col,                /**< LP column */
3555    BMS_BLKMEM*           blkmem,             /**< block memory */
3556    SCIP_SET*             set,                /**< global SCIP settings */
3557    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
3558    SCIP_LP*              lp,                 /**< current LP data */
3559    SCIP_ROW*             row,                /**< LP row */
3560    SCIP_Real             incval              /**< value to add to the coefficient */
3561    )
3562 {
3563    int pos;
3564 
3565    assert(col != NULL);
3566    assert(lp != NULL);
3567    assert(!lp->diving);
3568    assert(row != NULL);
3569 
3570    if( SCIPsetIsZero(set, incval) )
3571       return SCIP_OKAY;
3572 
3573    /* search the position of the row in the column's row vector */
3574    pos = colSearchCoef(col, row);
3575 
3576    /* check, if row already exists in the column's row vector */
3577    if( pos == -1 )
3578    {
3579       /* add previously not existing coefficient */
3580       SCIP_CALL( colAddCoef(col, blkmem, set, eventqueue, lp, row, incval, -1) );
3581    }
3582    else
3583    {
3584       /* modify already existing coefficient */
3585       assert(0 <= pos && pos < col->len);
3586       assert(col->rows[pos] == row);
3587 
3588       /* if row knows of the column, change the corresponding coefficient in the row */
3589       if( col->linkpos[pos] >= 0 )
3590       {
3591          assert(row->cols[col->linkpos[pos]] == col);
3592          assert(row->cols_index[col->linkpos[pos]] == col->index);
3593          assert(SCIPsetIsEQ(set, row->vals[col->linkpos[pos]], col->vals[pos]));
3594          SCIP_CALL( rowChgCoefPos(row, blkmem, set, eventqueue, lp, col->linkpos[pos], col->vals[pos] + incval) );
3595       }
3596 
3597       /* change the coefficient in the column */
3598       SCIP_CALL( colChgCoefPos(col, set, lp, pos, col->vals[pos] + incval) );
3599    }
3600 
3601    checkLinks(lp);
3602 
3603    return SCIP_OKAY;
3604 }
3605 
3606 /** insert column in the chgcols list (if not already there) */
3607 static
insertColChgcols(SCIP_COL * col,SCIP_SET * set,SCIP_LP * lp)3608 SCIP_RETCODE insertColChgcols(
3609    SCIP_COL*             col,                /**< LP column to change */
3610    SCIP_SET*             set,                /**< global SCIP settings */
3611    SCIP_LP*              lp                  /**< current LP data */
3612    )
3613 {
3614    if( !col->objchanged && !col->lbchanged && !col->ubchanged )
3615    {
3616       SCIP_CALL( ensureChgcolsSize(lp, set, lp->nchgcols+1) );
3617       lp->chgcols[lp->nchgcols] = col;
3618       lp->nchgcols++;
3619    }
3620 
3621    /* mark the current LP unflushed */
3622    lp->flushed = FALSE;
3623 
3624    return SCIP_OKAY;
3625 }
3626 
3627 /** Is the new value reliable or may we have cancellation?
3628  *
3629  *  @note: Here we only consider cancellations which can occur during decreasing the oldvalue to newvalue; not the
3630  *  cancellations which can occur during increasing the oldvalue to the newvalue
3631  */
3632 static
isNewValueUnreliable(SCIP_SET * set,SCIP_Real newvalue,SCIP_Real oldvalue)3633 SCIP_Bool isNewValueUnreliable(
3634    SCIP_SET*             set,                /**< global SCIP settings */
3635    SCIP_Real             newvalue,           /**< new value */
3636    SCIP_Real             oldvalue            /**< old reliable value */
3637    )
3638 {
3639    SCIP_Real quotient;
3640 
3641    assert(set != NULL);
3642    assert(oldvalue < SCIP_INVALID);
3643 
3644    quotient = (REALABS(newvalue)+1.0) / (REALABS(oldvalue) + 1.0);
3645 
3646    return SCIPsetIsZero(set, quotient);
3647 }
3648 
3649 /** update norms of objective function vector */
3650 static
lpUpdateObjNorms(SCIP_LP * lp,SCIP_SET * set,SCIP_Real oldobj,SCIP_Real newobj)3651 void lpUpdateObjNorms(
3652    SCIP_LP*              lp,                 /**< current LP data */
3653    SCIP_SET*             set,                /**< global SCIP settings */
3654    SCIP_Real             oldobj,             /**< old objective value of variable */
3655    SCIP_Real             newobj              /**< new objective value of variable */
3656    )
3657 {
3658    if( REALABS(newobj) != REALABS(oldobj) )   /*lint !e777*/
3659    {
3660       if( !lp->objsqrnormunreliable )
3661       {
3662          SCIP_Real oldvalue;
3663 
3664          oldvalue = lp->objsqrnorm;
3665          lp->objsqrnorm += SQR(newobj) - SQR(oldobj);
3666 
3667          /* due to numerical cancellations, we recalculate lp->objsqrnorm using all variables */
3668          if( SCIPsetIsLT(set, lp->objsqrnorm, 0.0) || isNewValueUnreliable(set, lp->objsqrnorm, oldvalue) )
3669             lp->objsqrnormunreliable = TRUE;
3670          else
3671          {
3672             assert(SCIPsetIsGE(set, lp->objsqrnorm, 0.0));
3673 
3674             /* due to numerical troubles it still can appear that lp->objsqrnorm is a little bit smaller than 0 */
3675             lp->objsqrnorm = MAX(lp->objsqrnorm, 0.0);
3676 
3677             assert(lp->objsqrnorm >= 0.0);
3678          }
3679       }
3680 
3681       lp->objsumnorm += REALABS(newobj) - REALABS(oldobj);
3682       lp->objsumnorm = MAX(lp->objsumnorm, 0.0);
3683    }
3684 }
3685 
3686 /** changes objective value of column */
SCIPcolChgObj(SCIP_COL * col,SCIP_SET * set,SCIP_LP * lp,SCIP_Real newobj)3687 SCIP_RETCODE SCIPcolChgObj(
3688    SCIP_COL*             col,                /**< LP column to change */
3689    SCIP_SET*             set,                /**< global SCIP settings */
3690    SCIP_LP*              lp,                 /**< current LP data */
3691    SCIP_Real             newobj              /**< new objective value */
3692    )
3693 {
3694    assert(col != NULL);
3695    assert(col->var != NULL);
3696    assert(SCIPvarGetStatus(col->var) == SCIP_VARSTATUS_COLUMN);
3697    assert(SCIPvarGetCol(col->var) == col);
3698    assert(lp != NULL);
3699 
3700    SCIPsetDebugMsg(set, "changing objective value of column <%s> from %f to %f\n", SCIPvarGetName(col->var), col->obj, newobj);
3701 
3702    /* only add actual changes */
3703    if( !SCIPsetIsEQ(set, col->obj, newobj) )
3704    {
3705       /* only variables with a real position in the LPI can be inserted */
3706       if( col->lpipos >= 0 )
3707       {
3708          /* insert column in the chgcols list (if not already there) */
3709          SCIP_CALL( insertColChgcols(col, set, lp) );
3710 
3711          /* mark objective value change in the column */
3712          col->objchanged = TRUE;
3713 
3714          assert(lp->nchgcols > 0);
3715       }
3716       /* in any case, when the sign of the objective (and thereby the best bound) changes, the variable has to enter the
3717        * LP and the LP has to be flushed
3718        */
3719       else if( (col->obj < 0.0 && newobj >= 0.0 && SCIPsetIsZero(set, col->ub))
3720          || (col->obj >= 0.0 && newobj < 0.0 && SCIPsetIsZero(set, col->lb)) )
3721       {
3722          /* mark the LP unflushed */
3723          lp->flushed = FALSE;
3724       }
3725    }
3726 
3727    /* store new objective function value */
3728    col->obj = newobj;
3729 
3730    /* update original objective value, as long as we are not in diving or probing and changed objective values */
3731    if( !lp->divingobjchg )
3732    {
3733       SCIP_Real oldobj = col->unchangedobj;
3734 
3735       assert(SCIPsetIsEQ(set, newobj, SCIPvarGetUnchangedObj(col->var)));
3736       col->unchangedobj = newobj;
3737 
3738       /* update the objective function vector norms */
3739       lpUpdateObjNorms(lp, set, oldobj, newobj);
3740    }
3741 
3742    return SCIP_OKAY;
3743 }
3744 
3745 /** changes lower bound of column */
SCIPcolChgLb(SCIP_COL * col,SCIP_SET * set,SCIP_LP * lp,SCIP_Real newlb)3746 SCIP_RETCODE SCIPcolChgLb(
3747    SCIP_COL*             col,                /**< LP column to change */
3748    SCIP_SET*             set,                /**< global SCIP settings */
3749    SCIP_LP*              lp,                 /**< current LP data */
3750    SCIP_Real             newlb               /**< new lower bound value */
3751    )
3752 {
3753    assert(col != NULL);
3754    assert(col->var != NULL);
3755    assert(SCIPvarGetStatus(col->var) == SCIP_VARSTATUS_COLUMN);
3756    assert(SCIPvarGetCol(col->var) == col);
3757    assert(lp != NULL);
3758 
3759    SCIPsetDebugMsg(set, "changing lower bound of column <%s> from %f to %f\n", SCIPvarGetName(col->var), col->lb, newlb);
3760 
3761    /* only add actual changes */
3762    if( !SCIPsetIsEQ(set, col->lb, newlb) )
3763    {
3764       /* only variables with a real position in the LPI can be inserted */
3765       if( col->lpipos >= 0 )
3766       {
3767          /* insert column in the chgcols list (if not already there) */
3768          SCIP_CALL( insertColChgcols(col, set, lp) );
3769 
3770          /* mark bound change in the column */
3771          col->lbchanged = TRUE;
3772 
3773          assert(lp->nchgcols > 0);
3774       }
3775       /* in any case, when the best bound is zero and gets changed, the variable has to enter the LP and the LP has to be
3776        * flushed
3777        */
3778       else if( col->obj >= 0.0 && SCIPsetIsZero(set, col->lb) )
3779       {
3780          /* mark the LP unflushed */
3781          lp->flushed = FALSE;
3782       }
3783    }
3784 
3785    col->lb = newlb;
3786 
3787    return SCIP_OKAY;
3788 }
3789 
3790 /** changes upper bound of column */
SCIPcolChgUb(SCIP_COL * col,SCIP_SET * set,SCIP_LP * lp,SCIP_Real newub)3791 SCIP_RETCODE SCIPcolChgUb(
3792    SCIP_COL*             col,                /**< LP column to change */
3793    SCIP_SET*             set,                /**< global SCIP settings */
3794    SCIP_LP*              lp,                 /**< current LP data */
3795    SCIP_Real             newub               /**< new upper bound value */
3796    )
3797 {
3798    assert(col != NULL);
3799    assert(col->var != NULL);
3800    assert(SCIPvarGetStatus(col->var) == SCIP_VARSTATUS_COLUMN);
3801    assert(SCIPvarGetCol(col->var) == col);
3802    assert(lp != NULL);
3803 
3804    SCIPsetDebugMsg(set, "changing upper bound of column <%s> from %f to %f\n", SCIPvarGetName(col->var), col->ub, newub);
3805 
3806    /* only add actual changes */
3807    if( !SCIPsetIsEQ(set, col->ub, newub) )
3808    {
3809       /* only variables with a real position in the LPI can be inserted */
3810       if( col->lpipos >= 0 )
3811       {
3812          /* insert column in the chgcols list (if not already there) */
3813          SCIP_CALL( insertColChgcols(col, set, lp) );
3814 
3815          /* mark bound change in the column */
3816          col->ubchanged = TRUE;
3817 
3818          assert(lp->nchgcols > 0);
3819       }
3820       /* in any case, when the best bound is zero and gets changed, the variable has to enter the LP and the LP has to be
3821        * flushed
3822        */
3823       else if( col->obj < 0.0 && SCIPsetIsZero(set, col->ub) )
3824       {
3825          /* mark the LP unflushed */
3826          lp->flushed = FALSE;
3827       }
3828    }
3829 
3830    col->ub = newub;
3831 
3832    return SCIP_OKAY;
3833 }
3834 
3835 /** calculates the reduced costs of a column using the given dual solution vector */
SCIPcolCalcRedcost(SCIP_COL * col,SCIP_Real * dualsol)3836 SCIP_Real SCIPcolCalcRedcost(
3837    SCIP_COL*             col,                /**< LP column */
3838    SCIP_Real*            dualsol             /**< dual solution vector for current LP rows */
3839    )
3840 {
3841    SCIP_ROW* row;
3842    SCIP_Real redcost;
3843    int i;
3844 
3845    assert(col != NULL);
3846    assert(SCIPvarGetStatus(col->var) == SCIP_VARSTATUS_COLUMN);
3847    assert(SCIPvarGetCol(col->var) == col);
3848    assert(dualsol != NULL);
3849 
3850    redcost = col->obj;
3851    for( i = 0; i < col->nlprows; ++i )
3852    {
3853       row = col->rows[i];
3854       assert(row != NULL);
3855       assert(row->lppos >= 0);
3856       redcost -= col->vals[i] * dualsol[row->lppos];
3857    }
3858 
3859    if( col->nunlinked > 0 )
3860    {
3861       for( i = col->nlprows; i < col->len; ++i )
3862       {
3863          row = col->rows[i];
3864          assert(row != NULL);
3865          assert(row->lppos == -1 || col->linkpos[i] == -1);
3866          if( row->lppos >= 0 )
3867             redcost -= col->vals[i] * dualsol[row->lppos];
3868       }
3869    }
3870 #ifndef NDEBUG
3871    else
3872    {
3873       for( i = col->nlprows; i < col->len; ++i )
3874       {
3875          row = col->rows[i];
3876          assert(row != NULL);
3877          assert(row->lppos == -1);
3878          assert(col->linkpos[i] >= 0);
3879       }
3880    }
3881 #endif
3882 
3883    return redcost;
3884 }
3885 
3886 /** calculates the reduced costs of a column using the dual solution stored in the rows */
3887 static
colCalcInternalRedcost(SCIP_COL * col)3888 SCIP_Real colCalcInternalRedcost(
3889    SCIP_COL*             col                 /**< LP column */
3890    )
3891 {
3892    SCIP_ROW* row;
3893    SCIP_Real redcost;
3894    int i;
3895 
3896    assert(col != NULL);
3897    assert(SCIPvarGetStatus(col->var) == SCIP_VARSTATUS_COLUMN);
3898    assert(SCIPvarGetCol(col->var) == col);
3899 
3900    redcost = col->obj;
3901    for( i = 0; i < col->nlprows; ++i )
3902    {
3903       row = col->rows[i];
3904       assert(row != NULL);
3905       assert(row->dualsol < SCIP_INVALID);
3906       assert(row->lppos >= 0);
3907       assert(col->linkpos[i] >= 0);
3908       redcost -= col->vals[i] * row->dualsol;
3909    }
3910 
3911    if( col->nunlinked > 0 )
3912    {
3913       for( i = col->nlprows; i < col->len; ++i )
3914       {
3915          row = col->rows[i];
3916          assert(row != NULL);
3917          assert(row->lppos >= 0 || row->dualsol == 0.0);
3918          assert(row->lppos == -1 || col->linkpos[i] == -1);
3919          if( row->lppos >= 0 )
3920             redcost -= col->vals[i] * row->dualsol;
3921       }
3922    }
3923 #ifndef NDEBUG
3924    else
3925    {
3926       for( i = col->nlprows; i < col->len; ++i )
3927       {
3928          row = col->rows[i];
3929          assert(row != NULL);
3930          assert(row->dualsol == 0.0);
3931          assert(row->lppos == -1);
3932          assert(col->linkpos[i] >= 0);
3933       }
3934    }
3935 #endif
3936 
3937    return redcost;
3938 }
3939 
3940 /** gets the reduced costs of a column in last LP or after recalculation */
SCIPcolGetRedcost(SCIP_COL * col,SCIP_STAT * stat,SCIP_LP * lp)3941 SCIP_Real SCIPcolGetRedcost(
3942    SCIP_COL*             col,                /**< LP column */
3943    SCIP_STAT*            stat,               /**< problem statistics */
3944    SCIP_LP*              lp                  /**< current LP data */
3945    )
3946 {
3947    assert(col != NULL);
3948    assert(stat != NULL);
3949    assert(lp != NULL);
3950    assert(col->validredcostlp <= stat->lpcount);
3951    assert(lp->validsollp == stat->lpcount);
3952 
3953    if( col->validredcostlp < stat->lpcount )
3954    {
3955       col->redcost = colCalcInternalRedcost(col);
3956       col->validredcostlp = stat->lpcount;
3957    }
3958    assert(col->validredcostlp == stat->lpcount);
3959    assert(col->redcost < SCIP_INVALID);
3960 
3961    return col->redcost;
3962 }
3963 
3964 /** gets the feasibility of (the dual row of) a column in last LP or after recalculation */
SCIPcolGetFeasibility(SCIP_COL * col,SCIP_SET * set,SCIP_STAT * stat,SCIP_LP * lp)3965 SCIP_Real SCIPcolGetFeasibility(
3966    SCIP_COL*             col,                /**< LP column */
3967    SCIP_SET*             set,                /**< global SCIP settings */
3968    SCIP_STAT*            stat,               /**< problem statistics */
3969    SCIP_LP*              lp                  /**< current LP data */
3970    )
3971 {
3972    assert(col != NULL);
3973    assert(set != NULL);
3974    assert(stat != NULL);
3975    assert(lp != NULL);
3976    assert(lp->validsollp == stat->lpcount);
3977 
3978    /* A column's reduced cost is defined as
3979     *   redcost  = obj - activity,  activity = y^T * col.   (activity = obj - redcost)
3980     * The activity is equal to the activity of the corresponding row in the dual LP.
3981     * The column's feasibility is the feasibility of the corresponding row in the dual LP.
3982     * The sides of the dual row depend on the bounds of the column:
3983     *  - lb == ub      :  dual row is a free row with infinite sides
3984     *  -  0 <= lb <  ub:         activity <= obj  =>  0 <= redcost
3985     *  - lb <   0 <  ub:  obj <= activity <= obj  =>  0 <= redcost <= 0
3986     *  - lb <  ub <=  0:  obj <= activity         =>       redcost <= 0
3987     */
3988    if( SCIPsetIsEQ(set, col->lb, col->ub) )
3989    {
3990       /* dual row is free */
3991       return SCIPsetInfinity(set);
3992    }
3993    else
3994    {
3995       SCIP_Real redcost;
3996 
3997       /* calculate reduced costs */
3998       redcost = SCIPcolGetRedcost(col, stat, lp);
3999 
4000       if( !SCIPsetIsNegative(set, col->lb) )
4001       {
4002          /* dual row is  activity <= obj  <=>  redcost >= 0 */
4003          return redcost;
4004       }
4005       else if( SCIPsetIsPositive(set, col->ub) )
4006       {
4007          /* dual row is  activity == obj  <=>  redcost == 0 */
4008          return -REALABS(redcost);
4009       }
4010       else
4011       {
4012          /* dual row is  activity >= obj  <=>  redcost <= 0 */
4013          return -redcost;
4014       }
4015    }
4016 }
4017 
4018 /** calculates the Farkas coefficient y^T A_i of a column i using the given dual Farkas vector y */
SCIPcolCalcFarkasCoef(SCIP_COL * col,SCIP_Real * dualfarkas)4019 SCIP_Real SCIPcolCalcFarkasCoef(
4020    SCIP_COL*             col,                /**< LP column */
4021    SCIP_Real*            dualfarkas          /**< dense dual Farkas vector for current LP rows */
4022    )
4023 {
4024    SCIP_ROW* row;
4025    SCIP_Real farkas;
4026    int i;
4027 
4028    assert(col != NULL);
4029    assert(SCIPvarGetStatus(col->var) == SCIP_VARSTATUS_COLUMN);
4030    assert(SCIPvarGetCol(col->var) == col);
4031    assert(dualfarkas != NULL);
4032 
4033    farkas = 0.0;
4034    for( i = 0; i < col->nlprows; ++i )
4035    {
4036       row = col->rows[i];
4037       assert(row != NULL);
4038       assert(row->lppos >= 0);
4039       farkas += col->vals[i] * dualfarkas[row->lppos];
4040    }
4041 
4042    if( col->nunlinked > 0 )
4043    {
4044       for( i = col->nlprows; i < col->len; ++i )
4045       {
4046          row = col->rows[i];
4047          assert(row != NULL);
4048          assert(row->lppos == -1 || col->linkpos[i] == -1);
4049          if( row->lppos >= 0 )
4050             farkas += col->vals[i] * dualfarkas[row->lppos];
4051       }
4052    }
4053 #ifndef NDEBUG
4054    else
4055    {
4056       for( i = col->nlprows; i < col->len; ++i )
4057       {
4058          row = col->rows[i];
4059          assert(row != NULL);
4060          assert(row->lppos == -1);
4061          assert(col->linkpos[i] >= 0);
4062       }
4063    }
4064 #endif
4065 
4066    return farkas;
4067 }
4068 
4069 /** gets the Farkas coefficient y^T A_i of a column i in last LP (which must be infeasible) */
4070 static
colCalcInternalFarkasCoef(SCIP_COL * col)4071 SCIP_Real colCalcInternalFarkasCoef(
4072    SCIP_COL*             col                 /**< LP column */
4073    )
4074 {
4075    SCIP_ROW* row;
4076    SCIP_Real farkas;
4077    int i;
4078 
4079    assert(col != NULL);
4080    assert(SCIPvarGetStatus(col->var) == SCIP_VARSTATUS_COLUMN);
4081    assert(SCIPvarGetCol(col->var) == col);
4082 
4083    farkas = 0.0;
4084    for( i = 0; i < col->nlprows; ++i )
4085    {
4086       row = col->rows[i];
4087       assert(row != NULL);
4088       assert(row->dualfarkas < SCIP_INVALID);
4089       assert(row->lppos >= 0);
4090       assert(col->linkpos[i] >= 0);
4091       farkas += col->vals[i] * row->dualfarkas;
4092    }
4093 
4094    if( col->nunlinked > 0 )
4095    {
4096       for( i = col->nlprows; i < col->len; ++i )
4097       {
4098          row = col->rows[i];
4099          assert(row != NULL);
4100          assert(row->lppos >= 0 || row->dualfarkas == 0.0);
4101          assert(row->lppos == -1 || col->linkpos[i] == -1);
4102          if( row->lppos >= 0 )
4103             farkas += col->vals[i] * row->dualfarkas;
4104       }
4105    }
4106 #ifndef NDEBUG
4107    else
4108    {
4109       for( i = col->nlprows; i < col->len; ++i )
4110       {
4111          row = col->rows[i];
4112          assert(row != NULL);
4113          assert(row->dualfarkas == 0.0);
4114          assert(row->lppos == -1);
4115          assert(col->linkpos[i] >= 0);
4116       }
4117    }
4118 #endif
4119 
4120    return farkas;
4121 }
4122 
4123 /** gets the Farkas coefficient of a column in last LP (which must be infeasible) */
SCIPcolGetFarkasCoef(SCIP_COL * col,SCIP_STAT * stat,SCIP_LP * lp)4124 SCIP_Real SCIPcolGetFarkasCoef(
4125    SCIP_COL*             col,                /**< LP column */
4126    SCIP_STAT*            stat,               /**< problem statistics */
4127    SCIP_LP*              lp                  /**< current LP data */
4128    )
4129 {
4130    assert(col != NULL);
4131    assert(stat != NULL);
4132    assert(lp != NULL);
4133    assert(col->validfarkaslp <= stat->lpcount);
4134    assert(lp->validfarkaslp == stat->lpcount);
4135 
4136    if( col->validfarkaslp < stat->lpcount )
4137    {
4138       col->farkascoef = colCalcInternalFarkasCoef(col);
4139       col->validfarkaslp = stat->lpcount;
4140    }
4141    assert(col->validfarkaslp == stat->lpcount);
4142    assert(col->farkascoef < SCIP_INVALID);
4143 
4144    return col->farkascoef;
4145 }
4146 
4147 /** gets the Farkas value of a column in last LP (which must be infeasible), i.e. the Farkas coefficient y^T A_i times
4148  *  the best bound for this coefficient, i.e. max{y^T A_i x_i | lb <= x_i <= ub}
4149  */
SCIPcolGetFarkasValue(SCIP_COL * col,SCIP_STAT * stat,SCIP_LP * lp)4150 SCIP_Real SCIPcolGetFarkasValue(
4151    SCIP_COL*             col,                /**< LP column */
4152    SCIP_STAT*            stat,               /**< problem statistics */
4153    SCIP_LP*              lp                  /**< current LP data */
4154    )
4155 {
4156    SCIP_Real farkascoef;
4157 
4158    assert(col != NULL);
4159 
4160    farkascoef = SCIPcolGetFarkasCoef(col, stat, lp);
4161 
4162    if( farkascoef > 0.0 )
4163       return col->ub * farkascoef;
4164    else
4165       return col->lb * farkascoef;
4166 }
4167 
4168 /** start strong branching - call before any strong branching */
SCIPlpStartStrongbranch(SCIP_LP * lp)4169 SCIP_RETCODE SCIPlpStartStrongbranch(
4170    SCIP_LP*              lp                  /**< LP data */
4171    )
4172 {
4173    assert(lp != NULL);
4174    assert(!lp->strongbranching);
4175 
4176    lp->strongbranching = TRUE;
4177    SCIPdebugMessage("starting strong branching ...\n");
4178    SCIP_CALL( SCIPlpiStartStrongbranch(lp->lpi) );
4179 
4180    return SCIP_OKAY;
4181 }
4182 
4183 /** end strong branching - call after any strong branching */
SCIPlpEndStrongbranch(SCIP_LP * lp)4184 SCIP_RETCODE SCIPlpEndStrongbranch(
4185    SCIP_LP*              lp                  /**< LP data */
4186    )
4187 {
4188    assert(lp != NULL);
4189    assert(lp->strongbranching);
4190 
4191    lp->strongbranching = FALSE;
4192    SCIPdebugMessage("ending strong branching ...\n");
4193    SCIP_CALL( SCIPlpiEndStrongbranch(lp->lpi) );
4194 
4195    return SCIP_OKAY;
4196 }
4197 
4198 /** sets strong branching information for a column variable */
SCIPcolSetStrongbranchData(SCIP_COL * col,SCIP_SET * set,SCIP_STAT * stat,SCIP_LP * lp,SCIP_Real lpobjval,SCIP_Real primsol,SCIP_Real sbdown,SCIP_Real sbup,SCIP_Bool sbdownvalid,SCIP_Bool sbupvalid,SCIP_Longint iter,int itlim)4199 void SCIPcolSetStrongbranchData(
4200    SCIP_COL*             col,                /**< LP column */
4201    SCIP_SET*             set,                /**< global SCIP settings */
4202    SCIP_STAT*            stat,               /**< dynamic problem statistics */
4203    SCIP_LP*              lp,                 /**< LP data */
4204    SCIP_Real             lpobjval,           /**< objective value of the current LP */
4205    SCIP_Real             primsol,            /**< primal solution value of the column in the current LP */
4206    SCIP_Real             sbdown,             /**< dual bound after branching column down */
4207    SCIP_Real             sbup,               /**< dual bound after branching column up */
4208    SCIP_Bool             sbdownvalid,        /**< is the returned down value a valid dual bound? */
4209    SCIP_Bool             sbupvalid,          /**< is the returned up value a valid dual bound? */
4210    SCIP_Longint          iter,               /**< total number of strong branching iterations */
4211    int                   itlim               /**< iteration limit applied to the strong branching call */
4212    )
4213 {
4214    assert(col != NULL);
4215    assert(col->var != NULL);
4216    assert(SCIPcolIsIntegral(col));
4217    assert(SCIPvarIsIntegral(col->var));
4218    assert(SCIPvarGetStatus(col->var) == SCIP_VARSTATUS_COLUMN);
4219    assert(SCIPvarGetCol(col->var) == col);
4220    assert(col->lpipos >= 0);
4221    assert(col->lppos >= 0);
4222    assert(set != NULL);
4223    assert(stat != NULL);
4224    assert(lp != NULL);
4225    assert(lp->strongbranchprobing);
4226    assert(col->lppos < lp->ncols);
4227    assert(lp->cols[col->lppos] == col);
4228    assert(itlim >= 1);
4229 
4230    col->sblpobjval = lpobjval;
4231    col->sbsolval = primsol;
4232    col->validsblp = stat->nlps;
4233    col->sbnode = stat->nnodes;
4234 
4235    col->sbitlim = itlim;
4236    col->nsbcalls++;
4237 
4238    col->sbdown = MIN(sbdown, lp->cutoffbound);
4239    col->sbup = MIN(sbup, lp->cutoffbound);
4240    col->sbdownvalid = sbdownvalid;
4241    col->sbupvalid = sbupvalid;
4242 
4243    SCIPstatIncrement(stat, set, nstrongbranchs);
4244    SCIPstatAdd(stat, set, nsblpiterations, iter);
4245    if( stat->nnodes == 1 )
4246    {
4247       SCIPstatIncrement(stat, set, nrootstrongbranchs);
4248       SCIPstatAdd(stat, set, nrootsblpiterations, iter);
4249    }
4250 }
4251 
4252 /** invalidates strong branching information for a column variable */
SCIPcolInvalidateStrongbranchData(SCIP_COL * col,SCIP_SET * set,SCIP_STAT * stat,SCIP_LP * lp)4253 void SCIPcolInvalidateStrongbranchData(
4254    SCIP_COL*             col,                /**< LP column */
4255    SCIP_SET*             set,                /**< global SCIP settings */
4256    SCIP_STAT*            stat,               /**< dynamic problem statistics */
4257    SCIP_LP*              lp                  /**< LP data */
4258    )
4259 {
4260    assert(col != NULL);
4261    assert(col->var != NULL);
4262    assert(SCIPcolIsIntegral(col));
4263    assert(SCIPvarIsIntegral(col->var));
4264    assert(SCIPvarGetStatus(col->var) == SCIP_VARSTATUS_COLUMN);
4265    assert(SCIPvarGetCol(col->var) == col);
4266    assert(col->lpipos >= 0);
4267    assert(col->lppos >= 0);
4268    assert(set != NULL);
4269    assert(stat != NULL);
4270    assert(lp != NULL);
4271    assert(lp->strongbranchprobing);
4272    assert(col->lppos < lp->ncols);
4273    assert(lp->cols[col->lppos] == col);
4274 
4275    col->sbdown = SCIP_INVALID;
4276    col->sbup = SCIP_INVALID;
4277    col->sbdownvalid = FALSE;
4278    col->sbupvalid = FALSE;
4279    col->validsblp = -1;
4280    col->sbsolval = SCIP_INVALID;
4281    col->sblpobjval = SCIP_INVALID;
4282    col->sbnode = -1;
4283    col->sbitlim = -1;
4284 }
4285 
4286 
4287 /** gets strong branching information on a column variable */
SCIPcolGetStrongbranch(SCIP_COL * col,SCIP_Bool integral,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * prob,SCIP_LP * lp,int itlim,SCIP_Bool updatecol,SCIP_Bool updatestat,SCIP_Real * down,SCIP_Real * up,SCIP_Bool * downvalid,SCIP_Bool * upvalid,SCIP_Bool * lperror)4288 SCIP_RETCODE SCIPcolGetStrongbranch(
4289    SCIP_COL*             col,                /**< LP column */
4290    SCIP_Bool             integral,           /**< should integral strong branching be performed? */
4291    SCIP_SET*             set,                /**< global SCIP settings */
4292    SCIP_STAT*            stat,               /**< dynamic problem statistics */
4293    SCIP_PROB*            prob,               /**< problem data */
4294    SCIP_LP*              lp,                 /**< LP data */
4295    int                   itlim,              /**< iteration limit for strong branchings */
4296    SCIP_Bool             updatecol,          /**< should col be updated, or should it stay in its current state ? */
4297    SCIP_Bool             updatestat,         /**< should stat be updated, or should it stay in its current state ? */
4298    SCIP_Real*            down,               /**< stores dual bound after branching column down */
4299    SCIP_Real*            up,                 /**< stores dual bound after branching column up */
4300    SCIP_Bool*            downvalid,          /**< stores whether the returned down value is a valid dual bound, or NULL;
4301                                               *   otherwise, it can only be used as an estimate value */
4302    SCIP_Bool*            upvalid,            /**< stores whether the returned up value is a valid dual bound, or NULL;
4303                                               *   otherwise, it can only be used as an estimate value */
4304    SCIP_Bool*            lperror             /**< pointer to store whether an unresolved LP error occurred */
4305    )
4306 {
4307    SCIP_Real sbdown;
4308    SCIP_Real sbup;
4309    SCIP_Bool sbdownvalid;
4310    SCIP_Bool sbupvalid;
4311    SCIP_Longint validsblp;
4312    SCIP_Real sbsolval;
4313    SCIP_Real sblpobjval;
4314    SCIP_Longint sbnode;
4315    int sbitlim;
4316    int nsbcalls;
4317 
4318    assert(col != NULL);
4319    assert(col->var != NULL);
4320    assert(SCIPcolIsIntegral(col));
4321    assert(SCIPvarIsIntegral(col->var));
4322    assert(SCIPvarGetStatus(col->var) == SCIP_VARSTATUS_COLUMN);
4323    assert(SCIPvarGetCol(col->var) == col);
4324    assert(col->primsol < SCIP_INVALID);
4325    assert(col->lpipos >= 0);
4326    assert(col->lppos >= 0);
4327    assert(set != NULL);
4328    assert(stat != NULL);
4329    assert(lp != NULL);
4330    assert(lp->flushed);
4331    assert(lp->solved);
4332    assert(lp->strongbranching);
4333    assert(lp->lpsolstat == SCIP_LPSOLSTAT_OPTIMAL);
4334    assert(lp->validsollp == stat->lpcount);
4335    assert(col->lppos < lp->ncols);
4336    assert(lp->cols[col->lppos] == col);
4337    assert(itlim >= 1);
4338    /*   assert(down != NULL);
4339     *  assert(up != NULL); temporary hack for cloud branching
4340     */
4341    assert(lperror != NULL);
4342 
4343    *lperror = FALSE;
4344 
4345    sbdown = col->sbdown;
4346    sbup = col->sbup;
4347    sbdownvalid = col->sbdownvalid;
4348    sbupvalid = col->sbupvalid;
4349    sbitlim = col->sbitlim;
4350    nsbcalls = col->nsbcalls;
4351 
4352    validsblp = stat->nlps;
4353    sbsolval = col->primsol;
4354    sblpobjval = SCIPlpGetObjval(lp, set, prob);
4355    sbnode = stat->nnodes;
4356    assert(integral || !SCIPsetIsFeasIntegral(set, col->primsol));
4357 
4358    /* if a loose variables has an infinite best bound, the LP bound is -infinity and no gain can be achieved */
4359    if( lp->looseobjvalinf > 0 )
4360    {
4361       sbdown = -SCIPsetInfinity(set);
4362       sbup = -SCIPsetInfinity(set);
4363       sbdownvalid = FALSE;
4364       sbupvalid = FALSE;
4365    }
4366    else
4367    {
4368       SCIP_RETCODE retcode;
4369       int iter;
4370 
4371       SCIPsetDebugMsg(set, "performing strong branching on variable <%s>(%g) with %d iterations\n",
4372          SCIPvarGetName(col->var), col->primsol, itlim);
4373 
4374       /* start timing */
4375       SCIPclockStart(stat->strongbranchtime, set);
4376 
4377       /* call LPI strong branching */
4378       sbitlim = itlim;
4379       nsbcalls++;
4380 
4381       sbdown = lp->lpobjval;
4382       sbup = lp->lpobjval;
4383 
4384       if( integral )
4385          retcode = SCIPlpiStrongbranchInt(lp->lpi, col->lpipos, col->primsol, itlim, down  == NULL ? NULL : &sbdown, up  == NULL ? NULL : &sbup, &sbdownvalid, &sbupvalid, &iter);
4386       else
4387       {
4388          assert( ! SCIPsetIsIntegral(set, col->primsol) );
4389          retcode = SCIPlpiStrongbranchFrac(lp->lpi, col->lpipos, col->primsol, itlim, down == NULL ? NULL : &sbdown, up == NULL ? NULL :  &sbup, &sbdownvalid, &sbupvalid, &iter);
4390       }
4391 
4392       /* check return code for errors */
4393       if( retcode == SCIP_LPERROR )
4394       {
4395          *lperror = TRUE;
4396          sbdown = SCIP_INVALID;
4397          sbup = SCIP_INVALID;
4398          sbdownvalid = FALSE;
4399          sbupvalid = FALSE;
4400          validsblp = -1;
4401          sbsolval = SCIP_INVALID;
4402          sblpobjval = SCIP_INVALID;
4403          sbnode = -1;
4404       }
4405       else
4406       {
4407          SCIP_Real looseobjval;
4408 
4409          *lperror = FALSE;
4410          SCIP_CALL( retcode );
4411 
4412          looseobjval = getFiniteLooseObjval(lp, set, prob);
4413          sbdown = MIN(sbdown + looseobjval, lp->cutoffbound);
4414          sbup = MIN(sbup + looseobjval, lp->cutoffbound);
4415 
4416          /* update strong branching statistics */
4417          if( updatestat )
4418          {
4419             if( iter == -1 )
4420             {
4421                /* calculate average iteration number */
4422                iter = stat->ndualresolvelps > 0 ? (int)(2*stat->ndualresolvelpiterations / stat->ndualresolvelps)
4423                   : stat->nduallps > 0 ? (int)((stat->nduallpiterations / stat->nduallps) / 5)
4424                   : stat->nprimalresolvelps > 0 ? (int)(2*stat->nprimalresolvelpiterations / stat->nprimalresolvelps)
4425                   : stat->nprimallps > 0 ? (int)((stat->nprimallpiterations / stat->nprimallps) / 5)
4426                   : 0;
4427                if( iter/2 >= itlim )
4428                   iter = 2*itlim;
4429             }
4430             SCIPstatIncrement(stat, set, nstrongbranchs);
4431             SCIPstatAdd(stat, set, nsblpiterations, iter);
4432             if( stat->nnodes == 1 )
4433             {
4434                SCIPstatIncrement(stat, set, nrootstrongbranchs);
4435                SCIPstatAdd(stat, set, nrootsblpiterations, iter);
4436             }
4437          }
4438       }
4439 
4440       /* stop timing */
4441       SCIPclockStop(stat->strongbranchtime, set);
4442    }
4443    assert(*lperror || sbdown < SCIP_INVALID);
4444    assert(*lperror || sbup < SCIP_INVALID);
4445 
4446    if( down != NULL)
4447       *down = sbdown;
4448    if( up != NULL )
4449       *up = sbup;
4450    if( downvalid != NULL )
4451       *downvalid = sbdownvalid;
4452    if( upvalid != NULL )
4453       *upvalid = sbupvalid;
4454 
4455    if( updatecol )
4456    {
4457       col->sbdown = sbdown;
4458       col->sbup = sbup;
4459       col->sbdownvalid = sbdownvalid;
4460       col->sbupvalid = sbupvalid;
4461       col->validsblp = validsblp;
4462       col->sbsolval = sbsolval;
4463       col->sblpobjval = sblpobjval;
4464       col->sbnode = sbnode;
4465       col->sbitlim = sbitlim;
4466       col->nsbcalls = nsbcalls;
4467    }
4468 
4469    return SCIP_OKAY;
4470 }
4471 
4472 /** gets strong branching information on column variables */
SCIPcolGetStrongbranches(SCIP_COL ** cols,int ncols,SCIP_Bool integral,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * prob,SCIP_LP * lp,int itlim,SCIP_Real * down,SCIP_Real * up,SCIP_Bool * downvalid,SCIP_Bool * upvalid,SCIP_Bool * lperror)4473 SCIP_RETCODE SCIPcolGetStrongbranches(
4474    SCIP_COL**            cols,               /**< LP columns */
4475    int                   ncols,              /**< number of columns */
4476    SCIP_Bool             integral,           /**< should integral strong branching be performed? */
4477    SCIP_SET*             set,                /**< global SCIP settings */
4478    SCIP_STAT*            stat,               /**< dynamic problem statistics */
4479    SCIP_PROB*            prob,               /**< problem data */
4480    SCIP_LP*              lp,                 /**< LP data */
4481    int                   itlim,              /**< iteration limit for strong branchings */
4482    SCIP_Real*            down,               /**< stores dual bounds after branching columns down */
4483    SCIP_Real*            up,                 /**< stores dual bounds after branching columns up */
4484    SCIP_Bool*            downvalid,          /**< stores whether the returned down values are valid dual bounds, or NULL;
4485                                               *   otherwise, they can only be used as an estimate value */
4486    SCIP_Bool*            upvalid,            /**< stores whether the returned up values are valid dual bounds, or NULL;
4487                                               *   otherwise, they can only be used as an estimate value */
4488    SCIP_Bool*            lperror             /**< pointer to store whether an unresolved LP error occurred */
4489    )
4490 {
4491    SCIP_RETCODE retcode;
4492    SCIP_Real* sbdown;
4493    SCIP_Real* sbup;
4494    SCIP_Bool* sbdownvalid;
4495    SCIP_Bool* sbupvalid;
4496    SCIP_Real* primsols;
4497    SCIP_COL** subcols;
4498    int* lpipos;
4499    int* subidx;
4500    int nsubcols;
4501    int iter;
4502    int j;
4503 
4504    assert(cols != NULL);
4505    assert(set != NULL);
4506    assert(stat != NULL);
4507    assert(lp != NULL);
4508    assert(lp->flushed);
4509    assert(lp->solved);
4510    assert(lp->lpsolstat == SCIP_LPSOLSTAT_OPTIMAL);
4511    assert(lp->validsollp == stat->lpcount);
4512    assert(itlim >= 1);
4513    assert(down != NULL);
4514    assert(up != NULL);
4515    assert(lperror != NULL);
4516 
4517    *lperror = FALSE;
4518 
4519    if ( ncols <= 0 )
4520       return SCIP_OKAY;
4521 
4522    /* start timing */
4523    SCIPclockStart(stat->strongbranchtime, set);
4524 
4525    /* initialize storage */
4526    SCIP_CALL( SCIPsetAllocBufferArray(set, &subcols, ncols) );
4527    SCIP_CALL( SCIPsetAllocBufferArray(set, &subidx, ncols) );
4528    SCIP_CALL( SCIPsetAllocBufferArray(set, &lpipos, ncols) );
4529    SCIP_CALL( SCIPsetAllocBufferArray(set, &primsols, ncols) );
4530    SCIP_CALL( SCIPsetAllocBufferArray(set, &sbdown, ncols) );
4531    SCIP_CALL( SCIPsetAllocBufferArray(set, &sbup, ncols) );
4532    SCIP_CALL( SCIPsetAllocBufferArray(set, &sbdownvalid, ncols) );
4533    SCIP_CALL( SCIPsetAllocBufferArray(set, &sbupvalid, ncols) );
4534 
4535    nsubcols = 0;
4536    for( j = 0; j < ncols; ++j )
4537    {
4538       SCIP_COL* col;
4539       col = cols[j];
4540 
4541       assert(col->lppos < lp->ncols);
4542       assert(lp->cols[col->lppos] == col);
4543       assert(SCIPcolIsIntegral(col));
4544       assert(SCIPvarIsIntegral(col->var));
4545       assert(SCIPvarGetStatus(col->var) == SCIP_VARSTATUS_COLUMN);
4546       assert(SCIPvarGetCol(col->var) == col);
4547       assert(col->primsol < SCIP_INVALID);
4548       assert(col->lpipos >= 0);
4549       assert(col->lppos >= 0);
4550 
4551       col->validsblp = stat->nlps;
4552       col->sbsolval = col->primsol;
4553       col->sblpobjval = SCIPlpGetObjval(lp, set, prob);
4554       col->sbnode = stat->nnodes;
4555       assert(!SCIPsetIsFeasIntegral(set, col->primsol));
4556 
4557       /* if a loose variables has an infinite best bound, the LP bound is -infinity and no gain can be achieved */
4558       if( lp->looseobjvalinf > 0 )
4559       {
4560          /* directly set up column and result vectors*/
4561          col->sbdown = -SCIPsetInfinity(set);
4562          col->sbup = -SCIPsetInfinity(set);
4563          col->sbdownvalid = FALSE;
4564          col->sbupvalid = FALSE;
4565          down[j] = col->sbdown;
4566          up[j] = col->sbup;
4567          if( downvalid != NULL )
4568             downvalid[j] = col->sbdownvalid;
4569          if( upvalid != NULL )
4570             upvalid[j] = col->sbupvalid;
4571       }
4572       else
4573       {
4574          col->sbitlim = itlim;
4575          col->nsbcalls++;
4576 
4577          lpipos[nsubcols] = col->lpipos;
4578          primsols[nsubcols] = col->primsol;
4579          assert( integral || ! SCIPsetIsFeasIntegral(set, col->primsol) );
4580          subidx[nsubcols] = j;
4581          subcols[nsubcols++] = col;
4582       }
4583    }
4584 
4585    SCIPsetDebugMsg(set, "performing strong branching on %d variables with %d iterations\n", ncols, itlim);
4586 
4587    /* call LPI strong branching */
4588    if ( integral )
4589       retcode = SCIPlpiStrongbranchesInt(lp->lpi, lpipos, nsubcols, primsols, itlim, sbdown, sbup, sbdownvalid, sbupvalid, &iter);
4590    else
4591       retcode = SCIPlpiStrongbranchesFrac(lp->lpi, lpipos, nsubcols, primsols, itlim, sbdown, sbup, sbdownvalid, sbupvalid, &iter);
4592 
4593    /* check return code for errors */
4594    if( retcode == SCIP_LPERROR )
4595    {
4596       *lperror = TRUE;
4597 
4598       for( j = 0; j < nsubcols; ++j )
4599       {
4600          SCIP_COL* col;
4601          int idx;
4602 
4603          col = subcols[j];
4604          idx = subidx[j];
4605 
4606          col->sbdown = SCIP_INVALID;
4607          col->sbup = SCIP_INVALID;
4608          col->sbdownvalid = FALSE;
4609          col->sbupvalid = FALSE;
4610          col->validsblp = -1;
4611          col->sbsolval = SCIP_INVALID;
4612          col->sblpobjval = SCIP_INVALID;
4613          col->sbnode = -1;
4614 
4615          down[idx] = col->sbdown;
4616          up[idx] = col->sbup;
4617          if( downvalid != NULL )
4618             downvalid[idx] = col->sbdownvalid;
4619          if( upvalid != NULL )
4620             upvalid[idx] = col->sbupvalid;
4621       }
4622    }
4623    else
4624    {
4625       SCIP_Real looseobjval;
4626 
4627       *lperror = FALSE;
4628       SCIP_CALL( retcode );
4629 
4630       looseobjval = getFiniteLooseObjval(lp, set, prob);
4631 
4632       for( j = 0; j < nsubcols; ++j )
4633       {
4634          SCIP_COL* col;
4635          int idx;
4636 
4637          col = subcols[j];
4638          idx = subidx[j];
4639 
4640          assert( col->sbdown < SCIP_INVALID);
4641          assert( col->sbup < SCIP_INVALID);
4642 
4643          col->sbdown = MIN(sbdown[j] + looseobjval, lp->cutoffbound);
4644          col->sbup = MIN(sbup[j] + looseobjval, lp->cutoffbound);
4645          col->sbdownvalid = sbdownvalid[j];
4646          col->sbupvalid = sbupvalid[j];
4647 
4648          down[idx] = col->sbdown;
4649          up[idx] = col->sbup;
4650          if( downvalid != NULL )
4651             downvalid[idx] = col->sbdownvalid;
4652          if( upvalid != NULL )
4653             upvalid[idx] = col->sbupvalid;
4654       }
4655 
4656       /* update strong branching statistics */
4657       if( iter == -1 )
4658       {
4659          /* calculate average iteration number */
4660          iter = stat->ndualresolvelps > 0 ? (int)(2*stat->ndualresolvelpiterations / stat->ndualresolvelps)
4661             : stat->nduallps > 0 ? (int)((stat->nduallpiterations / stat->nduallps) / 5)
4662             : stat->nprimalresolvelps > 0 ? (int)(2*stat->nprimalresolvelpiterations / stat->nprimalresolvelps)
4663             : stat->nprimallps > 0 ? (int)((stat->nprimallpiterations / stat->nprimallps) / 5)
4664             : 0;
4665          if( iter/2 >= itlim )
4666             iter = 2*itlim;
4667       }
4668       SCIPstatAdd(stat, set, nstrongbranchs, ncols);
4669       SCIPstatAdd(stat, set, nsblpiterations, iter);
4670       if( stat->nnodes == 1 )
4671       {
4672          SCIPstatAdd(stat, set, nrootstrongbranchs, ncols);
4673          SCIPstatAdd(stat, set, nrootsblpiterations, iter);
4674       }
4675    }
4676 
4677    SCIPsetFreeBufferArray(set, &sbupvalid);
4678    SCIPsetFreeBufferArray(set, &sbdownvalid);
4679    SCIPsetFreeBufferArray(set, &sbup);
4680    SCIPsetFreeBufferArray(set, &sbdown);
4681    SCIPsetFreeBufferArray(set, &primsols);
4682    SCIPsetFreeBufferArray(set, &lpipos);
4683    SCIPsetFreeBufferArray(set, &subidx);
4684    SCIPsetFreeBufferArray(set, &subcols);
4685 
4686    /* stop timing */
4687    SCIPclockStop(stat->strongbranchtime, set);
4688 
4689    return SCIP_OKAY;
4690 }
4691 
4692 /** gets last strong branching information available for a column variable;
4693  *  returns values of SCIP_INVALID, if strong branching was not yet called on the given column;
4694  *  keep in mind, that the returned old values may have nothing to do with the current LP solution
4695  */
SCIPcolGetStrongbranchLast(SCIP_COL * col,SCIP_Real * down,SCIP_Real * up,SCIP_Bool * downvalid,SCIP_Bool * upvalid,SCIP_Real * solval,SCIP_Real * lpobjval)4696 void SCIPcolGetStrongbranchLast(
4697    SCIP_COL*             col,                /**< LP column */
4698    SCIP_Real*            down,               /**< stores dual bound after branching column down, or NULL */
4699    SCIP_Real*            up,                 /**< stores dual bound after branching column up, or NULL */
4700    SCIP_Bool*            downvalid,          /**< stores whether the returned down value is a valid dual bound, or NULL;
4701                                               *   otherwise, it can only be used as an estimate value */
4702    SCIP_Bool*            upvalid,            /**< stores whether the returned up value is a valid dual bound, or NULL;
4703                                               *   otherwise, it can only be used as an estimate value */
4704    SCIP_Real*            solval,             /**< stores LP solution value of column at last strong branching call, or NULL */
4705    SCIP_Real*            lpobjval            /**< stores LP objective value at last strong branching call, or NULL */
4706    )
4707 {
4708    assert(col != NULL);
4709 
4710    if( down != NULL )
4711       *down = col->sbdown;
4712    if( up != NULL )
4713       *up = col->sbup;
4714    if( downvalid != NULL )
4715       *downvalid = col->sbdownvalid;
4716    if( upvalid != NULL )
4717       *upvalid = col->sbupvalid;
4718    if( solval != NULL )
4719       *solval = col->sbsolval;
4720    if( lpobjval != NULL )
4721       *lpobjval = col->sblpobjval;
4722 }
4723 
4724 /** if strong branching was already applied on the column at the current node, returns the number of LPs solved after
4725  *  the LP where the strong branching on this column was applied;
4726  *  if strong branching was not yet applied on the column at the current node, returns INT_MAX
4727  */
SCIPcolGetStrongbranchLPAge(SCIP_COL * col,SCIP_STAT * stat)4728 SCIP_Longint SCIPcolGetStrongbranchLPAge(
4729    SCIP_COL*             col,                /**< LP column */
4730    SCIP_STAT*            stat                /**< dynamic problem statistics */
4731    )
4732 {
4733    assert(col != NULL);
4734    assert(stat != NULL);
4735 
4736    return (col->sbnode != stat->nnodes ? SCIP_LONGINT_MAX : stat->nlps - col->validsblp);
4737 }
4738 
4739 /** marks a column to be not removable from the LP in the current node because it became obsolete */
SCIPcolMarkNotRemovableLocal(SCIP_COL * col,SCIP_STAT * stat)4740 void SCIPcolMarkNotRemovableLocal(
4741    SCIP_COL*             col,                /**< LP column */
4742    SCIP_STAT*            stat                /**< problem statistics */
4743    )
4744 {
4745    assert(col  != NULL);
4746    assert(stat != NULL);
4747    assert(stat->nnodes > 0);
4748 
4749    /* lpRemoveObsoleteCols() does not remove a column if the node number stored in obsoletenode equals the current node number */
4750    col->obsoletenode = stat->nnodes;
4751 }
4752 
4753 
4754 /*
4755  * Row methods
4756  */
4757 
4758 /** calculates row norms and min/maxidx from scratch, and checks for sorting */
4759 static
rowCalcNorms(SCIP_ROW * row,SCIP_SET * set)4760 void rowCalcNorms(
4761    SCIP_ROW*             row,                /**< LP row */
4762    SCIP_SET*             set                 /**< global SCIP settings */
4763    )
4764 {
4765    int i;
4766 
4767    assert(row != NULL);
4768    assert(set != NULL);
4769 
4770    row->sqrnorm = 0.0;
4771    row->sumnorm = 0.0;
4772    row->objprod = 0.0;
4773    row->maxval = 0.0;
4774    row->nummaxval = 1;
4775    row->minval = SCIPsetInfinity(set);
4776    row->numminval = 1;
4777    row->minidx = INT_MAX;
4778    row->maxidx = INT_MIN;
4779    row->validminmaxidx = TRUE;
4780    row->lpcolssorted = TRUE;
4781    row->nonlpcolssorted = TRUE;
4782 
4783    /* check, if row is sorted
4784     * calculate sqrnorm, sumnorm, maxval, minval, minidx, and maxidx
4785     */
4786    for( i = 0; i < row->nlpcols; ++i )
4787    {
4788       assert(row->cols[i] != NULL);
4789       assert(!SCIPsetIsZero(set, row->vals[i]));
4790       assert(row->cols[i]->lppos >= 0);
4791       assert(row->linkpos[i] >= 0);
4792       assert(row->cols[i]->index == row->cols_index[i]);
4793 
4794       rowAddNorms(row, set, row->cols[i], row->vals[i], TRUE);
4795       if( i > 0 )
4796       {
4797          assert(row->cols[i-1]->index == row->cols_index[i-1]);
4798          row->lpcolssorted = row->lpcolssorted && (row->cols_index[i-1] < row->cols_index[i]);
4799       }
4800    }
4801    for( i = row->nlpcols; i < row->len; ++i )
4802    {
4803       assert(row->cols[i] != NULL);
4804       assert(!SCIPsetIsZero(set, row->vals[i]));
4805       assert(row->cols[i]->lppos == -1 || row->linkpos[i] == -1);
4806       assert(row->cols[i]->index == row->cols_index[i]);
4807 
4808       rowAddNorms(row, set, row->cols[i], row->vals[i], TRUE);
4809       if( i > row->nlpcols )
4810       {
4811          assert(row->cols[i-1]->index == row->cols_index[i-1]);
4812          row->nonlpcolssorted = row->nonlpcolssorted && (row->cols_index[i-1] < row->cols_index[i]);
4813       }
4814    }
4815 }
4816 
4817 /** calculates min/maxval and min/maxidx from scratch */
4818 static
rowCalcIdxsAndVals(SCIP_ROW * row,SCIP_SET * set)4819 void rowCalcIdxsAndVals(
4820    SCIP_ROW*             row,                /**< LP row */
4821    SCIP_SET*             set                 /**< global SCIP settings */
4822    )
4823 {
4824    SCIP_COL* col;
4825    SCIP_Real absval;
4826    int i;
4827 
4828    assert(row != NULL);
4829    assert(set != NULL);
4830 
4831    row->maxval = 0.0;
4832    row->nummaxval = 1;
4833    row->numintcols = 0;
4834    row->minval = SCIPsetInfinity(set);
4835    row->numminval = 1;
4836    row->minidx = INT_MAX;
4837    row->maxidx = INT_MIN;
4838    row->validminmaxidx = TRUE;
4839 
4840    /* calculate maxval, minval, minidx, and maxidx */
4841    for( i = 0; i < row->len; ++i )
4842    {
4843       col = row->cols[i];
4844       assert(col != NULL);
4845       assert(!SCIPsetIsZero(set, row->vals[i]));
4846 
4847       absval = REALABS(row->vals[i]);
4848       assert(!SCIPsetIsZero(set, absval));
4849 
4850       /* update min/maxidx */
4851       row->minidx = MIN(row->minidx, col->index);
4852       row->maxidx = MAX(row->maxidx, col->index);
4853       row->numintcols += SCIPcolIsIntegral(col); /*lint !e713*/
4854 
4855       /* update maximal and minimal non-zero value */
4856       if( row->nummaxval > 0 )
4857       {
4858          if( SCIPsetIsGT(set, absval, row->maxval) )
4859          {
4860             row->maxval = absval;
4861             row->nummaxval = 1;
4862          }
4863          else if( SCIPsetIsGE(set, absval, row->maxval) )
4864          {
4865             /* make sure the maxval is always exactly the same */
4866             row->maxval = MAX(absval, row->maxval);
4867             row->nummaxval++;
4868          }
4869       }
4870       if( row->numminval > 0 )
4871       {
4872          if( SCIPsetIsLT(set, absval, row->minval) )
4873          {
4874             row->minval = absval;
4875             row->numminval = 1;
4876          }
4877          else if( SCIPsetIsLE(set, absval, row->minval) )
4878          {
4879             /* make sure the minval is always exactly the same */
4880             row->minval = MIN(absval, row->minval);
4881             row->numminval++;
4882          }
4883       }
4884    }
4885 }
4886 
4887 /** checks, whether the given scalar scales the given value to an integral number with error in the given bounds */
4888 static
isIntegralScalar(SCIP_Real val,SCIP_Real scalar,SCIP_Real mindelta,SCIP_Real maxdelta,SCIP_Real * intval)4889 SCIP_Bool isIntegralScalar(
4890    SCIP_Real             val,                /**< value that should be scaled to an integral value */
4891    SCIP_Real             scalar,             /**< scalar that should be tried */
4892    SCIP_Real             mindelta,           /**< minimal relative allowed difference of scaled coefficient s*c and integral i */
4893    SCIP_Real             maxdelta,           /**< maximal relative allowed difference of scaled coefficient s*c and integral i */
4894    SCIP_Real*            intval              /**< pointer to store the scaled integral value, or NULL */
4895    )
4896 {
4897    SCIP_Real sval;
4898    SCIP_Real downval;
4899    SCIP_Real upval;
4900 
4901    assert(mindelta <= 0.0);
4902    assert(maxdelta >= 0.0);
4903 
4904    sval = val * scalar;
4905    downval = floor(sval);
4906    upval = ceil(sval);
4907 
4908    if( SCIPrelDiff(sval, downval) <= maxdelta )
4909    {
4910       if( intval != NULL )
4911          *intval = downval;
4912       return TRUE;
4913    }
4914    else if( SCIPrelDiff(sval, upval) >= mindelta )
4915    {
4916       if( intval != NULL )
4917          *intval = upval;
4918       return TRUE;
4919    }
4920 
4921    return FALSE;
4922 }
4923 
4924 /** scales row with given factor, and rounds coefficients to integers if close enough;
4925  *  the constant is automatically moved to the sides;
4926  *  if the row's activity is proven to be integral, the sides are automatically rounded to the next integer
4927  */
4928 static
rowScale(SCIP_ROW * row,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_STAT * stat,SCIP_LP * lp,SCIP_Real scaleval,SCIP_Bool integralcontvars,SCIP_Real minrounddelta,SCIP_Real maxrounddelta)4929 SCIP_RETCODE rowScale(
4930    SCIP_ROW*             row,                /**< LP row */
4931    BMS_BLKMEM*           blkmem,             /**< block memory */
4932    SCIP_SET*             set,                /**< global SCIP settings */
4933    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
4934    SCIP_STAT*            stat,               /**< problem statistics */
4935    SCIP_LP*              lp,                 /**< current LP data */
4936    SCIP_Real             scaleval,           /**< value to scale row with */
4937    SCIP_Bool             integralcontvars,   /**< should the coefficients of the continuous variables also be made integral,
4938                                               *   if they are close to integral values? */
4939    SCIP_Real             minrounddelta,      /**< minimal relative difference of scaled coefficient s*c and integral i,
4940                                               *   upto which the integral is used instead of the scaled real coefficient */
4941    SCIP_Real             maxrounddelta       /**< maximal relative difference of scaled coefficient s*c and integral i
4942                                               *   upto which the integral is used instead of the scaled real coefficient */
4943    )
4944 {
4945    SCIP_COL* col;
4946    SCIP_Real val;
4947    SCIP_Real newval;
4948    SCIP_Real intval;
4949    SCIP_Real mindelta;
4950    SCIP_Real maxdelta;
4951    SCIP_Real lb;
4952    SCIP_Real ub;
4953    SCIP_Bool mindeltainf;
4954    SCIP_Bool maxdeltainf;
4955    int oldlen;
4956    int c;
4957 
4958    assert(row != NULL);
4959    assert(row->len == 0 || row->cols != NULL);
4960    assert(row->len == 0 || row->vals != NULL);
4961    assert(SCIPsetIsPositive(set, scaleval));
4962    assert(-1.0 < minrounddelta && minrounddelta <= 0.0);
4963    assert(0.0 <= maxrounddelta && maxrounddelta < 1.0);
4964 
4965    SCIPsetDebugMsg(set, "scale row <%s> with %g (tolerance=[%g,%g])\n", row->name, scaleval, minrounddelta, maxrounddelta);
4966 
4967    mindelta = 0.0;
4968    maxdelta = 0.0;
4969    mindeltainf = FALSE;
4970    maxdeltainf = FALSE;
4971    oldlen = row->len;
4972 
4973    /* scale the row coefficients, thereby recalculating whether the row's activity is always integral;
4974     * if the row coefficients are rounded to the nearest integer value, calculate the maximal activity difference,
4975     * this rounding can lead to
4976     */
4977    row->integral = TRUE;
4978 
4979    c = 0;
4980    while( c < row->len )
4981    {
4982       col = row->cols[c];
4983       val = row->vals[c];
4984       assert(!SCIPsetIsZero(set, val));
4985 
4986       /* get local or global bounds for column, depending on the local or global feasibility of the row */
4987       if( row->local )
4988       {
4989          lb = col->lb;
4990          ub = col->ub;
4991       }
4992       else
4993       {
4994          lb = SCIPvarGetLbGlobal(col->var);
4995          ub = SCIPvarGetUbGlobal(col->var);
4996       }
4997 
4998       /* calculate scaled coefficient */
4999       newval = val * scaleval;
5000       if( (integralcontvars || SCIPcolIsIntegral(col) || SCIPsetIsIntegral(set, newval))
5001          && isIntegralScalar(val, scaleval, minrounddelta, maxrounddelta, &intval) )
5002       {
5003          if( !SCIPsetIsEQ(set, intval, newval) )
5004          {
5005             if( intval < newval )
5006             {
5007                mindelta += (intval - newval)*ub;
5008                maxdelta += (intval - newval)*lb;
5009                mindeltainf = mindeltainf || SCIPsetIsInfinity(set, ub);
5010                maxdeltainf = maxdeltainf || SCIPsetIsInfinity(set, -lb);
5011             }
5012             else
5013             {
5014                mindelta += (intval - newval)*lb;
5015                maxdelta += (intval - newval)*ub;
5016                mindeltainf = mindeltainf || SCIPsetIsInfinity(set, -lb);
5017                maxdeltainf = maxdeltainf || SCIPsetIsInfinity(set, ub);
5018             }
5019          }
5020          newval = intval;
5021       }
5022 
5023       if( !SCIPsetIsEQ(set, val, newval) )
5024       {
5025          /* if column knows of the row, change the corresponding coefficient in the column */
5026          if( row->linkpos[c] >= 0 )
5027          {
5028             assert(col->rows[row->linkpos[c]] == row);
5029             assert(SCIPsetIsEQ(set, col->vals[row->linkpos[c]], row->vals[c]));
5030             SCIP_CALL( colChgCoefPos(col, set, lp, row->linkpos[c], newval) );
5031          }
5032 
5033          /* change the coefficient in the row, and update the norms and integrality status */
5034          SCIP_CALL( rowChgCoefPos(row, blkmem, set, eventqueue, lp, c, newval) );
5035 
5036          /* current coefficient has been deleted from the row because it was almost zero */
5037          if( oldlen != row->len )
5038          {
5039             assert(row->len == oldlen - 1);
5040             c--;
5041             oldlen = row->len;
5042          }
5043       }
5044       else
5045          row->integral = row->integral && SCIPcolIsIntegral(col) && SCIPsetIsIntegral(set, val);
5046 
5047       ++c;
5048    }
5049 
5050    /* scale the row sides, and move the constant to the sides; relax the sides with accumulated delta in order
5051     * to not destroy feasibility due to rounding
5052     */
5053    /**@todo ensure that returned cut does not have infinite lhs and rhs */
5054    if( !SCIPsetIsInfinity(set, -row->lhs) )
5055    {
5056       if( mindeltainf )
5057          newval = -SCIPsetInfinity(set);
5058       else
5059       {
5060          newval = (row->lhs - row->constant) * scaleval + mindelta;
5061          if( SCIPsetIsIntegral(set, newval) || (row->integral && !row->modifiable) )
5062             newval = SCIPsetSumCeil(set, newval);
5063       }
5064       SCIP_CALL( SCIProwChgLhs(row, blkmem, set, eventqueue, lp, newval) );
5065    }
5066    if( !SCIPsetIsInfinity(set, row->rhs) )
5067    {
5068       if( maxdeltainf )
5069          newval = SCIPsetInfinity(set);
5070       else
5071       {
5072          newval = (row->rhs - row->constant) * scaleval + maxdelta;
5073          if( SCIPsetIsIntegral(set, newval) || (row->integral && !row->modifiable) )
5074             newval = SCIPsetSumFloor(set, newval);
5075       }
5076       SCIP_CALL( SCIProwChgRhs(row, blkmem, set, eventqueue, lp, newval) );
5077    }
5078 
5079    /* clear the row constant */
5080    SCIP_CALL( SCIProwChgConstant(row, blkmem, set, stat, eventqueue, lp, 0.0) );
5081 
5082    SCIPsetDebugMsg(set, "scaled row <%s> (integral: %u)\n", row->name, row->integral);
5083    debugRowPrint(set, row);
5084 
5085 #ifdef SCIP_DEBUG
5086    /* check integrality status of row */
5087    for( c = 0; c < row->len && SCIPcolIsIntegral(row->cols[c]) && SCIPsetIsIntegral(set, row->vals[c]); ++c )
5088    {}
5089    assert(row->integral == (c == row->len));
5090 #endif
5091 
5092    /* invalid the activity */
5093    row->validactivitylp = -1;
5094 
5095    return SCIP_OKAY;
5096 }
5097 
5098 /** creates and captures an LP row */
SCIProwCreate(SCIP_ROW ** row,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,const char * name,int len,SCIP_COL ** cols,SCIP_Real * vals,SCIP_Real lhs,SCIP_Real rhs,SCIP_ROWORIGINTYPE origintype,void * origin,SCIP_Bool local,SCIP_Bool modifiable,SCIP_Bool removable)5099 SCIP_RETCODE SCIProwCreate(
5100    SCIP_ROW**            row,                /**< pointer to LP row data */
5101    BMS_BLKMEM*           blkmem,             /**< block memory */
5102    SCIP_SET*             set,                /**< global SCIP settings */
5103    SCIP_STAT*            stat,               /**< problem statistics */
5104    const char*           name,               /**< name of row */
5105    int                   len,                /**< number of nonzeros in the row */
5106    SCIP_COL**            cols,               /**< array with columns of row entries */
5107    SCIP_Real*            vals,               /**< array with coefficients of row entries */
5108    SCIP_Real             lhs,                /**< left hand side of row */
5109    SCIP_Real             rhs,                /**< right hand side of row */
5110    SCIP_ROWORIGINTYPE    origintype,         /**< type of origin of row */
5111    void*                 origin,             /**< pointer to constraint handler or separator who created the row (NULL if unkown) */
5112    SCIP_Bool             local,              /**< is row only valid locally? */
5113    SCIP_Bool             modifiable,         /**< is row modifiable during node processing (subject to column generation)? */
5114    SCIP_Bool             removable           /**< should the row be removed from the LP due to aging or cleanup? */
5115    )
5116 {
5117    assert(row != NULL);
5118    assert(blkmem != NULL);
5119    assert(stat != NULL);
5120    assert(len >= 0);
5121    assert(len == 0 || (cols != NULL && vals != NULL));
5122    /* note, that the assert tries to avoid numerical troubles in the LP solver.
5123     * in case, for example, lhs > rhs but they are equal with tolerances, one could pass lhs=rhs=lhs+rhs/2 to
5124     * SCIProwCreate() (see cons_linear.c: detectRedundantConstraints())
5125     */
5126    assert(lhs <= rhs);
5127 
5128    SCIP_ALLOC( BMSallocBlockMemory(blkmem, row) );
5129 
5130    (*row)->integral = TRUE;
5131    if( len > 0 )
5132    {
5133       SCIP_VAR* var;
5134       int i;
5135 
5136       SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*row)->cols, cols, len) );
5137       SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*row)->vals, vals, len) );
5138       SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*row)->cols_index, len) );
5139       SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*row)->linkpos, len) );
5140 
5141       for( i = 0; i < len; ++i )
5142       {
5143          assert(cols[i] != NULL);
5144          assert(!SCIPsetIsZero(set, vals[i]));
5145 
5146          var = cols[i]->var;
5147          (*row)->cols_index[i] = cols[i]->index;
5148          (*row)->linkpos[i] = -1;
5149          if( SCIPsetIsIntegral(set, (*row)->vals[i]) )
5150          {
5151             (*row)->vals[i] = SCIPsetRound(set, (*row)->vals[i]);
5152             (*row)->integral = (*row)->integral && SCIPvarIsIntegral(var);
5153          }
5154          else
5155          {
5156             (*row)->integral = FALSE;
5157          }
5158       }
5159    }
5160    else
5161    {
5162       (*row)->cols = NULL;
5163       (*row)->cols_index = NULL;
5164       (*row)->vals = NULL;
5165       (*row)->linkpos = NULL;
5166    }
5167 
5168    SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*row)->name, name, strlen(name)+1) );
5169    (*row)->constant = 0.0;
5170    (*row)->lhs = lhs;
5171    (*row)->rhs = rhs;
5172    (*row)->flushedlhs = -SCIPsetInfinity(set);
5173    (*row)->flushedrhs = SCIPsetInfinity(set);
5174    (*row)->sqrnorm = 0.0;
5175    (*row)->sumnorm = 0.0;
5176    (*row)->objprod = 0.0;
5177    (*row)->maxval = 0.0;
5178    (*row)->minval = SCIPsetInfinity(set);
5179    (*row)->dualsol = 0.0;
5180    (*row)->activity = SCIP_INVALID;
5181    (*row)->dualfarkas = 0.0;
5182    (*row)->pseudoactivity = SCIP_INVALID;
5183    (*row)->minactivity = SCIP_INVALID;
5184    (*row)->maxactivity = SCIP_INVALID;
5185    (*row)->origin = origin;
5186    (*row)->eventfilter = NULL;
5187    (*row)->index = stat->nrowidx;
5188    SCIPstatIncrement(stat, set, nrowidx);
5189    (*row)->size = len;
5190    (*row)->len = len;
5191    (*row)->nlpcols = 0;
5192    (*row)->nunlinked = len;
5193    (*row)->nuses = 0;
5194    (*row)->lppos = -1;
5195    (*row)->lpipos = -1;
5196    (*row)->lpdepth = -1;
5197    (*row)->minidx = INT_MAX;
5198    (*row)->maxidx = INT_MIN;
5199    (*row)->nummaxval = 0;
5200    (*row)->numminval = 0;
5201    (*row)->numintcols = -1;
5202    (*row)->validactivitylp = -1;
5203    (*row)->validpsactivitydomchg = -1;
5204    (*row)->validactivitybdsdomchg = -1;
5205    (*row)->nlpsaftercreation = 0L;
5206    (*row)->activeinlpcounter = 0L;
5207    (*row)->age = 0;
5208    (*row)->rank = 0;
5209    (*row)->obsoletenode = -1;
5210    (*row)->basisstatus = SCIP_BASESTAT_BASIC; /*lint !e641*/
5211    (*row)->lpcolssorted = TRUE;
5212    (*row)->nonlpcolssorted = (len <= 1);
5213    (*row)->delaysort = FALSE;
5214    (*row)->validminmaxidx = FALSE;
5215    (*row)->lhschanged = FALSE;
5216    (*row)->rhschanged = FALSE;
5217    (*row)->coefchanged = FALSE;
5218    (*row)->local = local;
5219    (*row)->modifiable = modifiable;
5220    (*row)->nlocks = 0;
5221    (*row)->origintype = origintype; /*lint !e641*/
5222    (*row)->removable = removable;
5223    (*row)->inglobalcutpool = FALSE;
5224    (*row)->storedsolvals = NULL;
5225 
5226    /* calculate row norms and min/maxidx, and check if row is sorted */
5227    rowCalcNorms(*row, set);
5228 
5229    /* capture the row */
5230    SCIProwCapture(*row);
5231 
5232    /* create event filter */
5233    SCIP_CALL( SCIPeventfilterCreate(&(*row)->eventfilter, blkmem) );
5234 
5235    /* capture origin constraint if available */
5236    if( origintype == SCIP_ROWORIGINTYPE_CONS )
5237    {
5238       SCIP_CONS* cons = (SCIP_CONS*) origin;
5239       assert(cons != NULL);
5240       SCIPconsCapture(cons);
5241    }
5242 
5243    return SCIP_OKAY;
5244 } /*lint !e715*/
5245 
5246 /** frees an LP row */
SCIProwFree(SCIP_ROW ** row,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_LP * lp)5247 SCIP_RETCODE SCIProwFree(
5248    SCIP_ROW**            row,                /**< pointer to LP row */
5249    BMS_BLKMEM*           blkmem,             /**< block memory */
5250    SCIP_SET*             set,                /**< global SCIP settings */
5251    SCIP_LP*              lp                  /**< current LP data */
5252    )
5253 {
5254    assert(blkmem != NULL);
5255    assert(row != NULL);
5256    assert(*row != NULL);
5257    assert((*row)->nuses == 0);
5258    assert((*row)->lppos == -1);
5259    assert((*row)->eventfilter != NULL);
5260 
5261    /* release constraint that has been used for creating the row */
5262    if( (SCIP_ROWORIGINTYPE) (*row)->origintype == SCIP_ROWORIGINTYPE_CONS )
5263    {
5264       SCIP_CONS* cons = (SCIP_CONS*) (*row)->origin;
5265       assert(cons != NULL);
5266       SCIP_CALL( SCIPconsRelease(&cons, blkmem, set) );
5267    }
5268 
5269    /* remove column indices from corresponding rows */
5270    SCIP_CALL( rowUnlink(*row, set, lp) );
5271 
5272    /* free event filter */
5273    SCIP_CALL( SCIPeventfilterFree(&(*row)->eventfilter, blkmem, set) );
5274 
5275    BMSfreeBlockMemoryNull(blkmem, &(*row)->storedsolvals);
5276    BMSfreeBlockMemoryArray(blkmem, &(*row)->name, strlen((*row)->name)+1);
5277    BMSfreeBlockMemoryArrayNull(blkmem, &(*row)->cols, (*row)->size);
5278    BMSfreeBlockMemoryArrayNull(blkmem, &(*row)->cols_index, (*row)->size);
5279    BMSfreeBlockMemoryArrayNull(blkmem, &(*row)->vals, (*row)->size);
5280    BMSfreeBlockMemoryArrayNull(blkmem, &(*row)->linkpos, (*row)->size);
5281    BMSfreeBlockMemory(blkmem, row);
5282 
5283    return SCIP_OKAY;
5284 }
5285 
5286 /** output row to file stream */
SCIProwPrint(SCIP_ROW * row,SCIP_MESSAGEHDLR * messagehdlr,FILE * file)5287 void SCIProwPrint(
5288    SCIP_ROW*             row,                /**< LP row */
5289    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
5290    FILE*                 file                /**< output file (or NULL for standard output) */
5291    )
5292 {
5293    int i;
5294 
5295    assert(row != NULL);
5296 
5297    /* print row name */
5298    if( row->name != NULL && row->name[0] != '\0' )
5299    {
5300       SCIPmessageFPrintInfo(messagehdlr, file, "%s: ", row->name);
5301    }
5302 
5303    /* print left hand side */
5304    SCIPmessageFPrintInfo(messagehdlr, file, "%.15g <= ", row->lhs);
5305 
5306    /* print coefficients */
5307    if( row->len == 0 )
5308       SCIPmessageFPrintInfo(messagehdlr, file, "0 ");
5309    for( i = 0; i < row->len; ++i )
5310    {
5311       assert(row->cols[i] != NULL);
5312       assert(row->cols[i]->var != NULL);
5313       assert(SCIPvarGetName(row->cols[i]->var) != NULL);
5314       assert(SCIPvarGetStatus(row->cols[i]->var) == SCIP_VARSTATUS_COLUMN);
5315       SCIPmessageFPrintInfo(messagehdlr, file, "%+.15g<%s> ", row->vals[i], SCIPvarGetName(row->cols[i]->var));
5316    }
5317 
5318    /* print constant */
5319    if( REALABS(row->constant) > SCIP_DEFAULT_EPSILON )
5320       SCIPmessageFPrintInfo(messagehdlr, file, "%+.15g ", row->constant);
5321 
5322    /* print right hand side */
5323    SCIPmessageFPrintInfo(messagehdlr, file, "<= %.15g\n", row->rhs);
5324 }
5325 
5326 /** increases usage counter of LP row */
SCIProwCapture(SCIP_ROW * row)5327 void SCIProwCapture(
5328    SCIP_ROW*             row                 /**< LP row */
5329    )
5330 {
5331    assert(row != NULL);
5332    assert(row->nuses >= 0);
5333    assert(row->nlocks <= (unsigned int)(row->nuses)); /*lint !e574*/
5334 
5335    SCIPdebugMessage("capture row <%s> with nuses=%d and nlocks=%u\n", row->name, row->nuses, row->nlocks);
5336    row->nuses++;
5337 }
5338 
5339 /** decreases usage counter of LP row, and frees memory if necessary */
SCIProwRelease(SCIP_ROW ** row,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_LP * lp)5340 SCIP_RETCODE SCIProwRelease(
5341    SCIP_ROW**            row,                /**< pointer to LP row */
5342    BMS_BLKMEM*           blkmem,             /**< block memory */
5343    SCIP_SET*             set,                /**< global SCIP settings */
5344    SCIP_LP*              lp                  /**< current LP data */
5345    )
5346 {
5347    assert(blkmem != NULL);
5348    assert(row != NULL);
5349    assert(*row != NULL);
5350    assert((*row)->nuses >= 1);
5351    assert((*row)->nlocks < (unsigned int)((*row)->nuses)); /*lint !e574*/
5352 
5353    SCIPsetDebugMsg(set, "release row <%s> with nuses=%d and nlocks=%u\n", (*row)->name, (*row)->nuses, (*row)->nlocks);
5354    (*row)->nuses--;
5355    if( (*row)->nuses == 0 )
5356    {
5357       SCIP_CALL( SCIProwFree(row, blkmem, set, lp) );
5358    }
5359 
5360    *row = NULL;
5361 
5362    return SCIP_OKAY;
5363 }
5364 
5365 /** locks an unmodifiable row, which forbids further changes; has no effect on modifiable rows */
SCIProwLock(SCIP_ROW * row)5366 void SCIProwLock(
5367    SCIP_ROW*             row                 /**< LP row */
5368    )
5369 {
5370    assert(row != NULL);
5371 
5372    /* check, if row is modifiable */
5373    if( !row->modifiable )
5374    {
5375       SCIPdebugMessage("lock row <%s> with nuses=%d and nlocks=%u\n", row->name, row->nuses, row->nlocks);
5376       row->nlocks++;
5377    }
5378 }
5379 
5380 /** unlocks a lock of an unmodifiable row; a row with no sealed lock may be modified; has no effect on modifiable rows */
SCIProwUnlock(SCIP_ROW * row)5381 void SCIProwUnlock(
5382    SCIP_ROW*             row                 /**< LP row */
5383    )
5384 {
5385    assert(row != NULL);
5386 
5387    /* check, if row is modifiable */
5388    if( !row->modifiable )
5389    {
5390       SCIPdebugMessage("unlock row <%s> with nuses=%d and nlocks=%u\n", row->name, row->nuses, row->nlocks);
5391       assert(row->nlocks > 0);
5392       row->nlocks--;
5393    }
5394 }
5395 
5396 /** adds a previously non existing coefficient to an LP row */
SCIProwAddCoef(SCIP_ROW * row,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp,SCIP_COL * col,SCIP_Real val)5397 SCIP_RETCODE SCIProwAddCoef(
5398    SCIP_ROW*             row,                /**< LP row */
5399    BMS_BLKMEM*           blkmem,             /**< block memory */
5400    SCIP_SET*             set,                /**< global SCIP settings */
5401    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
5402    SCIP_LP*              lp,                 /**< current LP data */
5403    SCIP_COL*             col,                /**< LP column */
5404    SCIP_Real             val                 /**< value of coefficient */
5405    )
5406 {
5407    assert(lp != NULL);
5408    assert(!lp->diving || row->lppos == -1);
5409 
5410    SCIP_CALL( rowAddCoef(row, blkmem, set, eventqueue, lp, col, val, -1) );
5411 
5412    checkLinks(lp);
5413 
5414    return SCIP_OKAY;
5415 }
5416 
5417 /** deletes coefficient from row */
SCIProwDelCoef(SCIP_ROW * row,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp,SCIP_COL * col)5418 SCIP_RETCODE SCIProwDelCoef(
5419    SCIP_ROW*             row,                /**< row to be changed */
5420    BMS_BLKMEM*           blkmem,             /**< block memory */
5421    SCIP_SET*             set,                /**< global SCIP settings */
5422    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
5423    SCIP_LP*              lp,                 /**< current LP data */
5424    SCIP_COL*             col                 /**< coefficient to be deleted */
5425    )
5426 {
5427    int pos;
5428 
5429    assert(row != NULL);
5430    assert(!row->delaysort);
5431    assert(lp != NULL);
5432    assert(!lp->diving || row->lppos == -1);
5433    assert(col != NULL);
5434    assert(col->var != NULL);
5435 
5436    /* search the position of the column in the row's col vector */
5437    pos = rowSearchCoef(row, col);
5438    if( pos == -1 )
5439    {
5440       SCIPerrorMessage("coefficient for column <%s> doesn't exist in row <%s>\n", SCIPvarGetName(col->var), row->name);
5441       return SCIP_INVALIDDATA;
5442    }
5443    assert(0 <= pos && pos < row->len);
5444    assert(row->cols[pos] == col);
5445    assert(row->cols_index[pos] == col->index);
5446 
5447    /* if column knows of the row, remove the row from the column's row vector */
5448    if( row->linkpos[pos] >= 0 )
5449    {
5450       assert(col->rows[row->linkpos[pos]] == row);
5451       assert(SCIPsetIsEQ(set, col->vals[row->linkpos[pos]], row->vals[pos]));
5452       SCIP_CALL( colDelCoefPos(col, set, lp, row->linkpos[pos]) );
5453    }
5454 
5455    /* delete the column from the row's col vector */
5456    SCIP_CALL( rowDelCoefPos(row, blkmem, set, eventqueue, lp, pos) );
5457 
5458    checkLinks(lp);
5459 
5460    return SCIP_OKAY;
5461 }
5462 
5463 /** changes or adds a coefficient to an LP row */
SCIProwChgCoef(SCIP_ROW * row,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp,SCIP_COL * col,SCIP_Real val)5464 SCIP_RETCODE SCIProwChgCoef(
5465    SCIP_ROW*             row,                /**< LP row */
5466    BMS_BLKMEM*           blkmem,             /**< block memory */
5467    SCIP_SET*             set,                /**< global SCIP settings */
5468    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
5469    SCIP_LP*              lp,                 /**< current LP data */
5470    SCIP_COL*             col,                /**< LP column */
5471    SCIP_Real             val                 /**< value of coefficient */
5472    )
5473 {
5474    int pos;
5475 
5476    assert(row != NULL);
5477    assert(!row->delaysort);
5478    assert(lp != NULL);
5479    assert(!lp->diving || row->lppos == -1);
5480    assert(col != NULL);
5481 
5482    /* search the position of the column in the row's col vector */
5483    pos = rowSearchCoef(row, col);
5484 
5485    /* check, if column already exists in the row's col vector */
5486    if( pos == -1 )
5487    {
5488       /* add previously not existing coefficient */
5489       SCIP_CALL( rowAddCoef(row, blkmem, set, eventqueue, lp, col, val, -1) );
5490    }
5491    else
5492    {
5493       /* modify already existing coefficient */
5494       assert(0 <= pos && pos < row->len);
5495       assert(row->cols[pos] == col);
5496       assert(row->cols_index[pos] == col->index);
5497 
5498       /* if column knows of the row, change the corresponding coefficient in the column */
5499       if( row->linkpos[pos] >= 0 )
5500       {
5501          assert(col->rows[row->linkpos[pos]] == row);
5502          assert(SCIPsetIsEQ(set, col->vals[row->linkpos[pos]], row->vals[pos]));
5503          SCIP_CALL( colChgCoefPos(col, set, lp, row->linkpos[pos], val) );
5504       }
5505 
5506       /* change the coefficient in the row */
5507       SCIP_CALL( rowChgCoefPos(row, blkmem, set, eventqueue, lp, pos, val) );
5508    }
5509 
5510    checkLinks(lp);
5511 
5512    return SCIP_OKAY;
5513 }
5514 
5515 /** increases value of an existing or non-existing coefficient in an LP row */
SCIProwIncCoef(SCIP_ROW * row,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp,SCIP_COL * col,SCIP_Real incval)5516 SCIP_RETCODE SCIProwIncCoef(
5517    SCIP_ROW*             row,                /**< LP row */
5518    BMS_BLKMEM*           blkmem,             /**< block memory */
5519    SCIP_SET*             set,                /**< global SCIP settings */
5520    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
5521    SCIP_LP*              lp,                 /**< current LP data */
5522    SCIP_COL*             col,                /**< LP column */
5523    SCIP_Real             incval              /**< value to add to the coefficient */
5524    )
5525 {
5526    int pos;
5527 
5528    assert(row != NULL);
5529    assert(lp != NULL);
5530    assert(!lp->diving || row->lppos == -1);
5531    assert(col != NULL);
5532 
5533    if( SCIPsetIsZero(set, incval) )
5534       return SCIP_OKAY;
5535 
5536    /* search the position of the column in the row's col vector */
5537    pos = rowSearchCoef(row, col);
5538 
5539    /* check, if column already exists in the row's col vector */
5540    if( pos == -1 )
5541    {
5542       /* coefficient doesn't exist, or sorting is delayed: add coefficient to the end of the row's arrays */
5543       SCIP_CALL( rowAddCoef(row, blkmem, set, eventqueue, lp, col, incval, -1) );
5544    }
5545    else
5546    {
5547       /* modify already existing coefficient */
5548       assert(0 <= pos && pos < row->len);
5549       assert(row->cols[pos] == col);
5550       assert(row->cols_index[pos] == col->index);
5551 
5552       /* if column knows of the row, change the corresponding coefficient in the column */
5553       if( row->linkpos[pos] >= 0 )
5554       {
5555          assert(col->rows[row->linkpos[pos]] == row);
5556          assert(SCIPsetIsEQ(set, col->vals[row->linkpos[pos]], row->vals[pos]));
5557          SCIP_CALL( colChgCoefPos(col, set, lp, row->linkpos[pos], row->vals[pos] + incval) );
5558       }
5559 
5560       /* change the coefficient in the row */
5561       SCIP_CALL( rowChgCoefPos(row, blkmem, set, eventqueue, lp, pos, row->vals[pos] + incval) );
5562    }
5563 
5564    checkLinks(lp);
5565 
5566    /* invalid the activity */
5567    row->validactivitylp = -1;
5568 
5569    return SCIP_OKAY;
5570 }
5571 
5572 /** changes constant value of a row */
SCIProwChgConstant(SCIP_ROW * row,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp,SCIP_Real constant)5573 SCIP_RETCODE SCIProwChgConstant(
5574    SCIP_ROW*             row,                /**< LP row */
5575    BMS_BLKMEM*           blkmem,             /**< block memory */
5576    SCIP_SET*             set,                /**< global SCIP settings */
5577    SCIP_STAT*            stat,               /**< problem statistics */
5578    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
5579    SCIP_LP*              lp,                 /**< current LP data */
5580    SCIP_Real             constant            /**< new constant value */
5581    )
5582 {
5583    assert(row != NULL);
5584    assert(row->lhs <= row->rhs);
5585    assert(!SCIPsetIsInfinity(set, REALABS(constant)));
5586    assert(stat != NULL);
5587    assert(lp != NULL);
5588    assert(!lp->diving || row->lppos == -1);
5589 
5590    if( !SCIPsetIsEQ(set, constant, row->constant) )
5591    {
5592       SCIP_Real oldconstant;
5593 
5594       if( row->validpsactivitydomchg == stat->domchgcount )
5595       {
5596          assert(row->pseudoactivity < SCIP_INVALID);
5597          row->pseudoactivity += constant - row->constant;
5598       }
5599       if( row->validactivitybdsdomchg == stat->domchgcount )
5600       {
5601          assert(row->minactivity < SCIP_INVALID);
5602          assert(row->maxactivity < SCIP_INVALID);
5603          row->minactivity += constant - row->constant;
5604          row->maxactivity += constant - row->constant;
5605       }
5606 
5607       if( !SCIPsetIsInfinity(set, -row->lhs) )
5608       {
5609          SCIP_CALL( rowSideChanged(row, set, lp, SCIP_SIDETYPE_LEFT) );
5610       }
5611       if( !SCIPsetIsInfinity(set, row->rhs) )
5612       {
5613          SCIP_CALL( rowSideChanged(row, set, lp, SCIP_SIDETYPE_RIGHT) );
5614       }
5615 
5616       oldconstant = row->constant;
5617 
5618       row->constant = constant;
5619 
5620       /* issue row constant changed event */
5621       SCIP_CALL( rowEventConstantChanged(row, blkmem, set, eventqueue, oldconstant, constant) );
5622    }
5623 
5624    return SCIP_OKAY;
5625 }
5626 
5627 /** add constant value to a row */
SCIProwAddConstant(SCIP_ROW * row,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp,SCIP_Real addval)5628 SCIP_RETCODE SCIProwAddConstant(
5629    SCIP_ROW*             row,                /**< LP row */
5630    BMS_BLKMEM*           blkmem,             /**< block memory */
5631    SCIP_SET*             set,                /**< global SCIP settings */
5632    SCIP_STAT*            stat,               /**< problem statistics */
5633    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
5634    SCIP_LP*              lp,                 /**< current LP data */
5635    SCIP_Real             addval              /**< constant value to add to the row */
5636    )
5637 {
5638    assert(row != NULL);
5639    assert(row->lhs <= row->rhs);
5640    assert(!SCIPsetIsInfinity(set, REALABS(addval)));
5641    assert(stat != NULL);
5642    assert(lp != NULL);
5643    assert(!lp->diving || row->lppos == -1);
5644 
5645    if( !SCIPsetIsZero(set, addval) )
5646    {
5647       SCIP_CALL( SCIProwChgConstant(row, blkmem, set, stat, eventqueue, lp, row->constant + addval) );
5648    }
5649 
5650    return SCIP_OKAY;
5651 }
5652 
5653 /** changes left hand side of LP row */
SCIProwChgLhs(SCIP_ROW * row,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp,SCIP_Real lhs)5654 SCIP_RETCODE SCIProwChgLhs(
5655    SCIP_ROW*             row,                /**< LP row */
5656    BMS_BLKMEM*           blkmem,             /**< block memory */
5657    SCIP_SET*             set,                /**< global SCIP settings */
5658    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
5659    SCIP_LP*              lp,                 /**< current LP data */
5660    SCIP_Real             lhs                 /**< new left hand side */
5661    )
5662 {
5663    assert(row != NULL);
5664    assert(lp != NULL);
5665 
5666    if( !SCIPsetIsEQ(set, row->lhs, lhs) )
5667    {
5668       SCIP_Real oldlhs;
5669 
5670       oldlhs = row->lhs;
5671 
5672       row->lhs = lhs;
5673       SCIP_CALL( rowSideChanged(row, set, lp, SCIP_SIDETYPE_LEFT) );
5674 
5675       if( !lp->diving )
5676       {
5677          /* issue row side changed event */
5678          SCIP_CALL( rowEventSideChanged(row, blkmem, set, eventqueue, SCIP_SIDETYPE_LEFT, oldlhs, lhs) );
5679       }
5680    }
5681 
5682    return SCIP_OKAY;
5683 }
5684 
5685 /** changes right hand side of LP row */
SCIProwChgRhs(SCIP_ROW * row,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp,SCIP_Real rhs)5686 SCIP_RETCODE SCIProwChgRhs(
5687    SCIP_ROW*             row,                /**< LP row */
5688    BMS_BLKMEM*           blkmem,             /**< block memory */
5689    SCIP_SET*             set,                /**< global SCIP settings */
5690    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
5691    SCIP_LP*              lp,                 /**< current LP data */
5692    SCIP_Real             rhs                 /**< new right hand side */
5693    )
5694 {
5695    assert(row != NULL);
5696    assert(lp != NULL);
5697 
5698    if( !SCIPsetIsEQ(set, row->rhs, rhs) )
5699    {
5700       SCIP_Real oldrhs;
5701 
5702       oldrhs = row->rhs;
5703 
5704       row->rhs = rhs;
5705       SCIP_CALL( rowSideChanged(row, set, lp, SCIP_SIDETYPE_RIGHT) );
5706 
5707       if( !lp->diving )
5708       {
5709          /* issue row side changed event */
5710          SCIP_CALL( rowEventSideChanged(row, blkmem, set, eventqueue, SCIP_SIDETYPE_RIGHT, oldrhs, rhs) );
5711       }
5712    }
5713 
5714    return SCIP_OKAY;
5715 }
5716 
5717 /** changes the local flag of LP row */
SCIProwChgLocal(SCIP_ROW * row,SCIP_Bool local)5718 SCIP_RETCODE SCIProwChgLocal(
5719    SCIP_ROW*             row,                /**< LP row */
5720    SCIP_Bool             local               /**< new value for local flag */
5721    )
5722 {
5723    assert(row != NULL);
5724 
5725    row->local = local;
5726 
5727    return SCIP_OKAY;
5728 }
5729 
5730 /** additional scalars that are tried in integrality scaling */
5731 static const SCIP_Real scalars[] = {3.0, 5.0, 7.0, 9.0, 11.0, 13.0, 15.0, 17.0, 19.0};
5732 static const int nscalars = 9;
5733 
5734 /** tries to find a value, such that all row coefficients, if scaled with this value become integral */
SCIProwCalcIntegralScalar(SCIP_ROW * row,SCIP_SET * set,SCIP_Real mindelta,SCIP_Real maxdelta,SCIP_Longint maxdnom,SCIP_Real maxscale,SCIP_Bool usecontvars,SCIP_Real * intscalar,SCIP_Bool * success)5735 SCIP_RETCODE SCIProwCalcIntegralScalar(
5736    SCIP_ROW*             row,                /**< LP row */
5737    SCIP_SET*             set,                /**< global SCIP settings */
5738    SCIP_Real             mindelta,           /**< minimal relative allowed difference of scaled coefficient s*c and integral i */
5739    SCIP_Real             maxdelta,           /**< maximal relative allowed difference of scaled coefficient s*c and integral i */
5740    SCIP_Longint          maxdnom,            /**< maximal denominator allowed in rational numbers */
5741    SCIP_Real             maxscale,           /**< maximal allowed scalar */
5742    SCIP_Bool             usecontvars,        /**< should the coefficients of the continuous variables also be made integral? */
5743    SCIP_Real*            intscalar,          /**< pointer to store scalar that would make the coefficients integral, or NULL */
5744    SCIP_Bool*            success             /**< stores whether returned value is valid */
5745    )
5746 {
5747 #ifndef NDEBUG
5748    SCIP_COL* col;
5749 #endif
5750    SCIP_Longint gcd;
5751    SCIP_Longint scm;
5752    SCIP_Longint nominator;
5753    SCIP_Longint denominator;
5754    SCIP_Real val;
5755    SCIP_Real absval;
5756    SCIP_Real minval;
5757    SCIP_Real scaleval;
5758    SCIP_Real twomultval;
5759    SCIP_Bool scalable;
5760    SCIP_Bool twomult;
5761    SCIP_Bool rational;
5762    int c;
5763    int s;
5764 
5765    /**@todo call misc.c:SCIPcalcIntegralScalar() instead - if usecontvars == FALSE, filter the integer variables first */
5766    assert(row != NULL);
5767    assert(row->len == 0 || row->cols != NULL);
5768    assert(row->len == 0 || row->cols_index != NULL);
5769    assert(row->len == 0 || row->vals != NULL);
5770    assert(maxdnom >= 1);
5771    assert(mindelta < 0.0);
5772    assert(maxdelta > 0.0);
5773    assert(success != NULL);
5774 
5775    SCIPsetDebugMsg(set, "trying to find rational representation for row <%s> (contvars: %u)\n", SCIProwGetName(row), usecontvars);
5776    SCIPdebug( val = 0; ); /* avoid warning "val might be used uninitialized; see SCIPdebugMessage lastval=%g below */
5777 
5778    if( intscalar != NULL )
5779       *intscalar = SCIP_INVALID;
5780    *success = FALSE;
5781 
5782    /* get minimal absolute non-zero value */
5783    minval = SCIP_REAL_MAX;
5784    for( c = 0; c < row->len; ++c )
5785    {
5786 #ifndef NDEBUG
5787       col = row->cols[c];
5788       assert(col != NULL);
5789       assert(col->var != NULL);
5790       assert(SCIPvarGetStatus(col->var) == SCIP_VARSTATUS_COLUMN);
5791       assert(SCIPvarGetCol(col->var) == col);
5792 #endif
5793       val = row->vals[c];
5794       assert(!SCIPsetIsZero(set, val));
5795 
5796       if( val < mindelta || val > maxdelta )
5797       {
5798          absval = REALABS(val);
5799          minval = MIN(minval, absval);
5800       }
5801    }
5802    if( minval == SCIP_REAL_MAX ) /*lint !e777*/
5803    {
5804       /* all coefficients are zero (inside tolerances) */
5805       if( intscalar != NULL )
5806          *intscalar = 1.0;
5807       *success = TRUE;
5808       SCIPsetDebugMsg(set, " -> all values are zero (inside tolerances)\n");
5809 
5810       return SCIP_OKAY;
5811    }
5812    assert(minval > MIN(-mindelta, maxdelta));
5813    assert(SCIPsetIsPositive(set, minval));
5814    assert(!SCIPsetIsInfinity(set, minval));
5815 
5816    /* try, if row coefficients can be made integral by multiplying them with the reciprocal of the smallest coefficient
5817     * and a power of 2
5818     */
5819    scaleval = 1.0/minval;
5820    scalable = (scaleval <= maxscale);
5821    for( c = 0; c < row->len && scalable; ++c )
5822    {
5823       /* don't look at continuous variables, if we don't have to */
5824       if( !usecontvars && !SCIPcolIsIntegral(row->cols[c]) )
5825          continue;
5826 
5827       /* check, if the coefficient can be scaled with a simple scalar */
5828       val = row->vals[c];
5829       absval = REALABS(val);
5830       while( scaleval <= maxscale
5831          && (absval * scaleval < 0.5 || !isIntegralScalar(val, scaleval, mindelta, maxdelta, NULL)) )
5832       {
5833          for( s = 0; s < nscalars; ++s )
5834          {
5835             if( isIntegralScalar(val, scaleval * scalars[s], mindelta, maxdelta, NULL) )
5836             {
5837                scaleval *= scalars[s];
5838                break;
5839             }
5840          }
5841          if( s >= nscalars )
5842             scaleval *= 2.0;
5843       }
5844       scalable = (scaleval <= maxscale);
5845       SCIPsetDebugMsg(set, " -> val=%g, scaleval=%g, val*scaleval=%g, scalable=%u\n", val, scaleval, val*scaleval, scalable);
5846    }
5847    if( scalable )
5848    {
5849       /* make row coefficients integral by dividing them by the smallest coefficient
5850        * (and multiplying them with a power of 2)
5851        */
5852       assert(scaleval <= maxscale);
5853       if( intscalar != NULL )
5854          *intscalar = scaleval;
5855       *success = TRUE;
5856       SCIPsetDebugMsg(set, " -> integrality can be achieved by scaling with %g (minval=%g)\n", scaleval, minval);
5857 
5858       return SCIP_OKAY;
5859    }
5860 
5861    /* try, if row coefficients can be made integral by multiplying them by a power of 2 */
5862    twomultval = 1.0;
5863    twomult = (twomultval <= maxscale);
5864    for( c = 0; c < row->len && twomult; ++c )
5865    {
5866       /* don't look at continuous variables, if we don't have to */
5867       if( !usecontvars && !SCIPcolIsIntegral(row->cols[c]) )
5868          continue;
5869 
5870       /* check, if the coefficient can be scaled with a simple scalar */
5871       val = row->vals[c];
5872       absval = REALABS(val);
5873       while( twomultval <= maxscale
5874          && (absval * twomultval < 0.5 || !isIntegralScalar(val, twomultval, mindelta, maxdelta, NULL)) )
5875       {
5876          for( s = 0; s < nscalars; ++s )
5877          {
5878             if( isIntegralScalar(val, twomultval * scalars[s], mindelta, maxdelta, NULL) )
5879             {
5880                twomultval *= scalars[s];
5881                break;
5882             }
5883          }
5884          if( s >= nscalars )
5885             twomultval *= 2.0;
5886       }
5887       twomult = (twomultval <= maxscale);
5888       SCIPsetDebugMsg(set, " -> val=%g, twomult=%g, val*twomult=%g, twomultable=%u\n",
5889          val, twomultval, val*twomultval, twomult);
5890    }
5891    if( twomult )
5892    {
5893       /* make row coefficients integral by multiplying them with a power of 2 */
5894       assert(twomultval <= maxscale);
5895       if( intscalar != NULL )
5896          *intscalar = twomultval;
5897       *success = TRUE;
5898       SCIPsetDebugMsg(set, " -> integrality can be achieved by scaling with %g (power of 2)\n", twomultval);
5899 
5900       return SCIP_OKAY;
5901    }
5902 
5903    /* convert each coefficient into a rational number, calculate the greatest common divisor of the numerators
5904     * and the smallest common multiple of the denominators
5905     */
5906    gcd = 1;
5907    scm = 1;
5908    rational = (maxdnom > 1);
5909 
5910    /* first coefficient (to initialize gcd) */
5911    for( c = 0; c < row->len && rational; ++c )
5912    {
5913       if( usecontvars || SCIPcolIsIntegral(row->cols[c]) )
5914       {
5915          val = row->vals[c];
5916          rational = SCIPrealToRational(val, mindelta, maxdelta, maxdnom, &nominator, &denominator);
5917          if( rational && nominator != 0 )
5918          {
5919             assert(denominator > 0);
5920             gcd = ABS(nominator);
5921             scm = denominator;
5922             rational = ((SCIP_Real)scm/(SCIP_Real)gcd <= maxscale);
5923             SCIPsetDebugMsg(set, " -> first rational: val: %g == %" SCIP_LONGINT_FORMAT "/%" SCIP_LONGINT_FORMAT ", gcd=%" SCIP_LONGINT_FORMAT ", scm=%" SCIP_LONGINT_FORMAT ", rational=%u\n",
5924                val, nominator, denominator, gcd, scm, rational);
5925             break;
5926          }
5927       }
5928    }
5929 
5930    /* remaining coefficients */
5931    for( ++c; c < row->len && rational; ++c )
5932    {
5933       if( usecontvars || SCIPcolIsIntegral(row->cols[c]) )
5934       {
5935          val = row->vals[c];
5936          rational = SCIPrealToRational(val, mindelta, maxdelta, maxdnom, &nominator, &denominator);
5937          if( rational && nominator != 0 )
5938          {
5939             assert(denominator > 0);
5940             gcd = SCIPcalcGreComDiv(gcd, ABS(nominator));
5941             scm *= denominator / SCIPcalcGreComDiv(scm, denominator);
5942             rational = ((SCIP_Real)scm/(SCIP_Real)gcd <= maxscale);
5943             SCIPsetDebugMsg(set, " -> next rational : val: %g == %" SCIP_LONGINT_FORMAT "/%" SCIP_LONGINT_FORMAT ", gcd=%" SCIP_LONGINT_FORMAT ", scm=%" SCIP_LONGINT_FORMAT ", rational=%u\n",
5944                val, nominator, denominator, gcd, scm, rational);
5945          }
5946       }
5947    }
5948 
5949    if( rational )
5950    {
5951       /* make row coefficients integral by multiplying them with the smallest common multiple of the denominators */
5952       assert((SCIP_Real)scm/(SCIP_Real)gcd <= maxscale);
5953       if( intscalar != NULL )
5954          *intscalar = (SCIP_Real)scm/(SCIP_Real)gcd;
5955       *success = TRUE;
5956       SCIPsetDebugMsg(set, " -> integrality can be achieved by scaling with %g (rational:%" SCIP_LONGINT_FORMAT "/%" SCIP_LONGINT_FORMAT ")\n",
5957          (SCIP_Real)scm/(SCIP_Real)gcd, scm, gcd);
5958    }
5959    else
5960    {
5961       assert(!(*success));
5962       SCIPsetDebugMsg(set, " -> rationalizing failed: gcd=%" SCIP_LONGINT_FORMAT ", scm=%" SCIP_LONGINT_FORMAT ", lastval=%g\n", gcd, scm, val); /*lint !e771*/
5963    }
5964 
5965    return SCIP_OKAY;
5966 }
5967 
5968 /** tries to scale row, s.t. all coefficients become integral */
SCIProwMakeIntegral(SCIP_ROW * row,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_STAT * stat,SCIP_LP * lp,SCIP_Real mindelta,SCIP_Real maxdelta,SCIP_Longint maxdnom,SCIP_Real maxscale,SCIP_Bool usecontvars,SCIP_Bool * success)5969 SCIP_RETCODE SCIProwMakeIntegral(
5970    SCIP_ROW*             row,                /**< LP row */
5971    BMS_BLKMEM*           blkmem,             /**< block memory */
5972    SCIP_SET*             set,                /**< global SCIP settings */
5973    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
5974    SCIP_STAT*            stat,               /**< problem statistics */
5975    SCIP_LP*              lp,                 /**< current LP data */
5976    SCIP_Real             mindelta,           /**< minimal relative allowed difference of scaled coefficient s*c and integral i */
5977    SCIP_Real             maxdelta,           /**< maximal relative allowed difference of scaled coefficient s*c and integral i */
5978    SCIP_Longint          maxdnom,            /**< maximal denominator allowed in rational numbers */
5979    SCIP_Real             maxscale,           /**< maximal value to scale row with */
5980    SCIP_Bool             usecontvars,        /**< should the coefficients of the continuous variables also be made integral? */
5981    SCIP_Bool*            success             /**< stores whether row could be made rational */
5982    )
5983 {
5984    SCIP_Real intscalar;
5985 
5986    assert(success != NULL);
5987 
5988    /* calculate scalar to make coefficients integral */
5989    SCIP_CALL( SCIProwCalcIntegralScalar(row, set, mindelta, maxdelta, maxdnom, maxscale, usecontvars,
5990          &intscalar, success) );
5991 
5992    if( *success )
5993    {
5994       /* scale the row */
5995       SCIP_CALL( rowScale(row, blkmem, set, eventqueue, stat, lp, intscalar, usecontvars, mindelta, maxdelta) );
5996    }
5997 
5998    return SCIP_OKAY;
5999 }
6000 
6001 /** sorts row entries such that LP columns precede non-LP columns and inside both parts lower column indices precede
6002  *  higher ones
6003  */
SCIProwSort(SCIP_ROW * row)6004 void SCIProwSort(
6005    SCIP_ROW*             row                 /**< row to be sorted */
6006    )
6007 {
6008    assert(row != NULL);
6009 
6010    /* sort LP columns */
6011    rowSortLP(row);
6012 
6013    /* sort non-LP columns */
6014    rowSortNonLP(row);
6015 
6016 #ifdef SCIP_MORE_DEBUG
6017    /* check the sorting */
6018    {
6019       int c;
6020       if( !row->delaysort )
6021       {
6022          for( c = 1; c < row->nlpcols; ++c )
6023             assert(row->cols[c]->index >= row->cols[c-1]->index);
6024          for( c = row->nlpcols + 1; c < row->len; ++c )
6025             assert(row->cols[c]->index >= row->cols[c-1]->index);
6026       }
6027    }
6028 #endif
6029 }
6030 
6031 /** sorts row, and merges equal column entries (resulting from lazy sorting and adding) into a single entry; removes
6032  *  zero entries from row
6033  *  the row must not be linked to the columns; otherwise, we would need to update the columns as
6034  *  well, which is too expensive
6035  */
6036 static
rowMerge(SCIP_ROW * row,SCIP_SET * set)6037 void rowMerge(
6038    SCIP_ROW*             row,                /**< row to be sorted */
6039    SCIP_SET*             set                 /**< global SCIP settings */
6040    )
6041 {
6042    assert(row != NULL);
6043    assert(!row->delaysort);
6044    assert(row->nunlinked == row->len);
6045    assert(row->nlpcols == 0);
6046 
6047    SCIPsetDebugMsg(set, "merging row <%s>\n", row->name);
6048 
6049    /* do nothing on empty rows; if row is sorted, nothing has to be done */
6050    if( row->len > 0 && (!row->lpcolssorted || !row->nonlpcolssorted) )
6051    {
6052       SCIP_COL** cols;
6053       int* cols_index;
6054       SCIP_Real* vals;
6055       int s;
6056       int t;
6057 
6058       /* make sure, the row is sorted */
6059       SCIProwSort(row);
6060       assert(row->lpcolssorted);
6061       assert(row->nonlpcolssorted);
6062 
6063       /* merge equal columns, thereby recalculating whether the row's activity is always integral */
6064       cols = row->cols;
6065       cols_index = row->cols_index;
6066       vals = row->vals;
6067       assert(cols != NULL);
6068       assert(cols_index != NULL);
6069       assert(vals != NULL);
6070 
6071       t = 0;
6072       row->integral = TRUE;
6073       assert(!SCIPsetIsZero(set, vals[0]));
6074       assert(row->linkpos[0] == -1);
6075 
6076       for( s = 1; s < row->len; ++s )
6077       {
6078          assert(!SCIPsetIsZero(set, vals[s]));
6079          assert(row->linkpos[s] == -1);
6080 
6081          if( cols[s] == cols[t] )
6082          {
6083             /* merge entries with equal column */
6084             vals[t] += vals[s];
6085          }
6086          else
6087          {
6088             /* go to the next entry, overwriting current entry if coefficient is zero */
6089             if( !SCIPsetIsZero(set, vals[t]) )
6090             {
6091                /* in case the coefficient is integral w.r.t. numerics we explicitly round the coefficient to an integral value */
6092                vals[t] = SCIPsetIsIntegral(set, vals[t]) ? SCIPsetRound(set, vals[t]) : vals[t];
6093 
6094                row->integral = row->integral && SCIPcolIsIntegral(cols[t]) && SCIPsetIsIntegral(set, vals[t]);
6095                t++;
6096             }
6097             cols[t] = cols[s];
6098             cols_index[t] = cols_index[s];
6099             vals[t] = vals[s];
6100          }
6101       }
6102       if( !SCIPsetIsZero(set, vals[t]) )
6103       {
6104          row->integral = row->integral && SCIPcolIsIntegral(cols[t]) && SCIPsetIsIntegral(set, vals[t]);
6105          t++;
6106       }
6107       assert(s == row->len);
6108       assert(t <= row->len);
6109 
6110       row->len = t;
6111       row->nunlinked = t;
6112 
6113       /* if equal entries were merged, we have to recalculate the norms, since the squared Euclidean norm is wrong */
6114       if( t < s )
6115          rowCalcNorms(row, set);
6116    }
6117 
6118 #ifndef NDEBUG
6119    /* check for double entries */
6120    {
6121       int i;
6122       int j;
6123 
6124       for( i = 0; i < row->len; ++i )
6125       {
6126          assert(row->cols[i] != NULL);
6127          assert(row->cols[i]->index == row->cols_index[i]);
6128          for( j = i+1; j < row->len; ++j )
6129             assert(row->cols[i] != row->cols[j]);
6130       }
6131    }
6132 #endif
6133 }
6134 
6135 /** enables delaying of row sorting */
SCIProwDelaySort(SCIP_ROW * row)6136 void SCIProwDelaySort(
6137    SCIP_ROW*             row                 /**< LP row */
6138    )
6139 {
6140    assert(row != NULL);
6141    assert(!row->delaysort);
6142 
6143    row->delaysort = TRUE;
6144 }
6145 
6146 /** disables delaying of row sorting, sorts row and merges coefficients with equal columns */
SCIProwForceSort(SCIP_ROW * row,SCIP_SET * set)6147 void SCIProwForceSort(
6148    SCIP_ROW*             row,                /**< LP row */
6149    SCIP_SET*             set                 /**< global SCIP settings */
6150    )
6151 {
6152    assert(row != NULL);
6153    assert(row->delaysort);
6154 
6155    row->delaysort = FALSE;
6156    rowMerge(row, set);
6157 }
6158 
6159 /** recalculates the current activity of a row */
SCIProwRecalcLPActivity(SCIP_ROW * row,SCIP_STAT * stat)6160 void SCIProwRecalcLPActivity(
6161    SCIP_ROW*             row,                /**< LP row */
6162    SCIP_STAT*            stat                /**< problem statistics */
6163    )
6164 {
6165    SCIP_COL* col;
6166    int c;
6167 
6168    assert(row != NULL);
6169    assert(stat != NULL);
6170 
6171    row->activity = row->constant;
6172    for( c = 0; c < row->nlpcols; ++c )
6173    {
6174       col = row->cols[c];
6175       assert(col != NULL);
6176       assert(col->primsol < SCIP_INVALID);
6177       assert(col->lppos >= 0);
6178       assert(row->linkpos[c] >= 0);
6179       row->activity += row->vals[c] * col->primsol;
6180    }
6181 
6182    if( row->nunlinked > 0 )
6183    {
6184       for( c = row->nlpcols; c < row->len; ++c )
6185       {
6186          col = row->cols[c];
6187          assert(col != NULL);
6188          assert(col->lppos >= 0 || col->primsol == 0.0);
6189          assert(col->lppos == -1 || row->linkpos[c] == -1);
6190          if( col->lppos >= 0 )
6191             row->activity += row->vals[c] * col->primsol;
6192       }
6193    }
6194 #ifndef NDEBUG
6195    else
6196    {
6197       for( c = row->nlpcols; c < row->len; ++c )
6198       {
6199          col = row->cols[c];
6200          assert(col != NULL);
6201          assert(col->primsol == 0.0);
6202          assert(col->lppos == -1);
6203          assert(row->linkpos[c] >= 0);
6204       }
6205    }
6206 #endif
6207 
6208    row->validactivitylp = stat->lpcount;
6209 }
6210 
6211 /** returns the activity of a row in the current LP solution */
SCIProwGetLPActivity(SCIP_ROW * row,SCIP_SET * set,SCIP_STAT * stat,SCIP_LP * lp)6212 SCIP_Real SCIProwGetLPActivity(
6213    SCIP_ROW*             row,                /**< LP row */
6214    SCIP_SET*             set,                /**< global SCIP settings */
6215    SCIP_STAT*            stat,               /**< problem statistics */
6216    SCIP_LP*              lp                  /**< current LP data */
6217    )
6218 {
6219    SCIP_Real inf;
6220    SCIP_Real activity;
6221 
6222    assert(row != NULL);
6223    assert(stat != NULL);
6224    assert(lp != NULL);
6225    assert(row->validactivitylp <= stat->lpcount);
6226    assert(lp->validsollp == stat->lpcount);
6227 
6228    if( row->validactivitylp != stat->lpcount )
6229       SCIProwRecalcLPActivity(row, stat);
6230    assert(row->validactivitylp == stat->lpcount);
6231    assert(row->activity < SCIP_INVALID);
6232 
6233    activity = row->activity;
6234    inf = SCIPsetInfinity(set);
6235    activity = MAX(activity, -inf);
6236    activity = MIN(activity, +inf);
6237 
6238    return activity;
6239 }
6240 
6241 /** returns the feasibility of a row in the current LP solution: negative value means infeasibility */
SCIProwGetLPFeasibility(SCIP_ROW * row,SCIP_SET * set,SCIP_STAT * stat,SCIP_LP * lp)6242 SCIP_Real SCIProwGetLPFeasibility(
6243    SCIP_ROW*             row,                /**< LP row */
6244    SCIP_SET*             set,                /**< global SCIP settings */
6245    SCIP_STAT*            stat,               /**< problem statistics */
6246    SCIP_LP*              lp                  /**< current LP data */
6247    )
6248 {
6249    SCIP_Real activity;
6250 
6251    assert(row != NULL);
6252 
6253    activity = SCIProwGetLPActivity(row, set, stat, lp);
6254 
6255    return MIN(row->rhs - activity, activity - row->lhs);
6256 }
6257 
6258 /** returns the feasibility of a row in the relaxed solution solution: negative value means infeasibility
6259  *
6260  *  @todo Implement calculation of activities similar to LPs.
6261  */
SCIProwGetRelaxFeasibility(SCIP_ROW * row,SCIP_SET * set,SCIP_STAT * stat)6262 SCIP_Real SCIProwGetRelaxFeasibility(
6263    SCIP_ROW*             row,                /**< LP row */
6264    SCIP_SET*             set,                /**< global SCIP settings */
6265    SCIP_STAT*            stat                /**< problem statistics */
6266    )
6267 {
6268    SCIP_Real inf;
6269    SCIP_Real activity;
6270    SCIP_COL* col;
6271    int c;
6272 
6273    assert( row != NULL );
6274    assert( stat != NULL );
6275 
6276    activity = row->constant;
6277    for (c = 0; c < row->nlpcols; ++c)
6278    {
6279       col = row->cols[c];
6280       assert( col != NULL );
6281       assert( col->lppos >= 0 );
6282       assert( col->var != NULL );
6283       assert( row->linkpos[c] >= 0 );
6284       activity += row->vals[c] * SCIPvarGetRelaxSol(col->var, set);
6285    }
6286 
6287    if ( row->nunlinked > 0 )
6288    {
6289       for (c = row->nlpcols; c < row->len; ++c)
6290       {
6291          col = row->cols[c];
6292          assert( col != NULL );
6293          assert( col->lppos == -1 || row->linkpos[c] == -1 );
6294          if ( col->lppos >= 0 )
6295          {
6296             assert( col->var != NULL );
6297             activity += row->vals[c] * SCIPvarGetRelaxSol(col->var, set);
6298          }
6299       }
6300    }
6301 #ifndef NDEBUG
6302    else
6303    {
6304       for (c = row->nlpcols; c < row->len; ++c)
6305       {
6306          col = row->cols[c];
6307          assert( col != NULL );
6308          assert( col->lppos == -1 );
6309          assert( row->linkpos[c] >= 0 );
6310       }
6311    }
6312 #endif
6313    inf = SCIPsetInfinity(set);
6314    activity = MAX(activity, -inf);
6315    activity = MIN(activity, +inf);
6316 
6317    return MIN(row->rhs - activity, activity - row->lhs);
6318 }
6319 
6320 /** returns the feasibility of a row in the current NLP solution: negative value means infeasibility
6321  *
6322  *  @todo Implement calculation of activities similar to LPs.
6323  */
SCIProwGetNLPFeasibility(SCIP_ROW * row,SCIP_SET * set,SCIP_STAT * stat)6324 SCIP_Real SCIProwGetNLPFeasibility(
6325    SCIP_ROW*             row,                /**< LP row */
6326    SCIP_SET*             set,                /**< global SCIP settings */
6327    SCIP_STAT*            stat                /**< problem statistics */
6328    )
6329 {
6330    SCIP_Real inf;
6331    SCIP_Real activity;
6332    SCIP_COL* col;
6333    int c;
6334 
6335    assert( row != NULL );
6336    assert( stat != NULL );
6337 
6338    activity = row->constant;
6339    for (c = 0; c < row->nlpcols; ++c)
6340    {
6341       col = row->cols[c];
6342       assert( col != NULL );
6343       assert( col->lppos >= 0 );
6344       assert( col->var != NULL );
6345       assert( row->linkpos[c] >= 0 );
6346       activity += row->vals[c] * SCIPvarGetNLPSol(col->var);
6347    }
6348 
6349    if ( row->nunlinked > 0 )
6350    {
6351       for (c = row->nlpcols; c < row->len; ++c)
6352       {
6353          col = row->cols[c];
6354          assert( col != NULL );
6355          assert( col->lppos == -1 || row->linkpos[c] == -1 );
6356          if ( col->lppos >= 0 )
6357          {
6358             assert( col->var != NULL );
6359             activity += row->vals[c] * SCIPvarGetNLPSol(col->var);
6360          }
6361       }
6362    }
6363 #ifndef NDEBUG
6364    else
6365    {
6366       for (c = row->nlpcols; c < row->len; ++c)
6367       {
6368          col = row->cols[c];
6369          assert( col != NULL );
6370          assert( col->lppos == -1 );
6371          assert( row->linkpos[c] >= 0 );
6372       }
6373    }
6374 #endif
6375    inf = SCIPsetInfinity(set);
6376    activity = MAX(activity, -inf);
6377    activity = MIN(activity, +inf);
6378 
6379    return MIN(row->rhs - activity, activity - row->lhs);
6380 }
6381 
6382 /** calculates the current pseudo activity of a row */
SCIProwRecalcPseudoActivity(SCIP_ROW * row,SCIP_STAT * stat)6383 void SCIProwRecalcPseudoActivity(
6384    SCIP_ROW*             row,                /**< row data */
6385    SCIP_STAT*            stat                /**< problem statistics */
6386    )
6387 {
6388    SCIP_COL* col;
6389    int i;
6390 
6391    assert(row != NULL);
6392    assert(stat != NULL);
6393 
6394    row->pseudoactivity = row->constant;
6395    for( i = 0; i < row->len; ++i )
6396    {
6397       col = row->cols[i];
6398       assert(col != NULL);
6399       assert((i < row->nlpcols) == (row->linkpos[i] >= 0 && col->lppos >= 0));
6400       assert(col->var != NULL);
6401       assert(SCIPvarGetStatus(col->var) == SCIP_VARSTATUS_COLUMN);
6402 
6403       row->pseudoactivity += SCIPcolGetBestBound(col) * row->vals[i];
6404    }
6405    row->validpsactivitydomchg = stat->domchgcount;
6406    assert(!row->integral || EPSISINT(row->pseudoactivity - row->constant, SCIP_DEFAULT_SUMEPSILON));
6407 }
6408 
6409 /** returns the pseudo activity of a row in the current pseudo solution */
SCIProwGetPseudoActivity(SCIP_ROW * row,SCIP_SET * set,SCIP_STAT * stat)6410 SCIP_Real SCIProwGetPseudoActivity(
6411    SCIP_ROW*             row,                /**< LP row */
6412    SCIP_SET*             set,                /**< global SCIP settings */
6413    SCIP_STAT*            stat                /**< problem statistics */
6414    )
6415 {
6416    SCIP_Real inf;
6417    SCIP_Real activity;
6418 
6419    assert(row != NULL);
6420    assert(stat != NULL);
6421    assert(row->validpsactivitydomchg <= stat->domchgcount);
6422 
6423    /* check, if pseudo activity has to be calculated */
6424    if( row->validpsactivitydomchg != stat->domchgcount )
6425       SCIProwRecalcPseudoActivity(row, stat);
6426    assert(row->validpsactivitydomchg == stat->domchgcount);
6427    assert(row->pseudoactivity < SCIP_INVALID);
6428 
6429    activity = row->pseudoactivity;
6430    inf = SCIPsetInfinity(set);
6431    activity = MAX(activity, -inf);
6432    activity = MIN(activity, +inf);
6433 
6434    return activity;
6435 }
6436 
6437 /** returns the pseudo feasibility of a row in the current pseudo solution: negative value means infeasibility */
SCIProwGetPseudoFeasibility(SCIP_ROW * row,SCIP_SET * set,SCIP_STAT * stat)6438 SCIP_Real SCIProwGetPseudoFeasibility(
6439    SCIP_ROW*             row,                /**< LP row */
6440    SCIP_SET*             set,                /**< global SCIP settings */
6441    SCIP_STAT*            stat                /**< problem statistics */
6442    )
6443 {
6444    SCIP_Real pseudoactivity;
6445 
6446    assert(row != NULL);
6447 
6448    pseudoactivity = SCIProwGetPseudoActivity(row, set, stat);
6449 
6450    return MIN(row->rhs - pseudoactivity, pseudoactivity - row->lhs);
6451 }
6452 
6453 /** returns the activity of a row for a given solution */
SCIProwGetSolActivity(SCIP_ROW * row,SCIP_SET * set,SCIP_STAT * stat,SCIP_SOL * sol)6454 SCIP_Real SCIProwGetSolActivity(
6455    SCIP_ROW*             row,                /**< LP row */
6456    SCIP_SET*             set,                /**< global SCIP settings */
6457    SCIP_STAT*            stat,               /**< problem statistics data */
6458    SCIP_SOL*             sol                 /**< primal CIP solution */
6459    )
6460 {
6461    SCIP_COL* col;
6462    SCIP_Real inf;
6463    SCIP_Real activity;
6464    SCIP_Real solval;
6465    int i;
6466 
6467    assert(row != NULL);
6468 
6469    activity = row->constant;
6470    for( i = 0; i < row->len; ++i )
6471    {
6472       col = row->cols[i];
6473       assert(col != NULL);
6474       assert((i < row->nlpcols) == (row->linkpos[i] >= 0 && col->lppos >= 0));
6475       solval = SCIPsolGetVal(sol, set, stat, col->var);
6476       if( solval == SCIP_UNKNOWN ) /*lint !e777*/
6477       {
6478          if( SCIPsetIsInfinity(set, -row->lhs) )
6479             solval = (row->vals[i] >= 0.0 ? col->lb : col->ub);
6480          else if( SCIPsetIsInfinity(set, row->rhs) )
6481             solval = (row->vals[i] >= 0.0 ? col->ub : col->lb);
6482          else
6483             solval = (col->lb + col->ub)/2.0;
6484       }
6485       activity += row->vals[i] * solval;
6486    }
6487 
6488    inf = SCIPsetInfinity(set);
6489    activity = MAX(activity, -inf);
6490    activity = MIN(activity, +inf);
6491 
6492    return activity;
6493 }
6494 
6495 /** returns the feasibility of a row for the given solution */
SCIProwGetSolFeasibility(SCIP_ROW * row,SCIP_SET * set,SCIP_STAT * stat,SCIP_SOL * sol)6496 SCIP_Real SCIProwGetSolFeasibility(
6497    SCIP_ROW*             row,                /**< LP row */
6498    SCIP_SET*             set,                /**< global SCIP settings */
6499    SCIP_STAT*            stat,               /**< problem statistics data */
6500    SCIP_SOL*             sol                 /**< primal CIP solution */
6501    )
6502 {
6503    SCIP_Real activity;
6504 
6505    assert(row != NULL);
6506 
6507    activity = SCIProwGetSolActivity(row, set, stat, sol);
6508 
6509    return MIN(row->rhs - activity, activity - row->lhs);
6510 }
6511 
6512 /** calculates minimal and maximal activity of row w.r.t. the column's bounds */
6513 static
rowCalcActivityBounds(SCIP_ROW * row,SCIP_SET * set,SCIP_STAT * stat)6514 void rowCalcActivityBounds(
6515    SCIP_ROW*             row,                /**< row data */
6516    SCIP_SET*             set,                /**< global SCIP settings */
6517    SCIP_STAT*            stat                /**< problem statistics data */
6518    )
6519 {
6520    SCIP_COL* col;
6521    SCIP_Real val;
6522    SCIP_Bool mininfinite;
6523    SCIP_Bool maxinfinite;
6524    int i;
6525 
6526    assert(row != NULL);
6527    assert(!SCIPsetIsInfinity(set, REALABS(row->constant)));
6528    assert(stat != NULL);
6529 
6530    /* calculate activity bounds */
6531    mininfinite = FALSE;
6532    maxinfinite = FALSE;
6533    row->minactivity = row->constant;
6534    row->maxactivity = row->constant;
6535    for( i = 0; i < row->len && (!mininfinite || !maxinfinite); ++i )
6536    {
6537       col = row->cols[i];
6538       assert(col != NULL);
6539       assert((i < row->nlpcols) == (row->linkpos[i] >= 0 && col->lppos >= 0));
6540       val = row->vals[i];
6541       if( val >= 0.0 )
6542       {
6543          mininfinite = mininfinite || SCIPsetIsInfinity(set, -col->lb);
6544          maxinfinite = maxinfinite || SCIPsetIsInfinity(set, col->ub);
6545          if( !mininfinite )
6546             row->minactivity += val * col->lb;
6547          if( !maxinfinite )
6548             row->maxactivity += val * col->ub;
6549       }
6550       else
6551       {
6552          mininfinite = mininfinite || SCIPsetIsInfinity(set, col->ub);
6553          maxinfinite = maxinfinite || SCIPsetIsInfinity(set, -col->lb);
6554          if( !mininfinite )
6555             row->minactivity += val * col->ub;
6556          if( !maxinfinite )
6557             row->maxactivity += val * col->lb;
6558       }
6559    }
6560 
6561    if( mininfinite )
6562       row->minactivity = -SCIPsetInfinity(set);
6563    if( maxinfinite )
6564       row->maxactivity = SCIPsetInfinity(set);
6565    row->validactivitybdsdomchg = stat->domchgcount;
6566 
6567 #ifndef NDEBUG
6568    {
6569       SCIP_Real inttol = 1000.0*SCIPsetFeastol(set);
6570 
6571       /* even if the row is integral, the bounds on the variables used for computing minimum and maximum activity might
6572        * be integral only within feasibility tolerance; this can happen, e.g., if a continuous variable is promoted to
6573        * an (implicit) integer variable and the bounds cannot be adjusted because they are minimally tighter than the
6574        * rounded bound value; hence, the activity may violate integrality; we allow 1000 times the default feasibility
6575        * tolerance as a proxy to account for the accumulation effect
6576        */
6577       assert(!row->integral || mininfinite || REALABS(row->minactivity - row->constant) > 1.0/SCIPsetSumepsilon(set)
6578          || EPSISINT(row->minactivity - row->constant, inttol));
6579       assert(!row->integral || maxinfinite || REALABS(row->maxactivity - row->constant) > 1.0/SCIPsetSumepsilon(set)
6580          || EPSISINT(row->maxactivity - row->constant, inttol));
6581    }
6582 #endif
6583 }
6584 
6585 /** returns the minimal activity of a row w.r.t. the columns' bounds */
SCIProwGetMinActivity(SCIP_ROW * row,SCIP_SET * set,SCIP_STAT * stat)6586 SCIP_Real SCIProwGetMinActivity(
6587    SCIP_ROW*             row,                /**< LP row */
6588    SCIP_SET*             set,                /**< global SCIP settings */
6589    SCIP_STAT*            stat                /**< problem statistics data */
6590    )
6591 {
6592    assert(row != NULL);
6593    assert(stat != NULL);
6594    assert(row->validactivitybdsdomchg <= stat->domchgcount);
6595 
6596    /* check, if activity bounds has to be calculated */
6597    if( row->validactivitybdsdomchg != stat->domchgcount )
6598       rowCalcActivityBounds(row, set, stat);
6599    assert(row->validactivitybdsdomchg == stat->domchgcount);
6600    assert(row->minactivity < SCIP_INVALID);
6601    assert(row->maxactivity < SCIP_INVALID);
6602 
6603    return row->minactivity;
6604 }
6605 
6606 /** returns the maximal activity of a row w.r.t. the columns' bounds */
SCIProwGetMaxActivity(SCIP_ROW * row,SCIP_SET * set,SCIP_STAT * stat)6607 SCIP_Real SCIProwGetMaxActivity(
6608    SCIP_ROW*             row,                /**< LP row */
6609    SCIP_SET*             set,                /**< global SCIP settings */
6610    SCIP_STAT*            stat                /**< problem statistics data */
6611    )
6612 {
6613    assert(row != NULL);
6614    assert(stat != NULL);
6615    assert(row->validactivitybdsdomchg <= stat->domchgcount);
6616 
6617    /* check, if activity bounds has to be calculated */
6618    if( row->validactivitybdsdomchg != stat->domchgcount )
6619       rowCalcActivityBounds(row, set, stat);
6620    assert(row->validactivitybdsdomchg == stat->domchgcount);
6621    assert(row->minactivity < SCIP_INVALID);
6622    assert(row->maxactivity < SCIP_INVALID);
6623 
6624    return row->maxactivity;
6625 }
6626 
6627 /** returns whether the row is unmodifiable and redundant w.r.t. the columns' bounds */
SCIProwIsRedundant(SCIP_ROW * row,SCIP_SET * set,SCIP_STAT * stat)6628 SCIP_Bool SCIProwIsRedundant(
6629    SCIP_ROW*             row,                /**< LP row */
6630    SCIP_SET*             set,                /**< global SCIP settings */
6631    SCIP_STAT*            stat                /**< problem statistics data */
6632    )
6633 {
6634    assert(row != NULL);
6635 
6636    if( row->modifiable )
6637       return FALSE;
6638    if( !SCIPsetIsInfinity(set, -row->lhs) )
6639    {
6640       SCIP_Real minactivity;
6641 
6642       minactivity = SCIProwGetMinActivity(row, set, stat);
6643       if( SCIPsetIsFeasLT(set, minactivity, row->lhs) )
6644          return FALSE;
6645    }
6646    if( !SCIPsetIsInfinity(set, row->rhs) )
6647    {
6648       SCIP_Real maxactivity;
6649 
6650       maxactivity = SCIProwGetMaxActivity(row, set, stat);
6651       if( SCIPsetIsFeasGT(set, maxactivity, row->rhs) )
6652          return FALSE;
6653    }
6654 
6655    return TRUE;
6656 }
6657 
6658 /** gets maximal absolute value of row vector coefficients */
SCIProwGetMaxval(SCIP_ROW * row,SCIP_SET * set)6659 SCIP_Real SCIProwGetMaxval(
6660    SCIP_ROW*             row,                /**< LP row */
6661    SCIP_SET*             set                 /**< global SCIP settings */
6662    )
6663 {
6664    assert(row != NULL);
6665 
6666    if( row->nummaxval == 0 )
6667       rowCalcIdxsAndVals(row, set);
6668    assert(row->nummaxval > 0);
6669    assert(row->maxval >= 0.0 || row->len == 0);
6670 
6671    return row->maxval;
6672 }
6673 
6674 /** gets minimal absolute value of row vector's non-zero coefficients */
SCIProwGetMinval(SCIP_ROW * row,SCIP_SET * set)6675 SCIP_Real SCIProwGetMinval(
6676    SCIP_ROW*             row,                /**< LP row */
6677    SCIP_SET*             set                 /**< global SCIP settings */
6678    )
6679 {
6680    assert(row != NULL);
6681 
6682    if( row->numminval == 0 )
6683       rowCalcIdxsAndVals(row, set);
6684    assert(row->numminval > 0);
6685    assert(row->minval >= 0.0 || row->len == 0);
6686 
6687    return row->minval;
6688 }
6689 
6690 /** gets maximal column index of row entries */
SCIProwGetMaxidx(SCIP_ROW * row,SCIP_SET * set)6691 int SCIProwGetMaxidx(
6692    SCIP_ROW*             row,                /**< LP row */
6693    SCIP_SET*             set                 /**< global SCIP settings */
6694    )
6695 {
6696    assert(row != NULL);
6697 
6698    if( row->validminmaxidx == 0 )
6699       rowCalcIdxsAndVals(row, set);
6700    assert(row->maxidx >= 0 || row->len == 0);
6701    assert(row->validminmaxidx);
6702 
6703    return row->maxidx;
6704 }
6705 
6706 /** gets minimal column index of row entries */
SCIProwGetMinidx(SCIP_ROW * row,SCIP_SET * set)6707 int SCIProwGetMinidx(
6708    SCIP_ROW*             row,                /**< LP row */
6709    SCIP_SET*             set                 /**< global SCIP settings */
6710    )
6711 {
6712    assert(row != NULL);
6713 
6714    if( row->validminmaxidx == 0 )
6715       rowCalcIdxsAndVals(row, set);
6716    assert(row->minidx >= 0 || row->len == 0);
6717    assert(row->validminmaxidx);
6718 
6719    return row->minidx;
6720 }
6721 
6722 /** gets number of integral columns in row */
SCIProwGetNumIntCols(SCIP_ROW * row,SCIP_SET * set)6723 int SCIProwGetNumIntCols(
6724    SCIP_ROW*             row,                /**< LP row */
6725    SCIP_SET*             set                 /**< global SCIP settings */
6726    )
6727 {
6728    assert(row != NULL);
6729 
6730    if( row->numintcols == -1 )
6731       rowCalcIdxsAndVals(row, set);
6732 
6733    assert(row->numintcols <= row->len && row->numintcols >= 0);
6734 
6735    return row->numintcols;
6736 }
6737 
6738 /** returns row's cutoff distance in the direction of the given primal solution */
SCIProwGetLPSolCutoffDistance(SCIP_ROW * row,SCIP_SET * set,SCIP_STAT * stat,SCIP_SOL * sol,SCIP_LP * lp)6739 SCIP_Real SCIProwGetLPSolCutoffDistance(
6740    SCIP_ROW*             row,                /**< LP row */
6741    SCIP_SET*             set,                /**< global SCIP settings */
6742    SCIP_STAT*            stat,               /**< problem statistics data */
6743    SCIP_SOL*             sol,                /**< solution to compute direction for cutoff distance; must not be NULL */
6744    SCIP_LP*              lp                  /**< current LP data */
6745    )
6746 {
6747    SCIP_Real solcutoffdist;
6748    int k;
6749 
6750    assert(sol != NULL);
6751 
6752    if( lp->validsoldirlp != stat->lpcount || lp->validsoldirsol != sol )
6753    {
6754       SCIP_Real scale = 0.0;
6755 
6756       lp->validsoldirlp = stat->lpcount;
6757       lp->validsoldirsol = sol;
6758 
6759       SCIP_CALL_ABORT( ensureSoldirectionSize(lp, lp->ncols) );
6760 
6761       for( k = 0; k < lp->ncols; ++k )
6762       {
6763          assert(lp->cols[k]->lppos == k);
6764          lp->soldirection[k] = SCIPsolGetVal(sol, set, stat, lp->cols[k]->var) - lp->cols[k]->primsol;
6765          scale += SQR(lp->soldirection[k]);
6766       }
6767 
6768       if( scale > 0.0 )
6769       {
6770          scale = 1.0 / SQRT(scale);
6771 
6772          for( k = 0; k < lp->ncols; ++k )
6773             lp->soldirection[k] *= scale;
6774       }
6775    }
6776 
6777    solcutoffdist = 0.0;
6778    for( k = 0; k < row->nlpcols; ++k )
6779       solcutoffdist += row->vals[k] * lp->soldirection[row->cols[k]->lppos];
6780 
6781    for( k = row->nlpcols; k < row->len; ++k )
6782    {
6783       if( row->cols[k]->lppos >= 0 )
6784          solcutoffdist += row->vals[k] * lp->soldirection[row->cols[k]->lppos];
6785    }
6786 
6787    if( SCIPsetIsSumZero(set, solcutoffdist) )
6788       solcutoffdist = set->num_sumepsilon;
6789 
6790    solcutoffdist = -SCIProwGetLPFeasibility(row, set, stat, lp) / ABS(solcutoffdist); /*lint !e795*/
6791 
6792    return solcutoffdist;
6793 }
6794 
6795 /** returns row's efficacy with respect to the current LP solution: e = -feasibility/norm */
SCIProwGetLPEfficacy(SCIP_ROW * row,SCIP_SET * set,SCIP_STAT * stat,SCIP_LP * lp)6796 SCIP_Real SCIProwGetLPEfficacy(
6797    SCIP_ROW*             row,                /**< LP row */
6798    SCIP_SET*             set,                /**< global SCIP settings */
6799    SCIP_STAT*            stat,               /**< problem statistics data */
6800    SCIP_LP*              lp                  /**< current LP data */
6801    )
6802 {
6803    SCIP_Real norm;
6804    SCIP_Real feasibility;
6805    SCIP_Real eps;
6806 
6807    assert(set != NULL);
6808 
6809    switch( set->sepa_efficacynorm )
6810    {
6811    case 'e':
6812       norm = SCIProwGetNorm(row);
6813       break;
6814    case 'm':
6815       norm = SCIProwGetMaxval(row, set);
6816       break;
6817    case 's':
6818       norm = SCIProwGetSumNorm(row);
6819       break;
6820    case 'd':
6821       norm = (row->len == 0 ? 0.0 : 1.0);
6822       break;
6823    default:
6824       SCIPerrorMessage("invalid efficacy norm parameter '%c'\n", set->sepa_efficacynorm);
6825       SCIPABORT();
6826       norm = 0.0; /*lint !e527*/
6827    }
6828 
6829    eps = SCIPsetSumepsilon(set);
6830    norm = MAX(norm, eps);
6831    feasibility = SCIProwGetLPFeasibility(row, set, stat, lp);
6832 
6833    return -feasibility / norm;
6834 }
6835 
6836 /** returns whether the row's efficacy with respect to the current LP solution is greater than the minimal cut efficacy */
SCIProwIsLPEfficacious(SCIP_ROW * row,SCIP_SET * set,SCIP_STAT * stat,SCIP_LP * lp,SCIP_Bool root)6837 SCIP_Bool SCIProwIsLPEfficacious(
6838    SCIP_ROW*             row,                /**< LP row */
6839    SCIP_SET*             set,                /**< global SCIP settings */
6840    SCIP_STAT*            stat,               /**< problem statistics data */
6841    SCIP_LP*              lp,                 /**< current LP data */
6842    SCIP_Bool             root                /**< should the root's minimal cut efficacy be used? */
6843    )
6844 {
6845    SCIP_Real efficacy;
6846 
6847    efficacy = SCIProwGetLPEfficacy(row, set, stat, lp);
6848 
6849    return SCIPsetIsEfficacious(set, root, efficacy);
6850 }
6851 
6852 /** returns row's efficacy with respect to the given primal solution: e = -feasibility/norm */
SCIProwGetSolEfficacy(SCIP_ROW * row,SCIP_SET * set,SCIP_STAT * stat,SCIP_SOL * sol)6853 SCIP_Real SCIProwGetSolEfficacy(
6854    SCIP_ROW*             row,                /**< LP row */
6855    SCIP_SET*             set,                /**< global SCIP settings */
6856    SCIP_STAT*            stat,               /**< problem statistics data */
6857    SCIP_SOL*             sol                 /**< primal CIP solution */
6858    )
6859 {
6860    SCIP_Real norm;
6861    SCIP_Real feasibility;
6862    SCIP_Real eps;
6863 
6864    assert(set != NULL);
6865 
6866    switch( set->sepa_efficacynorm )
6867    {
6868    case 'e':
6869       norm = SCIProwGetNorm(row);
6870       break;
6871    case 'm':
6872       norm = SCIProwGetMaxval(row, set);
6873       break;
6874    case 's':
6875       norm = SCIProwGetSumNorm(row);
6876       break;
6877    case 'd':
6878       norm = (row->len == 0 ? 0.0 : 1.0);
6879       break;
6880    default:
6881       SCIPerrorMessage("invalid efficacy norm parameter '%c'\n", set->sepa_efficacynorm);
6882       SCIPABORT();
6883       norm = 0.0; /*lint !e527*/
6884    }
6885 
6886    eps = SCIPsetSumepsilon(set);
6887    norm = MAX(norm, eps);
6888    feasibility = SCIProwGetSolFeasibility(row, set, stat, sol);
6889 
6890    return -feasibility / norm;
6891 }
6892 
6893 /** returns whether the row's efficacy with respect to the given primal solution is greater than the minimal cut
6894  *  efficacy
6895  */
SCIProwIsSolEfficacious(SCIP_ROW * row,SCIP_SET * set,SCIP_STAT * stat,SCIP_SOL * sol,SCIP_Bool root)6896 SCIP_Bool SCIProwIsSolEfficacious(
6897    SCIP_ROW*             row,                /**< LP row */
6898    SCIP_SET*             set,                /**< global SCIP settings */
6899    SCIP_STAT*            stat,               /**< problem statistics data */
6900    SCIP_SOL*             sol,                /**< primal CIP solution */
6901    SCIP_Bool             root                /**< should the root's minimal cut efficacy be used? */
6902    )
6903 {
6904    SCIP_Real efficacy;
6905 
6906    efficacy = SCIProwGetSolEfficacy(row, set, stat, sol);
6907 
6908    return SCIPsetIsEfficacious(set, root, efficacy);
6909 }
6910 
6911 /** returns row's efficacy with respect to the relaxed solution: e = -feasibility/norm */
SCIProwGetRelaxEfficacy(SCIP_ROW * row,SCIP_SET * set,SCIP_STAT * stat)6912 SCIP_Real SCIProwGetRelaxEfficacy(
6913    SCIP_ROW*             row,                /**< LP row */
6914    SCIP_SET*             set,                /**< global SCIP settings */
6915    SCIP_STAT*            stat                /**< problem statistics data */
6916    )
6917 {
6918    SCIP_Real norm;
6919    SCIP_Real feasibility;
6920    SCIP_Real eps;
6921 
6922    assert(set != NULL);
6923 
6924    switch( set->sepa_efficacynorm )
6925    {
6926    case 'e':
6927       norm = SCIProwGetNorm(row);
6928       break;
6929    case 'm':
6930       norm = SCIProwGetMaxval(row, set);
6931       break;
6932    case 's':
6933       norm = SCIProwGetSumNorm(row);
6934       break;
6935    case 'd':
6936       norm = (row->len == 0 ? 0.0 : 1.0);
6937       break;
6938    default:
6939       SCIPerrorMessage("invalid efficacy norm parameter '%c'\n", set->sepa_efficacynorm);
6940       SCIPABORT();
6941       norm = 0.0; /*lint !e527*/
6942    }
6943 
6944    eps = SCIPsetSumepsilon(set);
6945    norm = MAX(norm, eps);
6946    feasibility = SCIProwGetRelaxFeasibility(row, set, stat);
6947 
6948    return -feasibility / norm;
6949 }
6950 
6951 /** returns row's efficacy with respect to the NLP solution: e = -feasibility/norm */
SCIProwGetNLPEfficacy(SCIP_ROW * row,SCIP_SET * set,SCIP_STAT * stat)6952 SCIP_Real SCIProwGetNLPEfficacy(
6953    SCIP_ROW*             row,                /**< LP row */
6954    SCIP_SET*             set,                /**< global SCIP settings */
6955    SCIP_STAT*            stat                /**< problem statistics data */
6956    )
6957 {
6958    SCIP_Real norm;
6959    SCIP_Real feasibility;
6960    SCIP_Real eps;
6961 
6962    assert(set != NULL);
6963 
6964    switch( set->sepa_efficacynorm )
6965    {
6966    case 'e':
6967       norm = SCIProwGetNorm(row);
6968       break;
6969    case 'm':
6970       norm = SCIProwGetMaxval(row, set);
6971       break;
6972    case 's':
6973       norm = SCIProwGetSumNorm(row);
6974       break;
6975    case 'd':
6976       norm = (row->len == 0 ? 0.0 : 1.0);
6977       break;
6978    default:
6979       SCIPerrorMessage("invalid efficacy norm parameter '%c'\n", set->sepa_efficacynorm);
6980       SCIPABORT();
6981       norm = 0.0; /*lint !e527*/
6982    }
6983 
6984    eps = SCIPsetSumepsilon(set);
6985    norm = MAX(norm, eps);
6986    feasibility = SCIProwGetNLPFeasibility(row, set, stat);
6987 
6988    return -feasibility / norm;
6989 }
6990 
6991 /** returns the scalar product of the coefficient vectors of the two given rows
6992  *
6993  *  @note the scalar product is computed w.r.t. the current LP columns only
6994  *  @todo also consider non-LP columns for the computation?
6995  */
SCIProwGetScalarProduct(SCIP_ROW * row1,SCIP_ROW * row2)6996 SCIP_Real SCIProwGetScalarProduct(
6997    SCIP_ROW*             row1,               /**< first LP row */
6998    SCIP_ROW*             row2                /**< second LP row */
6999    )
7000 {
7001    SCIP_Real scalarprod;
7002    int* row1colsidx;
7003    int* row2colsidx;
7004    int i1;
7005    int i2;
7006 
7007    assert(row1 != NULL);
7008    assert(row2 != NULL);
7009 
7010    /* Sort the column indices of both rows.
7011     *
7012     * The columns in a row are divided into two parts: LP columns, which are currently in the LP and non-LP columns;
7013     * we sort the rows, but that only ensures that within these two parts, columns are sorted w.r.t. their index.
7014     * Normally, this should be suficient, because a column contained in both rows should either be one of the LP columns
7015     * for both or one of the non-LP columns for both.
7016     * However, directly after a row was created, before a row is added to the LP, the row is not linked to all its
7017     * columns and all columns are treated as non-LP columns. Moreover, for example when doing column generation,
7018     * columns can be added later and remain unlinked while all previously added columns might already be linked.
7019     * Therefore, we have to be very careful about whether we can rely on the partitioning of the variables.
7020     *
7021     * We distinguish the following cases:
7022     *
7023     * 1) both rows have no unlinked columns
7024     *    -> we just check the LP partitions
7025     *
7026     * 2) exactly one row is completely unlinked, the other one is completely linked
7027     *    -> we compare the non-LP (unlinked) partition with the LP partition of the other row
7028     *       (thus all common LP columns are regarded)
7029     *
7030     * 3) we have unlinked and LP columns in both rows
7031     *    -> we need to compare four partitions at once
7032     *
7033     * 4a) we have one row with unlinked and LP columns and the other without any unlinked columns
7034     *     -> we need to compare three partitions: the LP part of the completely linked row and both partitions of the
7035     *        other row
7036     *
7037     * 4b) we have one row with unlinked and LP columns and the other is completely unlinked
7038     *     -> we need to compare three partitions: the complete unlinked row and both partitions of the other row
7039     *
7040     * 5) both rows are completely unlinked
7041     *    -> we need to compare two partitions: both complete rows
7042     */
7043    SCIProwSort(row1);
7044    assert(row1->lpcolssorted);
7045    assert(row1->nonlpcolssorted);
7046    SCIProwSort(row2);
7047    assert(row2->lpcolssorted);
7048    assert(row2->nonlpcolssorted);
7049 
7050    assert(row1->nunlinked <= row1->len - row1->nlpcols);
7051    assert(row2->nunlinked <= row2->len - row2->nlpcols);
7052 
7053    row1colsidx = row1->cols_index;
7054    row2colsidx = row2->cols_index;
7055 
7056 #ifndef NDEBUG
7057    /* check that we can rely on the partition into LP columns and non-LP columns if the rows are completely linked */
7058    if( row1->nunlinked == 0 && row2->nunlinked == 0 )
7059    {
7060       i1 = 0;
7061       i2 = row2->nlpcols;
7062       while( i1 < row1->nlpcols && i2 < row2->len )
7063       {
7064          assert(row1->cols[i1] != row2->cols[i2]);
7065          if( row1->cols[i1]->index < row2->cols[i2]->index )
7066             ++i1;
7067          else
7068          {
7069             assert(row1->cols[i1]->index > row2->cols[i2]->index);
7070             ++i2;
7071          }
7072       }
7073       assert(i1 == row1->nlpcols || i2 == row2->len);
7074 
7075       i1 = row1->nlpcols;
7076       i2 = 0;
7077       while( i1 < row1->len && i2 < row2->nlpcols )
7078       {
7079          assert(row1->cols[i1] != row2->cols[i2]);
7080          if( row1->cols[i1]->index < row2->cols[i2]->index )
7081             ++i1;
7082          else
7083          {
7084             assert(row1->cols[i1]->index > row2->cols[i2]->index);
7085             ++i2;
7086          }
7087       }
7088       assert(i1 == row1->len || i2 == row2->nlpcols);
7089    }
7090 #endif
7091 
7092    /* The "easy" cases 1) and 2) */
7093    if( (row1->nunlinked == 0 && row2->nunlinked == 0) ||
7094       ((row1->nlpcols == row1->len || row1->nunlinked == row1->len)
7095          && (row2->nlpcols == row2->len || row2->nunlinked == row2->len)
7096          && (row1->nunlinked == 0 || row2->nunlinked == 0)) )
7097    {
7098       assert(row1->nunlinked == 0 || row1->nunlinked == row1->len);
7099       assert(row2->nunlinked == 0 || row2->nunlinked == row2->len);
7100 
7101       /* set the iterators to the last column we want to regard in the row: nunlinked is either 0 or row->len,
7102        * therefore, we get nlpcols if nunlinked is 0 and row->len if the row is completely unlinked
7103        */
7104       i1 = MAX(row1->nlpcols, row1->nunlinked) - 1;
7105       i2 = MAX(row2->nlpcols, row2->nunlinked) - 1;
7106       scalarprod = 0.0;
7107 
7108       /* calculate the scalar product */
7109       while( i1 >= 0 && i2 >= 0 )
7110       {
7111          assert(row1->cols[i1]->index == row1colsidx[i1]);
7112          assert(row2->cols[i2]->index == row2colsidx[i2]);
7113          assert((row1->cols[i1] == row2->cols[i2]) == (row1colsidx[i1] == row2colsidx[i2]));
7114          if( row1colsidx[i1] < row2colsidx[i2] )
7115             --i2;
7116          else if( row1colsidx[i1] > row2colsidx[i2] )
7117             --i1;
7118          else
7119          {
7120             scalarprod += row1->vals[i1] * row2->vals[i2];
7121             --i1;
7122             --i2;
7123          }
7124       }
7125    }
7126    /* the "harder" cases 3) - 5): start with four partitions and reduce their number iteratively */
7127    else
7128    {
7129       SCIP_Bool lpcols;
7130       int ilp1;
7131       int inlp1;
7132       int ilp2;
7133       int inlp2;
7134       int end1;
7135       int end2;
7136 
7137       scalarprod = 0;
7138       ilp1 = 0;
7139       ilp2 = 0;
7140 
7141       /* if a row is completely linked (case 4a), we do not have to consider its non-LP columns */
7142       inlp1 = (row1->nunlinked > 0 ? row1->nlpcols : row1->len);
7143       inlp2 = (row2->nunlinked > 0 ? row2->nlpcols : row2->len);
7144 
7145       /* handle the case of four partitions (case 3) until one partition is finished;
7146        * cases 4a), 4b), and 5) will fail the while-condition
7147        */
7148       while( ilp1 < row1->nlpcols && inlp1 < row1->len && ilp2 < row2->nlpcols && inlp2 < row2->len )
7149       {
7150          assert(row1->cols[ilp1]->index == row1colsidx[ilp1]);
7151          assert(row1->cols[inlp1]->index == row1colsidx[inlp1]);
7152          assert(row2->cols[ilp2]->index == row2colsidx[ilp2]);
7153          assert(row2->cols[inlp2]->index == row2colsidx[inlp2]);
7154          assert((row1->cols[ilp1] == row2->cols[ilp2]) == (row1colsidx[ilp1] == row2colsidx[ilp2]));
7155          assert((row1->cols[ilp1] == row2->cols[inlp2]) == (row1colsidx[ilp1] == row2colsidx[inlp2]));
7156          assert((row1->cols[inlp1] == row2->cols[ilp2]) == (row1colsidx[inlp1] == row2colsidx[ilp2]));
7157          assert((row1->cols[inlp1] == row2->cols[inlp2]) == (row1colsidx[inlp1] == row2colsidx[inlp2]));
7158 
7159          /* rows have the same linked LP columns */
7160          if( row1colsidx[ilp1] == row2colsidx[ilp2] )
7161          {
7162             scalarprod += row1->vals[ilp1] * row2->vals[ilp2];
7163             ++ilp1;
7164             ++ilp2;
7165          }
7166          /* LP column of row1 is the same as unlinked column of row2 */
7167          else if( row1colsidx[ilp1] == row2colsidx[inlp2] )
7168          {
7169             scalarprod += row1->vals[ilp1] * row2->vals[inlp2];
7170             ++ilp1;
7171             ++inlp2;
7172          }
7173          /* unlinked column of row1 is the same as LP column of row2 */
7174          else if( row1colsidx[inlp1] == row2colsidx[ilp2] )
7175          {
7176             scalarprod += row1->vals[inlp1] * row2->vals[ilp2];
7177             ++inlp1;
7178             ++ilp2;
7179          }
7180          /* two unlinked LP columns are the same */
7181          else if( row1colsidx[inlp1] == row2colsidx[inlp2] && row1->cols[inlp1]->lppos >= 0 )
7182          {
7183             scalarprod += row1->vals[inlp1] * row2->vals[inlp2];
7184             ++inlp1;
7185             ++inlp2;
7186          }
7187          /* increase smallest counter */
7188          else if( row1colsidx[ilp1] < row1colsidx[inlp1] )
7189          {
7190             if( row2colsidx[ilp2] < row2colsidx[inlp2] )
7191             {
7192                if( row1colsidx[ilp1] < row2colsidx[ilp2] )
7193                   ++ilp1;
7194                else
7195                   ++ilp2;
7196             }
7197             else
7198             {
7199                if( row1colsidx[ilp1] < row2colsidx[inlp2] )
7200                   ++ilp1;
7201                else
7202                   ++inlp2;
7203             }
7204          }
7205          else
7206          {
7207             if( row2colsidx[ilp2] < row2colsidx[inlp2] )
7208             {
7209                if( row1colsidx[inlp1] < row2colsidx[ilp2] )
7210                   ++inlp1;
7211                else
7212                   ++ilp2;
7213             }
7214             else
7215             {
7216                if( row1colsidx[inlp1] < row2colsidx[inlp2] )
7217                   ++inlp1;
7218                else
7219                   ++inlp2;
7220             }
7221          }
7222       }
7223 
7224       /* One partition was completely handled, we just have to handle the three remaining partitions:
7225        * the remaining partition of this row and the two partitions of the other row.
7226        * If necessary, we swap the partitions to ensure that row1 is the row with only one remaining partition.
7227        */
7228       if( ilp1 != row1->nlpcols && inlp1 != row1->len )
7229       {
7230          int tmpilp;
7231          int tmpinlp;
7232 
7233          assert(ilp2 == row2->nlpcols || inlp2 == row2->len);
7234 
7235          SCIPswapPointers((void**) &row1, (void**) &row2);
7236          SCIPswapPointers((void**) &row1colsidx, (void**) &row2colsidx);
7237          tmpilp = ilp1;
7238          tmpinlp = inlp1;
7239          ilp1 = ilp2;
7240          inlp1 = inlp2;
7241          ilp2 = tmpilp;
7242          inlp2 = tmpinlp;
7243       }
7244 
7245       /* determine section of row 1 that we want to look at (current iterator = begin, end, LP-columns?)
7246        * -> this merges cases 4a) and 4b)
7247        */
7248       if( ilp1 == row1->nlpcols )
7249       {
7250          i1 = inlp1;
7251          end1 = row1->len;
7252          lpcols = FALSE;
7253       }
7254       else
7255       {
7256          assert(inlp1 == row1->len);
7257 
7258          i1 = ilp1;
7259          end1 = row1->nlpcols;
7260          lpcols = TRUE;
7261       }
7262 
7263       /* handle the case of three partitions (case 4) until one partition is finished, this reduces our problem to case 1), 2), or 5);
7264        * case 5) will fail the while-condition
7265        */
7266       while( i1 < end1 && ilp2 < row2->nlpcols && inlp2 < row2->len )
7267       {
7268          assert(row1->cols[i1]->index == row1colsidx[i1]);
7269          assert(row2->cols[ilp2]->index == row2colsidx[ilp2]);
7270          assert(row2->cols[inlp2]->index == row2colsidx[inlp2]);
7271          assert((row1->cols[i1] == row2->cols[ilp2]) == (row1colsidx[i1] == row2colsidx[ilp2]));
7272          assert((row1->cols[i1] == row2->cols[inlp2]) == (row1colsidx[i1] == row2colsidx[inlp2]));
7273 
7274          /* current column in row 1 is the same as the current LP column in row 2 */
7275          if( row1colsidx[i1] == row2colsidx[ilp2] )
7276          {
7277             scalarprod += row1->vals[i1] * row2->vals[ilp2];
7278             ++i1;
7279             ++ilp2;
7280          }
7281          /* linked or unlinked LP column of row1 is the same as unlinked column of row2 */
7282          else if( row1colsidx[i1] == row2colsidx[inlp2] && (lpcols || row1->cols[i1]->lppos >= 0) )
7283          {
7284             scalarprod += row1->vals[i1] * row2->vals[inlp2];
7285             ++i1;
7286             ++inlp2;
7287          }
7288          /* increase smallest counter */
7289          else if( row2colsidx[ilp2] < row2colsidx[inlp2] )
7290          {
7291             if( row1colsidx[i1] < row2colsidx[ilp2] )
7292                ++i1;
7293             else
7294                ++ilp2;
7295          }
7296          else
7297          {
7298             if( row1colsidx[i1] < row2colsidx[inlp2] )
7299                ++i1;
7300             else
7301                ++inlp2;
7302          }
7303       }
7304 
7305       /* if the second section of row 1 was finished, we can stop; otherwise, we have to consider the remaining parts of
7306        * the two rows
7307        */
7308       if( i1 < end1 )
7309       {
7310          /* determine section of row 2 that we want to look at (current iterator = begin, end, LP-columns?) */
7311          if( ilp2 == row2->nlpcols )
7312          {
7313             i2 = inlp2;
7314             end2 = row2->len;
7315             lpcols = FALSE;
7316          }
7317          else
7318          {
7319             assert(inlp2 == row2->len);
7320 
7321             i2 = ilp2;
7322             end2 = row2->nlpcols;
7323          }
7324 
7325          /* handle the case of two partitions (standard case 5, or case 1 or 2 due to partition reduction) */
7326          while( i1 < end1 && i2 < end2 )
7327          {
7328             assert(row1->cols[i1]->index == row1colsidx[i1]);
7329             assert(row2->cols[i2]->index == row2colsidx[i2]);
7330             assert((row1->cols[i1] == row2->cols[i2]) == (row1colsidx[i1] == row2colsidx[i2]));
7331 
7332             /* linked or unlinked LP column of row1 is the same as linked or unlinked LP column of row2 */
7333             if( row1colsidx[i1] == row2colsidx[i2] && (lpcols || row1->cols[i1]->lppos >= 0) )
7334             {
7335                scalarprod += row1->vals[i1] * row2->vals[i2];
7336                ++i1;
7337                ++i2;
7338             }
7339             /* increase smallest counter */
7340             else if( row1colsidx[i1] < row2colsidx[i2] )
7341                ++i1;
7342             else
7343                ++i2;
7344          }
7345       }
7346    }
7347 
7348    return scalarprod;
7349 }
7350 
7351 /** returns the discrete scalar product of the coefficient vectors of the two given rows */
7352 static
SCIProwGetDiscreteScalarProduct(SCIP_ROW * row1,SCIP_ROW * row2)7353 int SCIProwGetDiscreteScalarProduct(
7354    SCIP_ROW*             row1,               /**< first LP row */
7355    SCIP_ROW*             row2                /**< second LP row */
7356    )
7357 {
7358    int prod;
7359    int* row1colsidx;
7360    int* row2colsidx;
7361    int i1;
7362    int i2;
7363 
7364    assert(row1 != NULL);
7365    assert(row2 != NULL);
7366 
7367    /* Sort the column indices of both rows.
7368     *
7369     * The columns in a row are divided into two parts: LP columns, which are currently in the LP and non-LP columns;
7370     * we sort the rows, but that only ensures that within these two parts, columns are sorted w.r.t. their index.
7371     * Normally, this should be suficient, because a column contained in both rows should either be one of the LP columns
7372     * for both or one of the non-LP columns for both.
7373     * However, directly after a row was created, before a row is added to the LP, the row is not linked to all its
7374     * columns and all columns are treated as non-LP columns. Moreover, for example when doing column generation,
7375     * columns can be added later and remain unlinked while all previously added columns might already be linked.
7376     * Therefore, we have to be very careful about whether we can rely on the partitioning of the variables.
7377     *
7378     * We distinguish the following cases:
7379     *
7380     * 1) both rows have no unlinked columns
7381     *    -> we just check the LP partitions
7382     *
7383     * 2) exactly one row is completely unlinked, the other one is completely linked
7384     *    -> we compare the non-LP (unlinked) partition with the LP partition of the other row
7385     *       (thus all common LP columns are regarded)
7386     *
7387     * 3) we have unlinked and LP columns in both rows
7388     *    -> we need to compare four partitions at once
7389     *
7390     * 4a) we have one row with unlinked and LP columns and the other without any unlinked columns
7391     *     -> we need to compare three partitions: the LP part of the completely linked row and both partitions of the
7392     *        other row
7393     *
7394     * 4b) we have one row with unlinked and LP columns and the other is completely unlinked
7395     *     -> we need to compare three partitions: the complete unlinked row and both partitions of the other row
7396     *
7397     * 5) both rows are completely unlinked
7398     *    -> we need to compare two partitions: both complete rows
7399     */
7400    SCIProwSort(row1);
7401    assert(row1->lpcolssorted);
7402    assert(row1->nonlpcolssorted);
7403    SCIProwSort(row2);
7404    assert(row2->lpcolssorted);
7405    assert(row2->nonlpcolssorted);
7406 
7407    assert(row1->nunlinked <= row1->len - row1->nlpcols);
7408    assert(row2->nunlinked <= row2->len - row2->nlpcols);
7409 
7410    row1colsidx = row1->cols_index;
7411    row2colsidx = row2->cols_index;
7412 
7413 #ifndef NDEBUG
7414    /* check that we can rely on the partition into LP columns and non-LP columns if the rows are completely linked */
7415    if( row1->nunlinked == 0 && row2->nunlinked == 0 )
7416    {
7417       i1 = 0;
7418       i2 = row2->nlpcols;
7419       while( i1 < row1->nlpcols && i2 < row2->len )
7420       {
7421          assert(row1->cols[i1] != row2->cols[i2]);
7422          if( row1->cols[i1]->index < row2->cols[i2]->index )
7423             ++i1;
7424          else
7425          {
7426             assert(row1->cols[i1]->index > row2->cols[i2]->index);
7427             ++i2;
7428          }
7429       }
7430       assert(i1 == row1->nlpcols || i2 == row2->len);
7431 
7432       i1 = row1->nlpcols;
7433       i2 = 0;
7434       while( i1 < row1->len && i2 < row2->nlpcols )
7435       {
7436          assert(row1->cols[i1] != row2->cols[i2]);
7437          if( row1->cols[i1]->index < row2->cols[i2]->index )
7438             ++i1;
7439          else
7440          {
7441             assert(row1->cols[i1]->index > row2->cols[i2]->index);
7442             ++i2;
7443          }
7444       }
7445       assert(i1 == row1->len || i2 == row2->nlpcols);
7446    }
7447 #endif
7448 
7449    /* The "easy" cases 1) and 2) */
7450    if( (row1->nunlinked == 0 && row2->nunlinked == 0) ||
7451       ((row1->nlpcols == row1->len || row1->nunlinked == row1->len)
7452          && (row2->nlpcols == row2->len || row2->nunlinked == row2->len)
7453          && (row1->nunlinked == 0 || row2->nunlinked == 0)) )
7454    {
7455       assert(row1->nunlinked == 0 || row1->nunlinked == row1->len);
7456       assert(row2->nunlinked == 0 || row2->nunlinked == row2->len);
7457 
7458       /* set the iterators to the last column we want to regard in the row: nunlinked is either 0 or row->len,
7459        * therefore, we get nlpcols if nunlinked is 0 and row->len if the row is completely unlinked
7460        */
7461       i1 = MAX(row1->nlpcols, row1->nunlinked) - 1;
7462       i2 = MAX(row2->nlpcols, row2->nunlinked) - 1;
7463       prod = 0;
7464 
7465       /* calculate the scalar product */
7466       while( i1 >= 0 && i2 >= 0 )
7467       {
7468          assert(row1->cols[i1]->index == row1colsidx[i1]);
7469          assert(row2->cols[i2]->index == row2colsidx[i2]);
7470          assert((row1->cols[i1] == row2->cols[i2]) == (row1colsidx[i1] == row2colsidx[i2]));
7471          if( row1colsidx[i1] < row2colsidx[i2] )
7472             --i2;
7473          else if( row1colsidx[i1] > row2colsidx[i2] )
7474             --i1;
7475          else
7476          {
7477             ++prod;
7478             --i1;
7479             --i2;
7480          }
7481       }
7482    }
7483    /* the "harder" cases 3) - 5): start with four partitions and reduce their number iteratively */
7484    else
7485    {
7486       SCIP_Bool lpcols;
7487       int ilp1;
7488       int inlp1;
7489       int ilp2;
7490       int inlp2;
7491       int end1;
7492       int end2;
7493 
7494       prod = 0;
7495       ilp1 = 0;
7496       ilp2 = 0;
7497 
7498       /* if a row is completely linked (case 4a), we do not have to consider its non-LP columns */
7499       inlp1 = (row1->nunlinked > 0 ? row1->nlpcols : row1->len);
7500       inlp2 = (row2->nunlinked > 0 ? row2->nlpcols : row2->len);
7501 
7502       /* handle the case of four partitions (case 3) until one partition is finished;
7503        * cases 4a), 4b), and 5) will fail the while-condition
7504        */
7505       while( ilp1 < row1->nlpcols && inlp1 < row1->len && ilp2 < row2->nlpcols && inlp2 < row2->len )
7506       {
7507          assert(row1->cols[ilp1]->index == row1colsidx[ilp1]);
7508          assert(row1->cols[inlp1]->index == row1colsidx[inlp1]);
7509          assert(row2->cols[ilp2]->index == row2colsidx[ilp2]);
7510          assert(row2->cols[inlp2]->index == row2colsidx[inlp2]);
7511          assert((row1->cols[ilp1] == row2->cols[ilp2]) == (row1colsidx[ilp1] == row2colsidx[ilp2]));
7512          assert((row1->cols[ilp1] == row2->cols[inlp2]) == (row1colsidx[ilp1] == row2colsidx[inlp2]));
7513          assert((row1->cols[inlp1] == row2->cols[ilp2]) == (row1colsidx[inlp1] == row2colsidx[ilp2]));
7514          assert((row1->cols[inlp1] == row2->cols[inlp2]) == (row1colsidx[inlp1] == row2colsidx[inlp2]));
7515 
7516          /* rows have the same linked LP columns */
7517          if( row1colsidx[ilp1] == row2colsidx[ilp2] )
7518          {
7519             ++prod;
7520             ++ilp1;
7521             ++ilp2;
7522          }
7523          /* LP column of row1 is the same as unlinked column of row2 */
7524          else if( row1colsidx[ilp1] == row2colsidx[inlp2] )
7525          {
7526             ++prod;
7527             ++ilp1;
7528             ++inlp2;
7529          }
7530          /* unlinked column of row1 is the same as LP column of row2 */
7531          else if( row1colsidx[inlp1] == row2colsidx[ilp2] )
7532          {
7533             ++prod;
7534             ++inlp1;
7535             ++ilp2;
7536          }
7537          /* two unlinked LP columns are the same */
7538          else if( row1colsidx[inlp1] == row2colsidx[inlp2] && row1->cols[inlp1]->lppos >= 0 )
7539          {
7540             ++prod;
7541             ++inlp1;
7542             ++inlp2;
7543          }
7544          /* increase smallest counter */
7545          else if( row1colsidx[ilp1] < row1colsidx[inlp1] )
7546          {
7547             if( row2colsidx[ilp2] < row2colsidx[inlp2] )
7548             {
7549                if( row1colsidx[ilp1] < row2colsidx[ilp2] )
7550                   ++ilp1;
7551                else
7552                   ++ilp2;
7553             }
7554             else
7555             {
7556                if( row1colsidx[ilp1] < row2colsidx[inlp2] )
7557                   ++ilp1;
7558                else
7559                   ++inlp2;
7560             }
7561          }
7562          else
7563          {
7564             if( row2colsidx[ilp2] < row2colsidx[inlp2] )
7565             {
7566                if( row1colsidx[inlp1] < row2colsidx[ilp2] )
7567                   ++inlp1;
7568                else
7569                   ++ilp2;
7570             }
7571             else
7572             {
7573                if( row1colsidx[inlp1] < row2colsidx[inlp2] )
7574                   ++inlp1;
7575                else
7576                   ++inlp2;
7577             }
7578          }
7579       }
7580 
7581       /* One partition was completely handled, we just have to handle the three remaining partitions:
7582        * the remaining partition of this row and the two partitions of the other row.
7583        * If necessary, we swap the partitions to ensure that row1 is the row with only one remaining partition.
7584        */
7585       if( ilp1 != row1->nlpcols && inlp1 != row1->len )
7586       {
7587          int tmpilp;
7588          int tmpinlp;
7589 
7590          assert(ilp2 == row2->nlpcols || inlp2 == row2->len);
7591 
7592          SCIPswapPointers((void**) &row1, (void**) &row2);
7593          SCIPswapPointers((void**) &row1colsidx, (void**) &row2colsidx);
7594          tmpilp = ilp1;
7595          tmpinlp = inlp1;
7596          ilp1 = ilp2;
7597          inlp1 = inlp2;
7598          ilp2 = tmpilp;
7599          inlp2 = tmpinlp;
7600       }
7601 
7602       /* determine section of row 1 that we want to look at (current iterator = begin, end, LP-columns?)
7603        * -> this merges cases 4a) and 4b)
7604        */
7605       if( ilp1 == row1->nlpcols )
7606       {
7607          i1 = inlp1;
7608          end1 = row1->len;
7609          lpcols = FALSE;
7610       }
7611       else
7612       {
7613          assert(inlp1 == row1->len);
7614 
7615          i1 = ilp1;
7616          end1 = row1->nlpcols;
7617          lpcols = TRUE;
7618       }
7619 
7620       /* handle the case of three partitions (case 4) until one partition is finished, this reduces our problem to case 1), 2), or 5);
7621        * case 5) will fail the while-condition
7622        */
7623       while( i1 < end1 && ilp2 < row2->nlpcols && inlp2 < row2->len )
7624       {
7625          assert(row1->cols[i1]->index == row1colsidx[i1]);
7626          assert(row2->cols[ilp2]->index == row2colsidx[ilp2]);
7627          assert(row2->cols[inlp2]->index == row2colsidx[inlp2]);
7628          assert((row1->cols[i1] == row2->cols[ilp2]) == (row1colsidx[i1] == row2colsidx[ilp2]));
7629          assert((row1->cols[i1] == row2->cols[inlp2]) == (row1colsidx[i1] == row2colsidx[inlp2]));
7630 
7631          /* current column in row 1 is the same as the current LP column in row 2 */
7632          if( row1colsidx[i1] == row2colsidx[ilp2] )
7633          {
7634             ++prod;
7635             ++i1;
7636             ++ilp2;
7637          }
7638          /* linked or unlinked LP column of row1 is the same as unlinked column of row2 */
7639          else if( row1colsidx[i1] == row2colsidx[inlp2] && (lpcols || row1->cols[i1]->lppos >= 0) )
7640          {
7641             ++prod;
7642             ++i1;
7643             ++inlp2;
7644          }
7645          /* increase smallest counter */
7646          else if( row2colsidx[ilp2] < row2colsidx[inlp2] )
7647          {
7648             if( row1colsidx[i1] < row2colsidx[ilp2] )
7649                ++i1;
7650             else
7651                ++ilp2;
7652          }
7653          else
7654          {
7655             if( row1colsidx[i1] < row2colsidx[inlp2] )
7656                ++i1;
7657             else
7658                ++inlp2;
7659          }
7660       }
7661 
7662       /* if the second section of row 1 was finished, we can stop; otherwise, we have to consider the remaining parts of
7663        * the two rows
7664        */
7665       if( i1 < end1 )
7666       {
7667          /* determine section of row 2 that we want to look at (current iterator = begin, end, LP-columns?) */
7668          if( ilp2 == row2->nlpcols )
7669          {
7670             i2 = inlp2;
7671             end2 = row2->len;
7672             lpcols = FALSE;
7673          }
7674          else
7675          {
7676             assert(inlp2 == row2->len);
7677 
7678             i2 = ilp2;
7679             end2 = row2->nlpcols;
7680          }
7681 
7682          /* handle the case of two partitions (standard case 5, or case 1 or 2 due to partition reduction) */
7683          while( i1 < end1 && i2 < end2 )
7684          {
7685             assert(row1->cols[i1]->index == row1colsidx[i1]);
7686             assert(row2->cols[i2]->index == row2colsidx[i2]);
7687             assert((row1->cols[i1] == row2->cols[i2]) == (row1colsidx[i1] == row2colsidx[i2]));
7688 
7689             /* linked or unlinked LP column of row1 is the same as linked or unlinked LP column of row2 */
7690             if( row1colsidx[i1] == row2colsidx[i2] && (lpcols || row1->cols[i1]->lppos >= 0) )
7691             {
7692                ++prod;
7693                ++i1;
7694                ++i2;
7695             }
7696             /* increase smallest counter */
7697             else if( row1colsidx[i1] < row2colsidx[i2] )
7698                ++i1;
7699             else
7700                ++i2;
7701          }
7702       }
7703    }
7704 
7705    return prod;
7706 }
7707 
7708 /** returns the degree of parallelism between the hyperplanes defined by the two row vectors v, w:
7709  *  p = |v*w|/(|v|*|w|);
7710  *  the hyperplanes are parallel, iff p = 1, they are orthogonal, iff p = 0
7711  */
SCIProwGetParallelism(SCIP_ROW * row1,SCIP_ROW * row2,char orthofunc)7712 SCIP_Real SCIProwGetParallelism(
7713    SCIP_ROW*             row1,               /**< first LP row */
7714    SCIP_ROW*             row2,               /**< second LP row */
7715    char                  orthofunc           /**< function used for calc. scalar prod. ('e'uclidean, 'd'iscrete) */
7716    )
7717 {
7718    SCIP_Real parallelism;
7719    SCIP_Real scalarprod;
7720 
7721    switch( orthofunc )
7722    {
7723    case 'e':
7724       scalarprod = SCIProwGetScalarProduct(row1, row2);
7725       if( scalarprod == 0.0 )
7726       {
7727          parallelism = 0.0;
7728          break;
7729       }
7730 
7731       if( SCIProwGetNorm(row1) == 0.0 )
7732       {
7733          /* In theory, this should not happen if the scalarproduct is not zero
7734           * But due to bug 520 (also issue 44), it is possible that norms are not correct.
7735           * Thus, if the norm is so bad that it is even 0, then reevaluate it here.
7736           * But as we don't have set available here, we cannot call rowCalcNorms, so do it by hand.
7737           */
7738          int i;
7739          for( i = 0; i < row1->len; ++i )
7740             if( row1->cols[i]->lppos >= 0 )
7741                row1->sqrnorm += SQR(row1->vals[i]);
7742          assert(SCIProwGetNorm(row1) != 0.0);
7743       }
7744 
7745       if( SCIProwGetNorm(row2) == 0.0 )
7746       {
7747          /* same as for row1 above: reeval norms if it is 0, which is wrong */
7748          int i;
7749          for( i = 0; i < row2->len; ++i )
7750             if( row2->cols[i]->lppos >= 0 )
7751                row2->sqrnorm += SQR(row2->vals[i]);
7752          assert(SCIProwGetNorm(row2) != 0.0);
7753       }
7754 
7755       parallelism = REALABS(scalarprod) / (SCIProwGetNorm(row1) * SCIProwGetNorm(row2));
7756       break;
7757 
7758    case 'd':
7759       scalarprod = (SCIP_Real) SCIProwGetDiscreteScalarProduct(row1, row2);
7760       parallelism = scalarprod / (sqrt((SCIP_Real) SCIProwGetNNonz(row1)) * sqrt((SCIP_Real) SCIProwGetNNonz(row2)));
7761       break;
7762 
7763    default:
7764       SCIPerrorMessage("invalid orthogonality function parameter '%c'\n", orthofunc);
7765       SCIPABORT();
7766       parallelism = 0.0; /*lint !e527*/
7767    }
7768 
7769    return parallelism;
7770 }
7771 
7772 /** returns the degree of orthogonality between the hyperplanes defined by the two row vectors v, w:
7773  *  o = 1 - |v*w|/(|v|*|w|);
7774  *  the hyperplanes are orthogonal, iff p = 1, they are parallel, iff p = 0
7775  */
SCIProwGetOrthogonality(SCIP_ROW * row1,SCIP_ROW * row2,char orthofunc)7776 SCIP_Real SCIProwGetOrthogonality(
7777    SCIP_ROW*             row1,               /**< first LP row */
7778    SCIP_ROW*             row2,               /**< second LP row */
7779    char                  orthofunc           /**< function used for calc. scalar prod. ('e'uclidean, 'd'iscrete) */
7780    )
7781 {
7782    return 1.0 - SCIProwGetParallelism(row1, row2, orthofunc);
7783 }
7784 
7785 /** gets parallelism of row with objective function: if the returned value is 1, the row is parallel to the objective
7786  *  function, if the value is 0, it is orthogonal to the objective function
7787  */
SCIProwGetObjParallelism(SCIP_ROW * row,SCIP_SET * set,SCIP_LP * lp)7788 SCIP_Real SCIProwGetObjParallelism(
7789    SCIP_ROW*             row,                /**< LP row */
7790    SCIP_SET*             set,                /**< global SCIP settings */
7791    SCIP_LP*              lp                  /**< current LP data */
7792    )
7793 {
7794    SCIP_Real prod;
7795    SCIP_Real parallelism;
7796 
7797    assert(row != NULL);
7798    assert(lp != NULL);
7799 
7800    if( lp->objsqrnormunreliable )
7801       SCIPlpRecalculateObjSqrNorm(set, lp);
7802 
7803    assert(!lp->objsqrnormunreliable);
7804    assert(lp->objsqrnorm >= 0.0);
7805 
7806    checkRowSqrnorm(row);
7807    checkRowObjprod(row);
7808 
7809    prod = row->sqrnorm * lp->objsqrnorm;
7810 
7811    parallelism = SCIPsetIsPositive(set, prod) ? REALABS(row->objprod) / SQRT(prod) : 0.0;
7812    assert(SCIPsetIsSumGE(set, parallelism, 0.0));
7813    assert(SCIPsetIsSumLE(set, parallelism, 1.0));
7814    parallelism = MIN(parallelism, 1.0);
7815    parallelism = MAX(parallelism, 0.0);
7816 
7817    return parallelism;
7818 }
7819 
7820 /** includes event handler with given data in row's event filter */
SCIProwCatchEvent(SCIP_ROW * row,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTTYPE eventtype,SCIP_EVENTHDLR * eventhdlr,SCIP_EVENTDATA * eventdata,int * filterpos)7821 SCIP_RETCODE SCIProwCatchEvent(
7822    SCIP_ROW*             row,                /**< row */
7823    BMS_BLKMEM*           blkmem,             /**< block memory */
7824    SCIP_SET*             set,                /**< global SCIP settings */
7825    SCIP_EVENTTYPE        eventtype,          /**< event type to catch */
7826    SCIP_EVENTHDLR*       eventhdlr,          /**< event handler to call for the event processing */
7827    SCIP_EVENTDATA*       eventdata,          /**< event data to pass to the event handler for the event processing */
7828    int*                  filterpos           /**< pointer to store position of event filter entry, or NULL */
7829    )
7830 {
7831    assert(row != NULL);
7832    assert(row->eventfilter != NULL);
7833    assert((eventtype & ~SCIP_EVENTTYPE_ROWCHANGED) == 0);
7834    assert((eventtype &  SCIP_EVENTTYPE_ROWCHANGED) != 0);
7835 
7836    SCIPsetDebugMsg(set, "catch event of type 0x%" SCIP_EVENTTYPE_FORMAT " of row <%s> with handler %p and data %p\n",
7837       eventtype, row->name, (void*)eventhdlr, (void*)eventdata);
7838 
7839    SCIP_CALL( SCIPeventfilterAdd(row->eventfilter, blkmem, set, eventtype, eventhdlr, eventdata, filterpos) );
7840 
7841    return SCIP_OKAY;
7842 }
7843 
7844 /** deletes event handler with given data from row's event filter */
SCIProwDropEvent(SCIP_ROW * row,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTTYPE eventtype,SCIP_EVENTHDLR * eventhdlr,SCIP_EVENTDATA * eventdata,int filterpos)7845 SCIP_RETCODE SCIProwDropEvent(
7846    SCIP_ROW*             row,                /**< row */
7847    BMS_BLKMEM*           blkmem,             /**< block memory */
7848    SCIP_SET*             set,                /**< global SCIP settings */
7849    SCIP_EVENTTYPE        eventtype,          /**< event type mask of dropped event */
7850    SCIP_EVENTHDLR*       eventhdlr,          /**< event handler to call for the event processing */
7851    SCIP_EVENTDATA*       eventdata,          /**< event data to pass to the event handler for the event processing */
7852    int                   filterpos           /**< position of event filter entry returned by SCIPvarCatchEvent(), or -1 */
7853    )
7854 {
7855    assert(row != NULL);
7856    assert(row->eventfilter != NULL);
7857 
7858    SCIPsetDebugMsg(set, "drop event of row <%s> with handler %p and data %p\n", row->name, (void*)eventhdlr, (void*)eventdata);
7859 
7860    SCIP_CALL( SCIPeventfilterDel(row->eventfilter, blkmem, set, eventtype, eventhdlr, eventdata, filterpos) );
7861 
7862    return SCIP_OKAY;
7863 }
7864 
7865 /** marks a row to be not removable from the LP in the current node because it became obsolete */
SCIProwMarkNotRemovableLocal(SCIP_ROW * row,SCIP_STAT * stat)7866 void SCIProwMarkNotRemovableLocal(
7867    SCIP_ROW*             row,                /**< LP row */
7868    SCIP_STAT*            stat                /**< problem statistics */
7869    )
7870 {
7871    assert(row  != NULL);
7872    assert(stat != NULL);
7873    assert(stat->nnodes > 0);
7874 
7875    /* lpRemoveObsoleteRows() does not remove a row if the node number stored in obsoletenode equals the current node number */
7876    row->obsoletenode = stat->nnodes;
7877 }
7878 
7879 /*
7880  * LP solver data update
7881  */
7882 
7883 /** resets column data to represent a column not in the LP solver */
7884 static
markColDeleted(SCIP_COL * col)7885 void markColDeleted(
7886    SCIP_COL*             col                 /**< column to be marked deleted */
7887    )
7888 {
7889    assert(col != NULL);
7890 
7891    col->lpipos = -1;
7892    col->primsol = 0.0;
7893    col->redcost = SCIP_INVALID;
7894    col->farkascoef = SCIP_INVALID;
7895    col->sbdown = SCIP_INVALID;
7896    col->sbup = SCIP_INVALID;
7897    col->sbdownvalid = FALSE;
7898    col->sbupvalid = FALSE;
7899    col->validredcostlp = -1;
7900    col->validfarkaslp = -1;
7901    col->sbitlim = -1;
7902    col->basisstatus = SCIP_BASESTAT_ZERO; /*lint !e641*/
7903 }
7904 
7905 /** applies all cached column removals to the LP solver */
7906 static
lpFlushDelCols(SCIP_LP * lp)7907 SCIP_RETCODE lpFlushDelCols(
7908    SCIP_LP*              lp                  /**< current LP data */
7909    )
7910 {
7911    assert(lp != NULL);
7912    assert(lp->lpifirstchgcol <= lp->nlpicols);
7913    assert(lp->lpifirstchgcol <= lp->ncols);
7914 
7915    /* find the first column to change */
7916    while( lp->lpifirstchgcol < lp->nlpicols
7917       && lp->lpifirstchgcol < lp->ncols
7918       && lp->cols[lp->lpifirstchgcol]->lpipos == lp->lpifirstchgcol
7919       && !lp->cols[lp->lpifirstchgcol]->coefchanged )
7920    {
7921       assert(lp->cols[lp->lpifirstchgcol] == lp->lpicols[lp->lpifirstchgcol]);
7922       lp->lpifirstchgcol++;
7923    }
7924 
7925    /* shrink LP to the part which didn't change */
7926    if( lp->lpifirstchgcol < lp->nlpicols )
7927    {
7928       int i;
7929 
7930       assert(!lp->diving);
7931       SCIPdebugMessage("flushing col deletions: shrink LP from %d to %d columns\n", lp->nlpicols, lp->lpifirstchgcol);
7932       SCIP_CALL( SCIPlpiDelCols(lp->lpi, lp->lpifirstchgcol, lp->nlpicols-1) );
7933       for( i = lp->lpifirstchgcol; i < lp->nlpicols; ++i )
7934       {
7935          markColDeleted(lp->lpicols[i]);
7936       }
7937       lp->nlpicols = lp->lpifirstchgcol;
7938       lp->flushdeletedcols = TRUE;
7939       lp->updateintegrality = TRUE;
7940 
7941       /* mark the LP unsolved */
7942       lp->solved = FALSE;
7943       lp->primalfeasible = FALSE;
7944       lp->primalchecked = FALSE;
7945       lp->lpobjval = SCIP_INVALID;
7946       lp->lpsolstat = SCIP_LPSOLSTAT_NOTSOLVED;
7947    }
7948    assert(lp->nlpicols == lp->lpifirstchgcol);
7949 
7950    return SCIP_OKAY;
7951 }
7952 
7953 /** computes for the given column the lower and upper bound that should be flushed into the LP
7954  *  depending on lazy bounds and diving mode; in diving mode, lazy bounds are ignored, i.e.,
7955  *  the bounds are explicitly added to the LP in any case
7956  */
7957 static
computeLPBounds(SCIP_LP * lp,SCIP_SET * set,SCIP_COL * col,SCIP_Real lpiinf,SCIP_Real * lb,SCIP_Real * ub)7958 void computeLPBounds(
7959    SCIP_LP*              lp,                 /**< current LP data */
7960    SCIP_SET*             set,                /**< global SCIP settings */
7961    SCIP_COL*             col,                /**< column to compute bounds for */
7962    SCIP_Real             lpiinf,             /**< infinity value if the LP solver */
7963    SCIP_Real*            lb,                 /**< pointer to store the new lower bound */
7964    SCIP_Real*            ub                  /**< pointer to store the new upper bound */
7965    )
7966 {
7967    assert(lp != NULL);
7968    assert(set != NULL);
7969    assert(col != NULL);
7970    assert(lb != NULL);
7971    assert(ub != NULL);
7972 
7973    /* get the correct new lower bound:
7974     * if lazy lower bound exists and is larger than lower bound, set lower bound to infinity;
7975     * if we are in diving mode, ignore lazy bounds and always take the lower bound
7976     */
7977    if( SCIPsetIsInfinity(set, -col->lb) || (SCIPsetIsLE(set, col->lb, col->lazylb) && !SCIPlpDiving(lp)) )
7978       (*lb) = -lpiinf;
7979    else
7980       (*lb) = col->lb;
7981    /* get the correct new upper bound:
7982     * if lazy upper bound exists and is larger than upper bound, set upper bound to infinity;
7983     * if we are in diving mode, ignore lazy bounds and always take the upper bound
7984     */
7985    if( SCIPsetIsInfinity(set, col->ub) || (SCIPsetIsGE(set, col->ub, col->lazyub) && !SCIPlpDiving(lp)) )
7986       (*ub) = lpiinf;
7987    else
7988       (*ub) = col->ub;
7989 }
7990 
7991 /** applies all cached column additions to the LP solver */
7992 static
lpFlushAddCols(SCIP_LP * lp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue)7993 SCIP_RETCODE lpFlushAddCols(
7994    SCIP_LP*              lp,                 /**< current LP data */
7995    BMS_BLKMEM*           blkmem,             /**< block memory */
7996    SCIP_SET*             set,                /**< global SCIP settings */
7997    SCIP_EVENTQUEUE*      eventqueue          /**< event queue */
7998    )
7999 {
8000    SCIP_Real* obj;
8001    SCIP_Real* lb;
8002    SCIP_Real* ub;
8003    int* beg;
8004    int* ind;
8005    SCIP_Real* val;
8006    char** name;
8007    SCIP_COL* col;
8008    SCIP_Real lpiinf;
8009    int c;
8010    int pos;
8011    int nnonz;
8012    int naddcols;
8013    int naddcoefs;
8014    int i;
8015    int lpipos;
8016 
8017    assert(lp != NULL);
8018    assert(lp->lpifirstchgcol == lp->nlpicols);
8019    assert(blkmem != NULL);
8020    assert(set != NULL);
8021 
8022    /* if there are no columns to add, we are ready */
8023    if( lp->ncols == lp->nlpicols )
8024       return SCIP_OKAY;
8025 
8026    /* add the additional columns */
8027    assert(!lp->diving);
8028    assert(lp->ncols > lp->nlpicols);
8029    SCIP_CALL( ensureLpicolsSize(lp, set, lp->ncols) );
8030 
8031    /* get the solver's infinity value */
8032    lpiinf = SCIPlpiInfinity(lp->lpi);
8033 
8034    /* count the (maximal) number of added coefficients, calculate the number of added columns */
8035    naddcols = lp->ncols - lp->nlpicols;
8036    naddcoefs = 0;
8037    for( c = lp->nlpicols; c < lp->ncols; ++c )
8038       naddcoefs += lp->cols[c]->len;
8039    assert(naddcols > 0);
8040 
8041    /* get temporary memory for changes */
8042    SCIP_CALL( SCIPsetAllocBufferArray(set, &obj, naddcols) );
8043    SCIP_CALL( SCIPsetAllocBufferArray(set, &lb, naddcols) );
8044    SCIP_CALL( SCIPsetAllocBufferArray(set, &ub, naddcols) );
8045    SCIP_CALL( SCIPsetAllocBufferArray(set, &beg, naddcols) );
8046    SCIP_CALL( SCIPsetAllocBufferArray(set, &ind, naddcoefs) );
8047    SCIP_CALL( SCIPsetAllocBufferArray(set, &val, naddcoefs) );
8048    SCIP_CALL( SCIPsetAllocBufferArray(set, &name, naddcols) );
8049 
8050    /* fill temporary memory with column data */
8051    nnonz = 0;
8052    for( pos = 0, c = lp->nlpicols; c < lp->ncols; ++pos, ++c )
8053    {
8054       col = lp->cols[c];
8055       assert(col != NULL);
8056       assert(col->var != NULL);
8057       assert(SCIPvarGetStatus(col->var) == SCIP_VARSTATUS_COLUMN);
8058       assert(SCIPvarGetCol(col->var) == col);
8059       assert(col->lppos == c);
8060       assert(nnonz + col->nlprows <= naddcoefs);
8061 
8062       SCIPsetDebugMsg(set, "flushing added column <%s>: ", SCIPvarGetName(col->var));
8063       debugColPrint(set, col);
8064 
8065       /* Because the column becomes a member of the LP solver, it now can take values
8066        * different from zero. That means, we have to include the column in the corresponding
8067        * row vectors.
8068        */
8069       SCIP_CALL( colLink(col, blkmem, set, eventqueue, lp) );
8070 
8071       lp->lpicols[c] = col;
8072       col->lpipos = c;
8073       col->primsol = SCIP_INVALID;
8074       col->redcost = SCIP_INVALID;
8075       col->farkascoef = SCIP_INVALID;
8076       col->sbdown = SCIP_INVALID;
8077       col->sbup = SCIP_INVALID;
8078       col->sbdownvalid = FALSE;
8079       col->sbupvalid = FALSE;
8080       col->validredcostlp = -1;
8081       col->validfarkaslp = -1;
8082       col->sbitlim = -1;
8083       col->objchanged = FALSE;
8084       col->lbchanged = FALSE;
8085       col->ubchanged = FALSE;
8086       col->coefchanged = FALSE;
8087       obj[pos] = col->obj;
8088 
8089       /* compute bounds that should be flushed into the LP (taking into account lazy bounds) */
8090       computeLPBounds(lp, set, col, lpiinf, &(lb[pos]), &(ub[pos]));
8091 
8092       beg[pos] = nnonz;
8093       name[pos] = (char*)SCIPvarGetName(col->var);
8094 
8095       col->flushedobj = obj[pos];
8096       col->flushedlb = lb[pos];
8097       col->flushedub = ub[pos];
8098 
8099       for( i = 0; i < col->nlprows; ++i )
8100       {
8101          assert(col->rows[i] != NULL);
8102          lpipos = col->rows[i]->lpipos;
8103          if( lpipos >= 0 )
8104          {
8105             assert(lpipos < lp->nrows);
8106             assert(nnonz < naddcoefs);
8107             ind[nnonz] = lpipos;
8108             val[nnonz] = col->vals[i];
8109             nnonz++;
8110          }
8111       }
8112 #ifndef NDEBUG
8113       for( i = col->nlprows; i < col->len; ++i )
8114       {
8115          assert(col->rows[i] != NULL);
8116          assert(col->rows[i]->lpipos == -1); /* because the row deletions are already performed */
8117       }
8118 #endif
8119    }
8120 
8121    /* call LP interface */
8122    SCIPsetDebugMsg(set, "flushing col additions: enlarge LP from %d to %d columns\n", lp->nlpicols, lp->ncols);
8123    SCIP_CALL( SCIPlpiAddCols(lp->lpi, naddcols, obj, lb, ub, name, nnonz, beg, ind, val) );
8124    lp->nlpicols = lp->ncols;
8125    lp->lpifirstchgcol = lp->nlpicols;
8126 
8127    /* free temporary memory */
8128    SCIPsetFreeBufferArray(set, &name);
8129    SCIPsetFreeBufferArray(set, &val);
8130    SCIPsetFreeBufferArray(set, &ind);
8131    SCIPsetFreeBufferArray(set, &beg);
8132    SCIPsetFreeBufferArray(set, &ub);
8133    SCIPsetFreeBufferArray(set, &lb);
8134    SCIPsetFreeBufferArray(set, &obj);
8135 
8136    lp->flushaddedcols = TRUE;
8137    lp->updateintegrality = TRUE;
8138 
8139    /* mark the LP unsolved */
8140    lp->solved = FALSE;
8141    lp->dualfeasible = FALSE;
8142    lp->dualchecked = FALSE;
8143    lp->lpobjval = SCIP_INVALID;
8144    lp->lpsolstat = SCIP_LPSOLSTAT_NOTSOLVED;
8145 
8146    return SCIP_OKAY;
8147 }
8148 
8149 /** resets row data to represent a row not in the LP solver */
8150 static
markRowDeleted(SCIP_ROW * row)8151 void markRowDeleted(
8152    SCIP_ROW*             row                 /**< row to be marked deleted */
8153    )
8154 {
8155    assert(row != NULL);
8156 
8157    row->lpipos = -1;
8158    row->dualsol = 0.0;
8159    row->activity = SCIP_INVALID;
8160    row->dualfarkas = 0.0;
8161    row->basisstatus = SCIP_BASESTAT_BASIC; /*lint !e641*/
8162    row->validactivitylp = -1;
8163 }
8164 
8165 /** applies all cached row removals to the LP solver */
8166 static
lpFlushDelRows(SCIP_LP * lp,BMS_BLKMEM * blkmem,SCIP_SET * set)8167 SCIP_RETCODE lpFlushDelRows(
8168    SCIP_LP*              lp,                 /**< current LP data */
8169    BMS_BLKMEM*           blkmem,             /**< block memory */
8170    SCIP_SET*             set                 /**< global SCIP settings */
8171    )
8172 {
8173    assert(lp != NULL);
8174    assert(lp->lpifirstchgrow <= lp->nlpirows);
8175    assert(lp->lpifirstchgrow <= lp->nrows);
8176 
8177    /* find the first row to change */
8178    while( lp->lpifirstchgrow < lp->nlpirows
8179       && lp->lpifirstchgrow < lp->nrows
8180       && lp->rows[lp->lpifirstchgrow]->lpipos == lp->lpifirstchgrow
8181       && !lp->rows[lp->lpifirstchgrow]->coefchanged )
8182    {
8183       assert(lp->rows[lp->lpifirstchgrow] == lp->lpirows[lp->lpifirstchgrow]);
8184       lp->lpifirstchgrow++;
8185    }
8186 
8187    /* shrink LP to the part which didn't change */
8188    if( lp->lpifirstchgrow < lp->nlpirows )
8189    {
8190       int i;
8191 
8192       SCIPsetDebugMsg(set, "flushing row deletions: shrink LP from %d to %d rows\n", lp->nlpirows, lp->lpifirstchgrow);
8193       SCIP_CALL( SCIPlpiDelRows(lp->lpi, lp->lpifirstchgrow, lp->nlpirows-1) );
8194       for( i = lp->lpifirstchgrow; i < lp->nlpirows; ++i )
8195       {
8196          markRowDeleted(lp->lpirows[i]);
8197          SCIP_CALL( SCIProwRelease(&lp->lpirows[i], blkmem, set, lp) );
8198       }
8199       lp->nlpirows = lp->lpifirstchgrow;
8200       lp->flushdeletedrows = TRUE;
8201 
8202       /* mark the LP unsolved */
8203       lp->solved = FALSE;
8204       lp->dualfeasible = FALSE;
8205       lp->dualchecked = FALSE;
8206       lp->lpobjval = SCIP_INVALID;
8207       lp->lpsolstat = SCIP_LPSOLSTAT_NOTSOLVED;
8208    }
8209    assert(lp->nlpirows == lp->lpifirstchgrow);
8210 
8211    return SCIP_OKAY;
8212 }
8213 
8214 /** applies all cached row additions and removals to the LP solver */
8215 static
lpFlushAddRows(SCIP_LP * lp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue)8216 SCIP_RETCODE lpFlushAddRows(
8217    SCIP_LP*              lp,                 /**< current LP data */
8218    BMS_BLKMEM*           blkmem,             /**< block memory */
8219    SCIP_SET*             set,                /**< global SCIP settings */
8220    SCIP_EVENTQUEUE*      eventqueue          /**< event queue */
8221    )
8222 {
8223    SCIP_Real* lhs;
8224    SCIP_Real* rhs;
8225    int* beg;
8226    int* ind;
8227    SCIP_Real* val;
8228    char** name;
8229    SCIP_ROW* row;
8230    SCIP_Real lpiinf;
8231    int r;
8232    int pos;
8233    int nnonz;
8234    int naddrows;
8235    int naddcoefs;
8236    int i;
8237    int lpipos;
8238 
8239    assert(lp != NULL);
8240    assert(lp->lpifirstchgrow == lp->nlpirows);
8241    assert(blkmem != NULL);
8242 
8243    /* if there are no rows to add, we are ready */
8244    if( lp->nrows == lp->nlpirows )
8245       return SCIP_OKAY;
8246 
8247    /* add the additional rows */
8248    assert(lp->nrows > lp->nlpirows);
8249    SCIP_CALL( ensureLpirowsSize(lp, set, lp->nrows) );
8250 
8251    /* get the solver's infinity value */
8252    lpiinf = SCIPlpiInfinity(lp->lpi);
8253 
8254    /* count the (maximal) number of added coefficients, calculate the number of added rows */
8255    naddrows = lp->nrows - lp->nlpirows;
8256    naddcoefs = 0;
8257    for( r = lp->nlpirows; r < lp->nrows; ++r )
8258       naddcoefs += lp->rows[r]->len;
8259    assert(naddrows > 0);
8260 
8261    /* get temporary memory for changes */
8262    SCIP_CALL( SCIPsetAllocBufferArray(set, &lhs, naddrows) );
8263    SCIP_CALL( SCIPsetAllocBufferArray(set, &rhs, naddrows) );
8264    SCIP_CALL( SCIPsetAllocBufferArray(set, &beg, naddrows) );
8265    SCIP_CALL( SCIPsetAllocBufferArray(set, &ind, naddcoefs) );
8266    SCIP_CALL( SCIPsetAllocBufferArray(set, &val, naddcoefs) );
8267    SCIP_CALL( SCIPsetAllocBufferArray(set, &name, naddrows) );
8268 
8269    /* fill temporary memory with row data */
8270    nnonz = 0;
8271    for( pos = 0, r = lp->nlpirows; r < lp->nrows; ++pos, ++r )
8272    {
8273       row = lp->rows[r];
8274       assert(row != NULL);
8275       assert(row->lppos == r);
8276       assert(nnonz + row->nlpcols <= naddcoefs);
8277 
8278       SCIPsetDebugMsg(set, "flushing added row <%s>: ", row->name);
8279       debugRowPrint(set, row);
8280 
8281       /* Because the row becomes a member of the LP solver, its dual variable now can take values
8282        * different from zero. That means, we have to include the row in the corresponding
8283        * column vectors.
8284        */
8285       SCIP_CALL( rowLink(row, blkmem, set, eventqueue, lp) );
8286 
8287       SCIProwCapture(row);
8288       lp->lpirows[r] = row;
8289       row->lpipos = r;
8290       row->dualsol = SCIP_INVALID;
8291       row->activity = SCIP_INVALID;
8292       row->dualfarkas = SCIP_INVALID;
8293       row->validactivitylp = -1;
8294       row->lhschanged = FALSE;
8295       row->rhschanged = FALSE;
8296       row->coefchanged = FALSE;
8297       if( SCIPsetIsInfinity(set, -row->lhs) )
8298          lhs[pos] = -lpiinf;
8299       else
8300          lhs[pos] = row->lhs - row->constant;
8301       if( SCIPsetIsInfinity(set, row->rhs) )
8302          rhs[pos] = lpiinf;
8303       else
8304          rhs[pos] = row->rhs - row->constant;
8305       beg[pos] = nnonz;
8306       name[pos] = row->name;
8307 
8308       row->flushedlhs = lhs[pos];
8309       row->flushedrhs = rhs[pos];
8310 
8311       SCIPsetDebugMsg(set, "flushing added row (SCIP_LPI): %+g <=", lhs[pos]);
8312       for( i = 0; i < row->nlpcols; ++i )
8313       {
8314          assert(row->cols[i] != NULL);
8315          lpipos = row->cols[i]->lpipos;
8316          if( lpipos >= 0 )
8317          {
8318             assert(lpipos < lp->ncols);
8319             assert(nnonz < naddcoefs);
8320             SCIPsetDebugMsgPrint(set, " %+gx%d(<%s>)", row->vals[i], lpipos+1, SCIPvarGetName(row->cols[i]->var));
8321             ind[nnonz] = lpipos;
8322             val[nnonz] = row->vals[i];
8323             nnonz++;
8324          }
8325       }
8326       SCIPsetDebugMsgPrint(set, " <= %+g\n", rhs[pos]);
8327 #ifndef NDEBUG
8328       for( i = row->nlpcols; i < row->len; ++i )
8329       {
8330          assert(row->cols[i] != NULL);
8331          assert(row->cols[i]->lpipos == -1); /* because the column deletions are already performed */
8332       }
8333 #endif
8334    }
8335 
8336    /* call LP interface */
8337    SCIPsetDebugMsg(set, "flushing row additions: enlarge LP from %d to %d rows\n", lp->nlpirows, lp->nrows);
8338    SCIP_CALL( SCIPlpiAddRows(lp->lpi, naddrows, lhs, rhs, name, nnonz, beg, ind, val) );
8339    lp->nlpirows = lp->nrows;
8340    lp->lpifirstchgrow = lp->nlpirows;
8341 
8342    /* free temporary memory */
8343    SCIPsetFreeBufferArray(set, &name);
8344    SCIPsetFreeBufferArray(set, &val);
8345    SCIPsetFreeBufferArray(set, &ind);
8346    SCIPsetFreeBufferArray(set, &beg);
8347    SCIPsetFreeBufferArray(set, &rhs);
8348    SCIPsetFreeBufferArray(set, &lhs);
8349 
8350    lp->flushaddedrows = TRUE;
8351 
8352    /* mark the LP unsolved */
8353    lp->solved = FALSE;
8354    lp->primalfeasible = FALSE;
8355    lp->primalchecked = FALSE;
8356    lp->lpobjval = SCIP_INVALID;
8357    lp->lpsolstat = SCIP_LPSOLSTAT_NOTSOLVED;
8358 
8359    return SCIP_OKAY;
8360 }
8361 
8362 /** applies all cached column bound and objective changes to the LP */
8363 static
lpFlushChgCols(SCIP_LP * lp,SCIP_SET * set)8364 SCIP_RETCODE lpFlushChgCols(
8365    SCIP_LP*              lp,                 /**< current LP data */
8366    SCIP_SET*             set                 /**< global SCIP settings */
8367    )
8368 {
8369 #ifndef NDEBUG
8370    SCIP_Bool lpinone = (strcmp( SCIPlpiGetSolverName(), "NONE") == 0);
8371 #endif
8372    SCIP_COL* col;
8373    int* objind;
8374    int* bdind;
8375    SCIP_Real* obj;
8376    SCIP_Real* lb;
8377    SCIP_Real* ub;
8378    SCIP_Real lpiinf;
8379    int nobjchg;
8380    int nbdchg;
8381    int i;
8382 
8383    assert(lp != NULL);
8384 
8385    if( lp->nchgcols == 0 )
8386       return SCIP_OKAY;
8387 
8388    /* get the solver's infinity value */
8389    lpiinf = SCIPlpiInfinity(lp->lpi);
8390 
8391    /* get temporary memory for changes */
8392    SCIP_CALL( SCIPsetAllocBufferArray(set, &objind, lp->ncols) );
8393    SCIP_CALL( SCIPsetAllocBufferArray(set, &obj, lp->ncols) );
8394    SCIP_CALL( SCIPsetAllocBufferArray(set, &bdind, lp->ncols) );
8395    SCIP_CALL( SCIPsetAllocBufferArray(set, &lb, lp->ncols) );
8396    SCIP_CALL( SCIPsetAllocBufferArray(set, &ub, lp->ncols) );
8397 
8398    /* collect all cached bound and objective changes */
8399    nobjchg = 0;
8400    nbdchg = 0;
8401    for( i = 0; i < lp->nchgcols; ++i )
8402    {
8403       col = lp->chgcols[i];
8404       assert(col != NULL);
8405       assert(col->var != NULL);
8406       assert(SCIPvarGetStatus(col->var) == SCIP_VARSTATUS_COLUMN);
8407       assert(SCIPvarGetCol(col->var) == col);
8408 
8409       if( col->lpipos >= 0 )
8410       {
8411 #ifndef NDEBUG
8412          /* do not check consistency of data with LPI in case of LPI=none */
8413          if( !lpinone )
8414          {
8415             SCIP_Real lpiobj;
8416             SCIP_Real lpilb;
8417             SCIP_Real lpiub;
8418 
8419             SCIP_CALL( SCIPlpiGetObj(lp->lpi, col->lpipos, col->lpipos, &lpiobj) );
8420             SCIP_CALL( SCIPlpiGetBounds(lp->lpi, col->lpipos, col->lpipos, &lpilb, &lpiub) );
8421             assert(SCIPsetIsFeasEQ(set, lpiobj, col->flushedobj));
8422             assert((SCIPsetIsInfinity(set, -lpilb) && SCIPsetIsInfinity(set, -col->flushedlb))
8423                   || (!SCIPsetIsInfinity(set, -lpilb) && !SCIPsetIsInfinity(set, -col->flushedlb) && SCIPsetIsFeasEQ(set, lpilb, col->flushedlb)));
8424             assert((SCIPsetIsInfinity(set, lpiub) && SCIPsetIsInfinity(set, col->flushedub))
8425                   || (!SCIPsetIsInfinity(set, lpiub) && !SCIPsetIsInfinity(set, col->flushedub) && SCIPsetIsFeasEQ(set, lpiub, col->flushedub)));
8426          }
8427 #endif
8428 
8429          if( col->objchanged )
8430          {
8431             SCIP_Real newobj;
8432 
8433             newobj = col->obj;
8434             if( col->flushedobj != newobj ) /*lint !e777*/
8435             {
8436                assert(nobjchg < lp->ncols);
8437                objind[nobjchg] = col->lpipos;
8438                obj[nobjchg] = newobj;
8439                nobjchg++;
8440                col->flushedobj = newobj;
8441             }
8442             col->objchanged = FALSE;
8443          }
8444 
8445          if( col->lbchanged || col->ubchanged )
8446          {
8447             SCIP_Real newlb;
8448             SCIP_Real newub;
8449 
8450             /* compute bounds that should be flushed into the LP (taking into account lazy bounds) */
8451             computeLPBounds(lp, set, col, lpiinf, &newlb, &newub);
8452 
8453             if( col->flushedlb != newlb || col->flushedub != newub ) /*lint !e777*/
8454             {
8455                assert(nbdchg < lp->ncols);
8456                bdind[nbdchg] = col->lpipos;
8457                lb[nbdchg] = newlb;
8458                ub[nbdchg] = newub;
8459                nbdchg++;
8460                col->flushedlb = newlb;
8461                col->flushedub = newub;
8462             }
8463             col->lbchanged = FALSE;
8464             col->ubchanged = FALSE;
8465          }
8466       }
8467       /* maybe lb/ub/objchanged should all be set to false when lpipos is -1 */
8468    }
8469 
8470    /* change objective values in LP */
8471    if( nobjchg > 0 )
8472    {
8473       SCIPsetDebugMsg(set, "flushing objective changes: change %d objective values of %d changed columns\n", nobjchg, lp->nchgcols);
8474       SCIP_CALL( SCIPlpiChgObj(lp->lpi, nobjchg, objind, obj) );
8475 
8476       /* mark the LP unsolved */
8477       lp->solved = FALSE;
8478       lp->dualfeasible = FALSE;
8479       lp->dualchecked = FALSE;
8480       lp->lpobjval = SCIP_INVALID;
8481       lp->lpsolstat = SCIP_LPSOLSTAT_NOTSOLVED;
8482    }
8483 
8484    /* change bounds in LP */
8485    if( nbdchg > 0 )
8486    {
8487       SCIPsetDebugMsg(set, "flushing bound changes: change %d bounds of %d changed columns\n", nbdchg, lp->nchgcols);
8488       SCIP_CALL( SCIPlpiChgBounds(lp->lpi, nbdchg, bdind, lb, ub) );
8489 
8490       /* mark the LP unsolved */
8491       lp->solved = FALSE;
8492       lp->primalfeasible = FALSE;
8493       lp->primalchecked = FALSE;
8494       lp->lpobjval = SCIP_INVALID;
8495       lp->lpsolstat = SCIP_LPSOLSTAT_NOTSOLVED;
8496    }
8497 
8498    lp->nchgcols = 0;
8499 
8500    /* free temporary memory */
8501    SCIPsetFreeBufferArray(set, &ub);
8502    SCIPsetFreeBufferArray(set, &lb);
8503    SCIPsetFreeBufferArray(set, &bdind);
8504    SCIPsetFreeBufferArray(set, &obj);
8505    SCIPsetFreeBufferArray(set, &objind);
8506 
8507    return SCIP_OKAY;
8508 }
8509 
8510 /** applies all cached row side changes to the LP */
8511 static
lpFlushChgRows(SCIP_LP * lp,SCIP_SET * set)8512 SCIP_RETCODE lpFlushChgRows(
8513    SCIP_LP*              lp,                 /**< current LP data */
8514    SCIP_SET*             set                 /**< global SCIP settings */
8515    )
8516 {
8517 #ifndef NDEBUG
8518    SCIP_Bool lpinone = (strcmp( SCIPlpiGetSolverName(), "NONE") == 0);
8519 #endif
8520    SCIP_ROW* row;
8521    int* ind;
8522    SCIP_Real* lhs;
8523    SCIP_Real* rhs;
8524    SCIP_Real lpiinf;
8525    int i;
8526    int nchg;
8527 
8528    assert(lp != NULL);
8529 
8530    if( lp->nchgrows == 0 )
8531       return SCIP_OKAY;
8532 
8533    /* get the solver's infinity value */
8534    lpiinf = SCIPlpiInfinity(lp->lpi);
8535 
8536    /* get temporary memory for changes */
8537    SCIP_CALL( SCIPsetAllocBufferArray(set, &ind, lp->nrows) );
8538    SCIP_CALL( SCIPsetAllocBufferArray(set, &lhs, lp->nrows) );
8539    SCIP_CALL( SCIPsetAllocBufferArray(set, &rhs, lp->nrows) );
8540 
8541    /* collect all cached left and right hand side changes */
8542    nchg = 0;
8543    for( i = 0; i < lp->nchgrows; ++i )
8544    {
8545       row = lp->chgrows[i];
8546       assert(row != NULL);
8547 
8548       if( row->lpipos >= 0 )
8549       {
8550 #ifndef NDEBUG
8551          /* do not check consistency of data with LPI in case of LPI=none */
8552          if( !lpinone )
8553          {
8554             SCIP_Real lpilhs;
8555             SCIP_Real lpirhs;
8556 
8557             SCIP_CALL( SCIPlpiGetSides(lp->lpi, row->lpipos, row->lpipos, &lpilhs, &lpirhs) );
8558             assert(SCIPsetIsSumEQ(set, lpilhs, row->flushedlhs));
8559             assert(SCIPsetIsSumEQ(set, lpirhs, row->flushedrhs));
8560          }
8561 #endif
8562          if( row->lhschanged || row->rhschanged )
8563          {
8564             SCIP_Real newlhs;
8565             SCIP_Real newrhs;
8566 
8567             newlhs = (SCIPsetIsInfinity(set, -row->lhs) ? -lpiinf : row->lhs - row->constant);
8568             newrhs = (SCIPsetIsInfinity(set, row->rhs) ? lpiinf : row->rhs - row->constant);
8569             if( row->flushedlhs != newlhs || row->flushedrhs != newrhs ) /*lint !e777*/
8570             {
8571                assert(nchg < lp->nrows);
8572                ind[nchg] = row->lpipos;
8573                lhs[nchg] = newlhs;
8574                rhs[nchg] = newrhs;
8575                nchg++;
8576                row->flushedlhs = newlhs;
8577                row->flushedrhs = newrhs;
8578             }
8579             row->lhschanged = FALSE;
8580             row->rhschanged = FALSE;
8581          }
8582       }
8583    }
8584 
8585    /* change left and right hand sides in LP */
8586    if( nchg > 0 )
8587    {
8588       SCIPsetDebugMsg(set, "flushing side changes: change %d sides of %d rows\n", nchg, lp->nchgrows);
8589       SCIP_CALL( SCIPlpiChgSides(lp->lpi, nchg, ind, lhs, rhs) );
8590 
8591       /* mark the LP unsolved */
8592       lp->solved = FALSE;
8593       lp->primalfeasible = FALSE;
8594       lp->primalchecked = FALSE;
8595       lp->lpobjval = SCIP_INVALID;
8596       lp->lpsolstat = SCIP_LPSOLSTAT_NOTSOLVED;
8597    }
8598 
8599    lp->nchgrows = 0;
8600 
8601    /* free temporary memory */
8602    SCIPsetFreeBufferArray(set, &rhs);
8603    SCIPsetFreeBufferArray(set, &lhs);
8604    SCIPsetFreeBufferArray(set, &ind);
8605 
8606    return SCIP_OKAY;
8607 }
8608 
8609 /** copy integrality information to the LP */
8610 static
lpCopyIntegrality(SCIP_LP * lp,SCIP_SET * set)8611 SCIP_RETCODE lpCopyIntegrality(
8612    SCIP_LP*              lp,                 /**< current LP data */
8613    SCIP_SET*             set                 /**< global SCIP settings */
8614    )
8615 {
8616    int i;
8617    int nintegers;
8618    int* integerInfo;
8619    SCIP_VAR* var;
8620 
8621    assert(lp != NULL);
8622 
8623    SCIP_CALL( SCIPsetAllocBufferArray(set, &integerInfo, lp->ncols) );
8624 
8625    /* count total number of integralities */
8626    nintegers = 0;
8627 
8628    for( i = 0; i < lp->ncols; ++i )
8629    {
8630       var = SCIPcolGetVar(lp->cols[i]);
8631       if( SCIPvarIsIntegral(var) || SCIPvarIsBinary(var) )
8632       {
8633          integerInfo[i] = 1;
8634          ++nintegers;
8635       }
8636       else
8637          integerInfo[i] = 0;
8638    }
8639 
8640    /* only pass integrality information if integer variables are present */
8641    if( nintegers > 0 )
8642    {
8643       SCIP_CALL( SCIPlpiSetIntegralityInformation(lp->lpi, lp->ncols, integerInfo) );
8644    }
8645    else
8646    {
8647       SCIP_CALL( SCIPlpiSetIntegralityInformation(lp->lpi, 0, NULL) );
8648    }
8649 
8650    SCIPsetFreeBufferArray(set, &integerInfo);
8651 
8652    /* mark integralities to be updated */
8653    lp->updateintegrality = FALSE;
8654 
8655    return SCIP_OKAY;
8656 }
8657 
8658 /** applies all cached changes to the LP solver */
SCIPlpFlush(SCIP_LP * lp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue)8659 SCIP_RETCODE SCIPlpFlush(
8660    SCIP_LP*              lp,                 /**< current LP data */
8661    BMS_BLKMEM*           blkmem,             /**< block memory */
8662    SCIP_SET*             set,                /**< global SCIP settings */
8663    SCIP_EVENTQUEUE*      eventqueue          /**< event queue */
8664    )
8665 {
8666    assert(lp != NULL);
8667    assert(blkmem != NULL);
8668 
8669    SCIPsetDebugMsg(set, "flushing LP changes: old (%d cols, %d rows), nchgcols=%d, nchgrows=%d, firstchgcol=%d, firstchgrow=%d, new (%d cols, %d rows), flushed=%u\n",
8670       lp->nlpicols, lp->nlpirows, lp->nchgcols, lp->nchgrows, lp->lpifirstchgcol, lp->lpifirstchgrow, lp->ncols, lp->nrows, lp->flushed);
8671 
8672    if( !lp->flushed )
8673    {
8674       lp->flushdeletedcols = FALSE;
8675       lp->flushaddedcols = FALSE;
8676       lp->flushdeletedrows = FALSE;
8677       lp->flushaddedrows = FALSE;
8678 
8679       SCIP_CALL( lpFlushDelCols(lp) );
8680       SCIP_CALL( lpFlushDelRows(lp, blkmem, set) );
8681       SCIP_CALL( lpFlushChgCols(lp, set) );
8682       SCIP_CALL( lpFlushChgRows(lp, set) );
8683       SCIP_CALL( lpFlushAddCols(lp, blkmem, set, eventqueue) );
8684       SCIP_CALL( lpFlushAddRows(lp, blkmem, set, eventqueue) );
8685 
8686       lp->flushed = TRUE;
8687 
8688       checkLinks(lp);
8689    }
8690 
8691    /* if the cutoff bound was changed in between and it is not disabled (e.g. for column generation),
8692     * we want to re-optimize the LP even if nothing else has changed */
8693    if( lp->cutoffbound != lp->lpiobjlim && lp->ncols > 0 && ! lpCutoffDisabled(set) ) /*lint !e777*/
8694    {
8695       lp->solved = FALSE;
8696       lp->lpsolstat = SCIP_LPSOLSTAT_NOTSOLVED;
8697    }
8698 
8699    assert(lp->nlpicols == lp->ncols);
8700    assert(lp->lpifirstchgcol == lp->nlpicols);
8701    assert(lp->nlpirows == lp->nrows);
8702    assert(lp->lpifirstchgrow == lp->nlpirows);
8703    assert(lp->nchgcols == 0);
8704    assert(lp->nchgrows == 0);
8705 #ifndef NDEBUG
8706    {
8707       int ncols;
8708       int nrows;
8709 
8710       SCIP_CALL( SCIPlpiGetNCols(lp->lpi, &ncols) );
8711       SCIP_CALL( SCIPlpiGetNRows(lp->lpi, &nrows) );
8712       assert(ncols == lp->ncols);
8713       assert(nrows == lp->nrows);
8714    }
8715 #endif
8716 
8717    return SCIP_OKAY;
8718 }
8719 
8720 /** marks the LP to be flushed, even if the LP thinks it is not flushed */
SCIPlpMarkFlushed(SCIP_LP * lp,SCIP_SET * set)8721 SCIP_RETCODE SCIPlpMarkFlushed(
8722    SCIP_LP*              lp,                 /**< current LP data */
8723    SCIP_SET*             set                 /**< global SCIP settings */
8724    )
8725 {
8726 #ifndef NDEBUG
8727    SCIP_Bool lpinone = (strcmp( SCIPlpiGetSolverName(), "NONE") == 0);
8728 #endif
8729    int i;
8730 
8731    assert(lp != NULL);
8732 
8733 #ifndef NDEBUG
8734    /* check, if there are really no column or row deletions or coefficient changes left */
8735    while( lp->lpifirstchgcol < lp->nlpicols
8736       && lp->lpifirstchgcol < lp->ncols
8737       && lp->cols[lp->lpifirstchgcol]->lpipos == lp->lpifirstchgcol
8738       && !lp->cols[lp->lpifirstchgcol]->coefchanged )
8739    {
8740       assert(lp->cols[lp->lpifirstchgcol] == lp->lpicols[lp->lpifirstchgcol]);
8741       lp->lpifirstchgcol++;
8742    }
8743    assert(lp->nlpicols == lp->lpifirstchgcol);
8744 
8745    while( lp->lpifirstchgrow < lp->nlpirows
8746       && lp->lpifirstchgrow < lp->nrows
8747       && lp->rows[lp->lpifirstchgrow]->lpipos == lp->lpifirstchgrow
8748       && !lp->rows[lp->lpifirstchgrow]->coefchanged )
8749    {
8750       assert(lp->rows[lp->lpifirstchgrow] == lp->lpirows[lp->lpifirstchgrow]);
8751       lp->lpifirstchgrow++;
8752    }
8753    assert(lp->nlpirows == lp->lpifirstchgrow);
8754 #endif
8755 
8756    lp->lpifirstchgcol = lp->nlpicols;
8757    lp->lpifirstchgrow = lp->nlpirows;
8758 
8759    /* check, if there are really no column or row additions left */
8760    assert(lp->ncols == lp->nlpicols);
8761    assert(lp->nrows == lp->nlpirows);
8762 
8763    /* mark the changed columns to be unchanged, and check, if this is really correct */
8764    for( i = 0; i < lp->nchgcols; ++i )
8765    {
8766       SCIP_COL* col;
8767 
8768       col = lp->chgcols[i];
8769       assert(col != NULL);
8770       assert(col->var != NULL);
8771       assert(SCIPvarGetStatus(col->var) == SCIP_VARSTATUS_COLUMN);
8772       assert(SCIPvarGetCol(col->var) == col);
8773 
8774       if( col->lpipos >= 0 )
8775       {
8776 #ifndef NDEBUG
8777          /* do not check consistency of data with LPI in case of LPI=none */
8778          if( !lpinone )
8779          {
8780             SCIP_Real lpiobj;
8781             SCIP_Real lpilb;
8782             SCIP_Real lpiub;
8783 
8784             SCIP_CALL( SCIPlpiGetObj(lp->lpi, col->lpipos, col->lpipos, &lpiobj) );
8785             SCIP_CALL( SCIPlpiGetBounds(lp->lpi, col->lpipos, col->lpipos, &lpilb, &lpiub) );
8786             assert(SCIPsetIsSumEQ(set, lpiobj, col->flushedobj));
8787             assert(SCIPsetIsSumEQ(set, lpilb, col->flushedlb));
8788             assert(SCIPsetIsSumEQ(set, lpiub, col->flushedub));
8789             assert(col->flushedobj == col->obj); /*lint !e777*/
8790             assert(col->flushedlb == (SCIPsetIsInfinity(set, -col->lb) ? -SCIPlpiInfinity(lp->lpi) : col->lb)); /*lint !e777*/
8791             assert(col->flushedub == (SCIPsetIsInfinity(set, col->ub) ? SCIPlpiInfinity(lp->lpi) : col->ub)); /*lint !e777*/
8792          }
8793 #endif
8794          col->objchanged = FALSE;
8795          col->lbchanged = FALSE;
8796          col->ubchanged = FALSE;
8797       }
8798       /* maybe lb/ub/objchanged should  be set to false also when lpipos is -1 */
8799    }
8800    lp->nchgcols = 0;
8801 
8802    /* mark the changed rows to be unchanged, and check, if this is really correct */
8803    for( i = 0; i < lp->nchgrows; ++i )
8804    {
8805       SCIP_ROW* row;
8806 
8807       row = lp->chgrows[i];
8808       assert(row != NULL);
8809 
8810       if( row->lpipos >= 0 )
8811       {
8812 #ifndef NDEBUG
8813          /* do not check consistency of data with LPI in case of LPI=none */
8814          if( !lpinone )
8815          {
8816             SCIP_Real lpilhs;
8817             SCIP_Real lpirhs;
8818 
8819             SCIP_CALL( SCIPlpiGetSides(lp->lpi, row->lpipos, row->lpipos, &lpilhs, &lpirhs) );
8820             assert(SCIPsetIsSumEQ(set, lpilhs, row->flushedlhs));
8821             assert(SCIPsetIsSumEQ(set, lpirhs, row->flushedrhs));
8822             assert(row->flushedlhs == (SCIPsetIsInfinity(set, -row->lhs) ? -SCIPlpiInfinity(lp->lpi) : row->lhs - row->constant)); /*lint !e777*/
8823             assert(row->flushedrhs == (SCIPsetIsInfinity(set, row->rhs) ? SCIPlpiInfinity(lp->lpi) : row->rhs - row->constant)); /*lint !e777*/
8824          }
8825 #endif
8826          row->lhschanged = FALSE;
8827          row->rhschanged = FALSE;
8828       }
8829    }
8830    lp->nchgrows = 0;
8831 
8832    /* mark the LP to be flushed */
8833    lp->flushed = TRUE;
8834 
8835    checkLinks(lp);
8836 
8837    return SCIP_OKAY;
8838 }
8839 
8840 
8841 
8842 
8843 /*
8844  * LP methods
8845  */
8846 
8847 /** updates link data after addition of column */
8848 static
colUpdateAddLP(SCIP_COL * col,SCIP_SET * set)8849 void colUpdateAddLP(
8850    SCIP_COL*             col,                /**< LP column */
8851    SCIP_SET*             set                 /**< global SCIP settings */
8852    )
8853 {
8854    SCIP_ROW* row;
8855    int i;
8856    int pos;
8857 
8858    assert(col != NULL);
8859    assert(col->lppos >= 0);
8860 
8861    /* update column arrays of all linked rows */
8862    for( i = 0; i < col->len; ++i )
8863    {
8864       pos = col->linkpos[i];
8865       if( pos >= 0 )
8866       {
8867          row = col->rows[i];
8868          assert(row != NULL);
8869          assert(row->linkpos[pos] == i);
8870          assert(row->cols[pos] == col);
8871          assert(row->nlpcols <= pos && pos < row->len);
8872 
8873          row->nlpcols++;
8874          rowSwapCoefs(row, pos, row->nlpcols-1);
8875          assert(row->cols[row->nlpcols-1] == col);
8876 
8877          /* if no swap was necessary, mark lpcols to be unsorted */
8878          if( pos == row->nlpcols-1 )
8879             row->lpcolssorted = FALSE;
8880 
8881          /* update norms */
8882          rowAddNorms(row, set, col, row->vals[row->nlpcols-1], FALSE);
8883       }
8884    }
8885 }
8886 
8887 /** updates link data after addition of row */
8888 static
rowUpdateAddLP(SCIP_ROW * row)8889 void rowUpdateAddLP(
8890    SCIP_ROW*             row                 /**< LP row */
8891    )
8892 {
8893    SCIP_COL* col;
8894    int i;
8895    int pos;
8896 
8897    assert(row != NULL);
8898    assert(row->lppos >= 0);
8899 
8900    /* update row arrays of all linked columns */
8901    for( i = 0; i < row->len; ++i )
8902    {
8903       pos = row->linkpos[i];
8904       if( pos >= 0 )
8905       {
8906          col = row->cols[i];
8907          assert(col != NULL);
8908          assert(col->linkpos[pos] == i);
8909          assert(col->rows[pos] == row);
8910          assert(col->nlprows <= pos && pos < col->len);
8911 
8912          col->nlprows++;
8913          colSwapCoefs(col, pos, col->nlprows-1);
8914 
8915          /* if no swap was necessary, mark lprows to be unsorted */
8916          if( pos == col->nlprows-1 )
8917             col->lprowssorted = FALSE;
8918       }
8919    }
8920 }
8921 
8922 /** updates link data after removal of column */
8923 static
colUpdateDelLP(SCIP_COL * col,SCIP_SET * set)8924 void colUpdateDelLP(
8925    SCIP_COL*             col,                /**< LP column */
8926    SCIP_SET*             set                 /**< global SCIP settings */
8927    )
8928 {
8929    SCIP_ROW* row;
8930    int i;
8931    int pos;
8932 
8933    assert(col != NULL);
8934    assert(col->lppos == -1);
8935 
8936    /* update column arrays of all linked rows */
8937    for( i = 0; i < col->len; ++i )
8938    {
8939       pos = col->linkpos[i];
8940       if( pos >= 0 )
8941       {
8942          row = col->rows[i];
8943          assert(row != NULL);
8944          assert(row->linkpos[pos] == i);
8945          assert(row->cols[pos] == col);
8946          assert(0 <= pos && pos < row->nlpcols);
8947 
8948          /* update norms */
8949          rowDelNorms(row, set, col, row->vals[pos], TRUE, FALSE, FALSE);
8950 
8951          row->nlpcols--;
8952          rowSwapCoefs(row, pos, row->nlpcols);
8953 
8954          /* if no swap was necessary, mark nonlpcols to be unsorted */
8955          if( pos == row->nlpcols )
8956             row->nonlpcolssorted = FALSE;
8957       }
8958    }
8959 }
8960 
8961 /** updates link data after removal of row */
8962 static
rowUpdateDelLP(SCIP_ROW * row)8963 void rowUpdateDelLP(
8964    SCIP_ROW*             row                 /**< LP row */
8965    )
8966 {
8967    SCIP_COL* col;
8968    int i;
8969    int pos;
8970 
8971    assert(row != NULL);
8972    assert(row->lppos == -1);
8973 
8974    /* update row arrays of all linked columns */
8975    for( i = 0; i < row->len; ++i )
8976    {
8977       pos = row->linkpos[i];
8978       if( pos >= 0 )
8979       {
8980          col = row->cols[i];
8981          assert(col != NULL);
8982          assert(0 <= pos && pos < col->nlprows);
8983          assert(col->linkpos[pos] == i);
8984          assert(col->rows[pos] == row);
8985 
8986          col->nlprows--;
8987          colSwapCoefs(col, pos, col->nlprows);
8988 
8989          /* if no swap was necessary, mark lprows to be unsorted */
8990          if( pos == col->nlprows )
8991             col->nonlprowssorted = FALSE;
8992       }
8993    }
8994 }
8995 
8996 static
allocDiveChgSideArrays(SCIP_LP * lp,int initsize)8997 SCIP_RETCODE allocDiveChgSideArrays(
8998    SCIP_LP*              lp,                 /**< LP data object */
8999    int                   initsize            /**< initial size of the arrays */
9000    )
9001 {
9002    assert(lp != NULL);
9003    assert(lp->divechgsides == NULL);
9004    assert(lp->divechgsidetypes == NULL);
9005    assert(lp->divechgrows == NULL);
9006    assert(lp->ndivechgsides == 0);
9007    assert(lp->divechgsidessize == 0);
9008    assert(initsize > 0);
9009 
9010    lp->divechgsidessize = initsize;
9011    SCIP_ALLOC( BMSallocMemoryArray(&lp->divechgsides, lp->divechgsidessize) );
9012    SCIP_ALLOC( BMSallocMemoryArray(&lp->divechgsidetypes, lp->divechgsidessize) );
9013    SCIP_ALLOC( BMSallocMemoryArray(&lp->divechgrows, lp->divechgsidessize) );
9014 
9015    return SCIP_OKAY;
9016 }
9017 
9018 static
reallocDiveChgSideArrays(SCIP_LP * lp,int minsize,SCIP_Real growfact)9019 SCIP_RETCODE reallocDiveChgSideArrays(
9020    SCIP_LP*              lp,                 /**< LP data object */
9021    int                   minsize,            /**< minimal number of elements */
9022    SCIP_Real             growfact            /**< growing factor */
9023    )
9024 {
9025    assert(lp != NULL);
9026    assert(lp->divechgsides != NULL);
9027    assert(lp->divechgsidetypes != NULL);
9028    assert(lp->divechgrows != NULL);
9029    assert(lp->ndivechgsides > 0);
9030    assert(lp->divechgsidessize > 0);
9031    assert(minsize > 0);
9032 
9033    if( minsize <= lp->divechgsidessize )
9034       return SCIP_OKAY;
9035 
9036    lp->divechgsidessize = MAX(minsize, (int)(lp->divechgsidessize * growfact));
9037    SCIP_ALLOC( BMSreallocMemoryArray(&lp->divechgsides, lp->divechgsidessize) );
9038    SCIP_ALLOC( BMSreallocMemoryArray(&lp->divechgsidetypes, lp->divechgsidessize) );
9039    SCIP_ALLOC( BMSreallocMemoryArray(&lp->divechgrows, lp->divechgsidessize) );
9040 
9041    return SCIP_OKAY;
9042 }
9043 
9044 static
freeDiveChgSideArrays(SCIP_LP * lp)9045 void freeDiveChgSideArrays(
9046    SCIP_LP*              lp                  /**< LP data object */
9047    )
9048 {
9049    assert(lp != NULL);
9050    assert(lp->divechgsides != NULL);
9051    assert(lp->divechgsidetypes != NULL);
9052    assert(lp->divechgrows != NULL);
9053    assert(lp->ndivechgsides == 0);
9054    assert(lp->divechgsidessize > 0);
9055 
9056    BMSfreeMemoryArrayNull(&lp->divechgsides);
9057    BMSfreeMemoryArrayNull(&lp->divechgsidetypes);
9058    BMSfreeMemoryArrayNull(&lp->divechgrows);
9059    lp->divechgsidessize = 0;
9060 }
9061 
9062 #define DIVESTACKINITSIZE 100
9063 
9064 /** creates empty LP data object */
SCIPlpCreate(SCIP_LP ** lp,SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr,SCIP_STAT * stat,const char * name)9065 SCIP_RETCODE SCIPlpCreate(
9066    SCIP_LP**             lp,                 /**< pointer to LP data object */
9067    SCIP_SET*             set,                /**< global SCIP settings */
9068    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
9069    SCIP_STAT*            stat,               /**< problem statistics */
9070    const char*           name                /**< problem name */
9071    )
9072 {
9073    SCIP_Bool success;
9074 
9075    assert(lp != NULL);
9076    assert(set != NULL);
9077    assert(stat != NULL);
9078    assert(name != NULL);
9079 
9080    SCIP_ALLOC( BMSallocMemory(lp) );
9081 
9082    /* open LP Solver interface */
9083    SCIP_CALL( SCIPlpiCreate(&(*lp)->lpi, messagehdlr, name, SCIP_OBJSEN_MINIMIZE) );
9084 
9085    (*lp)->lpicols = NULL;
9086    (*lp)->lpirows = NULL;
9087    (*lp)->chgcols = NULL;
9088    (*lp)->chgrows = NULL;
9089    (*lp)->cols = NULL;
9090    (*lp)->soldirection = NULL;
9091    (*lp)->lazycols = NULL;
9092    (*lp)->rows = NULL;
9093    (*lp)->lpobjval = 0.0;
9094    (*lp)->glbpseudoobjval = 0.0;
9095    (*lp)->relglbpseudoobjval = 0.0;
9096    (*lp)->glbpseudoobjvalid = TRUE;
9097    (*lp)->glbpseudoobjvalinf = 0;
9098    (*lp)->pseudoobjval = 0.0;
9099    (*lp)->relpseudoobjval = 0.0;
9100    (*lp)->pseudoobjvalid = TRUE;
9101    (*lp)->pseudoobjvalinf = 0;
9102    (*lp)->looseobjval = 0.0;
9103    (*lp)->rellooseobjval = 0.0;
9104    (*lp)->looseobjvalid = TRUE;
9105    (*lp)->looseobjvalinf = 0;
9106    (*lp)->nloosevars = 0;
9107    (*lp)->rootlpobjval = SCIP_INVALID;
9108    (*lp)->rootlooseobjval = SCIP_INVALID;
9109    (*lp)->cutoffbound = SCIPsetInfinity(set);
9110    (*lp)->feastol = SCIP_INVALID; /* to have it initialized */
9111    SCIPlpResetFeastol(*lp, set);
9112    (*lp)->validdegeneracylp = -1;
9113    (*lp)->objsqrnorm = 0.0;
9114    (*lp)->objsumnorm = 0.0;
9115    (*lp)->lpicolssize = 0;
9116    (*lp)->nlpicols = 0;
9117    (*lp)->lpirowssize = 0;
9118    (*lp)->nlpirows = 0;
9119    (*lp)->lpifirstchgcol = 0;
9120    (*lp)->lpifirstchgrow = 0;
9121    (*lp)->colssize = 0;
9122    (*lp)->soldirectionsize = 0;
9123    (*lp)->ncols = 0;
9124    (*lp)->lazycolssize = 0;
9125    (*lp)->nlazycols = 0;
9126    (*lp)->rowssize = 0;
9127    (*lp)->nrows = 0;
9128    (*lp)->chgcolssize = 0;
9129    (*lp)->nchgcols = 0;
9130    (*lp)->chgrowssize = 0;
9131    (*lp)->nchgrows = 0;
9132    (*lp)->firstnewcol = 0;
9133    (*lp)->firstnewrow = 0;
9134    (*lp)->nremovablecols = 0;
9135    (*lp)->nremovablerows = 0;
9136    (*lp)->validsollp = stat->lpcount; /* the initial (empty) SCIP_LP is solved with primal and dual solution of zero */
9137    (*lp)->validfarkaslp = -1;
9138    (*lp)->validsoldirlp = -1;
9139    (*lp)->validsoldirsol = NULL;
9140    (*lp)->objsqrnormunreliable = FALSE;
9141    (*lp)->flushdeletedcols = FALSE;
9142    (*lp)->flushaddedcols = FALSE;
9143    (*lp)->flushdeletedrows = FALSE;
9144    (*lp)->flushaddedrows = FALSE;
9145    (*lp)->updateintegrality = TRUE;
9146    (*lp)->flushed = TRUE;
9147    (*lp)->lpsolstat = SCIP_LPSOLSTAT_OPTIMAL;
9148    (*lp)->solved = TRUE;
9149    (*lp)->primalfeasible = TRUE;
9150    (*lp)->primalchecked = TRUE;
9151    (*lp)->dualfeasible = TRUE;
9152    (*lp)->dualchecked = TRUE;
9153    (*lp)->solisbasic = FALSE;
9154    (*lp)->rootlpisrelax = TRUE;
9155    (*lp)->isrelax = TRUE;
9156    (*lp)->installing = FALSE;
9157    (*lp)->strongbranching = FALSE;
9158    (*lp)->strongbranchprobing = FALSE;
9159    (*lp)->probing = FALSE;
9160    (*lp)->diving = FALSE;
9161    (*lp)->divingobjchg = FALSE;
9162    (*lp)->divinglazyapplied = FALSE;
9163    (*lp)->divelpistate = NULL;
9164    (*lp)->divelpwasprimfeas = TRUE;
9165    (*lp)->divelpwasprimchecked = TRUE;
9166    (*lp)->divelpwasdualfeas = TRUE;
9167    (*lp)->divelpwasdualchecked = TRUE;
9168    (*lp)->divechgsides = NULL;
9169    (*lp)->divechgsidetypes = NULL;
9170    (*lp)->divechgrows = NULL;
9171    (*lp)->ndivechgsides = 0;
9172    (*lp)->divechgsidessize = 0;
9173    (*lp)->ndivingrows = 0;
9174    (*lp)->divinglpiitlim = INT_MAX;
9175    (*lp)->resolvelperror = FALSE;
9176    (*lp)->divenolddomchgs = 0;
9177    (*lp)->adjustlpval = FALSE;
9178    (*lp)->lpiobjlim = SCIPlpiInfinity((*lp)->lpi);
9179    (*lp)->lpifeastol = (*lp)->feastol;
9180    (*lp)->lpidualfeastol = SCIPsetDualfeastol(set);
9181    (*lp)->lpibarrierconvtol = SCIPsetBarrierconvtol(set);
9182    (*lp)->lpifromscratch = FALSE;
9183    (*lp)->lpifastmip = set->lp_fastmip;
9184    (*lp)->lpiscaling = set->lp_scaling;
9185    (*lp)->lpipresolving = set->lp_presolving;
9186    (*lp)->lpilpinfo = set->disp_lpinfo;
9187    (*lp)->lpirowrepswitch = set->lp_rowrepswitch;
9188    (*lp)->lpisolutionpolishing = (set->lp_solutionpolishing > 0);
9189    (*lp)->lpirefactorinterval = set->lp_refactorinterval;
9190    (*lp)->lpiconditionlimit = set->lp_conditionlimit;
9191    (*lp)->lpimarkowitz = set->lp_markowitz;
9192    (*lp)->lpiitlim = INT_MAX;
9193    (*lp)->lpipricing = SCIP_PRICING_AUTO;
9194    (*lp)->lastlpalgo = SCIP_LPALGO_DUALSIMPLEX;
9195    (*lp)->lpithreads = set->lp_threads;
9196    (*lp)->lpitiming = (int) set->time_clocktype;
9197    (*lp)->lpirandomseed = set->random_randomseed;
9198    (*lp)->storedsolvals = NULL;
9199 
9200    /* allocate arrays for diving */
9201    SCIP_CALL( allocDiveChgSideArrays(*lp, DIVESTACKINITSIZE) );
9202 
9203    /* set default parameters in LP solver */
9204    SCIP_CALL( lpSetRealpar(*lp, SCIP_LPPAR_OBJLIM, (*lp)->lpiobjlim, &success) );
9205    if( !success )
9206    {
9207       SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
9208          "LP Solver <%s>: objective limit cannot be set -- can lead to unnecessary simplex iterations\n",
9209          SCIPlpiGetSolverName());
9210    }
9211    SCIP_CALL( lpSetRealpar(*lp, SCIP_LPPAR_FEASTOL, (*lp)->lpifeastol, &success) );
9212    (*lp)->lpihasfeastol = success;
9213    if( !success )
9214    {
9215       SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
9216          "LP Solver <%s>: primal feasibility tolerance cannot be set -- tolerance of SCIP and LP solver may differ\n",
9217          SCIPlpiGetSolverName());
9218    }
9219    SCIP_CALL( lpSetRealpar(*lp, SCIP_LPPAR_DUALFEASTOL, (*lp)->lpidualfeastol, &success) );
9220    (*lp)->lpihasdualfeastol = success;
9221    if( !success )
9222    {
9223       SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
9224          "LP Solver <%s>: dual feasibility tolerance cannot be set -- tolerance of SCIP and LP solver may differ\n",
9225          SCIPlpiGetSolverName());
9226    }
9227    SCIP_CALL( lpSetRealpar(*lp, SCIP_LPPAR_BARRIERCONVTOL, (*lp)->lpibarrierconvtol, &success) );
9228    (*lp)->lpihasbarrierconvtol = success;
9229    if( !success )
9230    {
9231       SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
9232          "LP Solver <%s>: barrier convergence tolerance cannot be set -- tolerance of SCIP and LP solver may differ\n",
9233          SCIPlpiGetSolverName());
9234    }
9235    SCIP_CALL( lpSetBoolpar(*lp, SCIP_LPPAR_FROMSCRATCH, (*lp)->lpifromscratch, &success) );
9236    SCIP_CALL( lpSetIntpar(*lp, SCIP_LPPAR_FASTMIP, (*lp)->lpifastmip, &success) );
9237    (*lp)->lpihasfastmip = success;
9238    if( !success )
9239    {
9240       SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
9241          "LP Solver <%s>: fastmip setting not available -- SCIP parameter has no effect\n",
9242          SCIPlpiGetSolverName());
9243    }
9244    SCIP_CALL( lpSetIntpar(*lp, SCIP_LPPAR_SCALING, (*lp)->lpiscaling, &success) );
9245    (*lp)->lpihasscaling = success;
9246    if( !success )
9247    {
9248       SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
9249          "LP Solver <%s>: scaling not available -- SCIP parameter has no effect\n",
9250          SCIPlpiGetSolverName());
9251    }
9252    SCIP_CALL( lpSetBoolpar(*lp, SCIP_LPPAR_PRESOLVING, (*lp)->lpipresolving, &success) );
9253    (*lp)->lpihaspresolving = success;
9254    if( !success )
9255    {
9256       SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
9257          "LP Solver <%s>: presolving not available -- SCIP parameter has no effect\n",
9258          SCIPlpiGetSolverName());
9259    }
9260    SCIP_CALL( lpSetIntpar(*lp, SCIP_LPPAR_TIMING, (*lp)->lpitiming, &success) );
9261    if( !success )
9262    {
9263       SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
9264          "LP Solver <%s>: clock type cannot be set\n",
9265          SCIPlpiGetSolverName());
9266    }
9267    SCIP_CALL( lpSetIntpar(*lp, SCIP_LPPAR_LPITLIM, (*lp)->lpiitlim, &success) );
9268    if( !success )
9269    {
9270       SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
9271          "LP Solver <%s>: iteration limit cannot be set -- can lead to unnecessary simplex iterations\n",
9272          SCIPlpiGetSolverName());
9273    }
9274    SCIP_CALL( lpSetIntpar(*lp, SCIP_LPPAR_PRICING, (int)(*lp)->lpipricing, &success) );
9275    if( !success )
9276    {
9277       SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
9278          "LP Solver <%s>: pricing strategy cannot be set -- SCIP parameter has no effect\n",
9279          SCIPlpiGetSolverName());
9280    }
9281    SCIP_CALL( lpSetBoolpar(*lp, SCIP_LPPAR_LPINFO, (*lp)->lpilpinfo, &success) );
9282    if( !success )
9283    {
9284       SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
9285          "LP Solver <%s>: lpinfo setting not available -- SCIP parameter has no effect\n",
9286          SCIPlpiGetSolverName());
9287    }
9288    SCIP_CALL( lpSetRealpar(*lp, SCIP_LPPAR_ROWREPSWITCH, (*lp)->lpirowrepswitch, &success) );
9289    (*lp)->lpihasrowrep = success;
9290    if( !success )
9291    {
9292       SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
9293          "LP Solver <%s>: row representation of the basis not available -- SCIP parameter lp/rowrepswitch has no effect\n",
9294          SCIPlpiGetSolverName());
9295    }
9296    SCIP_CALL( lpSetIntpar(*lp, SCIP_LPPAR_POLISHING, ((*lp)->lpisolutionpolishing ? 1 : 0), &success) );
9297    (*lp)->lpihaspolishing = success;
9298    if( !success )
9299    {
9300       SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
9301          "LP Solver <%s>: solution polishing not available -- SCIP parameter lp/solutionpolishing has no effect\n",
9302          SCIPlpiGetSolverName());
9303    }
9304    SCIP_CALL( lpSetIntpar(*lp, SCIP_LPPAR_REFACTOR, (*lp)->lpirefactorinterval, &success) );
9305    (*lp)->lpihasrefactor = success;
9306    if( !success )
9307    {
9308       SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
9309          "LP Solver <%s>: refactorization interval not available -- SCIP parameter lp/refactorinterval has no effect\n",
9310          SCIPlpiGetSolverName());
9311    }
9312    SCIP_CALL( lpSetRealpar(*lp, SCIP_LPPAR_CONDITIONLIMIT, (*lp)->lpiconditionlimit, &success) );
9313    if( !success )
9314    {
9315       SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
9316          "LP Solver <%s>: condition number limit for the basis not available -- SCIP parameter lp/conditionlimit has no effect\n",
9317          SCIPlpiGetSolverName());
9318    }
9319    SCIP_CALL( lpSetRealpar(*lp, SCIP_LPPAR_MARKOWITZ, (*lp)->lpimarkowitz, &success) );
9320    if( !success )
9321    {
9322       SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
9323          "LP Solver <%s>: markowitz threshhold not available -- SCIP parameter lp/minmarkowitz has no effect\n",
9324          SCIPlpiGetSolverName());
9325    }
9326    SCIP_CALL( lpSetIntpar(*lp, SCIP_LPPAR_THREADS, (*lp)->lpithreads, &success) );
9327    if( !success )
9328    {
9329       SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
9330          "LP Solver <%s>: number of threads settings not available -- SCIP parameter has no effect\n",
9331          SCIPlpiGetSolverName());
9332    }
9333    /* keep the default LP random seed if this parameter is set to 0 (current default) */
9334    if( (*lp)->lpirandomseed != 0 )
9335    {
9336       SCIP_CALL( lpSetIntpar(*lp, SCIP_LPPAR_RANDOMSEED, (*lp)->lpirandomseed, &success) );
9337       if( !success )
9338       {
9339          SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
9340             "LP Solver <%s>: random seed parameter not available -- SCIP parameter has no effect\n",
9341             SCIPlpiGetSolverName());
9342       }
9343    }
9344 
9345    /* Check that infinity value of LP-solver is at least as large as the one used in SCIP. This is necessary, because we
9346     * transfer SCIP infinity values to the ones by the LPI, but not the converse. */
9347    if ( set->num_infinity > SCIPlpiInfinity((*lp)->lpi) )
9348    {
9349       SCIPerrorMessage("The infinity value of the LP solver has to be at least as large as the one of SCIP.\n");
9350       return SCIP_PARAMETERWRONGVAL;
9351    }
9352 
9353    return SCIP_OKAY;
9354 }
9355 
9356 /** frees LP data object */
SCIPlpFree(SCIP_LP ** lp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_EVENTFILTER * eventfilter)9357 SCIP_RETCODE SCIPlpFree(
9358    SCIP_LP**             lp,                 /**< pointer to LP data object */
9359    BMS_BLKMEM*           blkmem,             /**< block memory */
9360    SCIP_SET*             set,                /**< global SCIP settings */
9361    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
9362    SCIP_EVENTFILTER*     eventfilter         /**< global event filter */
9363    )
9364 {
9365    int i;
9366 
9367    assert(lp != NULL);
9368    assert(*lp != NULL);
9369 
9370    SCIP_CALL( SCIPlpClear(*lp, blkmem, set, eventqueue, eventfilter) );
9371 
9372    freeDiveChgSideArrays(*lp);
9373 
9374    /* release LPI rows */
9375    for( i = 0; i < (*lp)->nlpirows; ++i )
9376    {
9377       SCIP_CALL( SCIProwRelease(&(*lp)->lpirows[i], blkmem, set, *lp) );
9378    }
9379 
9380    if( (*lp)->lpi != NULL )
9381    {
9382       SCIP_CALL( SCIPlpiFree(&(*lp)->lpi) );
9383    }
9384 
9385    BMSfreeMemoryNull(&(*lp)->storedsolvals);
9386    BMSfreeMemoryArrayNull(&(*lp)->lpicols);
9387    BMSfreeMemoryArrayNull(&(*lp)->lpirows);
9388    BMSfreeMemoryArrayNull(&(*lp)->chgcols);
9389    BMSfreeMemoryArrayNull(&(*lp)->chgrows);
9390    BMSfreeMemoryArrayNull(&(*lp)->lazycols);
9391    BMSfreeMemoryArrayNull(&(*lp)->cols);
9392    BMSfreeMemoryArrayNull(&(*lp)->rows);
9393    BMSfreeMemoryArrayNull(&(*lp)->soldirection);
9394    BMSfreeMemory(lp);
9395 
9396    return SCIP_OKAY;
9397 }
9398 
9399 /** resets the LP to the empty LP by removing all columns and rows from LP, releasing all rows, and flushing the
9400  *  changes to the LP solver
9401  */
SCIPlpReset(SCIP_LP * lp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_EVENTQUEUE * eventqueue,SCIP_EVENTFILTER * eventfilter)9402 SCIP_RETCODE SCIPlpReset(
9403    SCIP_LP*              lp,                 /**< LP data */
9404    BMS_BLKMEM*           blkmem,             /**< block memory */
9405    SCIP_SET*             set,                /**< global SCIP settings */
9406    SCIP_STAT*            stat,               /**< problem statistics */
9407    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
9408    SCIP_EVENTFILTER*     eventfilter         /**< global event filter */
9409    )
9410 {
9411    assert(stat != NULL);
9412 
9413    SCIP_CALL( SCIPlpClear(lp, blkmem, set, eventqueue, eventfilter) );
9414    SCIP_CALL( SCIPlpFlush(lp, blkmem, set, eventqueue) );
9415 
9416    /* mark the empty LP to be solved */
9417    lp->lpsolstat = SCIP_LPSOLSTAT_OPTIMAL;
9418    lp->lpobjval = 0.0;
9419    lp->validsollp = stat->lpcount; /* the initial (empty) SCIP_LP is solved with primal and dual solution of zero */
9420    lp->validfarkaslp = -1;
9421    lp->validdegeneracylp = -1;
9422    lp->validsoldirlp = -1;
9423    lp->validsoldirsol = NULL;
9424    lp->solved = TRUE;
9425    lp->primalfeasible = TRUE;
9426    lp->primalchecked = TRUE;
9427    lp->dualfeasible = TRUE;
9428    lp->dualchecked = TRUE;
9429    lp->solisbasic = FALSE;
9430    lp->lastlpalgo = SCIP_LPALGO_DUALSIMPLEX;
9431 
9432    return SCIP_OKAY;
9433 }
9434 
9435 /** adds a column to the LP */
SCIPlpAddCol(SCIP_LP * lp,SCIP_SET * set,SCIP_COL * col,int depth)9436 SCIP_RETCODE SCIPlpAddCol(
9437    SCIP_LP*              lp,                 /**< LP data */
9438    SCIP_SET*             set,                /**< global SCIP settings */
9439    SCIP_COL*             col,                /**< LP column */
9440    int                   depth               /**< depth in the tree where the column addition is performed */
9441    )
9442 {
9443    assert(lp != NULL);
9444    assert(!lp->diving);
9445    assert(col != NULL);
9446    assert(col->len == 0 || col->rows != NULL);
9447    assert(col->lppos == -1);
9448    assert(col->var != NULL);
9449    assert(SCIPvarGetStatus(col->var) == SCIP_VARSTATUS_COLUMN);
9450    assert(SCIPvarGetCol(col->var) == col);
9451    assert(SCIPvarIsIntegral(col->var) == col->integral);
9452 
9453    SCIPsetDebugMsg(set, "adding column <%s> to LP (%d rows, %d cols)\n", SCIPvarGetName(col->var), lp->nrows, lp->ncols);
9454 #ifdef SCIP_DEBUG
9455    {
9456       int i;
9457       SCIPsetDebugMsgPrint(set, "  (obj: %g) [%g,%g]", col->obj, col->lb, col->ub);
9458       for( i = 0; i < col->len; ++i )
9459          SCIPsetDebugMsgPrint(set, " %+g<%s>", col->vals[i], col->rows[i]->name);
9460       SCIPsetDebugMsgPrint(set, "\n");
9461    }
9462 #endif
9463 
9464    SCIP_CALL( ensureColsSize(lp, set, lp->ncols+1) );
9465    lp->cols[lp->ncols] = col;
9466    col->lppos = lp->ncols;
9467    col->lpdepth = depth;
9468    col->age = 0;
9469    lp->ncols++;
9470    if( col->removable )
9471       lp->nremovablecols++;
9472 
9473    if( !SCIPsetIsInfinity(set, -col->lazylb) || !SCIPsetIsInfinity(set, col->lazyub) )
9474    {
9475       SCIP_CALL( ensureLazycolsSize(lp, set, lp->nlazycols+1) );
9476       lp->lazycols[lp->nlazycols] = col;
9477       lp->nlazycols++;
9478    }
9479 
9480    /* mark the current LP unflushed */
9481    lp->flushed = FALSE;
9482 
9483    /* update column arrays of all linked rows */
9484    colUpdateAddLP(col, set);
9485 
9486    /* update the objective function vector norms */
9487    lpUpdateObjNorms(lp, set, 0.0, col->unchangedobj);
9488 
9489    checkLinks(lp);
9490 
9491    return SCIP_OKAY;
9492 }
9493 
9494 /** adds a row to the LP and captures it */
SCIPlpAddRow(SCIP_LP * lp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_EVENTFILTER * eventfilter,SCIP_ROW * row,int depth)9495 SCIP_RETCODE SCIPlpAddRow(
9496    SCIP_LP*              lp,                 /**< LP data */
9497    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
9498    SCIP_SET*             set,                /**< global SCIP settings */
9499    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
9500    SCIP_EVENTFILTER*     eventfilter,        /**< global event filter */
9501    SCIP_ROW*             row,                /**< LP row */
9502    int                   depth               /**< depth in the tree where the row addition is performed */
9503    )
9504 {
9505    assert(lp != NULL);
9506    assert(row != NULL);
9507    assert(row->len == 0 || row->cols != NULL);
9508    assert(row->lppos == -1);
9509 
9510    SCIProwCapture(row);
9511    SCIProwLock(row);
9512 
9513    SCIPsetDebugMsg(set, "adding row <%s> to LP (%d rows, %d cols)\n", row->name, lp->nrows, lp->ncols);
9514 #ifdef SCIP_DEBUG
9515    {
9516       int i;
9517       SCIPsetDebugMsgPrint(set, "  %g <=", row->lhs);
9518       for( i = 0; i < row->len; ++i )
9519          SCIPsetDebugMsgPrint(set, " %+g<%s>", row->vals[i], SCIPvarGetName(row->cols[i]->var));
9520       if( !SCIPsetIsZero(set, row->constant) )
9521          SCIPsetDebugMsgPrint(set, " %+g", row->constant);
9522       SCIPsetDebugMsgPrint(set, " <= %g\n", row->rhs);
9523    }
9524 #endif
9525 
9526    SCIP_CALL( ensureRowsSize(lp, set, lp->nrows+1) );
9527    lp->rows[lp->nrows] = row;
9528    row->lppos = lp->nrows;
9529    row->lpdepth = depth;
9530    row->age = 0;
9531    lp->nrows++;
9532    if( row->removable )
9533       lp->nremovablerows++;
9534 
9535    /* mark the current LP unflushed */
9536    lp->flushed = FALSE;
9537 
9538    /* update row arrays of all linked columns */
9539    rowUpdateAddLP(row);
9540 
9541    checkLinks(lp);
9542 
9543    rowCalcNorms(row, set);
9544 
9545    /* check, if row addition to LP events are tracked
9546     * if so, issue ROWADDEDLP event
9547     */
9548    if( (eventfilter->len > 0 && (eventfilter->eventmask & SCIP_EVENTTYPE_ROWADDEDLP) != 0) )
9549    {
9550       SCIP_EVENT* event;
9551 
9552       SCIP_CALL( SCIPeventCreateRowAddedLP(&event, blkmem, row) );
9553       SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, eventfilter, &event) );
9554    }
9555 
9556    return SCIP_OKAY;
9557 }
9558 
9559 
9560 #ifndef NDEBUG
9561 /** method checks if all columns in the lazycols array have at least one lazy bound and also have a counter part in the
9562  *  cols array; furthermore, it is checked if columns in the cols array which have a lazy bound have a counter part in
9563  *  the lazycols array
9564  */
9565 static
checkLazyColArray(SCIP_LP * lp,SCIP_SET * set)9566 void checkLazyColArray(
9567    SCIP_LP*              lp,                 /**< LP data */
9568    SCIP_SET*             set                 /**< global SCIP settings */
9569    )
9570 {
9571    SCIP_Bool contained;
9572    int c;
9573    int i;
9574 
9575    assert(lp != NULL);
9576 
9577    /* check if each column in the lazy column array has a counter part in the column array */
9578    for( i = 0; i < lp->nlazycols; ++i )
9579    {
9580       /* check if each lazy column has at least on lazy bound */
9581       assert(lp->lazycols[i] != NULL);
9582       assert(!SCIPsetIsInfinity(set, lp->lazycols[i]->lazyub) || !SCIPsetIsInfinity(set, -lp->lazycols[i]->lazylb));
9583 
9584       contained = FALSE;
9585       for( c = 0; c < lp->ncols; ++c )
9586       {
9587          if( lp->lazycols[i] == lp->cols[c] )
9588          {
9589             assert(!SCIPsetIsInfinity(set, lp->cols[c]->lazyub) || !SCIPsetIsInfinity(set, -lp->cols[c]->lazylb));
9590             contained = TRUE;
9591          }
9592       }
9593       assert(contained);
9594    }
9595 
9596    /* check if each column in the column array which has at least one lazy bound has a counter part in the lazy column *
9597     * array */
9598    for( c = 0; c < lp->ncols; ++c )
9599    {
9600       contained = FALSE;
9601       assert(lp->cols[c] != NULL);
9602 
9603       for( i = 0; i < lp->nlazycols; ++i )
9604       {
9605          if( lp->lazycols[i] == lp->cols[c] )
9606          {
9607             contained = TRUE;
9608          }
9609       }
9610 
9611       assert(contained == (!SCIPsetIsInfinity(set, lp->cols[c]->lazyub) || !SCIPsetIsInfinity(set, -lp->cols[c]->lazylb)));
9612    }
9613 }
9614 #else
9615 #define checkLazyColArray(lp, set) /**/
9616 #endif
9617 
9618 /** removes all columns after the given number of cols from the LP */
SCIPlpShrinkCols(SCIP_LP * lp,SCIP_SET * set,int newncols)9619 SCIP_RETCODE SCIPlpShrinkCols(
9620    SCIP_LP*              lp,                 /**< LP data */
9621    SCIP_SET*             set,                /**< global SCIP settings */
9622    int                   newncols            /**< new number of columns in the LP */
9623    )
9624 {
9625    SCIP_COL* col;
9626    int c;
9627 
9628    assert(lp != NULL);
9629 
9630    SCIPsetDebugMsg(set, "shrinking LP from %d to %d columns\n", lp->ncols, newncols);
9631    assert(0 <= newncols);
9632    assert(newncols <= lp->ncols);
9633 
9634    if( newncols < lp->ncols )
9635    {
9636       assert(!lp->diving);
9637 
9638       for( c = lp->ncols-1; c >= newncols; --c )
9639       {
9640          col = lp->cols[c];
9641          assert(col != NULL);
9642          assert(col->len == 0 || col->rows != NULL);
9643          assert(col->var != NULL);
9644          assert(SCIPvarGetStatus(col->var) == SCIP_VARSTATUS_COLUMN);
9645          assert(SCIPvarGetCol(col->var) == lp->cols[c]);
9646          assert(col->lppos == c);
9647 
9648          /* mark column to be removed from the LP */
9649          col->lppos = -1;
9650          col->lpdepth = -1;
9651          lp->ncols--;
9652 
9653          /* count removable columns */
9654          if( col->removable )
9655             lp->nremovablecols--;
9656 
9657          /* update column arrays of all linked rows */
9658          colUpdateDelLP(col, set);
9659 
9660          /* update the objective function vector norms */
9661          lpUpdateObjNorms(lp, set, col->unchangedobj, 0.0);
9662       }
9663       assert(lp->ncols == newncols);
9664       lp->lpifirstchgcol = MIN(lp->lpifirstchgcol, newncols);
9665 
9666       /* remove columns which are deleted from the lazy column array */
9667       c = 0;
9668       while( c < lp->nlazycols )
9669       {
9670          if( lp->lazycols[c]->lppos < 0 )
9671          {
9672             lp->lazycols[c] = lp->lazycols[lp->nlazycols-1];
9673             lp->nlazycols--;
9674          }
9675          else
9676             c++;
9677       }
9678 
9679       /* mark the current LP unflushed */
9680       lp->flushed = FALSE;
9681 
9682       checkLazyColArray(lp, set);
9683       checkLinks(lp);
9684    }
9685    assert(lp->nremovablecols <= lp->ncols);
9686 
9687    return SCIP_OKAY;
9688 }
9689 
9690 /** removes and releases all rows after the given number of rows from the LP */
SCIPlpShrinkRows(SCIP_LP * lp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_EVENTFILTER * eventfilter,int newnrows)9691 SCIP_RETCODE SCIPlpShrinkRows(
9692    SCIP_LP*              lp,                 /**< LP data */
9693    BMS_BLKMEM*           blkmem,             /**< block memory */
9694    SCIP_SET*             set,                /**< global SCIP settings */
9695    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
9696    SCIP_EVENTFILTER*     eventfilter,        /**< global event filter */
9697    int                   newnrows            /**< new number of rows in the LP */
9698    )
9699 {
9700    SCIP_ROW* row;
9701    int r;
9702 
9703    assert(lp != NULL);
9704    assert(0 <= newnrows && newnrows <= lp->nrows);
9705 
9706    SCIPsetDebugMsg(set, "shrinking LP from %d to %d rows\n", lp->nrows, newnrows);
9707    if( newnrows < lp->nrows )
9708    {
9709       for( r = lp->nrows-1; r >= newnrows; --r )
9710       {
9711          row = lp->rows[r];
9712          assert(row != NULL);
9713          assert(row->len == 0 || row->cols != NULL);
9714          assert(row->lppos == r);
9715 
9716          /* mark row to be removed from the LP */
9717          row->lppos = -1;
9718          row->lpdepth = -1;
9719          lp->nrows--;
9720 
9721          /* count removable rows */
9722          if( row->removable )
9723             lp->nremovablerows--;
9724 
9725          /* update row arrays of all linked columns */
9726          rowUpdateDelLP(row);
9727 
9728          SCIProwUnlock(lp->rows[r]);
9729 
9730          /* check, if row deletion events are tracked
9731           * if so, issue ROWDELETEDLP event
9732           */
9733          if( eventfilter->len > 0 && (eventfilter->eventmask & SCIP_EVENTTYPE_ROWDELETEDLP) != 0 )
9734          {
9735             SCIP_EVENT* event;
9736 
9737             SCIP_CALL( SCIPeventCreateRowDeletedLP(&event, blkmem, lp->rows[r]) );
9738             SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, eventfilter, &event) );
9739          }
9740 
9741          SCIP_CALL( SCIProwRelease(&lp->rows[r], blkmem, set, lp) );
9742       }
9743       assert(lp->nrows == newnrows);
9744       lp->lpifirstchgrow = MIN(lp->lpifirstchgrow, newnrows);
9745 
9746       /* mark the current LP unflushed */
9747       lp->flushed = FALSE;
9748 
9749       checkLinks(lp);
9750    }
9751    assert(lp->nremovablerows <= lp->nrows);
9752 
9753    return SCIP_OKAY;
9754 }
9755 
9756 /** removes all columns and rows from LP, releases all rows */
SCIPlpClear(SCIP_LP * lp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_EVENTFILTER * eventfilter)9757 SCIP_RETCODE SCIPlpClear(
9758    SCIP_LP*              lp,                 /**< LP data */
9759    BMS_BLKMEM*           blkmem,             /**< block memory */
9760    SCIP_SET*             set,                /**< global SCIP settings */
9761    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
9762    SCIP_EVENTFILTER*     eventfilter         /**< global event filter */
9763    )
9764 {
9765    assert(lp != NULL);
9766    assert(!lp->diving);
9767 
9768    SCIPsetDebugMsg(set, "clearing LP\n");
9769    SCIP_CALL( SCIPlpShrinkCols(lp, set, 0) );
9770    SCIP_CALL( SCIPlpShrinkRows(lp, blkmem, set, eventqueue, eventfilter, 0) );
9771 
9772    return SCIP_OKAY;
9773 }
9774 
9775 /** remembers number of columns and rows to track the newly added ones */
SCIPlpMarkSize(SCIP_LP * lp)9776 void SCIPlpMarkSize(
9777    SCIP_LP*              lp                  /**< current LP data */
9778    )
9779 {
9780    assert(lp != NULL);
9781    assert(!lp->diving);
9782 
9783    lp->firstnewrow = lp->nrows;
9784    lp->firstnewcol = lp->ncols;
9785 }
9786 
9787 /** sets the remembered number of columns and rows to the given values */
SCIPlpSetSizeMark(SCIP_LP * lp,int nrows,int ncols)9788 void SCIPlpSetSizeMark(
9789    SCIP_LP*              lp,                 /**< current LP data */
9790    int                   nrows,              /**< number of rows to set the size marker to */
9791    int                   ncols               /**< number of columns to set the size marker to */
9792    )
9793 {
9794    assert(lp != NULL);
9795    assert(!lp->diving);
9796 
9797    lp->firstnewrow = nrows;
9798    lp->firstnewcol = ncols;
9799 }
9800 
9801 /** gets all indices of basic columns and rows: index i >= 0 corresponds to column i, index i < 0 to row -i-1 */
SCIPlpGetBasisInd(SCIP_LP * lp,int * basisind)9802 SCIP_RETCODE SCIPlpGetBasisInd(
9803    SCIP_LP*              lp,                 /**< LP data */
9804    int*                  basisind            /**< pointer to store basis indices ready to keep number of rows entries */
9805    )
9806 {
9807    assert(lp != NULL);
9808    assert(lp->flushed);
9809    assert(lp->solved);
9810    assert(lp->solisbasic);
9811    assert(basisind != NULL);
9812 
9813    SCIP_CALL( SCIPlpiGetBasisInd(lp->lpi, basisind) );
9814 
9815    return SCIP_OKAY;
9816 }
9817 
9818 /** gets current basis status for columns and rows; arrays must be large enough to store the basis status */
SCIPlpGetBase(SCIP_LP * lp,int * cstat,int * rstat)9819 SCIP_RETCODE SCIPlpGetBase(
9820    SCIP_LP*              lp,                 /**< LP data */
9821    int*                  cstat,              /**< array to store column basis status, or NULL */
9822    int*                  rstat               /**< array to store row basis status, or NULL */
9823    )
9824 {
9825    assert(lp != NULL);
9826    assert(lp->flushed);
9827    assert(lp->solved);
9828    assert(lp->solisbasic);
9829 
9830    SCIP_CALL( SCIPlpiGetBase(lp->lpi, cstat, rstat) );
9831 
9832    return SCIP_OKAY;
9833 }
9834 
9835 /** gets a row from the inverse basis matrix B^-1 */
SCIPlpGetBInvRow(SCIP_LP * lp,int r,SCIP_Real * coef,int * inds,int * ninds)9836 SCIP_RETCODE SCIPlpGetBInvRow(
9837    SCIP_LP*              lp,                 /**< LP data */
9838    int                   r,                  /**< row number */
9839    SCIP_Real*            coef,               /**< pointer to store the coefficients of the row */
9840    int*                  inds,               /**< array to store the non-zero indices, or NULL */
9841    int*                  ninds               /**< pointer to store the number of non-zero indices, or NULL
9842                                               *   (-1: if we do not store sparsity informations) */
9843    )
9844 {
9845    assert(lp != NULL);
9846    assert(lp->flushed);
9847    assert(lp->solved);
9848    assert(lp->solisbasic);
9849    assert(0 <= r && r < lp->nrows);  /* the basis matrix is nrows x nrows */
9850    assert(coef != NULL);
9851 
9852    SCIP_CALL( SCIPlpiGetBInvRow(lp->lpi, r, coef, inds, ninds) );
9853 
9854    return SCIP_OKAY;
9855 }
9856 
9857 /** gets a column from the inverse basis matrix B^-1 */
SCIPlpGetBInvCol(SCIP_LP * lp,int c,SCIP_Real * coef,int * inds,int * ninds)9858 SCIP_RETCODE SCIPlpGetBInvCol(
9859    SCIP_LP*              lp,                 /**< LP data */
9860    int                   c,                  /**< column number of B^-1; this is NOT the number of the column in the LP
9861                                               *   returned by SCIPcolGetLPPos(); you have to call SCIPgetBasisInd()
9862                                               *   to get the array which links the B^-1 column numbers to the row and
9863                                               *   column numbers of the LP! c must be between 0 and nrows-1, since the
9864                                               *   basis has the size nrows * nrows */
9865    SCIP_Real*            coef,               /**< pointer to store the coefficients of the column */
9866    int*                  inds,               /**< array to store the non-zero indices, or NULL */
9867    int*                  ninds               /**< pointer to store the number of non-zero indices, or NULL
9868                                               *   (-1: if we do not store sparsity informations) */
9869    )
9870 {
9871    assert(lp != NULL);
9872    assert(lp->flushed);
9873    assert(lp->solved);
9874    assert(lp->solisbasic);
9875    assert(0 <= c && c < lp->nrows);  /* the basis matrix is nrows x nrows */
9876    assert(coef != NULL);
9877 
9878    SCIP_CALL( SCIPlpiGetBInvCol(lp->lpi, c, coef, inds, ninds) );
9879 
9880    return SCIP_OKAY;
9881 }
9882 
9883 /** gets a row from the product of inverse basis matrix B^-1 and coefficient matrix A (i.e. from B^-1 * A) */
SCIPlpGetBInvARow(SCIP_LP * lp,int r,SCIP_Real * binvrow,SCIP_Real * coef,int * inds,int * ninds)9884 SCIP_RETCODE SCIPlpGetBInvARow(
9885    SCIP_LP*              lp,                 /**< LP data */
9886    int                   r,                  /**< row number */
9887    SCIP_Real*            binvrow,            /**< row in B^-1 from prior call to SCIPlpGetBInvRow(), or NULL */
9888    SCIP_Real*            coef,               /**< pointer to store the coefficients of the row */
9889    int*                  inds,               /**< array to store the non-zero indices, or NULL */
9890    int*                  ninds               /**< pointer to store the number of non-zero indices, or NULL
9891                                               *  (-1: if we do not store sparsity informations) */
9892    )
9893 {
9894    assert(lp != NULL);
9895    assert(lp->flushed);
9896    assert(lp->solved);
9897    assert(lp->solisbasic);
9898    assert(0 <= r && r < lp->nrows);  /* the basis matrix is nrows x nrows */
9899    assert(coef != NULL);
9900 
9901    SCIP_CALL( SCIPlpiGetBInvARow(lp->lpi, r, binvrow, coef, inds, ninds) );
9902 
9903    return SCIP_OKAY;
9904 }
9905 
9906 /** gets a column from the product of inverse basis matrix B^-1 and coefficient matrix A (i.e. from B^-1 * A),
9907  *  i.e., it computes B^-1 * A_c with A_c being the c'th column of A
9908  */
SCIPlpGetBInvACol(SCIP_LP * lp,int c,SCIP_Real * coef,int * inds,int * ninds)9909 SCIP_RETCODE SCIPlpGetBInvACol(
9910    SCIP_LP*              lp,                 /**< LP data */
9911    int                   c,                  /**< column number which can be accessed by SCIPcolGetLPPos() */
9912    SCIP_Real*            coef,               /**< pointer to store the coefficients of the column */
9913    int*                  inds,               /**< array to store the non-zero indices, or NULL */
9914    int*                  ninds               /**< pointer to store the number of non-zero indices, or NULL
9915                                               *  (-1: if we do not store sparsity informations) */
9916    )
9917 {
9918    assert(lp != NULL);
9919    assert(lp->flushed);
9920    assert(lp->solved);
9921    assert(lp->solisbasic);
9922    assert(0 <= c && c < lp->ncols);
9923    assert(coef != NULL);
9924 
9925    SCIP_CALL( SCIPlpiGetBInvACol(lp->lpi, c, coef, inds, ninds) );
9926 
9927    return SCIP_OKAY;
9928 }
9929 
9930 /** calculates a weighted sum of all LP rows; for negative weights, the left and right hand side of the corresponding
9931  *  LP row are swapped in the summation
9932  */
SCIPlpSumRows(SCIP_LP * lp,SCIP_SET * set,SCIP_PROB * prob,SCIP_Real * weights,SCIP_REALARRAY * sumcoef,SCIP_Real * sumlhs,SCIP_Real * sumrhs)9933 SCIP_RETCODE SCIPlpSumRows(
9934    SCIP_LP*              lp,                 /**< LP data */
9935    SCIP_SET*             set,                /**< global SCIP settings */
9936    SCIP_PROB*            prob,               /**< problem data */
9937    SCIP_Real*            weights,            /**< row weights in row summation */
9938    SCIP_REALARRAY*       sumcoef,            /**< array to store sum coefficients indexed by variables' probindex */
9939    SCIP_Real*            sumlhs,             /**< pointer to store the left hand side of the row summation */
9940    SCIP_Real*            sumrhs              /**< pointer to store the right hand side of the row summation */
9941    )
9942 {
9943    SCIP_ROW* row;
9944    int r;
9945    int i;
9946    int idx;
9947    SCIP_Bool lhsinfinite;
9948    SCIP_Bool rhsinfinite;
9949 
9950    assert(lp != NULL);
9951    assert(prob != NULL);
9952    assert(weights != NULL);
9953    assert(sumcoef != NULL);
9954    assert(sumlhs != NULL);
9955    assert(sumrhs != NULL);
9956 
9957    /**@todo test, if a column based summation is faster */
9958 
9959    SCIP_CALL( SCIPrealarrayClear(sumcoef) );
9960    SCIP_CALL( SCIPrealarrayExtend(sumcoef, set->mem_arraygrowinit, set->mem_arraygrowfac, 0, prob->nvars-1) );
9961    *sumlhs = 0.0;
9962    *sumrhs = 0.0;
9963    lhsinfinite = FALSE;
9964    rhsinfinite = FALSE;
9965    for( r = 0; r < lp->nrows; ++r )
9966    {
9967       if( !SCIPsetIsZero(set, weights[r]) )
9968       {
9969          row = lp->rows[r];
9970          assert(row != NULL);
9971          assert(row->len == 0 || row->cols != NULL);
9972          assert(row->len == 0 || row->cols_index != NULL);
9973          assert(row->len == 0 || row->vals != NULL);
9974 
9975          /* add the row coefficients to the sum */
9976          for( i = 0; i < row->len; ++i )
9977          {
9978             assert(row->cols[i] != NULL);
9979             assert(row->cols[i]->var != NULL);
9980             assert(SCIPvarGetStatus(row->cols[i]->var) == SCIP_VARSTATUS_COLUMN);
9981             assert(SCIPvarGetCol(row->cols[i]->var) == row->cols[i]);
9982             assert(SCIPvarGetProbindex(row->cols[i]->var) == row->cols[i]->var_probindex);
9983             idx = row->cols[i]->var_probindex;
9984             assert(0 <= idx && idx < prob->nvars);
9985             SCIP_CALL( SCIPrealarrayIncVal(sumcoef, set->mem_arraygrowinit, set->mem_arraygrowfac, idx, weights[r] * row->vals[i]) );
9986          }
9987 
9988          /* add the row sides to the sum, depending on the sign of the weight */
9989          if( weights[r] > 0.0 )
9990          {
9991             lhsinfinite = lhsinfinite || SCIPsetIsInfinity(set, -row->lhs);
9992             if( !lhsinfinite )
9993                (*sumlhs) += weights[r] * (row->lhs - row->constant);
9994             rhsinfinite = rhsinfinite || SCIPsetIsInfinity(set, row->rhs);
9995             if( !rhsinfinite )
9996                (*sumrhs) += weights[r] * (row->rhs - row->constant);
9997          }
9998          else
9999          {
10000             lhsinfinite = lhsinfinite || SCIPsetIsInfinity(set, row->rhs);
10001             if( !lhsinfinite )
10002                (*sumlhs) += weights[r] * (row->rhs - row->constant);
10003             rhsinfinite = rhsinfinite || SCIPsetIsInfinity(set, -row->lhs);
10004             if( !rhsinfinite )
10005                (*sumrhs) += weights[r] * (row->lhs - row->constant);
10006          }
10007       }
10008    }
10009 
10010    if( lhsinfinite )
10011       *sumlhs = -SCIPsetInfinity(set);
10012    if( rhsinfinite )
10013       *sumrhs = SCIPsetInfinity(set);
10014 
10015    return SCIP_OKAY;
10016 }
10017 
10018 /** stores LP state (like basis information) into LP state object */
SCIPlpGetState(SCIP_LP * lp,BMS_BLKMEM * blkmem,SCIP_LPISTATE ** lpistate)10019 SCIP_RETCODE SCIPlpGetState(
10020    SCIP_LP*              lp,                 /**< LP data */
10021    BMS_BLKMEM*           blkmem,             /**< block memory */
10022    SCIP_LPISTATE**       lpistate            /**< pointer to LP state information (like basis information) */
10023    )
10024 {
10025    assert(lp != NULL);
10026    assert(lp->flushed);
10027    assert(lp->solved);
10028    assert(blkmem != NULL);
10029    assert(lpistate != NULL);
10030 
10031    /* check whether there is no lp */
10032    if( lp->nlpicols == 0 && lp->nlpirows == 0 )
10033       *lpistate = NULL;
10034    else
10035    {
10036       SCIP_CALL( SCIPlpiGetState(lp->lpi, blkmem, lpistate) );
10037    }
10038 
10039    return SCIP_OKAY;
10040 }
10041 
10042 /** loads LP state (like basis information) into solver */
SCIPlpSetState(SCIP_LP * lp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_LPISTATE * lpistate,SCIP_Bool wasprimfeas,SCIP_Bool wasprimchecked,SCIP_Bool wasdualfeas,SCIP_Bool wasdualchecked)10043 SCIP_RETCODE SCIPlpSetState(
10044    SCIP_LP*              lp,                 /**< LP data */
10045    BMS_BLKMEM*           blkmem,             /**< block memory */
10046    SCIP_SET*             set,                /**< global SCIP settings */
10047    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
10048    SCIP_LPISTATE*        lpistate,           /**< LP state information (like basis information) */
10049    SCIP_Bool             wasprimfeas,        /**< primal feasibility when LP state information was stored */
10050    SCIP_Bool             wasprimchecked,     /**< true if the LP solution has passed the primal feasibility check */
10051    SCIP_Bool             wasdualfeas,        /**< dual feasibility when LP state information was stored */
10052    SCIP_Bool             wasdualchecked      /**< true if the LP solution has passed the dual feasibility check */
10053    )
10054 {
10055    assert(lp != NULL);
10056    assert(blkmem != NULL);
10057 
10058    /* flush changes to the LP solver */
10059    SCIP_CALL( SCIPlpFlush(lp, blkmem, set, eventqueue) );
10060    assert(lp->flushed);
10061 
10062    if( lp->solved && lp->solisbasic )
10063       return SCIP_OKAY;
10064 
10065    /* set LPI state in the LP solver */
10066    if( lpistate == NULL )
10067       lp->solisbasic = FALSE;
10068    else
10069    {
10070       SCIP_CALL( SCIPlpiSetState(lp->lpi, blkmem, lpistate) );
10071       lp->solisbasic = SCIPlpiHasStateBasis(lp->lpi, lpistate);
10072    }
10073    /* @todo: setting feasibility to TRUE might be wrong because in probing mode, the state is even saved when the LP was
10074     *        flushed and solved, also, e.g., when we hit the iteration limit
10075     */
10076    lp->primalfeasible = wasprimfeas;
10077    lp->primalchecked = wasprimchecked;
10078    lp->dualfeasible = wasdualfeas;
10079    lp->dualchecked = wasdualchecked;
10080 
10081    return SCIP_OKAY;
10082 }
10083 
10084 /** frees LP state information */
SCIPlpFreeState(SCIP_LP * lp,BMS_BLKMEM * blkmem,SCIP_LPISTATE ** lpistate)10085 SCIP_RETCODE SCIPlpFreeState(
10086    SCIP_LP*              lp,                 /**< LP data */
10087    BMS_BLKMEM*           blkmem,             /**< block memory */
10088    SCIP_LPISTATE**       lpistate            /**< pointer to LP state information (like basis information) */
10089    )
10090 {
10091    assert(lp != NULL);
10092 
10093    if( *lpistate != NULL )
10094    {
10095       SCIP_CALL( SCIPlpiFreeState(lp->lpi, blkmem, lpistate) );
10096    }
10097 
10098    return SCIP_OKAY;
10099 }
10100 
10101 /** stores pricing norms into LP norms object */
SCIPlpGetNorms(SCIP_LP * lp,BMS_BLKMEM * blkmem,SCIP_LPINORMS ** lpinorms)10102 SCIP_RETCODE SCIPlpGetNorms(
10103    SCIP_LP*              lp,                 /**< LP data */
10104    BMS_BLKMEM*           blkmem,             /**< block memory */
10105    SCIP_LPINORMS**       lpinorms            /**< pointer to LP pricing norms information */
10106    )
10107 {
10108    assert(lp != NULL);
10109    assert(lp->flushed);
10110    assert(lp->solved);
10111    assert(blkmem != NULL);
10112    assert(lpinorms != NULL);
10113 
10114    /* check whether there is no lp */
10115    if( lp->nlpicols == 0 && lp->nlpirows == 0 )
10116       *lpinorms = NULL;
10117    else
10118    {
10119       SCIP_CALL( SCIPlpiGetNorms(lp->lpi, blkmem, lpinorms) );
10120    }
10121 
10122    return SCIP_OKAY;
10123 }
10124 
10125 /** loads pricing norms from LP norms object into solver */
SCIPlpSetNorms(SCIP_LP * lp,BMS_BLKMEM * blkmem,SCIP_LPINORMS * lpinorms)10126 SCIP_RETCODE SCIPlpSetNorms(
10127    SCIP_LP*              lp,                 /**< LP data */
10128    BMS_BLKMEM*           blkmem,             /**< block memory */
10129    SCIP_LPINORMS*        lpinorms            /**< LP pricing norms information */
10130    )
10131 {
10132    assert(lp != NULL);
10133    assert(blkmem != NULL);
10134    assert(lp->flushed);
10135 
10136    /* set LPI norms in the LP solver */
10137    if( lpinorms != NULL )
10138    {
10139       SCIP_CALL( SCIPlpiSetNorms(lp->lpi, blkmem, lpinorms) );
10140    }
10141 
10142    return SCIP_OKAY;
10143 }
10144 
10145 /** frees pricing norms information */
SCIPlpFreeNorms(SCIP_LP * lp,BMS_BLKMEM * blkmem,SCIP_LPINORMS ** lpinorms)10146 SCIP_RETCODE SCIPlpFreeNorms(
10147    SCIP_LP*              lp,                 /**< LP data */
10148    BMS_BLKMEM*           blkmem,             /**< block memory */
10149    SCIP_LPINORMS**       lpinorms            /**< pointer to LP pricing norms information */
10150    )
10151 {
10152    assert(lp != NULL);
10153 
10154    SCIP_CALL( SCIPlpiFreeNorms(lp->lpi, blkmem, lpinorms) );
10155 
10156    return SCIP_OKAY;
10157 }
10158 
10159 /** return the current cutoff bound of the lp */
SCIPlpGetCutoffbound(SCIP_LP * lp)10160 SCIP_Real SCIPlpGetCutoffbound(
10161    SCIP_LP*              lp                  /**< current LP data */
10162    )
10163 {
10164    assert(lp != NULL);
10165 
10166    return lp->cutoffbound;
10167 }
10168 
10169 /** sets the upper objective limit of the LP solver */
SCIPlpSetCutoffbound(SCIP_LP * lp,SCIP_SET * set,SCIP_PROB * prob,SCIP_Real cutoffbound)10170 SCIP_RETCODE SCIPlpSetCutoffbound(
10171    SCIP_LP*              lp,                 /**< current LP data */
10172    SCIP_SET*             set,                /**< global SCIP settings */
10173    SCIP_PROB*            prob,               /**< problem data */
10174    SCIP_Real             cutoffbound         /**< new upper objective limit */
10175    )
10176 {
10177    assert(lp != NULL);
10178 
10179    SCIPsetDebugMsg(set, "setting LP upper objective limit from %g to %g\n", lp->cutoffbound, cutoffbound);
10180 
10181    /* if the objective function was changed in diving, the cutoff bound has no meaning (it will be set correctly
10182     * in SCIPendDive())
10183     */
10184    if( SCIPlpDivingObjChanged(lp) )
10185    {
10186       assert(SCIPsetIsInfinity(set, lp->cutoffbound));
10187       return SCIP_OKAY;
10188    }
10189 
10190    /* if the cutoff bound is increased, and the LP was proved to exceed the old cutoff, it is no longer solved */
10191    if( SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_OBJLIMIT && cutoffbound > lp->cutoffbound )
10192    {
10193       /* mark the current solution invalid */
10194       lp->solved = FALSE;
10195       lp->lpobjval = SCIP_INVALID;
10196       lp->lpsolstat = SCIP_LPSOLSTAT_NOTSOLVED;
10197    }
10198    /* if the cutoff bound is decreased below the current optimal value, the LP now exceeds the objective limit;
10199     * if the objective limit in the LP solver was disabled, the solution status of the LP is not changed
10200     */
10201    else if( !lpCutoffDisabled(set) && SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_OPTIMAL
10202       && SCIPlpGetObjval(lp, set, prob) >= cutoffbound )
10203    {
10204       assert(lp->flushed);
10205       assert(lp->solved);
10206       lp->lpsolstat = SCIP_LPSOLSTAT_OBJLIMIT;
10207    }
10208 
10209    lp->cutoffbound = cutoffbound;
10210 
10211    return SCIP_OKAY;
10212 }
10213 
10214 /** gets current primal feasibility tolerance of LP solver */
SCIPlpGetFeastol(SCIP_LP * lp)10215 SCIP_Real SCIPlpGetFeastol(
10216    SCIP_LP*              lp                  /**< current LP data */
10217    )
10218 {
10219    assert(lp != NULL);
10220 
10221    return lp->feastol;
10222 }
10223 
10224 /** sets primal feasibility tolerance of LP solver */
SCIPlpSetFeastol(SCIP_LP * lp,SCIP_SET * set,SCIP_Real newfeastol)10225 void SCIPlpSetFeastol(
10226    SCIP_LP*              lp,                 /**< current LP data */
10227    SCIP_SET*             set,                /**< global SCIP settings */
10228    SCIP_Real             newfeastol          /**< new primal feasibility tolerance for LP */
10229    )
10230 {
10231    assert(lp != NULL);
10232    assert(newfeastol > 0.0);
10233 
10234    SCIPsetDebugMsg(set, "setting LP primal feasibility tolerance from %g to %g\n", lp->feastol, newfeastol);
10235 
10236    /* mark the LP unsolved, if the primal feasibility tolerance is tightened */
10237    if( newfeastol < lp->feastol )
10238    {
10239       lp->solved = FALSE;
10240       lp->lpsolstat = SCIP_LPSOLSTAT_NOTSOLVED;
10241    }
10242 
10243    lp->feastol = newfeastol;
10244 }
10245 
10246 /** resets primal feasibility tolerance of LP solver
10247  *
10248  * Sets primal feasibility tolerance to min of numerics/lpfeastolfactor * numerics/feastol and relaxfeastol.
10249  */
SCIPlpResetFeastol(SCIP_LP * lp,SCIP_SET * set)10250 void SCIPlpResetFeastol(
10251    SCIP_LP*              lp,                 /**< current LP data */
10252    SCIP_SET*             set                 /**< global SCIP settings */
10253    )
10254 {
10255    assert(lp != NULL);
10256 
10257    SCIPsetDebugMsg(set, "reset LP primal feasibility tolerance\n");
10258 
10259    if( SCIPsetRelaxfeastol(set) != SCIP_INVALID ) /*lint !e777*/
10260       SCIPlpSetFeastol(lp, set, MIN(SCIPsetRelaxfeastol(set), SCIPsetLPFeastolFactor(set) * SCIPsetFeastol(set))); /*lint !e666*/
10261    else
10262       SCIPlpSetFeastol(lp, set, SCIPsetLPFeastolFactor(set) * SCIPsetFeastol(set));
10263 }
10264 
10265 /** returns the name of the given LP algorithm */
10266 static
lpalgoName(SCIP_LPALGO lpalgo)10267 const char* lpalgoName(
10268    SCIP_LPALGO           lpalgo              /**< LP algorithm */
10269    )
10270 {
10271    switch( lpalgo )
10272    {
10273    case SCIP_LPALGO_PRIMALSIMPLEX:
10274       return "primal simplex";
10275    case SCIP_LPALGO_DUALSIMPLEX:
10276       return "dual simplex";
10277    case SCIP_LPALGO_BARRIER:
10278       return "barrier";
10279    case SCIP_LPALGO_BARRIERCROSSOVER:
10280       return "barrier/crossover";
10281    default:
10282       SCIPerrorMessage("invalid LP algorithm\n");
10283       SCIPABORT();
10284       return "invalid"; /*lint !e527*/
10285    }
10286 }
10287 
10288 /** calls LPI to perform primal simplex, measures time and counts iterations, gets basis feasibility status */
10289 static
lpPrimalSimplex(SCIP_LP * lp,SCIP_SET * set,SCIP_STAT * stat,SCIP_Bool resolve,SCIP_Bool keepsol,SCIP_Bool instable,SCIP_Bool * lperror)10290 SCIP_RETCODE lpPrimalSimplex(
10291    SCIP_LP*              lp,                 /**< current LP data */
10292    SCIP_SET*             set,                /**< global SCIP settings */
10293    SCIP_STAT*            stat,               /**< problem statistics */
10294    SCIP_Bool             resolve,            /**< is this a resolving call (starting with feasible basis)? */
10295    SCIP_Bool             keepsol,            /**< should the old LP solution be kept if no iterations were performed? */
10296    SCIP_Bool             instable,           /**< is this a resolving call to avoid instable LPs? */
10297    SCIP_Bool*            lperror             /**< pointer to store whether an unresolved LP error occurred */
10298    )
10299 {
10300    SCIP_Real timedelta;
10301    SCIP_RETCODE retcode;
10302    int iterations;
10303 
10304    assert(lp != NULL);
10305    assert(lp->flushed);
10306    assert(set != NULL);
10307    assert(stat != NULL);
10308    assert(lperror != NULL);
10309 
10310    SCIPsetDebugMsg(set, "solving LP %" SCIP_LONGINT_FORMAT " (%d cols, %d rows) with primal simplex (diving=%d, nprimallps=%" SCIP_LONGINT_FORMAT ", ndivinglps=%" SCIP_LONGINT_FORMAT ")\n",
10311       stat->lpcount+1, lp->ncols, lp->nrows, lp->diving || lp->probing, stat->nprimallps, stat->ndivinglps);
10312 
10313    *lperror = FALSE;
10314 
10315 #ifdef SCIP_MORE_DEBUG /* for debugging: write all root node LP's */
10316    if( stat->nnodes == 1 && !lp->diving && !lp->probing )
10317    {
10318       char fname[SCIP_MAXSTRLEN];
10319       (void) SCIPsnprintf(fname, SCIP_MAXSTRLEN, "lp%" SCIP_LONGINT_FORMAT "_%" SCIP_LONGINT_FORMAT ".lp", stat->nnodes, stat->lpcount);
10320       SCIP_CALL( SCIPlpWrite(lp, fname) );
10321       SCIPsetDebugMsg(set, "wrote LP to file <%s> (primal simplex, objlim=%.15g, feastol=%.15g/%.15g, fromscratch=%d, fastmip=%d, scaling=%d, presolving=%d)\n",
10322          fname, lp->lpiobjlim, lp->lpifeastol, lp->lpidualfeastol,
10323          lp->lpifromscratch, lp->lpifastmip, lp->lpiscaling, lp->lpipresolving);
10324    }
10325 #endif
10326 
10327    /* start timing */
10328    if( lp->diving || lp->probing )
10329    {
10330       if( lp->strongbranchprobing )
10331          SCIPclockStart(stat->strongbranchtime, set);
10332       else
10333          SCIPclockStart(stat->divinglptime, set);
10334 
10335       timedelta = 0.0;   /* unused for diving or probing */
10336    }
10337    else
10338    {
10339       SCIPclockStart(stat->primallptime, set);
10340       timedelta = -SCIPclockGetTime(stat->primallptime);
10341    }
10342 
10343    /* if this is a call to resolve an instable LP, collect time */
10344    if( instable )
10345    {
10346       SCIPclockStart(stat->resolveinstablelptime, set);
10347    }
10348 
10349    /* call primal simplex */
10350    retcode = SCIPlpiSolvePrimal(lp->lpi);
10351    if( retcode == SCIP_LPERROR )
10352    {
10353       *lperror = TRUE;
10354       SCIPsetDebugMsg(set, "(node %" SCIP_LONGINT_FORMAT ") primal simplex solving error in LP %" SCIP_LONGINT_FORMAT "\n", stat->nnodes, stat->nlps);
10355    }
10356    else
10357    {
10358       SCIP_CALL( retcode );
10359    }
10360    lp->lastlpalgo = SCIP_LPALGO_PRIMALSIMPLEX;
10361    lp->solisbasic = TRUE;
10362 
10363    /* stop timing */
10364    if( lp->diving || lp->probing )
10365    {
10366       if( lp->strongbranchprobing )
10367          SCIPclockStop(stat->strongbranchtime, set);
10368       else
10369          SCIPclockStop(stat->divinglptime, set);
10370    }
10371    else
10372    {
10373       timedelta += SCIPclockGetTime(stat->primallptime);
10374       SCIPclockStop(stat->primallptime, set);
10375    }
10376 
10377    if ( instable )
10378    {
10379       SCIPclockStop(stat->resolveinstablelptime, set);
10380    }
10381 
10382    /* count number of iterations */
10383    SCIPstatIncrement(stat, set, lpcount);
10384    SCIP_CALL( SCIPlpGetIterations(lp, &iterations) );
10385    if( iterations > 0 ) /* don't count the resolves after removing unused columns/rows */
10386    {
10387       if( !lp->strongbranchprobing )
10388       {
10389          SCIPstatIncrement(stat, set, nlps);
10390          SCIPstatAdd( stat, set, nlpiterations, iterations );
10391       }
10392       if( resolve && !lp->lpifromscratch && stat->nlps > 1 )
10393       {
10394          SCIPstatIncrement(stat, set, nprimalresolvelps );
10395          SCIPstatAdd(stat, set, nprimalresolvelpiterations, iterations);
10396       }
10397       if ( instable )
10398       {
10399          SCIPstatIncrement(stat, set, nresolveinstablelps);
10400          SCIPstatAdd(stat, set, nresolveinstablelpiters, iterations);
10401       }
10402       if( lp->diving || lp->probing )
10403       {
10404          if( lp->strongbranchprobing )
10405          {
10406             SCIPstatIncrement(stat, set, nsbdivinglps);
10407             SCIPstatAdd(stat, set, nsbdivinglpiterations, iterations);
10408          }
10409          else
10410          {
10411             SCIPstatUpdate(stat, set, lastdivenode, stat->nnodes);
10412             SCIPstatIncrement(stat, set, ndivinglps);
10413             SCIPstatAdd(stat, set, ndivinglpiterations, iterations);
10414          }
10415       }
10416       else
10417       {
10418          SCIPstatIncrement(stat, set, nprimallps);
10419          SCIPstatAdd(stat, set, nprimallpiterations, iterations);
10420       }
10421    }
10422    else
10423    {
10424       if ( ! lp->diving && ! lp->probing )
10425       {
10426          SCIPstatIncrement(stat, set, nprimalzeroitlps);
10427          SCIPstatAdd(stat, set, primalzeroittime, timedelta);
10428       }
10429 
10430       if ( keepsol && !(*lperror) )
10431       {
10432          /* the solution didn't change: if the solution was valid before resolve, it is still valid */
10433          if( lp->validsollp == stat->lpcount-1 )
10434             lp->validsollp = stat->lpcount;
10435          if( lp->validfarkaslp == stat->lpcount-1 )
10436             lp->validfarkaslp = stat->lpcount;
10437       }
10438    }
10439 
10440    SCIPsetDebugMsg(set, "solved LP %" SCIP_LONGINT_FORMAT " with primal simplex (diving=%d, nprimallps=%" SCIP_LONGINT_FORMAT ", ndivinglps=%" SCIP_LONGINT_FORMAT ")\n",
10441       stat->lpcount, lp->diving || lp->probing, stat->nprimallps, stat->ndivinglps);
10442 
10443    return SCIP_OKAY;
10444 }
10445 
10446 /** calls LPI to perform dual simplex, measures time and counts iterations */
10447 static
lpDualSimplex(SCIP_LP * lp,SCIP_SET * set,SCIP_STAT * stat,SCIP_Bool resolve,SCIP_Bool keepsol,SCIP_Bool instable,SCIP_Bool * lperror)10448 SCIP_RETCODE lpDualSimplex(
10449    SCIP_LP*              lp,                 /**< current LP data */
10450    SCIP_SET*             set,                /**< global SCIP settings */
10451    SCIP_STAT*            stat,               /**< problem statistics */
10452    SCIP_Bool             resolve,            /**< is this a resolving call (starting with feasible basis)? */
10453    SCIP_Bool             keepsol,            /**< should the old LP solution be kept if no iterations were performed? */
10454    SCIP_Bool             instable,           /**< is this a resolving call to avoid instable LPs? */
10455    SCIP_Bool*            lperror             /**< pointer to store whether an unresolved LP error occurred */
10456    )
10457 {
10458    SCIP_Real timedelta;
10459    SCIP_RETCODE retcode;
10460    int iterations;
10461 
10462    assert(lp != NULL);
10463    assert(lp->flushed);
10464    assert(set != NULL);
10465    assert(stat != NULL);
10466    assert(lperror != NULL);
10467 
10468    SCIPsetDebugMsg(set, "solving LP %" SCIP_LONGINT_FORMAT " (%d cols, %d rows) with dual simplex (diving=%d, nduallps=%" SCIP_LONGINT_FORMAT ", ndivinglps=%" SCIP_LONGINT_FORMAT ")\n",
10469       stat->lpcount+1, lp->ncols, lp->nrows, lp->diving || lp->probing, stat->nduallps, stat->ndivinglps);
10470 
10471    *lperror = FALSE;
10472 
10473 #ifdef SCIP_MORE_DEBUG /* for debugging: write all root node LP's */
10474    if( stat->nnodes == 1 && !lp->diving && !lp->probing )
10475    {
10476       char fname[SCIP_MAXSTRLEN];
10477       (void) SCIPsnprintf(fname, SCIP_MAXSTRLEN, "lp%" SCIP_LONGINT_FORMAT "_%" SCIP_LONGINT_FORMAT ".lp", stat->nnodes, stat->lpcount);
10478       SCIP_CALL( SCIPlpWrite(lp, fname) );
10479       SCIPsetDebugMsg(set, "wrote LP to file <%s> (dual simplex, objlim=%.15g, feastol=%.15g/%.15g, fromscratch=%d, fastmip=%d, scaling=%d, presolving=%d)\n",
10480          fname, lp->lpiobjlim, lp->lpifeastol, lp->lpidualfeastol,
10481          lp->lpifromscratch, lp->lpifastmip, lp->lpiscaling, lp->lpipresolving);
10482    }
10483 #endif
10484 
10485    /* start timing */
10486    if( lp->diving || lp->probing )
10487    {
10488       if( lp->strongbranchprobing )
10489          SCIPclockStart(stat->strongbranchtime, set);
10490       else
10491          SCIPclockStart(stat->divinglptime, set);
10492 
10493       timedelta = 0.0;   /* unused for diving or probing */
10494    }
10495    else
10496    {
10497       SCIPclockStart(stat->duallptime, set);
10498       timedelta = -SCIPclockGetTime(stat->duallptime);
10499    }
10500 
10501    /* if this is a call to resolve an instable LP, collect time */
10502    if ( instable )
10503    {
10504       SCIPclockStart(stat->resolveinstablelptime, set);
10505    }
10506 
10507    /* call dual simplex */
10508    retcode = SCIPlpiSolveDual(lp->lpi);
10509    if( retcode == SCIP_LPERROR )
10510    {
10511       *lperror = TRUE;
10512       SCIPsetDebugMsg(set, "(node %" SCIP_LONGINT_FORMAT ") dual simplex solving error in LP %" SCIP_LONGINT_FORMAT "\n", stat->nnodes, stat->nlps);
10513    }
10514    else
10515    {
10516       SCIP_CALL( retcode );
10517    }
10518    lp->lastlpalgo = SCIP_LPALGO_DUALSIMPLEX;
10519    lp->solisbasic = TRUE;
10520 
10521    /* stop timing */
10522    if( lp->diving || lp->probing )
10523    {
10524       if( lp->strongbranchprobing )
10525          SCIPclockStop(stat->strongbranchtime, set);
10526       else
10527          SCIPclockStop(stat->divinglptime, set);
10528    }
10529    else
10530    {
10531       timedelta += SCIPclockGetTime(stat->duallptime);
10532       SCIPclockStop(stat->duallptime, set);
10533    }
10534 
10535    if ( instable )
10536    {
10537       SCIPclockStop(stat->resolveinstablelptime, set);
10538    }
10539 
10540    /* count number of iterations */
10541    SCIPstatIncrement(stat, set, lpcount);
10542    SCIP_CALL( SCIPlpGetIterations(lp, &iterations) );
10543    if( iterations > 0 ) /* don't count the resolves after removing unused columns/rows */
10544    {
10545       if( !lp->strongbranchprobing )
10546       {
10547          SCIPstatIncrement(stat, set, nlps);
10548          SCIPstatAdd(stat, set, nlpiterations, iterations);
10549       }
10550       if( resolve && !lp->lpifromscratch && stat->nlps > 1  )
10551       {
10552          SCIPstatIncrement(stat, set, ndualresolvelps);
10553          SCIPstatAdd(stat, set, ndualresolvelpiterations, iterations);
10554       }
10555       if ( instable )
10556       {
10557          SCIPstatIncrement(stat, set, nresolveinstablelps);
10558          SCIPstatAdd(stat, set, nresolveinstablelpiters, iterations);
10559       }
10560       if( lp->diving || lp->probing )
10561       {
10562          if( lp->strongbranchprobing )
10563          {
10564             SCIPstatIncrement(stat, set, nsbdivinglps);
10565             SCIPstatAdd(stat, set, nsbdivinglpiterations, iterations);
10566          }
10567          else
10568          {
10569             SCIPstatUpdate(stat, set, lastdivenode, stat->nnodes);
10570             SCIPstatIncrement(stat, set, ndivinglps);
10571             SCIPstatAdd(stat, set, ndivinglpiterations, iterations);
10572          }
10573       }
10574       else
10575       {
10576          SCIPstatIncrement(stat, set, nduallps);
10577          SCIPstatAdd(stat, set, nduallpiterations, iterations);
10578       }
10579    }
10580    else
10581    {
10582       if ( ! lp->diving && ! lp->probing )
10583       {
10584          SCIPstatIncrement(stat, set, ndualzeroitlps);
10585          SCIPstatAdd(stat, set, dualzeroittime, timedelta);
10586       }
10587 
10588       if( keepsol && !(*lperror) )
10589       {
10590          /* the solution didn't change: if the solution was valid before resolve, it is still valid */
10591          if( lp->validsollp == stat->lpcount-1 )
10592             lp->validsollp = stat->lpcount;
10593          if( lp->validfarkaslp == stat->lpcount-1 )
10594             lp->validfarkaslp = stat->lpcount;
10595       }
10596    }
10597 
10598    SCIPsetDebugMsg(set, "solved LP %" SCIP_LONGINT_FORMAT " with dual simplex (diving=%d, nduallps=%" SCIP_LONGINT_FORMAT ", ndivinglps=%" SCIP_LONGINT_FORMAT ")\n",
10599       stat->lpcount, lp->diving || lp->probing, stat->nduallps, stat->ndivinglps);
10600 
10601    return SCIP_OKAY;
10602 }
10603 
10604 /** calls LPI to perform lexicographic dual simplex to find a lexicographically minimal optimal solution, measures time and counts iterations
10605  *
10606  *  We follow the approach of the following paper to find a lexicographically minimal optimal
10607  *  solution:
10608  *
10609  *  Zanette, Fischetti, Balas@n
10610  *  Can pure cutting plane algorithms work?@n
10611  *  IPCO 2008, Bertinoro, Italy.
10612  *
10613  *  We do, however, not aim for the exact lexicographically minimal optimal solutions, but perform a
10614  *  heuristic, i.e., we limit the number of components which are minimized.
10615  *
10616  *  More precisely, we first solve the problem with the dual simplex algorithm. Then we fix those
10617  *  nonbasic variables to their current value (i.e., one of the bounds except maybe for free
10618  *  variables) that have nonzero reduced cost. This fixes the objective function value, because only
10619  *  pivots that will not change the objective are allowed afterwards.
10620  *
10621  *  Then the not yet fixed variables are considered in turn. If they are at their lower bounds and
10622  *  nonbasic, they are fixed to this bound, since their value cannot be decreased further. Once a
10623  *  candidate is found, we set the objective to minimize this variable. We run the primal simplex
10624  *  algorithm (since the objective is changed the solution is not dual feasible anymore; if
10625  *  variables out of the basis have been fixed to their lower bound, the basis is also not primal
10626  *  feasible anymore). After the optimization, we again fix nonbasic variables that have nonzero
10627  *  reduced cost. We then choose the next variable and iterate.
10628  *
10629  *  We stop the process once we do not find candidates or have performed a maximum number of
10630  *  iterations.
10631  *
10632  *  @todo Does this really produce a lexicographically minimal solution?
10633  *  @todo Can we skip the consideration of basic variables that are at their lower bound? How can we
10634  *    guarantee that these variables will not be changed in later stages? We can fix these variables
10635  *    to their lower bound, but this destroys the basis.
10636  *  @todo Should we use lexicographical minimization in diving/probing or not?
10637  */
10638 static
lpLexDualSimplex(SCIP_LP * lp,SCIP_SET * set,SCIP_STAT * stat,SCIP_Bool resolve,SCIP_Bool keepsol,SCIP_Bool * lperror)10639 SCIP_RETCODE lpLexDualSimplex(
10640    SCIP_LP*              lp,                 /**< current LP data */
10641    SCIP_SET*             set,                /**< global SCIP settings */
10642    SCIP_STAT*            stat,               /**< problem statistics */
10643    SCIP_Bool             resolve,            /**< is this a resolving call (starting with feasible basis)? */
10644    SCIP_Bool             keepsol,            /**< should the old LP solution be kept if no iterations were performed? */
10645    SCIP_Bool*            lperror             /**< pointer to store whether an unresolved LP error occurred */
10646    )
10647 {
10648    SCIP_Real timedelta;
10649    SCIP_RETCODE retcode;
10650    int totalIterations;
10651    int lexIterations;
10652    int iterations;
10653    int rounds;
10654 
10655    assert(lp != NULL);
10656    assert(lp->flushed);
10657    assert(set != NULL);
10658    assert(stat != NULL);
10659    assert(lperror != NULL);
10660 
10661    SCIPsetDebugMsg(set, "solving LP %" SCIP_LONGINT_FORMAT " (%d cols, %d rows) with lex dual simplex (diving=%d, nduallps=%" SCIP_LONGINT_FORMAT ", ndivinglps=%" SCIP_LONGINT_FORMAT ")\n",
10662       stat->lpcount+1, lp->ncols, lp->nrows, lp->diving || lp->probing, stat->nduallps, stat->ndivinglps);
10663 
10664    *lperror = FALSE;
10665 
10666    /* start timing */
10667    if( lp->diving || lp->probing )
10668    {
10669       if( lp->strongbranchprobing )
10670          SCIPclockStart(stat->strongbranchtime, set);
10671       else
10672          SCIPclockStart(stat->divinglptime, set);
10673 
10674       timedelta = 0.0;   /* unused for diving or probing */
10675    }
10676    else
10677    {
10678       SCIPclockStart(stat->duallptime, set);
10679       timedelta = -SCIPclockGetTime(stat->duallptime);
10680    }
10681 
10682    /* call dual simplex for first lp */
10683    retcode = SCIPlpiSolveDual(lp->lpi);
10684    if( retcode == SCIP_LPERROR )
10685    {
10686       *lperror = TRUE;
10687       SCIPsetDebugMsg(set, "(node %" SCIP_LONGINT_FORMAT ") dual simplex solving error in LP %" SCIP_LONGINT_FORMAT "\n", stat->nnodes, stat->nlps);
10688    }
10689    else
10690    {
10691       SCIP_CALL( retcode );
10692    }
10693    SCIP_CALL( SCIPlpGetIterations(lp, &iterations) );
10694    totalIterations = iterations;
10695 
10696    /* stop timing */
10697    if( lp->diving || lp->probing )
10698    {
10699       if( lp->strongbranchprobing )
10700          SCIPclockStop(stat->strongbranchtime, set);
10701       else
10702          SCIPclockStop(stat->divinglptime, set);
10703    }
10704    else
10705    {
10706       timedelta += SCIPclockGetTime(stat->duallptime);
10707       SCIPclockStop(stat->duallptime, set);
10708    }
10709 
10710    /* count number of iterations */
10711    SCIPstatIncrement(stat, set, lpcount);
10712    if( iterations > 0 ) /* don't count the resolves after removing unused columns/rows */
10713    {
10714       if( lp->strongbranchprobing )
10715       {
10716          SCIPstatAdd(stat, set, nlpiterations, iterations);
10717       }
10718       if( resolve && !lp->lpifromscratch && stat->nlps > 1  )
10719       {
10720          SCIPstatIncrement(stat, set, ndualresolvelps);
10721          SCIPstatAdd(stat, set, ndualresolvelpiterations, iterations);
10722       }
10723       if( lp->diving || lp->probing )
10724       {
10725          if( lp->strongbranchprobing )
10726          {
10727             SCIPstatIncrement(stat, set, nsbdivinglps);
10728             SCIPstatAdd(stat, set, nsbdivinglpiterations, iterations);
10729          }
10730          else
10731          {
10732             SCIPstatUpdate(stat, set, lastdivenode, stat->nnodes);
10733             SCIPstatIncrement(stat, set, ndivinglps);
10734             SCIPstatAdd(stat, set, ndivinglpiterations, iterations);
10735          }
10736       }
10737       else
10738       {
10739          SCIPstatIncrement(stat, set, nduallps);
10740          SCIPstatAdd(stat, set, nduallpiterations, iterations);
10741       }
10742    }
10743    else
10744    {
10745       if ( ! lp->diving && ! lp->probing )
10746       {
10747          SCIPstatIncrement(stat, set, ndualzeroitlps);
10748          SCIPstatAdd(stat, set, dualzeroittime, timedelta);
10749       }
10750    }
10751    lexIterations = 0;
10752 
10753    /* search for lexicographically minimal optimal solution */
10754    if( !lp->diving && !lp->probing && SCIPlpiIsOptimal(lp->lpi) )
10755    {
10756       SCIP_Bool chooseBasic;
10757       SCIP_Real* primsol;
10758       SCIP_Real* dualsol;
10759       SCIP_Real* redcost;
10760       int* cstat;
10761       int* rstat;
10762       SCIP_Real* newobj;
10763       SCIP_Real* newlb;
10764       SCIP_Real* newub;
10765       SCIP_Real* newlhs;
10766       SCIP_Real* newrhs;
10767       SCIP_Real* oldlb;
10768       SCIP_Real* oldub;
10769       SCIP_Real* oldlhs;
10770       SCIP_Real* oldrhs;
10771       SCIP_Real* oldobj;
10772       SCIP_Bool* fixedc;
10773       SCIP_Bool* fixedr;
10774       int* indcol;
10775       int* indrow;
10776       int* indallcol;
10777       int* indallrow;
10778       int nDualDeg;
10779       int r, c;
10780       int cntcol;
10781       int cntrow;
10782       int nruns;
10783       int pos;
10784 
10785       chooseBasic = set->lp_lexdualbasic;
10786 
10787       /* start timing */
10788       SCIPclockStart(stat->lexduallptime, set);
10789 
10790       /* get all solution information */
10791       SCIP_CALL( SCIPsetAllocBufferArray(set, &dualsol, lp->nlpirows) );
10792       SCIP_CALL( SCIPsetAllocBufferArray(set, &redcost, lp->nlpicols) );
10793       if( chooseBasic )
10794       {
10795          SCIP_CALL( SCIPsetAllocBufferArray(set, &primsol, lp->nlpicols) );
10796       }
10797       else
10798          primsol = NULL;
10799 
10800       /* get basic and nonbasic information */
10801       SCIP_CALL( SCIPsetAllocBufferArray(set, &cstat, lp->nlpicols) );
10802       SCIP_CALL( SCIPsetAllocBufferArray(set, &rstat, lp->nlpirows) );
10803 
10804       /* save bounds, lhs/rhs, and objective */
10805       SCIP_CALL( SCIPsetAllocBufferArray(set, &oldobj, lp->nlpicols) );
10806       SCIP_CALL( SCIPsetAllocBufferArray(set, &oldlb, lp->nlpicols) );
10807       SCIP_CALL( SCIPsetAllocBufferArray(set, &oldub, lp->nlpicols) );
10808       SCIP_CALL( SCIPsetAllocBufferArray(set, &oldlhs, lp->nlpirows) );
10809       SCIP_CALL( SCIPsetAllocBufferArray(set, &oldrhs, lp->nlpirows) );
10810       SCIP_CALL( SCIPlpiGetBounds(lp->lpi, 0, lp->nlpicols-1, oldlb, oldub) );
10811       SCIP_CALL( SCIPlpiGetSides(lp->lpi, 0, lp->nlpirows-1, oldlhs, oldrhs) );
10812       SCIP_CALL( SCIPlpiGetObj(lp->lpi, 0, lp->nlpicols-1, oldobj) );
10813 
10814       /* get storage for several arrays */
10815       SCIP_CALL( SCIPsetAllocBufferArray(set, &newlb, lp->nlpicols) );
10816       SCIP_CALL( SCIPsetAllocBufferArray(set, &newub, lp->nlpicols) );
10817       SCIP_CALL( SCIPsetAllocBufferArray(set, &indcol, lp->nlpicols) );
10818 
10819       SCIP_CALL( SCIPsetAllocBufferArray(set, &newlhs, lp->nlpirows) );
10820       SCIP_CALL( SCIPsetAllocBufferArray(set, &newrhs, lp->nlpirows) );
10821       SCIP_CALL( SCIPsetAllocBufferArray(set, &indrow, lp->nlpirows) );
10822 
10823       SCIP_CALL( SCIPsetAllocBufferArray(set, &indallcol, lp->nlpicols) );
10824       SCIP_CALL( SCIPsetAllocBufferArray(set, &indallrow, lp->nlpirows) );
10825 
10826       SCIP_CALL( SCIPsetAllocBufferArray(set, &fixedc, lp->nlpicols) );
10827       SCIP_CALL( SCIPsetAllocBufferArray(set, &fixedr, lp->nlpirows) );
10828 
10829       /* initialize: set objective to 0, get fixed variables */
10830       SCIP_CALL( SCIPsetAllocBufferArray(set, &newobj, lp->nlpicols) );
10831       for( c = 0; c < lp->nlpicols; ++c )
10832       {
10833          newobj[c] = 0.0;
10834          indallcol[c] = c;
10835          if( SCIPsetIsFeasEQ(set, oldlb[c], oldub[c]) )
10836             fixedc[c] = TRUE;
10837          else
10838             fixedc[c] = FALSE;
10839       }
10840 
10841       /* initialize: get fixed slack variables */
10842       for( r = 0; r < lp->nlpirows; ++r )
10843       {
10844          indallrow[r] = r;
10845          if( SCIPsetIsFeasEQ(set, oldlhs[r], oldrhs[r]) )
10846             fixedr[r] = TRUE;
10847          else
10848             fixedr[r] = FALSE;
10849       }
10850 
10851 #ifdef DEBUG_LEXDUAL
10852       {
10853          int j;
10854 
10855          if( !chooseBasic )
10856          {
10857             assert(primsol == NULL);
10858             SCIP_CALL( SCIPsetAllocBufferArray(set, &primsol, lp->nlpicols) );
10859          }
10860          assert(primsol != NULL);
10861          SCIP_CALL( SCIPlpiGetSol(lp->lpi, NULL, primsol, NULL, NULL, NULL) );
10862          SCIP_CALL( SCIPlpiGetBase(lp->lpi, cstat, rstat) );
10863 
10864          for( j = 0; j < lp->nlpicols; ++j )
10865          {
10866             if( fixedc[j] )
10867             {
10868                SCIPsetDebugMsg(set, "%f (%d) [f] ", primsol[j], j);
10869             }
10870             else
10871             {
10872                char type;
10873                switch( (SCIP_BASESTAT) cstat[j] )
10874                {
10875                case SCIP_BASESTAT_LOWER:
10876                   type = 'l';
10877                   break;
10878                case SCIP_BASESTAT_UPPER:
10879                   type = 'u';
10880                   break;
10881                case SCIP_BASESTAT_ZERO:
10882                   type = 'z';
10883                   break;
10884                case SCIP_BASESTAT_BASIC:
10885                   type = 'b';
10886                   break;
10887                default:
10888                   type = '?';
10889                   SCIPerrorMessage("unknown base stat %d\n", cstat[j]);
10890                   SCIPABORT();
10891                }
10892                SCIPsetDebugMsg(set, "%f (%d) [%c] ", primsol[j], j, type);
10893             }
10894          }
10895          SCIPsetDebugMsg(set, "\n\n");
10896 
10897          if( !chooseBasic )
10898          {
10899             SCIPsetFreeBufferArray(set, &primsol);
10900             assert(primsol == NULL);
10901          }
10902       }
10903 #endif
10904 
10905       /* perform lexicographic rounds */
10906       pos = -1;
10907       nruns = 0;
10908       rounds = 0;
10909       /* SCIP_CALL( lpSetLPInfo(lp, TRUE) ); */
10910       do
10911       {
10912          int oldpos;
10913 
10914          /* get current solution */
10915          if( chooseBasic )
10916             SCIP_CALL( SCIPlpiGetSol(lp->lpi, NULL, primsol, dualsol, NULL, redcost) );
10917          else
10918          {
10919             SCIP_CALL( SCIPlpiGetSol(lp->lpi, NULL, NULL, dualsol, NULL, redcost) );
10920             assert(primsol == NULL);
10921          }
10922 
10923          /* get current basis */
10924          SCIP_CALL( SCIPlpiGetBase(lp->lpi, cstat, rstat) );
10925 
10926          /* check columns: find first candidate (either basic or nonbasic and zero reduced cost) and fix variables */
10927          nDualDeg = 0;
10928          cntcol = 0;
10929          oldpos = pos;
10930          pos = -1;
10931          for( c = 0; c < lp->nlpicols; ++c )
10932          {
10933             if( !fixedc[c] )
10934             {
10935                /* check whether variable is in basis */
10936                if( (SCIP_BASESTAT) cstat[c] == SCIP_BASESTAT_BASIC )
10937                {
10938                   /* store first candidate */
10939                   if( pos == -1 && c > oldpos )
10940                   {
10941                      if( !chooseBasic || !SCIPsetIsIntegral(set, primsol[c]) ) /*lint !e613*/
10942                         pos = c;
10943                   }
10944                }
10945                else
10946                {
10947                   /* reduced cost == 0 -> possible candidate */
10948                   if( SCIPsetIsDualfeasZero(set, redcost[c]) )
10949                   {
10950                      ++nDualDeg;
10951                      /* only if we have not yet found a candidate */
10952                      if( pos == -1 && c > oldpos )
10953                      {
10954                         /* if the variable is at its lower bound - fix it, because its value cannot be reduced */
10955                         if( (SCIP_BASESTAT) cstat[c] == SCIP_BASESTAT_LOWER )
10956                         {
10957                            newlb[cntcol] = oldlb[c];
10958                            newub[cntcol] = oldlb[c];
10959                            indcol[cntcol++] = c;
10960                            fixedc[c] = TRUE;
10961                         }
10962                         else /* found a non-fixed candidate */
10963                         {
10964                            if( !chooseBasic )
10965                               pos = c;
10966                         }
10967                      }
10968                   }
10969                   else
10970                   {
10971                      /* nonzero reduced cost -> variable can be fixed */
10972                      if( (SCIP_BASESTAT) cstat[c] == SCIP_BASESTAT_LOWER )
10973                      {
10974                         newlb[cntcol] = oldlb[c];
10975                         newub[cntcol] = oldlb[c];
10976                      }
10977                      else
10978                      {
10979                         if( (SCIP_BASESTAT) cstat[c] == SCIP_BASESTAT_UPPER )
10980                         {
10981                            newlb[cntcol] = oldub[c];
10982                            newub[cntcol] = oldub[c];
10983                         }
10984                         else
10985                         {
10986                            assert((SCIP_BASESTAT) cstat[c] == SCIP_BASESTAT_ZERO);
10987                            newlb[cntcol] = 0.0;
10988                            newub[cntcol] = 0.0;
10989                         }
10990                      }
10991                      indcol[cntcol++] = c;
10992                      fixedc[c] = TRUE;
10993                   }
10994                }
10995             }
10996          }
10997 
10998          /* check rows */
10999          cntrow = 0;
11000          for( r = 0; r < lp->nlpirows; ++r )
11001          {
11002             if( !fixedr[r] )
11003             {
11004                /* consider only nonbasic rows */
11005                if( (SCIP_BASESTAT) rstat[r] != SCIP_BASESTAT_BASIC )
11006                {
11007                   assert((SCIP_BASESTAT) rstat[r] != SCIP_BASESTAT_ZERO);
11008                   if( SCIPsetIsFeasZero(set, dualsol[r]) )
11009                      ++nDualDeg;
11010                   else
11011                   {
11012                      if( SCIPsetIsFeasPositive(set, dualsol[r]) )
11013                      {
11014                         assert(!SCIPsetIsInfinity(set, -oldlhs[r]));
11015                         newlhs[cntrow] = oldlhs[r];
11016                         newrhs[cntrow] = oldlhs[r];
11017                      }
11018                      else
11019                      {
11020                         assert(!SCIPsetIsInfinity(set, oldrhs[r]));
11021                         newlhs[cntrow] = oldrhs[r];
11022                         newrhs[cntrow] = oldrhs[r];
11023                      }
11024                      indrow[cntrow++] = r;
11025                      fixedr[r] = TRUE;
11026                   }
11027                }
11028             }
11029          }
11030 
11031          if( nDualDeg > 0 && pos >= 0 )
11032          {
11033             assert(0 <= pos && pos < lp->nlpicols && pos > oldpos);
11034 
11035             /* change objective */
11036             if( nruns == 0 )
11037             {
11038                /* set objective to appropriate unit vector for first run */
11039                newobj[pos] = 1.0;
11040                SCIP_CALL( SCIPlpiChgObj(lp->lpi, lp->nlpicols, indallcol, newobj) );
11041             }
11042             else
11043             {
11044                /* set obj. coef. to 1 for other runs (ones remain in previous positions) */
11045                SCIP_Real obj = 1.0;
11046                SCIP_CALL( SCIPlpiChgObj(lp->lpi, 1, &pos, &obj) );
11047             }
11048 
11049             /* fix variables */
11050             SCIP_CALL( SCIPlpiChgBounds(lp->lpi, cntcol, indcol, newlb, newub) );
11051             SCIP_CALL( SCIPlpiChgSides(lp->lpi, cntrow, indrow, newlhs, newrhs) );
11052 
11053             /* solve with primal simplex, because we are primal feasible, but not necessarily dual feasible */
11054             retcode = SCIPlpiSolvePrimal(lp->lpi);
11055             if( retcode == SCIP_LPERROR )
11056             {
11057                *lperror = TRUE;
11058                SCIPsetDebugMsg(set, "(node %" SCIP_LONGINT_FORMAT ") in lex-dual: primal simplex solving error in LP %" SCIP_LONGINT_FORMAT "\n", stat->nnodes, stat->nlps);
11059             }
11060             else
11061             {
11062                SCIP_CALL( retcode );
11063             }
11064             SCIP_CALL( SCIPlpGetIterations(lp, &iterations) );
11065             lexIterations += iterations;
11066 
11067 #ifdef DEBUG_LEXDUAL
11068             if( iterations > 0 )
11069             {
11070                int j;
11071 
11072                if( !chooseBasic )
11073                {
11074                   assert(primsol == NULL);
11075                   SCIP_CALL( SCIPsetAllocBufferArray(set, &primsol, lp->nlpicols) );
11076                }
11077                assert(primsol != NULL);
11078                SCIP_CALL( SCIPlpiGetSol(lp->lpi, NULL, primsol, NULL, NULL, NULL) );
11079 
11080                for( j = 0; j < lp->nlpicols; ++j )
11081                {
11082                   if( fixedc[j] )
11083                   {
11084                      SCIPsetDebugMsg(set, "%f (%d) [f] ", primsol[j], j);
11085                   }
11086                   else
11087                   {
11088                      char cstart = '[';
11089                      char cend = ']';
11090                      char type;
11091 
11092                      if(j == pos)
11093                      {
11094                         cstart = '*';
11095                         cend = '*';
11096                      }
11097 
11098                      switch( (SCIP_BASESTAT) cstat[j] )
11099                      {
11100                      case SCIP_BASESTAT_LOWER:
11101                         type = 'l';
11102                         break;
11103                      case SCIP_BASESTAT_UPPER:
11104                         type = 'u';
11105                         break;
11106                      case SCIP_BASESTAT_ZERO:
11107                         type = 'z';
11108                         break;
11109                      case SCIP_BASESTAT_BASIC:
11110                         type = 'b';
11111                         break;
11112                      default:
11113                         type = '?';
11114                         SCIPerrorMessage("unknown base state %d\n", cstat[j]);
11115                         SCIPABORT();
11116                      }
11117                      SCIPsetDebugMsg(set, "%f (%d) %c%c%c ", primsol[j], j, cstart, type, cend);
11118                   }
11119                }
11120                SCIPsetDebugMsg(set, "\n\n");
11121 
11122                if( !chooseBasic )
11123                {
11124                   SCIPsetFreeBufferArray(set, &primsol);
11125                   assert(primsol == NULL);
11126                }
11127             }
11128 #endif
11129 
11130             /* count only as round if iterations have been performed */
11131             if( iterations > 0 )
11132                ++rounds;
11133             ++nruns;
11134          }
11135       }
11136       while( pos >= 0 && nDualDeg > 0 && (set->lp_lexdualmaxrounds == -1 || rounds < set->lp_lexdualmaxrounds) );
11137 
11138       /* reset bounds, lhs/rhs, and obj */
11139       SCIP_CALL( SCIPlpiChgBounds(lp->lpi, lp->nlpicols, indallcol, oldlb, oldub) );
11140       SCIP_CALL( SCIPlpiChgSides(lp->lpi, lp->nlpirows, indallrow, oldlhs, oldrhs) );
11141       SCIP_CALL( SCIPlpiChgObj(lp->lpi, lp->nlpicols, indallcol, oldobj) );
11142 
11143       /* resolve to update solvers internal data structures - should only produce few pivots - is this needed? */
11144       retcode = SCIPlpiSolveDual(lp->lpi);
11145       if( retcode == SCIP_LPERROR )
11146       {
11147          *lperror = TRUE;
11148          SCIPsetDebugMsg(set, "(node %" SCIP_LONGINT_FORMAT ") dual simplex solving error in LP %" SCIP_LONGINT_FORMAT "\n", stat->nnodes, stat->nlps);
11149       }
11150       else
11151       {
11152          SCIP_CALL( retcode );
11153       }
11154       assert(SCIPlpiIsOptimal(lp->lpi));
11155       SCIP_CALL( SCIPlpGetIterations(lp, &iterations) );
11156       lexIterations += iterations;
11157 
11158       /* SCIP_CALL( lpSetLPInfo(lp, set->disp_lpinfo) ); */
11159 
11160       /* count number of iterations */
11161       if( totalIterations == 0 && lexIterations > 0 && !lp->strongbranchprobing )
11162          SCIPstatIncrement(stat, set, nlps);
11163 
11164       if( lexIterations > 0 ) /* don't count the resolves after removing unused columns/rows */
11165       {
11166          SCIPstatAdd(stat, set, nlpiterations, lexIterations);
11167          if( resolve && !lp->lpifromscratch && stat->nlps > 1  )
11168          {
11169             SCIPstatIncrement(stat, set, nlexdualresolvelps);
11170             SCIPstatAdd(stat, set, nlexdualresolvelpiterations, lexIterations);
11171          }
11172          SCIPstatIncrement(stat, set, nlexduallps);
11173          SCIPstatAdd(stat, set, nlexduallpiterations, lexIterations);
11174 
11175          totalIterations += lexIterations;
11176       }
11177 
11178       /* free space */
11179       SCIPsetFreeBufferArray(set, &newobj);
11180 
11181       SCIPsetFreeBufferArray(set, &fixedr);
11182       SCIPsetFreeBufferArray(set, &fixedc);
11183 
11184       SCIPsetFreeBufferArray(set, &indallrow);
11185       SCIPsetFreeBufferArray(set, &indallcol);
11186 
11187       SCIPsetFreeBufferArray(set, &indrow);
11188       SCIPsetFreeBufferArray(set, &newrhs);
11189       SCIPsetFreeBufferArray(set, &newlhs);
11190 
11191       SCIPsetFreeBufferArray(set, &indcol);
11192       SCIPsetFreeBufferArray(set, &newub);
11193       SCIPsetFreeBufferArray(set, &newlb);
11194 
11195       SCIPsetFreeBufferArray(set, &oldobj);
11196       SCIPsetFreeBufferArray(set, &oldrhs);
11197       SCIPsetFreeBufferArray(set, &oldlhs);
11198       SCIPsetFreeBufferArray(set, &oldub);
11199       SCIPsetFreeBufferArray(set, &oldlb);
11200 
11201       SCIPsetFreeBufferArray(set, &rstat);
11202       SCIPsetFreeBufferArray(set, &cstat);
11203 
11204       SCIPsetFreeBufferArray(set, &redcost);
11205       SCIPsetFreeBufferArray(set, &dualsol);
11206       if( chooseBasic )
11207          SCIPsetFreeBufferArray(set, &primsol);
11208 
11209       /* stop timing */
11210       SCIPclockStop(stat->lexduallptime, set);
11211 
11212       SCIPsetDebugMsg(set, "solved LP %" SCIP_LONGINT_FORMAT " with lex dual simplex (diving=%d, nduallps=%" SCIP_LONGINT_FORMAT ", ndivinglps=%" SCIP_LONGINT_FORMAT ")\n",
11213          stat->lpcount, lp->diving || lp->probing, stat->nduallps, stat->ndivinglps);
11214    }
11215    lp->lastlpalgo = SCIP_LPALGO_DUALSIMPLEX;
11216    lp->solisbasic = TRUE;
11217 
11218    if( totalIterations > 0 && !lp->strongbranchprobing )
11219       SCIPstatIncrement(stat, set, nlps);
11220    else
11221    {
11222       if( keepsol && !(*lperror) )
11223       {
11224          /* the solution didn't change: if the solution was valid before resolve, it is still valid */
11225          if( lp->validsollp == stat->lpcount-1 )
11226             lp->validsollp = stat->lpcount;
11227          if( lp->validfarkaslp == stat->lpcount-1 )
11228             lp->validfarkaslp = stat->lpcount;
11229       }
11230    }
11231 
11232    return SCIP_OKAY;
11233 }
11234 
11235 /** calls LPI to perform barrier, measures time and counts iterations, gets basis feasibility status */
11236 static
lpBarrier(SCIP_LP * lp,SCIP_SET * set,SCIP_STAT * stat,SCIP_Bool crossover,SCIP_Bool keepsol,SCIP_Bool * lperror)11237 SCIP_RETCODE lpBarrier(
11238    SCIP_LP*              lp,                 /**< current LP data */
11239    SCIP_SET*             set,                /**< global SCIP settings */
11240    SCIP_STAT*            stat,               /**< problem statistics */
11241    SCIP_Bool             crossover,          /**< should crossover be performed? */
11242    SCIP_Bool             keepsol,            /**< should the old LP solution be kept if no iterations were performed? */
11243    SCIP_Bool*            lperror             /**< pointer to store whether an unresolved LP error occurred */
11244    )
11245 {
11246    SCIP_Real timedelta;
11247    SCIP_RETCODE retcode;
11248    int iterations;
11249 
11250    assert(lp != NULL);
11251    assert(lp->flushed);
11252    assert(set != NULL);
11253    assert(stat != NULL);
11254    assert(lperror != NULL);
11255 
11256    SCIPsetDebugMsg(set, "solving LP %" SCIP_LONGINT_FORMAT " (%d cols, %d rows) with barrier%s (diving=%d, nbarrierlps=%" SCIP_LONGINT_FORMAT ", ndivinglps=%" SCIP_LONGINT_FORMAT ")\n",
11257       stat->lpcount+1, lp->ncols, lp->nrows, crossover ? "/crossover" : "", lp->diving || lp->probing,
11258       stat->nbarrierlps, stat->ndivinglps);
11259 
11260    *lperror = FALSE;
11261 
11262 #ifdef SCIP_MORE_DEBUG /* for debugging: write all root node LP's */
11263    if( stat->nnodes == 1 && !lp->diving && !lp->probing )
11264    {
11265       char fname[SCIP_MAXSTRLEN];
11266       (void) SCIPsnprintf(fname, SCIP_MAXSTRLEN, "lp%" SCIP_LONGINT_FORMAT "_%" SCIP_LONGINT_FORMAT ".lp", stat->nnodes, stat->lpcount);
11267       SCIP_CALL( SCIPlpWrite(lp, fname) );
11268       SCIPsetDebugMsg(set, "wrote LP to file <%s> (barrier, objlim=%.15g, feastol=%.15g/%.15g, convtol=%.15g, fromscratch=%d, fastmip=%d, scaling=%d, presolving=%d)\n",
11269          fname, lp->lpiobjlim, lp->lpifeastol, lp->lpidualfeastol, lp->lpibarrierconvtol,
11270          lp->lpifromscratch, lp->lpifastmip, lp->lpiscaling, lp->lpipresolving);
11271    }
11272 #endif
11273 
11274    /* start timing */
11275    if( lp->diving || lp->probing )
11276    {
11277       if( lp->strongbranchprobing )
11278          SCIPclockStart(stat->strongbranchtime, set);
11279       else
11280          SCIPclockStart(stat->divinglptime, set);
11281 
11282       timedelta = 0.0;   /* unused for diving or probing */
11283    }
11284    else
11285    {
11286       SCIPclockStart(stat->barrierlptime, set);
11287       timedelta = -SCIPclockGetTime(stat->barrierlptime);
11288    }
11289 
11290    /* call barrier algorithm */
11291    retcode = SCIPlpiSolveBarrier(lp->lpi, crossover);
11292    if( retcode == SCIP_LPERROR )
11293    {
11294       *lperror = TRUE;
11295       SCIPsetDebugMsg(set, "(node %" SCIP_LONGINT_FORMAT ") barrier solving error in LP %" SCIP_LONGINT_FORMAT "\n", stat->nnodes, stat->nlps);
11296    }
11297    else
11298    {
11299       SCIP_CALL( retcode );
11300    }
11301    lp->lastlpalgo = (crossover ? SCIP_LPALGO_BARRIERCROSSOVER : SCIP_LPALGO_BARRIER);
11302    lp->solisbasic = crossover;
11303 
11304    /* stop timing */
11305    if( lp->diving || lp->probing )
11306    {
11307       if( lp->strongbranchprobing )
11308          SCIPclockStop(stat->strongbranchtime, set);
11309       else
11310          SCIPclockStop(stat->divinglptime, set);
11311    }
11312    else
11313    {
11314       SCIPclockStop(stat->barrierlptime, set);
11315       timedelta += SCIPclockGetTime(stat->barrierlptime);
11316    }
11317 
11318    /* count number of iterations */
11319    SCIPstatIncrement(stat, set, lpcount);
11320    SCIP_CALL( SCIPlpGetIterations(lp, &iterations) );
11321    if( iterations > 0 ) /* don't count the resolves after removing unused columns/rows */
11322    {
11323       if( !lp->strongbranchprobing )
11324       {
11325          SCIPstatIncrement(stat, set, nlps);
11326          SCIPstatAdd(stat, set, nlpiterations, iterations);
11327       }
11328       if( lp->diving || lp->probing )
11329       {
11330          if( lp->strongbranchprobing )
11331          {
11332             SCIPstatIncrement(stat, set, nsbdivinglps);
11333             SCIPstatAdd(stat, set, nsbdivinglpiterations, iterations);
11334          }
11335          else
11336          {
11337             SCIPstatUpdate(stat, set, lastdivenode, stat->nnodes);
11338             SCIPstatIncrement(stat, set, ndivinglps);
11339             SCIPstatAdd(stat, set, ndivinglpiterations, iterations);
11340          }
11341       }
11342       else
11343       {
11344          SCIPstatIncrement(stat, set, nbarrierlps);
11345          SCIPstatAdd(stat, set, nbarrierlpiterations, iterations);
11346       }
11347    }
11348    else
11349    {
11350       if ( ! lp->diving && ! lp->probing )
11351       {
11352          SCIPstatIncrement(stat, set, nbarrierzeroitlps);
11353          SCIPstatAdd(stat, set, barrierzeroittime, timedelta);
11354       }
11355 
11356       if( keepsol && !(*lperror) )
11357       {
11358          /* the solution didn't change: if the solution was valid before resolve, it is still valid */
11359          if( lp->validsollp == stat->lpcount-1 )
11360             lp->validsollp = stat->lpcount;
11361          if( lp->validfarkaslp == stat->lpcount-1 )
11362             lp->validfarkaslp = stat->lpcount;
11363       }
11364    }
11365 
11366    SCIPsetDebugMsg(set, "solved LP %" SCIP_LONGINT_FORMAT " with barrier%s (diving=%d, nduallps=%" SCIP_LONGINT_FORMAT ", nbarrierlps=%" SCIP_LONGINT_FORMAT ")\n",
11367       stat->lpcount, crossover ? "/crossover" : "", lp->diving || lp->probing, stat->nbarrierlps, stat->ndivinglps);
11368 
11369    return SCIP_OKAY;
11370 }
11371 
11372 /** solves the LP with the given algorithm */
11373 static
lpAlgorithm(SCIP_LP * lp,SCIP_SET * set,SCIP_STAT * stat,SCIP_LPALGO lpalgo,SCIP_Bool resolve,SCIP_Bool keepsol,SCIP_Bool instable,SCIP_Bool * timelimit,SCIP_Bool * lperror)11374 SCIP_RETCODE lpAlgorithm(
11375    SCIP_LP*              lp,                 /**< current LP data */
11376    SCIP_SET*             set,                /**< global SCIP settings */
11377    SCIP_STAT*            stat,               /**< problem statistics */
11378    SCIP_LPALGO           lpalgo,             /**< LP algorithm that should be applied */
11379    SCIP_Bool             resolve,            /**< is this a resolving call (starting with feasible basis)? */
11380    SCIP_Bool             keepsol,            /**< should the old LP solution be kept if no iterations were performed? */
11381    SCIP_Bool             instable,           /**< is this a resolving call to avoid instable LPs? */
11382    SCIP_Bool*            timelimit,          /**< pointer to store whether the time limit was hit */
11383    SCIP_Bool*            lperror             /**< pointer to store whether an unresolved LP error occurred */
11384    )
11385 {
11386    SCIP_Real lptimelimit;
11387    SCIP_Bool success;
11388 
11389    assert(lp != NULL);
11390    assert(lp->flushed);
11391    assert(lperror != NULL);
11392 
11393    /* check if a time limit is set, and set time limit for LP solver accordingly */
11394    lptimelimit = SCIPlpiInfinity(lp->lpi);
11395    if( set->istimelimitfinite )
11396       lptimelimit = set->limit_time - SCIPclockGetTime(stat->solvingtime);
11397 
11398    success = FALSE;
11399    if( lptimelimit > 0.0 )
11400       SCIP_CALL( lpSetRealpar(lp, SCIP_LPPAR_LPTILIM, lptimelimit, &success) );
11401 
11402    if( lptimelimit <= 0.0 || !success )
11403    {
11404       SCIPsetDebugMsg(set, "time limit of %f seconds could not be set\n", lptimelimit);
11405       *lperror = ((lptimelimit > 0.0) ? TRUE : FALSE);
11406       *timelimit = TRUE;
11407       return SCIP_OKAY;
11408    }
11409    SCIPsetDebugMsg(set, "calling LP algorithm <%s> with a time limit of %g seconds\n", lpalgoName(lpalgo), lptimelimit);
11410 
11411    /* call appropriate LP algorithm */
11412    switch( lpalgo )
11413    {
11414    case SCIP_LPALGO_PRIMALSIMPLEX:
11415       SCIP_CALL( lpPrimalSimplex(lp, set, stat, resolve, keepsol, instable, lperror) );
11416       break;
11417 
11418    case SCIP_LPALGO_DUALSIMPLEX:
11419       /* run dual lexicographic simplex if required */
11420       if( set->lp_lexdualalgo && (!set->lp_lexdualrootonly || stat->maxdepth == 0) && (!set->lp_lexdualstalling || lp->installing) )
11421       {
11422          SCIP_CALL( lpLexDualSimplex(lp, set, stat, resolve, keepsol, lperror) );
11423       }
11424       else
11425       {
11426          SCIP_CALL( lpDualSimplex(lp, set, stat, resolve, keepsol, instable, lperror) );
11427       }
11428       break;
11429 
11430    case SCIP_LPALGO_BARRIER:
11431       SCIP_CALL( lpBarrier(lp, set, stat, FALSE, keepsol, lperror) );
11432       break;
11433 
11434    case SCIP_LPALGO_BARRIERCROSSOVER:
11435       SCIP_CALL( lpBarrier(lp, set, stat, TRUE, keepsol, lperror) );
11436       break;
11437 
11438    default:
11439       SCIPerrorMessage("invalid LP algorithm\n");
11440       return SCIP_INVALIDDATA;
11441    }
11442 
11443    if( !(*lperror) )
11444    {
11445       /* check for primal and dual feasibility */
11446       SCIP_CALL( SCIPlpiGetSolFeasibility(lp->lpi, &lp->primalfeasible, &lp->dualfeasible) );
11447 
11448       SCIPsetDebugMsg(set, "LP feasibility: primalfeasible=%u, dualfeasible=%u\n", lp->primalfeasible, lp->dualfeasible);
11449    }
11450 
11451    return SCIP_OKAY;
11452 }
11453 
11454 /** maximal number of verblevel-high messages about numerical trouble in LP that will be printed
11455  * when this number is reached and display/verblevel is not full, then further messages are suppressed in this run
11456  */
11457 #define MAXNUMTROUBLELPMSGS 10
11458 
11459 /** prints message about numerical trouble
11460  *
11461  * If message has verblevel at most high and display/verblevel is not full,
11462  * then the message is not printed if already MAXNUMTROUBLELPMSGS messages
11463  * were printed before in the current run.
11464  */
11465 static
lpNumericalTroubleMessage(SCIP_MESSAGEHDLR * messagehdlr,SCIP_SET * set,SCIP_STAT * stat,SCIP_VERBLEVEL verblevel,const char * formatstr,...)11466 void lpNumericalTroubleMessage(
11467    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
11468    SCIP_SET*             set,                /**< global SCIP settings */
11469    SCIP_STAT*            stat,               /**< problem statistics */
11470    SCIP_VERBLEVEL        verblevel,          /**< verbosity level of message */
11471    const char*           formatstr,          /**< message format string */
11472    ...                                       /**< arguments to format string */
11473    )
11474 {
11475    va_list ap;
11476 
11477    assert(verblevel > SCIP_VERBLEVEL_NONE);
11478    assert(verblevel <= SCIP_VERBLEVEL_FULL);
11479    assert(set->disp_verblevel <= SCIP_VERBLEVEL_FULL);
11480 
11481    if( set->disp_verblevel < SCIP_VERBLEVEL_FULL )
11482    {
11483       if( verblevel <= SCIP_VERBLEVEL_HIGH )
11484       {
11485          /* if already max number of messages about numerical trouble in LP on verblevel at most high, then skip message */
11486          if( stat->nnumtroublelpmsgs > MAXNUMTROUBLELPMSGS )
11487             return;
11488 
11489          /* increase count on messages with verblevel high */
11490          ++stat->nnumtroublelpmsgs ;
11491       }
11492 
11493       /* if messages wouldn't be printed, then return already */
11494       if( verblevel > set->disp_verblevel )
11495          return;
11496    }
11497 
11498    /* print common begin of message */
11499    SCIPmessagePrintInfo(messagehdlr,
11500       "(node %" SCIP_LONGINT_FORMAT ") numerical troubles in LP %" SCIP_LONGINT_FORMAT " -- ",
11501       stat->nnodes, stat->nlps);
11502 
11503    /* print individual part of message */
11504    va_start(ap, formatstr); /*lint !e838*/
11505    SCIPmessageVFPrintInfo(messagehdlr, NULL, formatstr, ap);
11506    va_end(ap);
11507 
11508    /* warn that further messages will be suppressed */
11509    if( set->disp_verblevel < SCIP_VERBLEVEL_FULL && verblevel <= SCIP_VERBLEVEL_HIGH && stat->nnumtroublelpmsgs > MAXNUMTROUBLELPMSGS )
11510    {
11511       SCIPmessagePrintInfo(messagehdlr, " -- further messages will be suppressed (use display/verblevel=5 to see all)");
11512    }
11513 
11514    /* print closing new-line */
11515    SCIPmessagePrintInfo(messagehdlr, "\n");
11516 }
11517 
11518 static
ignoreInstability(SCIP_LP * lp,SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr,SCIP_STAT * stat,SCIP_LPALGO lpalgo,SCIP_Bool * success)11519 SCIP_RETCODE ignoreInstability(
11520    SCIP_LP*              lp,                 /**< current LP data */
11521    SCIP_SET*             set,                /**< global SCIP settings */
11522    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
11523    SCIP_STAT*            stat,               /**< problem statistics */
11524    SCIP_LPALGO           lpalgo,             /**< LP algorithm that should be applied */
11525    SCIP_Bool*            success             /**< was instability successfully ignored */
11526    )
11527 {
11528    assert(lp != NULL);
11529    assert(set != NULL);
11530 
11531    SCIP_CALL( SCIPlpiIgnoreInstability(lp->lpi, success) );
11532 
11533    if( *success )
11534    {
11535       lpNumericalTroubleMessage(messagehdlr, set, stat, SCIP_VERBLEVEL_FULL, "ignoring instability of %s", lpalgoName(lpalgo));
11536       if( !set->lp_checkdualfeas )
11537          lp->dualfeasible = TRUE;
11538       if( !set->lp_checkprimfeas )
11539          lp->primalchecked = TRUE;
11540    }
11541 
11542    return SCIP_OKAY;
11543 }
11544 
11545 #define FEASTOLTIGHTFAC 0.001
11546 /** solves the LP with the given LP algorithm, and tries to resolve numerical problems */
11547 static
lpSolveStable(SCIP_LP * lp,SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr,SCIP_STAT * stat,SCIP_PROB * prob,SCIP_LPALGO lpalgo,int itlim,int harditlim,SCIP_Bool resolve,int fastmip,SCIP_Bool tightprimfeastol,SCIP_Bool tightdualfeastol,SCIP_Bool fromscratch,SCIP_Bool keepsol,SCIP_Bool * timelimit,SCIP_Bool * lperror)11548 SCIP_RETCODE lpSolveStable(
11549    SCIP_LP*              lp,                 /**< current LP data */
11550    SCIP_SET*             set,                /**< global SCIP settings */
11551    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
11552    SCIP_STAT*            stat,               /**< problem statistics */
11553    SCIP_PROB*            prob,               /**< problem data */
11554    SCIP_LPALGO           lpalgo,             /**< LP algorithm that should be applied */
11555    int                   itlim,              /**< maximal number of LP iterations to perform in first LP calls (before solving from scratch), or -1 for no limit */
11556    int                   harditlim,          /**< maximal number of LP iterations to perform (hard limit for all LP calls), or -1 for no limit */
11557    SCIP_Bool             resolve,            /**< is this a resolving call (starting with feasible basis)? */
11558    int                   fastmip,            /**< which FASTMIP setting of LP solver should be used? */
11559    SCIP_Bool             tightprimfeastol,   /**< should a tighter primal feasibility tolerance be used? */
11560    SCIP_Bool             tightdualfeastol,   /**< should a tighter dual feasibility tolerance be used? */
11561    SCIP_Bool             fromscratch,        /**< should the LP be solved from scratch without using current basis? */
11562    SCIP_Bool             keepsol,            /**< should the old LP solution be kept if no iterations were performed? */
11563    SCIP_Bool*            timelimit,          /**< pointer to store whether the time limit was hit */
11564    SCIP_Bool*            lperror             /**< pointer to store whether an unresolved LP error occurred */
11565    )
11566 {
11567    SCIP_Bool success;
11568    SCIP_Bool success2;
11569    SCIP_Bool success3;
11570    SCIP_Bool simplex;
11571    SCIP_Bool itlimishard;
11572    SCIP_Bool usepolishing;
11573 
11574    assert(lp != NULL);
11575    assert(lp->flushed);
11576    assert(set != NULL);
11577    assert(stat != NULL);
11578    assert(lperror != NULL);
11579    assert(timelimit != NULL);
11580 
11581    *lperror = FALSE;
11582 
11583    /**@todo implement solving the LP when loose variables with infinite best bound are present; for this, we need to
11584     *       solve with deactivated objective limit in order to determine whether we are (a) infeasible or (b) feasible
11585     *       and hence unbounded; to handle case (b) we need to store an array of loose variables with best bound in
11586     *       SCIP_LP such that we can return a primal ray
11587     */
11588    if( lp->looseobjvalinf > 0 )
11589    {
11590       SCIPerrorMessage("cannot solve LP when loose variable with infinite best bound is present\n");
11591       return SCIP_ERROR;
11592    }
11593 
11594    /* check, whether we solve with a simplex algorithm */
11595    simplex = (lpalgo == SCIP_LPALGO_PRIMALSIMPLEX || lpalgo == SCIP_LPALGO_DUALSIMPLEX);
11596 
11597    /* check whether the iteration limit is a hard one */
11598    itlimishard = (itlim == harditlim);
11599 
11600    /* check whether solution polishing should be used */
11601    if( lp->lpihaspolishing && (set->lp_solutionpolishing == 2 || (set->lp_solutionpolishing == 1 && stat->nnodes == 1 && !lp->probing)
11602          || (set->lp_solutionpolishing == 3 && ((lp->probing && !lp->strongbranchprobing) || lp->diving))) )
11603    {
11604       usepolishing = TRUE;
11605       if( lp->updateintegrality )
11606       {
11607          SCIP_CALL( lpCopyIntegrality(lp, set) );
11608       }
11609    }
11610    else
11611       usepolishing = FALSE;
11612 
11613    /* solve with given settings (usually fast but imprecise) */
11614    if( SCIPsetIsInfinity(set, lp->cutoffbound) )
11615    {
11616       SCIP_CALL( lpSetObjlim(lp, set, lp->cutoffbound, &success) );
11617    }
11618    else
11619    {
11620       SCIP_CALL( lpSetObjlim(lp, set, lp->cutoffbound - getFiniteLooseObjval(lp, set, prob), &success) );
11621    }
11622    SCIP_CALL( lpSetIterationLimit(lp, itlim) );
11623    SCIP_CALL( lpSetFeastol(lp, tightprimfeastol ? FEASTOLTIGHTFAC * lp->feastol : lp->feastol, &success) );
11624    SCIP_CALL( lpSetDualfeastol(lp, tightdualfeastol ? FEASTOLTIGHTFAC * SCIPsetDualfeastol(set) : SCIPsetDualfeastol(set),
11625          &success) );
11626    SCIP_CALL( lpSetBarrierconvtol(lp, (tightprimfeastol || tightdualfeastol) ? FEASTOLTIGHTFAC * SCIPsetBarrierconvtol(set)
11627          : SCIPsetBarrierconvtol(set), &success) );
11628    SCIP_CALL( lpSetFromscratch(lp, fromscratch, &success) );
11629    SCIP_CALL( lpSetFastmip(lp, fastmip, &success) );
11630    SCIP_CALL( lpSetScaling(lp, set->lp_scaling, &success) );
11631    SCIP_CALL( lpSetPresolving(lp, set->lp_presolving, &success) );
11632    SCIP_CALL( lpSetRowrepswitch(lp, set->lp_rowrepswitch, &success) );
11633    SCIP_CALL( lpSetPricingChar(lp, set->lp_pricing) );
11634    SCIP_CALL( lpSetThreads(lp, set->lp_threads, &success) );
11635    SCIP_CALL( lpSetLPInfo(lp, set->disp_lpinfo) );
11636    SCIP_CALL( lpSetConditionLimit(lp, set->lp_conditionlimit, &success) );
11637    SCIP_CALL( lpSetMarkowitz(lp, set->lp_markowitz, &success) );
11638    SCIP_CALL( lpSetTiming(lp, set->time_clocktype, set->time_enabled, &success) );
11639    SCIP_CALL( lpSetRandomseed(lp, (int) SCIPsetInitializeRandomSeed(set, (unsigned) set->random_randomseed), &success) );
11640    SCIP_CALL( lpSetSolutionPolishing(lp, usepolishing, &success) );
11641    SCIP_CALL( lpSetRefactorInterval(lp, set->lp_refactorinterval, &success) );
11642 
11643    SCIP_CALL( lpAlgorithm(lp, set, stat, lpalgo, resolve, keepsol, FALSE, timelimit, lperror) );
11644 
11645    /* after the first solve, do not use starting basis, since otherwise the solver will probably think the basis is
11646     * optimal without preforming scaling/change tolerances/presolving */
11647    resolve = FALSE;
11648 
11649    /* check for stability; iteration limit exceeded is also treated like instability if the iteration limit is soft */
11650    if( *timelimit || (!(*lperror) && SCIPlpiIsStable(lp->lpi) && (itlimishard || !SCIPlpiIsIterlimExc(lp->lpi))) )
11651       return SCIP_OKAY;
11652 
11653    if( !set->lp_checkstability )
11654    {
11655       SCIP_CALL( ignoreInstability(lp, set, messagehdlr, stat, lpalgo, &success) );
11656 
11657       if( success )
11658          return SCIP_OKAY;
11659    }
11660 
11661    /* In the following, whenever the LP iteration limit is exceeded in an LP solving call, we leave out the
11662     * remaining resolving calls with changed settings and go directly to solving the LP from scratch.
11663     */
11664 
11665    /* if FASTMIP is turned on, solve again without FASTMIP (starts from the solution of the last LP solving call);
11666     * do this only if the iteration limit was not exceeded in the last LP solving call
11667     */
11668    if( fastmip > 0 && simplex && ((*lperror) || !SCIPlpiIsIterlimExc(lp->lpi)) )
11669    {
11670       SCIP_CALL( lpSetFastmip(lp, 0, &success) );
11671       if( success )
11672       {
11673          lpNumericalTroubleMessage(messagehdlr, set, stat, SCIP_VERBLEVEL_FULL, "solve again with %s without FASTMIP", lpalgoName(lpalgo));
11674          SCIP_CALL( lpAlgorithm(lp, set, stat, lpalgo, resolve, keepsol, TRUE, timelimit, lperror) );
11675 
11676          /* check for stability */
11677          if( *timelimit || (!(*lperror) && SCIPlpiIsStable(lp->lpi) && (itlimishard || !SCIPlpiIsIterlimExc(lp->lpi))) )
11678             return SCIP_OKAY;
11679 
11680          if( !set->lp_checkstability )
11681          {
11682             SCIP_CALL( ignoreInstability(lp, set, messagehdlr, stat, lpalgo, &success) );
11683 
11684             if( success )
11685                return SCIP_OKAY;
11686          }
11687       }
11688    }
11689 
11690    /* if the iteration limit was exceeded in the last LP solving call, we leave out the remaining resolving calls with changed settings
11691     * and go directly to solving the LP from scratch
11692     */
11693    if( (*lperror) || !SCIPlpiIsIterlimExc(lp->lpi) )
11694    {
11695       /* solve again with opposite scaling setting (starts from the solution of the last LP solving call) */
11696       SCIP_CALL( lpSetScaling(lp, (set->lp_scaling > 0) ? 0 : 1, &success) );
11697       if( success )
11698       {
11699          lpNumericalTroubleMessage(messagehdlr, set, stat, SCIP_VERBLEVEL_FULL, "solve again with %s %s scaling",
11700             lpalgoName(lpalgo), (set->lp_scaling == 0) ? "with" : "without");
11701          SCIP_CALL( lpAlgorithm(lp, set, stat, lpalgo, resolve, keepsol, TRUE, timelimit, lperror) );
11702 
11703          /* check for stability */
11704          if( *timelimit || (!(*lperror) && SCIPlpiIsStable(lp->lpi) && (itlimishard || !SCIPlpiIsIterlimExc(lp->lpi))) )
11705             return SCIP_OKAY;
11706 
11707          if( !set->lp_checkstability )
11708          {
11709             SCIP_CALL( ignoreInstability(lp, set, messagehdlr, stat, lpalgo, &success) );
11710 
11711             if( success )
11712                return SCIP_OKAY;
11713          }
11714 
11715          /* reset scaling */
11716          SCIP_CALL( lpSetScaling(lp, set->lp_scaling, &success) );
11717          assert(success);
11718       }
11719    }
11720 
11721    /* if the iteration limit was exceeded in the last LP solving call, we leave out the remaining resolving calls with changed settings
11722     * and go directly to solving the LP from scratch */
11723    if( (*lperror) || !SCIPlpiIsIterlimExc(lp->lpi) )
11724    {
11725       /* solve again with opposite presolving setting (starts from the solution of the last LP solving call) */
11726       SCIP_CALL( lpSetPresolving(lp, !set->lp_presolving, &success) );
11727       if( success )
11728       {
11729          lpNumericalTroubleMessage(messagehdlr, set, stat, SCIP_VERBLEVEL_FULL, "solve again with %s %s presolving",
11730             lpalgoName(lpalgo), !set->lp_presolving ? "with" : "without");
11731          SCIP_CALL( lpAlgorithm(lp, set, stat, lpalgo, resolve, keepsol, TRUE, timelimit, lperror) );
11732 
11733          /* check for stability */
11734          if( *timelimit || (!(*lperror) && SCIPlpiIsStable(lp->lpi) && (itlimishard || !SCIPlpiIsIterlimExc(lp->lpi))) )
11735             return SCIP_OKAY;
11736 
11737          if( !set->lp_checkstability )
11738          {
11739             SCIP_CALL( ignoreInstability(lp, set, messagehdlr, stat, lpalgo, &success) );
11740 
11741             if( success )
11742                return SCIP_OKAY;
11743          }
11744 
11745          /* reset presolving */
11746          SCIP_CALL( lpSetPresolving(lp, set->lp_presolving, &success) );
11747          assert(success);
11748       }
11749    }
11750 
11751    /* solve again with a tighter feasibility tolerance (starts from the solution of the last LP solving call);
11752     * do this only if the iteration limit was not exceeded in the last LP solving call
11753     */
11754    if( ((simplex && (!tightprimfeastol || !tightdualfeastol)) || (!tightprimfeastol && !tightdualfeastol)) &&
11755       ((*lperror) || !SCIPlpiIsIterlimExc(lp->lpi)) )
11756    {
11757       success = FALSE;
11758       if( !tightprimfeastol )
11759       {
11760          SCIP_CALL( lpSetFeastol(lp, FEASTOLTIGHTFAC * lp->feastol, &success) );
11761       }
11762 
11763       success2 = FALSE;
11764       if( !tightdualfeastol )
11765       {
11766          SCIP_CALL( lpSetDualfeastol(lp, FEASTOLTIGHTFAC * SCIPsetDualfeastol(set), &success2) );
11767       }
11768 
11769       success3 = FALSE;
11770       if( !simplex && !tightprimfeastol && !tightdualfeastol )
11771       {
11772          SCIP_CALL( lpSetBarrierconvtol(lp, FEASTOLTIGHTFAC * SCIPsetBarrierconvtol(set), &success3) );
11773       }
11774 
11775       /* only resolve if at least one of the parameters was actually changed in the LP solver */
11776       if( success || success2 || success3 )
11777       {
11778          lpNumericalTroubleMessage(messagehdlr, set, stat, SCIP_VERBLEVEL_FULL, "solve again with %s with tighter primal and dual feasibility tolerance",
11779             lpalgoName(lpalgo));
11780          SCIP_CALL( lpAlgorithm(lp, set, stat, lpalgo, resolve, keepsol, TRUE, timelimit, lperror) );
11781 
11782          /* check for stability */
11783          if( *timelimit || (!(*lperror) && SCIPlpiIsStable(lp->lpi) && (itlimishard || !SCIPlpiIsIterlimExc(lp->lpi))) )
11784             return SCIP_OKAY;
11785 
11786          if( !set->lp_checkstability )
11787          {
11788             SCIP_CALL( ignoreInstability(lp, set, messagehdlr, stat, lpalgo, &success) );
11789 
11790             if( success )
11791                return SCIP_OKAY;
11792          }
11793 
11794          /* reset feasibility tolerance */
11795          if( !tightprimfeastol )
11796          {
11797             SCIP_CALL( lpSetFeastol(lp, lp->feastol, &success) );
11798          }
11799          if( !tightdualfeastol )
11800          {
11801             SCIP_CALL( lpSetDualfeastol(lp, SCIPsetDualfeastol(set), &success) );
11802          }
11803          if( !simplex && !tightprimfeastol && !tightdualfeastol )
11804          {
11805             SCIP_CALL( lpSetBarrierconvtol(lp, SCIPsetBarrierconvtol(set), &success) );
11806          }
11807       }
11808    }
11809 
11810    /* all LPs solved after this point are solved from scratch, so set the LP iteration limit to the hard limit;
11811     * the given iteration limit might be a soft one to restrict resolving calls only */
11812    SCIP_CALL( lpSetIterationLimit(lp, harditlim) );
11813 
11814    /* if not already done, solve again from scratch */
11815    if( !fromscratch && simplex )
11816    {
11817       SCIP_CALL( lpSetFromscratch(lp, TRUE, &success) );
11818       if( success )
11819       {
11820          lpNumericalTroubleMessage(messagehdlr, set, stat, SCIP_VERBLEVEL_FULL, "solve again from scratch with %s", lpalgoName(lpalgo));
11821          SCIP_CALL( lpAlgorithm(lp, set, stat, lpalgo, resolve, keepsol, TRUE, timelimit, lperror) );
11822 
11823          /* check for stability */
11824          if( *timelimit || (!(*lperror) && SCIPlpiIsStable(lp->lpi)) )
11825             return SCIP_OKAY;
11826 
11827          if( !set->lp_checkstability )
11828          {
11829             SCIP_CALL( ignoreInstability(lp, set, messagehdlr, stat, lpalgo, &success) );
11830 
11831             if( success )
11832                return SCIP_OKAY;
11833          }
11834       }
11835    }
11836 
11837    /* solve again, use other simplex this time */
11838    if( simplex )
11839    {
11840       lpalgo = (lpalgo == SCIP_LPALGO_PRIMALSIMPLEX ? SCIP_LPALGO_DUALSIMPLEX : SCIP_LPALGO_PRIMALSIMPLEX);
11841       lpNumericalTroubleMessage(messagehdlr, set, stat, SCIP_VERBLEVEL_FULL, "solve again from scratch with %s", lpalgoName(lpalgo));
11842       SCIP_CALL( lpAlgorithm(lp, set, stat, lpalgo, resolve, keepsol, TRUE, timelimit, lperror) );
11843 
11844       /* check for stability */
11845       if( *timelimit || (!(*lperror) && SCIPlpiIsStable(lp->lpi)) )
11846          return SCIP_OKAY;
11847 
11848       if( !set->lp_checkstability )
11849       {
11850          SCIP_CALL( ignoreInstability(lp, set, messagehdlr, stat, lpalgo, &success) );
11851 
11852          if( success )
11853             return SCIP_OKAY;
11854       }
11855 
11856       /* solve again with opposite scaling and other simplex */
11857       SCIP_CALL( lpSetScaling(lp, (set->lp_scaling > 0) ? 0 : 1, &success) );
11858       if( success )
11859       {
11860          lpNumericalTroubleMessage(messagehdlr, set, stat, SCIP_VERBLEVEL_FULL, "solve again from scratch with %s %s scaling",
11861             lpalgoName(lpalgo), (set->lp_scaling == 0) ? "with" : "without");
11862          SCIP_CALL( lpAlgorithm(lp, set, stat, lpalgo, resolve, keepsol, TRUE, timelimit, lperror) );
11863 
11864          /* check for stability */
11865          if( *timelimit || (!(*lperror) && SCIPlpiIsStable(lp->lpi)) )
11866             return SCIP_OKAY;
11867 
11868          if( !set->lp_checkstability )
11869          {
11870             SCIP_CALL( ignoreInstability(lp, set, messagehdlr, stat, lpalgo, &success) );
11871 
11872             if( success )
11873                return SCIP_OKAY;
11874          }
11875 
11876          /* reset scaling */
11877          SCIP_CALL( lpSetScaling(lp, set->lp_scaling, &success) );
11878          assert(success);
11879       }
11880 
11881       /* solve again with opposite presolving and other simplex */
11882       SCIP_CALL( lpSetPresolving(lp, !set->lp_presolving, &success) );
11883       if( success )
11884       {
11885          lpNumericalTroubleMessage(messagehdlr, set, stat, SCIP_VERBLEVEL_FULL, "solve again from scratch with %s %s presolving",
11886             lpalgoName(lpalgo), !set->lp_presolving ? "with" : "without");
11887          SCIP_CALL( lpAlgorithm(lp, set, stat, lpalgo, resolve, keepsol, TRUE, timelimit, lperror) );
11888 
11889          /* check for stability */
11890          if( *timelimit || (!(*lperror) && SCIPlpiIsStable(lp->lpi)) )
11891             return SCIP_OKAY;
11892 
11893          if( !set->lp_checkstability )
11894          {
11895             SCIP_CALL( ignoreInstability(lp, set, messagehdlr, stat, lpalgo, &success) );
11896 
11897             if( success )
11898                return SCIP_OKAY;
11899          }
11900 
11901          /* reset presolving */
11902          SCIP_CALL( lpSetPresolving(lp, set->lp_presolving, &success) );
11903          assert(success);
11904       }
11905 
11906       /* solve again with tighter feasibility tolerance, use other simplex this time */
11907       if( !tightprimfeastol || !tightdualfeastol )
11908       {
11909          success = FALSE;
11910          if( !tightprimfeastol )
11911          {
11912             SCIP_CALL( lpSetFeastol(lp, FEASTOLTIGHTFAC * lp->feastol, &success) );
11913          }
11914 
11915          success2 = FALSE;
11916          if( !tightdualfeastol )
11917          {
11918             SCIP_CALL( lpSetDualfeastol(lp, FEASTOLTIGHTFAC * SCIPsetDualfeastol(set), &success2) );
11919          }
11920 
11921          /* only resolve if at least one of the parameters was actually changed in the LP solver */
11922          if( success || success2 )
11923          {
11924             lpNumericalTroubleMessage(messagehdlr, set, stat, SCIP_VERBLEVEL_FULL, "solve again from scratch with %s with tighter feasibility tolerance",
11925                lpalgoName(lpalgo));
11926             SCIP_CALL( lpAlgorithm(lp, set, stat, lpalgo, resolve, keepsol, TRUE, timelimit, lperror) );
11927 
11928             /* check for stability */
11929             if( *timelimit || (!(*lperror) && SCIPlpiIsStable(lp->lpi)) )
11930                return SCIP_OKAY;
11931 
11932             if( !set->lp_checkstability )
11933             {
11934                SCIP_CALL( ignoreInstability(lp, set, messagehdlr, stat, lpalgo, &success) );
11935 
11936                if( success )
11937                   return SCIP_OKAY;
11938             }
11939 
11940             /* reset feasibility tolerance */
11941             if( !tightprimfeastol )
11942             {
11943                SCIP_CALL( lpSetFeastol(lp, lp->feastol, &success) );
11944             }
11945             if( !tightdualfeastol )
11946             {
11947                SCIP_CALL( lpSetDualfeastol(lp, SCIPsetDualfeastol(set), &success) );
11948             }
11949             SCIP_UNUSED(success);
11950          }
11951       }
11952    }
11953 
11954    /* nothing worked -- exit with an LPERROR */
11955    lpNumericalTroubleMessage(messagehdlr, set, stat, SCIP_VERBLEVEL_HIGH, "unresolved");
11956    *lperror = TRUE;
11957 
11958    return SCIP_OKAY;
11959 }
11960 
11961 /** adjust the LP objective value if it is greater/less than +/- SCIPsetInfinity() */
11962 static
adjustLPobjval(SCIP_LP * lp,SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr)11963 void adjustLPobjval(
11964    SCIP_LP*              lp,                 /**< current LP data */
11965    SCIP_SET*             set,                /**< global SCIP settings */
11966    SCIP_MESSAGEHDLR*     messagehdlr         /**< message handler */
11967    )
11968 {
11969    assert(lp != NULL);
11970    assert(set != NULL);
11971 
11972    if( SCIPsetIsInfinity(set, lp->lpobjval) && lp->lpobjval != SCIPsetInfinity(set) ) /*lint !e777*/
11973    {
11974       if( !lp->adjustlpval && messagehdlr != NULL )
11975       {
11976          SCIPmessagePrintWarning(messagehdlr, "LP solution value is above SCIP's infinity value\n");
11977          lp->adjustlpval = TRUE;
11978       }
11979       lp->lpobjval = SCIPsetInfinity(set);
11980    }
11981    else if( SCIPsetIsInfinity(set, -lp->lpobjval) && lp->lpobjval != -SCIPsetInfinity(set) ) /*lint !e777*/
11982    {
11983       if( !lp->adjustlpval && messagehdlr != NULL )
11984       {
11985          SCIPmessagePrintWarning(messagehdlr, "LP solution value is below SCIP's -infinity value\n");
11986          lp->adjustlpval = TRUE;
11987       }
11988       lp->lpobjval = -SCIPsetInfinity(set);
11989    }
11990 }
11991 
11992 /** solves the LP with the given algorithm and evaluates return status */
11993 static
lpSolve(SCIP_LP * lp,SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr,SCIP_STAT * stat,SCIP_PROB * prob,SCIP_LPALGO lpalgo,int resolveitlim,int harditlim,SCIP_Bool needprimalray,SCIP_Bool needdualray,SCIP_Bool resolve,int fastmip,SCIP_Bool tightprimfeastol,SCIP_Bool tightdualfeastol,SCIP_Bool fromscratch,SCIP_Bool keepsol,SCIP_Bool * lperror)11994 SCIP_RETCODE lpSolve(
11995    SCIP_LP*              lp,                 /**< current LP data */
11996    SCIP_SET*             set,                /**< global SCIP settings */
11997    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
11998    SCIP_STAT*            stat,               /**< problem statistics */
11999    SCIP_PROB*            prob,               /**< problem data */
12000    SCIP_LPALGO           lpalgo,             /**< LP algorithm that should be applied */
12001    int                   resolveitlim,       /**< maximal number of LP iterations to perform in resolving calls, or -1 for no limit */
12002    int                   harditlim,          /**< maximal number of LP iterations to perform (hard limit for all LP calls), or -1 for no limit */
12003    SCIP_Bool             needprimalray,      /**< if the LP is unbounded, do we need a primal ray? */
12004    SCIP_Bool             needdualray,        /**< if the LP is infeasible, do we need a dual ray? */
12005    SCIP_Bool             resolve,            /**< is this a resolving call (starting with feasible basis)? */
12006    int                   fastmip,            /**< which FASTMIP setting of LP solver should be used? */
12007    SCIP_Bool             tightprimfeastol,   /**< should a tighter primal feasibility tolerance be used? */
12008    SCIP_Bool             tightdualfeastol,   /**< should a tighter dual feasibility tolerance be used? */
12009    SCIP_Bool             fromscratch,        /**< should the LP be solved from scratch without using current basis? */
12010    SCIP_Bool             keepsol,            /**< should the old LP solution be kept if no iterations were performed? */
12011    SCIP_Bool*            lperror             /**< pointer to store whether an unresolved LP error occurred */
12012    )
12013 {
12014    SCIP_Bool solvedprimal;
12015    SCIP_Bool solveddual;
12016    SCIP_Bool timelimit;
12017    int itlim;
12018 
12019    assert(lp != NULL);
12020    assert(lp->flushed);
12021    assert(set != NULL);
12022    assert(stat != NULL);
12023    assert(lperror != NULL);
12024 
12025    checkLinks(lp);
12026 
12027    solvedprimal = FALSE;
12028    solveddual = FALSE;
12029    timelimit = FALSE;
12030 
12031    /* select the basic iteration limit depending on whether this is a resolving call or not */
12032    itlim = ( resolve ? resolveitlim : harditlim );
12033 
12034  SOLVEAGAIN:
12035    /* call simplex */
12036    SCIP_CALL( lpSolveStable(lp, set, messagehdlr, stat, prob, lpalgo, itlim, harditlim, resolve, fastmip, tightprimfeastol, tightdualfeastol, fromscratch,
12037          keepsol, &timelimit, lperror) );
12038    resolve = FALSE; /* only the first solve should be counted as resolving call */
12039    solvedprimal = solvedprimal || (lp->lastlpalgo == SCIP_LPALGO_PRIMALSIMPLEX);
12040    solveddual = solveddual || (lp->lastlpalgo == SCIP_LPALGO_DUALSIMPLEX);
12041 
12042    /* check, if an error occurred */
12043    if( *lperror )
12044    {
12045       SCIPsetDebugMsg(set, "unresolved error while solving LP with %s\n", lpalgoName(lp->lastlpalgo));
12046       lp->solved = FALSE;
12047       lp->lpsolstat = SCIP_LPSOLSTAT_NOTSOLVED;
12048       return SCIP_OKAY;
12049    }
12050 
12051    /* check, if a time limit was exceeded */
12052    if( timelimit )
12053    {
12054       SCIPsetDebugMsg(set, "time limit exceeded before solving LP\n");
12055       lp->solved = TRUE;
12056       lp->lpsolstat = SCIP_LPSOLSTAT_TIMELIMIT;
12057       lp->lpobjval = -SCIPsetInfinity(set);
12058       return SCIP_OKAY;
12059    }
12060 
12061    /* only one should return true */
12062    assert(!(SCIPlpiIsOptimal(lp->lpi) && SCIPlpiIsObjlimExc(lp->lpi) && SCIPlpiIsPrimalInfeasible(lp->lpi) &&
12063          SCIPlpiExistsPrimalRay(lp->lpi) && SCIPlpiIsIterlimExc(lp->lpi) && SCIPlpiIsTimelimExc(lp->lpi)));
12064 
12065    /* evaluate solution status */
12066    if( SCIPlpiIsOptimal(lp->lpi) )
12067    {
12068       assert(lp->primalfeasible);
12069       assert(lp->dualfeasible);
12070       lp->lpsolstat = SCIP_LPSOLSTAT_OPTIMAL;
12071       SCIP_CALL( SCIPlpiGetObjval(lp->lpi, &lp->lpobjval) );
12072       adjustLPobjval(lp, set, messagehdlr);
12073 
12074       if( !SCIPsetIsInfinity(set, lp->lpiobjlim) && SCIPsetIsGE(set, lp->lpobjval, lp->lpiobjlim) )
12075       {
12076          /* the solver may return the optimal value, even if this is greater or equal than the upper bound */
12077          SCIPsetDebugMsg(set, "optimal solution %.15g exceeds objective limit %.15g\n", lp->lpobjval, lp->lpiobjlim);
12078          lp->lpsolstat = SCIP_LPSOLSTAT_OBJLIMIT;
12079          lp->lpobjval = SCIPsetInfinity(set);
12080       }
12081       /* if we did not disable the cutoff bound in the LP solver, the LP solution status should be objective limit
12082        * reached if the LP objective value is greater than the cutoff bound
12083        */
12084       assert(lpCutoffDisabled(set) || lp->lpsolstat == SCIP_LPSOLSTAT_OBJLIMIT || SCIPsetIsInfinity(set, lp->cutoffbound)
12085          || SCIPsetIsLE(set, lp->lpobjval + getFiniteLooseObjval(lp, set, prob), lp->cutoffbound));
12086    }
12087    else if( SCIPlpiIsObjlimExc(lp->lpi) )
12088    {
12089       assert(!lpCutoffDisabled(set));
12090       lp->lpsolstat = SCIP_LPSOLSTAT_OBJLIMIT;
12091       lp->lpobjval = SCIPsetInfinity(set);
12092    }
12093    else if( SCIPlpiIsPrimalInfeasible(lp->lpi) )
12094    {
12095       /* because of numerical instability lpalgo != lp->lastlpalgo might happen - hence, we have to check both */
12096       if( needdualray && !SCIPlpiHasDualRay(lp->lpi) && !solveddual && lpalgo != SCIP_LPALGO_DUALSIMPLEX )
12097       {
12098          assert(lp->lastlpalgo != SCIP_LPALGO_DUALSIMPLEX);
12099          lpalgo = SCIP_LPALGO_DUALSIMPLEX;
12100          goto SOLVEAGAIN;
12101       }
12102       lp->lpsolstat = SCIP_LPSOLSTAT_INFEASIBLE;
12103       lp->lpobjval = SCIPsetInfinity(set);
12104    }
12105    else if( SCIPlpiExistsPrimalRay(lp->lpi) )
12106    {
12107       /* because of numerical instability lpalgo != lp->lastlpalgo might happen - hence, we have to check both */
12108       if( needprimalray && !SCIPlpiIsPrimalUnbounded(lp->lpi) && !solvedprimal && lpalgo != SCIP_LPALGO_PRIMALSIMPLEX )
12109       {
12110          /* unboundedness includes that the primal is feasible: ensure a primal solution here */
12111          assert(lp->lastlpalgo != SCIP_LPALGO_PRIMALSIMPLEX);
12112          lpalgo = SCIP_LPALGO_PRIMALSIMPLEX;
12113          goto SOLVEAGAIN;
12114       }
12115       lp->lpsolstat = SCIP_LPSOLSTAT_UNBOUNDEDRAY;
12116       lp->lpobjval = -SCIPsetInfinity(set);
12117    }
12118    else if( SCIPlpiIsIterlimExc(lp->lpi) )
12119    {
12120       SCIP_CALL( SCIPlpiGetObjval(lp->lpi, &lp->lpobjval) );
12121 
12122       /* The lpobjval might be infinite, e.g. if the LP solver was not able to produce a valid bound while reaching the
12123          iteration limit. In this case, we avoid the warning in adjustLPobjval() by setting the messagehdlr to NULL. */
12124       if ( REALABS(lp->lpobjval) == SCIPlpiInfinity(lp->lpi) ) /*lint !e777*/
12125          adjustLPobjval(lp, set, NULL);
12126       else
12127          adjustLPobjval(lp, set, messagehdlr);
12128 
12129       lp->lpsolstat = SCIP_LPSOLSTAT_ITERLIMIT;
12130    }
12131    else if( SCIPlpiIsTimelimExc(lp->lpi) )
12132    {
12133       lp->lpobjval = -SCIPsetInfinity(set);
12134       lp->lpsolstat = SCIP_LPSOLSTAT_TIMELIMIT;
12135    }
12136    else if( !solveddual && lpalgo != SCIP_LPALGO_DUALSIMPLEX)
12137    {
12138       assert(lp->lastlpalgo != SCIP_LPALGO_DUALSIMPLEX);
12139       lpalgo = SCIP_LPALGO_DUALSIMPLEX;
12140       SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
12141          "(node %" SCIP_LONGINT_FORMAT ") solution status of LP %" SCIP_LONGINT_FORMAT " could not be proven (internal status:%d) -- solve again with %s\n",
12142          stat->nnodes, stat->nlps, SCIPlpiGetInternalStatus(lp->lpi), lpalgoName(lpalgo));
12143       goto SOLVEAGAIN;
12144    }
12145    else if( !solvedprimal && lpalgo != SCIP_LPALGO_PRIMALSIMPLEX)
12146    {
12147       assert(lp->lastlpalgo != SCIP_LPALGO_PRIMALSIMPLEX);
12148       lpalgo = SCIP_LPALGO_PRIMALSIMPLEX;
12149       SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
12150          "(node %" SCIP_LONGINT_FORMAT ") solution status of LP %" SCIP_LONGINT_FORMAT " could not be proven (internal status:%d) -- solve again with %s\n",
12151          stat->nnodes, stat->nlps, SCIPlpiGetInternalStatus(lp->lpi), lpalgoName(lpalgo));
12152       goto SOLVEAGAIN;
12153    }
12154    else
12155    {
12156       SCIPerrorMessage("(node %" SCIP_LONGINT_FORMAT ") error or unknown return status of %s in LP %" SCIP_LONGINT_FORMAT " (internal status: %d)\n",
12157          stat->nnodes, lpalgoName(lp->lastlpalgo), stat->nlps, SCIPlpiGetInternalStatus(lp->lpi));
12158       lp->lpsolstat = SCIP_LPSOLSTAT_ERROR;
12159       return SCIP_LPERROR;
12160    }
12161 
12162    lp->solved = TRUE;
12163 
12164    SCIPsetDebugMsg(set, "solving LP with %s returned solstat=%d (internal status: %d, primalfeasible=%u, dualfeasible=%u)\n",
12165       lpalgoName(lp->lastlpalgo), lp->lpsolstat, SCIPlpiGetInternalStatus(lp->lpi),
12166       SCIPlpiIsPrimalFeasible(lp->lpi), SCIPlpiIsDualFeasible(lp->lpi));
12167 
12168    return SCIP_OKAY;
12169 }
12170 
12171 /** flushes the LP and solves it with the primal or dual simplex algorithm, depending on the current basis feasibility */
12172 static
lpFlushAndSolve(SCIP_LP * lp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr,SCIP_STAT * stat,SCIP_PROB * prob,SCIP_EVENTQUEUE * eventqueue,int resolveitlim,int harditlim,SCIP_Bool needprimalray,SCIP_Bool needdualray,int fastmip,SCIP_Bool tightprimfeastol,SCIP_Bool tightdualfeastol,SCIP_Bool fromscratch,SCIP_Bool keepsol,SCIP_Bool * lperror)12173 SCIP_RETCODE lpFlushAndSolve(
12174    SCIP_LP*              lp,                 /**< current LP data */
12175    BMS_BLKMEM*           blkmem,             /**< block memory */
12176    SCIP_SET*             set,                /**< global SCIP settings */
12177    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
12178    SCIP_STAT*            stat,               /**< problem statistics */
12179    SCIP_PROB*            prob,               /**< problem data */
12180    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
12181    int                   resolveitlim,       /**< maximal number of LP iterations to perform in resolving calls, or -1 for no limit */
12182    int                   harditlim,          /**< maximal number of LP iterations to perform (hard limit for all LP calls), or -1 for no limit */
12183    SCIP_Bool             needprimalray,      /**< if the LP is unbounded, do we need a primal ray? */
12184    SCIP_Bool             needdualray,        /**< if the LP is infeasible, do we need a dual ray? */
12185    int                   fastmip,            /**< which FASTMIP setting of LP solver should be used? */
12186    SCIP_Bool             tightprimfeastol,   /**< should a tighter primal feasibility tolerance be used? */
12187    SCIP_Bool             tightdualfeastol,   /**< should a tighter dual feasibility tolerance be used? */
12188    SCIP_Bool             fromscratch,        /**< should the LP be solved from scratch without using current basis? */
12189    SCIP_Bool             keepsol,            /**< should the old LP solution be kept if no iterations were performed? */
12190    SCIP_Bool*            lperror             /**< pointer to store whether an unresolved LP error occurred */
12191    )
12192 {
12193    SCIP_Bool resolve;
12194    char algo;
12195 
12196    assert(lp != NULL);
12197    assert(set != NULL);
12198    assert(lperror != NULL);
12199 
12200    /* flush changes to the LP solver */
12201    SCIP_CALL( SCIPlpFlush(lp, blkmem, set, eventqueue) );
12202    fastmip = ((!lp->flushaddedcols && !lp->flushdeletedcols) ? fastmip : 0); /* turn off FASTMIP if columns were changed */
12203 
12204    /* select LP algorithm to apply */
12205    resolve = lp->solisbasic && (lp->dualfeasible || lp->primalfeasible) && !fromscratch;
12206    algo = resolve ? set->lp_resolvealgorithm : set->lp_initalgorithm;
12207 
12208    switch( algo )
12209    {
12210    case 's':
12211       /* select simplex method */
12212       if( lp->dualfeasible || !lp->primalfeasible )
12213       {
12214          SCIPsetDebugMsg(set, "solving dual LP\n");
12215          SCIP_CALL( lpSolve(lp, set, messagehdlr, stat, prob, SCIP_LPALGO_DUALSIMPLEX, resolveitlim, harditlim, needprimalray,
12216                needdualray, resolve, fastmip, tightprimfeastol, tightdualfeastol, fromscratch, keepsol, lperror) );
12217       }
12218       else
12219       {
12220          SCIPsetDebugMsg(set, "solving primal LP\n");
12221          SCIP_CALL( lpSolve(lp, set, messagehdlr, stat, prob, SCIP_LPALGO_PRIMALSIMPLEX, resolveitlim, harditlim, needprimalray,
12222                needdualray, resolve, fastmip, tightprimfeastol, tightdualfeastol, fromscratch, keepsol, lperror) );
12223       }
12224       break;
12225 
12226    case 'p':
12227       SCIPsetDebugMsg(set, "solving primal LP\n");
12228       SCIP_CALL( lpSolve(lp, set, messagehdlr, stat, prob, SCIP_LPALGO_PRIMALSIMPLEX, resolveitlim, harditlim, needprimalray,
12229             needdualray, resolve, fastmip, tightprimfeastol, tightdualfeastol, fromscratch, keepsol, lperror) );
12230       break;
12231 
12232    case 'd':
12233       SCIPsetDebugMsg(set, "solving dual LP\n");
12234       SCIP_CALL( lpSolve(lp, set, messagehdlr, stat, prob, SCIP_LPALGO_DUALSIMPLEX, resolveitlim, harditlim, needprimalray,
12235             needdualray, resolve, fastmip, tightprimfeastol, tightdualfeastol, fromscratch, keepsol, lperror) );
12236       break;
12237 
12238    case 'b':
12239       SCIPsetDebugMsg(set, "solving barrier LP\n");
12240       SCIP_CALL( lpSolve(lp, set, messagehdlr, stat, prob, SCIP_LPALGO_BARRIER, resolveitlim, harditlim, needprimalray,
12241             needdualray, resolve, fastmip, tightprimfeastol, tightdualfeastol, fromscratch, keepsol, lperror) );
12242       break;
12243 
12244    case 'c':
12245       SCIPsetDebugMsg(set, "solving barrier LP with crossover\n");
12246       SCIP_CALL( lpSolve(lp, set, messagehdlr, stat, prob, SCIP_LPALGO_BARRIERCROSSOVER, resolveitlim, harditlim, needprimalray,
12247             needdualray, resolve, fastmip, tightprimfeastol, tightdualfeastol, fromscratch, keepsol, lperror) );
12248       break;
12249 
12250    default:
12251       SCIPerrorMessage("invalid parameter setting <%c> for LP algorithm\n", algo);
12252       return SCIP_PARAMETERWRONGVAL;
12253    }
12254    assert(!(*lperror) || !lp->solved);
12255 
12256    return SCIP_OKAY;
12257 }
12258 
12259 #ifndef NDEBUG
12260 /** checks if the lazy bounds are valid */
12261 static
checkLazyBounds(SCIP_LP * lp,SCIP_SET * set)12262 void checkLazyBounds(
12263    SCIP_LP*              lp,                 /**< LP data */
12264    SCIP_SET*             set                 /**< global SCIP settings */
12265    )
12266 {
12267    SCIP_COL* col;
12268    int c;
12269 
12270    assert(lp->flushed);
12271 
12272    for( c = 0; c < lp->nlazycols; ++c )
12273    {
12274       col = lp->lazycols[c];
12275 
12276       /* in case lazy bounds are given, check that the primal solution satisfies them */
12277       assert(SCIPsetIsInfinity(set, -col->lazylb) || SCIPsetIsFeasGE(set, col->primsol, col->lazylb));
12278       assert(SCIPsetIsInfinity(set, col->lazyub) || SCIPsetIsFeasLE(set, col->primsol, col->lazyub));
12279    }
12280 }
12281 #else
12282 #define checkLazyBounds(lp, set) /**/
12283 #endif
12284 
12285 /** marks all lazy columns to be changed; this is needed for reloading/removing bounds of these columns before and after
12286  *  diving
12287  */
12288 static
updateLazyBounds(SCIP_LP * lp,SCIP_SET * set)12289 SCIP_RETCODE updateLazyBounds(
12290    SCIP_LP*              lp,                 /**< LP data */
12291    SCIP_SET*             set                 /**< global SCIP settings */
12292    )
12293 {
12294    SCIP_COL* col;
12295    int c;
12296 
12297    assert(lp->nlazycols > 0);
12298 
12299    /* return, if we are in diving, and bounds were already applied
12300     * or if we are not in diving and bounds were not applied
12301     */
12302    if( lp->diving == lp->divinglazyapplied )
12303       return SCIP_OKAY;
12304 
12305    SCIPsetDebugMsg(set, "mark all lazy columns as changed in order to reload bounds (diving=%u, applied=%u)\n",
12306       lp->diving, lp->divinglazyapplied);
12307 
12308    for( c = 0; c < lp->nlazycols; ++c )
12309    {
12310       col = lp->lazycols[c];
12311 
12312       /* if the column has a lazy lower bound, mark its lower bounds as changed */
12313       if( !SCIPsetIsInfinity(set, -col->lazylb) )
12314       {
12315          assert((!(lp->divinglazyapplied)) || (col->flushedlb == col->lb) || col->lbchanged); /*lint !e777*/
12316          assert(lp->divinglazyapplied || SCIPsetIsGT(set, col->lb, col->lazylb)
12317             || (col->flushedlb == -SCIPlpiInfinity(lp->lpi)) || col->lbchanged); /*lint !e777*/
12318 
12319          /* insert column in the chgcols list (if not already there) */
12320          SCIP_CALL( insertColChgcols(col, set, lp) );
12321 
12322          /* mark bound change in the column */
12323          col->lbchanged = TRUE;
12324       }
12325 
12326       /* if the column has a lazy upper bound, mark its upper bounds as changed */
12327       if( !SCIPsetIsInfinity(set, col->lazyub) )
12328       {
12329          assert((!(lp->divinglazyapplied)) || (col->flushedub == col->ub) || col->ubchanged); /*lint !e777*/
12330          assert(lp->divinglazyapplied || SCIPsetIsLT(set, col->ub, col->lazyub)
12331             || (col->flushedub == SCIPlpiInfinity(lp->lpi)) || col->ubchanged); /*lint !e777*/
12332 
12333          /* insert column in the chgcols list (if not already there) */
12334          SCIP_CALL( insertColChgcols(col, set, lp) );
12335 
12336          /* mark bound change in the column */
12337          col->ubchanged = TRUE;
12338       }
12339    }
12340 
12341    /* update lp->divinglazyapplied flag: if we are in diving mode, we just applied the lazy bounds,
12342     * if not, we just removed them
12343     */
12344    lp->divinglazyapplied = lp->diving;
12345 
12346    return SCIP_OKAY;
12347 }
12348 
12349 /** returns the iteration limit for an LP resolving call */
12350 static
lpGetResolveItlim(SCIP_SET * set,SCIP_STAT * stat,int itlim)12351 int lpGetResolveItlim(
12352    SCIP_SET*             set,                /**< global SCIP settings */
12353    SCIP_STAT*            stat,               /**< dynamic problem statistics */
12354    int                   itlim               /**< hard iteration limit */
12355    )
12356 {
12357    /* no limit set or average not yet reliable */
12358    if( (set->lp_resolveiterfac == -1) || stat->nlps - stat->nrootlps < 5 )
12359       return itlim;
12360    /* set itlim to INT_MAX if it is -1 to reduce the number of cases to be regarded in the following */
12361    if( itlim == -1 )
12362       itlim = INT_MAX;
12363    /* return resolveiterfac * average iteration number per call after root, but at least resolveitermin and at most the hard iteration limit */
12364    return (int) MIN(itlim, MAX(set->lp_resolveitermin, \
12365          (set->lp_resolveiterfac * (stat->nlpiterations - stat->nrootlpiterations) / (SCIP_Real)(stat->nlps - stat->nrootlps))));
12366 }
12367 
12368 
12369 
12370 /** solves the LP with simplex algorithm, and copy the solution into the column's data */
SCIPlpSolveAndEval(SCIP_LP * lp,SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr,BMS_BLKMEM * blkmem,SCIP_STAT * stat,SCIP_EVENTQUEUE * eventqueue,SCIP_EVENTFILTER * eventfilter,SCIP_PROB * prob,SCIP_Longint itlim,SCIP_Bool limitresolveiters,SCIP_Bool aging,SCIP_Bool keepsol,SCIP_Bool * lperror)12371 SCIP_RETCODE SCIPlpSolveAndEval(
12372    SCIP_LP*              lp,                 /**< LP data */
12373    SCIP_SET*             set,                /**< global SCIP settings */
12374    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
12375    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
12376    SCIP_STAT*            stat,               /**< problem statistics */
12377    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
12378    SCIP_EVENTFILTER*     eventfilter,        /**< global event filter */
12379    SCIP_PROB*            prob,               /**< problem data */
12380    SCIP_Longint          itlim,              /**< maximal number of LP iterations to perform, or -1 for no limit */
12381    SCIP_Bool             limitresolveiters,  /**< should LP iterations for resolving calls be limited?
12382                                               *   (limit is computed within the method w.r.t. the average LP iterations) */
12383    SCIP_Bool             aging,              /**< should aging and removal of obsolete cols/rows be applied? */
12384    SCIP_Bool             keepsol,            /**< should the old LP solution be kept if no iterations were performed? */
12385    SCIP_Bool*            lperror             /**< pointer to store whether an unresolved LP error occurred */
12386    )
12387 {
12388    SCIP_RETCODE retcode;
12389    SCIP_Bool needprimalray;
12390    SCIP_Bool needdualray;
12391    int harditlim;
12392    int resolveitlim;
12393 
12394    assert(lp != NULL);
12395    assert(prob != NULL);
12396    assert(prob->nvars >= lp->ncols);
12397    assert(lperror != NULL);
12398 
12399    SCIPsetDebugMsg(set, "solving LP: %d rows, %d cols, primalfeasible=%u, dualfeasible=%u, solved=%u, diving=%u, probing=%u, cutoffbnd=%g\n",
12400       lp->nrows, lp->ncols, lp->primalfeasible, lp->dualfeasible, lp->solved, lp->diving, lp->probing, lp->cutoffbound);
12401 
12402    retcode = SCIP_OKAY;
12403    *lperror = FALSE;
12404 
12405    /* check whether we need a proof of unboundedness or infeasibility by a primal or dual ray */
12406    needprimalray = TRUE;
12407    needdualray = (!SCIPprobAllColsInLP(prob, set, lp) || set->misc_exactsolve
12408       || (set->conf_enable && set->conf_useinflp != 'o'));
12409 
12410    /* compute the limit for the number of LP resolving iterations, if needed (i.e. if limitresolveiters == TRUE) */
12411    harditlim = (int) MIN(itlim, INT_MAX);
12412    resolveitlim = ( limitresolveiters ? lpGetResolveItlim(set, stat, harditlim) : harditlim );
12413    assert(harditlim == -1 || (resolveitlim <= harditlim));
12414 
12415    /* if there are lazy bounds, check whether the bounds should explicitly be put into the LP (diving was started)
12416     * or removed from the LP (diving was ended)
12417     */
12418    if( lp->nlazycols > 0 )
12419    {
12420       /* @todo avoid loosing primal feasibility here after changing the objective already did destroy dual feasibility;
12421        * first resolve LP?
12422        */
12423       SCIP_CALL( updateLazyBounds(lp, set) );
12424       assert(lp->diving == lp->divinglazyapplied);
12425    }
12426 
12427    /* flush changes to the LP solver */
12428    SCIP_CALL( SCIPlpFlush(lp, blkmem, set, eventqueue) );
12429    assert(lp->flushed);
12430 
12431    /* if the time limit was reached in the last call and the LP did not change, lp->solved is set to TRUE, but we want
12432     * to run again anyway, since there seems to be some time left / the time limit was increased
12433     */
12434    if( !lp->solved || (lp->lpsolstat == SCIP_LPSOLSTAT_TIMELIMIT && stat->status != SCIP_STATUS_TIMELIMIT) )
12435    {
12436       SCIP_Bool* primalfeaspointer;
12437       SCIP_Bool* dualfeaspointer;
12438       SCIP_Bool primalfeasible;
12439       SCIP_Bool dualfeasible;
12440       SCIP_Bool farkasvalid;
12441       SCIP_Bool rayfeasible;
12442       SCIP_Bool tightprimfeastol;
12443       SCIP_Bool tightdualfeastol;
12444       SCIP_Bool fromscratch;
12445       SCIP_Bool wasfromscratch;
12446       SCIP_Longint oldnlps;
12447       int fastmip;
12448 
12449       /* set initial LP solver settings */
12450       fastmip = ((lp->lpihasfastmip && !lp->flushaddedcols && !lp->flushdeletedcols && stat->nnodes > 1) ? set->lp_fastmip : 0);
12451       tightprimfeastol = FALSE;
12452       tightdualfeastol = FALSE;
12453       fromscratch = FALSE;
12454       primalfeasible = FALSE;
12455       dualfeasible = FALSE;
12456       wasfromscratch = (stat->nlps == 0);
12457 
12458    SOLVEAGAIN:
12459       /* solve the LP */
12460       oldnlps = stat->nlps;
12461       SCIP_CALL( lpFlushAndSolve(lp, blkmem, set, messagehdlr, stat, prob, eventqueue, resolveitlim, harditlim, needprimalray,
12462             needdualray, fastmip, tightprimfeastol, tightdualfeastol, fromscratch, keepsol, lperror) );
12463       SCIPsetDebugMsg(set, "lpFlushAndSolve() returned solstat %d (error=%u)\n", SCIPlpGetSolstat(lp), *lperror);
12464       assert(!(*lperror) || !lp->solved);
12465 
12466       /* check for error */
12467       if( *lperror )
12468       {
12469          retcode = SCIP_OKAY;
12470          goto TERMINATE;
12471       }
12472 
12473       /* evaluate solution status */
12474       switch( SCIPlpGetSolstat(lp) )
12475       {
12476       case SCIP_LPSOLSTAT_OPTIMAL:
12477          /* get LP solution and possibly check the solution's feasibility again */
12478          if( set->lp_checkprimfeas )
12479          {
12480             primalfeaspointer = &primalfeasible;
12481             lp->primalchecked = TRUE;
12482          }
12483          else
12484          {
12485             /* believe in the primal feasibility of the LP solution */
12486             primalfeasible = TRUE;
12487             primalfeaspointer = NULL;
12488             lp->primalchecked = FALSE;
12489          }
12490          if( set->lp_checkdualfeas )
12491          {
12492             dualfeaspointer = &dualfeasible;
12493             lp->dualchecked = TRUE;
12494          }
12495          else
12496          {
12497             /* believe in the dual feasibility of the LP solution */
12498             dualfeasible = TRUE;
12499             dualfeaspointer = NULL;
12500             lp->dualchecked = FALSE;
12501          }
12502 
12503          SCIP_CALL( SCIPlpGetSol(lp, set, stat, primalfeaspointer, dualfeaspointer) );
12504 
12505          /* in debug mode, check that lazy bounds (if present) are not violated */
12506          checkLazyBounds(lp, set);
12507 
12508          if( primalfeasible && dualfeasible && aging && !lp->diving && stat->nlps > oldnlps )
12509          {
12510             /* update ages and remove obsolete columns and rows from LP */
12511             SCIP_CALL( SCIPlpUpdateAges(lp, stat) );
12512             if( stat->nlps % ((set->lp_rowagelimit+1)/2 + 1) == 0 ) /*lint !e776*/
12513             {
12514                SCIP_CALL( SCIPlpRemoveNewObsoletes(lp, blkmem, set, stat, eventqueue, eventfilter) );
12515             }
12516 
12517             if( !lp->solved )
12518             {
12519                /* resolve LP after removing obsolete columns and rows */
12520                SCIPsetDebugMsg(set, "removed obsoletes - resolve LP again: %d rows, %d cols\n", lp->nrows, lp->ncols);
12521                aging = FALSE; /* to prevent infinite loops */
12522                goto SOLVEAGAIN;
12523             }
12524          }
12525          if( !primalfeasible || !dualfeasible )
12526          {
12527             SCIP_Bool simplex = (lp->lastlpalgo == SCIP_LPALGO_PRIMALSIMPLEX || lp->lastlpalgo == SCIP_LPALGO_DUALSIMPLEX);
12528 
12529             if( (fastmip > 0) && simplex )
12530             {
12531                /* solution is infeasible (this can happen due to numerical problems): solve again without FASTMIP */
12532                SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
12533                   "(node %" SCIP_LONGINT_FORMAT ") solution of LP %" SCIP_LONGINT_FORMAT " not optimal (pfeas=%d, dfeas=%d) -- solving again without FASTMIP\n",
12534                   stat->nnodes, stat->nlps, primalfeasible, dualfeasible);
12535                fastmip = 0;
12536                goto SOLVEAGAIN;
12537             }
12538             else if( (!primalfeasible && !tightprimfeastol) || (!dualfeasible && !tightdualfeastol) )
12539             {
12540                /* solution is infeasible (this can happen due to numerical problems): solve again with tighter feasibility
12541                 * tolerance
12542                 */
12543                SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
12544                   "(node %" SCIP_LONGINT_FORMAT ") solution of LP %" SCIP_LONGINT_FORMAT " not optimal (pfeas=%d, dfeas=%d) -- solving again with tighter feasibility tolerance\n",
12545                   stat->nnodes, stat->nlps, primalfeasible, dualfeasible);
12546                tightprimfeastol = tightprimfeastol || !primalfeasible;
12547                tightdualfeastol = tightdualfeastol || !dualfeasible;
12548                goto SOLVEAGAIN;
12549             }
12550             else if( !fromscratch && !wasfromscratch && simplex )
12551             {
12552                /* solution is infeasible (this can happen due to numerical problems): solve again from scratch */
12553                SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
12554                   "(node %" SCIP_LONGINT_FORMAT ") solution of LP %" SCIP_LONGINT_FORMAT " not optimal (pfeas=%d, dfeas=%d) -- solving again from scratch\n",
12555                   stat->nnodes, stat->nlps, primalfeasible, dualfeasible);
12556                fromscratch = TRUE;
12557                goto SOLVEAGAIN;
12558             }
12559             else
12560             {
12561                lpNumericalTroubleMessage(messagehdlr, set, stat, SCIP_VERBLEVEL_FULL, "unresolved");
12562                lp->solved = FALSE;
12563                lp->lpsolstat = SCIP_LPSOLSTAT_NOTSOLVED;
12564                *lperror = TRUE;
12565             }
12566          }
12567          SCIPsetDebugMsg(set, " -> LP objective value: %g + %g = %g (solstat=%d, cutoff=%g)\n",
12568             lp->lpobjval, getFiniteLooseObjval(lp, set, prob), lp->lpobjval + getFiniteLooseObjval(lp, set, prob),
12569             lp->lpsolstat, lp->cutoffbound);
12570          break;
12571 
12572       case SCIP_LPSOLSTAT_INFEASIBLE:
12573          SCIPsetDebugMsg(set, " -> LP infeasible\n");
12574          if( !SCIPprobAllColsInLP(prob, set, lp) || set->lp_checkfarkas || set->misc_exactsolve || set->lp_alwaysgetduals )
12575          {
12576             if( SCIPlpiHasDualRay(lp->lpi) )
12577             {
12578                SCIP_CALL( SCIPlpGetDualfarkas(lp, set, stat, &farkasvalid) );
12579             }
12580             /* it might happen that we have no infeasibility proof for the current LP (e.g. if the LP was always solved
12581              * with the primal simplex due to numerical problems) - treat this case like an LP error
12582              */
12583             else
12584             {
12585                SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
12586                   "(node %" SCIP_LONGINT_FORMAT ") infeasibility of LP %" SCIP_LONGINT_FORMAT " could not be proven by dual ray\n", stat->nnodes, stat->nlps);
12587                lp->solved = FALSE;
12588                lp->lpsolstat = SCIP_LPSOLSTAT_NOTSOLVED;
12589                farkasvalid = FALSE;
12590                *lperror = TRUE;
12591             }
12592          }
12593          else
12594             farkasvalid = TRUE;
12595 
12596          /* if the LP solver does not provide a Farkas proof we don't want to resolve the LP */
12597          if( !farkasvalid && !(*lperror) )
12598          {
12599             SCIP_Bool simplex = (lp->lastlpalgo == SCIP_LPALGO_PRIMALSIMPLEX || lp->lastlpalgo == SCIP_LPALGO_DUALSIMPLEX);
12600 
12601             if( (fastmip > 0) && simplex )
12602             {
12603                /* the Farkas proof does not prove infeasibility (this can happen due to numerical problems): solve again
12604                 * without FASTMIP
12605                 */
12606                SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
12607                   "(node %" SCIP_LONGINT_FORMAT ") proof of infeasible LP %" SCIP_LONGINT_FORMAT " not valid -- solving again without FASTMIP\n",
12608                   stat->nnodes, stat->nlps);
12609                fastmip = 0;
12610                goto SOLVEAGAIN;
12611             }
12612             else if( !tightdualfeastol )
12613             {
12614                /* the Farkas proof does not prove infeasibility (this can happen due to numerical problems):
12615                 * solve again with tighter feasibility tolerance
12616                 */
12617                SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
12618                   "(node %" SCIP_LONGINT_FORMAT ") proof of infeasible LP %" SCIP_LONGINT_FORMAT " not valid -- solving again with tighter dual feasibility tolerance\n",
12619                   stat->nnodes, stat->nlps);
12620                tightdualfeastol = TRUE;
12621                goto SOLVEAGAIN;
12622             }
12623             else if( !fromscratch && simplex )
12624             {
12625                /* the Farkas proof does not prove infeasibility (this can happen due to numerical problems): solve again
12626                 * from scratch
12627                 */
12628                SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
12629                   "(node %" SCIP_LONGINT_FORMAT ") proof of infeasible LP %" SCIP_LONGINT_FORMAT " not valid -- solving again from scratch\n",
12630                   stat->nnodes, stat->nlps);
12631                fromscratch = TRUE;
12632                goto SOLVEAGAIN;
12633             }
12634             else
12635             {
12636                /* the Farkas proof does not prove infeasibility (this can happen due to numerical problems) and nothing
12637                 * helped forget about the LP at this node and mark it to be unsolved
12638                 */
12639                lpNumericalTroubleMessage(messagehdlr, set, stat, SCIP_VERBLEVEL_FULL, "unresolved, LP infeasible");
12640                lp->solved = FALSE;
12641                lp->lpsolstat = SCIP_LPSOLSTAT_NOTSOLVED;
12642                *lperror = TRUE;
12643             }
12644          }
12645 
12646          break;
12647 
12648       case SCIP_LPSOLSTAT_UNBOUNDEDRAY:
12649          if( set->lp_checkprimfeas )
12650          {
12651             /* get unbounded LP solution and check the solution's feasibility again */
12652             SCIP_CALL( SCIPlpGetUnboundedSol(lp, set, stat, &primalfeasible, &rayfeasible) );
12653 
12654             lp->primalchecked = TRUE;
12655          }
12656          else
12657          {
12658             /* get unbounded LP solution believing in the feasibility of the LP solution */
12659             SCIP_CALL( SCIPlpGetUnboundedSol(lp, set, stat, NULL, NULL) );
12660 
12661             primalfeasible = TRUE;
12662             rayfeasible = TRUE;
12663             lp->primalchecked = FALSE;
12664          }
12665 
12666          /* in debug mode, check that lazy bounds (if present) are not violated */
12667          checkLazyBounds(lp, set);
12668 
12669          SCIPsetDebugMsg(set, " -> LP has unbounded primal ray (primalfeas=%u, rayfeas=%u)\n",
12670             primalfeasible, rayfeasible);
12671 
12672          if( !primalfeasible || !rayfeasible )
12673          {
12674             SCIP_Bool simplex = (lp->lastlpalgo == SCIP_LPALGO_PRIMALSIMPLEX || lp->lastlpalgo == SCIP_LPALGO_DUALSIMPLEX);
12675 
12676             if( (fastmip > 0) && simplex )
12677             {
12678                /* unbounded solution is infeasible (this can happen due to numerical problems): solve again without FASTMIP */
12679                SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
12680                   "(node %" SCIP_LONGINT_FORMAT ") solution of unbounded LP %" SCIP_LONGINT_FORMAT " not optimal (pfeas=%d, rfeas=%d) -- solving again without FASTMIP\n",
12681                   stat->nnodes, stat->nlps, primalfeasible, rayfeasible);
12682                fastmip = 0;
12683                goto SOLVEAGAIN;
12684             }
12685             else if( !tightprimfeastol )
12686             {
12687                /* unbounded solution is infeasible (this can happen due to numerical problems): solve again with tighter feasibility
12688                 * tolerance
12689                 */
12690                SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
12691                   "(node %" SCIP_LONGINT_FORMAT ") solution of unbounded LP %" SCIP_LONGINT_FORMAT " not optimal (pfeas=%d, rfeas=%d) -- solving again with tighter primal feasibility tolerance\n",
12692                   stat->nnodes, stat->nlps, primalfeasible, rayfeasible);
12693                tightprimfeastol = TRUE;
12694                goto SOLVEAGAIN;
12695             }
12696             else if( !fromscratch && simplex )
12697             {
12698                /* unbounded solution is infeasible (this can happen due to numerical problems): solve again from scratch */
12699                SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
12700                   "(node %" SCIP_LONGINT_FORMAT ") solution of unbounded LP %" SCIP_LONGINT_FORMAT " not optimal (pfeas=%d, rfeas=%d) -- solving again from scratch\n",
12701                   stat->nnodes, stat->nlps, primalfeasible, rayfeasible);
12702                fromscratch = TRUE;
12703                goto SOLVEAGAIN;
12704             }
12705             else
12706             {
12707                /* unbounded solution is infeasible (this can happen due to numerical problems) and nothing helped:
12708                 * forget about the LP at this node and mark it to be unsolved
12709                 */
12710                lpNumericalTroubleMessage(messagehdlr, set, stat, SCIP_VERBLEVEL_FULL, "unresolved, LP unbounded");
12711                lp->solved = FALSE;
12712                lp->lpsolstat = SCIP_LPSOLSTAT_NOTSOLVED;
12713                *lperror = TRUE;
12714             }
12715          }
12716 
12717          break;
12718 
12719       case SCIP_LPSOLSTAT_OBJLIMIT:
12720          assert(!lpCutoffDisabled(set));
12721          /* Some LP solvers, e.g. CPLEX With FASTMIP setting, do not apply the final pivot to reach the dual solution
12722           * exceeding the objective limit. In some cases like branch-and-price, however, we must make sure that a dual
12723           * feasible solution exists that exceeds the objective limit. Therefore, we have to continue solving it without
12724           * objective limit for at least one iteration. We first try to continue with FASTMIP for one additional simplex
12725           * iteration using the steepest edge pricing rule. If this does not fix the problem, we temporarily disable
12726           * FASTMIP and solve again. */
12727          if( !SCIPprobAllColsInLP(prob, set, lp) || set->misc_exactsolve )
12728          {
12729             SCIP_LPI* lpi;
12730             SCIP_Real objval;
12731 
12732             lpi = SCIPlpGetLPI(lp);
12733 
12734             assert(lpi != NULL);
12735             /* actually, SCIPsetIsGE(set, lp->lpobjval, lp->lpiuobjlim) should hold, but we are a bit less strict in
12736              * the assert by using !SCIPsetIsFeasNegative()
12737              */
12738             assert(SCIPlpiIsObjlimExc(lpi) || !SCIPsetIsFeasNegative(set, lp->lpobjval - lp->lpiobjlim));
12739 
12740             SCIP_CALL( SCIPlpiGetObjval(lpi, &objval) );
12741 
12742             /* do one additional simplex step if the computed dual solution doesn't exceed the objective limit */
12743             if( SCIPsetIsLT(set, objval, lp->lpiobjlim) )
12744             {
12745                SCIP_Real tmpcutoff;
12746                char tmppricingchar;
12747                SCIP_LPSOLSTAT solstat;
12748 
12749                SCIPsetDebugMsg(set, "objval = %f < %f = lp->lpiobjlim, but status objlimit\n", objval, lp->lpiobjlim);
12750 
12751                /* we want to resolve from the current basis (also if the LP had to be solved from scratch) */
12752                fromscratch = FALSE;
12753 
12754                /* temporarily disable cutoffbound, which also disables the objective limit */
12755                tmpcutoff = lp->cutoffbound;
12756                lp->cutoffbound = SCIPlpiInfinity(lpi);
12757 
12758                /* set lp pricing strategy to steepest edge */
12759                SCIP_CALL( SCIPsetGetCharParam(set, "lp/pricing", &tmppricingchar) );
12760                SCIP_CALL( SCIPsetSetCharParam(set, messagehdlr, "lp/pricing", 's') );
12761 
12762                /* resolve LP with an iteration limit of 1 */
12763                SCIP_CALL( lpSolve(lp, set, messagehdlr, stat, prob, SCIP_LPALGO_DUALSIMPLEX, 1, 1,
12764                      FALSE, FALSE, TRUE, fastmip, tightprimfeastol, tightdualfeastol, fromscratch, keepsol, lperror) );
12765 
12766                /* reinstall old cutoff bound and lp pricing strategy */
12767                lp->cutoffbound = tmpcutoff;
12768                SCIP_CALL( SCIPsetSetCharParam(set, messagehdlr, "lp/pricing", tmppricingchar) );
12769 
12770                /* get objective value */
12771                SCIP_CALL( SCIPlpiGetObjval(lpi, &objval) );
12772 
12773                /* get solution status for the lp */
12774                solstat = SCIPlpGetSolstat(lp);
12775                assert(solstat != SCIP_LPSOLSTAT_OBJLIMIT);
12776 
12777                if( !(*lperror) && solstat != SCIP_LPSOLSTAT_ERROR && solstat != SCIP_LPSOLSTAT_NOTSOLVED )
12778                {
12779                   SCIPsetDebugMsg(set, " ---> new objval = %f (solstat: %d, 1 add. step)\n", objval, solstat);
12780                }
12781 
12782                /* disable fastmip for subsequent LP calls (if objective limit is not yet exceeded or LP solution is infeasible) */
12783                fastmip = 0;
12784 
12785                /* the solution is still not exceeding the objective limit and the solving process
12786                 * was stopped due to time or iteration limit, solve again with fastmip turned off
12787                 */
12788                if( solstat == SCIP_LPSOLSTAT_ITERLIMIT &&
12789                   SCIPsetIsLT(set, objval, lp->cutoffbound - getFiniteLooseObjval(lp, set, prob)) )
12790                {
12791                   assert(!(*lperror));
12792 
12793                   SCIP_CALL( lpSolve(lp, set, messagehdlr, stat, prob, SCIP_LPALGO_DUALSIMPLEX, -1, -1,
12794                         FALSE, FALSE, TRUE, fastmip, tightprimfeastol, tightdualfeastol, fromscratch, keepsol, lperror) );
12795 
12796                   /* get objective value */
12797                   SCIP_CALL( SCIPlpiGetObjval(lpi, &objval) );
12798 
12799                   /* get solution status for the lp */
12800                   solstat = SCIPlpGetSolstat(lp);
12801 
12802                   SCIPsetDebugMsg(set, " ---> new objval = %f (solstat: %d, without fastmip)\n", objval, solstat);
12803                }
12804 
12805                /* check for lp errors */
12806                if( *lperror || solstat == SCIP_LPSOLSTAT_ERROR || solstat == SCIP_LPSOLSTAT_NOTSOLVED )
12807                {
12808                   SCIPsetDebugMsg(set, "unresolved error while resolving LP in order to exceed the objlimit\n");
12809                   lp->solved = FALSE;
12810                   lp->lpsolstat = SCIP_LPSOLSTAT_NOTSOLVED;
12811 
12812                   retcode = *lperror ? SCIP_OKAY : SCIP_LPERROR;
12813                   goto TERMINATE;
12814                }
12815 
12816                lp->solved = TRUE;
12817 
12818                /* optimal solution / objlimit with fastmip turned off / itlimit or timelimit, but objlimit exceeded */
12819                if( solstat == SCIP_LPSOLSTAT_OPTIMAL || solstat == SCIP_LPSOLSTAT_OBJLIMIT
12820                   || ( (solstat == SCIP_LPSOLSTAT_ITERLIMIT || solstat == SCIP_LPSOLSTAT_TIMELIMIT)
12821                      && SCIPsetIsGE(set, objval, lp->cutoffbound - getFiniteLooseObjval(lp, set, prob)) ) )
12822                {
12823                   /* get LP solution and possibly check the solution's feasibility again */
12824                   if( set->lp_checkprimfeas )
12825                   {
12826                      primalfeaspointer = &primalfeasible;
12827                      lp->primalchecked = TRUE;
12828                   }
12829                   else
12830                   {
12831                      /* believe in the primal feasibility of the LP solution */
12832                      primalfeasible = TRUE;
12833                      primalfeaspointer = NULL;
12834                      lp->primalchecked = FALSE;
12835                   }
12836                   if( set->lp_checkdualfeas )
12837                   {
12838                      dualfeaspointer = &dualfeasible;
12839                      lp->dualchecked = TRUE;
12840                   }
12841                   else
12842                   {
12843                      /* believe in the dual feasibility of the LP solution */
12844                      dualfeasible = TRUE;
12845                      dualfeaspointer = NULL;
12846                      lp->dualchecked = FALSE;
12847                   }
12848 
12849                   SCIP_CALL( SCIPlpGetSol(lp, set, stat, primalfeaspointer, dualfeaspointer) );
12850 
12851                   /* in debug mode, check that lazy bounds (if present) are not violated by an optimal LP solution */
12852                   if( solstat == SCIP_LPSOLSTAT_OPTIMAL )
12853                   {
12854                      checkLazyBounds(lp, set);
12855                   }
12856 
12857                   /* if objective value is larger than the cutoff bound, set solution status to objective
12858                    * limit reached and objective value to infinity, in case solstat = SCIP_LPSOLSTAT_OBJLIMIT,
12859                    * this was already done in the lpSolve() method
12860                    */
12861                   if( SCIPsetIsGE(set, objval, lp->cutoffbound - getFiniteLooseObjval(lp, set, prob)) )
12862                   {
12863                      lp->lpsolstat = SCIP_LPSOLSTAT_OBJLIMIT;
12864                      lp->lpobjval = SCIPsetInfinity(set);
12865                   }
12866 
12867                   /* LP solution is not feasible or objective limit was reached without the LP value really exceeding
12868                    * the cutoffbound; mark the LP to be unsolved
12869                    */
12870                   if( !primalfeasible || !dualfeasible
12871                      || (solstat == SCIP_LPSOLSTAT_OBJLIMIT &&
12872                         !SCIPsetIsGE(set, objval, lp->cutoffbound - getFiniteLooseObjval(lp, set, prob))) )
12873                   {
12874                      lpNumericalTroubleMessage(messagehdlr, set, stat, SCIP_VERBLEVEL_HIGH, "unresolved");
12875                      lp->solved = FALSE;
12876                      lp->lpsolstat = SCIP_LPSOLSTAT_NOTSOLVED;
12877                      *lperror = TRUE;
12878                   }
12879 
12880                   SCIPsetDebugMsg(set, " -> LP objective value: %g + %g = %g (solstat=%d, cutoff=%g)\n",
12881                      lp->lpobjval, getFiniteLooseObjval(lp, set, prob), lp->lpobjval + getFiniteLooseObjval(lp, set, prob),
12882                      lp->lpsolstat, lp->cutoffbound);
12883                }
12884                /* infeasible solution */
12885                else if( solstat == SCIP_LPSOLSTAT_INFEASIBLE )
12886                {
12887                   SCIPsetDebugMsg(set, " -> LP infeasible\n");
12888 
12889                   if( !SCIPprobAllColsInLP(prob, set, lp) || set->lp_checkfarkas || set->misc_exactsolve )
12890                   {
12891                      if( SCIPlpiHasDualRay(lp->lpi) )
12892                      {
12893                         SCIP_CALL( SCIPlpGetDualfarkas(lp, set, stat, &farkasvalid) );
12894                      }
12895                      /* it might happen that we have no infeasibility proof for the current LP (e.g. if the LP was always solved
12896                       * with the primal simplex due to numerical problems) - treat this case like an LP error
12897                       */
12898                      else
12899                      {
12900                         SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
12901                            "(node %" SCIP_LONGINT_FORMAT ") infeasibility of LP %" SCIP_LONGINT_FORMAT " could not be proven by dual ray\n", stat->nnodes, stat->nlps);
12902                         lp->solved = FALSE;
12903                         lp->lpsolstat = SCIP_LPSOLSTAT_NOTSOLVED;
12904                         farkasvalid = FALSE;
12905                         *lperror = TRUE;
12906                      }
12907                   }
12908                   else
12909                      farkasvalid = TRUE;
12910 
12911                   if( !farkasvalid )
12912                   {
12913                      SCIP_Bool simplex = (lp->lastlpalgo == SCIP_LPALGO_PRIMALSIMPLEX || lp->lastlpalgo == SCIP_LPALGO_DUALSIMPLEX);
12914 
12915                      if( !tightprimfeastol )
12916                      {
12917                         /* the Farkas proof does not prove infeasibility (this can happen due to numerical problems):
12918                          * solve again with tighter feasibility tolerance
12919                          */
12920                         SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
12921                               "(node %" SCIP_LONGINT_FORMAT ") proof of infeasible LP %" SCIP_LONGINT_FORMAT " not valid -- solving again with tighter primal feasibility tolerance\n",
12922                               stat->nnodes, stat->nlps);
12923                         tightprimfeastol = TRUE;
12924                         goto SOLVEAGAIN;
12925                      }
12926                      else if( simplex )
12927                      {
12928                         /* the Farkas proof does not prove infeasibility (this can happen due to numerical problems): solve again
12929                          * from scratch
12930                          */
12931                         SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
12932                               "(node %" SCIP_LONGINT_FORMAT ") proof of infeasible LP %" SCIP_LONGINT_FORMAT " not valid -- solving again from scratch\n",
12933                               stat->nnodes, stat->nlps);
12934                         fromscratch = TRUE;
12935                         goto SOLVEAGAIN;
12936                      }
12937                      else
12938                      {
12939                         /* the Farkas proof does not prove infeasibility (this can happen due to numerical problems) and nothing
12940                          * helped forget about the LP at this node and mark it to be unsolved
12941                          */
12942                         lpNumericalTroubleMessage(messagehdlr, set, stat, SCIP_VERBLEVEL_FULL, "unresolved, LP infeasible");
12943                         lp->solved = FALSE;
12944                         lp->lpsolstat = SCIP_LPSOLSTAT_NOTSOLVED;
12945                         *lperror = TRUE;
12946                      }
12947                   }
12948                }
12949                /* unbounded solution */
12950                else if( solstat == SCIP_LPSOLSTAT_UNBOUNDEDRAY )
12951                {
12952                   if( set->lp_checkprimfeas )
12953                   {
12954                      /* get unbounded LP solution and check the solution's feasibility again */
12955                      SCIP_CALL( SCIPlpGetUnboundedSol(lp, set, stat, &primalfeasible, &rayfeasible) );
12956 
12957                      lp->primalchecked = TRUE;
12958                   }
12959                   else
12960                   {
12961                      /* get unbounded LP solution believing in its feasibility */
12962                      SCIP_CALL( SCIPlpGetUnboundedSol(lp, set, stat, NULL, NULL) );
12963 
12964                      primalfeasible = TRUE;
12965                      rayfeasible = TRUE;
12966                      lp->primalchecked = FALSE;
12967                   }
12968 
12969                   SCIPsetDebugMsg(set, " -> LP has unbounded primal ray\n");
12970 
12971                   /* in debug mode, check that lazy bounds (if present) are not violated */
12972                   checkLazyBounds(lp, set);
12973 
12974                   if( !primalfeasible || !rayfeasible )
12975                   {
12976                      /* unbounded solution is infeasible (this can happen due to numerical problems):
12977                       * forget about the LP at this node and mark it to be unsolved
12978                       *
12979                       * @todo: like in the default LP solving evaluation, solve without fastmip,
12980                       * with tighter feasibility tolerance and from scratch
12981                       */
12982                      lpNumericalTroubleMessage(messagehdlr, set, stat, SCIP_VERBLEVEL_FULL, "unresolved, unbounded LP");
12983                      lp->solved = FALSE;
12984                      lp->lpsolstat = SCIP_LPSOLSTAT_NOTSOLVED;
12985                      *lperror = TRUE;
12986                   }
12987                }
12988 
12989                assert(lp->lpsolstat != SCIP_LPSOLSTAT_ITERLIMIT);
12990                assert(SCIPsetIsGE(set, objval, lp->cutoffbound - getFiniteLooseObjval(lp, set, prob))
12991                   || lp->lpsolstat != SCIP_LPSOLSTAT_OBJLIMIT);
12992             }
12993             else
12994             {
12995                SCIP_CALL( SCIPlpGetSol(lp, set, stat, NULL, NULL) );
12996             }
12997          }
12998          SCIPsetDebugMsg(set, " -> LP objective limit reached\n");
12999          break;
13000 
13001       case SCIP_LPSOLSTAT_ITERLIMIT:
13002          SCIPsetDebugMsg(set, " -> LP iteration limit exceeded\n");
13003          break;
13004 
13005       case SCIP_LPSOLSTAT_TIMELIMIT:
13006          SCIPsetDebugMsg(set, " -> LP time limit exceeded\n");
13007 
13008          /* make sure that we evaluate the time limit exactly in order to avoid erroneous warning */
13009          stat->nclockskipsleft = 0;
13010          if( !SCIPsolveIsStopped(set, stat, FALSE) )
13011          {
13012             SCIPmessagePrintWarning(messagehdlr, "LP solver reached time limit, but SCIP time limit is not exceeded yet; "
13013                "you might consider switching the clock type of SCIP\n");
13014             stat->status = SCIP_STATUS_TIMELIMIT;
13015          }
13016          break;
13017 
13018       case SCIP_LPSOLSTAT_ERROR:
13019       case SCIP_LPSOLSTAT_NOTSOLVED:
13020          SCIPerrorMessage("error in LP solver\n");
13021          retcode = SCIP_LPERROR;
13022          goto TERMINATE;
13023 
13024       default:
13025          SCIPerrorMessage("unknown LP solution status\n");
13026          retcode = SCIP_ERROR;
13027          goto TERMINATE;
13028       }
13029    }
13030    assert(!(*lperror) || !lp->solved);
13031 
13032  TERMINATE:
13033    /* if the LP had to be solved from scratch, we have to reset this flag since it is stored in the LPI; otherwise it
13034     * may happen that we continue to solve from scratch during strong branching */
13035    if( lp->lpifromscratch )
13036    {
13037       SCIP_Bool success;
13038       (void) lpSetFromscratch(lp, FALSE, &success);
13039       SCIPsetDebugMsg(set, "resetting parameter SCIP_LPPARAM_FROMSCRATCH to FALSE %s\n", success ? "" : "failed");
13040       SCIP_UNUSED(success);
13041    }
13042 
13043    return retcode;
13044 }
13045 
13046 /** gets solution status of current LP */
SCIPlpGetSolstat(SCIP_LP * lp)13047 SCIP_LPSOLSTAT SCIPlpGetSolstat(
13048    SCIP_LP*              lp                  /**< current LP data */
13049    )
13050 {
13051    assert(lp != NULL);
13052    assert(lp->solved || lp->lpsolstat == SCIP_LPSOLSTAT_NOTSOLVED);
13053 
13054    return (lp->flushed ? lp->lpsolstat : SCIP_LPSOLSTAT_NOTSOLVED);
13055 }
13056 
13057 /** gets objective value of current LP
13058  *
13059  *  @note This method returns the objective value of the current LP solution, which might be primal or dual infeasible
13060  *        if a limit was hit during solving. It must not be used as a dual bound if the LP solution status is
13061  *        SCIP_LPSOLSTAT_ITERLIMIT or SCIP_LPSOLSTAT_TIMELIMIT.
13062  */
SCIPlpGetObjval(SCIP_LP * lp,SCIP_SET * set,SCIP_PROB * prob)13063 SCIP_Real SCIPlpGetObjval(
13064    SCIP_LP*              lp,                 /**< current LP data */
13065    SCIP_SET*             set,                /**< global SCIP settings */
13066    SCIP_PROB*            prob                /**< problem data */
13067    )
13068 {
13069    assert(lp != NULL);
13070    assert(lp->solved);
13071    assert((lp->nloosevars > 0) || (lp->looseobjvalinf == 0 && lp->looseobjval == 0.0));
13072    assert(set != NULL);
13073 
13074    if( !lp->flushed )
13075       return SCIP_INVALID;
13076    else if( SCIPsetIsInfinity(set, lp->lpobjval) || SCIPsetIsInfinity(set, -lp->lpobjval))
13077       return lp->lpobjval;
13078    else if( lp->looseobjvalinf > 0 )
13079       return -SCIPsetInfinity(set);
13080    else
13081    {
13082       /* recalculate the loose objective value, if needed */
13083       if( !lp->looseobjvalid )
13084          recomputeLooseObjectiveValue(lp, set, prob);
13085 
13086       return lp->lpobjval + lp->looseobjval;
13087    }
13088 }
13089 
13090 /** gets part of objective value of current LP that results from COLUMN variables only */
SCIPlpGetColumnObjval(SCIP_LP * lp)13091 SCIP_Real SCIPlpGetColumnObjval(
13092    SCIP_LP*              lp                  /**< current LP data */
13093    )
13094 {
13095    assert(lp != NULL);
13096    assert(lp->solved);
13097 
13098    return (lp->flushed ? lp->lpobjval : SCIP_INVALID);
13099 }
13100 
13101 /** gets part of objective value of current LP that results from LOOSE variables only */
SCIPlpGetLooseObjval(SCIP_LP * lp,SCIP_SET * set,SCIP_PROB * prob)13102 SCIP_Real SCIPlpGetLooseObjval(
13103    SCIP_LP*              lp,                 /**< current LP data */
13104    SCIP_SET*             set,                /**< global SCIP settings */
13105    SCIP_PROB*            prob                /**< problem data */
13106    )
13107 {
13108    assert(lp != NULL);
13109    assert(lp->solved);
13110    assert((lp->nloosevars > 0) || (lp->looseobjvalinf == 0 && lp->looseobjval == 0.0));
13111    assert(set != NULL);
13112 
13113    if( !lp->flushed )
13114       return SCIP_INVALID;
13115    else if( lp->looseobjvalinf > 0 )
13116       return -SCIPsetInfinity(set);
13117    else
13118       return getFiniteLooseObjval(lp, set, prob);
13119 }
13120 
13121 /** remembers the current LP objective value as root solution value */
SCIPlpStoreRootObjval(SCIP_LP * lp,SCIP_SET * set,SCIP_PROB * prob)13122 void SCIPlpStoreRootObjval(
13123    SCIP_LP*              lp,                 /**< current LP data */
13124    SCIP_SET*             set,                /**< global SCIP settings */
13125    SCIP_PROB*            prob                /**< problem data */
13126    )
13127 {
13128    assert(lp != NULL);
13129 
13130    lp->rootlpobjval = SCIPlpGetColumnObjval(lp);
13131    lp->rootlooseobjval = SCIPlpGetLooseObjval(lp, set, prob);
13132 }
13133 
13134 /** invalidates the root LP solution value */
SCIPlpInvalidateRootObjval(SCIP_LP * lp)13135 void SCIPlpInvalidateRootObjval(
13136    SCIP_LP*              lp                  /**< current LP data */
13137    )
13138 {
13139    assert(lp != NULL);
13140 
13141    lp->rootlpobjval = SCIP_INVALID;
13142    lp->rootlooseobjval = SCIP_INVALID;
13143 }
13144 
13145 /** recomputes local and global pseudo objective values */
SCIPlpRecomputeLocalAndGlobalPseudoObjval(SCIP_LP * lp,SCIP_SET * set,SCIP_PROB * prob)13146 void SCIPlpRecomputeLocalAndGlobalPseudoObjval(
13147    SCIP_LP*              lp,                 /**< current LP data */
13148    SCIP_SET*             set,                /**< global SCIP settings */
13149    SCIP_PROB*            prob                /**< problem data */
13150    )
13151 {
13152    SCIP_VAR** vars;
13153    int nvars;
13154    int v;
13155 
13156    assert(lp != NULL);
13157    assert(set != NULL);
13158    assert(prob != NULL);
13159 
13160    vars = prob->vars;
13161    nvars = prob->nvars;
13162 
13163    lp->glbpseudoobjvalinf = 0;
13164    lp->glbpseudoobjval = 0.0;
13165 
13166    lp->pseudoobjvalinf = 0;
13167    lp->pseudoobjval = 0.0;
13168 
13169    for( v = 0; v < nvars; ++v )
13170    {
13171       SCIP_Real obj = SCIPvarGetObj(vars[v]);
13172 
13173       if( SCIPsetIsPositive(set, obj) )
13174       {
13175          /* update the global pseudo objective value */
13176          if( SCIPsetIsInfinity(set, -SCIPvarGetLbGlobal(vars[v])) )
13177             ++(lp->glbpseudoobjvalinf);
13178          else
13179             lp->glbpseudoobjval += obj * SCIPvarGetLbGlobal(vars[v]);
13180 
13181          /* update the local pseudo objective value */
13182          if( SCIPsetIsInfinity(set, -SCIPvarGetLbLocal(vars[v])) )
13183             ++(lp->pseudoobjvalinf);
13184          else
13185             lp->pseudoobjval += obj * SCIPvarGetLbLocal(vars[v]);
13186       }
13187 
13188       if( SCIPsetIsNegative(set, obj) )
13189       {
13190          /* update the global pseudo objective value */
13191          if( SCIPsetIsInfinity(set, SCIPvarGetUbGlobal(vars[v])) )
13192             ++(lp->glbpseudoobjvalinf);
13193          else
13194             lp->glbpseudoobjval += obj * SCIPvarGetUbGlobal(vars[v]);
13195 
13196          /* update the local pseudo objective value */
13197          if( SCIPsetIsInfinity(set, SCIPvarGetUbLocal(vars[v])) )
13198             ++(lp->pseudoobjvalinf);
13199          else
13200             lp->pseudoobjval += obj * SCIPvarGetUbLocal(vars[v]);
13201       }
13202    }
13203 
13204    /* the recomputed values are reliable */
13205    lp->relglbpseudoobjval = lp->glbpseudoobjval;
13206    lp->glbpseudoobjvalid = TRUE;
13207    lp->relpseudoobjval = lp->pseudoobjval;
13208    lp->pseudoobjvalid = TRUE;
13209 }
13210 
13211 /** gets the global pseudo objective value; that is all variables set to their best (w.r.t. the objective function)
13212  *  global bound
13213  */
SCIPlpGetGlobalPseudoObjval(SCIP_LP * lp,SCIP_SET * set,SCIP_PROB * prob)13214 SCIP_Real SCIPlpGetGlobalPseudoObjval(
13215    SCIP_LP*              lp,                 /**< current LP data */
13216    SCIP_SET*             set,                /**< global SCIP settings */
13217    SCIP_PROB*            prob                /**< problem data */
13218    )
13219 {
13220    assert(lp != NULL);
13221    assert(lp->glbpseudoobjvalinf >= 0);
13222    assert(set != NULL);
13223 
13224    if( lp->glbpseudoobjvalinf > 0 || set->nactivepricers > 0 )
13225       return -SCIPsetInfinity(set);
13226    else
13227    {
13228       /* recalculate the global pseudo solution value, if needed */
13229       if( !lp->glbpseudoobjvalid )
13230          recomputeGlbPseudoObjectiveValue(lp, set, prob);
13231 
13232       /* if the global pseudo objective value is smaller than -infinity, we just return -infinity */
13233       if( SCIPsetIsInfinity(set, -lp->glbpseudoobjval) )
13234          return -SCIPsetInfinity(set);
13235 
13236       if( SCIPsetIsInfinity(set, lp->glbpseudoobjval) )
13237          return SCIPsetInfinity(set);
13238 
13239       return lp->glbpseudoobjval;
13240    }
13241 }
13242 
13243 /** gets the pseudo objective value for the current search node; that is all variables set to their best (w.r.t. the
13244  *  objective function) local bound
13245  */
SCIPlpGetPseudoObjval(SCIP_LP * lp,SCIP_SET * set,SCIP_PROB * prob)13246 SCIP_Real SCIPlpGetPseudoObjval(
13247    SCIP_LP*              lp,                 /**< current LP data */
13248    SCIP_SET*             set,                /**< global SCIP settings */
13249    SCIP_PROB*            prob                /**< problem data */
13250    )
13251 {
13252    assert(lp != NULL);
13253    assert(lp->pseudoobjvalinf >= 0);
13254    assert(set != NULL);
13255 
13256    if( lp->pseudoobjvalinf > 0 || set->nactivepricers > 0 )
13257       return -SCIPsetInfinity(set);
13258    else
13259    {
13260       /* recalculate the pseudo solution value, if needed */
13261       if( !lp->pseudoobjvalid )
13262          recomputePseudoObjectiveValue(lp, set, prob);
13263 
13264       /* if the pseudo objective value is smaller than -infinity, we just return -infinity */
13265       if( SCIPsetIsInfinity(set, -lp->pseudoobjval) )
13266          return -SCIPsetInfinity(set);
13267 
13268       if( SCIPsetIsInfinity(set, lp->pseudoobjval) )
13269          return SCIPsetInfinity(set);
13270 
13271       return lp->pseudoobjval;
13272    }
13273 }
13274 
13275 /** gets pseudo objective value, if a bound of the given variable would be modified in the given way */
SCIPlpGetModifiedPseudoObjval(SCIP_LP * lp,SCIP_SET * set,SCIP_PROB * prob,SCIP_VAR * var,SCIP_Real oldbound,SCIP_Real newbound,SCIP_BOUNDTYPE boundtype)13276 SCIP_Real SCIPlpGetModifiedPseudoObjval(
13277    SCIP_LP*              lp,                 /**< current LP data */
13278    SCIP_SET*             set,                /**< global SCIP settings */
13279    SCIP_PROB*            prob,               /**< problem data */
13280    SCIP_VAR*             var,                /**< problem variable */
13281    SCIP_Real             oldbound,           /**< old value for bound */
13282    SCIP_Real             newbound,           /**< new value for bound */
13283    SCIP_BOUNDTYPE        boundtype           /**< type of bound: lower or upper bound */
13284    )
13285 {
13286    SCIP_Real pseudoobjval;
13287    int pseudoobjvalinf;
13288    SCIP_Real obj;
13289 
13290    pseudoobjval = getFinitePseudoObjval(lp, set, prob);
13291    pseudoobjvalinf = lp->pseudoobjvalinf;
13292    obj = SCIPvarGetObj(var);
13293    if( !SCIPsetIsZero(set, obj) && boundtype == SCIPvarGetBestBoundType(var) )
13294    {
13295       if( SCIPsetIsInfinity(set, REALABS(oldbound)) )
13296          pseudoobjvalinf--;
13297       else
13298          pseudoobjval -= oldbound * obj;
13299       assert(pseudoobjvalinf >= 0);
13300       if( SCIPsetIsInfinity(set, REALABS(newbound)) )
13301          pseudoobjvalinf++;
13302       else
13303          pseudoobjval += newbound * obj;
13304    }
13305    assert(pseudoobjvalinf >= 0);
13306 
13307    if( pseudoobjvalinf > 0 || set->nactivepricers > 0 )
13308       return -SCIPsetInfinity(set);
13309    else
13310       return pseudoobjval;
13311 }
13312 
13313 /** gets pseudo objective value, if a bound of the given variable would be modified in the given way;
13314  *  perform calculations with interval arithmetic to get an exact lower bound
13315  */
SCIPlpGetModifiedProvedPseudoObjval(SCIP_LP * lp,SCIP_SET * set,SCIP_VAR * var,SCIP_Real oldbound,SCIP_Real newbound,SCIP_BOUNDTYPE boundtype)13316 SCIP_Real SCIPlpGetModifiedProvedPseudoObjval(
13317    SCIP_LP*              lp,                 /**< current LP data */
13318    SCIP_SET*             set,                /**< global SCIP settings */
13319    SCIP_VAR*             var,                /**< problem variable */
13320    SCIP_Real             oldbound,           /**< old value for bound */
13321    SCIP_Real             newbound,           /**< new value for bound */
13322    SCIP_BOUNDTYPE        boundtype           /**< type of bound: lower or upper bound */
13323    )
13324 {
13325    SCIP_Real pseudoobjval;
13326    int pseudoobjvalinf;
13327    SCIP_Real obj;
13328 
13329    assert(lp->pseudoobjvalid);
13330 
13331    pseudoobjval = lp->pseudoobjval;
13332    pseudoobjvalinf = lp->pseudoobjvalinf;
13333    obj = SCIPvarGetObj(var);
13334    if( !SCIPsetIsZero(set, obj) && boundtype == SCIPvarGetBestBoundType(var) )
13335    {
13336       SCIP_INTERVAL objint;
13337       SCIP_INTERVAL bd;
13338       SCIP_INTERVAL prod;
13339       SCIP_INTERVAL psval;
13340 
13341       SCIPintervalSet(&psval, pseudoobjval);
13342       SCIPintervalSet(&objint, SCIPvarGetObj(var));
13343 
13344       if( SCIPsetIsInfinity(set, REALABS(oldbound)) )
13345          pseudoobjvalinf--;
13346       else
13347       {
13348          SCIPintervalSet(&bd, oldbound);
13349          SCIPintervalMul(SCIPsetInfinity(set), &prod, bd, objint);
13350          SCIPintervalSub(SCIPsetInfinity(set), &psval, psval, prod);
13351       }
13352       assert(pseudoobjvalinf >= 0);
13353       if( SCIPsetIsInfinity(set, REALABS(newbound)) )
13354          pseudoobjvalinf++;
13355       else
13356       {
13357          SCIPintervalSet(&bd, newbound);
13358          SCIPintervalMul(SCIPsetInfinity(set), &prod, bd, objint);
13359          SCIPintervalAdd(SCIPsetInfinity(set), &psval, psval, prod);
13360       }
13361 
13362       pseudoobjval = SCIPintervalGetInf(psval);
13363    }
13364    assert(pseudoobjvalinf >= 0);
13365 
13366    if( pseudoobjvalinf > 0 || set->nactivepricers > 0 )
13367       return -SCIPsetInfinity(set);
13368    else
13369       return pseudoobjval;
13370 }
13371 
13372 /** compute the objective delta due the new objective coefficient */
13373 static
getObjvalDeltaObj(SCIP_SET * set,SCIP_Real oldobj,SCIP_Real newobj,SCIP_Real lb,SCIP_Real ub,SCIP_Real * deltaval,int * deltainf)13374 void getObjvalDeltaObj(
13375    SCIP_SET*             set,                /**< global SCIP settings */
13376    SCIP_Real             oldobj,             /**< old objective value of variable */
13377    SCIP_Real             newobj,             /**< new objective value of variable */
13378    SCIP_Real             lb,                 /**< lower bound of variable */
13379    SCIP_Real             ub,                 /**< upper bound of variable */
13380    SCIP_Real*            deltaval,           /**< pointer to store the delta value */
13381    int*                  deltainf            /**< pointer to store the number of variables with infinite best bound */
13382    )
13383 {
13384    assert(!SCIPsetIsInfinity(set, REALABS(oldobj)));
13385    assert(!SCIPsetIsInfinity(set, REALABS(newobj)));
13386    assert(!SCIPsetIsInfinity(set, lb));
13387    assert(!SCIPsetIsInfinity(set, -ub));
13388    assert(!SCIPsetIsEQ(set, oldobj, newobj));
13389 
13390    (*deltaval) = 0.0;
13391    (*deltainf) = 0;
13392 
13393    if( SCIPsetIsPositive(set, oldobj) )
13394    {
13395       /* sign of objective did not change */
13396       if( SCIPsetIsPositive(set, newobj) )
13397       {
13398          /* if the bound is finite, calculate the deltaval */
13399          if( !SCIPsetIsInfinity(set, -lb) )
13400             (*deltaval) = lb * (newobj - oldobj);
13401       }
13402       /* sign of objective did change, so the best bound does change */
13403       else if( SCIPsetIsNegative(set, newobj) )
13404       {
13405          if( SCIPsetIsInfinity(set, -lb) )
13406          {
13407             /* old best bound was infinite while new one is not */
13408             if( !SCIPsetIsInfinity(set, ub) )
13409             {
13410                (*deltainf) = -1;
13411                (*deltaval) = ub * newobj;
13412             }
13413          }
13414          else
13415          {
13416             /* new best bound is infinite while old one was not */
13417             if( SCIPsetIsInfinity(set, ub) )
13418             {
13419                (*deltainf) = 1;
13420                (*deltaval) = -lb * oldobj;
13421             }
13422             /* neither old nor new best bound is infinite, so just calculate the deltaval */
13423             else
13424             {
13425                (*deltaval) = (ub * newobj) - (lb * oldobj);
13426             }
13427          }
13428       }
13429       /* new objective is 0.0 */
13430       else
13431       {
13432          if( SCIPsetIsInfinity(set, -lb) )
13433             (*deltainf) = -1;
13434          else
13435             (*deltaval) = -lb * oldobj;
13436       }
13437    }
13438    else if( SCIPsetIsNegative(set, oldobj) )
13439    {
13440       /* sign of objective did not change */
13441       if( SCIPsetIsNegative(set, newobj) )
13442       {
13443          /* if the bound is finite, calculate the deltaval */
13444          if( !SCIPsetIsInfinity(set, ub) )
13445             (*deltaval) = ub * (newobj - oldobj);
13446       }
13447       /* sign of objective did change, so the best bound does change */
13448       else if( SCIPsetIsPositive(set, newobj) )
13449       {
13450          if( SCIPsetIsInfinity(set, ub) )
13451          {
13452             /* old best bound was infinite while new one is not */
13453             if( !SCIPsetIsInfinity(set, -lb) )
13454             {
13455                (*deltainf) = -1;
13456                (*deltaval) = lb * newobj;
13457             }
13458          }
13459          else
13460          {
13461             /* new best bound is infinite while old one was not */
13462             if( SCIPsetIsInfinity(set, -lb) )
13463             {
13464                (*deltainf) = 1;
13465                (*deltaval) = -ub * oldobj;
13466             }
13467             /* neither old nor new best bound is infinite, so just calculate the deltaval */
13468             else
13469             {
13470                (*deltaval) = (lb * newobj) - (ub * oldobj);
13471             }
13472          }
13473       }
13474       /* new objective is 0.0 */
13475       else
13476       {
13477          if( SCIPsetIsInfinity(set, ub) )
13478             (*deltainf) = -1;
13479          else
13480             (*deltaval) = -ub * oldobj;
13481       }
13482    }
13483    /* old objective was 0.0 */
13484    else
13485    {
13486       if( SCIPsetIsNegative(set, newobj) )
13487       {
13488          if( SCIPsetIsInfinity(set, ub) )
13489             (*deltainf) = 1;
13490          else
13491             (*deltaval) = ub * newobj;
13492       }
13493       else if( SCIPsetIsPositive(set, newobj) )
13494       {
13495          if( SCIPsetIsInfinity(set, -lb) )
13496             (*deltainf) = 1;
13497          else
13498             (*deltaval) = lb * newobj;
13499       }
13500    }
13501 }
13502 
13503 /** compute the objective delta due the new lower bound */
13504 static
getObjvalDeltaLb(SCIP_SET * set,SCIP_Real obj,SCIP_Real oldlb,SCIP_Real newlb,SCIP_Real * deltaval,int * deltainf)13505 void getObjvalDeltaLb(
13506    SCIP_SET*             set,                /**< global SCIP settings */
13507    SCIP_Real             obj,                /**< objective value of variable */
13508    SCIP_Real             oldlb,              /**< old lower bound of variable */
13509    SCIP_Real             newlb,              /**< new lower bound of variable */
13510    SCIP_Real*            deltaval,           /**< pointer to store the delta value */
13511    int*                  deltainf            /**< pointer to store the number of variables with infinite best bound */
13512    )
13513 {
13514    assert(!SCIPsetIsInfinity(set, REALABS(obj)));
13515    assert(!SCIPsetIsInfinity(set, oldlb));
13516    assert(!SCIPsetIsInfinity(set, -oldlb) || !SCIPsetIsInfinity(set, -newlb));
13517    assert(SCIPsetIsPositive(set, obj)); /* we only need to update if the objective is positive */
13518 
13519    if( SCIPsetIsInfinity(set, -oldlb) )
13520    {
13521       if( !SCIPsetIsInfinity(set, newlb) )
13522       {
13523          (*deltainf) = -1;
13524          (*deltaval) = newlb * obj;
13525       }
13526       else
13527       {
13528          (*deltainf) = 0;
13529          (*deltaval) = 0.0;
13530       }
13531    }
13532    else if( SCIPsetIsInfinity(set, REALABS(newlb)) )
13533    {
13534       (*deltainf) = 1;
13535       (*deltaval) = -oldlb * obj;
13536    }
13537    else
13538    {
13539       (*deltainf) = 0;
13540       (*deltaval) = obj * (newlb - oldlb);
13541    }
13542 }
13543 
13544 /** compute the objective delta due the new upper bound */
13545 static
getObjvalDeltaUb(SCIP_SET * set,SCIP_Real obj,SCIP_Real oldub,SCIP_Real newub,SCIP_Real * deltaval,int * deltainf)13546 void getObjvalDeltaUb(
13547    SCIP_SET*             set,                /**< global SCIP settings */
13548    SCIP_Real             obj,                /**< objective value of variable */
13549    SCIP_Real             oldub,              /**< old upper bound of variable */
13550    SCIP_Real             newub,              /**< new upper bound of variable */
13551    SCIP_Real*            deltaval,           /**< pointer to store the delta value */
13552    int*                  deltainf            /**< pointer to store the number of variables with infinite best bound */
13553    )
13554 {
13555    assert(!SCIPsetIsInfinity(set, REALABS(obj)));
13556    assert(!SCIPsetIsInfinity(set, -oldub));
13557    assert(!SCIPsetIsInfinity(set, oldub) || !SCIPsetIsInfinity(set, newub));
13558    assert(SCIPsetIsNegative(set, obj)); /* we only need to update if the objective is negative */
13559 
13560    if( SCIPsetIsInfinity(set, oldub) )
13561    {
13562       if( !SCIPsetIsInfinity(set, -newub) )
13563       {
13564          (*deltainf) = -1;
13565          (*deltaval) = newub * obj;
13566       }
13567       else
13568       {
13569          (*deltainf) = 0;
13570          (*deltaval) = 0.0;
13571       }
13572    }
13573    else if( SCIPsetIsInfinity(set, REALABS(newub)) )
13574    {
13575       (*deltainf) = 1;
13576       (*deltaval) = -oldub * obj;
13577    }
13578    else
13579    {
13580       (*deltainf) = 0;
13581       (*deltaval) = obj * (newub - oldub);
13582    }
13583 }
13584 
13585 /** updates current pseudo and loose objective values for a change in a variable's objective value or bounds */
13586 static
lpUpdateObjval(SCIP_LP * lp,SCIP_SET * set,SCIP_VAR * var,SCIP_Real deltaval,int deltainf,SCIP_Bool local,SCIP_Bool loose,SCIP_Bool global)13587 void lpUpdateObjval(
13588    SCIP_LP*              lp,                 /**< current LP data */
13589    SCIP_SET*             set,                /**< global SCIP settings */
13590    SCIP_VAR*             var,                /**< problem variable that changed */
13591    SCIP_Real             deltaval,           /**< delta value in the objective function */
13592    int                   deltainf,           /**< delta value for the number of variables with infinite best bound */
13593    SCIP_Bool             local,              /**< should the local pseudo objective value be updated? */
13594    SCIP_Bool             loose,              /**< should the loose objective value be updated? */
13595    SCIP_Bool             global              /**< should the global pseudo objective value be updated? */
13596    )
13597 {
13598    assert(lp != NULL);
13599    assert(lp->looseobjvalinf >= 0);
13600    assert(lp->pseudoobjvalinf >= 0);
13601    assert(lp->glbpseudoobjvalinf >= 0);
13602 
13603    /* update the pseudo objective value */
13604    if( local )
13605    {
13606       lp->pseudoobjvalinf += deltainf;
13607       if( lp->pseudoobjvalid )
13608       {
13609          lp->pseudoobjval += deltaval;
13610 
13611          /* if the absolute value was increased, this is regarded as reliable,
13612           * otherwise, we check whether we can still trust the updated value
13613           */
13614          if( REALABS(lp->relpseudoobjval) < REALABS(lp->pseudoobjval) )
13615             lp->relpseudoobjval = lp->pseudoobjval;
13616          else if( SCIPsetIsUpdateUnreliable(set, lp->pseudoobjval, lp->relpseudoobjval) )
13617             lp->pseudoobjvalid = FALSE;
13618       }
13619 
13620       /* after changing a local bound on a LOOSE variable, we have to update the loose objective value, too */
13621       if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE )
13622          loose = TRUE;
13623    }
13624    /* update the loose objective value */
13625    if( loose )
13626    {
13627       lp->looseobjvalinf += deltainf;
13628 
13629       if( deltaval != 0.0 && lp->looseobjvalid )
13630       {
13631          lp->looseobjval += deltaval;
13632 
13633          /* if the absolute value was increased, this is regarded as reliable,
13634           * otherwise, we check whether we can still trust the updated value
13635           */
13636          if( REALABS(lp->rellooseobjval) < REALABS(lp->looseobjval) )
13637             lp->rellooseobjval = lp->looseobjval;
13638          else if( SCIPsetIsUpdateUnreliable(set, lp->looseobjval, lp->rellooseobjval) )
13639             lp->looseobjvalid = FALSE;
13640       }
13641    }
13642    /* update the root pseudo objective values */
13643    if( global )
13644    {
13645       lp->glbpseudoobjvalinf += deltainf;
13646       if( lp->glbpseudoobjvalid )
13647       {
13648          lp->glbpseudoobjval += deltaval;
13649 
13650          /* if the absolute value was increased, this is regarded as reliable,
13651           * otherwise, we check whether we can still trust the updated value
13652           */
13653          if( REALABS(lp->relglbpseudoobjval) < REALABS(lp->glbpseudoobjval) )
13654             lp->relglbpseudoobjval = lp->glbpseudoobjval;
13655          else if( SCIPsetIsUpdateUnreliable(set, lp->glbpseudoobjval, lp->relglbpseudoobjval) )
13656             lp->glbpseudoobjvalid = FALSE;
13657       }
13658    }
13659 
13660    assert(lp->looseobjvalinf >= 0);
13661    assert(lp->pseudoobjvalinf >= 0);
13662    assert(lp->glbpseudoobjvalinf >= 0);
13663 }
13664 
13665 /** updates current pseudo and loose objective values for a change in a variable's objective value or bounds;
13666  *  pseudo objective value is calculated with interval arithmetics to get a proved lower bound
13667  */
13668 static
lpUpdateVarProved(SCIP_LP * lp,SCIP_SET * set,SCIP_VAR * var,SCIP_Real oldobj,SCIP_Real oldlb,SCIP_Real oldub,SCIP_Real newobj,SCIP_Real newlb,SCIP_Real newub)13669 SCIP_RETCODE lpUpdateVarProved(
13670    SCIP_LP*              lp,                 /**< current LP data */
13671    SCIP_SET*             set,                /**< global SCIP settings */
13672    SCIP_VAR*             var,                /**< problem variable that changed */
13673    SCIP_Real             oldobj,             /**< old objective value of variable */
13674    SCIP_Real             oldlb,              /**< old objective value of variable */
13675    SCIP_Real             oldub,              /**< old objective value of variable */
13676    SCIP_Real             newobj,             /**< new objective value of variable */
13677    SCIP_Real             newlb,              /**< new objective value of variable */
13678    SCIP_Real             newub               /**< new objective value of variable */
13679    )
13680 {
13681    SCIP_INTERVAL deltaval;
13682    SCIP_INTERVAL bd;
13683    SCIP_INTERVAL obj;
13684    SCIP_INTERVAL prod;
13685    SCIP_INTERVAL psval;
13686    int deltainf;
13687 
13688    assert(lp != NULL);
13689    assert(lp->pseudoobjvalinf >= 0);
13690    assert(lp->looseobjvalinf >= 0);
13691    assert(!SCIPsetIsInfinity(set, REALABS(oldobj)));
13692    assert(!SCIPsetIsInfinity(set, oldlb));
13693    assert(!SCIPsetIsInfinity(set, -oldub));
13694    assert(!SCIPsetIsInfinity(set, REALABS(newobj)));
13695    assert(!SCIPsetIsInfinity(set, newlb));
13696    assert(!SCIPsetIsInfinity(set, -newub));
13697    assert(var != NULL);
13698 
13699    if( SCIPvarGetStatus(var) != SCIP_VARSTATUS_LOOSE && SCIPvarGetStatus(var) != SCIP_VARSTATUS_COLUMN )
13700    {
13701       SCIPerrorMessage("LP was informed of an objective change of a non-active variable\n");
13702       return SCIP_INVALIDDATA;
13703    }
13704 
13705    assert(SCIPvarGetProbindex(var) >= 0);
13706 
13707    SCIPintervalSet(&deltaval, 0.0);
13708    deltainf = 0;
13709 
13710    /* subtract old pseudo objective value */
13711    if( oldobj > 0.0 )
13712    {
13713       if( SCIPsetIsInfinity(set, -oldlb) )
13714          deltainf--;
13715       else
13716       {
13717          SCIPintervalSet(&bd, oldlb);
13718          SCIPintervalSet(&obj, oldobj);
13719          SCIPintervalMul(SCIPsetInfinity(set), &prod, bd, obj);
13720          SCIPintervalSub(SCIPsetInfinity(set), &deltaval, deltaval, prod);  /* deltaval -= oldlb * oldobj; */
13721       }
13722    }
13723    else if( oldobj < 0.0 )
13724    {
13725       if( SCIPsetIsInfinity(set, oldub) )
13726          deltainf--;
13727       else
13728       {
13729          SCIPintervalSet(&bd, oldub);
13730          SCIPintervalSet(&obj, oldobj);
13731          SCIPintervalMul(SCIPsetInfinity(set), &prod, bd, obj);
13732          SCIPintervalSub(SCIPsetInfinity(set), &deltaval, deltaval, prod);  /* deltaval -= oldub * oldobj; */
13733       }
13734    }
13735 
13736    /* add new pseudo objective value */
13737    if( newobj > 0.0 )
13738    {
13739       if( SCIPsetIsInfinity(set, -newlb) )
13740          deltainf++;
13741       else
13742       {
13743          SCIPintervalSet(&bd, newlb);
13744          SCIPintervalSet(&obj, newobj);
13745          SCIPintervalMul(SCIPsetInfinity(set), &prod, bd, obj);
13746          SCIPintervalAdd(SCIPsetInfinity(set), &deltaval, deltaval, prod);  /* deltaval += newlb * newobj; */
13747       }
13748    }
13749    else if( newobj < 0.0 )
13750    {
13751       if( SCIPsetIsInfinity(set, newub) )
13752          deltainf++;
13753       else
13754       {
13755          SCIPintervalSet(&bd, newub);
13756          SCIPintervalSet(&obj, newobj);
13757          SCIPintervalMul(SCIPsetInfinity(set), &prod, bd, obj);
13758          SCIPintervalAdd(SCIPsetInfinity(set), &deltaval, deltaval, prod);  /* deltaval += newub * newobj; */
13759       }
13760    }
13761 
13762    /* update the pseudo and loose objective values */
13763    SCIPintervalSet(&psval, lp->pseudoobjval);
13764    SCIPintervalAdd(SCIPsetInfinity(set), &psval, psval, deltaval);
13765    lp->pseudoobjval = SCIPintervalGetInf(psval);
13766    lp->pseudoobjvalinf += deltainf;
13767    if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE )
13768    {
13769       SCIPintervalSet(&psval, lp->looseobjval);
13770       SCIPintervalAdd(SCIPsetInfinity(set), &psval, psval, deltaval);
13771       lp->looseobjval = SCIPintervalGetInf(psval);
13772       lp->looseobjvalinf += deltainf;
13773    }
13774 
13775    assert(lp->pseudoobjvalinf >= 0);
13776    assert(lp->looseobjvalinf >= 0);
13777 
13778    return SCIP_OKAY;
13779 }
13780 
13781 /** updates current pseudo and loose objective value for a change in a variable's objective coefficient */
SCIPlpUpdateVarObj(SCIP_LP * lp,SCIP_SET * set,SCIP_VAR * var,SCIP_Real oldobj,SCIP_Real newobj)13782 SCIP_RETCODE SCIPlpUpdateVarObj(
13783    SCIP_LP*              lp,                 /**< current LP data */
13784    SCIP_SET*             set,                /**< global SCIP settings */
13785    SCIP_VAR*             var,                /**< problem variable that changed */
13786    SCIP_Real             oldobj,             /**< old objective coefficient of variable */
13787    SCIP_Real             newobj              /**< new objective coefficient of variable */
13788    )
13789 {
13790    assert(set != NULL);
13791    assert(var != NULL);
13792 
13793    if( set->misc_exactsolve )
13794    {
13795       if( oldobj != newobj ) /*lint !e777*/
13796       {
13797          SCIP_CALL( lpUpdateVarProved(lp, set, var, oldobj, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var),
13798                newobj, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) );
13799       }
13800    }
13801    else
13802    {
13803       if( !SCIPsetIsEQ(set, oldobj, newobj) )
13804       {
13805          SCIP_Real deltaval;
13806          int deltainf;
13807 
13808          assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
13809          assert(SCIPvarGetProbindex(var) >= 0);
13810 
13811          /* the objective coefficient can only be changed during presolving, that implies that the global and local
13812           * domain of the variable are the same
13813           */
13814          assert(lp->probing || SCIPsetIsEQ(set, SCIPvarGetLbGlobal(var), SCIPvarGetLbLocal(var)));
13815          assert(lp->probing || SCIPsetIsEQ(set, SCIPvarGetUbGlobal(var), SCIPvarGetUbLocal(var)));
13816 
13817          /* compute the pseudo objective delta due the new objective coefficient */
13818          getObjvalDeltaObj(set, oldobj, newobj, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), &deltaval, &deltainf);
13819 
13820          /* update the local pseudo objective value */
13821          lpUpdateObjval(lp, set, var, deltaval, deltainf, TRUE, FALSE, FALSE);
13822 
13823          /* compute the pseudo objective delta due the new objective coefficient */
13824          getObjvalDeltaObj(set, oldobj, newobj, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), &deltaval, &deltainf);
13825 
13826          /* update the global pseudo objective value */
13827          lpUpdateObjval(lp, set, var, deltaval, deltainf, FALSE, FALSE, TRUE);
13828       }
13829    }
13830 
13831    return SCIP_OKAY;
13832 }
13833 
13834 
13835 /** updates current root pseudo objective value for a global change in a variable's lower bound */
SCIPlpUpdateVarLbGlobal(SCIP_LP * lp,SCIP_SET * set,SCIP_VAR * var,SCIP_Real oldlb,SCIP_Real newlb)13836 SCIP_RETCODE SCIPlpUpdateVarLbGlobal(
13837    SCIP_LP*              lp,                 /**< current LP data */
13838    SCIP_SET*             set,                /**< global SCIP settings */
13839    SCIP_VAR*             var,                /**< problem variable that changed */
13840    SCIP_Real             oldlb,              /**< old lower bound of variable */
13841    SCIP_Real             newlb               /**< new lower bound of variable */
13842    )
13843 {
13844    assert(set != NULL);
13845    assert(var != NULL);
13846 
13847    if( !SCIPsetIsEQ(set, oldlb, newlb) && SCIPsetIsPositive(set, SCIPvarGetObj(var)) )
13848    {
13849       SCIP_Real deltaval;
13850       int deltainf;
13851 
13852       /* compute the pseudo objective delta due the new lower bound */
13853       getObjvalDeltaLb(set, SCIPvarGetObj(var), oldlb, newlb, &deltaval, &deltainf);
13854 
13855       /* update the root pseudo objective values */
13856       lpUpdateObjval(lp, set, var, deltaval, deltainf, FALSE, FALSE, TRUE);
13857    }
13858 
13859    return SCIP_OKAY;
13860 }
13861 
13862 /** updates current pseudo and loose objective value for a change in a variable's lower bound */
SCIPlpUpdateVarLb(SCIP_LP * lp,SCIP_SET * set,SCIP_VAR * var,SCIP_Real oldlb,SCIP_Real newlb)13863 SCIP_RETCODE SCIPlpUpdateVarLb(
13864    SCIP_LP*              lp,                 /**< current LP data */
13865    SCIP_SET*             set,                /**< global SCIP settings */
13866    SCIP_VAR*             var,                /**< problem variable that changed */
13867    SCIP_Real             oldlb,              /**< old lower bound of variable */
13868    SCIP_Real             newlb               /**< new lower bound of variable */
13869    )
13870 {
13871    assert(set != NULL);
13872    assert(var != NULL);
13873 
13874    if( set->misc_exactsolve )
13875    {
13876       if( oldlb != newlb && SCIPvarGetObj(var) > 0.0 ) /*lint !e777*/
13877       {
13878          SCIP_CALL( lpUpdateVarProved(lp, set, var, SCIPvarGetObj(var), oldlb, SCIPvarGetUbLocal(var),
13879                SCIPvarGetObj(var), newlb, SCIPvarGetUbLocal(var)) );
13880       }
13881    }
13882    else
13883    {
13884       if( !SCIPsetIsEQ(set, oldlb, newlb) && SCIPsetIsPositive(set, SCIPvarGetObj(var)) )
13885       {
13886          SCIP_Real deltaval;
13887          int deltainf;
13888 
13889          assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
13890          assert(SCIPvarGetProbindex(var) >= 0);
13891 
13892          /* compute the pseudo objective delta due the new lower bound */
13893          getObjvalDeltaLb(set, SCIPvarGetObj(var), oldlb, newlb, &deltaval, &deltainf);
13894 
13895          /* update the pseudo and loose objective values */
13896          lpUpdateObjval(lp, set, var, deltaval, deltainf, TRUE, FALSE, FALSE);
13897       }
13898    }
13899 
13900    return SCIP_OKAY;
13901 }
13902 
13903 /** updates current root pseudo objective value for a global change in a variable's upper bound */
SCIPlpUpdateVarUbGlobal(SCIP_LP * lp,SCIP_SET * set,SCIP_VAR * var,SCIP_Real oldub,SCIP_Real newub)13904 SCIP_RETCODE SCIPlpUpdateVarUbGlobal(
13905    SCIP_LP*              lp,                 /**< current LP data */
13906    SCIP_SET*             set,                /**< global SCIP settings */
13907    SCIP_VAR*             var,                /**< problem variable that changed */
13908    SCIP_Real             oldub,              /**< old upper bound of variable */
13909    SCIP_Real             newub               /**< new upper bound of variable */
13910    )
13911 {
13912    assert(set != NULL);
13913    assert(var != NULL);
13914 
13915    if( !SCIPsetIsEQ(set, oldub, newub) && SCIPsetIsNegative(set, SCIPvarGetObj(var)) )
13916    {
13917       SCIP_Real deltaval;
13918       int deltainf;
13919 
13920       /* compute the pseudo objective delta due the new upper bound */
13921       getObjvalDeltaUb(set, SCIPvarGetObj(var), oldub, newub, &deltaval, &deltainf);
13922 
13923       /* update the root pseudo objective values */
13924       lpUpdateObjval(lp, set, var, deltaval, deltainf, FALSE, FALSE, TRUE);
13925    }
13926 
13927    return SCIP_OKAY;
13928 }
13929 
13930 /** updates current pseudo objective value for a change in a variable's upper bound */
SCIPlpUpdateVarUb(SCIP_LP * lp,SCIP_SET * set,SCIP_VAR * var,SCIP_Real oldub,SCIP_Real newub)13931 SCIP_RETCODE SCIPlpUpdateVarUb(
13932    SCIP_LP*              lp,                 /**< current LP data */
13933    SCIP_SET*             set,                /**< global SCIP settings */
13934    SCIP_VAR*             var,                /**< problem variable that changed */
13935    SCIP_Real             oldub,              /**< old upper bound of variable */
13936    SCIP_Real             newub               /**< new upper bound of variable */
13937    )
13938 {
13939    assert(set != NULL);
13940    assert(var != NULL);
13941 
13942    if( set->misc_exactsolve )
13943    {
13944       if( oldub != newub && SCIPvarGetObj(var) < 0.0 ) /*lint !e777*/
13945       {
13946          SCIP_CALL( lpUpdateVarProved(lp, set, var, SCIPvarGetObj(var), SCIPvarGetLbLocal(var), oldub,
13947                SCIPvarGetObj(var), SCIPvarGetLbLocal(var), newub) );
13948       }
13949    }
13950    else
13951    {
13952       if( !SCIPsetIsEQ(set, oldub, newub) && SCIPsetIsNegative(set, SCIPvarGetObj(var)) )
13953       {
13954          SCIP_Real deltaval;
13955          int deltainf;
13956 
13957          assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
13958          assert(SCIPvarGetProbindex(var) >= 0);
13959 
13960          /* compute the pseudo objective delta due the new upper bound */
13961          getObjvalDeltaUb(set, SCIPvarGetObj(var), oldub, newub, &deltaval, &deltainf);
13962 
13963          /* update the pseudo and loose objective values */
13964          lpUpdateObjval(lp, set, var, deltaval, deltainf, TRUE, FALSE, FALSE);
13965       }
13966    }
13967 
13968    return SCIP_OKAY;
13969 }
13970 
13971 /** informs LP, that given variable was added to the problem */
SCIPlpUpdateAddVar(SCIP_LP * lp,SCIP_SET * set,SCIP_VAR * var)13972 SCIP_RETCODE SCIPlpUpdateAddVar(
13973    SCIP_LP*              lp,                 /**< current LP data */
13974    SCIP_SET*             set,                /**< global SCIP settings */
13975    SCIP_VAR*             var                 /**< variable that is now a LOOSE problem variable */
13976    )
13977 {
13978    assert(lp != NULL);
13979    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
13980    assert(SCIPvarGetProbindex(var) >= 0);
13981 
13982    /* add the variable to the loose objective value sum */
13983    SCIP_CALL( SCIPlpUpdateVarObj(lp, set, var, 0.0, SCIPvarGetObj(var)) );
13984 
13985    /* update the loose variables counter */
13986    if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE )
13987       lp->nloosevars++;
13988 
13989    return SCIP_OKAY;
13990 }
13991 
13992 /** informs LP, that given variable is to be deleted from the problem */
SCIPlpUpdateDelVar(SCIP_LP * lp,SCIP_SET * set,SCIP_VAR * var)13993 SCIP_RETCODE SCIPlpUpdateDelVar(
13994    SCIP_LP*              lp,                 /**< current LP data */
13995    SCIP_SET*             set,                /**< global SCIP settings */
13996    SCIP_VAR*             var                 /**< variable that will be deleted from the problem */
13997    )
13998 {
13999    assert(lp != NULL);
14000    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
14001    assert(SCIPvarGetProbindex(var) >= 0);
14002 
14003    /* subtract the variable from the loose objective value sum */
14004    SCIP_CALL( SCIPlpUpdateVarObj(lp, set, var, SCIPvarGetObj(var), 0.0) );
14005 
14006    /* update the loose variables counter */
14007    if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE )
14008    {
14009       SCIPlpDecNLoosevars(lp);
14010    }
14011 
14012    return SCIP_OKAY;
14013 }
14014 
14015 /** informs LP, that given formerly loose problem variable is now a column variable */
14016 static
lpUpdateVarColumn(SCIP_LP * lp,SCIP_SET * set,SCIP_VAR * var)14017 SCIP_RETCODE lpUpdateVarColumn(
14018    SCIP_LP*              lp,                 /**< current LP data */
14019    SCIP_SET*             set,                /**< global SCIP settings */
14020    SCIP_VAR*             var                 /**< problem variable that changed from LOOSE to COLUMN */
14021    )
14022 {
14023    SCIP_Real obj;
14024    SCIP_Real lb;
14025    SCIP_Real ub;
14026 
14027    assert(lp != NULL);
14028    assert(lp->nloosevars > 0);
14029    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
14030    assert(SCIPvarGetProbindex(var) >= 0);
14031    assert(lp->looseobjvalinf >= 0);
14032 
14033    obj = SCIPvarGetObj(var);
14034 
14035    /* update loose objective value */
14036    if( SCIPsetIsPositive(set, obj) )
14037    {
14038       lb = SCIPvarGetLbLocal(var);
14039       if( SCIPsetIsInfinity(set, -lb) )
14040          lp->looseobjvalinf--;
14041       else
14042          lpUpdateObjval(lp, set, var, -lb * obj, 0, FALSE, TRUE, FALSE);
14043    }
14044    else if( SCIPsetIsNegative(set, obj) )
14045    {
14046       ub = SCIPvarGetUbLocal(var);
14047       if( SCIPsetIsInfinity(set, ub) )
14048          lp->looseobjvalinf--;
14049       else
14050          lpUpdateObjval(lp, set, var, -ub * obj, 0, FALSE, TRUE, FALSE);
14051    }
14052 
14053    SCIPlpDecNLoosevars(lp);
14054 
14055    assert(lp->looseobjvalinf >= 0);
14056 
14057    return SCIP_OKAY;
14058 }
14059 
14060 /** informs LP, that given formerly loose problem variable is now a column variable
14061  *  pseudo objective value is calculated with interval arithmetics to get a proved lower bound
14062  */
14063 static
lpUpdateVarColumnProved(SCIP_LP * lp,SCIP_SET * set,SCIP_VAR * var)14064 SCIP_RETCODE lpUpdateVarColumnProved(
14065    SCIP_LP*              lp,                 /**< current LP data */
14066    SCIP_SET*             set,                /**< global SCIP settings */
14067    SCIP_VAR*             var                 /**< problem variable that changed from LOOSE to COLUMN */
14068    )
14069 {
14070    SCIP_INTERVAL bd;
14071    SCIP_INTERVAL ob;
14072    SCIP_INTERVAL prod;
14073    SCIP_INTERVAL loose;
14074    SCIP_Real obj;
14075    SCIP_Real lb;
14076    SCIP_Real ub;
14077 
14078    assert(lp != NULL);
14079    assert(lp->nloosevars > 0);
14080    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
14081    assert(SCIPvarGetProbindex(var) >= 0);
14082 
14083    obj = SCIPvarGetObj(var);
14084 
14085    SCIPintervalSet(&loose, lp->looseobjval);
14086 
14087    /* update loose objective value corresponding to the deletion of variable */
14088    if( obj > 0.0 )
14089    {
14090       lb = SCIPvarGetLbLocal(var);
14091       if( SCIPsetIsInfinity(set, -lb) )
14092          lp->looseobjvalinf--;
14093       else
14094       {
14095          SCIPintervalSet(&bd, lb);
14096          SCIPintervalSet(&ob, obj);
14097          SCIPintervalMul(SCIPsetInfinity(set), &prod, bd, ob);
14098          SCIPintervalSub(SCIPsetInfinity(set), &loose, loose, prod);  /* lp->looseobjval -= lb * obj; */
14099       }
14100    }
14101    else if( SCIPsetIsNegative(set, obj) )
14102    {
14103       ub = SCIPvarGetUbLocal(var);
14104       if( SCIPsetIsInfinity(set, ub) )
14105          lp->looseobjvalinf--;
14106       else
14107       {
14108          SCIPintervalSet(&bd, ub);
14109          SCIPintervalSet(&ob, obj);
14110          SCIPintervalMul(SCIPsetInfinity(set), &prod, bd, ob);
14111          SCIPintervalSub(SCIPsetInfinity(set), &loose, loose, prod);  /* lp->looseobjval -= ub * obj; */
14112       }
14113    }
14114    lp->nloosevars--;
14115 
14116    /* get rid of numerical problems: set loose objective value explicitly to zero, if no loose variables remain */
14117    if( lp->nloosevars == 0 )
14118    {
14119       assert(lp->looseobjvalinf == 0);
14120       lp->looseobjval = 0.0;
14121    }
14122    else
14123       lp->looseobjval = SCIPintervalGetInf(loose);
14124 
14125    return SCIP_OKAY;
14126 }
14127 
14128 /** informs LP, that given formerly loose problem variable is now a column variable */
SCIPlpUpdateVarColumn(SCIP_LP * lp,SCIP_SET * set,SCIP_VAR * var)14129 SCIP_RETCODE SCIPlpUpdateVarColumn(
14130    SCIP_LP*              lp,                 /**< current LP data */
14131    SCIP_SET*             set,                /**< global SCIP settings */
14132    SCIP_VAR*             var                 /**< problem variable that changed from LOOSE to COLUMN */
14133    )
14134 {
14135    assert(set != NULL);
14136 
14137    if( set->misc_exactsolve )
14138    {
14139       SCIP_CALL( lpUpdateVarColumnProved(lp, set, var) );
14140    }
14141    else
14142    {
14143       SCIP_CALL( lpUpdateVarColumn(lp, set, var) );
14144    }
14145 
14146    return SCIP_OKAY;
14147 }
14148 
14149 /** informs LP, that given formerly column problem variable is now again a loose variable */
14150 static
lpUpdateVarLoose(SCIP_LP * lp,SCIP_SET * set,SCIP_VAR * var)14151 SCIP_RETCODE lpUpdateVarLoose(
14152    SCIP_LP*              lp,                 /**< current LP data */
14153    SCIP_SET*             set,                /**< global SCIP settings */
14154    SCIP_VAR*             var                 /**< problem variable that changed from COLUMN to LOOSE */
14155    )
14156 {
14157    SCIP_Real obj;
14158    SCIP_Real lb;
14159    SCIP_Real ub;
14160 
14161    assert(lp != NULL);
14162    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE);
14163    assert(SCIPvarGetProbindex(var) >= 0);
14164    assert(lp->looseobjvalinf >= 0);
14165 
14166    obj = SCIPvarGetObj(var);
14167 
14168    /* update loose objective value corresponding to the addition of variable */
14169    if( SCIPsetIsPositive(set, obj) )
14170    {
14171       lb = SCIPvarGetLbLocal(var);
14172       if( SCIPsetIsInfinity(set, -lb) )
14173          lp->looseobjvalinf++;
14174       else
14175          lpUpdateObjval(lp, set, var, lb * obj, 0, FALSE, TRUE, FALSE);
14176    }
14177    else if( SCIPsetIsNegative(set, obj) )
14178    {
14179       ub = SCIPvarGetUbLocal(var);
14180       if( SCIPsetIsInfinity(set, ub) )
14181          lp->looseobjvalinf++;
14182       else
14183          lpUpdateObjval(lp, set, var, ub * obj, 0, FALSE, TRUE, FALSE);
14184    }
14185    lp->nloosevars++;
14186 
14187    assert(lp->looseobjvalinf >= 0);
14188 
14189    return SCIP_OKAY;
14190 }
14191 
14192 /** informs LP, that given formerly column problem variable is now again a loose variable
14193  *  pseudo objective value is calculated with interval arithmetics to get a proved lower bound
14194  */
14195 static
lpUpdateVarLooseProved(SCIP_LP * lp,SCIP_SET * set,SCIP_VAR * var)14196 SCIP_RETCODE lpUpdateVarLooseProved(
14197    SCIP_LP*              lp,                 /**< current LP data */
14198    SCIP_SET*             set,                /**< global SCIP settings */
14199    SCIP_VAR*             var                 /**< problem variable that changed from COLUMN to LOOSE */
14200    )
14201 {
14202    SCIP_INTERVAL bd;
14203    SCIP_INTERVAL ob;
14204    SCIP_INTERVAL prod;
14205    SCIP_INTERVAL loose;
14206    SCIP_Real obj;
14207    SCIP_Real lb;
14208    SCIP_Real ub;
14209 
14210    assert(lp != NULL);
14211    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE);
14212    assert(SCIPvarGetProbindex(var) >= 0);
14213 
14214    obj = SCIPvarGetObj(var);
14215 
14216    SCIPintervalSet(&loose, lp->looseobjval);
14217 
14218    /* update loose objective value corresponding to the deletion of variable */
14219    if( obj > 0.0 )
14220    {
14221       lb = SCIPvarGetLbLocal(var);
14222       if( SCIPsetIsInfinity(set, -lb) )
14223          lp->looseobjvalinf++;
14224       else
14225       {
14226          SCIPintervalSet(&bd, lb);
14227          SCIPintervalSet(&ob, obj);
14228          SCIPintervalMul(SCIPsetInfinity(set), &prod, bd, ob);
14229          SCIPintervalAdd(SCIPsetInfinity(set), &loose, loose, prod);  /* lp->looseobjval += lb * obj; */
14230       }
14231    }
14232    else if( SCIPsetIsNegative(set, obj) )
14233    {
14234       ub = SCIPvarGetUbLocal(var);
14235       if( SCIPsetIsInfinity(set, ub) )
14236          lp->looseobjvalinf++;
14237       else
14238       {
14239          SCIPintervalSet(&bd, ub);
14240          SCIPintervalSet(&ob, obj);
14241          SCIPintervalMul(SCIPsetInfinity(set), &prod, bd, ob);
14242          SCIPintervalAdd(SCIPsetInfinity(set), &loose, loose, prod);  /* lp->looseobjval += ub * obj; */
14243       }
14244    }
14245    lp->nloosevars++;
14246 
14247    lp->looseobjval = SCIPintervalGetInf(loose);
14248 
14249    return SCIP_OKAY;
14250 }
14251 
14252 /** informs LP, that given formerly column problem variable is now again a loose variable */
SCIPlpUpdateVarLoose(SCIP_LP * lp,SCIP_SET * set,SCIP_VAR * var)14253 SCIP_RETCODE SCIPlpUpdateVarLoose(
14254    SCIP_LP*              lp,                 /**< current LP data */
14255    SCIP_SET*             set,                /**< global SCIP settings */
14256    SCIP_VAR*             var                 /**< problem variable that changed from COLUMN to LOOSE */
14257    )
14258 {
14259    assert(set != NULL);
14260 
14261    if( set->misc_exactsolve )
14262    {
14263       SCIP_CALL( lpUpdateVarLooseProved(lp, set, var) );
14264    }
14265    else
14266    {
14267       SCIP_CALL( lpUpdateVarLoose(lp, set, var) );
14268    }
14269 
14270    return SCIP_OKAY;
14271 }
14272 
14273 /** decrease the number of loose variables by one */
SCIPlpDecNLoosevars(SCIP_LP * lp)14274 void SCIPlpDecNLoosevars(
14275    SCIP_LP*              lp                  /**< current LP data */
14276    )
14277 {
14278    assert(lp != NULL);
14279    assert(lp->nloosevars > 0);
14280 
14281    lp->nloosevars--;
14282 
14283    /* get rid of numerical problems: set loose objective value explicitly to zero, if no loose variables remain */
14284    if( lp->nloosevars == 0 )
14285    {
14286       assert(lp->looseobjvalinf == 0);
14287       lp->looseobjval = 0.0;
14288    }
14289 }
14290 
14291 /** stores the LP solution in the columns and rows */
SCIPlpGetSol(SCIP_LP * lp,SCIP_SET * set,SCIP_STAT * stat,SCIP_Bool * primalfeasible,SCIP_Bool * dualfeasible)14292 SCIP_RETCODE SCIPlpGetSol(
14293    SCIP_LP*              lp,                 /**< current LP data */
14294    SCIP_SET*             set,                /**< global SCIP settings */
14295    SCIP_STAT*            stat,               /**< problem statistics */
14296    SCIP_Bool*            primalfeasible,     /**< pointer to store whether the solution is primal feasible, or NULL */
14297    SCIP_Bool*            dualfeasible        /**< pointer to store whether the solution is dual feasible, or NULL */
14298    )
14299 {
14300    SCIP_COL** lpicols;
14301    SCIP_ROW** lpirows;
14302    SCIP_Real* primsol;
14303    SCIP_Real* dualsol;
14304    SCIP_Real* activity;
14305    SCIP_Real* redcost;
14306    SCIP_Real primalbound;
14307    SCIP_Real dualbound;
14308    SCIP_Bool stillprimalfeasible;
14309    SCIP_Bool stilldualfeasible;
14310    int* cstat;
14311    int* rstat;
14312    SCIP_Longint lpcount;
14313    int nlpicols;
14314    int nlpirows;
14315    int c;
14316    int r;
14317 
14318    assert(lp != NULL);
14319    assert(lp->flushed);
14320    assert(lp->solved);
14321    assert(set != NULL);
14322    assert(stat != NULL);
14323    assert(lp->validsollp <= stat->lpcount);
14324 
14325    /* initialize return and feasibility flags; if primal oder dual feasibility shall not be checked, we set the
14326     * corresponding flag immediately to FALSE to skip all checks
14327     */
14328    if( primalfeasible == NULL )
14329       stillprimalfeasible = FALSE;
14330    else
14331    {
14332       *primalfeasible = TRUE;
14333       stillprimalfeasible = TRUE;
14334    }
14335    if( dualfeasible == NULL )
14336       stilldualfeasible = FALSE;
14337    else
14338    {
14339       *dualfeasible = TRUE;
14340       stilldualfeasible = TRUE;
14341    }
14342 
14343    /* check if the values are already calculated */
14344    if( lp->validsollp == stat->lpcount )
14345       return SCIP_OKAY;
14346    lp->validsollp = stat->lpcount;
14347 
14348    SCIPsetDebugMsg(set, "getting new LP solution %" SCIP_LONGINT_FORMAT " for solstat %d\n",
14349       stat->lpcount, SCIPlpGetSolstat(lp));
14350 
14351    lpicols = lp->lpicols;
14352    lpirows = lp->lpirows;
14353    nlpicols = lp->nlpicols;
14354    nlpirows = lp->nlpirows;
14355    lpcount = stat->lpcount;
14356 
14357    /* get temporary memory */
14358    SCIP_CALL( SCIPsetAllocBufferArray(set, &primsol, nlpicols) );
14359    SCIP_CALL( SCIPsetAllocBufferArray(set, &dualsol, nlpirows) );
14360    SCIP_CALL( SCIPsetAllocBufferArray(set, &activity, nlpirows) );
14361    SCIP_CALL( SCIPsetAllocBufferArray(set, &redcost, nlpicols) );
14362    SCIP_CALL( SCIPsetAllocBufferArray(set, &cstat, nlpicols) );
14363    SCIP_CALL( SCIPsetAllocBufferArray(set, &rstat, nlpirows) );
14364 
14365    SCIP_CALL( SCIPlpiGetSol(lp->lpi, NULL, primsol, dualsol, activity, redcost) );
14366    if( lp->solisbasic )
14367    {
14368       SCIP_CALL( SCIPlpiGetBase(lp->lpi, cstat, rstat) );
14369    }
14370    else
14371    {
14372       BMSclearMemoryArray(cstat, nlpicols);
14373       BMSclearMemoryArray(rstat, nlpirows);
14374    }
14375 
14376    primalbound = 0.0;
14377    dualbound = 0.0;
14378 
14379    /* copy primal solution and reduced costs into columns */
14380    for( c = 0; c < nlpicols; ++c )
14381    {
14382       assert( 0 <= cstat[c] && cstat[c] < 4 );
14383       lpicols[c]->primsol = primsol[c];
14384       lpicols[c]->minprimsol = MIN(lpicols[c]->minprimsol, primsol[c]);
14385       lpicols[c]->maxprimsol = MAX(lpicols[c]->maxprimsol, primsol[c]);
14386       lpicols[c]->redcost = redcost[c];
14387       lpicols[c]->basisstatus = (unsigned int) cstat[c];
14388       lpicols[c]->validredcostlp = lpcount;
14389       if( stillprimalfeasible )
14390       {
14391          stillprimalfeasible =
14392             (SCIPsetIsInfinity(set, -lpicols[c]->lb) || !SCIPsetIsFeasNegative(set, lpicols[c]->primsol - lpicols[c]->lb))
14393             && (SCIPsetIsInfinity(set, lpicols[c]->ub) || !SCIPsetIsFeasPositive(set, lpicols[c]->primsol - lpicols[c]->ub));
14394          primalbound += (lpicols[c]->primsol * lpicols[c]->obj);
14395       }
14396       if( lp->lastlpalgo == SCIP_LPALGO_BARRIER )
14397       {
14398          double compslack;
14399 
14400          /* complementary slackness in barrier solutions is measured as product of primal slack and dual multiplier;
14401           * we use a slack of at most 1, because otherwise we multiply by something like SCIPinfinty() for unbounded
14402           * variables, which would magnify even the tiniest violation in the dual multiplier
14403           */
14404          if( stilldualfeasible )
14405          {
14406             compslack = MIN((lpicols[c]->primsol - lpicols[c]->lb), 1.0) * lpicols[c]->redcost;
14407             stilldualfeasible = !SCIPsetIsDualfeasPositive(set, compslack);
14408          }
14409          if( stilldualfeasible )
14410          {
14411             compslack = MIN((lpicols[c]->ub - lpicols[c]->primsol), 1.0) * lpicols[c]->redcost;
14412             stilldualfeasible = !SCIPsetIsDualfeasNegative(set, compslack);
14413          }
14414 
14415          SCIPsetDebugMsg(set, " col <%s> [%.9g,%.9g]: primsol=%.9f, redcost=%.9f, pfeas=%u/%u(%u), dfeas=%d/%d(%u)\n",
14416             SCIPvarGetName(lpicols[c]->var), lpicols[c]->lb, lpicols[c]->ub, lpicols[c]->primsol, lpicols[c]->redcost,
14417             SCIPsetIsFeasGE(set, lpicols[c]->primsol, lpicols[c]->lb),
14418             SCIPsetIsFeasLE(set, lpicols[c]->primsol, lpicols[c]->ub),
14419             primalfeasible != NULL ? stillprimalfeasible : TRUE,
14420             !SCIPsetIsDualfeasPositive(set, MIN((lpicols[c]->primsol - lpicols[c]->lb), 1.0) * lpicols[c]->redcost),
14421             !SCIPsetIsDualfeasNegative(set, MIN((lpicols[c]->ub - lpicols[c]->primsol), 1.0) * lpicols[c]->redcost),
14422             dualfeasible != NULL ? stilldualfeasible : TRUE);
14423       }
14424       else
14425       {
14426          /* if dual feasibility check is disabled, set reduced costs of basic variables to 0 */
14427          if( dualfeasible == NULL && lpicols[c]->basisstatus == (unsigned int) SCIP_BASESTAT_BASIC )
14428          {
14429             lpicols[c]->redcost = 0.0;
14430          }
14431 
14432          /* complementary slackness means that if a variable is not at its lower or upper bound, its reduced costs
14433           * must be non-positive or non-negative, respectively; in particular, if a variable is strictly within its
14434           * bounds, its reduced cost must be zero
14435           */
14436          if( stilldualfeasible
14437             && (SCIPsetIsInfinity(set, -lpicols[c]->lb) || SCIPsetIsFeasGT(set, lpicols[c]->primsol, lpicols[c]->lb)) )
14438             stilldualfeasible = !SCIPsetIsDualfeasPositive(set, lpicols[c]->redcost);
14439          if( stilldualfeasible
14440             && (SCIPsetIsInfinity(set, lpicols[c]->ub) || SCIPsetIsFeasLT(set, lpicols[c]->primsol, lpicols[c]->ub)) )
14441             stilldualfeasible = !SCIPsetIsDualfeasNegative(set, lpicols[c]->redcost);
14442 
14443          SCIPsetDebugMsg(set, " col <%s> [%.9g,%.9g]: primsol=%.9f, redcost=%.9f, pfeas=%u/%u(%u), dfeas=%d/%d(%u)\n",
14444             SCIPvarGetName(lpicols[c]->var), lpicols[c]->lb, lpicols[c]->ub, lpicols[c]->primsol, lpicols[c]->redcost,
14445             SCIPsetIsFeasGE(set, lpicols[c]->primsol, lpicols[c]->lb),
14446             SCIPsetIsFeasLE(set, lpicols[c]->primsol, lpicols[c]->ub),
14447             primalfeasible != NULL ? stillprimalfeasible : TRUE,
14448             !SCIPsetIsFeasGT(set, lpicols[c]->primsol, lpicols[c]->lb) || !SCIPsetIsDualfeasPositive(set, lpicols[c]->redcost),
14449             !SCIPsetIsFeasLT(set, lpicols[c]->primsol, lpicols[c]->ub) || !SCIPsetIsDualfeasNegative(set, lpicols[c]->redcost),
14450             dualfeasible != NULL ? stilldualfeasible : TRUE);
14451       }
14452 
14453       /* we intentionally use an exact positive/negative check because ignoring small reduced cost values may lead to a
14454        * wrong bound value; if the corresponding bound is +/-infinity, we use zero reduced cost (if stilldualfeasible is
14455        * TRUE, we are in the case that the reduced cost is tiny with wrong sign)
14456        */
14457       if( stilldualfeasible )
14458       {
14459          if( lpicols[c]->redcost > 0.0 && !SCIPsetIsInfinity(set, -lpicols[c]->lb) )
14460             dualbound += (lpicols[c]->redcost * lpicols[c]->lb);
14461          else if( lpicols[c]->redcost < 0.0 && !SCIPsetIsInfinity(set, lpicols[c]->ub) )
14462             dualbound += (lpicols[c]->redcost * lpicols[c]->ub);
14463       }
14464    }
14465 
14466    /* copy dual solution and activities into rows */
14467    for( r = 0; r < nlpirows; ++r )
14468    {
14469       assert( 0 <= rstat[r] && rstat[r] < 4 );
14470       lpirows[r]->dualsol = dualsol[r];
14471       lpirows[r]->activity = activity[r] + lpirows[r]->constant;
14472       lpirows[r]->basisstatus = (unsigned int) rstat[r]; /*lint !e732*/
14473       lpirows[r]->validactivitylp = lpcount;
14474       if( stillprimalfeasible )
14475       {
14476          stillprimalfeasible =
14477             (SCIPsetIsInfinity(set,-lpirows[r]->lhs) ||SCIPsetIsFeasGE(set, lpirows[r]->activity, lpirows[r]->lhs))
14478             && (SCIPsetIsInfinity(set, lpirows[r]->rhs) || SCIPsetIsFeasLE(set, lpirows[r]->activity, lpirows[r]->rhs));
14479       }
14480       if( lp->lastlpalgo == SCIP_LPALGO_BARRIER )
14481       {
14482          double compslack;
14483 
14484          /* complementary slackness in barrier solutions is measured as product of primal slack and dual multiplier;
14485           * we use a slack of at most 1, because otherwise we multiply by something like SCIPinfinity() for unbounded
14486           * variables, which would magnify even the tiniest violation in the dual multiplier
14487           */
14488          if( stilldualfeasible )
14489          {
14490             compslack = MIN((lpirows[r]->activity - lpirows[r]->lhs), 1.0) * lpirows[r]->dualsol;
14491             stilldualfeasible = !SCIPsetIsDualfeasPositive(set, compslack);
14492          }
14493          if( stilldualfeasible )
14494          {
14495             compslack = MIN((lpirows[r]->rhs - lpirows[r]->activity), 1.0) * lpirows[r]->dualsol;
14496             stilldualfeasible = !SCIPsetIsDualfeasNegative(set, compslack);
14497          }
14498 
14499          SCIPsetDebugMsg(set, " row <%s> [%.9g,%.9g]: activity=%.9f, dualsol=%.9f, pfeas=%u/%u(%u), dfeas=%d/%d(%u)\n",
14500             lpirows[r]->name, lpirows[r]->lhs, lpirows[r]->rhs, lpirows[r]->activity, lpirows[r]->dualsol,
14501             SCIPsetIsFeasGE(set, lpirows[r]->activity, lpirows[r]->lhs),
14502             SCIPsetIsFeasLE(set, lpirows[r]->activity, lpirows[r]->rhs),
14503             primalfeasible != NULL ? stillprimalfeasible : TRUE,
14504             !SCIPsetIsDualfeasPositive(set, MIN((lpirows[r]->activity - lpirows[r]->lhs), 1.0) * lpirows[r]->dualsol),
14505             !SCIPsetIsDualfeasNegative(set, MIN((lpirows[r]->rhs - lpirows[r]->activity), 1.0) * lpirows[r]->dualsol),
14506             dualfeasible != NULL ? stilldualfeasible : TRUE);
14507       }
14508       else
14509       {
14510          /* complementary slackness means that if the activity of a row is not at its left-hand or right-hand side,
14511           * its dual multiplier must be non-positive or non-negative, respectively; in particular, if the activity is
14512           * strictly within left-hand and right-hand side, its dual multiplier must be zero
14513           */
14514          if( stilldualfeasible &&
14515                (SCIPsetIsInfinity(set, -lpirows[r]->lhs) || SCIPsetIsFeasGT(set, lpirows[r]->activity, lpirows[r]->lhs)) )
14516             stilldualfeasible = !SCIPsetIsDualfeasPositive(set, lpirows[r]->dualsol);
14517          if( stilldualfeasible &&
14518                (SCIPsetIsInfinity(set,lpirows[r]->rhs) || SCIPsetIsFeasLT(set, lpirows[r]->activity, lpirows[r]->rhs)) )
14519             stilldualfeasible = !SCIPsetIsDualfeasNegative(set, lpirows[r]->dualsol);
14520 
14521          SCIPsetDebugMsg(set, " row <%s> [%.9g,%.9g] + %.9g: activity=%.9f, dualsol=%.9f, pfeas=%u/%u(%u), dfeas=%d/%d(%u)\n",
14522             lpirows[r]->name, lpirows[r]->lhs, lpirows[r]->rhs, lpirows[r]->constant, lpirows[r]->activity, lpirows[r]->dualsol,
14523             SCIPsetIsFeasGE(set, lpirows[r]->activity, lpirows[r]->lhs),
14524             SCIPsetIsFeasLE(set, lpirows[r]->activity, lpirows[r]->rhs),
14525             primalfeasible != NULL ? stillprimalfeasible : TRUE,
14526             !SCIPsetIsFeasGT(set, lpirows[r]->activity, lpirows[r]->lhs) || !SCIPsetIsDualfeasPositive(set, lpirows[r]->dualsol),
14527             !SCIPsetIsFeasLT(set, lpirows[r]->activity, lpirows[r]->rhs) || !SCIPsetIsDualfeasNegative(set, lpirows[r]->dualsol),
14528             dualfeasible != NULL ? stilldualfeasible : TRUE);
14529       }
14530 
14531       /* we intentionally use an exact positive/negative check because ignoring small dual multipliers may lead to a
14532        * wrong bound value; if the corresponding side is +/-infinity, we use a zero dual multiplier (if
14533        * stilldualfeasible is TRUE, we are in the case that the dual multiplier is tiny with wrong sign)
14534        */
14535       if( stilldualfeasible )
14536       {
14537          if( lpirows[r]->dualsol > 0.0 && !SCIPsetIsInfinity(set, -lpirows[r]->lhs) )
14538             dualbound += (lpirows[r]->dualsol * (lpirows[r]->lhs - lpirows[r]->constant));
14539          else if( lpirows[r]->dualsol < 0.0 && !SCIPsetIsInfinity(set, lpirows[r]->rhs) )
14540             dualbound += (lpirows[r]->dualsol * (lpirows[r]->rhs - lpirows[r]->constant));
14541       }
14542    }
14543 
14544    /* if the objective value returned by the LP solver is smaller than the internally computed primal bound, then we
14545     * declare the solution primal infeasible; we assume primalbound and lp->lpobjval to be equal if they are both +/-
14546     * infinity
14547     */
14548    /**@todo alternatively, if otherwise the LP solution is feasible, we could simply update the objective value */
14549    if( stillprimalfeasible && !(SCIPsetIsInfinity(set, primalbound) && SCIPsetIsInfinity(set, lp->lpobjval))
14550       && !(SCIPsetIsInfinity(set, -primalbound) && SCIPsetIsInfinity(set, -lp->lpobjval)) )
14551    {
14552       stillprimalfeasible = SCIPsetIsFeasLE(set, primalbound, lp->lpobjval);
14553       SCIPsetDebugMsg(set, " primalbound=%.9f, lpbound=%.9g, pfeas=%u(%u)\n", primalbound, lp->lpobjval,
14554          SCIPsetIsFeasLE(set, primalbound, lp->lpobjval), primalfeasible != NULL ? stillprimalfeasible : TRUE);
14555    }
14556 
14557    /* if the objective value returned by the LP solver is smaller than the internally computed dual bound, we declare
14558     * the solution dual infeasible; we assume dualbound and lp->lpobjval to be equal if they are both +/- infinity
14559     */
14560    /**@todo alternatively, if otherwise the LP solution is feasible, we could simply update the objective value */
14561    if( stilldualfeasible && !(SCIPsetIsInfinity(set, dualbound) && SCIPsetIsInfinity(set, lp->lpobjval))
14562       && !(SCIPsetIsInfinity(set, -dualbound) && SCIPsetIsInfinity(set, -lp->lpobjval)) )
14563    {
14564       stilldualfeasible =  SCIPsetIsFeasGE(set, dualbound, lp->lpobjval);
14565       SCIPsetDebugMsg(set, " dualbound=%.9f, lpbound=%.9g, dfeas=%u(%u)\n", dualbound, lp->lpobjval,
14566          SCIPsetIsFeasGE(set, dualbound, lp->lpobjval), dualfeasible != NULL ? stilldualfeasible : TRUE);
14567    }
14568 
14569    if( primalfeasible != NULL )
14570       *primalfeasible = stillprimalfeasible;
14571    if( dualfeasible != NULL )
14572       *dualfeasible = stilldualfeasible;
14573 
14574    /* free temporary memory */
14575    SCIPsetFreeBufferArray(set, &rstat);
14576    SCIPsetFreeBufferArray(set, &cstat);
14577    SCIPsetFreeBufferArray(set, &redcost);
14578    SCIPsetFreeBufferArray(set, &activity);
14579    SCIPsetFreeBufferArray(set, &dualsol);
14580    SCIPsetFreeBufferArray(set, &primsol);
14581 
14582    return SCIP_OKAY;
14583 }
14584 
14585 /** stores LP solution with infinite objective value in the columns and rows */
SCIPlpGetUnboundedSol(SCIP_LP * lp,SCIP_SET * set,SCIP_STAT * stat,SCIP_Bool * primalfeasible,SCIP_Bool * rayfeasible)14586 SCIP_RETCODE SCIPlpGetUnboundedSol(
14587    SCIP_LP*              lp,                 /**< current LP data */
14588    SCIP_SET*             set,                /**< global SCIP settings */
14589    SCIP_STAT*            stat,               /**< problem statistics */
14590    SCIP_Bool*            primalfeasible,     /**< pointer to store whether the solution is primal feasible, or NULL */
14591    SCIP_Bool*            rayfeasible         /**< pointer to store whether the primal ray is a feasible unboundedness proof, or NULL */
14592    )
14593 {
14594    SCIP_COL** lpicols;
14595    SCIP_ROW** lpirows;
14596    SCIP_Real* primsol;
14597    SCIP_Real* activity;
14598    SCIP_Real* ray;
14599    SCIP_Real rayobjval;
14600    SCIP_Real rayscale;
14601    SCIP_Longint lpcount;
14602    SCIP_COL* col;
14603    int nlpicols;
14604    int nlpirows;
14605    int c;
14606    int r;
14607 
14608    assert(lp != NULL);
14609    assert(lp->flushed);
14610    assert(lp->solved);
14611    assert(lp->lpsolstat == SCIP_LPSOLSTAT_UNBOUNDEDRAY);
14612    assert(SCIPsetIsInfinity(set, -lp->lpobjval));
14613    assert(set != NULL);
14614    assert(stat != NULL);
14615    assert(lp->validsollp <= stat->lpcount);
14616 
14617    if( primalfeasible != NULL )
14618       *primalfeasible = TRUE;
14619    if( rayfeasible != NULL )
14620       *rayfeasible = TRUE;
14621 
14622    /* check if the values are already calculated */
14623    if( lp->validsollp == stat->lpcount )
14624       return SCIP_OKAY;
14625 
14626    /* check if the LP solver is able to provide a primal unbounded ray */
14627    if( !SCIPlpiHasPrimalRay(lp->lpi) )
14628    {
14629       SCIPerrorMessage("LP solver has no primal ray to prove unboundedness\n");
14630       return SCIP_LPERROR;
14631    }
14632 
14633    lp->validsollp = stat->lpcount;
14634 
14635    SCIPsetDebugMsg(set, "getting new unbounded LP solution %" SCIP_LONGINT_FORMAT "\n", stat->lpcount);
14636 
14637    /* get temporary memory */
14638    SCIP_CALL( SCIPsetAllocBufferArray(set, &primsol, lp->nlpicols) );
14639    SCIP_CALL( SCIPsetAllocBufferArray(set, &activity, lp->nlpirows) );
14640    SCIP_CALL( SCIPsetAllocBufferArray(set, &ray, lp->nlpicols) );
14641 
14642    /* get primal unbounded ray */
14643    SCIP_CALL( SCIPlpiGetPrimalRay(lp->lpi, ray) );
14644 
14645    lpicols = lp->lpicols;
14646    lpirows = lp->lpirows;
14647    nlpicols = lp->nlpicols;
14648    nlpirows = lp->nlpirows;
14649    lpcount = stat->lpcount;
14650 
14651    /* calculate the objective value decrease of the ray and heuristically try to construct primal solution */
14652    rayobjval = 0.0;
14653    for( c = 0; c < nlpicols; ++c )
14654    {
14655       assert(lpicols[c] != NULL);
14656       assert(lpicols[c]->var != NULL);
14657 
14658       col = lpicols[c];
14659 
14660       /* there should only be a nonzero value in the ray if there is no finite bound in this direction */
14661       if( rayfeasible != NULL )
14662       {
14663          *rayfeasible = *rayfeasible
14664             && (!SCIPsetIsNegative(set, ray[c]) || SCIPsetIsInfinity(set, -col->lb))
14665             && (!SCIPsetIsPositive(set, ray[c]) || SCIPsetIsInfinity(set,  col->ub));
14666       }
14667 
14668       if( ! SCIPsetIsZero(set, ray[c]) )
14669          rayobjval += ray[c] * col->obj;
14670 
14671       /* Many LP solvers cannot directly provide a feasible solution if they detected unboundedness. We therefore first
14672        * heuristically try to construct a primal solution.
14673        */
14674       primsol[c] = 0.0;
14675       if( SCIPsetIsFeasZero(set, ray[c]) )
14676       {
14677          /* if the ray component is 0, we try to satisfy as many rows as possible */
14678          if( SCIPvarGetNLocksDown(col->var) == 0 && ! SCIPsetIsInfinity(set, -col->lb) )
14679             primsol[c] = col->lb;
14680          else if( SCIPvarGetNLocksUp(col->var) == 0 && ! SCIPsetIsInfinity(set, col->ub) )
14681             primsol[c] = col->ub;
14682       }
14683 
14684       /* make sure we respect the bounds */
14685       primsol[c] = MAX(primsol[c], col->lb);
14686       primsol[c] = MIN(primsol[c], col->ub);
14687 
14688       assert( SCIPsetIsFeasGE(set, primsol[c], col->lb) && SCIPsetIsFeasGE(set, primsol[c], col->lb) );
14689    }
14690 
14691    /* check feasibility of heuristic solution and compute activity */
14692    for( r = 0; r < nlpirows; ++r )
14693    {
14694       SCIP_Real act = 0.0;
14695       SCIP_ROW* row;
14696 
14697       row = lpirows[r];
14698       assert( row != NULL );
14699 
14700       for( c = 0; c < row->nlpcols; ++c )
14701       {
14702          col = row->cols[c];
14703 
14704          assert( col != NULL );
14705          assert( col->lppos >= 0 );
14706          assert( row->linkpos[c] >= 0 );
14707          assert( primsol[col->lppos] < SCIP_INVALID );
14708 
14709          act += row->vals[c] * primsol[col->lppos];
14710       }
14711 
14712       if( row->nunlinked > 0 )
14713       {
14714          for( c = row->nlpcols; c < row->len; ++c )
14715          {
14716             col = row->cols[c];
14717 
14718             assert( col != NULL );
14719 
14720             if( col->lppos >= 0 )
14721                act += row->vals[c] * primsol[col->lppos];
14722          }
14723       }
14724 
14725       /* check feasibility */
14726       if( (! SCIPsetIsInfinity(set, -row->lhs) && SCIPsetIsFeasLT(set, act, row->lhs) ) ||
14727           (! SCIPsetIsInfinity(set, row->rhs)  && SCIPsetIsFeasGT(set, act, row->rhs) ) )
14728          break;
14729 
14730       activity[r] = act;
14731    }
14732 
14733    /* if heuristic solution is not feasible, try to obtain solution from LPI */
14734    if( r < nlpirows )
14735    {
14736       /* get primal feasible point */
14737       SCIP_CALL( SCIPlpiGetSol(lp->lpi, NULL, primsol, NULL, activity, NULL) );
14738 
14739       /* determine feasibility status */
14740       if( primalfeasible != NULL )
14741       {
14742          for( c = 0; c < nlpicols; ++c )
14743          {
14744             assert( lpicols[c] != NULL );
14745             assert( lpicols[c]->var != NULL );
14746 
14747             /* check primal feasibility of (finite) primal solution; note that the comparisons ensure that the primal
14748              * solution is within SCIP's infinity bounds; otherwise the rayscale below is not well-defined
14749              */
14750             *primalfeasible = *primalfeasible
14751                && !SCIPsetIsFeasNegative(set, primsol[c] - lpicols[c]->lb)
14752                && !SCIPsetIsFeasPositive(set, primsol[c] - lpicols[c]->ub);
14753          }
14754       }
14755    }
14756    else
14757    {
14758       if( primalfeasible != NULL )
14759          *primalfeasible = TRUE;
14760    }
14761 
14762    if( primalfeasible != NULL && !(*primalfeasible) )
14763    {
14764       /* if the finite point is already infeasible, we do not have to add the ray */
14765       rayscale = 0.0;
14766    }
14767    else if( rayfeasible != NULL && !(*rayfeasible) )
14768    {
14769       /* if the ray is already infeasible (due to numerics), we do not want to add the ray */
14770       rayscale = 0.0;
14771    }
14772    else if( !SCIPsetIsNegative(set, rayobjval) )
14773    {
14774       /* due to numerical problems, the objective of the ray might be nonnegative,
14775        *
14776        * @todo How to check for negative objective value here?
14777        */
14778       if( rayfeasible != NULL )
14779       {
14780          *rayfeasible = FALSE;
14781       }
14782 
14783       rayscale = 0.0;
14784    }
14785    else
14786    {
14787       assert(rayobjval != 0.0);
14788 
14789       /* scale the ray, such that the resulting point has infinite objective value */
14790       rayscale = -2*SCIPsetInfinity(set)/rayobjval;
14791       assert(SCIPsetIsFeasPositive(set, rayscale));
14792 
14793       /* ensure that unbounded point does not violate the bounds of the variables */
14794       for( c = 0; c < nlpicols; ++c )
14795       {
14796          if( SCIPsetIsPositive(set, ray[c]) )
14797          {
14798             if( !SCIPsetIsInfinity(set, primsol[c]) )
14799                rayscale = MIN(rayscale, (lpicols[c]->ub - primsol[c])/ray[c]);
14800             /* if the primsol is infinity, as well as the bound, don't scale the ray to 0 */
14801             else
14802             {
14803                assert(SCIPsetIsInfinity(set, lpicols[c]->ub));
14804                rayscale = MIN(rayscale, 1/ray[c]);
14805             }
14806          }
14807          else if( SCIPsetIsNegative(set, ray[c]) )
14808          {
14809             if( !SCIPsetIsInfinity(set, -primsol[c]) )
14810                rayscale = MIN(rayscale, (lpicols[c]->lb - primsol[c])/ray[c]);
14811             /* if the primsol is infinity, as well as the bound, don't scal the ray to 0 */
14812             else
14813             {
14814                assert(SCIPsetIsInfinity(set, -lpicols[c]->lb));
14815                rayscale = MIN(rayscale, -1/ray[c]);
14816             }
14817          }
14818 
14819          assert(SCIPsetIsFeasPositive(set, rayscale));
14820       }
14821    }
14822 
14823    SCIPsetDebugMsg(set, "unbounded LP solution: rayobjval=%f, rayscale=%f\n", rayobjval, rayscale);
14824 
14825    /* calculate the unbounded point: x' = x + rayscale * ray */
14826    for( c = 0; c < nlpicols; ++c )
14827    {
14828       if( SCIPsetIsZero(set, ray[c]) )
14829          lpicols[c]->primsol = primsol[c];
14830       else
14831       {
14832          SCIP_Real primsolval;
14833          primsolval = primsol[c] + rayscale * ray[c];
14834          lpicols[c]->primsol = MAX(-SCIPsetInfinity(set), MIN(SCIPsetInfinity(set), primsolval)); /*lint !e666*/
14835       }
14836       lpicols[c]->redcost = SCIP_INVALID;
14837       lpicols[c]->validredcostlp = -1;
14838    }
14839 
14840    /* transfer solution and check feasibility */
14841    for( r = 0; r < nlpirows; ++r )
14842    {
14843       lpirows[r]->dualsol = SCIP_INVALID;
14844       lpirows[r]->activity = activity[r] + lpirows[r]->constant;
14845       lpirows[r]->validactivitylp = lpcount;
14846 
14847       /* check for feasibility of the rows */
14848       if( primalfeasible != NULL )
14849          *primalfeasible = *primalfeasible
14850             && (SCIPsetIsInfinity(set, -lpirows[r]->lhs) || SCIPsetIsFeasGE(set, lpirows[r]->activity, lpirows[r]->lhs))
14851             && (SCIPsetIsInfinity(set, lpirows[r]->rhs) || SCIPsetIsFeasLE(set, lpirows[r]->activity, lpirows[r]->rhs));
14852    }
14853 
14854    /* free temporary memory */
14855    SCIPsetFreeBufferArray(set, &ray);
14856    SCIPsetFreeBufferArray(set, &activity);
14857    SCIPsetFreeBufferArray(set, &primsol);
14858 
14859    return SCIP_OKAY;
14860 }
14861 
14862 /** returns primal ray proving the unboundedness of the current LP */
SCIPlpGetPrimalRay(SCIP_LP * lp,SCIP_SET * set,SCIP_Real * ray)14863 SCIP_RETCODE SCIPlpGetPrimalRay(
14864    SCIP_LP*              lp,                 /**< current LP data */
14865    SCIP_SET*             set,                /**< global SCIP settings */
14866    SCIP_Real*            ray                 /**< array for storing primal ray values, they are stored w.r.t. the problem index of the variables,
14867                                               *   so the size of this array should be at least number of active variables
14868                                               *   (all entries have to be initialized to 0 before) */
14869    )
14870 {
14871    SCIP_COL** lpicols;
14872    SCIP_Real* lpiray;
14873    SCIP_VAR* var;
14874    int nlpicols;
14875    int c;
14876 
14877    assert(lp != NULL);
14878    assert(set != NULL);
14879    assert(ray != NULL);
14880    assert(lp->flushed);
14881    assert(lp->solved);
14882    assert(lp->lpsolstat == SCIP_LPSOLSTAT_UNBOUNDEDRAY);
14883    assert(SCIPsetIsInfinity(set, -lp->lpobjval));
14884 
14885    /* check if the LP solver is able to provide a primal unbounded ray */
14886    if( !SCIPlpiHasPrimalRay(lp->lpi) )
14887    {
14888       SCIPerrorMessage("LP solver has no primal ray for unbounded LP\n");
14889       return SCIP_LPERROR;
14890    }
14891 
14892    /* get temporary memory */
14893    SCIP_CALL( SCIPsetAllocBufferArray(set, &lpiray, lp->nlpicols) );
14894 
14895    SCIPsetDebugMsg(set, "getting primal ray values\n");
14896 
14897    /* get primal unbounded ray */
14898    SCIP_CALL( SCIPlpiGetPrimalRay(lp->lpi, lpiray) );
14899 
14900    lpicols = lp->lpicols;
14901    nlpicols = lp->nlpicols;
14902 
14903    /* store the ray values of active problem variables */
14904    for( c = 0; c < nlpicols; c++ )
14905    {
14906       assert(lpicols[c] != NULL);
14907 
14908       var = lpicols[c]->var;
14909       assert(var != NULL);
14910       assert(SCIPvarGetProbindex(var) != -1);
14911       ray[SCIPvarGetProbindex(var)] = lpiray[c];
14912    }
14913 
14914    SCIPsetFreeBufferArray(set, &lpiray);
14915 
14916    return SCIP_OKAY;
14917 }
14918 
14919 /** stores the dual Farkas multipliers for infeasibility proof in rows. besides, the proof is checked for validity if
14920  *  lp/checkfarkas = TRUE.
14921  *
14922  *  @note the check will not be performed if @p valid is NULL.
14923  */
SCIPlpGetDualfarkas(SCIP_LP * lp,SCIP_SET * set,SCIP_STAT * stat,SCIP_Bool * valid)14924 SCIP_RETCODE SCIPlpGetDualfarkas(
14925    SCIP_LP*              lp,                 /**< current LP data */
14926    SCIP_SET*             set,                /**< global SCIP settings */
14927    SCIP_STAT*            stat,               /**< problem statistics */
14928    SCIP_Bool*            valid               /**< pointer to store whether the Farkas proof is valid or NULL */
14929    )
14930 {
14931    SCIP_COL** lpicols;
14932    SCIP_ROW** lpirows;
14933    SCIP_Real* dualfarkas;
14934    SCIP_Real* farkascoefs;
14935    SCIP_Real farkaslhs;
14936    SCIP_Real maxactivity;
14937    SCIP_Bool checkfarkas;
14938    int nlpicols;
14939    int nlpirows;
14940    int c;
14941    int r;
14942 
14943    assert(lp != NULL);
14944    assert(lp->flushed);
14945    assert(lp->solved);
14946    assert(lp->lpsolstat == SCIP_LPSOLSTAT_INFEASIBLE);
14947    assert(set != NULL);
14948    assert(stat != NULL);
14949    assert(lp->validfarkaslp <= stat->lpcount);
14950 
14951    if( valid != NULL )
14952       *valid = TRUE;
14953 
14954    /* check if the values are already calculated */
14955    if( lp->validfarkaslp == stat->lpcount )
14956       return SCIP_OKAY;
14957    lp->validfarkaslp = stat->lpcount;
14958 
14959    farkascoefs = NULL;
14960    maxactivity = 0.0;
14961    farkaslhs = 0.0;
14962 
14963    checkfarkas = (set->lp_checkfarkas && valid != NULL);
14964 
14965    /* get temporary memory */
14966    SCIP_CALL( SCIPsetAllocBufferArray(set, &dualfarkas, lp->nlpirows) );
14967 
14968    if( checkfarkas )
14969    {
14970       SCIP_CALL( SCIPsetAllocBufferArray(set, &farkascoefs, lp->nlpicols) );
14971       BMSclearMemoryArray(farkascoefs, lp->nlpicols);
14972    }
14973 
14974    /* get dual Farkas infeasibility proof */
14975    SCIP_CALL( SCIPlpiGetDualfarkas(lp->lpi, dualfarkas) );
14976 
14977    lpicols = lp->lpicols;
14978    lpirows = lp->lpirows;
14979    nlpicols = lp->nlpicols;
14980    nlpirows = lp->nlpirows;
14981 
14982    /* store infeasibility proof in rows */
14983    SCIPsetDebugMsg(set, "LP is infeasible:\n");
14984    for( r = 0; r < nlpirows; ++r )
14985    {
14986       SCIPsetDebugMsg(set, " row <%s>: dualfarkas=%f\n", lpirows[r]->name, dualfarkas[r]);
14987       lpirows[r]->dualfarkas = dualfarkas[r];
14988       lpirows[r]->dualsol = SCIP_INVALID;
14989       lpirows[r]->activity = 0.0;
14990       lpirows[r]->validactivitylp = -1L;
14991       lpirows[r]->basisstatus = (unsigned int) SCIP_BASESTAT_BASIC;
14992 
14993       if( checkfarkas )
14994       {
14995          assert(farkascoefs != NULL);
14996 
14997          /* the infeasibility proof would be invalid if
14998           *   (i)  dualfarkas[r] > 0 and lhs = -inf
14999           *   (ii) dualfarkas[r] < 0 and rhs = inf
15000           * however, due to numerics we accept slightly negative / positive values
15001           */
15002          if( (SCIPsetIsDualfeasGT(set, dualfarkas[r], 0.0) && SCIPsetIsInfinity(set, -lpirows[r]->lhs))
15003             || (SCIPsetIsDualfeasLT(set, dualfarkas[r], 0.0) && SCIPsetIsInfinity(set, lpirows[r]->rhs)) )
15004          {
15005             SCIPsetDebugMsg(set, "farkas proof is invalid: row <%s>[lhs=%g,rhs=%g,c=%g] has multiplier %g\n",
15006                SCIProwGetName(lpirows[r]), lpirows[r]->lhs, lpirows[r]->rhs, lpirows[r]->constant, dualfarkas[r]);
15007 
15008             if( valid != NULL )
15009                *valid = FALSE;
15010 
15011             goto TERMINATE;
15012          }
15013 
15014          /* dual multipliers, for which the corresponding row side in infinite, are treated as zero if they are zero
15015           * within tolerances (see above) but slighty positive / negative
15016           */
15017          if( (dualfarkas[r] > 0.0 && SCIPsetIsInfinity(set, -lpirows[r]->lhs))
15018             || (dualfarkas[r] < 0.0 && SCIPsetIsInfinity(set, lpirows[r]->rhs)) )
15019             continue;
15020 
15021          /* iterate over all columns and scale with dual solution */
15022          for( c = 0; c < lpirows[r]->len; c++ )
15023          {
15024             int pos = SCIPcolGetLPPos(lpirows[r]->cols[c]);
15025 
15026             if( pos == -1 )
15027                continue;
15028 
15029             assert(pos >= 0 && pos < nlpicols);
15030 
15031             farkascoefs[pos] += dualfarkas[r] * lpirows[r]->vals[c];
15032          }
15033 
15034          /* the row contributes with its left-hand side to the proof */
15035          if( dualfarkas[r] > 0.0 )
15036          {
15037             assert(!SCIPsetIsInfinity(set, -lpirows[r]->lhs));
15038 
15039             farkaslhs += dualfarkas[r] * (lpirows[r]->lhs - lpirows[r]->constant);
15040          }
15041          /* the row contributes with its right-hand side to the proof */
15042          else if( dualfarkas[r] < 0.0 )
15043          {
15044             assert(!SCIPsetIsInfinity(set, lpirows[r]->rhs));
15045 
15046             farkaslhs += dualfarkas[r] * (lpirows[r]->rhs - lpirows[r]->constant);
15047          }
15048       }
15049    }
15050 
15051    /* set columns as invalid */
15052    for( c = 0; c < nlpicols; ++c )
15053    {
15054       lpicols[c]->primsol = SCIP_INVALID;
15055       lpicols[c]->redcost = SCIP_INVALID;
15056       lpicols[c]->validredcostlp = -1L;
15057       lpicols[c]->validfarkaslp = -1L;
15058 
15059       if( checkfarkas )
15060       {
15061          assert(farkascoefs != NULL);
15062          assert(SCIPcolGetLPPos(lpicols[c]) == c);
15063 
15064          /* skip coefficients that are too close to zero */
15065          if( SCIPsetIsFeasZero(set, farkascoefs[c]) )
15066             continue;
15067 
15068          /* calculate the maximal activity */
15069          if( farkascoefs[c] > 0.0 )
15070             maxactivity += farkascoefs[c] * SCIPcolGetUb(lpicols[c]);
15071          else
15072             maxactivity += farkascoefs[c] * SCIPcolGetLb(lpicols[c]);
15073       }
15074    }
15075 
15076    /* check whether the farkasproof is valid
15077     * due to numerics, it might happen that the left-hand side of the aggregation is larger/smaller or equal than +/- infinity.
15078     * in that case, we declare the Farkas proof to be invalid.
15079     */
15080    if( checkfarkas && (SCIPsetIsInfinity(set, REALABS(farkaslhs)) || SCIPsetIsGE(set, maxactivity, farkaslhs)) )
15081    {
15082       SCIPsetDebugMsg(set, "farkas proof is invalid: maxactivity=%.12f, lhs=%.12f\n", maxactivity, farkaslhs);
15083 
15084       if( valid != NULL )
15085          *valid = FALSE;
15086    }
15087 
15088   TERMINATE:
15089    /* free temporary memory */
15090    if( checkfarkas )
15091       SCIPsetFreeBufferArray(set, &farkascoefs);
15092 
15093    SCIPsetFreeBufferArray(set, &dualfarkas);
15094 
15095    return SCIP_OKAY;
15096 }
15097 
15098 /** get number of iterations used in last LP solve */
SCIPlpGetIterations(SCIP_LP * lp,int * iterations)15099 SCIP_RETCODE SCIPlpGetIterations(
15100    SCIP_LP*              lp,                 /**< current LP data */
15101    int*                  iterations          /**< pointer to store the iteration count */
15102    )
15103 {
15104    assert(lp != NULL);
15105 
15106    SCIP_CALL( SCIPlpiGetIterations(lp->lpi, iterations) );
15107 
15108    return SCIP_OKAY;
15109 }
15110 
15111 /** increases age of columns with solution value 0.0 and basic rows with activity not at its bounds,
15112  *  resets age of non-zero columns and sharp rows
15113  */
SCIPlpUpdateAges(SCIP_LP * lp,SCIP_STAT * stat)15114 SCIP_RETCODE SCIPlpUpdateAges(
15115    SCIP_LP*              lp,                 /**< current LP data */
15116    SCIP_STAT*            stat                /**< problem statistics */
15117    )
15118 {
15119    SCIP_COL** lpicols;
15120    SCIP_ROW** lpirows;
15121    int nlpicols;
15122    int nlpirows;
15123    int c;
15124    int r;
15125 
15126    assert(lp != NULL);
15127    assert(lp->flushed);
15128    assert(lp->solved);
15129    assert(lp->nlpicols == lp->ncols);
15130    assert(lp->nlpirows == lp->nrows);
15131    assert(stat != NULL);
15132    assert(lp->validsollp == stat->lpcount);
15133 
15134    SCIPdebugMessage("updating LP ages\n");
15135 
15136    lpicols = lp->lpicols;
15137    lpirows = lp->lpirows;
15138    nlpicols = lp->nlpicols;
15139    nlpirows = lp->nlpirows;
15140 
15141    for( c = 0; c < nlpicols; ++c )
15142    {
15143       assert(lpicols[c] == lp->cols[c]);
15144       if( lpicols[c]->primsol == 0.0 )  /* non-basic columns to remove are exactly at 0.0 */
15145          lpicols[c]->age++;
15146       else
15147          lpicols[c]->age = 0;
15148       /*SCIPstatDebugMsg(stat, " -> col <%s>: primsol=%f, age=%d\n",
15149         SCIPvarGetName(lpicols[c]->var), lpicols[c]->primsol, lpicols[c]->age);*/
15150    }
15151 
15152    for( r = 0; r < nlpirows; ++r )
15153    {
15154       lpirows[r]->nlpsaftercreation++;
15155       assert(lpirows[r] == lp->rows[r]);
15156 
15157       if( lpirows[r]->dualsol == 0.0 ) /* basic rows to remove are exactly at 0.0 */
15158       {
15159          lpirows[r]->age++;
15160       }
15161       else
15162       {
15163          lpirows[r]->activeinlpcounter++;
15164          lpirows[r]->age = 0;
15165       }
15166       /*debugMsg(scip, " -> row <%s>: activity=%f, age=%d\n", lpirows[r]->name, lpirows[r]->activity, lpirows[r]->age);*/
15167    }
15168 
15169    return SCIP_OKAY;
15170 }
15171 
15172 /* deletes the marked columns from the LP and the LP interface */
15173 static
lpDelColset(SCIP_LP * lp,SCIP_SET * set,int * coldstat)15174 SCIP_RETCODE lpDelColset(
15175    SCIP_LP*              lp,                 /**< current LP data */
15176    SCIP_SET*             set,                /**< global SCIP settings */
15177    int*                  coldstat            /**< deletion status of columns:  1 if column should be deleted, 0 if not */
15178    )
15179 {
15180    SCIP_COL* col;
15181    int ncols;
15182    int c;
15183 
15184    assert(lp != NULL);
15185    assert(lp->flushed);
15186    assert(lp->ncols == lp->nlpicols);
15187    assert(!lp->diving);
15188    assert(coldstat != NULL);
15189    assert(lp->nlazycols <= lp->ncols);
15190 
15191    ncols = lp->ncols;
15192 
15193    /* delete columns in LP solver */
15194    SCIP_CALL( SCIPlpiDelColset(lp->lpi, coldstat) );
15195 
15196    /* update LP data respectively */
15197    for( c = 0; c < ncols; ++c )
15198    {
15199       col = lp->cols[c];
15200       assert(col != NULL);
15201       assert(col == lp->lpicols[c]);
15202       assert(coldstat[c] <= c);
15203       col->lppos = coldstat[c];
15204       if( coldstat[c] == -1 )
15205       {
15206          assert(col->removable);
15207 
15208          /* mark column to be deleted from the LPI, update column arrays of all linked rows, and update the objective
15209           * function vector norms
15210           */
15211          markColDeleted(col);
15212          colUpdateDelLP(col, set);
15213          lpUpdateObjNorms(lp, set, col->unchangedobj, 0.0);
15214          col->lpdepth = -1;
15215 
15216          lp->cols[c] = NULL;
15217          lp->lpicols[c] = NULL;
15218          lp->ncols--;
15219          lp->nremovablecols--;
15220          lp->nlpicols--;
15221       }
15222       else if( coldstat[c] < c )
15223       {
15224          assert(lp->cols[coldstat[c]] == NULL);
15225          assert(lp->lpicols[coldstat[c]] == NULL);
15226          lp->cols[coldstat[c]] = col;
15227          lp->lpicols[coldstat[c]] = col;
15228          lp->cols[coldstat[c]]->lppos = coldstat[c];
15229          lp->cols[coldstat[c]]->lpipos = coldstat[c];
15230          lp->cols[c] = NULL;
15231          lp->lpicols[c] = NULL;
15232       }
15233    }
15234 
15235    /* remove columns which are deleted from the lazy column array */
15236    c = 0;
15237    while( c < lp->nlazycols )
15238    {
15239       if( lp->lazycols[c]->lpipos < 0 )
15240       {
15241          lp->lazycols[c] = lp->lazycols[lp->nlazycols-1];
15242          lp->nlazycols--;
15243       }
15244       else
15245          c++;
15246    }
15247 
15248    /* mark LP to be unsolved */
15249    if( lp->ncols < ncols )
15250    {
15251       assert(lp->ncols == lp->nlpicols);
15252       assert(lp->nchgcols == 0);
15253       assert(lp->flushed);
15254 
15255       lp->lpifirstchgcol = lp->nlpicols;
15256 
15257       /* mark the current solution invalid */
15258       lp->solved = FALSE;
15259       lp->primalfeasible = FALSE;
15260       lp->primalchecked = FALSE;
15261       lp->lpobjval = SCIP_INVALID;
15262       lp->lpsolstat = SCIP_LPSOLSTAT_NOTSOLVED;
15263    }
15264 
15265    checkLazyColArray(lp, set);
15266    checkLinks(lp);
15267 
15268    return SCIP_OKAY;
15269 }
15270 
15271 /* deletes the marked rows from the LP and the LP interface */
15272 static
lpDelRowset(SCIP_LP * lp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_EVENTFILTER * eventfilter,int * rowdstat)15273 SCIP_RETCODE lpDelRowset(
15274    SCIP_LP*              lp,                 /**< current LP data */
15275    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
15276    SCIP_SET*             set,                /**< global SCIP settings */
15277    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
15278    SCIP_EVENTFILTER*     eventfilter,        /**< global event filter */
15279    int*                  rowdstat            /**< deletion status of rows:  1 if row should be deleted, 0 if not */
15280    )
15281 {
15282    SCIP_ROW* row;
15283    int nrows;
15284    int r;
15285 
15286    assert(lp != NULL);
15287    assert(lp->flushed);
15288    assert(lp->nrows == lp->nlpirows);
15289    assert(!lp->diving);
15290    assert(rowdstat != NULL);
15291 
15292    nrows = lp->nrows;
15293 
15294    /* delete rows in LP solver */
15295    SCIP_CALL( SCIPlpiDelRowset(lp->lpi, rowdstat) );
15296 
15297    /* update LP data respectively */
15298    for( r = 0; r < nrows; ++r )
15299    {
15300       row = lp->rows[r];
15301       assert(row == lp->lpirows[r]);
15302       assert(rowdstat[r] <= r);
15303       assert(row != NULL);
15304       row->lppos = rowdstat[r];
15305       if( rowdstat[r] == -1 )
15306       {
15307          if( row->removable )
15308             lp->nremovablerows--;
15309 
15310          /* mark row to be deleted from the LPI and update row arrays of all linked columns */
15311          markRowDeleted(row);
15312          rowUpdateDelLP(row);
15313          row->lpdepth = -1;
15314 
15315          /* check, if row deletion events are tracked
15316           * if so, issue ROWDELETEDLP event
15317           */
15318          if( eventfilter->len > 0 && (eventfilter->eventmask & SCIP_EVENTTYPE_ROWDELETEDLP) != 0 )
15319          {
15320             SCIP_EVENT* event;
15321 
15322             SCIP_CALL( SCIPeventCreateRowDeletedLP(&event, blkmem, row) );
15323             SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, eventfilter, &event) );
15324          }
15325 
15326          SCIP_CALL( SCIProwRelease(&lp->lpirows[r], blkmem, set, lp) );
15327          SCIProwUnlock(lp->rows[r]);
15328          SCIP_CALL( SCIProwRelease(&lp->rows[r], blkmem, set, lp) );
15329          assert(lp->lpirows[r] == NULL);
15330          assert(lp->rows[r] == NULL);
15331          lp->nrows--;
15332          lp->nlpirows--;
15333       }
15334       else if( rowdstat[r] < r )
15335       {
15336          assert(lp->rows[rowdstat[r]] == NULL);
15337          assert(lp->lpirows[rowdstat[r]] == NULL);
15338          lp->rows[rowdstat[r]] = row;
15339          lp->lpirows[rowdstat[r]] = row;
15340          lp->rows[rowdstat[r]]->lppos = rowdstat[r];
15341          lp->rows[rowdstat[r]]->lpipos = rowdstat[r];
15342          lp->rows[r] = NULL;
15343          lp->lpirows[r] = NULL;
15344       }
15345    }
15346 
15347    /* mark LP to be unsolved */
15348    if( lp->nrows < nrows )
15349    {
15350       assert(lp->nrows == lp->nlpirows);
15351       assert(lp->nchgrows == 0);
15352       assert(lp->flushed);
15353 
15354       lp->lpifirstchgrow = lp->nlpirows;
15355 
15356       /* mark the current solution invalid */
15357       lp->solved = FALSE;
15358       lp->dualfeasible = FALSE;
15359       lp->dualchecked = FALSE;
15360       lp->lpobjval = SCIP_INVALID;
15361       lp->lpsolstat = SCIP_LPSOLSTAT_NOTSOLVED;
15362    }
15363 
15364    checkLinks(lp);
15365 
15366    return SCIP_OKAY;
15367 }
15368 
15369 /** removes all non-basic columns, that are too old, beginning with the given firstcol */
15370 static
lpRemoveObsoleteCols(SCIP_LP * lp,SCIP_SET * set,SCIP_STAT * stat,int firstcol)15371 SCIP_RETCODE lpRemoveObsoleteCols(
15372    SCIP_LP*              lp,                 /**< current LP data */
15373    SCIP_SET*             set,                /**< global SCIP settings */
15374    SCIP_STAT*            stat,               /**< problem statistics */
15375    int                   firstcol            /**< first column to check for clean up */
15376    )
15377 {
15378    SCIP_COL** cols;
15379 #ifndef NDEBUG
15380    SCIP_COL** lpicols;
15381 #endif
15382    int* coldstat;
15383    int ncols;
15384    int ndelcols;
15385    int c;
15386 
15387    assert(lp != NULL);
15388    assert(lp->flushed);
15389    assert(lp->ncols == lp->nlpicols);
15390    assert(lp->nremovablecols <= lp->ncols);
15391    assert(!lp->diving);
15392    assert(set != NULL);
15393    assert(stat != NULL);
15394 
15395    if( lp->nremovablecols == 0 || set->lp_colagelimit == -1 || !lp->solisbasic )
15396       return SCIP_OKAY;
15397 
15398    ncols = lp->ncols;
15399    cols = lp->cols;
15400 #ifndef NDEBUG
15401    lpicols = lp->lpicols;
15402 #endif
15403 
15404    /* get temporary memory */
15405    SCIP_CALL( SCIPsetAllocBufferArray(set, &coldstat, ncols) );
15406 
15407    /* mark obsolete columns to be deleted */
15408    ndelcols = 0;
15409    BMSclearMemoryArray(coldstat, ncols);
15410    for( c = firstcol; c < ncols; ++c )
15411    {
15412       assert(cols[c] == lpicols[c]);
15413       assert(cols[c]->lppos == c);
15414       assert(cols[c]->lpipos == c);
15415       if( cols[c]->removable
15416          && cols[c]->obsoletenode != stat->nnodes /* don't remove column a second time from same node (avoid cycling), or a first time if marked nonremovable locally */
15417          && cols[c]->age > set->lp_colagelimit
15418          && (SCIP_BASESTAT)cols[c]->basisstatus != SCIP_BASESTAT_BASIC
15419          && SCIPsetIsZero(set, SCIPcolGetBestBound(cols[c])) ) /* bestbd != 0 -> column would be priced in next time */
15420       {
15421          assert(cols[c]->primsol == 0.0);
15422          coldstat[c] = 1;
15423          ndelcols++;
15424          cols[c]->obsoletenode = stat->nnodes;
15425          SCIPsetDebugMsg(set, "removing obsolete col <%s>: primsol=%f, bounds=[%g,%g]\n",
15426             SCIPvarGetName(cols[c]->var), cols[c]->primsol, cols[c]->lb, cols[c]->ub);
15427       }
15428    }
15429 
15430    SCIPsetDebugMsg(set, "removing %d/%d obsolete columns from LP\n", ndelcols, ncols);
15431 
15432    /* delete the marked columns in the LP solver interface, update the LP respectively */
15433    if( ndelcols > 0 )
15434    {
15435       SCIP_CALL( lpDelColset(lp, set, coldstat) );
15436    }
15437    assert(lp->ncols == ncols - ndelcols);
15438 
15439    /* release temporary memory */
15440    SCIPsetFreeBufferArray(set, &coldstat);
15441 
15442    return SCIP_OKAY;
15443 }
15444 
15445 /** removes all basic rows, that are too old, beginning with the given firstrow */
15446 static
lpRemoveObsoleteRows(SCIP_LP * lp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_EVENTQUEUE * eventqueue,SCIP_EVENTFILTER * eventfilter,int firstrow)15447 SCIP_RETCODE lpRemoveObsoleteRows(
15448    SCIP_LP*              lp,                 /**< current LP data */
15449    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
15450    SCIP_SET*             set,                /**< global SCIP settings */
15451    SCIP_STAT*            stat,               /**< problem statistics */
15452    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
15453    SCIP_EVENTFILTER*     eventfilter,        /**< global event filter */
15454    int                   firstrow            /**< first row to check for clean up */
15455    )
15456 {
15457    SCIP_ROW** rows;
15458 #ifndef NDEBUG
15459    SCIP_ROW** lpirows;
15460 #endif
15461    int* rowdstat;
15462    int nrows;
15463    int ndelrows;
15464    int r;
15465 
15466    assert(lp != NULL);
15467    assert(lp->flushed);
15468    assert(lp->nrows == lp->nlpirows);
15469    assert(lp->nremovablerows <= lp->nrows);
15470    assert(!lp->diving);
15471    assert(set != NULL);
15472    assert(stat != NULL);
15473 
15474    if( lp->nremovablerows == 0 || set->lp_rowagelimit == -1 || !lp->solisbasic )
15475       return SCIP_OKAY;
15476 
15477    nrows = lp->nrows;
15478    rows = lp->rows;
15479 #ifndef NDEBUG
15480    lpirows = lp->lpirows;
15481 #endif
15482 
15483    /* get temporary memory */
15484    SCIP_CALL( SCIPsetAllocBufferArray(set, &rowdstat, nrows) );
15485 
15486    /* mark obsolete rows to be deleted */
15487    ndelrows = 0;
15488    BMSclearMemoryArray(rowdstat, nrows);
15489    for( r = firstrow; r < nrows; ++r )
15490    {
15491       assert(rows[r] == lpirows[r]);
15492       assert(rows[r]->lppos == r);
15493       assert(rows[r]->lpipos == r);
15494       if( rows[r]->removable
15495          && rows[r]->obsoletenode != stat->nnodes  /* don't remove row a second time from same node (avoid cycling), or a first time if marked nonremovable locally */
15496          && rows[r]->age > set->lp_rowagelimit
15497          && (SCIP_BASESTAT)rows[r]->basisstatus == SCIP_BASESTAT_BASIC )
15498       {
15499          rowdstat[r] = 1;
15500          ndelrows++;
15501          rows[r]->obsoletenode = stat->nnodes;
15502          SCIPsetDebugMsg(set, "removing obsolete row <%s>: activity=%f, sides=[%g,%g]\n",
15503             rows[r]->name, rows[r]->activity, rows[r]->lhs, rows[r]->rhs);
15504       }
15505    }
15506 
15507    SCIPsetDebugMsg(set, "removing %d/%d obsolete rows from LP\n", ndelrows, nrows);
15508 
15509    /* delete the marked rows in the LP solver interface, update the LP respectively */
15510    if( ndelrows > 0 )
15511    {
15512       SCIP_CALL( lpDelRowset(lp, blkmem, set, eventqueue, eventfilter, rowdstat) );
15513    }
15514    assert(lp->nrows == nrows - ndelrows);
15515 
15516    /* release temporary memory */
15517    SCIPsetFreeBufferArray(set, &rowdstat);
15518 
15519    return SCIP_OKAY;
15520 }
15521 
15522 /** removes all non-basic columns and basic rows in the part of the LP created at the current node, that are too old */
SCIPlpRemoveNewObsoletes(SCIP_LP * lp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_EVENTQUEUE * eventqueue,SCIP_EVENTFILTER * eventfilter)15523 SCIP_RETCODE SCIPlpRemoveNewObsoletes(
15524    SCIP_LP*              lp,                 /**< current LP data */
15525    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
15526    SCIP_SET*             set,                /**< global SCIP settings */
15527    SCIP_STAT*            stat,               /**< problem statistics */
15528    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
15529    SCIP_EVENTFILTER*     eventfilter         /**< global event filter */
15530    )
15531 {
15532    assert(lp != NULL);
15533    assert(lp->solved);
15534    assert(!lp->diving);
15535    assert(SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_OPTIMAL);
15536    assert(set != NULL);
15537 
15538    SCIPsetDebugMsg(set, "removing obsolete columns starting with %d/%d, obsolete rows starting with %d/%d\n",
15539       lp->firstnewcol, lp->ncols, lp->firstnewrow, lp->nrows);
15540 
15541    if( lp->firstnewcol < lp->ncols )
15542    {
15543       SCIP_CALL( lpRemoveObsoleteCols(lp, set, stat, lp->firstnewcol) );
15544    }
15545    if( lp->firstnewrow < lp->nrows )
15546    {
15547       SCIP_CALL( lpRemoveObsoleteRows(lp, blkmem, set, stat, eventqueue, eventfilter, lp->firstnewrow) );
15548    }
15549 
15550    return SCIP_OKAY;
15551 }
15552 
15553 /** removes all non-basic columns and basic rows in whole LP, that are too old */
SCIPlpRemoveAllObsoletes(SCIP_LP * lp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_EVENTQUEUE * eventqueue,SCIP_EVENTFILTER * eventfilter)15554 SCIP_RETCODE SCIPlpRemoveAllObsoletes(
15555    SCIP_LP*              lp,                 /**< current LP data */
15556    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
15557    SCIP_SET*             set,                /**< global SCIP settings */
15558    SCIP_STAT*            stat,               /**< problem statistics */
15559    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
15560    SCIP_EVENTFILTER*     eventfilter         /**< global event filter */
15561    )
15562 {
15563    assert(lp != NULL);
15564    assert(lp->solved);
15565    assert(!lp->diving);
15566    assert(SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_OPTIMAL);
15567    assert(set != NULL);
15568 
15569    SCIPsetDebugMsg(set, "removing all obsolete columns and rows\n");
15570 
15571    if( 0 < lp->ncols )
15572    {
15573       SCIP_CALL( lpRemoveObsoleteCols(lp, set, stat, 0) );
15574    }
15575    if( 0 < lp->nrows )
15576    {
15577       SCIP_CALL( lpRemoveObsoleteRows(lp, blkmem, set, stat, eventqueue, eventfilter, 0) );
15578    }
15579 
15580    return SCIP_OKAY;
15581 }
15582 
15583 /** removes all non-basic columns at 0.0 beginning with the given firstcol */
15584 static
lpCleanupCols(SCIP_LP * lp,SCIP_SET * set,SCIP_STAT * stat,int firstcol)15585 SCIP_RETCODE lpCleanupCols(
15586    SCIP_LP*              lp,                 /**< current LP data */
15587    SCIP_SET*             set,                /**< global SCIP settings */
15588    SCIP_STAT*            stat,               /**< problem statistics */
15589    int                   firstcol            /**< first column to check for clean up */
15590    )
15591 {
15592    SCIP_COL** cols;
15593    SCIP_COL** lpicols;
15594    int* coldstat;
15595    int ncols;
15596    int ndelcols;
15597    int c;
15598 
15599    assert(lp != NULL);
15600    assert(lp->flushed);
15601    assert(lp->ncols == lp->nlpicols);
15602    assert(!lp->diving);
15603    assert(stat != NULL);
15604    assert(lp->validsollp == stat->lpcount);
15605    assert(0 <= firstcol && firstcol < lp->ncols);
15606 
15607    if( lp->nremovablecols == 0 || !lp->solisbasic )
15608       return SCIP_OKAY;
15609 
15610    ncols = lp->ncols;
15611    cols = lp->cols;
15612    lpicols = lp->lpicols;
15613 
15614    /* get temporary memory */
15615    SCIP_CALL( SCIPsetAllocBufferArray(set, &coldstat, ncols) );
15616 
15617    /* mark unused columns to be deleted */
15618    ndelcols = 0;
15619    BMSclearMemoryArray(coldstat, ncols);
15620    for( c = firstcol; c < ncols; ++c )
15621    {
15622       assert(cols[c] == lpicols[c]);
15623       assert(cols[c]->lppos == c);
15624       assert(cols[c]->lpipos == c);
15625       if( lpicols[c]->removable
15626          && (SCIP_BASESTAT)lpicols[c]->basisstatus != SCIP_BASESTAT_BASIC
15627          && lpicols[c]->primsol == 0.0 /* non-basic columns to remove are exactly at 0.0 */
15628          && SCIPsetIsZero(set, SCIPcolGetBestBound(cols[c])) ) /* bestbd != 0 -> column would be priced in next time */
15629       {
15630          coldstat[c] = 1;
15631          ndelcols++;
15632       }
15633    }
15634 
15635    SCIPsetDebugMsg(set, "removing %d/%d unused columns from LP\n", ndelcols, ncols);
15636 
15637    /* delete the marked columns in the LP solver interface, update the LP respectively */
15638    if( ndelcols > 0 )
15639    {
15640       SCIP_CALL( lpDelColset(lp, set, coldstat) );
15641    }
15642    assert(lp->ncols == ncols - ndelcols);
15643 
15644    /* release temporary memory */
15645    SCIPsetFreeBufferArray(set, &coldstat);
15646 
15647    return SCIP_OKAY;
15648 }
15649 
15650 /** removes all basic rows beginning with the given firstrow */
15651 static
lpCleanupRows(SCIP_LP * lp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_EVENTQUEUE * eventqueue,SCIP_EVENTFILTER * eventfilter,int firstrow)15652 SCIP_RETCODE lpCleanupRows(
15653    SCIP_LP*              lp,                 /**< current LP data */
15654    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
15655    SCIP_SET*             set,                /**< global SCIP settings */
15656    SCIP_STAT*            stat,               /**< problem statistics */
15657    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
15658    SCIP_EVENTFILTER*     eventfilter,        /**< global event filter */
15659    int                   firstrow            /**< first row to check for clean up */
15660    )
15661 {
15662 #ifndef NDEBUG
15663    SCIP_ROW** rows;
15664 #endif
15665    SCIP_ROW** lpirows;
15666    int* rowdstat;
15667    int nrows;
15668    int ndelrows;
15669    int r;
15670 
15671    assert(lp != NULL);
15672    assert(lp->flushed);
15673    assert(lp->ncols == lp->nlpicols);
15674    assert(lp->nrows == lp->nlpirows);
15675    assert(!lp->diving);
15676    assert(stat != NULL);
15677    assert(lp->validsollp == stat->lpcount);
15678    assert(0 <= firstrow && firstrow < lp->nrows);
15679 
15680    if( lp->nremovablerows == 0 || !lp->solisbasic  )
15681       return SCIP_OKAY;
15682 
15683 #ifndef NDEBUG
15684    rows = lp->rows;
15685 #endif
15686    nrows = lp->nrows;
15687    lpirows = lp->lpirows;
15688 
15689    /* get temporary memory */
15690    SCIP_CALL( SCIPsetAllocBufferArray(set, &rowdstat, nrows) );
15691 
15692    /* mark unused rows to be deleted */
15693    ndelrows = 0;
15694    BMSclearMemoryArray(rowdstat, nrows);
15695    for( r = firstrow; r < nrows; ++r )
15696    {
15697       assert(rows[r] == lpirows[r]);
15698       assert(rows[r]->lppos == r);
15699       assert(rows[r]->lpipos == r);
15700       if( lpirows[r]->removable && (SCIP_BASESTAT)lpirows[r]->basisstatus == SCIP_BASESTAT_BASIC )
15701       {
15702          rowdstat[r] = 1;
15703          ndelrows++;
15704       }
15705    }
15706 
15707    SCIPsetDebugMsg(set, "removing %d/%d unused rows from LP\n", ndelrows, nrows);
15708 
15709    /* delete the marked rows in the LP solver interface, update the LP respectively */
15710    if( ndelrows > 0 )
15711    {
15712       SCIP_CALL( lpDelRowset(lp, blkmem, set, eventqueue, eventfilter, rowdstat) );
15713    }
15714    assert(lp->nrows == nrows - ndelrows);
15715 
15716    /* release temporary memory */
15717    SCIPsetFreeBufferArray(set, &rowdstat);
15718 
15719    return SCIP_OKAY;
15720 }
15721 
15722 /** removes all non-basic columns at 0.0 and basic rows in the part of the LP created at the current node */
SCIPlpCleanupNew(SCIP_LP * lp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_EVENTQUEUE * eventqueue,SCIP_EVENTFILTER * eventfilter,SCIP_Bool root)15723 SCIP_RETCODE SCIPlpCleanupNew(
15724    SCIP_LP*              lp,                 /**< current LP data */
15725    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
15726    SCIP_SET*             set,                /**< global SCIP settings */
15727    SCIP_STAT*            stat,               /**< problem statistics */
15728    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
15729    SCIP_EVENTFILTER*     eventfilter,        /**< global event filter */
15730    SCIP_Bool             root                /**< are we at the root node? */
15731    )
15732 {
15733    SCIP_Bool cleanupcols;
15734    SCIP_Bool cleanuprows;
15735 
15736    assert(lp != NULL);
15737    assert(lp->solved);
15738    assert(!lp->diving);
15739    assert(SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_OPTIMAL);
15740    assert(set != NULL);
15741 
15742    /* check, if we want to clean up the columns and rows */
15743    cleanupcols = (root ? set->lp_cleanupcolsroot : set->lp_cleanupcols);
15744    cleanuprows = (root ? set->lp_cleanuprowsroot : set->lp_cleanuprows);
15745 
15746    SCIPsetDebugMsg(set, "removing unused columns starting with %d/%d (%u), unused rows starting with %d/%d (%u), LP algo: %d, basic sol: %u\n",
15747       lp->firstnewcol, lp->ncols, cleanupcols, lp->firstnewrow, lp->nrows, cleanuprows, lp->lastlpalgo, lp->solisbasic);
15748 
15749    if( cleanupcols && lp->firstnewcol < lp->ncols )
15750    {
15751       SCIP_CALL( lpCleanupCols(lp, set, stat, lp->firstnewcol) );
15752    }
15753    if( cleanuprows && lp->firstnewrow < lp->nrows )
15754    {
15755       SCIP_CALL( lpCleanupRows(lp, blkmem, set, stat, eventqueue, eventfilter, lp->firstnewrow) );
15756    }
15757 
15758    return SCIP_OKAY;
15759 }
15760 
15761 /** removes all non-basic columns at 0.0 and basic rows in the whole LP */
SCIPlpCleanupAll(SCIP_LP * lp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_EVENTQUEUE * eventqueue,SCIP_EVENTFILTER * eventfilter,SCIP_Bool root)15762 SCIP_RETCODE SCIPlpCleanupAll(
15763    SCIP_LP*              lp,                 /**< current LP data */
15764    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
15765    SCIP_SET*             set,                /**< global SCIP settings */
15766    SCIP_STAT*            stat,               /**< problem statistics */
15767    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
15768    SCIP_EVENTFILTER*     eventfilter,        /**< global event filter */
15769    SCIP_Bool             root                /**< are we at the root node? */
15770    )
15771 {
15772    SCIP_Bool cleanupcols;
15773    SCIP_Bool cleanuprows;
15774 
15775    assert(lp != NULL);
15776    assert(lp->solved);
15777    assert(!lp->diving);
15778    assert(SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_OPTIMAL);
15779    assert(set != NULL);
15780 
15781    /* check, if we want to clean up the columns and rows */
15782    cleanupcols = (root ? set->lp_cleanupcolsroot : set->lp_cleanupcols);
15783    cleanuprows = (root ? set->lp_cleanuprowsroot : set->lp_cleanuprows);
15784 
15785    SCIPsetDebugMsg(set, "removing all unused columns (%u) and rows (%u), LP algo: %d, basic sol: %u\n",
15786       cleanupcols, cleanuprows, lp->lastlpalgo, lp->solisbasic);
15787 
15788    if( cleanupcols && 0 < lp->ncols )
15789    {
15790       SCIP_CALL( lpCleanupCols(lp, set, stat, 0) );
15791    }
15792    if( cleanuprows && 0 < lp->nrows )
15793    {
15794       SCIP_CALL( lpCleanupRows(lp, blkmem, set, stat, eventqueue, eventfilter, 0) );
15795    }
15796 
15797    return SCIP_OKAY;
15798 }
15799 
15800 /** removes all redundant rows that were added at the current node */
SCIPlpRemoveRedundantRows(SCIP_LP * lp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_EVENTQUEUE * eventqueue,SCIP_EVENTFILTER * eventfilter)15801 SCIP_RETCODE SCIPlpRemoveRedundantRows(
15802    SCIP_LP*              lp,                 /**< current LP data */
15803    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
15804    SCIP_SET*             set,                /**< global SCIP settings */
15805    SCIP_STAT*            stat,               /**< problem statistics */
15806    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
15807    SCIP_EVENTFILTER*     eventfilter         /**< global event filter */
15808    )
15809 {
15810 #ifndef NDEBUG
15811    SCIP_ROW** rows;
15812 #endif
15813    SCIP_ROW** lpirows;
15814    int* rowdstat;
15815    int nrows;
15816    int ndelrows;
15817    int r;
15818 
15819    assert(lp != NULL);
15820    assert(lp->flushed);
15821    assert(lp->ncols == lp->nlpicols);
15822    assert(lp->nrows == lp->nlpirows);
15823    assert(!lp->diving);
15824    assert(stat != NULL);
15825    assert(lp->validsollp == stat->lpcount);
15826    assert(lp->firstnewrow <= lp->nrows);
15827 
15828    if( lp->firstnewrow == lp->nrows )
15829       return SCIP_OKAY;
15830 
15831 #ifndef NDEBUG
15832    rows = lp->rows;
15833 #endif
15834    nrows = lp->nrows;
15835    lpirows = lp->lpirows;
15836 
15837    /* get temporary memory */
15838    SCIP_CALL( SCIPsetAllocBufferArray(set, &rowdstat, nrows) );
15839 
15840    /* mark redundant rows to be deleted (only delete basic rows!) */
15841    ndelrows = 0;
15842    BMSclearMemoryArray(rowdstat, nrows);
15843    for( r = lp->firstnewrow; r < nrows; ++r )
15844    {
15845       assert(rows[r] == lpirows[r]);
15846       assert(rows[r]->lppos == r);
15847       assert(rows[r]->lpipos == r);
15848       if( (!lp->solisbasic || (SCIP_BASESTAT)lpirows[r]->basisstatus == SCIP_BASESTAT_BASIC)
15849          && SCIProwIsRedundant(lpirows[r], set, stat) )
15850       {
15851          SCIPsetDebugMsg(set, "basic row <%s> is redundant: sides=[%g,%g], act=[%g,%g]\n",
15852             SCIProwGetName(lpirows[r]), SCIProwGetLhs(lpirows[r]), SCIProwGetRhs(lpirows[r]),
15853             SCIProwGetMinActivity(lpirows[r], set, stat), SCIProwGetMaxActivity(lpirows[r], set, stat));
15854          rowdstat[r] = 1;
15855          ndelrows++;
15856       }
15857    }
15858 
15859    SCIPsetDebugMsg(set, "removing %d/%d redundant basic rows from LP\n", ndelrows, nrows);
15860 
15861    /* delete the marked rows in the LP solver interface, update the LP respectively */
15862    if( ndelrows > 0 )
15863    {
15864       SCIP_CALL( lpDelRowset(lp, blkmem, set, eventqueue, eventfilter, rowdstat) );
15865    }
15866    assert(lp->nrows == nrows - ndelrows);
15867 
15868    /* release temporary memory */
15869    SCIPsetFreeBufferArray(set, &rowdstat);
15870 
15871    return SCIP_OKAY;
15872 }
15873 
15874 /** initiates LP diving */
SCIPlpStartDive(SCIP_LP * lp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat)15875 SCIP_RETCODE SCIPlpStartDive(
15876    SCIP_LP*              lp,                 /**< current LP data */
15877    BMS_BLKMEM*           blkmem,             /**< block memory */
15878    SCIP_SET*             set,                /**< global SCIP settings */
15879    SCIP_STAT*            stat                /**< problem statistics */
15880    )
15881 {
15882    int c;
15883    int r;
15884 
15885    assert(lp != NULL);
15886    assert(lp->flushed || !lp->solved);
15887    assert(!lp->diving);
15888    assert(!lp->probing);
15889    assert(lp->divelpistate == NULL);
15890    assert(lp->divelpwasprimfeas);
15891    assert(lp->divelpwasdualfeas);
15892    assert(lp->validsollp <= stat->lpcount);
15893    assert(blkmem != NULL);
15894    assert(set != NULL);
15895    assert(lp->ndivechgsides == 0);
15896 
15897    SCIPsetDebugMsg(set, "diving started (LP flushed: %u, LP solved: %u, solstat: %d)\n",
15898       lp->flushed, lp->solved, SCIPlpGetSolstat(lp));
15899 
15900 #ifndef NDEBUG
15901    for( c = 0; c < lp->ncols; ++c )
15902    {
15903       assert(lp->cols[c] != NULL);
15904       assert(lp->cols[c]->var != NULL);
15905       assert(SCIPvarGetStatus(lp->cols[c]->var) == SCIP_VARSTATUS_COLUMN);
15906       assert(SCIPvarGetCol(lp->cols[c]->var) == lp->cols[c]);
15907       assert(SCIPsetIsFeasEQ(set, SCIPvarGetObj(lp->cols[c]->var), lp->cols[c]->obj));
15908       assert(SCIPsetIsFeasEQ(set, SCIPvarGetLbLocal(lp->cols[c]->var), lp->cols[c]->lb));
15909       assert(SCIPsetIsFeasEQ(set, SCIPvarGetUbLocal(lp->cols[c]->var), lp->cols[c]->ub));
15910    }
15911 #endif
15912 
15913    /* save current LPI state (basis information) */
15914    SCIP_CALL( SCIPlpiGetState(lp->lpi, blkmem, &lp->divelpistate) );
15915    lp->divelpwasprimfeas = lp->primalfeasible;
15916    lp->divelpwasdualfeas = lp->dualfeasible;
15917    lp->divelpwasprimchecked = lp->primalchecked;
15918    lp->divelpwasdualchecked = lp->dualchecked;
15919 
15920    /* save current LP values dependent on the solution */
15921    SCIP_CALL( lpStoreSolVals(lp, stat, blkmem) );
15922    assert(lp->storedsolvals != NULL);
15923    if( !set->lp_resolverestore && lp->solved )
15924    {
15925       SCIP_Bool store = TRUE;
15926 
15927       switch ( lp->lpsolstat )
15928       {
15929       case SCIP_LPSOLSTAT_OPTIMAL:
15930          SCIP_CALL( SCIPlpGetSol(lp, set, stat, NULL, NULL) );
15931          assert(lp->validsollp == stat->lpcount);
15932          break;
15933       case SCIP_LPSOLSTAT_UNBOUNDEDRAY:
15934          SCIP_CALL( SCIPlpGetUnboundedSol(lp, set, stat, NULL, NULL) );
15935          assert(lp->validsollp == stat->lpcount);
15936          break;
15937       case SCIP_LPSOLSTAT_OBJLIMIT:
15938       case SCIP_LPSOLSTAT_ITERLIMIT:
15939       case SCIP_LPSOLSTAT_TIMELIMIT:
15940          SCIP_CALL( SCIPlpGetSol(lp, set, stat, NULL, NULL) );
15941          assert(lp->validsollp == stat->lpcount);
15942          break;
15943       case SCIP_LPSOLSTAT_INFEASIBLE:
15944          SCIP_CALL( SCIPlpGetDualfarkas(lp, set, stat, NULL) );
15945          break;
15946       case SCIP_LPSOLSTAT_NOTSOLVED:
15947       case SCIP_LPSOLSTAT_ERROR:
15948       default:
15949          store = FALSE;
15950       }
15951 
15952       if ( store )
15953       {
15954          for( c = 0; c < lp->ncols; ++c )
15955          {
15956             SCIP_CALL( colStoreSolVals(lp->cols[c], blkmem) );
15957          }
15958          for( r = 0; r < lp->nrows; ++r )
15959          {
15960             SCIP_CALL( rowStoreSolVals(lp->rows[r], blkmem, lp->storedsolvals->lpsolstat == SCIP_LPSOLSTAT_INFEASIBLE) );
15961          }
15962       }
15963    }
15964 
15965    /* store LPI iteration limit */
15966    SCIP_CALL( SCIPlpiGetIntpar(lp->lpi, SCIP_LPPAR_LPITLIM, &lp->divinglpiitlim) );
15967 
15968    /* remember the number of domain changes */
15969    lp->divenolddomchgs = stat->domchgcount;
15970 
15971    /* store current number of rows */
15972    lp->ndivingrows = lp->nrows;
15973 
15974    /* switch to diving mode */
15975    lp->diving = TRUE;
15976 
15977    return SCIP_OKAY;
15978 }
15979 
15980 /** quits LP diving and resets bounds and objective values of columns to the current node's values */
SCIPlpEndDive(SCIP_LP * lp,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr,SCIP_STAT * stat,SCIP_EVENTQUEUE * eventqueue,SCIP_EVENTFILTER * eventfilter,SCIP_PROB * prob,SCIP_VAR ** vars,int nvars)15981 SCIP_RETCODE SCIPlpEndDive(
15982    SCIP_LP*              lp,                 /**< current LP data */
15983    BMS_BLKMEM*           blkmem,             /**< block memory */
15984    SCIP_SET*             set,                /**< global SCIP settings */
15985    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
15986    SCIP_STAT*            stat,               /**< problem statistics */
15987    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
15988    SCIP_EVENTFILTER*     eventfilter,        /**< global event filter */
15989    SCIP_PROB*            prob,               /**< problem data */
15990    SCIP_VAR**            vars,               /**< array with all active variables */
15991    int                   nvars               /**< number of active variables */
15992    )
15993 {
15994    SCIP_VAR* var;
15995    int v;
15996 
15997    assert(lp != NULL);
15998    assert(lp->diving);
15999    assert(blkmem != NULL);
16000    assert(nvars == 0 || vars != NULL);
16001 
16002    SCIPsetDebugMsg(set, "diving ended (LP flushed: %u, solstat: %d)\n", lp->flushed, SCIPlpGetSolstat(lp));
16003 
16004    /* reset all columns' objective values and bounds to its original values */
16005    for( v = 0; v < nvars; ++v )
16006    {
16007       var = vars[v];
16008       assert(var != NULL);
16009       if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN )
16010       {
16011          SCIP_CALL( SCIPcolChgObj(SCIPvarGetCol(var), set, lp, SCIPvarGetObj(var)) );
16012          SCIP_CALL( SCIPcolChgLb(SCIPvarGetCol(var), set, lp, SCIPvarGetLbLocal(var)) );
16013          SCIP_CALL( SCIPcolChgUb(SCIPvarGetCol(var), set, lp, SCIPvarGetUbLocal(var)) );
16014       }
16015    }
16016 
16017    /* remove rows which were added in diving mode */
16018    SCIP_CALL( SCIPlpShrinkRows(lp, blkmem, set, eventqueue, eventfilter, lp->ndivingrows) );
16019 
16020    /* undo changes to left hand sides and right hand sides */
16021    while( lp->ndivechgsides > 0 )
16022    {
16023       SCIP_Real oldside;
16024       SCIP_SIDETYPE sidetype;
16025       SCIP_ROW* row;
16026 
16027       lp->ndivechgsides--;
16028       oldside = lp->divechgsides[lp->ndivechgsides];
16029       sidetype = lp->divechgsidetypes[lp->ndivechgsides];
16030       row = lp->divechgrows[lp->ndivechgsides];
16031 
16032       if( sidetype == SCIP_SIDETYPE_LEFT )
16033       {
16034          SCIP_CALL( SCIProwChgLhs(row, blkmem, set, eventqueue, lp, oldside) );
16035       }
16036       else
16037       {
16038          SCIP_CALL( SCIProwChgRhs(row, blkmem, set, eventqueue, lp, oldside) );
16039       }
16040    }
16041 
16042    /* restore LPI iteration limit */
16043    SCIP_CALL( lpSetIterationLimit(lp, lp->divinglpiitlim) );
16044 
16045    /* reload LPI state saved at start of diving and free it afterwards; it may be NULL, in which case simply nothing
16046     * happens
16047     */
16048    SCIP_CALL( SCIPlpSetState(lp, blkmem, set, eventqueue, lp->divelpistate,
16049          lp->divelpwasprimfeas, lp->divelpwasprimchecked, lp->divelpwasdualfeas, lp->divelpwasdualchecked) );
16050    SCIP_CALL( SCIPlpFreeState(lp, blkmem, &lp->divelpistate) );
16051    lp->divelpwasprimfeas = TRUE;
16052    lp->divelpwasdualfeas = TRUE;
16053    lp->divelpwasprimchecked = TRUE;
16054    lp->divelpwasdualchecked = TRUE;
16055    assert(lp->divelpistate == NULL);
16056 
16057    /* switch to standard (non-diving) mode */
16058    lp->diving = FALSE;
16059    lp->divingobjchg = FALSE;
16060 
16061    /* if the LP was solved before starting the dive, but not to optimality (or unboundedness), then we need to solve the
16062     * LP again to reset the solution (e.g. we do not save the Farkas proof for infeasible LPs, because we assume that we
16063     * are not called in this case, anyway); restoring by solving the LP again in either case can be forced by setting
16064     * the parameter resolverestore to TRUE
16065     * restoring an unbounded ray after solve does not seem to work currently (bug 631), so we resolve also in this case
16066     */
16067    assert(lp->storedsolvals != NULL);
16068    if( lp->storedsolvals->lpissolved
16069       && (set->lp_resolverestore || lp->storedsolvals->lpsolstat != SCIP_LPSOLSTAT_OPTIMAL || lp->divenolddomchgs < stat->domchgcount) )
16070    {
16071       SCIP_Bool lperror;
16072 
16073       SCIP_CALL( SCIPlpSolveAndEval(lp, set, messagehdlr,  blkmem, stat, eventqueue, eventfilter, prob, -1LL, FALSE, FALSE, FALSE, &lperror) );
16074       if( lperror )
16075       {
16076          lpNumericalTroubleMessage(messagehdlr, set, stat, SCIP_VERBLEVEL_FULL, "unresolved when resolving LP after diving");
16077          lp->resolvelperror = TRUE;
16078       }
16079       else if( SCIPlpGetSolstat(lp) != SCIP_LPSOLSTAT_OPTIMAL
16080          && SCIPlpGetSolstat(lp) != SCIP_LPSOLSTAT_INFEASIBLE
16081          && SCIPlpGetSolstat(lp) != SCIP_LPSOLSTAT_UNBOUNDEDRAY
16082          && SCIPlpGetSolstat(lp) != SCIP_LPSOLSTAT_OBJLIMIT )
16083       {
16084          SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
16085             "LP was not resolved to a sufficient status after diving\n");
16086          lp->resolvelperror = TRUE;
16087       }
16088    }
16089    /* otherwise, we can just reload the buffered LP solution values at start of diving; this has the advantage that we
16090     * are guaranteed to continue with the same LP status as before diving, while in numerically difficult cases, a
16091     * re-solve as above can lead to a different LP status
16092     */
16093    else
16094    {
16095       int c;
16096       int r;
16097 
16098       /* if there are lazy bounds, remove them from the LP */
16099       if( lp->nlazycols > 0 )
16100       {
16101          /* @todo avoid loosing primal feasibility here after changing the objective already did destroy dual feasibility;
16102           * first resolve LP?
16103           */
16104          SCIP_CALL( updateLazyBounds(lp, set) );
16105          assert(lp->diving == lp->divinglazyapplied);
16106 
16107          /* flush changes to the LP solver */
16108          SCIP_CALL( SCIPlpFlush(lp, blkmem, set, eventqueue) );
16109       }
16110 
16111       /* increment lp counter to ensure that we do not use solution values from the last solved diving lp */
16112       SCIPstatIncrement(stat, set, lpcount);
16113 
16114       /* restore LP solution values in lp data, columns and rows */
16115       if( lp->storedsolvals->lpissolved &&
16116          (lp->storedsolvals->lpsolstat == SCIP_LPSOLSTAT_OPTIMAL ||
16117             lp->storedsolvals->lpsolstat == SCIP_LPSOLSTAT_UNBOUNDEDRAY ||
16118             lp->storedsolvals->lpsolstat == SCIP_LPSOLSTAT_OBJLIMIT ||
16119             lp->storedsolvals->lpsolstat == SCIP_LPSOLSTAT_ITERLIMIT ||
16120             lp->storedsolvals->lpsolstat == SCIP_LPSOLSTAT_TIMELIMIT ||
16121             lp->storedsolvals->lpsolstat == SCIP_LPSOLSTAT_INFEASIBLE)
16122          )
16123       {
16124          SCIP_CALL( lpRestoreSolVals(lp, blkmem, stat->lpcount) );
16125 
16126          for( c = 0; c < lp->ncols; ++c )
16127          {
16128             SCIP_CALL( colRestoreSolVals(lp->cols[c], blkmem, stat->lpcount, set->lp_freesolvalbuffers) );
16129          }
16130          for( r = 0; r < lp->nrows; ++r )
16131          {
16132             SCIP_CALL( rowRestoreSolVals(lp->rows[r], blkmem, stat->lpcount, set->lp_freesolvalbuffers, lp->storedsolvals->lpsolstat == SCIP_LPSOLSTAT_INFEASIBLE) );
16133          }
16134       }
16135       else
16136       {
16137          SCIP_CALL( lpRestoreSolVals(lp, blkmem, -1LL) );
16138       }
16139    }
16140 
16141 #ifndef NDEBUG
16142    {
16143       int c;
16144       for( c = 0; c < lp->ncols; ++c )
16145       {
16146          assert(lp->cols[c] != NULL);
16147          assert(lp->cols[c]->var != NULL);
16148          assert(SCIPvarGetStatus(lp->cols[c]->var) == SCIP_VARSTATUS_COLUMN);
16149          assert(SCIPvarGetCol(lp->cols[c]->var) == lp->cols[c]);
16150          assert(SCIPsetIsEQ(set, SCIPvarGetObj(lp->cols[c]->var), lp->cols[c]->obj));
16151          assert(SCIPsetIsEQ(set, SCIPvarGetLbLocal(lp->cols[c]->var), lp->cols[c]->lb));
16152          assert(SCIPsetIsEQ(set, SCIPvarGetUbLocal(lp->cols[c]->var), lp->cols[c]->ub));
16153       }
16154    }
16155 #endif
16156 
16157    return SCIP_OKAY;
16158 }
16159 
16160 #define DIVESTACKGROWFACT 1.5
16161 
16162 /** records a current row side such that any change will be undone after diving */
SCIPlpRecordOldRowSideDive(SCIP_LP * lp,SCIP_ROW * row,SCIP_SIDETYPE sidetype)16163 SCIP_RETCODE SCIPlpRecordOldRowSideDive(
16164    SCIP_LP*              lp,                 /**< LP data object */
16165    SCIP_ROW*             row,                /**< row affected by the change */
16166    SCIP_SIDETYPE         sidetype            /**< side type */
16167    )
16168 {
16169    assert(lp != NULL);
16170    assert(row != NULL);
16171 
16172    if( lp->ndivechgsides == lp->divechgsidessize )
16173    {
16174       SCIP_CALL( reallocDiveChgSideArrays(lp, lp->divechgsidessize + 1, DIVESTACKGROWFACT) );
16175    }
16176    assert(lp->ndivechgsides < lp->divechgsidessize);
16177 
16178    lp->divechgsides[lp->ndivechgsides] = (sidetype == SCIP_SIDETYPE_LEFT) ? row->lhs : row->rhs;
16179    lp->divechgsidetypes[lp->ndivechgsides] = sidetype;
16180    lp->divechgrows[lp->ndivechgsides] = row;
16181    lp->ndivechgsides++;
16182 
16183    return SCIP_OKAY;
16184 }
16185 
16186 /** informs the LP that probing mode was initiated */
SCIPlpStartProbing(SCIP_LP * lp)16187 SCIP_RETCODE SCIPlpStartProbing(
16188    SCIP_LP*              lp                  /**< current LP data */
16189    )
16190 {
16191    assert(lp != NULL);
16192    assert(!lp->probing);
16193    assert(!lp->strongbranching);
16194    assert(!lp->strongbranchprobing);
16195 
16196    lp->probing = TRUE;
16197 
16198    return SCIP_OKAY;
16199 }
16200 
16201 /** informs the LP that probing mode was finished */
SCIPlpEndProbing(SCIP_LP * lp)16202 SCIP_RETCODE SCIPlpEndProbing(
16203    SCIP_LP*              lp                  /**< current LP data */
16204    )
16205 {
16206    assert(lp != NULL);
16207    assert(lp->probing);
16208    assert(!lp->strongbranching);
16209    assert(!lp->strongbranchprobing);
16210 
16211    lp->probing = FALSE;
16212 
16213    return SCIP_OKAY;
16214 }
16215 
16216 /** informs the LP that the probing mode is now used for strongbranching */
SCIPlpStartStrongbranchProbing(SCIP_LP * lp)16217 void SCIPlpStartStrongbranchProbing(
16218    SCIP_LP*              lp                  /**< current LP data */
16219    )
16220 {
16221    assert(lp != NULL);
16222    assert(lp->probing);
16223    assert(!lp->strongbranching);
16224    assert(!lp->strongbranchprobing);
16225 
16226    lp->strongbranchprobing = TRUE;
16227 }
16228 
16229 /** informs the LP that the probing mode is not used for strongbranching anymore */
SCIPlpEndStrongbranchProbing(SCIP_LP * lp)16230 void SCIPlpEndStrongbranchProbing(
16231    SCIP_LP*              lp                  /**< current LP data */
16232    )
16233 {
16234    assert(lp != NULL);
16235    assert(lp->probing);
16236    assert(!lp->strongbranching);
16237    assert(lp->strongbranchprobing);
16238 
16239    lp->strongbranchprobing = FALSE;
16240 }
16241 
16242 /** calculates y*b + min{(c - y*A)*x | lb <= x <= ub} for given vectors y and c;
16243  *  the vector b is defined with b[i] = lhs[i] if y[i] >= 0, b[i] = rhs[i] if y[i] < 0
16244  *  Calculating this value in interval arithmetics gives a proved lower LP bound for the following reason (assuming,
16245  *  we have only left hand sides):
16246  *           min{cx       |  b <=  Ax, lb <= x <= ub}
16247  *   >=      min{cx       | yb <= yAx, lb <= x <= ub}   (restriction in minimum is relaxed)
16248  *   == yb + min{cx - yb  | yb <= yAx, lb <= x <= ub}   (added yb - yb == 0)
16249  *   >= yb + min{cx - yAx | yb <= yAx, lb <= x <= ub}   (because yAx >= yb inside minimum)
16250  *   >= yb + min{cx - yAx |            lb <= x <= ub}   (restriction in minimum is relaxed)
16251  */
16252 static
provedBound(SCIP_LP * lp,SCIP_SET * set,SCIP_Bool usefarkas,SCIP_Real * bound)16253 SCIP_RETCODE provedBound(
16254    SCIP_LP*              lp,                 /**< current LP data */
16255    SCIP_SET*             set,                /**< global SCIP settings */
16256    SCIP_Bool             usefarkas,          /**< use y = dual Farkas and c = 0 instead of y = dual solution and c = obj? */
16257    SCIP_Real*            bound               /**< result of interval arithmetic minimization */
16258    )
16259 {
16260    SCIP_INTERVAL* yinter;
16261    SCIP_INTERVAL b;
16262    SCIP_INTERVAL ytb;
16263    SCIP_INTERVAL prod;
16264    SCIP_INTERVAL diff;
16265    SCIP_INTERVAL x;
16266    SCIP_INTERVAL minprod;
16267    SCIP_INTERVAL a;
16268    SCIP_ROW* row;
16269    SCIP_COL* col;
16270    SCIP_Real y;
16271    SCIP_Real c;
16272    int i;
16273    int j;
16274 
16275    assert(lp != NULL);
16276    assert(lp->solved);
16277    assert(set != NULL);
16278    assert(bound != NULL);
16279 
16280    /* allocate buffer for storing y in interval arithmetic */
16281    SCIP_CALL( SCIPsetAllocBufferArray(set, &yinter, lp->nrows) );
16282 
16283    /* create y vector in interval arithmetic, setting near zeros to zero; calculate y^Tb */
16284    SCIPintervalSet(&ytb, 0.0);
16285    for( j = 0; j < lp->nrows; ++j )
16286    {
16287       row = lp->rows[j];
16288       assert(row != NULL);
16289 
16290       y = (usefarkas ? row->dualfarkas : row->dualsol);
16291 
16292       if( SCIPsetIsFeasPositive(set, y) )
16293       {
16294          SCIPintervalSet(&yinter[j], y);
16295          SCIPintervalSet(&b, row->lhs - row->constant);
16296       }
16297       else if( SCIPsetIsFeasNegative(set, y) )
16298       {
16299          SCIPintervalSet(&yinter[j], y);
16300          SCIPintervalSet(&b, row->rhs - row->constant);
16301       }
16302       else
16303       {
16304          SCIPintervalSet(&yinter[j], 0.0);
16305          SCIPintervalSet(&b, 0.0);
16306       }
16307 
16308       SCIPintervalMul(SCIPsetInfinity(set), &prod, yinter[j], b);
16309       SCIPintervalAdd(SCIPsetInfinity(set), &ytb, ytb, prod);
16310    }
16311 
16312    /* calculate min{(c^T - y^TA)x} */
16313    SCIPintervalSet(&minprod, 0.0);
16314    for( j = 0; j < lp->ncols; ++j )
16315    {
16316       col = lp->cols[j];
16317       assert(col != NULL);
16318       assert(col->nunlinked == 0);
16319 
16320       SCIPintervalSetBounds(&x, SCIPcolGetLb(col), SCIPcolGetUb(col));
16321 
16322       c = usefarkas ? 0.0 : col->obj;
16323       SCIPintervalSet(&diff, c);
16324 
16325       for( i = 0; i < col->nlprows; ++i )
16326       {
16327          assert(col->rows[i] != NULL);
16328          assert(col->rows[i]->lppos >= 0);
16329          assert(col->linkpos[i] >= 0);
16330          SCIPintervalSet(&a, col->vals[i]);
16331          SCIPintervalMul(SCIPsetInfinity(set), &prod, yinter[col->rows[i]->lppos], a);
16332          SCIPintervalSub(SCIPsetInfinity(set), &diff, diff, prod);
16333       }
16334 
16335 #ifndef NDEBUG
16336       for( i = col->nlprows; i < col->len; ++i )
16337       {
16338          assert(col->rows[i] != NULL);
16339          assert(col->rows[i]->lppos == -1);
16340          assert(col->rows[i]->dualsol == 0.0);
16341          assert(col->rows[i]->dualfarkas == 0.0);
16342          assert(col->linkpos[i] >= 0);
16343       }
16344 #endif
16345 
16346       SCIPintervalSetBounds(&x, col->lb, col->ub);
16347       SCIPintervalMul(SCIPsetInfinity(set), &diff, diff, x);
16348       SCIPintervalAdd(SCIPsetInfinity(set), &minprod, minprod, diff);
16349    }
16350 
16351    /* add y^Tb */
16352    SCIPintervalAdd(SCIPsetInfinity(set), &minprod, minprod, ytb);
16353 
16354    /* free buffer for storing y in interval arithmetic */
16355    SCIPsetFreeBufferArray(set, &yinter);
16356 
16357    *bound = SCIPintervalGetInf(minprod);
16358 
16359    return SCIP_OKAY;
16360 }
16361 
16362 /** gets proven lower (dual) bound of last LP solution */
SCIPlpGetProvedLowerbound(SCIP_LP * lp,SCIP_SET * set,SCIP_Real * bound)16363 SCIP_RETCODE SCIPlpGetProvedLowerbound(
16364    SCIP_LP*              lp,                 /**< current LP data */
16365    SCIP_SET*             set,                /**< global SCIP settings */
16366    SCIP_Real*            bound               /**< pointer to store proven dual bound */
16367    )
16368 {
16369    SCIP_CALL( provedBound(lp, set, FALSE, bound) );
16370 
16371    SCIPsetDebugMsg(set, "proved lower bound of LP: %.15g\n", *bound);
16372 
16373    return SCIP_OKAY;
16374 }
16375 
16376 /** gets proven dual bound of last LP solution */
SCIPlpIsInfeasibilityProved(SCIP_LP * lp,SCIP_SET * set,SCIP_Bool * proved)16377 SCIP_RETCODE SCIPlpIsInfeasibilityProved(
16378    SCIP_LP*              lp,                 /**< current LP data */
16379    SCIP_SET*             set,                /**< global SCIP settings */
16380    SCIP_Bool*            proved              /**< pointer to store whether infeasibility is proven */
16381    )
16382 {
16383    SCIP_Real bound;
16384 
16385    assert(proved != NULL);
16386 
16387    SCIP_CALL( provedBound(lp, set, TRUE, &bound) );
16388 
16389    *proved = (bound > 0.0);
16390 
16391    SCIPsetDebugMsg(set, "proved Farkas value of LP: %g -> infeasibility %sproved\n", bound, *proved ? "" : "not ");
16392 
16393    return SCIP_OKAY;
16394 }
16395 
16396 
16397 
16398 /** writes LP to a file */
SCIPlpWrite(SCIP_LP * lp,const char * fname)16399 SCIP_RETCODE SCIPlpWrite(
16400    SCIP_LP*              lp,                 /**< current LP data */
16401    const char*           fname               /**< file name */
16402    )
16403 {
16404    assert(lp != NULL);
16405    assert(lp->flushed);
16406    assert(fname != NULL);
16407 
16408    SCIP_CALL( SCIPlpiWriteLP(lp->lpi, fname) );
16409 
16410    return SCIP_OKAY;
16411 }
16412 
16413 /** writes MIP relaxation of the current B&B node to a file */
SCIPlpWriteMip(SCIP_LP * lp,SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr,const char * fname,SCIP_Bool genericnames,SCIP_Bool origobj,SCIP_OBJSENSE objsense,SCIP_Real objscale,SCIP_Real objoffset,SCIP_Bool lazyconss)16414 SCIP_RETCODE SCIPlpWriteMip(
16415    SCIP_LP*              lp,                 /**< current LP data */
16416    SCIP_SET*             set,                /**< global SCIP settings */
16417    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
16418    const char*           fname,              /**< file name */
16419    SCIP_Bool             genericnames,       /**< should generic names like x_i and row_j be used in order to avoid
16420                                               *   troubles with reserved symbols? */
16421    SCIP_Bool             origobj,            /**< should the original objective function be used? */
16422    SCIP_OBJSENSE         objsense,           /**< objective sense */
16423    SCIP_Real             objscale,           /**< objective scaling factor */
16424    SCIP_Real             objoffset,          /**< objective offset, e.g., caused by variable fixings in presolving */
16425    SCIP_Bool             lazyconss           /**< output removable rows as lazy constraints? */
16426    )
16427 {
16428    FILE* file;
16429    int i;
16430    int j;
16431    char rowname[SCIP_MAXSTRLEN];
16432    SCIP_Real coeff;
16433 
16434    assert(lp != NULL);
16435    assert(lp->flushed);
16436    assert(fname != NULL);
16437 
16438    SCIPsetDebugMsg(set, "Start to write MIP to file <%s>\n", fname);
16439    file = fopen(fname, "w");
16440    if( file == NULL )
16441    {
16442       SCIPerrorMessage("cannot open file <%s> for writing\n", fname);
16443       SCIPprintSysError(fname);
16444       return SCIP_FILECREATEERROR;
16445    }
16446 
16447    /* print comments */
16448    if( genericnames )
16449       SCIPmessageFPrintInfo(messagehdlr, file, "\\ Original Variable and Constraint Names have been replaced by generic names.\n");
16450    else
16451    {
16452       SCIPmessageFPrintInfo(messagehdlr, file, "\\ Warning: Variable and Constraint Names should not contain special characters like '+', '=' etc.\n");
16453       SCIPmessageFPrintInfo(messagehdlr, file, "\\ If this is the case, the model may be corrupted!\n");
16454    }
16455 
16456    if( origobj && objoffset != 0.0 )
16457    {
16458       SCIPmessageFPrintInfo(messagehdlr, file, "\\ An artificial variable 'objoffset' has been added and fixed to 1.\n");
16459       SCIPmessageFPrintInfo(messagehdlr, file, "\\ Switching this variable to 0 will disable the offset in the objective.\n\n");
16460    }
16461 
16462    /* print objective function */
16463    /**@note the transformed problem in SCIP is always a minimization problem */
16464    if( !origobj || objsense == SCIP_OBJSENSE_MINIMIZE )
16465       SCIPmessageFPrintInfo(messagehdlr, file, "Minimize");
16466    else
16467       SCIPmessageFPrintInfo(messagehdlr, file, "Maximize");
16468 
16469    /* print objective */
16470    SCIPmessageFPrintInfo(messagehdlr, file, "\nObj:");
16471    j = 0;
16472    for( i = 0; i < lp->ncols; ++i )
16473    {
16474       if( lp->cols[i]->obj != 0.0 )
16475       {
16476          coeff = lp->cols[i]->obj;
16477          if( origobj )
16478          {
16479             coeff *= (SCIP_Real) objsense;
16480             coeff *= objscale;
16481          }
16482 
16483          if( genericnames )
16484             SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g x_%d", coeff, lp->cols[i]->lppos);
16485          else
16486             SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g %s", coeff, lp->cols[i]->var->name);
16487 
16488          ++j;
16489          if( j % 10 == 0 )
16490             SCIPmessageFPrintInfo(messagehdlr, file, "\n     ");
16491       }
16492    }
16493    /* add artificial variable 'objoffset' to transfer objective offset */
16494    if( origobj && objoffset != 0.0 )
16495       SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g objoffset", objoffset * (SCIP_Real) objsense * objscale);
16496 
16497    /* print constraint section */
16498    SCIPmessageFPrintInfo(messagehdlr, file, "\nSubject to\n");
16499    for( i = 0; i < lp->nrows; i++ )
16500    {
16501       char type = 'i';
16502 
16503       /* skip removable rows if we want to write them as lazy constraints */
16504       if ( lazyconss && SCIProwIsRemovable(lp->rows[i]) )
16505          continue;
16506 
16507       /* constraint types: 'l' means: only lhs exists, 'r' means: only rhs exists, 'e' means: both sides exist and are
16508        * equal, 'b' and 'B' mean: both sides exist, if the type is 'b', the lhs will be written, if the type is 'B',
16509        * the rhs will be written. Ergo: set type to b first, change it to 'B' afterwards and go back to WRITEROW.
16510        * type 'i' means: lhs and rhs are both infinite */
16511       if( SCIPsetIsInfinity(set, REALABS(lp->rows[i]->lhs)) && !SCIPsetIsInfinity(set, REALABS(lp->rows[i]->rhs)) )
16512          type = 'r';
16513       else if( !SCIPsetIsInfinity(set, REALABS(lp->rows[i]->lhs)) && SCIPsetIsInfinity(set, REALABS(lp->rows[i]->rhs)) )
16514          type = 'l';
16515       else if( !SCIPsetIsInfinity(set, REALABS(lp->rows[i]->lhs)) && SCIPsetIsEQ(set, lp->rows[i]->lhs, lp->rows[i]->rhs) )
16516          type = 'e';
16517       else if( !SCIPsetIsInfinity(set, REALABS(lp->rows[i]->lhs)) && !SCIPsetIsInfinity(set, REALABS(lp->rows[i]->rhs)) )
16518          type = 'b';
16519 
16520       /* print name of row */
16521       if( genericnames )
16522          (void) SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "row_%d", lp->rows[i]->lppos);
16523       else
16524          (void) SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "%s", lp->rows[i]->name);
16525 
16526    WRITEROW:
16527       switch( type )
16528       {
16529       case 'r':
16530       case 'l':
16531       case 'e':
16532          if( strlen(rowname) > 0 )
16533             SCIPmessageFPrintInfo(messagehdlr, file, "%s: ", rowname);
16534          break;
16535       case 'i':
16536          SCIPmessageFPrintInfo(messagehdlr, file, "\\\\ WARNING: The lhs and the rhs of the row with original name <%s>", lp->rows[i]->name);
16537          SCIPmessageFPrintInfo(messagehdlr, file, "are not in a valid range. The following two constraints may be corrupted!\n");
16538          SCIPmessagePrintWarning(messagehdlr, "The lhs and rhs of row <%s> are not in a valid range.\n", lp->rows[i]->name);
16539          type = 'b';
16540          /*lint -fallthrough*/
16541       case 'b':
16542          SCIPmessageFPrintInfo(messagehdlr, file, "%s_lhs: ", rowname);
16543          break;
16544       default:
16545          assert(type == 'B');
16546          SCIPmessageFPrintInfo(messagehdlr, file, "%s_rhs: ", rowname);
16547          break;
16548       }
16549 
16550       /* print coefficients and variables */
16551       for( j = 0; j < lp->rows[i]->nlpcols; ++j )
16552       {
16553          if( genericnames )
16554             SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g x_%d", lp->rows[i]->vals[j], lp->rows[i]->cols[j]->lppos);
16555          else
16556             SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g %s", lp->rows[i]->vals[j], lp->rows[i]->cols[j]->var->name);
16557 
16558          if( (j+1) % 10 == 0 )
16559             SCIPmessageFPrintInfo(messagehdlr, file, "\n          ");
16560       }
16561 
16562       /* print right hand side */
16563       switch( type )
16564       {
16565       case 'b':
16566          SCIPmessageFPrintInfo(messagehdlr, file, " >= %.15g\n", lp->rows[i]->lhs - lp->rows[i]->constant);
16567          type = 'B';
16568          goto WRITEROW;
16569       case 'l':
16570          SCIPmessageFPrintInfo(messagehdlr, file, " >= %.15g\n", lp->rows[i]->lhs - lp->rows[i]->constant);
16571          break;
16572       case 'B':
16573       case 'r':
16574          SCIPmessageFPrintInfo(messagehdlr, file, " <= %.15g\n", lp->rows[i]->rhs - lp->rows[i]->constant);
16575          break;
16576       case 'e':
16577          SCIPmessageFPrintInfo(messagehdlr, file, " = %.15g\n", lp->rows[i]->lhs - lp->rows[i]->constant);
16578          break;
16579       default:
16580          SCIPerrorMessage("Undefined row type!\n");
16581          fclose(file);
16582          return SCIP_ERROR;
16583       }
16584    }
16585 
16586    if ( lazyconss )
16587    {
16588       /* print lazy constraint section */
16589       SCIPmessageFPrintInfo(messagehdlr, file, "lazy constraints\n");
16590       for( i = 0; i < lp->nrows; i++ )
16591       {
16592          char type = 'i';
16593 
16594          /* skip non-removable rows if we want to write lazy constraints */
16595          if ( ! SCIProwIsRemovable(lp->rows[i]) )
16596             continue;
16597 
16598          /* constraint types: 'l' means: only lhs exists, 'r' means: only rhs exists, 'e' means: both sides exist and are
16599           * equal, 'b' and 'B' mean: both sides exist, if the type is 'b', the lhs will be written, if the type is 'B',
16600           * the rhs will be written. Ergo: set type to b first, change it to 'B' afterwards and go back to WRITEROW.
16601           * type 'i' means: lhs and rhs are both infinite */
16602          if( SCIPsetIsInfinity(set, REALABS(lp->rows[i]->lhs)) && !SCIPsetIsInfinity(set, REALABS(lp->rows[i]->rhs)) )
16603             type = 'r';
16604          else if( !SCIPsetIsInfinity(set, REALABS(lp->rows[i]->lhs)) && SCIPsetIsInfinity(set, REALABS(lp->rows[i]->rhs)) )
16605             type = 'l';
16606          else if( !SCIPsetIsInfinity(set, REALABS(lp->rows[i]->lhs)) && SCIPsetIsEQ(set, lp->rows[i]->lhs, lp->rows[i]->rhs) )
16607             type = 'e';
16608          else if( !SCIPsetIsInfinity(set, REALABS(lp->rows[i]->lhs)) && !SCIPsetIsInfinity(set, REALABS(lp->rows[i]->rhs)) )
16609             type = 'b';
16610 
16611          /* print name of row */
16612          if( genericnames )
16613             (void) SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "row_%d", lp->rows[i]->lppos);
16614          else
16615             (void) SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "%s", lp->rows[i]->name);
16616 
16617       WRITELAZYROW:
16618          switch( type )
16619          {
16620          case 'r':
16621          case 'l':
16622          case 'e':
16623             if( strlen(rowname) > 0 )
16624                SCIPmessageFPrintInfo(messagehdlr, file, "%s: ", rowname);
16625             break;
16626          case 'i':
16627             SCIPmessageFPrintInfo(messagehdlr, file, "\\\\ WARNING: The lhs and the rhs of the row with original name <%s>", lp->rows[i]->name);
16628             SCIPmessageFPrintInfo(messagehdlr, file, "are not in a valid range. The following two constraints may be corrupted!\n");
16629             SCIPmessagePrintWarning(messagehdlr, "The lhs and rhs of row <%s> are not in a valid range.\n",lp->rows[i]->name);
16630             type = 'b';
16631             /*lint -fallthrough*/
16632          case 'b':
16633             SCIPmessageFPrintInfo(messagehdlr, file, "%s_lhs: ", rowname);
16634             break;
16635          default:
16636             assert(type == 'B');
16637             SCIPmessageFPrintInfo(messagehdlr, file, "%s_rhs: ", rowname);
16638             break;
16639          }
16640 
16641          /* print coefficients and variables */
16642          for( j = 0; j < lp->rows[i]->nlpcols; ++j )
16643          {
16644             if( genericnames )
16645                SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g x_%d", lp->rows[i]->vals[j], lp->rows[i]->cols[j]->lppos);
16646             else
16647                SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g %s", lp->rows[i]->vals[j], lp->rows[i]->cols[j]->var->name);
16648 
16649             if( (j+1) % 10 == 0 )
16650                SCIPmessageFPrintInfo(messagehdlr, file, "\n          ");
16651          }
16652 
16653          /* print right hand side */
16654          switch( type )
16655          {
16656          case 'b':
16657             SCIPmessageFPrintInfo(messagehdlr, file, " >= %.15g\n", lp->rows[i]->lhs - lp->rows[i]->constant);
16658             type = 'B';
16659             goto WRITELAZYROW;
16660          case 'l':
16661             SCIPmessageFPrintInfo(messagehdlr, file, " >= %.15g\n", lp->rows[i]->lhs - lp->rows[i]->constant);
16662             break;
16663          case 'B':
16664          case 'r':
16665             SCIPmessageFPrintInfo(messagehdlr, file, " <= %.15g\n", lp->rows[i]->rhs - lp->rows[i]->constant);
16666             break;
16667          case 'e':
16668             SCIPmessageFPrintInfo(messagehdlr, file, " = %.15g\n", lp->rows[i]->lhs - lp->rows[i]->constant);
16669             break;
16670          default:
16671             SCIPerrorMessage("Undefined row type!\n");
16672             fclose(file);
16673             return SCIP_ERROR;
16674          }
16675       }
16676    }
16677 
16678    /* print variable bounds */
16679    SCIPmessageFPrintInfo(messagehdlr, file, "Bounds\n");
16680    for( i = 0; i < lp->ncols; ++i )
16681    {
16682       if( !SCIPsetIsInfinity(set,-lp->cols[i]->lb) || !SCIPsetIsInfinity(set,lp->cols[i]->ub) )
16683       {
16684          /* print lower bound as far this one is not infinity */
16685          if( !SCIPsetIsInfinity(set,-lp->cols[i]->lb) )
16686             SCIPmessageFPrintInfo(messagehdlr, file, " %.15g <=", lp->cols[i]->lb);
16687 
16688          /* print variable name */
16689          if( genericnames )
16690             SCIPmessageFPrintInfo(messagehdlr, file, " x_%d ", lp->cols[i]->lppos);
16691          else
16692             SCIPmessageFPrintInfo(messagehdlr, file, " %s ", lp->cols[i]->var->name);
16693 
16694          /* print upper bound as far this one is not infinity */
16695          if( !SCIPsetIsInfinity(set,lp->cols[i]->ub) )
16696             SCIPmessageFPrintInfo(messagehdlr, file, "<= %.15g", lp->cols[i]->ub);
16697          SCIPmessageFPrintInfo(messagehdlr, file, "\n");
16698       }
16699    }
16700    if( origobj && objoffset != 0.0 )
16701       SCIPmessageFPrintInfo(messagehdlr, file, " objoffset = 1\n");
16702 
16703    /* print integer variables */
16704    SCIPmessageFPrintInfo(messagehdlr, file, "Generals\n");
16705    j = 0;
16706    for( i = 0; i < lp->ncols; ++i )
16707    {
16708       if( SCIPvarIsIntegral(lp->cols[i]->var) )
16709       {
16710          /* print variable name */
16711          if( genericnames )
16712             SCIPmessageFPrintInfo(messagehdlr, file, " x_%d ", lp->cols[i]->lppos);
16713          else
16714             SCIPmessageFPrintInfo(messagehdlr, file, " %s ", lp->cols[i]->var->name);
16715 
16716          j++;
16717          if( j % 10 == 0 )
16718             SCIPmessageFPrintInfo(messagehdlr, file, "\n");
16719       }
16720    }
16721 
16722    SCIPmessageFPrintInfo(messagehdlr, file, "\nEnd");
16723    fclose(file);
16724 
16725    return SCIP_OKAY;
16726 }
16727 
16728 /*
16729  * simple functions implemented as defines
16730  */
16731 
16732 /* In debug mode, the following methods are implemented as function calls to ensure
16733  * type validity.
16734  * In optimized mode, the methods are implemented as defines to improve performance.
16735  * However, we want to have them in the library anyways, so we have to undef the defines.
16736  */
16737 
16738 #undef SCIPcolGetObj
16739 #undef SCIPcolGetLb
16740 #undef SCIPcolGetUb
16741 #undef SCIPcolGetBestBound
16742 #undef SCIPcolGetPrimsol
16743 #undef SCIPcolGetMinPrimsol
16744 #undef SCIPcolGetMaxPrimsol
16745 #undef SCIPcolGetBasisStatus
16746 #undef SCIPcolGetVar
16747 #undef SCIPcolGetIndex
16748 #undef SCIPcolGetVarProbindex
16749 #undef SCIPcolIsIntegral
16750 #undef SCIPcolIsRemovable
16751 #undef SCIPcolGetLPPos
16752 #undef SCIPcolGetLPDepth
16753 #undef SCIPcolIsInLP
16754 #undef SCIPcolGetNNonz
16755 #undef SCIPcolGetNLPNonz
16756 #undef SCIPcolGetRows
16757 #undef SCIPcolGetVals
16758 #undef SCIPcolGetStrongbranchNode
16759 #undef SCIPcolGetNStrongbranchs
16760 #undef SCIPcolGetAge
16761 #undef SCIPboundtypeOpposite
16762 #undef SCIProwGetNNonz
16763 #undef SCIProwGetNLPNonz
16764 #undef SCIProwGetCols
16765 #undef SCIProwGetVals
16766 #undef SCIProwGetConstant
16767 #undef SCIProwGetNorm
16768 #undef SCIProwGetSumNorm
16769 #undef SCIProwGetLhs
16770 #undef SCIProwGetRhs
16771 #undef SCIProwGetDualsol
16772 #undef SCIProwGetDualfarkas
16773 #undef SCIProwGetBasisStatus
16774 #undef SCIProwGetName
16775 #undef SCIProwGetIndex
16776 #undef SCIProwGetAge
16777 #undef SCIProwGetRank
16778 #undef SCIProwIsIntegral
16779 #undef SCIProwIsLocal
16780 #undef SCIProwIsModifiable
16781 #undef SCIProwIsRemovable
16782 #undef SCIProwGetOrigintype
16783 #undef SCIProwGetOriginCons
16784 #undef SCIProwGetOriginConshdlr
16785 #undef SCIProwGetOriginSepa
16786 #undef SCIProwIsInGlobalCutpool
16787 #undef SCIProwGetLPPos
16788 #undef SCIProwGetLPDepth
16789 #undef SCIProwIsInLP
16790 #undef SCIProwGetActiveLPCount
16791 #undef SCIProwGetNLPsAfterCreation
16792 #undef SCIProwChgRank
16793 #undef SCIPlpGetCols
16794 #undef SCIPlpGetNCols
16795 #undef SCIPlpGetRows
16796 #undef SCIPlpGetNRows
16797 #undef SCIPlpGetNewcols
16798 #undef SCIPlpGetNNewcols
16799 #undef SCIPlpGetNewrows
16800 #undef SCIPlpGetNNewrows
16801 #undef SCIPlpGetObjNorm
16802 #undef SCIPlpGetRootObjval
16803 #undef SCIPlpGetRootColumnObjval
16804 #undef SCIPlpGetRootLooseObjval
16805 #undef SCIPlpGetLPI
16806 #undef SCIPlpSetIsRelax
16807 #undef SCIPlpIsRelax
16808 #undef SCIPlpIsSolved
16809 #undef SCIPlpIsSolBasic
16810 #undef SCIPlpDiving
16811 #undef SCIPlpDivingObjChanged
16812 #undef SCIPlpMarkDivingObjChanged
16813 #undef SCIPlpUnmarkDivingObjChanged
16814 #undef SCIPlpDivingRowsChanged
16815 
16816 /** gets objective value of column */
SCIPcolGetObj(SCIP_COL * col)16817 SCIP_Real SCIPcolGetObj(
16818    SCIP_COL*             col                 /**< LP column */
16819    )
16820 {
16821    assert(col != NULL);
16822 
16823    return col->obj;
16824 }
16825 
16826 /** gets lower bound of column */
SCIPcolGetLb(SCIP_COL * col)16827 SCIP_Real SCIPcolGetLb(
16828    SCIP_COL*             col                 /**< LP column */
16829    )
16830 {
16831    assert(col != NULL);
16832 
16833    return col->lb;
16834 }
16835 
16836 /** gets upper bound of column */
SCIPcolGetUb(SCIP_COL * col)16837 SCIP_Real SCIPcolGetUb(
16838    SCIP_COL*             col                 /**< LP column */
16839    )
16840 {
16841    assert(col != NULL);
16842 
16843    return col->ub;
16844 }
16845 
16846 /** gets best bound of column with respect to the objective function */
SCIPcolGetBestBound(SCIP_COL * col)16847 SCIP_Real SCIPcolGetBestBound(
16848    SCIP_COL*             col                 /**< LP column */
16849    )
16850 {
16851    assert(col != NULL);
16852 
16853    if( col->obj >= 0.0 )
16854       return col->lb;
16855    else
16856       return col->ub;
16857 }
16858 
16859 /** gets the primal LP solution of a column */
SCIPcolGetPrimsol(SCIP_COL * col)16860 SCIP_Real SCIPcolGetPrimsol(
16861    SCIP_COL*             col                 /**< LP column */
16862    )
16863 {
16864    assert(col != NULL);
16865 
16866    if( col->lppos >= 0 )
16867       return col->primsol;
16868    else
16869       return 0.0;
16870 }
16871 
16872 /** gets the minimal LP solution value, this column ever assumed */
SCIPcolGetMinPrimsol(SCIP_COL * col)16873 SCIP_Real SCIPcolGetMinPrimsol(
16874    SCIP_COL*             col                 /**< LP column */
16875    )
16876 {
16877    assert(col != NULL);
16878 
16879    return col->minprimsol;
16880 }
16881 
16882 /** gets the maximal LP solution value, this column ever assumed */
SCIPcolGetMaxPrimsol(SCIP_COL * col)16883 SCIP_Real SCIPcolGetMaxPrimsol(
16884    SCIP_COL*             col                 /**< LP column */
16885    )
16886 {
16887    assert(col != NULL);
16888 
16889    return col->maxprimsol;
16890 }
16891 
16892 /** gets the basis status of a column in the LP solution; only valid for LPs with status SCIP_LPSOLSTAT_OPTIMAL
16893  *  and with SCIPisLPSolBasic(scip) == TRUE; returns SCIP_BASESTAT_ZERO for columns not in the current SCIP_LP
16894  */
SCIPcolGetBasisStatus(SCIP_COL * col)16895 SCIP_BASESTAT SCIPcolGetBasisStatus(
16896    SCIP_COL*             col                 /**< LP column */
16897    )
16898 {
16899    assert(col != NULL);
16900    assert(col->lppos >= 0 || (SCIP_BASESTAT)col->basisstatus == SCIP_BASESTAT_ZERO);
16901 
16902    return (SCIP_BASESTAT)col->basisstatus;
16903 }
16904 
16905 /** gets variable this column represents */
SCIPcolGetVar(SCIP_COL * col)16906 SCIP_VAR* SCIPcolGetVar(
16907    SCIP_COL*             col                 /**< LP column */
16908    )
16909 {
16910    assert(col != NULL);
16911 
16912    return col->var;
16913 }
16914 
16915 /** gets unique index of col */
SCIPcolGetIndex(SCIP_COL * col)16916 int SCIPcolGetIndex(
16917    SCIP_COL*             col                 /**< LP col */
16918    )
16919 {
16920    assert(col != NULL);
16921 
16922    return col->index;
16923 }
16924 
16925 /** gets probindex of corresponding variable */
SCIPcolGetVarProbindex(SCIP_COL * col)16926 int SCIPcolGetVarProbindex(
16927    SCIP_COL*             col                 /**< LP col */
16928    )
16929 {
16930    assert(col != NULL);
16931 
16932    return col->var_probindex;
16933 }
16934 
16935 /** returns whether the associated variable is of integral type (binary, integer, implicit integer) */
SCIPcolIsIntegral(SCIP_COL * col)16936 SCIP_Bool SCIPcolIsIntegral(
16937    SCIP_COL*             col                 /**< LP column */
16938    )
16939 {
16940    assert(col != NULL);
16941    assert(SCIPvarIsIntegral(col->var) == col->integral);
16942 
16943    return col->integral;
16944 }
16945 
16946 /** returns TRUE iff column is removable from the LP (due to aging or cleanup) */
SCIPcolIsRemovable(SCIP_COL * col)16947 SCIP_Bool SCIPcolIsRemovable(
16948    SCIP_COL*             col                 /**< LP column */
16949    )
16950 {
16951    assert(col != NULL);
16952 
16953    return col->removable;
16954 }
16955 
16956 /** gets position of column in current LP, or -1 if it is not in LP */
SCIPcolGetLPPos(SCIP_COL * col)16957 int SCIPcolGetLPPos(
16958    SCIP_COL*             col                 /**< LP column */
16959    )
16960 {
16961    assert(col != NULL);
16962    assert((col->lppos == -1) == (col->lpdepth == -1));
16963 
16964    return col->lppos;
16965 }
16966 
16967 /** gets depth in the tree where the column entered the LP, or -1 if it is not in LP */
SCIPcolGetLPDepth(SCIP_COL * col)16968 int SCIPcolGetLPDepth(
16969    SCIP_COL*             col                 /**< LP column */
16970    )
16971 {
16972    assert(col != NULL);
16973    assert((col->lppos == -1) == (col->lpdepth == -1));
16974 
16975    return col->lpdepth;
16976 }
16977 
16978 /** returns TRUE iff column is member of current LP */
SCIPcolIsInLP(SCIP_COL * col)16979 SCIP_Bool SCIPcolIsInLP(
16980    SCIP_COL*             col                 /**< LP column */
16981    )
16982 {
16983    assert(col != NULL);
16984    assert((col->lppos == -1) == (col->lpdepth == -1));
16985 
16986    return (col->lppos >= 0);
16987 }
16988 
16989 /** get number of nonzero entries in column vector */
SCIPcolGetNNonz(SCIP_COL * col)16990 int SCIPcolGetNNonz(
16991    SCIP_COL*             col                 /**< LP column */
16992    )
16993 {
16994    assert(col != NULL);
16995 
16996    return col->len;
16997 }
16998 
16999 /** get number of nonzero entries in column vector, that correspond to rows currently in the SCIP_LP;
17000  *
17001  *  @warning This method is only applicable on columns, that are completely linked to their rows (e.g. a column
17002  *  that is in the current LP and the LP was solved, or a column that was in a solved LP and didn't change afterwards
17003  */
SCIPcolGetNLPNonz(SCIP_COL * col)17004 int SCIPcolGetNLPNonz(
17005    SCIP_COL*             col                 /**< LP column */
17006    )
17007 {
17008    assert(col != NULL);
17009    assert(col->nunlinked == 0);
17010 
17011    return col->nlprows;
17012 }
17013 
17014 /** gets array with rows of nonzero entries */
SCIPcolGetRows(SCIP_COL * col)17015 SCIP_ROW** SCIPcolGetRows(
17016    SCIP_COL*             col                 /**< LP column */
17017    )
17018 {
17019    assert(col != NULL);
17020 
17021    return col->rows;
17022 }
17023 
17024 /** gets array with coefficients of nonzero entries */
SCIPcolGetVals(SCIP_COL * col)17025 SCIP_Real* SCIPcolGetVals(
17026    SCIP_COL*             col                 /**< LP column */
17027    )
17028 {
17029    assert(col != NULL);
17030 
17031    return col->vals;
17032 }
17033 
17034 /** gets node number of the last node in current branch and bound run, where strong branching was used on the
17035  *  given column, or -1 if strong branching was never applied to the column in current run
17036  */
SCIPcolGetStrongbranchNode(SCIP_COL * col)17037 SCIP_Longint SCIPcolGetStrongbranchNode(
17038    SCIP_COL*             col                 /**< LP column */
17039    )
17040 {
17041    assert(col != NULL);
17042 
17043    return col->sbnode;
17044 }
17045 
17046 /** gets number of times, strong branching was applied in current run on the given column */
SCIPcolGetNStrongbranchs(SCIP_COL * col)17047 int SCIPcolGetNStrongbranchs(
17048    SCIP_COL*             col                 /**< LP column */
17049    )
17050 {
17051    assert(col != NULL);
17052 
17053    return col->nsbcalls;
17054 }
17055 
17056 /** gets the age of a column, i.e., the total number of successive times a column was in the LP and was 0.0 in the solution */
SCIPcolGetAge(SCIP_COL * col)17057 int SCIPcolGetAge(
17058    SCIP_COL*             col                 /**< LP column */
17059    )
17060 {
17061    assert(col != NULL);
17062 
17063    return col->age;
17064 }
17065 
17066 /** gets opposite bound type of given bound type */
SCIPboundtypeOpposite(SCIP_BOUNDTYPE boundtype)17067 SCIP_BOUNDTYPE SCIPboundtypeOpposite(
17068    SCIP_BOUNDTYPE        boundtype           /**< type of bound (lower or upper) */
17069    )
17070 {
17071    assert(boundtype == SCIP_BOUNDTYPE_LOWER || boundtype == SCIP_BOUNDTYPE_UPPER);
17072 
17073    return (boundtype == SCIP_BOUNDTYPE_LOWER ? SCIP_BOUNDTYPE_UPPER : SCIP_BOUNDTYPE_LOWER);
17074 }
17075 
17076 /** get number of nonzero entries in row vector */
SCIProwGetNNonz(SCIP_ROW * row)17077 int SCIProwGetNNonz(
17078    SCIP_ROW*             row                 /**< LP row */
17079    )
17080 {
17081    assert(row != NULL);
17082 
17083    return row->len;
17084 }
17085 
17086 /** get number of nonzero entries in row vector, that correspond to columns currently in the SCIP_LP;
17087  *
17088  *  @warning This method is only applicable on rows, that are completely linked to their columns (e.g. a row
17089  *  that is in the current LP and the LP was solved, or a row that was in a solved LP and didn't change afterwards
17090  */
SCIProwGetNLPNonz(SCIP_ROW * row)17091 int SCIProwGetNLPNonz(
17092    SCIP_ROW*             row                 /**< LP row */
17093    )
17094 {
17095    assert(row != NULL);
17096    assert(row->nunlinked == 0);
17097 
17098    return row->nlpcols;
17099 }
17100 
17101 /** gets array with columns of nonzero entries */
SCIProwGetCols(SCIP_ROW * row)17102 SCIP_COL** SCIProwGetCols(
17103    SCIP_ROW*             row                 /**< LP row */
17104    )
17105 {
17106    assert(row != NULL);
17107 
17108    return row->cols;
17109 }
17110 
17111 /** gets array with coefficients of nonzero entries */
SCIProwGetVals(SCIP_ROW * row)17112 SCIP_Real* SCIProwGetVals(
17113    SCIP_ROW*             row                 /**< LP row */
17114    )
17115 {
17116    assert(row != NULL);
17117 
17118    return row->vals;
17119 }
17120 
17121 /** gets constant shift of row */
SCIProwGetConstant(SCIP_ROW * row)17122 SCIP_Real SCIProwGetConstant(
17123    SCIP_ROW*             row                 /**< LP row */
17124    )
17125 {
17126    assert(row != NULL);
17127 
17128    return row->constant;
17129 }
17130 
17131 /** gets Euclidean norm of row vector */
SCIProwGetNorm(SCIP_ROW * row)17132 SCIP_Real SCIProwGetNorm(
17133    SCIP_ROW*             row                 /**< LP row */
17134    )
17135 {
17136    assert(row != NULL);
17137 
17138    checkRowSqrnorm(row);
17139 
17140    return sqrt(row->sqrnorm);
17141 }
17142 
17143 /** gets sum norm of row vector (sum of absolute values of coefficients) */
SCIProwGetSumNorm(SCIP_ROW * row)17144 SCIP_Real SCIProwGetSumNorm(
17145    SCIP_ROW*             row                 /**< LP row */
17146    )
17147 {
17148    assert(row != NULL);
17149 
17150    checkRowSumnorm(row);
17151 
17152    return row->sumnorm;
17153 }
17154 
17155 /** returns the left hand side of the row */
SCIProwGetLhs(SCIP_ROW * row)17156 SCIP_Real SCIProwGetLhs(
17157    SCIP_ROW*             row                 /**< LP row */
17158    )
17159 {
17160    assert(row != NULL);
17161 
17162    return row->lhs;
17163 }
17164 
17165 /** returns the right hand side of the row */
SCIProwGetRhs(SCIP_ROW * row)17166 SCIP_Real SCIProwGetRhs(
17167    SCIP_ROW*             row                 /**< LP row */
17168    )
17169 {
17170    assert(row != NULL);
17171 
17172    return row->rhs;
17173 }
17174 
17175 /** gets the dual LP solution of a row */
SCIProwGetDualsol(SCIP_ROW * row)17176 SCIP_Real SCIProwGetDualsol(
17177    SCIP_ROW*             row                 /**< LP row */
17178    )
17179 {
17180    assert(row != NULL);
17181 
17182    if( row->lppos >= 0 )
17183       return row->dualsol;
17184    else
17185       return 0.0;
17186 }
17187 
17188 /** gets the dual Farkas coefficient of a row in an infeasible LP */
SCIProwGetDualfarkas(SCIP_ROW * row)17189 SCIP_Real SCIProwGetDualfarkas(
17190    SCIP_ROW*             row                 /**< LP row */
17191    )
17192 {
17193    assert(row != NULL);
17194 
17195    if( row->lppos >= 0 )
17196       return row->dualfarkas;
17197    else
17198       return 0.0;
17199 }
17200 
17201 /** gets the basis status of a row in the LP solution; only valid for LPs with status SCIP_LPSOLSTAT_OPTIMAL
17202  *  and with SCIPisLPSolBasic(scip) == TRUE; returns SCIP_BASESTAT_BASIC for rows not in the current SCIP_LP
17203  */
SCIProwGetBasisStatus(SCIP_ROW * row)17204 SCIP_BASESTAT SCIProwGetBasisStatus(
17205    SCIP_ROW*             row                 /**< LP row */
17206    )
17207 {
17208    assert(row != NULL);
17209    assert(row->lppos >= 0 || (SCIP_BASESTAT)row->basisstatus == SCIP_BASESTAT_BASIC);
17210 
17211    return (SCIP_BASESTAT)row->basisstatus;
17212 }
17213 
17214 /** returns the name of the row */
SCIProwGetName(SCIP_ROW * row)17215 const char* SCIProwGetName(
17216    SCIP_ROW*             row                 /**< LP row */
17217    )
17218 {
17219    assert(row != NULL);
17220 
17221    return row->name;
17222 }
17223 
17224 /** gets unique index of row */
SCIProwGetIndex(SCIP_ROW * row)17225 int SCIProwGetIndex(
17226    SCIP_ROW*             row                 /**< LP row */
17227    )
17228 {
17229    assert(row != NULL);
17230 
17231    return row->index;
17232 }
17233 
17234 /** gets age of row */
SCIProwGetAge(SCIP_ROW * row)17235 int SCIProwGetAge(
17236    SCIP_ROW*             row                 /**< LP row */
17237    )
17238 {
17239    assert(row != NULL);
17240 
17241    return row->age;
17242 }
17243 
17244 /** gets rank of row */
SCIProwGetRank(SCIP_ROW * row)17245 int SCIProwGetRank(
17246    SCIP_ROW*             row                 /**< LP row */
17247    )
17248 {
17249    assert(row != NULL);
17250 
17251    return row->rank;
17252 }
17253 
17254 /** returns TRUE iff the activity of the row (without the row's constant) is always integral in a feasible solution */
SCIProwIsIntegral(SCIP_ROW * row)17255 SCIP_Bool SCIProwIsIntegral(
17256    SCIP_ROW*             row                 /**< LP row */
17257    )
17258 {
17259    assert(row != NULL);
17260 
17261    return row->integral;
17262 }
17263 
17264 /** returns TRUE iff row is only valid locally */
SCIProwIsLocal(SCIP_ROW * row)17265 SCIP_Bool SCIProwIsLocal(
17266    SCIP_ROW*             row                 /**< LP row */
17267    )
17268 {
17269    assert(row != NULL);
17270 
17271    return row->local;
17272 }
17273 
17274 /** returns TRUE iff row is modifiable during node processing (subject to column generation) */
SCIProwIsModifiable(SCIP_ROW * row)17275 SCIP_Bool SCIProwIsModifiable(
17276    SCIP_ROW*             row                 /**< LP row */
17277    )
17278 {
17279    assert(row != NULL);
17280 
17281    return row->modifiable;
17282 }
17283 
17284 /** returns TRUE iff row is removable from the LP (due to aging or cleanup) */
SCIProwIsRemovable(SCIP_ROW * row)17285 SCIP_Bool SCIProwIsRemovable(
17286    SCIP_ROW*             row                 /**< LP row */
17287    )
17288 {
17289    assert(row != NULL);
17290 
17291    return row->removable;
17292 }
17293 
17294 /** returns type of origin that created the row */
SCIProwGetOrigintype(SCIP_ROW * row)17295 SCIP_ROWORIGINTYPE SCIProwGetOrigintype(
17296    SCIP_ROW*             row                 /**< LP row */
17297    )
17298 {
17299    assert( row != NULL );
17300 
17301    return (SCIP_ROWORIGINTYPE) row->origintype;
17302 }
17303 
17304 /** returns origin constraint that created the row (NULL if not available) */
SCIProwGetOriginCons(SCIP_ROW * row)17305 SCIP_CONS* SCIProwGetOriginCons(
17306    SCIP_ROW*             row                 /**< LP row */
17307    )
17308 {
17309    assert( row != NULL );
17310 
17311    if ( (SCIP_ROWORIGINTYPE) row->origintype == SCIP_ROWORIGINTYPE_CONS )
17312    {
17313       assert( row->origin != NULL );
17314       return (SCIP_CONS*) row->origin;
17315    }
17316    return NULL;
17317 }
17318 
17319 /** returns origin constraint handler that created the row (NULL if not available) */
SCIProwGetOriginConshdlr(SCIP_ROW * row)17320 SCIP_CONSHDLR* SCIProwGetOriginConshdlr(
17321    SCIP_ROW*             row                 /**< LP row */
17322    )
17323 {
17324    assert( row != NULL );
17325 
17326    if ( (SCIP_ROWORIGINTYPE) row->origintype == SCIP_ROWORIGINTYPE_CONSHDLR )
17327    {
17328       assert( row->origin != NULL );
17329       return (SCIP_CONSHDLR*) row->origin;
17330    }
17331    else if( (SCIP_ROWORIGINTYPE) row->origintype == SCIP_ROWORIGINTYPE_CONS )
17332    {
17333       assert(row->origin != NULL);
17334       return SCIPconsGetHdlr((SCIP_CONS*)row->origin);
17335    }
17336    return NULL;
17337 }
17338 
17339 /** returns origin separator that created the row (NULL if not available) */
SCIProwGetOriginSepa(SCIP_ROW * row)17340 SCIP_SEPA* SCIProwGetOriginSepa(
17341    SCIP_ROW*             row                 /**< LP row */
17342    )
17343 {
17344    assert( row != NULL );
17345 
17346    if ( (SCIP_ROWORIGINTYPE) row->origintype == SCIP_ROWORIGINTYPE_SEPA )
17347    {
17348       assert( row->origin != NULL );
17349       return (SCIP_SEPA*) row->origin;
17350    }
17351    return NULL;
17352 }
17353 
17354 /** returns TRUE iff row is member of the global cut pool */
SCIProwIsInGlobalCutpool(SCIP_ROW * row)17355 SCIP_Bool SCIProwIsInGlobalCutpool(
17356    SCIP_ROW*             row                 /**< LP row */
17357    )
17358 {
17359    assert(row != NULL);
17360 
17361    return row->inglobalcutpool;
17362 }
17363 
17364 /** gets position of row in current LP, or -1 if it is not in LP */
SCIProwGetLPPos(SCIP_ROW * row)17365 int SCIProwGetLPPos(
17366    SCIP_ROW*             row                 /**< LP row */
17367    )
17368 {
17369    assert(row != NULL);
17370    assert((row->lppos == -1) == (row->lpdepth == -1));
17371 
17372    return row->lppos;
17373 }
17374 
17375 /** gets depth in the tree where the row entered the LP, or -1 if it is not in LP */
SCIProwGetLPDepth(SCIP_ROW * row)17376 int SCIProwGetLPDepth(
17377    SCIP_ROW*             row                 /**< LP row */
17378    )
17379 {
17380    assert(row != NULL);
17381    assert((row->lppos == -1) == (row->lpdepth == -1));
17382 
17383    return row->lpdepth;
17384 }
17385 
17386 /** returns TRUE iff row is member of current LP */
SCIProwIsInLP(SCIP_ROW * row)17387 SCIP_Bool SCIProwIsInLP(
17388    SCIP_ROW*             row                 /**< LP row */
17389    )
17390 {
17391    assert(row != NULL);
17392    assert((row->lppos == -1) == (row->lpdepth == -1));
17393 
17394    return (row->lppos >= 0);
17395 }
17396 
17397 /** changes the rank of LP row */
SCIProwChgRank(SCIP_ROW * row,int rank)17398 void SCIProwChgRank(
17399    SCIP_ROW*             row,                /**< LP row */
17400    int                   rank                /**< new value for rank */
17401    )
17402 {
17403    assert(row != NULL);
17404 
17405    row->rank = rank;
17406 }
17407 
17408 /** returns the number of times that this row has been sharp in an optimal LP solution */
SCIProwGetActiveLPCount(SCIP_ROW * row)17409 SCIP_Longint SCIProwGetActiveLPCount(
17410    SCIP_ROW*             row                 /**< row */
17411    )
17412 {
17413    assert(row != NULL);
17414 
17415    return row->activeinlpcounter;
17416 }
17417 
17418 /** returns the number of LPs since this row has been created */
SCIProwGetNLPsAfterCreation(SCIP_ROW * row)17419 SCIP_Longint SCIProwGetNLPsAfterCreation(
17420    SCIP_ROW*             row                 /**< row */
17421    )
17422 {
17423    assert(row != NULL);
17424 
17425    return row->nlpsaftercreation;
17426 }
17427 
17428 /** gets array with columns of the LP */
SCIPlpGetCols(SCIP_LP * lp)17429 SCIP_COL** SCIPlpGetCols(
17430    SCIP_LP*              lp                  /**< current LP data */
17431    )
17432 {
17433    assert(lp != NULL);
17434 
17435    return lp->cols;
17436 }
17437 
17438 /** gets current number of columns in LP */
SCIPlpGetNCols(SCIP_LP * lp)17439 int SCIPlpGetNCols(
17440    SCIP_LP*              lp                  /**< current LP data */
17441    )
17442 {
17443    assert(lp != NULL);
17444 
17445    return lp->ncols;
17446 }
17447 
17448 /** gets array with rows of the LP */
SCIPlpGetRows(SCIP_LP * lp)17449 SCIP_ROW** SCIPlpGetRows(
17450    SCIP_LP*              lp                  /**< current LP data */
17451    )
17452 {
17453    assert(lp != NULL);
17454 
17455    return lp->rows;
17456 }
17457 
17458 /** gets current number of rows in LP */
SCIPlpGetNRows(SCIP_LP * lp)17459 int SCIPlpGetNRows(
17460    SCIP_LP*              lp                  /**< current LP data */
17461    )
17462 {
17463    assert(lp != NULL);
17464 
17465    return lp->nrows;
17466 }
17467 
17468 /** gets array with newly added columns after the last mark */
SCIPlpGetNewcols(SCIP_LP * lp)17469 SCIP_COL** SCIPlpGetNewcols(
17470    SCIP_LP*              lp                  /**< current LP data */
17471    )
17472 {
17473    assert(lp != NULL);
17474    assert(0 <= lp->firstnewcol && lp->firstnewcol <= lp->ncols);
17475 
17476    return &(lp->cols[lp->firstnewcol]);
17477 }
17478 
17479 /** gets number of newly added columns after the last mark */
SCIPlpGetNNewcols(SCIP_LP * lp)17480 int SCIPlpGetNNewcols(
17481    SCIP_LP*              lp                  /**< current LP data */
17482    )
17483 {
17484    assert(lp != NULL);
17485    assert(0 <= lp->firstnewcol && lp->firstnewcol <= lp->ncols);
17486 
17487    return lp->ncols - lp->firstnewcol;
17488 }
17489 
17490 /** gets array with newly added rows after the last mark */
SCIPlpGetNewrows(SCIP_LP * lp)17491 SCIP_ROW** SCIPlpGetNewrows(
17492    SCIP_LP*              lp                  /**< current LP data */
17493    )
17494 {
17495    assert(lp != NULL);
17496    assert(0 <= lp->firstnewrow && lp->firstnewrow <= lp->nrows);
17497 
17498    return &(lp->rows[lp->firstnewrow]);
17499 }
17500 
17501 /** gets number of newly added rows after the last mark */
SCIPlpGetNNewrows(SCIP_LP * lp)17502 int SCIPlpGetNNewrows(
17503    SCIP_LP*              lp                  /**< current LP data */
17504    )
17505 {
17506    assert(lp != NULL);
17507    assert(0 <= lp->firstnewrow && lp->firstnewrow <= lp->nrows);
17508 
17509    return lp->nrows - lp->firstnewrow;
17510 }
17511 
17512 /** recalculates Euclidean norm of objective function vector of column variables if it have gotten unreliable during calculation */
SCIPlpRecalculateObjSqrNorm(SCIP_SET * set,SCIP_LP * lp)17513 void SCIPlpRecalculateObjSqrNorm(
17514    SCIP_SET*             set,                /**< global SCIP settings */
17515    SCIP_LP*              lp                  /**< LP data */
17516    )
17517 {
17518    if( lp->objsqrnormunreliable )
17519    {
17520       SCIP_COL** cols;
17521       int c;
17522 
17523       cols = lp->cols;
17524       assert(cols != NULL || lp->ncols == 0);
17525 
17526       lp->objsqrnorm = 0.0;
17527 
17528       for( c = lp->ncols - 1; c >= 0; --c )
17529       {
17530          lp->objsqrnorm += SQR(cols[c]->unchangedobj);  /*lint !e613*/
17531       }
17532       assert(SCIPsetIsGE(set, lp->objsqrnorm, 0.0));
17533 
17534       /* due to numerical troubles it still can appear that lp->objsqrnorm is a little bit smaller than 0 */
17535       lp->objsqrnorm = MAX(lp->objsqrnorm, 0.0);
17536 
17537       lp->objsqrnormunreliable = FALSE;
17538    }
17539    return;
17540 }
17541 
17542 /** gets Euclidean norm of objective function vector of column variables, only use this method if
17543  *  lp->objsqrnormunreliable == FALSE, so probably you have to call SCIPlpRecalculateObjSqrNorm before */
SCIPlpGetObjNorm(SCIP_LP * lp)17544 SCIP_Real SCIPlpGetObjNorm(
17545    SCIP_LP*              lp                  /**< LP data */
17546    )
17547 {
17548    assert(lp != NULL);
17549    assert(!lp->objsqrnormunreliable);
17550    assert(lp->objsqrnorm >= 0.0);
17551 
17552    return SQRT(lp->objsqrnorm);
17553 }
17554 
17555 /** sets whether the root lp is a relaxation of the problem and its optimal objective value is a global lower bound */
SCIPlpSetRootLPIsRelax(SCIP_LP * lp,SCIP_Bool isrelax)17556 void SCIPlpSetRootLPIsRelax(
17557    SCIP_LP*              lp,                 /**< LP data */
17558    SCIP_Bool             isrelax             /**< is the root lp a relaxation of the problem? */
17559    )
17560 {
17561    assert(lp != NULL);
17562 
17563    lp->rootlpisrelax = isrelax;
17564 }
17565 
17566 /** returns whether the root lp is a relaxation of the problem and its optimal objective value is a global lower bound */
SCIPlpIsRootLPRelax(SCIP_LP * lp)17567 SCIP_Bool SCIPlpIsRootLPRelax(
17568    SCIP_LP*              lp                  /**< LP data */
17569    )
17570 {
17571    assert(lp != NULL);
17572 
17573    return lp->rootlpisrelax;
17574 }
17575 
17576 /** gets the objective value of the root node LP; returns SCIP_INVALID if the root node LP was not (yet) solved */
SCIPlpGetRootObjval(SCIP_LP * lp)17577 SCIP_Real SCIPlpGetRootObjval(
17578    SCIP_LP*              lp                  /**< LP data */
17579    )
17580 {
17581    assert(lp != NULL);
17582 
17583    return MIN(lp->rootlpobjval + lp->rootlooseobjval, SCIP_INVALID);
17584 }
17585 
17586 /** gets part of the objective value of the root node LP that results from COLUMN variables only;
17587  *  returns SCIP_INVALID if the root node LP was not (yet) solved
17588  */
SCIPlpGetRootColumnObjval(SCIP_LP * lp)17589 SCIP_Real SCIPlpGetRootColumnObjval(
17590    SCIP_LP*              lp                  /**< LP data */
17591    )
17592 {
17593    assert(lp != NULL);
17594 
17595    return lp->rootlpobjval;
17596 }
17597 
17598 /** gets part of the objective value of the root node LP that results from LOOSE variables only;
17599  *  returns SCIP_INVALID if the root node LP was not (yet) solved
17600  */
SCIPlpGetRootLooseObjval(SCIP_LP * lp)17601 SCIP_Real SCIPlpGetRootLooseObjval(
17602    SCIP_LP*              lp                  /**< LP data */
17603    )
17604 {
17605    assert(lp != NULL);
17606 
17607    return lp->rootlooseobjval;
17608 }
17609 
17610 /** gets the LP solver interface */
SCIPlpGetLPI(SCIP_LP * lp)17611 SCIP_LPI* SCIPlpGetLPI(
17612    SCIP_LP*              lp                  /**< current LP data */
17613    )
17614 {
17615    assert(lp != NULL);
17616 
17617    return lp->lpi;
17618 }
17619 
17620 /** sets whether the current LP is a relaxation of the current problem and its optimal objective value is a local lower bound */
SCIPlpSetIsRelax(SCIP_LP * lp,SCIP_Bool relax)17621 void SCIPlpSetIsRelax(
17622    SCIP_LP*              lp,                 /**< LP data */
17623    SCIP_Bool             relax               /**< is the current lp a relaxation? */
17624    )
17625 {
17626    assert(lp != NULL);
17627 
17628    lp->isrelax = relax;
17629 }
17630 
17631 /** returns whether the current LP is a relaxation of the problem for which it has been solved and its
17632  *  solution value a valid local lower bound?
17633  */
SCIPlpIsRelax(SCIP_LP * lp)17634 SCIP_Bool SCIPlpIsRelax(
17635    SCIP_LP*              lp                  /**< LP data */
17636    )
17637 {
17638    assert(lp != NULL);
17639 
17640    return lp->isrelax;
17641 }
17642 
17643 /** returns whether the current LP is flushed and solved */
SCIPlpIsSolved(SCIP_LP * lp)17644 SCIP_Bool SCIPlpIsSolved(
17645    SCIP_LP*              lp                  /**< current LP data */
17646    )
17647 {
17648    assert(lp != NULL);
17649 
17650    return lp->flushed && lp->solved;
17651 }
17652 
17653 /** return whether the current LP solution passed the primal feasibility check */
SCIPlpIsPrimalReliable(SCIP_LP * lp)17654 SCIP_Bool SCIPlpIsPrimalReliable(
17655    SCIP_LP*              lp                  /**< current LP data */
17656    )
17657 {
17658    assert(lp != NULL);
17659 
17660    return (lp->primalchecked && lp->primalfeasible);
17661 }
17662 
17663 /** return whether the current LP solution passed the dual feasibility check */
SCIPlpIsDualReliable(SCIP_LP * lp)17664 SCIP_Bool SCIPlpIsDualReliable(
17665    SCIP_LP*              lp                  /**< current LP data */
17666    )
17667 {
17668    assert(lp != NULL);
17669 
17670    return (lp->dualchecked && lp->dualfeasible);
17671 }
17672 
17673 /** returns whether the current LP solution is a basic solution */
SCIPlpIsSolBasic(SCIP_LP * lp)17674 SCIP_Bool SCIPlpIsSolBasic(
17675    SCIP_LP*              lp                  /**< current LP data */
17676    )
17677 {
17678    assert(lp != NULL);
17679 
17680    return lp->solisbasic;
17681 }
17682 
17683 /** returns whether the LP is in diving mode */
SCIPlpDiving(SCIP_LP * lp)17684 SCIP_Bool SCIPlpDiving(
17685    SCIP_LP*              lp                  /**< current LP data */
17686    )
17687 {
17688    assert(lp != NULL);
17689 
17690    return lp->diving;
17691 }
17692 
17693 /** returns whether the LP is in diving mode and the objective value of at least one column was changed */
SCIPlpDivingObjChanged(SCIP_LP * lp)17694 SCIP_Bool SCIPlpDivingObjChanged(
17695    SCIP_LP*              lp                  /**< current LP data */
17696    )
17697 {
17698    assert(lp != NULL);
17699 
17700    return lp->divingobjchg;
17701 }
17702 
17703 /** marks the diving LP to have a changed objective function */
SCIPlpMarkDivingObjChanged(SCIP_LP * lp)17704 void SCIPlpMarkDivingObjChanged(
17705    SCIP_LP*              lp                  /**< current LP data */
17706    )
17707 {
17708    assert(lp != NULL);
17709    assert(lp->diving || lp->probing);
17710 
17711    lp->divingobjchg = TRUE;
17712 }
17713 
17714 /** marks the diving LP to not have a changed objective function anymore */
SCIPlpUnmarkDivingObjChanged(SCIP_LP * lp)17715 void SCIPlpUnmarkDivingObjChanged(
17716    SCIP_LP*              lp                  /**< current LP data */
17717    )
17718 {
17719    assert(lp != NULL);
17720    assert(lp->diving || lp->probing);
17721 
17722    lp->divingobjchg = FALSE;
17723 }
17724 
17725 /* returns TRUE if at least one left/right hand side of an LP row was changed during diving mode */
SCIPlpDivingRowsChanged(SCIP_LP * lp)17726 SCIP_Bool SCIPlpDivingRowsChanged(
17727    SCIP_LP*              lp                  /**< current LP data */
17728    )
17729 {
17730    assert(lp != NULL);
17731    assert(lp->diving || lp->ndivechgsides == 0);
17732 
17733    return (lp->ndivechgsides > 0);
17734 }
17735 
17736 /** compute relative interior point with auxiliary lpi, see SCIPlpComputeRelIntPoint() */
17737 static
computeRelIntPoint(SCIP_LPI * lpi,SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr,SCIP_LP * lp,SCIP_PROB * prob,SCIP_Bool relaxrows,SCIP_Bool inclobjcutoff,SCIP_Real timelimit,int iterlimit,SCIP_Real * point,SCIP_Bool * success)17738 SCIP_RETCODE computeRelIntPoint(
17739    SCIP_LPI*             lpi,                /**< auxiliary LP interface */
17740    SCIP_SET*             set,                /**< global SCIP settings */
17741    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
17742    SCIP_LP*              lp,                 /**< LP data */
17743    SCIP_PROB*            prob,               /**< problem data */
17744    SCIP_Bool             relaxrows,          /**< should the rows be relaxed */
17745    SCIP_Bool             inclobjcutoff,      /**< should a row for the objective cutoff be included */
17746    SCIP_Real             timelimit,          /**< time limit for LP solver */
17747    int                   iterlimit,          /**< iteration limit for LP solver */
17748    SCIP_Real*            point,              /**< array to store relative interior point on exit */
17749    SCIP_Bool*            success             /**< buffer to indicate whether interior point was successfully computed */
17750    )
17751 {
17752    SCIP_RETCODE retcode;
17753    SCIP_Real* primal;
17754    SCIP_Real* obj;
17755    SCIP_Real* lb;
17756    SCIP_Real* ub;
17757    SCIP_Real* matvals;
17758    SCIP_Real* matlhs;
17759    SCIP_Real* matrhs;
17760    SCIP_Real objval;
17761    SCIP_Real alpha;
17762    int* matinds;
17763    int* matbeg;
17764 #ifndef NDEBUG
17765    int nslacks;
17766 #endif
17767    int nnewcols;
17768    int ntotnonz = 0;
17769    int ntotrows = 0;
17770    int matrowidx;
17771    int matidx;
17772    int cnt;
17773    int j;
17774    int i;
17775 
17776    assert(lpi != NULL);
17777 
17778    retcode = SCIPlpiSetRealpar(lpi, SCIP_LPPAR_FEASTOL, lp->feastol);
17779    if( retcode != SCIP_OKAY )
17780    {
17781       /* stop execution on error, since result is likely to be unsuable */
17782       SCIPmessagePrintWarning(messagehdlr, "Could not set feasibility tolerance of LP solver for relative interior point computation.\n");
17783       return SCIP_LPERROR;
17784    }
17785 
17786    retcode = SCIPlpiSetRealpar(lpi, SCIP_LPPAR_DUALFEASTOL, SCIPsetDualfeastol(set));
17787    if( retcode != SCIP_OKAY )
17788    {
17789       /* stop execution on error, since result is likely to be unsuable */
17790       SCIPmessagePrintWarning(messagehdlr, "Could not set dual feasibility tolerance of LP solver for relative interior point computation.\n");
17791       return SCIP_LPERROR;
17792    }
17793 
17794    /* get storage */
17795    nnewcols = 3*lp->ncols + 2*lp->nrows + (inclobjcutoff ? 1 : 0) + 1;
17796    SCIP_CALL( SCIPsetAllocBufferArray(set, &lb, nnewcols) );
17797    SCIP_CALL( SCIPsetAllocBufferArray(set, &ub, nnewcols) );
17798    SCIP_CALL( SCIPsetAllocBufferArray(set, &obj, nnewcols) );
17799 
17800    /* create original columns (bounds are relaxed below, unless the variable is fixed) */
17801    for( j = 0; j < lp->ncols; ++j )
17802    {
17803       /* note: if the variable is fixed we cannot simply fix the variables (because alpha scales the problem) */
17804       obj[j] = 0.0;
17805       lb[j] = -SCIPlpiInfinity(lpi);
17806       ub[j] =  SCIPlpiInfinity(lpi);
17807       /* note: we could also use the original bounds - free variables seem to be faster. */
17808    }
17809 
17810    /* add artificial alpha variable */
17811    nnewcols = lp->ncols;
17812    obj[nnewcols] = 0.0;
17813    lb[nnewcols] = 1.0;
17814    ub[nnewcols] = SCIPlpiInfinity(lpi);
17815    ++nnewcols;
17816 
17817    /* create slacks for rows */
17818    for( i = 0; i < lp->nrows; ++i )
17819    {
17820       SCIP_ROW* row;
17821 
17822       row = lp->rows[i];
17823       assert( row != NULL );
17824 
17825       if( SCIProwIsModifiable(row) )
17826          continue;
17827 
17828       /* make sure row is sorted */
17829       rowSortLP(row);
17830       assert( row->lpcolssorted );
17831 
17832       /* check whether we have an equation */
17833       if( SCIPsetIsEQ(set, row->lhs, row->rhs) )
17834       {
17835          assert( !SCIPsetIsInfinity(set, REALABS(row->lhs)) );
17836          assert( !SCIPsetIsInfinity(set, REALABS(row->rhs)) );
17837          ntotnonz += row->nlpcols + 1;
17838          ++ntotrows;
17839       }
17840       else
17841       {
17842          /* otherwise add slacks for each side if necessary */
17843          if ( ! SCIPsetIsInfinity(set, REALABS(row->lhs)) )
17844          {
17845             if ( relaxrows )
17846             {
17847                lb[nnewcols] = 0.0;
17848                ub[nnewcols] = 1.0;
17849                obj[nnewcols++] = 1.0;
17850                ntotnonz += row->nlpcols + 2;
17851             }
17852             else
17853                ntotnonz += row->nlpcols + 1;
17854             ++ntotrows;
17855          }
17856          if ( ! SCIPsetIsInfinity(set, REALABS(row->rhs)) )
17857          {
17858             if ( relaxrows )
17859             {
17860                lb[nnewcols] = 0.0;
17861                ub[nnewcols] = 1.0;
17862                obj[nnewcols++] = 1.0;
17863                ntotnonz += row->nlpcols + 2;
17864             }
17865             else
17866                ntotnonz += row->nlpcols + 1;
17867             ++ntotrows;
17868          }
17869       }
17870    }
17871 
17872    /* create slacks for objective cutoff row */
17873    if( inclobjcutoff && relaxrows )
17874    {
17875       /* add slacks for right hand side */
17876       lb[nnewcols] = 0.0;
17877       ub[nnewcols] = 1.0;
17878       obj[nnewcols++] = 1.0;
17879       ntotnonz += lp->ncols + 2;
17880       ++ntotrows;
17881    }
17882 
17883    /* create slacks for bounds */
17884    for( j = 0; j < lp->ncols; ++j )
17885    {
17886       SCIP_COL* col;
17887 
17888       col = lp->cols[j];
17889       assert( col != NULL );
17890 
17891       /* no slacks for fixed variables */
17892       if( SCIPsetIsEQ(set, col->lb, col->ub) )
17893       {
17894          ++ntotrows;
17895          ntotnonz += 2;
17896       }
17897       else
17898       {
17899          /* add slacks for each bound if necessary */
17900          if ( ! SCIPsetIsInfinity(set, REALABS(col->lb)) )
17901          {
17902             lb[nnewcols] = 0.0;
17903             ub[nnewcols] = 1.0;
17904             obj[nnewcols++] = 1.0;
17905             ntotnonz += 3;
17906             ++ntotrows;
17907          }
17908          if( ! SCIPsetIsInfinity(set, REALABS(col->ub)) )
17909          {
17910             lb[nnewcols] = 0.0;
17911             ub[nnewcols] = 1.0;
17912             obj[nnewcols++] = 1.0;
17913             ntotnonz += 3;
17914             ++ntotrows;
17915          }
17916       }
17917    }
17918 #ifndef NDEBUG
17919    nslacks = nnewcols - lp->ncols - 1;
17920    assert( nslacks >= 0 );
17921    assert( nnewcols <= 3*lp->ncols + 2*lp->nrows + (inclobjcutoff ? 1 : 0) + 1 );
17922 #endif
17923 
17924    /* add columns */
17925    SCIP_CALL( SCIPlpiAddCols(lpi, nnewcols, obj, lb, ub, NULL, 0, NULL, NULL, NULL) );
17926 
17927    /* free storage */
17928    SCIPsetFreeBufferArray(set, &obj);
17929    SCIPsetFreeBufferArray(set, &ub);
17930    SCIPsetFreeBufferArray(set, &lb);
17931 
17932    /* prepare storage for rows */
17933    SCIP_CALL( SCIPsetAllocBufferArray(set, &matinds, ntotnonz) );
17934    SCIP_CALL( SCIPsetAllocBufferArray(set, &matvals, ntotnonz) );
17935    SCIP_CALL( SCIPsetAllocBufferArray(set, &matbeg, ntotrows) );
17936    SCIP_CALL( SCIPsetAllocBufferArray(set, &matlhs, ntotrows) );
17937    SCIP_CALL( SCIPsetAllocBufferArray(set, &matrhs, ntotrows) );
17938 
17939    /* create rows arising from original rows */
17940    cnt = 0;
17941    matrowidx = 0;
17942    matidx = 0;
17943    for( i = 0; i < lp->nrows; ++i )
17944    {
17945       SCIP_ROW* row;
17946       SCIP_COL** rowcols;
17947       SCIP_Real* rowvals;
17948       SCIP_Real lhs;
17949       SCIP_Real rhs;
17950       int nnonz;
17951 
17952       row = lp->rows[i];
17953       assert( row != NULL );
17954 
17955       if( SCIProwIsModifiable(row) )
17956          continue;
17957       assert( row->lpcolssorted );
17958 
17959       /* get row data */
17960       lhs = row->lhs - (SCIPsetIsInfinity(set, -row->lhs) ? 0.0 : row->constant);
17961       rhs = row->rhs - (SCIPsetIsInfinity(set,  row->rhs) ? 0.0 : row->constant);
17962       nnonz = row->nlpcols;
17963       assert( nnonz <= lp->ncols );
17964       rowcols = row->cols;
17965       rowvals = row->vals;
17966 
17967       /* if we have an equation */
17968       if( SCIPsetIsEQ(set, lhs, rhs) )
17969       {
17970          /* set up indices */
17971          matbeg[matrowidx] = matidx;
17972          for( j = 0; j < nnonz; ++j )
17973          {
17974             assert( rowcols[j] != NULL );
17975             assert( 0 <= rowcols[j]->lppos && rowcols[j]->lppos < lp->ncols );
17976             assert( lp->cols[rowcols[j]->lppos] == rowcols[j] );
17977             assert( ! SCIPsetIsZero(set, rowvals[j]) );
17978             matinds[matidx] = rowcols[j]->lppos;
17979             matvals[matidx++] = rowvals[j];
17980             assert( matidx <= ntotnonz );
17981          }
17982 
17983          /* add artificial variable */
17984          if ( ! SCIPsetIsZero(set, rhs) )
17985          {
17986             matinds[matidx] = lp->ncols;
17987             matvals[matidx++] = -rhs;
17988             assert( matidx <= ntotnonz );
17989          }
17990 
17991          matlhs[matrowidx] = 0.0;
17992          matrhs[matrowidx++] = 0.0;
17993          assert( matrowidx <= ntotrows );
17994       }
17995       else
17996       {
17997          SCIP_Real abslhs = REALABS(lhs);
17998          SCIP_Real absrhs = REALABS(rhs);
17999 
18000          assert(!SCIPsetIsEQ(set, lhs, rhs));
18001 
18002          /* treat lhs */
18003          if( !SCIPsetIsInfinity(set, abslhs) )
18004          {
18005             /* set up indices */
18006             matbeg[matrowidx] = matidx;
18007             for( j = 0; j < nnonz; ++j )
18008             {
18009                assert( rowcols[j] != NULL );
18010                assert( 0 <= rowcols[j]->lppos && rowcols[j]->lppos < lp->ncols );
18011                assert( lp->cols[rowcols[j]->lppos] == rowcols[j] );
18012                assert( ! SCIPsetIsZero(set, rowvals[j]) );
18013                matinds[matidx] = rowcols[j]->lppos;
18014                matvals[matidx++] = rowvals[j];
18015                assert( matidx <= ntotnonz );
18016             }
18017 
18018             /* add artificial variable */
18019             if ( ! SCIPsetIsZero(set, lhs) )
18020             {
18021                matinds[matidx] = lp->ncols;
18022                matvals[matidx++] = -lhs;
18023                assert( matidx <= ntotnonz );
18024             }
18025 
18026             if( relaxrows )
18027             {
18028                /* add slack variable */
18029                matvals[matidx] = -MAX(1.0, lhs);      /*lint !e679*/
18030                matinds[matidx++] = lp->ncols + 1 + cnt; /*lint !e679*/
18031                assert( matidx <= ntotnonz );
18032                ++cnt;
18033             }
18034 
18035             matlhs[matrowidx] = 0.0;
18036             matrhs[matrowidx++] = SCIPlpiInfinity(lpi);
18037             assert( matrowidx <= ntotrows );
18038          }
18039 
18040          /* treat rhs */
18041          if( !SCIPsetIsInfinity(set, absrhs) )
18042          {
18043             /* set up indices */
18044             matbeg[matrowidx] = matidx;
18045             for( j = 0; j < nnonz; ++j )
18046             {
18047                assert( rowcols[j] != NULL );
18048                assert( 0 <= rowcols[j]->lppos && rowcols[j]->lppos < lp->ncols );
18049                assert( lp->cols[rowcols[j]->lppos] == rowcols[j] );
18050                assert( ! SCIPsetIsZero(set, rowvals[j]) );
18051                matinds[matidx] = rowcols[j]->lppos;
18052                matvals[matidx++] = rowvals[j];
18053                assert( matidx <= ntotnonz );
18054             }
18055 
18056             /* add artificial variable */
18057             if ( ! SCIPsetIsZero(set, rhs) )
18058             {
18059                matinds[matidx] = lp->ncols;
18060                matvals[matidx++] = -rhs;
18061                assert( matidx <= ntotnonz );
18062             }
18063 
18064             if( relaxrows )
18065             {
18066                /* add slack variable */
18067                matvals[matidx] = MAX(1.0, absrhs);    /*lint !e679*/
18068                matinds[matidx++] = lp->ncols + 1 + cnt; /*lint !e679*/
18069                ++cnt;
18070             }
18071 
18072             matlhs[matrowidx] = -SCIPlpiInfinity(lpi);
18073             matrhs[matrowidx++] = 0.0;
18074             assert( matrowidx <= ntotrows );
18075          }
18076       }
18077    }
18078 
18079    /* create row arising from objective cutoff */
18080    if( inclobjcutoff )
18081    {
18082       SCIP_Real rhs;
18083 
18084       /* get row data */
18085       assert(lp->looseobjvalinf == 0);
18086       rhs = lp->cutoffbound - getFiniteLooseObjval(lp, set, prob);
18087 
18088       /* set up indices and coefficients */
18089       matbeg[matrowidx] = matidx;
18090       for( j = 0; j < lp->ncols; ++j )
18091       {
18092          assert( lp->cols[j] != NULL );
18093          assert( 0 <= lp->cols[j]->lppos && lp->cols[j]->lppos < lp->ncols );
18094          assert( lp->cols[lp->cols[j]->lppos] == lp->cols[j] );
18095 
18096          if( ! SCIPsetIsZero(set, lp->cols[j]->obj) )
18097          {
18098             matinds[matidx] = lp->cols[j]->lppos;
18099             matvals[matidx++] = lp->cols[j]->obj;
18100             assert( matidx <= ntotnonz );
18101          }
18102       }
18103 
18104       /* treat rhs */
18105 
18106       /* add artificial variable */
18107       if ( ! SCIPsetIsZero(set, rhs) )
18108       {
18109          matinds[matidx] = lp->ncols;
18110          matvals[matidx++] = -rhs;
18111          assert( matidx <= ntotnonz );
18112       }
18113 
18114       if( relaxrows )
18115       {
18116          SCIP_Real absrhs = REALABS(rhs);
18117 
18118          /* add slack variable */
18119          matvals[matidx] = MAX(1.0, absrhs);
18120          matinds[matidx++] = lp->ncols + 1 + cnt;
18121          assert( matidx <= ntotnonz );
18122          ++cnt;
18123       }
18124       matlhs[matrowidx] = -SCIPsetInfinity(set);
18125       matrhs[matrowidx++] = 0.0;
18126       assert( matrowidx <= ntotrows );
18127    }
18128 
18129    /* create rows arising from bounds */
18130    for( j = 0; j < lp->ncols; ++j )
18131    {
18132       SCIP_COL* col;
18133       SCIP_Real abscollb;
18134       SCIP_Real abscolub;
18135 
18136       col = lp->cols[j];
18137       assert( col != NULL );
18138       assert( col->lppos == j );
18139 
18140       /* fixed variable */
18141       if( SCIPsetIsEQ(set, col->lb, col->ub) )
18142       {
18143          /* set up index of column */
18144          matbeg[matrowidx] = matidx;
18145 
18146          matinds[matidx] = j;
18147          matvals[matidx++] = 1.0;
18148          assert( matidx <= ntotnonz );
18149 
18150          /* add artificial variable */
18151          if ( ! SCIPsetIsZero(set, col->ub) )
18152          {
18153             matinds[matidx] = lp->ncols;
18154             matvals[matidx++] = -col->ub;
18155             assert( matidx <= ntotnonz );
18156          }
18157 
18158          matlhs[matrowidx] = 0.0;
18159          matrhs[matrowidx++] = 0.0;
18160          assert( matrowidx <= ntotrows );
18161 
18162          continue;
18163       }
18164 
18165       abscollb = REALABS(col->lb);
18166       abscolub = REALABS(col->ub);
18167 
18168       /* lower bound */
18169       if ( ! SCIPsetIsInfinity(set, abscollb) )
18170       {
18171          /* set up index of column */
18172          matbeg[matrowidx] = matidx;
18173 
18174          matinds[matidx] = j;
18175          matvals[matidx++] = 1.0;
18176          assert( matidx <= ntotnonz );
18177 
18178          /* add artificial variable */
18179          if ( ! SCIPsetIsZero(set, col->lb) )
18180          {
18181             matinds[matidx] = lp->ncols;
18182             matvals[matidx++] = -col->lb;
18183             assert( matidx <= ntotnonz );
18184          }
18185 
18186          /* add slack variable */
18187          matvals[matidx] = -MAX(1.0, abscollb);
18188          matinds[matidx++] = lp->ncols + 1 + cnt;
18189          assert( matidx <= ntotnonz );
18190          ++cnt;
18191 
18192          matlhs[matrowidx] = 0.0;
18193          matrhs[matrowidx++] = SCIPsetInfinity(set);
18194          assert( matrowidx <= ntotrows );
18195       }
18196 
18197       /* upper bound */
18198       if ( ! SCIPsetIsInfinity(set, abscolub) )
18199       {
18200          /* set up index of column */
18201          matbeg[matrowidx] = matidx;
18202 
18203          matinds[matidx] = j;
18204          matvals[matidx++] = 1.0;
18205          assert( matidx <= ntotnonz );
18206 
18207          /* add artificial variable */
18208          if ( ! SCIPsetIsZero(set, col->ub) )
18209          {
18210             matinds[matidx] = lp->ncols;
18211             matvals[matidx++] = -col->ub;
18212             assert( matidx <= ntotnonz );
18213          }
18214 
18215          /* add slack variable */
18216          matvals[matidx] = MAX(1.0, abscolub);
18217          matinds[matidx++] = lp->ncols + 1 + cnt;
18218          assert( matidx <= ntotnonz );
18219          ++cnt;
18220 
18221          matlhs[matrowidx] = -SCIPsetInfinity(set);
18222          matrhs[matrowidx++] = 0.0;
18223          assert( matrowidx <= ntotrows );
18224       }
18225    }
18226    assert( cnt == nslacks );
18227    assert( matrowidx == ntotrows );
18228 
18229    /* add rows */
18230    SCIP_CALL( SCIPlpiAddRows(lpi, ntotrows, matlhs, matrhs, NULL, matidx, matbeg, matinds, matvals) );
18231 
18232    SCIPsetFreeBufferArray(set, &matrhs);
18233    SCIPsetFreeBufferArray(set, &matlhs);
18234    SCIPsetFreeBufferArray(set, &matbeg);
18235    SCIPsetFreeBufferArray(set, &matvals);
18236    SCIPsetFreeBufferArray(set, &matinds);
18237 
18238 #ifdef SCIP_OUTPUT
18239    SCIP_CALL( SCIPlpiWriteLP(lpi, "relativeInterior.lp") );
18240 #endif
18241 
18242 #ifndef NDEBUG
18243    {
18244       int ncols;
18245       SCIP_CALL( SCIPlpiGetNCols(lpi, &ncols) );
18246       assert( ncols == nnewcols );
18247    }
18248 #endif
18249 
18250    /* set time limit */
18251    if( SCIPsetIsInfinity(set, timelimit) )
18252       timelimit = SCIPlpiInfinity(lpi);
18253    retcode = SCIPlpiSetRealpar(lpi, SCIP_LPPAR_LPTILIM, timelimit);
18254 
18255    /* check, if parameter is unknown */
18256    if( retcode == SCIP_PARAMETERUNKNOWN )
18257       SCIPmessagePrintWarning(messagehdlr, "Could not set time limit of LP solver for relative interior point computation.\n");
18258    else if ( retcode != SCIP_OKAY )
18259       return retcode;
18260 
18261    /* set iteration limit */
18262    retcode = SCIPlpiSetIntpar(lpi, SCIP_LPPAR_LPITLIM, iterlimit);
18263 
18264    /* check, if parameter is unknown */
18265    if( retcode == SCIP_PARAMETERUNKNOWN )
18266       SCIPmessagePrintWarning(messagehdlr, "Could not set iteration limit of LP solver for relative interior point computation.\n");
18267    else if ( retcode != SCIP_OKAY )
18268       return retcode;
18269 
18270    /* solve and store point */
18271    /* SCIP_CALL( SCIPlpiSolvePrimal(lpi) ); */
18272    SCIP_CALL( SCIPlpiSolveDual(lpi) );   /* dual is usually faster */
18273 
18274 #ifndef NDEBUG
18275    if ( SCIPlpiIsIterlimExc(lpi) )
18276       SCIPmessagePrintWarning(messagehdlr, "Iteration limit exceeded in relative interior point computation.\n");
18277    if ( SCIPlpiIsTimelimExc(lpi) )
18278       SCIPmessagePrintWarning(messagehdlr, "Time limit exceeded in relative interior point computation.\n");
18279 #endif
18280 
18281    if( SCIPlpiIsOptimal(lpi) )
18282    {
18283       /* get primal solution */
18284       SCIP_CALL( SCIPsetAllocBufferArray(set, &primal, nnewcols) );
18285       SCIP_CALL( SCIPlpiGetSol(lpi, &objval, primal, NULL, NULL, NULL) );
18286       alpha = primal[lp->ncols];
18287       assert( SCIPsetIsFeasGE(set, alpha, 1.0) );
18288 
18289       SCIPsetDebugMsg(set, "Solved relative interior lp with objective %g.\n", objval);
18290 
18291       /* construct relative interior point */
18292       for( j = 0; j < lp->ncols; ++j )
18293          point[j] = primal[j]/alpha;
18294 
18295 #ifdef SCIP_DEBUG
18296       /* check whether the point is a relative interior point */
18297       cnt = 0;
18298       if( relaxrows )
18299       {
18300          for( i = 0; i < lp->nrows; ++i )
18301          {
18302             SCIP_ROW* row;
18303             SCIP_COL** rowcols;
18304             SCIP_Real* rowvals;
18305             SCIP_Real lhs;
18306             SCIP_Real rhs;
18307             SCIP_Real sum;
18308             int nnonz;
18309 
18310             row = lp->rows[i];
18311             assert( row != NULL );
18312 
18313             /* get row data */
18314             lhs = row->lhs - (SCIPsetIsInfinity(set, -row->lhs) ? 0.0 : row->constant);
18315             rhs = row->rhs - (SCIPsetIsInfinity(set,  row->rhs) ? 0.0 : row->constant);
18316             nnonz = row->nlpcols;
18317             assert( nnonz <= lp->ncols );
18318             rowcols = row->cols;
18319             rowvals = row->vals;
18320 
18321             sum = 0.0;
18322             for( j = 0; j < nnonz; ++j )
18323                sum += rowvals[j] * primal[rowcols[j]->lppos];
18324             sum /= alpha;
18325 
18326             /* if we have an equation */
18327             if( SCIPsetIsEQ(set, lhs, rhs) )
18328             {
18329                assert( SCIPsetIsFeasEQ(set, sum, lhs) );
18330             }
18331             else
18332             {
18333                /* treat lhs */
18334                if( !SCIPsetIsInfinity(set, REALABS(lhs)) )
18335                {
18336                   assert( SCIPsetIsFeasZero(set, primal[lp->ncols+1+cnt]) || SCIPsetIsFeasGT(set, sum, lhs) );
18337                   ++cnt;
18338                }
18339                /* treat rhs */
18340                if( !SCIPsetIsInfinity(set, REALABS(rhs)) )
18341                {
18342                   assert( SCIPsetIsFeasZero(set, primal[lp->ncols+1+cnt]) || SCIPsetIsFeasLT(set, sum, rhs) );
18343                   ++cnt;
18344                }
18345             }
18346          }
18347          if( inclobjcutoff )
18348          {
18349             SCIP_Real sum;
18350 #ifndef NDEBUG
18351             SCIP_Real rhs;
18352 
18353             rhs = lp->cutoffbound - getFiniteLooseObjval(lp, set, prob);
18354 #endif
18355             sum = 0.0;
18356             for( j = 0; j < lp->ncols; ++j )
18357                sum += lp->cols[j]->obj * primal[lp->cols[j]->lppos];
18358             sum /= alpha;
18359 
18360             assert( SCIPsetIsFeasZero(set, primal[lp->ncols+1+cnt]) || SCIPsetIsFeasLT(set, sum, rhs) );
18361             ++cnt;
18362          }
18363       }
18364       /* check bounds */
18365       for( j = 0; j < lp->ncols; ++j )
18366       {
18367          SCIP_COL* col;
18368 #ifndef NDEBUG
18369          SCIP_Real val;
18370 #endif
18371 
18372          col = lp->cols[j];
18373          assert( col != NULL );
18374 #ifndef NDEBUG
18375          val = primal[col->lppos] / alpha;
18376 #endif
18377          /* if the variable is not fixed */
18378          if( !SCIPsetIsEQ(set, col->lb, col->ub) )
18379          {
18380             /* treat lb */
18381             if( !SCIPsetIsInfinity(set, REALABS(col->lb)) )
18382             {
18383                assert( SCIPsetIsFeasZero(set, primal[lp->ncols+1+cnt]) || SCIPsetIsFeasGT(set, val, col->lb) );
18384                ++cnt;
18385             }
18386             /* treat rhs */
18387             if( !SCIPsetIsInfinity(set, REALABS(col->ub)) )
18388             {
18389                assert( SCIPsetIsFeasZero(set, primal[lp->ncols+1+cnt]) || SCIPsetIsFeasLT(set, val, col->ub) );
18390                ++cnt;
18391             }
18392          }
18393       }
18394 #endif
18395 
18396       /* free */
18397       SCIPsetFreeBufferArray(set, &primal);
18398 
18399       *success = TRUE;
18400    }
18401 
18402    return SCIP_OKAY;
18403 }
18404 
18405 /** compute relative interior point
18406  *
18407  *  We use the approach of@par
18408  *  R. Freund, R. Roundy, M. J. Todd@par
18409  *  "Identifying the Set of Always-Active Constraints in a System of Linear Inequalities by a Single Linear Program"@par
18410  *  Tech. Rep, No. 1674-85, Sloan School, M.I.T., 1985
18411  *
18412  *  to compute a relative interior point for the current LP.
18413  *
18414  *  Assume the original LP looks as follows:
18415  *  \f[
18416  *     \begin{array}{rrl}
18417  *        \min & c^T x &\\
18418  *             & A x & \geq a\\
18419  *             & B x & \leq b\\
18420  *             & D x & = d.
18421  *     \end{array}
18422  *  \f]
18423  *  Note that bounds should be included in the system.
18424  *
18425  *  To find an interior point the following LP does the job:
18426  *  \f[
18427  *     \begin{array}{rrl}
18428  *        \max & 1^T y &\\
18429  *             & A x - y - \alpha a & \geq 0\\
18430  *             & B x + y - \alpha b & \leq 0\\
18431  *             & D x - \alpha d & = 0\\
18432  *             & 0 \leq y & \leq 1\\
18433  *             & \alpha & \geq 1.
18434  *     \end{array}
18435  *  \f]
18436  *  If the original LP is feasible, this LP is feasible as well. Any optimal solution yields the relative interior point
18437  *  \f$x^*_j/\alpha^*\f$. Note that this will just produce some relative interior point. It does not produce a
18438  *  particular relative interior point, e.g., one that maximizes the distance to the boundary in some norm.
18439  */
SCIPlpComputeRelIntPoint(SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr,SCIP_LP * lp,SCIP_PROB * prob,SCIP_Bool relaxrows,SCIP_Bool inclobjcutoff,SCIP_Real timelimit,int iterlimit,SCIP_Real * point,SCIP_Bool * success)18440 SCIP_RETCODE SCIPlpComputeRelIntPoint(
18441    SCIP_SET*             set,                /**< global SCIP settings */
18442    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
18443    SCIP_LP*              lp,                 /**< LP data */
18444    SCIP_PROB*            prob,               /**< problem data */
18445    SCIP_Bool             relaxrows,          /**< should the rows be relaxed */
18446    SCIP_Bool             inclobjcutoff,      /**< should a row for the objective cutoff be included */
18447    SCIP_Real             timelimit,          /**< time limit for LP solver */
18448    int                   iterlimit,          /**< iteration limit for LP solver */
18449    SCIP_Real*            point,              /**< array to store relative interior point on exit */
18450    SCIP_Bool*            success             /**< buffer to indicate whether interior point was successfully computed */
18451    )
18452 {
18453    SCIP_LPI* lpi;
18454    SCIP_RETCODE retcode;
18455 
18456    assert(set != NULL);
18457    assert(lp  != NULL);
18458    assert(point != NULL);
18459    assert(success != NULL);
18460 
18461    *success = FALSE;
18462 
18463    /* check time and iteration limits */
18464    if ( timelimit <= 0.0 || iterlimit <= 0 )
18465       return SCIP_OKAY;
18466 
18467    /* exit if there are no columns */
18468    assert(lp->nrows >= 0);
18469    assert(lp->ncols >= 0);
18470    if( lp->ncols == 0 )
18471       return SCIP_OKAY;
18472 
18473    /* disable objective cutoff if we have none */
18474    if( inclobjcutoff && (SCIPsetIsInfinity(set, lp->cutoffbound) || lp->looseobjvalinf > 0 || lp->looseobjval == SCIP_INVALID) ) /*lint !e777 */
18475       inclobjcutoff = FALSE;
18476 
18477    SCIPsetDebugMsg(set, "Computing relative interior point to current LP.\n");
18478 
18479    /* if there are no rows, we return the zero point */
18480    if( lp->nrows == 0 && !inclobjcutoff )
18481    {
18482       /* create zero point */
18483       BMSclearMemoryArray(point, lp->ncols);
18484       *success = TRUE;
18485 
18486       return SCIP_OKAY;
18487    }
18488 
18489    /* create auxiliary LP */
18490    SCIP_CALL( SCIPlpiCreate(&lpi, messagehdlr, "relativeInterior", SCIP_OBJSEN_MAXIMIZE) );
18491 
18492    /* catch return code and ensure that lpi is freed, anyway */
18493    retcode = computeRelIntPoint(lpi, set, messagehdlr, lp, prob, relaxrows, inclobjcutoff, timelimit, iterlimit, point, success);
18494 
18495    SCIP_CALL( SCIPlpiFree(&lpi) );
18496 
18497    /* return error, unless we obtained an LP error */
18498    if ( retcode != SCIP_OKAY && retcode != SCIP_LPERROR )
18499    {
18500       SCIP_CALL( retcode );
18501    }
18502 
18503    return SCIP_OKAY;
18504 }
18505 
18506 /** computes the changes to the problem when fixing to the optimal face
18507  *
18508  *  returns the degeneracy rate, i.e., the number of nonbasic variables with reduced cost 0
18509  *  and the variable constraint ratio, i.e., the number of unfixed variables in relation to the basis size
18510  */
SCIPlpGetDegeneracy(SCIP_LP * lp,SCIP_SET * set,SCIP_STAT * stat,SCIP_Real * degeneracy,SCIP_Real * varconsratio)18511 SCIP_RETCODE SCIPlpGetDegeneracy(
18512    SCIP_LP*              lp,                 /**< LP data */
18513    SCIP_SET*             set,                /**< global SCIP settings */
18514    SCIP_STAT*            stat,               /**< problem statistics */
18515    SCIP_Real*            degeneracy,         /**< pointer to store degeneracy share */
18516    SCIP_Real*            varconsratio        /**< pointer to store variable constraint ratio */
18517    )
18518 {
18519    assert(lp != NULL);
18520    assert(lp->solved);
18521    assert(lp->flushed);
18522 
18523    if( lp->validdegeneracylp != stat->nlps )
18524    {
18525       lp->validdegeneracylp = stat->nlps;
18526 
18527       /* if the LP was solved to optimality, we determine the degeneracy */
18528       if( SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_OPTIMAL )
18529       {
18530          SCIP_COL** cols;
18531          SCIP_ROW** rows;
18532          SCIP_COL* col;
18533          int ncols;
18534          int nrows;
18535          int nfixedcols = 0;
18536          int nalreadyfixedcols = 0;
18537          int nfixedrows = 0;
18538          int nimplicitfixedrows = 0;
18539          int nineq = 0;
18540          int c;
18541          int r;
18542          int nbasicequalities = 0;
18543 
18544          cols = lp->cols;
18545          rows = lp->rows;
18546          ncols = lp->ncols;
18547          nrows = lp->nrows;
18548 
18549          /* count number of columns that will be fixed when reducing the LP to the optimal face */
18550          for( c = ncols - 1 ; c >= 0; --c )
18551          {
18552             col = cols[c];
18553             assert(SCIPcolIsInLP(col));
18554 
18555             /* column is not basic and not fixed already */
18556             if( (SCIPcolGetBasisStatus(col) != SCIP_BASESTAT_BASIC) )
18557             {
18558                /* variable with nonzero reduced costs are fixed */
18559                /* @todo which tolerance should be used here? epsilon or dualfeastol? */
18560                if( !SCIPsetIsZero(set, SCIPcolGetRedcost(col, stat, lp)) )
18561                   ++nfixedcols;
18562                else if( SCIPsetIsEQ(set, SCIPcolGetLb(col), SCIPcolGetUb(col)) )
18563                   ++nalreadyfixedcols;
18564             }
18565          }
18566 
18567          /* count number of rows that will be turned into equations when reducing the LP to the optimal face */
18568          for( r = nrows - 1; r >= 0; --r )
18569          {
18570             SCIP_ROW* row = rows[r];
18571 
18572             assert(SCIProwIsInLP(row));
18573 
18574             if( !SCIPsetIsEQ(set, SCIProwGetLhs(row), SCIProwGetRhs(row)) )
18575             {
18576                SCIP_Real dualsol = SCIProwGetDualsol(row);
18577 
18578                ++nineq;
18579 
18580                if( (SCIProwGetBasisStatus(row) != SCIP_BASESTAT_BASIC) )
18581                {
18582                   /* rows with nonzero dual solution are turned into equations */
18583                   /* @todo which tolerance should be used here? epsilon or dualfeastol? */
18584                   if( !SCIPsetIsZero(set, dualsol) )
18585                   {
18586                      if( SCIPsetIsEQ(set, SCIProwGetLhs(row), SCIProwGetLPActivity(row, set, stat, lp)) )
18587                      {
18588                         assert(!SCIPlpIsDualReliable(lp) || !SCIPsetIsDualfeasNegative(set, dualsol));
18589                         ++nfixedrows;
18590                      }
18591                      else if( SCIPsetIsEQ(set, SCIProwGetRhs(row), SCIProwGetLPActivity(row, set, stat, lp)) )
18592                      {
18593                         assert(!SCIPlpIsDualReliable(lp) || !SCIPsetIsDualfeasPositive(set, dualsol));
18594                         ++nfixedrows;
18595                      }
18596                   }
18597                   else if( SCIPsetIsEQ(set, SCIProwGetLhs(row), SCIProwGetMaxActivity(row, set, stat))
18598                      || SCIPsetIsEQ(set, SCIProwGetRhs(row), SCIProwGetMinActivity(row, set, stat)) )
18599                   {
18600                      ++nimplicitfixedrows;
18601                   }
18602                }
18603             }
18604             else if( SCIProwGetBasisStatus(row) == SCIP_BASESTAT_BASIC )
18605                ++nbasicequalities;
18606          }
18607          assert(nfixedcols + nfixedrows <= ncols + nineq + nbasicequalities - nrows - nalreadyfixedcols - nimplicitfixedrows);
18608 
18609          if( ncols + nineq - nrows + nbasicequalities - nalreadyfixedcols > 0 )
18610             lp->degeneracy = 1.0 - 1.0 * (nfixedcols + nfixedrows) / (ncols + nineq - nrows + nbasicequalities - nalreadyfixedcols);
18611          else
18612             lp->degeneracy = 0.0;
18613 
18614          if( nrows > 0 )
18615             lp->varconsratio = 1.0 * (ncols + nineq + nbasicequalities - nfixedcols - nfixedrows - nalreadyfixedcols) / nrows;
18616          else
18617             lp->varconsratio = 1.0; /* @todo should this rather be set to a large value? */
18618          assert(lp->degeneracy >= 0);
18619          assert(SCIPsetIsLE(set, lp->degeneracy, 1.0));
18620          assert(SCIPsetIsGE(set, lp->varconsratio, 1.0));
18621       }
18622       else
18623       {
18624          lp->degeneracy = 0.0;
18625          lp->varconsratio = 0.0;
18626       }
18627    }
18628 
18629    *degeneracy = lp->degeneracy;
18630    *varconsratio = lp->varconsratio;
18631 
18632    return SCIP_OKAY;
18633 }
18634