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