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 lpi_msk.c
17 * @ingroup LPIS
18 * @brief LP interface for MOSEK
19 * @author Bo Jensen
20 * @author Tristan Gally
21 * @author Marc Pfetsch
22 *
23 * @todo Check whether MSK_IPAR_{SIM_DUAL|PRIMAL}_RESTRICT_SELECTION should be used if problem is solved from scratch or
24 * if no basis is available.
25 * @todo Revise handling of the MSK_RES_TRM_MAX_NUM_SETBACKS return value: Remove it form the check of MOSEK_CALL and
26 * include it in filterTRMrescode().
27 * @todo Check whether SCIPlpiGetSolFeasibility() should also return primal/dual feasible if the status is
28 * MSK_SOL_STA_NEAR_PRIM_FEAS, MSK_SOL_STA_NEAR_DUAL_FEAS.
29 * @todo Check why it can happen that the termination code is MSK_RES_OK, but the solution status is MSK_SOL_STA_UNKNOWN.
30 */
31
32 #include <assert.h>
33
34 #define MSKCONST const /* this define is needed for older MOSEK versions */
35 #include "mosek.h"
36
37 #include "lpi/lpi.h"
38 #include "scip/bitencode.h"
39 #include "scip/pub_message.h"
40 #include <string.h>
41
42 /* do defines for windows directly here to make the lpi more independent */
43 #if defined(_WIN32) || defined(_WIN64)
44 #define snprintf _snprintf
45 #endif
46
47 #if ( MSK_VERSION_MAJOR < 7 )
48 #error "The MOSEK interface only works for MOSEK versions 7.0.0.0 and newer"
49 #endif
50
51 #define scipmskobjsen MSKobjsensee
52 #define SENSE2MOSEK(objsen) (((objsen)==SCIP_OBJSEN_MINIMIZE)?(MSK_OBJECTIVE_SENSE_MINIMIZE):(MSK_OBJECTIVE_SENSE_MAXIMIZE))
53
54 typedef enum MSKoptimizertype_enum MSKoptimizertype;
55
56 #define MOSEK_CALL(x) do \
57 { /*lint --e{641}*/ \
58 MSKrescodee _restat_; \
59 _restat_ = (x); \
60 if( (_restat_) != MSK_RES_OK && (_restat_ ) != MSK_RES_TRM_MAX_NUM_SETBACKS ) \
61 { \
62 SCIPerrorMessage("LP Error: MOSEK returned %d.\n", (int)_restat_); \
63 return SCIP_LPERROR; \
64 } \
65 } \
66 while( FALSE )
67
68 /* this macro is only called in functions returning SCIP_Bool; thus, we return FALSE if there is an error in optimized mode */
69 #define SCIP_ABORT_FALSE(x) do \
70 { \
71 SCIP_RETCODE _restat_; \
72 if( (_restat_ = (x)) != SCIP_OKAY ) \
73 { \
74 SCIPerrorMessage("LP Error: MOSEK returned %d.\n", (int)_restat_); \
75 SCIPABORT(); \
76 return FALSE; \
77 } \
78 } \
79 while( FALSE )
80
81 #define IS_POSINF(x) ((x) >= MSK_INFINITY)
82 #define IS_NEGINF(x) ((x) <= -MSK_INFINITY)
83
84 /* global variables */
85 static MSKenv_t MosekEnv = NULL;
86 static int numlp = 0;
87
88 static int optimizecount = 0;
89 static int nextlpid = 1;
90
91 #if MSK_VERSION_MAJOR >= 9
92 #define NEAR_REL_TOLERANCE 1.0 /* MOSEK will multiply all tolerances with this factor after stalling */
93 #endif
94 #define DEBUG_PRINT_STAT 0
95 #define DEBUG_PARAM_SETTING 0
96 #define DEBUG_CHECK_DATA 0
97 #define DEBUG_EASY_REPRODUCE 0
98 #define DEBUG_DO_INTPNT_FEAS_CHECK 0
99 #define DEBUG_CHECK_STATE_TOL 1e-5
100 #define SHOW_ERRORS 0
101 #define SHOW_RELATIVE_OPTIMAL_GAP 0
102 #define ASSERT_ON_NUMERICAL_TROUBLES 0
103 #define ASSERT_ON_WARNING 0
104 #define FORCE_MOSEK_LOG 0 /* note that changing this AND setting lpinfo will lead to asserts in lpCheckIntpar */
105 #define FORCE_MOSEK_SUMMARY 0
106 #define FORCE_NO_MAXITER 0
107 #define SETBACK_LIMIT 250
108 #define STRONGBRANCH_PRICING MSK_SIM_SELECTION_SE
109 #define SUPRESS_NAME_ERROR 1
110 #define WRITE_DUAL 0
111 #define WRITE_PRIMAL 0
112 #define WRITE_INTPNT 0
113 #if WRITE_DUAL > 0 || WRITE_PRIMAL > 0 || WRITE_INTPNT > 0 || FORCE_MOSEK_LOG > 0 || FORCE_MOSEK_SUMMARY > 0
114 #define WRITE_ABOVE 0
115 #endif
116 #define DEGEN_LEVEL MSK_SIM_DEGEN_FREE
117 #define ALWAYS_SOLVE_PRIMAL_FORM 1
118 #if DEBUG_PRINT_STAT > 0
119 static int numstrongbranchmaxiterup = 0;
120 static int numstrongbranchmaxiterdo = 0;
121 static int numprimalmaxiter = 0;
122 static int numdualmaxiter = 0;
123 static int numstrongbranchobjup = 0;
124 static int numstrongbranchobjdo = 0;
125 static int numprimalobj = 0;
126 static int numdualobj = 0;
127 #endif
128
129 #if DEBUG_PRINT_STAT > 0
130 static int numstrongbranchmaxiterup = 0;
131 static int numstrongbranchmaxiterdo = 0;
132 static int numprimalmaxiter = 0;
133 static int numdualmaxiter = 0;
134 static int numstrongbranchobjup = 0;
135 static int numstrongbranchobjdo = 0;
136 static int numprimalobj = 0;
137 static int numdualobj = 0;
138 #endif
139
140
141 /** internal data for Mosek LPI */
142 struct SCIP_LPi
143 {
144 MSKtask_t task; /**< Mosek task */
145 MSKrescodee termcode; /**< termination code of last optimization run */
146 int itercount; /**< iteration count of last optimization run */
147 SCIP_PRICING pricing; /**< SCIP pricing setting */
148 int lpid; /**< id for LP within same task */
149 MSKoptimizertype lastalgo; /**< algorithm type of last solving call */
150 MSKstakeye* skx; /**< basis status for columns */
151 MSKstakeye* skc; /**< basis status for rows */
152 MSKboundkeye* bkx; /**< bound keys for columns */
153 MSKboundkeye* bkc; /**< bound keys for rows */
154 MSKint32t* aptre; /**< row or column end pointers */
155 int skxsize; /**< size of skx array */
156 int skcsize; /**< size of skc array */
157 int bkxsize; /**< size of bkx */
158 int bkcsize; /**< size of bkx */
159 int aptresize; /**< size of aptre */
160 MSKsoltypee lastsolvetype; /**< Which solver was called last and which solution should be returned? */
161 SCIP_Bool solved; /**< was the current LP solved? */
162 SCIP_Bool fromscratch; /**< Shall solves be performed with MSK_IPAR_SIM_HOTSTART turned off? */
163 SCIP_Bool clearstate; /**< Shall next solve be performed with MSK_IPAR_SIM_HOTSTART turned off? */
164 SCIP_Bool lpinfo; /**< Should LP solver output information to the screen? */
165 int restrictselectdef; /**< default value for MSK_IPAR_SIM_DUAL_RESTRICT_SELECTION */
166 SCIP_MESSAGEHDLR* messagehdlr; /**< messagehdlr handler to printing messages, or NULL */
167 };
168
169 typedef SCIP_DUALPACKET COLPACKET; /* each column needs two bits of information (basic/on_lower/on_upper) */
170 #define COLS_PER_PACKET SCIP_DUALPACKETSIZE
171 typedef SCIP_DUALPACKET ROWPACKET; /* each row needs two bit of information (basic/on_lower/on_upper) */
172 #define ROWS_PER_PACKET SCIP_DUALPACKETSIZE
173
174 /** basis status */
175 struct SCIP_LPiState
176 {
177 int num;
178 MSKsolstae solsta; /**< solution status */
179 int ncols; /**< number of columns */
180 int nrows; /**< number of rows */
181 COLPACKET* skx; /**< basis status for columns */
182 ROWPACKET* skc; /**< basis status for rows */
183 };
184
185
186 /*
187 * Local functions
188 */
189
190 /** gives problem and solution status for a Mosek Task
191 *
192 * With Mosek 7.0, the routine MSK_getsolutionstatus was replaced by MSK_getprosta and MSK_getsolsta.
193 */
194 static
MSK_getsolutionstatus(MSKtask_t task,MSKsoltypee whichsol,MSKprostae * prosta,MSKsolstae * solsta)195 MSKrescodee MSK_getsolutionstatus(
196 MSKtask_t task, /**< Mosek Task */
197 MSKsoltypee whichsol, /**< for which type of solution a status is requested */
198 MSKprostae* prosta, /**< buffer to store problem status, or NULL if not needed */
199 MSKsolstae* solsta /**< buffer to store solution status, or NULL if not needed */
200 )
201 {
202 MSKrescodee res;
203
204 if( prosta != NULL )
205 {
206 res = MSK_getprosta(task, whichsol, prosta);
207 if ( res != MSK_RES_OK )
208 return res;
209 }
210 if( solsta != NULL )
211 {
212 res = MSK_getsolsta(task, whichsol, solsta);
213 if ( res != MSK_RES_OK )
214 return res;
215 }
216
217 return MSK_RES_OK;
218 }
219
220 /** returns the number of packets needed to store column packet information */
221 static
colpacketNum(int ncols)222 int colpacketNum(
223 int ncols /**< number of columns to store */
224 )
225 {
226 return (ncols+(int)COLS_PER_PACKET-1)/(int)COLS_PER_PACKET;
227 }
228
229 /** returns the number of packets needed to store row packet information */
230 static
rowpacketNum(int nrows)231 int rowpacketNum(
232 int nrows /**< number of rows to store */
233 )
234 {
235 return (nrows+(int)ROWS_PER_PACKET-1)/(int)ROWS_PER_PACKET;
236 }
237
238 /** print string using message handler of SCIP */
239 static
printstr(MSKuserhandle_t handle,const char * str)240 void MSKAPI printstr(
241 MSKuserhandle_t handle, /**< error handle */
242 const char* str /**< string that contains string on output */
243 )
244 { /*lint --e{715}*/
245 #if SUPRESS_NAME_ERROR
246 char errstr[32];
247 (void) snprintf(errstr, 32, "MOSEK Error %d", MSK_RES_ERR_DUP_NAME);
248 if (0 == strncmp(errstr, str, strlen(errstr)))
249 return;
250 #endif
251
252 SCIPmessagePrintInfo((SCIP_MESSAGEHDLR *) handle, "MOSEK: %s", str);
253 }
254
255 #if DEBUG_CHECK_DATA > 0
256 /** check data */
257 static
scip_checkdata(SCIP_LPI * lpi,const char * functionname)258 SCIP_RETCODE scip_checkdata(
259 SCIP_LPI* lpi, /**< pointer to an LP interface structure */
260 const char* functionname /**< function name */
261 )
262 {
263 int i;
264 int numcon;
265 int numvar;
266 int gotbasicsol;
267 MSKboundkeye* tbkc;
268 MSKboundkeye* tbkx;
269 MSKstakeye *tskc;
270 MSKstakeye* tskx;
271 double* tblc;
272 double* tbuc;
273 double* tblx;
274 double* tbux;
275
276 assert(MosekEnv != NULL);
277 assert(lpi != NULL);
278 assert(lpi->task != NULL);
279
280 MOSEK_CALL( MSK_solutiondef(lpi->task, MSK_SOL_BAS, &gotbasicsol) );
281
282 MOSEK_CALL( MSK_getnumvar(lpi->task, &numvar) );
283 MOSEK_CALL( MSK_getnumcon(lpi->task, &numcon) );
284
285 /* allocate memory */
286 SCIP_ALLOC( BMSallocMemoryArray(&tbkc, numcon) );
287 SCIP_ALLOC( BMSallocMemoryArray(&tskc, numcon) );
288 SCIP_ALLOC( BMSallocMemoryArray(&tblc, numcon) );
289 SCIP_ALLOC( BMSallocMemoryArray(&tbuc, numcon) );
290
291 SCIP_ALLOC( BMSallocMemoryArray(&tbkx, numvar) );
292 SCIP_ALLOC( BMSallocMemoryArray(&tskx, numvar) );
293 SCIP_ALLOC( BMSallocMemoryArray(&tblx, numvar) );
294 SCIP_ALLOC( BMSallocMemoryArray(&tbux, numvar) );
295
296 /* Check bounds */
297 if( gotbasicsol )
298 {
299 MOSEK_CALL( MSK_getsolution(lpi->task, MSK_SOL_BAS, NULL, NULL, tskc, tskx,
300 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) );
301 }
302
303 for( i = 0; i < numvar; i++ )
304 {
305 MOSEK_CALL( MSK_getbound(lpi->task, MSK_ACC_VAR, i, &tbkx[i], &tblx[i], &tbux[i]) );
306 }
307
308 for( i = 0; i < numcon; i++ )
309 {
310 MOSEK_CALL( MSK_getbound(lpi->task, MSK_ACC_CON, i, &tbkc[i], &tblc[i], &tbuc[i]) );
311 }
312
313 for( i = 0; i < numcon; ++i )
314 {
315 if( gotbasicsol )
316 {
317 if( ( tskc[i] == MSK_SK_FIX && tbkc[i] != MSK_BK_FX ) ||
318 ( tskc[i] == MSK_SK_LOW && !(tbkc[i] == MSK_BK_FX || tbkc[i] == MSK_BK_LO || tbkc[i] == MSK_BK_RA ) ) ||
319 ( tskc[i] == MSK_SK_UPR && !(tbkc[i] == MSK_BK_FX || tbkc[i] == MSK_BK_UP || tbkc[i] == MSK_BK_RA ) ) )
320 {
321 SCIPerrorMessage("STATUS KEY ERROR i %d bkc %d skc %d %s\n", i, tbkc[i], tskc[i], functionname);
322 }
323 }
324
325 if( tbkc[i] == MSK_BK_LO || tbkc[i] == MSK_BK_FX || tbkc[i] == MSK_BK_RA )
326 {
327 if( isnan(tblc[i]) )
328 {
329 SCIPdebugMessage("nan in blc : %s\n", functionname);
330 }
331 }
332
333 if( tbkc[i] == MSK_BK_UP || tbkc[i] == MSK_BK_FX || tbkc[i] == MSK_BK_RA )
334 {
335 if( isnan(tbuc[i]) )
336 {
337 SCIPdebugMessage("nan in bux : %s\n", functionname);
338 }
339 }
340 }
341
342 for( i = 0; i < numvar; ++i )
343 {
344 if( tbkx[i] == MSK_BK_LO || tbkx[i] == MSK_BK_FX || tbkx[i] == MSK_BK_RA )
345 {
346 if( isnan(tblx[i]) )
347 {
348 SCIPdebugMessage("nan in blx : %s\n", functionname);
349 }
350 }
351
352 if( tbkx[i] == MSK_BK_UP || tbkx[i] == MSK_BK_FX || tbkx[i] == MSK_BK_RA )
353 {
354 if( isnan(tbux[i]) )
355 {
356 SCIPdebugMessage("nan in bux : %s\n", functionname);
357 getchar();
358 }
359 }
360 }
361
362 BMSfreeMemoryArray(&tbkc);
363 BMSfreeMemoryArray(&tskc);
364 BMSfreeMemoryArray(&tblc);
365 BMSfreeMemoryArray(&tbuc);
366 BMSfreeMemoryArray(&tbkx);
367 BMSfreeMemoryArray(&tskx);
368 BMSfreeMemoryArray(&tblx);
369 BMSfreeMemoryArray(&tbux);
370
371 return SCIP_OKAY;
372 }
373 #endif
374
375 /** resizes bound keys array bkx to have at least ncols entries */
376 static
ensureBkxMem(SCIP_LPI * lpi,int ncols)377 SCIP_RETCODE ensureBkxMem(
378 SCIP_LPI* lpi, /**< pointer to an LP interface structure */
379 int ncols /**< number of columns */
380 )
381 {
382 if ( lpi->bkxsize < ncols )
383 {
384 int newsize;
385 newsize = MAX(2*lpi->bkxsize, ncols);
386
387 SCIP_ALLOC( BMSreallocMemoryArray(&(lpi->bkx), newsize) );
388 lpi->bkxsize = newsize;
389 }
390
391 return SCIP_OKAY;
392 }
393
394 /** resizes bound keys array bkc to have at least nrows entries */
395 static
ensureBkcMem(SCIP_LPI * lpi,int nrows)396 SCIP_RETCODE ensureBkcMem(
397 SCIP_LPI* lpi, /**< pointer to an LP interface structure */
398 int nrows /**< number of rows */
399 )
400 {
401 if ( lpi->bkcsize < nrows )
402 {
403 int newsize;
404 newsize = MAX(2*lpi->bkcsize, nrows);
405
406 SCIP_ALLOC( BMSreallocMemoryArray(&(lpi->bkc), newsize) );
407 lpi->bkcsize = newsize;
408 }
409
410 return SCIP_OKAY;
411 }
412
413 /** resizes aptre array to have at least n entries */
414 static
ensureAptreMem(SCIP_LPI * lpi,int n)415 SCIP_RETCODE ensureAptreMem(
416 SCIP_LPI* lpi, /**< pointer to an LP interface structure */
417 int n /**< number of entries */
418 )
419 {
420 if ( lpi->aptresize < n )
421 {
422 int newsize;
423 newsize = MAX(2*lpi->aptresize, n);
424
425 SCIP_ALLOC( BMSreallocMemoryArray(&(lpi->aptre), newsize) );
426 lpi->aptresize = newsize;
427 }
428
429 return SCIP_OKAY;
430 }
431
432 /** marks the current LP to be unsolved */
433 static
invalidateSolution(SCIP_LPI * lpi)434 void invalidateSolution(
435 SCIP_LPI* lpi /**< pointer to an LP interface structure */
436 )
437 {
438 assert(lpi != NULL);
439
440 lpi->solved = FALSE;
441 }
442
443 /** compute boundkeys to inform MOSEK about fixed/free/ranged/lower bounded/upper bounded variables or constraints */
444 static
generateMskBoundkeys(int n,const double * lb,const double * ub,MSKboundkeye * bk)445 void generateMskBoundkeys(
446 int n, /**< array size */
447 const double* lb, /**< lower bounds of variables or left-hand sides of ranged rows */
448 const double* ub, /**< upper bounds of variables or right-hand sides of ranged rows */
449 MSKboundkeye* bk /**< pointer to store boundkeys to inform MOSEK about status of var/row */
450 )
451 {
452 int i;
453
454 assert(lb != NULL);
455 assert(ub != NULL);
456 assert(bk != NULL);
457
458 for( i = 0; i < n; i++ )
459 {
460 if (IS_NEGINF(lb[i]))
461 {
462 if (IS_POSINF(ub[i]))
463 {
464 bk[i] = MSK_BK_FR;
465 }
466 else
467 {
468 assert(!IS_NEGINF(ub[i]));
469 bk[i] = MSK_BK_UP;
470 }
471 }
472 else
473 {
474 assert(!IS_POSINF(lb[i]));
475 if (IS_POSINF(ub[i]))
476 {
477 bk[i] = MSK_BK_LO;
478 }
479 else if (lb[i] == ub[i])/*lint !e777*/ /* No epsilon-test since MOSEK will also test for exact equality */
480 {
481 assert(lb[i] - ub[i] == 0);
482 assert(ub[i] - lb[i] == 0);
483 bk[i] = MSK_BK_FX;
484 }
485 else
486 {
487 assert(lb[i] < ub[i]);
488 bk[i] = MSK_BK_RA;
489 }
490 }
491 }
492 }
493
494 /** get end pointers of arrays */
495 static
getEndptrs(int n,const int * beg,int nnonz,MSKint32t * aptre)496 SCIP_RETCODE getEndptrs(
497 int n, /**< array size */
498 const int* beg, /**< array of beginning indices */
499 int nnonz, /**< number of nonzeros */
500 MSKint32t* aptre /**< array to store the result */
501 )
502 {
503 int i;
504
505 assert(beg != NULL || nnonz == 0);
506
507 if (nnonz > 0)
508 {
509 assert(beg != NULL);
510 for(i = 0; i < n-1; i++)
511 {
512 aptre[i] = beg[i+1];
513 assert(aptre[i] >= beg[i]);
514 }
515
516 aptre[n-1] = nnonz;
517 assert(aptre[n-1] >= beg[n-1]);
518 }
519 else
520 {
521 for( i = 0; i < n; i++ )
522 aptre[i] = 0;
523 }
524
525 return SCIP_OKAY;
526 }
527
528 /** compute indices from range */
529 static
getIndicesRange(int first,int last,int ** sub)530 SCIP_RETCODE getIndicesRange(
531 int first, /**< first index */
532 int last, /**< last index */
533 int** sub /**< pointer to store the indices ranges */
534 )
535 {
536 int i;
537
538 assert(first <= last);
539
540 SCIP_ALLOC( BMSallocMemoryArray(sub, (last - first + 1)) );
541
542 for( i = first; i <= last; i++ )
543 {
544 (*sub)[i-first] = i;
545 }
546
547 return SCIP_OKAY;
548 }
549
550 /** compute indices from dense array */
551 static
getIndicesFromDense(int * dstat,int n,int * count,int ** sub)552 SCIP_RETCODE getIndicesFromDense(
553 int* dstat, /**< array */
554 int n, /**< size of array */
555 int* count, /**< array of counts (sizes) */
556 int** sub /**< pointer to store array of indices */
557 )
558 {
559 int i;
560 int j;
561
562 assert(dstat != NULL);
563 assert(count != NULL);
564
565 *count = 0;
566 for( i = 0; i < n; i++ )
567 {
568 if (dstat[i] == 1)
569 {
570 (*count)++;
571 }
572 }
573
574 if( (*count) > 0 )
575 {
576 SCIP_ALLOC( BMSallocMemoryArray(sub, (*count)) );
577 }
578 else
579 return SCIP_OKAY;
580
581 j = 0;
582 for( i = 0; i < n; i++ )
583 {
584 if (dstat[i] == 1)
585 {
586 (*sub)[j++] = i;
587 }
588 }
589
590 return SCIP_OKAY;
591 }
592
593 /** scale a vector */
594 static
scale_vec(int len,double * vec,double s)595 void scale_vec(
596 int len, /**< length of vector */
597 double* vec, /**< vector to be scaled */
598 double s /**< scaling factor */
599 )
600 {
601 int i;
602 for( i = 0; i < len; i++ )
603 {
604 vec[i] *= s;
605 }
606 }
607
608 /** scale lower and upper bound */
609 static
scale_bound(MSKboundkeye * bk,double * bl,double * bu,double s)610 void scale_bound(
611 MSKboundkeye* bk, /**< pointer to store boundkeys to inform MOSEK about status of var/row */
612 double* bl, /**< lower bound */
613 double* bu, /**< upper bound */
614 double s /**< scaling factor */
615 )
616 {
617 switch( *bk )
618 {
619 case MSK_BK_LO:
620 *bl *= s;
621 if ( s < 0.0 )
622 *bk = MSK_BK_UP;
623 break;
624 case MSK_BK_UP:
625 *bu *= s;
626 if ( s < 0.0 )
627 *bk = MSK_BK_LO;
628 break;
629 case MSK_BK_FX:
630 case MSK_BK_RA:
631 *bl *= s;
632 *bu *= s;
633 break;
634 case MSK_BK_FR:
635 break;
636 default:
637 SCIPABORT();
638 break;
639 } /*lint !e788*/
640
641 /* switch bounds if scaling is negative */
642 if ( s < 0.0 )
643 {
644 double tmp;
645 tmp = *bl;
646 *bl = *bu;
647 *bu = tmp;
648 }
649 }
650
651 /** resizes state arrays to have at least ncols/nrows entries */
652 static
ensureStateMem(SCIP_LPI * lpi,int ncols,int nrows)653 SCIP_RETCODE ensureStateMem(
654 SCIP_LPI* lpi, /**< pointer to an LP interface structure */
655 int ncols, /**< number of columns */
656 int nrows /**< number of rows */
657 )
658 {
659 if ( lpi->skxsize < ncols )
660 {
661 int newsize;
662 newsize = MAX(2*lpi->skxsize, ncols);
663
664 SCIP_ALLOC( BMSreallocMemoryArray(&(lpi->skx), newsize) );
665 lpi->skxsize = newsize;
666 }
667
668 if ( lpi->skcsize < nrows )
669 {
670 int newsize;
671 newsize = MAX(2*lpi->skcsize, nrows);
672
673 SCIP_ALLOC( BMSreallocMemoryArray(&(lpi->skc), newsize) );
674 lpi->skcsize = newsize;
675 }
676
677 return SCIP_OKAY;
678 }
679
680 /** get base and store in skc/skx arrays */
681 static
getbase(SCIP_LPI * lpi,int ncols,int nrows)682 SCIP_RETCODE getbase(
683 SCIP_LPI* lpi, /**< pointer to an LP interface structure */
684 int ncols, /**< number of columns */
685 int nrows /**< number of rows */
686 )
687 {
688 assert(lpi->lastsolvetype == MSK_SOL_BAS);
689
690 SCIPdebugMessage("Calling getbase (%d)\n", lpi->lpid);
691
692 SCIP_CALL( ensureStateMem(lpi, ncols, nrows) );
693 MOSEK_CALL( MSK_getsolution(lpi->task, MSK_SOL_BAS, NULL, NULL, lpi->skc, lpi->skx,
694 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) );
695
696 return SCIP_OKAY;
697 }
698
699 /** set base to the values given in skc/skx arrays */
700 static
setbase(SCIP_LPI * lpi)701 SCIP_RETCODE setbase(
702 SCIP_LPI* lpi /**< pointer to an LP interface structure */
703 )
704 {
705 SCIPdebugMessage("Calling setbase (%d)\n", lpi->lpid);
706
707 lpi->lastsolvetype = MSK_SOL_BAS;
708 lpi->solved = FALSE;
709
710 MOSEK_CALL( MSK_putsolution(lpi->task, MSK_SOL_BAS, lpi->skc, lpi->skx, NULL, NULL,
711 NULL, NULL, NULL, NULL, NULL, NULL, NULL) );
712
713 return SCIP_OKAY;
714 }
715
716
717
718 /*
719 * Miscellaneous Methods
720 */
721
722 static char mskname[100];
723
724 /**@name Miscellaneous Methods */
725 /**@{ */
726
727 /** gets name and version of LP solver */
SCIPlpiGetSolverName(void)728 const char* SCIPlpiGetSolverName(
729 void
730 )
731 {
732 #if MSK_VERSION_MAJOR < 9
733 (void) snprintf(mskname, 100, "MOSEK %d.%d.%d.%d", MSK_VERSION_MAJOR, MSK_VERSION_MINOR, MSK_VERSION_BUILD, MSK_VERSION_REVISION);
734 #else
735 (void) snprintf(mskname, 100, "MOSEK %d.%d.%d", MSK_VERSION_MAJOR, MSK_VERSION_MINOR, MSK_VERSION_REVISION);
736 #endif
737 return mskname;
738 }
739
740 /** gets description of LP solver (developer, webpage, ...) */
SCIPlpiGetSolverDesc(void)741 const char* SCIPlpiGetSolverDesc(
742 void
743 )
744 {
745 return "Linear Programming Solver developed by MOSEK Optimization Software (www.mosek.com)";
746 }
747
748 /** gets pointer for LP solver - use only with great care */
SCIPlpiGetSolverPointer(SCIP_LPI * lpi)749 void* SCIPlpiGetSolverPointer(
750 SCIP_LPI* lpi /**< pointer to an LP interface structure */
751 )
752 {
753 assert(MosekEnv != NULL);
754 assert(lpi != NULL);
755 assert(lpi->task != NULL);
756
757 return (void*) lpi->task;
758 }
759
760 /** pass integrality information to LP solver */
SCIPlpiSetIntegralityInformation(SCIP_LPI * lpi,int ncols,int * intInfo)761 SCIP_RETCODE SCIPlpiSetIntegralityInformation(
762 SCIP_LPI* lpi, /**< pointer to an LP interface structure */
763 int ncols, /**< length of integrality array */
764 int* intInfo /**< integrality array (0: continuous, 1: integer). May be NULL iff ncols is 0. */
765 )
766 { /*lint --e{715}*/
767 assert( lpi != NULL );
768 assert( ncols >= 0 );
769 assert( intInfo != NULL );
770
771 SCIPerrorMessage("SCIPlpiSetIntegralityInformation() has not been implemented yet.\n");
772 return SCIP_LPERROR;
773 }
774
775 /** informs about availability of a primal simplex solving method */
SCIPlpiHasPrimalSolve(void)776 SCIP_Bool SCIPlpiHasPrimalSolve(
777 void
778 )
779 {
780 return TRUE;
781 }
782
783 /** informs about availability of a dual simplex solving method */
SCIPlpiHasDualSolve(void)784 SCIP_Bool SCIPlpiHasDualSolve(
785 void
786 )
787 {
788 return TRUE;
789 }
790
791 /** informs about availability of a barrier solving method */
SCIPlpiHasBarrierSolve(void)792 SCIP_Bool SCIPlpiHasBarrierSolve(
793 void
794 )
795 {
796 return TRUE;
797 }
798
799 /**@} */
800
801
802 /*
803 * LPI Creation and Destruction Methods
804 */
805
806 /**@name LPI Creation and Destruction Methods */
807 /**@{ */
808
809 /** creates an LP problem object */
SCIPlpiCreate(SCIP_LPI ** lpi,SCIP_MESSAGEHDLR * messagehdlr,const char * name,SCIP_OBJSEN objsen)810 SCIP_RETCODE SCIPlpiCreate(
811 SCIP_LPI** lpi, /**< pointer to an LP interface structure */
812 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler to use for printing messages, or NULL */
813 const char* name, /**< problem name */
814 SCIP_OBJSEN objsen /**< objective sense */
815 )
816 {
817 assert(lpi != NULL);
818 assert(name != NULL);
819 assert(numlp >= 0);
820
821 SCIPdebugMessage("Calling SCIPlpiCreate\n");
822
823 if (MosekEnv == NULL)
824 {
825 MOSEK_CALL( MSK_makeenv(&MosekEnv, NULL) );
826 MOSEK_CALL( MSK_linkfunctoenvstream(MosekEnv, MSK_STREAM_LOG, (MSKuserhandle_t) messagehdlr, printstr) );
827 #if MSK_VERSION_MAJOR < 8
828 MOSEK_CALL( MSK_initenv(MosekEnv) );
829 #endif
830 }
831
832 numlp++;
833
834 SCIP_ALLOC( BMSallocMemory(lpi) );
835
836 MOSEK_CALL( MSK_makeemptytask(MosekEnv, &((*lpi)->task)) );
837
838 MOSEK_CALL( MSK_linkfunctotaskstream((*lpi)->task, MSK_STREAM_LOG, (MSKuserhandle_t) messagehdlr, printstr) );
839
840 MOSEK_CALL( MSK_putobjsense((*lpi)->task, SENSE2MOSEK(objsen)) );
841 MOSEK_CALL( MSK_putintparam((*lpi)->task, MSK_IPAR_SIM_MAX_NUM_SETBACKS, SETBACK_LIMIT) );
842 MOSEK_CALL( MSK_putintparam((*lpi)->task, MSK_IPAR_OPTIMIZER, MSK_OPTIMIZER_FREE_SIMPLEX) );
843 MOSEK_CALL( MSK_putintparam((*lpi)->task, MSK_IPAR_SIM_DEGEN, DEGEN_LEVEL) );
844 MOSEK_CALL( MSK_putintparam((*lpi)->task, MSK_IPAR_SIM_SWITCH_OPTIMIZER, MSK_ON) );
845 MOSEK_CALL( MSK_puttaskname((*lpi)->task, (char*) name) );
846
847 /* disable errors for huge values */
848 MOSEK_CALL( MSK_putdouparam((*lpi)->task, MSK_DPAR_DATA_TOL_AIJ_HUGE, MSK_INFINITY * 2)); /* not clear why the *2 is needed */
849 MOSEK_CALL( MSK_putdouparam((*lpi)->task, MSK_DPAR_DATA_TOL_C_HUGE, MSK_INFINITY));
850
851 /* disable warnings for large values */
852 MOSEK_CALL( MSK_putdouparam((*lpi)->task, MSK_DPAR_DATA_TOL_AIJ_LARGE, MSK_INFINITY * 2));
853 MOSEK_CALL( MSK_putdouparam((*lpi)->task, MSK_DPAR_DATA_TOL_CJ_LARGE, MSK_INFINITY));
854
855 /* disable warnings for large bounds */
856 MOSEK_CALL( MSK_putdouparam((*lpi)->task, MSK_DPAR_DATA_TOL_BOUND_WRN, MSK_INFINITY));
857
858 (*lpi)->termcode = MSK_RES_OK;
859 (*lpi)->itercount = 0;
860 (*lpi)->pricing = SCIP_PRICING_LPIDEFAULT;
861 (*lpi)->lpid = nextlpid++;
862 (*lpi)->lastalgo = MSK_OPTIMIZER_FREE;
863 (*lpi)->skx = NULL;
864 (*lpi)->skc = NULL;
865 (*lpi)->bkx = NULL;
866 (*lpi)->bkc = NULL;
867 (*lpi)->aptre = NULL;
868 (*lpi)->skxsize = 0;
869 (*lpi)->skcsize = 0;
870 (*lpi)->bkxsize = 0;
871 (*lpi)->bkcsize = 0;
872 (*lpi)->aptresize = 0;
873 (*lpi)->lastsolvetype = (MSKsoltypee) -1;
874 (*lpi)->lpinfo = FALSE;
875 (*lpi)->restrictselectdef = 50;
876 (*lpi)->fromscratch = FALSE;
877 (*lpi)->clearstate = FALSE;
878 (*lpi)->messagehdlr = messagehdlr;
879
880 invalidateSolution(*lpi);
881
882 MOSEK_CALL( MSK_putintparam((*lpi)->task, MSK_IPAR_LOG, MSK_OFF) );
883 MOSEK_CALL( MSK_putintparam((*lpi)->task, MSK_IPAR_LOG_SIM, MSK_OFF) );
884
885 return SCIP_OKAY;
886 }
887
888 /** deletes an LP problem object */
SCIPlpiFree(SCIP_LPI ** lpi)889 SCIP_RETCODE SCIPlpiFree(
890 SCIP_LPI** lpi /**< pointer to an LP interface structure */
891 )
892 {
893 assert(lpi != NULL);
894 assert(*lpi != NULL);
895 assert(numlp > 0);
896
897 SCIPdebugMessage("Calling SCIPlpiFree (%d)\n", (*lpi)->lpid);
898
899 MOSEK_CALL( MSK_deletetask(&(*lpi)->task) );
900
901 BMSfreeMemoryArrayNull(&(*lpi)->aptre);
902 BMSfreeMemoryArrayNull(&(*lpi)->bkx);
903 BMSfreeMemoryArrayNull(&(*lpi)->bkc);
904 BMSfreeMemoryArrayNull(&(*lpi)->skx);
905 BMSfreeMemoryArrayNull(&(*lpi)->skc);
906 BMSfreeMemory(lpi);
907
908 numlp--;
909 if (numlp == 0)
910 {
911 MOSEK_CALL( MSK_deleteenv(&MosekEnv) );
912 MosekEnv = NULL;
913 }
914
915 return SCIP_OKAY;
916 }
917
918 /*
919 * Modification Methods
920 */
921
922
923 /** copies LP data with column matrix into LP solver */
SCIPlpiLoadColLP(SCIP_LPI * lpi,SCIP_OBJSEN objsen,int ncols,const SCIP_Real * obj,const SCIP_Real * lb,const SCIP_Real * ub,char ** colnames,int nrows,const SCIP_Real * lhs,const SCIP_Real * rhs,char ** rownames,int nnonz,const int * beg,const int * ind,const SCIP_Real * val)924 SCIP_RETCODE SCIPlpiLoadColLP(
925 SCIP_LPI* lpi, /**< LP interface structure */
926 SCIP_OBJSEN objsen, /**< objective sense */
927 int ncols, /**< number of columns */
928 const SCIP_Real* obj, /**< objective function values of columns */
929 const SCIP_Real* lb, /**< lower bounds of columns */
930 const SCIP_Real* ub, /**< upper bounds of columns */
931 char** colnames, /**< column names, or NULL */
932 int nrows, /**< number of rows */
933 const SCIP_Real* lhs, /**< left hand sides of rows */
934 const SCIP_Real* rhs, /**< right hand sides of rows */
935 char** rownames, /**< row names, or NULL */
936 int nnonz, /**< number of nonzero elements in the constraint matrix */
937 const int* beg, /**< start index of each column in ind- and val-array */
938 const int* ind, /**< row indices of constraint matrix entries */
939 const SCIP_Real* val /**< values of constraint matrix entries */
940 )
941 {
942 #ifndef NDEBUG
943 {
944 int j;
945 for( j = 0; j < nnonz; j++ )
946 assert( val[j] != 0.0 );
947 }
948 #endif
949
950 assert(MosekEnv != NULL);
951 assert(lpi != NULL);
952 assert(lpi->task != NULL);
953 assert(lhs != NULL);
954 assert(rhs != NULL);
955 assert(obj != NULL);
956 assert(lb != NULL);
957 assert(ub != NULL);
958 assert(beg != NULL);
959 assert(ind != NULL);
960 assert(val != NULL);
961
962 SCIPdebugMessage("Calling SCIPlpiLoadColLP (%d)\n", lpi->lpid);
963
964 invalidateSolution(lpi);
965
966 #if DEBUG_CHECK_DATA > 0
967 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiLoadColLP") );
968 #endif
969
970 if (nrows > 0)
971 {
972 SCIP_CALL( ensureBkcMem(lpi, nrows) );
973 generateMskBoundkeys(nrows, lhs, rhs, lpi->bkc);
974 }
975
976 if (ncols > 0)
977 {
978 SCIP_CALL( ensureBkxMem(lpi, ncols) );
979 generateMskBoundkeys(ncols, lb, ub, lpi->bkx);
980
981 SCIP_CALL( ensureAptreMem(lpi, ncols) );
982 SCIP_CALL( getEndptrs(ncols, beg, nnonz, lpi->aptre) );
983 }
984
985 MOSEK_CALL( MSK_inputdata(lpi->task, nrows, ncols, nrows, ncols, obj, 0.0, beg, lpi->aptre, ind, val,
986 lpi->bkc, lhs, rhs, lpi->bkx, lb, ub) );
987
988 MOSEK_CALL( MSK_putobjsense(lpi->task, SENSE2MOSEK(objsen)) );
989
990 if( colnames != NULL )
991 {
992 int c;
993
994 for( c = 0; c < ncols; c++ )
995 {
996 MOSEK_CALL( MSK_putvarname(lpi->task, c, colnames[c]) );
997 }
998 }
999
1000 if( rownames != NULL )
1001 {
1002 int r;
1003
1004 for( r = 0; r < nrows; r++ )
1005 {
1006 MOSEK_CALL( MSK_putconname(lpi->task, r, rownames[r]) );
1007 }
1008 }
1009
1010 #if DEBUG_CHECK_DATA > 0
1011 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiLoadColLP") );
1012 #endif
1013
1014 return SCIP_OKAY;
1015 }
1016
1017 /** adds columns to the LP */
SCIPlpiAddCols(SCIP_LPI * lpi,int ncols,const SCIP_Real * obj,const SCIP_Real * lb,const SCIP_Real * ub,char ** colnames,int nnonz,const int * beg,const int * ind,const SCIP_Real * val)1018 SCIP_RETCODE SCIPlpiAddCols(
1019 SCIP_LPI* lpi, /**< LP interface structure */
1020 int ncols, /**< number of columns to be added */
1021 const SCIP_Real* obj, /**< objective function values of new columns */
1022 const SCIP_Real* lb, /**< lower bounds of new columns */
1023 const SCIP_Real* ub, /**< upper bounds of new columns */
1024 char** colnames, /**< column names, or NULL */
1025 int nnonz, /**< number of nonzero elements to be added to the constraint matrix */
1026 const int* beg, /**< start index of each column in ind- and val-array, or NULL if nnonz == 0 */
1027 const int* ind, /**< row indices of constraint matrix entries, or NULL if nnonz == 0 */
1028 const SCIP_Real* val /**< values of constraint matrix entries, or NULL if nnonz == 0 */
1029 )
1030 {
1031 #if MSK_VERSION_MAJOR < 7
1032 const int* aptrb;
1033 #endif
1034
1035 int oldcols;
1036
1037 assert(MosekEnv != NULL);
1038 assert(lpi != NULL);
1039 assert(lpi->task != NULL);
1040 assert(obj != NULL);
1041 assert(lb != NULL);
1042 assert(ub != NULL);
1043 assert(nnonz == 0 || beg != NULL);
1044 assert(nnonz == 0 || ind != NULL);
1045 assert(nnonz == 0 || val != NULL);
1046 assert(nnonz >= 0);
1047 assert(ncols >= 0);
1048
1049 SCIPdebugMessage("Calling SCIPlpiAddCols (%d)\n", lpi->lpid);
1050
1051 invalidateSolution(lpi);
1052
1053 #if DEBUG_CHECK_DATA > 0
1054 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiAddCols") );
1055 #endif
1056
1057 if (ncols == 0)
1058 return SCIP_OKAY;
1059
1060 SCIP_CALL( ensureBkxMem(lpi, ncols) );
1061 generateMskBoundkeys(ncols, lb, ub, lpi->bkx);
1062
1063 MOSEK_CALL( MSK_getnumvar(lpi->task, &oldcols) );
1064
1065 MOSEK_CALL( MSK_appendvars(lpi->task, ncols) );
1066 MOSEK_CALL( MSK_putcslice(lpi->task, oldcols, oldcols+ncols, obj) );
1067 MOSEK_CALL( MSK_putvarboundslice(lpi->task, oldcols, oldcols+ncols, lpi->bkx, lb, ub) );
1068
1069 if( nnonz > 0 )
1070 {
1071 #ifndef NDEBUG
1072 /* perform check that no new rows are added - this is forbidden */
1073 int nrows;
1074 int j;
1075
1076 MOSEK_CALL( MSK_getnumcon(lpi->task, &nrows) );
1077 for (j = 0; j < nnonz; ++j)
1078 {
1079 assert( 0 <= ind[j] && ind[j] < nrows );
1080 assert( val[j] != 0.0 );
1081 }
1082 #endif
1083
1084 SCIP_CALL( ensureAptreMem(lpi, ncols) );
1085 SCIP_CALL( getEndptrs(ncols, beg, nnonz, lpi->aptre) );
1086 MOSEK_CALL( MSK_putacolslice(lpi->task, oldcols, oldcols+ncols, beg, lpi->aptre, ind, val) );
1087 }
1088
1089 if( colnames != NULL )
1090 {
1091 int c;
1092
1093 for( c = 0; c < ncols; c++ )
1094 {
1095 MOSEK_CALL( MSK_putvarname(lpi->task, c, colnames[c]) );
1096 }
1097 }
1098
1099 #if DEBUG_CHECK_DATA > 0
1100 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiAddCols") );
1101 #endif
1102
1103 return SCIP_OKAY;
1104 }
1105
1106 /** deletes all columns in the given range from LP */
SCIPlpiDelCols(SCIP_LPI * lpi,int firstcol,int lastcol)1107 SCIP_RETCODE SCIPlpiDelCols(
1108 SCIP_LPI* lpi, /**< LP interface structure */
1109 int firstcol, /**< first column to be deleted */
1110 int lastcol /**< last column to be deleted */
1111 )
1112 {
1113 int* sub;
1114
1115 assert(MosekEnv != NULL);
1116 assert(lpi != NULL);
1117 assert(lpi->task != NULL);
1118
1119 SCIPdebugMessage("Calling SCIPlpiDelCols (%d)\n", lpi->lpid);
1120
1121 invalidateSolution(lpi);
1122
1123 #if DEBUG_CHECK_DATA > 0
1124 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiDelCols") );
1125 #endif
1126
1127 SCIP_CALL( getIndicesRange(firstcol, lastcol, &sub) );
1128
1129 MOSEK_CALL( MSK_removevars(lpi->task, lastcol-firstcol+1, sub) );
1130
1131 BMSfreeMemoryArray(&sub);
1132
1133 #if DEBUG_CHECK_DATA > 0
1134 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiDelCols") );
1135 #endif
1136
1137 return SCIP_OKAY;
1138 }
1139
1140 /** deletes columns from SCIP_LP; the new position of a column must not be greater that its old position */
SCIPlpiDelColset(SCIP_LPI * lpi,int * dstat)1141 SCIP_RETCODE SCIPlpiDelColset(
1142 SCIP_LPI* lpi, /**< LP interface structure */
1143 int* dstat /**< deletion status of columns
1144 * input: 1 if column should be deleted, 0 if not
1145 * output: new position of column, -1 if column was deleted */
1146 )
1147 {
1148 int* sub = NULL;
1149 int count;
1150 int ncols;
1151 int col;
1152 int i;
1153
1154 assert(MosekEnv != NULL);
1155 assert(lpi != NULL);
1156 assert(lpi->task != NULL);
1157 assert(dstat != NULL);
1158
1159 SCIPdebugMessage("Calling SCIPlpiDelColset (%d)\n", lpi->lpid);
1160
1161 invalidateSolution(lpi);
1162
1163 #if DEBUG_CHECK_DATA > 0
1164 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiDelColset") );
1165 #endif
1166
1167 MOSEK_CALL( MSK_getnumvar(lpi->task, &ncols) );
1168
1169 SCIP_CALL( getIndicesFromDense(dstat, ncols, &count, &sub) );
1170
1171 col = 0;
1172 for( i = 0; i < ncols; i++)
1173 {
1174 if (dstat[i] == 1)
1175 {
1176 dstat[i] = -1;
1177 }
1178 else
1179 {
1180 dstat[i] = col;
1181 col++;
1182 }
1183 }
1184
1185 if (count > 0)
1186 {
1187 SCIPdebugMessage("Deleting %d vars %d, ...\n", count, sub[0]);
1188 MOSEK_CALL( MSK_removevars(lpi->task, count, sub) );
1189 BMSfreeMemoryArray(&sub);
1190 }
1191
1192 #if DEBUG_CHECK_DATA > 0
1193 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiDelColset") );
1194 #endif
1195
1196 return SCIP_OKAY;
1197 }
1198
1199 /** adds rows to the LP */
SCIPlpiAddRows(SCIP_LPI * lpi,int nrows,const SCIP_Real * lhs,const SCIP_Real * rhs,char ** rownames,int nnonz,const int * beg,const int * ind,const SCIP_Real * val)1200 SCIP_RETCODE SCIPlpiAddRows(
1201 SCIP_LPI* lpi, /**< LP interface structure */
1202 int nrows, /**< number of rows to be added */
1203 const SCIP_Real* lhs, /**< left hand sides of new rows */
1204 const SCIP_Real* rhs, /**< right hand sides of new rows */
1205 char** rownames, /**< row names, or NULL */
1206 int nnonz, /**< number of nonzero elements to be added to the constraint matrix */
1207 const int* beg, /**< start index of each row in ind- and val-array, or NULL if nnonz == 0 */
1208 const int* ind, /**< column indices of constraint matrix entries, or NULL if nnonz == 0 */
1209 const SCIP_Real* val /**< values of constraint matrix entries, or NULL if nnonz == 0 */
1210 )
1211 {
1212 int oldrows;
1213
1214 assert(MosekEnv != NULL);
1215 assert(lpi != NULL);
1216 assert(lpi->task != NULL);
1217 assert(nnonz == 0 || beg != NULL);
1218 assert(nnonz == 0 || ind != NULL);
1219 assert(nnonz == 0 || val != NULL);
1220
1221 SCIPdebugMessage("Calling SCIPlpiAddRows (%d)\n", lpi->lpid);
1222
1223 invalidateSolution(lpi);
1224
1225 #if DEBUG_CHECK_DATA > 0
1226 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiAddRows") );
1227 #endif
1228
1229 if (nrows == 0)
1230 return SCIP_OKAY;
1231
1232 SCIP_CALL( ensureBkcMem(lpi, nrows) );
1233
1234 generateMskBoundkeys(nrows, lhs, rhs, lpi->bkc);
1235
1236 MOSEK_CALL( MSK_getnumcon(lpi->task, &oldrows) );
1237
1238 MOSEK_CALL( MSK_appendcons(lpi->task, nrows) );
1239 MOSEK_CALL( MSK_putconboundslice(lpi->task, oldrows, oldrows+nrows, lpi->bkc, lhs, rhs) );
1240
1241 if( nnonz > 0 )
1242 {
1243 #ifndef NDEBUG
1244 /* perform check that no new cols are added - this is forbidden */
1245 int ncols;
1246 int j;
1247
1248 MOSEK_CALL( MSK_getnumvar(lpi->task, &ncols) );
1249 for (j = 0; j < nnonz; ++j)
1250 {
1251 assert( val[j] != 0.0 );
1252 assert( 0 <= ind[j] && ind[j] < ncols );
1253 }
1254 #endif
1255
1256 SCIP_CALL( ensureAptreMem(lpi, nrows) );
1257 SCIP_CALL( getEndptrs(nrows, beg, nnonz, lpi->aptre) );
1258 MOSEK_CALL( MSK_putarowslice(lpi->task, oldrows, oldrows+nrows, beg, lpi->aptre, ind, val) );
1259 }
1260
1261 if( rownames != NULL )
1262 {
1263 int r;
1264
1265 for( r = 0; r < nrows; r++ )
1266 {
1267 MOSEK_CALL( MSK_putconname(lpi->task, r, rownames[r]) );
1268 }
1269 }
1270
1271 #if DEBUG_CHECK_DATA > 0
1272 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiAddRows") );
1273 #endif
1274
1275 return SCIP_OKAY;
1276 }
1277
1278 /** deletes all rows in the given range from LP */
SCIPlpiDelRows(SCIP_LPI * lpi,int firstrow,int lastrow)1279 SCIP_RETCODE SCIPlpiDelRows(
1280 SCIP_LPI* lpi, /**< LP interface structure */
1281 int firstrow, /**< first row to be deleted */
1282 int lastrow /**< last row to be deleted */
1283 )
1284 {
1285 int* sub;
1286
1287 assert(MosekEnv != NULL);
1288 assert(lpi != NULL);
1289 assert(lpi->task != NULL);
1290
1291 SCIPdebugMessage("Calling SCIPlpiDelRows (%d)\n", lpi->lpid);
1292
1293 invalidateSolution(lpi);
1294
1295 #if DEBUG_CHECK_DATA > 0
1296 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiDelRows") );
1297 #endif
1298
1299 SCIP_CALL( getIndicesRange(firstrow, lastrow, &sub) );
1300
1301 SCIPdebugMessage("Deleting cons %d to %d\n", firstrow, lastrow);
1302
1303 MOSEK_CALL( MSK_removecons(lpi->task, lastrow-firstrow+1, sub) );
1304
1305 BMSfreeMemoryArray(&sub);
1306
1307 #if DEBUG_CHECK_DATA > 0
1308 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiDelRows") );
1309 #endif
1310
1311 return SCIP_OKAY;
1312 }
1313
1314 /** deletes rows from SCIP_LP; the new position of a row must not be greater that its old position */
SCIPlpiDelRowset(SCIP_LPI * lpi,int * dstat)1315 SCIP_RETCODE SCIPlpiDelRowset(
1316 SCIP_LPI* lpi, /**< LP interface structure */
1317 int* dstat /**< deletion status of rows
1318 * input: 1 if row should be deleted, 0 if not
1319 * output: new position of row, -1 if row was deleted */
1320 )
1321 {
1322 int* sub;
1323 int count;
1324 int nrows;
1325 int row;
1326 int i;
1327
1328 assert(MosekEnv != NULL);
1329 assert(lpi != NULL);
1330 assert(lpi->task != NULL);
1331
1332 SCIPdebugMessage("Calling SCIPlpiDelRowset (%d)\n", lpi->lpid);
1333
1334 invalidateSolution(lpi);
1335
1336 #if DEBUG_CHECK_DATA > 0
1337 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiDelRowset") );
1338 #endif
1339
1340 MOSEK_CALL( MSK_getnumcon(lpi->task, &nrows) );
1341
1342 sub = NULL;
1343 SCIP_CALL( getIndicesFromDense(dstat, nrows, &count, &sub) );
1344
1345 row = 0;
1346 for( i = 0; i < nrows; i++ )
1347 {
1348 if (dstat[i] == 1)
1349 {
1350 dstat[i] = -1;
1351 }
1352 else
1353 {
1354 dstat[i] = row;
1355 row++;
1356 }
1357 }
1358
1359 if (count > 0)
1360 {
1361 SCIPdebugMessage("Deleting %d cons %d, ...\n", count, sub[0]);
1362 MOSEK_CALL( MSK_removecons(lpi->task, count, sub) );
1363 BMSfreeMemoryArray(&sub);
1364 }
1365
1366 #if DEBUG_CHECK_DATA > 0
1367 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiDelRowset end") );
1368 #endif
1369
1370 return SCIP_OKAY;
1371 }
1372
1373 /** clears the whole LP */
SCIPlpiClear(SCIP_LPI * lpi)1374 SCIP_RETCODE SCIPlpiClear(
1375 SCIP_LPI* lpi /**< LP interface structure */
1376 )
1377 {
1378 int nrows;
1379 int ncols;
1380
1381 assert(MosekEnv != NULL);
1382 assert(lpi != NULL);
1383 assert(lpi->task != NULL);
1384
1385 SCIPdebugMessage("Calling SCIPlpiClear (%d)\n", lpi->lpid);
1386
1387 invalidateSolution(lpi);
1388
1389 MOSEK_CALL( MSK_getnumcon(lpi->task, &nrows) );
1390 MOSEK_CALL( MSK_getnumvar(lpi->task, &ncols) );
1391
1392 SCIP_CALL( SCIPlpiDelRows(lpi, 0, nrows - 1) );
1393 SCIP_CALL( SCIPlpiDelCols(lpi, 0, ncols - 1) );
1394
1395 return SCIP_OKAY;
1396 }
1397
1398 /** changes lower and upper bounds of columns */
SCIPlpiChgBounds(SCIP_LPI * lpi,int ncols,const int * ind,const SCIP_Real * lb,const SCIP_Real * ub)1399 SCIP_RETCODE SCIPlpiChgBounds(
1400 SCIP_LPI* lpi, /**< LP interface structure */
1401 int ncols, /**< number of columns to change bounds for */
1402 const int* ind, /**< column indices or NULL if ncols is zero */
1403 const SCIP_Real* lb, /**< values for the new lower bounds or NULL if ncols is zero */
1404 const SCIP_Real* ub /**< values for the new upper bounds or NULL if ncols is zero */
1405 )
1406 {
1407 int i;
1408
1409 assert(MosekEnv != NULL);
1410 assert(lpi != NULL);
1411 assert(lpi->task != NULL);
1412 assert(ncols == 0 || (ind != NULL && lb != NULL && ub != NULL));
1413
1414 SCIPdebugMessage("Calling SCIPlpiChgBounds (%d)\n", lpi->lpid);
1415 if( ncols <= 0 )
1416 return SCIP_OKAY;
1417
1418 invalidateSolution(lpi);
1419
1420 #if DEBUG_CHECK_DATA > 0
1421 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiChgBounds") );
1422 #endif
1423
1424 /* @todo This test could be integrated into generateMskBoundkeys, but then this function needs to be able to return an
1425 * error, which requires some rewriting. */
1426 for (i = 0; i < ncols; ++i)
1427 {
1428 if ( SCIPlpiIsInfinity(lpi, lb[i]) )
1429 {
1430 SCIPerrorMessage("LP Error: fixing lower bound for variable %d to infinity.\n", ind[i]);
1431 return SCIP_LPERROR;
1432 }
1433 if ( SCIPlpiIsInfinity(lpi, -ub[i]) )
1434 {
1435 SCIPerrorMessage("LP Error: fixing upper bound for variable %d to -infinity.\n", ind[i]);
1436 return SCIP_LPERROR;
1437 }
1438 }
1439
1440 SCIP_CALL( ensureBkxMem(lpi, ncols) );
1441
1442 generateMskBoundkeys(ncols, lb, ub, lpi->bkx);
1443 #if MSK_VERSION_MAJOR < 9
1444 MOSEK_CALL( MSK_putboundlist(lpi->task, MSK_ACC_VAR, ncols, ind, lpi->bkx, lb, ub) );
1445 #else
1446 MOSEK_CALL( MSK_putvarboundlist(lpi->task, ncols, ind, lpi->bkx, lb, ub) );
1447 #endif
1448
1449 #if DEBUG_CHECK_DATA > 0
1450 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiChgBounds") );
1451 #endif
1452
1453 return SCIP_OKAY;
1454 }
1455
1456 /** changes left and right hand sides of rows */
SCIPlpiChgSides(SCIP_LPI * lpi,int nrows,const int * ind,const SCIP_Real * lhs,const SCIP_Real * rhs)1457 SCIP_RETCODE SCIPlpiChgSides(
1458 SCIP_LPI* lpi, /**< LP interface structure */
1459 int nrows, /**< number of rows to change sides for */
1460 const int* ind, /**< row indices */
1461 const SCIP_Real* lhs, /**< new values for left hand sides */
1462 const SCIP_Real* rhs /**< new values for right hand sides */
1463 )
1464 {
1465 assert(MosekEnv != NULL);
1466 assert(lpi != NULL);
1467 assert(lpi->task != NULL);
1468 assert(ind != NULL);
1469
1470 if( nrows <= 0 )
1471 return SCIP_OKAY;
1472
1473 invalidateSolution(lpi);
1474
1475 SCIPdebugMessage("Calling SCIPlpiChgSides (%d)\n", lpi->lpid);
1476
1477 #if DEBUG_CHECK_DATA > 0
1478 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiChgSides") );
1479 #endif
1480
1481 SCIP_CALL( ensureBkcMem(lpi, nrows) );
1482
1483 generateMskBoundkeys(nrows, lhs, rhs, lpi->bkc);
1484 #if MSK_VERSION_MAJOR < 9
1485 MOSEK_CALL( MSK_putboundlist(lpi->task, MSK_ACC_CON, nrows, ind, lpi->bkc, lhs, rhs) );
1486 #else
1487 MOSEK_CALL( MSK_putconboundlist(lpi->task, nrows, ind, lpi->bkc, lhs, rhs) );
1488 #endif
1489
1490 #if DEBUG_CHECK_DATA > 0
1491 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiChgSides") );
1492 #endif
1493
1494 return SCIP_OKAY;
1495 }
1496
1497 /** changes a single coefficient */
SCIPlpiChgCoef(SCIP_LPI * lpi,int row,int col,SCIP_Real newval)1498 SCIP_RETCODE SCIPlpiChgCoef(
1499 SCIP_LPI* lpi, /**< LP interface structure */
1500 int row, /**< row number of coefficient to change */
1501 int col, /**< column number of coefficient to change */
1502 SCIP_Real newval /**< new value of coefficient */
1503 )
1504 {
1505 assert(MosekEnv != NULL);
1506 assert(lpi != NULL);
1507 assert(lpi->task != NULL);
1508
1509 SCIPdebugMessage("Calling SCIPlpiChgCoef (%d)\n", lpi->lpid);
1510
1511 invalidateSolution(lpi);
1512
1513 #if DEBUG_CHECK_DATA > 0
1514 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiChgCoef") );
1515 #endif
1516
1517 MOSEK_CALL( MSK_putaij(lpi->task, row, col, newval) );
1518
1519 #if DEBUG_CHECK_DATA > 0
1520 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiChgCoef") );
1521 #endif
1522
1523 return SCIP_OKAY;
1524 }
1525
1526 /** changes the objective sense */
SCIPlpiChgObjsen(SCIP_LPI * lpi,SCIP_OBJSEN objsen)1527 SCIP_RETCODE SCIPlpiChgObjsen(
1528 SCIP_LPI* lpi, /**< LP interface structure */
1529 SCIP_OBJSEN objsen /**< new objective sense */
1530 )
1531 {
1532 assert(MosekEnv != NULL);
1533 assert(lpi != NULL);
1534 assert(lpi->task != NULL);
1535
1536 SCIPdebugMessage("Calling SCIPlpiChgObjsen (%d)\n", lpi->lpid);
1537
1538 invalidateSolution(lpi);
1539
1540 MOSEK_CALL( MSK_putobjsense(lpi->task, SENSE2MOSEK(objsen)) );
1541
1542 return SCIP_OKAY;
1543 }
1544
1545 /** changes objective values of columns in the LP */
SCIPlpiChgObj(SCIP_LPI * lpi,int ncols,const int * ind,const SCIP_Real * obj)1546 SCIP_RETCODE SCIPlpiChgObj(
1547 SCIP_LPI* lpi, /**< LP interface structure */
1548 int ncols, /**< number of columns to change objective value for */
1549 const int* ind, /**< column indices to change objective value for */
1550 const SCIP_Real* obj /**< new objective values for columns */
1551 )
1552 {
1553 assert(MosekEnv != NULL);
1554 assert(lpi != NULL);
1555 assert(lpi->task != NULL);
1556 assert(ind != NULL);
1557 assert(obj != NULL);
1558
1559 SCIPdebugMessage("Calling SCIPlpiChgObj (%d)\n", lpi->lpid);
1560
1561 invalidateSolution(lpi);
1562
1563 #if DEBUG_CHECK_DATA > 0
1564 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiChgObj") );
1565 #endif
1566
1567 MOSEK_CALL( MSK_putclist(lpi->task, ncols, ind, obj) );
1568
1569 #if DEBUG_CHECK_DATA > 0
1570 SCIP_CALL( scip_checkdata(lpi,"SCIPlpiChgObj") );
1571 #endif
1572
1573 return SCIP_OKAY;
1574 }
1575
1576 /** multiplies a row with a non-zero scalar; for negative scalars, the row's sense is switched accordingly */
SCIPlpiScaleRow(SCIP_LPI * lpi,int row,SCIP_Real scaleval)1577 SCIP_RETCODE SCIPlpiScaleRow(
1578 SCIP_LPI* lpi, /**< LP interface structure */
1579 int row, /**< row number to scale */
1580 SCIP_Real scaleval /**< scaling multiplier */
1581 )
1582 {
1583 int nnonz;
1584 int* sub;
1585 double* val;
1586 MSKboundkeye bkc;
1587 double blc;
1588 double buc;
1589
1590 assert(MosekEnv != NULL);
1591 assert(lpi != NULL);
1592 assert(lpi->task != NULL);
1593
1594 SCIPdebugMessage("Calling SCIPlpiScaleRow (%d)\n", lpi->lpid);
1595
1596 invalidateSolution(lpi);
1597
1598 #if DEBUG_CHECK_DATA > 0
1599 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiScaleRow") );
1600 #endif
1601
1602 assert(scaleval != 0);
1603
1604 MOSEK_CALL( MSK_getarownumnz(lpi->task, row, &nnonz) );
1605
1606 if (nnonz != 0)
1607 {
1608 SCIP_ALLOC( BMSallocMemoryArray(&sub, nnonz) );
1609 SCIP_ALLOC( BMSallocMemoryArray(&val, nnonz) );
1610
1611 MOSEK_CALL( MSK_getarow(lpi->task, row, &nnonz, sub, val) );
1612 scale_vec(nnonz, val, scaleval);
1613 MOSEK_CALL( MSK_putarow(lpi->task, row, nnonz, sub, val) );
1614
1615 BMSfreeMemoryArray(&val);
1616 BMSfreeMemoryArray(&sub);
1617 }
1618
1619 #if MSK_VERSION_MAJOR < 9
1620 MOSEK_CALL( MSK_getbound(lpi->task, MSK_ACC_CON, row, &bkc, &blc, &buc) );
1621 scale_bound(&bkc, &blc, &buc, scaleval);
1622 MOSEK_CALL( MSK_putbound(lpi->task, MSK_ACC_CON, row, bkc, blc, buc) );
1623 #else
1624 MOSEK_CALL( MSK_getconbound(lpi->task, row, &bkc, &blc, &buc) );
1625 scale_bound(&bkc, &blc, &buc, scaleval);
1626 MOSEK_CALL( MSK_putconbound(lpi->task, row, bkc, blc, buc) );
1627 #endif
1628
1629 #if DEBUG_CHECK_DATA > 0
1630 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiScaleRow") );
1631 #endif
1632
1633 return SCIP_OKAY;
1634 }
1635
1636 /** multiplies a column with a non-zero scalar; the objective value is multiplied with the scalar, and the bounds
1637 * are divided by the scalar; for negative scalars, the column's bounds are switched
1638 */
SCIPlpiScaleCol(SCIP_LPI * lpi,int col,SCIP_Real scaleval)1639 SCIP_RETCODE SCIPlpiScaleCol(
1640 SCIP_LPI* lpi, /**< LP interface structure */
1641 int col, /**< column number to scale */
1642 SCIP_Real scaleval /**< scaling multiplier */
1643 )
1644 {
1645 int nnonz;
1646 int *sub = NULL;
1647 double *val = NULL;
1648 MSKboundkeye bkx;
1649 double blx, bux, c;
1650
1651 assert(MosekEnv != NULL);
1652 assert(lpi != NULL);
1653 assert(lpi->task != NULL);
1654
1655 SCIPdebugMessage("Calling SCIPlpiScaleCol (%d)\n", lpi->lpid);
1656
1657 invalidateSolution(lpi);
1658
1659 #if DEBUG_CHECK_DATA > 0
1660 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiScaleCol") );
1661 #endif
1662
1663 assert(scaleval != 0);
1664 MOSEK_CALL( MSK_getacolnumnz(lpi->task, col, &nnonz) );
1665
1666 if (nnonz != 0)
1667 {
1668 SCIP_ALLOC( BMSallocMemoryArray(&sub, nnonz) );
1669 SCIP_ALLOC( BMSallocMemoryArray(&val, nnonz) );
1670
1671 MOSEK_CALL( MSK_getacol(lpi->task, col, &nnonz, sub, val) );
1672 scale_vec(nnonz, val, scaleval);
1673 MOSEK_CALL( MSK_putacol(lpi->task, col, nnonz, sub, val) );
1674
1675 BMSfreeMemoryArray(&val);
1676 BMSfreeMemoryArray(&sub);
1677 }
1678
1679 #if MSK_VERSION_MAJOR < 9
1680 MOSEK_CALL( MSK_getbound(lpi->task, MSK_ACC_VAR, col, &bkx, &blx, &bux) );
1681 scale_bound(&bkx, &blx, &bux, 1.0/scaleval);
1682 MOSEK_CALL( MSK_putbound(lpi->task, MSK_ACC_VAR, col, bkx, blx, bux) );
1683 #else
1684 MOSEK_CALL( MSK_getvarbound(lpi->task, col, &bkx, &blx, &bux) );
1685 scale_bound(&bkx, &blx, &bux, 1.0/scaleval);
1686 MOSEK_CALL( MSK_putvarbound(lpi->task, col, bkx, blx, bux) );
1687 #endif
1688
1689 MOSEK_CALL( MSK_getcslice(lpi->task, col, col+1, &c) );
1690 MOSEK_CALL( MSK_putcj(lpi->task, col, c*scaleval) );
1691
1692 #if DEBUG_CHECK_DATA > 0
1693 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiScaleCol") );
1694 #endif
1695
1696 return SCIP_OKAY;
1697 }
1698
1699
1700 /*
1701 * Data Accessing Methods
1702 */
1703
1704
1705 /** gets the number of rows in the LP */
SCIPlpiGetNRows(SCIP_LPI * lpi,int * nrows)1706 SCIP_RETCODE SCIPlpiGetNRows(
1707 SCIP_LPI* lpi, /**< LP interface structure */
1708 int* nrows /**< pointer to store the number of rows */
1709 )
1710 {
1711 assert(MosekEnv != NULL);
1712 assert(lpi != NULL);
1713 assert(lpi->task != NULL);
1714 assert(nrows != NULL);
1715
1716 SCIPdebugMessage("Calling SCIPlpiGetNRows (%d)\n", lpi->lpid);
1717
1718 MOSEK_CALL( MSK_getnumcon(lpi->task, nrows) );
1719
1720 return SCIP_OKAY;
1721 }
1722
1723 /** gets the number of columns in the LP */
SCIPlpiGetNCols(SCIP_LPI * lpi,int * ncols)1724 SCIP_RETCODE SCIPlpiGetNCols(
1725 SCIP_LPI* lpi, /**< LP interface structure */
1726 int* ncols /**< pointer to store the number of cols */
1727 )
1728 {
1729 assert(MosekEnv != NULL);
1730 assert(lpi != NULL);
1731 assert(lpi->task != NULL);
1732 assert(ncols != NULL);
1733
1734 SCIPdebugMessage("Calling SCIPlpiGetNCols (%d)\n", lpi->lpid);
1735
1736 MOSEK_CALL( MSK_getnumvar(lpi->task, ncols) );
1737
1738 return SCIP_OKAY;
1739 }
1740
1741 /** gets the number of nonzero elements in the LP constraint matrix */
SCIPlpiGetNNonz(SCIP_LPI * lpi,int * nnonz)1742 SCIP_RETCODE SCIPlpiGetNNonz(
1743 SCIP_LPI* lpi, /**< LP interface structure */
1744 int* nnonz /**< pointer to store the number of nonzeros */
1745 )
1746 {
1747 assert(MosekEnv != NULL);
1748 assert(lpi != NULL);
1749 assert(lpi->task != NULL);
1750 assert(nnonz != NULL);
1751
1752 SCIPdebugMessage("Calling SCIPlpiGetNNonz (%d)\n", lpi->lpid);
1753
1754 MOSEK_CALL( MSK_getnumanz(lpi->task, nnonz) );
1755
1756 return SCIP_OKAY;
1757 }
1758
1759 /** get a slice of a row or column */
1760 static
getASlice(SCIP_LPI * lpi,SCIP_Bool iscon,int first,int last,int * nnonz,int * beg,int * ind,double * val)1761 SCIP_RETCODE getASlice(
1762 SCIP_LPI* lpi, /**< LP interface structure */
1763 SCIP_Bool iscon, /**< whether we are requesting a slice of a constraint or column */
1764 int first, /**< first index */
1765 int last, /**< last index */
1766 int* nnonz, /**< pointer to store the number of nonzeros */
1767 int* beg, /**< array for begins of indices/values */
1768 int* ind, /**< array of row/column indices */
1769 double* val /**< array of values */
1770 )
1771 {
1772 assert(MosekEnv != NULL);
1773 assert(lpi != NULL);
1774 assert(lpi->task != NULL);
1775 assert(first <= last);
1776
1777 SCIPdebugMessage("Calling SCIPlpiGetNNonz (%d)\n", lpi->lpid);
1778
1779 #if DEBUG_CHECK_DATA > 0
1780 SCIP_CALL( scip_checkdata(lpi, "getASlice") );
1781 #endif
1782
1783 if( nnonz != 0 )
1784 {
1785 int surplus;
1786
1787 assert(beg != NULL);
1788 assert(ind != NULL);
1789 assert(val != NULL);
1790
1791 SCIP_CALL( ensureAptreMem(lpi, last - first + 1) );
1792
1793 #if MSK_VERSION_MAJOR < 9
1794 MOSEK_CALL( MSK_getaslicenumnz(lpi->task, iscon ? MSK_ACC_CON : MSK_ACC_VAR, first, last+1, nnonz) );
1795 surplus = *nnonz;
1796 MOSEK_CALL( MSK_getaslice(lpi->task, iscon ? MSK_ACC_CON : MSK_ACC_VAR, first, last+1, *nnonz, &surplus, beg, lpi->aptre, ind, val) );
1797 #else
1798 if( iscon )
1799 {
1800 MOSEK_CALL( MSK_getarowslicenumnz(lpi->task, first, last+1, nnonz) );
1801 surplus = *nnonz;
1802 MOSEK_CALL( MSK_getarowslice(lpi->task, first, last+1, *nnonz, &surplus, beg, lpi->aptre, ind, val) );
1803 }
1804 else
1805 {
1806 MOSEK_CALL( MSK_getacolslicenumnz(lpi->task, first, last+1, nnonz) );
1807 surplus = *nnonz;
1808 MOSEK_CALL( MSK_getacolslice(lpi->task, first, last+1, *nnonz, &surplus, beg, lpi->aptre, ind, val) );
1809 }
1810 #endif
1811
1812 assert(surplus == 0);
1813 }
1814
1815 #if DEBUG_CHECK_DATA > 0
1816 SCIP_CALL( scip_checkdata(lpi, "getASlice") );
1817 #endif
1818
1819 return SCIP_OKAY;
1820 }
1821
1822 /** gets columns from LP problem object; the arrays have to be large enough to store all values;
1823 * Either both, lb and ub, have to be NULL, or both have to be non-NULL,
1824 * either nnonz, beg, ind, and val have to be NULL, or all of them have to be non-NULL.
1825 */
SCIPlpiGetCols(SCIP_LPI * lpi,int firstcol,int lastcol,SCIP_Real * lb,SCIP_Real * ub,int * nnonz,int * beg,int * ind,SCIP_Real * val)1826 SCIP_RETCODE SCIPlpiGetCols(
1827 SCIP_LPI* lpi, /**< LP interface structure */
1828 int firstcol, /**< first column to get from LP */
1829 int lastcol, /**< last column to get from LP */
1830 SCIP_Real* lb, /**< buffer to store the lower bound vector, or NULL */
1831 SCIP_Real* ub, /**< buffer to store the upper bound vector, or NULL */
1832 int* nnonz, /**< pointer to store the number of nonzero elements returned, or NULL */
1833 int* beg, /**< buffer to store start index of each column in ind- and val-array, or NULL */
1834 int* ind, /**< buffer to store row indices of constraint matrix entries, or NULL */
1835 SCIP_Real* val /**< buffer to store values of constraint matrix entries, or NULL */
1836 )
1837 {
1838 assert(MosekEnv != NULL);
1839 assert(lpi != NULL);
1840 assert(lpi->task != NULL);
1841 assert((lb != NULL && ub != NULL) || (lb == NULL && ub == NULL));
1842 assert((nnonz != NULL && beg != NULL && ind != NULL && val != NULL) || (nnonz == NULL && beg == NULL && ind == NULL && val == NULL));
1843
1844 #ifndef NDEBUG
1845 {
1846 int ncols;
1847 SCIP_CALL( SCIPlpiGetNCols(lpi, &ncols) );
1848 assert(0 <= firstcol && firstcol <= lastcol && lastcol < ncols);
1849 }
1850 #endif
1851
1852 SCIPdebugMessage("Calling SCIPlpiGetCols (%d)\n", lpi->lpid);
1853
1854 SCIP_CALL( SCIPlpiGetBounds(lpi, firstcol, lastcol, lb, ub) );
1855 SCIP_CALL( getASlice(lpi, FALSE, firstcol, lastcol, nnonz, beg, ind, val) );
1856
1857 return SCIP_OKAY;
1858 }
1859
1860 /** gets rows from LP problem object; the arrays have to be large enough to store all values.
1861 * Either both, lhs and rhs, have to be NULL, or both have to be non-NULL,
1862 * either nnonz, beg, ind, and val have to be NULL, or all of them have to be non-NULL.
1863 */
SCIPlpiGetRows(SCIP_LPI * lpi,int firstrow,int lastrow,SCIP_Real * lhs,SCIP_Real * rhs,int * nnonz,int * beg,int * ind,SCIP_Real * val)1864 SCIP_RETCODE SCIPlpiGetRows(
1865 SCIP_LPI* lpi, /**< LP interface structure */
1866 int firstrow, /**< first row to get from LP */
1867 int lastrow, /**< last row to get from LP */
1868 SCIP_Real* lhs, /**< buffer to store left hand side vector, or NULL */
1869 SCIP_Real* rhs, /**< buffer to store right hand side vector, or NULL */
1870 int* nnonz, /**< pointer to store the number of nonzero elements returned, or NULL */
1871 int* beg, /**< buffer to store start index of each row in ind- and val-array, or NULL */
1872 int* ind, /**< buffer to store column indices of constraint matrix entries, or NULL */
1873 SCIP_Real* val /**< buffer to store values of constraint matrix entries, or NULL */
1874 )
1875 {
1876 assert(MosekEnv != NULL);
1877 assert(lpi != NULL);
1878 assert(lpi->task != NULL);
1879 assert((lhs != NULL && rhs != NULL) || (lhs == NULL && rhs == NULL));
1880 assert((nnonz != NULL && beg != NULL && ind != NULL && val != NULL) || (nnonz == NULL && beg == NULL && ind == NULL && val == NULL));
1881
1882 #ifndef NDEBUG
1883 {
1884 int nrows;
1885 SCIP_CALL( SCIPlpiGetNRows(lpi, &nrows) );
1886 assert(0 <= firstrow && firstrow <= lastrow && lastrow < nrows);
1887 }
1888 #endif
1889
1890 SCIPdebugMessage("Calling SCIPlpiGetRows (%d)\n", lpi->lpid);
1891
1892 #if DEBUG_CHECK_DATA > 0
1893 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiGetRows") );
1894 #endif
1895
1896 SCIP_CALL( SCIPlpiGetSides(lpi, firstrow, lastrow, lhs, rhs) );
1897 SCIP_CALL( getASlice(lpi, TRUE, firstrow, lastrow, nnonz, beg, ind, val) );
1898
1899 #if DEBUG_CHECK_DATA > 0
1900 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiGetRows") );
1901 #endif
1902
1903 return SCIP_OKAY;
1904 }
1905
1906 /** gets column names */
SCIPlpiGetColNames(SCIP_LPI * lpi,int firstcol,int lastcol,char ** colnames,char * namestorage,int namestoragesize,int * storageleft)1907 SCIP_RETCODE SCIPlpiGetColNames(
1908 SCIP_LPI* lpi, /**< LP interface structure */
1909 int firstcol, /**< first column to get name from LP */
1910 int lastcol, /**< last column to get name from LP */
1911 char** colnames, /**< pointers to column names (of size at least lastcol-firstcol+1) or NULL if namestoragesize is zero */
1912 char* namestorage, /**< storage for col names or NULL if namestoragesize is zero */
1913 int namestoragesize, /**< size of namestorage (if 0, storageleft returns the storage needed) */
1914 int* storageleft /**< amount of storage left (if < 0 the namestorage was not big enough) or NULL if namestoragesize is zero */
1915 )
1916 { /*lint --e{715}*/
1917 assert(MosekEnv != NULL);
1918 assert(lpi != NULL);
1919 assert(lpi->task != NULL);
1920 assert(0 <= firstcol && firstcol <= lastcol);
1921 assert(colnames != NULL || namestoragesize == 0);
1922 assert(namestorage != NULL || namestoragesize == 0);
1923 assert(namestoragesize >= 0);
1924 assert(storageleft != NULL);
1925
1926 SCIPerrorMessage("SCIPlpiGetColNames() has not been implemented yet.\n");
1927
1928 return SCIP_LPERROR;
1929 }
1930
1931 /** gets row names */
SCIPlpiGetRowNames(SCIP_LPI * lpi,int firstrow,int lastrow,char ** rownames,char * namestorage,int namestoragesize,int * storageleft)1932 SCIP_RETCODE SCIPlpiGetRowNames(
1933 SCIP_LPI* lpi, /**< LP interface structure */
1934 int firstrow, /**< first row to get name from LP */
1935 int lastrow, /**< last row to get name from LP */
1936 char** rownames, /**< pointers to row names (of size at least lastrow-firstrow+1) or NULL if namestoragesize is zero */
1937 char* namestorage, /**< storage for row names or NULL if namestoragesize is zero */
1938 int namestoragesize, /**< size of namestorage (if 0, -storageleft returns the storage needed) */
1939 int* storageleft /**< amount of storage left (if < 0 the namestorage was not big enough) or NULL if namestoragesize is zero */
1940 )
1941 { /*lint --e{715}*/
1942 assert(MosekEnv != NULL);
1943 assert(lpi != NULL);
1944 assert(lpi->task != NULL);
1945 assert(0 <= firstrow && firstrow <= lastrow);
1946 assert(rownames != NULL || namestoragesize == 0);
1947 assert(namestorage != NULL || namestoragesize == 0);
1948 assert(namestoragesize >= 0);
1949 assert(storageleft != NULL);
1950
1951 SCIPerrorMessage("SCIPlpiGetRowNames() has not been implemented yet.\n");
1952
1953 return SCIP_LPERROR;
1954 }
1955
1956 /** gets the objective sense of the LP */
SCIPlpiGetObjsen(SCIP_LPI * lpi,SCIP_OBJSEN * objsen)1957 SCIP_RETCODE SCIPlpiGetObjsen(
1958 SCIP_LPI* lpi, /**< LP interface structure */
1959 SCIP_OBJSEN* objsen /**< pointer to store objective sense */
1960 )
1961 {
1962 MSKobjsensee mskobjsen;
1963
1964 assert(MosekEnv != NULL);
1965 assert(lpi != NULL);
1966 assert(lpi->task != NULL);
1967 assert(objsen != NULL);
1968
1969 SCIPdebugMessage("Calling SCIPlpiGetObjsen (%d)\n", lpi->lpid);
1970
1971 MOSEK_CALL( MSK_getobjsense(lpi->task, &mskobjsen) );
1972 *objsen = (mskobjsen == MSK_OBJECTIVE_SENSE_MINIMIZE ? SCIP_OBJSEN_MINIMIZE : SCIP_OBJSEN_MAXIMIZE);
1973
1974 return SCIP_OKAY;
1975 }
1976
1977 /** gets objective coefficients from LP problem object */
SCIPlpiGetObj(SCIP_LPI * lpi,int firstcol,int lastcol,SCIP_Real * vals)1978 SCIP_RETCODE SCIPlpiGetObj(
1979 SCIP_LPI* lpi, /**< LP interface structure */
1980 int firstcol, /**< first column to get objective coefficient for */
1981 int lastcol, /**< last column to get objective coefficient for */
1982 SCIP_Real* vals /**< array to store objective coefficients */
1983 )
1984 {
1985 assert(MosekEnv != NULL);
1986 assert(lpi != NULL);
1987 assert(lpi->task != NULL);
1988 assert(firstcol <= lastcol);
1989 assert(vals != NULL);
1990
1991 SCIPdebugMessage("Calling SCIPlpiGetObj (%d)\n", lpi->lpid);
1992
1993 MOSEK_CALL( MSK_getcslice(lpi->task, firstcol, lastcol+1, vals) );
1994
1995 return SCIP_OKAY;
1996 }
1997
1998 /** gets current bounds from LP problem object */
SCIPlpiGetBounds(SCIP_LPI * lpi,int firstcol,int lastcol,SCIP_Real * lbs,SCIP_Real * ubs)1999 SCIP_RETCODE SCIPlpiGetBounds(
2000 SCIP_LPI* lpi, /**< LP interface structure */
2001 int firstcol, /**< first column to get bounds for */
2002 int lastcol, /**< last column to get bounds for */
2003 SCIP_Real* lbs, /**< array to store lower bound values, or NULL */
2004 SCIP_Real* ubs /**< array to store upper bound values, or NULL */
2005 )
2006 {
2007 assert(MosekEnv != NULL);
2008 assert(lpi != NULL);
2009 assert(lpi->task != NULL);
2010 assert(firstcol <= lastcol);
2011
2012 SCIPdebugMessage("Calling SCIPlpiGetBounds (%d)\n", lpi->lpid);
2013
2014 #if DEBUG_CHECK_DATA > 0
2015 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiGetBounds") );
2016 #endif
2017
2018 #if MSK_VERSION_MAJOR < 9
2019 MOSEK_CALL( MSK_getboundslice(lpi->task, MSK_ACC_VAR, firstcol, lastcol+1, NULL, lbs, ubs) );
2020 #else
2021 MOSEK_CALL( MSK_getvarboundslice(lpi->task, firstcol, lastcol+1, NULL, lbs, ubs) );
2022 #endif
2023
2024 return SCIP_OKAY;
2025 }
2026
2027 /** gets current row sides from LP problem object */
SCIPlpiGetSides(SCIP_LPI * lpi,int firstrow,int lastrow,SCIP_Real * lhss,SCIP_Real * rhss)2028 SCIP_RETCODE SCIPlpiGetSides(
2029 SCIP_LPI* lpi, /**< LP interface structure */
2030 int firstrow, /**< first row to get sides for */
2031 int lastrow, /**< last row to get sides for */
2032 SCIP_Real* lhss, /**< array to store left hand side values, or NULL */
2033 SCIP_Real* rhss /**< array to store right hand side values, or NULL */
2034 )
2035 {
2036 assert(MosekEnv != NULL);
2037 assert(lpi != NULL);
2038 assert(lpi->task != NULL);
2039 assert(firstrow <= lastrow);
2040
2041 SCIPdebugMessage("Calling SCIPlpiGetSides (%d)\n", lpi->lpid);
2042
2043 #if DEBUG_CHECK_DATA > 0
2044 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiGetSides") );
2045 #endif
2046
2047 #if MSK_VERSION_MAJOR < 9
2048 MOSEK_CALL( MSK_getboundslice(lpi->task, MSK_ACC_CON, firstrow, lastrow+1, NULL, lhss, rhss) );
2049 #else
2050 MOSEK_CALL( MSK_getconboundslice(lpi->task, firstrow, lastrow+1, NULL, lhss, rhss) );
2051 #endif
2052
2053 #if DEBUG_CHECK_DATA > 0
2054 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiGetSides") );
2055 #endif
2056
2057 return SCIP_OKAY;
2058 }
2059
2060 /** gets a single coefficient */
SCIPlpiGetCoef(SCIP_LPI * lpi,int row,int col,SCIP_Real * val)2061 SCIP_RETCODE SCIPlpiGetCoef(
2062 SCIP_LPI* lpi, /**< LP interface structure */
2063 int row, /**< row number of coefficient */
2064 int col, /**< column number of coefficient */
2065 SCIP_Real* val /**< pointer to store the value of the coefficient */
2066 )
2067 {
2068 assert(MosekEnv != NULL);
2069 assert(lpi != NULL);
2070 assert(lpi->task != NULL);
2071 assert(val != NULL);
2072
2073 SCIPdebugMessage("Calling SCIPlpiGetCoef (%d)\n", lpi->lpid);
2074
2075 #if DEBUG_CHECK_DATA > 0
2076 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiGetCoef") );
2077 #endif
2078
2079 MOSEK_CALL( MSK_getaij(lpi->task, row, col, val) );
2080
2081 #if DEBUG_CHECK_DATA > 0
2082 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiGetCoef") );
2083 #endif
2084
2085 return SCIP_OKAY;
2086 }
2087
2088 /*
2089 * Solving Methods
2090 */
2091
2092
2093 /** gets the internal solution status of the solver */
2094 static
getSolutionStatus(SCIP_LPI * lpi,MSKprostae * prosta,MSKsolstae * solsta)2095 SCIP_RETCODE getSolutionStatus(
2096 SCIP_LPI* lpi, /**< LP interface structure */
2097 MSKprostae* prosta, /**< pointer to store the problem status */
2098 MSKsolstae* solsta /**< pointer to store the solution status */
2099 )
2100 {
2101 assert(MosekEnv != NULL);
2102 assert(lpi != NULL);
2103 assert(lpi->task != NULL);
2104
2105 MOSEK_CALL( MSK_getsolutionstatus(lpi->task, lpi->lastsolvetype, prosta, solsta) );
2106
2107 return SCIP_OKAY;
2108 }
2109
2110 /** helper method to filter out numerical problems */
2111 static
filterTRMrescode(SCIP_MESSAGEHDLR * messagehdlr,MSKrescodee * termcode,MSKrescodee res)2112 MSKrescodee filterTRMrescode(
2113 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
2114 MSKrescodee* termcode, /**< pointer to store output termination code */
2115 MSKrescodee res /**< input result of call to Mosek function */
2116 )
2117 { /*lint --e{715}*/
2118 assert( termcode != NULL );
2119
2120 #if ASSERT_ON_NUMERICAL_TROUBLES > 0
2121 if ( res == MSK_RES_TRM_MAX_NUM_SETBACKS || res == MSK_RES_TRM_NUMERICAL_PROBLEM )
2122 {
2123 SCIPmessagePrintWarning(messagehdlr, "Return code %d in [%d]\n", res, optimizecount);
2124 assert(0);
2125 *termcode = res;
2126 return MSK_RES_OK;
2127 }
2128 #else
2129 SCIP_UNUSED(messagehdlr);
2130 #endif
2131
2132 if ( res == MSK_RES_TRM_MAX_ITERATIONS || res == MSK_RES_TRM_MAX_TIME
2133 || res == MSK_RES_TRM_OBJECTIVE_RANGE || res == MSK_RES_TRM_STALL )
2134 {
2135 *termcode = res;
2136 res = MSK_RES_OK;
2137 }
2138 else
2139 *termcode = MSK_RES_OK;
2140
2141 return res;
2142 }
2143
2144 /** solve problem with the simplex algorithm */
2145 static
SolveWSimplex(SCIP_LPI * lpi)2146 SCIP_RETCODE SolveWSimplex(
2147 SCIP_LPI* lpi /**< LP interface structure */
2148 )
2149 {
2150 int itercount_primal;
2151 int itercount_dual;
2152 int gotbasicsol;
2153 int presolve;
2154 int maxiter;
2155 MSKprostae prosta;
2156 MSKsolstae solsta;
2157 double pobj, dobj;
2158
2159 assert(MosekEnv != NULL);
2160 assert(lpi != NULL);
2161 assert(lpi->task != NULL);
2162
2163 invalidateSolution(lpi);
2164 lpi->lastsolvetype = MSK_SOL_BAS;
2165
2166 /* store original settings */
2167 MOSEK_CALL( MSK_getintparam(lpi->task, MSK_IPAR_PRESOLVE_USE, &presolve) );
2168 MOSEK_CALL( MSK_getintparam(lpi->task, MSK_IPAR_SIM_MAX_ITERATIONS, &maxiter) );
2169
2170 /* set some paramters */
2171 #if DEBUG_EASY_REPRODUCE
2172 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_AUTO_SORT_A_BEFORE_OPT, MSK_ON) );
2173 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_SIM_HOTSTART_LU, MSK_OFF) );
2174 #else
2175 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_SIM_HOTSTART_LU, MSK_ON) );
2176 #endif
2177
2178 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_AUTO_UPDATE_SOL_INFO, MSK_OFF) );
2179
2180 #if FORCE_MOSEK_LOG
2181 if( optimizecount > WRITE_ABOVE )
2182 {
2183 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_LOG_SIM, 4) );
2184 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_LOG_SIM_FREQ, 1) );
2185 }
2186 else
2187 {
2188 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_LOG_SIM, 4) );
2189 }
2190 #endif
2191
2192 MOSEK_CALL( MSK_solutiondef(lpi->task, MSK_SOL_BAS, &gotbasicsol) );
2193
2194 if( gotbasicsol )
2195 {
2196 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_PRESOLVE_USE, MSK_PRESOLVE_MODE_OFF) );
2197 }
2198 else
2199 {
2200 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_PRESOLVE_USE, MSK_PRESOLVE_MODE_ON) );
2201 }
2202
2203 #if ALWAYS_SOLVE_PRIMAL_FORM > 0
2204 /* always solve the primal formulation */
2205 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_SIM_SOLVE_FORM, MSK_SOLVE_PRIMAL) );
2206 #endif
2207
2208 #if DEBUG_CHECK_DATA > 0
2209 SCIP_CALL( scip_checkdata(lpi, "SolveWSimplex") );
2210 #endif
2211
2212 if( gotbasicsol && maxiter < 20000 )
2213 {
2214 /* Since max iter often is set, we switch off restricted pricing */
2215 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_SIM_DUAL_RESTRICT_SELECTION, 0) );
2216 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_SIM_PRIMAL_RESTRICT_SELECTION, 0) );
2217 }
2218 else
2219 {
2220 /* otherwise use default value */
2221 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_SIM_DUAL_RESTRICT_SELECTION, lpi->restrictselectdef) );
2222 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_SIM_PRIMAL_RESTRICT_SELECTION, lpi->restrictselectdef) );
2223 }
2224
2225 #if FORCE_NO_MAXITER > 0
2226 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_SIM_MAX_ITERATIONS, 2000000000) );
2227 #endif
2228
2229
2230 #if DEBUG_CHECK_DATA > 0
2231 SCIP_CALL( scip_checkdata(lpi, "Begin optimize with simplex") );
2232 #endif
2233
2234 #if FORCE_MOSEK_SUMMARY > 1
2235 if( optimizecount > WRITE_ABOVE )
2236 {
2237 MOSEK_CALL( MSK_solutionsummary(lpi->task, MSK_STREAM_LOG) );
2238 }
2239 #endif
2240
2241 /* perform actual optimization */
2242 MOSEK_CALL( filterTRMrescode(lpi->messagehdlr, &lpi->termcode, MSK_optimize(lpi->task)) );
2243
2244 /* resolve with aggresive scaling if the maximal number of setbacks has been reached */
2245 if( lpi->termcode == MSK_RES_TRM_MAX_NUM_SETBACKS )
2246 {
2247 int scaling;
2248
2249 MOSEK_CALL( MSK_getintparam(lpi->task, MSK_IPAR_SIM_SCALING, &scaling) );
2250 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_SIM_SCALING, MSK_SCALING_AGGRESSIVE) );
2251 MOSEK_CALL( filterTRMrescode(lpi->messagehdlr, &lpi->termcode, MSK_optimize(lpi->task)) );
2252 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_SIM_SCALING, scaling) );
2253 }
2254
2255 #if FORCE_MOSEK_SUMMARY
2256 if( optimizecount > WRITE_ABOVE )
2257 {
2258 MOSEK_CALL( MSK_solutionsummary(lpi->task, MSK_STREAM_LOG) );
2259 }
2260 #else
2261 if( lpi->lpinfo )
2262 {
2263 MOSEK_CALL( MSK_solutionsummary(lpi->task, MSK_STREAM_LOG) );
2264 }
2265 #endif
2266
2267 #if DEBUG_CHECK_DATA > 0
2268 SCIP_CALL( scip_checkdata(lpi, "End optimize with simplex") );
2269 #endif
2270
2271 /* set paramaters to their original values */
2272 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_PRESOLVE_USE, presolve) );
2273 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_SIM_MAX_ITERATIONS, maxiter) );
2274
2275 /* obtain iteration count */
2276 MOSEK_CALL( MSK_getintinf(lpi->task, MSK_IINF_SIM_PRIMAL_ITER, &itercount_primal) );
2277 MOSEK_CALL( MSK_getintinf(lpi->task, MSK_IINF_SIM_DUAL_ITER, &itercount_dual) );
2278
2279 lpi->itercount = itercount_primal + itercount_dual;
2280
2281 /* get solution information */
2282 MOSEK_CALL( MSK_getprimalobj(lpi->task, MSK_SOL_BAS, &pobj) );
2283 MOSEK_CALL( MSK_getdualobj(lpi->task, MSK_SOL_BAS, &dobj) );
2284
2285 MOSEK_CALL( MSK_getsolutionstatus(lpi->task, MSK_SOL_BAS, &prosta, &solsta) );
2286
2287 SCIPdebugMessage("maxiter = %d, termcode = %d, prosta = %d, solsta = %d, objval = %g : %g, iter = %d+%d\n",
2288 maxiter, lpi->termcode, prosta, solsta, pobj, dobj, itercount_primal, itercount_dual);
2289
2290 switch (solsta)
2291 {
2292 case MSK_SOL_STA_OPTIMAL:
2293 case MSK_SOL_STA_PRIM_AND_DUAL_FEAS:
2294 case MSK_SOL_STA_PRIM_FEAS:
2295 case MSK_SOL_STA_DUAL_FEAS:
2296 case MSK_SOL_STA_PRIM_INFEAS_CER:
2297 case MSK_SOL_STA_DUAL_INFEAS_CER:
2298 if (lpi->termcode == MSK_RES_OK)
2299 lpi->solved = TRUE;
2300 break;
2301
2302 case MSK_SOL_STA_UNKNOWN:
2303 /* Mosek seems to have status unknown on the following termination codes */
2304 assert( lpi->termcode == MSK_RES_TRM_MAX_ITERATIONS || lpi->termcode == MSK_RES_TRM_MAX_TIME ||
2305 lpi->termcode == MSK_RES_TRM_OBJECTIVE_RANGE || lpi->termcode == MSK_RES_TRM_STALL ||
2306 lpi->termcode == MSK_RES_OK );
2307
2308 if ( lpi->termcode != MSK_RES_TRM_MAX_ITERATIONS && lpi->termcode != MSK_RES_TRM_MAX_TIME &&
2309 lpi->termcode != MSK_RES_TRM_OBJECTIVE_RANGE )
2310 {
2311 SCIPmessagePrintWarning(lpi->messagehdlr, "Numerical problem: simplex[%d] returned solsta = %d.\n", optimizecount, solsta);
2312 lpi->termcode = MSK_RES_TRM_NUMERICAL_PROBLEM;
2313 #if ASSERT_ON_WARNING
2314 assert(0);
2315 #endif
2316 }
2317 break;
2318
2319 #if MSK_VERSION_MAJOR < 9
2320 case MSK_SOL_STA_NEAR_OPTIMAL:
2321 case MSK_SOL_STA_NEAR_PRIM_FEAS:
2322 case MSK_SOL_STA_NEAR_DUAL_FEAS:
2323 case MSK_SOL_STA_NEAR_PRIM_AND_DUAL_FEAS:
2324 case MSK_SOL_STA_NEAR_PRIM_INFEAS_CER:
2325 case MSK_SOL_STA_NEAR_DUAL_INFEAS_CER:
2326
2327 assert(lpi->termcode == MSK_RES_OK);
2328
2329 SCIPmessagePrintWarning(lpi->messagehdlr, "Simplex[%d] returned solsta = %d (numerical problem).\n", optimizecount, solsta);
2330 lpi->termcode = MSK_RES_TRM_NUMERICAL_PROBLEM;
2331 #if ASSERT_ON_WARNING
2332 assert(0);
2333 #endif
2334 break;
2335 #endif
2336
2337 case MSK_SOL_STA_INTEGER_OPTIMAL:
2338 #if MSK_VERSION_MAJOR < 9
2339 case MSK_SOL_STA_NEAR_INTEGER_OPTIMAL:
2340 #endif
2341 default:
2342 #if SHOW_ERRORS
2343 SCIPerrorMessage("Simplex[%d] returned solsta = %d\n", optimizecount, solsta);
2344 #endif
2345
2346 #if ASSERT_ON_WARNING
2347 assert(0);
2348 #endif
2349
2350 return SCIP_LPERROR;
2351 } /*lint !e788*/
2352
2353 switch (prosta)
2354 {
2355 /* already handled above */
2356 case MSK_PRO_STA_PRIM_AND_DUAL_FEAS:
2357 case MSK_PRO_STA_PRIM_FEAS:
2358 case MSK_PRO_STA_DUAL_FEAS:
2359 case MSK_PRO_STA_PRIM_AND_DUAL_INFEAS:
2360 case MSK_PRO_STA_PRIM_INFEAS:
2361 case MSK_PRO_STA_DUAL_INFEAS:
2362 case MSK_PRO_STA_UNKNOWN:
2363 break;
2364
2365 #if MSK_VERSION_MAJOR < 9
2366 case MSK_PRO_STA_NEAR_PRIM_AND_DUAL_FEAS:
2367 case MSK_PRO_STA_NEAR_PRIM_FEAS:
2368 case MSK_PRO_STA_NEAR_DUAL_FEAS:
2369 #endif
2370 case MSK_PRO_STA_ILL_POSED:
2371 case MSK_PRO_STA_PRIM_INFEAS_OR_UNBOUNDED:
2372 assert(lpi->termcode == MSK_RES_OK);
2373
2374 SCIPmessagePrintWarning(lpi->messagehdlr, "Simplex[%d] returned prosta = %d\n", optimizecount, prosta);
2375 lpi->termcode = MSK_RES_TRM_NUMERICAL_PROBLEM;
2376 invalidateSolution(lpi);
2377 #if ASSERT_ON_WARNING
2378 assert(0);
2379 #endif
2380 break;
2381
2382 default:
2383 #if SHOW_ERRORS
2384 SCIPerrorMessage("Simplex[%d] returned prosta = %d\n", optimizecount, prosta);
2385 #endif
2386
2387 #if ASSERT_ON_WARNING
2388 assert(0);
2389 #endif
2390
2391 return SCIP_LPERROR;
2392 } /*lint !e788*/
2393
2394 /* todo: replace numbers by constants, e.g., tolerances */
2395 #if SHOW_RELATIVE_OPTIMAL_GAP
2396 if ( solsta == MSK_SOL_STA_OPTIMAL && fabs(pobj) + fabs(dobj) > 1.0e-6 && fabs(pobj-dobj) > 0.0001*(fabs(pobj) + fabs(dobj)))
2397 {
2398 SCIPerrorMessage("Simplex[%d] returned optimal solution with different objvals %g != %g reldiff %.2g%%\n",
2399 optimizecount, pobj, dobj, 100.0 * fabs(pobj-dobj)/ MAX(fabs(pobj), fabs(dobj))); /*lint !e666*/
2400 }
2401 #endif
2402
2403 /* The optimizer terminated with an objective value outside the objective range. */
2404 if (lpi->termcode == MSK_RES_TRM_OBJECTIVE_RANGE)
2405 {
2406 if (solsta != MSK_SOL_STA_DUAL_FEAS && solsta != MSK_SOL_STA_OPTIMAL && solsta != MSK_SOL_STA_PRIM_AND_DUAL_FEAS)
2407 {
2408 SCIPerrorMessage("[%d] Terminated on objective range without dual feasible solsta.\n", optimizecount);
2409
2410 /* solve again with barrier */
2411 SCIP_CALL( SCIPlpiSolveBarrier(lpi, TRUE) );
2412 }
2413 else
2414 {
2415 scipmskobjsen objsen;
2416 double bound;
2417
2418 MOSEK_CALL( MSK_getobjsense(lpi->task, &objsen) );
2419
2420 if (objsen == MSK_OBJECTIVE_SENSE_MINIMIZE)
2421 {
2422 MOSEK_CALL( MSK_getdouparam(lpi->task, MSK_DPAR_UPPER_OBJ_CUT, &bound) );
2423
2424 if (1.0e-6*(fabs(bound) + fabs(dobj)) < bound-dobj)
2425 {
2426 SCIPerrorMessage("[%d] Terminated on obj range, dobj = %g, bound = %g\n", optimizecount, dobj, bound);
2427
2428 SCIP_CALL( SCIPlpiSolveBarrier(lpi, TRUE) );
2429 }
2430 }
2431 else /* objsen == MSK_OBJECTIVE_SENSE_MAX */
2432 {
2433 MOSEK_CALL( MSK_getdouparam(lpi->task, MSK_DPAR_LOWER_OBJ_CUT, &bound) );
2434
2435 if (1.0e-6*(fabs(bound) + fabs(dobj)) < dobj-bound)
2436 {
2437 SCIPerrorMessage("[%d] Terminated on obj range, dobj = %g, bound = %g\n", optimizecount, dobj, bound);
2438
2439 SCIP_CALL( SCIPlpiSolveBarrier(lpi, TRUE) );
2440 }
2441 }
2442 }
2443 }
2444
2445 /* if the simplex took too many iterations, solve again with barrier */
2446 if (maxiter >= 2000000000)
2447 {
2448 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_SIM_MAX_ITERATIONS, maxiter) );
2449
2450 if (lpi->termcode == MSK_RES_TRM_MAX_ITERATIONS)
2451 {
2452 SCIPmessagePrintWarning(lpi->messagehdlr, "Simplex[%d] failed to terminate in 10000 iterations, switching to interior point\n",
2453 optimizecount);
2454
2455 SCIP_CALL( SCIPlpiSolveBarrier(lpi, TRUE) );
2456 }
2457 }
2458
2459 #if DEBUG_DO_INTPNT_FEAS_CHECK
2460 if (solsta == MSK_SOL_STA_PRIM_INFEAS_CER || solsta == MSK_SOL_STA_DUAL_INFEAS_CER)
2461 {
2462 SCIPdebugMessage("Checking infeasibility[%d]... ", optimizecount);
2463
2464 SCIP_CALL( SCIPlpiSolveBarrier(lpi, true) );
2465
2466 MOSEK_CALL( MSK_getsolutionstatus(lpi->task, MSK_SOL_BAS, &prosta, &solsta) );
2467
2468 if (solsta == MSK_SOL_STA_PRIM_INFEAS_CER || solsta == MSK_SOL_STA_DUAL_INFEAS_CER)
2469 {
2470 SCIPdebugPrintf("ok\n");
2471 }
2472 else
2473 {
2474 SCIPdebugPrintf("wrong [%d] prosta = %d, solsta = %d\n", optimizecount, prosta, solsta);
2475 }
2476 }
2477 #endif
2478
2479
2480 #if DEBUG_PRINT_STAT > 0
2481 SCIPdebugMessage("Max iter stat : Count %d branchup = %d branchlo = %d primal %d dual %d\n",
2482 optimizecount, numstrongbranchmaxiterup, numstrongbranchmaxiterdo, numprimalmaxiter, numdualmaxiter);
2483 SCIPdebugMessage("Objcut iter stat : Count %d branchup = %d branchlo = %d primal %d dual %d\n",
2484 optimizecount, numstrongbranchobjup, numstrongbranchobjdo, numprimalobj, numdualobj);
2485 #endif
2486
2487 #if DEBUG_CHECK_DATA > 0
2488 SCIP_CALL( scip_checkdata(lpi, "SolveWSimplex") );
2489 #endif
2490
2491 return SCIP_OKAY;
2492 }
2493
2494 /** calls primal simplex to solve the LP */
SCIPlpiSolvePrimal(SCIP_LPI * lpi)2495 SCIP_RETCODE SCIPlpiSolvePrimal(
2496 SCIP_LPI* lpi /**< LP interface structure */
2497 )
2498 {
2499 assert(MosekEnv != NULL);
2500 assert(lpi != NULL);
2501 assert(lpi->task != NULL);
2502
2503 optimizecount++;
2504
2505 SCIPdebugMessage("Calling SCIPlpiSolvePrimal[%d] (%d) ", optimizecount, lpi->lpid);
2506
2507 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_SIM_HOTSTART_LU, MSK_ON) );
2508
2509 /* Set warmstarting information in MOSEK. We only have status keys (recalculate dual solution without dual superbasics) */
2510 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_SIM_HOTSTART, lpi->fromscratch || lpi->clearstate ?
2511 MSK_SIM_HOTSTART_NONE : MSK_SIM_HOTSTART_STATUS_KEYS) );
2512 lpi->clearstate = FALSE;
2513
2514 #if DEBUG_CHECK_DATA > 0
2515 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiSolvePrimal") );
2516 #endif
2517
2518 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_OPTIMIZER, MSK_OPTIMIZER_PRIMAL_SIMPLEX) );
2519 lpi->lastalgo = MSK_OPTIMIZER_PRIMAL_SIMPLEX;
2520
2521 #if WRITE_PRIMAL > 0
2522 if( optimizecount > WRITE_ABOVE )
2523 {
2524 char fname[40];
2525 snprintf(fname, 40, "primal_%d.lp", optimizecount);
2526 SCIPdebugMessage("\nWriting lp %s\n", fname);
2527 /*MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_WRITE_GENERIC_NAMES, MSK_ON) );*/
2528 MSK_writedata(lpi->task, fname);
2529 }
2530 #endif
2531
2532 SCIP_CALL( SolveWSimplex(lpi) );
2533
2534 #ifdef SCIP_DISABLED_CODE
2535 /* the following code is unclear: Why should the resolve change anything ?????? */
2536 if ( lpi->termcode == MSK_RES_TRM_OBJECTIVE_RANGE )
2537 {
2538 MSKsolstae solsta;
2539
2540 MOSEK_CALL( MSK_getsolutionstatus(lpi->task, MSK_SOL_BAS, NULL, &solsta) );
2541
2542 if( solsta != MSK_SOL_STA_PRIM_FEAS )
2543 {
2544 SCIP_CALL( SolveWSimplex(lpi) );
2545 }
2546 }
2547 #endif
2548
2549 #if DEBUG_PRINT_STAT > 0
2550 if (lpi->termcode == MSK_RES_TRM_OBJECTIVE_RANGE)
2551 ++numprimalobj;
2552 #endif
2553
2554 #if DEBUG_PRINT_STAT > 0
2555 if (lpi->termcode == MSK_RES_TRM_MAX_ITERATIONS)
2556 ++numprimalmaxiter;
2557 #endif
2558
2559 #if DEBUG_CHECK_DATA > 0
2560 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiSolvePrimal") );
2561 #endif
2562
2563 return SCIP_OKAY;
2564 }
2565
2566 /** calls dual simplex to solve the LP */
SCIPlpiSolveDual(SCIP_LPI * lpi)2567 SCIP_RETCODE SCIPlpiSolveDual(
2568 SCIP_LPI* lpi /**< LP interface structure */
2569 )
2570 {
2571 assert(MosekEnv != NULL);
2572 assert(lpi != NULL);
2573 assert(lpi->task != NULL);
2574
2575 optimizecount++;
2576
2577 SCIPdebugMessage("Calling SCIPlpiSolveDual[%d] (%d)\n", optimizecount, lpi->lpid);
2578
2579 /* MSK_IPAR_SIM_INTEGER is removed in Mosek 8.1 */
2580 #if (MSK_VERSION_MAJOR < 8) || (MSK_VERSION_MAJOR == 8 && MSK_VERSION_MINOR == 0)
2581 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_SIM_INTEGER, MSK_ON) );
2582 #endif
2583 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_SIM_HOTSTART_LU, MSK_ON) );
2584
2585 /* Set warmstarting information in MOSEK. We only have status keys (recalculate dual solution without dual superbasics) */
2586 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_SIM_HOTSTART, (lpi->fromscratch || lpi->clearstate) ?
2587 MSK_SIM_HOTSTART_NONE : MSK_SIM_HOTSTART_STATUS_KEYS) );
2588 lpi->clearstate = FALSE;
2589
2590 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_OPTIMIZER, MSK_OPTIMIZER_DUAL_SIMPLEX) );
2591 lpi->lastalgo = MSK_OPTIMIZER_DUAL_SIMPLEX;
2592
2593 #if WRITE_DUAL > 0
2594 if( optimizecount > WRITE_ABOVE )
2595 {
2596 char fname[40];
2597 snprintf(fname,40,"dual_%d.lp", optimizecount);
2598 SCIPdebugMessage("\nWriting lp %s\n", fname);
2599 MSK_writedata(lpi->task, fname);
2600 }
2601 #endif
2602
2603 SCIP_CALL( SolveWSimplex(lpi) );
2604
2605 #ifdef SCIP_DISABLED_CODE
2606 /* the following code is unclear: Why should the resolve change anything ?????? */
2607 if ( lpi->termcode == MSK_RES_TRM_OBJECTIVE_RANGE )
2608 {
2609 MSKsolstae solsta;
2610
2611 MOSEK_CALL( MSK_getsolutionstatus(lpi->task, MSK_SOL_BAS, NULL, &solsta) );
2612
2613 if( solsta != MSK_SOL_STA_DUAL_FEAS )
2614 {
2615 SCIP_CALL( SolveWSimplex(lpi) );
2616 }
2617 }
2618 #endif
2619
2620 #if DEBUG_PRINT_STAT > 0
2621 if (lpi->termcode == MSK_RES_TRM_OBJECTIVE_RANGE)
2622 ++numdualobj;
2623 #endif
2624
2625 #if DEBUG_PRINT_STAT > 0
2626 if (lpi->termcode == MSK_RES_TRM_MAX_ITERATIONS)
2627 ++numdualmaxiter;
2628 #endif
2629
2630 return SCIP_OKAY;
2631 }
2632
2633 /** calls barrier or interior point algorithm to solve the LP with crossover to simplex basis */
SCIPlpiSolveBarrier(SCIP_LPI * lpi,SCIP_Bool crossover)2634 SCIP_RETCODE SCIPlpiSolveBarrier(
2635 SCIP_LPI* lpi, /**< LP interface structure */
2636 SCIP_Bool crossover /**< perform crossover */
2637 )
2638 {
2639 MSKprostae prosta;
2640 MSKsolstae solsta;
2641
2642 assert(MosekEnv != NULL);
2643 assert(lpi != NULL);
2644 assert(lpi->task != NULL);
2645
2646 optimizecount++;
2647
2648 invalidateSolution(lpi);
2649 lpi->lastsolvetype = crossover ? MSK_SOL_BAS : MSK_SOL_ITR;
2650
2651 #if FORCE_MOSEK_LOG
2652 if( optimizecount > WRITE_ABOVE )
2653 {
2654 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_LOG, 4) );
2655 }
2656 else
2657 {
2658 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_LOG, 0) );
2659 }
2660 #endif
2661
2662 SCIPdebugMessage("Calling SCIPlpiSolveBarrier[%d] (%d) ", optimizecount, lpi->lpid);
2663
2664 #if DEBUG_CHECK_DATA > 0
2665 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiSolveBarrier") );
2666 #endif
2667
2668 #ifdef SCIP_DISABLED_CODE
2669 /* The parameter exists in MOSEK, but as of version 8, it is not in use and the interior-point solver is never warmstarted */
2670 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_INTPNT_HOTSTART, (lpi->fromscratch || lpi->clearstate) ?
2671 MSK_SIM_HOTSTART_NONE : MSK_INTPNT_HOTSTART_PRIMAL_DUAL) );
2672 #endif
2673 lpi->clearstate = FALSE;
2674
2675 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_INTPNT_BASIS, crossover ? MSK_BI_ALWAYS : MSK_BI_NEVER) );
2676 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_OPTIMIZER, MSK_OPTIMIZER_INTPNT) );
2677 lpi->lastalgo = MSK_OPTIMIZER_INTPNT;
2678
2679 #if MSK_VERSION_MAJOR >= 9
2680 MOSEK_CALL( MSK_putdouparam(lpi->task, MSK_DPAR_INTPNT_CO_TOL_NEAR_REL, NEAR_REL_TOLERANCE) );
2681 #endif
2682
2683 #if WRITE_INTPNT > 0
2684 if( optimizecount > WRITE_ABOVE )
2685 {
2686 char fname[40];
2687 snprintf(fname,40,"intpnt_%d.lp", optimizecount);
2688 SCIPdebugMessage("\nWriting lp %s\n", fname);
2689 /*MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_WRITE_GENERIC_NAMES, MSK_ON) );*/
2690 MSK_writedata(lpi->task, fname);
2691 }
2692 #endif
2693
2694 MOSEK_CALL( filterTRMrescode(lpi->messagehdlr, &lpi->termcode, MSK_optimize(lpi->task)) );
2695
2696 #if DEBUG_PRINT_STAT > 0
2697 if (lpi->termcode == MSK_RES_TRM_MAX_ITERATIONS)
2698 ++numdualmaxiter;
2699 #endif
2700
2701 MOSEK_CALL( MSK_getintinf(lpi->task, MSK_IINF_INTPNT_ITER, &lpi->itercount) );
2702
2703 MOSEK_CALL( MSK_getsolutionstatus(lpi->task, lpi->lastsolvetype, &prosta, &solsta) );
2704 SCIPdebugMessage("termcode = %d, prosta = %d, solsta = %d, iter = %d\n",
2705 lpi->termcode, prosta, solsta, lpi->itercount);
2706
2707 switch (solsta)
2708 {
2709 case MSK_SOL_STA_OPTIMAL:
2710 case MSK_SOL_STA_PRIM_AND_DUAL_FEAS:
2711 case MSK_SOL_STA_PRIM_FEAS:
2712 case MSK_SOL_STA_DUAL_FEAS:
2713 case MSK_SOL_STA_PRIM_INFEAS_CER:
2714 case MSK_SOL_STA_DUAL_INFEAS_CER:
2715 if (lpi->termcode == MSK_RES_OK)
2716 lpi->solved = TRUE;
2717 break;
2718 case MSK_SOL_STA_UNKNOWN:
2719 #if MSK_VERSION_MAJOR < 9
2720 case MSK_SOL_STA_NEAR_OPTIMAL:
2721 case MSK_SOL_STA_NEAR_PRIM_FEAS:
2722 case MSK_SOL_STA_NEAR_DUAL_FEAS:
2723 case MSK_SOL_STA_NEAR_PRIM_AND_DUAL_FEAS:
2724 case MSK_SOL_STA_NEAR_PRIM_INFEAS_CER:
2725 case MSK_SOL_STA_NEAR_DUAL_INFEAS_CER:
2726 #endif
2727 SCIPmessagePrintWarning(lpi->messagehdlr, "Barrier[%d] returned solsta = %d\n", optimizecount, solsta);
2728
2729 if (lpi->termcode == MSK_RES_OK)
2730 lpi->termcode = MSK_RES_TRM_NUMERICAL_PROBLEM;
2731
2732 #if ASSERT_ON_WARNING
2733 assert(0);
2734 #endif
2735 break;
2736 case MSK_SOL_STA_INTEGER_OPTIMAL:
2737 #if MSK_VERSION_MAJOR < 9
2738 case MSK_SOL_STA_NEAR_INTEGER_OPTIMAL:
2739 #endif
2740 default:
2741 #if SHOW_ERRORS
2742 SCIPerrorMessage("Barrier[%d] returned solsta = %d\n", optimizecount, solsta);
2743 #endif
2744
2745 #if ASSERT_ON_WARNING
2746 assert(0);
2747 #endif
2748
2749 return SCIP_LPERROR;
2750 } /*lint !e788*/
2751
2752 switch (prosta)
2753 {
2754 case MSK_PRO_STA_PRIM_AND_DUAL_FEAS:
2755 case MSK_PRO_STA_PRIM_FEAS:
2756 case MSK_PRO_STA_DUAL_FEAS:
2757 case MSK_PRO_STA_PRIM_AND_DUAL_INFEAS:
2758 case MSK_PRO_STA_PRIM_INFEAS:
2759 case MSK_PRO_STA_DUAL_INFEAS:
2760 break;
2761 case MSK_PRO_STA_UNKNOWN:
2762 #if MSK_VERSION_MAJOR < 9
2763 case MSK_PRO_STA_NEAR_PRIM_AND_DUAL_FEAS:
2764 case MSK_PRO_STA_NEAR_PRIM_FEAS:
2765 case MSK_PRO_STA_NEAR_DUAL_FEAS:
2766 #endif
2767 case MSK_PRO_STA_ILL_POSED:
2768 case MSK_PRO_STA_PRIM_INFEAS_OR_UNBOUNDED:
2769 SCIPmessagePrintWarning(lpi->messagehdlr, "Barrier[%d] returned prosta = %d\n", optimizecount, prosta);
2770
2771 if (lpi->termcode == MSK_RES_OK)
2772 lpi->termcode = MSK_RES_TRM_NUMERICAL_PROBLEM;
2773
2774 invalidateSolution(lpi);
2775
2776 #if ASSERT_ON_WARNING
2777 assert(0);
2778 #endif
2779 break;
2780 default:
2781 #if SHOW_ERRORS
2782 SCIPerrorMessage("Barrier[%d] returned prosta = %d\n", optimizecount, prosta);
2783 #endif
2784
2785 #if ASSERT_ON_WARNING
2786 assert(0);
2787 #endif
2788
2789 return SCIP_LPERROR;
2790 } /*lint !e788*/
2791
2792 #if DEBUG_CHECK_DATA > 0
2793 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiSolveBarrier") );
2794 #endif
2795
2796 return SCIP_OKAY;
2797 }
2798
2799 /** start strong branching - call before any strong branching */
SCIPlpiStartStrongbranch(SCIP_LPI * lpi)2800 SCIP_RETCODE SCIPlpiStartStrongbranch(
2801 SCIP_LPI* lpi /**< LP interface structure */
2802 )
2803 { /*lint --e{715}*/
2804 assert(MosekEnv != NULL);
2805 assert(lpi != NULL);
2806 assert(lpi->task != NULL);
2807
2808 /* currently do nothing */
2809 return SCIP_OKAY;
2810 }
2811
2812 /** end strong branching - call after any strong branching */
SCIPlpiEndStrongbranch(SCIP_LPI * lpi)2813 SCIP_RETCODE SCIPlpiEndStrongbranch(
2814 SCIP_LPI* lpi /**< LP interface structure */
2815 )
2816 { /* lint --e{715}*/
2817 assert(lpi != NULL);
2818 /* assert(MosekEnv != NULL);
2819 assert(lpi->task != NULL); */
2820
2821 /* currently do nothing */
2822 return SCIP_OKAY;
2823 }
2824
2825 /** performs strong branching iterations on all candidates
2826 *
2827 * @note last solve call must have been either simplex or barrier with crossover or base must have been set manually
2828 */
2829 static
SCIPlpiStrongbranch(SCIP_LPI * lpi,int col,SCIP_Real psol,int itlim,SCIP_Real * down,SCIP_Real * up,SCIP_Bool * downvalid,SCIP_Bool * upvalid,int * iter)2830 SCIP_RETCODE SCIPlpiStrongbranch(
2831 SCIP_LPI* lpi, /**< LP interface structure */
2832 int col, /**< column to apply strong branching on */
2833 SCIP_Real psol, /**< current primal solution value of column */
2834 int itlim, /**< iteration limit for strong branchings */
2835 SCIP_Real* down, /**< stores dual bound after branching column down */
2836 SCIP_Real* up, /**< stores dual bound after branching column up */
2837 SCIP_Bool* downvalid, /**< stores whether the returned down value is a valid dual bound;
2838 * otherwise, it can only be used as an estimate value */
2839 SCIP_Bool* upvalid, /**< stores whether the returned up value is a valid dual bound;
2840 * otherwise, it can only be used as an estimate value */
2841 int* iter /**< stores total number of strong branching iterations, or -1; may be NULL */
2842 )
2843 {
2844 MSKobjsensee objsen;
2845 int olditerlim;
2846 int oldselection;
2847 int oldhotstart;
2848
2849 double bound;
2850 int ncols;
2851 int nrows;
2852 MSKboundkeye bkx;
2853 double blx;
2854 double bux;
2855 double newub;
2856 double newlb;
2857
2858 assert(MosekEnv != NULL);
2859 assert(lpi != NULL);
2860 assert(lpi->task != NULL);
2861
2862 SCIPdebugMessage("Calling SCIPlpiStrongbranch (%d)\n", lpi->lpid);
2863
2864 #if DEBUG_CHECK_DATA > 0
2865 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiStrongbranch") );
2866 #endif
2867
2868 if (lpi->termcode != MSK_RES_OK)
2869 {
2870 SCIPmessagePrintWarning(lpi->messagehdlr, "SB Warning: Previous termcode is %d\n", lpi->termcode);
2871 }
2872
2873 MOSEK_CALL( MSK_getnumvar(lpi->task, &ncols) );
2874 MOSEK_CALL( MSK_getnumcon(lpi->task, &nrows) );
2875
2876 SCIP_CALL( getbase(lpi, ncols, nrows) );
2877
2878 MOSEK_CALL( MSK_getobjsense(lpi->task, &objsen) );
2879 MOSEK_CALL( MSK_getintparam(lpi->task, MSK_IPAR_SIM_MAX_ITERATIONS, &olditerlim) );
2880 MOSEK_CALL( MSK_getintparam(lpi->task, MSK_IPAR_SIM_DUAL_SELECTION, &oldselection) );
2881 MOSEK_CALL( MSK_getintparam(lpi->task, MSK_IPAR_SIM_HOTSTART, &oldhotstart) );
2882
2883 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_SIM_MAX_ITERATIONS, itlim) );
2884 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_SIM_DUAL_SELECTION, STRONGBRANCH_PRICING) );
2885
2886 if (objsen == MSK_OBJECTIVE_SENSE_MINIMIZE)
2887 {
2888 MOSEK_CALL( MSK_getdouparam(lpi->task, MSK_DPAR_UPPER_OBJ_CUT, &bound) );
2889 }
2890 else /* objsen == MSK_OBJECTIVE_SENSE_MAX */
2891 {
2892 MOSEK_CALL( MSK_getdouparam(lpi->task, MSK_DPAR_LOWER_OBJ_CUT, &bound) );
2893 }
2894
2895 #if MSK_VERSION_MAJOR < 9
2896 MOSEK_CALL( MSK_getbound(lpi->task, MSK_ACC_VAR, col, &bkx, &blx, &bux) );
2897 #else
2898 MOSEK_CALL( MSK_getvarbound(lpi->task, col, &bkx, &blx, &bux) );
2899 #endif
2900
2901 *iter = 0;
2902
2903 newub = EPSCEIL(psol-1.0, 1e-06);
2904
2905 if (newub < blx - 0.5) /* infeasible */
2906 {
2907 *down = bound;
2908 *downvalid = TRUE;
2909 }
2910 else
2911 {
2912 MSKboundkeye newbk;
2913
2914 if (IS_NEGINF(blx))
2915 newbk = MSK_BK_UP;
2916 else if (EPSEQ(blx, newub,1.0e-6))
2917 {
2918 newbk = MSK_BK_FX;
2919 newub = blx;
2920 }
2921 else
2922 newbk = MSK_BK_RA;
2923
2924 #if MSK_VERSION_MAJOR < 9
2925 MOSEK_CALL( MSK_putbound(lpi->task, MSK_ACC_VAR, col, newbk, blx, newub) );
2926 #else
2927 MOSEK_CALL( MSK_putvarbound(lpi->task, col, newbk, blx, newub) );
2928 #endif
2929
2930 SCIP_CALL( SCIPlpiSolveDual(lpi) );
2931
2932 *iter += lpi->itercount;
2933
2934 if (SCIPlpiIsStable(lpi))
2935 *downvalid = TRUE;
2936 else
2937 *downvalid = FALSE;
2938
2939 if (SCIPlpiExistsPrimalRay(lpi))
2940 {
2941 SCIPmessagePrintWarning(lpi->messagehdlr, "SB ERROR: Lp [%d] is dual infeasible\n", optimizecount);
2942
2943 *down = -1e20;
2944 *downvalid = FALSE;
2945 }
2946 else if (SCIPlpiExistsDualRay(lpi))
2947 {
2948 *down = bound;
2949 }
2950 else
2951 {
2952 SCIP_Bool pfeas;
2953 SCIP_Bool dfeas;
2954
2955 SCIP_CALL( SCIPlpiGetSolFeasibility(lpi, &pfeas, &dfeas) );
2956
2957 if (!dfeas)
2958 {
2959 SCIPmessagePrintWarning(lpi->messagehdlr, "SB ERROR: Lp [%d] is not dual feasible\n", optimizecount);
2960
2961 *down = -1e20;
2962 *downvalid = FALSE;
2963 }
2964 else
2965 {
2966 MOSEK_CALL( MSK_getdualobj(lpi->task, lpi->lastsolvetype, down) );
2967 }
2968 }
2969
2970 #if DEBUG_PRINT_STAT > 0
2971 if (lpi->termcode == MSK_RES_TRM_OBJECTIVE_RANGE)
2972 ++numstrongbranchobjup;
2973
2974 if (lpi->termcode == MSK_RES_TRM_MAX_ITERATIONS)
2975 ++numstrongbranchmaxiterup;
2976 #endif
2977 }
2978
2979 /* Reset basis solution before doing the up branch */
2980 #if MSK_VERSION_MAJOR < 9
2981 MOSEK_CALL( MSK_putbound(lpi->task, MSK_ACC_VAR, col, bkx, blx, bux) );
2982 #else
2983 MOSEK_CALL( MSK_putvarbound(lpi->task, col, bkx, blx, bux) );
2984 #endif
2985 SCIP_CALL( setbase(lpi) );
2986
2987 newlb = EPSFLOOR(psol+1.0, 1e-06);
2988 if (newlb > bux + 0.5) /* infeasible */
2989 {
2990 *up = bound;
2991 *upvalid = TRUE;
2992 }
2993 else
2994 {
2995 MSKboundkeye newbk;
2996
2997 if (IS_POSINF(bux))
2998 newbk = MSK_BK_LO;
2999 else if (EPSEQ(bux, newlb,1.0e-6))
3000 {
3001 newbk = MSK_BK_FX;
3002 newlb = bux;
3003 }
3004 else
3005 newbk = MSK_BK_RA;
3006
3007 #if MSK_VERSION_MAJOR < 9
3008 MOSEK_CALL( MSK_putbound(lpi->task, MSK_ACC_VAR, col, newbk, newlb, bux) );
3009 #else
3010 MOSEK_CALL( MSK_putvarbound(lpi->task, col, newbk, newlb, bux) );
3011 #endif
3012 SCIP_CALL( SCIPlpiSolveDual(lpi) );
3013
3014 *iter += lpi->itercount;
3015
3016 if (SCIPlpiIsStable(lpi))
3017 *upvalid = TRUE;
3018 else
3019 *upvalid = FALSE;
3020
3021 if (SCIPlpiExistsPrimalRay(lpi))
3022 {
3023 *up = -1e20;
3024 *upvalid = FALSE;
3025 }
3026 else if (SCIPlpiExistsDualRay(lpi))
3027 {
3028 *up = bound;
3029 }
3030 else
3031 {
3032 SCIP_Bool pfeas;
3033 SCIP_Bool dfeas;
3034
3035 SCIP_CALL( SCIPlpiGetSolFeasibility(lpi, &pfeas, &dfeas) );
3036
3037 if (!dfeas)
3038 {
3039 SCIPmessagePrintWarning(lpi->messagehdlr, "SB ERROR: Lp [%d] is not dual feasible\n", optimizecount);
3040
3041 *up = -1e20;
3042 *upvalid = FALSE;
3043 }
3044 else
3045 {
3046 MOSEK_CALL( MSK_getdualobj(lpi->task, lpi->lastsolvetype, up) );
3047 }
3048 }
3049
3050 #if DEBUG_PRINT_STAT > 0
3051 if (lpi->termcode == MSK_RES_TRM_OBJECTIVE_RANGE)
3052 ++numstrongbranchobjdo;
3053
3054 if (lpi->termcode == MSK_RES_TRM_MAX_ITERATIONS)
3055 ++numstrongbranchmaxiterdo;
3056 #endif
3057 }
3058
3059 #if MSK_VERSION_MAJOR < 9
3060 MOSEK_CALL( MSK_putbound(lpi->task, MSK_ACC_VAR, col, bkx, blx, bux) );
3061 #else
3062 MOSEK_CALL( MSK_putvarbound(lpi->task, col, bkx, blx, bux) );
3063 #endif
3064 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_SIM_MAX_ITERATIONS, olditerlim) );
3065 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_SIM_DUAL_SELECTION, oldselection) );
3066 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_SIM_HOTSTART, oldhotstart) );
3067
3068 SCIP_CALL( setbase(lpi) );
3069
3070 invalidateSolution(lpi);
3071
3072 lpi->termcode = MSK_RES_OK;
3073 lpi->itercount = 0;
3074
3075 #if DEBUG_CHECK_DATA > 0
3076 SCIP_CALL( scip_checkdata(lpi, "SCIPlpiStrongbranch") );
3077 #endif
3078
3079 SCIPdebugMessage("End SCIPlpiStrongbranch (%d)\n", lpi->lpid);
3080
3081 return SCIP_OKAY;
3082 }
3083
3084 /** performs strong branching iterations on one @b fractional candidate
3085 *
3086 * @note last solve call must have been either simplex or barrier with crossover or base must have been set manually
3087 */
SCIPlpiStrongbranchFrac(SCIP_LPI * lpi,int col,SCIP_Real psol,int itlim,SCIP_Real * down,SCIP_Real * up,SCIP_Bool * downvalid,SCIP_Bool * upvalid,int * iter)3088 SCIP_RETCODE SCIPlpiStrongbranchFrac(
3089 SCIP_LPI* lpi, /**< LP interface structure */
3090 int col, /**< column to apply strong branching on */
3091 SCIP_Real psol, /**< fractional current primal solution value of column */
3092 int itlim, /**< iteration limit for strong branchings */
3093 SCIP_Real* down, /**< stores dual bound after branching column down */
3094 SCIP_Real* up, /**< stores dual bound after branching column up */
3095 SCIP_Bool* downvalid, /**< stores whether the returned down value is a valid dual bound;
3096 * otherwise, it can only be used as an estimate value */
3097 SCIP_Bool* upvalid, /**< stores whether the returned up value is a valid dual bound;
3098 * otherwise, it can only be used as an estimate value */
3099 int* iter /**< stores total number of strong branching iterations, or -1; may be NULL */
3100 )
3101 {
3102 /* pass call on to lpiStrongbranch() */
3103 SCIP_CALL( SCIPlpiStrongbranch(lpi, col, psol, itlim, down, up, downvalid, upvalid, iter) );
3104
3105 return SCIP_OKAY;
3106 }
3107
3108 /** performs strong branching iterations on given @b fractional candidates
3109 *
3110 * @note last solve call must have been either simplex or barrier with crossover or base must have been set manually
3111 */
SCIPlpiStrongbranchesFrac(SCIP_LPI * lpi,int * cols,int ncols,SCIP_Real * psols,int itlim,SCIP_Real * down,SCIP_Real * up,SCIP_Bool * downvalid,SCIP_Bool * upvalid,int * iter)3112 SCIP_RETCODE SCIPlpiStrongbranchesFrac(
3113 SCIP_LPI* lpi, /**< LP interface structure */
3114 int* cols, /**< columns to apply strong branching on */
3115 int ncols, /**< number of columns */
3116 SCIP_Real* psols, /**< fractional current primal solution values of columns */
3117 int itlim, /**< iteration limit for strong branchings */
3118 SCIP_Real* down, /**< stores dual bounds after branching columns down */
3119 SCIP_Real* up, /**< stores dual bounds after branching columns up */
3120 SCIP_Bool* downvalid, /**< stores whether the returned down values are valid dual bounds;
3121 * otherwise, they can only be used as an estimate values */
3122 SCIP_Bool* upvalid, /**< stores whether the returned up values are a valid dual bounds;
3123 * otherwise, they can only be used as an estimate values */
3124 int* iter /**< stores total number of strong branching iterations, or -1; may be NULL */
3125 )
3126 {
3127 int j;
3128
3129 assert( cols != NULL );
3130 assert( psols != NULL );
3131 assert( down != NULL );
3132 assert( up != NULL );
3133 assert( downvalid != NULL );
3134 assert( upvalid != NULL );
3135 assert( down != NULL );
3136
3137 if ( iter != NULL )
3138 *iter = 0;
3139
3140 for (j = 0; j < ncols; ++j)
3141 {
3142 /* pass call on to lpiStrongbranch() */
3143 SCIP_CALL( SCIPlpiStrongbranch(lpi, cols[j], psols[j], itlim, &(down[j]), &(up[j]), &(downvalid[j]), &(upvalid[j]), iter) );
3144 }
3145 return SCIP_OKAY;
3146 }
3147
3148 /** performs strong branching iterations on one candidate with @b integral value
3149 *
3150 * @note last solve call must have been either simplex or barrier with crossover or base must have been set manually
3151 */
SCIPlpiStrongbranchInt(SCIP_LPI * lpi,int col,SCIP_Real psol,int itlim,SCIP_Real * down,SCIP_Real * up,SCIP_Bool * downvalid,SCIP_Bool * upvalid,int * iter)3152 SCIP_RETCODE SCIPlpiStrongbranchInt(
3153 SCIP_LPI* lpi, /**< LP interface structure */
3154 int col, /**< column to apply strong branching on */
3155 SCIP_Real psol, /**< current integral primal solution value of column */
3156 int itlim, /**< iteration limit for strong branchings */
3157 SCIP_Real* down, /**< stores dual bound after branching column down */
3158 SCIP_Real* up, /**< stores dual bound after branching column up */
3159 SCIP_Bool* downvalid, /**< stores whether the returned down value is a valid dual bound;
3160 * otherwise, it can only be used as an estimate value */
3161 SCIP_Bool* upvalid, /**< stores whether the returned up value is a valid dual bound;
3162 * otherwise, it can only be used as an estimate value */
3163 int* iter /**< stores total number of strong branching iterations, or -1; may be NULL */
3164 )
3165 {
3166 /* pass call on to lpiStrongbranch() */
3167 SCIP_CALL( SCIPlpiStrongbranch(lpi, col, psol, itlim, down, up, downvalid, upvalid, iter) );
3168
3169 return SCIP_OKAY;
3170 }
3171
3172 /** performs strong branching iterations on given candidates with @b integral values
3173 *
3174 * @note last solve call must have been either simplex or barrier with crossover or base must have been set manually
3175 */
SCIPlpiStrongbranchesInt(SCIP_LPI * lpi,int * cols,int ncols,SCIP_Real * psols,int itlim,SCIP_Real * down,SCIP_Real * up,SCIP_Bool * downvalid,SCIP_Bool * upvalid,int * iter)3176 SCIP_RETCODE SCIPlpiStrongbranchesInt(
3177 SCIP_LPI* lpi, /**< LP interface structure */
3178 int* cols, /**< columns to apply strong branching on */
3179 int ncols, /**< number of columns */
3180 SCIP_Real* psols, /**< current integral primal solution values of columns */
3181 int itlim, /**< iteration limit for strong branchings */
3182 SCIP_Real* down, /**< stores dual bounds after branching columns down */
3183 SCIP_Real* up, /**< stores dual bounds after branching columns up */
3184 SCIP_Bool* downvalid, /**< stores whether the returned down values are valid dual bounds;
3185 * otherwise, they can only be used as an estimate values */
3186 SCIP_Bool* upvalid, /**< stores whether the returned up values are a valid dual bounds;
3187 * otherwise, they can only be used as an estimate values */
3188 int* iter /**< stores total number of strong branching iterations, or -1; may be NULL */
3189 )
3190 {
3191 int j;
3192
3193 assert( cols != NULL );
3194 assert( psols != NULL );
3195 assert( down != NULL );
3196 assert( up != NULL );
3197 assert( downvalid != NULL );
3198 assert( upvalid != NULL );
3199 assert( down != NULL );
3200
3201 if ( iter != NULL )
3202 *iter = 0;
3203
3204 for (j = 0; j < ncols; ++j)
3205 {
3206 /* pass call on to lpiStrongbranch() */
3207 SCIP_CALL( SCIPlpiStrongbranch(lpi, cols[j], psols[j], itlim, &(down[j]), &(up[j]), &(downvalid[j]), &(upvalid[j]), iter) );
3208 }
3209 return SCIP_OKAY;
3210 }
3211
3212
3213 /*
3214 * Solution Information Methods
3215 */
3216
3217
3218 /** returns whether a solve method was called after the last modification of the LP */
SCIPlpiWasSolved(SCIP_LPI * lpi)3219 SCIP_Bool SCIPlpiWasSolved(
3220 SCIP_LPI* lpi /**< LP interface structure */
3221 )
3222 {
3223 assert(lpi != NULL);
3224
3225 return lpi->solved;
3226 }
3227
3228 /** gets information about primal and dual feasibility of the current LP solution
3229 *
3230 * The feasibility information is with respect to the last solving call and it is only relevant if SCIPlpiWasSolved()
3231 * returns true. If the LP is changed, this information might be invalidated.
3232 *
3233 * Note that @a primalfeasible and @a dualfeasible should only return true if the solver has proved the respective LP to
3234 * be feasible. Thus, the return values should be equal to the values of SCIPlpiIsPrimalFeasible() and
3235 * SCIPlpiIsDualFeasible(), respectively. Note that if feasibility cannot be proved, they should return false (even if
3236 * the problem might actually be feasible).
3237 */
SCIPlpiGetSolFeasibility(SCIP_LPI * lpi,SCIP_Bool * primalfeasible,SCIP_Bool * dualfeasible)3238 SCIP_RETCODE SCIPlpiGetSolFeasibility(
3239 SCIP_LPI* lpi, /**< LP interface structure */
3240 SCIP_Bool* primalfeasible, /**< pointer to store primal feasibility status */
3241 SCIP_Bool* dualfeasible /**< pointer to store dual feasibility status */
3242 )
3243 {
3244 MSKprostae prosta;
3245
3246 assert( MosekEnv != NULL );
3247 assert( lpi != NULL );
3248 assert( lpi->task != NULL );
3249 assert( primalfeasible != NULL );
3250 assert( dualfeasible != NULL );
3251
3252 SCIPdebugMessage("Calling SCIPlpiGetSolFeasibility (%d)\n", lpi->lpid);
3253
3254 MOSEK_CALL( MSK_getsolutionstatus(lpi->task, lpi->lastsolvetype, &prosta, NULL) );
3255
3256 switch (prosta)
3257 {
3258 case MSK_PRO_STA_PRIM_AND_DUAL_FEAS:
3259 *primalfeasible = TRUE;
3260 *dualfeasible = TRUE;
3261 break;
3262 case MSK_PRO_STA_PRIM_FEAS:
3263 *primalfeasible = TRUE;
3264 *dualfeasible = FALSE;
3265 break;
3266 case MSK_PRO_STA_DUAL_FEAS:
3267 *primalfeasible = FALSE;
3268 *dualfeasible = TRUE;
3269 break;
3270 case MSK_PRO_STA_DUAL_INFEAS:
3271 /* assume that we have a primal solution if we used the primal simplex */
3272 *primalfeasible = (lpi->lastalgo == MSK_OPTIMIZER_PRIMAL_SIMPLEX);
3273 *dualfeasible = FALSE;
3274 break;
3275 case MSK_PRO_STA_UNKNOWN:
3276 case MSK_PRO_STA_PRIM_INFEAS:
3277 case MSK_PRO_STA_PRIM_AND_DUAL_INFEAS:
3278 case MSK_PRO_STA_ILL_POSED:
3279 #if MSK_VERSION_MAJOR < 9
3280 case MSK_PRO_STA_NEAR_PRIM_AND_DUAL_FEAS:
3281 case MSK_PRO_STA_NEAR_PRIM_FEAS:
3282 case MSK_PRO_STA_NEAR_DUAL_FEAS:
3283 #endif
3284 case MSK_PRO_STA_PRIM_INFEAS_OR_UNBOUNDED:
3285 *primalfeasible = FALSE;
3286 *dualfeasible = FALSE;
3287 break;
3288 default:
3289 return SCIP_LPERROR;
3290 } /*lint !e788*/
3291
3292 return SCIP_OKAY;
3293 }
3294
3295 /** returns TRUE iff LP is proven to have a primal unbounded ray (but not necessary a primal feasible point);
3296 * this does not necessarily mean, that the solver knows and can return the primal ray
3297 */
SCIPlpiExistsPrimalRay(SCIP_LPI * lpi)3298 SCIP_Bool SCIPlpiExistsPrimalRay(
3299 SCIP_LPI* lpi /**< LP interface structure */
3300 )
3301 {
3302 MSKprostae prosta;
3303 MSKsolstae solsta;
3304
3305 assert(MosekEnv != NULL);
3306 assert(lpi != NULL);
3307 assert(lpi->task != NULL);
3308
3309 SCIPdebugMessage("Calling SCIPlpiExistsPrimalRay (%d)\n", lpi->lpid);
3310
3311 SCIP_ABORT_FALSE( getSolutionStatus(lpi, &prosta, &solsta) );
3312
3313 return ( solsta == MSK_SOL_STA_DUAL_INFEAS_CER
3314 || prosta == MSK_PRO_STA_DUAL_INFEAS
3315 || prosta == MSK_PRO_STA_PRIM_AND_DUAL_INFEAS );
3316 }
3317
3318 /** returns TRUE iff LP is proven to have a primal unbounded ray (but not necessary a primal feasible point),
3319 * and the solver knows and can return the primal ray
3320 */
SCIPlpiHasPrimalRay(SCIP_LPI * lpi)3321 SCIP_Bool SCIPlpiHasPrimalRay(
3322 SCIP_LPI* lpi /**< LP interface structure */
3323 )
3324 {
3325 MSKsolstae solsta;
3326
3327 assert(MosekEnv != NULL);
3328 assert(lpi != NULL);
3329 assert(lpi->task != NULL);
3330
3331 SCIPdebugMessage("Calling SCIPlpiHasPrimalRay (%d)\n", lpi->lpid);
3332
3333 SCIP_ABORT_FALSE( getSolutionStatus(lpi, NULL, &solsta) );
3334
3335 return (solsta == MSK_SOL_STA_DUAL_INFEAS_CER);
3336 }
3337
3338 /** returns TRUE iff LP is proven to be primal unbounded */
SCIPlpiIsPrimalUnbounded(SCIP_LPI * lpi)3339 SCIP_Bool SCIPlpiIsPrimalUnbounded(
3340 SCIP_LPI* lpi /**< LP interface structure */
3341 )
3342 { /*lint --e{715}*/
3343 MSKsolstae solsta;
3344
3345 assert(MosekEnv != NULL);
3346 assert(lpi != NULL);
3347 assert(lpi->task != NULL);
3348
3349 SCIP_ABORT_FALSE( getSolutionStatus(lpi, NULL, &solsta) );
3350
3351 /* assume primal solution and ray is available if we used the primal simplex and the dual is proven to be infeasible */
3352 return (solsta == MSK_SOL_STA_DUAL_INFEAS_CER && lpi->lastalgo == MSK_OPTIMIZER_PRIMAL_SIMPLEX);
3353 }
3354
3355 /** returns TRUE iff LP is proven to be primal infeasible */
SCIPlpiIsPrimalInfeasible(SCIP_LPI * lpi)3356 SCIP_Bool SCIPlpiIsPrimalInfeasible(
3357 SCIP_LPI* lpi /**< LP interface structure */
3358 )
3359 {
3360 assert(MosekEnv != NULL);
3361 assert(lpi != NULL);
3362 assert(lpi->task != NULL);
3363
3364 return SCIPlpiExistsDualRay(lpi);
3365 }
3366
3367 /** returns TRUE iff LP is proven to be primal feasible */
SCIPlpiIsPrimalFeasible(SCIP_LPI * lpi)3368 SCIP_Bool SCIPlpiIsPrimalFeasible(
3369 SCIP_LPI* lpi /**< LP interface structure */
3370 )
3371 {
3372 MSKprostae prosta;
3373
3374 assert(MosekEnv != NULL);
3375 assert(lpi != NULL);
3376 assert(lpi->task != NULL);
3377
3378 SCIPdebugMessage("Calling SCIPlpiIsPrimalFeasible (%d)\n", lpi->lpid);
3379
3380 SCIP_ABORT_FALSE( getSolutionStatus(lpi, &prosta, NULL) );
3381
3382 return (prosta == MSK_PRO_STA_PRIM_FEAS || prosta == MSK_PRO_STA_PRIM_AND_DUAL_FEAS || (prosta == MSK_PRO_STA_DUAL_INFEAS && lpi->lastalgo == MSK_OPTIMIZER_PRIMAL_SIMPLEX));
3383 }
3384
3385 /** returns TRUE iff LP is proven to have a dual unbounded ray (but not necessary a dual feasible point);
3386 * this does not necessarily mean, that the solver knows and can return the dual ray
3387 */
SCIPlpiExistsDualRay(SCIP_LPI * lpi)3388 SCIP_Bool SCIPlpiExistsDualRay(
3389 SCIP_LPI* lpi /**< LP interface structure */
3390 )
3391 {
3392 MSKprostae prosta;
3393 MSKsolstae solsta;
3394
3395 assert(MosekEnv != NULL);
3396 assert(lpi != NULL);
3397 assert(lpi->task != NULL);
3398
3399 SCIPdebugMessage("Calling SCIPlpiExistsDualRay (%d)\n", lpi->lpid);
3400
3401 SCIP_ABORT_FALSE( getSolutionStatus(lpi, &prosta, &solsta) );
3402
3403 return ( solsta == MSK_SOL_STA_PRIM_INFEAS_CER
3404 || prosta == MSK_PRO_STA_PRIM_INFEAS
3405 || prosta == MSK_PRO_STA_PRIM_AND_DUAL_INFEAS );
3406 }
3407
3408 /** returns TRUE iff LP is proven to have a dual unbounded ray (but not necessary a dual feasible point),
3409 * and the solver knows and can return the dual ray
3410 */
SCIPlpiHasDualRay(SCIP_LPI * lpi)3411 SCIP_Bool SCIPlpiHasDualRay(
3412 SCIP_LPI* lpi /**< LP interface structure */
3413 )
3414 {
3415 MSKsolstae solsta;
3416
3417 assert(MosekEnv != NULL);
3418 assert(lpi != NULL);
3419 assert(lpi->task != NULL);
3420
3421 SCIPdebugMessage("Calling SCIPlpiHasDualRay (%d)\n", lpi->lpid);
3422
3423 SCIP_ABORT_FALSE( getSolutionStatus(lpi, NULL, &solsta) );
3424
3425 return (solsta == MSK_SOL_STA_PRIM_INFEAS_CER);
3426 }
3427
3428 /** returns TRUE iff LP is proven to be dual unbounded */
SCIPlpiIsDualUnbounded(SCIP_LPI * lpi)3429 SCIP_Bool SCIPlpiIsDualUnbounded(
3430 SCIP_LPI* lpi /**< LP interface structure */
3431 )
3432 { /*lint --e{715}*/
3433 assert(MosekEnv != NULL);
3434 assert(lpi != NULL);
3435 assert(lpi->task != NULL);
3436
3437 return FALSE;
3438 }
3439
3440 /** returns TRUE iff LP is proven to be dual infeasible */
SCIPlpiIsDualInfeasible(SCIP_LPI * lpi)3441 SCIP_Bool SCIPlpiIsDualInfeasible(
3442 SCIP_LPI* lpi /**< LP interface structure */
3443 )
3444 {
3445 assert(MosekEnv != NULL);
3446 assert(lpi != NULL);
3447 assert(lpi->task != NULL);
3448
3449 return SCIPlpiExistsPrimalRay(lpi);
3450 }
3451
3452 /** returns TRUE iff LP is proven to be dual feasible */
SCIPlpiIsDualFeasible(SCIP_LPI * lpi)3453 SCIP_Bool SCIPlpiIsDualFeasible(
3454 SCIP_LPI* lpi /**< LP interface structure */
3455 )
3456 {
3457 MSKprostae prosta;
3458
3459 assert(MosekEnv != NULL);
3460 assert(lpi != NULL);
3461 assert(lpi->task != NULL);
3462
3463 SCIPdebugMessage("Calling SCIPlpiIsDualFeasible (%d)\n", lpi->lpid);
3464
3465 SCIP_ABORT_FALSE( getSolutionStatus(lpi, &prosta, NULL) );
3466
3467 return (prosta == MSK_PRO_STA_DUAL_FEAS || prosta == MSK_PRO_STA_PRIM_AND_DUAL_FEAS);
3468 }
3469
3470 /** returns TRUE iff LP was solved to optimality */
SCIPlpiIsOptimal(SCIP_LPI * lpi)3471 SCIP_Bool SCIPlpiIsOptimal(
3472 SCIP_LPI* lpi /**< LP interface structure */
3473 )
3474 {
3475 MSKsolstae solsta;
3476
3477 assert(MosekEnv != NULL);
3478 assert(lpi != NULL);
3479 assert(lpi->task != NULL);
3480
3481 SCIPdebugMessage("Calling SCIPlpiIsOptimal (%d)\n", lpi->lpid);
3482
3483 SCIP_ABORT_FALSE( getSolutionStatus(lpi, NULL, &solsta) );
3484
3485 return (solsta == MSK_SOL_STA_OPTIMAL);
3486 }
3487
3488 /** returns TRUE iff current LP solution is stable
3489 *
3490 * This function should return true if the solution is reliable, i.e., feasible and optimal (or proven
3491 * infeasible/unbounded) with respect to the original problem. The optimality status might be with respect to a scaled
3492 * version of the problem, but the solution might not be feasible to the unscaled original problem; in this case,
3493 * SCIPlpiIsStable() should return false.
3494 */
SCIPlpiIsStable(SCIP_LPI * lpi)3495 SCIP_Bool SCIPlpiIsStable(
3496 SCIP_LPI* lpi /**< LP interface structure */
3497 )
3498 {
3499 assert(MosekEnv != NULL);
3500 assert(lpi != NULL);
3501 assert(lpi->task != NULL);
3502
3503 return ( lpi->termcode == MSK_RES_OK
3504 || lpi->termcode == MSK_RES_TRM_MAX_ITERATIONS
3505 || lpi->termcode == MSK_RES_TRM_MAX_TIME
3506 || lpi->termcode == MSK_RES_TRM_OBJECTIVE_RANGE );
3507 }
3508
3509 /** returns TRUE iff the objective limit was reached */
SCIPlpiIsObjlimExc(SCIP_LPI * lpi)3510 SCIP_Bool SCIPlpiIsObjlimExc(
3511 SCIP_LPI* lpi /**< LP interface structure */
3512 )
3513 {
3514 assert(MosekEnv != NULL);
3515 assert(lpi != NULL);
3516 assert(lpi->task != NULL);
3517
3518 return ( lpi->termcode == MSK_RES_TRM_OBJECTIVE_RANGE );
3519 }
3520
3521 /** returns TRUE iff the iteration limit was reached */
SCIPlpiIsIterlimExc(SCIP_LPI * lpi)3522 SCIP_Bool SCIPlpiIsIterlimExc(
3523 SCIP_LPI* lpi /**< LP interface structure */
3524 )
3525 {
3526 assert(MosekEnv != NULL);
3527 assert(lpi != NULL);
3528 assert(lpi->task != NULL);
3529
3530 return ( lpi->termcode == MSK_RES_TRM_MAX_ITERATIONS );
3531 }
3532
3533 /** returns TRUE iff the time limit was reached */
SCIPlpiIsTimelimExc(SCIP_LPI * lpi)3534 SCIP_Bool SCIPlpiIsTimelimExc(
3535 SCIP_LPI* lpi /**< LP interface structure */
3536 )
3537 {
3538 assert(MosekEnv != NULL);
3539 assert(lpi != NULL);
3540 assert(lpi->task != NULL);
3541
3542 return ( lpi->termcode == MSK_RES_TRM_MAX_TIME );
3543 }
3544
3545 /** returns the internal solution status of the solver */
SCIPlpiGetInternalStatus(SCIP_LPI * lpi)3546 int SCIPlpiGetInternalStatus(
3547 SCIP_LPI* lpi /**< LP interface structure */
3548 )
3549 {
3550 MSKsolstae solsta;
3551 SCIP_RETCODE retcode;
3552
3553 assert(MosekEnv != NULL);
3554 assert(lpi != NULL);
3555 assert(lpi->task != NULL);
3556
3557 SCIPdebugMessage("Calling SCIPlpiGetInternalStatus (%d)\n", lpi->lpid);
3558
3559 retcode = getSolutionStatus(lpi, NULL, &solsta);
3560 if ( retcode != SCIP_OKAY )
3561 return 0;
3562
3563 return (int) solsta;
3564 }
3565
3566 /** tries to reset the internal status of the LP solver in order to ignore an instability of the last solving call */
SCIPlpiIgnoreInstability(SCIP_LPI * lpi,SCIP_Bool * success)3567 SCIP_RETCODE SCIPlpiIgnoreInstability(
3568 SCIP_LPI* lpi, /**< LP interface structure */
3569 SCIP_Bool* success /**< pointer to store, whether the instability could be ignored */
3570 )
3571 {
3572 assert(MosekEnv != NULL);
3573 assert(lpi != NULL);
3574 assert(lpi->task != NULL);
3575 assert(success != NULL);
3576
3577 SCIPdebugMessage("Calling SCIPlpiIgnoreInstability (%d)\n", lpi->lpid);
3578
3579 *success = FALSE;
3580
3581 return SCIP_OKAY;
3582 }
3583
3584 /** gets objective value of solution */
SCIPlpiGetObjval(SCIP_LPI * lpi,SCIP_Real * objval)3585 SCIP_RETCODE SCIPlpiGetObjval(
3586 SCIP_LPI* lpi, /**< LP interface structure */
3587 SCIP_Real* objval /**< stores the objective value */
3588 )
3589 {
3590 assert(MosekEnv != NULL);
3591 assert(lpi != NULL);
3592 assert(lpi->task != NULL);
3593 assert(objval != NULL);
3594
3595 SCIPdebugMessage("Calling SCIPlpiGetObjval (%d)\n", lpi->lpid);
3596
3597 MOSEK_CALL( MSK_getprimalobj(lpi->task, lpi->lastsolvetype, objval) );
3598
3599 /* TODO: tjek lighed med dual objektiv i de fleste tilfaelde. */
3600
3601 return SCIP_OKAY;
3602 }
3603
3604 /** gets primal and dual solution vectors for feasible LPs
3605 *
3606 * Before calling this function, the caller must ensure that the LP has been solved to optimality, i.e., that
3607 * SCIPlpiIsOptimal() returns true.
3608 */
SCIPlpiGetSol(SCIP_LPI * lpi,SCIP_Real * objval,SCIP_Real * primsol,SCIP_Real * dualsol,SCIP_Real * activity,SCIP_Real * redcost)3609 SCIP_RETCODE SCIPlpiGetSol(
3610 SCIP_LPI* lpi, /**< LP interface structure */
3611 SCIP_Real* objval, /**< stores the objective value, may be NULL if not needed */
3612 SCIP_Real* primsol, /**< primal solution vector, may be NULL if not needed */
3613 SCIP_Real* dualsol, /**< dual solution vector, may be NULL if not needed */
3614 SCIP_Real* activity, /**< row activity vector, may be NULL if not needed */
3615 SCIP_Real* redcost /**< reduced cost vector, may be NULL if not needed */
3616 )
3617 {
3618 MSKsolstae solsta;
3619 double* sux = NULL;
3620 int ncols = 0;
3621 int i;
3622
3623 assert(MosekEnv != NULL);
3624 assert(lpi != NULL);
3625 assert(lpi->task != NULL);
3626
3627 SCIPdebugMessage("Calling SCIPlpiGetSol (%d)\n", lpi->lpid);
3628
3629 if ( objval != NULL )
3630 {
3631 MOSEK_CALL( MSK_getprimalobj(lpi->task, lpi->lastsolvetype, objval) );
3632 }
3633
3634 if( redcost )
3635 {
3636 MOSEK_CALL( MSK_getnumvar(lpi->task, &ncols) );
3637 SCIP_ALLOC( BMSallocMemoryArray(&sux, ncols) );
3638 }
3639
3640 if ( primsol != NULL && lpi->lastalgo == MSK_OPTIMIZER_PRIMAL_SIMPLEX )
3641 {
3642 /* If the status shows that the dual is infeasible this is due to the primal being unbounded. In this case, we need
3643 * to compute a feasible solution by setting the objective to 0.
3644 */
3645 MOSEK_CALL( MSK_getsolutionstatus(lpi->task, MSK_SOL_BAS, NULL, &solsta) );
3646 if ( solsta == MSK_SOL_STA_DUAL_INFEAS_CER )
3647 {
3648 SCIP_Real* objcoefs;
3649 int j;
3650
3651 MOSEK_CALL( MSK_getnumvar(lpi->task, &ncols) );
3652 SCIP_ALLOC( BMSallocMemoryArray(&objcoefs, ncols) );
3653
3654 /* store old objective coefficients and set them to 0 */
3655 for (j = 0; j < ncols; ++j)
3656 {
3657 MOSEK_CALL( MSK_getcj(lpi->task, j, &objcoefs[j]) );
3658 MOSEK_CALL( MSK_putcj(lpi->task, j, 0.0) );
3659 }
3660
3661 /* solve problem again */
3662 SCIP_CALL( SolveWSimplex(lpi) );
3663
3664 /* At this point we assume that the problem is feasible, since we previously ran the primal simplex and it
3665 * produced a ray.
3666 */
3667
3668 /* get primal solution */
3669 MOSEK_CALL( MSK_getsolution(lpi->task, lpi->lastsolvetype, NULL, NULL, NULL, NULL, NULL, activity,
3670 primsol, NULL, NULL, NULL, NULL, NULL, NULL) );
3671
3672 /* restore objective */
3673 MOSEK_CALL( MSK_putcslice(lpi->task, 0, ncols, objcoefs) );
3674
3675 /* resolve to restore original status */
3676 SCIP_CALL( SolveWSimplex(lpi) );
3677
3678 BMSfreeMemoryArray(&objcoefs);
3679 }
3680 else
3681 {
3682 MOSEK_CALL( MSK_getsolution(lpi->task, lpi->lastsolvetype, NULL, NULL, NULL, NULL, NULL, activity,
3683 primsol, dualsol, NULL, NULL, redcost, sux, NULL) );
3684 }
3685 }
3686 else
3687 {
3688 MOSEK_CALL( MSK_getsolution(lpi->task, lpi->lastsolvetype, NULL, NULL, NULL, NULL, NULL, activity,
3689 primsol, dualsol, NULL, NULL, redcost, sux, NULL) );
3690 }
3691
3692 /* the reduced costs are given by the difference of the slx and sux variables (third and second to last parameters) */
3693 if( redcost )
3694 {
3695 for( i = 0; i < ncols; i++ )
3696 {
3697 assert(sux != NULL);
3698 redcost[i] -= sux[i];
3699 }
3700 BMSfreeMemoryArray(&sux);
3701 }
3702
3703 return SCIP_OKAY;
3704 }
3705
3706 /** gets primal ray for unbounded LPs */
SCIPlpiGetPrimalRay(SCIP_LPI * lpi,SCIP_Real * ray)3707 SCIP_RETCODE SCIPlpiGetPrimalRay(
3708 SCIP_LPI* lpi, /**< LP interface structure */
3709 SCIP_Real* ray /**< primal ray */
3710 )
3711 {
3712 assert(MosekEnv != NULL);
3713 assert(lpi != NULL);
3714 assert(lpi->task != NULL);
3715 assert(ray != NULL);
3716
3717 SCIPdebugMessage("Calling SCIPlpiGetPrimalRay (%d)\n", lpi->lpid);
3718
3719 MOSEK_CALL( MSK_getsolution(lpi->task, lpi->lastsolvetype, NULL, NULL, NULL, NULL, NULL, NULL, ray,
3720 NULL, NULL, NULL, NULL, NULL, NULL) );
3721
3722 return SCIP_OKAY;
3723 }
3724
3725 /** gets dual Farkas proof for infeasibility */
SCIPlpiGetDualfarkas(SCIP_LPI * lpi,SCIP_Real * dualfarkas)3726 SCIP_RETCODE SCIPlpiGetDualfarkas(
3727 SCIP_LPI* lpi, /**< LP interface structure */
3728 SCIP_Real* dualfarkas /**< dual Farkas row multipliers */
3729 )
3730 {
3731 assert(MosekEnv != NULL);
3732 assert(lpi != NULL);
3733 assert(lpi->task != NULL);
3734 assert(dualfarkas != NULL);
3735
3736 SCIPdebugMessage("Calling SCIPlpiGetDualfarkas (%d)\n", lpi->lpid);
3737
3738 MOSEK_CALL( MSK_getsolution(lpi->task, lpi->lastsolvetype, NULL, NULL, NULL, NULL, NULL, NULL, NULL, dualfarkas,
3739 NULL, NULL, NULL, NULL, NULL) );
3740
3741 return SCIP_OKAY;
3742 }
3743
3744 /** gets the number of LP iterations of the last solve call */
SCIPlpiGetIterations(SCIP_LPI * lpi,int * iterations)3745 SCIP_RETCODE SCIPlpiGetIterations(
3746 SCIP_LPI* lpi, /**< LP interface structure */
3747 int* iterations /**< pointer to store the number of iterations of the last solve call */
3748 )
3749 {
3750 assert(MosekEnv != NULL);
3751 assert(lpi != NULL);
3752 assert(lpi->task != NULL);
3753 assert(iterations != NULL);
3754
3755 SCIPdebugMessage("Calling SCIPlpiGetIterations (%d)\n", lpi->lpid);
3756
3757 *iterations = lpi->itercount;
3758
3759 return SCIP_OKAY;
3760 }
3761
3762 /** gets information about the quality of an LP solution
3763 *
3764 * Such information is usually only available, if also a (maybe not optimal) solution is available.
3765 * The LPI should return SCIP_INVALID for @p quality, if the requested quantity is not available.
3766 */
SCIPlpiGetRealSolQuality(SCIP_LPI * lpi,SCIP_LPSOLQUALITY qualityindicator,SCIP_Real * quality)3767 SCIP_RETCODE SCIPlpiGetRealSolQuality(
3768 SCIP_LPI* lpi, /**< LP interface structure */
3769 SCIP_LPSOLQUALITY qualityindicator, /**< indicates which quality should be returned */
3770 SCIP_Real* quality /**< pointer to store quality number */
3771 )
3772 { /*lint --e{715}*/
3773 assert(MosekEnv != NULL);
3774 assert(lpi != NULL);
3775 assert(lpi->task != NULL);
3776 assert(quality != NULL);
3777 SCIP_UNUSED(qualityindicator);
3778
3779 *quality = SCIP_INVALID;
3780
3781 return SCIP_OKAY;
3782 }
3783
3784 /** handle singular basis */
3785 static
handle_singular(SCIP_LPI * lpi,int * basis,MSKrescodee res)3786 SCIP_RETCODE handle_singular(
3787 SCIP_LPI* lpi, /**< LP interface structure */
3788 int* basis, /**< array of basis indices */
3789 MSKrescodee res /**< result */
3790 )
3791 {
3792 if (res == MSK_RES_ERR_BASIS_SINGULAR)
3793 {
3794 SCIP_CALL( SCIPlpiSolvePrimal(lpi) );
3795
3796 MOSEK_CALL( MSK_initbasissolve(lpi->task, basis) );
3797 }
3798 else
3799 {
3800 MOSEK_CALL( res );
3801 }
3802
3803 return SCIP_OKAY;
3804 }
3805
3806
3807 /*
3808 * LP Basis Methods
3809 */
3810
3811 /** convert Mosek basis status to SCIP basis status
3812 *
3813 * @note last solve call must have been either simplex or barrier with crossover or base must have been set manually
3814 */
3815 static
convertstat_mosek2scip(SCIP_LPI * lpi,SCIP_Bool iscon,MSKstakeye * sk,int n,int * stat)3816 SCIP_RETCODE convertstat_mosek2scip(
3817 SCIP_LPI* lpi, /**< LP interface structure */
3818 SCIP_Bool iscon, /**< whether constraints/variables are considered */
3819 MSKstakeye* sk, /**< status array of Mosek */
3820 int n, /**< size */
3821 int* stat /**< status array of SCIP */
3822 )
3823 {
3824 int i;
3825
3826 assert(lpi->lastsolvetype == MSK_SOL_BAS);
3827
3828 for( i = 0; i < n; i++ )
3829 {
3830 double sl;
3831 double su;
3832
3833 switch (sk[i])
3834 {
3835 case MSK_SK_BAS:
3836 stat[i] = (int)SCIP_BASESTAT_BASIC;
3837 break;
3838 case MSK_SK_SUPBAS:
3839 stat[i] = (int)SCIP_BASESTAT_ZERO;
3840 break;
3841 case MSK_SK_FIX:
3842 #if MSK_VERSION_MAJOR < 9
3843 MOSEK_CALL( MSK_getsolutioni(lpi->task, iscon ? MSK_ACC_CON : MSK_ACC_VAR, i, MSK_SOL_BAS, NULL, NULL, &sl, &su, NULL) );
3844 #else
3845 if( iscon )
3846 {
3847 MOSEK_CALL( MSK_getslcslice(lpi->task, MSK_SOL_BAS, i, i+1, &sl ) );
3848 MOSEK_CALL( MSK_getsucslice(lpi->task, MSK_SOL_BAS, i, i+1, &su ) );
3849 }
3850 else
3851 {
3852 MOSEK_CALL( MSK_getslxslice(lpi->task, MSK_SOL_BAS, i, i+1, &sl ) );
3853 MOSEK_CALL( MSK_getsuxslice(lpi->task, MSK_SOL_BAS, i, i+1, &su ) );
3854 }
3855 #endif
3856
3857 if (sl < su) /* Negative reduced cost */
3858 stat[i] = (int)SCIP_BASESTAT_UPPER;
3859 else
3860 stat[i] = (int)SCIP_BASESTAT_LOWER;
3861 break;
3862 case MSK_SK_UNK:
3863 stat[i] = (int)SCIP_BASESTAT_LOWER;
3864 break;
3865 case MSK_SK_INF:
3866 stat[i] = (int)SCIP_BASESTAT_LOWER;
3867 break;
3868 case MSK_SK_LOW:
3869 stat[i] = (int)SCIP_BASESTAT_LOWER;
3870 break;
3871 case MSK_SK_UPR:
3872 stat[i] = (int)SCIP_BASESTAT_UPPER;
3873 break;
3874 case MSK_SK_END:
3875 break;
3876 default:
3877 SCIPABORT();
3878 return SCIP_INVALIDDATA; /*lint !e527*/
3879 } /*lint !e788*/
3880 }
3881
3882 return SCIP_OKAY;
3883 }
3884
3885 /** convert Mosek to SCIP basis status - slack variables
3886 *
3887 * @note last solve call must have been either simplex or barrier with crossover or base must have been set manually
3888 */
3889 static
convertstat_mosek2scip_slack(SCIP_LPI * lpi,SCIP_Bool iscon,MSKstakeye * sk,int m,int * stat)3890 SCIP_RETCODE convertstat_mosek2scip_slack(
3891 SCIP_LPI* lpi, /**< LP interface structure */
3892 SCIP_Bool iscon, /**< whether constraints or variables are accessed */
3893 MSKstakeye* sk, /**< Mosek basis status */
3894 int m, /**< size */
3895 int* stat /**< status array */
3896 )
3897 {
3898 int i;
3899
3900 assert(lpi->lastsolvetype == MSK_SOL_BAS);
3901
3902 for( i = 0; i < m; i++ )
3903 {
3904 double sl;
3905 double su;
3906 switch (sk[i])
3907 {
3908 case MSK_SK_BAS:
3909 stat[i] = (int)SCIP_BASESTAT_BASIC;
3910 break;
3911 case MSK_SK_SUPBAS:
3912 stat[i] = (int)SCIP_BASESTAT_ZERO;
3913 break;
3914 case MSK_SK_FIX:
3915 #if MSK_VERSION_MAJOR < 9
3916 MOSEK_CALL( MSK_getsolutioni(lpi->task, iscon ? MSK_ACC_CON : MSK_ACC_VAR, i, MSK_SOL_BAS, NULL, NULL, &sl, &su, NULL) );
3917 #else
3918 if( iscon )
3919 {
3920 MOSEK_CALL( MSK_getslcslice(lpi->task, MSK_SOL_BAS, i, i+1, &sl ) );
3921 MOSEK_CALL( MSK_getsucslice(lpi->task, MSK_SOL_BAS, i, i+1, &su ) );
3922 }
3923 else
3924 {
3925 MOSEK_CALL( MSK_getslxslice(lpi->task, MSK_SOL_BAS, i, i+1, &sl ) );
3926 MOSEK_CALL( MSK_getsuxslice(lpi->task, MSK_SOL_BAS, i, i+1, &su ) );
3927 }
3928 #endif
3929
3930 if (sl < su) /* Negative reduced cost */
3931 stat[i] = (int)SCIP_BASESTAT_UPPER;
3932 else
3933 stat[i] = (int)SCIP_BASESTAT_LOWER;
3934 break;
3935 case MSK_SK_UNK:
3936 case MSK_SK_INF:
3937 case MSK_SK_UPR:
3938 stat[i] = (int)SCIP_BASESTAT_UPPER;
3939 break;
3940 case MSK_SK_LOW:
3941 stat[i] = (int)SCIP_BASESTAT_LOWER;
3942 break;
3943 case MSK_SK_END:
3944 default:
3945 SCIPABORT();
3946 return SCIP_INVALIDDATA; /*lint !e527*/
3947 } /*lint !e788*/
3948 }
3949
3950 return SCIP_OKAY;
3951 }
3952
3953 /** convert SCIP to Mosek basis status */
3954 static
convertstat_scip2mosek(const int * stat,int n,MSKstakeye * resstat)3955 void convertstat_scip2mosek(
3956 const int* stat, /**< SCIP status array */
3957 int n, /**< size of array */
3958 MSKstakeye* resstat /**< resulting Mosek status array */
3959 )
3960 {
3961 int i;
3962 for( i = 0; i < n; i++ )
3963 {
3964 switch (stat[i])
3965 {
3966 case SCIP_BASESTAT_LOWER:
3967 resstat[i] = MSK_SK_LOW;
3968 break;
3969 case SCIP_BASESTAT_BASIC:
3970 resstat[i] = MSK_SK_BAS;
3971 break;
3972 case SCIP_BASESTAT_UPPER:
3973 resstat[i] = MSK_SK_UPR;
3974 break;
3975 case SCIP_BASESTAT_ZERO:
3976 resstat[i] = MSK_SK_SUPBAS;
3977 break;
3978 default:
3979 SCIPABORT();
3980 }
3981 }
3982 }
3983
3984 /** convert SCIP to Mosek basis status - slack variables */
3985 static
convertstat_scip2mosek_slack(const int * stat,int n,MSKstakeye * resstat)3986 void convertstat_scip2mosek_slack(
3987 const int* stat, /**< SCIP status array */
3988 int n, /**< size of array */
3989 MSKstakeye* resstat /**< resulting Mosek status array */
3990 )
3991 {
3992 /* slacks are stored as -1 in Mosek, i.e., bounds are reversed compared to SCIP */
3993 int i;
3994
3995 for( i = 0; i < n; i++ )
3996 {
3997 switch (stat[i])
3998 {
3999 case SCIP_BASESTAT_LOWER:
4000 resstat[i] = MSK_SK_UPR; /* Reversed */
4001 break;
4002 case SCIP_BASESTAT_BASIC:
4003 resstat[i] = MSK_SK_BAS;
4004 break;
4005 case SCIP_BASESTAT_UPPER:
4006 resstat[i] = MSK_SK_LOW; /* Reversed */
4007 break;
4008 case SCIP_BASESTAT_ZERO:
4009 resstat[i] = MSK_SK_SUPBAS;
4010 break;
4011 default:
4012 SCIPABORT();
4013 }
4014 }
4015 }
4016
4017 /** gets current basis status for columns and rows; arrays must be large enough to store the basis status
4018 *
4019 * @note last solve call must have been either simplex or barrier with crossover or base must have been set manually
4020 */
SCIPlpiGetBase(SCIP_LPI * lpi,int * cstat,int * rstat)4021 SCIP_RETCODE SCIPlpiGetBase(
4022 SCIP_LPI* lpi, /**< LP interface structure */
4023 int* cstat, /**< array to store column basis status, or NULL */
4024 int* rstat /**< array to store row basis status, or NULL */
4025 )
4026 {
4027 int nrows;
4028 int ncols;
4029
4030 assert(MosekEnv != NULL);
4031 assert(lpi != NULL);
4032 assert(lpi->task != NULL);
4033 assert(lpi->lastsolvetype == MSK_SOL_BAS);
4034
4035 SCIPdebugMessage("Calling SCIPlpiGetBase (%d)\n", lpi->lpid);
4036
4037 MOSEK_CALL( MSK_getnumvar(lpi->task, &ncols) );
4038 MOSEK_CALL( MSK_getnumcon(lpi->task, &nrows) );
4039
4040 SCIP_CALL( getbase(lpi, ncols, nrows) );
4041
4042 if (cstat)
4043 {
4044 SCIP_CALL( convertstat_mosek2scip(lpi, FALSE, lpi->skx, ncols, cstat) );
4045 }
4046
4047 if (rstat)
4048 {
4049 SCIP_CALL( convertstat_mosek2scip_slack(lpi, TRUE, lpi->skc, nrows, rstat) );
4050 }
4051
4052 return SCIP_OKAY;
4053 }
4054
4055 /** sets current basis status for columns and rows */
SCIPlpiSetBase(SCIP_LPI * lpi,const int * cstat,const int * rstat)4056 SCIP_RETCODE SCIPlpiSetBase(
4057 SCIP_LPI* lpi, /**< LP interface structure */
4058 const int* cstat, /**< array with column basis status */
4059 const int* rstat /**< array with row basis status */
4060 )
4061 {
4062 int nrows;
4063 int ncols;
4064
4065 assert(MosekEnv != NULL);
4066 assert(lpi != NULL);
4067 assert(lpi->task != NULL);
4068
4069 SCIP_CALL( SCIPlpiGetNRows(lpi, &nrows) );
4070 SCIP_CALL( SCIPlpiGetNCols(lpi, &ncols) );
4071
4072 assert(cstat != NULL || ncols == 0);
4073 assert(rstat != NULL || nrows == 0);
4074
4075 SCIPdebugMessage("Calling SCIPlpiSetBase (%d)\n", lpi->lpid);
4076
4077 SCIP_CALL( ensureStateMem(lpi, ncols, nrows) );
4078
4079 convertstat_scip2mosek(cstat, ncols, lpi->skx);
4080 convertstat_scip2mosek_slack(rstat, nrows, lpi->skc);
4081
4082 SCIP_CALL( setbase(lpi) );
4083
4084 invalidateSolution(lpi);
4085
4086 return SCIP_OKAY;
4087 }
4088
4089 /** returns the indices of the basic columns and rows; basic column n gives value n, basic row m gives value -1-m */
SCIPlpiGetBasisInd(SCIP_LPI * lpi,int * bind)4090 SCIP_RETCODE SCIPlpiGetBasisInd(
4091 SCIP_LPI* lpi, /**< LP interface structure */
4092 int* bind /**< pointer to store basis indices ready to keep number of rows entries */
4093 )
4094 {
4095 int nrows;
4096 int i;
4097
4098 assert(MosekEnv != NULL);
4099 assert(lpi != NULL);
4100 assert(lpi->task != NULL);
4101 assert(bind != NULL);
4102
4103 SCIPdebugMessage("Calling SCIPlpiGetBasisInd (%d)\n", lpi->lpid);
4104
4105 MOSEK_CALL( MSK_getnumcon(lpi->task, &nrows) );
4106
4107 SCIP_CALL( handle_singular(lpi, bind, MSK_initbasissolve(lpi->task, bind)) );
4108
4109 for (i = 0; i < nrows; i++ )
4110 {
4111 if (bind[i] < nrows) /* row bind[i] is basic */
4112 bind[i] = -1 - bind[i];
4113 else /* column bind[i]-nrows is basic */
4114 bind[i] = bind[i] - nrows;
4115 }
4116
4117 return SCIP_OKAY;
4118 }
4119
4120 /** get row of inverse basis matrix B^-1
4121 *
4122 * @note The LP interface defines slack variables to have coefficient +1. This means that if, internally, the LP solver
4123 * uses a -1 coefficient, then rows associated with slacks variables whose coefficient is -1, should be negated;
4124 * see also the explanation in lpi.h.
4125 *
4126 * @todo check that the result is in terms of the LP interface definition
4127 *
4128 * @todo check if this should invalidate the solution
4129 */
SCIPlpiGetBInvRow(SCIP_LPI * lpi,int r,SCIP_Real * coef,int * inds,int * ninds)4130 SCIP_RETCODE SCIPlpiGetBInvRow(
4131 SCIP_LPI* lpi, /**< LP interface structure */
4132 int r, /**< row number */
4133 SCIP_Real* coef, /**< pointer to store the coefficients of the row */
4134 int* inds, /**< array to store the non-zero indices, or NULL */
4135 int* ninds /**< pointer to store the number of non-zero indices, or NULL
4136 * (-1: if we do not store sparsity information) */
4137 )
4138 {
4139 int nrows;
4140 int i;
4141
4142 assert(MosekEnv != NULL);
4143 assert(lpi != NULL);
4144 assert(lpi->task != NULL);
4145 assert(coef != NULL);
4146
4147 SCIPdebugMessage("Calling SCIPlpiGetBInvRow (%d)\n", lpi->lpid);
4148
4149 MOSEK_CALL( MSK_getnumcon(lpi->task, &nrows) );
4150
4151 /* set coefficient for slack variables to be 1 instead of -1 */
4152 MOSEK_CALL( MSK_putnaintparam(lpi->task, MSK_IPAR_BASIS_SOLVE_USE_PLUS_ONE_, MSK_ON) );
4153
4154 /* prepare basis in Mosek, since we do not need the basis ourselves, we set the return parameter to NULL */
4155 SCIP_CALL( handle_singular(lpi, NULL, MSK_initbasissolve(lpi->task, NULL)) );
4156
4157 /* initialize rhs of system to be a dense +/- unit vector (needed for MSK_solvewithbasis()) */
4158 for (i = 0; i < nrows; ++i)
4159 coef[i] = 0.0;
4160 coef[r] = 1.0; /* unit vector e_r */
4161
4162 /* check whether we require a dense or sparse result vector */
4163 if ( ninds != NULL && inds != NULL )
4164 {
4165 *ninds = 1;
4166 inds[0]= r;
4167
4168 /* solve transposed system */
4169 MOSEK_CALL( MSK_solvewithbasis(lpi->task, 1, ninds, inds, coef) );
4170 assert( *ninds <= nrows );
4171 }
4172 else
4173 {
4174 int* sub;
4175 int numnz;
4176
4177 SCIP_ALLOC( BMSallocMemoryArray(&sub, nrows) );
4178
4179 numnz = 1;
4180 sub[0] = r;
4181
4182 /* solve transposed system */
4183 MOSEK_CALL( MSK_solvewithbasis(lpi->task, 1, &numnz, sub, coef) );
4184 assert( numnz <= nrows );
4185
4186 BMSfreeMemoryArray(&sub);
4187 }
4188 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_SIM_HOTSTART_LU, MSK_ON) );
4189
4190 SCIPdebugMessage("End SCIPlpiGetBInvRow (%d)\n", lpi->lpid);
4191
4192 return SCIP_OKAY;
4193 }
4194
4195 /** get column of inverse basis matrix B^-1
4196 *
4197 * @note The LP interface defines slack variables to have coefficient +1. This means that if, internally, the LP solver
4198 * uses a -1 coefficient, then rows associated with slacks variables whose coefficient is -1, should be negated;
4199 * see also the explanation in lpi.h.
4200 *
4201 * @todo check that the result is in terms of the LP interface definition
4202 *
4203 * @todo check if this should invalidate the solution
4204 */
SCIPlpiGetBInvCol(SCIP_LPI * lpi,int c,SCIP_Real * coef,int * inds,int * ninds)4205 SCIP_RETCODE SCIPlpiGetBInvCol(
4206 SCIP_LPI* lpi, /**< LP interface structure */
4207 int c, /**< column number of B^-1; this is NOT the number of the column in the LP;
4208 * you have to call SCIPlpiGetBasisInd() to get the array which links the
4209 * B^-1 column numbers to the row and column numbers of the LP!
4210 * c must be between 0 and nrows-1, since the basis has the size
4211 * nrows * nrows */
4212 SCIP_Real* coef, /**< pointer to store the coefficients of the column */
4213 int* inds, /**< array to store the non-zero indices, or NULL */
4214 int* ninds /**< pointer to store the number of non-zero indices, or NULL
4215 * (-1: if we do not store sparsity information) */
4216 )
4217 {
4218 int nrows;
4219 int i;
4220
4221 assert(MosekEnv != NULL);
4222 assert(lpi != NULL);
4223 assert(lpi->task != NULL);
4224 assert(coef != NULL);
4225
4226 SCIPdebugMessage("Calling SCIPlpiGetBInvCol (%d)\n", lpi->lpid);
4227
4228 MOSEK_CALL( MSK_getnumcon(lpi->task, &nrows) );
4229
4230 /* set coefficient for slack variables to be 1 instead of -1 */
4231 MOSEK_CALL( MSK_putnaintparam(lpi->task, MSK_IPAR_BASIS_SOLVE_USE_PLUS_ONE_, MSK_ON) );
4232
4233 /* prepare basis in Mosek, since we do not need the basis ourselves, we set the return parameter to NULL */
4234 SCIP_CALL( handle_singular(lpi, NULL, MSK_initbasissolve(lpi->task, NULL)) );
4235
4236 /* initialize rhs of system to be a dense +/- unit vector (needed for MSK_solvewithbasis()) */
4237 for (i = 0; i < nrows; ++i)
4238 coef[i] = 0.0;
4239 coef[c] = 1.0; /* unit vector e_c */
4240
4241 /* check whether we require a dense or sparse result vector */
4242 if ( ninds != NULL && inds != NULL )
4243 {
4244 *ninds = 1;
4245 inds[0]= c;
4246
4247 MOSEK_CALL( MSK_solvewithbasis(lpi->task, 0, ninds, inds, coef) );
4248 assert( *ninds <= nrows );
4249 }
4250 else
4251 {
4252 int* sub;
4253 int numnz;
4254
4255 SCIP_ALLOC( BMSallocMemoryArray(&sub, nrows) );
4256
4257 numnz = 1;
4258 sub[0]= c;
4259
4260 MOSEK_CALL( MSK_solvewithbasis(lpi->task, 0, &numnz, sub, coef) );
4261 assert( numnz <= nrows );
4262
4263 BMSfreeMemoryArray(&sub);
4264 }
4265 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_SIM_HOTSTART_LU, MSK_ON) );
4266
4267 return SCIP_OKAY;
4268 }
4269
4270 /** get row of inverse basis matrix times constraint matrix B^-1 * A
4271 *
4272 * @note The LP interface defines slack variables to have coefficient +1. This means that if, internally, the LP solver
4273 * uses a -1 coefficient, then rows associated with slacks variables whose coefficient is -1, should be negated;
4274 * see also the explanation in lpi.h.
4275 *
4276 * @todo check that the result is in terms of the LP interface definition
4277 *
4278 * @todo check if this should invalidate the solution
4279 */
SCIPlpiGetBInvARow(SCIP_LPI * lpi,int row,const SCIP_Real * binvrow,SCIP_Real * coef,int * inds,int * ninds)4280 SCIP_RETCODE SCIPlpiGetBInvARow(
4281 SCIP_LPI* lpi, /**< LP interface structure */
4282 int row, /**< row number */
4283 const SCIP_Real* binvrow, /**< row in (A_B)^-1 from prior call to SCIPlpiGetBInvRow(), or NULL */
4284 SCIP_Real* coef, /**< vector to return coefficients of the row */
4285 int* inds, /**< array to store the non-zero indices, or NULL */
4286 int* ninds /**< pointer to store the number of non-zero indices, or NULL
4287 * (-1: if we do not store sparsity information) */
4288 )
4289 { /*lint --e{715}*/
4290 int nrows;
4291 int ncols;
4292 int numnz;
4293 int* csub;
4294 int didalloc = 0;
4295 double* cval;
4296 double* binv;
4297 int i;
4298 int k;
4299
4300 assert(MosekEnv != NULL);
4301 assert(lpi != NULL);
4302 assert(lpi->task != NULL);
4303 assert(coef != NULL);
4304 SCIP_UNUSED(inds);
4305
4306 SCIPdebugMessage("Calling SCIPlpiGetBInvARow (%d)\n", lpi->lpid);
4307
4308 /* currently only return dense result */
4309 if ( ninds != NULL )
4310 *ninds = -1;
4311
4312 MOSEK_CALL( MSK_getnumcon(lpi->task, &nrows) );
4313 MOSEK_CALL( MSK_getnumvar(lpi->task, &ncols) );
4314
4315 SCIP_ALLOC( BMSallocMemoryArray(&csub, nrows) );
4316 SCIP_ALLOC( BMSallocMemoryArray(&cval, nrows) );
4317
4318 if( binvrow == NULL )
4319 {
4320 didalloc = 1;
4321
4322 /* get dense vector */
4323 SCIP_ALLOC( BMSallocMemoryArray(&binv, nrows) );
4324 SCIP_CALL( SCIPlpiGetBInvRow(lpi, row, binv, NULL, NULL) );
4325 }
4326 else
4327 binv = (SCIP_Real*)binvrow;
4328
4329 /* binvrow*A */
4330 for (i = 0; i < ncols; ++i)
4331 {
4332 MOSEK_CALL( MSK_getacol(lpi->task, i, &numnz, csub, cval) );
4333
4334 /* compute dense vector */
4335 coef[i] = 0.0;
4336 for (k = 0; k < numnz; ++k)
4337 {
4338 assert( 0 <= csub[k] && csub[k] < nrows );
4339 coef[i] += binv[csub[k]] * cval[k];
4340 }
4341 }
4342
4343 /* free memory arrays */
4344 BMSfreeMemoryArray(&cval);
4345 BMSfreeMemoryArray(&csub);
4346
4347 if ( didalloc > 0 )
4348 {
4349 BMSfreeMemoryArray(&binv);
4350 }
4351
4352 return SCIP_OKAY;
4353 }
4354
4355 /** get column of inverse basis matrix times constraint matrix B^-1 * A
4356 *
4357 * @todo check if this should invalidate the solution
4358 */
SCIPlpiGetBInvACol(SCIP_LPI * lpi,int c,SCIP_Real * coef,int * inds,int * ninds)4359 SCIP_RETCODE SCIPlpiGetBInvACol(
4360 SCIP_LPI* lpi, /**< LP interface structure */
4361 int c, /**< column number */
4362 SCIP_Real* coef, /**< vector to return coefficients of the columnn */
4363 int* inds, /**< array to store the non-zero indices, or NULL */
4364 int* ninds /**< pointer to store the number of non-zero indices, or NULL
4365 * (-1: if we do not store sparsity information) */
4366 )
4367 { /*lint --e{715}*/
4368 SCIP_Real* val;
4369 int nrows;
4370 int numnz;
4371 int i;
4372
4373 assert(MosekEnv != NULL);
4374 assert(lpi != NULL);
4375 assert(lpi->task != NULL);
4376 assert(coef != NULL);
4377
4378 SCIPdebugMessage("Calling SCIPlpiGetBInvACol (%d)\n", lpi->lpid);
4379
4380 MOSEK_CALL( MSK_getnumcon(lpi->task, &nrows) );
4381 MOSEK_CALL( MSK_getacolnumnz(lpi->task, c, &numnz) );
4382 SCIP_ALLOC( BMSallocMemoryArray(&val, numnz+1) );
4383
4384 /* set coefficient for slack variables to be 1 instead of -1 */
4385 MOSEK_CALL( MSK_putnaintparam(lpi->task, MSK_IPAR_BASIS_SOLVE_USE_PLUS_ONE_, MSK_ON) );
4386
4387 /* prepare basis in Mosek, since we do not need the basis ourselves, we set the return parameter to NULL */
4388 SCIP_CALL( handle_singular(lpi, NULL, MSK_initbasissolve(lpi->task, NULL)) );
4389
4390 /* init coefficients */
4391 for (i = 0; i < nrows; ++i)
4392 coef[i] = 0.0;
4393
4394 /* check whether we require a dense or sparse result vector */
4395 if ( ninds != NULL && inds != NULL )
4396 {
4397 /* fill column into dense vector */
4398 MOSEK_CALL( MSK_getacol(lpi->task, c, &numnz, inds, val) );
4399 for (i = 0; i < numnz; ++i)
4400 {
4401 assert( 0 <= inds[i] && inds[i] < nrows );
4402 coef[inds[i]] = val[i];
4403 }
4404
4405 *ninds = numnz;
4406
4407 MOSEK_CALL( MSK_solvewithbasis(lpi->task, 0, ninds, inds, coef) );
4408 assert( *ninds <= nrows );
4409 }
4410 else
4411 {
4412 int* sub;
4413 SCIP_ALLOC( BMSallocMemoryArray(&sub, nrows) );
4414
4415 /* fill column into dense vector */
4416 MOSEK_CALL( MSK_getacol(lpi->task, c, &numnz, sub, val) );
4417 for (i = 0; i < numnz; ++i)
4418 {
4419 assert( 0 <= sub[i] && sub[i] < nrows );
4420 coef[sub[i]] = val[i];
4421 }
4422
4423 MOSEK_CALL( MSK_solvewithbasis(lpi->task, 0, &numnz, sub, coef) );
4424
4425 if ( ninds != NULL )
4426 *ninds = numnz;
4427
4428 BMSfreeMemoryArray(&sub);
4429 }
4430
4431 BMSfreeMemoryArray(&val);
4432 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_SIM_HOTSTART_LU, MSK_ON) );
4433
4434 return SCIP_OKAY;
4435 }
4436
4437
4438 /*
4439 * LP State Methods
4440 */
4441
4442 /** creates LPi state information object */
4443 static
lpistateCreate(SCIP_LPISTATE ** lpistate,BMS_BLKMEM * blkmem,int ncols,int nrows)4444 SCIP_RETCODE lpistateCreate(
4445 SCIP_LPISTATE** lpistate, /**< pointer to LPi state */
4446 BMS_BLKMEM* blkmem, /**< block memory */
4447 int ncols, /**< number of columns to store */
4448 int nrows /**< number of rows to store */
4449 )
4450 {
4451 assert(lpistate != NULL);
4452 assert(blkmem != NULL);
4453 assert(ncols >= 0);
4454 assert(nrows >= 0);
4455
4456 SCIP_ALLOC( BMSallocBlockMemory(blkmem, lpistate) );
4457 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*lpistate)->skx, colpacketNum(ncols)) );
4458 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*lpistate)->skc, rowpacketNum(nrows)) );
4459
4460 (*lpistate)->solsta = MSK_SOL_STA_UNKNOWN;
4461 (*lpistate)->num = -1;
4462 (*lpistate)->ncols = ncols;
4463 (*lpistate)->nrows = nrows;
4464
4465 return SCIP_OKAY;
4466 }
4467
4468 /** frees LPi state information */
4469 static
lpistateFree(SCIP_LPISTATE ** lpistate,BMS_BLKMEM * blkmem)4470 void lpistateFree(
4471 SCIP_LPISTATE** lpistate, /**< pointer to LPi state information (like basis information) */
4472 BMS_BLKMEM* blkmem /**< block memory */
4473 )
4474 {
4475 assert(blkmem != NULL);
4476 assert(lpistate != NULL);
4477 assert(*lpistate != NULL);
4478
4479 BMSfreeBlockMemoryArray(blkmem, &(*lpistate)->skx, colpacketNum((*lpistate)->ncols));
4480 BMSfreeBlockMemoryArray(blkmem, &(*lpistate)->skc, rowpacketNum((*lpistate)->nrows));
4481 BMSfreeBlockMemory(blkmem, lpistate);
4482 }
4483
4484 #ifndef NDEBUG
4485 /** check state
4486 *
4487 * @note last solve call must have been either simplex or barrier with crossover or base must have been set manually
4488 */
4489 static
checkState1(SCIP_LPI * lpi,int n,MSKstakeye * sk,SCIP_Bool isrow)4490 SCIP_RETCODE checkState1(
4491 SCIP_LPI* lpi, /**< LP interface structure */
4492 int n, /**< number of rows or columns */
4493 MSKstakeye* sk, /**< basis status */
4494 SCIP_Bool isrow /**< whether rows/columns are considered */
4495 )
4496 {
4497 char xc;
4498 int i;
4499
4500 assert(lpi != NULL);
4501 assert(lpi->lastsolvetype == MSK_SOL_BAS);
4502
4503 #ifdef SCIP_DEBUG
4504 if( !isrow )
4505 xc = 'x';
4506 else
4507 xc = 'c';
4508 #endif
4509
4510 /* printout for all except LOW, UPR, FIX and BAS with sl[xc]==su[xc] */
4511 for( i = 0; i < n; i++ )
4512 {
4513 double sl;
4514 double su;
4515 switch (sk[i])
4516 {
4517 case MSK_SK_UNK:
4518 SCIPdebugMessage("STATE[%d]: %c[%d] = unk\n", optimizecount, xc, i);
4519 break;
4520 case MSK_SK_BAS:
4521 /* the following function is deprecated */
4522 #if MSK_VERSION_MAJOR < 9
4523 MOSEK_CALL( MSK_getsolutioni(lpi->task, isrow ? MSK_ACC_CON : MSK_ACC_VAR, i, MSK_SOL_BAS, NULL, NULL, &sl, &su, NULL) );
4524 #else
4525 if( isrow )
4526 {
4527 MOSEK_CALL( MSK_getslcslice(lpi->task, MSK_SOL_BAS, i, i+1, &sl ) );
4528 MOSEK_CALL( MSK_getsucslice(lpi->task, MSK_SOL_BAS, i, i+1, &su ) );
4529 }
4530 else
4531 {
4532 MOSEK_CALL( MSK_getslxslice(lpi->task, MSK_SOL_BAS, i, i+1, &sl ) );
4533 MOSEK_CALL( MSK_getsuxslice(lpi->task, MSK_SOL_BAS, i, i+1, &su ) );
4534 }
4535 #endif
4536 if (fabs(sl-su) > DEBUG_CHECK_STATE_TOL)
4537 {
4538 SCIPdebugMessage("STATE[%d]: %c[%d] = bas, sl%c = %g, su%c = %g\n", optimizecount, xc, i, xc, sl, xc, su);
4539 }
4540 break;
4541 case MSK_SK_SUPBAS:
4542 SCIPdebugMessage("STATE[%d]: %c[%d] = supbas\n", optimizecount, xc, i);
4543 break;
4544 case MSK_SK_LOW:
4545 case MSK_SK_UPR:
4546 case MSK_SK_FIX:
4547 break;
4548 case MSK_SK_INF:
4549 SCIPdebugMessage("STATE[%d]: %c[%d] = inf\n", optimizecount, xc, i);
4550 break;
4551 default:
4552 SCIPdebugMessage("STATE[%d]: %c[%d] = unknown status <%d>\n", optimizecount, xc, i, sk[i]);
4553 break;
4554 } /*lint !e788*/
4555 }
4556
4557 return SCIP_OKAY;
4558 }
4559
4560 /** check state
4561 *
4562 * @note last solve call must have been either simplex or barrier with crossover or base must have been set manually
4563 */
4564 static
checkState(SCIP_LPI * lpi,int ncols,int nrows)4565 SCIP_RETCODE checkState(
4566 SCIP_LPI* lpi, /**< LP interface structure */
4567 int ncols, /**< number of columns */
4568 int nrows /**< number of rows */
4569 )
4570 {
4571 assert(lpi != NULL);
4572 assert(lpi->lastsolvetype == MSK_SOL_BAS);
4573
4574 SCIP_CALL( checkState1(lpi, ncols, lpi->skx, FALSE) );
4575 SCIP_CALL( checkState1(lpi, nrows, lpi->skc, TRUE) );
4576
4577 return SCIP_OKAY;
4578 }
4579 #endif
4580
4581 /** store row and column basis status in a packed LPi state object
4582 *
4583 * @note last solve call must have been either simplex or barrier with crossover or base must have been set manually
4584 */
4585 static
lpistatePack(SCIP_LPI * lpi,SCIP_LPISTATE * lpistate)4586 SCIP_RETCODE lpistatePack(
4587 SCIP_LPI* lpi, /**< LP interface structure */
4588 SCIP_LPISTATE* lpistate /**< pointer to LPi state data */
4589 )
4590 {
4591 int *skxi = (int *) lpi->skx; /* Used as temp. buffer */
4592 int *skci = (int *) lpi->skc; /* Used as temp. buffer */
4593
4594 assert(sizeof(int) == sizeof(MSKstakeye)); /*lint !e506*/
4595 assert(lpi != NULL);
4596 assert(lpistate != NULL);
4597 assert(lpi->lastsolvetype == MSK_SOL_BAS);
4598
4599 SCIP_CALL( convertstat_mosek2scip(lpi, FALSE, lpi->skx, lpistate->ncols, skxi) );
4600 SCIP_CALL( convertstat_mosek2scip_slack(lpi, TRUE, lpi->skc, lpistate->nrows, skci) );
4601
4602 SCIPencodeDualBit(skxi, lpistate->skx, lpistate->ncols);
4603 SCIPencodeDualBit(skci, lpistate->skc, lpistate->nrows);
4604
4605 return SCIP_OKAY;
4606 }
4607
4608 /** unpacks row and column basis status from a packed LPi state object */
4609 static
lpistateUnpack(const SCIP_LPISTATE * lpistate,MSKstakeye * skx,MSKstakeye * skc)4610 void lpistateUnpack(
4611 const SCIP_LPISTATE* lpistate, /**< pointer to LPi state data */
4612 MSKstakeye* skx, /**< basis status for columns */
4613 MSKstakeye* skc /**< basis status for rows */
4614 )
4615 {
4616 assert(sizeof(int) == sizeof(MSKstakeye)); /*lint !e506*/
4617
4618 SCIPdecodeDualBit(lpistate->skx, (int*) skx, lpistate->ncols);
4619 SCIPdecodeDualBit(lpistate->skc, (int*) skc, lpistate->nrows);
4620
4621 convertstat_scip2mosek((int*) skx, lpistate->ncols, skx);
4622 convertstat_scip2mosek_slack((int*) skc, lpistate->nrows, skc);
4623 }
4624
4625 /** stores LP state (like basis information) into lpistate object
4626 *
4627 * @note last solve call must have been either simplex or barrier with crossover or base must have been set manually
4628 */
SCIPlpiGetState(SCIP_LPI * lpi,BMS_BLKMEM * blkmem,SCIP_LPISTATE ** lpistate)4629 SCIP_RETCODE SCIPlpiGetState(
4630 SCIP_LPI* lpi, /**< LP interface structure */
4631 BMS_BLKMEM* blkmem, /**< block memory */
4632 SCIP_LPISTATE** lpistate /**< pointer to LP state information (like basis information) */
4633 )
4634 {
4635 int gotbasicsol;
4636 int nrows;
4637 int ncols;
4638
4639 assert(MosekEnv != NULL);
4640 assert(lpi != NULL);
4641 assert(lpi->task != NULL);
4642 assert(lpistate != NULL);
4643 assert(blkmem != NULL);
4644 assert(lpi->lastsolvetype == MSK_SOL_BAS);
4645
4646 SCIPdebugMessage("Calling SCIPlpiGetState (%d)\n", lpi->lpid);
4647
4648 *lpistate = NULL;
4649
4650 MOSEK_CALL( MSK_solutiondef(lpi->task, MSK_SOL_BAS, &gotbasicsol) );
4651
4652 if ( gotbasicsol == 0 || SCIPlpiExistsDualRay(lpi) || lpi->clearstate )
4653 return SCIP_OKAY;
4654
4655 MOSEK_CALL( MSK_getnumcon(lpi->task, &nrows) );
4656 MOSEK_CALL( MSK_getnumvar(lpi->task, &ncols) );
4657
4658 /* allocate lpistate data */
4659 SCIP_CALL( lpistateCreate(lpistate, blkmem, ncols, nrows) );
4660
4661 lpistate[0]->num = optimizecount;
4662
4663 MOSEK_CALL( MSK_getsolutionstatus(lpi->task, MSK_SOL_BAS, NULL, &lpistate[0]->solsta) );
4664
4665 SCIP_CALL( getbase(lpi, ncols, nrows) );
4666
4667 #ifndef NDEBUG
4668 SCIP_CALL( checkState(lpi, ncols, nrows) );
4669 #endif
4670
4671 SCIP_CALL( lpistatePack(lpi, lpistate[0]) );
4672
4673 SCIPdebugMessage("Store into state from iter : %d\n", optimizecount);
4674
4675 /* if (r != SCIP_OKAY)
4676 * lpistateFree(lpistate, blkmem );
4677 */
4678
4679 return SCIP_OKAY;
4680 }
4681
4682 /** loads LPi state (like basis information) into solver; note that the LP might have been extended with additional
4683 * columns and rows since the state was stored with SCIPlpiGetState()
4684 */
SCIPlpiSetState(SCIP_LPI * lpi,BMS_BLKMEM * blkmem,const SCIP_LPISTATE * lpistate)4685 SCIP_RETCODE SCIPlpiSetState(
4686 SCIP_LPI* lpi, /**< LP interface structure */
4687 BMS_BLKMEM* blkmem, /**< block memory */
4688 const SCIP_LPISTATE* lpistate /**< LP state information (like basis information), or NULL */
4689 )
4690 { /*lint --e{715}*/
4691 int nrows;
4692 int ncols;
4693 int i;
4694
4695 assert(MosekEnv != NULL);
4696 assert(lpi != NULL);
4697 assert(lpi->task != NULL);
4698 assert(blkmem != NULL);
4699 #ifdef SCIP_DISABLED_CODE
4700 assert(lpi->lastsolvetype == MSK_SOL_BAS);
4701 #endif
4702
4703 if (lpistate == NULL)
4704 {
4705 SCIPdebugMessage("Setting NULL state\n");
4706 return SCIP_OKAY;
4707 }
4708
4709 if (lpistate->nrows == 0 || lpistate->ncols == 0)
4710 return SCIP_OKAY;
4711
4712 MOSEK_CALL( MSK_getnumcon(lpi->task, &nrows) );
4713 MOSEK_CALL( MSK_getnumvar(lpi->task, &ncols) );
4714 assert(lpistate->nrows <= nrows);
4715 assert(lpistate->ncols <= ncols);
4716
4717 SCIP_CALL( ensureStateMem(lpi, ncols, nrows) );
4718
4719 #ifdef SCIP_DISABLED_CODE
4720 SCIP_CALL( getbase(lpi, ncols, nrows) ); /* Why do we need to get the basis ????? */
4721 #endif
4722
4723 lpistateUnpack(lpistate, lpi->skx, lpi->skc);
4724
4725 /* extend the basis to the current LP beyond the previously existing columns */
4726 for (i = lpistate->ncols; i < ncols; ++i)
4727 {
4728 SCIP_Real lb;
4729 SCIP_Real ub;
4730 #if MSK_VERSION_MAJOR < 9
4731 MOSEK_CALL( MSK_getboundslice(lpi->task, MSK_ACC_VAR, i, i, NULL, &lb, &ub) );
4732 #else
4733 MOSEK_CALL( MSK_getvarboundslice(lpi->task, i, i, NULL, &lb, &ub) );
4734 #endif
4735 if ( SCIPlpiIsInfinity(lpi, REALABS(lb)) )
4736 {
4737 /* if lower bound is +/- infinity -> try upper bound */
4738 if ( SCIPlpiIsInfinity(lpi, REALABS(ub)) )
4739 lpi->skx[i] = MSK_SK_SUPBAS; /* variable is free (super basic) */
4740 else
4741 lpi->skx[i] = MSK_SK_UPR; /* use finite upper bound */
4742 }
4743 else
4744 lpi->skx[i] = MSK_SK_LOW; /* use finite lower bound */
4745 }
4746 for (i = lpistate->nrows; i < nrows; ++i)
4747 lpi->skc[i] = MSK_SK_BAS;
4748
4749 /* load basis information into MOSEK */
4750 SCIP_CALL( setbase(lpi) );
4751
4752 invalidateSolution(lpi);
4753
4754 SCIPdebugMessage("Store from state into task iter : %d with solsta : %d\n", lpistate->num, lpistate->solsta);
4755
4756 return SCIP_OKAY;
4757 }
4758
4759 /** clears current LPi state (like basis information) of the solver */
SCIPlpiClearState(SCIP_LPI * lpi)4760 SCIP_RETCODE SCIPlpiClearState(
4761 SCIP_LPI* lpi /**< LP interface structure */
4762 )
4763 {
4764 assert(MosekEnv != NULL);
4765 assert(lpi != NULL);
4766 assert(lpi->task != NULL);
4767
4768 lpi->clearstate = TRUE;
4769
4770 return SCIP_OKAY;
4771 }
4772
4773 /** frees LP state information */
SCIPlpiFreeState(SCIP_LPI * lpi,BMS_BLKMEM * blkmem,SCIP_LPISTATE ** lpistate)4774 SCIP_RETCODE SCIPlpiFreeState(
4775 SCIP_LPI* lpi, /**< LP interface structure */
4776 BMS_BLKMEM* blkmem, /**< block memory */
4777 SCIP_LPISTATE** lpistate /**< pointer to LP state information (like basis information) */
4778 )
4779 { /*lint --e{715}*/
4780 assert(MosekEnv != NULL);
4781 assert(lpi != NULL);
4782 assert(lpi->task != NULL);
4783 assert(lpistate != NULL);
4784 assert(blkmem != NULL);
4785
4786 SCIPdebugMessage("Calling SCIPlpiFreeState (%d)\n", lpi->lpid);
4787
4788 if( *lpistate != NULL )
4789 {
4790 lpistateFree(lpistate, blkmem);
4791 }
4792
4793 return SCIP_OKAY;
4794 }
4795
4796 /** checks, whether the given LP state contains simplex basis information */
SCIPlpiHasStateBasis(SCIP_LPI * lpi,SCIP_LPISTATE * lpistate)4797 SCIP_Bool SCIPlpiHasStateBasis(
4798 SCIP_LPI* lpi, /**< LP interface structure */
4799 SCIP_LPISTATE* lpistate /**< LP state information (like basis information), or NULL */
4800 )
4801 { /*lint --e{715}*/
4802 assert(MosekEnv != NULL);
4803 assert(lpi != NULL);
4804 assert(lpi->task != NULL);
4805
4806 SCIPdebugMessage("Calling SCIPlpiHasStateBasis (%d)\n", lpi->lpid);
4807
4808 return ( lpistate != NULL && lpistate->num >= 0);
4809 }
4810
4811 /** reads LP state (like basis information) from a file
4812 *
4813 * @note last solve call must have been either simplex or barrier with crossover or base must have been set manually
4814 */
SCIPlpiReadState(SCIP_LPI * lpi,const char * fname)4815 SCIP_RETCODE SCIPlpiReadState(
4816 SCIP_LPI* lpi, /**< LP interface structure */
4817 const char* fname /**< file name */
4818 )
4819 {
4820 assert(MosekEnv != NULL);
4821 assert(lpi != NULL);
4822 assert(lpi->task != NULL);
4823 assert(fname != NULL);
4824
4825 SCIPdebugMessage("reading LP state from file <%s>\n", fname);
4826
4827 lpi->clearstate = FALSE;
4828
4829 MOSEK_CALL( MSK_readsolution(lpi->task, MSK_SOL_BAS, fname) );
4830
4831 return SCIP_OKAY;
4832 }
4833
4834 /** writes LPi state (i.e. basis information) to a file */
SCIPlpiWriteState(SCIP_LPI * lpi,const char * fname)4835 SCIP_RETCODE SCIPlpiWriteState(
4836 SCIP_LPI* lpi, /**< LP interface structure */
4837 const char* fname /**< file name */
4838 )
4839 {
4840 int v;
4841 int nvars;
4842 int c = 0;
4843 int nconss;
4844 SCIP_Bool emptyname = FALSE;
4845 char name[SCIP_MAXSTRLEN];
4846
4847 assert(MosekEnv != NULL);
4848 assert(lpi != NULL);
4849 assert(lpi->task != NULL);
4850 assert(fname != NULL);
4851 assert(lpi->lastsolvetype == MSK_SOL_BAS);
4852
4853 SCIPdebugMessage("writing LP state to file <%s>\n", fname);
4854
4855 if( lpi->clearstate )
4856 {
4857 SCIPdebugMessage("No LP state written, since it was cleared after the last solve \n");
4858 return SCIP_OKAY;
4859 }
4860
4861 /* If any rows or columns have empty names, MOSEK will make up names like C1 and X1, but will no
4862 * longer recognize them when reading the same state file back in, therefore we return an error in
4863 * this case
4864 */
4865 MOSEK_CALL( MSK_getnumvar(lpi->task, &nvars) );
4866 for( v = 0; v < nvars; v++ )
4867 {
4868 MOSEK_CALL( MSK_getvarname(lpi->task, v, SCIP_MAXSTRLEN, name) );
4869 if( strcmp(name, "") == 0 )
4870 {
4871 emptyname = TRUE;
4872 break;
4873 }
4874 }
4875 if( !emptyname )
4876 {
4877 MOSEK_CALL( MSK_getnumcon(lpi->task, &nconss) );
4878 for( c = 0; c < nconss; c++ )
4879 {
4880 MOSEK_CALL( MSK_getconname(lpi->task, c, SCIP_MAXSTRLEN, name) );
4881 if( strcmp(name, "") == 0 )
4882 {
4883 emptyname = TRUE;
4884 break;
4885 }
4886 }
4887 }
4888
4889 if( emptyname )
4890 {
4891 SCIPmessagePrintWarning(lpi->messagehdlr, "Writing LP state with unnamed %s %d, using default"
4892 " names instead. Note that this state cannot be read back in later!\n",
4893 v < nvars ? "variable" : "constraint", v < nvars ? v : c);
4894 }
4895
4896 /* set parameter to be able to write */
4897 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_WRITE_SOL_HEAD, MSK_ON) );
4898 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_WRITE_SOL_VARIABLES, MSK_ON) );
4899 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_WRITE_SOL_CONSTRAINTS, MSK_ON) );
4900
4901 MOSEK_CALL( MSK_writesolution(lpi->task, MSK_SOL_BAS, fname) );
4902
4903 return SCIP_OKAY;
4904 }
4905
4906 /**@} */
4907
4908 /*
4909 * LP Pricing Norms Methods
4910 */
4911
4912 /**@name LP Pricing Norms Methods */
4913 /**@{ */
4914
4915 /** stores LPi pricing norms information
4916 * @todo should we store norm information?
4917 */
SCIPlpiGetNorms(SCIP_LPI * lpi,BMS_BLKMEM * blkmem,SCIP_LPINORMS ** lpinorms)4918 SCIP_RETCODE SCIPlpiGetNorms(
4919 SCIP_LPI* lpi, /**< LP interface structure */
4920 BMS_BLKMEM* blkmem, /**< block memory */
4921 SCIP_LPINORMS** lpinorms /**< pointer to LPi pricing norms information */
4922 )
4923 { /*lint --e{715}*/
4924 assert(MosekEnv != NULL);
4925 assert(lpi != NULL);
4926 assert(lpi->task != NULL);
4927 assert(lpinorms != NULL);
4928 assert(blkmem != NULL);
4929
4930 (*lpinorms) = NULL;
4931
4932 return SCIP_OKAY;
4933 }
4934
4935 /** loads LPi pricing norms into solver; note that the LP might have been extended with additional
4936 * columns and rows since the state was stored with SCIPlpiGetNorms()
4937 */
SCIPlpiSetNorms(SCIP_LPI * lpi,BMS_BLKMEM * blkmem,const SCIP_LPINORMS * lpinorms)4938 SCIP_RETCODE SCIPlpiSetNorms(
4939 SCIP_LPI* lpi, /**< LP interface structure */
4940 BMS_BLKMEM* blkmem, /**< block memory */
4941 const SCIP_LPINORMS* lpinorms /**< LPi pricing norms information, or NULL */
4942 )
4943 { /*lint --e{715}*/
4944 assert(lpi != NULL);
4945 SCIP_UNUSED(blkmem);
4946 assert(lpinorms == NULL);
4947
4948 /* no work necessary */
4949 return SCIP_OKAY;
4950 }
4951
4952 /** frees pricing norms information */
SCIPlpiFreeNorms(SCIP_LPI * lpi,BMS_BLKMEM * blkmem,SCIP_LPINORMS ** lpinorms)4953 SCIP_RETCODE SCIPlpiFreeNorms(
4954 SCIP_LPI* lpi, /**< LP interface structure */
4955 BMS_BLKMEM* blkmem, /**< block memory */
4956 SCIP_LPINORMS** lpinorms /**< pointer to LPi pricing norms information, or NULL */
4957 )
4958 { /*lint --e{715}*/
4959 assert(lpi != NULL);
4960 SCIP_UNUSED(blkmem);
4961 assert(lpinorms == NULL);
4962
4963 /* no work necessary */
4964 return SCIP_OKAY;
4965 }
4966
4967 /**@} */
4968
4969 /*
4970 * Parameter Methods
4971 */
4972
4973 /** constant array containing the parameter names */
4974 static const char* paramname[] = {
4975 "SCIP_LPPAR_FROMSCRATCH", /* solver should start from scratch at next call? */
4976 "SCIP_LPPAR_FASTMIP", /* fast mip setting of LP solver */
4977 "SCIP_LPPAR_SCALING", /* which scaling should LP solver use? */
4978 "SCIP_LPPAR_PRESOLVING", /* should LP solver use presolving? */
4979 "SCIP_LPPAR_PRICING", /* pricing strategy */
4980 "SCIP_LPPAR_LPINFO", /* should LP solver output information to the screen? */
4981 "SCIP_LPPAR_FEASTOL", /* feasibility tolerance for primal variables and slacks */
4982 "SCIP_LPPAR_DUALFEASTOL", /* feasibility tolerance for dual variables and reduced costs */
4983 "SCIP_LPPAR_BARRIERCONVTOL", /* convergence tolerance used in barrier algorithm */
4984 "SCIP_LPPAR_OBJLIM", /* objective limit (stop if objective is known be larger/smaller than limit for min/max-imization) */
4985 "SCIP_LPPAR_LPITLIM", /* LP iteration limit, greater than or equal 0 */
4986 "SCIP_LPPAR_LPTILIM", /* LP time limit, positive */
4987 "SCIP_LPPAR_MARKOWITZ", /* Markowitz tolerance */
4988 "SCIP_LPPAR_ROWREPSWITCH", /* simplex algorithm shall use row representation of the basis
4989 * if number of rows divided by number of columns exceeds this value */
4990 "SCIP_LPPAR_THREADS", /* number of threads used to solve the LP */
4991 "SCIP_LPPAR_CONDITIONLIMIT", /* maximum condition number of LP basis counted as stable */
4992 "SCIP_LPPAR_TIMING", /* type of timer (1 - cpu, 2 - wallclock, 0 - off) */
4993 "SCIP_LPPAR_RANDOMSEED", /* inital random seed, e.g. for perturbations in the simplex (0: LP default) */
4994 "SCIP_LPPAR_POLISHING", /* set solution polishing (0 - disable, 1 - enable) */
4995 "SCIP_LPPAR_REFACTOR" /* set refactorization interval (0 - automatic) */
4996 };
4997
4998 /** method mapping parameter index to parameter name */
4999 static
paramty2str(SCIP_LPPARAM type)5000 const char* paramty2str(
5001 SCIP_LPPARAM type
5002 )
5003 { /*lint --e{641}*/
5004 /* check whether the parameters are in the right order */
5005 /*lint --e{506}*/
5006 assert(SCIP_LPPAR_FROMSCRATCH == 0); /* solver should start from scratch at next call? */
5007 assert(SCIP_LPPAR_FASTMIP == 1); /* fast mip setting of LP solver */
5008 assert(SCIP_LPPAR_SCALING == 2); /* which scaling should LP solver use? */
5009 assert(SCIP_LPPAR_PRESOLVING == 3); /* should LP solver use presolving? */
5010 assert(SCIP_LPPAR_PRICING == 4); /* pricing strategy */
5011 assert(SCIP_LPPAR_LPINFO == 5); /* should LP solver output information to the screen? */
5012 assert(SCIP_LPPAR_FEASTOL == 6); /* feasibility tolerance for primal variables and slacks */
5013 assert(SCIP_LPPAR_DUALFEASTOL == 7); /* feasibility tolerance for dual variables and reduced costs */
5014 assert(SCIP_LPPAR_BARRIERCONVTOL == 8); /* convergence tolerance used in barrier algorithm */
5015 assert(SCIP_LPPAR_OBJLIM == 9); /* objective limit (stop if objective is known be larger/smaller than limit for min/max-imization) */
5016 assert(SCIP_LPPAR_LPITLIM == 10); /* LP iteration limit, greater than or equal 0 */
5017 assert(SCIP_LPPAR_LPTILIM == 11); /* LP time limit, positive */
5018 assert(SCIP_LPPAR_MARKOWITZ == 12); /* Markowitz tolerance */
5019 assert(SCIP_LPPAR_ROWREPSWITCH == 13); /* row representation switch */
5020 assert(SCIP_LPPAR_THREADS == 14); /* number of threads used to solve the LP */
5021 assert(SCIP_LPPAR_CONDITIONLIMIT == 15); /* maximum condition number of LP basis counted as stable */
5022 assert(SCIP_LPPAR_TIMING == 16); /* type of timer (1 - cpu, 2 - wallclock, 0 - off) */
5023 assert(SCIP_LPPAR_RANDOMSEED == 17); /* inital random seed, e.g. for perturbations in the simplex (0: LP default) */
5024 assert(SCIP_LPPAR_POLISHING == 18); /* set solution polishing (0 - disable, 1 - enable) */
5025 assert(SCIP_LPPAR_REFACTOR == 19); /* set refactorization interval (0 - automatic) */
5026
5027 return paramname[type];
5028 }
5029
5030 /** gets integer parameter of LP */
SCIPlpiGetIntpar(SCIP_LPI * lpi,SCIP_LPPARAM type,int * ival)5031 SCIP_RETCODE SCIPlpiGetIntpar(
5032 SCIP_LPI* lpi, /**< LP interface structure */
5033 SCIP_LPPARAM type, /**< parameter number */
5034 int* ival /**< buffer to store the parameter value */
5035 )
5036 { /*lint --e{641}*/
5037 assert(MosekEnv != NULL);
5038 assert(lpi != NULL);
5039 assert(lpi->task != NULL);
5040 assert(ival != NULL);
5041
5042 SCIPdebugMessage("getting int parameter %s\n", paramty2str(type));
5043
5044 switch (type)
5045 {
5046 case SCIP_LPPAR_FROMSCRATCH: /* solver should start from scratch at next call? */
5047 *ival = (int) lpi->fromscratch;
5048 break;
5049 case SCIP_LPPAR_FASTMIP: /* fast mip setting of LP solver */
5050 return SCIP_PARAMETERUNKNOWN;
5051 case SCIP_LPPAR_SCALING: /* should LP solver use scaling? */
5052 MOSEK_CALL( MSK_getintparam(lpi->task, MSK_IPAR_SIM_SCALING, ival) );
5053 if( *ival == MSK_SCALING_NONE )
5054 *ival = 0;
5055 else if( *ival == MSK_SCALING_FREE )
5056 *ival = 1;
5057 else if( *ival == MSK_SCALING_AGGRESSIVE )
5058 *ival = 2;
5059 else /* MSK_SCALING_MODERATE should not be used by the interface */
5060 return SCIP_PARAMETERWRONGVAL;
5061 break;
5062 case SCIP_LPPAR_PRESOLVING: /* should LP solver use presolving? */
5063 MOSEK_CALL( MSK_getintparam(lpi->task, MSK_IPAR_PRESOLVE_USE, ival) );
5064 *ival = (*ival != MSK_PRESOLVE_MODE_OFF);
5065 break;
5066 case SCIP_LPPAR_PRICING: /* pricing strategy */
5067 *ival = lpi->pricing;
5068 break;
5069 case SCIP_LPPAR_LPINFO: /* should LP solver output information to the screen? */
5070 *ival = (int) lpi->lpinfo;
5071 break;
5072 case SCIP_LPPAR_LPITLIM: /* LP iteration limit */
5073 MOSEK_CALL( MSK_getintparam(lpi->task, MSK_IPAR_SIM_MAX_ITERATIONS, ival) );
5074 break;
5075 case SCIP_LPPAR_THREADS: /* number of threads */
5076 MOSEK_CALL( MSK_getintparam(lpi->task, MSK_IPAR_NUM_THREADS, ival) );
5077 break;
5078 case SCIP_LPPAR_REFACTOR: /* refactorization interval */
5079 MOSEK_CALL( MSK_getintparam(lpi->task, MSK_IPAR_SIM_REFACTOR_FREQ, ival) );
5080 break;
5081 default:
5082 return SCIP_PARAMETERUNKNOWN;
5083 } /*lint !e788*/
5084
5085 return SCIP_OKAY;
5086 }
5087
5088 /** sets integer parameter of LP */
SCIPlpiSetIntpar(SCIP_LPI * lpi,SCIP_LPPARAM type,int ival)5089 SCIP_RETCODE SCIPlpiSetIntpar(
5090 SCIP_LPI* lpi, /**< LP interface structure */
5091 SCIP_LPPARAM type, /**< parameter number */
5092 int ival /**< parameter value */
5093 )
5094 {
5095 static int pricing[7] =
5096 {
5097 (int)MSK_SIM_SELECTION_SE, /**< mosek pricing for SCIP_PRICING_LPIDEFAULT */
5098 (int)MSK_SIM_SELECTION_FREE, /**< mosek pricing for SCIP_PRICING_AUTO */
5099 (int)MSK_SIM_SELECTION_FULL, /**< mosek pricing for SCIP_PRICING_FULL */
5100 (int)MSK_SIM_SELECTION_PARTIAL, /**< mosek pricing for SCIP_PRICING_PARTIAL */
5101 (int)MSK_SIM_SELECTION_SE, /**< mosek pricing for SCIP_PRICING_STEEP */
5102 (int)MSK_SIM_SELECTION_ASE, /**< mosek pricing for SCIP_PRICING_STEEPQSTART */
5103 (int)MSK_SIM_SELECTION_DEVEX, /**< mosek pricing for SCIP_PRICING_DEVEX */
5104 };
5105
5106 /*lint --e{506}*/
5107 assert((int)SCIP_PRICING_LPIDEFAULT == 0);
5108 assert((int)SCIP_PRICING_AUTO == 1);
5109 assert((int)SCIP_PRICING_FULL == 2);
5110 assert((int)SCIP_PRICING_PARTIAL == 3);
5111 assert((int)SCIP_PRICING_STEEP == 4);
5112 assert((int)SCIP_PRICING_STEEPQSTART == 5);
5113 assert((int)SCIP_PRICING_DEVEX == 6);
5114
5115 assert(MosekEnv != NULL);
5116 assert(lpi != NULL);
5117 assert(lpi->task != NULL);
5118
5119 SCIPdebugMessage("Calling SCIPlpiSetIntpar (%d) Parameter=<%s> Value=<%d>\n", lpi->lpid, paramty2str(type), ival);
5120
5121 switch (type)
5122 {
5123 case SCIP_LPPAR_FROMSCRATCH: /* solver should start from scratch at next call? */
5124 lpi->fromscratch = (SCIP_Bool) ival;
5125 break;
5126 case SCIP_LPPAR_FASTMIP: /* fast mip setting of LP solver */
5127 return SCIP_PARAMETERUNKNOWN;
5128 case SCIP_LPPAR_SCALING: /* should LP solver use scaling? */
5129 assert( ival >= 0 && ival <= 2 );
5130 if( ival == 0 )
5131 {
5132 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_SIM_SCALING, MSK_SCALING_NONE) );
5133 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_INTPNT_SCALING, MSK_SCALING_NONE) );
5134 }
5135 else if( ival == 1 )
5136 {
5137 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_SIM_SCALING, MSK_SCALING_FREE) );
5138 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_INTPNT_SCALING, MSK_SCALING_FREE) );
5139 }
5140 else
5141 {
5142 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_SIM_SCALING, MSK_SCALING_AGGRESSIVE) );
5143 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_INTPNT_SCALING, MSK_SCALING_AGGRESSIVE) );
5144 }
5145
5146 break;
5147 case SCIP_LPPAR_PRESOLVING: /* should LP solver use presolving? */
5148 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_PRESOLVE_USE,
5149 ival ? MSK_PRESOLVE_MODE_FREE : MSK_PRESOLVE_MODE_OFF) );
5150 break;
5151 case SCIP_LPPAR_PRICING: /* pricing strategy */
5152 assert(ival >= 0 && ival <= (int)SCIP_PRICING_DEVEX);
5153 lpi->pricing = (SCIP_PRICING)ival;
5154
5155 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_SIM_PRIMAL_SELECTION, pricing[ival]) );
5156 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_SIM_DUAL_SELECTION, pricing[ival]) );
5157
5158 /* for certain pricing values, do not use restricted pricing */
5159 if( lpi->pricing == SCIP_PRICING_PARTIAL || lpi->pricing == SCIP_PRICING_AUTO )
5160 lpi->restrictselectdef = 50;
5161 else
5162 lpi->restrictselectdef = 0;
5163
5164 break;
5165 case SCIP_LPPAR_LPINFO:
5166 /* should LP solver output information to the screen? */
5167 #if FORCE_MOSEK_LOG
5168 SCIPdebugMessage("Ignoring log setting!\n");
5169 #else
5170 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_LOG, ival ? 4 : MSK_OFF) );
5171 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_LOG_SIM, ival ? 4 : MSK_OFF) );
5172 #endif
5173 lpi->lpinfo = (SCIP_Bool) ival;
5174 break;
5175 case SCIP_LPPAR_LPITLIM: /* LP iteration limit */
5176 #if DEBUG_PARAM_SETTING
5177 if( ival )
5178 {
5179 SCIPdebugMessage("Setting max iter to : %d\n", ival);
5180 }
5181 #endif
5182 /* 0 <= ival, 0 stopping immediately */
5183 assert( ival >= 0 );
5184 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_SIM_MAX_ITERATIONS, ival) );
5185 break;
5186 case SCIP_LPPAR_THREADS: /* number of threads (0 => MOSEK chooses) */
5187 assert(ival >= 0);
5188 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_NUM_THREADS, ival) );
5189 break;
5190 case SCIP_LPPAR_REFACTOR: /* refactorization interval */
5191 assert(ival >= 0);
5192 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_SIM_REFACTOR_FREQ, ival) );
5193 break;
5194 default:
5195 return SCIP_PARAMETERUNKNOWN;
5196 } /*lint !e788*/
5197
5198 return SCIP_OKAY;
5199 }
5200
5201 /** gets floating point parameter of LP */
SCIPlpiGetRealpar(SCIP_LPI * lpi,SCIP_LPPARAM type,SCIP_Real * dval)5202 SCIP_RETCODE SCIPlpiGetRealpar(
5203 SCIP_LPI* lpi, /**< LP interface structure */
5204 SCIP_LPPARAM type, /**< parameter number */
5205 SCIP_Real* dval /**< buffer to store the parameter value */
5206 )
5207 {
5208 assert(MosekEnv != NULL);
5209 assert(lpi != NULL);
5210 assert(lpi->task != NULL);
5211 assert(dval != NULL);
5212
5213 SCIPdebugMessage("getting real parameter %s\n", paramty2str(type));
5214
5215 switch (type)
5216 {
5217 case SCIP_LPPAR_FEASTOL: /* feasibility tolerance for primal variables and slacks */
5218 MOSEK_CALL( MSK_getdouparam(lpi->task, MSK_DPAR_BASIS_TOL_X, dval) );
5219 break;
5220 case SCIP_LPPAR_DUALFEASTOL: /* feasibility tolerance for dual variables and reduced costs */
5221 MOSEK_CALL( MSK_getdouparam(lpi->task, MSK_DPAR_BASIS_TOL_S, dval) );
5222 break;
5223 case SCIP_LPPAR_BARRIERCONVTOL: /* convergence tolerance used in barrier algorithm */
5224 MOSEK_CALL( MSK_getdouparam(lpi->task, MSK_DPAR_INTPNT_TOL_REL_GAP, dval) );
5225 break;
5226 case SCIP_LPPAR_OBJLIM: /* objective limit */
5227 {
5228 MSKobjsensee objsen;
5229 MOSEK_CALL( MSK_getobjsense(lpi->task, &objsen) );
5230 if (objsen == MSK_OBJECTIVE_SENSE_MINIMIZE)
5231 {
5232 MOSEK_CALL( MSK_getdouparam(lpi->task, MSK_DPAR_UPPER_OBJ_CUT, dval) );
5233 }
5234 else /* objsen == MSK_OBJECTIVE_SENSE_MAX */
5235 {
5236 MOSEK_CALL( MSK_getdouparam(lpi->task, MSK_DPAR_LOWER_OBJ_CUT, dval) );
5237 }
5238 break;
5239 }
5240 case SCIP_LPPAR_LPTILIM: /* LP time limit */
5241 MOSEK_CALL( MSK_getdouparam(lpi->task, MSK_DPAR_OPTIMIZER_MAX_TIME, dval) );
5242 break;
5243 case SCIP_LPPAR_MARKOWITZ: /* Markowitz tolerance */
5244 default:
5245 return SCIP_PARAMETERUNKNOWN;
5246 } /*lint !e788*/
5247
5248 return SCIP_OKAY;
5249 }
5250
5251 /** sets floating point parameter of LP */
SCIPlpiSetRealpar(SCIP_LPI * lpi,SCIP_LPPARAM type,SCIP_Real dval)5252 SCIP_RETCODE SCIPlpiSetRealpar(
5253 SCIP_LPI* lpi, /**< LP interface structure */
5254 SCIP_LPPARAM type, /**< parameter number */
5255 SCIP_Real dval /**< parameter value */
5256 )
5257 {
5258 assert(MosekEnv != NULL);
5259 assert(lpi != NULL);
5260 assert(lpi->task != NULL);
5261
5262 SCIPdebugMessage("setting real parameter %s to %g\n", paramty2str(type), dval);
5263
5264 /**@todo Limits shouldn't be hardcoded */
5265
5266 switch (type)
5267 {
5268 case SCIP_LPPAR_FEASTOL: /* feasibility tolerance for primal variables and slacks */
5269 assert( dval > 0.0 );
5270 /* 1e-9 <= dval <= inf */
5271 if( dval < 1e-9 )
5272 dval = 1e-9;
5273
5274 MOSEK_CALL( MSK_putdouparam(lpi->task, MSK_DPAR_BASIS_TOL_X, dval) );
5275 break;
5276 case SCIP_LPPAR_DUALFEASTOL: /* feasibility tolerance for dual variables and reduced costs */
5277 assert( dval > 0.0 );
5278 /* 1e-9 <= dval <= inf */
5279 if( dval < 1e-9 )
5280 dval = 1e-9;
5281
5282 MOSEK_CALL( MSK_putdouparam(lpi->task, MSK_DPAR_BASIS_TOL_S, dval) );
5283 break;
5284 case SCIP_LPPAR_BARRIERCONVTOL: /* convergence tolerance used in barrier algorithm */
5285 /* 1e-14 <= dval <= inf */
5286 assert( dval >= 0.0 );
5287 if( dval < 1e-14 )
5288 dval = 1e-14;
5289
5290 MOSEK_CALL( MSK_putdouparam(lpi->task, MSK_DPAR_INTPNT_TOL_REL_GAP, dval) );
5291 break;
5292 case SCIP_LPPAR_OBJLIM: /* objective limit */
5293 {
5294 /* no restriction on dval */
5295 MSKobjsensee objsen;
5296 MOSEK_CALL( MSK_getobjsense(lpi->task, &objsen) );
5297 if (objsen == MSK_OBJECTIVE_SENSE_MINIMIZE)
5298 {
5299 MOSEK_CALL( MSK_putdouparam(lpi->task, MSK_DPAR_UPPER_OBJ_CUT, dval) );
5300 }
5301 else /* objsen == MSK_OBJECTIVE_SENSE_MAX */
5302 {
5303 MOSEK_CALL( MSK_putdouparam(lpi->task, MSK_DPAR_LOWER_OBJ_CUT, dval) );
5304 }
5305 break;
5306 }
5307 case SCIP_LPPAR_LPTILIM: /* LP time limit */
5308 assert( dval > 0.0 );
5309 /* mosek requires 0 <= dval
5310 *
5311 * However for consistency we assert the timelimit to be strictly positive.
5312 */
5313 MOSEK_CALL( MSK_putdouparam(lpi->task, MSK_DPAR_OPTIMIZER_MAX_TIME, dval) );
5314 break;
5315 case SCIP_LPPAR_MARKOWITZ: /* Markowitz tolerance */
5316 default:
5317 return SCIP_PARAMETERUNKNOWN;
5318 } /*lint !e788*/
5319
5320 return SCIP_OKAY;
5321 }
5322
5323
5324 /*
5325 * Numerical Methods
5326 */
5327
5328
5329 /** returns value treated as infinity in the LP solver */
SCIPlpiInfinity(SCIP_LPI * lpi)5330 SCIP_Real SCIPlpiInfinity(
5331 SCIP_LPI* lpi /**< LP interface structure */
5332 )
5333 { /*lint --e{715}*/
5334 assert(MosekEnv != NULL);
5335 assert(lpi != NULL);
5336 assert(lpi->task != NULL);
5337
5338 return MSK_INFINITY;
5339 }
5340
5341 /** checks if given value is treated as infinity in the LP solver */
SCIPlpiIsInfinity(SCIP_LPI * lpi,SCIP_Real val)5342 SCIP_Bool SCIPlpiIsInfinity(
5343 SCIP_LPI* lpi, /**< LP interface structure */
5344 SCIP_Real val /**< value to be checked for infinity */
5345 )
5346 { /*lint --e{715}*/
5347 assert(MosekEnv != NULL);
5348 assert(lpi != NULL);
5349 assert(lpi->task != NULL);
5350
5351 return IS_POSINF(val);
5352 }
5353
5354
5355 /*
5356 * File Interface Methods
5357 */
5358
5359
5360 /** reads LP from a file */
SCIPlpiReadLP(SCIP_LPI * lpi,const char * fname)5361 SCIP_RETCODE SCIPlpiReadLP(
5362 SCIP_LPI* lpi, /**< LP interface structure */
5363 const char* fname /**< file name */
5364 )
5365 {
5366 #if MSK_VERSION_MAJOR < 9
5367 int olddataformat;
5368 #endif
5369
5370 assert(MosekEnv != NULL);
5371 assert(lpi != NULL);
5372 assert(lpi->task != NULL);
5373 assert(fname != NULL);
5374
5375 SCIPdebugMessage("Calling SCIPlpiReadLP (%d), filename <%s>\n", lpi->lpid, fname);
5376
5377 #if MSK_VERSION_MAJOR < 9
5378 MOSEK_CALL( MSK_getintparam(lpi->task, MSK_IPAR_READ_DATA_FORMAT, &olddataformat) );
5379 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_READ_DATA_FORMAT, MSK_DATA_FORMAT_LP) );
5380 MOSEK_CALL( MSK_readdata(lpi->task, fname) );
5381 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_READ_DATA_FORMAT, olddataformat) );
5382 #else
5383 MOSEK_CALL( MSK_readdataformat(lpi->task, fname, MSK_DATA_FORMAT_LP, MSK_COMPRESS_FREE) );
5384 #endif
5385
5386 return SCIP_OKAY;
5387 }
5388
5389 /** writes LP to a file */
SCIPlpiWriteLP(SCIP_LPI * lpi,const char * fname)5390 SCIP_RETCODE SCIPlpiWriteLP(
5391 SCIP_LPI* lpi, /**< LP interface structure */
5392 const char* fname /**< file name */
5393 )
5394 {
5395 #if MSK_VERSION_MAJOR < 9
5396 int olddataformat;
5397 #endif
5398
5399 assert(MosekEnv != NULL);
5400 assert(lpi != NULL);
5401 assert(lpi->task != NULL);
5402 assert(fname != NULL);
5403 #if MSK_VERSION_MAJOR >= 9
5404 /* Mosek 9 derives file format from given filename */
5405 assert(strstr(fname, ".lp") != NULL);
5406 #endif
5407
5408 SCIPdebugMessage("Calling SCIPlpiWriteLP (%d), filename <%s>\n", lpi->lpid, fname);
5409
5410 #if MSK_VERSION_MAJOR < 9
5411 MOSEK_CALL( MSK_getintparam(lpi->task, MSK_IPAR_WRITE_DATA_FORMAT, &olddataformat) );
5412 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_WRITE_DATA_FORMAT, MSK_DATA_FORMAT_LP) );
5413 MOSEK_CALL( MSK_writedata(lpi->task, fname) );
5414 MOSEK_CALL( MSK_putintparam(lpi->task, MSK_IPAR_WRITE_DATA_FORMAT, olddataformat) );
5415 #else
5416 MOSEK_CALL( MSK_writedata(lpi->task, fname) );
5417 #endif
5418
5419 return SCIP_OKAY;
5420 }
5421