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