SCIP-SDP  3.2.0
relax_sdp.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of SCIPSDP - a solving framework for mixed-integer */
4 /* semidefinite programs based on SCIP. */
5 /* */
6 /* Copyright (C) 2011-2013 Discrete Optimization, TU Darmstadt */
7 /* EDOM, FAU Erlangen-Nürnberg */
8 /* 2014-2020 Discrete Optimization, TU Darmstadt */
9 /* */
10 /* */
11 /* This program is free software; you can redistribute it and/or */
12 /* modify it under the terms of the GNU Lesser General Public License */
13 /* as published by the Free Software Foundation; either version 3 */
14 /* of the License, or (at your option) any later version. */
15 /* */
16 /* This program is distributed in the hope that it will be useful, */
17 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
18 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
19 /* GNU Lesser General Public License for more details. */
20 /* */
21 /* You should have received a copy of the GNU Lesser General Public License */
22 /* along with this program; if not, write to the Free Software */
23 /* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.*/
24 /* */
25 /* */
26 /* Based on SCIP - Solving Constraint Integer Programs */
27 /* Copyright (C) 2002-2020 Zuse Institute Berlin */
28 /* SCIP is distributed under the terms of the SCIP Academic Licence, */
29 /* see file COPYING in the SCIP distribution. */
30 /* */
31 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
32 
42 /* #define SCIP_DEBUG*/
43 /* #define SCIP_MORE_DEBUG *//* displays complete solution for each relaxation */
44 /* #define SCIP_EVEN_MORE_DEBUG *//* shows number of deleted empty cols/rows for every relaxation and variable status &
45  * bounds as well as all constraints in the beginning */
46 /* #define SCIP_PRINT_WARMSTART */ /* print initial point given for warmstarts */
47 #define SLATERSOLVED_ABSOLUTE /* uncomment this to return the absolute number of nodes for, e.g., solved fast with slater in addition to percentages */
48 
49 #include "relax_sdp.h"
50 
51 #include "assert.h" /*lint !e451*/
52 #include "string.h" /* for strcmp */
53 
54 #include "SdpVarmapper.h"
55 #include "SdpVarfixer.h"
56 #include "sdpi/sdpi.h"
57 #include "sdpi/lapack_interface.h"
58 #include "scipsdp/cons_sdp.h"
61 
62 /* turn off lint warnings for whole file: */
63 /*lint --e{788,818}*/
64 
65 #define RELAX_NAME "SDP"
66 #define RELAX_DESC "SDP-relaxator"
67 #define RELAX_PRIORITY 1
68 #define RELAX_FREQ 1
69 
70 /* default values for parameters: */
71 #define DEFAULT_PENALTYPARAM -1.0
72 #define DEFAULT_LAMBDASTAR -1.0
73 #define DEFAULT_MAXPENALTYPARAM -1.0
74 #define DEFAULT_WARMSTARTIPFACTOR 0.50
75 #define DEFAULT_WARMSTARTPRIMALTYPE 3
76 #define DEFAULT_WARMSTARTIPTYPE 1
77 #define DEFAULT_WARMSTARTPROJECT 2
78 #define DEFAULT_WARMSTARTPROJMINEV -1.0
79 #define DEFAULT_WARMSTARTPROJPDSAME TRUE
80 #define DEFAULT_WARMSTART_PREOPTIMAL_SOL FALSE
81 #define DEFAULT_WARMSTARTPREOPTGAP 1e-2
82 #define DEFAULT_WARMSTARTROUNDONLYINF FALSE
83 #define DEFAULT_SLATERCHECK 0
84 #define DEFAULT_OBJLIMIT FALSE
85 #define DEFAULT_RESOLVE TRUE
86 #define DEFAULT_TIGHTENVB TRUE
87 #define DEFAULT_SDPINFO FALSE
88 #define DEFAULT_WARMSTART FALSE
89 #define DEFAULT_DISPLAYSTAT FALSE
90 #define DEFAULT_SETTINGSRESETFREQ -1
91 #define DEFAULT_SETTINGSRESETOFS 0
92 #define DEFAULT_SDPSOLVERTHREADS -1
93 #define DEFAULT_PENINFEASADJUST 10.0
95 #define WARMSTART_MINVAL 0.01
96 #define WARMSTART_PROJ_MINRHSOBJ 1
97 #define WARMSTART_PROJ_FACTOR 0.1
98 #define WARMSTART_PROJ_FACTOR_LHS 10
99 #define WARMSTART_PROJ_FACTOR_PRIMAL 0.1
100 #define WARMSTART_PREOPT_MIN_Z_LPVAL 0.01
103 /*
104  * Data structures
105  */
106 
108 struct SCIP_RelaxData
109 {
110  SCIP_SDPI* sdpi;
111  SCIP_LPI* lpi;
112  SdpVarmapper* varmapper;
114  SCIP_Real objval;
115  SCIP_Bool origsolved;
116  SCIP_Bool probingsolved;
117  long int lastsdpnode;
118  SCIP_Bool feasible;
120  SCIP_Real sdpsolvergaptol;
121  SCIP_Real sdpsolverfeastol;
122  SCIP_Real penaltyparam;
123  SCIP_Real maxpenaltyparam;
124  SCIP_Real lambdastar;
125  int npenaltyincr;
126  SCIP_Real peninfeasadjust;
127  int slatercheck;
128  SCIP_Bool sdpinfo;
129  SCIP_Bool displaystat;
130  SCIP_Bool objlimit;
131  SCIP_Bool resolve;
132  SCIP_Bool tightenvb;
133  int settingsresetfreq;
134  int settingsresetofs;
135  int sdpsolverthreads;
137  int sdpcalls;
138  int sdpinterfacecalls;
139  int sdpiterations;
140  int solvedfast;
141  int solvedmedium;
142  int solvedstable;
143  int solvedpenalty;
144  int unsolved;
145  int stablewslater;
146  int unstablewslater;
147  int penaltywslater;
148  int boundedwslater;
149  int unsolvedwslater;
150  int stablenoslater;
151  int unstablenoslater;
152  int penaltynoslater;
153  int boundednoslater;
154  int unsolvednoslater;
155  int nslaterholds;
156  int nnoslater;
157  int nslatercheckfailed;
159  int npslaterholds;
160  int npnoslater;
161  int npslatercheckfailed;
162  int ndslaterholds;
163  int ndnoslater;
164  int ndslatercheckfailed;
165  int nslaterinfeasible;
166  int stableinfeasible;
167  int unstableinfeasible;
168  int penaltyinfeasible;
169  int boundedinfeasible;
170  int unsolvedinfeasible;
171  int roundingprobinf;
172  int primalroundfails;
173  int dualroundfails;
174  int roundstartsuccess;
175  int roundingoptimal;
176  int roundingcutoff;
177  SCIP_CLOCK* roundingprobtime;
178  SCIP_Bool warmstart;
179  SCIP_Real warmstartipfactor;
180  int warmstartprimaltype;
182  int warmstartproject;
183  SCIP_Real warmstartpmevprimalpar;
184  SCIP_Real warmstartpmevdualpar;
185  SCIP_Real warmstartprojminevprimal;
186  SCIP_Real warmstartprojminevdual;
187  SCIP_Bool warmstartprojpdsame;
188  int warmstartiptype;
189  SCIP_Bool warmstartpreoptsol;
190  SCIP_Real warmstartpreoptgap;
191  SCIP_Bool warmstartroundonlyinf;
192  int nblocks;
193  SCIP_Bool ipXexists;
194  int* ipXnblocknonz;
196  int** ipXrow;
197  int** ipXcol;
198  SCIP_Real** ipXval;
199  SCIP_Bool ipZexists;
200  SCIP_SOL* ipy;
201  int* ipZnblocknonz;
203  int** ipZrow;
204  int** ipZcol;
205  SCIP_Real** ipZval;
207  SCIP_CONSHDLR* sdpconshdlr;
208  SCIP_CONSHDLR* sdprank1conshdlr;
209 };
210 
212 static
213 SCIP_RETCODE expandSparseMatrix(
214  int nnonz,
215  int blocksize,
216  int* row,
217  int* col,
218  SCIP_Real* val,
219  SCIP_Real* fullmat
220  )
221 {
222  int i;
223  int matrixsize;
224 
225  assert( nnonz >= 0 );
226  assert( row != NULL );
227  assert( col != NULL );
228  assert( val != NULL );
229  assert( fullmat != NULL );
230 
231  matrixsize = blocksize * blocksize;
232 
233  /* initialize matrix with zeros */
234  for (i = 0; i < matrixsize; i++)
235  fullmat[i] = 0.0;
236 
237  for (i = 0; i < nnonz; i++)
238  {
239  assert( row[i] * blocksize + col[i] <= matrixsize );
240  fullmat[row[i] * blocksize + col[i]] = val[i]; /*lint !e679*/
241  assert( col[i] * blocksize + row[i] <= matrixsize );
242  fullmat[col[i] * blocksize + row[i]] = val[i]; /*lint !e679*/
243  }
244 
245  return SCIP_OKAY;
246 }
247 
249 static
251  int blocksize,
252  SCIP_Real* matrix,
253  SCIP_Real* scale
254  )
255 {
256  int r;
257  int c;
258 
259  assert( blocksize >= 0 );
260  assert( matrix != NULL );
261  assert( scale != NULL );
262 
263  for (r = 0; r < blocksize; r++)
264  {
265  for (c = 0; c < blocksize; c++)
266  {
267  matrix[r * blocksize + c] *= scale[c]; /*lint !e679*/
268  }
269  }
270 
271  return SCIP_OKAY;
272 }
273 
275 static
276 SCIP_RETCODE updateSDPStatistics(
277  SCIP_RELAXDATA* relaxdata
278  )
279 {
281  SCIP_SDPSLATER primalslater = SCIP_SDPSLATER_NOINFO;
284  int naddedsdpcalls;
285  int naddediters;
286 
287  assert( relaxdata != NULL );
288 
289  /* increase number of calls */
290  relaxdata->sdpinterfacecalls++;
291 
292  /* if no SDP solve actually occured during last call, then exit */
293  SCIP_CALL( SCIPsdpiGetSdpCalls(relaxdata->sdpi, &naddedsdpcalls) );
294  if ( naddedsdpcalls == 0 )
295  return SCIP_OKAY;
296 
297  relaxdata->sdpcalls += naddedsdpcalls;
298 
299  /* update number of iterations */
300  SCIP_CALL( SCIPsdpiGetIterations(relaxdata->sdpi, &naddediters) );
301  relaxdata->sdpiterations += naddediters;
302 
303  /* get settings used for last call */
304  SCIP_CALL( SCIPsdpiSettingsUsed(relaxdata->sdpi, &usedsetting) );
305  switch ( usedsetting )
306  {
308  relaxdata->solvedpenalty++;
309  break;
311  relaxdata->solvedfast++;
312  break;
314  relaxdata->solvedmedium++;
315  break;
317  relaxdata->solvedstable++;
318  break;
320  relaxdata->unsolved++;
321  break;
322  default:
323  break;
324  }
325 
326  /* get information on primal and dual Slater condition during last call */
327  SCIP_CALL( SCIPsdpiSlater(relaxdata->sdpi, &primalslater, &dualslater) );
328  switch ( primalslater )
329  {
331  relaxdata->npslatercheckfailed++;
332  switch ( dualslater )
333  {
335  relaxdata->ndslatercheckfailed++;
336  relaxdata->nslatercheckfailed++;
337  break;
338  case SCIP_SDPSLATER_NOT:
339  relaxdata->ndnoslater++;
340  relaxdata->nnoslater++;
341  break;
343  relaxdata->ndslaterholds++;
344  relaxdata->nslatercheckfailed++;
345  break;
346  case SCIP_SDPSLATER_INF:
347  relaxdata->nslaterinfeasible++;
348  break;
349  default:
350  relaxdata->ndslatercheckfailed++;
351  relaxdata->nslatercheckfailed++;
352  break;
353  }
354  break;
355 
356  case SCIP_SDPSLATER_NOT:
357  relaxdata->npnoslater++;
358  switch ( dualslater )
359  {
361  relaxdata->ndslatercheckfailed++;
362  relaxdata->nnoslater++;
363  break;
364  case SCIP_SDPSLATER_NOT:
365  relaxdata->ndnoslater++;
366  relaxdata->nnoslater++;
367  break;
369  relaxdata->ndslaterholds++;
370  relaxdata->nnoslater++;
371  break;
372  case SCIP_SDPSLATER_INF:
373  relaxdata->nslaterinfeasible++;
374  break;
375  default:
376  relaxdata->ndslatercheckfailed++;
377  relaxdata->nnoslater++;
378  break;
379  }
380  break;
381 
383  relaxdata->npslaterholds++;
384  switch ( dualslater )
385  {
387  relaxdata->ndslatercheckfailed++;
388  relaxdata->nslatercheckfailed++;
389  break;
390  case SCIP_SDPSLATER_NOT:
391  relaxdata->ndnoslater++;
392  relaxdata->nnoslater++;
393  break;
395  relaxdata->ndslaterholds++;
396  relaxdata->nslaterholds++;
397  break;
398  case SCIP_SDPSLATER_INF:
399  relaxdata->nslaterinfeasible++;
400  break;
401  default:
402  relaxdata->ndslatercheckfailed++;
403  relaxdata->nslatercheckfailed++;
404  break;
405  }
406  break;
407 
408  default:
409  relaxdata->npslatercheckfailed++;
410  relaxdata->ndslatercheckfailed++;
411  relaxdata->nslatercheckfailed++;
412  break;
413  }
414 
415  /* get information on Slater setting of last call */
416  SCIP_CALL( SCIPsdpiSlaterSettings(relaxdata->sdpi, &slatersetting) );
417  switch ( slatersetting )
418  {
420  relaxdata->stablewslater++;
421  break;
423  relaxdata->unstablewslater++;
424  break;
426  relaxdata->penaltywslater++;
427  break;
429  relaxdata->boundedwslater++;
430  break;
432  relaxdata->unsolvedwslater++;
433  break;
435  relaxdata->stablenoslater++;
436  break;
438  relaxdata->unstablenoslater++;
439  break;
441  relaxdata->penaltynoslater++;
442  break;
444  relaxdata->boundednoslater++;
445  break;
447  relaxdata->unsolvednoslater++;
448  break;
450  relaxdata->stableinfeasible++;
451  break;
453  relaxdata->unstableinfeasible++;
454  break;
456  relaxdata->penaltyinfeasible++;
457  break;
459  relaxdata->boundedinfeasible++;
460  break;
462  relaxdata->unsolvedinfeasible++;
463  break;
464  default:
465  break;
466  }
467 
468  return SCIP_OKAY;
469 }
470 
472 static
474  SCIP* scip,
475  SCIP_SDPI* sdpi,
476  SdpVarmapper* varmapper,
477  SCIP_Bool primalobj,
478  SCIP_Bool boundprimal
479  )
480 {
481  SCIP_CONSHDLR* conshdlr;
482  const char* conshdlrname;
483  SCIP_CONS** conss;
484  SCIP_VAR** blockvars;
485  SCIP_VAR** vars;
486  SCIP_Real*** val;
487  SCIP_Real** constval;
488  SCIP_Real* obj;
489  SCIP_Real* lb;
490  SCIP_Real* ub;
491  int*** row;
492  int*** col;
493  int** nblockvarnonz;
494  int** constrow;
495  int** constcol;
496  int** sdpvar;
497  int* sdpblocksizes;
498  int* nblockvars;
499  int* nconstblocknonz;
500  int constnnonzcounter;
501  int blocknnonz;
502  int sdpconstnnonz;
503  int sdpnnonz;
504  int nsdpblocks;
505  int constlength;
506  int nvars;
507  int nvarspen;
508  int nconss;
509  int ind;
510  int i;
511  int j;
512 
513  assert( scip != NULL );
514  assert( sdpi != NULL );
515  assert( varmapper != NULL );
516 
517  SCIPdebugMsg(scip, "Putting SDP Data in general SDP interface!\n");
518 
519  vars = SCIPgetVars(scip);
520  nvars = SCIPgetNVars(scip);
521  nvarspen = boundprimal ? nvars + 1 : nvars; /* if the primal should be bounded, an additional penalty variable is added to the dual */
522 
523  /* prepare arrays of objective values and bounds */
524  SCIP_CALL( SCIPallocBufferArray(scip, &obj, nvarspen) );
525  SCIP_CALL( SCIPallocBufferArray(scip, &lb, nvarspen) );
526  SCIP_CALL( SCIPallocBufferArray(scip, &ub, nvarspen) );
527 
528  for (i = 0; i < nvars; i++)
529  {
530  obj[i] = SCIPvarGetObj(vars[i]);
531  lb[i] = SCIPvarGetLbLocal(vars[i]);
532  ub[i] = SCIPvarGetUbLocal(vars[i]);
533  }
534 
535  if ( boundprimal )
536  {
537  obj[nvars] = 1.0; /* this objective coefficient together with lb = 0 and the identity matrix leads to constraint Tr(X) <= 1 */
538  lb[nvars] = 0.0;
539  ub[nvars] = SCIPinfinity(scip);
540  }
541 
542  nconss = SCIPgetNConss(scip);
543  conss = SCIPgetConss(scip);
544 
545  /* count the number of sdpblocks and compute the number of nonzeros */
546  nsdpblocks = 0;
547  sdpnnonz = 0;
548  sdpconstnnonz = 0;
549 
550  for (i = 0; i < nconss; i++)
551  {
552  conshdlr = SCIPconsGetHdlr(conss[i]);
553  assert( conshdlr != NULL );
554 
555  conshdlrname = SCIPconshdlrGetName(conshdlr);
556 
557 #ifdef SCIP_EVEN_MORE_DEBUG
558  SCIP_CALL( SCIPprintCons(scip, conss[i], NULL) );
559  SCIPinfoMessage(scip, NULL, "\n");
560 #endif
561 
562  if ( strcmp(conshdlrname, "SDP") == 0 || strcmp(conshdlrname, "SDPrank1") == 0 )
563  {
564  nsdpblocks++;
565 
566  SCIP_CALL( SCIPconsSdpGetNNonz(scip, conss[i], &blocknnonz, &constnnonzcounter) );
567  sdpnnonz += blocknnonz;
568  sdpconstnnonz += constnnonzcounter;
569  }
570  }
571 
572  /* create the sdp- and sdpconst-arrays */
573  SCIP_CALL( SCIPallocBufferArray(scip, &sdpblocksizes, nsdpblocks) );
574  SCIP_CALL( SCIPallocBufferArray(scip, &nblockvarnonz, nsdpblocks) );
575  SCIP_CALL( SCIPallocBufferArray(scip, &nconstblocknonz, nsdpblocks) );
576  SCIP_CALL( SCIPallocBufferArray(scip, &col, nsdpblocks) );
577  SCIP_CALL( SCIPallocBufferArray(scip, &row, nsdpblocks) );
578  SCIP_CALL( SCIPallocBufferArray(scip, &val, nsdpblocks) );
579  SCIP_CALL( SCIPallocBufferArray(scip, &constcol, nsdpblocks) );
580  SCIP_CALL( SCIPallocBufferArray(scip, &constrow, nsdpblocks) );
581  SCIP_CALL( SCIPallocBufferArray(scip, &constval, nsdpblocks) );
582  SCIP_CALL( SCIPallocBufferArray(scip, &nblockvars, nsdpblocks) );
583  SCIP_CALL( SCIPallocBufferArray(scip, &sdpvar, nsdpblocks) );
584 
585  for (i = 0; i < nsdpblocks; i++)
586  {
587  SCIP_CALL( SCIPallocBufferArray(scip, &(nblockvarnonz[i]), nvarspen) );
588  SCIP_CALL( SCIPallocBufferArray(scip, &col[i], nvarspen) );
589  SCIP_CALL( SCIPallocBufferArray(scip, &row[i], nvarspen) );
590  SCIP_CALL( SCIPallocBufferArray(scip, &val[i], nvarspen) );
591  }
592 
593  /* get the SDP-data */
594  ind = 0; /* index of the current sdp block in the complete sdp */
595  SCIP_CALL( SCIPallocBufferArray(scip, &blockvars, nvars) );
596 
597  for (i = 0; i < nconss; i++)
598  {
599  conshdlr = SCIPconsGetHdlr(conss[i]);
600  assert( conshdlr != NULL );
601 
602  conshdlrname = SCIPconshdlrGetName(conshdlr);
603 
604  if ( strcmp(conshdlrname, "SDP") == 0 || strcmp(conshdlrname, "SDPrank1") == 0 )
605  {
606  assert( ind < nsdpblocks );
607 
608  /* allocate memory for the constant nonzeros */
609  SCIP_CALL( SCIPconsSdpGetNNonz(scip, conss[i], NULL, &constlength) );
610  nconstblocknonz[ind] = constlength;
611  SCIP_CALL( SCIPallocBufferArray(scip, &(constcol[ind]), constlength) );
612  SCIP_CALL( SCIPallocBufferArray(scip, &(constrow[ind]), constlength) );
613  SCIP_CALL( SCIPallocBufferArray(scip, &(constval[ind]), constlength) );
614 
615  /* get the data */
616  SCIP_CALL( SCIPconsSdpGetData(scip, conss[i], &nblockvars[ind], &blocknnonz, &sdpblocksizes[ind], &nvars, nblockvarnonz[ind], col[ind],
617  row[ind], val[ind], blockvars, &nconstblocknonz[ind], constcol[ind], constrow[ind], constval[ind], NULL, NULL, NULL) );
618 
619  /* nvars and nconstblocknonz[ind] would have been overwritten if the space in the given arrays hadn't been sufficient */
620  assert( nvars == SCIPgetNVars(scip) );
621  assert( nconstblocknonz[ind] <= constlength );
622 
623  SCIP_CALL( SCIPallocBufferArray(scip, &(sdpvar[ind]), boundprimal ? nblockvars[ind] + 1 : nblockvars[ind]) );
624 
625  /* get global variable indices */
626  for (j = 0; j < nblockvars[ind]; j++)
627  sdpvar[ind][j] = SCIPsdpVarmapperGetSdpIndex(varmapper, blockvars[j]);
628 
629  if ( boundprimal )
630  {
631  /* penalty variable is added as final variable to bound the primal */
632  sdpvar[ind][nblockvars[ind]] = SCIPsdpVarmapperGetNVars(varmapper);
633  nblockvarnonz[ind][nblockvars[ind]] = sdpblocksizes[ind];
634 
635  /* add identity matrix times penalty variable */
636  SCIP_CALL( SCIPallocBufferArray(scip, &col[ind][nblockvars[ind]], sdpblocksizes[ind]) );
637  SCIP_CALL( SCIPallocBufferArray(scip, &row[ind][nblockvars[ind]], sdpblocksizes[ind]) );
638  SCIP_CALL( SCIPallocBufferArray(scip, &val[ind][nblockvars[ind]], sdpblocksizes[ind]) );
639 
640  for (j = 0; j < sdpblocksizes[ind]; j++)
641  {
642  col[ind][nblockvars[ind]][j] = j;
643  row[ind][nblockvars[ind]][j] = j;
644  val[ind][nblockvars[ind]][j] = 1.0;
645  }
646  nblockvars[ind]++;
647  }
648 
649  ind++;
650  }
651  }
652 
653  /* free the memory that is no longer needed */
654  SCIPfreeBufferArray(scip, &blockvars);
655 
656  /* load data into SDPI */
657  if ( primalobj )
658  {
659  SCIP_CALL( SCIPsdpiLoadSDP(sdpi, nvarspen, obj, lb, ub, nsdpblocks, sdpblocksizes, nblockvars, sdpconstnnonz, nconstblocknonz, constrow,
660  constcol, constval, sdpnnonz, nblockvarnonz, sdpvar, row, col, val, 0,
661  NULL, NULL, 0, NULL, NULL, NULL) ); /* insert the SDP part, add an empty LP part */
662  }
663  else
664  {
665  /* overwrite nconstblocknonz */
666  for (i = 0; i < nsdpblocks; i++)
667  nconstblocknonz[i] = 0;
668 
669  SCIP_CALL( SCIPsdpiLoadSDP(sdpi, nvarspen, obj, lb, ub, nsdpblocks, sdpblocksizes, nblockvars, 0, nconstblocknonz, NULL,
670  NULL, NULL, sdpnnonz, nblockvarnonz, sdpvar, row, col, val, 0,
671  NULL, NULL, 0, NULL, NULL, NULL) ); /* insert the SDP part, add an empty LP part */
672  }
673 
674  /* free the remaining memory */
675  for (i = 0; i < nsdpblocks; i++)
676  {
677  if ( boundprimal )
678  {
679  SCIPfreeBufferArrayNull(scip, &val[i][nblockvars[i] - 1]);
680  SCIPfreeBufferArrayNull(scip, &row[i][nblockvars[i] - 1]);
681  SCIPfreeBufferArrayNull(scip, &col[i][nblockvars[i] - 1]);
682  }
683  SCIPfreeBufferArrayNull(scip, &(sdpvar[i]));
684  SCIPfreeBufferArrayNull(scip, &val[i]);
685  SCIPfreeBufferArrayNull(scip, &row[i]);
686  SCIPfreeBufferArrayNull(scip, &col[i]);
687  SCIPfreeBufferArrayNull(scip, &(nblockvarnonz[i]));
688  SCIPfreeBufferArrayNull(scip, &(constval[i]));
689  SCIPfreeBufferArrayNull(scip, &(constrow[i]));
690  SCIPfreeBufferArrayNull(scip, &(constcol[i]));
691  }
692 
693  SCIPfreeBufferArrayNull(scip, &sdpvar);
694  SCIPfreeBufferArrayNull(scip, &nblockvars);
695  SCIPfreeBufferArrayNull(scip, &constval);
696  SCIPfreeBufferArrayNull(scip, &constrow);
697  SCIPfreeBufferArrayNull(scip, &constcol);
698  SCIPfreeBufferArrayNull(scip, &val);
699  SCIPfreeBufferArrayNull(scip, &row);
700  SCIPfreeBufferArrayNull(scip, &col);
701  SCIPfreeBufferArrayNull(scip, &nconstblocknonz);
702  SCIPfreeBufferArrayNull(scip, &nblockvarnonz);
703  SCIPfreeBufferArrayNull(scip, &sdpblocksizes);
704  SCIPfreeBufferArray(scip, &ub);
705  SCIPfreeBufferArray(scip, &lb);
706  SCIPfreeBufferArray(scip, &obj);
707 
708  return SCIP_OKAY;
709 }
710 
712 static
713 SCIP_RETCODE putLpDataInInterface(
714  SCIP* scip,
715  SCIP_RELAXDATA* relaxdata,
716  SCIP_Bool primalobj,
717  SCIP_Bool dualobj
718  )
719 {
720  SCIP_VAR** vars;
721  SCIP_COL** rowcols;
722  SCIP_ROW** rows;
723  SCIP_Real* rowvals;
724  SCIP_Real* lhs;
725  SCIP_Real* rhs;
726  SCIP_Real* obj;
727  SCIP_Real* lb;
728  SCIP_Real* ub;
729  SCIP_Real* val;
730  SCIP_Real sciplhs;
731  SCIP_Real sciprhs;
732  int* inds;
733  int* objinds;
734  int* rowind;
735  int* colind;
736  int nrowssdpi;
737  int nrows;
738  int rownnonz;
739  int nvars;
740  int nconss;
741  int scipnnonz;
742  int nnonz;
743  int i;
744  int j;
745 
746  assert( scip != NULL );
747  assert( relaxdata != NULL );
748 
749  nvars = SCIPgetNVars(scip);
750  assert( nvars > 0 );
751 
752  SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
753 
754  SCIPdebugMsg(scip, "inserting %d LPRows into the interface.\n", nrows);
755 
756  /* compute the total number of LP nonzeroes in SCIP */
757  scipnnonz = 0;
758  for (i = 0; i < nrows; i++)
759  {
760  assert( rows[i] != NULL );
761  scipnnonz += SCIProwGetNNonz(rows[i]);
762  }
763 
764  /* allocate memory */
765  SCIP_CALL( SCIPallocBufferArray(scip, &lhs, nrows) );
766  SCIP_CALL( SCIPallocBufferArray(scip, &rhs, nrows) );
767  SCIP_CALL( SCIPallocBufferArray(scip, &rowind, scipnnonz) );
768  SCIP_CALL( SCIPallocBufferArray(scip, &colind, scipnnonz) );
769  SCIP_CALL( SCIPallocBufferArray(scip, &val, scipnnonz) );
770 
771  /* insert the nonzeroes */
772  nnonz = 0; /* this is recomputed for the sdpi, because of the possible duplication of non-zeroes for lhs and rhs */
773  nconss = 0; /* this will be increased for each finite lhs and rhs */
774 
775  for (i = 0; i < nrows; i++)
776  {
777  SCIP_ROW* row;
778  SCIP_Bool tightened = FALSE;
779  SCIP_Real tightenedval = 0.0;
780  SCIP_Bool swapped = FALSE;
781 
782  row = rows[i];
783  assert( row != 0 );
784  rownnonz = SCIProwGetNNonz(row);
785 
786  rowvals = SCIProwGetVals(row);
787  rowcols = SCIProwGetCols(row);
788  sciplhs = SCIProwGetLhs(row) - SCIProwGetConstant(row);
789  sciprhs = SCIProwGetRhs(row) - SCIProwGetConstant(row);
790 
791  /* check whether we have a variable bound and can strenghten the big-M */
792  if ( relaxdata->tightenvb && rownnonz == 2 && (SCIPisZero(scip, sciplhs) || SCIPisZero(scip, sciprhs) ) )
793  {
794  SCIP_VAR* var1;
795  SCIP_VAR* var2;
796  SCIP_Real val1;
797  SCIP_Real val2;
798 
799  val1 = rowvals[0];
800  val2 = rowvals[1];
801 
802  assert( rowcols[0] != NULL );
803  assert( rowcols[1] != NULL );
804  var1 = SCIPcolGetVar(rowcols[0]);
805  var2 = SCIPcolGetVar(rowcols[1]);
806  assert( var1 != NULL );
807  assert( var2 != NULL );
808 
809  /* check that variables are not locally fixed */
810  if ( ! SCIPisEQ(scip, SCIPvarGetLbLocal(var1), SCIPvarGetUbLocal(var1)) && ! SCIPisEQ(scip, SCIPvarGetLbLocal(var2), SCIPvarGetUbLocal(var2)) )
811  {
812  /* one coefficient must be 1 and the other negative */
813  if ( (SCIPisEQ(scip, val1, 1.0) || SCIPisEQ(scip, val2, 1.0)) && ( SCIPisNegative(scip, val1) || SCIPisNegative(scip, val2) ) )
814  {
815  /* We want x - a z <= 0 or x - a z >= 0, where var1 = x and var2 = z; possibly swap variables otherwise */
816  if ( ! SCIPisEQ(scip, val1, 1.0) || ! SCIPisNegative(scip, val2) )
817  {
818  SCIPswapPointers((void**) &var1, (void**) &var2);
819 
820  val2 = val1;
821  swapped = TRUE;
822  }
823 
824  /* var2 needs to be binary */
825  if ( SCIPvarIsBinary(var2) )
826  {
827  if ( SCIPisZero(scip, sciprhs) )
828  {
829  if ( SCIPisLT(scip, SCIPvarGetUbLocal(var1), REALABS(val2)) )
830  {
831  SCIPdebugMsg(scip, "Big-M in %s changed from %f to %f\n", SCIProwGetName(row), REALABS(val2), SCIPvarGetUbLocal(var1));
832 
833  tightened = TRUE;
834  tightenedval = -SCIPvarGetUbLocal(var1); /* negative sign because the coefficient needs to be negative */
835  }
836  }
837 
838  if ( SCIPisZero(scip, sciplhs) )
839  {
840  if ( SCIPisGT(scip, SCIPvarGetLbLocal(var1), REALABS(val2)) )
841  {
842  SCIPdebugMsg(scip, "Big-M in %s changed from %f to %f\n", SCIProwGetName(row), REALABS(val2), SCIPvarGetLbLocal(var1));
843 
844  tightened = TRUE;
845  tightenedval = -SCIPvarGetUbLocal(var1); /* negative sign because the coefficient needs to be negative */
846  }
847  }
848  }
849  }
850  }
851  }
852 
853  for (j = 0; j < rownnonz; j++)
854  {
855  /* if the Big-M was tightened, we use the new value (the position where this new value is used is dependant on wheter we needed to swap) */
856  if ( tightened && ( (swapped && (j == 0)) || ((! swapped) && (j == 1)) ) ) /* use the tightened value */
857  {
858  if ( SCIPisFeasGT(scip, REALABS(tightenedval), 0.0) )
859  {
860  assert( SCIPcolGetVar(rowcols[j]) != 0 );
861  colind[nnonz] = SCIPsdpVarmapperGetSdpIndex(relaxdata->varmapper, SCIPcolGetVar(rowcols[j]));
862  rowind[nnonz] = nconss;
863  val[nnonz] = tightenedval;
864  nnonz++;
865  }
866  }
867  else if ( SCIPisFeasGT(scip, REALABS(rowvals[j]), 0.0))
868  {
869  assert( SCIPcolGetVar(rowcols[j]) != 0 );
870  colind[nnonz] = SCIPsdpVarmapperGetSdpIndex(relaxdata->varmapper, SCIPcolGetVar(rowcols[j]));
871  rowind[nnonz] = nconss;
872  val[nnonz] = rowvals[j];
873  nnonz++;
874  }
875  }
876  lhs[nconss] = primalobj ? sciplhs : (SCIPisInfinity(scip, -sciplhs) ? -sciplhs : 0.0);
877  rhs[nconss] = primalobj ? sciprhs : (SCIPisInfinity(scip, sciprhs) ? sciprhs : 0.0);
878  nconss++;
879  }
880 
881  /* delete the old LP-block from the sdpi */
882  SCIP_CALL( SCIPsdpiGetNLPRows(relaxdata->sdpi, &nrowssdpi) );
883  if ( nrowssdpi > 0 )
884  {
885  SCIP_CALL( SCIPsdpiDelLPRows(relaxdata->sdpi, 0, nrowssdpi - 1) );
886  }
887 
888  /* add the LP-block to the sdpi */
889  SCIP_CALL( SCIPsdpiAddLPRows(relaxdata->sdpi, nconss, lhs, rhs, nnonz, (const int*)rowind, (const int*)colind, val) );
890 
891  /* free the remaining arrays */
892  SCIPfreeBufferArray(scip, &val);
893  SCIPfreeBufferArray(scip, &colind);
894  SCIPfreeBufferArray(scip, &rowind);
895  SCIPfreeBufferArray(scip, &rhs);
896  SCIPfreeBufferArray(scip, &lhs);
897 
898  /* update bounds */
899 
900  /* get the variables */
901  vars = SCIPgetVars(scip);
902  assert( vars != NULL );
903 
904  /* prepare arrays of bounds */
905  SCIP_CALL( SCIPallocBufferArray(scip, &lb, nvars) );
906  SCIP_CALL( SCIPallocBufferArray(scip, &ub, nvars) );
907  SCIP_CALL( SCIPallocBufferArray(scip, &inds, nvars) );
908  SCIP_CALL( SCIPallocBufferArray(scip, &obj, nvars) );
909  SCIP_CALL( SCIPallocBufferArray(scip, &objinds, nvars) );
910 
911  /* get new bounds and objective coefficients */
912  for (i = 0; i < nvars; i++)
913  {
914  assert( vars[i] != NULL );
915  lb[i] = primalobj ? SCIPvarGetLbLocal(vars[i]) : (SCIPisInfinity(scip, -SCIPvarGetLbLocal(vars[i])) ? SCIPvarGetLbLocal(vars[i]) : 0.0);
916  ub[i] = primalobj ? SCIPvarGetUbLocal(vars[i]) : (SCIPisInfinity(scip, SCIPvarGetUbLocal(vars[i])) ? SCIPvarGetUbLocal(vars[i]) : 0.0);
917  inds[i] = i; /* we want to change all bounds, so all indices are included in inds */
918  obj[i] = dualobj ? SCIPvarGetObj(vars[i]) : 0.0;
919  objinds[i] = i;
920  }
921 
922  /* inform interface */
923  SCIP_CALL( SCIPsdpiChgBounds(relaxdata->sdpi, nvars, inds, lb, ub) );
924  SCIP_CALL( SCIPsdpiChgObj(relaxdata->sdpi, nvars, objinds, obj) );
925 
926  /* free the bounds-arrays */
927  SCIPfreeBufferArray(scip, &objinds);
928  SCIPfreeBufferArray(scip, &obj);
929  SCIPfreeBufferArray(scip, &inds);
930  SCIPfreeBufferArray(scip, &ub);
931  SCIPfreeBufferArray(scip, &lb);
932 
933  return SCIP_OKAY;
934 }
935 
937 static
938 SCIP_RETCODE calcRelax(
939  SCIP* scip,
940  SCIP_RELAX* relax,
941  SCIP_RESULT* result,
942  SCIP_Real* lowerbound
943  )
944 {
945  char saveconsname[SCIP_MAXSTRLEN];
946  SCIP_SDPSOLVERSETTING startsetting;
947  SCIP_RELAXDATA* relaxdata;
948  SCIP_CONS* savedsetting;
949  SCIP_CONS** conss;
950  SCIP_VAR** vars;
951  SCIP_SDPI* sdpi;
952  SCIP_Bool rootnode;
953  SCIP_Bool enforceslater;
954  SCIP_Real timelimit;
955  SCIP_Real objforscip;
956  SCIP_Real* solforscip;
957  int nblocks;
958  int nvars;
959  int b;
960  int i;
961  int v;
962 
963  SCIPdebugMsg(scip, "calcRelax called\n");
964 
965  assert( scip != NULL );
966  assert( relax != NULL );
967  assert( result != NULL );
968  assert( lowerbound != NULL );
969 
970  relaxdata = SCIPrelaxGetData(relax);
971  assert( relaxdata != NULL );
972 
973  nvars = SCIPgetNVars(scip);
974  assert( nvars > 0 );
975  vars = SCIPgetVars (scip);
976 
977  sdpi = relaxdata->sdpi;
978  assert( sdpi != NULL );
979 
980  if ( relaxdata->objlimit )
981  {
982  /* set the objective limit */
983  assert( SCIPgetUpperbound(scip) > -SCIPsdpiInfinity(sdpi) );
984  SCIP_CALL( SCIPsdpiSetRealpar(sdpi, SCIP_SDPPAR_OBJLIMIT, SCIPgetUpperbound(scip)) );
985  }
986  /* if this is the root node and we cannot solve the problem, we want to check for the Slater condition independent from the SCIP parameter */
987  rootnode = ! SCIPnodeGetParent(SCIPgetCurrentNode(scip));
988 
989  /* find settings to use for this relaxation */
990  if ( rootnode || (SCIPnodeGetDepth(SCIPgetCurrentNode(scip)) == relaxdata->settingsresetofs) ||
991  ( relaxdata->settingsresetfreq > 0 && ((SCIPnodeGetDepth(SCIPgetCurrentNode(scip)) - relaxdata->settingsresetofs) % relaxdata->settingsresetfreq == 0)) ||
992  ( strcmp(SCIPsdpiGetSolverName(), "DSDP") == 0) || (strstr(SCIPsdpiGetSolverName(), "Mosek") != NULL) )
993  {
994  startsetting = SCIP_SDPSOLVERSETTING_UNSOLVED; /* in the root node we have no information, at each multiple of resetfreq we reset */
995  }
996  else
997  {
998  SCIP_CONSHDLR* conshdlr;
999  int parentconsind;
1000 
1001  /* get constraint handler */
1002  conshdlr = SCIPfindConshdlr(scip, "Savedsdpsettings");
1003  if ( conshdlr == NULL )
1004  {
1005  SCIPerrorMessage("Savedsdpsettings constraint handler not found!\n");
1006  return SCIP_PLUGINNOTFOUND;
1007  }
1008 
1009  /* get startsettings of parent node, usually it will be the last active constraint of the corresponding constraint handler, so we iterate from
1010  * the end of the list until we find the correct one */
1011  conss = SCIPconshdlrGetConss(conshdlr);
1012  parentconsind = SCIPconshdlrGetNActiveConss(conshdlr) - 1;
1013  (void) SCIPsnprintf(saveconsname, SCIP_MAXSTRLEN, "savedsettings_node_%d", SCIPnodeGetNumber(SCIPnodeGetParent(SCIPgetCurrentNode(scip))));
1014 
1015  while ( parentconsind >= 0 && strcmp(saveconsname, SCIPconsGetName(conss[parentconsind])) )
1016  parentconsind--;
1017  if ( parentconsind >= 0 )
1018  startsetting = SCIPconsSavedsdpsettingsGetSettings(scip, conss[parentconsind]);
1019  else
1020  {
1021  SCIPdebugMsg(scip, "Startsetting from parent node not found, restarting with fastest settings!\n");
1022  startsetting = SCIP_SDPSOLVERSETTING_UNSOLVED;
1023  }
1024  }
1025 
1026  /* set time limit */
1027  SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
1028  if ( ! SCIPisInfinity(scip, timelimit) )
1029  {
1030  timelimit -= SCIPgetSolvingTime(scip);
1031  if ( timelimit <= 0.0 )
1032  {
1033  SCIPdebugMsg(scip, "Time limit reached, not running relax SDP!\n");
1034  *result = SCIP_DIDNOTRUN;
1035  return SCIP_OKAY;
1036  }
1037  }
1038 
1039  /* if no dual bound is known (we are in the root node and not only repropagating), we will have to abort, so we want
1040  * to check the Slater condition in this case */
1041  enforceslater = SCIPisInfinity(scip, -1 * SCIPnodeGetLowerbound(SCIPgetCurrentNode(scip)));
1042 
1043  /* solve the problem (using warmstarts if parameter is true and we are not in the root node and all neccessary data is available) */
1044  if ( ( ! SCIPnodeGetParent(SCIPgetCurrentNode(scip))) || ( ! relaxdata->warmstart ) || ((relaxdata->warmstartiptype == 2) &&
1045  SCIPisGT(scip, relaxdata->warmstartipfactor, 0.0) && ((SCIPsdpiDoesWarmstartNeedPrimal() && ! relaxdata->ipXexists) || (! relaxdata->ipZexists))) )
1046  {
1047  SCIP_CALL( SCIPsdpiSolve(sdpi, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, startsetting, enforceslater, timelimit) );
1048  }
1049  else if ( relaxdata->warmstart && (relaxdata->warmstartprimaltype != 2) && (relaxdata->warmstartiptype == 2) && SCIPisEQ(scip, relaxdata->warmstartipfactor, 1.0) )
1050  {
1051  SCIP_Real* ipy;
1052 
1053  /* if we warmstart with the analytic center, we give a pointer to the arrays in relaxdata (just the sol needs to be transformed to a vector first) */
1054 
1055  SCIP_CALL( SCIPallocBufferArray(scip, &ipy, nvars) );
1056  for (v = 0; v < nvars; v++)
1057  ipy[v] = SCIPgetSolVal(scip, relaxdata->ipy, SCIPsdpVarmapperGetSCIPvar(relaxdata->varmapper, v));
1058 
1059 #ifdef SCIP_PRINT_WARMSTART
1060  SCIPdebugMsg(scip, "warmstart using the following analytic centers:\n");
1061  for (v = 0; v < nvars; v++)
1062  SCIPdebugMsg(scip, "y[%d] = %f\n", v, ipy[v]);
1064  {
1065  for (b = 0; b < relaxdata->nblocks; b++)
1066  {
1067  SCIPdebugMsg(scip, "dual block %d\n", b);
1068  for (i = 0; i < relaxdata->ipZnblocknonz[b]; i++)
1069  {
1070  SCIPdebugMsg(scip, "Z(%d,%d)=%f\n", relaxdata->ipZrow[b][i], relaxdata->ipZcol[b][i], relaxdata->ipZval[b][i]);
1071  }
1072  }
1073  for (b = 0; b < relaxdata->nblocks; b++)
1074  {
1075  SCIPdebugMsg(scip, "primal block %d\n", b);
1076  for (i = 0; i < relaxdata->ipXnblocknonz[b]; i++)
1077  {
1078  SCIPdebugMsg(scip, "X(%d,%d)=%f\n", relaxdata->ipXrow[b][i], relaxdata->ipXcol[b][i], relaxdata->ipXval[b][i]);
1079  }
1080  }
1081  }
1082 #endif
1083 
1084  SCIP_CALL( SCIPsdpiSolve(sdpi, ipy, relaxdata->ipZnblocknonz, relaxdata->ipZrow, relaxdata->ipZcol, relaxdata->ipZval, relaxdata->ipXnblocknonz,
1085  relaxdata->ipXrow, relaxdata->ipXcol, relaxdata->ipXval, startsetting, enforceslater, timelimit) );
1086 
1087  SCIPfreeBufferArray(scip, &ipy);
1088  }
1089  else
1090  {
1091  SCIP_CONSHDLR* conshdlr;
1092  SCIP_SOL* dualsol;
1093  SCIP_CONS** sdpblocks = NULL;
1094  SCIP_Real* starty = NULL;
1095  int* startZnblocknonz = NULL;
1096  int** startZrow = NULL;
1097  int** startZcol = NULL;
1098  SCIP_Real** startZval = NULL;
1099  int* startXnblocknonz = NULL;
1100  int** startXrow = NULL;
1101  int** startXcol = NULL;
1102  SCIP_Real** startXval = NULL;
1103  int parentconsind;
1104  SCIP_Longint parentnodenumber;
1105  SCIP_VAR* var;
1106 
1107  /* find starting solution as optimal solution of parent node */
1108 
1109  /* get constraint handler */
1110  conshdlr = SCIPfindConshdlr(scip, "Savesdpsol");
1111  if ( conshdlr == NULL )
1112  {
1113  SCIPerrorMessage("Savesdpsol constraint handler not found\n");
1114  return SCIP_PLUGINNOTFOUND;
1115  }
1116 
1117  /* get saveconstraint of parent node, usually it will be the last active constraint of the corresponding constraint handler, so we iterate from
1118  * the end of the list until we find the correct one */
1119  conss = SCIPconshdlrGetConss(conshdlr);
1120  parentconsind = SCIPconshdlrGetNActiveConss(conshdlr) - 1;
1121  parentnodenumber = SCIPnodeGetNumber(SCIPnodeGetParent(SCIPgetCurrentNode(scip)));
1122 
1123  while ( parentconsind >= 0 && SCIPconsSavesdpsolGetNodeIndex(scip, conss[parentconsind]) != parentnodenumber)
1124  parentconsind--;
1125 
1126  /* If there are no savesdpsol constraints (e.g. because the parent node couldn't be solved successfully), solve
1127  * without warmstart. */
1128  if ( parentconsind < 0 )
1129  {
1130  SCIPdebugMsg(scip, "Starting SDP-Solving from scratch since no warmstart information available for node %lld\n", parentnodenumber);
1131  SCIP_CALL( SCIPsdpiSolve(sdpi, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, startsetting, enforceslater, timelimit) );
1132  }
1133  else
1134  {
1135  SCIPdebugMsg(scip, "Using warmstartinformation from node %lld\n", parentnodenumber);
1136 
1137  /* get solution */
1138  dualsol = SCIPconsSavesdpsolGetDualVector(scip, conss[parentconsind]);
1139 
1140  /* allocate memory */
1141  SCIP_CALL( SCIPallocBufferArray(scip, &starty, nvars) );
1142 
1143  /* transform solution to vector for SDPI and check if it is still feasible for the variable bounds, otherwise round it */
1144  for (v = 0; v < nvars; v++)
1145  {
1146  var = SCIPsdpVarmapperGetSCIPvar(relaxdata->varmapper, v);
1147  starty[v] = SCIPgetSolVal(scip, dualsol, var);
1148 
1149  /* correct solution to new bounds unless warmstartproject == 1 */
1150  if (SCIPisLT(scip, starty[v], SCIPvarGetLbLocal(var)) && (relaxdata->warmstartproject == 2 || relaxdata->warmstartproject == 3 || relaxdata->warmstartproject == 4))
1151  {
1152  starty[v] = SCIPvarGetLbLocal(var);
1153  /* update solution (used to compute dual matrix) according to new bounds */
1154  SCIP_CALL( SCIPsetSolVal(scip, dualsol, var, SCIPvarGetLbLocal(var)) );
1155  }
1156  else if (SCIPisGT(scip, starty[v], SCIPvarGetUbLocal(var)) && (relaxdata->warmstartproject == 2 || relaxdata->warmstartproject == 3 || relaxdata->warmstartproject == 4))
1157  {
1158  starty[v] = SCIPvarGetUbLocal(var);
1159  /* update solution (used to compute dual matrix) according to new bounds */
1160  SCIP_CALL( SCIPsetSolVal(scip, dualsol, var, SCIPvarGetUbLocal(var)) );
1161  }
1162 
1163  /* if we take a convex combination, adjust y accordingly (if we use rounding problems, we recompute y later anyways) */
1164  if ( SCIPisGT(scip, relaxdata->warmstartipfactor, 0.0) && relaxdata->warmstartproject != 4 )
1165  {
1166  if ( relaxdata->warmstartiptype == 1 )
1167  {
1168  /* we take a convex combination with 0, so we just scale */
1169  starty[v] *= 1 - relaxdata->warmstartipfactor;
1170  }
1171  else if ( relaxdata->warmstartiptype == 2 )
1172  {
1173  /* take the convex combination with the saved analytic center */
1174  starty[v] = (1 - relaxdata->warmstartipfactor) * starty[v] + relaxdata->warmstartipfactor * SCIPgetSolVal(scip, relaxdata->ipy, var);
1175  }
1176  }
1177  }
1178 
1179  /* if the SDP-solver needs the primal solution (and the dual matrix) in addition to the dual vector... */
1181  {
1182  SCIP_CONSHDLR* sdpconshdlr;
1183  SCIP_CONSHDLR* sdprank1conshdlr;
1184  SCIP_CONS** sdporigblocks;
1185  SCIP_CONS** sdprank1blocks;
1186  SCIP_COL** rowcols;
1187  SCIP_ROW** rows;
1188  int blocksize;
1189  int nrows;
1190  int rownnonz;
1191  int r;
1192  int nsdpblocks;
1193  int nrank1blocks;
1194  SCIP_Real maxprimalentry = 0.0;
1195  SCIP_Real maxdualentry;
1196  SCIP_Real identitydiagonal = 0.0;
1197  SCIP_Real rowval;
1198  SCIP_Real* rowvals;
1199  SCIP_Bool* diagentryexists;
1200 
1201  sdpconshdlr = relaxdata->sdpconshdlr;
1202  sdprank1conshdlr = relaxdata->sdprank1conshdlr;
1203  nsdpblocks = SCIPconshdlrGetNConss(sdpconshdlr);
1204  nrank1blocks = SCIPconshdlrGetNConss(sdprank1conshdlr);
1205  sdporigblocks = SCIPconshdlrGetConss(sdpconshdlr);
1206  sdprank1blocks = SCIPconshdlrGetConss(sdprank1conshdlr);
1207 
1208  nblocks = nsdpblocks + nrank1blocks;
1209 
1210  SCIP_CALL( SCIPallocBufferArray(scip, &sdpblocks, nblocks) );
1211  for (r = 0; r < nsdpblocks; ++r)
1212  sdpblocks[r] = sdporigblocks[r];
1213 
1214  for (r = 0; r < nrank1blocks; ++r)
1215  sdpblocks[nsdpblocks + r] = sdprank1blocks[r];
1216 
1217  SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
1218 
1219  SCIP_CALL( SCIPallocBufferArray(scip, &startZnblocknonz, nblocks + 1) );
1220  SCIP_CALL( SCIPallocBufferArray(scip, &startZrow, nblocks + 1) );
1221  SCIP_CALL( SCIPallocBufferArray(scip, &startZcol, nblocks + 1) );
1222  SCIP_CALL( SCIPallocBufferArray(scip, &startZval, nblocks + 1) );
1223  SCIP_CALL( SCIPallocBufferArray(scip, &startXnblocknonz, nblocks + 1) );
1224  SCIP_CALL( SCIPallocBufferArray(scip, &startXrow, nblocks + 1) );
1225  SCIP_CALL( SCIPallocBufferArray(scip, &startXcol, nblocks + 1) );
1226  SCIP_CALL( SCIPallocBufferArray(scip, &startXval, nblocks + 1) );
1227 
1228  /* compute the scaling factor for the dual identity matrix (for numerical stability, this should be at least 1) */
1229  if ( relaxdata->warmstartiptype == 1 )
1230  {
1231  maxprimalentry = SCIPconsSavesdpsolGetMaxPrimalEntry(scip, conss[0]);
1232  if ( SCIPisLT(scip, maxprimalentry, 1.0) )
1233  maxprimalentry = 1.0;
1234  }
1235 
1236  /* iterate over all blocks and fill X and Z */
1237  for (b = 0; b < nblocks; b++)
1238  {
1239  blocksize = SCIPconsSdpGetBlocksize(scip, sdpblocks[b]);
1240 
1241  if ( relaxdata->warmstartproject == 3 || relaxdata->warmstartproject == 4 )
1242  {
1243  /* since we later take the projection onto the psd cone, we cannot a priori determine the size, so we take the maximum possible */
1244  startZnblocknonz[b] = blocksize * (blocksize + 1) / 2;
1245  }
1246  else
1247  {
1248  startZnblocknonz[b] = SCIPconsSdpComputeUbSparseSdpMatrixLength(sdpblocks[b]);
1249 
1250  /* since we take a convex combination with either the identity matrix or the analytic center, we have to allocate memory for that as well */
1251  if ( SCIPisGT(scip, relaxdata->warmstartipfactor, 0.0) )
1252  {
1253  if ( relaxdata->warmstartiptype == 1 )
1254  startZnblocknonz[b] += blocksize;
1255  else if ( relaxdata->warmstartiptype == 2 )
1256  startZnblocknonz[b] += relaxdata->ipZnblocknonz[b];
1257  }
1258  }
1259 
1260  SCIP_CALL( SCIPallocBufferArray(scip, &startZrow[b], startZnblocknonz[b]) );
1261  SCIP_CALL( SCIPallocBufferArray(scip, &startZcol[b], startZnblocknonz[b]) );
1262  SCIP_CALL( SCIPallocBufferArray(scip, &startZval[b], startZnblocknonz[b]) );
1263 
1264  /* compute Z matrix */
1265  SCIP_CALL( SCIPconsSdpComputeSparseSdpMatrix(scip, sdpblocks[b], dualsol, &(startZnblocknonz[b]), startZrow[b], startZcol[b], startZval[b]) );
1266 
1267  /* compute projection onto psd cone (computed as U * diag(lambda_i_+) * U^T where U consists of the eigenvectors of the matrix) */
1268  if ( relaxdata->warmstartproject == 3 )
1269  {
1270  SCIP_Real* fullZmatrix;
1271  SCIP_Real* eigenvalues;
1272  SCIP_Real* eigenvectors;
1273  SCIP_Real* scaledeigenvectors;
1274  SCIP_Real epsilon;
1275  int matrixsize;
1276  int c;
1277  int matrixpos;
1278 
1279  matrixsize = blocksize * blocksize;
1280 
1281  SCIP_CALL( SCIPallocBufferArray(scip, &fullZmatrix, matrixsize) );
1282  SCIP_CALL( SCIPallocBufferArray(scip, &eigenvalues, blocksize) );
1283  SCIP_CALL( SCIPallocBufferArray(scip, &eigenvectors, matrixsize) );
1284 
1285  SCIP_CALL( expandSparseMatrix(startZnblocknonz[b], blocksize, startZrow[b], startZcol[b], startZval[b], fullZmatrix) );
1286 
1287  SCIP_CALL( SCIPlapackComputeEigenvectorDecomposition(SCIPbuffer(scip), blocksize, fullZmatrix, eigenvalues, eigenvectors) );
1288 
1289  /* duplicate memory of eigenvectors to compute diag(lambda_i_+) * U^T */
1290  SCIP_CALL( SCIPduplicateBufferArray(scip, &scaledeigenvectors, eigenvectors, matrixsize) );
1291 
1292  /* set all negative eigenvalues to zero (using the property that LAPACK returns them in ascending order) */
1293  i = 0;
1294  while (i < blocksize && SCIPisLT(scip, eigenvalues[i], relaxdata->warmstartprojminevdual) )
1295  {
1296  eigenvalues[i] = relaxdata->warmstartprojminevdual;
1297  i++;
1298  }
1299 
1300  /* compute diag(lambda_i_+) * U^T */
1301  SCIP_CALL( scaleTransposedMatrix(blocksize, scaledeigenvectors, eigenvalues) );
1302 
1303  /* compute U * [diag(lambda_i_+) * U^T] (note that transposes are switched because LAPACK uses column-first-format) */
1304  SCIP_CALL( SCIPlapackMatrixMatrixMult(blocksize, blocksize, eigenvectors, TRUE, blocksize, blocksize, scaledeigenvectors,
1305  FALSE, fullZmatrix) );
1306 
1307  /* extract sparse matrix from projection */
1308  startZnblocknonz[b] = 0;
1309  epsilon = SCIPepsilon(scip);
1310  for (r = 0; r < blocksize; r++)
1311  {
1312  for (c = r; c < blocksize; c++)
1313  {
1314  matrixpos = r * blocksize + c;
1315  if ( REALABS(fullZmatrix[matrixpos]) > epsilon )
1316  {
1317  startZrow[b][startZnblocknonz[b]] = r;
1318  startZcol[b][startZnblocknonz[b]] = c;
1319  startZval[b][startZnblocknonz[b]] = fullZmatrix[matrixpos];
1320  startZnblocknonz[b]++;
1321  }
1322  }
1323  }
1324 
1325  /* free memory */
1326  SCIPfreeBufferArray(scip, &scaledeigenvectors);
1327  SCIPfreeBufferArray(scip, &eigenvectors);
1328  SCIPfreeBufferArray(scip, &eigenvalues);
1329  SCIPfreeBufferArray(scip, &fullZmatrix);
1330  }
1331 
1332  if ( relaxdata->warmstartprimaltype == 1 )
1333  {
1334  /* we set X to maxprimalentry times the identity matrix */
1335  if ( relaxdata->warmstartiptype == 1 )
1336  {
1337  startXnblocknonz[b] = blocksize;
1338  SCIP_CALL( SCIPallocBufferArray(scip, &startXrow[b], startXnblocknonz[b]) );
1339  SCIP_CALL( SCIPallocBufferArray(scip, &startXcol[b], startXnblocknonz[b]) );
1340  SCIP_CALL( SCIPallocBufferArray(scip, &startXval[b], startXnblocknonz[b]) );
1341  for (i = 0; i < startXnblocknonz[b]; i++)
1342  {
1343  startXrow[b][i] = i;
1344  startXcol[b][i] = i;
1345  startXval[b][i] = maxprimalentry;
1346  }
1347  }
1348  }
1349  else if ( relaxdata->warmstartprimaltype == 2 )
1350  {
1351  startXnblocknonz[b] = startZnblocknonz[b];
1352  SCIP_CALL( SCIPallocBufferArray(scip, &startXrow[b], startXnblocknonz[b]) );
1353  SCIP_CALL( SCIPallocBufferArray(scip, &startXcol[b], startXnblocknonz[b]) );
1354  SCIP_CALL( SCIPallocBufferArray(scip, &startXval[b], startXnblocknonz[b]) );
1355  for (i = 0; i < startZnblocknonz[b]; i++)
1356  {
1357  startXrow[b][i] = startZrow[b][i];
1358  startXcol[b][i] = startZcol[b][i];
1359  startXval[b][i] = 1 / startZval[b][i];
1360  }
1361  }
1362  else if ( relaxdata->warmstartprimaltype != 3 && relaxdata->warmstartproject != 4 )
1363  {
1364  SCIPerrorMessage("Unknown value %d for warmstartprimaltype.\n", relaxdata->warmstartprimaltype);
1365  SCIPABORT();
1366  }
1367  }
1368 
1369  if ( relaxdata->warmstartproject != 4 )
1370  {
1371  /* fill LP-block */
1372  SCIP_CALL( SCIPallocBufferArray(scip, &startZrow[b], 2 * nrows + 2 * nvars) );
1373  SCIP_CALL( SCIPallocBufferArray(scip, &startZcol[b], 2 * nrows + 2 * nvars) );
1374  SCIP_CALL( SCIPallocBufferArray(scip, &startZval[b], 2 * nrows + 2 * nvars) );
1375  SCIP_CALL( SCIPallocBufferArray(scip, &startXrow[b], 2 * nrows + 2 * nvars) );
1376  SCIP_CALL( SCIPallocBufferArray(scip, &startXcol[b], 2 * nrows + 2 * nvars) );
1377  SCIP_CALL( SCIPallocBufferArray(scip, &startXval[b], 2 * nrows + 2 * nvars) );
1378 
1379  /* to get a positive definite matrix, all the entries need to be strictly positive */
1380  startZnblocknonz[b] = 2 * nrows + 2 * nvars;
1381  startXnblocknonz[b] = 2 * nrows + 2 * nvars;
1382 
1383  for (r = 0; r < nrows; r++)
1384  {
1385  /* compute row value for current solution */
1386  rowval = 0.0;
1387  rownnonz = SCIProwGetNNonz(rows[r]);
1388  rowvals = SCIProwGetVals(rows[r]);
1389  rowcols = SCIProwGetCols(rows[r]);
1390  for (i = 0; i < rownnonz; i++)
1391  rowval += SCIPgetSolVal(scip, dualsol, SCIPcolGetVar(rowcols[i])) * rowvals[i];
1392 
1393  startZrow[b][2*r] = 2*r;
1394  startZcol[b][2*r] = 2*r;
1395  startZval[b][2*r] = rowval - (SCIProwGetLhs(rows[r]) - SCIProwGetConstant(rows[r]));
1396 
1397  if ( relaxdata->warmstartiptype == 1 && relaxdata->warmstartproject == 3 && SCIPisLT(scip, startZval[b][2*r], relaxdata->warmstartprojminevdual) )
1398  startZval[b][2*r] = relaxdata->warmstartprojminevdual;
1399  /* we only take the convex combination if the value is less than one, since the maxblockentry is equal to the value
1400  * otherwise, so taking the convex combination doesn't change anything in that case
1401  */
1402  else if ( relaxdata->warmstartiptype == 1 && SCIPisLT(scip, startZval[b][2*r], 1.0) )
1403  {
1404  /* since we want the value to be strictly positive, if the original entry is negative we just set it to warmstartipfactor */
1405  if ( SCIPisLT(scip, startZval[b][2*r], 0.0) )
1406  startZval[b][2*r] = relaxdata->warmstartipfactor;
1407  else
1408  startZval[b][2*r] = (1 - relaxdata->warmstartipfactor) * startZval[b][2*r] + relaxdata->warmstartipfactor;
1409  }
1410  else if ( relaxdata->warmstartiptype == 2 )
1411  {
1412  startZval[b][2*r] = (1 - relaxdata->warmstartipfactor) * startZval[b][2*r] + relaxdata->warmstartipfactor * relaxdata->ipZval[b][2*r];
1413 
1414  /* if this is non-positive, we shift it to a strictly positive value */
1415  if ( SCIPisLT(scip, startZval[b][2*r], WARMSTART_MINVAL) )
1416  startZval[b][2*r] = WARMSTART_MINVAL;
1417  }
1418 
1419  if ( relaxdata->warmstartpreoptsol && startZval[b][2*r] < WARMSTART_PREOPT_MIN_Z_LPVAL )
1420  startZval[b][2*r] = WARMSTART_PREOPT_MIN_Z_LPVAL;
1421 
1422  startZrow[b][2*r + 1] = 2*r + 1;
1423  startZcol[b][2*r + 1] = 2*r + 1;
1424  startZval[b][2*r + 1] = SCIProwGetRhs(rows[r]) - SCIProwGetConstant(rows[r]) - rowval;
1425 
1426  if ( relaxdata->warmstartiptype == 1 && relaxdata->warmstartproject == 3 && SCIPisLT(scip, startZval[b][2*r + 1], relaxdata->warmstartprojminevdual) )
1427  startZval[b][2*r + 1] = relaxdata->warmstartprojminevdual;
1428  else if ( relaxdata->warmstartiptype == 1 && SCIPisLT(scip, startZval[b][2*r + 1], 1.0) )
1429  {
1430  /* since we want the value to be strictly positive, if the original entry is negative we just set it to warmstartipfactor */
1431  if ( SCIPisLT(scip, startZval[b][2*r + 1], 0.0) )
1432  startZval[b][2*r + 1] = relaxdata->warmstartipfactor;
1433  else
1434  startZval[b][2*r + 1] = (1 - relaxdata->warmstartipfactor) * startZval[b][2*r + 1] + relaxdata->warmstartipfactor;
1435  }
1436  else if ( relaxdata->warmstartiptype == 2 )
1437  {
1438  startZval[b][2*r + 1] = (1 - relaxdata->warmstartipfactor) * startZval[b][2*r + 1] + relaxdata->warmstartipfactor * relaxdata->ipZval[b][2*r + 1];
1439 
1440  /* if this is non-positive, we shift it to a strictly positive value */
1441  if ( SCIPisLT(scip, startZval[b][2*r + 1], WARMSTART_MINVAL) )
1442  startZval[b][2*r + 1] = WARMSTART_MINVAL;
1443  }
1444 
1445  if ( relaxdata->warmstartpreoptsol && startZval[b][2*r + 1] < WARMSTART_PREOPT_MIN_Z_LPVAL )
1446  startZval[b][2*r + 1] = WARMSTART_PREOPT_MIN_Z_LPVAL;
1447 
1448  if ( relaxdata->warmstartprimaltype == 1 && relaxdata->warmstartiptype == 1 )
1449  {
1450  startXrow[b][2*r] = 2*r;
1451  startXcol[b][2*r] = 2*r;
1452  startXval[b][2*r] = maxprimalentry;
1453  startXrow[b][2*r + 1] = 2*r + 1;
1454  startXcol[b][2*r + 1] = 2*r + 1;
1455  startXval[b][2*r + 1] = maxprimalentry;
1456  }
1457  else if ( relaxdata->warmstartprimaltype == 2 )
1458  {
1459  startXrow[b][2*r] = startZrow[b][2*r];
1460  startXcol[b][2*r] = startZcol[b][2*r];
1461  startXval[b][2*r] = 1 / startZval[b][2*r];
1462  startXrow[b][2*r + 1] = startZrow[b][2*r + 1];
1463  startXcol[b][2*r + 1] = startZcol[b][2*r + 1];
1464  startXval[b][2*r + 1] = 1 / startZval[b][2*r + 1];
1465  }
1466  else if ( relaxdata->warmstartprimaltype != 3 && relaxdata->warmstartiptype == 1 )
1467  {
1468  SCIPerrorMessage("Unknown value %d for warmstartprimaltype.\n", relaxdata->warmstartprimaltype);
1469  SCIPABORT();
1470  }
1471  }
1472 
1473  for (v = 0; v < nvars; v++)
1474  {
1475  startZrow[b][2*nrows + 2*v] = 2*nrows + 2*v;
1476  startZcol[b][2*nrows + 2*v] = 2*nrows + 2*v;
1477  startZval[b][2*nrows + 2*v] = SCIPgetSolVal(scip, dualsol, vars[v]) - SCIPvarGetLbLocal(vars[v]);
1478  if ( relaxdata->warmstartiptype == 1 && relaxdata->warmstartproject == 3 && SCIPisLT(scip, startZval[b][2*nrows + 2*v], relaxdata->warmstartprojminevdual) )
1479  startZval[b][2*nrows + 2*v] = relaxdata->warmstartprojminevdual;
1480  else if ( relaxdata->warmstartiptype == 1 && SCIPisLT(scip, startZval[b][2*nrows + 2*v], 1.0) )
1481  {
1482  /* since we want the value to be strictly positive, if the original entry is negative we just set it to warmstartipfactor */
1483  if ( SCIPisLT(scip, startZval[b][2*nrows + 2*v], 0.0) )
1484  startZval[b][2*nrows + 2*v] = relaxdata->warmstartipfactor;
1485  else
1486  startZval[b][2*nrows + 2*v] = (1 - relaxdata->warmstartipfactor) * startZval[b][2*nrows + 2*v] + relaxdata->warmstartipfactor;
1487  }
1488  else if ( relaxdata->warmstartiptype == 2 )
1489  {
1490  startZval[b][2*nrows + 2*v] = (1 - relaxdata->warmstartipfactor) * startZval[b][2*nrows + 2*v] + relaxdata->warmstartipfactor * relaxdata->ipZval[b][2*nrows + 2*v];
1491 
1492  /* if this is non-positive, we shift it to a strictly positive value */
1493  if ( SCIPisLT(scip, startZval[b][2*nrows + 2*v], WARMSTART_MINVAL) )
1494  startZval[b][2*nrows + 2*v] = WARMSTART_MINVAL;
1495  }
1496 
1497  if ( relaxdata->warmstartpreoptsol && startZval[b][2*nrows + 2*v] < WARMSTART_PREOPT_MIN_Z_LPVAL )
1498  startZval[b][2*nrows + 2*v] = WARMSTART_PREOPT_MIN_Z_LPVAL;
1499 
1500  startZrow[b][2*nrows + 2*v + 1] = 2*nrows + 2*v + 1;
1501  startZcol[b][2*nrows + 2*v + 1] = 2*nrows + 2*v + 1;
1502  startZval[b][2*nrows + 2*v + 1] = SCIPvarGetUbLocal(vars[v]) - SCIPgetSolVal(scip, dualsol, vars[v]);
1503  if ( relaxdata->warmstartiptype == 1 && relaxdata->warmstartproject == 3 && SCIPisLT(scip, startZval[b][2*nrows + 2*v + 1], relaxdata->warmstartprojminevdual) )
1504  startZval[b][2*nrows + 2*v + 1] = relaxdata->warmstartprojminevdual;
1505  else if ( relaxdata->warmstartiptype == 1 && SCIPisLT(scip, startZval[b][2*nrows + 2*v + 1], 1.0) )
1506  {
1507  /* since we want the value to be strictly positive, if the original entry is negative we just set it to warmstartipfactor */
1508  if ( SCIPisLT(scip, startZval[b][2*nrows + 2*v + 1], 0.0) )
1509  startZval[b][2*nrows + 2*v + 1] = relaxdata->warmstartipfactor;
1510  else
1511  startZval[b][2*nrows + 2*v + 1] = (1 - relaxdata->warmstartipfactor) * startZval[b][2*nrows + 2*v + 1] + relaxdata->warmstartipfactor;
1512  }
1513  else if ( relaxdata->warmstartiptype == 2 )
1514  {
1515  startZval[b][2*nrows + 2*v + 1] = (1 - relaxdata->warmstartipfactor) * startZval[b][2*nrows + 2*v] + relaxdata->warmstartipfactor * relaxdata->ipZval[b][2*nrows + 2*v + 1];
1516 
1517  /* if this is non-positive, we shift it to a strictly positive value */
1518  if ( SCIPisLT(scip, startZval[b][2*nrows + 2*v + 1], WARMSTART_MINVAL) )
1519  startZval[b][2*nrows + 2*v + 1] = WARMSTART_MINVAL;
1520  }
1521 
1522  if ( relaxdata->warmstartpreoptsol && startZval[b][2*nrows + 2*v + 1] < WARMSTART_PREOPT_MIN_Z_LPVAL )
1523  startZval[b][2*nrows + 2*v + 1] = WARMSTART_PREOPT_MIN_Z_LPVAL;
1524 
1525  if ( relaxdata->warmstartprimaltype == 1 && relaxdata->warmstartiptype == 1 )
1526  {
1527  startXrow[b][2*nrows + 2*v] = 2*nrows + 2*v;
1528  startXcol[b][2*nrows + 2*v] = 2*nrows + 2*v;
1529  startXval[b][2*nrows + 2*v] = maxprimalentry;
1530  startXrow[b][2*nrows + 2*v + 1] = 2*nrows + 2*v + 1;
1531  startXcol[b][2*nrows + 2*v + 1] = 2*nrows + 2*v + 1;
1532  startXval[b][2*nrows + 2*v + 1] = maxprimalentry;
1533  }
1534  else if ( relaxdata->warmstartprimaltype == 2 )
1535  {
1536  startXrow[b][2*nrows + 2*v] = startZrow[b][2*nrows + 2*v];
1537  startXcol[b][2*nrows + 2*v] = startZcol[b][2*nrows + 2*v];
1538  startXval[b][2*nrows + 2*v] = 1 / startZval[b][2*nrows + 2*v];
1539  startXrow[b][2*nrows + 2*v + 1] = startZrow[b][2*nrows + 2*v + 1];
1540  startXcol[b][2*nrows + 2*v + 1] = startZcol[b][2*nrows + 2*v + 1];
1541  startXval[b][2*nrows + 2*v + 1] = 1 / startZval[b][2*nrows + 2*v + 1];
1542  }
1543  else if ( relaxdata->warmstartprimaltype != 3 && relaxdata->warmstartproject == 1 )
1544  {
1545  SCIPerrorMessage("Unknown value %d for warmstartprimaltype.\n", relaxdata->warmstartprimaltype);
1546  SCIPABORT();
1547  }
1548  }
1549  }
1550 
1551  /* Solve the primal rounding problem
1552  * \f{eqnarray*}{
1553  * \max & & \sum_{k \in K} A_0^{(k)} \bullet (V^{(k)} \text{diag}(\lambda^{(k)}) (V^{(k)})^T) + \sum_{j \in J} c_j x_j - \sum_{i \in I_u} u_i v_i + \sum_{i \in I_\ell} \ell_i w_i \\
1554  * \mbox{s.t.} & & \sum_{k \in K} A_i^{(k)} \bullet (V^{(k)} \text{diag}(\lambda^{(k)}) (V^{(k)})^T) + \sum_{j \in J} d_{ij} x_j - 1_{\{u_i < \infty\}} v_i + 1_{\{\ell_i > -\infty\}} w_i = b_i \quad \forall \ i \in I,\\
1555  * & & \lambda^{(k)}_i \geq 0 \quad \forall \ k \in K, i \leq n \\
1556  * & & x_j \geq 0 \quad \forall \ j \in J,\\
1557  * & & v_i \geq 0 \quad \forall \ i \in I_u,\\
1558  * & & w_i \geq 0 \quad \forall \ i \in I_\ell,
1559  * \f}
1560  * where \f$ V^{(k)} \text{diag}(\bar{\lambda}^{(k)}) (V^{(k)})^T \f$ is an eigenvector decomposition of the optimal primal solution
1561  * of the parent node, as well as the dual rounding problem
1562  * \f{eqnarray*}{
1563  * \min & & b^T y \\
1564  * \mbox{s.t.} & & \sum_{i \in I} d_{ij} y_i \geq c_j \quad \forall \ j \in J, \\
1565  * & & \sum_{i \in I} A_i^{(k)} y_i - A_0^{(k)} = V^{(k)} \text{diag}(\lambda^{(k)}) (V^{(k)})^T \quad \forall \ k \in K, \\
1566  * & & \ell_i \leq y_i \leq u_i \quad \forall \ i \in I, \\
1567  * & & \lambda^{(k)}_i \geq 0 \quad \forall \ k \in K, i \leq n \\
1568  * \f}
1569  * where \f$ V^{(k)} \text{diag}(\bar{\lambda}^{(k)}) (V^{(k)})^T \f$ is now an eigenvector decomposition of the optimal solution
1570  * of the parent node for the dual problem. The matrix equation is reformulated as blocksize * (blocksize + 1) /2 linear constraints
1571  * over the lower triangular entries.
1572  */
1573  if ( relaxdata->warmstartproject == 4 )
1574  {
1575  SCIP_VAR** blockvars;
1576  SCIP_LPI* lpi;
1577  SCIP_ROW* row;
1578  SCIP_Real** blockval;
1579  SCIP_Real** blockeigenvalues;
1580  SCIP_Real** blockeigenvectors;
1581  SCIP_Real** blockrowvals;
1582  SCIP_Real* obj;
1583  SCIP_Real* lb;
1584  SCIP_Real* ub;
1585  SCIP_Real* lhs;
1586  SCIP_Real* rhs;
1587  SCIP_Real* val;
1588  SCIP_Real* blockconstval;
1589  SCIP_Real* scaledeigenvectors;
1590  SCIP_Real* fullXmatrix;
1591  SCIP_Real* fullZmatrix;
1592  SCIP_Real rowlhs;
1593  SCIP_Real rowrhs;
1594  SCIP_Real varobj;
1595  SCIP_Real epsilon;
1596  SCIP_Real primalroundobj;
1597  SCIP_Real dualroundobj;
1598  int** blockcol;
1599  int** blockrow;
1600  int** blockrowcols;
1601  int* beg;
1602  int* ind;
1603  int* blocknvarnonz;
1604  int* blockconstcol;
1605  int* blockconstrow;
1606  int* blocksizes;
1607  int* nblockrownonz;
1608  int* rowinds;
1609  int pos;
1610  int indpos;
1611  int startpos;
1612  int blocknvars;
1613  int blocknnonz;
1614  int arraylength;
1615  int blockconstnnonz;
1616  int varind;
1617  int roundingvars;
1618  int matrixsize;
1619  int evind;
1620  int c;
1621  int matrixpos;
1622  int nroundingrows;
1623  int j;
1624  int nremovedentries;
1625 
1626  /* since the main purpose of the rounding problem approach is detecting infeasibility through the restricted primal problem,
1627  * it doesn't make sense to use this approach unless the whole primal solution is saved */
1628  if ( relaxdata->warmstartprimaltype != 3 )
1629  {
1630  SCIPerrorMessage("Invalid parameter combination, use relax/warmstartproject = 4 only with relax/warmstartprimaltype = 3.\n");
1631  return SCIP_PARAMETERWRONGVAL;
1632  }
1633 
1634  SCIP_CALL( SCIPstartClock(scip, relaxdata->roundingprobtime) );
1635 
1636  /* since we cannot compute the number of nonzeros of the solution of the rounding problem beforehand, we allocate the maximum possible (blocksize * (blocksize + 1) / 2 */
1637  for (b = 0; b < nblocks; b++)
1638  {
1639  matrixsize = SCIPconsSdpGetBlocksize(scip, sdpblocks[b]);
1640  matrixsize = (matrixsize * (matrixsize + 1)) / 2;
1641  startXnblocknonz[b] = matrixsize;
1642 
1643  SCIP_CALL( SCIPallocBufferArray(scip, &startXrow[b], matrixsize) );
1644  SCIP_CALL( SCIPallocBufferArray(scip, &startXcol[b], matrixsize) );
1645  SCIP_CALL( SCIPallocBufferArray(scip, &startXval[b], matrixsize) );
1646  }
1647 
1648  /* allocate memory for LP and variable bound block of warmstart matrix (note that we need to allocate the maximum, since additional
1649  * entries may be generated through the convex combination */
1650  SCIP_CALL( SCIPallocBufferArray(scip, &startXrow[nblocks], 2 * nvars + 2 * nrows) );
1651  SCIP_CALL( SCIPallocBufferArray(scip, &startXcol[nblocks], 2 * nvars + 2 * nrows) );
1652  SCIP_CALL( SCIPallocBufferArray(scip, &startXval[nblocks], 2 * nvars + 2 * nrows) );
1653  startXnblocknonz[nblocks] = 2 * nvars + 2 * nrows;
1654 
1655  SCIP_CALL( SCIPconsSavesdpsolGetPrimalMatrix(scip, conss[parentconsind], nblocks + 1, startXnblocknonz, startXrow, startXcol, startXval) );
1656 
1657  lpi = relaxdata->lpi;
1658 
1659  /* clear the old LP */
1660  SCIP_CALL( SCIPlpiClear(lpi) );
1661 
1662  /* we want to maximize for the primal rounding problem */
1663  SCIP_CALL( SCIPlpiChgObjsen(lpi, SCIP_OBJSEN_MAXIMIZE) );
1664 
1665  /* if the varmapper has a different number of variables than SCIP, we might get problems with empty spots in the obj/lb/ub arrays */
1666  assert( SCIPsdpVarmapperGetNVars(relaxdata->varmapper) == nvars );
1667 
1668  /* initialize the rows */
1669  SCIP_CALL( SCIPallocBufferArray(scip, &lhs, nvars) );
1670  SCIP_CALL( SCIPallocBufferArray(scip, &rhs, nvars) );
1671  for (v = 0; v < nvars; v++)
1672  {
1673  varobj = SCIPvarGetObj(vars[v]);
1674  lhs[SCIPsdpVarmapperGetSdpIndex(relaxdata->varmapper, vars[v])] = varobj;
1675  rhs[SCIPsdpVarmapperGetSdpIndex(relaxdata->varmapper, vars[v])] = varobj;
1676  }
1677 
1678  /* this vector will be used to later map the solution to the correspoding blocks */
1679  SCIP_CALL( SCIPallocBufferArray(scip, &blocksizes, nblocks + 2) );
1680  SCIP_CALL( SCIPallocBufferArray(scip, &blockeigenvalues, nblocks) );
1681  SCIP_CALL( SCIPallocBufferArray(scip, &blockeigenvectors, nblocks) );
1682 
1683  /* initialize rows; columns will be added blockwise later (note that we reenter the whole problem each time
1684  * and do not allow warmstarts, we could store the LP- and bound-constraints between nodes (TODO, but would
1685  * need to check for added/removed cuts then), but warmstarting doesn't seem to make sense since the whole
1686  * SDP part is changed, which should form the main difficulty when solving (MI)SDPs */
1687  SCIP_CALL( SCIPlpiAddRows(lpi, nvars, lhs, rhs, NULL, 0, NULL, NULL, NULL) );
1688 
1689  SCIPfreeBufferArray(scip, &rhs);
1690  SCIPfreeBufferArray(scip, &lhs);
1691 
1692  /* add columns corresponding to bound constraints (at most we get two entries [lb & ub] per variable) */
1693  SCIP_CALL( SCIPallocBufferArray(scip, &obj, 2*nvars) );
1694  SCIP_CALL( SCIPallocBufferArray(scip, &lb, 2*nvars) );
1695  SCIP_CALL( SCIPallocBufferArray(scip, &ub, 2*nvars) );
1696  SCIP_CALL( SCIPallocBufferArray(scip, &beg, 2*nvars) );
1697  SCIP_CALL( SCIPallocBufferArray(scip, &ind, 2*nvars) );
1698  SCIP_CALL( SCIPallocBufferArray(scip, &val, 2*nvars) );
1699 
1700  /* iterate over all finite variable bounds and set the corresponding entries */
1701  pos = 0;
1702  for (v = 0; v < nvars; v++)
1703  {
1704  if ( ! SCIPisInfinity(scip, -1 * SCIPvarGetLbLocal(vars[v])) )
1705  {
1706  obj[pos] = SCIPvarGetLbLocal(vars[v]);
1707  lb[pos] = 0.0;
1708  ub[pos] = SCIPlpiInfinity(lpi);
1709  beg[pos] = pos;
1710  ind[pos] = SCIPsdpVarmapperGetSdpIndex(relaxdata->varmapper, vars[v]);
1711  val[pos] = 1.0;
1712  pos++;
1713  }
1714  if ( ! SCIPisInfinity(scip, SCIPvarGetUbLocal(vars[v])) )
1715  {
1716  obj[pos] = -1 * SCIPvarGetUbLocal(vars[v]);
1717  lb[pos] = 0.0;
1718  ub[pos] = SCIPlpiInfinity(lpi);
1719  beg[pos] = pos;
1720  ind[pos] = SCIPsdpVarmapperGetSdpIndex(relaxdata->varmapper, vars[v]);
1721  val[pos] = -1.0;
1722  pos++;
1723  }
1724  }
1725 
1726  SCIP_CALL( SCIPlpiAddCols(lpi, pos, obj, lb, ub, NULL, pos, beg, ind, val) );
1727  blocksizes[0] = pos;
1728  roundingvars = pos;
1729 
1730  SCIPfreeBufferArray(scip, &val);
1731  SCIPfreeBufferArray(scip, &ind);
1732  SCIPfreeBufferArray(scip, &beg);
1733  SCIPfreeBufferArray(scip, &ub);
1734  SCIPfreeBufferArray(scip, &lb);
1735  SCIPfreeBufferArray(scip, &obj);
1736 
1737  /* add columns corresponding to linear constraints (at most we get two columns per ranged row) */
1738  SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
1739 
1740  SCIP_CALL( SCIPallocBufferArray(scip, &obj, 2*nrows) );
1741  SCIP_CALL( SCIPallocBufferArray(scip, &lb, 2*nrows) );
1742  SCIP_CALL( SCIPallocBufferArray(scip, &ub, 2*nrows) );
1743  SCIP_CALL( SCIPallocBufferArray(scip, &beg, 2*nrows) );
1744  SCIP_CALL( SCIPallocBufferArray(scip, &ind, 2*nrows*nvars) );
1745  SCIP_CALL( SCIPallocBufferArray(scip, &val, 2*nrows*nvars) );
1746 
1747  pos = 0;
1748  indpos = 0;
1749  /* iterate over all LP-ranged-rows and add corresponding entries if lhs and/or rhs is finite */
1750  for (r = 0; r < nrows; r++)
1751  {
1752  row = rows[r];
1753  assert( row != 0 );
1754  rownnonz = SCIProwGetNNonz(row);
1755 
1756  rowvals = SCIProwGetVals(row);
1757  rowcols = SCIProwGetCols(row);
1758  rowlhs = SCIProwGetLhs(row) - SCIProwGetConstant(row);
1759  rowrhs = SCIProwGetRhs(row) - SCIProwGetConstant(row);
1760 
1761  if ( ! SCIPisInfinity(scip, -1 * rowlhs) )
1762  {
1763  obj[pos] = rowlhs;
1764  lb[pos] = 0.0;
1765  ub[pos] = SCIPlpiInfinity(lpi);
1766  beg[pos] = indpos;
1767  for (i = 0; i < rownnonz; i++)
1768  {
1769  ind[indpos] = SCIPsdpVarmapperGetSdpIndex(relaxdata->varmapper, SCIPcolGetVar(rowcols[i]));
1770  val[indpos] = rowvals[i];
1771  indpos++;
1772  }
1773  pos++;
1774  }
1775  /* since we assume >= constraints in the dual, we have to multiply all entries of <= constraints by -1 */
1776  if ( ! SCIPisInfinity(scip, rowrhs) )
1777  {
1778  obj[pos] = -1 * rowrhs;
1779  lb[pos] = 0.0;
1780  ub[pos] = SCIPlpiInfinity(lpi);
1781  beg[pos] = indpos;
1782  for (i = 0; i < rownnonz; i++)
1783  {
1784  ind[indpos] = SCIPsdpVarmapperGetSdpIndex(relaxdata->varmapper, SCIPcolGetVar(rowcols[i]));
1785  val[indpos] = -1 * rowvals[i];
1786  indpos++;
1787  }
1788  pos++;
1789  }
1790  }
1791 
1792  SCIP_CALL( SCIPlpiAddCols(lpi, pos, obj, lb, ub, NULL, indpos, beg, ind, val) );
1793  blocksizes[1] = pos;
1794  roundingvars += pos;
1795 
1796  SCIPfreeBufferArray(scip, &val);
1797  SCIPfreeBufferArray(scip, &ind);
1798  SCIPfreeBufferArray(scip, &beg);
1799  SCIPfreeBufferArray(scip, &ub);
1800  SCIPfreeBufferArray(scip, &lb);
1801  SCIPfreeBufferArray(scip, &obj);
1802 
1803  /* finally add columns corresponding to SDP-constraints */
1804  for (b = 0; b < nblocks; b++)
1805  {
1806  /* get data for this SDP block */
1807  SCIP_CALL( SCIPconsSdpGetNNonz(scip, sdpblocks[b], NULL, &blockconstnnonz) );
1808  SCIP_CALL( SCIPallocBufferArray(scip, &blocknvarnonz, nvars) );
1809  SCIP_CALL( SCIPallocBufferArray(scip, &blockcol, nvars) );
1810  SCIP_CALL( SCIPallocBufferArray(scip, &blockrow, nvars) );
1811  SCIP_CALL( SCIPallocBufferArray(scip, &blockval, nvars) );
1812  SCIP_CALL( SCIPallocBufferArray(scip, &blockvars, nvars) );
1813  SCIP_CALL( SCIPallocBufferArray(scip, &blockconstcol, blockconstnnonz) );
1814  SCIP_CALL( SCIPallocBufferArray(scip, &blockconstrow, blockconstnnonz) );
1815  SCIP_CALL( SCIPallocBufferArray(scip, &blockconstval, blockconstnnonz) );
1816 
1817  arraylength = nvars;
1818  SCIP_CALL( SCIPconsSdpGetData(scip, sdpblocks[b], &blocknvars, &blocknnonz, &blocksize, &arraylength, blocknvarnonz,
1819  blockcol, blockrow, blockval, blockvars, &blockconstnnonz, blockconstcol, blockconstrow, blockconstval, NULL, NULL, NULL) );
1820  assert( arraylength == nvars ); /* arraylength should alwys be sufficient */
1821 
1822  matrixsize = blocksize * blocksize;
1823 
1824  SCIP_CALL( SCIPallocBufferArray(scip, &fullXmatrix, matrixsize) );
1825  SCIP_CALL( SCIPallocBufferArray(scip, &blockeigenvalues[b], blocksize) );
1826  SCIP_CALL( SCIPallocBufferArray(scip, &blockeigenvectors[b], matrixsize) );
1827 
1828  SCIP_CALL( expandSparseMatrix(startXnblocknonz[b], blocksize, startXrow[b], startXcol[b], startXval[b], fullXmatrix) );
1829 
1830  SCIP_CALL( SCIPlapackComputeEigenvectorDecomposition(SCIPbuffer(scip), blocksize, fullXmatrix, blockeigenvalues[b], blockeigenvectors[b]) );
1831 
1832  /* compute coefficients for rounding problems, we get blocksize many variables corresponding to the eigenvalues of X* */
1833  SCIP_CALL( SCIPallocBufferArray(scip, &obj, blocksize) );
1834  SCIP_CALL( SCIPallocBufferArray(scip, &lb, blocksize) );
1835  SCIP_CALL( SCIPallocBufferArray(scip, &ub, blocksize) );
1836  SCIP_CALL( SCIPallocBufferArray(scip, &beg, blocksize) );
1837  SCIP_CALL( SCIPallocBufferArray(scip, &ind, blocksize*nvars) );
1838  SCIP_CALL( SCIPallocBufferArray(scip, &val, blocksize*nvars) );
1839 
1840  /* initialize arrays */
1841  for (i = 0; i < blocksize; i++)
1842  {
1843  obj[i] = 0.0;
1844  beg[i] = i * nvars;
1845 
1846  for (v = 0; v < nvars; v++)
1847  {
1848  ind[i * nvars + v] = v;
1849  val[i * nvars + v] = 0.0;
1850  }
1851 
1852  /* make all eigenvalues non-negative, so that matrix stays positive semidefinite */
1853  lb[i] = 0.0;
1854  ub[i] = SCIPlpiInfinity(lpi);
1855  }
1856 
1857  /* iterate over constant entries to compute objective coefficients */
1858  for (i = 0; i < blockconstnnonz; i++)
1859  {
1860  /* for every constant matrix entry (k,l) and every eigenvector i, we get an entry A_kl * V_ki *V_li
1861  * entry V_ki corresponds to entry k of the i-th eigenvector, which is given as the i-th row of the eigenvectors array
1862  * note that we need to mulitply by two for non-diagonal entries to also account for entry (l,k) */
1863  for (evind = 0; evind < blocksize; evind++)
1864  {
1865  if ( blockconstrow[i] == blockconstcol[i] )
1866  obj[evind] += blockconstval[i] * blockeigenvectors[b][evind * blocksize + blockconstrow[i]] * blockeigenvectors[b][evind * blocksize + blockconstcol[i]];
1867  else
1868  obj[evind] += 2 * blockconstval[i] * blockeigenvectors[b][evind * blocksize + blockconstrow[i]] * blockeigenvectors[b][evind * blocksize + blockconstcol[i]];
1869  }
1870  }
1871 
1872  SCIPfreeBufferArray(scip, &blockconstval);
1873  SCIPfreeBufferArray(scip, &blockconstrow);
1874  SCIPfreeBufferArray(scip, &blockconstcol);
1875 
1876  /* compute constraint coefficients */
1877  for (v = 0; v < blocknvars; v++)
1878  {
1879  varind = SCIPsdpVarmapperGetSdpIndex(relaxdata->varmapper, blockvars[v]);
1880  for (i = 0; i < blocknvarnonz[v]; i++)
1881  {
1882  /* for every matrix entry (k,l) and every eigenvector i, we get an entry A_kl * V_kj *V_lj
1883  * entry V_kj corresponds to entry k of the j-th eigenvector, which is given as the j-th row of the eigenvectors array
1884  * note that we need to mulitply by two for non-diagonal entries to also account for entry (l,k) */
1885  for (evind = 0; evind < blocksize; evind++)
1886  {
1887  if ( blockrow[v][i] == blockcol[v][i] )
1888  val[evind * nvars + varind] += blockval[v][i] * blockeigenvectors[b][evind * blocksize + blockrow[v][i]] * blockeigenvectors[b][evind * blocksize + blockcol[v][i]];
1889  else
1890  val[evind * nvars + varind] += 2 * blockval[v][i] * blockeigenvectors[b][evind * blocksize + blockrow[v][i]] * blockeigenvectors[b][evind * blocksize + blockcol[v][i]];
1891  }
1892  }
1893  }
1894 
1895  SCIPfreeBufferArray(scip, &blockvars);
1896  SCIPfreeBufferArray(scip, &blockval);
1897  SCIPfreeBufferArray(scip, &blockrow);
1898  SCIPfreeBufferArray(scip, &blockcol);
1899  SCIPfreeBufferArray(scip, &blocknvarnonz);
1900  SCIPfreeBufferArray(scip, &fullXmatrix);
1901 
1902  /* remove zero entries */
1903  nremovedentries = 0;
1904  for (i = 0; i < blocksize; i++)
1905  {
1906  beg[i] = beg[i] - nremovedentries;
1907  for (v = 0; v < nvars; v++)
1908  {
1909  if ( REALABS(val[i * nvars + v]) < SCIPepsilon(scip) )
1910  {
1911  nremovedentries++;
1912  }
1913  else
1914  {
1915  val[i * nvars + v - nremovedentries] = val[i * nvars + v];
1916  ind[i * nvars + v - nremovedentries] = ind[i * nvars + v];
1917  }
1918  }
1919  }
1920 
1921  SCIP_CALL( SCIPlpiAddCols(lpi, blocksize, obj, lb, ub, NULL, blocksize*nvars - nremovedentries, beg, ind, val) );
1922 
1923  blocksizes[2 + b] = blocksize;
1924  roundingvars += blocksize;
1925 
1926  SCIPfreeBufferArray(scip, &val);
1927  SCIPfreeBufferArray(scip, &ind);
1928  SCIPfreeBufferArray(scip, &beg);
1929  SCIPfreeBufferArray(scip, &ub);
1930  SCIPfreeBufferArray(scip, &lb);
1931  SCIPfreeBufferArray(scip, &obj);
1932  }
1933 
1934  /* solve the problem (since we may encounter unboundedness, which sometimes causes trouble for the CPLEX interior-point solver,
1935  * we use the dual Simplex solver) */
1936  SCIP_CALL( SCIPlpiSolveDual(lpi) );
1937 
1938  /* get optimal objective value of the primal rounding problem (will be -infinity if infeasible) */
1939  SCIP_CALL( SCIPlpiGetObjval(lpi, &primalroundobj) );
1940 
1941  SCIP_CALL( SCIPstopClock(scip, relaxdata->roundingprobtime) );
1942 
1943  /* if the restricted primal problem is already dual infeasible, then the original primal has to be dual infeasible as
1944  * well, so the dual we actually want to solve is infeasible and we can cut the node off
1945  * the same is true by weak duality if the restricted primal already has a larger objective value than the current cutoff-bound */
1946  if ( SCIPlpiIsDualInfeasible(lpi) || SCIPisGE(scip, primalroundobj, SCIPgetCutoffbound(scip)) )
1947  {
1948  if ( SCIPlpiIsDualInfeasible(lpi) )
1949  {
1950  SCIPdebugMsg(scip, "Infeasibility of node %lld detected through primal rounding problem during warmstarting\n",
1951  SCIPnodeGetNumber(SCIPgetCurrentNode(scip)));
1952 
1953  relaxdata->roundingprobinf++;
1954  }
1955  else if ( SCIPisGT(scip, primalroundobj, SCIPgetCutoffbound(scip)) )
1956  {
1957  SCIPdebugMsg(scip, "Suboptimality of node %lld detected through primal rounding problem during warmstarting:"
1958  "lower bound = %f > %f = cutoffbound\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip)), primalroundobj, SCIPgetCutoffbound(scip));
1959 
1960  relaxdata->roundingcutoff++;
1961  }
1962 
1963  /* free memory */
1964  SCIPfreeBufferArrayNull(scip, &startXval[nblocks]);
1965  SCIPfreeBufferArrayNull(scip, &startXcol[nblocks]);
1966  SCIPfreeBufferArrayNull(scip, &startXrow[nblocks]);
1967  for (b = 0; b < nblocks; b++)
1968  {
1969  SCIPfreeBufferArrayNull(scip,&blockeigenvectors[b]);
1970  SCIPfreeBufferArrayNull(scip,&blockeigenvalues[b]);
1971  SCIPfreeBufferArrayNull(scip, &startXval[b]);
1972  SCIPfreeBufferArrayNull(scip, &startXcol[b]);
1973  SCIPfreeBufferArrayNull(scip, &startXrow[b]);
1974  SCIPfreeBufferArrayNull(scip, &startZval[b]);
1975  SCIPfreeBufferArrayNull(scip, &startZcol[b]);
1976  SCIPfreeBufferArrayNull(scip, &startZrow[b]);
1977  }
1978  SCIPfreeBufferArray(scip, &blocksizes);
1979  SCIPfreeBufferArray(scip, &blockeigenvectors);
1980  SCIPfreeBufferArray(scip, &blockeigenvalues);
1981  SCIPfreeBufferArrayNull(scip, &startXval);
1982  SCIPfreeBufferArrayNull(scip, &startXcol);
1983  SCIPfreeBufferArrayNull(scip, &startXrow);
1984  SCIPfreeBufferArrayNull(scip, &startXnblocknonz);
1985  SCIPfreeBufferArrayNull(scip, &startZval);
1986  SCIPfreeBufferArrayNull(scip, &startZcol);
1987  SCIPfreeBufferArrayNull(scip, &startZrow);
1988  SCIPfreeBufferArrayNull(scip, &startZnblocknonz);
1989  SCIPfreeBufferArrayNull(scip, &sdpblocks);
1990  SCIPfreeBufferArray(scip, &starty);
1991 
1992  relaxdata->feasible = FALSE;
1993  *result = SCIP_CUTOFF;
1994  return SCIP_OKAY;
1995  }
1996  else if ( relaxdata->warmstartroundonlyinf )
1997  {
1998  /* in this case we only cared about checking infeasibility and coldstart now */
1999  SCIPfreeBufferArrayNull(scip, &startXval[nblocks]);
2000  SCIPfreeBufferArrayNull(scip, &startXcol[nblocks]);
2001  SCIPfreeBufferArrayNull(scip, &startXrow[nblocks]);
2002  for (b = 0; b < nblocks; b++)
2003  {
2004  SCIPfreeBufferArrayNull(scip, &blockeigenvectors[b]);
2005  SCIPfreeBufferArrayNull(scip, &blockeigenvalues[b]);
2006  SCIPfreeBufferArrayNull(scip, &startXval[b]);
2007  SCIPfreeBufferArrayNull(scip, &startXcol[b]);
2008  SCIPfreeBufferArrayNull(scip, &startXrow[b]);
2009  SCIPfreeBufferArrayNull(scip, &startZval[b]);
2010  SCIPfreeBufferArrayNull(scip, &startZcol[b]);
2011  SCIPfreeBufferArrayNull(scip, &startZrow[b]);
2012  }
2013  SCIPfreeBufferArray(scip, &blocksizes);
2014  SCIPfreeBufferArray(scip, &blockeigenvectors);
2015  SCIPfreeBufferArray(scip, &blockeigenvalues);
2016  SCIPfreeBufferArrayNull(scip, &startXval);
2017  SCIPfreeBufferArrayNull(scip, &startXcol);
2018  SCIPfreeBufferArrayNull(scip, &startXrow);
2019  SCIPfreeBufferArrayNull(scip, &startXnblocknonz);
2020  SCIPfreeBufferArrayNull(scip, &startZval);
2021  SCIPfreeBufferArrayNull(scip, &startZcol);
2022  SCIPfreeBufferArrayNull(scip, &startZrow);
2023  SCIPfreeBufferArrayNull(scip, &startZnblocknonz);
2024  SCIPfreeBufferArrayNull(scip, &sdpblocks);
2025  SCIPfreeBufferArray(scip, &starty);
2026 
2027  SCIP_CALL( SCIPsdpiSolve(sdpi, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, startsetting, enforceslater, timelimit) );
2028  goto solved;
2029  }
2030  else if ( ! SCIPlpiIsOptimal(lpi) )
2031  {
2032  SCIPdebugMsg(scip, "Solving without warmstart since solving of the primal rounding problem failed with status %d!\n", SCIPlpiGetInternalStatus(lpi));
2033  relaxdata->primalroundfails++;
2034 
2035  /* since warmstart computation failed, we solve without warmstart, free memory and skip the remaining warmstarting code */
2036  SCIPfreeBufferArrayNull(scip, &startXval[nblocks]);
2037  SCIPfreeBufferArrayNull(scip, &startXcol[nblocks]);
2038  SCIPfreeBufferArrayNull(scip, &startXrow[nblocks]);
2039  for (b = 0; b < nblocks; b++)
2040  {
2041  SCIPfreeBufferArrayNull(scip, &blockeigenvectors[b]);
2042  SCIPfreeBufferArrayNull(scip, &blockeigenvalues[b]);
2043  SCIPfreeBufferArrayNull(scip, &startXval[b]);
2044  SCIPfreeBufferArrayNull(scip, &startXcol[b]);
2045  SCIPfreeBufferArrayNull(scip, &startXrow[b]);
2046  SCIPfreeBufferArrayNull(scip, &startZval[b]);
2047  SCIPfreeBufferArrayNull(scip, &startZcol[b]);
2048  SCIPfreeBufferArrayNull(scip, &startZrow[b]);
2049  }
2050  SCIPfreeBufferArray(scip, &blocksizes);
2051  SCIPfreeBufferArray(scip, &blockeigenvectors);
2052  SCIPfreeBufferArray(scip, &blockeigenvalues);
2053  SCIPfreeBufferArrayNull(scip, &startXval);
2054  SCIPfreeBufferArrayNull(scip, &startXcol);
2055  SCIPfreeBufferArrayNull(scip, &startXrow);
2056  SCIPfreeBufferArrayNull(scip, &startXnblocknonz);
2057  SCIPfreeBufferArrayNull(scip, &startZval);
2058  SCIPfreeBufferArrayNull(scip, &startZcol);
2059  SCIPfreeBufferArrayNull(scip, &startZrow);
2060  SCIPfreeBufferArrayNull(scip, &startZnblocknonz);
2061  SCIPfreeBufferArrayNull(scip, &sdpblocks);
2062  SCIPfreeBufferArray(scip, &starty);
2063 
2064  SCIP_CALL( SCIPsdpiSolve(sdpi, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, startsetting, enforceslater, timelimit) );
2065  goto solved;
2066  }
2067  else
2068  {
2069  SCIP_Real* optev;
2070  int evpos;
2071 
2072  /* the problem was solved to optimality: we construct the primal matrix using the computed eigenvalues */
2073  SCIP_CALL( SCIPallocBufferArray(scip, &optev, roundingvars) );
2074 
2075  SCIP_CALL( SCIPlpiGetSol(lpi, NULL, optev, NULL, NULL, NULL) );
2076 
2077  /* build varbound block */
2078  pos = blocksizes[1]; /* to save some sorting later, the startX arrays should start with the LP block */
2079  evpos = 0;
2080  for (v = 0; v < nvars; v++)
2081  {
2082  startXrow[nblocks][pos] = 2 * nrows + 2 * v;
2083  startXcol[nblocks][pos] = 2 * nrows + 2 * v;
2084  if ( ! SCIPisInfinity(scip, -1 * SCIPvarGetLbLocal(vars[v])) )
2085  {
2086  startXval[nblocks][pos] = optev[evpos];
2087  evpos++;
2088  }
2089  else
2090  startXval[nblocks][pos] = SCIPinfinity(scip);
2091  pos++;
2092 
2093  startXrow[nblocks][pos] = 2 * nrows + 2 * v + 1;
2094  startXcol[nblocks][pos] = 2 * nrows + 2 * v + 1;
2095  if ( ! SCIPisInfinity(scip, SCIPvarGetUbLocal(vars[v])) )
2096  {
2097  startXval[nblocks][pos] = optev[evpos];
2098  evpos++;
2099  }
2100  else
2101  startXval[nblocks][pos] = SCIPinfinity(scip);
2102  pos++;
2103  }
2104  assert( evpos == blocksizes[0] );
2105 
2106  /* build LP block */
2107  pos = 0;
2108  evpos = blocksizes[0];
2109  for (r = 0; r < nrows; r++)
2110  {
2111  row = rows[r];
2112 
2113  rowlhs = SCIProwGetLhs(row) - SCIProwGetConstant(row);
2114  rowrhs = SCIProwGetRhs(row) - SCIProwGetConstant(row);
2115 
2116  startXrow[nblocks][pos] = 2 * r;
2117  startXcol[nblocks][pos] = 2 * r;
2118  if ( ! SCIPisInfinity(scip, -1 * rowlhs) )
2119  {
2120  startXval[nblocks][pos] = optev[evpos];
2121  evpos++;
2122  }
2123  else
2124  startXval[nblocks][pos] = SCIPinfinity(scip);
2125  pos++;
2126 
2127  startXrow[nblocks][pos] = 2 * r + 1;
2128  startXcol[nblocks][pos] = 2 * r + 1;
2129  if ( ! SCIPisInfinity(scip, rowrhs) )
2130  {
2131  startXval[nblocks][pos] = optev[evpos];
2132  evpos++;
2133  }
2134  else
2135  startXval[nblocks][pos] = SCIPinfinity(scip);
2136  pos++;
2137  }
2138  assert( evpos == blocksizes[0] + blocksizes[1] );
2139 
2140  startXnblocknonz[nblocks] = blocksizes[0] + blocksizes[1];
2141 
2142  /* build SDP blocks */
2143  pos = blocksizes[0] + blocksizes[1];
2144  for (b = 0; b < nblocks; b++)
2145  {
2146  blocksize = blocksizes[2 + b];
2147  matrixsize = blocksize * blocksize;
2148 
2149  /* duplicate memory of eigenvectors to compute diag(lambda_i^*) * U^T */
2150  SCIP_CALL( SCIPduplicateBufferArray(scip, &scaledeigenvectors, blockeigenvectors[b], matrixsize) );
2151 
2152  /* compute diag(lambda_i_+) * U^T */
2153  SCIP_CALL( scaleTransposedMatrix(blocksize, scaledeigenvectors, &(optev[pos])) );
2154 
2155  /* allocate memory for full X matrix */
2156  SCIP_CALL( SCIPallocBufferArray(scip, &fullXmatrix, matrixsize) );
2157 
2158  /* compute U * [diag(lambda_i_+) * U^T] (note that transposes are switched because LAPACK/Fortran uses column-first-format) */
2159  SCIP_CALL( SCIPlapackMatrixMatrixMult(blocksizes[2 + b], blocksizes[2 + b], blockeigenvectors[b], TRUE, blocksizes[2 + b], blocksizes[2 + b],
2160  scaledeigenvectors, FALSE, fullXmatrix) );
2161 
2162  /* extract sparse matrix */
2163  startXnblocknonz[b] = 0;
2164  epsilon = SCIPepsilon(scip);
2165  for (r = 0; r < blocksize; r++)
2166  {
2167  for (c = r; c < blocksize; c++)
2168  {
2169  matrixpos = r * blocksize + c;
2170  if ( REALABS(fullXmatrix[matrixpos]) > epsilon )
2171  {
2172  startXrow[b][startXnblocknonz[b]] = r;
2173  startXcol[b][startXnblocknonz[b]] = c;
2174  startXval[b][startXnblocknonz[b]] = fullXmatrix[matrixpos];
2175  startXnblocknonz[b]++;
2176  }
2177  }
2178  }
2179  pos += blocksizes[2 + b];
2180  SCIPfreeBufferArray(scip, &fullXmatrix);
2181  SCIPfreeBufferArray(scip, &scaledeigenvectors);
2182  }
2183  SCIPfreeBufferArray(scip, &optev);
2184  }
2185 
2186  /* solve dual rounding problem */
2187 
2188  /* allocate memory for LP and varbound-block (we take a worst-case guess here) */
2189  matrixsize = 2 * nvars + 2 * nrows;
2190  SCIP_CALL( SCIPallocBufferArray(scip, &startZrow[nblocks], matrixsize) );
2191  SCIP_CALL( SCIPallocBufferArray(scip, &startZcol[nblocks], matrixsize) );
2192  SCIP_CALL( SCIPallocBufferArray(scip, &startZval[nblocks], matrixsize) );
2193 
2194  /* clear the old LP */
2195  SCIP_CALL( SCIPlpiClear(lpi) );
2196 
2197  /* we want to maximize for the primal rounding problem */
2198  SCIP_CALL( SCIPlpiChgObjsen(lpi, SCIP_OBJSEN_MINIMIZE) );
2199 
2200  /* compute number of columns */
2201  roundingvars = nvars;
2202  for (b = 0; b < nblocks; b++)
2203  roundingvars += blocksizes[2 + b];
2204 
2205  SCIP_CALL( SCIPallocBufferArray(scip, &obj, roundingvars) );
2206  SCIP_CALL( SCIPallocBufferArray(scip, &lb, roundingvars) );
2207  SCIP_CALL( SCIPallocBufferArray(scip, &ub, roundingvars) );
2208 
2209  for (v = 0; v < nvars; v++)
2210  {
2211  obj[SCIPsdpVarmapperGetSdpIndex(relaxdata->varmapper, vars[v])] = SCIPvarGetObj(vars[v]);
2212  lb[SCIPsdpVarmapperGetSdpIndex(relaxdata->varmapper, vars[v])] = SCIPvarGetLbLocal(vars[v]);
2213  ub[SCIPsdpVarmapperGetSdpIndex(relaxdata->varmapper, vars[v])] = SCIPvarGetUbLocal(vars[v]);
2214  }
2215 
2216  /* the eigenvalue-variables should all be non-negative, but do not appear in the objective */
2217  for (v = nvars; v < roundingvars; v++)
2218  {
2219  obj[v] = 0.0;
2220  lb[v] = 0.0;
2221  ub[v] = SCIPlpiInfinity(lpi);
2222  }
2223 
2224  /* initialize columns; rows will be added blockwise later (note that we reenter the whole problem each time
2225  * and do not allow warmstarts, we could store the LP- and bound-constraints between nodes (TODO, but would
2226  * need to check for added/removed cuts then), but warmstarting doesn't seem to make sense since the whole
2227  * SDP part is changed, which should form the main difficulty when solving (MI)SDPs */
2228  SCIP_CALL( SCIPlpiAddCols(lpi, roundingvars, obj, lb, ub, NULL, 0, NULL, NULL, NULL) );
2229 
2230  SCIPfreeBufferArray(scip, &ub);
2231  SCIPfreeBufferArray(scip, &lb);
2232  SCIPfreeBufferArray(scip, &obj);
2233 
2234  /* add LP rows */
2235  SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
2236 
2237  for (r = 0; r < nrows; r++)
2238  {
2239  row = rows[r];
2240  assert( row != NULL );
2241  rownnonz = SCIProwGetNNonz(row);
2242 
2243  rowvals = SCIProwGetVals(row);
2244  rowcols = SCIProwGetCols(row);
2245  rowlhs = SCIProwGetLhs(row) - SCIProwGetConstant(row);
2246  rowrhs = SCIProwGetRhs(row) - SCIProwGetConstant(row);
2247 
2248  SCIP_CALL( SCIPallocBufferArray(scip, &rowinds, rownnonz) );
2249 
2250  /* iterate over rowcols and get corresponding indices */
2251  for (i = 0; i < rownnonz; i++)
2252  rowinds[i] = SCIPsdpVarmapperGetSdpIndex(relaxdata->varmapper, SCIPcolGetVar(rowcols[i]));
2253 
2254  pos = 0;
2255 
2256  SCIP_CALL( SCIPlpiAddRows(lpi, 1, &rowlhs, &rowrhs, NULL, rownnonz, &pos, rowinds, rowvals) );
2257 
2258  SCIPfreeBufferArray(scip, &rowinds);
2259  }
2260 
2261  /* for each SDP-block add constraints linking y-variables to eigenvalues of Z matrix */
2262  startpos = nvars;
2263  for (b = 0; b < nblocks; b++)
2264  {
2265  /* get data for this SDP block */
2266  SCIP_CALL( SCIPconsSdpGetNNonz(scip, sdpblocks[b], NULL, &blockconstnnonz) );
2267  SCIP_CALL( SCIPallocBufferArray(scip, &blocknvarnonz, nvars) );
2268  SCIP_CALL( SCIPallocBufferArray(scip, &blockcol, nvars) );
2269  SCIP_CALL( SCIPallocBufferArray(scip, &blockrow, nvars) );
2270  SCIP_CALL( SCIPallocBufferArray(scip, &blockval, nvars) );
2271  SCIP_CALL( SCIPallocBufferArray(scip, &blockvars, nvars) );
2272  SCIP_CALL( SCIPallocBufferArray(scip, &blockconstcol, blockconstnnonz) );
2273  SCIP_CALL( SCIPallocBufferArray(scip, &blockconstrow, blockconstnnonz) );
2274  SCIP_CALL( SCIPallocBufferArray(scip, &blockconstval, blockconstnnonz) );
2275  blocksize = blocksizes[2 + b];
2276  matrixsize = blocksize * blocksize;
2277 
2278  SCIP_CALL( SCIPallocBufferArray(scip, &fullZmatrix, matrixsize) );
2279 
2280  SCIP_CALL( expandSparseMatrix(startZnblocknonz[b], blocksize, startZrow[b], startZcol[b], startZval[b], fullZmatrix) );
2281 
2282  SCIP_CALL( SCIPlapackComputeEigenvectorDecomposition(SCIPbuffer(scip), blocksize, fullZmatrix, blockeigenvalues[b], blockeigenvectors[b]) );
2283 
2284  arraylength = nvars;
2285  SCIP_CALL( SCIPconsSdpGetData(scip, sdpblocks[b], &blocknvars, &blocknnonz, &blocksize, &arraylength, blocknvarnonz,
2286  blockcol, blockrow, blockval, blockvars, &blockconstnnonz, blockconstcol, blockconstrow, blockconstval, NULL, NULL, NULL) );
2287 
2288  nroundingrows = (blocksize * (blocksize + 1)) / 2;
2289 
2290  SCIP_CALL( SCIPallocBufferArray(scip, &lhs, nroundingrows) );
2291  SCIP_CALL( SCIPallocBufferArray(scip, &rhs, nroundingrows) );
2292  SCIP_CALL( SCIPallocBufferArray(scip, &nblockrownonz , nroundingrows) );
2293  SCIP_CALL( SCIPallocBufferArray(scip, &blockrowcols , nroundingrows) );
2294  SCIP_CALL( SCIPallocBufferArray(scip, &blockrowvals , nroundingrows) );
2295 
2296  /* initialize lhs and rhs with 0 and allocate memory for nonzeros (we take the worst case of nvars y entries and blocksize lambda entries) */
2297  for (i = 0; i < nroundingrows; i++)
2298  {
2299  lhs[i] = 0.0;
2300  rhs[i] = 0.0;
2301 
2302  nblockrownonz[i] = 0;
2303  SCIP_CALL( SCIPallocBufferArray(scip, &blockrowcols[i], nvars + blocksize) );
2304  SCIP_CALL( SCIPallocBufferArray(scip, &blockrowvals[i], nvars + blocksize) );
2305  }
2306 
2307  /* iterate over constant matrix to compute right-hand sides of equality constraints */
2308  for (i = 0; i < blockconstnnonz; i++)
2309  {
2310  assert( lhs[SCIPconsSdpCompLowerTriangPos(blockconstrow[i], blockconstcol[i])] == 0.0 ); /* there should only be a single entry per index-pair */
2311  lhs[SCIPconsSdpCompLowerTriangPos(blockconstrow[i], blockconstcol[i])] = blockconstval[i];
2312  rhs[SCIPconsSdpCompLowerTriangPos(blockconstrow[i], blockconstcol[i])] = blockconstval[i];
2313  }
2314 
2315  /* iterate over all nonzeros to add them to the roundingrows */
2316  for (v = 0; v < blocknvars; v++)
2317  {
2318  varind = SCIPsdpVarmapperGetSdpIndex(relaxdata->varmapper, blockvars[v]);
2319 
2320  for (i = 0; i < blocknvarnonz[v]; i++)
2321  {
2322  pos = SCIPconsSdpCompLowerTriangPos(blockrow[v][i], blockcol[v][i]);
2323  blockrowcols[pos][nblockrownonz[pos]] = varind;
2324  blockrowvals[pos][nblockrownonz[pos]] = blockval[v][i];
2325  nblockrownonz[pos]++;
2326  }
2327  }
2328 
2329  /* add entries corresponding to eigenvalues */
2330  for (evind = 0; evind < blocksize; evind++)
2331  {
2332  for (i = 0; i < blocksize; i++)
2333  {
2334  for (j = 0; j <= i; j++)
2335  {
2336  /* for index (i,j) and every eigenvector v, we get an entry -V_iv *V_jv (we get the -1 by transferring this to the left-hand side of the equation)
2337  * entry V_iv corresponds to entry i of the v-th eigenvector, which is given as the v-th row of the eigenvectors array */
2338  if ( SCIPisGT(scip, REALABS(-1 * blockeigenvectors[b][evind * blocksize + i] * blockeigenvectors[b][evind * blocksize + j]), 0.0) )
2339  {
2340  pos = SCIPconsSdpCompLowerTriangPos(i, j);
2341  blockrowcols[pos][nblockrownonz[pos]] = startpos + evind;
2342  blockrowvals[pos][nblockrownonz[pos]] = -1 * blockeigenvectors[b][evind * blocksize + i] * blockeigenvectors[b][evind * blocksize + j];
2343  nblockrownonz[pos]++;
2344  }
2345  }
2346  }
2347  }
2348  startpos += blocksize;
2349 
2350  pos = 0;
2351  /* add the rows one by one */
2352  for (r = 0; r < nroundingrows; r++)
2353  {
2354  SCIP_CALL( SCIPlpiAddRows(lpi, 1, &lhs[r], &rhs[r], NULL, nblockrownonz[r], &pos, blockrowcols[r], blockrowvals[r]) );
2355  SCIPfreeBufferArray(scip, &blockrowvals[r]);
2356  SCIPfreeBufferArray(scip, &blockrowcols[r]);
2357  }
2358 
2359  SCIPfreeBufferArray(scip, &blockrowvals);
2360  SCIPfreeBufferArray(scip, &blockrowcols);
2361  SCIPfreeBufferArray(scip, &nblockrownonz);
2362  SCIPfreeBufferArray(scip, &rhs);
2363  SCIPfreeBufferArray(scip, &lhs);
2364  SCIPfreeBufferArray(scip, &fullZmatrix);
2365  SCIPfreeBufferArray(scip, &blockconstval);
2366  SCIPfreeBufferArray(scip, &blockconstrow);
2367  SCIPfreeBufferArray(scip, &blockconstcol);
2368  SCIPfreeBufferArray(scip, &blockvars);
2369  SCIPfreeBufferArray(scip, &blockval);
2370  SCIPfreeBufferArray(scip, &blockrow);
2371  SCIPfreeBufferArray(scip, &blockcol);
2372  SCIPfreeBufferArray(scip, &blocknvarnonz);
2373  }
2374 
2375  /* solve the problem (for some reason dual simplex seems to work better here) */
2376  SCIP_CALL( SCIPstartClock(scip, relaxdata->roundingprobtime) );
2377  SCIP_CALL( SCIPlpiSolveDual(lpi) );
2378  SCIP_CALL( SCIPstopClock(scip, relaxdata->roundingprobtime) );
2379 
2380  if ( ! SCIPlpiIsOptimal(lpi) )
2381  {
2382  SCIPdebugMsg(scip, "Solution of dual rounding problem failed with status %d, continuing without warmstart\n", SCIPlpiGetInternalStatus(lpi));
2383  relaxdata->dualroundfails++;
2384 
2385  /* free memory */
2386  SCIPfreeBufferArrayNull(scip, &startZval[nblocks]);
2387  SCIPfreeBufferArrayNull(scip, &startZcol[nblocks]);
2388  SCIPfreeBufferArrayNull(scip, &startZrow[nblocks]);
2389  SCIPfreeBufferArrayNull(scip, &startXval[nblocks]);
2390  SCIPfreeBufferArrayNull(scip, &startXcol[nblocks]);
2391  SCIPfreeBufferArrayNull(scip, &startXrow[nblocks]);
2392  for (b = 0; b < nblocks; b++)
2393  {
2394  SCIPfreeBufferArrayNull(scip, &blockeigenvectors[b]);
2395  SCIPfreeBufferArrayNull(scip, &blockeigenvalues[b]);
2396  SCIPfreeBufferArrayNull(scip, &startZval[b]);
2397  SCIPfreeBufferArrayNull(scip, &startZcol[b]);
2398  SCIPfreeBufferArrayNull(scip, &startZrow[b]);
2399  SCIPfreeBufferArrayNull(scip, &startXval[b]);
2400  SCIPfreeBufferArrayNull(scip, &startXcol[b]);
2401  SCIPfreeBufferArrayNull(scip, &startXrow[b]);
2402  }
2403  SCIPfreeBufferArray(scip, &blocksizes);
2404  SCIPfreeBufferArray(scip, &blockeigenvectors);
2405  SCIPfreeBufferArray(scip, &blockeigenvalues);
2406  SCIPfreeBufferArrayNull(scip, &startXval);
2407  SCIPfreeBufferArrayNull(scip, &startXcol);
2408  SCIPfreeBufferArrayNull(scip, &startXrow);
2409  SCIPfreeBufferArrayNull(scip, &startXnblocknonz);
2410  SCIPfreeBufferArrayNull(scip, &startZval);
2411  SCIPfreeBufferArrayNull(scip, &startZcol);
2412  SCIPfreeBufferArrayNull(scip, &startZrow);
2413  SCIPfreeBufferArrayNull(scip, &startZnblocknonz);
2414  SCIPfreeBufferArrayNull(scip, &sdpblocks);
2415  SCIPfreeBufferArray(scip, &starty);
2416 
2417  /* since warmstart computation failed, we solve without warmstart, free memory and skip the remaining warmstarting code */
2418  SCIP_CALL( SCIPsdpiSolve(sdpi, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, startsetting, enforceslater, timelimit) );
2419 
2420  goto solved;
2421  }
2422  else
2423  {
2424  SCIP_Real* optev;
2425 
2426  relaxdata->roundstartsuccess++;
2427 
2428  /* the problem was solved to optimality: we construct the dual vector and matrix using the computed eigenvalues */
2429  SCIP_CALL( SCIPallocBufferArray(scip, &optev, nvars + roundingvars) );
2430  SCIP_CALL( SCIPlpiGetSol(lpi, &dualroundobj, optev, NULL, NULL, NULL) );
2431 
2432  /* if the objective values of the primal and dual rounding problem agree, the problem has been solved to optimality,
2433  * since both of them are respective restrictions of the original primal and dual problem */
2434  if ( SCIPisEQ(scip, primalroundobj, dualroundobj) )
2435  {
2436  SCIP_SOL* scipsol; /* TODO: eliminate this */
2437  SCIP_CONS* savedcons;
2438 
2439  SCIPdebugMsg(scip, "Node %lld solved to optimality through rounding problems with optimal objective %f\n",
2440  SCIPnodeGetNumber(SCIPgetCurrentNode(scip)), dualroundobj);
2441 
2442  relaxdata->roundingoptimal++;
2443 
2444  /* create SCIP solution (first nvars entries of optev correspond to y variables) */
2445  SCIP_CALL( SCIPcreateSol(scip, &scipsol, NULL) );
2446  SCIP_CALL( SCIPsetSolVals(scip, scipsol, nvars, vars, optev) );
2447 
2448  *lowerbound = dualroundobj;
2449  relaxdata->objval = dualroundobj;
2450 
2451  /* copy solution */
2452 #if ( SCIP_VERSION >= 700 || (SCIP_VERSION >= 602 && SCIP_SUBVERSION > 0) )
2453  SCIP_CALL( SCIPsetRelaxSolValsSol(scip, relax, scipsol, TRUE) );
2454 #else
2455  SCIP_CALL( SCIPsetRelaxSolValsSol(scip, scipsol, TRUE) );
2456 #endif
2457 
2458  relaxdata->feasible = TRUE;
2459  *result = SCIP_SUCCESS;
2460 
2461  /* save solution for warmstarts */
2462  if ( relaxdata->warmstart )
2463  {
2464  char consname[SCIP_MAXSTRLEN];
2465 #ifndef NDEBUG
2466  int snprintfreturn; /* this is used to assert that the SCIP string concatenation works */
2467 #endif
2468 
2469 #ifndef NDEBUG
2470  snprintfreturn = SCIPsnprintf(consname, SCIP_MAXSTRLEN, "saved_relax_sol_%d", SCIPnodeGetNumber(SCIPgetCurrentNode(scip)));
2471  assert( snprintfreturn < SCIP_MAXSTRLEN ); /* check whether name fit into string */
2472 #else
2473  (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "saved_relax_sol_%d", SCIPnodeGetNumber(SCIPgetCurrentNode(scip)));
2474 #endif
2475  SCIP_CALL( createConsSavesdpsol(scip, &savedcons, consname, SCIPnodeGetNumber(SCIPgetCurrentNode(scip)), scipsol,
2476  maxprimalentry, nblocks + 1, startXnblocknonz, startXrow, startXcol, startXval) );
2477 
2478  SCIP_CALL( SCIPaddCons(scip, savedcons) );
2479  SCIP_CALL( SCIPreleaseCons(scip, &savedcons) );
2480  }
2481 
2482  SCIP_CALL( SCIPfreeSol(scip, &scipsol) );
2483 
2484  /* free memory */
2485  SCIPfreeBufferArray(scip, &optev);
2486  SCIPfreeBufferArrayNull(scip, &startZval[nblocks]);
2487  SCIPfreeBufferArrayNull(scip, &startZcol[nblocks]);
2488  SCIPfreeBufferArrayNull(scip, &startZrow[nblocks]);
2489  SCIPfreeBufferArrayNull(scip, &startXval[nblocks]);
2490  SCIPfreeBufferArrayNull(scip, &startXcol[nblocks]);
2491  SCIPfreeBufferArrayNull(scip, &startXrow[nblocks]);
2492  for (b = 0; b < nblocks; b++)
2493  {
2494  SCIPfreeBufferArrayNull(scip,&blockeigenvectors[b]);
2495  SCIPfreeBufferArrayNull(scip,&blockeigenvalues[b]);
2496  SCIPfreeBufferArrayNull(scip, &startXval[b]);
2497  SCIPfreeBufferArrayNull(scip, &startXcol[b]);
2498  SCIPfreeBufferArrayNull(scip, &startXrow[b]);
2499  SCIPfreeBufferArrayNull(scip, &startZval[b]);
2500  SCIPfreeBufferArrayNull(scip, &startZcol[b]);
2501  SCIPfreeBufferArrayNull(scip, &startZrow[b]);
2502  }
2503  SCIPfreeBufferArray(scip, &blocksizes);
2504  SCIPfreeBufferArray(scip, &blockeigenvectors);
2505  SCIPfreeBufferArray(scip, &blockeigenvalues);
2506  SCIPfreeBufferArrayNull(scip, &startXval);
2507  SCIPfreeBufferArrayNull(scip, &startXcol);
2508  SCIPfreeBufferArrayNull(scip, &startXrow);
2509  SCIPfreeBufferArrayNull(scip, &startXnblocknonz);
2510  SCIPfreeBufferArrayNull(scip, &startZval);
2511  SCIPfreeBufferArrayNull(scip, &startZcol);
2512  SCIPfreeBufferArrayNull(scip, &startZrow);
2513  SCIPfreeBufferArrayNull(scip, &startZnblocknonz);
2514  SCIPfreeBufferArrayNull(scip, &sdpblocks);
2515  SCIPfreeBufferArray(scip, &starty);
2516 
2517  return SCIP_OKAY;
2518  }
2519 
2520  /* adjust dual vector */
2521  for (v = 0; v < nvars; v++)
2522  {
2523  if ( relaxdata->warmstartiptype == 1 )
2524  {
2525  /* we take a convex combination with 0, so we just scale */
2526  starty[v] = (1 - relaxdata->warmstartipfactor) * optev[v];
2527  }
2528  else if ( relaxdata->warmstartiptype == 2 )
2529  {
2530  /* take the convex combination with the saved analytic center */
2531  starty[v] = (1 - relaxdata->warmstartipfactor) * optev[v] + relaxdata->warmstartipfactor * SCIPgetSolVal(scip, relaxdata->ipy, vars[v]);
2532  }
2533  }
2534 
2535  /* build Z matrix */
2536  pos = nvars;
2537  for (b = 0; b < nblocks; b++)
2538  {
2539  blocksize = blocksizes[2 + b];
2540  matrixsize = blocksize * blocksize;
2541 
2542  /* duplicate memory of eigenvectors to compute diag(lambda_i^*) * U^T */
2543  SCIP_CALL( SCIPduplicateBufferArray(scip, &scaledeigenvectors, blockeigenvectors[b], matrixsize) );
2544 
2545  /* compute diag(lambda_i_+) * U^T */
2546  SCIP_CALL( scaleTransposedMatrix(blocksize, scaledeigenvectors, &(optev[pos])) );
2547 
2548  /* allocate memory for full Z matrix */
2549  SCIP_CALL( SCIPallocBufferArray(scip, &fullZmatrix, matrixsize) );
2550 
2551  /* compute U * [diag(lambda_i_+) * U^T] (note that transposes are switched because LAPACK uses column-first-format) */
2552  SCIP_CALL( SCIPlapackMatrixMatrixMult(blocksize, blocksize, blockeigenvectors[b], TRUE, blocksize, blocksize,
2553  scaledeigenvectors, FALSE, fullZmatrix) );
2554 
2555  /* extract sparse matrix */
2556  startZnblocknonz[b] = 0;
2557  epsilon = SCIPepsilon(scip);
2558  for (r = 0; r < blocksize; r++)
2559  {
2560  for (c = r; c < blocksize; c++)
2561  {
2562  matrixpos = r * blocksize + c;
2563  if ( REALABS(fullZmatrix[matrixpos]) > epsilon )
2564  {
2565  startZrow[b][startZnblocknonz[b]] = r;
2566  startZcol[b][startZnblocknonz[b]] = c;
2567  startZval[b][startZnblocknonz[b]] = fullZmatrix[matrixpos];
2568  startZnblocknonz[b]++;
2569  }
2570  }
2571  }
2572  pos += blocksize;
2573  SCIPfreeBufferArray(scip, &fullZmatrix);
2574  SCIPfreeBufferArray(scip, &scaledeigenvectors);
2575  SCIPfreeBufferArray(scip, &blockeigenvectors[b]);
2576  SCIPfreeBufferArray(scip, &blockeigenvalues[b]);
2577  }
2578 
2579  SCIPfreeBufferArray(scip, &optev);
2580  SCIPfreeBufferArray(scip, &blockeigenvectors);
2581  SCIPfreeBufferArray(scip, &blockeigenvalues);
2582  SCIPfreeBufferArray(scip, &blocksizes);
2583 
2584  /* build LP and varbound block of Z matrix */
2585 
2586  /* to get a positive definite matrix, all the entries need to be strictly positive */
2587  startZnblocknonz[b] = 2 * nrows + 2 * nvars;
2588 
2589  /* fill LP-block */
2590  for (r = 0; r < nrows; r++)
2591  {
2592  /* compute row value for current solution */
2593  rowval = 0.0;
2594  rownnonz = SCIProwGetNNonz(rows[r]);
2595  rowvals = SCIProwGetVals(rows[r]);
2596  rowcols = SCIProwGetCols(rows[r]);
2597 
2598  for (i = 0; i < rownnonz; i++)
2599  rowval += starty[SCIPsdpVarmapperGetSdpIndex(relaxdata->varmapper, SCIPcolGetVar(rowcols[i]))] * rowvals[i];
2600 
2601  startZrow[b][2*r] = 2*r;
2602  startZcol[b][2*r] = 2*r;
2603  startZval[b][2*r] = rowval - (SCIProwGetLhs(rows[r]) - SCIProwGetConstant(rows[r]));
2604 
2605  startZrow[b][2*r + 1] = 2*r + 1;
2606  startZcol[b][2*r + 1] = 2*r + 1;
2607  startZval[b][2*r + 1] = SCIProwGetRhs(rows[r]) - SCIProwGetConstant(rows[r]) - rowval;
2608  }
2609 
2610  /* fill varbound block */
2611  for (v = 0; v < nvars; v++)
2612  {
2613  startZrow[b][2*nrows + 2*v] = 2*nrows + 2*v;
2614  startZcol[b][2*nrows + 2*v] = 2*nrows + 2*v;
2615  startZval[b][2*nrows + 2*v] = starty[SCIPsdpVarmapperGetSdpIndex(relaxdata->varmapper, vars[v])] - SCIPvarGetLbLocal(vars[v]);
2616 
2617  startZrow[b][2*nrows + 2*v + 1] = 2*nrows + 2*v + 1;
2618  startZcol[b][2*nrows + 2*v + 1] = 2*nrows + 2*v + 1;
2619  startZval[b][2*nrows + 2*v + 1] = SCIPvarGetUbLocal(vars[v]) - starty[SCIPsdpVarmapperGetSdpIndex(relaxdata->varmapper, vars[v])];
2620  }
2621  }
2622  }
2623 
2624  /* if we saved the whole primal solution before, we can set it at once */
2625  if ( relaxdata->warmstartprimaltype == 3 )
2626  {
2627  /* if we wanted to use the rounding problem, we already created the solution and just want to do the convex combination */
2628  if ( relaxdata->warmstartproject != 4 )
2629  {
2630  SCIP_CALL( SCIPconsSavesdpsolGetPrimalMatrixNonzeros(scip, conss[parentconsind], nblocks + 1, startXnblocknonz) );
2631 
2632  /* allocate sufficient memory (memory for LP-block was already allocated); we allocate an extra blocksize for adding the diagonal matrix or analytic center */
2633  if ( relaxdata->warmstartproject == 3 )
2634  {
2635  int matrixsize;
2636 
2637  /* since we cannot compute the number of nonzeros of the projection beforehand, we allocate the maximum possible (blocksize * (blocksize + 1) / 2) */
2638  for (b = 0; b < nblocks; b++)
2639  {
2640  matrixsize = SCIPconsSdpGetBlocksize(scip, sdpblocks[b]);
2641  matrixsize = (matrixsize * (matrixsize + 1)) / 2;
2642 
2643  SCIP_CALL( SCIPallocBufferArray(scip, &startXrow[b], matrixsize) );
2644  SCIP_CALL( SCIPallocBufferArray(scip, &startXcol[b], matrixsize) );
2645  SCIP_CALL( SCIPallocBufferArray(scip, &startXval[b], matrixsize) );
2646  }
2647  }
2648  else if ( relaxdata->warmstartiptype == 1 )
2649  {
2650  for (b = 0; b < nblocks; b++)
2651  {
2652  SCIP_CALL( SCIPallocBufferArray(scip, &startXrow[b], startXnblocknonz[b] + SCIPconsSdpGetBlocksize(scip, sdpblocks[b])) );
2653  SCIP_CALL( SCIPallocBufferArray(scip, &startXcol[b], startXnblocknonz[b] + SCIPconsSdpGetBlocksize(scip, sdpblocks[b])) );
2654  SCIP_CALL( SCIPallocBufferArray(scip, &startXval[b], startXnblocknonz[b] + SCIPconsSdpGetBlocksize(scip, sdpblocks[b])) );
2655  }
2656  }
2657  else if ( relaxdata->warmstartiptype == 2 )
2658  {
2659  for (b = 0; b < nblocks; b++)
2660  {
2661  SCIP_CALL( SCIPallocBufferArray(scip, &startXrow[b], startXnblocknonz[b] + relaxdata->ipXnblocknonz[b]) );
2662  SCIP_CALL( SCIPallocBufferArray(scip, &startXcol[b], startXnblocknonz[b] + relaxdata->ipXnblocknonz[b]) );
2663  SCIP_CALL( SCIPallocBufferArray(scip, &startXval[b], startXnblocknonz[b] + relaxdata->ipXnblocknonz[b]) );
2664  }
2665  }
2666 
2667  SCIP_CALL( SCIPconsSavesdpsolGetPrimalMatrix(scip, conss[parentconsind], nblocks + 1, startXnblocknonz, startXrow, startXcol, startXval) );
2668  }
2669  }
2670 
2671  /* iterate over all blocks again to compute convex combination / projection */
2672 
2673  /* in case of warmstartprojpdsame first compute a single maximum value for all primal and dual blocks */
2674  if ( relaxdata->warmstartprojpdsame && SCIPisGT(scip, relaxdata->warmstartipfactor, 0.0) )
2675  {
2676  identitydiagonal = 1.0;
2677 
2678  for (b = 0; b < nblocks; b++)
2679  {
2680  for (i = 0; i < startZnblocknonz[b]; i++)
2681  {
2682  if ( REALABS(startZval[b][i]) > identitydiagonal )
2683  identitydiagonal = REALABS(startZval[b][i]);
2684  }
2685  for (i = 0; i < startXnblocknonz[b]; i++)
2686  {
2687  if ( REALABS(startXval[b][i]) > identitydiagonal )
2688  identitydiagonal = REALABS(startXval[b][i]);
2689  }
2690  }
2691  identitydiagonal *= relaxdata->warmstartipfactor; /* the diagonal entries of the scaled identity matrix */
2692  }
2693 
2694  for (b = 0; b < nblocks; b++)
2695  {
2696  /* compute projection onto psd cone (computed as U * diag(lambda_i_+) * U^T where U consists of the eigenvectors of the matrix) */
2697  if ( relaxdata->warmstartproject == 3 )
2698  {
2699  SCIP_Real* fullXmatrix;
2700  SCIP_Real* eigenvalues;
2701  SCIP_Real* eigenvectors;
2702  SCIP_Real* scaledeigenvectors;
2703  SCIP_Real epsilon;
2704  int matrixsize;
2705  int matrixpos;
2706  int c;
2707 
2708  blocksize = SCIPconsSdpGetBlocksize(scip, sdpblocks[b]);
2709  matrixsize = blocksize * blocksize;
2710 
2711  SCIP_CALL( SCIPallocBufferArray(scip, &fullXmatrix, matrixsize) );
2712  SCIP_CALL( SCIPallocBufferArray(scip, &eigenvalues, blocksize) );
2713  SCIP_CALL( SCIPallocBufferArray(scip, &eigenvectors, matrixsize) );
2714 
2715  SCIP_CALL( expandSparseMatrix(startXnblocknonz[b], blocksize, startXrow[b], startXcol[b], startXval[b], fullXmatrix) );
2716 
2717  SCIP_CALL( SCIPlapackComputeEigenvectorDecomposition(SCIPbuffer(scip), blocksize, fullXmatrix, eigenvalues, eigenvectors) );
2718 
2719  /* duplicate memory of eigenvectors to compute diag(lambda_i_+) * U^T */
2720  SCIP_CALL( SCIPduplicateBufferArray(scip, &scaledeigenvectors, eigenvectors, matrixsize) );
2721 
2722  /* set all negative eigenvalues to zero (using the property that LAPACK returns them in ascending order) */
2723  i = 0;
2724  while (i < blocksize && SCIPisLT(scip, eigenvalues[i], relaxdata->warmstartprojminevprimal) )
2725  {
2726  eigenvalues[i] = relaxdata->warmstartprojminevprimal;
2727  i++;
2728  }
2729 
2730  /* compute diag(lambda_i_+) * U^T */
2731  SCIP_CALL( scaleTransposedMatrix(blocksize, scaledeigenvectors, eigenvalues) );
2732 
2733  /* compute U * [diag(lambda_i_+) * U^T] (note that transposes are switched because LAPACK uses column-first-format) */
2734  SCIP_CALL( SCIPlapackMatrixMatrixMult(blocksize, blocksize, eigenvectors, TRUE, blocksize, blocksize, scaledeigenvectors,
2735  FALSE, fullXmatrix) );
2736 
2737  /* extract sparse matrix from projection */
2738  startXnblocknonz[b] = 0;
2739  epsilon = SCIPepsilon(scip);
2740  for (r = 0; r < blocksize; r++)
2741  {
2742  for (c = r; c < blocksize; c++)
2743  {
2744  matrixpos = r * blocksize + c;
2745  if ( REALABS(fullXmatrix[matrixpos]) > epsilon )
2746  {
2747  startXrow[b][startXnblocknonz[b]] = r;
2748  startXcol[b][startXnblocknonz[b]] = c;
2749  startXval[b][startXnblocknonz[b]] = fullXmatrix[matrixpos];
2750  startXnblocknonz[b]++;
2751  }
2752  }
2753  }
2754 
2755  /* free memory */
2756  SCIPfreeBufferArray(scip, &scaledeigenvectors);
2757  SCIPfreeBufferArray(scip, &eigenvectors);
2758  SCIPfreeBufferArray(scip, &eigenvalues);
2759  SCIPfreeBufferArray(scip, &fullXmatrix);
2760  }
2761 
2762  /* use convex combination between X and scaled identity matrix to move solution to the interior */
2763  if ( SCIPisGT(scip, relaxdata->warmstartipfactor, 0.0) )
2764  {
2765  if ( relaxdata->warmstartiptype == 1 )
2766  {
2767  /* compute maxprimalentry (should be at least one or warmstartprojminevprimal) */
2768  if ( ! relaxdata->warmstartprojpdsame )
2769  {
2770  if ( relaxdata->warmstartproject == 3 )
2771  maxprimalentry = relaxdata->warmstartprojminevprimal;
2772  else
2773  maxprimalentry = 1.0;
2774  for (i = 0; i < startXnblocknonz[b]; i++)
2775  {
2776  if ( REALABS(startXval[b][i]) > maxprimalentry )
2777  maxprimalentry = REALABS(startXval[b][i]);
2778  }
2779  identitydiagonal = relaxdata->warmstartipfactor * maxprimalentry; /* the diagonal entries of the scaled identity matrix */
2780  }
2781  blocksize = SCIPconsSdpGetBlocksize(scip, sdpblocks[b]);
2782 
2783  SCIP_CALL( SCIPallocBufferArray(scip, &diagentryexists, blocksize) ); /* TODO: could allocate this once for Z and X with max-blocksize */
2784  for (i = 0; i < blocksize; i++)
2785  diagentryexists[i] = FALSE;
2786 
2787  for (i = 0; i < startXnblocknonz[b]; i++)
2788  {
2789  if ( startXrow[b][i] == startXcol[b][i] )
2790  {
2791  startXval[b][i] = startXval[b][i] * (1 - relaxdata->warmstartipfactor) + identitydiagonal; /* add identity for diagonal entries */
2792  assert( startXval[b][i] >= 0.0 ); /* since the original matrix should have been positive semidefinite, diagonal entries should be >= 0 */
2793  diagentryexists[startXrow[b][i]] = TRUE;
2794  }
2795  else
2796  startXval[b][i] *= (1 - relaxdata->warmstartipfactor); /* since this is an off-diagonal entry, we scale towards zero */
2797  }
2798 
2799  /* if a diagonal entry was missing (because we had a zero row before), we have to add it to the end */
2800  for (i = 0; i < blocksize; i++)
2801  {
2802  if ( ! diagentryexists[i] )
2803  {
2804  startXrow[b][startXnblocknonz[b]] = i;
2805  startXcol[b][startXnblocknonz[b]] = i;
2806  startXval[b][startXnblocknonz[b]] = identitydiagonal;
2807  startXnblocknonz[b]++;
2808  }
2809  }
2810  SCIPfreeBufferArrayNull(scip, &diagentryexists);
2811  }
2812  else if ( relaxdata->warmstartiptype == 2 )
2813  {
2814  /* iterate once over all entries to multiply them with (1 - warmstartipfactor) */
2815  for (i = 0; i < startXnblocknonz[b]; i++)
2816  startXval[b][i] *= 1 - relaxdata->warmstartipfactor;
2817 
2818  /* merge the scaled interior point array into the warmstart array */
2819  SCIP_CALL( SCIPsdpVarfixerMergeArrays(SCIPblkmem(scip), SCIPepsilon(scip), relaxdata->ipXrow[b], relaxdata->ipXcol[b],
2820  relaxdata->ipXval[b], relaxdata->ipXnblocknonz[b], TRUE, relaxdata->warmstartipfactor,
2821  startXrow[b], startXcol[b], startXval[b], &(startXnblocknonz[b]), startXnblocknonz[b] + relaxdata->ipXnblocknonz[b]) );
2822  }
2823  }
2824  }
2825 
2826  for (b = 0; b < nblocks; b++)
2827  {
2828  /* use convex combination between Z and scaled identity matrix to move solution to the interior */
2829  if ( SCIPisGT(scip, relaxdata->warmstartipfactor, 0.0) )
2830  {
2831  if ( relaxdata->warmstartiptype == 1 )
2832  {
2833  if ( ! relaxdata->warmstartprojpdsame )
2834  {
2835  /* compute maxdualentry (should be at least one) */
2836  maxdualentry = 1.0;
2837  for (i = 0; i < startZnblocknonz[b]; i++)
2838  {
2839  if ( REALABS(startZval[b][i]) > maxdualentry )
2840  maxdualentry = REALABS(startZval[b][i]);
2841  }
2842  identitydiagonal = relaxdata->warmstartipfactor * maxdualentry; /* the diagonal entries of the scaled identity matrix */
2843  }
2844 
2845  blocksize = SCIPconsSdpGetBlocksize(scip, sdpblocks[b]);
2846  SCIP_CALL( SCIPallocBufferArray(scip, &diagentryexists, blocksize) ); /* TODO: could allocate this once for Z and X with max-blocksize */
2847  for (i = 0; i < blocksize; i++)
2848  diagentryexists[i] = FALSE;
2849 
2850  for (i = 0; i < startZnblocknonz[b]; i++)
2851  {
2852  if ( startZrow[b][i] == startZcol[b][i] )
2853  {
2854  startZval[b][i] = startZval[b][i] * (1 - relaxdata->warmstartipfactor) + identitydiagonal; /* add identity for diagonal entries */
2855  assert( startZval[b][i] >= 0 ); /* since the original matrix should have been positive semidefinite, diagonal entries should be >= 0 */
2856  diagentryexists[startZrow[b][i]] = TRUE;
2857  }
2858  else
2859  startZval[b][i] *= (1 - relaxdata->warmstartipfactor); /* since this is an off-diagonal entry, we scale towards zero */
2860  }
2861 
2862  /* if a diagonal entry was missing (because we had a zero row before), we have to add it to the end */
2863  for (i = 0; i < blocksize; i++)
2864  {
2865  if ( ! diagentryexists[i] )
2866  {
2867  startZrow[b][startZnblocknonz[b]] = i;
2868  startZcol[b][startZnblocknonz[b]] = i;
2869  startZval[b][startZnblocknonz[b]] = identitydiagonal;
2870  startZnblocknonz[b]++;
2871  }
2872  }
2873 
2874  SCIPfreeBufferArrayNull(scip, &diagentryexists);
2875  }
2876  else if ( relaxdata->warmstartiptype == 2 )
2877  {
2878  /* iterate once over all entries to multiply them with (1 - warmstartipfactor) */
2879  for (i = 0; i < startZnblocknonz[b]; i++)
2880  startZval[b][i] *= 1 - relaxdata->warmstartipfactor;
2881 
2882  /* merge the scaled interior point array into the warmstart array */
2883  SCIP_CALL( SCIPsdpVarfixerMergeArrays(SCIPblkmem(scip), SCIPepsilon(scip), relaxdata->ipZrow[b],
2884  relaxdata->ipZcol[b], relaxdata->ipZval[b], relaxdata->ipZnblocknonz[b], TRUE, relaxdata->warmstartipfactor,
2885  startZrow[b], startZcol[b], startZval[b], &(startZnblocknonz[b]), startZnblocknonz[b] + relaxdata->ipZnblocknonz[b]) );
2886  }
2887  }
2888  }
2889 
2890  /* compute projection for LP block */
2891  if ( relaxdata->warmstartproject == 3 )
2892  {
2893  int nsavedentries;
2894  int lastentry;
2895  int j;
2896 
2897  /* sort indices by row/col; TODO: check if this is necessary */
2898  SCIPsortIntIntReal(startXrow[nblocks], startXcol[nblocks], startXval[nblocks], startXnblocknonz[nblocks]);
2899 
2900  /* iterate over all entries */
2901  nsavedentries = startXnblocknonz[nblocks];
2902  lastentry = 0;
2903 
2904  for (i = 0; i < nsavedentries; i++)
2905  {
2906  assert( startXrow[nblocks][i] == startXcol[nblocks][i] ); /* this is the LP-block */
2907  /* if some entries are missing, we add them at the end */
2908  for (j = lastentry + 1; j < startXrow[nblocks][i]; j++)
2909  {
2910  assert( startXnblocknonz[nblocks] < 2 * nrows + 2 * nvars );
2911  startXrow[nblocks][startXnblocknonz[nblocks]] = j;
2912  startXcol[nblocks][startXnblocknonz[nblocks]] = j;
2913  startXval[nblocks][startXnblocknonz[nblocks]] = relaxdata->warmstartprojminevprimal;
2914  startXnblocknonz[nblocks]++;
2915  }
2916  if ( SCIPisLT(scip, startXval[b][i], 1.0) )
2917  startXval[b][i] = relaxdata->warmstartprojminevprimal;
2918 
2919  lastentry = startXrow[nblocks][i];
2920  }
2921  /* add missing entries at the end */
2922  for (j = lastentry + 1; j < 2 * nrows + 2 * nvars; j++)
2923  {
2924  assert( startXnblocknonz[nblocks] < 2 * nrows + 2 * nvars );
2925  startXrow[nblocks][startXnblocknonz[nblocks]] = j;
2926  startXcol[nblocks][startXnblocknonz[nblocks]] = j;
2927  startXval[nblocks][startXnblocknonz[nblocks]] = relaxdata->warmstartprojminevprimal;
2928  startXnblocknonz[nblocks]++;
2929  }
2930  }
2931 
2932  /* take convex combination for LP block */
2933  if ( SCIPisGT(scip, relaxdata->warmstartipfactor, 0.0) )
2934  {
2935  if ( relaxdata->warmstartiptype == 1 )
2936  {
2937  int nsavedentries;
2938  int lastentry;
2939  int j;
2940 
2941  /* if warmstartprojpdsame is true we use the computed value, otherwise we use the maximum of this block, which is one */
2942  if ( ! relaxdata->warmstartprojpdsame )
2943  identitydiagonal = relaxdata->warmstartipfactor;
2944 
2945  /* sort indices by row/col; TODO: check if this is necessary */
2946  SCIPsortIntIntReal(startXrow[nblocks], startXcol[nblocks], startXval[nblocks], startXnblocknonz[nblocks]);
2947 
2948  /* iterate over all entries */
2949  nsavedentries = startXnblocknonz[nblocks];
2950  lastentry = 0;
2951 
2952  for (i = 0; i < nsavedentries; i++)
2953  {
2954  assert( startXrow[nblocks][i] == startXcol[nblocks][i] ); /* this is the LP-block */
2955  /* if some entries are missing, we add them at the end */
2956  for (j = lastentry + 1; j < startXrow[nblocks][i]; j++)
2957  {
2958  assert( startXnblocknonz[nblocks] < 2 * nrows + 2 * nvars );
2959  startXrow[nblocks][startXnblocknonz[nblocks]] = j;
2960  startXcol[nblocks][startXnblocknonz[nblocks]] = j;
2961  /* if warmstartprojpdsame is true we use the computed value, otherwise we use the maximum of this block, which is one */
2962  if ( relaxdata->warmstartprojpdsame )
2963  startXval[nblocks][startXnblocknonz[nblocks]] = identitydiagonal;
2964  else
2965  startXval[nblocks][startXnblocknonz[nblocks]] = relaxdata->warmstartipfactor;
2966  startXnblocknonz[nblocks]++;
2967  }
2968  /* we only take the convex combination if the value is less than one, since the maxblockentry is equal to the value
2969  * otherwise, so taking the convex combination doesn't change anything in that case (unless warmstarprojpdsame)
2970  */
2971  if ( relaxdata->warmstartprojpdsame )
2972  startXval[b][i] = (1 - relaxdata->warmstartipfactor) * startXval[b][i] + identitydiagonal;
2973  else if ( SCIPisLT(scip, startXval[b][i], 1.0) )
2974  startXval[b][i] = (1 - relaxdata->warmstartipfactor) * startXval[b][i] + relaxdata->warmstartipfactor;
2975 
2976  lastentry = startXrow[nblocks][i];
2977  }
2978  /* add missing entries at the end */
2979  for (j = lastentry + 1; j < 2 * nrows + 2 * nvars; j++)
2980  {
2981  assert( startXnblocknonz[nblocks] < 2 * nrows + 2 * nvars );
2982  startXrow[nblocks][startXnblocknonz[nblocks]] = j;
2983  startXcol[nblocks][startXnblocknonz[nblocks]] = j;
2984  startXval[nblocks][startXnblocknonz[nblocks]] = identitydiagonal;
2985  startXnblocknonz[nblocks]++;
2986  }
2987  }
2988  else if ( relaxdata->warmstartiptype == 2 )
2989  {
2990  /* iterate once over all entries to multiply them with (1 - warmstartipfactor) */
2991  for (i = 0; i < startXnblocknonz[nblocks]; i++)
2992  startXval[nblocks][i] *= 1 - relaxdata->warmstartipfactor;
2993 
2994  /* merge the scaled interior point array into the warmstart array */
2995  SCIP_CALL( SCIPsdpVarfixerMergeArrays(SCIPblkmem(scip), SCIPepsilon(scip), relaxdata->ipXrow[nblocks],
2996  relaxdata->ipXcol[nblocks], relaxdata->ipXval[nblocks], relaxdata->ipXnblocknonz[nblocks], TRUE,
2997  relaxdata->warmstartipfactor, startXrow[nblocks], startXcol[nblocks], startXval[nblocks],
2998  &(startXnblocknonz[nblocks]), startXnblocknonz[nblocks] + relaxdata->ipXnblocknonz[nblocks]) );
2999  }
3000 
3001  /* take the convex combination for the dual (in this case we do not need to check for missing entries since we added all of them ourselves) */
3002  if ( relaxdata->warmstartiptype == 1 )
3003  {
3004  for (r = 0; r < nrows; r++)
3005  {
3006  /* for the project we just set all values smaller than minev to minev */
3007  if ( relaxdata->warmstartiptype == 1 && relaxdata->warmstartproject == 3 && SCIPisLT(scip, startZval[b][2*r], relaxdata->warmstartprojminevdual) )
3008  startZval[nblocks][2*r] = relaxdata->warmstartprojminevdual;
3009  /* we only take the convex combination if the value is less than one, since the maxblockentry is equal to the value
3010  * otherwise, so taking the convex combination doesn't change anything in that case (unless projpdsame)
3011  */
3012  else if ( relaxdata->warmstartiptype == 1 && (SCIPisLT(scip, startZval[nblocks][2*r], 1.0) || relaxdata->warmstartprojpdsame) )
3013  {
3014  /* since we want the value to be strictly positive, if the original entry is negative we just set it to identitydiagonal */
3015  if ( SCIPisLT(scip, startZval[nblocks][2*r], 0.0) )
3016  startZval[nblocks][2*r] = identitydiagonal;
3017  else
3018  startZval[nblocks][2*r] = (1 - relaxdata->warmstartipfactor) * startZval[nblocks][2*r] + identitydiagonal;
3019  }
3020 
3021  if ( relaxdata->warmstartiptype == 1 && relaxdata->warmstartproject == 3 && SCIPisLT(scip, startZval[nblocks][2*r + 1], relaxdata->warmstartprojminevdual) )
3022  startZval[nblocks][2*r + 1] = relaxdata->warmstartprojminevdual;
3023  else if ( relaxdata->warmstartiptype == 1 && (SCIPisLT(scip, startZval[nblocks][2*r + 1], 1.0) || relaxdata->warmstartprojpdsame) )
3024  {
3025  /* since we want the value to be strictly positive, if the original entry is negative we just set it to identitydiagonal */
3026  if ( SCIPisLT(scip, startZval[nblocks][2*r + 1], 0.0) )
3027  startZval[nblocks][2*r + 1] = identitydiagonal;
3028  else
3029  startZval[nblocks][2*r + 1] = (1 - relaxdata->warmstartipfactor) * startZval[nblocks][2*r + 1] + identitydiagonal;
3030  }
3031  }
3032 
3033  for (v = 0; v < nvars; v++)
3034  {
3035  if ( relaxdata->warmstartiptype == 1 && relaxdata->warmstartproject == 3 && SCIPisLT(scip, startZval[nblocks][2*nrows + 2*v], relaxdata->warmstartprojminevdual) )
3036  startZval[nblocks][2*nrows + 2*v] = relaxdata->warmstartprojminevdual;
3037  else if ( relaxdata->warmstartiptype == 1 && (SCIPisLT(scip, startZval[nblocks][2*nrows + 2*v], 1.0) || relaxdata->warmstartprojpdsame) )
3038  {
3039  /* since we want the value to be strictly positive, if the original entry is negative we just set it to identitydiagonal */
3040  if ( SCIPisLT(scip, startZval[nblocks][2*nrows + 2*v], 0.0) )
3041  startZval[nblocks][2*nrows + 2*v] = identitydiagonal;
3042  else
3043  startZval[nblocks][2*nrows + 2*v] = (1 - relaxdata->warmstartipfactor) * startZval[nblocks][2*nrows + 2*v] + identitydiagonal;
3044  }
3045 
3046  if ( relaxdata->warmstartiptype == 1 && relaxdata->warmstartproject == 3 && SCIPisLT(scip, startZval[nblocks][2*nrows + 2*v + 1], relaxdata->warmstartprojminevdual) )
3047  startZval[nblocks][2*nrows + 2*v + 1] = relaxdata->warmstartprojminevdual;
3048  else if ( relaxdata->warmstartiptype == 1 && (SCIPisLT(scip, startZval[nblocks][2*nrows + 2*v + 1], 1.0) || relaxdata->warmstartprojpdsame) )
3049  {
3050  /* since we want the value to be strictly positive, if the original entry is negative we just set it to identitydiagonal */
3051  if ( SCIPisLT(scip, startZval[nblocks][2*nrows + 2*v + 1], 0.0) )
3052  startZval[nblocks][2*nrows + 2*v + 1] = identitydiagonal;
3053  else
3054  startZval[nblocks][2*nrows + 2*v + 1] = (1 - relaxdata->warmstartipfactor) * startZval[nblocks][2*nrows + 2*v + 1] + identitydiagonal;
3055  }
3056  }
3057  }
3058  else if ( relaxdata->warmstartiptype == 2 )
3059  {
3060  /* iterate once over all entries to multiply them with (1 - warmstartipfactor) */
3061  for (i = 0; i < startZnblocknonz[nblocks]; i++)
3062  startZval[nblocks][i] *= 1 - relaxdata->warmstartipfactor;
3063 
3064  /* merge the scaled interior point array into the warmstart array */
3065  SCIP_CALL( SCIPsdpVarfixerMergeArrays(SCIPblkmem(scip), SCIPepsilon(scip), relaxdata->ipZrow[nblocks],
3066  relaxdata->ipZcol[nblocks], relaxdata->ipZval[nblocks], relaxdata->ipZnblocknonz[nblocks], TRUE,
3067  relaxdata->warmstartipfactor, startZrow[nblocks], startZcol[nblocks], startZval[nblocks],
3068  &(startZnblocknonz[nblocks]), startZnblocknonz[nblocks] + relaxdata->ipZnblocknonz[nblocks]) );
3069  }
3070  }
3071  }
3072 
3073 #ifdef SCIP_PRINT_WARMSTART
3074  SCIPdebugMsg(scip, "warmstart using the following point:\n");
3075  nblocks = SCIPconshdlrGetNConss(relaxdata->sdpconshdlr) + SCIPconshdlrGetNConss(relaxdata->sdprank1conshdlr);
3076  for (i = 0; i < nvars; i++)
3077  SCIPdebugMsg(scip, "y[%d]=%f\n", i, starty[i]);
3078 
3080  {
3081  for (b = 0; b < nblocks + 1; b++)
3082  {
3083  SCIPdebugMsg(scip, "dual block %d\n", b);
3084  for (i = 0; i < startZnblocknonz[b]; i++)
3085  {
3086  SCIPdebugMsg(scip, "Z(%d,%d)=%f\n", startZrow[b][i], startZcol[b][i], startZval[b][i]);
3087  }
3088  }
3089  for (b = 0; b < nblocks + 1; b++)
3090  {
3091  SCIPdebugMsg(scip, "primal block %d\n", b);
3092  for (i = 0; i < startXnblocknonz[b]; i++)
3093  {
3094  SCIPdebugMsg(scip, "X(%d,%d)=%f\n", startXrow[b][i], startXcol[b][i], startXval[b][i]);
3095  }
3096  }
3097  }
3098 #endif
3099 
3100  /* solve with given starting point */
3101  SCIP_CALL( SCIPsdpiSolve(sdpi, starty, startZnblocknonz, startZrow, startZcol, startZval, startXnblocknonz, startXrow,
3102  startXcol, startXval, startsetting, enforceslater, timelimit) );
3103 
3105  {
3106  SCIP_CONSHDLR* sdpconshdlr;
3107  SCIP_CONSHDLR* sdprank1conshdlr;
3108 
3109  sdpconshdlr = relaxdata->sdpconshdlr;
3110  sdprank1conshdlr = relaxdata->sdprank1conshdlr;
3111  nblocks = SCIPconshdlrGetNConss(sdpconshdlr) + SCIPconshdlrGetNConss(sdprank1conshdlr) + 1; /* +1 for LP block */
3112 
3113  assert( startXval != NULL );
3114  assert( startXcol != NULL );
3115  assert( startXrow != NULL );
3116  assert( startZval != NULL );
3117  assert( startZcol != NULL );
3118  assert( startZrow != NULL );
3119 
3120  /* free memory */
3121  for (b = 0; b < nblocks; b++)
3122  {
3123  SCIPfreeBufferArray(scip, &startXval[b]);
3124  SCIPfreeBufferArray(scip, &startXcol[b]);
3125  SCIPfreeBufferArray(scip, &startXrow[b]);
3126  SCIPfreeBufferArray(scip, &startZval[b]);
3127  SCIPfreeBufferArray(scip, &startZcol[b]);
3128  SCIPfreeBufferArray(scip, &startZrow[b]);
3129  }
3130 
3131  SCIPfreeBufferArray(scip, &startXval);
3132  SCIPfreeBufferArray(scip, &startXcol);
3133  SCIPfreeBufferArray(scip, &startXrow);
3134  SCIPfreeBufferArray(scip, &startXnblocknonz);
3135  SCIPfreeBufferArray(scip, &startZval);
3136  SCIPfreeBufferArray(scip, &startZcol);
3137  SCIPfreeBufferArray(scip, &startZrow);
3138  SCIPfreeBufferArray(scip, &startZnblocknonz);
3139  SCIPfreeBufferArray(scip, &sdpblocks);
3140  }
3141  SCIPfreeBufferArray(scip, &starty);
3142  }
3143  }
3144 
3145  solved:
3146 
3147  relaxdata->lastsdpnode = SCIPnodeGetNumber(SCIPgetCurrentNode(scip));
3148 
3149  /* update calls, iterations and stability numbers (only if the SDP-solver was actually called) */
3150  SCIP_CALL( updateSDPStatistics(relaxdata) );
3151 
3152  /* remember settings */
3153  if ( ! (strcmp(SCIPsdpiGetSolverName(), "DSDP") == 0) && ! (strstr(SCIPsdpiGetSolverName(), "MOSEK") != NULL) )
3154  {
3155  SCIP_SDPSOLVERSETTING usedsetting;
3156  SCIP_CALL( SCIPsdpiSettingsUsed(relaxdata->sdpi, &usedsetting) );
3157 
3158  (void) SCIPsnprintf(saveconsname, SCIP_MAXSTRLEN, "savedsettings_node_%d", SCIPnodeGetNumber(SCIPgetCurrentNode(scip)));
3159  SCIP_CALL( createConsSavedsdpsettings(scip, &savedsetting, saveconsname, usedsetting) );
3160  SCIP_CALL( SCIPaddCons(scip, savedsetting) );
3161  SCIP_CALL( SCIPreleaseCons(scip, &savedsetting) );
3162  }
3163 
3164  if ( ! SCIPsdpiWasSolved(sdpi) )
3165  relaxdata->feasible = FALSE;
3166 
3167  if ( SCIPinProbing(scip) )
3168  relaxdata->probingsolved = SCIPsdpiWasSolved(sdpi) && ( ! SCIPsdpiIsTimelimExc(sdpi) );
3169  else
3170  relaxdata->origsolved = SCIPsdpiSolvedOrig(sdpi) && ( ! SCIPsdpiIsTimelimExc(sdpi) );
3171 
3172  if ( SCIPsdpiIsAcceptable(sdpi) )
3173  {
3174 #ifdef SCIP_MORE_DEBUG /* print the optimal solution */
3175  {
3176  int sollength;
3177  SCIP_CALL( SCIPallocBufferArray(scip, &solforscip, nvars) );
3178  sollength = nvars;
3179  SCIP_CALL( SCIPsdpiGetSol(sdpi, &objforscip, solforscip, &sollength) ); /* get both the objective and the solution from the SDP solver */
3180 
3181  assert( sollength == nvars ); /* If this isn't true any longer, the getSol-call was unsuccessfull, because the given array wasn't long enough,
3182  * but this can't happen, because the array has enough space for all SDP variables. */
3183 
3184  if ( SCIPsdpiFeasibilityKnown(sdpi) )
3185  {
3186  SCIPdebugMsg(scip, "optimal solution: objective = %f, dual feasible: %u, primal feasible: %u.\n",
3187  objforscip, SCIPsdpiIsDualFeasible(sdpi), SCIPsdpiIsPrimalFeasible(sdpi));
3188  }
3189  else
3190  {
3191  SCIPdebugMsg(scip, "The solver could not determine feasibility ! ");
3192  }
3193 
3194  /* output solution */
3195  for (i = 0; i < nvars; ++i)
3196  {
3197  SCIPdebugMsg(scip, "<%s> = %f\n", SCIPvarGetName(vars[i]), solforscip[i]);
3198  }
3199  SCIPfreeBufferArray(scip, &solforscip);
3200  }
3201 #endif
3202 
3203  if ( SCIPsdpiIsDualInfeasible(sdpi) )
3204  {
3205  SCIPdebugMsg(scip, "Node cut off due to infeasibility.\n");
3206  relaxdata->feasible = FALSE;
3207  *result = SCIP_CUTOFF;
3208  return SCIP_OKAY;
3209  }
3210  else if ( SCIPsdpiIsObjlimExc(sdpi) )
3211  {
3212  SCIPdebugMsg(scip, "Node cut off due to objective limit.\n");
3213  relaxdata->feasible = FALSE;
3214  *result = SCIP_CUTOFF;
3215  return SCIP_OKAY;
3216  }
3217  else if ( SCIPsdpiIsDualUnbounded(sdpi) )
3218  {
3219  SCIPdebugMsg(scip, "Node unbounded.");
3220  relaxdata->feasible = TRUE;
3221  *result = SCIP_SUCCESS;
3222  *lowerbound = -SCIPinfinity(scip);
3223  return SCIP_OKAY;
3224  }
3225  else if ( SCIPsdpiIsPrimalFeasible(sdpi) && SCIPsdpiIsDualFeasible(sdpi) )
3226  {
3227  SCIP_SOL* scipsol; /* TODO: eliminate this from warmstart and save array instead */
3228  SCIP_SOL* preoptimalsol = NULL;
3229  SCIP_CONS* savedcons;
3230  int slength;
3231  SCIP_Bool preoptimalsolsuccess;
3232 
3233  /* get solution w.r.t. SCIP variables */
3234  SCIP_CALL( SCIPallocBufferArray(scip, &solforscip, nvars) );
3235  slength = nvars;
3236  SCIP_CALL( SCIPsdpiGetSol(sdpi, &objforscip, solforscip, &slength) ); /* get both the objective and the solution from the SDP solver */
3237 
3238  assert( slength == nvars ); /* If this isn't true any longer, the getSol-Call was unsuccessfull, because the given array wasn't long enough,
3239  * but this can't happen, because the array has enough space for all sdp variables. */
3240 
3241  /* create SCIP solution */
3242  SCIP_CALL( SCIPcreateSol(scip, &scipsol, NULL) );
3243  SCIP_CALL( SCIPsetSolVals(scip, scipsol, nvars, vars, solforscip) );
3244 
3245  *lowerbound = objforscip;
3246  relaxdata->objval = objforscip;
3247 
3248  /* copy solution */
3249 #if ( SCIP_VERSION >= 700 || (SCIP_VERSION >= 602 && SCIP_SUBVERSION > 0) )
3250  SCIP_CALL( SCIPsetRelaxSolVals(scip, relax, nvars, vars, solforscip, TRUE) );
3251 #else
3252  SCIP_CALL( SCIPsetRelaxSolVals(scip, nvars, vars, solforscip, TRUE) );
3253 #endif
3254 
3255  relaxdata->feasible = TRUE;
3256  *result = SCIP_SUCCESS;
3257  preoptimalsolsuccess = FALSE;
3258 
3259  /* save solution for warmstarts (only if we did not use the penalty formulation, since this would change the problem structure) */
3260  if ( relaxdata->warmstart && SCIPsdpiSolvedOrig(relaxdata->sdpi) )
3261  {
3262  SCIP_Real maxprimalentry;
3263  int* startXnblocknonz = NULL;
3264  int** startXrow = NULL;
3265  int** startXcol = NULL;
3266  SCIP_Real** startXval = NULL;
3267  char consname[SCIP_MAXSTRLEN];
3268 #ifndef NDEBUG
3269  int snprintfreturn; /* this is used to assert that the SCIP string concatenation works */
3270 #endif
3271 
3272  /* use preoptimal solution if using DSDP and parameter is set accordingly */
3273  if ( relaxdata->warmstartpreoptsol )
3274  {
3275  if ( strcmp(SCIPsdpiGetSolverName(), "DSDP") == 0.0 || strcmp(SCIPsdpiGetSolverName(), "SDPA") == 0.0 )
3276  {
3277  SCIP_Real* preoptimalvec;
3278  int nvarsgiven;
3279 
3280  SCIP_CALL( SCIPallocBufferArray(scip, &preoptimalvec, nvars) );
3281  nvarsgiven = nvars;
3282 
3284  {
3285  maxprimalentry = 0.0;
3286  if ( relaxdata->warmstartprimaltype == 3 )
3287  {
3288  nblocks = SCIPconshdlrGetNConss(relaxdata->sdpconshdlr) + SCIPconshdlrGetNConss(relaxdata->sdprank1conshdlr) + 1; /* +1 for the LP part */
3289  SCIP_CALL( SCIPallocBufferArray(scip, &startXnblocknonz, nblocks) );
3290 
3291  /* get amount of memory to allocate for row/col/val from sdpi */
3292  SCIP_CALL( SCIPsdpiGetPreoptimalPrimalNonzeros(relaxdata->sdpi, nblocks, startXnblocknonz) );
3293 
3294  /* check if the primal matrix exists, otherwise skip creation of the savedsol contraint */
3295  if ( startXnblocknonz[0] > -1 )
3296  {
3297  preoptimalsolsuccess = TRUE;
3298 
3299  SCIP_CALL( SCIPallocBufferArray(scip, &startXrow, nblocks) );
3300  SCIP_CALL( SCIPallocBufferArray(scip, &startXcol, nblocks) );
3301  SCIP_CALL( SCIPallocBufferArray(scip, &startXval, nblocks) );
3302 
3303  /* allocate memory for different blocks in row/col/val */
3304  for (b = 0; b < nblocks; b++)
3305  {
3306  SCIP_CALL( SCIPallocBufferArray(scip, &startXrow[b], startXnblocknonz[b]) );
3307  SCIP_CALL( SCIPallocBufferArray(scip, &startXcol[b], startXnblocknonz[b]) );
3308  SCIP_CALL( SCIPallocBufferArray(scip, &startXval[b], startXnblocknonz[b]) );
3309  }
3310 
3311  SCIP_CALL( SCIPsdpiGetPreoptimalSol(relaxdata->sdpi, &preoptimalsolsuccess, preoptimalvec, &nvarsgiven,
3312  nblocks, startXnblocknonz, startXrow, startXcol, startXval) );
3313  }
3314  else
3315  preoptimalsolsuccess = FALSE;
3316  }
3317  else
3318  {
3319  nblocks = 0;
3320  maxprimalentry = SCIPsdpiGetMaxPrimalEntry(relaxdata->sdpi);
3321  }
3322  }
3323  else
3324  {
3325  maxprimalentry = 0.0;
3326  SCIP_CALL( SCIPsdpiGetPreoptimalSol(relaxdata->sdpi, &preoptimalsolsuccess, preoptimalvec, &nvarsgiven,
3327  -1, NULL, NULL, NULL, NULL) );
3328  nblocks = 0;
3329  }
3330 
3331  if ( preoptimalsolsuccess )
3332  {
3333  assert( nvarsgiven == nvars ); /* length of solution should be nvars */
3334 
3335  /* create SCIP solution */
3336  SCIP_CALL( SCIPcreateSol(scip, &preoptimalsol, NULL) );
3337  SCIP_CALL( SCIPsetSolVals(scip, preoptimalsol, nvars, vars, preoptimalvec) );
3338  }
3339 
3340  SCIPfreeBufferArray(scip, &preoptimalvec);
3341  }
3342  else
3343  {
3344  SCIPerrorMessage("Warmstarting with preoptimal solutions currently only supported for DSDP and SDPA\n");
3345  return SCIP_LPERROR;
3346  }
3347  }
3348  else if ( SCIPsdpiDoesWarmstartNeedPrimal() )
3349  {
3350  maxprimalentry = 0.0;
3351  if ( relaxdata->warmstartprimaltype == 3 )
3352  {
3353  nblocks = SCIPconshdlrGetNConss(relaxdata->sdpconshdlr) + SCIPconshdlrGetNConss(relaxdata->sdprank1conshdlr) + 1; /* +1 for the LP part */
3354  SCIP_CALL( SCIPallocBufferArray(scip, &startXnblocknonz, nblocks) );
3355  SCIP_CALL( SCIPallocBufferArray(scip, &startXrow, nblocks) );
3356  SCIP_CALL( SCIPallocBufferArray(scip, &startXcol, nblocks) );
3357  SCIP_CALL( SCIPallocBufferArray(scip, &startXval, nblocks) );
3358 
3359  /* get amount of memory to allocate for row/col/val from sdpi */
3360  SCIP_CALL( SCIPsdpiGetPrimalNonzeros(relaxdata->sdpi, nblocks, startXnblocknonz) );
3361 
3362  /* allocate memory for different blocks in row/col/val */
3363  for (b = 0; b < nblocks; b++)
3364  {
3365  SCIP_CALL( SCIPallocBufferArray(scip, &startXrow[b], startXnblocknonz[b]) );
3366  SCIP_CALL( SCIPallocBufferArray(scip, &startXcol[b], startXnblocknonz[b]) );
3367  SCIP_CALL( SCIPallocBufferArray(scip, &startXval[b], startXnblocknonz[b]) );
3368  }
3369  SCIP_CALL( SCIPsdpiGetPrimalMatrix(sdpi, nblocks, startXnblocknonz, startXrow, startXcol, startXval) );
3370  }
3371  else
3372  {
3373  nblocks = 0;
3374  maxprimalentry = SCIPsdpiGetMaxPrimalEntry(relaxdata->sdpi);
3375  }
3376  }
3377  else
3378  {
3379  maxprimalentry = 0.0;
3380  nblocks = 0;
3381  }
3382 #ifndef NDEBUG
3383  snprintfreturn = SCIPsnprintf(consname, SCIP_MAXSTRLEN, "saved_relax_sol_%d", SCIPnodeGetNumber(SCIPgetCurrentNode(scip)));
3384  assert( snprintfreturn < SCIP_MAXSTRLEN ); /* check whether name fit into string */
3385 #else
3386  (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "saved_relax_sol_%d", SCIPnodeGetNumber(SCIPgetCurrentNode(scip)));
3387 #endif
3388  if ( relaxdata->warmstartpreoptsol )
3389  {
3390  /* only create constraint if the preoptimal solution exists, otherwise we don't want to warmstart at all */
3391  if ( preoptimalsolsuccess )
3392  {
3393  SCIP_CALL( createConsSavesdpsol(scip, &savedcons, consname, SCIPnodeGetNumber(SCIPgetCurrentNode(scip)), preoptimalsol,
3394  maxprimalentry, nblocks, startXnblocknonz, startXrow, startXcol, startXval) );
3395 
3396  SCIP_CALL( SCIPaddCons(scip, savedcons) );
3397  SCIP_CALL( SCIPreleaseCons(scip, &savedcons) );
3398  }
3399  }
3400  else
3401  {
3402  SCIP_CALL( createConsSavesdpsol(scip, &savedcons, consname, SCIPnodeGetNumber(SCIPgetCurrentNode(scip)), scipsol,
3403  maxprimalentry, nblocks, startXnblocknonz, startXrow, startXcol, startXval) );
3404 
3405  SCIP_CALL( SCIPaddCons(scip, savedcons) );
3406  SCIP_CALL( SCIPreleaseCons(scip, &savedcons) );
3407  }
3408 
3409  if ( SCIPsdpiDoesWarmstartNeedPrimal() && relaxdata->warmstartprimaltype == 3 )
3410  {
3411  /* free memory for primal matrix */
3412  assert( startXnblocknonz != NULL );
3413  if ( startXnblocknonz[0] > 1 ) /* no memory was allocated if computation of preoptimal solution failed */
3414  {
3415  for (b = 0; b < nblocks; b++)
3416  {
3417  assert( startXval != NULL ); /* for lint */
3418  assert( startXcol != NULL ); /* for lint */
3419  assert( startXrow != NULL ); /* for lint */
3420 
3421  SCIPfreeBufferArrayNull(scip, &startXval[b]);
3422  SCIPfreeBufferArrayNull(scip, &startXcol[b]);
3423  SCIPfreeBufferArrayNull(scip, &startXrow[b]);
3424  }
3425  SCIPfreeBufferArrayNull(scip, &startXval);
3426  SCIPfreeBufferArrayNull(scip, &startXcol);
3427  SCIPfreeBufferArrayNull(scip, &startXrow);
3428  }
3429  SCIPfreeBufferArrayNull(scip, &startXnblocknonz);
3430  }
3431  }
3432 
3433  SCIPfreeBufferArray(scip, &solforscip);
3434  SCIP_CALL( SCIPfreeSol(scip, &scipsol) );
3435  if ( preoptimalsolsuccess )
3436  {
3437  SCIP_CALL( SCIPfreeSol(scip, &preoptimalsol) );
3438  }
3439  }
3440  }
3441  else
3442  {
3443  SCIP_Real objlb;
3444 
3445  if ( SCIPsdpiIsTimelimExc(relaxdata->sdpi) )
3446  {
3447  *result = SCIP_DIDNOTRUN;
3448  return SCIP_OKAY;
3449  }
3450 
3451  /* if we used the penalty approach, we might have calculated a good lower bound, even if we did not produce a feasible solution, otherwise we
3452  * keep the current bound, if the current bound is -infty, we abort */
3453  objlb = -SCIPinfinity(scip);
3454  SCIP_CALL( SCIPsdpiGetLowerObjbound(relaxdata->sdpi, &objlb) );
3455  if ( ! SCIPisInfinity(scip, objlb) )
3456  {
3457  *lowerbound = objlb;
3458  SCIPdebugMsg(scip, "The relaxation could not be solved, using best computed bound from penalty formulation.\n");
3459  }
3460  else if ( ! SCIPisInfinity(scip, -1 * SCIPnodeGetLowerbound(SCIPgetCurrentNode(scip))) )
3461  {
3462  *lowerbound = SCIPnodeGetLowerbound(SCIPgetCurrentNode(scip));
3463  SCIPdebugMsg(scip, "The relaxation could not be solved, keeping old bound.\n");
3464  }
3465  else
3466  {
3467  *result = SCIP_SUSPENDED;
3468  SCIPerrorMessage("The relaxation of the root node could not be solved, so there is no hope to solve this instance.\n");
3469  return SCIP_ERROR;
3470  }
3471 
3472  *result = SCIP_SUCCESS;
3473  return SCIP_OKAY;
3474  }
3475 
3476  return SCIP_OKAY;
3477 }
3478 
3480 static
3481 SCIP_Bool allVarsFixed(
3482  SCIP* scip
3483  )
3484 {
3485  SCIP_VAR** vars;
3486  int i;
3487 
3488  assert( scip != NULL );
3489 
3490  vars = SCIPgetVars(scip);
3491 
3492  /* try to find a variable that is not fixed */
3493  for (i = 0; i < SCIPgetNVars(scip); i++)
3494  {
3495  if ( SCIPisLT(scip, SCIPvarGetLbLocal(vars[i]), SCIPvarGetUbLocal(vars[i])) )
3496  return FALSE;
3497  }
3498 
3499  /* if no variable with lower bound strictly lower than upper bound has been found, all variables are fixed */
3500  return TRUE;
3501 }
3502 
3504 static
3505 SCIP_DECL_RELAXEXEC(relaxExecSdp)
3506 {
3507  SCIP_RELAXDATA* relaxdata;
3508  SCIP_VAR** vars;
3509  SCIP_Real* ubs;
3510  SCIP_Bool cutoff;
3511  SCIP_SOL* scipsol; /* TODO: eliminate this */
3512  int nconss;
3513  int nvars;
3514  int i;
3515 #ifdef SCIP_EVEN_MORE_DEBUG
3516  SCIP_VAR** varsfordebug = SCIPgetVars(scip);
3517  const int nvarsfordebug = SCIPgetNVars(scip);
3518 #endif
3519 
3520  SCIPdebugMsg(scip, "Calling relaxExecSdp.\n");
3521 
3522  relaxdata = SCIPrelaxGetData(relax);
3523  vars = SCIPgetVars(scip);
3524  nvars = SCIPgetNVars(scip);
3525 
3526  /* set the solved flags to false in case a timeout happens */
3527  relaxdata->origsolved = FALSE;
3528  relaxdata->probingsolved = FALSE;
3529 
3530  /* don't run again if we already solved the current node (except during probing), and we solved the correct problem */
3531  if ( (relaxdata->lastsdpnode == SCIPnodeGetNumber(SCIPgetCurrentNode(scip)) && ( ! SCIPinProbing(scip) ) ) && relaxdata->origsolved && ! relaxdata->resolve )
3532  {
3533  SCIP_COL** cols;
3534  SCIP_Real objforscip;
3535  SCIP_Real* solforscip;
3536  int ncols;
3537  int slength;
3538 
3539  SCIPdebugMsg(scip, "Already solved SDP-relaxation for node %ld, returning with SCIP_SUCCESS so that no other relaxator is called.\n",
3540  SCIPrelaxGetData(relax)->lastsdpnode);
3541 
3542  if ( SCIPsdpiIsDualUnbounded(relaxdata->sdpi) )
3543  {
3544  relaxdata->feasible = TRUE;
3545  *result = SCIP_SUCCESS;
3546  *lowerbound = -SCIPinfinity(scip);
3547  return SCIP_OKAY;
3548  }
3549 
3550  /* get solution w.r.t. SCIP variables */
3551  SCIP_CALL( SCIPallocBufferArray(scip, &solforscip, nvars) );
3552  slength = nvars;
3553  SCIP_CALL( SCIPsdpiGetSol(relaxdata->sdpi, &objforscip, solforscip, &slength) ); /* get both the objective and the solution from the SDP solver */
3554 
3555  assert( slength == nvars ); /* If this isn't true any longer, the getSol-Call was unsuccessfull, because the given array wasn't long enough,
3556  * but this can't happen, because the array has enough space for all sdp variables. */
3557 
3558  /* create SCIP solution */
3559  SCIP_CALL( SCIPcreateSol(scip, &scipsol, NULL) );
3560 #if ( SCIP_VERSION >= 700 || (SCIP_VERSION >= 602 && SCIP_SUBVERSION > 0) )
3561  SCIP_CALL( SCIPsetRelaxSolVals(scip, relax, nvars, vars, solforscip, TRUE) );
3562 #else
3563  SCIP_CALL( SCIPsetRelaxSolVals(scip, nvars, vars, solforscip, TRUE) );
3564 #endif
3565  *lowerbound = objforscip;
3566 
3567  /* copy solution */
3568  SCIP_CALL( SCIPgetLPColsData(scip, &cols, &ncols) );
3569  for (i = 0; i < ncols; i++)
3570  {
3571 #if ( SCIP_VERSION >= 700 || (SCIP_VERSION >= 602 && SCIP_SUBVERSION > 0) )
3572  SCIP_CALL( SCIPsetRelaxSolVal(scip, relax, SCIPcolGetVar(cols[i]), SCIPgetSolVal(scip, scipsol, SCIPcolGetVar(cols[i]))) );
3573 #else
3574  SCIP_CALL( SCIPsetRelaxSolVal(scip, SCIPcolGetVar(cols[i]), SCIPgetSolVal(scip, scipsol, SCIPcolGetVar(cols[i]))) );
3575 #endif
3576  }
3577 
3578 #if ( SCIP_VERSION >= 700 || (SCIP_VERSION >= 602 && SCIP_SUBVERSION > 0) )
3579  SCIP_CALL( SCIPmarkRelaxSolValid(scip, relax, TRUE) );
3580 #else
3581  SCIP_CALL( SCIPmarkRelaxSolValid(scip, TRUE) );
3582 #endif
3583  *result = SCIP_SUCCESS;
3584 
3585  SCIPfreeBufferArray(scip, &solforscip);
3586  SCIP_CALL( SCIPfreeSol(scip, &scipsol) );
3587 
3588  *result = SCIP_SUCCESS;
3589  return SCIP_OKAY;
3590  }
3591 
3592  /* construct the lp and make sure, that everything is where it should be */
3593  SCIP_CALL( SCIPconstructLP(scip, &cutoff) );
3594 
3595  if ( cutoff )
3596  {
3597  relaxdata->feasible = FALSE;
3598  *result = SCIP_CUTOFF;
3599  return SCIP_OKAY;
3600  }
3601 
3602  /* very important to call flushLP */
3603  SCIP_CALL( SCIPflushLP(scip) );
3604 
3605  /* get varmapper */
3606  nconss = SCIPgetNConss(scip);
3607 
3608 #ifdef SCIP_EVEN_MORE_DEBUG
3609  for (i = 0; i < nvarsfordebug; i++)
3610  {
3611  SCIPdebugMsg(scip, "variable %s: status = %u, integral = %u, bounds = [%f, %f]\n", SCIPvarGetName(varsfordebug[i]), SCIPvarGetStatus(varsfordebug[i]),
3612  SCIPvarIsIntegral(varsfordebug[i]), SCIPvarGetLbLocal(varsfordebug[i]), SCIPvarGetUbLocal(varsfordebug[i]));
3613  }
3614 #endif
3615 
3616  if ( nconss == 0 )
3617  {
3618  /* if there are no constraints, there is nothing to do */
3619  relaxdata->feasible = TRUE;
3620  *result = SCIP_DIDNOTRUN;
3621  return SCIP_OKAY;
3622  }
3623 
3624  if ( allVarsFixed(scip) )
3625  {
3626  SCIP_Bool feasible;
3627 
3628  /* if all variables, really all, are fixed, we give this fixed solution to SCIP */
3629 
3630  SCIP_CALL( SCIPallocBufferArray(scip, &ubs, nvars) );
3631 
3632  *lowerbound = 0.0;
3633  for (i = 0; i < nvars; i++)
3634  {
3635  ubs[i] = SCIPvarGetUbLocal(vars[i]);
3636  *lowerbound += SCIPvarGetObj(vars[i]) * ubs[i];
3637  assert( SCIPisFeasEQ(scip, SCIPvarGetUbLocal(vars[i]), SCIPvarGetLbLocal(vars[i])));
3638  }
3639 
3640  SCIPdebugMsg(scip, "EVERYTHING IS FIXED, objective value = %f\n", *lowerbound);
3641 
3642  SCIP_CALL( SCIPcreateSol(scip, &scipsol, NULL) );
3643  SCIP_CALL( SCIPsetSolVals(scip, scipsol, nvars, vars, ubs) );
3644 
3645  /* set the relaxation solution */
3646  for (i = 0; i < nvars; i++)
3647  {
3648 #if ( SCIP_VERSION >= 700 || (SCIP_VERSION >= 602 && SCIP_SUBVERSION > 0) )
3649  SCIP_CALL( SCIPsetRelaxSolVal(scip, relax, vars[i], SCIPvarGetLbLocal(vars[i])) );
3650 #else
3651  SCIP_CALL( SCIPsetRelaxSolVal(scip, vars[i], SCIPvarGetLbLocal(vars[i])) );
3652 #endif
3653  }
3654 #if ( SCIP_VERSION >= 700 || (SCIP_VERSION >= 602 && SCIP_SUBVERSION > 0) )
3655  SCIP_CALL( SCIPmarkRelaxSolValid(scip, relax, TRUE) );
3656 #else
3657  SCIP_CALL( SCIPmarkRelaxSolValid(scip, TRUE) );
3658 #endif
3659 
3660  /* check if the solution really is feasible */
3661  SCIP_CALL( SCIPcheckSol(scip, scipsol, FALSE, TRUE, TRUE, TRUE, TRUE, &feasible) );
3662 
3663  relaxdata->feasible = feasible;
3664 
3665  SCIP_CALL( SCIPfreeSol(scip, &scipsol) );
3666 
3667  SCIPfreeBufferArray(scip, &ubs);
3668 
3669  *result = SCIP_SUCCESS;
3670  return SCIP_OKAY;
3671  }
3672 
3673  /* update LP Data in Interface */
3674  SCIP_CALL( putLpDataInInterface(scip, relaxdata, TRUE, TRUE) );
3675 
3676  SCIP_CALL( calcRelax(scip, relax, result, lowerbound));
3677 
3678  return SCIP_OKAY;
3679 }
3680 
3681 
3684 static
3685 SCIP_DECL_RELAXINITSOL(relaxInitSolSdp)
3686 {
3687  SCIP_RELAXDATA* relaxdata;
3688  SCIP_RETCODE retcode;
3689  SCIP_VAR** vars;
3690  SCIP_Real givenpenaltyparam;
3691  SCIP_Real projminevprimal;
3692  SCIP_Real projminevdual;
3693  int nvars;
3694 
3695  assert( relax != NULL );
3696 
3697  relaxdata = SCIPrelaxGetData(relax);
3698  assert( relaxdata != NULL );
3699 
3700  relaxdata->objval = 0.0;
3701  relaxdata->origsolved = FALSE;
3702  relaxdata->probingsolved = FALSE;
3703  relaxdata->sdpcalls = 0;
3704  relaxdata->sdpinterfacecalls = 0;
3705  relaxdata->sdpiterations = 0;
3706  relaxdata->solvedfast = 0;
3707  relaxdata->solvedmedium = 0;
3708  relaxdata->solvedstable = 0;
3709  relaxdata->solvedpenalty = 0;
3710  relaxdata->stablewslater = 0;
3711  relaxdata->unstablewslater = 0;
3712  relaxdata->boundedwslater = 0;
3713  relaxdata->unsolvedwslater = 0;
3714  relaxdata->stablenoslater = 0;
3715  relaxdata->unsolvednoslater = 0;
3716  relaxdata->boundednoslater = 0;
3717  relaxdata->unsolvednoslater = 0;
3718  relaxdata->nslaterholds = 0;
3719  relaxdata->nnoslater = 0;
3720  relaxdata->nslatercheckfailed = 0;
3721  relaxdata->npslaterholds = 0;
3722  relaxdata->npnoslater = 0;
3723  relaxdata->npslatercheckfailed = 0;
3724  relaxdata->ndslaterholds = 0;
3725  relaxdata->ndnoslater = 0;
3726  relaxdata->ndslatercheckfailed = 0;
3727  relaxdata->nslaterinfeasible = 0;
3728  relaxdata->stableinfeasible = 0;
3729  relaxdata->unstableinfeasible = 0;
3730  relaxdata->penaltyinfeasible = 0;
3731  relaxdata->boundedinfeasible = 0;
3732  relaxdata->unsolvedinfeasible = 0;
3733  relaxdata->roundingprobinf = 0;
3734  relaxdata->primalroundfails = 0;
3735  relaxdata->dualroundfails = 0;
3736  relaxdata->roundstartsuccess = 0;
3737  relaxdata->roundingoptimal = 0;
3738  relaxdata->roundingcutoff = 0;
3739 
3740  if ( relaxdata->warmstart && relaxdata->warmstartproject == 4 )
3741  {
3742  if ( relaxdata->roundingprobtime == NULL )
3743  {
3744  SCIP_CALL( SCIPcreateClock(scip, &relaxdata->roundingprobtime) );
3745  }
3746  }
3747  else
3748  {
3749  assert( relaxdata->roundingprobtime == NULL );
3750  }
3751  relaxdata->unsolved = 0;
3752  relaxdata->feasible = FALSE;
3753 
3754  relaxdata->ipXexists = FALSE;
3755  relaxdata->ipZexists = FALSE;
3756 
3757  relaxdata->sdpconshdlr = SCIPfindConshdlr(scip, "SDP");
3758  if ( relaxdata->sdpconshdlr == NULL )
3759  return SCIP_PLUGINNOTFOUND;
3760 
3761  relaxdata->sdprank1conshdlr = SCIPfindConshdlr(scip, "SDPrank1");
3762  if ( relaxdata->sdprank1conshdlr == NULL )
3763  return SCIP_PLUGINNOTFOUND;
3764 
3765  nvars = SCIPgetNVars(scip);
3766  vars = SCIPgetVars(scip);
3767 
3768  /* all SCIPvars will be added to this list, and 3/4 seems like a good load factor (java uses this factor) */
3769  SCIP_CALL( SCIPsdpVarmapperCreate(scip, &(relaxdata->varmapper), (int) ceil(1.33 * nvars)) );
3770  SCIP_CALL( SCIPsdpVarmapperAddVars(scip, relaxdata->varmapper, nvars, vars) );
3771 
3772  if ( nvars > 0 )
3773  {
3774  SCIP_CALL( putSdpDataInInterface(scip, relaxdata->sdpi, relaxdata->varmapper, TRUE, FALSE) );
3775  }
3776 
3777  /* set the parameters of the SDP-Solver */
3778  retcode = SCIPsdpiSetRealpar(relaxdata->sdpi, SCIP_SDPPAR_GAPTOL, relaxdata->sdpsolvergaptol);
3779  if ( retcode == SCIP_PARAMETERUNKNOWN )
3780  {
3781  SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL,
3782  "SDP Solver <%s>: gaptol setting not available -- SCIP parameter has no effect.\n",
3784  }
3785  else
3786  {
3787  SCIP_CALL( retcode );
3788  }
3789 
3790  retcode = SCIPsdpiSetRealpar(relaxdata->sdpi, SCIP_SDPPAR_SDPSOLVERFEASTOL, relaxdata->sdpsolverfeastol);
3791  if ( retcode == SCIP_PARAMETERUNKNOWN )
3792  {
3793  SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL,
3794  "SDP Solver <%s>: sdpsolverfeastol setting not available -- SCIP parameter has no effect.\n",
3796  }
3797  else
3798  {
3799  SCIP_CALL( retcode );
3800  }
3801 
3802  retcode = SCIPsdpiSetRealpar(relaxdata->sdpi, SCIP_SDPPAR_EPSILON, SCIPepsilon(scip));
3803  if ( retcode == SCIP_PARAMETERUNKNOWN )
3804  {
3805  SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL,
3806  "SDP Solver <%s>: epsilon setting not available -- SCIP parameter has no effect.\n",
3808  }
3809  else
3810  {
3811  SCIP_CALL( retcode );
3812  }
3813 
3814  retcode = SCIPsdpiSetRealpar(relaxdata->sdpi, SCIP_SDPPAR_FEASTOL, SCIPfeastol(scip));
3815  if ( retcode == SCIP_PARAMETERUNKNOWN )
3816  {
3817  SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL,
3818  "SDP Solver <%s>: feastol setting not available -- SCIP parameter has no effect.\n",
3820  }
3821  else
3822  {
3823  SCIP_CALL( retcode );
3824  }
3825 
3826  /* set/compute the starting penalty parameter */
3827  if ( SCIPisGE(scip, relaxdata->penaltyparam, 0.0) )
3828  {
3829  retcode = SCIPsdpiSetRealpar(relaxdata->sdpi, SCIP_SDPPAR_PENALTYPARAM, relaxdata->penaltyparam);
3830  givenpenaltyparam = relaxdata->penaltyparam;
3831  if ( retcode == SCIP_PARAMETERUNKNOWN )
3832  {
3833  SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL,
3834  "SDP Solver <%s>: penaltyparam setting not available -- SCIP parameter has no effect\n",
3836  }
3837  else
3838  {
3839  SCIP_CALL( retcode );
3840  }
3841  }
3842  else
3843  {
3844  SCIP_Real maxcoeff;
3845  int v;
3846 
3847  /* compute the maximum coefficient in the objective */
3848  maxcoeff = 0.0;
3849  for (v = 0; v < nvars; v++)
3850  {
3851  if ( SCIPisGT(scip, REALABS(SCIPvarGetObj(vars[v])), maxcoeff) )
3852  maxcoeff = REALABS(SCIPvarGetObj(vars[v]));
3853  }
3854 
3855  SCIP_CALL( SCIPsdpiComputePenaltyparam(relaxdata->sdpi, maxcoeff, &givenpenaltyparam) );
3856  }
3857 
3858  /* set/compute the maximum penalty parameter */
3859  if ( SCIPisGE(scip, relaxdata->maxpenaltyparam, 0.0) )
3860  {
3861  retcode = SCIPsdpiSetRealpar(relaxdata->sdpi, SCIP_SDPPAR_MAXPENALTYPARAM, relaxdata->maxpenaltyparam);
3862 
3863  if ( retcode == SCIP_PARAMETERUNKNOWN )
3864  {
3865  SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL,
3866  "SDP Solver <%s>: maxpenaltyparam setting not available -- SCIP parameter has no effect.\n",
3868  }
3869  else
3870  {
3871  SCIP_CALL( retcode );
3872  }
3873 
3874  /* check if the starting value is not bigger than the maximum one, otherwise update it */
3875  if ( SCIPisLT(scip, givenpenaltyparam, relaxdata->maxpenaltyparam) )
3876  {
3877  SCIPdebugMsg(scip, "Penalty parameter %f overwritten by maxpenaltyparam %f!\n", givenpenaltyparam, relaxdata->maxpenaltyparam);
3878  SCIP_CALL( SCIPsdpiSetRealpar(relaxdata->sdpi, SCIP_SDPPAR_PENALTYPARAM, relaxdata->maxpenaltyparam) );
3879  }
3880  }
3881  else
3882  {
3883  SCIP_Real givenmaxpenaltyparam;
3884 
3885  SCIP_CALL( SCIPsdpiComputeMaxPenaltyparam(relaxdata->sdpi, givenpenaltyparam, &givenmaxpenaltyparam) );
3886  }
3887 
3888  /* set maximum number of penalty increasing rounds */
3889  retcode = SCIPsdpiSetIntpar(relaxdata->sdpi, SCIP_SDPPAR_NPENALTYINCR, relaxdata->npenaltyincr);
3890  if ( retcode == SCIP_PARAMETERUNKNOWN )
3891  {
3892  SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL,
3893  "SDP Solver <%s>: npenaltyincr setting not available -- SCIP parameter has no effect.\n",
3895  }
3896  else
3897  {
3898  SCIP_CALL( retcode );
3899  }
3900 
3901  /* set penalty-infeasibility-adjustment */
3902  retcode = SCIPsdpiSetRealpar(relaxdata->sdpi, SCIP_SDPPAR_PENINFEASADJUST, relaxdata->peninfeasadjust);
3903 
3904  if ( retcode == SCIP_PARAMETERUNKNOWN )
3905  {
3906  SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL,
3907  "SDP Solver <%s>: peninfeasadjust setting not available -- SCIP parameter has no effect.\n",
3909  }
3910  else
3911  {
3912  SCIP_CALL( retcode );
3913  }
3914 
3915  /* set/compute lambda star if SDPA is used as the SDP-Solver */
3916  if ( strcmp(SCIPsdpiGetSolverName(), "SDPA") == 0.0 )
3917  {
3918  if ( SCIPisGE(scip, relaxdata->lambdastar, 0.0) )
3919  {
3920  retcode = SCIPsdpiSetRealpar(relaxdata->sdpi, SCIP_SDPPAR_LAMBDASTAR, relaxdata->lambdastar);
3921  }
3922  else
3923  {
3924  SCIP_Real guess;
3925  SCIP_Real maxguess;
3926  SCIP_CONS** conss;
3927  int nconss;
3928  int c;
3929 
3930  /* iterate over all SDP-constraints to compute the biggest guess for lambdastar */
3931  conss = SCIPgetConss(scip);
3932  nconss = SCIPgetNConss(scip);
3933  maxguess = 0.0;
3934 
3935  for (c = 0; c < nconss; c++)
3936  {
3937  /* only check the SDP constraints (including SDPrank1-Constraints) */
3938  if ( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(conss[c])), "SDP") == 0 || strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(conss[c])), "SDPrank1") == 0 )
3939  {
3940  SCIP_CALL( SCIPconsSdpGuessInitialPoint(scip, conss[c], &guess) );
3941  if ( (! SCIPisInfinity(scip, maxguess) ) && SCIPisGT(scip, guess, maxguess) )
3942  maxguess = guess;
3943  }
3944  }
3945 
3946  SCIP_CALL( SCIPsdpiComputeLambdastar(relaxdata->sdpi, maxguess) );
3947  retcode = SCIPsdpiGetRealpar(relaxdata->sdpi, SCIP_SDPPAR_LAMBDASTAR, &relaxdata->lambdastar);
3948  }
3949  }
3950  else
3951  relaxdata->lambdastar = 1.0;
3952 
3953  if ( retcode == SCIP_PARAMETERUNKNOWN )
3954  {
3955  SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL,
3956  "SDP Solver <%s>: lambdastar setting not available -- SCIP parameter has no effect.\n",
3958  }
3959  else
3960  {
3961  SCIP_CALL( retcode );
3962  }
3963 
3964  /* set/compute minimum eigenvalue for projecting warmstarting points */
3965  SCIP_CALL( SCIPgetRealParam(scip, "relaxing/SDP/warmstartprminevpri", &projminevprimal) );
3966  SCIP_CALL( SCIPgetRealParam(scip, "relaxing/SDP/warmstartprminevdu", &projminevdual) );
3967 
3968  if ( SCIPisGE(scip, projminevprimal, 0.0) && SCIPisGE(scip, projminevdual, 0.0) ) /* TODO: maybe only do these computations if warmstart = TRUE? */
3969  {
3970  relaxdata->warmstartprojminevprimal = projminevprimal;
3971  relaxdata->warmstartprojminevdual = projminevdual;
3972  }
3973  else if ( SCIPisGE(scip, projminevprimal, 0.0) && relaxdata->warmstartprojpdsame )
3974  {
3975  relaxdata->warmstartprojminevprimal = projminevprimal;
3976  relaxdata->warmstartprojminevdual = projminevprimal;
3977  }
3978  else if ( SCIPisGE(scip, projminevdual, 0.0) && relaxdata->warmstartprojpdsame )
3979  {
3980  relaxdata->warmstartprojminevprimal = projminevdual;
3981  relaxdata->warmstartprojminevdual = projminevdual;
3982  }
3983  else
3984  {
3985  SCIP_CONSHDLR* sdpconshdlr;
3986  SCIP_CONSHDLR* sdprank1conshdlr;
3987  SCIP_CONS** sdpblocks;
3988  SCIP_CONS** sdporigblocks;
3989  SCIP_CONS** sdprank1blocks;
3990  int nsdpblocks;
3991  int nsdporigblocks;
3992  int nrank1blocks;
3993  int b;
3994  int c;
3995  int v;
3996  SCIP_Real maxsdprhs; /* note that we only take the maximum value of the SDP constraints, since these tend to be the most problematic */
3997  SCIP_Real maxobj;
3998  SCIP_Real maxsdpcoef; /* note that we only take the maximum value of the SDP constraints, since these tend to be the most problematic */
3999  SCIP_Real maxval;
4000  SCIP_Real sdpcoef;
4001 
4002  /* compute value as WARMSTART_PROJ_FACTOR * max{maxrhs, maxobj, maxsdpcoef} */
4003  sdpconshdlr = relaxdata->sdpconshdlr;
4004  sdprank1conshdlr = relaxdata->sdprank1conshdlr;
4005 
4006  nsdporigblocks = SCIPconshdlrGetNConss(sdpconshdlr);
4007  nrank1blocks = SCIPconshdlrGetNConss(sdprank1conshdlr);
4008  sdporigblocks = SCIPconshdlrGetConss(sdpconshdlr);
4009  sdprank1blocks = SCIPconshdlrGetConss(sdprank1conshdlr);
4010 
4011  nsdpblocks = nsdporigblocks + nrank1blocks;
4012 
4013  SCIP_CALL( SCIPallocBufferArray(scip, &sdpblocks, nsdpblocks) );
4014  for (c = 0; c < nsdporigblocks; ++c)
4015  sdpblocks[c] = sdporigblocks[c];
4016 
4017  for (c = 0; c < nrank1blocks; ++c)
4018  sdpblocks[nsdporigblocks + c] = sdprank1blocks[c];
4019 
4020  /* compute maxsdpcoef */
4021  maxsdpcoef = WARMSTART_PROJ_MINRHSOBJ;
4022  for (b = 0; b < nsdpblocks; b++)
4023  {
4024  sdpcoef = SCIPconsSdpGetMaxSdpCoef(scip, sdpblocks[b]);
4025  if ( SCIPisGT(scip, sdpcoef, maxsdpcoef) )
4026  maxsdpcoef = sdpcoef;
4027  }
4028  maxsdpcoef *= WARMSTART_PROJ_FACTOR_LHS; /* multiply by additional factor to account for summation of lhs entries */
4029 
4030  /* compute maxsdprhs */
4031  maxsdprhs = WARMSTART_PROJ_MINRHSOBJ;
4032  for (b = 0; b < nsdpblocks; b++)
4033  {
4034  if ( SCIPisGT(scip, SCIPconsSdpGetMaxConstEntry(scip, sdpblocks[b]), maxsdprhs) )
4035  maxsdprhs = SCIPconsSdpGetMaxConstEntry(scip, sdpblocks[b]);
4036  }
4037 
4038  /* compute maxobj */
4039  maxobj = WARMSTART_PROJ_MINRHSOBJ;
4040  for (v = 0; v < nvars; v++)
4041  {
4042  if ( SCIPisGT(scip, REALABS(SCIPvarGetObj(vars[v])), maxobj) )
4043  maxobj = REALABS(SCIPvarGetObj(vars[v]));
4044  }
4045 
4046  if ( relaxdata->warmstartprojpdsame )
4047  {
4048  maxval = SCIPisGT(scip, maxsdprhs, maxobj) ? maxsdprhs : maxobj;
4049  maxval = SCIPisGT(scip, maxsdpcoef, maxval) ? maxsdpcoef : maxval;
4050 
4051  relaxdata->warmstartprojminevprimal = WARMSTART_PROJ_FACTOR * maxval;
4052  relaxdata->warmstartprojminevdual = WARMSTART_PROJ_FACTOR * maxval;
4053 
4054  SCIPdebugMsg(scip, "Setting warmstartprojminev to %f\n", relaxdata->warmstartprojminevdual);
4055  }
4056  else
4057  {
4058  if ( ! SCIPisGE(scip, projminevprimal, 0.0) )
4059  {
4060  relaxdata->warmstartprojminevprimal = WARMSTART_PROJ_FACTOR_PRIMAL * (SCIPisGT(scip, maxobj, maxsdpcoef) ? maxobj : maxsdpcoef);
4061 
4062  SCIPdebugMsg(scip, "Setting warmstartprojminevprimal to %f\n", relaxdata->warmstartprojminevprimal);
4063  }
4064 
4065  if ( ! SCIPisGE(scip, projminevdual, 0.0) )
4066  {
4067  relaxdata->warmstartprojminevdual = WARMSTART_PROJ_FACTOR_PRIMAL * (SCIPisGT(scip, maxsdprhs, maxsdpcoef) ? maxsdprhs : maxsdpcoef);
4068 
4069  SCIPdebugMsg(scip, "Setting warmstartprojminevdual to %f\n", relaxdata->warmstartprojminevdual);
4070  }
4071  }
4072  SCIPfreeBufferArray(scip, &sdpblocks);
4073  }
4074 
4075  retcode = SCIPsdpiSetIntpar(relaxdata->sdpi, SCIP_SDPPAR_SDPINFO, (int) relaxdata->sdpinfo);
4076  if ( retcode == SCIP_PARAMETERUNKNOWN )
4077  {
4078  SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL,
4079  "SDP Solver <%s>: sdpinfo setting not available -- SCIP parameter has no effect.\n",
4081  }
4082  else
4083  {
4084  SCIP_CALL( retcode );
4085  }
4086 
4087  /* only try to set nthreads if the value differs from the default to prevent unnecessary warning messages for unknown parameter */
4088  if ( relaxdata->sdpsolverthreads != DEFAULT_SDPSOLVERTHREADS )
4089  {
4090  retcode = SCIPsdpiSetIntpar(relaxdata->sdpi, SCIP_SDPPAR_NTHREADS, relaxdata->sdpsolverthreads);
4091  if ( retcode == SCIP_PARAMETERUNKNOWN )
4092  {
4093  SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL,
4094  "SDP Solver <%s>: nthreads setting not available -- SCIP parameter has no effect.\n",
4096  }
4097  else
4098  {
4099  SCIP_CALL( retcode );
4100  }
4101  }
4102 
4103  retcode = SCIPsdpiSetIntpar(relaxdata->sdpi, SCIP_SDPPAR_SLATERCHECK, relaxdata->slatercheck);
4104  if ( retcode == SCIP_PARAMETERUNKNOWN )
4105  {
4106  SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL,
4107  "SDP Solver <%s>: slatercheck setting not available -- SCIP parameter has no effect.\n",
4109  }
4110  else
4111  {
4112  SCIP_CALL( retcode );
4113  }
4114 
4115  /* initialize objective limit in case it was set in an earlier optimize call */
4116  SCIP_CALL( SCIPsdpiSetRealpar(relaxdata->sdpi, SCIP_SDPPAR_OBJLIMIT, SCIPsdpiInfinity(relaxdata->sdpi)) );
4117 
4118  /* set warmstartpreoptimal gap if DSDP is used as the SDP-Solver and preoptimal solutions should be saved */
4119  if ( relaxdata->warmstartpreoptsol && (strcmp(SCIPsdpiGetSolverName(), "DSDP") == 0.0 || strcmp(SCIPsdpiGetSolverName(), "SDPA") == 0.0) )
4120  {
4121  retcode = SCIPsdpiSetRealpar(relaxdata->sdpi, SCIP_SDPPAR_WARMSTARTPOGAP, relaxdata->warmstartpreoptgap);
4122  if ( retcode == SCIP_PARAMETERUNKNOWN )
4123  {
4124  SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL,
4125  "SDP Solver <%s>: warmstartpreoptgap setting not available -- SCIP parameter has no effect.\n",
4127  }
4128  else
4129  {
4130  SCIP_CALL( retcode );
4131  }
4132  }
4133 
4134  return SCIP_OKAY;
4135 }
4136 
4138 static
4139 SCIP_DECL_RELAXCOPY(relaxCopySdp)
4140 {
4141  assert( scip != NULL );
4142  assert( relax != NULL );
4143  assert( strcmp(SCIPrelaxGetName(relax), RELAX_NAME) == 0 );
4144 
4145  SCIP_CALL( SCIPincludeRelaxSdp(scip) );
4146 
4147  return SCIP_OKAY;
4148 }
4149 
4151 static
4152 SCIP_DECL_RELAXEXITSOL(relaxExitSolSdp)
4153 {
4154  SCIP_RELAXDATA* relaxdata;
4155 
4156  assert( scip != NULL );
4157  assert( relax != NULL );
4158 
4159  relaxdata = SCIPrelaxGetData(relax);
4160  assert( relaxdata != NULL );
4161 
4162  SCIPdebugMsg(scip, "Exiting Relaxation Handler.\n");
4163 
4164  if ( relaxdata->displaystat && SCIPgetSubscipDepth(scip) == 0 )
4165  {
4166  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "\nSDP iterations:\t\t\t\t%6d\n", relaxdata->sdpiterations);
4167  if ( relaxdata->sdpcalls )
4168  {
4169  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Average SDP-iterations:\t\t\t%6.2f\n",
4170  (SCIP_Real) relaxdata->sdpiterations / (SCIP_Real) relaxdata->sdpcalls );
4171  }
4172  if ( relaxdata->sdpinterfacecalls )
4173  {
4174  if ( strcmp(SCIPsdpiGetSolverName(), "SDPA") == 0 )
4175  {
4176  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Percentage 'fastest settings' solved:\t%6.2f\n",
4177  100.0 * (SCIP_Real) relaxdata->solvedfast / (SCIP_Real) relaxdata->sdpinterfacecalls);
4178  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Percentage 'medium settings' solved:\t%6.2f\n",
4179  100.0 * (SCIP_Real) relaxdata->solvedmedium / (SCIP_Real) relaxdata->sdpinterfacecalls);
4180  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Percentage 'stable settings' solved:\t%6.2f\n",
4181  100.0 * (SCIP_Real) relaxdata->solvedstable / (SCIP_Real) relaxdata->sdpinterfacecalls);
4182  }
4183  else
4184  {
4185  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Percentage 'default formulation' solved:\t%6.2f\n",
4186  100.0 * (SCIP_Real) relaxdata->solvedfast / (SCIP_Real) relaxdata->sdpinterfacecalls);
4187  }
4188  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Percentage penalty formulation used:\t%6.2f\n",
4189  100.0 * (SCIP_Real) relaxdata->solvedpenalty / (SCIP_Real) relaxdata->sdpinterfacecalls);
4190  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Percentage unsolved even with penalty:\t%6.2f\n",
4191  100.0 * (SCIP_Real) relaxdata->unsolved / (SCIP_Real) relaxdata->sdpinterfacecalls);
4192  }
4193  if ( relaxdata->slatercheck )
4194  {
4195  if ( relaxdata->sdpinterfacecalls )
4196  {
4197  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Percentage primal Slater condition held:\t%6.2f\n",
4198  100.0 * (SCIP_Real) relaxdata->npslaterholds / (SCIP_Real) relaxdata->sdpinterfacecalls);
4199  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Percentage primal Slater condition did not hold:\t%6.2f\n",
4200  100.0 * (SCIP_Real) relaxdata->npnoslater / (SCIP_Real) relaxdata->sdpinterfacecalls);
4201  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Percentage primal Slater check failed:\t%6.2f\n",
4202  100.0 * (SCIP_Real) relaxdata->npslatercheckfailed / (SCIP_Real) relaxdata->sdpinterfacecalls);
4203 
4204  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Percentage dual Slater condition held:\t%6.2f\n",
4205  100.0 * (SCIP_Real) relaxdata->ndslaterholds / (SCIP_Real) relaxdata->sdpinterfacecalls);
4206  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Percentage dual Slater condition did not hold:\t%6.2f\n",
4207  100.0 * (SCIP_Real) relaxdata->ndnoslater / (SCIP_Real) relaxdata->sdpinterfacecalls);
4208  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Percentage dual Slater check failed:\t%6.2f\n",
4209  100.0 * (SCIP_Real) relaxdata->ndslatercheckfailed / (SCIP_Real) relaxdata->sdpinterfacecalls);
4210  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Percentage dual Slater check detected infeasibility:\t%6.2f\n",
4211  100.0 * (SCIP_Real) relaxdata->nslaterinfeasible / (SCIP_Real) relaxdata->sdpinterfacecalls);
4212  }
4213  if ( relaxdata->nslaterholds )
4214  {
4215  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Percentage 'fastest settings' with primal and dual slater holding:\t%6.2f\n",
4216  100.0 * (SCIP_Real) relaxdata->stablewslater / (SCIP_Real) relaxdata->nslaterholds);
4217  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Percentage 'stable settings' with primal and dual slater holding:\t%6.2f\n",
4218  100.0 * (SCIP_Real) relaxdata->unstablewslater / (SCIP_Real) relaxdata->nslaterholds);
4219  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Percentage 'penalty' with primal and dual slater holding:\t%6.2f\n",
4220  100.0 * (SCIP_Real) relaxdata->penaltywslater / (SCIP_Real) relaxdata->nslaterholds);
4221  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Percentage 'computed infeasible lower bound' with primal and dual slater holding:\t%6.2f\n",
4222  100.0 * (SCIP_Real) relaxdata->boundedwslater / (SCIP_Real) relaxdata->nslaterholds);
4223  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Percentage 'unsolved' with primal and dual slater holding:\t%6.2f\n",
4224  100.0 * (SCIP_Real) relaxdata->unsolvedwslater / (SCIP_Real) relaxdata->nslaterholds);
4225  }
4226  if ( relaxdata->nnoslater )
4227  {
4228  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Percentage 'fastest settings' with either primal or dual slater not holding:\t%6.2f\n",
4229  100.0 * (SCIP_Real) relaxdata->stablenoslater / (SCIP_Real) relaxdata->nnoslater);
4230  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Percentage 'stable settings' with either primal or dual slater not holding:\t%6.2f\n",
4231  100.0 * (SCIP_Real) relaxdata->unstablenoslater / (SCIP_Real) relaxdata->nnoslater);
4232  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Percentage 'penalty' with either primal or dual slater not holding:\t%6.2f\n",
4233  100.0 * (SCIP_Real) relaxdata->penaltynoslater / (SCIP_Real) relaxdata->nnoslater);
4234  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Percentage 'computed infeasible lower bound' with either primal or dual slater not holding:\t%6.2f\n",
4235  100.0 * (SCIP_Real) relaxdata->boundednoslater / (SCIP_Real) relaxdata->nnoslater);
4236  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Percentage 'unsolved' with either primal or dual slater not holding:\t%6.2f\n",
4237  100.0 * (SCIP_Real) relaxdata->unsolvednoslater / (SCIP_Real) relaxdata->nnoslater);
4238  }
4239  if ( relaxdata->nslaterinfeasible )
4240  {
4241  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Percentage 'fastest settings' with slater check showing infeasibility:\t%6.2f\n",
4242  100.0 * (SCIP_Real) relaxdata->stableinfeasible / (SCIP_Real) relaxdata->nslaterinfeasible);
4243  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Percentage 'stable settings' with slater check showing infeasibility:\t%6.2f\n",
4244  100.0 * (SCIP_Real) relaxdata->unstableinfeasible / (SCIP_Real) relaxdata->nslaterinfeasible);
4245  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Percentage 'penalty' with slater check showing infeasibility:\t%6.2f\n",
4246  100.0 * (SCIP_Real) relaxdata->penaltyinfeasible / (SCIP_Real) relaxdata->nslaterinfeasible);
4247  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Percentage 'computed infeasible lower bound' with slater check showing infeasibility:\t%6.2f\n",
4248  100.0 * (SCIP_Real) relaxdata->boundedinfeasible / (SCIP_Real) relaxdata->nslaterinfeasible);
4249  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Percentage 'unsolved' with slater check showing infeasibility:\t%6.2f\n",
4250  100.0 * (SCIP_Real) relaxdata->unsolvedinfeasible / (SCIP_Real) relaxdata->nslaterinfeasible);
4251  }
4252 #ifdef SLATERSOLVED_ABSOLUTE
4253  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Number of nodes with primal and dual slater holding:\t%d\n", relaxdata->nslaterholds);
4254  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Number of nodes with 'fastest settings' and primal and dual slater holding:\t%d\n", relaxdata->stablewslater);
4255  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Number of nodes with 'stable settings' and primal and dual slater holding:\t%d\n", relaxdata->unstablewslater);
4256  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Number of nodes with 'penalty' and primal and dual slater holding:\t%d\n", relaxdata->penaltywslater);
4257  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Number of nodes with 'computed infeasible lower bound' and primal and dual slater holding:\t%d\n", relaxdata->boundedwslater);
4258  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Number of nodes with 'unsolved' and primal and dual slater holding:\t%d\n", relaxdata->unsolvedwslater);
4259 
4260  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Number of nodes with either primal or dual slater not holding:\t%d\n", relaxdata->nnoslater);
4261  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Number of nodes with 'fastest settings' and either primal or dual slater not holding:\t%d\n", relaxdata->stablenoslater);
4262  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Number of nodes with 'stable settings' and either primal or dual slater not holding:\t%d\n", relaxdata->unstablenoslater);
4263  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Number of nodes with 'penalty' and either primal or dual slater not holding:\t%d\n", relaxdata->penaltynoslater);
4264  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Number of nodes with 'computed infeasible lower bound' and either primal or dual slater not holding:\t%d\n", relaxdata->boundednoslater);
4265  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Number of nodes with 'unsolved' and either primal or dual slater not holding:\t%d\n", relaxdata->unsolvednoslater);
4266 
4267  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Number of infeasible nodes:\t%d\n", relaxdata->nslaterinfeasible);
4268  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Number of infeasible nodes with 'fastest settings':\t%d\n", relaxdata->stableinfeasible);
4269  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Number of infeasible nodes with 'stable settings':\t%d\n", relaxdata->unstableinfeasible);
4270  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Number of infeasible nodes with 'penalty':\t%d\n", relaxdata->penaltyinfeasible);
4271  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Number of infeasible nodes with 'computed infeasible lower bound':\t%d\n", relaxdata->boundedinfeasible);
4272  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Number of infeasible nodes with 'unsolved':\t%d\n", relaxdata->unsolvedinfeasible);
4273 #endif
4274  }
4275  if ( relaxdata->warmstart && relaxdata->warmstartproject == 4 )
4276  {
4277  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Number of nodes detected infeasible through primal rounding problem:\t%d\n", relaxdata->roundingprobinf);
4278  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Number of nodes that were successfully warmstarted using the rounding problems:\t%d\n", relaxdata->roundstartsuccess);
4279  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Number of nodes where the primal rounding problem failed:\t%d\n", relaxdata->primalroundfails);
4280  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Number of nodes where the dual rounding problem failed:\t%d\n", relaxdata->dualroundfails);
4281  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Number of nodes where the optimal solution was determined by the rounding problem:\t%d\n", relaxdata->roundingoptimal);
4282  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Number of nodes cut off through bounding by the rounding problem:\t%d\n", relaxdata->roundingcutoff);
4283  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Time spent in rounding problems for warmstarting / detecting infeasibility:\t%f s\n",
4284  SCIPgetClockTime(scip, relaxdata->roundingprobtime));
4285  }
4286  }
4287 
4288  if ( relaxdata->varmapper != NULL )
4289  {
4290  SCIP_CALL( SCIPsdpVarmapperFree(scip, &(relaxdata->varmapper)) );
4291  relaxdata->varmapper = NULL;
4292  }
4293 
4294  /* free warmstart data (the nblocks > 0 check is only needed in case the parameter was changed after initsol) */
4295  if ( relaxdata->warmstart && SCIPisGT(scip, relaxdata->warmstartipfactor, 0.0) && relaxdata->nblocks > 0 )
4296  {
4297  int b;
4298 
4299  for (b = 0; b < relaxdata->nblocks; b++)
4300  {
4301  if ( relaxdata->warmstartprimaltype != 2 && SCIPsdpiDoesWarmstartNeedPrimal() && relaxdata->ipXnblocknonz[b] > 0 )
4302  {
4303  SCIPfreeBlockMemoryArrayNull(scip, &(relaxdata->ipXval[b]), relaxdata->ipXnblocknonz[b]);
4304  SCIPfreeBlockMemoryArrayNull(scip, &(relaxdata->ipXcol[b]), relaxdata->ipXnblocknonz[b]);
4305  SCIPfreeBlockMemoryArrayNull(scip, &(relaxdata->ipXrow[b]), relaxdata->ipXnblocknonz[b]);
4306  }
4307  if ( relaxdata->ipZnblocknonz[b] > 0 )
4308  {
4309  SCIPfreeBlockMemoryArrayNull(scip, &(relaxdata->ipZval[b]), relaxdata->ipZnblocknonz[b]);
4310  SCIPfreeBlockMemoryArrayNull(scip, &(relaxdata->ipZcol[b]), relaxdata->ipZnblocknonz[b]);
4311  SCIPfreeBlockMemoryArrayNull(scip, &(relaxdata->ipZrow[b]), relaxdata->ipZnblocknonz[b]);
4312  }
4313  }
4314  if ( relaxdata->warmstartprimaltype != 2 && SCIPsdpiDoesWarmstartNeedPrimal() )
4315  {
4316  SCIPfreeBlockMemoryArrayNull(scip, &relaxdata->ipXval, relaxdata->nblocks);
4317  SCIPfreeBlockMemoryArrayNull(scip, &relaxdata->ipXcol, relaxdata->nblocks);
4318  SCIPfreeBlockMemoryArrayNull(scip, &relaxdata->ipXrow, relaxdata->nblocks);
4319  SCIPfreeBlockMemoryArrayNull(scip, &relaxdata->ipXnblocknonz, relaxdata->nblocks);
4320  }
4321  SCIPfreeBlockMemoryArrayNull(scip, &relaxdata->ipZval, relaxdata->nblocks);
4322  SCIPfreeBlockMemoryArrayNull(scip, &relaxdata->ipZcol, relaxdata->nblocks);
4323  SCIPfreeBlockMemoryArrayNull(scip, &relaxdata->ipZrow, relaxdata->nblocks);
4324  SCIPfreeBlockMemoryArrayNull(scip, &relaxdata->ipZnblocknonz, relaxdata->nblocks);
4325  SCIP_CALL( SCIPfreeSol(scip, &relaxdata->ipy) );
4326  }
4327 
4328  relaxdata->objval = 0.0;
4329  relaxdata->origsolved = FALSE;
4330  relaxdata->probingsolved = FALSE;
4331  relaxdata->feasible = FALSE;
4332  relaxdata->sdpiterations = 0;
4333  relaxdata->sdpcalls = 0;
4334  relaxdata->sdpinterfacecalls = 0;
4335  relaxdata->lastsdpnode = 0;
4336  relaxdata->unsolved = 0;
4337  SCIP_CALL( SCIPsdpiClear(relaxdata->sdpi) );
4338 
4339  return SCIP_OKAY;
4340 }
4341 
4343 static
4344 SCIP_DECL_RELAXEXIT(relaxExitSdp)
4345 {
4346  SCIP_RELAXDATA* relaxdata;
4347 
4348  assert( relax != NULL );
4349 
4350  relaxdata = SCIPrelaxGetData(relax);
4351  assert( relaxdata != NULL );
4352 
4353  if ( relaxdata->roundingprobtime != NULL )
4354  {
4355  SCIP_CALL( SCIPfreeClock(scip, &relaxdata->roundingprobtime) );
4356  }
4357 
4358  return SCIP_OKAY;
4359 }
4360 
4362 static
4363 SCIP_DECL_RELAXFREE(relaxFreeSdp)
4364 {/*lint --e{715}*/
4365  SCIP_RELAXDATA* relaxdata;
4366 
4367  relaxdata = SCIPrelaxGetData(relax);
4368  assert(relaxdata != NULL);
4369 
4370  if ( relaxdata->sdpi != NULL )
4371  {
4372  SCIP_CALL( SCIPsdpiFree(&(relaxdata->sdpi)) );
4373  }
4374  if ( relaxdata->lpi != NULL )
4375  {
4376  SCIP_CALL( SCIPlpiFree(&(relaxdata->lpi)) );
4377  }
4378 
4379  SCIPfreeMemory(scip, &relaxdata);
4380 
4381  SCIPrelaxSetData(relax, NULL);
4382 
4383  return SCIP_OKAY;
4384 }
4385 
4387 SCIP_RETCODE SCIPincludeRelaxSdp(
4388  SCIP* scip
4389  )
4390 {
4391  SCIP_RELAXDATA* relaxdata = NULL;
4392  SCIP_RELAX* relax;
4393  SCIP_SDPI* sdpi;
4394  SCIP_LPI* lpi;
4395 
4396  assert( scip != NULL );
4397 
4398  /* create SDP-relaxator data */
4399  SCIP_CALL( SCIPallocMemory(scip, &relaxdata) );
4400  SCIP_CALL( SCIPsdpiCreate(&sdpi, SCIPgetMessagehdlr(scip), SCIPblkmem(scip), SCIPbuffer(scip)) );
4401  SCIP_CALL( SCIPlpiCreate(&lpi, SCIPgetMessagehdlr(scip), "SDProundingProb", SCIP_OBJSEN_MINIMIZE) );
4402 
4403  relaxdata->sdpi = sdpi;
4404  relaxdata->lpi = lpi;
4405  relaxdata->lastsdpnode = -1;
4406  relaxdata->nblocks = 0;
4407  relaxdata->varmapper = NULL;
4408  relaxdata->roundingprobtime = NULL;
4409  relaxdata->sdpconshdlr = NULL;
4410  relaxdata->sdprank1conshdlr = NULL;
4411 
4412  /* include relaxator */
4413  SCIP_CALL( SCIPincludeRelaxBasic(scip, &relax, RELAX_NAME, RELAX_DESC, RELAX_PRIORITY, RELAX_FREQ, relaxExecSdp, relaxdata) );
4414  assert( relax != NULL );
4415 
4416  /* include additional callbacks */
4417  SCIP_CALL( SCIPsetRelaxInitsol(scip, relax, relaxInitSolSdp) );
4418  SCIP_CALL( SCIPsetRelaxExitsol(scip, relax, relaxExitSolSdp) );
4419  SCIP_CALL( SCIPsetRelaxExit(scip, relax, relaxExitSdp) );
4420  SCIP_CALL( SCIPsetRelaxFree(scip, relax, relaxFreeSdp) );
4421  SCIP_CALL( SCIPsetRelaxCopy(scip, relax, relaxCopySdp) );
4422 
4423  /* add parameters for SDP-solver */
4424  SCIP_CALL( SCIPaddRealParam(scip, "relaxing/SDP/sdpsolvergaptol",
4425  "the stopping criterion for the duality gap the sdpsolver should use",
4426  &(relaxdata->sdpsolvergaptol), TRUE, SCIPsdpiGetDefaultSdpiSolverGaptol(), 1e-20, 0.001, NULL, NULL) );
4427 
4428  SCIP_CALL( SCIPaddRealParam(scip, "relaxing/SDP/sdpsolverfeastol",
4429  "the feasibility tolerance for the SDP solver",
4430  &(relaxdata->sdpsolverfeastol), TRUE, SCIPsdpiGetDefaultSdpiSolverFeastol(), 1e-17, 0.001, NULL, NULL) );
4431 
4432  SCIP_CALL( SCIPaddRealParam(scip, "relaxing/SDP/penaltyparam",
4433  "the starting value of the penalty parameter Gamma used for the penalty formulation if the "
4434  "SDP solver didn't converge; set this to a negative value to compute the parameter depending on the given problem",
4435  &(relaxdata->penaltyparam), TRUE, DEFAULT_PENALTYPARAM, -1.0, 1e+20, NULL, NULL) );
4436 
4437  SCIP_CALL( SCIPaddRealParam(scip, "relaxing/SDP/maxpenaltyparam",
4438  "the maximum value of the penalty parameter Gamma used for the penalty formulation if the "
4439  "SDP solver didn't converge; set this to a negative value to compute the parameter depending on the given problem",
4440  &(relaxdata->maxpenaltyparam), TRUE, DEFAULT_MAXPENALTYPARAM, -1.0, 1e+20, NULL, NULL) );
4441 
4442  SCIP_CALL( SCIPaddRealParam(scip, "relaxing/SDP/peninfeasadjust",
4443  "gap- or feastol will be multiplied by this before checking for infeasibility using the penalty formulation",
4444  &(relaxdata->peninfeasadjust), TRUE, DEFAULT_PENINFEASADJUST, 0.0, 1e+20, NULL, NULL) );
4445 
4446  SCIP_CALL( SCIPaddRealParam(scip, "relaxing/SDP/warmstartipfactor",
4447  "factor for interior point in convexcombination of IP and parent solution, if warmstarts are enabled",
4448  &(relaxdata->warmstartipfactor), TRUE, DEFAULT_WARMSTARTIPFACTOR, 0.0, 1.0, NULL, NULL) );
4449 
4450  SCIP_CALL( SCIPaddIntParam(scip, "relaxing/SDP/warmstartprimaltype",
4451  "how to warmstart the primal problem? 1: scaled identity/analytic center, 2: elementwise reciprocal, 3: saved primal sol",
4452  &(relaxdata->warmstartprimaltype), TRUE, DEFAULT_WARMSTARTPRIMALTYPE, 1, 3, NULL, NULL) );
4453 
4454  SCIP_CALL( SCIPaddIntParam(scip, "relaxing/SDP/warmstartiptype",
4455  "which interior point to use for convex combination for warmstarts? 1: scaled identity, 2: analytic center",
4456  &(relaxdata->warmstartiptype), TRUE, DEFAULT_WARMSTARTIPTYPE, 1, 2, NULL, NULL) );
4457 
4458  SCIP_CALL( SCIPaddIntParam(scip, "relaxing/SDP/warmstartproject",
4459  "how to update dual matrix for new bounds? 1: use old bounds, 2: use new bounds, 3: use new bounds and project on psd cone, 4: use new bounds and solve rounding problem",
4460  &(relaxdata->warmstartproject), TRUE, DEFAULT_WARMSTARTPROJECT, 1, 4, NULL, NULL) );
4461 
4462  SCIP_CALL( SCIPaddRealParam(scip, "relaxing/SDP/warmstartprminevpri",
4463  "minimum eigenvalue to allow when projecting primal matrices onto the positive (semi-)definite cone for warmstarting; -1 to compute automatically",
4464  &(relaxdata->warmstartpmevprimalpar), TRUE, DEFAULT_WARMSTARTPROJMINEV, -1.0, 1e+20, NULL, NULL) );
4465 
4466  SCIP_CALL( SCIPaddRealParam(scip, "relaxing/SDP/warmstartprminevdu",
4467  "minimum eigenvalue to allow when projecting dual matrices onto the positive (semi-)definite cone for warmstarting; -1 to compute automatically",
4468  &(relaxdata->warmstartpmevdualpar), TRUE, DEFAULT_WARMSTARTPROJMINEV, -1.0, 1e+20, NULL, NULL) );
4469 
4470  SCIP_CALL( SCIPaddBoolParam(scip, "relaxing/SDP/warmstartprojpdsame",
4471  "Should one shared minimum eigenvalue respectively maximum entry be computed for primal and dual problem instead "
4472  "of different ones for primal and dual and each block for projection or convex combination ?",
4473  &(relaxdata->warmstartprojpdsame), TRUE, DEFAULT_WARMSTARTPROJPDSAME, NULL, NULL) );
4474 
4475  SCIP_CALL( SCIPaddBoolParam(scip, "relaxing/SDP/warmstartpreoptsol",
4476  "Should a preoptimal solution (with larger gap) instead of the optimal solution be used for warmstarts",
4477  &(relaxdata->warmstartpreoptsol), TRUE, DEFAULT_WARMSTART_PREOPTIMAL_SOL, NULL, NULL) );
4478 
4479  SCIP_CALL( SCIPaddRealParam(scip, "relaxing/SDP/warmstartpreoptgap",
4480  "If warmstartpreoptsol is TRUE, this is the gap where the preoptimal solution will be saved",
4481  &(relaxdata->warmstartpreoptgap), TRUE, DEFAULT_WARMSTARTPREOPTGAP, 0.0, 1e+20, NULL, NULL) );
4482 
4483  SCIP_CALL( SCIPaddBoolParam(scip, "relaxing/SDP/warmstartroundonlyinf",
4484  "Only use solution of roundingproblem to detect infeasibility (only has an effect for warmstartproject = 4)",
4485  &(relaxdata->warmstartroundonlyinf), TRUE, DEFAULT_WARMSTARTROUNDONLYINF, NULL, NULL) );
4486 
4487  SCIP_CALL( SCIPaddIntParam(scip, "relaxing/SDP/npenaltyincr",
4488  "maximum number of times the penalty parameter will be increased if the penalty formulation failed",
4489  &(relaxdata->npenaltyincr), TRUE, SCIPsdpiGetDefaultSdpiSolverNpenaltyIncreases(), 0, INT_MAX, NULL, NULL) );
4490 
4491  SCIP_CALL( SCIPaddRealParam(scip, "relaxing/SDP/lambdastar",
4492  "the parameter lambda star used by SDPA to set the initial point;"
4493  "set this to a negative value to compute the parameter depending on the given problem",
4494  &(relaxdata->lambdastar), TRUE, DEFAULT_LAMBDASTAR, -1.0, 1e+20, NULL, NULL) );
4495 
4496  SCIP_CALL( SCIPaddIntParam(scip, "relaxing/SDP/slatercheck",
4497  "Should the Slater condition for the primal and dual problem be checked ahead of solving each SDP? 0: no, 1: yes but only for statistics, 2: yes and print warning for "
4498  "every problem not satisfying primal and dual Slater condition",
4499  &(relaxdata->slatercheck), TRUE, DEFAULT_SLATERCHECK, 0, 2, NULL, NULL) );
4500 
4501  SCIP_CALL( SCIPaddBoolParam(scip, "relaxing/SDP/sdpinfo",
4502  "Should the SDP solver output information to the screen?",
4503  &(relaxdata->sdpinfo), TRUE, DEFAULT_SDPINFO, NULL, NULL) );
4504 
4505  SCIP_CALL( SCIPaddBoolParam(scip, "relaxing/SDP/warmstart",
4506  "Should the SDP solver try to use warmstarts?",
4507  &(relaxdata->warmstart), TRUE, DEFAULT_WARMSTART, NULL, NULL) );
4508 
4509  SCIP_CALL( SCIPaddBoolParam(scip, "relaxing/SDP/objlimit",
4510  "Should an objective limit be given to the SDP-Solver?",
4511  &(relaxdata->objlimit), TRUE, DEFAULT_OBJLIMIT, NULL, NULL) );
4512 
4513  SCIP_CALL( SCIPaddBoolParam(scip, "relaxing/SDP/resolve",
4514  "Should the relaxation be resolved after bound-tightenings were found during propagation (outside of probing)?",
4515  &(relaxdata->resolve), TRUE, DEFAULT_RESOLVE, NULL, NULL) );
4516 
4517  SCIP_CALL( SCIPaddBoolParam(scip, "relaxing/SDP/tightenvb",
4518  "Should Big-Ms in varbound-like constraints be tightened before giving them to the SDP-solver ?",
4519  &(relaxdata->tightenvb), TRUE, DEFAULT_TIGHTENVB, NULL, NULL) );
4520 
4521  SCIP_CALL( SCIPaddBoolParam(scip, "relaxing/SDP/displaystatistics",
4522  "Should statistics about SDP iterations and solver settings/success be printed after quitting SCIP-SDP ?",
4523  &(relaxdata->displaystat), TRUE, DEFAULT_DISPLAYSTAT, NULL, NULL) );
4524 
4525  SCIP_CALL( SCIPaddIntParam(scip, "relaxing/SDP/settingsresetfreq",
4526  "frequency for resetting parameters in SDP solver and trying again with fastest settings (-1: never, 0: only at depth settingsresetofs);"
4527  "currently only supported for SDPA",
4528  &(relaxdata->settingsresetfreq), TRUE, DEFAULT_SETTINGSRESETFREQ, -1, INT_MAX, NULL, NULL) );
4529 
4530  SCIP_CALL( SCIPaddIntParam(scip, "relaxing/SDP/settingsresetofs",
4531  "frequency offset for resetting parameters in SDP solver and trying again with fastest settings; currently only supported for SDPA",
4532  &(relaxdata->settingsresetofs), TRUE, DEFAULT_SETTINGSRESETOFS, 0, INT_MAX, NULL, NULL) );
4533 
4534  SCIP_CALL( SCIPaddIntParam(scip, "relaxing/SDP/sdpsolverthreads",
4535  "number of threads the SDP solver should use (-1 = number of cores); currently only supported for MOSEK",
4536  &(relaxdata->sdpsolverthreads), TRUE, DEFAULT_SDPSOLVERTHREADS, -1, INT_MAX, NULL, NULL) );
4537 
4538  /* add description of SDP-solver */
4539  SCIP_CALL( SCIPincludeExternalCodeInformation(scip, SCIPsdpiGetSolverName(), SCIPsdpiGetSolverDesc()) );
4540 
4541  return SCIP_OKAY;
4542 }
4543 
4544 
4545 /* external functions */
4546 
4552  SCIP* scip,
4553  SCIP_RELAX* relax
4554  )
4555 {
4556  SCIP_CONSHDLR* sdpconshdlr;
4557  SCIP_CONSHDLR* sdprank1conshdlr;
4558  SCIP_RELAXDATA* relaxdata;
4559  SCIP_ROW** rows;
4560  SCIP_COL** rowcols;
4561  SCIP_CONS** sdpblocks;
4562  SCIP_Real* solforscip;
4563  SCIP_Real* rowvals;
4564  SCIP_Real timelimit;
4565  SCIP_Real rowval;
4566  int slength;
4567  int arraylength;
4568  int nrows;
4569  int rownnonz;
4570  int i;
4571  int r;
4572  int v;
4573 
4574  SCIP_CONS** sdporigblocks;
4575  SCIP_CONS** sdprank1blocks;
4576  int nsdpblocks;
4577  int nrank1blocks;
4578  int b;
4579 
4580  assert( scip != NULL );
4581  assert( relax != NULL );
4582  assert( SCIPgetStage(scip) == SCIP_STAGE_SOLVING );
4583 
4584  SCIPdebugMsg(scip, "computing analytic centers for warmstarting\n");
4585 
4586  relaxdata = SCIPrelaxGetData(relax);
4587  assert( relaxdata != NULL );
4588 
4589  /* this function should only be executed once */
4590  if ( relaxdata->ipXexists || relaxdata->ipZexists )
4591  {
4592  SCIPdebugMsg(scip, "aborting SCIPrelaxSdpComputeAnalyticCenters since analytic centers have already been computed\n");
4593  return SCIP_OKAY;
4594  }
4595 
4596  /* nothing to be done without variables */
4597  if ( SCIPgetNVars(scip) == 0 )
4598  return SCIP_OKAY;
4599 
4600  /* exit if not warmstart is required or not we do not need the analytic centers */
4601  if ( ! relaxdata->warmstart || relaxdata->warmstartiptype != 2 || SCIPisLE(scip, relaxdata->warmstartipfactor, 0.0) )
4602  return SCIP_OKAY;
4603 
4604  /* exit if no SDP and rows are present */
4605  sdpconshdlr = relaxdata->sdpconshdlr;
4606  nsdpblocks = SCIPconshdlrGetNConss(sdpconshdlr);
4607  sdprank1conshdlr = relaxdata->sdprank1conshdlr;
4608  nrank1blocks = SCIPconshdlrGetNConss(sdprank1conshdlr);
4609  if ( nsdpblocks + nrank1blocks + SCIPgetNLPRows(scip) <= 0 )
4610  return SCIP_OKAY;
4611 
4612  relaxdata->nblocks = SCIPgetNLPRows(scip) + SCIPgetNVars(scip) > 0 ? nsdpblocks + nrank1blocks + 1 : SCIPconshdlrGetNConss(sdpconshdlr) + SCIPconshdlrGetNConss(sdprank1conshdlr);
4613 
4614  /* first solve SDP with primal objective (dual constant part) set to zero to compute analytic center of primal feasible set */
4615  if ( relaxdata->warmstartprimaltype != 2 && SCIPsdpiDoesWarmstartNeedPrimal() )
4616  {
4617  SCIP_CALL( putSdpDataInInterface(scip, relaxdata->sdpi, relaxdata->varmapper, FALSE, TRUE) );
4618  SCIP_CALL( putLpDataInInterface(scip, relaxdata, FALSE, TRUE) );
4619 
4620  /* set time limit */
4621  SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
4622  if ( ! SCIPisInfinity(scip, timelimit) )
4623  {
4624  timelimit -= SCIPgetSolvingTime(scip);
4625  if ( timelimit <= 0.0 )
4626  return SCIP_OKAY;
4627  }
4628 
4629  /* TODO: might want to add an additional parameter to solve to disable penalty, since we cannot use that here anyways */
4630  SCIP_CALL( SCIPsdpiSolve(relaxdata->sdpi, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, SCIP_SDPSOLVERSETTING_UNSOLVED, FALSE, timelimit) );
4631 
4632  /* update calls, iterations and stability numbers (only if the SDP-solver was actually called) */
4633  SCIP_CALL( updateSDPStatistics(relaxdata) );
4634 
4635  if ( SCIPsdpiWasSolved(relaxdata->sdpi) && SCIPsdpiSolvedOrig(relaxdata->sdpi) && SCIPsdpiIsPrimalFeasible(relaxdata->sdpi) )
4636  {
4637  int npenaltybounds = 0;
4638 
4639  relaxdata->ipXexists = TRUE;
4640 
4641  /* allocate memory (for the different blocks the neccessary anount first needs to be computed) */
4642  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &relaxdata->ipXnblocknonz, relaxdata->nblocks) );
4643  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &relaxdata->ipXrow, relaxdata->nblocks) );
4644  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &relaxdata->ipXcol, relaxdata->nblocks) );
4645  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &relaxdata->ipXval, relaxdata->nblocks) );
4646 
4647  SCIP_CALL( SCIPsdpiGetPrimalNonzeros(relaxdata->sdpi, relaxdata->nblocks, relaxdata->ipXnblocknonz) );
4648  for (b = 0; b < relaxdata->nblocks; b++)
4649  {
4650  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &relaxdata->ipXrow[b], relaxdata->ipXnblocknonz[b]) );
4651  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &relaxdata->ipXcol[b], relaxdata->ipXnblocknonz[b]) );
4652  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &relaxdata->ipXval[b], relaxdata->ipXnblocknonz[b]) );
4653  }
4654 
4655  /* get primal solution */
4656  SCIP_CALL( SCIPsdpiGetPrimalMatrix(relaxdata->sdpi, relaxdata->nblocks, relaxdata->ipXnblocknonz,
4657  relaxdata->ipXrow, relaxdata->ipXcol, relaxdata->ipXval) );
4658 
4659  /* count the number of primal entries corresponding to bounds of the penalty variable and remove them */
4660  for (i = 0; i < relaxdata->ipXnblocknonz[relaxdata->nblocks - 1]; i++)
4661  {
4662  if ( relaxdata->ipXrow[relaxdata->nblocks - 1][i] == SCIPsdpVarmapperGetNVars(relaxdata->varmapper) )
4663  npenaltybounds++;
4664  }
4665 
4666  if ( npenaltybounds > 0 )
4667  {
4668  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &relaxdata->ipXrow[relaxdata->nblocks - 1],
4669  relaxdata->ipXnblocknonz[relaxdata->nblocks - 1], relaxdata->ipXnblocknonz[relaxdata->nblocks - 1] - npenaltybounds) );
4670  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &relaxdata->ipXcol[relaxdata->nblocks - 1],
4671  relaxdata->ipXnblocknonz[relaxdata->nblocks - 1], relaxdata->ipXnblocknonz[relaxdata->nblocks - 1] - npenaltybounds) );
4672  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &relaxdata->ipXval[relaxdata->nblocks - 1],
4673  relaxdata->ipXnblocknonz[relaxdata->nblocks - 1], relaxdata->ipXnblocknonz[relaxdata->nblocks - 1] - npenaltybounds) );
4674  relaxdata->ipXnblocknonz[relaxdata->nblocks - 1] = relaxdata->ipXnblocknonz[relaxdata->nblocks - 1] - npenaltybounds;
4675  }
4676 
4677  for (b = 0; b < relaxdata->nblocks; b++)
4678  {
4679  /* TODO check if they are already sorted (sorting is needed since they will later be merged into warmstart arrays) */
4680  SCIPsdpVarfixerSortRowCol(relaxdata->ipXrow[b], relaxdata->ipXcol[b], relaxdata->ipXval[b], relaxdata->ipXnblocknonz[b]);
4681  }
4682 
4683 #ifdef SCIP_PRINT_WARMSTART
4684  SCIPdebugMsg(scip, "Computed primal analytic center:\n");
4685  for (b = 0; b < relaxdata->nblocks; b++)
4686  {
4687  SCIPdebugMsg(scip, "primal matrix, block %d:\n", b);
4688  for (i = 0; i < relaxdata->ipXnblocknonz[b]; i++)
4689  {
4690  SCIPdebugMsg(scip, "X_%d[%d,%d]: %f\n", b, relaxdata->ipXrow[b][i], relaxdata->ipXcol[b][i], relaxdata->ipXval[b][i]);
4691  }
4692  }
4693 #endif
4694  }
4695  else
4696  {
4697  relaxdata->ipXexists = TRUE;
4698 
4699  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &relaxdata->ipXnblocknonz, relaxdata->nblocks) );
4700  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &relaxdata->ipXrow, relaxdata->nblocks) );
4701  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &relaxdata->ipXcol, relaxdata->nblocks) );
4702  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &relaxdata->ipXval, relaxdata->nblocks) );
4703 
4704  nsdpblocks = SCIPconshdlrGetNConss(sdpconshdlr);
4705  nrank1blocks = SCIPconshdlrGetNConss(sdprank1conshdlr);
4706  sdporigblocks = SCIPconshdlrGetConss(sdpconshdlr);
4707  sdprank1blocks = SCIPconshdlrGetConss(sdprank1conshdlr);
4708 
4709  SCIP_CALL( SCIPallocBufferArray(scip, &sdpblocks, nsdpblocks + nrank1blocks) );
4710  for (r = 0; r < nsdpblocks; ++r)
4711  sdpblocks[r] = sdporigblocks[r];
4712 
4713  for (r = 0; r < nrank1blocks; ++r)
4714  sdpblocks[nsdpblocks + r] = sdprank1blocks[r];
4715 
4716  nsdpblocks += nrank1blocks;
4717 
4718  for (b = 0; b < relaxdata->nblocks; b++)
4719  {
4720  if ( b < relaxdata->nblocks - 1 )
4721  {
4722  /* SDP block */
4723  relaxdata->ipXnblocknonz[b] = SCIPconsSdpGetBlocksize(scip, sdpblocks[b]);
4724  }
4725  else
4726  {
4727  /* LP block */
4728  relaxdata->ipXnblocknonz[b] = SCIPgetNLPRows(scip) + 2 * SCIPgetNVars(scip);
4729  }
4730  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &relaxdata->ipXrow[b], relaxdata->ipXnblocknonz[b]) );
4731  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &relaxdata->ipXcol[b], relaxdata->ipXnblocknonz[b]) );
4732  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &relaxdata->ipXval[b], relaxdata->ipXnblocknonz[b]) );
4733 
4734  for (i = 0; i < relaxdata->ipXnblocknonz[b]; i++)
4735  {
4736  relaxdata->ipXrow[b][i] = i;
4737  relaxdata->ipXcol[b][i] = i;
4738  relaxdata->ipXval[b][i] = relaxdata->lambdastar;
4739  }
4740  }
4741 
4742  SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL, "Failed to compute analytic center of primal feasible set, using scaled identity instead.\n");
4743  SCIPfreeBufferArray(scip, &sdpblocks);
4744  }
4745  }
4746 
4747  /* set dual objective coefficients to zero to compute analytic center of dual feasible set */
4748  SCIP_CALL( putSdpDataInInterface(scip, relaxdata->sdpi, relaxdata->varmapper, TRUE, FALSE) );
4749  SCIP_CALL( putLpDataInInterface(scip, relaxdata, TRUE, FALSE) );
4750 
4751  /* set time limit */
4752  SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
4753  if ( ! SCIPisInfinity(scip, timelimit) )
4754  {
4755  timelimit -= SCIPgetSolvingTime(scip);
4756  if ( timelimit <= 0.0 )
4757  return SCIP_OKAY;
4758  }
4759 
4760  /* TODO: might want to add an additional parameter to solve to disable penalty, since we cannot use that here anyways */
4761  SCIP_CALL( SCIPsdpiSolve(relaxdata->sdpi, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, SCIP_SDPSOLVERSETTING_UNSOLVED, FALSE, timelimit) );
4762 
4763  /* update calls, iterations and stability numbers (only if the SDP-solver was actually called) */
4764  SCIP_CALL( updateSDPStatistics(relaxdata) );
4765 
4766  if ( SCIPsdpiWasSolved(relaxdata->sdpi) && SCIPsdpiSolvedOrig(relaxdata->sdpi) && SCIPsdpiIsDualFeasible(relaxdata->sdpi) )
4767  {
4768  int nvars;
4769  SCIP_VAR** vars;
4770 
4771  relaxdata->ipZexists = TRUE;
4772 
4773  nvars = SCIPgetNVars(scip);
4774  vars = SCIPgetVars(scip);
4775 
4776  /* allocate memory */
4777  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &relaxdata->ipZnblocknonz, relaxdata->nblocks) );
4778  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &relaxdata->ipZrow, relaxdata->nblocks) );
4779  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &relaxdata->ipZcol, relaxdata->nblocks) );
4780  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &relaxdata->ipZval, relaxdata->nblocks) );
4781 
4782  /* get solution w.r.t. SCIP variables */
4783  SCIP_CALL( SCIPallocBufferArray(scip, &solforscip, nvars) );
4784  slength = nvars;
4785 
4786  SCIP_CALL( SCIPsdpiGetSol(relaxdata->sdpi, NULL, solforscip, &slength) ); /* get the solution from the SDP solver */
4787 
4788  assert( slength == nvars ); /* If this isn't true any longer, the getSol-Call was unsuccessfull, because the given array wasn't long enough,
4789  * but this can't happen, because the array has enough space for all sdp variables. */
4790 
4791  /* create SCIP solution */
4792  SCIP_CALL( SCIPcreateSol(scip, &relaxdata->ipy, NULL) );
4793  SCIP_CALL( SCIPsetSolVals(scip, relaxdata->ipy, nvars, vars, solforscip) );
4794 #ifdef SCIP_PRINT_WARMSTART
4795  SCIPdebugMsg(scip, "Computed dual analytic center:\n");
4796  for (i = 0; i < nvars; i++)
4797  {
4798  SCIPdebugMsg(scip, "y[%d] = %f\n", i, solforscip[i]);
4799  }
4800 #endif
4801 
4802  SCIPfreeBufferArray(scip, &solforscip);
4803 
4804  /* compute SDP blocks of dual analytic center */
4805  nsdpblocks = SCIPconshdlrGetNConss(sdpconshdlr);
4806  nrank1blocks = SCIPconshdlrGetNConss(sdprank1conshdlr);
4807  sdporigblocks = SCIPconshdlrGetConss(sdpconshdlr);
4808  sdprank1blocks = SCIPconshdlrGetConss(sdprank1conshdlr);
4809 
4810  SCIP_CALL( SCIPallocBufferArray(scip, &sdpblocks, nsdpblocks + nrank1blocks) );
4811  for (r = 0; r < nsdpblocks; ++r)
4812  sdpblocks[r] = sdporigblocks[r];
4813 
4814  for (r = 0; r < nrank1blocks; ++r)
4815  sdpblocks[nsdpblocks + r] = sdprank1blocks[r];
4816 
4817  nsdpblocks += nrank1blocks;
4818 
4819  for (b = 0; b < relaxdata->nblocks - 1; b++)
4820  {
4821  relaxdata->ipZnblocknonz[b] = SCIPconsSdpComputeUbSparseSdpMatrixLength(sdpblocks[b]);
4822  arraylength = relaxdata->ipZnblocknonz[b];
4823 
4824  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &relaxdata->ipZrow[b], relaxdata->ipZnblocknonz[b]) );
4825  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &relaxdata->ipZcol[b], relaxdata->ipZnblocknonz[b]) );
4826  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &relaxdata->ipZval[b], relaxdata->ipZnblocknonz[b]) );
4827 
4828  /* compute Z matrix */
4829  SCIP_CALL( SCIPconsSdpComputeSparseSdpMatrix(scip, sdpblocks[b], relaxdata->ipy,
4830  &(relaxdata->ipZnblocknonz[b]), relaxdata->ipZrow[b], relaxdata->ipZcol[b], relaxdata->ipZval[b]) );
4831 
4832  assert( relaxdata->ipZnblocknonz[b] <= arraylength );
4833 
4834  if ( relaxdata->ipZnblocknonz[b] < arraylength )
4835  {
4836  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &relaxdata->ipZrow[b], arraylength, relaxdata->ipZnblocknonz[b]) );
4837  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &relaxdata->ipZcol[b], arraylength, relaxdata->ipZnblocknonz[b]) );
4838  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &relaxdata->ipZval[b], arraylength, relaxdata->ipZnblocknonz[b]) );
4839  }
4840 
4841  /* TODO check if they are already sorted (sorting is needed since they will later be merged into warmstart arrays) */
4842  SCIPsdpVarfixerSortRowCol(relaxdata->ipZrow[b], relaxdata->ipZcol[b], relaxdata->ipZval[b], relaxdata->ipZnblocknonz[b]);
4843  }
4844 
4845  /* compute LP block */
4846  SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
4847  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &relaxdata->ipZrow[b], 2 * nrows + 2 * nvars) );
4848  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &relaxdata->ipZcol[b], 2 * nrows + 2 * nvars) );
4849  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &relaxdata->ipZval[b], 2 * nrows + 2 * nvars) );
4850 
4851  /* for the analytic center all the entries should be strictly positive */
4852  relaxdata->ipZnblocknonz[b] = 2 * nrows + 2 * nvars;
4853 
4854  for (r = 0; r < nrows; r++)
4855  {
4856  /* compute row value for current solution */
4857  rowval = 0.0;
4858  rownnonz = SCIProwGetNNonz(rows[r]);
4859  rowvals = SCIProwGetVals(rows[r]);
4860  rowcols = SCIProwGetCols(rows[r]);
4861  for (i = 0; i < rownnonz; i++)
4862  rowval += SCIPgetSolVal(scip, relaxdata->ipy, SCIPcolGetVar(rowcols[i])) * rowvals[i];
4863 
4864  relaxdata->ipZrow[b][2*r] = 2*r;
4865  relaxdata->ipZcol[b][2*r] = 2*r;
4866  relaxdata->ipZval[b][2*r] = rowval - (SCIProwGetLhs(rows[r]) - SCIProwGetConstant(rows[r]));
4867  relaxdata->ipZrow[b][2*r + 1] = 2*r + 1;
4868  relaxdata->ipZcol[b][2*r + 1] = 2*r + 1;
4869  relaxdata->ipZval[b][2*r + 1] = SCIProwGetRhs(rows[r]) - SCIProwGetConstant(rows[r]) - rowval;
4870  }
4871 
4872  for (v = 0; v < nvars; v++)
4873  {
4874  relaxdata->ipZrow[b][2*nrows + 2*v] = 2*nrows + 2*v;
4875  relaxdata->ipZcol[b][2*nrows + 2*v] = 2*nrows + 2*v;
4876  relaxdata->ipZval[b][2*nrows + 2*v] = SCIPgetSolVal(scip, relaxdata->ipy, vars[v]) - SCIPvarGetLbLocal(vars[v]);
4877  relaxdata->ipZrow[b][2*nrows + 2*v + 1] = 2*nrows + 2*v + 1;
4878  relaxdata->ipZcol[b][2*nrows + 2*v + 1] = 2*nrows + 2*v + 1;
4879  relaxdata->ipZval[b][2*nrows + 2*v + 1] = SCIPvarGetUbLocal(vars[v]) - SCIPgetSolVal(scip, relaxdata->ipy, vars[v]);
4880  }
4881 #ifdef SCIP_PRINT_WARMSTART
4882  for (b = 0; b < relaxdata->nblocks - 1; b++)
4883  {
4884  SCIPdebugMsg(scip, "dual matrix, block %d:\n", b);
4885  for (i = 0; i < relaxdata->ipZnblocknonz[b]; i++)
4886  {
4887  SCIPdebugMsg(scip, "Z_%d[%d,%d]: %f\n", b, relaxdata->ipZrow[b][i], relaxdata->ipZcol[b][i], relaxdata->ipZval[b][i]);
4888  }
4889  }
4890  SCIPdebugMsg(scip, "dual matrix, LP constraints:\n");
4891  for (r = 0; r < nrows; r++)
4892  {
4893  SCIPdebugMsg(scip, "Z_%d[%d,%d]: %f\n", relaxdata->nblocks, relaxdata->ipZrow[b][2*r], relaxdata->ipZcol[b][2*r], relaxdata->ipZval[b][2*r]);
4894  SCIPdebugMsg(scip, "Z_%d[%d,%d]: %f\n", relaxdata->nblocks, relaxdata->ipZrow[b][2*r+1], relaxdata->ipZcol[b][2*r+1], relaxdata->ipZval[b][2*r+1]);
4895  }
4896  for (v = 0; v < nvars; v++)
4897  {
4898  SCIPdebugMsg(scip, "Z_%d[%d,%d]: %f\n", relaxdata->nblocks,
4899  relaxdata->ipZrow[b][2*nrows + 2*v], relaxdata->ipZcol[b][2*nrows + 2*v], relaxdata->ipZval[b][2*nrows + 2*v]);
4900  SCIPdebugMsg(scip, "Z_%d[%d,%d]: %f\n", relaxdata->nblocks,
4901  relaxdata->ipZrow[b][2*nrows + 2*v + 1], relaxdata->ipZcol[b][2*nrows + 2*v + 1], relaxdata->ipZval[b][2*nrows + 2*v + 1]);
4902  }
4903 #endif
4904  SCIPfreeBufferArray(scip, &sdpblocks);
4905  }
4906  else
4907  {
4908  /* use a scaled identity matrix (and y=0) if the computation of the dual analytic center failed */
4909  relaxdata->ipZexists = TRUE;
4910 
4911  /* y is set to the zero vector */
4912  SCIP_CALL( SCIPcreateSol(scip, &relaxdata->ipy, NULL) );
4913 
4914  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &relaxdata->ipZnblocknonz, relaxdata->nblocks) );
4915  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &relaxdata->ipZrow, relaxdata->nblocks) );
4916  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &relaxdata->ipZcol, relaxdata->nblocks) );
4917  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &relaxdata->ipZval, relaxdata->nblocks) );
4918 
4919  nsdpblocks = SCIPconshdlrGetNConss(sdpconshdlr);
4920  nrank1blocks = SCIPconshdlrGetNConss(sdprank1conshdlr);
4921  sdporigblocks = SCIPconshdlrGetConss(sdpconshdlr);
4922  sdprank1blocks = SCIPconshdlrGetConss(sdprank1conshdlr);
4923 
4924  SCIP_CALL( SCIPallocBufferArray(scip, &sdpblocks, nsdpblocks + nrank1blocks) );
4925  for (r = 0; r < nsdpblocks; ++r)
4926  sdpblocks[r] = sdporigblocks[r];
4927 
4928  for (r = 0; r < nrank1blocks; ++r)
4929  sdpblocks[nsdpblocks + r] = sdprank1blocks[r];
4930 
4931  nsdpblocks += nrank1blocks;
4932 
4933  for (b = 0; b < relaxdata->nblocks; b++)
4934  {
4935  if ( b < relaxdata->nblocks - 1 )
4936  {
4937  /* SDP block */
4938  relaxdata->ipZnblocknonz[b] = SCIPconsSdpGetBlocksize(scip, sdpblocks[b]);
4939  }
4940  else
4941  {
4942  /* LP block */
4943  relaxdata->ipZnblocknonz[b] = SCIPgetNLPRows(scip) + 2 * SCIPgetNVars(scip);
4944  }
4945  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &relaxdata->ipZrow[b], relaxdata->ipZnblocknonz[b]) );
4946  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &relaxdata->ipZcol[b], relaxdata->ipZnblocknonz[b]) );
4947  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &relaxdata->ipZval[b], relaxdata->ipZnblocknonz[b]) );
4948 
4949  for (i = 0; i < relaxdata->ipXnblocknonz[b]; i++)
4950  {
4951  relaxdata->ipZrow[b][i] = i;
4952  relaxdata->ipZcol[b][i] = i;
4953  relaxdata->ipZval[b][i] = relaxdata->lambdastar;
4954  }
4955  }
4956 
4957  SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL, "Failed to compute analytic center of dual feasible set, using scaled identity instead.\n");
4958  SCIPfreeBufferArray(scip, &sdpblocks);
4959  }
4960 
4961  return SCIP_OKAY;
4962 }
4963 
4973  SCIP_RELAX* relax,
4974  SCIP_Real* lbvars,
4975  SCIP_Real* ubvars,
4976  int* arraylength
4978  )
4979 {
4980  SCIP_RELAXDATA* relaxdata;
4981 
4982  assert( relax != NULL );
4983  assert( lbvars != NULL );
4984  assert( ubvars != NULL );
4985  assert( arraylength != NULL );
4986  assert( *arraylength >= 0 );
4987 
4988  relaxdata = SCIPrelaxGetData(relax);
4989  assert( relaxdata != NULL );
4990 
4991  SCIP_CALL( SCIPsdpiGetPrimalBoundVars(relaxdata->sdpi, lbvars, ubvars, arraylength) );
4992 
4993  return SCIP_OKAY;
4994 }
4995 
4998  SCIP_RELAX* relax,
4999  SCIP_Bool* success,
5000  SCIP_Real* objval
5001  )
5002 {
5003  SCIP_RELAXDATA* relaxdata;
5004 
5005  assert( relax != NULL );
5006  assert( success != NULL );
5007  assert( objval != NULL );
5008 
5009  relaxdata = SCIPrelaxGetData(relax);
5010  assert( relaxdata != NULL );
5011 
5012  *success = relaxdata->origsolved;
5013  *objval = relaxdata->objval;
5014 
5015  return SCIP_OKAY;
5016 }
5017 
5020  SCIP* scip,
5021  SCIP_RELAX* relax,
5022  SCIP_Bool* success,
5023  SCIP_Real* solarray,
5024  int* sollength
5025  )
5026 {
5027  SCIP_RELAXDATA* relaxdata;
5028 
5029  assert( relax != NULL );
5030  assert( success != NULL );
5031  assert( solarray != NULL );
5032 
5033  relaxdata = SCIPrelaxGetData(relax);
5034  assert( relaxdata != NULL );
5035 
5036  *success = relaxdata->origsolved;
5037 
5038  if ( *sollength >= SCIPgetNVars(scip) )
5039  {
5040  SCIP_CALL( SCIPsdpiGetSol(relaxdata->sdpi, NULL, solarray, sollength) );
5041  }
5042  else
5043  {
5044  SCIPdebugMsg(scip, "Called SCIPrelaxSdpGetRelaxSol with an array that wasn't big enough, needed length %d, given %d!\n", SCIPgetNVars(scip), *sollength);
5045  *sollength = SCIPgetNVars(scip);
5046  }
5047 
5048  return SCIP_OKAY;
5049 }
5050 
5053  SCIP_RELAX* relax
5054  )
5055 {
5056  assert( relax != NULL );
5057  assert( SCIPrelaxGetData(relax) != NULL );
5058 
5059  return SCIPrelaxGetData(relax)->lastsdpnode;
5060 }
5061 
5064  SCIP_RELAX* relax
5065  )
5066 {
5067  SCIP_RELAXDATA* relaxdata;
5068 
5069  assert( relax != NULL );
5070 
5071  relaxdata = SCIPrelaxGetData(relax);
5072 
5073  assert( relaxdata != NULL );
5074  assert( relaxdata->sdpi != NULL );
5075 
5076  return relaxdata->origsolved && SCIPsdpiSolvedOrig(relaxdata->sdpi);
5077 }
5078 
5081  SCIP_RELAX* relax
5082  )
5083 {
5084  SCIP_RELAXDATA* relaxdata;
5085 
5086  assert( relax != NULL );
5087 
5088  relaxdata = SCIPrelaxGetData(relax);
5089 
5090  assert( relaxdata != NULL );
5091  assert( relaxdata->sdpi != NULL );
5092 
5093  return relaxdata->probingsolved;
5094 }
5095 
5098  SCIP_RELAX* relax
5099  )
5100 {
5101  assert( relax != NULL );
5102  assert( SCIPrelaxGetData(relax) != NULL );
5103 
5104  return ( SCIPrelaxGetData(relax)->feasible );
5105 }
5106 
5109  SCIP_RELAX* relax
5110  )
5111 {
5112  SCIP_RELAXDATA* relaxdata;
5113 
5114  assert( relax != NULL );
5115 
5116  relaxdata = SCIPrelaxGetData(relax);
5117 
5118  assert( SCIPrelaxGetData(relax) != NULL );
5119  assert( relaxdata->sdpi != NULL );
5120 
5121  return SCIPsdpiIsDualUnbounded(relaxdata->sdpi);
5122 }
5123 
5126  SCIP_RELAX* relax
5127  )
5128 {
5129  assert( relax != NULL );
5130  assert( SCIPrelaxGetData(relax) != NULL );
5131 
5132  return SCIPrelaxGetData(relax)->sdpiterations;
5133 }
5134 
5137  SCIP_RELAX* relax
5138  )
5139 {
5140  assert( relax != NULL );
5141  assert( SCIPrelaxGetData(relax) != NULL );
5142 
5143  return ( SCIPrelaxGetData(relax)->sdpcalls );
5144 }
5145 
5148  SCIP_RELAX* relax
5149  )
5150 {
5151  assert( relax != NULL );
5152  assert( SCIPrelaxGetData(relax) != NULL );
5153 
5154  return ( SCIPrelaxGetData(relax)->sdpinterfacecalls );
5155 }
5156 
5159  SCIP_RELAX* relax
5160  )
5161 {
5162  assert( relax != NULL );
5163  assert( SCIPrelaxGetData(relax) != NULL );
5164 
5165  return ( SCIPrelaxGetData(relax)->solvedfast );
5166 }
5167 
5170  SCIP_RELAX* relax
5171  )
5172 {
5173  assert( relax != NULL );
5174  assert( SCIPrelaxGetData(relax) != NULL );
5175 
5176  return ( SCIPrelaxGetData(relax)->solvedmedium );
5177 }
5178 
5181  SCIP_RELAX* relax
5182  )
5183 {
5184  assert( relax != NULL );
5185  assert( SCIPrelaxGetData(relax) != NULL );
5186 
5187  return ( SCIPrelaxGetData(relax)->solvedstable );
5188 }
5189 
5192  SCIP_RELAX* relax
5193  )
5194 {
5195  assert( relax != NULL );
5196  assert( SCIPrelaxGetData(relax) != NULL );
5197 
5198  return ( SCIPrelaxGetData(relax)->solvedpenalty );
5199 }
5200 
5203  SCIP_RELAX* relax
5204  )
5205 {
5206  assert( relax != NULL );
5207  assert( SCIPrelaxGetData(relax) != NULL );
5208 
5209  return ( SCIPrelaxGetData(relax)->unsolved );
5210 }
5211 
5214  SCIP_RELAX* relax
5215  )
5216 {
5217  assert( relax != NULL );
5218  assert( SCIPrelaxGetData(relax) != NULL );
5219 
5220  return ( SCIPrelaxGetData(relax)->ndslaterholds );
5221 }
5222 
5225  SCIP_RELAX* relax
5226  )
5227 {
5228  assert( relax != NULL );
5229  assert( SCIPrelaxGetData(relax) != NULL );
5230 
5231  return ( SCIPrelaxGetData(relax)->ndnoslater );
5232 }
5233 
5236  SCIP_RELAX* relax
5237  )
5238 {
5239  assert( relax != NULL );
5240  assert( SCIPrelaxGetData(relax) != NULL );
5241 
5242  return ( SCIPrelaxGetData(relax)->nslaterinfeasible );
5243 }
5244 
5247  SCIP_RELAX* relax
5248  )
5249 {
5250  assert( relax != NULL );
5251  assert( SCIPrelaxGetData(relax) != NULL );
5252 
5253  return ( SCIPrelaxGetData(relax)->ndslatercheckfailed );
5254 }
5255 
5258  SCIP_RELAX* relax
5259  )
5260 {
5261  assert( relax != NULL );
5262  assert( SCIPrelaxGetData(relax) != NULL );
5263 
5264  return ( SCIPrelaxGetData(relax)->npslaterholds );
5265 }
5266 
5269  SCIP_RELAX* relax
5270  )
5271 {
5272  assert( relax != NULL );
5273  assert( SCIPrelaxGetData(relax) != NULL );
5274 
5275  return ( SCIPrelaxGetData(relax)->npnoslater );
5276 }
5277 
5280  SCIP_RELAX* relax
5281  )
5282 {
5283  assert( relax != NULL );
5284  assert( SCIPrelaxGetData(relax) != NULL );
5285 
5286  return ( SCIPrelaxGetData(relax)->npslatercheckfailed );
5287 }
5288 
5291  SCIP_RELAX* relax
5292  )
5293 {
5294  assert( relax != NULL );
5295  assert( SCIPrelaxGetData(relax) != NULL );
5296 
5297  return ( SCIPrelaxGetData(relax)->nslaterholds );
5298 }
5299 
5302  SCIP_RELAX* relax
5303  )
5304 {
5305  assert( relax != NULL );
5306  assert( SCIPrelaxGetData(relax) != NULL );
5307 
5308  return ( SCIPrelaxGetData(relax)->stablewslater );
5309 }
5310 
5313  SCIP_RELAX* relax
5314  )
5315 {
5316  assert( relax != NULL );
5317  assert( SCIPrelaxGetData(relax) != NULL );
5318 
5319  return ( SCIPrelaxGetData(relax)->unstablewslater );
5320 }
5321 
5324  SCIP_RELAX* relax
5325  )
5326 {
5327  assert( relax != NULL );
5328  assert( SCIPrelaxGetData(relax) != NULL );
5329 
5330  return ( SCIPrelaxGetData(relax)->penaltywslater );
5331 }
5332 
5335  SCIP_RELAX* relax
5336  )
5337 {
5338  assert( relax != NULL );
5339  assert( SCIPrelaxGetData(relax) != NULL );
5340 
5341  return ( SCIPrelaxGetData(relax)->boundedwslater );
5342 }
5343 
5346  SCIP_RELAX* relax
5347  )
5348 {
5349  assert( relax != NULL );
5350  assert( SCIPrelaxGetData(relax) != NULL );
5351 
5352  return ( SCIPrelaxGetData(relax)->unsolvedwslater );
5353 }
5354 
5357  SCIP_RELAX* relax
5358  )
5359 {
5360  assert( relax != NULL );
5361  assert( SCIPrelaxGetData(relax) != NULL );
5362 
5363  return ( SCIPrelaxGetData(relax)->nnoslater );
5364 }
5365 
5368  SCIP_RELAX* relax
5369  )
5370 {
5371  assert( relax != NULL );
5372  assert( SCIPrelaxGetData(relax) != NULL );
5373 
5374  return ( SCIPrelaxGetData(relax)->stablenoslater );
5375 }
5376 
5379  SCIP_RELAX* relax
5380  )
5381 {
5382  assert( relax != NULL );
5383  assert( SCIPrelaxGetData(relax) != NULL );
5384 
5385  return ( SCIPrelaxGetData(relax)->unstablenoslater );
5386 }
5387 
5390  SCIP_RELAX* relax
5391  )
5392 {
5393  assert( relax != NULL );
5394  assert( SCIPrelaxGetData(relax) != NULL );
5395 
5396  return ( SCIPrelaxGetData(relax)->penaltynoslater );
5397 }
5398 
5401  SCIP_RELAX* relax
5402  )
5403 {
5404  assert( relax != NULL );
5405  assert( SCIPrelaxGetData(relax) != NULL );
5406 
5407  return ( SCIPrelaxGetData(relax)->boundednoslater );
5408 }
5409 
5412  SCIP_RELAX* relax
5413  )
5414 {
5415  assert( relax != NULL );
5416  assert( SCIPrelaxGetData(relax) != NULL );
5417 
5418  return ( SCIPrelaxGetData(relax)->unsolvednoslater );
5419 }
5420 
5423  SCIP_RELAX* relax
5424  )
5425 {
5426  assert( relax != NULL );
5427  assert( SCIPrelaxGetData(relax) != NULL );
5428 
5429  return ( SCIPrelaxGetData(relax)->stableinfeasible );
5430 }
5431 
5434  SCIP_RELAX* relax
5435  )
5436 {
5437  assert( relax != NULL );
5438  assert( SCIPrelaxGetData(relax) != NULL );
5439 
5440  return ( SCIPrelaxGetData(relax)->unstableinfeasible );
5441 }
5442 
5445  SCIP_RELAX* relax
5446  )
5447 {
5448  assert( relax != NULL );
5449  assert( SCIPrelaxGetData(relax) != NULL );
5450 
5451  return ( SCIPrelaxGetData(relax)->penaltyinfeasible );
5452 }
5453 
5456  SCIP_RELAX* relax
5457  )
5458 {
5459  assert( relax != NULL );
5460  assert( SCIPrelaxGetData(relax) != NULL );
5461 
5462  return ( SCIPrelaxGetData(relax)->boundedinfeasible );
5463 }
5464 
5467  SCIP_RELAX* relax
5468  )
5469 {
5470  assert( relax != NULL );
5471  assert( SCIPrelaxGetData(relax) != NULL );
5472 
5473  return ( SCIPrelaxGetData(relax)->unsolvedinfeasible );
5474 }
SCIP_Real SCIPconsSdpGetMaxConstEntry(SCIP *scip, SCIP_CONS *cons)
Definition: cons_sdp.c:4956
#define RELAX_DESC
Definition: relax_sdp.c:66
SCIP_RETCODE SCIPsdpiFree(SCIP_SDPI **sdpi)
Definition: sdpi.c:1514
#define WARMSTART_PROJ_FACTOR_PRIMAL
Definition: relax_sdp.c:99
SCIP_Bool SCIPsdpiIsDualUnbounded(SCIP_SDPI *sdpi)
Definition: sdpi.c:2994
SCIP_RETCODE SCIPsdpiDelLPRows(SCIP_SDPI *sdpi, int firstrow, int lastrow)
Definition: sdpi.c:1984
int SCIPrelaxSdpGetNSlaterHoldsStable(SCIP_RELAX *relax)
Definition: relax_sdp.c:5312
int SCIPconsSdpComputeUbSparseSdpMatrixLength(SCIP_CONS *cons)
Definition: cons_sdp.c:5006
static SCIP_RETCODE putLpDataInInterface(SCIP *scip, SCIP_RELAXDATA *relaxdata, SCIP_Bool primalobj, SCIP_Bool dualobj)
Definition: relax_sdp.c:713
#define WARMSTART_MINVAL
Definition: relax_sdp.c:95
int SCIPrelaxSdpGetNSlaterInfeasibleFast(SCIP_RELAX *relax)
Definition: relax_sdp.c:5422
SCIP_RETCODE SCIPsdpiGetSdpCalls(SCIP_SDPI *sdpi, int *calls)
Definition: sdpi.c:3606
SCIP_Bool SCIPsdpiDoesWarmstartNeedPrimal(void)
Definition: sdpi.c:1428
static SCIP_DECL_RELAXCOPY(relaxCopySdp)
Definition: relax_sdp.c:4139
SCIP_RETCODE SCIPsdpVarmapperAddVars(SCIP *scip, SdpVarmapper *varmapper, int nvars, SCIP_VAR **vars)
Definition: SdpVarmapper.c:108
int SCIPrelaxSdpGetNSlaterFailsBounded(SCIP_RELAX *relax)
Definition: relax_sdp.c:5400
static SCIP_DECL_RELAXEXITSOL(relaxExitSolSdp)
Definition: relax_sdp.c:4152
#define DEFAULT_PENINFEASADJUST
Definition: relax_sdp.c:93
int SCIPrelaxSdpGetNprimalSlaterHolds(SCIP_RELAX *relax)
Definition: relax_sdp.c:5257
SCIP_Real SCIPconsSavesdpsolGetMaxPrimalEntry(SCIP *scip, SCIP_CONS *cons)
static SCIP_Bool allVarsFixed(SCIP *scip)
Definition: relax_sdp.c:3481
#define DEFAULT_SLATERCHECK
Definition: relax_sdp.c:83
#define WARMSTART_PREOPT_MIN_Z_LPVAL
Definition: relax_sdp.c:100
int SCIPrelaxSdpGetNSdpPenalty(SCIP_RELAX *relax)
Definition: relax_sdp.c:5191
void SCIPsdpVarfixerSortRowCol(int *row, int *col, SCIP_Real *val, int length)
Definition: SdpVarfixer.c:50
SCIP_RETCODE SCIPsdpiGetPrimalMatrix(SCIP_SDPI *sdpi, int nblocks, int *startXnblocknonz, int **startXrow, int **startXcol, SCIP_Real **startXval)
Definition: sdpi.c:3553
enum SCIP_SDPSolverSetting SCIP_SDPSOLVERSETTING
Definition: type_sdpi.h:80
static SCIP_DECL_RELAXEXIT(relaxExitSdp)
Definition: relax_sdp.c:4344
SCIP_RETCODE SCIPconsSavesdpsolGetPrimalMatrixNonzeros(SCIP *scip, SCIP_CONS *cons, int nblocks, int *startXnblocknonz)
int SCIPrelaxSdpGetNdualSlaterHolds(SCIP_RELAX *relax)
Definition: relax_sdp.c:5213
const char * SCIPsdpiGetSolverName(void)
Definition: sdpi.c:1375
SCIP_RETCODE SCIPsdpiGetSol(SCIP_SDPI *sdpi, SCIP_Real *objval, SCIP_Real *dualsol, int *dualsollength)
Definition: sdpi.c:3328
SDP-relaxator.
#define RELAX_PRIORITY
Definition: relax_sdp.c:67
int SCIPrelaxSdpGetNSdpUnsolved(SCIP_RELAX *relax)
Definition: relax_sdp.c:5202
#define DEFAULT_PENALTYPARAM
Definition: relax_sdp.c:71
SCIP_RETCODE createConsSavesdpsol(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_Longint node, SCIP_SOL *sol, SCIP_Real maxprimalentry, int nblocks, int *startXnblocknonz, int **startXrow, int **startXcol, SCIP_Real **startXval)
SCIP_RETCODE SCIPsdpiSolve(SCIP_SDPI *sdpi, SCIP_Real *starty, int *startZnblocknonz, int **startZrow, int **startZcol, SCIP_Real **startZval, int *startXnblocknonz, int **startXrow, int **startXcol, SCIP_Real **startXval, SCIP_SDPSOLVERSETTING startsettings, SCIP_Bool enforceslatercheck, SCIP_Real timelimit)
Definition: sdpi.c:2454
SCIP_Bool SCIPsdpiFeasibilityKnown(SCIP_SDPI *sdpi)
Definition: sdpi.c:2878
SCIP_RETCODE SCIPsdpiLoadSDP(SCIP_SDPI *sdpi, int nvars, SCIP_Real *obj, SCIP_Real *lb, SCIP_Real *ub, int nsdpblocks, int *sdpblocksizes, int *sdpnblockvars, int sdpconstnnonz, int *sdpconstnblocknonz, int **sdpconstrow, int **sdpconstcol, SCIP_Real **sdpconstval, int sdpnnonz, int **sdpnblockvarnonz, int **sdpvar, int ***sdprow, int ***sdpcol, SCIP_Real ***sdpval, int nlpcons, SCIP_Real *lplhs, SCIP_Real *lprhs, int lpnnonz, int *lprow, int *lpcol, SCIP_Real *lpval)
Definition: sdpi.c:1699
SCIP_RETCODE SCIPsdpiComputeLambdastar(SCIP_SDPI *sdpi, SCIP_Real maxguess)
Definition: sdpi.c:4190
SCIP_RETCODE SCIPsdpiGetPrimalNonzeros(SCIP_SDPI *sdpi, int nblocks, int *startXnblocknonz)
Definition: sdpi.c:3523
SCIP_RETCODE createConsSavedsdpsettings(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_SDPSOLVERSETTING settings)
SCIP_SOL * SCIPconsSavesdpsolGetDualVector(SCIP *scip, SCIP_CONS *cons)
#define DEFAULT_TIGHTENVB
Definition: relax_sdp.c:86
static SCIP_DECL_RELAXEXEC(relaxExecSdp)
Definition: relax_sdp.c:3505
SCIP_VAR * SCIPsdpVarmapperGetSCIPvar(SdpVarmapper *varmapper, int ind)
Definition: SdpVarmapper.c:253
SCIP_RETCODE SCIPsdpiGetIterations(SCIP_SDPI *sdpi, int *iterations)
Definition: sdpi.c:3592
#define DEFAULT_SETTINGSRESETFREQ
Definition: relax_sdp.c:90
SCIP_RETCODE SCIPsdpiSettingsUsed(SCIP_SDPI *sdpi, SCIP_SDPSOLVERSETTING *usedsetting)
Definition: sdpi.c:3620
SCIP_RETCODE SCIPsdpiSlaterSettings(SCIP_SDPI *sdpi, SCIP_SDPSLATERSETTING *slatersetting)
Definition: sdpi.c:3657
int SCIPrelaxSdpGetNdualSlaterFails(SCIP_RELAX *relax)
Definition: relax_sdp.c:5224
SCIP_Bool SCIPsdpiIsAcceptable(SCIP_SDPI *sdpi)
Definition: sdpi.c:3216
int SCIPsdpVarmapperGetNVars(SdpVarmapper *varmapper)
Definition: SdpVarmapper.c:215
static SCIP_DECL_RELAXINITSOL(relaxInitSolSdp)
Definition: relax_sdp.c:3685
int SCIPrelaxSdpGetNSdpStable(SCIP_RELAX *relax)
Definition: relax_sdp.c:5180
SCIP_RETCODE SCIPconsSdpComputeSparseSdpMatrix(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, int *length, int *row, int *col, SCIP_Real *val)
Definition: cons_sdp.c:5034
int SCIPrelaxSdpGetNSdpMedium(SCIP_RELAX *relax)
Definition: relax_sdp.c:5169
SCIP_RETCODE SCIPsdpVarmapperCreate(SCIP *scip, SdpVarmapper **varmapper, int size)
Definition: SdpVarmapper.c:53
#define DEFAULT_WARMSTARTIPFACTOR
Definition: relax_sdp.c:74
SCIP_Bool SCIPsdpiIsTimelimExc(SCIP_SDPI *sdpi)
Definition: sdpi.c:3130
SCIP_RETCODE SCIPrelaxSdpRelaxVal(SCIP_RELAX *relax, SCIP_Bool *success, SCIP_Real *objval)
Definition: relax_sdp.c:4997
SCIP_Bool SCIPsdpiIsDualInfeasible(SCIP_SDPI *sdpi)
Definition: sdpi.c:3018
General interface methods for SDP-preprocessing (mainly fixing variables and removing empty rows/cols...
int SCIPrelaxSdpGetNSlaterFailsFast(SCIP_RELAX *relax)
Definition: relax_sdp.c:5367
static SCIP_DECL_RELAXFREE(relaxFreeSdp)
Definition: relax_sdp.c:4363
SCIP_RETCODE SCIPlapackMatrixMatrixMult(int nrowsA, int ncolsA, SCIP_Real *matrixA, SCIP_Bool transposeA, int nrowsB, int ncolsB, SCIP_Real *matrixB, SCIP_Bool transposeB, SCIP_Real *result)
struct Sdpvarmapper SdpVarmapper
Definition: SdpVarmapper.h:48
int SCIPrelaxSdpGetNSlaterFailsStable(SCIP_RELAX *relax)
Definition: relax_sdp.c:5378
enum SCIP_SDPSlaterSetting SCIP_SDPSLATERSETTING
Definition: type_sdpi.h:102
#define DEFAULT_DISPLAYSTAT
Definition: relax_sdp.c:89
int SCIPsdpVarmapperGetSdpIndex(SdpVarmapper *varmapper, SCIP_VAR *var)
Definition: SdpVarmapper.c:237
int SCIPrelaxSdpGetNSdpInterfaceCalls(SCIP_RELAX *relax)
Definition: relax_sdp.c:5147
int SCIPrelaxSdpGetNSlaterHolds(SCIP_RELAX *relax)
Definition: relax_sdp.c:5290
SCIP_RETCODE SCIPsdpiChgBounds(SCIP_SDPI *sdpi, int nvars, const int *ind, const SCIP_Real *lb, const SCIP_Real *ub)
Definition: sdpi.c:2181
int SCIPrelaxSdpGetNSdpCalls(SCIP_RELAX *relax)
Definition: relax_sdp.c:5136
Constraint handler for SDP-constraints.
SCIP_RETCODE SCIPsdpiGetLowerObjbound(SCIP_SDPI *sdpi, SCIP_Real *objlb)
Definition: sdpi.c:3278
SCIP_Bool SCIPsdpiIsObjlimExc(SCIP_SDPI *sdpi)
Definition: sdpi.c:3086
maps SCIP variables to SDP indices (the SCIP variables are given SDP indices in the order in which th...
#define DEFAULT_MAXPENALTYPARAM
Definition: relax_sdp.c:73
SCIP_Real SCIPconsSdpGetMaxSdpCoef(SCIP *scip, SCIP_CONS *cons)
Definition: cons_sdp.c:4972
SCIP_Real SCIPsdpiGetDefaultSdpiSolverFeastol(void)
Definition: sdpi.c:1404
int SCIPconsSdpCompLowerTriangPos(int i, int j)
Definition: cons_sdp.c:4585
int SCIPrelaxSdpGetNSlaterHoldsUnsolved(SCIP_RELAX *relax)
Definition: relax_sdp.c:5345
#define DEFAULT_SDPINFO
Definition: relax_sdp.c:87
#define WARMSTART_PROJ_FACTOR_LHS
Definition: relax_sdp.c:98
SCIP_RETCODE SCIPsdpiAddLPRows(SCIP_SDPI *sdpi, int nrows, const SCIP_Real *lhs, const SCIP_Real *rhs, int nnonz, const int *row, const int *col, const SCIP_Real *val)
Definition: sdpi.c:1919
#define WARMSTART_PROJ_FACTOR
Definition: relax_sdp.c:97
SCIP_RETCODE SCIPconsSdpGetData(SCIP *scip, SCIP_CONS *cons, int *nvars, int *nnonz, int *blocksize, int *arraylength, int *nvarnonz, int **col, int **row, SCIP_Real **val, SCIP_VAR **vars, int *constnnonz, int *constcol, int *constrow, SCIP_Real *constval, SCIP_Bool *rankone, int **maxevsubmat, SCIP_Bool *addedquadcons)
Definition: cons_sdp.c:4603
int SCIPrelaxSdpGetNSlaterInfeasibleStable(SCIP_RELAX *relax)
Definition: relax_sdp.c:5433
int SCIPrelaxSdpGetNdualSlaterUnknown(SCIP_RELAX *relax)
Definition: relax_sdp.c:5246
#define DEFAULT_OBJLIMIT
Definition: relax_sdp.c:84
const char * SCIPsdpiGetSolverDesc(void)
Definition: sdpi.c:1383
SCIP_RETCODE SCIPsdpiComputePenaltyparam(SCIP_SDPI *sdpi, SCIP_Real maxcoeff, SCIP_Real *penaltyparam)
Definition: sdpi.c:4199
SCIP_RETCODE SCIPsdpiSetIntpar(SCIP_SDPI *sdpi, SCIP_SDPPARAM type, int ival)
Definition: sdpi.c:4158
SCIP_SDPSOLVERSETTING SCIPconsSavedsdpsettingsGetSettings(SCIP *scip, SCIP_CONS *cons)
#define DEFAULT_SETTINGSRESETOFS
Definition: relax_sdp.c:91
SCIP_Bool SCIPrelaxSdpSolvedProbing(SCIP_RELAX *relax)
Definition: relax_sdp.c:5080
SCIP_Real SCIPsdpiInfinity(SCIP_SDPI *sdpi)
Definition: sdpi.c:4005
#define RELAX_FREQ
Definition: relax_sdp.c:68
SCIP_RETCODE SCIPconsSavesdpsolGetPrimalMatrix(SCIP *scip, SCIP_CONS *cons, int nblocks, int *startXnblocknonz, int **startXrow, int **startXcol, SCIP_Real **startXval)
long int SCIPrelaxSdpGetSdpNode(SCIP_RELAX *relax)
Definition: relax_sdp.c:5052
SCIP_RETCODE SCIPsdpiCreate(SCIP_SDPI **sdpi, SCIP_MESSAGEHDLR *messagehdlr, BMS_BLKMEM *blkmem, BMS_BUFMEM *bufmem)
Definition: sdpi.c:1446
#define DEFAULT_WARMSTARTPROJECT
Definition: relax_sdp.c:77
int SCIPrelaxSdpGetNSlaterFailsPenalty(SCIP_RELAX *relax)
Definition: relax_sdp.c:5389
int SCIPrelaxSdpGetNSdpFast(SCIP_RELAX *relax)
Definition: relax_sdp.c:5158
SCIP_Bool SCIPrelaxSdpSolvedOrig(SCIP_RELAX *relax)
Definition: relax_sdp.c:5063
#define DEFAULT_WARMSTARTIPTYPE
Definition: relax_sdp.c:76
adds the main functionality to fix/unfix/(multi-)aggregate variables by merging two three-tuple-array...
int SCIPrelaxSdpGetNSlaterHoldsFast(SCIP_RELAX *relax)
Definition: relax_sdp.c:5301
int SCIPrelaxSdpGetNSlaterInfeasiblePenalty(SCIP_RELAX *relax)
Definition: relax_sdp.c:5444
#define WARMSTART_PROJ_MINRHSOBJ
Definition: relax_sdp.c:96
int SCIPsdpiGetDefaultSdpiSolverNpenaltyIncreases(void)
Definition: sdpi.c:1420
#define DEFAULT_WARMSTARTPRIMALTYPE
Definition: relax_sdp.c:75
SCIP_Bool SCIPsdpiWasSolved(SCIP_SDPI *sdpi)
Definition: sdpi.c:2855
int SCIPrelaxSdpGetNIterations(SCIP_RELAX *relax)
Definition: relax_sdp.c:5125
int SCIPrelaxSdpGetNSlaterFails(SCIP_RELAX *relax)
Definition: relax_sdp.c:5356
SCIP_RETCODE SCIPsdpiComputeMaxPenaltyparam(SCIP_SDPI *sdpi, SCIP_Real penaltyparam, SCIP_Real *maxpenaltyparam)
Definition: sdpi.c:4213
SCIP_RETCODE SCIPsdpiClear(SCIP_SDPI *sdpi)
Definition: sdpi.c:2136
SCIP_RETCODE SCIPsdpiChgObj(SCIP_SDPI *sdpi, int nvars, const int *ind, const SCIP_Real *obj)
Definition: sdpi.c:2152
SCIP_RETCODE SCIPrelaxSdpGetRelaxSol(SCIP *scip, SCIP_RELAX *relax, SCIP_Bool *success, SCIP_Real *solarray, int *sollength)
Definition: relax_sdp.c:5019
SCIP_RETCODE SCIPsdpiGetPreoptimalSol(SCIP_SDPI *sdpi, SCIP_Bool *success, SCIP_Real *dualsol, int *dualsollength, int nblocks, int *startXnblocknonz, int **startXrow, int **startXcol, SCIP_Real **startXval)
Definition: sdpi.c:3417
int SCIPconsSdpGetBlocksize(SCIP *scip, SCIP_CONS *cons)
Definition: cons_sdp.c:4735
int SCIPrelaxSdpGetNSlaterHoldsBounded(SCIP_RELAX *relax)
Definition: relax_sdp.c:5334
int SCIPrelaxSdpGetNprimalSlaterFails(SCIP_RELAX *relax)
Definition: relax_sdp.c:5268
int SCIPrelaxSdpGetNSlaterInfeasibleBounded(SCIP_RELAX *relax)
Definition: relax_sdp.c:5455
SCIP_RETCODE SCIPsdpVarmapperFree(SCIP *scip, SdpVarmapper **varmapper)
Definition: SdpVarmapper.c:80
SCIP_RETCODE SCIPrelaxSdpGetPrimalBoundVars(SCIP_RELAX *relax, SCIP_Real *lbvars, SCIP_Real *ubvars, int *arraylength)
Definition: relax_sdp.c:4972
#define DEFAULT_LAMBDASTAR
Definition: relax_sdp.c:72
static SCIP_RETCODE scaleTransposedMatrix(int blocksize, SCIP_Real *matrix, SCIP_Real *scale)
Definition: relax_sdp.c:250
SCIP_RETCODE SCIPsdpVarfixerMergeArrays(BMS_BLKMEM *blkmem, SCIP_Real epsilon, int *originrow, int *origincol, SCIP_Real *originval, int originlength, SCIP_Bool originsorted, SCIP_Real scalar, int *targetrow, int *targetcol, SCIP_Real *targetval, int *targetlength, int targetmemory)
Definition: SdpVarfixer.c:87
#define DEFAULT_WARMSTARTROUNDONLYINF
Definition: relax_sdp.c:82
SCIP_Bool SCIPsdpiIsDualFeasible(SCIP_SDPI *sdpi)
Definition: sdpi.c:3042
struct SCIP_SDPi SCIP_SDPI
Definition: type_sdpi.h:114
SCIP_Bool SCIPsdpiIsPrimalFeasible(SCIP_SDPI *sdpi)
Definition: sdpi.c:2970
SCIP_Bool SCIPrelaxSdpIsFeasible(SCIP_RELAX *relax)
Definition: relax_sdp.c:5097
SCIP_RETCODE SCIPsdpiSetRealpar(SCIP_SDPI *sdpi, SCIP_SDPPARAM type, SCIP_Real dval)
Definition: sdpi.c:4076
SCIP_Longint SCIPconsSavesdpsolGetNodeIndex(SCIP *scip, SCIP_CONS *cons)
int SCIPrelaxSdpGetNSlaterFailsUnsolved(SCIP_RELAX *relax)
Definition: relax_sdp.c:5411
#define DEFAULT_WARMSTARTPROJMINEV
Definition: relax_sdp.c:78
static SCIP_RETCODE calcRelax(SCIP *scip, SCIP_RELAX *relax, SCIP_RESULT *result, SCIP_Real *lowerbound)
Definition: relax_sdp.c:938
enum SCIP_SDPSlater SCIP_SDPSLATER
Definition: type_sdpi.h:112
SCIP_Real SCIPsdpiGetMaxPrimalEntry(SCIP_SDPI *sdpi)
Definition: sdpi.c:3582
#define RELAX_NAME
Definition: relax_sdp.c:65
SCIP_RETCODE SCIPconsSdpGetNNonz(SCIP *scip, SCIP_CONS *cons, int *nnonz, int *constnnonz)
Definition: cons_sdp.c:4710
SCIP_Bool SCIPrelaxSdpIsUnbounded(SCIP_RELAX *relax)
Definition: relax_sdp.c:5108
interface methods for eigenvector computation and matrix multiplication using openblas ...
SCIP_RETCODE SCIPsdpiGetRealpar(SCIP_SDPI *sdpi, SCIP_SDPPARAM type, SCIP_Real *dval)
Definition: sdpi.c:4026
static SCIP_RETCODE putSdpDataInInterface(SCIP *scip, SCIP_SDPI *sdpi, SdpVarmapper *varmapper, SCIP_Bool primalobj, SCIP_Bool boundprimal)
Definition: relax_sdp.c:473
int SCIPrelaxSdpGetNdualSlaterInfeasible(SCIP_RELAX *relax)
Definition: relax_sdp.c:5235
SCIP_Real SCIPsdpiGetDefaultSdpiSolverGaptol(void)
Definition: sdpi.c:1412
static SCIP_RETCODE updateSDPStatistics(SCIP_RELAXDATA *relaxdata)
Definition: relax_sdp.c:276
SCIP_RETCODE SCIPsdpiGetPreoptimalPrimalNonzeros(SCIP_SDPI *sdpi, int nblocks, int *startXnblocknonz)
Definition: sdpi.c:3379
SCIP_RETCODE SCIPrelaxSdpComputeAnalyticCenters(SCIP *scip, SCIP_RELAX *relax)
Definition: relax_sdp.c:4551
static SCIP_RETCODE expandSparseMatrix(int nnonz, int blocksize, int *row, int *col, SCIP_Real *val, SCIP_Real *fullmat)
Definition: relax_sdp.c:213
#define DEFAULT_WARMSTART
Definition: relax_sdp.c:88
SCIP_RETCODE SCIPlapackComputeEigenvectorDecomposition(BMS_BUFMEM *bufmem, int n, SCIP_Real *A, SCIP_Real *eigenvalues, SCIP_Real *eigenvectors)
int SCIPrelaxSdpGetNSlaterHoldsPenalty(SCIP_RELAX *relax)
Definition: relax_sdp.c:5323
#define DEFAULT_RESOLVE
Definition: relax_sdp.c:85
SCIP_RETCODE SCIPsdpiGetNLPRows(SCIP_SDPI *sdpi, int *nlprows)
Definition: sdpi.c:2259
#define DEFAULT_WARMSTARTPREOPTGAP
Definition: relax_sdp.c:81
SCIP_RETCODE SCIPsdpiGetPrimalBoundVars(SCIP_SDPI *sdpi, SCIP_Real *lbvars, SCIP_Real *ubvars, int *arraylength)
Definition: sdpi.c:3491
#define DEFAULT_WARMSTARTPROJPDSAME
Definition: relax_sdp.c:79
int SCIPrelaxSdpGetNprimalSlaterUnknown(SCIP_RELAX *relax)
Definition: relax_sdp.c:5279
SCIP_RETCODE SCIPconsSdpGuessInitialPoint(SCIP *scip, SCIP_CONS *cons, SCIP_Real *lambdastar)
Definition: cons_sdp.c:4860
int SCIPrelaxSdpGetNSlaterInfeasibleUnsolved(SCIP_RELAX *relax)
Definition: relax_sdp.c:5466
SCIP_Bool SCIPsdpiSolvedOrig(SCIP_SDPI *sdpi)
Definition: sdpi.c:2865
SCIP_RETCODE SCIPsdpiSlater(SCIP_SDPI *sdpi, SCIP_SDPSLATER *primalslater, SCIP_SDPSLATER *dualslater)
Definition: sdpi.c:3962
#define DEFAULT_SDPSOLVERTHREADS
Definition: relax_sdp.c:92
constraint handler for saving SDP solutions in nodes
SCIP_RETCODE SCIPincludeRelaxSdp(SCIP *scip)
Definition: relax_sdp.c:4387
#define DEFAULT_WARMSTART_PREOPTIMAL_SOL
Definition: relax_sdp.c:80
constraint handler for saving SDP settings