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