SCIP-SDP  4.0.0
cons_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 
49 /* #define SCIP_DEBUG */
50 /* #define SCIP_MORE_DEBUG /\* shows all cuts added and prints constraint after parsing *\/ */
51 /* #define PRINT_HUMAN_READABLE /\* change the output of PRINTCONS to a better readable format (dense instead of sparse), WHICH CAN NO LONGER BE PARSED *\/ */
52 /* #define PRINTMATRICES /\* Should all matrices appearing in best rank-1 approximation heuristic be printed? *\/ */
53 
54 #include "cons_sdp.h"
55 
56 #include <assert.h> /*lint !e451*/
57 #include <string.h> /* for NULL, strcmp */
58 #include <ctype.h> /* for isspace */
59 #include <math.h>
60 #include "sdpi/lapack_interface.h"
61 #include "sdpi/solveonevarsdp.h"
62 #include "relax_sdp.h"
63 
64 #include "scipsdp/SdpVarmapper.h"
65 #include "scipsdp/SdpVarfixer.h"
66 
67 #include "scip/cons_linear.h" /* for SCIPcreateConsLinear */
68 #include "scip/cons_nonlinear.h" /* for newer SCIP versions */
69 #include "scip/cons_quadratic.h" /* for SCIPcreateConsBasicQuadratic */
70 #include "scip/cons_soc.h" /* for SCIPcreateConsSOC */
71 #include "scip/cons_linear.h" /* for separateSol() */
72 #include "scip/scip_cons.h" /* for SCIPgetConsVars */
73 #include "scip/scip.h" /* for SCIPallocBufferArray, etc */
74 #include "scip/def.h"
75 
76 #ifdef OMP
77 #include "omp.h" /* for changing the number of threads */
78 #endif
79 
80 /* turn off lint warnings for whole file: */
81 /*lint --e{788,818}*/
82 
83 #define CONSHDLR_NAME "SDP"
84 #define CONSHDLR_DESC "SDP constraints of the form \\sum_{j} A_j y_j - A_0 psd"
85 
86 #define CONSHDLRRANK1_NAME "SDPrank1"
87 #define CONSHDLRRANK1_DESC "rank 1 SDP constraints"
88 
89 #define CONSHDLR_SEPAPRIORITY +1000000
90 #define CONSHDLR_ENFOPRIORITY -2000000
91 #define CONSHDLR_CHECKPRIORITY -2000000
92 #define CONSHDLR_PROPFREQ 1
93 #define CONSHDLR_SEPAFREQ 1
94 #define CONSHDLR_EAGERFREQ 100
96 #define CONSHDLR_MAXPREROUNDS -1
97 #define CONSHDLR_DELAYSEPA FALSE
98 #define CONSHDLR_NEEDSCONS TRUE
100 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_EXHAUSTIVE
101 #define CONSHDLR_PROPTIMING SCIP_PROPTIMING_BEFORELP
103 #define PARSE_STARTSIZE 1
104 #define PARSE_SIZEFACTOR 10
106 #define DEFAULT_PROPUPPERBOUNDS TRUE
107 #define DEFAULT_PROPUBPRESOL TRUE
108 #define DEFAULT_PROPTIGHTENBOUNDS TRUE
109 #define DEFAULT_PROPTBPROBING FALSE
110 #define DEFAULT_TIGHTENBOUNDSCONT FALSE
111 #define DEFAULT_TIGHTENMATRICES FALSE
112 #define DEFAULT_TIGHTENBOUNDS TRUE
113 #define DEFAULT_DIAGGEZEROCUTS FALSE
114 #define DEFAULT_DIAGZEROIMPLCUTS TRUE
115 #define DEFAULT_TWOMINORLINCONSS FALSE
116 #define DEFAULT_TWOMINORPRODCONSS FALSE
117 #define DEFAULT_TWOMINORVARBOUNDS TRUE
118 #define DEFAULT_QUADCONSRANK1 TRUE
119 #define DEFAULT_UPGRADEQUADCONSS FALSE
120 #define DEFAULT_UPGRADEKEEPQUAD FALSE
121 #define DEFAULT_MAXNVARSQUADUPGD 1000
122 #define DEFAULT_RANK1APPROXHEUR FALSE
123 #define DEFAULT_SEPARATEONECUT FALSE
124 #define DEFAULT_CUTSTOPOOL TRUE
125 #define DEFAULT_SPARSIFYCUT FALSE
126 #define DEFAULT_SPARSIFYFACTOR 0.1
127 #define DEFAULT_SPARSIFYTARGETSIZE -1
128 #define DEFAULT_MULTIPLESPARSECUTS FALSE
129 #define DEFAULT_MAXNSPARSECUTS 0
130 #define DEFAULT_ENFORCESDP FALSE
131 #define DEFAULT_ONLYFIXEDINTSSDP FALSE
132 #define DEFAULT_ADDSOCRELAX FALSE
133 #define DEFAULT_USEDIMACSFEASTOL FALSE
134 #define DEFAULT_GENERATEROWS TRUE
136 #ifdef OMP
137 #define DEFAULT_NTHREADS 1
138 #endif
139 
140 /* defines for sparsification of eigenvector cuts using TPower */
141 #define DEFAULT_RECOMPUTESPARSEEV FALSE
142 #define DEFAULT_RECOMPUTEINITIAL FALSE
143 #define DEFAULT_EXACTTRANS FALSE
146 struct SCIP_ConsData
147 {
148  int nvars;
149  int nnonz;
150  int blocksize;
151  int* nvarnonz;
152  int** col;
153  int** row;
154  SCIP_Real** val;
155  SCIP_VAR** vars;
156  int* locks;
157  int constnnonz;
158  int* constcol;
159  int* constrow;
160  SCIP_Real* constval;
161  SCIP_Real maxrhsentry;
162  SCIP_Bool rankone;
163  int* maxevsubmat;
164  SCIP_Bool addedquadcons;
165  /* alternative view via matrix entries for propagation */
166  SCIP_VAR** matrixvar;
167  SCIP_Real* matrixval;
168  SCIP_Real* matrixconst;
169  int nsingle;
170  SCIP_Real tracebound;
171  SCIP_Bool allmatricespsd;
172  SCIP_Bool initallmatricespsd;
173 };
174 
176 struct SCIP_ConshdlrData
177 {
178  int neigveccuts;
179  SCIP_Bool diaggezerocuts;
180  int ndiaggezerocuts;
181  int n1x1blocks;
182  SCIP_Bool propupperbounds;
183  SCIP_Bool propubpresol;
184  SCIP_Bool tightenboundscont;
185  SCIP_Bool proptightenbounds;
186  SCIP_Bool proptbprobing;
187  SCIP_Bool tightenmatrices;
188  SCIP_Bool tightenbounds;
189  SCIP_Bool diagzeroimplcuts;
190  SCIP_Bool twominorlinconss;
191  SCIP_Bool twominorprodconss;
192  SCIP_Bool twominorvarbounds;
193  SCIP_Bool quadconsrank1;
194  SCIP_Bool upgradequadconss;
195  SCIP_Bool upgradekeepquad;
196  SCIP_Bool separateonecut;
197  SCIP_Bool cutstopool;
198  SCIP_Bool sparsifycut;
199  SCIP_Real sparsifyfactor;
200  int sparsifytargetsize;
201  SCIP_Bool multiplesparsecuts;
202  int maxnsparsecuts;
203  SCIP_Bool enforcesdp;
204  SCIP_Bool onlyfixedintssdp;
205  SCIP_Bool addsocrelax;
206  int maxnvarsquadupgd;
207  SCIP_Bool triedlinearconss;
208  SCIP_Bool triedvarbounds;
209  SCIP_Bool rank1approxheur;
210  SCIP_Bool generaterows;
211 #ifdef OMP
212  int nthreads;
213 #endif
214  int* quadconsidx;
215  SCIP_VAR** quadconsvars;
216  int nquadconsidx;
217  SCIP_VAR*** X;
218  int nsdpvars;
219  SCIP_CONS* sdpcons;
220  SCIP_CONSHDLRDATA* sdpconshdlrdata;
221  SCIP_RANDNUMGEN* randnumgen;
222  SCIP_RELAX* relaxsdp;
223  SCIP_Bool usedimacsfeastol;
224  SCIP_Real dimacsfeastol;
225  SCIP_Bool recomputesparseev;
226  SCIP_Bool recomputeinitial;
227  SCIP_Bool exacttrans;
228 };
229 
233 static
235  int rows,
236  int cols,
237  SCIP_Real* rowmatrix,
238  SCIP_Real* colmatrix
240  )
241 {
242  int i;
243  int j;
244  SCIP_Real act;
245 
246  assert( rows > 0 );
247  assert( cols > 0 );
248  assert( rowmatrix != NULL );
249  assert( colmatrix != NULL );
250 
251  for (i = 0; i < rows; ++i)
252  {
253  for (j = 0; j < cols; ++j)
254  {
255  act = rowmatrix[i*cols + j];
256  colmatrix[j*rows + i] = act;
257  }
258  }
259 
260  return SCIP_OKAY;
261 }
262 
264 static
265 SCIP_RETCODE scaleRowsMatrix(
266  int blocksize, /* number of rows and columns */
267  SCIP_Real* matrix, /* matrix entries given as blocksize^2 array */
268  SCIP_Real* scale /* array of length blocksize to multiply the rows of matrix with */
269  )
270 {
271  int r; /* rows */
272  int c; /* columns */
273 
274  assert( blocksize >= 0 );
275  assert( matrix != NULL );
276  assert( scale != NULL );
277 
278  for (r = 0; r < blocksize; r++)
279  {
280  for (c = 0; c < blocksize; c++)
281  {
282  /* row-first format! */
283  matrix[r * blocksize + c] *= scale[r]; /*lint !e679*/
284  }
285  }
286 
287  return SCIP_OKAY;
288 }
289 
291 static
292 SCIP_RETCODE expandSymMatrix(
293  int size,
294  SCIP_Real* symMat,
295  SCIP_Real* fullMat
296  )
297 {
298  int i;
299  int j;
300  int ind = 0;
301 
302  assert( size >= 0 );
303  assert( symMat != NULL );
304  assert( fullMat != NULL );
305 
306  /* traverse the lower triangular part in the order of the indices and copy the values to both lower and upper triangular part */
307  for (i = 0; i < size; i++)
308  {
309  for (j = 0; j <= i; j++)
310  {
311  assert( ind == SCIPconsSdpCompLowerTriangPos(i,j) );
312  fullMat[i*size + j] = symMat[ind]; /*lint !e679*/
313  fullMat[j*size + i] = symMat[ind]; /*lint !e679*/
314  ind++;
315  }
316  }
317 
318  return SCIP_OKAY;
319 }
320 
324 static
325 SCIP_RETCODE computeSdpMatrix(
326  SCIP* scip,
327  SCIP_CONSDATA* consdata,
328  SCIP_SOL* sol,
329  SCIP_Real* matrix
330  )
331 {
332  SCIP_Real yval;
333  int blocksize;
334  int nvars;
335  int i;
336  int j;
337 
338  assert( consdata != NULL );
339  assert( matrix != NULL );
340 
341  nvars = consdata->nvars;
342  blocksize = consdata->blocksize;
343 
344  /* initialize the matrix with 0 */
345  for (i = 0; i < (blocksize * (blocksize + 1))/2; ++i)
346  matrix[i] = 0.0;
347 
348  /* add the non-constant-part */
349  for (i = 0; i < nvars; i++)
350  {
351  yval = SCIPgetSolVal(scip, sol, consdata->vars[i]);
352  if ( ! SCIPisZero(scip, yval) )
353  {
354  for (j = 0; j < consdata->nvarnonz[i]; ++j)
355  matrix[SCIPconsSdpCompLowerTriangPos(consdata->row[i][j], consdata->col[i][j])] += yval * consdata->val[i][j];
356  }
357  }
358 
359  /* substract the constant part */
360  for (j = 0; j < consdata->constnnonz; ++j)
361  matrix[SCIPconsSdpCompLowerTriangPos(consdata->constrow[j], consdata->constcol[j])] -= consdata->constval[j];
362 
363  return SCIP_OKAY;
364 }
365 
367 static
368 SCIP_RETCODE computeFullSdpMatrix(
369  SCIP* scip,
370  SCIP_CONSDATA* consdata,
371  SCIP_SOL* sol,
372  SCIP_Real* fullmatrix
373  )
374 {
375  SCIP_Real aval;
376  int blocksize;
377  int nvars;
378  int r;
379  int c;
380  int i;
381  int j;
382 
383  assert( scip != NULL );
384  assert( consdata != NULL );
385  assert( fullmatrix != NULL );
386 
387  nvars = consdata->nvars;
388  blocksize = consdata->blocksize;
389 
390  /* initialize the matrix with 0 */
391  for (i = 0; i < blocksize * blocksize; ++i)
392  fullmatrix[i] = 0.0;
393 
394  /* add the non-constant-part */
395  for (i = 0; i < nvars; i++)
396  {
397  SCIP_Real yval;
398 
399  yval = SCIPgetSolVal(scip, sol, consdata->vars[i]);
400  if ( ! SCIPisZero(scip, yval) )
401  {
402  for (j = 0; j < consdata->nvarnonz[i]; ++j)
403  {
404  r = consdata->row[i][j];
405  c = consdata->col[i][j];
406  aval = consdata->val[i][j];
407 
408  if ( r == c )
409  fullmatrix[r * blocksize + c] += yval * aval;
410  else
411  {
412  fullmatrix[r * blocksize + c] += yval * aval;
413  fullmatrix[c * blocksize + r] += yval * aval;
414  }
415  }
416  }
417  }
418 
419  /* substract the constant part */
420  for (j = 0; j < consdata->constnnonz; ++j)
421  {
422  r = consdata->constrow[j];
423  c = consdata->constcol[j];
424  aval = consdata->constval[j];
425 
426  if ( r == c )
427  fullmatrix[r * blocksize + c] -= aval;
428  else
429  {
430  fullmatrix[r * blocksize + c] -= aval;
431  fullmatrix[c * blocksize + r] -= aval;
432  }
433  }
434 
435  return SCIP_OKAY;
436 }
437 
439 static
440 SCIP_RETCODE constructMatrixvar(
441  SCIP* scip,
442  SCIP_CONS* cons,
443  SCIP_CONSDATA* consdata
444  )
445 {
446  SCIP_Real* constmatrix;
447  SCIP_Real** matrices;
448  int blocksize;
449  int cnt = 0;
450  int s;
451  int t;
452  int i;
453 
454  assert( scip != NULL );
455  assert( consdata != NULL );
456 
457  if ( consdata->matrixvar != NULL )
458  return SCIP_OKAY;
459 
460  consdata->nsingle = 0;
461  blocksize = consdata->blocksize;
462 
463  /* allocate matrices */
464  SCIP_CALL( SCIPallocBufferArray(scip, &constmatrix, blocksize * blocksize) );
465  SCIP_CALL( SCIPconsSdpGetFullConstMatrix(scip, cons, constmatrix) );
466 
467  SCIP_CALL( SCIPallocBufferArray(scip, &matrices, consdata->nvars) );
468  for (i = 0; i < consdata->nvars; ++i)
469  {
470  SCIP_CALL( SCIPallocBufferArray(scip, &matrices[i], blocksize * blocksize) );
471  SCIP_CALL( SCIPconsSdpGetFullAj(scip, cons, i, matrices[i]) );
472  }
473 
474  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->matrixvar, blocksize * (blocksize+1)/2) );
475  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->matrixval, blocksize * (blocksize+1)/2) );
476  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->matrixconst, blocksize * (blocksize+1)/2) );
477 
478  for (s = 0; s < blocksize; ++s)
479  {
480  for (t = 0; t <= s; ++t)
481  {
482  SCIP_VAR* var = NULL;
483  SCIP_Real val = 0.0;
484  int pos;
485 
486  pos = s * blocksize + t;
487 
488  for (i = 0; i < consdata->nvars; ++i)
489  {
490  if ( ! SCIPisZero(scip, matrices[i][pos]) )
491  {
492  if ( var == NULL )
493  {
494  var = consdata->vars[i];
495  val = matrices[i][pos];
496  }
497  else
498  break;
499  }
500  }
501 
502  /* if at most one entry was found */
503  if ( i >= consdata->nvars )
504  {
505  consdata->matrixvar[cnt] = var; /* note that var == NULL is possible */
506  consdata->matrixval[cnt] = val;
507  consdata->matrixconst[cnt] = constmatrix[pos];
508  ++consdata->nsingle;
509  }
510  else
511  {
512  consdata->matrixvar[cnt] = NULL;
513  consdata->matrixval[cnt] = SCIP_INVALID;
514  consdata->matrixconst[cnt] = SCIP_INVALID;
515  }
516  ++cnt;
517  }
518  }
519  assert( cnt == blocksize * (blocksize + 1)/2 );
520 
521  SCIPfreeBufferArray(scip, &constmatrix);
522  for (i = consdata->nvars - 1; i >= 0; --i)
523  SCIPfreeBufferArray(scip, &matrices[i]);
524  SCIPfreeBufferArray(scip, &matrices);
525 
526  if ( SCIPgetSubscipDepth(scip) == 0 )
527  SCIPdebugMsg(scip, "Number of entries depending on a single variable: %d.\n", consdata->nsingle);
528 
529  return SCIP_OKAY;
530 }
531 
533 static
534 SCIP_RETCODE SCIPconsSdpCheckSdpCons(
535  SCIP* scip,
536  SCIP_CONSHDLRDATA* conshdlrdata,
537  SCIP_CONS* cons,
538  SCIP_SOL* sol,
539  SCIP_Bool printreason,
540  SCIP_RESULT* result
541  )
542 { /*lint --e{715}*/
543  SCIP_CONSDATA* consdata;
544  SCIP_Real* fullmatrix = NULL;
545  SCIP_Real eigenvalue;
546  SCIP_Real tol;
547  int blocksize;
548 
549  assert( scip != NULL );
550  assert( cons != NULL );
551  assert( result != NULL );
552 
553  consdata = SCIPconsGetData(cons);
554  assert( consdata != NULL );
555  assert( consdata->rankone || strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0 );
556  assert( ! consdata->rankone || strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLRRANK1_NAME) == 0 );
557  blocksize = consdata->blocksize;
558 
559  SCIP_CALL( SCIPallocBufferArray(scip, &fullmatrix, blocksize * blocksize) ); /*lint !e647*/
560 
561  SCIP_CALL( computeFullSdpMatrix(scip, consdata, sol, fullmatrix) );
562 
563  SCIP_CALL( SCIPlapackComputeIthEigenvalue(SCIPbuffer(scip), FALSE, blocksize, fullmatrix, 1, &eigenvalue, NULL) );
564 
565  if ( conshdlrdata->sdpconshdlrdata->usedimacsfeastol )
566  {
567  assert( conshdlrdata->dimacsfeastol != SCIP_INVALID );
568  tol = conshdlrdata->dimacsfeastol;
569  }
570  else
571  tol = SCIPfeastol(scip);
572 
573  if ( eigenvalue >= -tol )
574  *result = SCIP_FEASIBLE;
575  else
576  {
577  *result = SCIP_INFEASIBLE;
578  if ( printreason )
579  {
580  SCIPinfoMessage(scip, NULL, "SDP-constraint <%s> violated: non psd matrix (eigenvalue %f).\n", SCIPconsGetName(cons), eigenvalue);
581  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
582  }
583  }
584 
585  if ( sol != NULL )
586  SCIPupdateSolConsViolation(scip, sol, -eigenvalue, (-eigenvalue) / (1.0 + consdata->maxrhsentry));
587 
588  SCIPfreeBufferArray(scip, &fullmatrix);
589 
590  return SCIP_OKAY;
591 }
592 
594 static
595 SCIP_RETCODE isMatrixRankOne(
596  SCIP* scip,
597  SCIP_CONSHDLRDATA* conshdlrdata,
598  SCIP_CONS* cons,
599  SCIP_SOL* sol,
600  SCIP_Bool* result
601  )
602 {
603  SCIP_CONSDATA* consdata;
604  SCIP_Real* matrix = NULL;
605  SCIP_Real* fullmatrix = NULL;
606  SCIP_Real eigenvalue;
607  int blocksize;
608  SCIP_RESULT resultSDPtest;
609  int i;
610  int j;
611  int ind1 = 0;
612  int ind2 = 0;
613  SCIP_Real submatrix[4];
614  SCIP_Real largestminev = 0.0;
615 
616  assert( cons != NULL );
617  assert( result != NULL );
618 
619  consdata = SCIPconsGetData(cons);
620  assert( consdata != NULL );
621 
622  blocksize = consdata->blocksize;
623 
624  resultSDPtest = SCIP_INFEASIBLE;
625 
626  SCIP_CALL( SCIPconsSdpCheckSdpCons(scip, conshdlrdata, cons, sol, FALSE, &resultSDPtest) );
627 
628  if ( resultSDPtest == SCIP_INFEASIBLE )
629  {
630  SCIPerrorMessage("Try to check for a matrix to be rank 1 even if the matrix is not psd.\n");
631  return SCIP_ERROR;
632  }
633 
634  /* allocate memory to store full matrix */
635  SCIP_CALL( SCIPallocBufferArray(scip, &matrix, (blocksize * (blocksize+1))/2 ) );
636  SCIP_CALL( SCIPallocBufferArray(scip, &fullmatrix, blocksize * blocksize ) );
637 
638  /* compute the matrix \f$ \sum_j A_j y_j - A_0 \f$ - we need an undestroyed version in matrix below */
639  SCIP_CALL( computeSdpMatrix(scip, consdata, sol, matrix) );
640 
641  /* expand it because LAPACK wants the full matrix instead of the lower triangular part */
642  SCIP_CALL( expandSymMatrix(blocksize, matrix, fullmatrix) );
643 
644  /* compute the second largest eigenvalue */
645  SCIP_CALL( SCIPlapackComputeIthEigenvalue(SCIPbuffer(scip), FALSE, blocksize, fullmatrix, blocksize - 1, &eigenvalue, NULL) );
646 
647  /* the matrix is rank 1 iff the second largest eigenvalue is zero (since the matrix is symmetric and psd) */
648 
649  /* changed eigenvalue to 0.1*eigenvalue here, since here seems to be a problem with optimal solutions not satisfying
650  SCIPisFeasEQ(scip, 0.1*eigenvalue, 0.0), even if they are feasible for all other constraints, including the
651  quadratic 2x2 principal minor constraints. */
652  if ( SCIPisFeasEQ(scip, 0.1 * eigenvalue, 0.0) )
653  *result = TRUE;
654  else
655  {
656  *result = FALSE;
657 
658  /* if the matrix is not rank 1, compute minimal eigenvalues of 2x2 minors */
659  for (i = 0; i < blocksize; ++i)
660  {
661  for (j = 0; j < i; ++j)
662  {
663  submatrix[0] = matrix[SCIPconsSdpCompLowerTriangPos(i,i)];
664  submatrix[1] = matrix[SCIPconsSdpCompLowerTriangPos(i,j)];
665  submatrix[2] = matrix[SCIPconsSdpCompLowerTriangPos(i,j)];
666  submatrix[3] = matrix[SCIPconsSdpCompLowerTriangPos(j,j)];
667 
668  SCIP_CALL( SCIPlapackComputeIthEigenvalue(SCIPbuffer(scip), FALSE, 2, submatrix, 1, &eigenvalue, NULL) );
669  /* TODO: Compute eigenvalues by solving quadratic constraint */
670 
671  if ( eigenvalue > largestminev )
672  {
673  largestminev = eigenvalue;
674  ind1 = i;
675  ind2 = j;
676  }
677  }
678  }
679 
680  assert( ind1 > 0 || ind2 > 0 );
681  assert( SCIPisFeasPositive(scip, largestminev) ); /* because the second largest eigenvalue satisfies SCIPisFeasPositive. */
682 
683  /* save indices for submatrix with largest minimal eigenvalue */
684  consdata->maxevsubmat[0] = ind1;
685  consdata->maxevsubmat[1] = ind2;
686  }
687 
688  SCIPfreeBufferArray(scip, &fullmatrix);
689  SCIPfreeBufferArray(scip, &matrix);
690 
691  return SCIP_OKAY;
692 }
693 
695 static
696 SCIP_RETCODE multiplyConstraintMatrix(
697  SCIP_CONS* cons,
698  int j,
699  SCIP_Real* v,
700  SCIP_Real* vAv
701  )
702 {
703  SCIP_CONSDATA* consdata;
704  SCIP_Real s = 0.0;
705  int r;
706  int c;
707  int i;
708 
709  assert( cons != NULL );
710  assert( j >= 0 );
711  assert( vAv != NULL );
712 
713  consdata = SCIPconsGetData(cons);
714  assert( consdata != NULL );
715 
716  assert( j < consdata->nvars );
717 
718  for (i = 0; i < consdata->nvarnonz[j]; i++)
719  {
720  r = consdata->row[j][i];
721  c = consdata->col[j][i];
722  if ( r == c )
723  s += v[c] * consdata->val[j][i] * v[r];
724  else
725  {
726  /* Multiply by 2, because the matrix is symmetric and there is one identical contribution each from lower and upper triangular part. */
727  s += 2.0 * v[c] * consdata->val[j][i] * v[r];
728  }
729  }
730 
731  *vAv = s;
732 
733  return SCIP_OKAY;
734 }
735 
739 static
740 SCIP_RETCODE setMaxRhsEntry(
741  SCIP_CONS* cons
742  )
743 {
744  SCIP_CONSDATA* consdata;
745  SCIP_Real max = 0.0; /* initialize max with zero (this is used if there is no constant-matrix) */
746  int i;
747 
748  consdata = SCIPconsGetData(cons);
749  assert( consdata != NULL );
750 
751  /* iterate over the entries of the constant matrix, updating max if a higher absolute value is found */
752  for (i = 0; i < consdata->constnnonz; i++)
753  {
754  if ( REALABS(consdata->constval[i]) > max )
755  max = REALABS(consdata->constval[i]);
756  }
757 
758  consdata->maxrhsentry = max;
759 
760  return SCIP_OKAY;
761 }
762 
769 static
770 SCIP_RETCODE truncatedPowerMethod(
771  SCIP* scip,
772  int blocksize,
773  SCIP_Real* fullmatrix,
775  SCIP_Real* vector,
776  int sparsity,
777  SCIP_Real convergencetol,
778  SCIP_Real* eigenvector,
779  int* support,
780  SCIP_Real* eigenvalue
781  )
782 {
783  SCIP_Real* sortedev;
784  SCIP_Real* oldev;
785  SCIP_Real oldeig;
786  SCIP_Real neweig;
787  SCIP_Real norm;
788  int* indices;
789  int i;
790 
791  assert( scip != NULL );
792  assert( blocksize > 0 );
793  assert( fullmatrix != NULL );
794  assert( vector != NULL );
795  assert( sparsity > 0 && sparsity <= blocksize );
796  assert( eigenvector != NULL );
797  assert( eigenvalue != NULL );
798 
799  SCIPdebugMsg(scip, "Executing truncatedPowerMethod\n");
800 
801  SCIP_CALL( SCIPallocBufferArray(scip, &indices, blocksize) );
802  SCIP_CALL( SCIPallocBufferArray(scip, &sortedev, blocksize) );
803  SCIP_CALL( SCIPallocBufferArray(scip, &oldev, blocksize) );
804 
805  neweig = -1.0;
806  oldeig = -2.0;
807 
808  for (i = 0; i < blocksize; i++)
809  eigenvector[i] = vector[i];
810 
811  while ( neweig - oldeig > convergencetol )
812  {
813  /* reset eigenvector and eigenvalue */
814  oldeig = neweig;
815  neweig = 0.0;
816 
817  for (i = 0; i < blocksize; i++)
818  oldev[i] = eigenvector[i];
819 
820  SCIP_CALL( SCIPlapackMatrixVectorMult(blocksize, blocksize, fullmatrix, oldev, eigenvector) );
821 
822  /* get indices of largest absolute values */
823  for (i = 0; i < blocksize; i++)
824  {
825  indices[i] = i;
826  sortedev[i] = REALABS(eigenvector[i]);
827  }
828 
829  SCIPsortDownRealInt(sortedev, indices, blocksize);
830 
831  /* truncate iterate to entries with largest absolute value and save support */
832  for (i = sparsity; i < blocksize; i++)
833  {
834  eigenvector[indices[i]] = 0.0;
835  support[indices[i]] = 0;
836  }
837 
838  /* normalize iterate */
839  norm = 0.0;
840  for (i = 0; i < sparsity; i++)
841  {
842  norm += eigenvector[indices[i]] * eigenvector[indices[i]];
843  support[indices[i]] = 1;
844  }
845  norm = sqrt(norm);
846 
847  for (i = 0; i < sparsity; i++)
848  eigenvector[indices[i]] /= norm;
849 
850  /* compute iterate^T * fullmatrix * iterate */
851  SCIP_CALL( SCIPlapackMatrixVectorMult(blocksize, blocksize, fullmatrix, eigenvector, oldev) );
852 
853  for (i = 0; i < blocksize; i++)
854  neweig += eigenvector[i] * oldev[i];
855  }
856 
857  SCIPfreeBufferArray(scip, &oldev);
858  SCIPfreeBufferArray(scip, &sortedev);
859  SCIPfreeBufferArray(scip, &indices);
860 
861  *eigenvalue = neweig;
862 
863  return SCIP_OKAY;
864 }
865 
872 static
873 SCIP_RETCODE sparsifyCut(
874  SCIP* scip,
875  SCIP_CONSHDLR* conshdlr,
876  SCIP_CONS* cons,
877  SCIP_CONSDATA* consdata,
878  SCIP_SOL* sol,
879  int blocksize,
880  SCIP_Real* fullconstmatrix,
881  SCIP_Real* eigenvector,
882  SCIP_Real* vector,
883  SCIP_VAR** vars,
884  SCIP_Real* vals,
885  SCIP_Bool* success,
886  SCIP_RESULT* result
887  )
888 {
889  char cutname[SCIP_MAXSTRLEN];
890  SCIP_CONSHDLRDATA* conshdlrdata;
891  SCIP_Real* ev;
892  SCIP_Real norm = 0.0;
893  SCIP_Real lhs = 0.0;
894  SCIP_Real coef;
895  int cnt = 0;
896  int size;
897  int* idx;
898  int j;
899 
900  assert( scip != NULL );
901  assert( conshdlr != NULL );
902  assert( fullconstmatrix != NULL );
903  assert( eigenvector != NULL );
904  assert( vector != NULL );
905  assert( success != NULL );
906  assert( result != NULL );
907  assert( *result != SCIP_CUTOFF );
908 
909  *success = FALSE;
910 
911  conshdlrdata = SCIPconshdlrGetData(conshdlr);
912  assert( conshdlrdata != NULL );
913 
914  /* produce random indices */
915  SCIP_CALL( SCIPallocBufferArray(scip, &idx, blocksize) );
916  for (j = 0; j < blocksize; ++j)
917  idx[j] = j;
918 
919  /* the following should only be allocated once */
920  assert( conshdlrdata->randnumgen != NULL );
921  SCIPrandomPermuteIntArray(conshdlrdata->randnumgen, idx, 0, blocksize);
922 
923  /* compute target size, use sparsifytargetsize if specified, and sparsifyfactor else */
924  if ( conshdlrdata->sdpconshdlrdata->sparsifytargetsize > 0 )
925  size = conshdlrdata->sdpconshdlrdata->sparsifytargetsize;
926  else
927  size = MAX(10, (int) conshdlrdata->sdpconshdlrdata->sparsifyfactor * consdata->nvars);
928 
929  /* if size is larger than blocksize, trigger a debug message and set size to blocksize */
930  if ( size > blocksize )
931  {
932  SCIPdebugMsg(scip, "Eigenvector cut is not sparsified since desired sparsity %d is larger than SDP blocksize %d.\n", size, blocksize);
933  size = blocksize;
934  }
935 
936  assert( size <= blocksize );
937 
938  /* take random subset of eigenvector - the remaining entries are 0 */
939  SCIP_CALL( SCIPallocClearBufferArray(scip, &ev, blocksize) );
940  for (j = 0; j < size; ++j)
941  {
942  ev[idx[j]] = eigenvector[j];
943  norm += eigenvector[j] * eigenvector[j];
944  }
945 
946  /* if we by chance selected a zero subvector */
947  if ( SCIPisFeasZero(scip, norm) )
948  {
949  SCIPfreeBufferArray(scip, &ev);
950  SCIPfreeBufferArray(scip, &idx);
951  return SCIP_OKAY;
952  }
953 
954  /* normalize */
955  norm = sqrt(norm);
956  for (j = 0; j < size; ++j)
957  ev[idx[j]] /= norm;
958 
959  /* multiply eigenvector with constant matrix to get lhs (after multiplying again with eigenvector from the left) */
960  SCIP_CALL( SCIPlapackMatrixVectorMult(blocksize, blocksize, fullconstmatrix, ev, vector) );
961 
962  for (j = 0; j < blocksize; ++j)
963  lhs += ev[j] * vector[j];
964 
965  /* compute \f$ v^T A_j v \f$ for eigenvector v and each matrix \f$ A_j \f$ to get the coefficients of the LP cut */
966  for (j = 0; j < consdata->nvars; ++j)
967  {
968  SCIP_CALL( multiplyConstraintMatrix(cons, j, ev, &coef) );
969 
970  if ( SCIPisFeasZero(scip, coef) )
971  continue;
972 
973  vars[cnt] = consdata->vars[j];
974  vals[cnt++] = coef;
975  }
976 
977  (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "sepa_eig_sdp_%d", ++(conshdlrdata->neigveccuts));
978  if ( conshdlrdata->sdpconshdlrdata->generaterows )
979  {
980  SCIP_Bool infeasible;
981  SCIP_ROW* row;
982 
983  SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &row, conshdlr, cutname, lhs, SCIPinfinity(scip), FALSE, FALSE, TRUE) );
984  SCIP_CALL( SCIPaddVarsToRow(scip, row, cnt, vars, vals) );
985 
986  /* since the sparsified cut need not separate the current solution, we take only efficacious cuts */
987  if ( SCIPisCutEfficacious(scip, sol, row) )
988  {
989 #ifdef SCIP_MORE_DEBUG
990  SCIP_CALL( SCIPprintRow(scip, row, NULL) );
991 #endif
992  SCIP_CALL( SCIPaddRow(scip, row, FALSE, &infeasible) );
993  SCIP_CALL( SCIPresetConsAge(scip, cons) );
994 
995  if ( conshdlrdata->sdpconshdlrdata->cutstopool )
996  {
997  SCIP_CALL( SCIPaddPoolCut(scip, row) );
998  }
999 
1000  assert( *result != SCIP_CONSADDED );
1001  if ( infeasible )
1002  *result = SCIP_CUTOFF;
1003  else
1004  *result = SCIP_SEPARATED;
1005  *success = TRUE;
1006  }
1007  SCIP_CALL( SCIPreleaseRow(scip, &row) );
1008  }
1009  else
1010  {
1011  SCIP_CONS* newcons;
1012 
1013  SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, cutname, cnt, vars, vals, lhs, SCIPinfinity(scip),
1014  TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE) );
1015  SCIP_CALL( SCIPaddCons(scip, newcons) );
1016  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
1017 
1018  assert( *result != SCIP_SEPARATED );
1019  *result = SCIP_CONSADDED;
1020  *success = TRUE;
1021  }
1022 
1023  SCIPfreeBufferArray(scip, &ev);
1024  SCIPfreeBufferArray(scip, &idx);
1025 
1026  return SCIP_OKAY;
1027 }
1028 
1034 static
1035 SCIP_RETCODE addMultipleSparseCuts(
1036  SCIP* scip,
1037  SCIP_CONSHDLR* conshdlr,
1038  SCIP_CONS* cons,
1039  SCIP_CONSDATA* consdata,
1040  SCIP_SOL* sol,
1041  int blocksize,
1042  SCIP_Real* fullmatrix,
1043  SCIP_Real* fullconstmatrix,
1044  SCIP_Real* eigenvector,
1045  SCIP_Real tol,
1046  int maxncuts,
1047  SCIP_Real* vector,
1048  SCIP_VAR** vars,
1049  SCIP_Real* vals,
1050  int* ncuts,
1051  SCIP_Bool* success,
1052  SCIP_RESULT* result
1053  )
1054 {
1055  char cutname[SCIP_MAXSTRLEN];
1056  SCIP_CONSHDLRDATA* conshdlrdata;
1057  SCIP_Real* fullmatrixcopy;
1058  SCIP_Real* modmatrix;
1059  SCIP_Real* submatrix;
1060  SCIP_Real* sparseev;
1061  SCIP_Real* liftedev;
1062  SCIP_Real* minev;
1063  SCIP_Real convergencetol;
1064  SCIP_Real eigenvalue;
1065  SCIP_Real maxeig;
1066  SCIP_Real scalar;
1067  SCIP_Real lhs = 0.0;
1068  SCIP_Real coef;
1069  int* support;
1070  int cnt = 0;
1071  int size;
1072  int i;
1073  int j;
1074 
1075  assert( scip != NULL );
1076  assert( conshdlr != NULL );
1077  assert( fullmatrix != NULL );
1078  assert( fullconstmatrix != NULL );
1079  assert( eigenvector != NULL );
1080  assert( maxncuts > 0 );
1081  assert( vector != NULL );
1082  assert( ncuts != NULL );
1083  assert( result != NULL );
1084  assert( *result != SCIP_CUTOFF );
1085 
1086  *ncuts = 0;
1087  *success = FALSE;
1088 
1089  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1090  assert( conshdlrdata != NULL );
1091 
1092  SCIPdebugMsg(scip, "Executing addMultipleSparseCuts.\n");
1093 
1094  /* compute target size, use sparsifytargetsize if specified, and sparsifyfactor else */
1095  if ( conshdlrdata->sdpconshdlrdata->sparsifytargetsize > 0 )
1096  size = conshdlrdata->sdpconshdlrdata->sparsifytargetsize;
1097  else
1098  size = MAX(10, (int) conshdlrdata->sdpconshdlrdata->sparsifyfactor * consdata->nvars);
1099 
1100  /* if size is larger than blocksize, trigger a debug message and set size to blocksize */
1101  if ( size > blocksize )
1102  {
1103  SCIPdebugMsg(scip, "No sparse eigenvector cuts produced since desired sparsity %d is larger than SDP blocksize %d.\n", size, blocksize);
1104  return SCIP_OKAY;
1105  }
1106 
1107  assert( size <= blocksize );
1108 
1109  /* copy fullmatrix, since Lapack destroys it when computing eigenvalues! */
1110  SCIP_CALL( SCIPallocBufferArray(scip, &fullmatrixcopy, blocksize * blocksize) );
1111  for (i = 0; i < blocksize * blocksize; i++)
1112  fullmatrixcopy[i] = fullmatrix[i];
1113 
1114  /* compute the largest eigenvalue of A(y), the eigenvector is not needed */
1115  SCIP_CALL( SCIPlapackComputeIthEigenvalue(SCIPbuffer(scip), FALSE, blocksize, fullmatrixcopy, blocksize, &maxeig, NULL) );
1116  SCIPdebugMsg(scip, "Largest eigenvalue of A(y): %.15g\n", maxeig);
1117 
1118  /* compute the modified matrix \lambda_{max} I - A(y), where \lambda_{max} is the largest eigenvalue of A(y) */
1119  SCIP_CALL( SCIPallocBufferArray(scip, &modmatrix, blocksize * blocksize) );
1120  for (i = 0; i < blocksize; i++)
1121  {
1122  for (j = 0; j < blocksize; j++)
1123  {
1124  if ( i == j )
1125  modmatrix[i * blocksize + j] = maxeig - fullmatrix[i * blocksize + j];
1126  else
1127  modmatrix[i * blocksize + j] = -fullmatrix[i * blocksize + j];
1128  }
1129  }
1130 
1131  /* allocate necessary memory */
1132  SCIP_CALL( SCIPallocBufferArray(scip, &submatrix, size * size) );
1133  SCIP_CALL( SCIPallocBufferArray(scip, &liftedev, blocksize) );
1134  SCIP_CALL( SCIPallocBufferArray(scip, &support, blocksize) );
1135  SCIP_CALL( SCIPallocBufferArray(scip, &sparseev, size) );
1136  SCIP_CALL( SCIPallocBufferArray(scip, &minev, blocksize) );
1137 
1138  /* compute sparse eigenvector with the truncated power method for the modified matrix */
1139  convergencetol = 1e-6;
1140  SCIP_CALL( truncatedPowerMethod(scip, blocksize, modmatrix, eigenvector, size, convergencetol, liftedev, support, &eigenvalue) );
1141 
1142  SCIPdebugMsg(scip, "Smallest sparse eigenvalue computed by TPower: %.15g\n", maxeig - eigenvalue);
1143 
1144  /* instead of adding the sparse eigenvector, use it as initial point for adding many sparse eigenvectors */
1145  /* compute v^T A(y) v, which is equal to maxeig - eigenvalue */
1146  scalar = maxeig - eigenvalue;
1147 
1148  if ( ! SCIPisFeasNegative(scip, scalar) )
1149  {
1150  SCIPdebugMsg(scip, "Did not add any sparse eigenvector cuts, since sparsified initial eigenvector cut does not cut off the solution!\n");
1151  }
1152 
1153  if ( maxncuts < 0 )
1154  maxncuts = INT_MAX;
1155 
1156  while ( SCIPisFeasNegative(scip, scalar) && *ncuts < maxncuts )
1157  {
1158  if ( conshdlrdata->sdpconshdlrdata->recomputesparseev )
1159  {
1160  SCIP_Real norm;
1161 
1162  /* Recompute smallest eigenvalue \lambda_{min} and corresponding unit norm eigenvector w of principal submatrix
1163  * A(y)_S, lift it to a full vector by adding zeros, and normalize, instead of using the eigenvector and
1164  * eigenvalue returned from TPower.
1165  */
1166 
1167  cnt = 0;
1168  for (i = 0; i < blocksize; i++)
1169  {
1170  if ( support[i] == 1 )
1171  {
1172  for (j = 0; j < blocksize; j++)
1173  {
1174  if ( support[j] == 1 )
1175  submatrix[cnt++] = fullmatrix[i * blocksize + j];
1176  }
1177  }
1178  }
1179  assert( cnt == size * size );
1180 
1181  SCIP_CALL( SCIPlapackComputeIthEigenvalue(SCIPbuffer(scip), TRUE, size, submatrix, 1, &eigenvalue, sparseev) );
1182 
1183  assert( SCIPisFeasNegative(scip, eigenvalue) );
1184 
1185  if ( eigenvalue >= -tol )
1186  break;
1187 
1188  SCIPdebugMsg(scip, "Smallest eigenvalue of principal submatrix: %.15g\n", eigenvalue);
1189 
1190  /* normalize sparse eigenvector */
1191  norm = 0.0;
1192  for (j = 0; j < size; j++)
1193  norm += sparseev[j] * sparseev[j];
1194 
1195  norm = sqrt(norm);
1196  for (j = 0; j < size; j++)
1197  sparseev[j] /= norm;
1198 
1199  /* lift eigenvector by setting all entries not in the support to 0 */
1200  cnt = 0;
1201  for (i = 0; i < blocksize; i++)
1202  {
1203  if ( support[i] == 1 )
1204  {
1205  /* assert( SCIPisFeasEQ(scip, liftedev[i], sparseev[cnt]) ); */
1206  liftedev[i] = sparseev[cnt++];
1207  }
1208  else
1209  liftedev[i] = 0.0;
1210  }
1211  assert( cnt == size );
1212  }
1213  else
1214  {
1215  /* scalar is the smallest sparse eigenvalue computed with TPower */
1216  eigenvalue = scalar;
1217  }
1218 
1219  /* check if cut obtained from new eigenvector is efficacious and add cut/constraint */
1220  /* multiply eigenvector with constant matrix to get lhs (after multiplying again with eigenvector from the left) */
1221  SCIP_CALL( SCIPlapackMatrixVectorMult(blocksize, blocksize, fullconstmatrix, liftedev, vector) );
1222 
1223  lhs = 0.0;
1224  for (j = 0; j < blocksize; ++j)
1225  lhs += liftedev[j] * vector[j];
1226 
1227  /* compute \f$ v^T A_j v \f$ for eigenvector v and each matrix \f$ A_j \f$ to get the coefficients of the LP cut */
1228  cnt = 0;
1229  for (j = 0; j < consdata->nvars; ++j)
1230  {
1231  SCIP_CALL( multiplyConstraintMatrix(cons, j, liftedev, &coef) );
1232 
1233  if ( SCIPisFeasZero(scip, coef) )
1234  continue;
1235 
1236  vars[cnt] = consdata->vars[j];
1237  vals[cnt++] = coef;
1238  }
1239 
1240  (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "sepa_eig_sdp_%d", ++(conshdlrdata->neigveccuts));
1241  if ( conshdlrdata->sdpconshdlrdata->generaterows )
1242  {
1243  SCIP_Bool infeasible;
1244  SCIP_ROW* row;
1245 
1246 #if ( SCIP_VERSION >= 700 || (SCIP_VERSION >= 602 && SCIP_SUBVERSION > 0) )
1247  SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &row, conshdlr, cutname, lhs, SCIPinfinity(scip), FALSE, FALSE, TRUE) );
1248 #else
1249  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, conshdlr, cutname, lhs, SCIPinfinity(scip), FALSE, FALSE, TRUE) );
1250 #endif
1251 
1252  SCIP_CALL( SCIPaddVarsToRow(scip, row, cnt, vars, vals) );
1253 
1254  /* since the sparsified cut need not separate the current solution, we take only efficacious cuts */
1255  if ( SCIPisCutEfficacious(scip, sol, row) )
1256  {
1257 #ifdef SCIP_MORE_DEBUG
1258  SCIP_CALL( SCIPprintRow(scip, row, NULL) );
1259 #endif
1260  SCIP_CALL( SCIPaddRow(scip, row, FALSE, &infeasible) );
1261  SCIP_CALL( SCIPresetConsAge(scip, cons) );
1262 
1263  if ( conshdlrdata->sdpconshdlrdata->cutstopool )
1264  {
1265  SCIP_CALL( SCIPaddPoolCut(scip, row) );
1266  }
1267 
1268  assert( *result != SCIP_CONSADDED );
1269  if ( infeasible )
1270  {
1271  *result = SCIP_CUTOFF;
1272  SCIPdebugMsg(scip, "Detected infeasibility.\n");
1273  SCIP_CALL( SCIPreleaseRow(scip, &row) );
1274  break;
1275  }
1276  else
1277  {
1278  *result = SCIP_SEPARATED;
1279  ++(*ncuts);
1280  SCIPdebugMsg(scip, "Successfully added sparse eigenvector cut.\n");
1281  }
1282  }
1283  else
1284  SCIPdebugMsg(scip, "Cut is not efficacious!\n");
1285  SCIP_CALL( SCIPreleaseRow(scip, &row) );
1286  }
1287  else
1288  {
1289  SCIP_CONS* newcons;
1290 
1291  SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, cutname, cnt, vars, vals, lhs, SCIPinfinity(scip),
1292  TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE) );
1293  SCIP_CALL( SCIPaddCons(scip, newcons) );
1294  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
1295 
1296  assert( *result != SCIP_SEPARATED );
1297  *result = SCIP_CONSADDED;
1298  ++(*ncuts);
1299  SCIPdebugMsg(scip, "Successfully added sparse eigenvector cut.\n");
1300  }
1301 
1302  /* compute A(y) = A(y) - \lambda_{min} w w^T */
1303  for (i = 0; i < blocksize; i++)
1304  {
1305  for (j = 0; j < blocksize; j++)
1306  fullmatrix[i * blocksize + j] -= eigenvalue * liftedev[i] * liftedev[j];
1307  }
1308 
1309 
1310  if ( conshdlrdata->sdpconshdlrdata->recomputeinitial )
1311  {
1312  SCIP_Real mineig;
1313  /* compute smallest eigenvalue and corresponding eigenvector of A(y) as initial vector for TPpower, instead of
1314  using the eigenvector to the smallest eigenvalue of the original matrix */
1315 
1316  /* copy fullmatrix, since Lapack destroys it when computing eigenvalues! */
1317  for (i = 0; i < blocksize * blocksize; i++)
1318  fullmatrixcopy[i] = fullmatrix[i];
1319 
1320  SCIP_CALL( SCIPlapackComputeIthEigenvalue(SCIPbuffer(scip), TRUE, blocksize, fullmatrixcopy, 1, &mineig, minev) );
1321 
1322  SCIPdebugMsg(scip, "Smallest eigenvalue: %.15g\n", mineig);
1323  }
1324  else
1325  {
1326  for (i = 0; i < blocksize; i++)
1327  minev[i] = eigenvector[i];
1328  }
1329 
1330  if ( conshdlrdata->sdpconshdlrdata->exacttrans )
1331  {
1332  /* we need to modify the matrix again in order to use the truncated power method */
1333 
1334  /* copy fullmatrix, since Lapack destroys it when computing eigenvalues! */
1335  for (i = 0; i < blocksize * blocksize; i++)
1336  fullmatrixcopy[i] = fullmatrix[i];
1337 
1338  /* compute the largest eigenvalue of A(y), the eigenvector is not needed */
1339  SCIP_CALL( SCIPlapackComputeIthEigenvalue(SCIPbuffer(scip), FALSE, blocksize, fullmatrixcopy, blocksize, &maxeig, NULL) );
1340  SCIPdebugMsg(scip, "Largest eigenvalue: %.15g\n", maxeig);
1341  }
1342  else
1343  {
1344  /* use estimate for largest eigenvalue of modified matrix: \lambda_{max}(A+B) \leq \lambda_{max}(A) + \lambda_{max}(B) */
1345  maxeig -= eigenvalue;
1346  }
1347 
1348  /* compute the modified matrix \lambda_{max} I - A(y), where \lambda_{max} is the largest eigenvalue of A(y) */
1349  for (i = 0; i < blocksize; i++)
1350  {
1351  for (j = 0; j < blocksize; j++)
1352  {
1353  if ( i == j )
1354  modmatrix[i * blocksize + j] = maxeig - fullmatrix[i * blocksize +j];
1355  else
1356  modmatrix[i * blocksize + j] = -fullmatrix[i * blocksize +j];
1357  }
1358  }
1359 
1360  /* compute smallest sparse eigenvalue and corresponding eigenvector of A(y) with the truncated power method */
1361  SCIP_CALL( truncatedPowerMethod(scip, blocksize, modmatrix, minev, size, convergencetol, liftedev, support, &eigenvalue) );
1362 
1363  SCIPdebugMsg(scip, "Smallest sparse eigenvalue computed by TPower: %.15g\n", maxeig - eigenvalue);
1364 
1365  /* compute v^T A(y) v for the new sparse eigenvector, which is equal to maxeig - eigenvalue, as computed by TPower */
1366  scalar = maxeig - eigenvalue;
1367  }
1368 
1369  if ( *ncuts > 0 || *result == SCIP_CUTOFF )
1370  {
1371  *success = TRUE;
1372  SCIPdebugMsg(scip, "Added %d sparse eigenvector cuts\n", *ncuts);
1373  }
1374 
1375  /* free all memory */
1376  SCIPfreeBufferArray(scip, &minev);
1377  SCIPfreeBufferArray(scip, &sparseev);
1378  SCIPfreeBufferArray(scip, &support);
1379  SCIPfreeBufferArray(scip, &liftedev);
1380  SCIPfreeBufferArray(scip, &submatrix);
1381  SCIPfreeBufferArray(scip, &modmatrix);
1382  SCIPfreeBufferArray(scip, &fullmatrixcopy);
1383 
1384  return SCIP_OKAY;
1385 }
1386 
1387 
1389 static
1390 SCIP_RETCODE separateSol(
1391  SCIP* scip,
1392  SCIP_CONSHDLR* conshdlr,
1393  SCIP_CONS* cons,
1394  SCIP_SOL* sol,
1395  SCIP_Bool enforce,
1396  SCIP_RESULT* result
1397  )
1398 {
1399  char cutname[SCIP_MAXSTRLEN];
1400  SCIP_CONSDATA* consdata;
1401  SCIP_CONSHDLRDATA* conshdlrdata;
1402  SCIP_RETCODE retcode;
1403  SCIP_VAR** vars;
1404  SCIP_Real* vals;
1405  SCIP_Real* eigenvectors;
1406  SCIP_Real* vector;
1407  SCIP_Real* fullmatrix;
1408  SCIP_Real* fullmatrixcopy;
1409  SCIP_Real* fullconstmatrix = NULL;
1410  SCIP_Real* eigenvalues;
1411  SCIP_Real tol;
1412  int neigenvalues;
1413  int blocksize;
1414  int nvars;
1415  int ngen = 0;
1416  int i;
1417  int j;
1418 
1419  assert( cons != NULL );
1420  assert( result != NULL );
1421 
1422  consdata = SCIPconsGetData(cons);
1423  assert( consdata != NULL );
1424 
1425  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1426  assert( conshdlrdata != NULL );
1427 
1428  /* prepare computations */
1429  nvars = consdata->nvars;
1430  blocksize = consdata->blocksize;
1431 
1432  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars ) );
1433  SCIP_CALL( SCIPallocBufferArray(scip, &vals, nvars ) );
1434 
1435  SCIP_CALL( SCIPallocBufferArray(scip, &fullmatrix, blocksize * blocksize ) );
1436  SCIP_CALL( SCIPallocBufferArray(scip, &fullmatrixcopy, blocksize * blocksize ) );
1437  SCIP_CALL( SCIPallocBufferArray(scip, &eigenvectors, blocksize * blocksize) );
1438  SCIP_CALL( SCIPallocBufferArray(scip, &eigenvalues, blocksize) );
1439  SCIP_CALL( SCIPallocBufferArray(scip, &vector, blocksize) );
1440 
1441  /* compute the matrix \f$ \sum_j A_j y_j - A_0 \f$ */
1442  SCIP_CALL( computeFullSdpMatrix(scip, consdata, sol, fullmatrix) );
1443 
1444  /* copy fullmatrix, since Lapack destroys it when computing eigenvalues! */
1445  for (i = 0; i < blocksize * blocksize; i++)
1446  fullmatrixcopy[i] = fullmatrix[i];
1447 
1448  /* determine tolerance */
1449  if ( conshdlrdata->sdpconshdlrdata->usedimacsfeastol )
1450  {
1451  assert( conshdlrdata->dimacsfeastol != SCIP_INVALID );
1452  tol = conshdlrdata->dimacsfeastol;
1453  }
1454  else
1455  {
1456  if ( enforce )
1457  tol = SCIPfeastol(scip);
1458  else
1459  tol = SCIPgetSepaMinEfficacy(scip);
1460  }
1461 
1462  /* compute eigenvector(s) */
1463  if ( conshdlrdata->sdpconshdlrdata->separateonecut || conshdlrdata->sdpconshdlrdata->multiplesparsecuts )
1464  {
1465  /* compute smallest eigenvalue */
1466  retcode = SCIPlapackComputeIthEigenvalue(SCIPbuffer(scip), TRUE, blocksize, fullmatrixcopy, 1, eigenvalues, eigenvectors);
1467  if ( retcode == SCIP_OKAY )
1468  {
1469  if ( eigenvalues[0] < -tol )
1470  neigenvalues = 1;
1471  else
1472  neigenvalues = 0;
1473  }
1474  }
1475  else
1476  {
1477  /* compute all eigenvectors for negative eigenvalues */
1478  retcode = SCIPlapackComputeEigenvectorsNegative(SCIPbuffer(scip), blocksize, fullmatrixcopy, tol, &neigenvalues, eigenvalues, eigenvectors);
1479  }
1480 
1481  /* treat possible error */
1482  if ( retcode != SCIP_OKAY )
1483  {
1484  SCIPfreeBufferArray(scip, &vector);
1485  SCIPfreeBufferArray(scip, &eigenvalues);
1486  SCIPfreeBufferArray(scip, &eigenvectors);
1487  SCIPfreeBufferArray(scip, &fullmatrixcopy);
1488  SCIPfreeBufferArray(scip, &fullmatrix);
1489 
1490  SCIPfreeBufferArray(scip, &vals);
1491  SCIPfreeBufferArray(scip, &vars);
1492 
1493  /* if we are enforcing, generate error */
1494  if ( enforce )
1495  {
1496  SCIP_CALL( retcode );
1497  }
1498  else
1499  return SCIP_OKAY; /* in separation just exit */
1500  }
1501 
1502  if ( neigenvalues > 0 )
1503  {
1504  /* there are no variables, but the matrix is negative definite -> cutoff */
1505  if ( consdata->nvars == 0 )
1506  *result = SCIP_CUTOFF;
1507  else
1508  {
1509  /* get full constant matrix */
1510  SCIP_CALL( SCIPallocBufferArray(scip, &fullconstmatrix, blocksize * blocksize) );
1511  SCIP_CALL( SCIPconsSdpGetFullConstMatrix(scip, cons, fullconstmatrix) );
1512  }
1513  }
1514 
1515  /* loop through eigenvectors and add cuts as long as cut is violated */
1516  for (i = 0; i < neigenvalues && *result != SCIP_CUTOFF; ++i)
1517  {
1518  SCIP_Real* eigenvector;
1519  SCIP_Real lhs = 0.0;
1520  SCIP_Bool success;
1521  int cnt = 0;
1522  int ncuts;
1523 
1524  /* get pointer to current eigenvector */
1525  eigenvector = &(eigenvectors[i * blocksize]);
1526 
1527  /* if we want to sparsify the cut */
1528  if ( ! enforce && conshdlrdata->sdpconshdlrdata->sparsifycut )
1529  {
1530  SCIP_CALL( sparsifyCut(scip, conshdlr, cons, consdata, sol, blocksize, fullconstmatrix, eigenvector, vector, vars, vals, &success, result) );
1531 
1532  if ( success )
1533  {
1534  ++ngen;
1535  continue;
1536  }
1537  }
1538  else if ( conshdlrdata->sdpconshdlrdata->multiplesparsecuts )
1539  {
1540  SCIPdebugMsg(scip, "Smallest eigenvalue: %.15g\n", eigenvalues[i]);
1541  SCIP_CALL( addMultipleSparseCuts(scip, conshdlr, cons, consdata, sol, blocksize, fullmatrix, fullconstmatrix,
1542  eigenvector, tol, conshdlrdata->sdpconshdlrdata->maxnsparsecuts, vector, vars, vals, &ncuts, &success, result) );
1543 
1544  if ( success )
1545  {
1546  SCIPdebugMsg(scip, "Successfully added %d sparse eigenvector cuts.\n", ncuts);
1547  ngen += ncuts;
1548  continue;
1549  }
1550  }
1551  else
1552  {
1553  /* to avoid numerical trouble, we eliminate small entries in absolute value */
1554  for (j = 0; j < consdata->blocksize; ++j)
1555  {
1556  if ( SCIPisFeasZero(scip, eigenvector[j]) )
1557  eigenvector[j] = 0.0;
1558  }
1559  }
1560 
1561  /* multiply eigenvector with constant matrix to get lhs (after multiplying again with eigenvector from the left) */
1562  SCIP_CALL( SCIPlapackMatrixVectorMult(blocksize, blocksize, fullconstmatrix, eigenvector, vector) );
1563 
1564  for (j = 0; j < blocksize; ++j)
1565  lhs += eigenvector[j] * vector[j];
1566 
1567  /* compute \f$ v^T A_j v \f$ for eigenvector v and each matrix \f$ A_j \f$ to get the coefficients of the LP cut */
1568  for (j = 0; j < consdata->nvars; ++j)
1569  {
1570  SCIP_Real coef;
1571 
1572  SCIP_CALL( multiplyConstraintMatrix(cons, j, eigenvector, &coef) );
1573 
1574  if ( ! SCIPisFeasZero(scip, coef) )
1575  {
1576  vars[cnt] = consdata->vars[j];
1577  vals[cnt++] = coef;
1578  }
1579  }
1580 
1581  (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "sepa_eig_sdp_%d", ++(conshdlrdata->neigveccuts));
1582  if ( conshdlrdata->sdpconshdlrdata->generaterows )
1583  {
1584  SCIP_Bool infeasible;
1585  SCIP_ROW* row;
1586 
1587  SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &row, conshdlr, cutname, lhs, SCIPinfinity(scip), FALSE, FALSE, TRUE) );
1588  SCIP_CALL( SCIPaddVarsToRow(scip, row, cnt, vars, vals) );
1589 
1590  /* if we are enforcing, we take any of the cuts, otherwise only efficacious cuts */
1591  if ( enforce || SCIPisCutEfficacious(scip, sol, row) )
1592  {
1593 #ifdef SCIP_MORE_DEBUG
1594  SCIP_CALL( SCIPprintRow(scip, row, NULL) );
1595 #endif
1596  SCIP_CALL( SCIPaddRow(scip, row, FALSE, &infeasible) );
1597  if ( infeasible )
1598  *result = SCIP_CUTOFF;
1599  else
1600  *result = SCIP_SEPARATED;
1601  SCIP_CALL( SCIPresetConsAge(scip, cons) );
1602 
1603  if ( conshdlrdata->sdpconshdlrdata->cutstopool )
1604  {
1605  SCIP_CALL( SCIPaddPoolCut(scip, row) );
1606  }
1607  ++ngen;
1608  }
1609 
1610  SCIP_CALL( SCIPreleaseRow(scip, &row) );
1611  }
1612  else
1613  {
1614  SCIP_CONS* newcons;
1615 
1616  SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, cutname, cnt, vars, vals, lhs, SCIPinfinity(scip),
1617  TRUE, TRUE, enforce, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE) );
1618  SCIP_CALL( SCIPaddCons(scip, newcons) );
1619  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
1620  *result = SCIP_CONSADDED;
1621  ++ngen;
1622  }
1623  }
1624  SCIPdebugMsg(scip, "<%s>: Separated cuts = %d.\n", SCIPconsGetName(cons), ngen);
1625 
1626  SCIPfreeBufferArrayNull(scip, &fullconstmatrix);
1627  SCIPfreeBufferArray(scip, &vector);
1628  SCIPfreeBufferArray(scip, &eigenvalues);
1629  SCIPfreeBufferArray(scip, &eigenvectors);
1630  SCIPfreeBufferArray(scip, &fullmatrixcopy);
1631  SCIPfreeBufferArray(scip, &fullmatrix);
1632 
1633  SCIPfreeBufferArray(scip, &vals);
1634  SCIPfreeBufferArray(scip, &vars);
1635 
1636  return SCIP_OKAY;
1637 }
1638 
1643 static
1644 SCIP_RETCODE computeAllmatricespsd(
1645  SCIP* scip,
1646  SCIP_CONS* cons
1647  )
1648 {
1649  SCIP_CONSDATA* consdata;
1650  SCIP_Real* Aj;
1651  int blocksize;
1652  int v;
1653 
1654  assert( scip != NULL );
1655  assert( cons != NULL );
1656  consdata = SCIPconsGetData(cons);
1657  assert( consdata != NULL );
1658  assert( consdata->rankone );
1659 
1660  /* exit if allmatricespsd has been initialized already */
1661  if ( consdata->initallmatricespsd )
1662  return SCIP_OKAY;
1663 
1664  assert( consdata->allmatricespsd == FALSE );
1665 
1666  blocksize = consdata->blocksize;
1667  SCIP_CALL( SCIPallocBufferArray(scip, &Aj, blocksize * blocksize) );
1668 
1669  SCIPdebugMsg(scip, "Computing allmatricespsd for constraint <%s>.\n", SCIPconsGetName(cons));
1670 
1671  consdata->allmatricespsd = TRUE;
1672  for (v = 0; v < consdata->nvars && consdata->allmatricespsd; ++v)
1673  {
1674  SCIP_Real eigenvalue;
1675 
1676  SCIP_CALL( SCIPconsSdpGetFullAj(scip, cons, v, Aj) );
1677 
1678  /* compute minimal eigenvalue */
1679  SCIP_CALL( SCIPlapackComputeIthEigenvalue(SCIPbuffer(scip), FALSE, blocksize, Aj, 1, &eigenvalue, NULL) );
1680  if ( SCIPisNegative(scip, eigenvalue) )
1681  consdata->allmatricespsd = FALSE;
1682  }
1683 
1684  SCIPfreeBufferArray(scip, &Aj);
1685 
1686  consdata->initallmatricespsd = TRUE;
1687 
1688  return SCIP_OKAY;
1689 }
1690 
1692 static
1693 SCIP_RETCODE tightenMatrices(
1694  SCIP* scip,
1695  SCIP_CONS** conss,
1696  int nconss,
1697  int* nchgcoefs
1698  )
1699 {
1700  int c;
1701 
1702  assert( scip != NULL );
1703  assert( nchgcoefs != NULL );
1704 
1705  for (c = 0; c < nconss; ++c)
1706  {
1707  SCIP_CONSDATA* consdata;
1708  SCIP_Real* constmatrix;
1709  int blocksize;
1710  int nvars;
1711  int i;
1712 
1713  assert( conss != NULL );
1714  assert( conss[c] != NULL );
1715 
1716  consdata = SCIPconsGetData(conss[c]);
1717  assert( consdata != NULL );
1718  assert( consdata->rankone || strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(conss[c])), CONSHDLR_NAME) == 0 );
1719  assert( ! consdata->rankone || strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(conss[c])), CONSHDLRRANK1_NAME) == 0 );
1720 
1721  /* compute allmatricespsd for rank-1 constraints */
1722  if ( consdata->rankone )
1723  {
1724  SCIP_CALL( computeAllmatricespsd(scip, conss[c]) );
1725  }
1726 
1727  /* skip constraints in which not all matrices are psd */
1728  if ( ! consdata->allmatricespsd )
1729  continue;
1730 
1731  /* make sure that all lower bounds are nonnegative */
1732  nvars = consdata->nvars;
1733  for (i = 0; i < nvars; ++i)
1734  {
1735  if ( SCIPisNegative(scip, SCIPvarGetLbGlobal(consdata->vars[i])) )
1736  break;
1737  }
1738  if ( i < nvars )
1739  continue;
1740 
1741  SCIPdebugMsg(scip, "Trying to tighten matrices for constraint <%s>.\n", SCIPconsGetName(conss[c]));
1742 
1743  /* get matrices */
1744  blocksize = consdata->blocksize;
1745  SCIP_CALL( SCIPallocBufferArray(scip, &constmatrix, blocksize * blocksize) );
1746 
1747  SCIP_CALL( SCIPconsSdpGetFullConstMatrix(scip, conss[c], constmatrix) );
1748 
1749  for (i = 0; i < nvars; ++i)
1750  {
1751  SCIP_Real objval;
1752  SCIP_Real factor;
1753  SCIP_Real lb;
1754  SCIP_Real ub;
1755 
1756  /* only treat binary variables */
1757  if ( ! SCIPvarIsBinary(consdata->vars[i]) )
1758  continue;
1759 
1760  /* skip fixed variables (will be removed anyway */
1761  lb = SCIPvarGetLbLocal(consdata->vars[i]);
1762  ub = SCIPvarGetLbLocal(consdata->vars[i]);
1763  if ( SCIPisEQ(scip, lb, ub) )
1764  continue;
1765 
1766  assert( SCIPisEQ(scip, lb, 0.0) );
1767  assert( SCIPisEQ(scip, ub, 1.0) );
1768 
1769  /* solve 1d SDP */
1770  SCIP_CALL( SCIPsolveOneVarSDPDense(SCIPbuffer(scip), 1.0, 0.0, 1.0, blocksize, constmatrix, consdata->nvarnonz[i], consdata->row[i], consdata->col[i], consdata->val[i],
1771  SCIPinfinity(scip), SCIPfeastol(scip), &objval, &factor) );
1772 
1773  if ( SCIPisInfinity(scip, objval) )
1774  continue;
1775 
1776  if ( factor == SCIP_INVALID ) /*lint !e777*/
1777  continue;
1778 
1779  if ( ! SCIPisFeasEQ(scip, factor, 1.0) )
1780  {
1781  int j;
1782 
1783  SCIPdebugMsg(scip, "Tightened coefficent matrix of variable <%s> with tightening factor %g.\n", SCIPvarGetName(consdata->vars[i]), factor);
1784 
1785  /* tighten matrix */
1786  for (j = 0; j < consdata->nvarnonz[i]; j++)
1787  consdata->val[i][j] *= factor;
1788 
1789  ++(*nchgcoefs);
1790  }
1791  }
1792 
1793  SCIPfreeBufferArray(scip, &constmatrix);
1794  }
1795 
1796  return SCIP_OKAY;
1797 }
1798 
1800 static
1801 SCIP_RETCODE tightenBounds(
1802  SCIP* scip,
1803  SCIP_CONS** conss,
1804  int nconss,
1805  SCIP_Bool tightenboundscont,
1806  int* nchgbds,
1807  SCIP_Bool* infeasible
1808  )
1809 {
1810  int c;
1811 
1812  assert( scip != NULL );
1813  assert( nchgbds != NULL );
1814  assert( infeasible != NULL );
1815 
1816  *infeasible = FALSE;
1817 
1818  for (c = 0; c < nconss && !(*infeasible); ++c)
1819  {
1820  SCIP_CONSDATA* consdata;
1821  SCIP_Real* matrix = NULL;
1822  SCIP_Real* constmatrix;
1823  SCIP_Real factor;
1824  SCIP_Bool havebinaryvar = FALSE;
1825  int blocksize;
1826  int nvars;
1827  int i;
1828 
1829  assert( conss != NULL );
1830  assert( conss[c] != NULL );
1831 
1832  consdata = SCIPconsGetData(conss[c]);
1833  assert( consdata != NULL );
1834  assert( consdata->rankone || strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(conss[c])), CONSHDLR_NAME) == 0 );
1835  assert( ! consdata->rankone || strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(conss[c])), CONSHDLRRANK1_NAME) == 0 );
1836 
1837  /* compute allmatricespsd for rank-1 constraints */
1838  if ( consdata->rankone )
1839  {
1840  SCIP_CALL( computeAllmatricespsd(scip, conss[c]) );
1841  }
1842 
1843  /* skip constraints in which not all matrices are psd */
1844  if ( ! consdata->allmatricespsd )
1845  continue;
1846 
1847  /* make sure that all upper bounds finite */
1848  nvars = consdata->nvars;
1849  for (i = 0; i < nvars; ++i)
1850  {
1851  if ( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->vars[i])) )
1852  break;
1853 
1854  if ( SCIPvarIsBinary(consdata->vars[i]) )
1855  havebinaryvar = TRUE;
1856  }
1857  if ( i < nvars )
1858  continue;
1859 
1860  SCIPdebugMsg(scip, "Trying to tighten bounds for constraint <%s>.\n", SCIPconsGetName(conss[c]));
1861 
1862  /* get matrices */
1863  blocksize = consdata->blocksize;
1864  SCIP_CALL( SCIPallocBufferArray(scip, &constmatrix, blocksize * blocksize) );
1865  if ( havebinaryvar )
1866  {
1867  SCIP_CALL( SCIPallocBufferArray(scip, &matrix, blocksize * blocksize) );
1868  }
1869 
1870  for (i = 0; i < nvars; ++i)
1871  {
1872  SCIP_Real* sdpval;
1873  SCIP_Real lb;
1874  SCIP_Real ub;
1875  SCIP_Real ubk;
1876  SCIP_Real objval;
1877  int* sdprow;
1878  int* sdpcol;
1879  int sdpnnonz;
1880  int row;
1881  int col;
1882  int k;
1883  int l;
1884 
1885  /* possibly restrict tightening to continuous variables */
1886  if ( tightenboundscont && SCIPvarIsIntegral(consdata->vars[i]) )
1887  continue;
1888 
1889  /* skip fixed variables */
1890  lb = SCIPvarGetLbLocal(consdata->vars[i]);
1891  ub = SCIPvarGetUbLocal(consdata->vars[i]);
1892  if ( SCIPisEQ(scip, lb, ub) )
1893  continue;
1894 
1895  /* skip infinite lower bound (cannot currently deal with this in SCIPsolveOneVarSDPDense()) */
1896  assert( ! SCIPisInfinity(scip, ub) );
1897  if ( SCIPisInfinity(scip, -lb) )
1898  continue;
1899 
1900  /* get fresh copy of the constant matrix */
1901  SCIP_CALL( SCIPconsSdpGetFullConstMatrix(scip, conss[c], constmatrix) );
1902 
1903  /* loop over other variables */
1904  for (k = 0; k < nvars; ++k)
1905  {
1906  if ( k == i )
1907  continue;
1908 
1909  ubk = SCIPvarGetUbLocal(consdata->vars[k]);
1910 
1911  /* subtract matrix times upper bound from constant matrix (because of minus const. matrix) */
1912  if ( ! SCIPisZero(scip, ubk) )
1913  {
1914  sdprow = consdata->row[k];
1915  sdpcol = consdata->col[k];
1916  sdpval = consdata->val[k];
1917  sdpnnonz = consdata->nvarnonz[k];
1918  for (l = 0; l < sdpnnonz; ++l)
1919  {
1920  row = sdprow[l];
1921  col = sdpcol[l];
1922  constmatrix[row * blocksize + col] -= sdpval[l] * ubk;
1923  if ( row != col )
1924  constmatrix[col * blocksize + row] -= sdpval[l] * ubk;
1925  }
1926  }
1927  }
1928 
1929  /* special handling of binary variables */
1930  if ( SCIPvarIsBinary(consdata->vars[i]) )
1931  {
1932  SCIP_Real eigenvalue;
1933 
1934  assert( matrix != NULL );
1935 
1936  /* first copy constant matrix (possibly needed later) */
1937  for (l = 0; l < blocksize * blocksize; ++l)
1938  matrix[l] = - constmatrix[l];
1939 
1940  /* compute maximal eigenvalue; this corresponds to checking the lower bound because of minus sign; constmatrix is destroyed. */
1941  SCIP_CALL( SCIPlapackComputeIthEigenvalue(SCIPbuffer(scip), FALSE, blocksize, constmatrix, blocksize, &eigenvalue, NULL) );
1942 
1943  /* take minus sign into account */
1944  eigenvalue = -eigenvalue;
1945 
1946  /* if the negative of the constant matrix is psd, then the lower bound (= 0) is feasible -> cannot tighten */
1947  if ( SCIPisFeasGE(scip, eigenvalue, 0.0) )
1948  continue;
1949  assert( SCIPisFeasNegative(scip, eigenvalue) );
1950 
1951  /* otherwise, we check whether the upper bound is feasible */
1952 
1953  /* add matrix i for evaluating upper bound */
1954  sdprow = consdata->row[i];
1955  sdpcol = consdata->col[i];
1956  sdpval = consdata->val[i];
1957  sdpnnonz = consdata->nvarnonz[i];
1958  for (l = 0; l < sdpnnonz; ++l)
1959  {
1960  row = sdprow[l];
1961  col = sdpcol[l];
1962  matrix[row * blocksize + col] += sdpval[l];
1963  if ( row != col )
1964  matrix[col * blocksize + row] += sdpval[l];
1965  }
1966 
1967  /* compute minimal eigenvalue; matrix is destroyed */
1968  SCIP_CALL( SCIPlapackComputeIthEigenvalue(SCIPbuffer(scip), FALSE, blocksize, matrix, 1, &eigenvalue, NULL) );
1969 
1970  /* if matrix is not psd, we are infeasible */
1971  if ( SCIPisFeasNegative(scip, eigenvalue) )
1972  {
1973  SCIPdebugMsg(scip, "Binary variable <%s> yields infeasibility.\n", SCIPvarGetName(consdata->vars[i]));
1974  *infeasible = TRUE;
1975  break;
1976  }
1977 
1978  /* otherwise, we need at least the matrix for variable i to become feasible -> can tighten variable to 1 */
1979  factor = 0.5;
1980  SCIPdebugMsg(scip, "Tighten lower bound for binary variable <%s> to 1.\n", SCIPvarGetName(consdata->vars[i]));
1981  }
1982  else
1983  {
1984  /* solve 1d SDP */
1985  SCIP_CALL( SCIPsolveOneVarSDPDense(SCIPbuffer(scip), 1.0, lb, ub, blocksize, constmatrix, consdata->nvarnonz[i], consdata->row[i], consdata->col[i], consdata->val[i],
1986  SCIPinfinity(scip), SCIPfeastol(scip), &objval, &factor) );
1987 
1988  /* if problem is infeasible */
1989  if ( SCIPisInfinity(scip, objval) )
1990  {
1991  SCIPdebugMsg(scip, "Variable <%s> yields infeasibility.\n", SCIPvarGetName(consdata->vars[i]));
1992  *infeasible = TRUE;
1993  break;
1994  }
1995 
1996  if ( factor == SCIP_INVALID ) /*lint !e777*/
1997  continue;
1998  }
1999 
2000  if ( SCIPisGT(scip, factor, lb) )
2001  {
2002  SCIP_Bool tightened;
2003 
2004  SCIP_CALL( SCIPinferVarLbCons(scip, consdata->vars[i], factor, conss[c], -(i+1), FALSE, infeasible, &tightened) );
2005 
2006  if ( *infeasible )
2007  break;
2008 
2009  if ( tightened )
2010  {
2011  SCIPdebugMsg(scip, "%sTightened lower bound of variable <%s> from %g to %g.\n", SCIPinProbing(scip) ? "In probing: " : "", SCIPvarGetName(consdata->vars[i]), lb, factor);
2012  ++(*nchgbds);
2013  }
2014  }
2015  }
2016 
2017  SCIPfreeBufferArrayNull(scip, &matrix);
2018  SCIPfreeBufferArray(scip, &constmatrix);
2019  }
2020 
2021  return SCIP_OKAY;
2022 }
2023 
2027 static
2028 SCIP_RETCODE diagGEzero(
2029  SCIP* scip,
2030  SCIP_CONSHDLR* conshdlr,
2031  SCIP_CONS** conss,
2032  int nconss,
2033  SCIP_Bool solvesdps,
2034  int* naddconss,
2035  int* nchgbds,
2036  SCIP_Bool* infeasible
2037  )
2038 {
2039  char cutname[SCIP_MAXSTRLEN];
2040  SCIP_CONSHDLRDATA* conshdlrdata;
2041  SCIP_CONSDATA* consdata;
2042  SCIP_Real* matrix;
2043  SCIP_Real* consvals;
2044  SCIP_VAR** consvars;
2045  SCIP_Real* diagentries;
2046  int blocksize;
2047  int nvars;
2048  int i;
2049  int j;
2050  int k;
2051  int c;
2052 
2053  assert( scip != NULL );
2054  assert( naddconss != NULL );
2055  assert( nchgbds != NULL );
2056  assert( infeasible != NULL );
2057 
2058  *infeasible = FALSE;
2059 
2060  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2061  assert( conshdlrdata != NULL );
2062 
2063  for (c = 0; c < nconss; ++c)
2064  {
2065  consdata = SCIPconsGetData(conss[c]);
2066  assert( consdata != NULL );
2067  assert( consdata->rankone || strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(conss[c])), CONSHDLR_NAME) == 0 );
2068  assert( ! consdata->rankone || strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(conss[c])), CONSHDLRRANK1_NAME) == 0 );
2069 
2070  blocksize = consdata->blocksize;
2071  nvars = consdata->nvars;
2072 
2073  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nvars) );
2074  SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nvars) );
2075 
2076  SCIP_CALL( SCIPallocBufferArray(scip, &matrix, (blocksize * (blocksize + 1)) / 2) ); /*lint !e647*/
2077  SCIP_CALL( SCIPconsSdpGetLowerTriangConstMatrix(scip, conss[c], matrix) );
2078 
2079  /* allocate diagonal entries and init to 0.0 */
2080  SCIP_CALL( SCIPallocClearBufferArray(scip, &diagentries, blocksize * nvars) ); /*lint !e647*/
2081 
2082  /* get the (k,k)-entry of every matrix A_j */
2083  for (j = 0; j < nvars; ++j)
2084  {
2085  /* go through the nonzeros of A_j and look for diagonal entries */
2086  for (i = 0; i < consdata->nvarnonz[j]; i++)
2087  {
2088  if ( consdata->col[j][i] == consdata->row[j][i] )
2089  diagentries[consdata->col[j][i] * nvars + j] = consdata->val[j][i]; /*lint !e679*/
2090  }
2091  }
2092 
2093  /* add the LP-cuts to SCIP */
2094  for (k = 0; k < blocksize && !(*infeasible); ++k)
2095  {
2096  SCIP_CONS* cons;
2097  SCIP_Real lhs;
2098  SCIP_Real activitylb = 0.0;
2099  int cnt = 0;
2100 
2101  for ( j = 0; j < nvars; ++j)
2102  {
2103  SCIP_Real val;
2104  SCIP_VAR* var;
2105 
2106  val = diagentries[k * nvars + j];
2107  if ( ! SCIPisZero(scip, val) )
2108  {
2109  var = consdata->vars[j];
2110  consvals[cnt] = val;
2111  consvars[cnt++] = var;
2112 
2113  /* compute lower bound on activity */
2114  if ( val > 0 )
2115  activitylb += val * SCIPvarGetLbGlobal(var);
2116  else
2117  activitylb += val * SCIPvarGetUbGlobal(var);
2118  }
2119  }
2120 
2121  /* the lhs is the (k,k)-entry of the constant matrix */
2122  lhs = matrix[SCIPconsSdpCompLowerTriangPos(k,k)];
2123 
2124  if ( cnt == 0 )
2125  {
2126  /* if there are no variables, but the lhs is positive, we are infeasible */
2127  if ( SCIPisPositive(scip, lhs) )
2128  *infeasible = TRUE;
2129  }
2130  else if ( cnt == 1 && SCIPvarGetStatus(consvars[0]) != SCIP_VARSTATUS_MULTAGGR )
2131  {
2132  SCIP_Bool tightened;
2133  SCIP_VAR* var;
2134  SCIP_Real val;
2135 
2136  var = consvars[0];
2137  val = consvals[0];
2138  assert( var != NULL );
2139 
2140  /* try to tighten bound */
2141  if ( SCIPisPositive(scip, val) )
2142  {
2143  SCIP_CALL( SCIPtightenVarLb(scip, var, lhs / val, FALSE, infeasible, &tightened) );
2144  if ( tightened )
2145  {
2146  SCIPdebugMsg(scip, "Tightend lower bound of <%s> to %g because of diagonal values of SDP-constraint <%s>!\n",
2147  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPconsGetName(conss[c]));
2148  ++(*nchgbds);
2149  }
2150  }
2151  else if ( SCIPisNegative(scip, val) )
2152  {
2153  SCIP_CALL( SCIPtightenVarUb(scip, var, lhs / val, FALSE, infeasible, &tightened) );
2154  if ( tightened )
2155  {
2156  SCIPdebugMsg(scip, "Tightend upper bound of <%s> to %g because of diagonal values of SDP-constraint <%s>!\n",
2157  SCIPvarGetName(var), SCIPvarGetUbGlobal(var), SCIPconsGetName(conss[c]));
2158  ++(*nchgbds);
2159  }
2160  }
2161  }
2162  /* generate linear inequality if lower bound on activity is less than the lhs, so the cut is not redundant */
2163  else if ( SCIPisLT(scip, activitylb, lhs) )
2164  {
2165  (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "diag_ge_zero_%d", ++(conshdlrdata->ndiaggezerocuts));
2166 
2167  /* Only separate if solving LPs */
2168  SCIP_CALL( SCIPcreateConsLinear(scip, &cons, cutname, cnt, consvars, consvals, lhs, SCIPinfinity(scip),
2169  FALSE, ! solvesdps, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE) ); /*lint !e679*/
2170 
2171  SCIP_CALL( SCIPaddCons(scip, cons) );
2172 #ifdef SCIP_MORE_DEBUG
2173  SCIPinfoMessage(scip, NULL, "Added diagonal lp-constraint: ");
2174  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
2175  SCIPinfoMessage(scip, NULL, "\n");
2176 #endif
2177  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
2178  ++(*naddconss);
2179  }
2180  }
2181 
2182  SCIPfreeBufferArray(scip, &diagentries);
2183  SCIPfreeBufferArray(scip, &matrix);
2184  SCIPfreeBufferArray(scip, &consvals);
2185  SCIPfreeBufferArray(scip, &consvars);
2186  }
2187 
2188  return SCIP_OKAY;
2189 }
2190 
2198 static
2199 SCIP_RETCODE diagZeroImpl(
2200  SCIP* scip,
2201  SCIP_CONS** conss,
2202  int nconss,
2203  int* naddconss
2204  )
2205 {
2206  char name[SCIP_MAXSTRLEN];
2207  SCIP_CONSDATA* consdata;
2208  int c;
2209 
2210  assert( scip != NULL );
2211  assert( naddconss != NULL );
2212 
2213  for (c = 0; c < nconss; ++c)
2214  {
2215  SCIP_Shortbool* nonzeroentries;
2216  SCIP_Shortbool* diagnonzero;
2217  SCIP_VAR** vars;
2218  SCIP_Real* vals;
2219  SCIP_Bool negintvar = FALSE;
2220  int** diagvars;
2221  int* ndiagvars;
2222  int ndiagnonzero = 0;
2223  int blocksize;
2224  int rowidx;
2225  int colidx;
2226  int nvars;
2227  int pos;
2228  int j;
2229  int v;
2230 
2231  assert( conss[c] != NULL );
2232  consdata = SCIPconsGetData(conss[c]);
2233  assert( consdata != NULL );
2234 
2235  blocksize = consdata->blocksize;
2236  nvars = consdata->nvars;
2237 
2238  /* allocate storage */
2239  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
2240  SCIP_CALL( SCIPallocBufferArray(scip, &vals, nvars) );
2241  SCIP_CALL( SCIPallocClearBufferArray(scip, &nonzeroentries, blocksize * (blocksize+1) / 2) );
2242  SCIP_CALL( SCIPallocClearBufferArray(scip, &diagnonzero, blocksize) );
2243  SCIP_CALL( SCIPallocClearBufferArray(scip, &ndiagvars, blocksize) );
2244  SCIP_CALL( SCIPallocBufferArray(scip, &diagvars, blocksize) );
2245  for (j = 0; j < blocksize; ++j)
2246  {
2247  SCIP_CALL( SCIPallocClearBufferArray(scip, &diagvars[j], nvars) );
2248  }
2249 
2250  /* collect nonzero entries of matrices */
2251  for (v = 0; v < nvars; ++v)
2252  {
2253  if ( SCIPvarIsIntegral(consdata->vars[v]) && SCIPisNegative(scip, SCIPvarGetLbGlobal(consdata->vars[v])) )
2254  {
2255  negintvar = TRUE;
2256  break;
2257  }
2258 
2259  for (j = 0; j < consdata->nvarnonz[v]; j++)
2260  {
2261  rowidx = consdata->row[v][j];
2262  colidx = consdata->col[v][j];
2263  assert( 0 <= rowidx && rowidx < blocksize );
2264  assert( 0 <= colidx && colidx < blocksize );
2265  assert( ! SCIPisZero(scip, consdata->val[v][j]) );
2266 
2267  pos = rowidx * (rowidx + 1)/2 + colidx;
2268  nonzeroentries[pos] = TRUE;
2269 
2270  /* treat diagonal entries */
2271  if ( rowidx == colidx )
2272  {
2273  /* collect variables for positive diagonal entries */
2274  if ( SCIPisPositive(scip, consdata->val[v][j]) )
2275  diagvars[rowidx][ndiagvars[rowidx]++] = v;
2276 
2277  /* mark nonzero entries for non-integral variables */
2278  if ( ! SCIPvarIsIntegral(consdata->vars[v]) )
2279  {
2280  if ( ! diagnonzero[rowidx] )
2281  {
2282  diagnonzero[rowidx] = TRUE;
2283  ++ndiagnonzero;
2284  }
2285  }
2286  }
2287  }
2288  }
2289 
2290  /* early termination if there is an integral variable with a negative lower bound */
2291  if ( negintvar )
2292  {
2293  for (j = blocksize - 1; j >= 0; j--)
2294  {
2295  SCIPfreeBufferArray(scip, &diagvars[j]);
2296  }
2297  SCIPfreeBufferArray(scip, &diagvars);
2298  SCIPfreeBufferArray(scip, &ndiagvars);
2299  SCIPfreeBufferArray(scip, &diagnonzero);
2300  SCIPfreeBufferArray(scip, &nonzeroentries);
2301  SCIPfreeBufferArray(scip, &vals);
2302  SCIPfreeBufferArray(scip, &vars);
2303  continue;
2304  }
2305 
2306  /* add nonzero diagonal entries of constant matrix */
2307  for (j = 0; j < consdata->constnnonz; j++)
2308  {
2309  rowidx = consdata->constrow[j];
2310  colidx = consdata->constcol[j];
2311  assert( 0 <= colidx && colidx < blocksize );
2312  assert( 0 <= rowidx && rowidx < blocksize );
2313  assert( ! SCIPisZero(scip, consdata->constval[j]) );
2314 
2315  if ( rowidx == colidx )
2316  {
2317  if ( ! diagnonzero[rowidx] )
2318  {
2319  diagnonzero[rowidx] = TRUE;
2320  ++ndiagnonzero;
2321  }
2322  }
2323  }
2324  assert( 0 <= ndiagnonzero && ndiagnonzero <= blocksize );
2325 
2326  /* early termination if all diagonals are marked to be nonzero */
2327  if ( ndiagnonzero >= blocksize )
2328  {
2329  for (j = blocksize - 1; j >= 0; j--)
2330  {
2331  SCIPfreeBufferArray(scip, &diagvars[j]);
2332  }
2333  SCIPfreeBufferArray(scip, &diagvars);
2334  SCIPfreeBufferArray(scip, &ndiagvars);
2335  SCIPfreeBufferArray(scip, &diagnonzero);
2336  SCIPfreeBufferArray(scip, &nonzeroentries);
2337  SCIPfreeBufferArray(scip, &vals);
2338  SCIPfreeBufferArray(scip, &vars);
2339  continue;
2340  }
2341 
2342  /* iterate over all nonzeros of the constant matrix to produce cuts */
2343  for (j = 0; j < consdata->constnnonz; j++)
2344  {
2345  SCIP_CONS* cons;
2346 
2347  rowidx = consdata->constrow[j];
2348  colidx = consdata->constcol[j];
2349  assert( 0 <= colidx && colidx < blocksize );
2350  assert( 0 <= rowidx && rowidx < blocksize );
2351  assert( ! SCIPisZero(scip, consdata->constval[j]) );
2352 
2353  /* skip diagonal entries */
2354  if ( rowidx == colidx )
2355  continue;
2356 
2357  pos = rowidx * (rowidx + 1)/2 + colidx;
2358 
2359  /* skip entry if it is non-zero in some non-constant matrix */
2360  if ( nonzeroentries[pos] )
2361  continue;
2362 
2363  /* if all continuous variables have a zero diagonal entry and the constant matrix is 0 as well */
2364  if ( ! diagnonzero[rowidx] && ndiagvars[rowidx] > 0 )
2365  {
2366  /* get the corresponding SCIP variables and set all coefficients to 1 */
2367  for (v = 0; v < ndiagvars[rowidx]; ++v)
2368  {
2369  assert( SCIPvarIsIntegral(consdata->vars[diagvars[rowidx][v]]) );
2370  assert( 0 <= diagvars[rowidx][v] && diagvars[rowidx][v] < nvars );
2371  vars[v] = consdata->vars[diagvars[rowidx][v]];
2372  vals[v] = 1.0;
2373  }
2374  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "diag_0_impl_row_%d_%d", rowidx, colidx);
2375 
2376  /* add the linear constraint sum_v 1.0 * diagvars[v] >= 1.0 */
2377  SCIP_CALL( SCIPcreateConsLinear(scip, &cons, name, ndiagvars[rowidx], vars, vals, 1.0, SCIPinfinity(scip), TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE) );
2378  SCIP_CALL( SCIPaddCons(scip, cons) );
2379 #ifdef SCIP_MORE_DEBUG
2380  SCIPinfoMessage(scip, NULL, "Added constraint: ");
2381  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
2382  SCIPinfoMessage(scip, NULL, "\n");
2383 #endif
2384  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
2385  (*naddconss)++;
2386 
2387  /* mark diagonal entry as covered */
2388  diagnonzero[rowidx] = TRUE;
2389  }
2390 
2391  /* same possibility for column index */
2392  if ( ! diagnonzero[colidx] && ndiagvars[colidx] > 0 )
2393  {
2394  /* get the corresponding SCIP variables and set all coefficients to 1 */
2395  for (v = 0; v < ndiagvars[colidx]; ++v)
2396  {
2397  assert( SCIPvarIsIntegral(consdata->vars[diagvars[colidx][v]]) );
2398  assert( 0 <= diagvars[colidx][v] && diagvars[colidx][v] < nvars );
2399  vars[v] = consdata->vars[diagvars[colidx][v]];
2400  vals[v] = 1.0;
2401  }
2402  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "diag_0_impl_col_%d_%d", rowidx, colidx);
2403 
2404  /* add the linear constraint sum_v 1.0 * diagvars[v] >= 1.0 */
2405  SCIP_CALL( SCIPcreateConsLinear(scip, &cons, name, ndiagvars[colidx], vars, vals, 1.0, SCIPinfinity(scip), TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE) );
2406  SCIP_CALL( SCIPaddCons(scip, cons) );
2407 #ifdef SCIP_MORE_DEBUG
2408  SCIPinfoMessage(scip, NULL, "Added constraint: ");
2409  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
2410  SCIPinfoMessage(scip, NULL, "\n");
2411 #endif
2412  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
2413  (*naddconss)++;
2414 
2415  /* mark diagonal entry as covered */
2416  diagnonzero[colidx] = TRUE;
2417  }
2418  }
2419 
2420  /* free space */
2421  for (j = blocksize - 1; j >= 0; j--)
2422  {
2423  SCIPfreeBufferArray(scip, &diagvars[j]);
2424  }
2425  SCIPfreeBufferArray(scip, &diagvars);
2426  SCIPfreeBufferArray(scip, &ndiagvars);
2427  SCIPfreeBufferArray(scip, &diagnonzero);
2428  SCIPfreeBufferArray(scip, &nonzeroentries);
2429  SCIPfreeBufferArray(scip, &vals);
2430  SCIPfreeBufferArray(scip, &vars);
2431  }
2432 
2433  return SCIP_OKAY;
2434 }
2435 
2453 static
2454 SCIP_RETCODE addTwoMinorLinConstraints(
2455  SCIP* scip,
2456  SCIP_CONS** conss,
2457  int nconss,
2458  SCIP_Bool solvesdps,
2459  int* naddconss
2460  )
2461 {
2462  char name[SCIP_MAXSTRLEN];
2463  SCIP_VAR** consvars;
2464  SCIP_Real* consvals;
2465  int blocksize;
2466  int nvars;
2467  int c;
2468  int i;
2469 
2470  assert( scip != NULL );
2471  assert( naddconss != NULL );
2472 
2473  for (c = 0; c < nconss; ++c)
2474  {
2475  SCIP_CONSDATA* consdata;
2476  SCIP_Real** matrices = NULL;
2477  SCIP_Real* constmatrix;
2478  int s;
2479  int t;
2480 
2481  assert( conss[c] != NULL );
2482  consdata = SCIPconsGetData(conss[c]);
2483  assert( consdata != NULL );
2484 
2485  blocksize = consdata->blocksize;
2486  nvars = consdata->nvars;
2487 
2488  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nvars) );
2489  SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nvars) );
2490 
2491  /* get matrices */
2492  SCIP_CALL( SCIPallocBufferArray(scip, &constmatrix, blocksize * blocksize) );
2493  SCIP_CALL( SCIPconsSdpGetFullConstMatrix(scip, conss[c], constmatrix) );
2494 
2495  SCIP_CALL( SCIPallocBufferArray(scip, &matrices, nvars) );
2496  for (i = 0; i < nvars; ++i)
2497  {
2498  SCIP_CALL( SCIPallocBufferArray(scip, &matrices[i], blocksize * blocksize) );
2499  SCIP_CALL( SCIPconsSdpGetFullAj(scip, conss[c], i, matrices[i]) );
2500  }
2501 
2502  /* loop over all possible entries */
2503  for (s = 0; s < blocksize; ++s)
2504  {
2505  for (t = 0; t < s; ++t)
2506  {
2507  SCIP_CONS* cons;
2508  SCIP_Real val;
2509  SCIP_Real lhs;
2510  SCIP_Real activitylb = 0.0;
2511  int nconsvars = 0;
2512  int cnt = 0;
2513 
2514  /* collect coefficients */
2515  for (i = 0; i < nvars; ++i)
2516  {
2517  SCIP_Real coef = 0.0;
2518 
2519  val = matrices[i][s * blocksize + t];
2520  if ( ! SCIPisZero(scip, val) )
2521  {
2522  coef = -2.0 * val;
2523  ++cnt;
2524  }
2525 
2526  /* add diagonal entries for s and t */
2527  val = matrices[i][s * blocksize + s];
2528  if ( ! SCIPisZero(scip, val) )
2529  coef += val;
2530 
2531  val = matrices[i][t * blocksize + t];
2532  if ( ! SCIPisZero(scip, val) )
2533  coef += val;
2534 
2535  if ( ! SCIPisZero(scip, coef) )
2536  {
2537  consvals[nconsvars] = coef;
2538  consvars[nconsvars] = consdata->vars[i];
2539  ++nconsvars;
2540 
2541  /* compute lower bound on activity */
2542  if ( coef > 0 )
2543  activitylb += coef * SCIPvarGetLbGlobal(consdata->vars[i]);
2544  else
2545  activitylb += coef * SCIPvarGetUbGlobal(consdata->vars[i]);
2546  }
2547  }
2548 
2549  /* only proceed if off-diagonal is nonzero and cut is nontrivial */
2550  if ( cnt <= 0 || nconsvars <= 0 )
2551  continue;
2552 
2553  /* compute rhs */
2554  lhs = constmatrix[s * blocksize + s] + constmatrix[t * blocksize + t] - 2.0 * constmatrix[s * blocksize + t];
2555 
2556  /* only proceed if constraint is not redundant */
2557  if ( SCIPisGE(scip, activitylb, lhs) )
2558  continue;
2559 
2560  /* add linear constraint (if not solving LPs only propagate) */
2561  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "2x2minorlin#%d#%d", s, t);
2562  SCIP_CALL( SCIPcreateConsLinear(scip, &cons, name, nconsvars, consvars, consvals, lhs, SCIPinfinity(scip),
2563  FALSE, ! solvesdps, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE) );
2564  SCIP_CALL( SCIPaddCons(scip, cons) );
2565 #ifdef SCIP_MORE_DEBUG
2566  SCIPinfoMessage(scip, NULL, "Added 2x2 minor linear constraint: ");
2567  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
2568  SCIPinfoMessage(scip, NULL, "\n");
2569 #endif
2570  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
2571  ++(*naddconss);
2572  }
2573  }
2574 
2575  for (i = nvars - 1; i >= 0; --i)
2576  SCIPfreeBufferArray(scip, &matrices[i]);
2577  SCIPfreeBufferArray(scip, &matrices);
2578  SCIPfreeBufferArray(scip, &constmatrix);
2579  SCIPfreeBufferArray(scip, &consvals);
2580  SCIPfreeBufferArray(scip, &consvars);
2581  }
2582 
2583  return SCIP_OKAY;
2584 }
2585 
2604 static
2605 SCIP_RETCODE addTwoMinorSOCConstraints(
2606  SCIP* scip,
2607  SCIP_CONS** conss,
2608  int nconss,
2609  SCIP_Bool solvesdps,
2610  int* naddconss
2611  )
2612 {
2613  char name[SCIP_MAXSTRLEN];
2614  SCIP_VAR*** matrixvars;
2615  SCIP_VAR** consvars;
2616  SCIP_Real* consvals;
2617  int blocksize;
2618  int nvars;
2619  int c;
2620  int i;
2621 
2622  assert( scip != NULL );
2623  assert( naddconss != NULL );
2624 
2625  for (c = 0; c < nconss; ++c)
2626  {
2627  SCIP_CONSDATA* consdata;
2628  SCIP_Real** matrices = NULL;
2629  SCIP_Real* constmatrix;
2630  int size;
2631  int s;
2632  int t;
2633 
2634  assert( conss[c] != NULL );
2635  consdata = SCIPconsGetData(conss[c]);
2636  assert( consdata != NULL );
2637 
2638  blocksize = consdata->blocksize;
2639  nvars = consdata->nvars;
2640 
2641  size = MAX(nvars + 1, 3);
2642  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, size) );
2643  SCIP_CALL( SCIPallocBufferArray(scip, &consvals, size) );
2644 
2645  /* get matrices */
2646  SCIP_CALL( SCIPallocBufferArray(scip, &constmatrix, blocksize * blocksize) );
2647  SCIP_CALL( SCIPconsSdpGetFullConstMatrix(scip, conss[c], constmatrix) );
2648 
2649  SCIP_CALL( SCIPallocBufferArray(scip, &matrices, nvars) );
2650  for (i = 0; i < nvars; ++i)
2651  {
2652  SCIP_CALL( SCIPallocBufferArray(scip, &matrices[i], blocksize * blocksize) );
2653  SCIP_CALL( SCIPconsSdpGetFullAj(scip, conss[c], i, matrices[i]) );
2654  }
2655 
2656  SCIP_CALL( SCIPallocBufferArray(scip, &matrixvars, blocksize) );
2657 
2658  /* loop over all possible entries */
2659  for (s = 0; s < blocksize; ++s)
2660  {
2661  SCIP_CALL( SCIPallocClearBufferArray(scip, &matrixvars[s], blocksize) );
2662 
2663  for (t = s; t >= 0; --t)
2664  {
2665  SCIP_VAR* matrixvar = NULL;
2666  SCIP_VAR* matrixsumvar;
2667  SCIP_VAR* matrixdiffvar;
2668  SCIP_CONS* cons;
2669  SCIP_Real val;
2670  SCIP_Real lhs;
2671  int nconsvars = 0;
2672 
2673  /* create linear constraint defining matrix variable */
2674  for (i = 0; i < nvars; ++i)
2675  {
2676  val = matrices[i][s * blocksize + t];
2677  if ( ! SCIPisZero(scip, val) )
2678  {
2679  consvals[nconsvars] = val;
2680  consvars[nconsvars++] = consdata->vars[i];
2681  }
2682  }
2683 
2684  /* only proceed if entry is nontrivial */
2685  if ( nconsvars == 0 )
2686  continue;
2687 
2688  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "M%d#%d#%d", c, s, t);
2689  SCIP_CALL( SCIPcreateVarBasic(scip, &matrixvar, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0, SCIP_VARTYPE_CONTINUOUS) );
2690  SCIP_CALL( SCIPaddVar(scip, matrixvar) );
2691  SCIPdebugMsg(scip, "Added new matrix variable <%s>\n", name );
2692 
2693  consvals[nconsvars] = -1.0;
2694  consvars[nconsvars++] = matrixvar;
2695 
2696  /* compute lhs and rhs */
2697  lhs = constmatrix[s * blocksize + t];
2698 
2699  /* create linear constraint */
2700  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "C%d#%d#%d", c, s, t);
2701  SCIP_CALL( SCIPcreateConsLinear(scip, &cons, name, nconsvars, consvars, consvals, lhs, lhs,
2702  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE) );
2703  SCIP_CALL( SCIPaddCons(scip, cons) );
2704 
2705 #ifdef SCIP_MORE_DEBUG
2706  SCIPinfoMessage(scip, NULL, "Added linear constraint for coupling the new matrix variable: ");
2707  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
2708  SCIPinfoMessage(scip, NULL, "\n");
2709 #endif
2710 
2711  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
2712  assert( matrixvar != NULL );
2713 
2714  /* store variable (variable is captured) */
2715  matrixvars[s][t] = matrixvar;
2716 
2717  /* skip diagonal entries */
2718  if ( s == t )
2719  continue;
2720 
2721  /* skip if any of the variables is trivial */
2722  if ( matrixvars[s][s] == NULL || matrixvars[t][t] == NULL || matrixvars[s][t] == NULL )
2723  continue;
2724 
2725  /* create variable for sum of two matrix variables (note they they are nonnegative) */
2726  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "sum%d#%d#%d", c, s, t);
2727  SCIP_CALL( SCIPcreateVarBasic(scip, &matrixsumvar, name, 0.0, SCIPinfinity(scip), 0.0, SCIP_VARTYPE_CONTINUOUS) );
2728  SCIP_CALL( SCIPaddVar(scip, matrixsumvar) );
2729  SCIPdebugMsg(scip, "Added new variable <%s> for sum of two matrix variables.\n", name);
2730 
2731  consvars[0] = matrixvars[s][s];
2732  consvars[1] = matrixvars[t][t];
2733  consvars[2] = matrixsumvar;
2734 
2735  consvals[0] = 1.0;
2736  consvals[1] = 1.0;
2737  consvals[2] = -1.0;
2738 
2739  /* create linear constraint */
2740  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "Sum%d#%d#%d", c, s, t);
2741  SCIP_CALL( SCIPcreateConsLinear(scip, &cons, name, 3, consvars, consvals, 0.0, 0.0,
2742  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE) );
2743  SCIP_CALL( SCIPaddCons(scip, cons) );
2744 
2745 #ifdef SCIP_MORE_DEBUG
2746  SCIPinfoMessage(scip, NULL, "Added linear constraint for sum of two matrix variables: ");
2747  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
2748  SCIPinfoMessage(scip, NULL, "\n");
2749 #endif
2750 
2751  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
2752 
2753  /* create variable for difference of two matrix variablees */
2754  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "diff%d#%d#%d", c, s, t);
2755  SCIP_CALL( SCIPcreateVarBasic(scip, &matrixdiffvar, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0, SCIP_VARTYPE_CONTINUOUS) );
2756  SCIP_CALL( SCIPaddVar(scip, matrixdiffvar) );
2757  SCIPdebugMsg(scip, "Added new variable <%s> for difference of two matrix variables.\n", name);
2758 
2759  consvars[0] = matrixvars[s][s];
2760  consvars[1] = matrixvars[t][t];
2761  consvars[2] = matrixdiffvar;
2762 
2763  consvals[0] = 1.0;
2764  consvals[1] = -1.0;
2765  consvals[2] = -1.0;
2766 
2767  /* create linear constraint */
2768  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "Diff%d#%d#%d", c, s, t);
2769  SCIP_CALL( SCIPcreateConsLinear(scip, &cons, name, 3, consvars, consvals, 0.0, 0.0,
2770  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE) );
2771  SCIP_CALL( SCIPaddCons(scip, cons) );
2772 
2773 #ifdef SCIP_MORE_DEBUG
2774  SCIPinfoMessage(scip, NULL, "Added linear constraint for difference of two matrix variables: ");
2775  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
2776  SCIPinfoMessage(scip, NULL, "\n");
2777 #endif
2778 
2779  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
2780 
2781  /* construct SOC constraint */
2782  consvars[0] = matrixvars[s][t];
2783  consvars[1] = matrixdiffvar;
2784 
2785  consvals[0] = 2.0;
2786  consvals[1] = 1.0;
2787 
2788  /* add SOC constraint (if not solving LPs only propagate) */
2789  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "2x2minorSOC#%d#%d#%d", c, s, t);
2790 
2791 #if ( SCIP_VERSION >= 800 || ( SCIP_VERSION < 800 && SCIP_APIVERSION >= 100 ) )
2792  consvals[0] = 4.0; /* correct to 4, because coefficient is outside of square */
2793  consvars[2] = matrixsumvar;
2794  consvals[2] = -1.0;
2795  SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, &cons, name, 0, NULL, NULL, 3, consvars, consvars, consvals,
2796  - SCIPinfinity(scip), 0.0, TRUE, ! solvesdps, ! solvesdps, ! solvesdps, TRUE, FALSE, FALSE, TRUE, TRUE) );
2797 #else
2798  SCIP_CALL( SCIPcreateConsSOC(scip, &cons, name, 2, consvars, consvals, NULL, 0.0, matrixsumvar, 1.0, 0.0,
2799  TRUE, ! solvesdps, ! solvesdps, ! solvesdps, TRUE, FALSE, FALSE, TRUE, TRUE) );
2800 #endif
2801  SCIP_CALL( SCIPaddCons(scip, cons) );
2802 
2803 #ifdef SCIP_MORE_DEBUG
2804  SCIPinfoMessage(scip, NULL, "Added 2x2 minor linear constraint: ");
2805  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
2806  SCIPinfoMessage(scip, NULL, "\n");
2807  SCIPinfoMessage(scip, NULL, "\n");
2808 #endif
2809  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
2810  ++(*naddconss);
2811 
2812  SCIP_CALL( SCIPreleaseVar(scip, &matrixsumvar) );
2813  SCIP_CALL( SCIPreleaseVar(scip, &matrixdiffvar) );
2814  }
2815  }
2816 
2817  for (s = blocksize - 1; s >= 0; --s)
2818  {
2819  for (t = 0; t <= s; ++t)
2820  {
2821  if ( matrixvars[s][t] != NULL )
2822  {
2823  SCIP_CALL( SCIPreleaseVar(scip, &matrixvars[s][t]) );
2824  }
2825  }
2826  SCIPfreeBufferArray(scip, &matrixvars[s]);
2827  }
2828  SCIPfreeBufferArray(scip, &matrixvars);
2829 
2830  for (i = 0; i < nvars; ++i)
2831  SCIPfreeBufferArray(scip, &matrices[i]);
2832  SCIPfreeBufferArray(scip, &matrices);
2833  SCIPfreeBufferArray(scip, &constmatrix);
2834  SCIPfreeBufferArray(scip, &consvals);
2835  SCIPfreeBufferArray(scip, &consvars);
2836  }
2837 
2838  return SCIP_OKAY;
2839 }
2840 
2846 static
2847 SCIP_RETCODE addTwoMinorProdConstraints(
2848  SCIP* scip,
2849  SCIP_CONS** conss,
2850  int nconss,
2851  SCIP_Bool solvesdps,
2852  int* naddconss
2853  )
2854 {
2855  char name[SCIP_MAXSTRLEN];
2856  SCIP_VAR** consvars;
2857  SCIP_Real* consvals;
2858  int blocksize;
2859  int nvars;
2860  int c;
2861  int i;
2862  int j;
2863 
2864  assert( scip != NULL );
2865  assert( naddconss != NULL );
2866 
2867  for (c = 0; c < nconss; ++c)
2868  {
2869  SCIP_CONSDATA* consdata;
2870  SCIP_Real** matrices = NULL;
2871  SCIP_Real* constmatrix;
2872 
2873  assert( conss[c] != NULL );
2874  consdata = SCIPconsGetData(conss[c]);
2875  assert( consdata != NULL );
2876 
2877  blocksize = consdata->blocksize;
2878  nvars = consdata->nvars;
2879 
2880  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nvars) );
2881  SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nvars) );
2882 
2883  SCIP_CALL( SCIPallocBufferArray(scip, &constmatrix, blocksize * blocksize) );
2884  SCIP_CALL( SCIPconsSdpGetFullConstMatrix(scip, conss[c], constmatrix) );
2885 
2886  /* loop over all nonzero matrix entries in the constant part */
2887  for (j = 0; j < consdata->constnnonz; ++j)
2888  {
2889  SCIP_Real val;
2890  SCIP_Real prod;
2891  int s;
2892  int t;
2893 
2894  s = consdata->constrow[j];
2895  t = consdata->constcol[j];
2896 
2897  /* skip diagonal entries */
2898  if ( s == t )
2899  continue;
2900 
2901  /* compute matrices if not yet done */
2902  if ( matrices == NULL )
2903  {
2904  SCIP_CALL( SCIPallocBufferArray(scip, &matrices, nvars) );
2905  for (i = 0; i < nvars; ++i)
2906  {
2907  SCIP_CALL( SCIPallocBufferArray(scip, &matrices[i], blocksize * blocksize) );
2908  SCIP_CALL( SCIPconsSdpGetFullAj(scip, conss[c], i, matrices[i]) );
2909  }
2910  }
2911  assert( matrices != NULL );
2912 
2913  /* check whether diagonal entries in the matrices are all 0 */
2914  for (i = 0; i < nvars; ++i)
2915  {
2916  if ( ! SCIPisZero(scip, matrices[i][s * blocksize + s]) )
2917  break;
2918  if ( ! SCIPisZero(scip, matrices[i][t * blocksize + t]) )
2919  break;
2920  }
2921  if ( i < nvars )
2922  continue;
2923 
2924  /* check if product is sufficiently positive */
2925  prod = constmatrix[s * blocksize + s] * constmatrix[t * blocksize + t];
2926  if ( SCIPisEfficacious(scip, prod) )
2927  {
2928  SCIP_CONS* cons;
2929  SCIP_Real activitylb = 0.0;
2930  SCIP_Real lhs;
2931  int nconsvars = 0;
2932 
2933  /* fill in constraint */
2934  for (i = 0; i < nvars; ++i)
2935  {
2936  val = matrices[i][s * blocksize + t];
2937  if ( ! SCIPisZero(scip, val) )
2938  {
2939  consvals[nconsvars] = val;
2940  consvars[nconsvars] = consdata->vars[i];
2941  ++nconsvars;
2942 
2943  /* compute lower bound on activity */
2944  if ( val > 0 )
2945  activitylb += val * SCIPvarGetLbGlobal(consdata->vars[i]);
2946  else
2947  activitylb += val * SCIPvarGetUbGlobal(consdata->vars[i]);
2948  }
2949  }
2950 
2951  lhs = consdata->constval[j] - sqrt(prod);
2952 
2953  /* only proceed if constraint is not redundant */
2954  if ( SCIPisGE(scip, activitylb, lhs) )
2955  continue;
2956 
2957  /* add linear constraint (if not solving LPs only propagate) */
2958  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "2x2minorprod#%d#%d", s, t);
2959  SCIP_CALL( SCIPcreateConsLinear(scip, &cons, name, nconsvars, consvars, consvals, lhs, SCIPinfinity(scip),
2960  FALSE, ! solvesdps, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE) );
2961  SCIP_CALL( SCIPaddCons(scip, cons) );
2962 #ifdef SCIP_MORE_DEBUG
2963  SCIPinfoMessage(scip, NULL, "Added 2x2 minor product constraint: ");
2964  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
2965  SCIPinfoMessage(scip, NULL, "\n");
2966 #endif
2967  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
2968  ++(*naddconss);
2969  }
2970  }
2971 
2972  if ( matrices != NULL )
2973  {
2974  for (i = nvars - 1; i >= 0; --i)
2975  SCIPfreeBufferArray(scip, &matrices[i]);
2976  SCIPfreeBufferArray(scip, &matrices);
2977  }
2978  SCIPfreeBufferArray(scip, &constmatrix);
2979  SCIPfreeBufferArray(scip, &consvals);
2980  SCIPfreeBufferArray(scip, &consvars);
2981  }
2982 
2983  return SCIP_OKAY;
2984 }
2985 
2993 static
2994 SCIP_RETCODE addTwoMinorVarBounds(
2995  SCIP* scip,
2996  SCIP_CONS** conss,
2997  int nconss,
2998  SCIP_Bool solvesdps,
2999  int* naddconss
3000  )
3001 {
3002  int c;
3003 
3004  assert( scip != NULL );
3005  assert( naddconss != NULL );
3006 
3007  for (c = 0; c < nconss; ++c)
3008  {
3009  char name[SCIP_MAXSTRLEN];
3010  SCIP_VAR** consvars;
3011  SCIP_Real* consvals;
3012  SCIP_CONSDATA* consdata;
3013  SCIP_Real* constmatrix;
3014  SCIP_Real** matrices;
3015  int blocksize;
3016  int nvars;
3017  int s;
3018  int t;
3019  int i;
3020 
3021  assert( conss[c] != NULL );
3022  consdata = SCIPconsGetData(conss[c]);
3023  assert( consdata != NULL );
3024 
3025  blocksize = consdata->blocksize;
3026  nvars = consdata->nvars;
3027 
3028  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, 2 * nvars) );
3029  SCIP_CALL( SCIPallocBufferArray(scip, &consvals, 2 * nvars) );
3030 
3031  /* get matrices */
3032  SCIP_CALL( SCIPallocBufferArray(scip, &constmatrix, blocksize * blocksize) );
3033  SCIP_CALL( SCIPconsSdpGetFullConstMatrix(scip, conss[c], constmatrix) );
3034 
3035  SCIP_CALL( SCIPallocBufferArray(scip, &matrices, nvars) );
3036  for (i = 0; i < nvars; ++i)
3037  {
3038  SCIP_CALL( SCIPallocBufferArray(scip, &matrices[i], blocksize * blocksize) );
3039  SCIP_CALL( SCIPconsSdpGetFullAj(scip, conss[c], i, matrices[i]) );
3040  }
3041 
3042  /* loop over all possible entries */
3043  for (s = 1; s < blocksize; ++s)
3044  {
3045  SCIP_Real ubs = 0.0;
3046  SCIP_Real val;
3047  SCIP_Real bound;
3048  int pos;
3049 
3050  /* compute upper bound */
3051  pos = s * blocksize + s;
3052  for (i = 0; i < nvars; ++i)
3053  {
3054  val = matrices[i][pos];
3055  if ( ! SCIPisZero(scip, val) )
3056  {
3057  if ( val > 0.0 )
3058  bound = SCIPvarGetUbLocal(consdata->vars[i]);
3059  else
3060  bound = SCIPvarGetLbLocal(consdata->vars[i]);
3061 
3062  if ( SCIPisInfinity(scip, REALABS(bound)) )
3063  {
3064  ubs = SCIPinfinity(scip);
3065  break;
3066  }
3067 
3068  ubs += val * bound;
3069  }
3070  assert( ! SCIPisInfinity(scip, ubs) );
3071  }
3072  if ( ! SCIPisInfinity(scip, ubs) )
3073  ubs -= constmatrix[pos];
3074 
3075  /* loop over all other entries */
3076  for (t = s-1; t >= 0; --t)
3077  {
3078  SCIP_CONS* cons;
3079  SCIP_Real ubt = 0.0;
3080  SCIP_Real ubst = 0.0;
3081 
3082  /* compute upper bound for off-diagonal */
3083  pos = s * blocksize + t;
3084  for (i = 0; i < nvars; ++i)
3085  {
3086  val = matrices[i][pos];
3087  if ( ! SCIPisZero(scip, val) )
3088  {
3089  if ( val > 0.0 )
3090  bound = SCIPvarGetUbLocal(consdata->vars[i]);
3091  else
3092  bound = SCIPvarGetLbLocal(consdata->vars[i]);
3093 
3094  if ( SCIPisInfinity(scip, REALABS(bound)) )
3095  {
3096  ubst = SCIPinfinity(scip);
3097  break;
3098  }
3099 
3100  ubst += val * bound;
3101  }
3102  assert( ! SCIPisInfinity(scip, ubst) );
3103  }
3104  if ( ! SCIPisInfinity(scip, ubst) )
3105  ubst -= constmatrix[pos];
3106 
3107  /* if the bound is zero, no interesting inequality arises */
3108  if ( SCIPisZero(scip, ubst) )
3109  continue;
3110 
3111  /* we need a finite bound on the off-diagonal */
3112  if ( SCIPisInfinity(scip, ubst) )
3113  continue;
3114 
3115  /* compute upper bound for diagonal */
3116  pos = t * blocksize + t;
3117  for (i = 0; i < nvars; ++i)
3118  {
3119  val = matrices[i][pos];
3120  if ( ! SCIPisZero(scip, val) )
3121  {
3122  if ( val > 0.0 )
3123  bound = SCIPvarGetUbLocal(consdata->vars[i]);
3124  else
3125  bound = SCIPvarGetLbLocal(consdata->vars[i]);
3126 
3127  if ( SCIPisInfinity(scip, REALABS(bound)) )
3128  {
3129  ubt = SCIPinfinity(scip);
3130  break;
3131  }
3132 
3133  ubt += val * bound;
3134  }
3135  assert( ! SCIPisInfinity(scip, ubt) );
3136  }
3137  if ( ! SCIPisInfinity(scip, ubt) )
3138  ubt -= constmatrix[pos];
3139 
3140  assert( ! SCIPisZero(scip, ubst) );
3141  assert( ! SCIPisInfinity(scip, ubst) );
3142 
3143  /* first type of constraint */
3144  if ( ! SCIPisInfinity(scip, ubt) )
3145  {
3146  SCIP_Real rhs;
3147  int nconsvars = 0;
3148 
3149  rhs = ubst * ubst;
3150 
3151  if ( ! SCIPisZero(scip, ubst) )
3152  {
3153  for (i = 0; i < nvars; ++i)
3154  {
3155  val = matrices[i][s * blocksize + t];
3156  if ( ! SCIPisZero(scip, val) )
3157  {
3158  consvals[nconsvars] = 2.0 * ubst * val;
3159  consvars[nconsvars++] = consdata->vars[i];
3160  }
3161  }
3162  rhs += 2.0 * ubst * constmatrix[s * blocksize + t];
3163  }
3164 
3165  if ( ! SCIPisZero(scip, ubt) )
3166  {
3167  for (i = 0; i < nvars; ++i)
3168  {
3169  val = matrices[i][s * blocksize + s];
3170  if ( ! SCIPisZero(scip, val) )
3171  {
3172  consvals[nconsvars] = - ubt * val;
3173  consvars[nconsvars++] = consdata->vars[i];
3174  }
3175  }
3176  rhs -= ubt * constmatrix[s * blocksize + s];
3177  }
3178 
3179  if ( nconsvars >= 1 )
3180  {
3181  /* add linear constraint (if not solving LPs only propagate) */
3182  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "twominorvarbounda#%d#%d", s, t);
3183  SCIP_CALL( SCIPcreateConsLinear(scip, &cons, name, nconsvars, consvars, consvals, -SCIPinfinity(scip), rhs,
3184  FALSE, ! solvesdps, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE) );
3185  SCIP_CALL( SCIPaddCons(scip, cons) );
3186 #ifdef SCIP_MORE_DEBUG
3187  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
3188  SCIPinfoMessage(scip, NULL, "\n");
3189 #endif
3190  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
3191  ++(*naddconss);
3192  }
3193  }
3194 
3195  /* second type of constraint */
3196  if ( ! SCIPisInfinity(scip, ubs) )
3197  {
3198  SCIP_Real rhs;
3199  int nconsvars = 0;
3200 
3201  rhs = ubst * ubst;
3202 
3203  if ( ! SCIPisZero(scip, ubst) )
3204  {
3205  for (i = 0; i < nvars; ++i)
3206  {
3207  val = matrices[i][s * blocksize + t];
3208  if ( ! SCIPisZero(scip, val) )
3209  {
3210  consvals[nconsvars] = 2.0 * ubst * val;
3211  consvars[nconsvars++] = consdata->vars[i];
3212  }
3213  }
3214  rhs += 2.0 * ubst * constmatrix[s * blocksize + t];
3215  }
3216 
3217  if ( ! SCIPisZero(scip, ubs) )
3218  {
3219  for (i = 0; i < nvars; ++i)
3220  {
3221  val = matrices[i][t * blocksize + t];
3222  if ( ! SCIPisZero(scip, val) )
3223  {
3224  consvals[nconsvars] = - ubs * val;
3225  consvars[nconsvars++] = consdata->vars[i];
3226  }
3227  }
3228  rhs -= ubs * constmatrix[t * blocksize + t];
3229  }
3230 
3231  if ( nconsvars >= 1 )
3232  {
3233  /* add linear constraint (if not solving LPs only propagate) */
3234  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "twominorvarboundb#%d#%d", s, t);
3235  SCIP_CALL( SCIPcreateConsLinear(scip, &cons, name, nconsvars, consvars, consvals, -SCIPinfinity(scip), rhs,
3236  FALSE, ! solvesdps, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE) );
3237  SCIP_CALL( SCIPaddCons(scip, cons) );
3238 #ifdef SCIP_MORE_DEBUG
3239  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
3240  SCIPinfoMessage(scip, NULL, "\n");
3241 #endif
3242  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
3243  ++(*naddconss);
3244  }
3245  }
3246  }
3247  }
3248 
3249  for (i = nvars - 1; i >= 0; --i)
3250  SCIPfreeBufferArray(scip, &matrices[i]);
3251  SCIPfreeBufferArray(scip, &matrices);
3252  SCIPfreeBufferArray(scip, &constmatrix);
3253  SCIPfreeBufferArray(scip, &consvals);
3254  SCIPfreeBufferArray(scip, &consvars);
3255  }
3256 
3257  return SCIP_OKAY;
3258 }
3259 
3261 static
3262 SCIP_RETCODE addRank1QuadConss(
3263  SCIP* scip,
3264  SCIP_CONSHDLR* conshdlr,
3265  SCIP_CONS** conss,
3266  int nconss,
3267  int* naddconss
3268  )
3269 {
3270  int c;
3271 
3272  assert( scip != NULL );
3273  assert( conshdlr != NULL );
3274  assert( naddconss != NULL );
3275 
3276  if ( conss == NULL )
3277  return SCIP_OKAY;
3278 
3279  for (c = 0; c < nconss; ++c)
3280  {
3281  SCIP_CONSDATA* consdata;
3282 
3283  consdata = SCIPconsGetData(conss[c]);
3284  assert( consdata != NULL );
3285 
3286  consdata->maxevsubmat[0] = -1;
3287  consdata->maxevsubmat[1] = -1;
3288 
3289  /* For each constraint, if it should be rank one, add all quadratic constraints given by the 2x2 principal
3290  * minors. */
3291  if ( consdata->rankone && ! consdata->addedquadcons )
3292  {
3293  SCIP_VAR** quadvars1;
3294  SCIP_VAR** quadvars2;
3295  SCIP_VAR** linvars;
3296  SCIP_CONS* quadcons;
3297  SCIP_Real* lincoefs;
3298  SCIP_Real* quadcoefs;
3299  SCIP_Real* constmatrix;
3300  SCIP_Real** matrixAk;
3301  SCIP_Real lhs;
3302  SCIP_Real aiik;
3303  SCIP_Real ajjk;
3304  SCIP_Real aijk;
3305  SCIP_Real aiil;
3306  SCIP_Real ajjl;
3307  SCIP_Real aijl;
3308  SCIP_Real cii;
3309  SCIP_Real cjj;
3310  SCIP_Real cij;
3311  char name[SCIP_MAXSTRLEN];
3312  int* nnonzvars;
3313  int** nonzvars;
3314  int i;
3315  int j;
3316  int k;
3317  int l;
3318  int blocksize;
3319  int varind1;
3320  int varind2;
3321 
3322  blocksize = consdata->blocksize;
3323 
3324  SCIP_CALL( SCIPallocBufferArray(scip, &constmatrix, (blocksize * (blocksize + 1)) / 2) ); /*lint !e647*/
3325  SCIP_CALL( SCIPconsSdpGetLowerTriangConstMatrix(scip, conss[c], constmatrix) );
3326 
3327  SCIP_CALL( SCIPallocBufferArray(scip, &quadvars1, consdata->nvars * consdata->nvars) );
3328  SCIP_CALL( SCIPallocBufferArray(scip, &quadvars2, consdata->nvars * consdata->nvars) );
3329  SCIP_CALL( SCIPallocBufferArray(scip, &linvars, consdata->nvars) );
3330  SCIP_CALL( SCIPallocBufferArray(scip, &quadcoefs, consdata->nvars * consdata->nvars) );
3331  SCIP_CALL( SCIPallocBufferArray(scip, &lincoefs, consdata->nvars) );
3332  SCIP_CALL( SCIPallocBufferArray(scip, &matrixAk, consdata->nvars) );
3333 
3334  for (i = 0; i < consdata->nvars; ++i)
3335  {
3336  SCIP_CALL( SCIPallocBufferArray(scip, &matrixAk[i], blocksize * blocksize) );
3337  SCIP_CALL( SCIPconsSdpGetFullAj(scip, conss[c], i, matrixAk[i]) );
3338  }
3339 
3340  SCIP_CALL( SCIPallocBufferArray(scip, &nnonzvars, (blocksize * (blocksize + 1)) / 2) );
3341  SCIP_CALL( SCIPallocBufferArray(scip, &nonzvars, (blocksize * (blocksize + 1)) / 2) );
3342 
3343  for (i = 0; i < blocksize; ++i)
3344  {
3345  for (j = 0; j <= i; ++j)
3346  {
3347  int varcnt = 0;
3348 
3349  SCIP_CALL( SCIPallocBufferArray(scip, &nonzvars[SCIPconsSdpCompLowerTriangPos(i,j)], consdata->nvars) );
3350 
3351  for (k = 0; k < consdata->nvars; ++k)
3352  {
3353  if ( ! SCIPisZero(scip, matrixAk[k][i * blocksize + j]) || ! SCIPisZero(scip, matrixAk[k][i * blocksize + i]) || ! SCIPisZero(scip, matrixAk[k][j * blocksize + j]) )
3354  {
3355  nonzvars[SCIPconsSdpCompLowerTriangPos(i,j)][varcnt] = k;
3356  varcnt++;
3357  }
3358  }
3359  nnonzvars[SCIPconsSdpCompLowerTriangPos(i,j)] = varcnt;
3360  }
3361  }
3362 
3363  for (i = 0; i < blocksize; ++i)
3364  {
3365  for (j = 0; j < i; ++j)
3366  {
3367  int lincnt = 0;
3368  int quadcnt = 0;
3369 
3370  cii = constmatrix[SCIPconsSdpCompLowerTriangPos(i,i)];
3371  cjj = constmatrix[SCIPconsSdpCompLowerTriangPos(j,j)];
3372  cij = constmatrix[SCIPconsSdpCompLowerTriangPos(i,j)];
3373 
3374  for (k = 0; k < nnonzvars[SCIPconsSdpCompLowerTriangPos(i,j)]; ++k)
3375  {
3376  varind1 = nonzvars[SCIPconsSdpCompLowerTriangPos(i,j)][k];
3377  ajjk = matrixAk[varind1][j * consdata->blocksize + j];
3378  aiik = matrixAk[varind1][i * consdata->blocksize + i];
3379  aijk = matrixAk[varind1][j * consdata->blocksize + i];
3380 
3381  if ( ! SCIPisZero(scip, -cii * ajjk - cjj * aiik + cij * aijk) )
3382  {
3383  linvars[lincnt] = consdata->vars[varind1];
3384  lincoefs[lincnt] = -cii * ajjk - cjj * aiik + cij * aijk;
3385  ++lincnt;
3386  }
3387 
3388  for (l = 0; l < k; ++l)
3389  {
3390  varind2 = nonzvars[SCIPconsSdpCompLowerTriangPos(i,j)][l];
3391  ajjl = matrixAk[varind2][j * consdata->blocksize + j];
3392  aiil = matrixAk[varind2][i * consdata->blocksize + i];
3393  aijl = matrixAk[varind2][j * consdata->blocksize + i];
3394 
3395  if ( ! SCIPisZero(scip, aiik * ajjl + ajjk * aiil - 2 * aijk * aijl) )
3396  {
3397  quadvars1[quadcnt] = consdata->vars[varind1];
3398  quadvars2[quadcnt] = consdata->vars[varind2];
3399  quadcoefs[quadcnt] = aiik * ajjl + ajjk * aiil - 2 * aijk * aijl;
3400  ++quadcnt;
3401  }
3402  }
3403 
3404  /* case l == k needs special treatment */
3405  if ( ! SCIPisZero(scip, aiik * ajjk - aijk * aijk) )
3406  {
3407  quadvars1[quadcnt] = consdata->vars[varind1];
3408  quadvars2[quadcnt] = consdata->vars[varind1];
3409  quadcoefs[quadcnt] = aiik * ajjk - aijk * aijk;
3410  ++quadcnt;
3411  }
3412  }
3413  assert( quadcnt <= consdata->nvars * consdata->nvars );
3414  assert( lincnt <= consdata->nvars );
3415 
3416  lhs = cij * cij - cii * cjj;
3417 
3418  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "quadcons#%d#%d#%d", i, j, c);
3419 
3420  /* create quadratic constraint */
3421 #if ( SCIP_VERSION >= 800 || ( SCIP_VERSION < 800 && SCIP_APIVERSION >= 100 ) )
3422  SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, &quadcons, name, lincnt, linvars, lincoefs, quadcnt, quadvars1, quadvars2, quadcoefs, lhs, lhs,
3423  TRUE, /* initial */
3424  TRUE, /* separate */
3425  TRUE, /* enforce */
3426  TRUE, /* check */
3427  TRUE, /* propagate */
3428  FALSE, /* local */
3429  FALSE, /* modifiable */
3430  FALSE, /* dynamic */
3431  TRUE) ); /* removable */
3432 #else
3433  SCIP_CALL( SCIPcreateConsQuadratic(scip, &quadcons, name, lincnt, linvars, lincoefs, quadcnt, quadvars1, quadvars2, quadcoefs, lhs, lhs,
3434  TRUE, /* initial */
3435  TRUE, /* separate */
3436  TRUE, /* enforce */
3437  TRUE, /* check */
3438  TRUE, /* propagate */
3439  FALSE, /* local */
3440  FALSE, /* modifiable */
3441  FALSE, /* dynamic */
3442  TRUE) ); /* removable */
3443 #endif
3444 
3445 #ifdef SCIP_MORE_DEBUG
3446  SCIP_CALL( SCIPprintCons(scip, quadcons, NULL) );
3447  SCIPinfoMessage(scip, NULL, "\n");
3448 #endif
3449 
3450  SCIP_CALL( SCIPaddCons(scip, quadcons) );
3451  SCIP_CALL( SCIPreleaseCons(scip, &quadcons) );
3452  ++(*naddconss);
3453  }
3454  }
3455 
3456  for (i = blocksize - 1; i >= 0; --i)
3457  {
3458  for (j = i; j >= 0; --j)
3459  SCIPfreeBufferArray(scip, &nonzvars[SCIPconsSdpCompLowerTriangPos(i,j)]);
3460  }
3461 
3462  SCIPfreeBufferArray(scip, &nonzvars);
3463  SCIPfreeBufferArray(scip, &nnonzvars);
3464 
3465  for (i = consdata->nvars - 1; i >= 0; --i)
3466  SCIPfreeBufferArray(scip, &matrixAk[i]);
3467 
3468  SCIPfreeBufferArray(scip, &matrixAk);
3469  SCIPfreeBufferArray(scip, &lincoefs);
3470  SCIPfreeBufferArray(scip, &quadcoefs);
3471  SCIPfreeBufferArray(scip, &linvars);
3472  SCIPfreeBufferArray(scip, &quadvars2);
3473  SCIPfreeBufferArray(scip, &quadvars1);
3474  SCIPfreeBufferArray(scip, &constmatrix);
3475  }
3476  consdata->addedquadcons = TRUE;
3477  }
3478 
3479  return SCIP_OKAY;
3480 }
3481 
3482 
3484 static
3485 SCIP_RETCODE move_1x1_blocks_to_lp(
3486  SCIP* scip,
3487  SCIP_CONSHDLR* conshdlr,
3488  SCIP_CONS** conss,
3489  int nconss,
3490  int* naddconss,
3491  int* ndelconss,
3492  int* nchgbds,
3493  SCIP_Bool* infeasible
3494  )
3495 {
3496  char cutname[SCIP_MAXSTRLEN];
3497  SCIP_CONSDATA* consdata;
3498  SCIP_CONSHDLRDATA* conshdlrdata;
3499  SCIP_CONS* cons;
3500  SCIP_VAR** vars;
3501  SCIP_Real* coeffs;
3502  SCIP_Real rhs;
3503  int nnonz;
3504  int nvars;
3505  int i;
3506  int j;
3507  int v;
3508 #ifndef NDEBUG
3509  int snprintfreturn; /* used to assert the return code of snprintf */
3510 #endif
3511 
3512  assert( scip != NULL );
3513  assert( conshdlr != NULL );
3514  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 || strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLRRANK1_NAME) == 0 );
3515  assert( infeasible != NULL );
3516 
3517  *infeasible = FALSE;
3518 
3519  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3520  assert( conshdlrdata != NULL );
3521 
3522  for (i = 0; i < nconss && !(*infeasible); ++i)
3523  {
3524  consdata = SCIPconsGetData(conss[i]);
3525  assert( consdata != NULL );
3526 
3527  /* if there is a 1x1 SDP-Block */
3528  if ( consdata->blocksize == 1 )
3529  {
3530  int cnt = 0;
3531 
3532  nvars = consdata->nvars;
3533  nnonz = consdata->nnonz;
3534  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
3535  SCIP_CALL( SCIPallocBufferArray(scip, &coeffs, nnonz) );
3536 
3537  /* get all lhs-entries */
3538  for (v = 0; v < nvars; v++)
3539  {
3540  assert( consdata->nvarnonz[v] <= 1 ); /* in a 1x1 block there may be at most one entry per variable */
3541 
3542  for (j = 0; j < consdata->nvarnonz[v]; j++)
3543  {
3544  assert( consdata->col[v][j] == 0 && consdata->row[v][j] == 0 ); /* if the block has size 1, all entries should have row and col equal to 0 */
3545  if ( ! SCIPisZero(scip, consdata->val[v][j]) )
3546  {
3547  coeffs[cnt] = consdata->val[v][j];
3548  vars[cnt++] = consdata->vars[v];
3549  }
3550  }
3551  }
3552 
3553  /* get rhs */
3554  assert( consdata->constnnonz <= 1 ); /* the 1x1 constant matrix may only have one entry */
3555 
3556  rhs = (consdata->constnnonz == 1) ? consdata->constval[0] : 0.0; /* if this one entry is not 0, than this is the rhs, otherwise it's 0 */
3557 
3558  /* if there is more than one nonzero left-hand-side-entry, add a linear constraint, otherwise update the variable bound */
3559  if ( cnt > 1 )
3560  {
3561  /* add new linear cons */
3562 #ifndef NDEBUG
3563  snprintfreturn = SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "1x1block_%d", ++(conshdlrdata->n1x1blocks));
3564  assert( snprintfreturn < SCIP_MAXSTRLEN ); /* check whether name fits into string */
3565 #else
3566  (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "1x1block_%d", ++(conshdlrdata->n1x1blocks));
3567 #endif
3568 
3569  SCIP_CALL( SCIPcreateConsLinear(scip, &cons, cutname, cnt, vars, coeffs, rhs, SCIPinfinity(scip),
3570  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE) );
3571 
3572  SCIP_CALL( SCIPaddCons(scip, cons) );
3573 #ifdef SCIP_MORE_DEBUG
3574  SCIPinfoMessage(scip, NULL, "Added lp-constraint:\n");
3575  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
3576  SCIPinfoMessage(scip, NULL, "\n");
3577 #endif
3578  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
3579 
3580  (*naddconss)++;
3581  }
3582  else if ( cnt == 1 )
3583  {
3584  SCIP_Bool tightened;
3585 
3586  /* try to tighten bound */
3587  if ( SCIPisPositive(scip, coeffs[0]) )
3588  {
3589  SCIP_CALL( SCIPtightenVarLb(scip, vars[0], rhs / coeffs[0], FALSE, infeasible, &tightened) );
3590  if ( tightened )
3591  {
3592  SCIPdebugMsg(scip, "Tightend lower bound of <%s> to %g because of diagonal values of SDP-constraint %s!\n",
3593  SCIPvarGetName(vars[0]), SCIPvarGetLbGlobal(vars[0]), SCIPconsGetName(conss[i]));
3594  ++(*nchgbds);
3595  }
3596  }
3597  else
3598  {
3599  assert( SCIPisNegative(scip, coeffs[0]) );
3600  SCIP_CALL( SCIPtightenVarUb(scip, vars[0], rhs / coeffs[0], FALSE, infeasible, &tightened) );
3601  if ( tightened )
3602  {
3603  SCIPdebugMsg(scip, "Tightend upper bound of <%s> to %g because of diagonal values of SDP-constraint %s!\n",
3604  SCIPvarGetName(vars[0]), SCIPvarGetUbGlobal(vars[0]), SCIPconsGetName(conss[i]));
3605  ++(*nchgbds);
3606  }
3607  }
3608  }
3609  else
3610  {
3611  assert( cnt == 0 );
3612  SCIPdebugMsg(scip, "Detected 1x1 SDP-block without any nonzero coefficients \n");
3613  if ( SCIPisFeasGT(scip, rhs, 0.0) )
3614  {
3615  SCIPdebugMsg(scip, "Detected infeasibility in 1x1 SDP-block without any nonzero coefficients but with strictly positive rhs\n");
3616  *infeasible = TRUE;
3617  }
3618  }
3619 
3620  /* delete old 1x1 sdpcone */
3621  SCIP_CALL( SCIPdelCons(scip, conss[i]) );
3622  (*ndelconss)++;
3623 
3624  SCIPfreeBufferArray(scip, &coeffs);
3625  SCIPfreeBufferArray(scip, &vars);
3626  }
3627  }
3628  return SCIP_OKAY;
3629 }
3630 
3632 static
3633 SCIP_RETCODE unlockVar(
3634  SCIP* scip,
3635  SCIP_CONSDATA* consdata,
3636  int v
3637  )
3638 {
3639  assert( scip != NULL );
3640  assert( consdata != NULL );
3641  assert( 0 <= v && v < consdata->nvars );
3642 
3643  if ( consdata->locks != NULL )
3644  {
3645  assert( consdata->locks[v] == -2 || consdata->locks[v] == -1 || consdata->locks[v] == 0 || consdata->locks[v] == 1 );
3646 
3647  if ( consdata->locks[v] == 1 )
3648  {
3649  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[v], SCIP_LOCKTYPE_MODEL, 0, -1) );
3650  }
3651  else if ( consdata->locks[v] == - 1 )
3652  {
3653  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[v], SCIP_LOCKTYPE_MODEL, -1, 0) );
3654  }
3655  else if ( consdata->locks[v] == 0 )
3656  {
3657  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[v], SCIP_LOCKTYPE_MODEL, -1, -1) );
3658  }
3659  }
3660 
3661  return SCIP_OKAY;
3662 }
3663 
3665 static
3666 SCIP_RETCODE updateVarLocks(
3667  SCIP* scip,
3668  SCIP_CONS* cons,
3669  int v
3670  )
3671 {
3672  SCIP_CONSDATA* consdata;
3673  SCIP_Real eigenvalue;
3674  SCIP_Real* Aj;
3675  int blocksize;
3676  int newlock = -2;
3677 
3678  assert( scip != NULL );
3679  assert( cons != NULL );
3680 
3681  consdata = SCIPconsGetData(cons);
3682  assert( consdata != NULL );
3683  assert( consdata->locks != NULL );
3684  assert( 0 <= v && v < consdata->nvars );
3685 
3686  /* rank-1 constraints are always up- and down-locked */
3687  if ( consdata->rankone )
3688  {
3689  SCIP_CALL( unlockVar(scip, consdata, v) );
3690  consdata->locks[v] = 0;
3691  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[v], SCIP_LOCKTYPE_MODEL, 1, 1) );
3692  consdata->initallmatricespsd = FALSE; /* needs to be recomputed */
3693  return SCIP_OKAY;
3694  }
3695 
3696  blocksize = consdata->blocksize;
3697  SCIP_CALL( SCIPallocBufferArray(scip, &Aj, blocksize * blocksize) );
3698 
3699  SCIP_CALL( SCIPconsSdpGetFullAj(scip, cons, v, Aj) );
3700 
3701  /* compute new lock as in consLockSdp */
3702  SCIP_CALL( SCIPlapackComputeIthEigenvalue(SCIPbuffer(scip), FALSE, blocksize, Aj, 1, &eigenvalue, NULL) );
3703  if ( SCIPisNegative(scip, eigenvalue) )
3704  {
3705  newlock = 1; /* up-lock */
3706  consdata->allmatricespsd = FALSE;
3707  }
3708 
3709  /* @todo check whether one can set allmatrices to true */
3710  if ( SCIPisPositive(scip, eigenvalue) )
3711  newlock = -1; /* down-lock */
3712  else
3713  {
3714  consdata->allmatricespsd = FALSE;
3715  SCIP_CALL( SCIPlapackComputeIthEigenvalue(SCIPbuffer(scip), FALSE, blocksize, Aj, blocksize, &eigenvalue, NULL) );
3716  if ( SCIPisPositive(scip, eigenvalue) )
3717  {
3718  if ( newlock == 1 )
3719  newlock = 0; /* up- and down-lock */
3720  else
3721  newlock = -1; /* down-lock */
3722  }
3723  }
3724 
3725  SCIPfreeBufferArray(scip, &Aj);
3726 
3727  /* if new lock is not equal to the old one, unlock variable and add new locks */
3728  if ( newlock != consdata->locks[v] )
3729  {
3730  SCIP_CALL( unlockVar(scip, consdata, v) );
3731  if ( newlock == 1 ) /* up-lock */
3732  {
3733  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[v], SCIP_LOCKTYPE_MODEL, 0, 1) );
3734  }
3735  else if ( newlock == -1 ) /* down-lock */
3736  {
3737  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[v], SCIP_LOCKTYPE_MODEL, 1, 0) );
3738  }
3739  else if ( newlock == 0 ) /* up and down lock */
3740  {
3741  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[v], SCIP_LOCKTYPE_MODEL, 1, 1) );
3742  }
3743  else
3744  assert( newlock == -2 );
3745 
3746  consdata->locks[v] = newlock;
3747  }
3748 
3749  return SCIP_OKAY;
3750 }
3751 
3752 #ifndef NDEBUG
3753 
3754 static
3755 SCIP_RETCODE checkVarsLocks(
3756  SCIP* scip,
3757  SCIP_CONS* cons
3758  )
3759 {
3760  SCIP_CONSDATA* consdata;
3761  SCIP_Real* Aj;
3762  int blocksize;
3763  int v;
3764 
3765  assert( scip != NULL );
3766  assert( cons != NULL );
3767 
3768  consdata = SCIPconsGetData(cons);
3769  assert( consdata != NULL );
3770  assert( consdata->locks != NULL );
3771 
3772  /* rank-1 constraints should always be up- and down-locked */
3773  if ( consdata->rankone )
3774  {
3775  for (v = 0; v < consdata->nvars; ++v)
3776  assert( consdata->locks[v] == 0 );
3777  return SCIP_OKAY;
3778  }
3779 
3780  blocksize = consdata->blocksize;
3781  SCIP_CALL( SCIPallocBufferArray(scip, &Aj, blocksize * blocksize) );
3782 
3783  for (v = 0; v < consdata->nvars; ++v)
3784  {
3785  SCIP_Real eigenvalue;
3786  int newlock = -2;
3787 
3788  SCIP_CALL( SCIPconsSdpGetFullAj(scip, cons, v, Aj) );
3789 
3790  /* compute new lock as in consLockSdp */
3791  SCIP_CALL( SCIPlapackComputeIthEigenvalue(SCIPbuffer(scip), FALSE, blocksize, Aj, 1, &eigenvalue, NULL) );
3792  if ( SCIPisNegative(scip, eigenvalue) )
3793  newlock = 1; /* up-lock */
3794 
3795  if ( SCIPisPositive(scip, eigenvalue) )
3796  newlock = -1; /* down-lock */
3797  else
3798  {
3799  SCIP_CALL( SCIPlapackComputeIthEigenvalue(SCIPbuffer(scip), FALSE, blocksize, Aj, blocksize, &eigenvalue, NULL) );
3800  if ( SCIPisPositive(scip, eigenvalue) )
3801  {
3802  if ( newlock == 1 )
3803  newlock = 0; /* up- and down-lock */
3804  else
3805  newlock = -1; /* down-lock */
3806  }
3807  }
3808 
3809  assert( newlock == consdata->locks[v] );
3810  }
3811 
3812  SCIPfreeBufferArray(scip, &Aj);
3813 
3814  return SCIP_OKAY;
3815 }
3816 #endif
3817 
3819 static
3820 SCIP_RETCODE multiaggrVar(
3821  SCIP* scip,
3822  SCIP_CONS* cons,
3823  int v,
3824  SCIP_VAR** aggrvars,
3825  SCIP_Real* scalars,
3826  int naggrvars,
3827  SCIP_Real constant,
3828  int* savedcol,
3829  int* savedrow,
3830  SCIP_Real* savedval,
3831  int* nfixednonz,
3832  int* vararraylength
3833  )
3834 {
3835  SCIP_CONSDATA* consdata;
3836  SCIP_Real* vals;
3837  int* rows;
3838  int* cols;
3839  int nvarnonz;
3840  int aggrind;
3841  int aggrtargetlength;
3842  int globalnvars;
3843  int i;
3844 
3845  assert( scip != NULL );
3846  assert( cons != NULL );
3847  assert( scalars != NULL );
3848  assert( naggrvars > 0 );
3849  assert( savedcol != NULL );
3850  assert( savedrow != NULL );
3851  assert( savedval != NULL );
3852  assert( nfixednonz != NULL );
3853 
3854  consdata = SCIPconsGetData(cons);
3855  assert( consdata != NULL );
3856  assert( consdata->locks != NULL );
3857  assert( 0 <= v && v < consdata->nvars );
3858 
3859  /* unlock variable */
3860  SCIP_CALL( unlockVar(scip, consdata, v) );
3861 
3862  /* save matrix of variable v (will be freed later) */
3863  rows = consdata->row[v];
3864  cols = consdata->col[v];
3865  vals = consdata->val[v];
3866  nvarnonz = consdata->nvarnonz[v];
3867 
3868  /* Sort matrix of variable v by nondecreasing row and then col to make merging below faster. */
3869  SCIPsdpVarfixerSortRowCol(rows, cols, vals, nvarnonz);
3870 
3871  /* fill the empty spot of the (multi-)aggregated variable with the last variable of this constraint (since variables do not have to be sorted) */
3872  SCIP_CALL( SCIPreleaseVar(scip, &consdata->vars[v]) );
3873  consdata->col[v] = consdata->col[consdata->nvars - 1];
3874  consdata->row[v] = consdata->row[consdata->nvars - 1];
3875  consdata->val[v] = consdata->val[consdata->nvars - 1];
3876  consdata->nvarnonz[v] = consdata->nvarnonz[consdata->nvars - 1];
3877  consdata->vars[v] = consdata->vars[consdata->nvars - 1];
3878  consdata->locks[v] = consdata->locks[consdata->nvars - 1];
3879  (consdata->nvars)--;
3880 
3881  /* iterate over all variables that variable v was aggregated to and insert the corresponding nonzeros */
3882  for (aggrind = 0; aggrind < naggrvars; aggrind++)
3883  {
3884  int aggrconsind = -1;
3885 
3886  assert( ! SCIPisZero(scip, scalars[aggrind]) );
3887 
3888  /* check if the variable already exists in this block */
3889  for (i = 0; i < consdata->nvars; i++)
3890  {
3891  if ( consdata->vars[i] == aggrvars[aggrind] )
3892  {
3893  aggrconsind = i;
3894  break;
3895  }
3896  }
3897 
3898  if ( aggrconsind > -1 )
3899  {
3900  /* if the variable to aggregate to is already part of this sdp-constraint, just add the nonzeros of the old variable to it */
3901 
3902  /* resize the arrays to the maximally needed length */
3903  aggrtargetlength = consdata->nvarnonz[aggrconsind] + nvarnonz;
3904  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(consdata->row[aggrconsind]), consdata->nvarnonz[aggrconsind], aggrtargetlength) );
3905  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(consdata->col[aggrconsind]), consdata->nvarnonz[aggrconsind], aggrtargetlength) );
3906  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(consdata->val[aggrconsind]), consdata->nvarnonz[aggrconsind], aggrtargetlength) );
3907 
3908  /* merge: add scalar times matrix for variable v to aggregated matrix */
3909  SCIP_CALL( SCIPsdpVarfixerMergeArrays(SCIPblkmem(scip), SCIPepsilon(scip), rows, cols, vals, nvarnonz, TRUE,
3910  scalars[aggrind], consdata->row[aggrconsind], consdata->col[aggrconsind],
3911  consdata->val[aggrconsind], &(consdata->nvarnonz[aggrconsind]), aggrtargetlength) );
3912 
3913  /* shrink them again if nonzeros could be combined */
3914  assert( consdata->nvarnonz[aggrconsind] <= aggrtargetlength );
3915  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(consdata->row[aggrconsind]), aggrtargetlength, consdata->nvarnonz[aggrconsind]) );
3916  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(consdata->col[aggrconsind]), aggrtargetlength, consdata->nvarnonz[aggrconsind]) );
3917  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(consdata->val[aggrconsind]), aggrtargetlength, consdata->nvarnonz[aggrconsind]) );
3918 
3919  SCIP_CALL( updateVarLocks(scip, cons, aggrconsind) );
3920  }
3921  else
3922  {
3923  int cnt = 0;
3924 
3925  /* the variable has to be added to this constraint */
3926  SCIPdebugMsg(scip, "adding variable %s to SDP constraint %s because of (multi-)aggregation\n", SCIPvarGetName(aggrvars[aggrind]), SCIPconsGetName(cons));
3927 
3928  /* check if we have to enlarge the arrays */
3929  if ( consdata->nvars == *vararraylength )
3930  {
3931  globalnvars = SCIPgetNVars(scip);
3932 
3933  /* we don't want to enlarge this by one for every variable added, so we immediately set it to the maximum possible size */
3934  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->col, *vararraylength, globalnvars) );
3935  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->row, *vararraylength, globalnvars) );
3936  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->val, *vararraylength, globalnvars) );
3937  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->nvarnonz, *vararraylength, globalnvars) );
3938  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, *vararraylength, globalnvars) );
3939  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->locks, *vararraylength, globalnvars) );
3940  *vararraylength = globalnvars;
3941  }
3942 
3943  /* we insert this variable at the last position, as the ordering doesn't matter */
3944  SCIP_CALL( SCIPcaptureVar(scip, aggrvars[aggrind]) );
3945  consdata->vars[consdata->nvars] = aggrvars[aggrind];
3946 
3947  /* as there were no nonzeros thus far, we can just duplicate the saved arrays to get the nonzeros for the new variable */
3948  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(consdata->col[consdata->nvars]), cols, nvarnonz) );
3949  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(consdata->row[consdata->nvars]), rows, nvarnonz) );
3950 
3951  /* we have to multiply all entries by scalar before inserting them */
3952  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(consdata->val[consdata->nvars]), nvarnonz) );
3953  for (i = 0; i < nvarnonz; i++)
3954  {
3955  /* if both scalar and savedval are small this might become too small */
3956  if ( ! SCIPisZero(scip, scalars[aggrind] * vals[i]) )
3957  consdata->val[consdata->nvars][cnt++] = scalars[aggrind] * vals[i];
3958  }
3959  consdata->nvarnonz[consdata->nvars] = cnt;
3960 
3961  consdata->locks[consdata->nvars] = -2;
3962  consdata->nvars++;
3963  SCIP_CALL( updateVarLocks(scip, cons, consdata->nvars-1) );
3964  }
3965  }
3966 
3967  /* if constant is not 0, insert entries for variable v into a long array of entries that is merged with constant matrix */
3968  if ( ! SCIPisZero(scip, constant) )
3969  {
3970  for (i = 0; i < nvarnonz; i++)
3971  {
3972  savedcol[*nfixednonz] = cols[i];
3973  savedrow[*nfixednonz] = rows[i];
3974  savedval[*nfixednonz] = vals[i] * constant; /* multiply with constant, since this is added to the constant matrix */
3975  (*nfixednonz)++;
3976  }
3977  }
3978 
3979  /* free the memory for the entries of the aggregated variable */
3980  SCIPfreeBlockMemoryArray(scip, &vals, nvarnonz);
3981  SCIPfreeBlockMemoryArray(scip, &rows, nvarnonz);
3982  SCIPfreeBlockMemoryArray(scip, &cols, nvarnonz);
3983 
3984 #ifndef NDEBUG
3985  SCIP_CALL( checkVarsLocks(scip, cons) );
3986 #endif
3987 
3988  return SCIP_OKAY;
3989 }
3990 
3991 
3993 static
3994 SCIP_RETCODE fixAndAggrVars(
3995  SCIP* scip,
3996  SCIP_CONS** conss,
3997  int nconss,
3998  SCIP_Bool aggregate
3999  )
4000 {
4001  SCIP_CONSDATA* consdata;
4002  int i;
4003  int* savedcol;
4004  int* savedrow;
4005  SCIP_Real* savedval;
4006  int c;
4007  int v;
4008  int arraylength;
4009  SCIP_VAR* var;
4010  SCIP_VAR** aggrvars;
4011  SCIP_Real scalar;
4012  SCIP_Real* scalars;
4013  int naggrvars;
4014  SCIP_Real constant;
4015  int requiredsize;
4016  int globalnvars;
4017  int vararraylength;
4018 
4019  /* Loop over all variables once and collect all matrix entries that should be added to the constant matrix in
4020  * savedrow/col/val; this can then be merged with the constant matrix. */
4021 
4022  assert( scip != NULL );
4023  assert( conss != NULL );
4024  assert( nconss >= 0 );
4025 
4026  SCIPdebugMsg(scip, "Calling fixAndAggrVars with aggregate = %u.\n", aggregate);
4027 
4028  for (c = 0; c < nconss; ++c)
4029  {
4030  int nfixednonz = 0;
4031 
4032  assert( conss[c] != NULL );
4033 
4034  consdata = SCIPconsGetData(conss[c]);
4035  assert( consdata != NULL );
4036  assert( consdata->locks != NULL );
4037  assert( consdata->rankone || strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(conss[c])), CONSHDLR_NAME) == 0 );
4038  assert( ! consdata->rankone || strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(conss[c])), CONSHDLRRANK1_NAME) == 0 );
4039 
4040  /* allocate memory to save nonzeros that need to be fixed */
4041  SCIP_CALL( SCIPallocBufferArray(scip, &savedcol, consdata->nnonz) );
4042  SCIP_CALL( SCIPallocBufferArray(scip, &savedrow, consdata->nnonz) );
4043  SCIP_CALL( SCIPallocBufferArray(scip, &savedval, consdata->nnonz) );
4044 
4045  vararraylength = consdata->nvars;
4046  globalnvars = SCIPgetNVars(scip);
4047 
4048  for (v = 0; v < consdata->nvars; v++)/*lint --e{850}*/
4049  {
4050  SCIP_Bool negated = FALSE;
4051 
4052  /* if the variable is negated, get the negation var */
4053  if ( SCIPvarIsBinary(consdata->vars[v]) && SCIPvarIsNegated(consdata->vars[v]) )
4054  {
4055  negated = TRUE;
4056  var = SCIPvarGetNegationVar(consdata->vars[v]);
4057  }
4058  else
4059  var = consdata->vars[v];
4060 
4061  /* check if the variable is fixed in SCIP */
4062  if ( SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED || SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)) )
4063  {
4064  assert( SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)) );
4065 
4066 #ifdef SCIP_MORE_DEBUG
4067  SCIPdebugMsg(scip, "<%s>: Treating globally fixed variable %s with value %f!\n", SCIPconsGetName(conss[c]), SCIPvarGetName(var), SCIPvarGetLbGlobal(var));
4068 #endif
4069 
4070  if ( (! negated && ! SCIPisEQ(scip, SCIPvarGetLbGlobal(var), 0.0)) || (negated && SCIPisEQ(scip, SCIPvarGetLbGlobal(var), 0.0)) )
4071  {
4072  /* the nonzeros are saved to later be inserted into the constant part (this is only done after all nonzeros of fixed variables have been
4073  * assembled, because we need to sort the constant nonzeros and loop over them, which we only want to do once and not once for each fixed
4074  * variable) */
4075  for (i = 0; i < consdata->nvarnonz[v]; i++)
4076  {
4077  savedcol[nfixednonz] = consdata->col[v][i];
4078  savedrow[nfixednonz] = consdata->row[v][i];
4079 
4080  /* this is the final value to add, we no longer have to remember from which variable this comes, minus because we have +A_i but -A_0 */
4081  if ( ! negated )
4082  savedval[nfixednonz] = consdata->val[v][i] * SCIPvarGetLbGlobal(var);
4083  else
4084  savedval[nfixednonz] = consdata->val[v][i]; /* if it is the negation of a variable fixed to zero, this variable is fixed to one */
4085 
4086  nfixednonz++;
4087  consdata->nnonz--;
4088  }
4089  }
4090  else
4091  {
4092  /* if the variable is fixed to zero, the nonzeros will just vanish, so we only reduce the number of nonzeros */
4093  consdata->nnonz -= consdata->nvarnonz[v];
4094  }
4095 
4096  /* free the memory of the corresponding entries in col/row/val */
4097  SCIPfreeBlockMemoryArrayNull(scip, &(consdata->val[v]), consdata->nvarnonz[v]);
4098  SCIPfreeBlockMemoryArrayNull(scip, &(consdata->row[v]), consdata->nvarnonz[v]);
4099  SCIPfreeBlockMemoryArrayNull(scip, &(consdata->col[v]), consdata->nvarnonz[v]);
4100 
4101  /* unlock variable */
4102  SCIP_CALL( unlockVar(scip, consdata, v) );
4103 
4104  /* as the variables don't need to be sorted, we just put the last variable into the empty spot and decrease sizes by one (at the end) */
4105  SCIP_CALL( SCIPreleaseVar(scip, &(consdata->vars[v])) );
4106  if ( v < consdata->nvars -1 )
4107  {
4108  consdata->col[v] = consdata->col[consdata->nvars - 1];
4109  consdata->row[v] = consdata->row[consdata->nvars - 1];
4110  consdata->val[v] = consdata->val[consdata->nvars - 1];
4111  consdata->nvarnonz[v] = consdata->nvarnonz[consdata->nvars - 1];
4112  consdata->vars[v] = consdata->vars[consdata->nvars - 1];
4113  consdata->locks[v] = consdata->locks[consdata->nvars - 1];
4114  }
4115  consdata->nvars--;
4116  v--; /* we need to check again if the variable we just shifted to this position also needs to be fixed */
4117  }
4118  else if ( aggregate && (SCIPvarGetStatus(var) == SCIP_VARSTATUS_AGGREGATED || SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR) )
4119  {
4120  SCIP_CALL( SCIPallocBufferArray(scip, &aggrvars, globalnvars) );
4121  SCIP_CALL( SCIPallocBufferArray(scip, &scalars, globalnvars) );
4122 
4123  /* this is how they should be initialized before calling SCIPgetProbvarLinearSum */
4124  if ( ! negated )
4125  {
4126  aggrvars[0] = consdata->vars[v];
4127  naggrvars = 1;
4128  constant = 0.0;
4129  scalars[0] = 1.0;
4130  }
4131  else
4132  {
4133  /* if this variable is the negation of var, than we look for a representation of 1.0 - var */
4134  aggrvars[0] = consdata->vars[v];
4135  naggrvars = 1;
4136  constant = 1.0;
4137  scalars[0] = -1.0;
4138  }
4139 
4140  /* get the variables this var was aggregated to */
4141  SCIP_CALL( SCIPgetProbvarLinearSum(scip, aggrvars, scalars, &naggrvars, globalnvars, &constant, &requiredsize, TRUE) );
4142  assert( requiredsize <= globalnvars ); /* requiredsize is the number of empty spots in aggrvars needed, globalnvars is the number
4143  * of spots we provided */
4144 
4145  /* in the unlikely event that the multiaggregation reduces to 0 variables, the original one is fixed */
4146  if ( naggrvars == 0 )
4147  {
4148  assert( ! negated );
4149  if ( ! SCIPisZero(scip, constant) )
4150  {
4151  for (i = 0; i < consdata->nvarnonz[v]; i++)
4152  {
4153  savedcol[nfixednonz] = consdata->col[v][i];
4154  savedrow[nfixednonz] = consdata->row[v][i];
4155 
4156  /* this is the final value to add, we no longer have to remember from which variable this comes, minus because we have +A_i but -A_0 */
4157  savedval[nfixednonz] = consdata->val[v][i] * constant;
4158 
4159  nfixednonz++;
4160  consdata->nnonz--;
4161  }
4162  }
4163  else
4164  {
4165  /* if the variable is fixed to zero, the nonzeros will just vanish, so we only reduce the number of nonzeros */
4166  consdata->nnonz -= consdata->nvarnonz[v];
4167  }
4168 
4169  /* free the memory of the corresponding entries in col/row/val */
4170  SCIPfreeBlockMemoryArrayNull(scip, &(consdata->val[v]), consdata->nvarnonz[v]);
4171  SCIPfreeBlockMemoryArrayNull(scip, &(consdata->row[v]), consdata->nvarnonz[v]);
4172  SCIPfreeBlockMemoryArrayNull(scip, &(consdata->col[v]), consdata->nvarnonz[v]);
4173 
4174  /* unlock variable */
4175  SCIP_CALL( unlockVar(scip, consdata, v) );
4176 
4177  /* as the variables don't need to be sorted, we just put the last variable into the empty spot and decrease sizes by one (at the end) */
4178  SCIP_CALL( SCIPreleaseVar(scip, &(consdata->vars[v])) );
4179  if ( v < consdata->nvars -1 )
4180  {
4181  consdata->col[v] = consdata->col[consdata->nvars - 1];
4182  consdata->row[v] = consdata->row[consdata->nvars - 1];
4183  consdata->val[v] = consdata->val[consdata->nvars - 1];
4184  consdata->nvarnonz[v] = consdata->nvarnonz[consdata->nvars - 1];
4185  consdata->vars[v] = consdata->vars[consdata->nvars - 1];
4186  consdata->locks[v] = consdata->locks[consdata->nvars - 1];
4187  }
4188  consdata->nvars--;
4189  v--; /* we need to check again if the variable we just shifted to this position also needs to be fixed */
4190  }
4191  else
4192  {
4193  /* Debugmessages for the (multi-)aggregation */
4194 #ifdef SCIP_DEBUG
4195  if ( SCIPvarGetStatus(consdata->vars[v]) == SCIP_VARSTATUS_AGGREGATED )
4196  SCIPdebugMsg(scip, "aggregating variable %s to ", SCIPvarGetName(var));
4197  else
4198  SCIPdebugMsg(scip, "multiaggregating variable %s to ", SCIPvarGetName(var));
4199  for (i = 0; i < naggrvars; i++)
4200  SCIPdebugMessagePrint(scip, "+ %g %s ", scalars[i], SCIPvarGetName(aggrvars[i]));
4201  SCIPdebugMessagePrint(scip, "+ %g.\n", constant);
4202 #endif
4203 
4204  /* add the nonzeros to the saved-arrays for the constant part, remove the nonzeros for the old variables and add them to the variables this variable
4205  * was (multi-)aggregated to */
4206  SCIP_CALL( multiaggrVar(scip, conss[c], v, aggrvars, scalars, naggrvars, constant, savedcol, savedrow, savedval, &nfixednonz, &vararraylength) );
4207  v--; /* we need to check again if the variable we just shifted to this position also needs to be fixed */
4208  }
4209 
4210  SCIPfreeBufferArray(scip, &aggrvars);
4211  SCIPfreeBufferArray(scip, &scalars);
4212  }
4213  else if ( negated && (SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN) && aggregate )
4214  {
4215  /* if var1 is the negation of var2, then this is equivalent to it being aggregated to -var2 + 1 = 1 - var2 */
4216 
4217  SCIPdebugMsg(scip, "Changing variable %s to negation of variable <%s>!\n", SCIPvarGetName(consdata->vars[v]), SCIPvarGetName(var));
4218 
4219  scalar = -1.0;
4220 
4221  SCIP_CALL( multiaggrVar(scip, conss[c], v, &var, &scalar, 1, 1.0, savedcol, savedrow, savedval, &nfixednonz, &vararraylength) );
4222  v--; /* we need to check again if the variable we just shifted to this position also needs to be fixed */
4223  }
4224  }
4225 
4226  /* shrink the variable arrays if they were enlarged too much (or more vars were removed than added) */
4227  assert( consdata->nvars <= vararraylength );
4228  if ( consdata->nvars < vararraylength )
4229  {
4230  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->col, vararraylength, consdata->nvars) );
4231  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->row, vararraylength, consdata->nvars) );
4232  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->val, vararraylength, consdata->nvars) );
4233  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->nvarnonz, vararraylength, consdata->nvars) );
4234  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, vararraylength, consdata->nvars) );
4235  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->locks, vararraylength, consdata->nvars) );
4236  }
4237 
4238  /* allocate the maximally needed memory for inserting the fixed variables into the constant part */
4239  arraylength = consdata->constnnonz + nfixednonz;
4240  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(consdata->constcol), consdata->constnnonz, arraylength) );
4241  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(consdata->constrow), consdata->constnnonz, arraylength) );
4242  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(consdata->constval), consdata->constnnonz, arraylength) );
4243 
4244  /* insert the fixed variables into the constant arrays, as we have +A_i but -A_0 we mutliply them by -1 */
4245  SCIP_CALL( SCIPsdpVarfixerMergeArrays(SCIPblkmem(scip), SCIPepsilon(scip), savedrow, savedcol, savedval, nfixednonz, FALSE, -1.0, consdata->constrow,
4246  consdata->constcol, consdata->constval, &(consdata->constnnonz), arraylength) );
4247 
4248  assert( consdata->constnnonz <= arraylength ); /* the allocated memory should always be sufficient */
4249 
4250  /* shrink the arrays if nonzeros could be combined */
4251  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(consdata->constcol), arraylength, consdata->constnnonz) );
4252  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(consdata->constrow), arraylength, consdata->constnnonz) );
4253  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(consdata->constval), arraylength, consdata->constnnonz) );
4254 
4255  /* free the saved arrays */
4256  SCIPfreeBufferArray(scip, &savedval);
4257  SCIPfreeBufferArray(scip, &savedrow);
4258  SCIPfreeBufferArray(scip, &savedcol);
4259 
4260  /* recompute sdpnnonz */
4261  consdata->nnonz = 0;
4262  for (v = 0; v < consdata->nvars; v++)
4263  consdata->nnonz += consdata->nvarnonz[v];
4264  }
4265 
4266  return SCIP_OKAY;
4267 }
4268 
4270 static
4271 SCIP_RETCODE analyzeConflict(
4272  SCIP* scip,
4273  SCIP_CONS* cons,
4274  int diags,
4275  int diagt,
4276  int pos,
4277  SCIP_Bool upperbound,
4278  SCIP_Bool usepos
4279  )
4280 {
4281  SCIP_CONSDATA* consdata;
4282  SCIP_Bool success;
4283 
4284  assert( scip != NULL );
4285  assert( cons != NULL );
4286 
4287  consdata = SCIPconsGetData(cons);
4288  assert( consdata != NULL );
4289 
4290  SCIPdebugMsg(scip, "Analyzing a conflict during propagation\n");
4291 
4292  /* conflict analysis can only be applied in solving stage and if it is applicable */
4293  if ( (SCIPgetStage(scip) != SCIP_STAGE_SOLVING && ! SCIPinProbing(scip)) || ! SCIPisConflictAnalysisApplicable(scip) )
4294  return SCIP_OKAY;
4295 
4296  /* initialize conflict analysis, and add all variables of infeasible constraint to conflict candidate queue */
4297  SCIP_CALL( SCIPinitConflictAnalysis(scip, SCIP_CONFTYPE_PROPAGATION, FALSE) );
4298 
4299  assert( consdata->matrixvar != NULL );
4300  assert( consdata->matrixval != NULL );
4301  if ( consdata->matrixvar[diags] != NULL )
4302  {
4303  assert( consdata->matrixval[diags] != SCIP_INVALID );
4304 
4305  if ( consdata->matrixval[diags] > 0.0 )
4306  SCIP_CALL( SCIPaddConflictUb(scip, consdata->matrixvar[diags], NULL) );
4307  else
4308  SCIP_CALL( SCIPaddConflictLb(scip, consdata->matrixvar[diags], NULL) );
4309  }
4310 
4311  if ( consdata->matrixvar[diagt] != NULL )
4312  {
4313  assert( consdata->matrixval[diagt] != SCIP_INVALID );
4314 
4315  if ( consdata->matrixval[diagt] > 0.0 )
4316  SCIP_CALL( SCIPaddConflictUb(scip, consdata->matrixvar[diagt], NULL) );
4317  else
4318  SCIP_CALL( SCIPaddConflictLb(scip, consdata->matrixvar[diagt], NULL) );
4319  }
4320 
4321  if ( usepos )
4322  {
4323  assert( consdata->matrixvar[pos] != NULL);
4324  assert( consdata->matrixval[pos] != SCIP_INVALID);
4325 
4326  if ( upperbound )
4327  SCIP_CALL( SCIPaddConflictUb(scip, consdata->matrixvar[pos], NULL) );
4328  else
4329  SCIP_CALL( SCIPaddConflictLb(scip, consdata->matrixvar[pos], NULL) );
4330  }
4331 
4332  /* analyze the conflict */
4333  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, &success) );
4334 
4335  if ( success )
4336  SCIPdebugMsg(scip, "Succesfully analyzed and resolved conflict!\n");
4337 
4338  return SCIP_OKAY;
4339 }
4340 
4342 static
4343 SCIP_RETCODE propagateUpperBounds(
4344  SCIP* scip,
4345  SCIP_CONS** conss,
4346  int nconss,
4347  SCIP_Bool* infeasible,
4348  int* nprop
4349  )
4350 {
4351  int c;
4352 
4353  assert( infeasible != NULL );
4354  assert( nprop != NULL );
4355 
4356  *infeasible = FALSE;
4357  *nprop = 0;
4358 
4359  for (c = 0; c < nconss; ++c)
4360  {
4361  SCIP_CONSDATA* consdata;
4362  int blocksize;
4363  int i;
4364 
4365  assert( conss[c] != NULL );
4366  consdata = SCIPconsGetData(conss[c]);
4367  blocksize = consdata->blocksize;
4368 
4369  /* build matrix if not yet done */
4370  SCIP_CALL( constructMatrixvar(scip, conss[c], consdata) );
4371  assert( consdata->matrixvar != NULL );
4372  assert( consdata->matrixval != NULL );
4373  assert( consdata->matrixconst != NULL );
4374 
4375  /* search for trace constraint */
4376  if ( consdata->tracebound < -1.5 )
4377  {
4378  SCIP_CONSHDLR* linconshdlr;
4379  linconshdlr = SCIPfindConshdlr(scip, "linear");
4380  if ( linconshdlr != NULL )
4381  {
4382  SCIP_CONS** linconss;
4383  int nlinconss;
4384 
4385  linconss = SCIPconshdlrGetConss(linconshdlr);
4386  nlinconss = SCIPconshdlrGetNConss(linconshdlr);
4387 
4388  for (i = 0; i < nlinconss; ++i)
4389  {
4390  SCIP_Real* linvals;
4391  SCIP_VAR** linvars;
4392  SCIP_Bool coefok = TRUE;
4393  int nlinvars;
4394  int j;
4395 
4396  nlinvars = SCIPgetNVarsLinear(scip, linconss[i]);
4397 
4398  /* if the number of variables is not equal to the dimension, we do not have a trace bound */
4399  if ( nlinvars != consdata->blocksize )
4400  continue;
4401 
4402  linvars = SCIPgetVarsLinear(scip, linconss[i]);
4403  linvals = SCIPgetValsLinear(scip, linconss[i]);
4404 
4405  /* check whether all variables are diagonal entries */
4406  for (j = 0; j < nlinvars; ++j)
4407  {
4408  SCIP_VAR* var;
4409  int k;
4410 
4411  if ( ! SCIPisEQ(scip, linvals[j], 1.0) )
4412  {
4413  coefok = FALSE;
4414  break;
4415  }
4416 
4417  var = linvars[j];
4418  for (k = 0; k < consdata->blocksize; ++k)
4419  {
4420  if ( consdata->matrixvar[k * (k + 1)/2 + k] == var )
4421  break;
4422  }
4423 
4424  if ( k >= consdata->blocksize )
4425  {
4426  SCIPdebugMsg(scip, "Could not find variable <%s>.\n", SCIPvarGetName(linvars[j]));
4427  break;
4428  }
4429  }
4430 
4431  /* did not find variables or coefficients != 1 -> consider next linear constraint */
4432  if ( j < nlinvars || ! coefok )
4433  continue;
4434 
4435  consdata->tracebound = SCIPgetRhsLinear(scip, linconss[i]);
4436  SCIPdebugMsg(scip, "Found tracebound constraint with bound = %g.\n", consdata->tracebound);
4437  break;
4438  }
4439  }
4440  if ( consdata->tracebound < -1.5 )
4441  consdata->tracebound = -1.0;
4442  }
4443 
4444  /* if there is at least one entry that only depends on a single variable */
4445  if ( consdata->nsingle > 0 )
4446  {
4447  int s;
4448  int t;
4449 
4450  /* check all off-diagonal positions */
4451  for (s = 0; s < blocksize; ++s)
4452  {
4453  SCIP_VAR* vars;
4454  SCIP_Real ubs = 0.0;
4455  int diags;
4456 
4457  diags = s * (s + 1)/2 + s;
4458  if ( consdata->matrixval[diags] == SCIP_INVALID ) /*lint !e777*/
4459  continue;
4460 
4461  vars = consdata->matrixvar[diags];
4462  if ( vars != NULL )
4463  {
4464  if ( consdata->matrixval[diags] > 0.0 )
4465  ubs = SCIPvarGetUbLocal(vars);
4466  else
4467  ubs = SCIPvarGetLbLocal(vars);
4468 
4469  if ( SCIPisInfinity(scip, REALABS(ubs)) )
4470  continue;
4471 
4472  ubs *= consdata->matrixval[diags];
4473  }
4474  assert( consdata->matrixconst[diags] != SCIP_INVALID );
4475  assert( ! SCIPisInfinity(scip, ubs) );
4476 
4477  ubs -= consdata->matrixconst[diags];
4478 
4479  for (t = 0; t < s; ++t)
4480  {
4481  SCIP_Bool tightened;
4482  SCIP_VAR* vart;
4483  SCIP_VAR* varst;
4484  SCIP_Real bound;
4485  SCIP_Real ubt = 0.0;
4486  int diagt;
4487  int pos;
4488 
4489  pos = s * (s + 1)/2 + t;
4490  varst = consdata->matrixvar[pos];
4491  if ( varst == NULL || ! SCIPvarIsActive(varst) )
4492  continue;
4493 
4494  diagt = t * (t + 1)/2 + t;
4495  if ( consdata->matrixval[diagt] == SCIP_INVALID ) /*lint !e777*/
4496  continue;
4497 
4498  vart = consdata->matrixvar[diagt];
4499  if ( vart != NULL )
4500  {
4501  if ( consdata->matrixval[diagt] > 0.0 )
4502  ubt = SCIPvarGetUbLocal(vart);
4503  else
4504  ubt = SCIPvarGetLbLocal(vart);
4505 
4506  if ( SCIPisInfinity(scip, REALABS(ubt)) )
4507  continue;
4508 
4509  ubt *= consdata->matrixval[diagt];
4510  }
4511  assert( consdata->matrixconst[diagt] != SCIP_INVALID );
4512  assert( ! SCIPisInfinity(scip, ubt) );
4513 
4514  ubt -= consdata->matrixconst[diagt];
4515 
4516  if ( SCIPisFeasLT(scip, ubs, 0.0) || SCIPisFeasLT(scip, ubt, 0.0) )
4517  {
4518  *infeasible = TRUE;
4519  SCIP_CALL( analyzeConflict(scip, conss[c], diags, diagt, pos, TRUE, FALSE) );
4520  return SCIP_OKAY;
4521  }
4522 
4523  /* compute upper bound without trace bound */
4524  if ( consdata->matrixval[pos] > 0.0 )
4525  bound = (sqrt(ubs * ubt) + consdata->matrixconst[pos]) / consdata->matrixval[pos];
4526  else
4527  bound = (- sqrt(ubs * ubt) + consdata->matrixconst[pos]) / consdata->matrixval[pos];
4528 
4529  /* check for stronger bound with trace bound */
4530  if ( consdata->tracebound > 0.0 )
4531  {
4532  /* Note that tracebound is only computed for a primal SDP, thus it does not need to be retransformed
4533  * to matrix pencil notation. */
4534  if ( consdata->tracebound/2.0 < bound )
4535  bound = consdata->tracebound/2.0;
4536  }
4537 
4538  assert( varst != NULL );
4539  if ( SCIPisFeasLT(scip, bound, SCIPvarGetUbLocal(varst)) )
4540  {
4541  SCIP_CALL( SCIPinferVarUbCons(scip, varst, bound, conss[c], s * blocksize + t, FALSE, infeasible, &tightened) );
4542  if ( *infeasible )
4543  {
4544  SCIPdebugMsg(scip, "Propagation detected infeasibility, call analyzeConfilct.\n");
4545  SCIP_CALL( analyzeConflict(scip, conss[c], diags, diagt, pos, TRUE, TRUE) );
4546  return SCIP_OKAY;
4547  }
4548  if ( tightened )
4549  {
4550  SCIPdebugMsg(scip, "Propagation successfully tightened a bound.\n");
4551  ++(*nprop);
4552  }
4553  }
4554 
4555  /* compute lower bound without trace bound */
4556  if ( consdata->matrixval[pos] > 0.0 )
4557  bound = (- sqrt(ubs * ubt) + consdata->matrixconst[pos]) / consdata->matrixval[pos];
4558  else
4559  bound = (sqrt(ubs * ubt) + consdata->matrixconst[pos]) / consdata->matrixval[pos];
4560 
4561  /* check for stronger bound with trace bound */
4562  if ( consdata->tracebound > 0.0 )
4563  {
4564  if ( -consdata->tracebound/2.0 > bound )
4565  bound = -consdata->tracebound/2.0;
4566  }
4567 
4568  if ( SCIPisFeasGT(scip, bound, SCIPvarGetLbLocal(varst)) )
4569  {
4570  SCIP_CALL( SCIPinferVarLbCons(scip, varst, bound, conss[c], s * blocksize + t, FALSE, infeasible, &tightened) );
4571  if ( *infeasible )
4572  {
4573  SCIPdebugMsg(scip, "Propagation detected infeasibility, call analyzeConfilct.\n");
4574  SCIP_CALL( analyzeConflict(scip, conss[c], diags, diagt, pos, FALSE, TRUE) );
4575  return SCIP_OKAY;
4576  }
4577  if ( tightened )
4578  {
4579  SCIPdebugMsg(scip, "Propagation successfully tightened a bound.\n");
4580  ++(*nprop);
4581  }
4582  }
4583  }
4584  }
4585  }
4586  }
4587 
4588  return SCIP_OKAY;
4589 }
4590 
4591 
4592 #if ( SCIP_VERSION >= 800 || ( SCIP_VERSION < 800 && SCIP_APIVERSION >= 100 ) )
4593 
4595 static
4596 SCIP_DECL_NONLINCONSUPGD(consQuadConsUpgdSdp)
4597 {
4598  char name[SCIP_MAXSTRLEN];
4599  SCIP_CONSHDLR* conshdlr;
4600  SCIP_CONSHDLRDATA* conshdlrdata;
4601  SCIP_CONS* lincons;
4602  SCIP_VAR** linconsvars;
4603  SCIP_Real* linconsvals;
4604  SCIP_Real* linvalsterms;
4605  int nlinvarterms;
4606  int nquadvarterms;
4607  int nbilinterms;
4608  int nlinconsterms;
4609  int j;
4610 
4611  assert( scip != NULL );
4612  assert( cons != NULL );
4613  assert( nupgdconss != NULL );
4614  assert( upgdconss != NULL );
4615 
4616  *nupgdconss = 0;
4617 
4618  /* do not upgrade modifiable/sticking at node constraints */
4619  if ( SCIPconsIsModifiable(cons) || SCIPconsIsStickingAtNode(cons) )
4620  return SCIP_OKAY;
4621 
4622  /* do not run in sub-SCIPs to avoid recursive reformulations due to rank 1 constraints */
4623  if ( SCIPgetSubscipDepth(scip) > 0 )
4624  return SCIP_OKAY;
4625 
4626  /* do not upgrade after a restart */
4627  if ( SCIPgetNRuns(scip) > 1 )
4628  return SCIP_OKAY;
4629 
4630  /* make sure there is enough space to store the replacing constraints */
4631  if ( upgdconsssize < 1 )
4632  {
4633  *nupgdconss = -1;
4634  return SCIP_OKAY;
4635  }
4636 
4637  conshdlr = SCIPfindConshdlr(scip, CONSHDLRRANK1_NAME);
4638  if ( conshdlr == NULL )
4639  {
4640  SCIPerrorMessage("rank 1 SDP constraint handler not found\n");
4641  return SCIP_PLUGINNOTFOUND;
4642  }
4643  assert( conshdlr != NULL );
4644 
4645  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4646  assert( conshdlrdata != NULL );
4647 
4648  /* check whether upgrading should be performed */
4649  if ( ! conshdlrdata->sdpconshdlrdata->upgradequadconss )
4650  return SCIP_OKAY;
4651 
4652  /* we have to collect all variables appearing in quadratic constraints first */
4653  if ( conshdlrdata->sdpconshdlrdata->quadconsvars == NULL )
4654  {
4655  SCIP_CONSHDLR* nonlinearconshdlr;
4656  SCIP_CONS** conss;
4657  int nconss;
4658  int nvars;
4659  int c;
4660  int i;
4661  int nsdpvars = 0;
4662 
4663  int** cols;
4664  int** rows;
4665  SCIP_Real** vals;
4666  SCIP_VAR** vars;
4667  int* nvarnonz;
4668  int nnonz;
4669  int nvarscnt;
4670  int constcol = 0;
4671  int constrow = 0;
4672  SCIP_Real constval = -1.0;
4673  int nquadconss = 0;
4674 
4675  /* todo: The arrays quadconsidx and quadconsvars are needed to check if variables have already been seen in a
4676  quadratic constraint. This could be replaced with a hashmap. */
4677  nvars = SCIPgetNTotalVars(scip);
4678  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &conshdlrdata->sdpconshdlrdata->quadconsidx, nvars) );
4679  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &conshdlrdata->sdpconshdlrdata->quadconsvars, nvars) );
4680  conshdlrdata->sdpconshdlrdata->nquadconsidx = nvars;
4681  for (j = 0; j < nvars; ++j)
4682  conshdlrdata->sdpconshdlrdata->quadconsidx[j] = -1;
4683 
4684  nonlinearconshdlr = SCIPfindConshdlr(scip, "nonlinear");
4685  if ( nonlinearconshdlr == NULL )
4686  {
4687  SCIPerrorMessage("Nonlinear constraint handler not found\n");
4688  return SCIP_PLUGINNOTFOUND;
4689  }
4690  assert( nonlinearconshdlr != NULL );
4691 
4692  conss = SCIPconshdlrGetConss(nonlinearconshdlr);
4693  nconss = SCIPconshdlrGetNConss(nonlinearconshdlr);
4694 
4695  for (c = 0; c < nconss; ++c)
4696  {
4697  SCIP_Bool isquadratic;
4698 
4699  assert( conss[c] != NULL );
4700 
4701  SCIP_CALL( SCIPcheckQuadraticNonlinear(scip, conss[c], &isquadratic) );
4702  if ( ! isquadratic )
4703  continue;
4704 
4705  if ( ! SCIPexprAreQuadraticExprsVariables(SCIPgetExprNonlinear(conss[c])) )
4706  continue;
4707 
4708  ++nquadconss;
4709 
4710  /* Do not perform upgrade, if there are too many quadratic constraints present. */
4711  if ( nquadconss > conshdlrdata->sdpconshdlrdata->maxnvarsquadupgd )
4712  {
4713  SCIPdebugMsg(scip, "There are %d many quadratic constraints present in the problem, thus do not upgrade quadratic constraints to an SDPrank1 constraint.\n", nquadconss);
4714  SCIPfreeBlockMemoryArray(scip, &conshdlrdata->sdpconshdlrdata->quadconsvars, nvars);
4715  SCIPfreeBlockMemoryArray(scip, &conshdlrdata->sdpconshdlrdata->quadconsidx, nvars);
4716  return SCIP_OKAY;
4717  }
4718 
4719 #ifdef SCIP_MORE_DEBUG
4720  SCIPinfoMessage(scip, NULL, "Found quadratic constraint to upgrade:\n");
4721  SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
4722  SCIPinfoMessage(scip, NULL, "\n");
4723 #endif
4724 
4725  SCIPexprGetQuadraticData(SCIPgetExprNonlinear(conss[c]), NULL, NULL, NULL, NULL, &nquadvarterms, &nbilinterms, NULL, NULL);
4726  assert( nquadvarterms + nbilinterms > 0 );
4727 
4728  for (i = 0; i < nquadvarterms; ++i)
4729  {
4730  SCIP_VAR* var;
4731  SCIP_EXPR* expr;
4732  int idx;
4733 
4734  /* get quadratic expression */
4735  SCIPexprGetQuadraticQuadTerm(SCIPgetExprNonlinear(conss[c]), i, &expr, NULL, NULL, NULL, NULL, NULL);
4736 
4737  var = SCIPgetVarExprVar(expr);
4738  assert( var != NULL );
4739  idx = SCIPvarGetIndex(var);
4740  assert( 0 <= idx && idx < nvars );
4741  if ( conshdlrdata->sdpconshdlrdata->quadconsidx[idx] < 0 )
4742  {
4743  conshdlrdata->sdpconshdlrdata->quadconsvars[nsdpvars] = var;
4744  conshdlrdata->sdpconshdlrdata->quadconsidx[idx] = nsdpvars++;
4745  }
4746  }
4747 
4748  for (i = 0; i < nbilinterms; ++i)
4749  {
4750  SCIP_VAR* var;
4751  SCIP_EXPR* expr1;
4752  SCIP_EXPR* expr2;
4753  int idx;
4754 
4755  /* get bilinear expression */
4756  SCIPexprGetQuadraticBilinTerm(SCIPgetExprNonlinear(conss[c]), i, &expr1, &expr2, NULL, NULL, NULL);
4757 
4758  var = SCIPgetVarExprVar(expr1);
4759  assert( var != NULL );
4760  idx = SCIPvarGetIndex(var);
4761  assert( 0 <= idx && idx < nvars );
4762  if ( conshdlrdata->sdpconshdlrdata->quadconsidx[idx] < 0 )
4763  {
4764  conshdlrdata->sdpconshdlrdata->quadconsvars[nsdpvars] = var;
4765  conshdlrdata->sdpconshdlrdata->quadconsidx[idx] = nsdpvars++;
4766  }
4767 
4768  var = SCIPgetVarExprVar(expr2);
4769  assert( var != NULL );
4770  idx = SCIPvarGetIndex(var);
4771  assert( 0 <= idx && idx < nvars );
4772  if ( conshdlrdata->sdpconshdlrdata->quadconsidx[idx] < 0 )
4773  {
4774  conshdlrdata->sdpconshdlrdata->quadconsvars[nsdpvars] = var;
4775  conshdlrdata->sdpconshdlrdata->quadconsidx[idx] = nsdpvars++;
4776  }
4777  }
4778  }
4779 
4780  /* do not perform upgrade, if no sdpvars have been added */
4781  if ( nsdpvars == 0 )
4782  {
4783  SCIPdebugMsg(scip, "No sdp variables have been added\n");
4784  SCIPfreeBlockMemoryArray(scip, &conshdlrdata->sdpconshdlrdata->quadconsvars, nvars);
4785  SCIPfreeBlockMemoryArray(scip, &conshdlrdata->sdpconshdlrdata->quadconsidx, nvars);
4786  return SCIP_OKAY;
4787  }
4788 
4789  /* do not perform upgrade, if there are too many variables in the quadratic constraints, since we need sdpvars *
4790  sdpvars many variables for the (dual) SDPrank1 constraint */
4791  if ( nsdpvars > conshdlrdata->sdpconshdlrdata->maxnvarsquadupgd )
4792  {
4793  SCIPdebugMsg(scip, "There are %d many variables present in the quadratic constraints, thus do not upgrade quadratic constraints to an SDPrank1 constraint\n", nsdpvars);
4794  SCIPfreeBlockMemoryArray(scip, &conshdlrdata->sdpconshdlrdata->quadconsvars, nvars);
4795  SCIPfreeBlockMemoryArray(scip, &conshdlrdata->sdpconshdlrdata->quadconsidx, nvars);
4796  return SCIP_OKAY;
4797  }
4798 
4799  /* create bilinear variables */
4800  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &conshdlrdata->sdpconshdlrdata->X, nsdpvars) );
4801  conshdlrdata->sdpconshdlrdata->nsdpvars = nsdpvars;
4802 
4803  for (i = 0; i < nsdpvars; ++i)
4804  {
4805  SCIP_Real lb1;
4806  SCIP_Real ub1;
4807  SCIP_VAR* var1;
4808 
4809  var1 = conshdlrdata->sdpconshdlrdata->quadconsvars[i];
4810  assert( var1 != NULL );
4811  lb1 = SCIPvarGetLbGlobal(var1);
4812  ub1 = SCIPvarGetUbGlobal(var1);
4813 
4814  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &conshdlrdata->sdpconshdlrdata->X[i], nsdpvars) );
4815 
4816  for (j = 0; j <= i; ++j)
4817  {
4818  SCIP_VARTYPE vartype;
4819  SCIP_VAR* var2;
4820  SCIP_Real lb2;
4821  SCIP_Real ub2;
4822  SCIP_Real lb;
4823  SCIP_Real ub;
4824 
4825  var2 = conshdlrdata->sdpconshdlrdata->quadconsvars[j];
4826  assert( var2 != NULL );
4827  lb2 = SCIPvarGetLbGlobal(var2);
4828  ub2 = SCIPvarGetUbGlobal(var2);
4829 
4830  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "X%d#%d", i, j);
4831 
4832  lb = MIN3(lb1 * lb2, lb1 * ub2, ub1 * lb2);
4833  lb = MIN(lb, ub1 * ub2);
4834  ub = MAX3(lb1 * lb2, lb1 * ub2, ub1 * lb2);
4835  ub = MAX(ub, ub1 * ub2);
4836 
4837  if ( SCIPvarIsBinary(var1) && SCIPvarIsBinary(var2) )
4838  vartype = SCIP_VARTYPE_BINARY;
4839  else if ( SCIPvarIsIntegral(var1) && SCIPvarIsIntegral(var2) )
4840  vartype = SCIP_VARTYPE_INTEGER;
4841  else
4842  vartype = SCIP_VARTYPE_CONTINUOUS;
4843 
4844  SCIP_CALL( SCIPcreateVarBasic(scip, &(conshdlrdata->sdpconshdlrdata->X[i][j]), name, lb, ub, 0.0, vartype) );
4845  SCIP_CALL( SCIPaddVar(scip, conshdlrdata->sdpconshdlrdata->X[i][j]) );
4846  }
4847  }
4848 
4849  /* fill SDP data */
4850  nnonz = nsdpvars + nsdpvars * (nsdpvars + 1) / 2;
4851  SCIP_CALL( SCIPallocBufferArray(scip, &cols, nnonz) );
4852  SCIP_CALL( SCIPallocBufferArray(scip, &rows, nnonz) );
4853  SCIP_CALL( SCIPallocBufferArray(scip, &vals, nnonz) );
4854  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nnonz) );
4855  SCIP_CALL( SCIPallocBufferArray(scip, &nvarnonz, nnonz) );
4856 
4857  /* first the terms for the original variables */
4858  for (j = 0; j < nsdpvars; ++j)
4859  {
4860  SCIP_CALL( SCIPallocBufferArray(scip, &cols[j], 1) );
4861  SCIP_CALL( SCIPallocBufferArray(scip, &rows[j], 1) );
4862  SCIP_CALL( SCIPallocBufferArray(scip, &vals[j], 1) );
4863  nvarnonz[j] = 1;
4864  cols[j][0] = 0;
4865  rows[j][0] = 1 + j;
4866  vals[j][0] = 1.0;
4867  vars[j] = conshdlrdata->sdpconshdlrdata->quadconsvars[j];
4868  }
4869 
4870  /* now the terms for the bilinear terms */
4871  nvarscnt = nsdpvars;
4872  for (i = 0; i < nsdpvars; ++i)
4873  {
4874  for (j = 0; j <= i; ++j)
4875  {
4876  SCIP_CALL( SCIPallocBufferArray(scip, &cols[nvarscnt], 1) );
4877  SCIP_CALL( SCIPallocBufferArray(scip, &rows[nvarscnt], 1) );
4878  SCIP_CALL( SCIPallocBufferArray(scip, &vals[nvarscnt], 1) );
4879  nvarnonz[nvarscnt] = 1;
4880  cols[nvarscnt][0] = 1 + j;
4881  rows[nvarscnt][0] = 1 + i;
4882  vals[nvarscnt][0] = 1.0;
4883  vars[nvarscnt] = conshdlrdata->sdpconshdlrdata->X[i][j];
4884  ++nvarscnt;
4885  }
4886  }
4887  assert( nvarscnt == nsdpvars + nsdpvars * (nsdpvars + 1)/2 );
4888 
4889  /* create corresponding rank 1 SDP constraint */
4890  if ( conshdlrdata->sdpconshdlrdata->upgradekeepquad )
4891  {
4892  SCIP_CALL( SCIPcreateConsSdp(scip, &conshdlrdata->sdpconshdlrdata->sdpcons, "QuadraticSDPcons", nvarscnt, nvarscnt, 1 + nsdpvars, nvarnonz,
4893  cols, rows, vals, vars, 1, &constcol, &constrow, &constval, FALSE) );
4894  SCIP_CALL( SCIPaddCons(scip, conshdlrdata->sdpconshdlrdata->sdpcons) );
4895  }
4896  else
4897  {
4898  SCIP_CALL( SCIPcreateConsSdpRank1(scip, &conshdlrdata->sdpconshdlrdata->sdpcons, "QuadraticSDPrank1cons", nvarscnt, nvarscnt, 1 + nsdpvars, nvarnonz,
4899  cols, rows, vals, vars, 1, &constcol, &constrow, &constval, FALSE) );
4900  SCIP_CALL( SCIPaddCons(scip, conshdlrdata->sdpconshdlrdata->sdpcons) );
4901  }
4902 
4903 #ifdef SCIP_MORE_DEBUG
4904  SCIPinfoMessage(scip, NULL, "In upgrade of quadratic constraint the following SDPrank1 constraint has been added:\n");
4905  SCIP_CALL( SCIPprintCons(scip, conshdlrdata->sdpconshdlrdata->sdpcons, NULL) );
4906  SCIPinfoMessage(scip, NULL, "\n");
4907 #endif
4908 
4909  /* free local memory */
4910  for (j = nvarscnt - 1; j >= 0; --j)
4911  {
4912  SCIPfreeBufferArray(scip, &vals[j]);
4913  SCIPfreeBufferArray(scip, &rows[j]);
4914  SCIPfreeBufferArray(scip, &cols[j]);
4915  }
4916  SCIPfreeBufferArray(scip, &nvarnonz);
4917  SCIPfreeBufferArray(scip, &vars);
4918  SCIPfreeBufferArray(scip, &vals);
4919  SCIPfreeBufferArray(scip, &rows);
4920  SCIPfreeBufferArray(scip, &cols);
4921  }
4922 
4923  /* create linear constraint for quadratic constraint */
4924  if ( ! conshdlrdata->sdpconshdlrdata->upgradekeepquad )
4925  {
4926  SCIP_EXPR** linexprs;
4927  SCIP_EXPR* expr;
4928  int cnt = 0;
4929 
4930  /* get information */
4931  SCIPexprGetQuadraticData(SCIPgetExprNonlinear(cons), NULL, &nlinvarterms, &linexprs, &linvalsterms, &nquadvarterms, &nbilinterms, NULL, NULL);
4932 
4933  /* a quadvarterm consists of a variable x and two coefficients, one for the linear term x and one for the quadratic
4934  term x^2, where at least one of the two coefficients is nonzero */
4935  nlinconsterms = nlinvarterms + 2 * nquadvarterms + nbilinterms;
4936  SCIP_CALL( SCIPallocBufferArray(scip, &linconsvars, nlinconsterms) );
4937  SCIP_CALL( SCIPallocBufferArray(scip, &linconsvals, nlinconsterms) );
4938 
4939  /* fill in constraint */
4940  for (j = 0; j < nlinvarterms; ++j)
4941  {
4942  linconsvals[cnt] = linvalsterms[j];
4943 
4944  SCIPexprGetQuadraticQuadTerm(SCIPgetExprNonlinear(cons), j, &expr, NULL, NULL, NULL, NULL, NULL);
4945  linconsvars[cnt] = SCIPgetVarExprVar(linexprs[j]);;
4946  assert( linconsvars[cnt] != NULL );
4947  ++cnt;
4948  }
4949  assert( cnt == nlinvarterms );
4950 
4951  for (j = 0; j < nquadvarterms; ++j)
4952  {
4953  SCIP_Real lincoef;
4954  SCIP_Real sqrcoef;
4955  SCIP_VAR* var;
4956  int idx;
4957 
4958  /* get quadratic expression */
4959  SCIPexprGetQuadraticQuadTerm(SCIPgetExprNonlinear(cons), j, &expr, &lincoef, &sqrcoef, NULL, NULL, NULL);
4960  var = SCIPgetVarExprVar(expr);
4961  assert( var != NULL );
4962 
4963  idx = SCIPvarGetIndex(var);
4964  idx = conshdlrdata->sdpconshdlrdata->quadconsidx[idx];
4965  assert( 0 <= idx && idx < conshdlrdata->sdpconshdlrdata->nsdpvars );
4966 
4967  /* add coefficient for linear term corresponding to the current variable (may be zero) */
4968  if ( ! SCIPisZero(scip, lincoef) )
4969  {
4970  linconsvals[cnt] = lincoef;
4971  linconsvars[cnt] = var;
4972  assert( linconsvars[cnt] != NULL );
4973  ++cnt;
4974  }
4975 
4976  /* add coefficient for quadratic term corresponding to the current variable (may be zero) */
4977  if ( ! SCIPisZero(scip, sqrcoef) )
4978  {
4979  linconsvals[cnt] = sqrcoef;
4980  linconsvars[cnt] = conshdlrdata->sdpconshdlrdata->X[idx][idx];
4981  assert( linconsvars[cnt] != NULL );
4982  ++cnt;
4983  }
4984 
4985  SCIPdebugMsg(scip, "New variable %s corresponds to squared original variable %s\n",
4986  SCIPvarGetName(conshdlrdata->sdpconshdlrdata->X[idx][idx]), SCIPvarGetName(var));
4987  }
4988  assert( cnt <= nlinvarterms + 2 * nquadvarterms );
4989 
4990  for (j = 0; j < nbilinterms; ++j)
4991  {
4992  SCIP_EXPR* expr1;
4993  SCIP_EXPR* expr2;
4994  SCIP_Real coef;
4995  SCIP_VAR* var1;
4996  SCIP_VAR* var2;
4997  int idx1;
4998  int idx2;
4999 
5000  /* get bilinear expression */
5001  SCIPexprGetQuadraticBilinTerm(SCIPgetExprNonlinear(cons), j, &expr1, &expr2, &coef, NULL, NULL);
5002 
5003  var1 = SCIPgetVarExprVar(expr1);
5004  assert( var1 != NULL );
5005  idx1 = SCIPvarGetIndex(var1);
5006  idx1 = conshdlrdata->sdpconshdlrdata->quadconsidx[idx1];
5007  assert( 0 <= idx1 && idx1 < conshdlrdata->sdpconshdlrdata->nsdpvars );
5008 
5009  var2 = SCIPgetVarExprVar(expr2);
5010  assert( var2 != NULL );
5011  idx2 = SCIPvarGetIndex(var2);
5012  idx2 = conshdlrdata->sdpconshdlrdata->quadconsidx[idx2];
5013  assert( 0 <= idx2 && idx2 < conshdlrdata->sdpconshdlrdata->nsdpvars );
5014 
5015  if ( idx2 > idx1 )
5016  SCIPswapInts(&idx1, &idx2);
5017 
5018  linconsvals[cnt] = coef;
5019  linconsvars[cnt] = conshdlrdata->sdpconshdlrdata->X[idx1][idx2];
5020  assert( linconsvars[cnt] != NULL );
5021  ++cnt;
5022 
5023  SCIPdebugMsg(scip, "New variable %s corresponds to product of original variables %s and %s\n",
5024  SCIPvarGetName(conshdlrdata->sdpconshdlrdata->X[idx1][idx2]), SCIPvarGetName(var1), SCIPvarGetName(var2));
5025  }
5026  assert( cnt <= nlinvarterms + 2 * nquadvarterms + nbilinterms );
5027 
5028  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "lin_%s", SCIPconsGetName(cons));
5029  SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, name, cnt, linconsvars, linconsvals, SCIPgetLhsNonlinear(cons), SCIPgetRhsNonlinear(cons),
5030  SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons), SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons),
5031  FALSE, SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), FALSE) );
5032 
5033 #ifdef SCIP_MORE_DEBUG
5034  SCIPinfoMessage(scip, NULL, "In upgrade of quadratic constraint the following linear constraint has been added:\n");
5035  SCIP_CALL( SCIPprintCons(scip, lincons, NULL) );
5036  SCIPinfoMessage(scip, NULL, "\n");
5037 #endif
5038 
5039  /* fill in upgdconss - do not mention SDP constraint, since this has been added already */
5040  upgdconss[0] = lincons;
5041  *nupgdconss = 1;
5042 
5043  SCIPfreeBufferArray(scip, &linconsvals);
5044  SCIPfreeBufferArray(scip, &linconsvars);
5045  }
5046  else
5047  {
5048  /* todo: Check whether adding the linear constraints helps */
5049  *nupgdconss = 0; /* the original quadratic constraint should be kept in the problem */
5050  }
5051 
5052  /* turn off upgrading in order to avoid a possibly infinite loop */
5053  conshdlrdata->sdpconshdlrdata->upgradequadconss = FALSE;
5054 
5055  return SCIP_OKAY;
5056 }
5057 
5058 
5059 /* -----------------------------------------------------------------*/
5060 #else
5061 /* -----------------------------------------------------------------*/
5062 
5063 
5065 static
5066 SCIP_DECL_QUADCONSUPGD(consQuadConsUpgdSdp)
5068  char name[SCIP_MAXSTRLEN];
5069  SCIP_CONSHDLR* conshdlr;
5070  SCIP_CONSHDLRDATA* conshdlrdata;
5071  SCIP_CONS* lincons;
5072  SCIP_VAR** linconsvars;
5073  SCIP_Real* linconsvals;
5074  SCIP_VAR** linvarsterms;
5075  SCIP_Real* linvalsterms;
5076  SCIP_QUADVARTERM* quadvarterms;
5077  SCIP_BILINTERM* bilinterms;
5078  int nlinvarterms;
5079  int nquadvarterms;
5080  int nbilinterms;
5081  int nlinconsterms;
5082  int j;
5083 
5084  assert( scip != NULL );
5085  assert( cons != NULL );
5086  assert( nupgdconss != NULL );
5087  assert( upgdconss != NULL );
5088 
5089  *nupgdconss = 0;
5090 
5091  /* do not upgrade modifiable/sticking at node constraints */
5092  if ( SCIPconsIsModifiable(cons) || SCIPconsIsStickingAtNode(cons) )
5093  return SCIP_OKAY;
5094 
5095  /* do not run in sub-SCIPs to avoid recursive reformulations due to rank 1 constraints */
5096  if ( SCIPgetSubscipDepth(scip) > 0 )
5097  return SCIP_OKAY;
5098 
5099  /* do not upgrade after a restart */
5100  if ( SCIPgetNRuns(scip) > 1 )
5101  return SCIP_OKAY;
5102 
5103  /* make sure there is enough space to store the replacing constraints */
5104  if ( upgdconsssize < 1 )
5105  {
5106  *nupgdconss = -1;
5107  return SCIP_OKAY;
5108  }
5109 
5110  conshdlr = SCIPfindConshdlr(scip, CONSHDLRRANK1_NAME);
5111  if ( conshdlr == NULL )
5112  {
5113  SCIPerrorMessage("rank 1 SDP constraint handler not found\n");
5114  return SCIP_PLUGINNOTFOUND;
5115  }
5116  assert( conshdlr != NULL );
5117 
5118  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5119  assert( conshdlrdata != NULL );
5120 
5121  /* check whether upgrading should be performed */
5122  if ( ! conshdlrdata->sdpconshdlrdata->upgradequadconss )
5123  return SCIP_OKAY;
5124 
5125  /* we have to collect all variables appearing in quadratic constraints first */
5126  if ( conshdlrdata->sdpconshdlrdata->quadconsvars == NULL )
5127  {
5128  SCIP_CONSHDLR* quadconshdlr;
5129  SCIP_CONS** conss;
5130  int nconss;
5131  int nvars;
5132  int c;
5133  int i;
5134  int nsdpvars = 0;
5135 
5136  int** cols;
5137  int** rows;
5138  SCIP_Real** vals;
5139  SCIP_VAR** vars;
5140  int* nvarnonz;
5141  int nnonz;
5142  int nvarscnt;
5143  int constcol = 0;
5144  int constrow = 0;
5145  SCIP_Real constval = -1.0;
5146 
5147  /* todo: The arrays quadconsidx and quadconsvars are needed to check if variables have already been seen in a
5148  quadratic constraint. This could be replaced with a hashmap. */
5149  nvars = SCIPgetNTotalVars(scip);
5150  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &conshdlrdata->sdpconshdlrdata->quadconsidx, nvars) );
5151  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &conshdlrdata->sdpconshdlrdata->quadconsvars, nvars) );
5152  conshdlrdata->sdpconshdlrdata->nquadconsidx = nvars;
5153  for (j = 0; j < nvars; ++j)
5154  conshdlrdata->sdpconshdlrdata->quadconsidx[j] = -1;
5155 
5156  quadconshdlr = SCIPfindConshdlr(scip, "quadratic");
5157  if ( quadconshdlr == NULL )
5158  {
5159  SCIPerrorMessage("Quadratic constraint handler not found\n");
5160  return SCIP_PLUGINNOTFOUND;
5161  }
5162  assert( quadconshdlr != NULL );
5163 
5164  conss = SCIPconshdlrGetConss(quadconshdlr);
5165  nconss = SCIPconshdlrGetNConss(quadconshdlr);
5166 
5167  /* Do not perform upgrade, if there are too many quadratic constraints present. */
5168  if ( nconss > conshdlrdata->sdpconshdlrdata->maxnvarsquadupgd )
5169  {
5170  SCIPdebugMsg(scip, "There are %d many quadratic constraints present in the problem, thus do not upgrade quadratic constraints to an SDPrank1 constraint\n", nconss);
5171  SCIPfreeBlockMemoryArray(scip, &conshdlrdata->sdpconshdlrdata->quadconsvars, nvars);
5172  SCIPfreeBlockMemoryArray(scip, &conshdlrdata->sdpconshdlrdata->quadconsidx, nvars);
5173  return SCIP_OKAY;
5174  }
5175 
5176  for (c = 0; c < nconss; ++c)
5177  {
5178  assert( conss[c] != NULL );
5179 #ifdef SCIP_MORE_DEBUG
5180  SCIPinfoMessage(scip, NULL, "Found quadratic constraint to upgrade:\n");
5181  SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
5182  SCIPinfoMessage(scip, NULL, "\n");
5183 #endif
5184  nquadvarterms = SCIPgetNQuadVarTermsQuadratic(scip, conss[c]);
5185  quadvarterms = SCIPgetQuadVarTermsQuadratic(scip, conss[c]);
5186 
5187  for (i = 0; i < nquadvarterms; ++i)
5188  {
5189  SCIP_VAR* var;
5190  int idx;
5191 
5192  assert( quadvarterms != NULL );
5193  var = quadvarterms[i].var;
5194  idx = SCIPvarGetIndex(var);
5195  assert( 0 <= idx && idx < nvars );
5196  if ( conshdlrdata->sdpconshdlrdata->quadconsidx[idx] < 0 )
5197  {
5198  conshdlrdata->sdpconshdlrdata->quadconsvars[nsdpvars] = var;
5199  conshdlrdata->sdpconshdlrdata->quadconsidx[idx] = nsdpvars++;
5200  }
5201  }
5202 
5203  nbilinterms = SCIPgetNBilinTermsQuadratic(scip, conss[c]);
5204  bilinterms = SCIPgetBilinTermsQuadratic(scip, conss[c]);
5205 
5206  for (i = 0; i < nbilinterms; ++i)
5207  {
5208  SCIP_VAR* var;
5209  int idx;
5210 
5211  assert( bilinterms != NULL );
5212  var = bilinterms[i].var1;
5213  idx = SCIPvarGetIndex(var);
5214  assert( 0 <= idx && idx < nvars );
5215  if ( conshdlrdata->sdpconshdlrdata->quadconsidx[idx] < 0 )
5216  {
5217  conshdlrdata->sdpconshdlrdata->quadconsvars[nsdpvars] = var;
5218  conshdlrdata->sdpconshdlrdata->quadconsidx[idx] = nsdpvars++;
5219  }
5220 
5221  var = bilinterms[i].var2;
5222  idx = SCIPvarGetIndex(var);
5223  assert( 0 <= idx && idx < nvars );
5224  if ( conshdlrdata->sdpconshdlrdata->quadconsidx[idx] < 0 )
5225  {
5226  conshdlrdata->sdpconshdlrdata->quadconsvars[nsdpvars] = var;
5227  conshdlrdata->sdpconshdlrdata->quadconsidx[idx] = nsdpvars++;
5228  }
5229  }
5230  }
5231 
5232  /* do not perform upgrade, if no sdpvars have been added */
5233  if ( nsdpvars == 0 )
5234  {
5235  SCIPdebugMsg(scip, "No sdp variables have been added\n");
5236  SCIPfreeBlockMemoryArray(scip, &conshdlrdata->sdpconshdlrdata->quadconsvars, nvars);
5237  SCIPfreeBlockMemoryArray(scip, &conshdlrdata->sdpconshdlrdata->quadconsidx, nvars);
5238  return SCIP_OKAY;
5239  }
5240 
5241  /* do not perform upgrade, if there are too many variables in the quadratic constraints, since we need sdpvars *
5242  sdpvars many variables for the (dual) SDPrank1 constraint */
5243  if ( nsdpvars > conshdlrdata->sdpconshdlrdata->maxnvarsquadupgd )
5244  {
5245  SCIPdebugMsg(scip, "There are %d many variables present in the quadratic constraints, thus do not upgrade quadratic constraints to an SDPrank1 constraint\n", nsdpvars);
5246  SCIPfreeBlockMemoryArray(scip, &conshdlrdata->sdpconshdlrdata->quadconsvars, nvars);
5247  SCIPfreeBlockMemoryArray(scip, &conshdlrdata->sdpconshdlrdata->quadconsidx, nvars);
5248  return SCIP_OKAY;
5249  }
5250 
5251  /* create bilinear variables */
5252  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &conshdlrdata->sdpconshdlrdata->X, nsdpvars) );
5253  conshdlrdata->sdpconshdlrdata->nsdpvars = nsdpvars;
5254 
5255  for (i = 0; i < nsdpvars; ++i)
5256  {
5257  SCIP_Real lb1;
5258  SCIP_Real ub1;
5259  SCIP_VAR* var1;
5260 
5261  var1 = conshdlrdata->sdpconshdlrdata->quadconsvars[i];
5262  assert( var1 != NULL );
5263  lb1 = SCIPvarGetLbGlobal(var1);
5264  ub1 = SCIPvarGetUbGlobal(var1);
5265 
5266  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &conshdlrdata->sdpconshdlrdata->X[i], nsdpvars) );
5267 
5268  for (j = 0; j <= i; ++j)
5269  {
5270  SCIP_VARTYPE vartype;
5271  SCIP_VAR* var2;
5272  SCIP_Real lb2;
5273  SCIP_Real ub2;
5274  SCIP_Real lb;
5275  SCIP_Real ub;
5276 
5277  var2 = conshdlrdata->sdpconshdlrdata->quadconsvars[j];
5278  assert( var2 != NULL );
5279  lb2 = SCIPvarGetLbGlobal(var2);
5280  ub2 = SCIPvarGetUbGlobal(var2);
5281 
5282  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "X%d#%d", i, j);
5283 
5284  lb = MIN3(lb1 * lb2, lb1 * ub2, ub1 * lb2);
5285  lb = MIN(lb, ub1 * ub2);
5286  ub = MAX3(lb1 * lb2, lb1 * ub2, ub1 * lb2);
5287  ub = MAX(ub, ub1 * ub2);
5288 
5289  if ( SCIPvarIsBinary(var1) && SCIPvarIsBinary(var2) )
5290  vartype = SCIP_VARTYPE_BINARY;
5291  else if ( SCIPvarIsIntegral(var1) && SCIPvarIsIntegral(var2) )
5292  vartype = SCIP_VARTYPE_INTEGER;
5293  else
5294  vartype = SCIP_VARTYPE_CONTINUOUS;
5295 
5296  SCIP_CALL( SCIPcreateVarBasic(scip, &(conshdlrdata->sdpconshdlrdata->X[i][j]), name, lb, ub, 0.0, vartype) );
5297  SCIP_CALL( SCIPaddVar(scip, conshdlrdata->sdpconshdlrdata->X[i][j]) );
5298  }
5299  }
5300 
5301  /* fill SDP data */
5302  nnonz = nsdpvars + nsdpvars * (nsdpvars + 1) / 2;
5303  SCIP_CALL( SCIPallocBufferArray(scip, &cols, nnonz) );
5304  SCIP_CALL( SCIPallocBufferArray(scip, &rows, nnonz) );
5305  SCIP_CALL( SCIPallocBufferArray(scip, &vals, nnonz) );
5306  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nnonz) );
5307  SCIP_CALL( SCIPallocBufferArray(scip, &nvarnonz, nnonz) );
5308 
5309  /* first the terms for the original variables */
5310  for (j = 0; j < nsdpvars; ++j)
5311  {
5312  SCIP_CALL( SCIPallocBufferArray(scip, &cols[j], 1) );
5313  SCIP_CALL( SCIPallocBufferArray(scip, &rows[j], 1) );
5314  SCIP_CALL( SCIPallocBufferArray(scip, &vals[j], 1) );
5315  nvarnonz[j] = 1;
5316  cols[j][0] = 0;
5317  rows[j][0] = 1 + j;
5318  vals[j][0] = 1.0;
5319  vars[j] = conshdlrdata->sdpconshdlrdata->quadconsvars[j];
5320  }
5321 
5322  /* now the terms for the bilinear terms */
5323  nvarscnt = nsdpvars;
5324  for (i = 0; i < nsdpvars; ++i)
5325  {
5326  for (j = 0; j <= i; ++j)
5327  {
5328  SCIP_CALL( SCIPallocBufferArray(scip, &cols[nvarscnt], 1) );
5329  SCIP_CALL( SCIPallocBufferArray(scip, &rows[nvarscnt], 1) );
5330  SCIP_CALL( SCIPallocBufferArray(scip, &vals[nvarscnt], 1) );
5331  nvarnonz[nvarscnt] = 1;
5332  cols[nvarscnt][0] = 1 + j;
5333  rows[nvarscnt][0] = 1 + i;
5334  vals[nvarscnt][0] = 1.0;
5335  vars[nvarscnt] = conshdlrdata->sdpconshdlrdata->X[i][j];
5336  ++nvarscnt;
5337  }
5338  }
5339  assert( nvarscnt == nsdpvars + nsdpvars * (nsdpvars + 1)/2 );
5340 
5341  /* create corresponding rank 1 SDP constraint */
5342  if ( conshdlrdata->sdpconshdlrdata->upgradekeepquad )
5343  {
5344  SCIP_CALL( SCIPcreateConsSdp(scip, &conshdlrdata->sdpconshdlrdata->sdpcons, "QuadraticSDPcons", nvarscnt, nvarscnt, 1 + nsdpvars, nvarnonz,
5345  cols, rows, vals, vars, 1, &constcol, &constrow, &constval, FALSE) );
5346  SCIP_CALL( SCIPaddCons(scip, conshdlrdata->sdpconshdlrdata->sdpcons) );
5347  }
5348  else
5349  {
5350  SCIP_CALL( SCIPcreateConsSdpRank1(scip, &conshdlrdata->sdpconshdlrdata->sdpcons, "QuadraticSDPrank1cons", nvarscnt, nvarscnt, 1 + nsdpvars, nvarnonz,
5351  cols, rows, vals, vars, 1, &constcol, &constrow, &constval, FALSE) );
5352  SCIP_CALL( SCIPaddCons(scip, conshdlrdata->sdpconshdlrdata->sdpcons) );
5353  }
5354 
5355 #ifdef SCIP_MORE_DEBUG
5356  SCIPinfoMessage(scip, NULL, "In upgrade of quadratic constraint the following SDPrank1 constraint has been added:\n");
5357  SCIP_CALL( SCIPprintCons(scip, conshdlrdata->sdpconshdlrdata->sdpcons, NULL) );
5358  SCIPinfoMessage(scip, NULL, "\n");
5359 #endif
5360 
5361  /* free local memory */
5362  for (j = nvarscnt - 1; j >= 0; --j)
5363  {
5364  SCIPfreeBufferArray(scip, &vals[j]);
5365  SCIPfreeBufferArray(scip, &rows[j]);
5366  SCIPfreeBufferArray(scip, &cols[j]);
5367  }
5368  SCIPfreeBufferArray(scip, &nvarnonz);
5369  SCIPfreeBufferArray(scip, &vars);
5370  SCIPfreeBufferArray(scip, &vals);
5371  SCIPfreeBufferArray(scip, &rows);
5372  SCIPfreeBufferArray(scip, &cols);
5373  }
5374 
5375  if ( ! conshdlrdata->sdpconshdlrdata->upgradekeepquad )
5376  {
5377  int cnt = 0;
5378 
5379  /* create linear constraint for quadratic constraint */
5380  nlinvarterms = SCIPgetNLinearVarsQuadratic(scip, cons);
5381  linvarsterms = SCIPgetLinearVarsQuadratic(scip, cons);
5382  linvalsterms = SCIPgetCoefsLinearVarsQuadratic(scip, cons);
5383  nquadvarterms = SCIPgetNQuadVarTermsQuadratic(scip, cons);
5384  quadvarterms = SCIPgetQuadVarTermsQuadratic(scip, cons);
5385  nbilinterms = SCIPgetNBilinTermsQuadratic(scip, cons);
5386  bilinterms = SCIPgetBilinTermsQuadratic(scip, cons);
5387 
5388  /* a quadvarterm consists of a variable x and two coefficients, one for the linear term x and one for the quadratic
5389  term x^2, where at least one of the two coefficients is nonzero */
5390  nlinconsterms = nlinvarterms + 2 * nquadvarterms + nbilinterms;
5391  SCIP_CALL( SCIPallocBufferArray(scip, &linconsvars, nlinconsterms) );
5392  SCIP_CALL( SCIPallocBufferArray(scip, &linconsvals, nlinconsterms) );
5393 
5394  /* fill in constraint */
5395  for (j = 0; j < nlinvarterms; ++j)
5396  {
5397  linconsvals[cnt] = linvalsterms[j];
5398  linconsvars[cnt] = linvarsterms[j];
5399  assert( linconsvars[cnt] != NULL );
5400  ++cnt;
5401  }
5402  assert( cnt == nlinvarterms );
5403  for (j = 0; j < nquadvarterms; ++j)
5404  {
5405  int idx;
5406 
5407  idx = SCIPvarGetIndex(quadvarterms[j].var);
5408  idx = conshdlrdata->sdpconshdlrdata->quadconsidx[idx];
5409  assert( 0 <= idx && idx < conshdlrdata->sdpconshdlrdata->nsdpvars );
5410 
5411  /* add coefficient for linear term corresponding to the current variable (may be zero) */
5412  if ( ! SCIPisZero(scip, quadvarterms[j].lincoef) )
5413  {
5414  linconsvals[cnt] = quadvarterms[j].lincoef;
5415  linconsvars[cnt] = quadvarterms[j].var;
5416  assert( linconsvars[cnt] != NULL );
5417  ++cnt;
5418  }
5419 
5420  /* add coefficient for quadratic term corresponding to the current variable (may be zero) */
5421  if ( ! SCIPisZero(scip, quadvarterms[j].sqrcoef) )
5422  {
5423  linconsvals[cnt] = quadvarterms[j].sqrcoef;
5424  linconsvars[cnt] = conshdlrdata->sdpconshdlrdata->X[idx][idx];
5425  assert( linconsvars[cnt] != NULL );
5426  ++cnt;
5427  }
5428 
5429  SCIPdebugMsg(scip, "New variable %s corresponds to squared original variable %s\n",
5430  SCIPvarGetName(conshdlrdata->sdpconshdlrdata->X[idx][idx]), SCIPvarGetName(quadvarterms[j].var));
5431  }
5432  assert( cnt <= nlinvarterms + 2 * nquadvarterms );
5433 
5434  for (j = 0; j < nbilinterms; ++j)
5435  {
5436  int idx1;
5437  int idx2;
5438 
5439  idx1 = SCIPvarGetIndex(bilinterms[j].var1);
5440  idx1 = conshdlrdata->sdpconshdlrdata->quadconsidx[idx1];
5441  assert( 0 <= idx1 && idx1 < conshdlrdata->sdpconshdlrdata->nsdpvars );
5442 
5443  idx2 = SCIPvarGetIndex(bilinterms[j].var2);
5444  idx2 = conshdlrdata->sdpconshdlrdata->quadconsidx[idx2];
5445  assert( 0 <= idx2 && idx2 < conshdlrdata->sdpconshdlrdata->nsdpvars );
5446 
5447  if ( idx2 > idx1 )
5448  SCIPswapInts(&idx1, &idx2);
5449 
5450  linconsvals[cnt] = bilinterms[j].coef;
5451  linconsvars[cnt] = conshdlrdata->sdpconshdlrdata->X[idx1][idx2];
5452  assert( linconsvars[cnt] != NULL );
5453  ++cnt;
5454 
5455  SCIPdebugMsg(scip, "New variable %s corresponds to product of original variables %s and %s\n",
5456  SCIPvarGetName(conshdlrdata->sdpconshdlrdata->X[idx1][idx2]), SCIPvarGetName(bilinterms[j].var1), SCIPvarGetName(bilinterms[j].var2));
5457  }
5458  assert( cnt <= nlinvarterms + 2 * nquadvarterms + nbilinterms );
5459 
5460  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "lin_%s", SCIPconsGetName(cons));
5461  SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, name, cnt, linconsvars, linconsvals, SCIPgetLhsQuadratic(scip, cons), SCIPgetRhsQuadratic(scip, cons),
5462  SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons), SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons),
5463  FALSE, SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), FALSE) );
5464 
5465 #ifdef SCIP_MORE_DEBUG
5466  SCIPinfoMessage(scip, NULL, "In upgrade of quadratic constraint the following linear constraint has been added:\n");
5467  SCIP_CALL( SCIPprintCons(scip, lincons, NULL) );
5468  SCIPinfoMessage(scip, NULL, "\n");
5469 #endif
5470 
5471  /* fill in upgdconss - do not mention SDP constraint, since this has been added already */
5472  upgdconss[0] = lincons;
5473  *nupgdconss = 1;
5474 
5475  SCIPfreeBufferArray(scip, &linconsvals);
5476  SCIPfreeBufferArray(scip, &linconsvars);
5477  }
5478  else
5479  {
5480  /* todo: Check whether adding the linear constraints helps */
5481  *nupgdconss = 0; /* the original quadratic constraint should be kept in the problem */
5482  }
5483 
5484  /* turn off upgrading in order to avoid a possibly infinite loop */
5485  conshdlrdata->sdpconshdlrdata->upgradequadconss = FALSE;
5486 
5487  return SCIP_OKAY;
5488 }
5489 
5490 #endif
5491 
5492 
5493 
5494 /*
5495  * callbacks
5496  */
5497 
5499 static
5500 SCIP_DECL_CONSINITPRE(consInitpreSdp)
5501 {/*lint --e{715}*/
5502  SCIP_CONSHDLRDATA* conshdlrdata;
5503 
5504  assert( conshdlr != NULL );
5505 
5506  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5507  assert( conshdlrdata != NULL );
5508 
5509  conshdlrdata->neigveccuts = 0; /* this is used to give the eigenvector-cuts distinguishable names */
5510  conshdlrdata->ndiaggezerocuts = 0; /* this is used to give the diagGEzero-cuts distinguishable names */
5511  conshdlrdata->n1x1blocks = 0; /* this is used to give the lp constraints resulting from 1x1 sdp-blocks distinguishable names */
5512 
5513  return SCIP_OKAY;
5514 }
5515 
5517 static
5518 SCIP_DECL_CONSLOCK(consLockSdp)
5519 {/*lint --e{715}*/
5520  SCIP_Real* Aj;
5521  SCIP_CONSDATA* consdata;
5522  int nvars;
5523  int v;
5524 
5525  consdata = SCIPconsGetData(cons);
5526  assert( consdata != NULL );
5527  nvars = consdata->nvars;
5528 
5529  SCIPdebugMsg(scip, "locking method of <%s>.\n", SCIPconsGetName(cons));
5530 
5531  /* rank-1 constraints are always up- and down-locked */
5532  if ( consdata->rankone )
5533  {
5534  if ( consdata->locks == NULL )
5535  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->locks, nvars) );
5536 
5537  for (v = 0; v < consdata->nvars; ++v)
5538  {
5539  consdata->locks[v] = 0;
5540  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[v], locktype, nlockspos + nlocksneg, nlockspos + nlocksneg) );
5541  }
5542  return SCIP_OKAY;
5543  }
5544 
5545  /* if locks have not yet been computed */
5546  if ( consdata->locks == NULL )
5547  {
5548  SCIP_Real mineigenvalue = SCIP_REAL_MAX;
5549  SCIP_Real eigenvalue;
5550  int blocksize;
5551 
5552  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->locks, nvars) );
5553 
5554  blocksize = consdata->blocksize;
5555 
5556  SCIP_CALL( SCIPallocBufferArray(scip, &Aj, blocksize * blocksize) ); /*lint !e647*/
5557 
5558  for (v = 0; v < nvars; v++)
5559  {
5560  SCIP_CALL( SCIPconsSdpGetFullAj(scip, cons, v, Aj) );
5561  consdata->locks[v] = -2; /* unintitialized */
5562 
5563  /* compute the smallest eigenvalue */
5564  SCIP_CALL( SCIPlapackComputeIthEigenvalue(SCIPbuffer(scip), FALSE, blocksize, Aj, 1, &eigenvalue, NULL) );
5565  if ( SCIPisNegative(scip, eigenvalue) )
5566  {
5567  /* as the lowest eigenvalue is negative, the matrix is not positive semidefinite, so adding more of it can remove positive
5568  * semidefiniteness of the SDP-matrix */
5569  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[v], locktype, nlocksneg, nlockspos) );
5570  consdata->locks[v] = 1; /* up-lock */
5571  }
5572  if ( eigenvalue < mineigenvalue )
5573  mineigenvalue = eigenvalue;
5574 
5575  /* if the smallest eigenvalue is already positive, we don't need to compute the biggest one */
5576  if ( SCIPisPositive(scip, eigenvalue) )
5577  {
5578  /* as an eigenvalue is positive, the matrix is not negative semidefinite, so substracting more of it can remove positive
5579  * semidefiniteness of the SDP-matrix */
5580  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[v], locktype, nlockspos, nlocksneg) );
5581  consdata->locks[v] = -1; /* down-lock */
5582  }
5583  else
5584  {
5585  /* compute the biggest eigenvalue */
5586  SCIP_CALL( SCIPlapackComputeIthEigenvalue(SCIPbuffer(scip), FALSE, blocksize, Aj, blocksize, &eigenvalue, NULL) );
5587  if ( SCIPisPositive(scip, eigenvalue) )
5588  {
5589  /* as the biggest eigenvalue is positive, the matrix is not negative semidefinite, so substracting more of it can remove positive
5590  * semidefiniteness of the SDP-matrix */
5591  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[v], locktype, nlockspos, nlocksneg) );
5592  if ( consdata->locks[v] == 1 )
5593  {
5594  consdata->locks[v] = 0; /* up- and down-lock */
5595  }
5596  else
5597  consdata->locks[v] = -1; /* down-lock */
5598  }
5599  }
5600  }
5601 
5602  if ( SCIPisFeasGE(scip, mineigenvalue, 0.0) )
5603  {
5604  consdata->allmatricespsd = TRUE;
5605  if ( SCIPgetSubscipDepth(scip) == 0 )
5606  SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "All matrices are positive semidefinite (minimial eigenvalue: %g).\n", mineigenvalue);
5607  }
5608  consdata->initallmatricespsd = TRUE;
5609 
5610  SCIPfreeBufferArray(scip, &Aj);
5611  }
5612  else
5613  {
5614 #ifndef NDEBUG
5615  SCIP_CALL( checkVarsLocks(scip, cons) );
5616 #endif
5617  for (v = 0; v < nvars; v++)
5618  {
5619  if ( consdata->locks[v] == 1 ) /* up-lock */
5620  {
5621  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[v], locktype, nlocksneg, nlockspos) );
5622  }
5623  else if ( consdata->locks[v] == -1 ) /* down-lock */
5624  {
5625  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[v], locktype, nlockspos, nlocksneg) );
5626  }
5627  else if ( consdata->locks[v] == 0 ) /* up and down lock */
5628  {
5629  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[v], locktype, nlockspos + nlocksneg, nlockspos + nlocksneg) );
5630  }
5631  else
5632  assert( consdata->locks[v] == -2 );
5633  }
5634  }
5635 
5636  return SCIP_OKAY;
5637 }
5638 
5643 static
5644 SCIP_DECL_CONSEXIT(consExitSdp)
5646  SCIP_CONSHDLRDATA* conshdlrdata;
5647 
5648  assert(scip != NULL);
5649 
5650  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5651  assert(conshdlrdata != NULL);
5652 
5653  /* reset parameter triedlinearconss */
5654  conshdlrdata->sdpconshdlrdata->triedlinearconss = FALSE;
5655  conshdlrdata->sdpconshdlrdata->triedvarbounds = FALSE;
5656 
5657  return SCIP_OKAY;
5658 }
5659 
5661 static
5662 SCIP_DECL_CONSEXITPRE(consExitpreSdp)
5663 {/*lint --e{715}*/
5664  SCIP_CONSHDLRDATA* conshdlrdata;
5665  int i;
5666  int j;
5667 
5668  assert( scip != NULL );
5669  assert( conshdlr != NULL );
5670 
5671  if ( conss == NULL )
5672  return SCIP_OKAY;
5673 
5674  SCIPdebugMsg(scip, "Exitpre method of conshdlr <%s>.\n", SCIPconshdlrGetName(conshdlr));
5675 
5676  if ( SCIPgetStatus(scip) != SCIP_STATUS_OPTIMAL && SCIPgetStatus(scip) != SCIP_STATUS_INFEASIBLE )
5677  {
5678  SCIP_CALL( fixAndAggrVars(scip, conss, nconss, TRUE) );
5679  }
5680 
5681  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5682  assert( conshdlrdata != NULL );
5683 
5684  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->sdpconshdlrdata->quadconsidx, conshdlrdata->sdpconshdlrdata->nquadconsidx);
5685  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->sdpconshdlrdata->quadconsvars, conshdlrdata->sdpconshdlrdata->nquadconsidx);
5686  if ( conshdlrdata->sdpconshdlrdata->X != NULL )
5687  {
5688  SCIPdebugMsg(scip, "Releasing additional variables from upgrading method\n");
5689  for (i = 0; i < conshdlrdata->sdpconshdlrdata->nsdpvars; ++i)
5690  {
5691  for (j = 0; j <= i; ++j)
5692  {
5693  SCIP_CALL( SCIPreleaseVar(scip, &(conshdlrdata->sdpconshdlrdata->X[i][j])) );
5694  }
5695  SCIPfreeBlockMemoryArray(scip, &conshdlrdata->sdpconshdlrdata->X[i], conshdlrdata->sdpconshdlrdata->nsdpvars);
5696  }
5697  SCIPfreeBlockMemoryArray(scip, &conshdlrdata->sdpconshdlrdata->X, conshdlrdata->sdpconshdlrdata->nsdpvars);
5698  }
5699 
5700  if ( conshdlrdata->sdpconshdlrdata->sdpcons != NULL )
5701  {
5702  SCIPdebugMsg(scip, "Releasing constraint %s from upgrading method\n", SCIPconsGetName(conshdlrdata->sdpconshdlrdata->sdpcons) );
5703  SCIP_CALL( SCIPreleaseCons(scip, &conshdlrdata->sdpconshdlrdata->sdpcons) );
5704  }
5705 
5706  /* TODO: test if branching and/or separation of Chen et al. can be applied */
5707 
5708  return SCIP_OKAY;
5709 }
5710 
5715 static
5716 SCIP_DECL_CONSINITSOL(consInitsolSdp)
5717 {/*lint --e{715}*/
5718  SCIP_CONSHDLRDATA* conshdlrdata;
5719 
5720  assert( scip != NULL );
5721  assert( conshdlr != NULL );
5722 
5723  if ( conss == NULL )
5724  return SCIP_OKAY;
5725 
5726  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5727  assert( conshdlrdata != NULL );
5728 
5729  if ( (conshdlrdata->sdpconshdlrdata->sparsifycut || conshdlrdata->sdpconshdlrdata->multiplesparsecuts) && conshdlrdata->randnumgen == NULL )
5730  {
5731  SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->randnumgen, 64293, FALSE) );
5732  }
5733 
5734  conshdlrdata->relaxsdp = SCIPfindRelax(scip, "SDP");
5735 
5736  /* make sure that quadratic constraints are added */
5737  if ( SCIPgetSubscipDepth(scip) == 0 && conshdlrdata->sdpconshdlrdata->quadconsrank1 )
5738  {
5739  int naddconss = 0;
5740  SCIP_CALL( addRank1QuadConss(scip, conshdlr, conss, nconss, &naddconss) );
5741  SCIPdebugMsg(scip, "Added %d quadratic constraints for rank 1 constraints.\n", naddconss);
5742 
5743  /* turn off upgrading in order to avoid upgrading to a rank-1 constraint again */
5744  conshdlrdata->sdpconshdlrdata->upgradequadconss = FALSE;
5745  }
5746 
5747  return SCIP_OKAY;
5748 }
5749 
5751 static
5752 SCIP_DECL_CONSPROP(consPropSdp)
5754  SCIP_CONSHDLRDATA* conshdlrdata;
5755  SCIP_Bool infeasible;
5756  int nprop = 0;
5757 
5758  assert( conshdlr != NULL );
5759  assert( result != NULL );
5760 
5761  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5762  assert( conshdlrdata != NULL );
5763 
5764  *result = SCIP_DIDNOTRUN;
5765 
5766  /* if we want to propagate upper bounds */
5767  if ( conshdlrdata->sdpconshdlrdata->propupperbounds )
5768  {
5769  *result = SCIP_DIDNOTFIND;
5770 
5771  SCIPdebugMsg(scip, "Propagate upper bounds of conshdlr <%s> ...\n", SCIPconshdlrGetName(conshdlr));
5772 
5773  SCIP_CALL( propagateUpperBounds(scip, conss, nconss, &infeasible, &nprop) );
5774 
5775  if ( infeasible )
5776  {
5777  SCIPdebugMsg(scip, "Propagation detected cutoff.\n");
5778  *result = SCIP_CUTOFF;
5779  }
5780  else
5781  {
5782  if ( nprop > 0 )
5783  {
5784  SCIPdebugMsg(scip, "Propagation tightened %d bounds.\n", nprop);
5785  *result = SCIP_REDUCEDDOM;
5786  }
5787  }
5788  }
5789 
5790  /* if we want to propagate upper bounds */
5791  if ( conshdlrdata->sdpconshdlrdata->proptightenbounds )
5792  {
5793  /* possibly avoid propagation in probing */
5794  if ( conshdlrdata->sdpconshdlrdata->proptbprobing || ! SCIPinProbing(scip) )
5795  {
5796  if ( *result == SCIP_DIDNOTRUN )
5797  *result = SCIP_DIDNOTFIND;
5798 
5799  SCIPdebugMsg(scip, "Propagate tighten bounds of conshdlr <%s> ...\n", SCIPconshdlrGetName(conshdlr));
5800 
5801  nprop = 0;
5802  SCIP_CALL( tightenBounds(scip, conss, nconss, conshdlrdata->sdpconshdlrdata->tightenboundscont, &nprop, &infeasible) );
5803 
5804  if ( infeasible )
5805  {
5806  SCIPdebugMsg(scip, "Propagation detected cutoff.\n");
5807  *result = SCIP_CUTOFF;
5808  }
5809  else
5810  {
5811  if ( nprop > 0 )
5812  {
5813  SCIPdebugMsg(scip, "Propagation tightened %d bounds.\n", nprop);
5814  *result = SCIP_REDUCEDDOM;
5815  }
5816  }
5817  }
5818  }
5819 
5820  return SCIP_OKAY;
5821 }
5822 
5824 static
5825 SCIP_DECL_CONSRESPROP(consRespropSdp)
5827  SCIP_CONSDATA* consdata;
5828  int diags;
5829  int diagt;
5830  int s;
5831  int t;
5832 
5833  assert( conshdlr != NULL );
5834  assert( cons != NULL );
5835  assert( infervar != NULL );
5836  assert( result != NULL );
5837 
5838  consdata = SCIPconsGetData(cons);
5839  assert( consdata != NULL );
5840  assert( consdata->rankone || strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0 );
5841  assert( ! consdata->rankone || strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLRRANK1_NAME) == 0 );
5842 
5843  SCIPdebugMsg(scip, "Executing conflict resolving method of <%s> constraint handler.\n", SCIPconshdlrGetName(conshdlr));
5844 
5845  /* if inferinfo is >=, the bound change came from propagateUpperBounds() */
5846  if ( inferinfo >= 0 )
5847  {
5848  s = inferinfo / consdata->blocksize;
5849  t = inferinfo % consdata->blocksize;
5850  assert( 0 <= s && s < consdata->blocksize );
5851  assert( 0 <= t && t < consdata->blocksize );
5852  assert( consdata->matrixvar[s * (s + 1)/2 + t] == infervar );
5853 
5854  diags = s * (s + 1)/2 + s;
5855  diagt = t * (t + 1)/2 + t;
5856 
5857  assert( consdata->matrixvar[diags] != NULL );
5858  assert( consdata->matrixvar[diagt] != NULL );
5859  assert( consdata->matrixval[diags] != SCIP_INVALID );
5860  assert( consdata->matrixval[diagt] != SCIP_INVALID );
5861 
5862  if ( consdata->matrixval[diags] > 0.0 )
5863  SCIP_CALL( SCIPaddConflictUb(scip, consdata->matrixvar[diags], bdchgidx) );
5864  else
5865  SCIP_CALL( SCIPaddConflictLb(scip, consdata->matrixvar[diags], bdchgidx) );
5866 
5867  if ( consdata->matrixval[diagt] > 0.0 )
5868  SCIP_CALL( SCIPaddConflictUb(scip, consdata->matrixvar[diagt], bdchgidx) );
5869  else
5870  SCIP_CALL( SCIPaddConflictLb(scip, consdata->matrixvar[diagt], bdchgidx) );
5871 
5872  *result = SCIP_SUCCESS;
5873  }
5874  else
5875  {
5876  int i;
5877  int k;
5878 
5879  /* otherwise the bound change came from tightenbounds() */
5880  i = -inferinfo - 1;
5881  assert( 0 <= i && i < consdata->nvars );
5882 
5883  /* the upper bounds of all other variables are responsible */
5884  for (k = 0; k < consdata->nvars; ++k)
5885  {
5886  if ( k == i )
5887  continue;
5888 
5889  SCIP_CALL( SCIPaddConflictUb(scip, consdata->vars[k], bdchgidx) );
5890  }
5891  *result = SCIP_SUCCESS;
5892  }
5893 
5894  return SCIP_OKAY;
5895 }
5896 
5898 static
5899 SCIP_DECL_CONSPRESOL(consPresolSdp)
5900 {/*lint --e{715}*/
5901  SCIP_CONSHDLRDATA* conshdlrdata;
5902  SCIP_Bool infeasible;
5903  int nprop;
5904  int c;
5905 
5906  assert( conshdlr != NULL );
5907  assert( result != NULL );
5908 
5909  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5910  assert( conshdlrdata != NULL );
5911 
5912  *result = SCIP_DIDNOTRUN;
5913 
5914  /* if some variables have been fixed or aggregated */
5915  if ( nnewfixedvars + nnewaggrvars > 0 )
5916  {
5917  /* check whether some fixed or aggregated variables can be removed from constraint */
5918  SCIP_CALL( fixAndAggrVars(scip, conss, nconss, TRUE) );
5919  }
5920 
5921  /* check for empty constraints */
5922  for (c = 0; c < nconss && *result != SCIP_CUTOFF; ++c)
5923  {
5924  SCIP_CONSDATA* consdata;
5925 
5926  assert( conss[c] != NULL );
5927  consdata = SCIPconsGetData(conss[c]);
5928  assert( consdata != NULL );
5929 
5930  /* for empty constraint check whether constant matrix is not infeasible */
5931  if ( consdata->nvars <= 0 )
5932  {
5933  SCIP_Real* constmatrix;
5934  SCIP_Real eigenvalue;
5935  int blocksize;
5936 
5937  blocksize = consdata->blocksize;
5938  SCIP_CALL( SCIPallocBufferArray(scip, &constmatrix, blocksize * blocksize) );
5939  SCIP_CALL( SCIPconsSdpGetFullConstMatrix(scip, conss[c], constmatrix) );
5940  SCIP_CALL( SCIPlapackComputeIthEigenvalue(SCIPbuffer(scip), FALSE, blocksize, constmatrix, blocksize, &eigenvalue, NULL) );
5941 
5942  /* if largest eigenvalue is positive then minus the constant matrix is not psd and we are infeasible */
5943  if ( SCIPisFeasPositive(scip, eigenvalue) )
5944  {
5945  SCIPdebugMsg(scip, "Infeasible constraint <%s> containts no variable.\n", SCIPconsGetName(conss[c]));
5946  *result = SCIP_CUTOFF;
5947  }
5948  else
5949  {
5950  SCIPdebugMsg(scip, "Feasible constraint <%s> containts no variable, removing.\n", SCIPconsGetName(conss[c]));
5951  SCIP_CALL( SCIPdelConsLocal(scip, conss[c]) );
5952  ++(ndelconss);
5953  *result = SCIP_SUCCESS;
5954  }
5955  SCIPfreeBufferArray(scip, &constmatrix);
5956  }
5957  else if ( *result == SCIP_DIDNOTRUN )
5958  *result = SCIP_DIDNOTFIND;
5959  }
5960 
5961  if ( *result == SCIP_CUTOFF )
5962  return SCIP_OKAY;
5963 
5964  /* call propagation */
5965  if ( conshdlrdata->sdpconshdlrdata->propubpresol )
5966  {
5967  SCIPdebugMsg(scip, "Propagate upper bounds of conshdlr <%s> ...\n", SCIPconshdlrGetName(conshdlr));
5968 
5969  SCIP_CALL( propagateUpperBounds(scip, conss, nconss, &infeasible, &nprop) );
5970 
5971  if ( infeasible )
5972  {
5973  SCIPdebugMsg(scip, "Presolving detected cutoff.\n");
5974  *result = SCIP_CUTOFF;
5975  return SCIP_OKAY;
5976  }
5977  else
5978  {
5979  SCIPdebugMsg(scip, "Presolving upper bounds: %d.\n", nprop);
5980  if ( nprop > 0 )
5981  {
5982  *nchgbds += nprop;
5983  *result = SCIP_SUCCESS;
5984  }
5985  }
5986  }
5987 
5988  /* add constraints in initial round */
5989  if ( SCIPconshdlrGetNPresolCalls(conshdlr) == 0 )
5990  {
5991  int noldaddconss;
5992  int nolddelconss;
5993  int noldchgbds;
5994  int noldchgcoefs;
5995 
5996  if ( *result == SCIP_DIDNOTRUN )
5997  *result = SCIP_DIDNOTFIND;
5998 
5999  noldaddconss = *naddconss;
6000  nolddelconss = *ndelconss;
6001  noldchgbds = *nchgbds;
6002  noldchgcoefs = *nchgcoefs;
6003 
6004  SCIP_CALL( move_1x1_blocks_to_lp(scip, conshdlr, conss, nconss, naddconss, ndelconss, nchgbds, &infeasible) );
6005  if ( infeasible )
6006  {
6007  *result = SCIP_CUTOFF;
6008  return SCIP_OKAY;
6009  }
6010  if ( noldaddconss != *naddconss || nolddelconss != *ndelconss || noldchgbds != *nchgbds )
6011  *result = SCIP_SUCCESS;
6012 
6013  /* possibly compute tightening of matrices */
6014  if ( conshdlrdata->sdpconshdlrdata->tightenmatrices )
6015  {
6016  SCIP_CALL( tightenMatrices(scip, conss, nconss, nchgcoefs) );
6017  if ( noldchgcoefs != *nchgcoefs )
6018  {
6019  SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Tightened %d SDP coefficient matrices.\n", *nchgcoefs - noldchgcoefs);
6020  *result = SCIP_SUCCESS;
6021  }
6022  }
6023 
6024  /* possibly tighten bounds */
6025  if ( conshdlrdata->sdpconshdlrdata->tightenbounds )
6026  {
6027  SCIP_CALL( tightenBounds(scip, conss, nconss, conshdlrdata->sdpconshdlrdata->tightenboundscont, nchgbds, &infeasible) );
6028  if ( infeasible )
6029  {
6030  *result = SCIP_CUTOFF;
6031  return SCIP_OKAY;
6032  }
6033 
6034  if ( noldchgbds != *nchgbds )
6035  {
6036  SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Tightened %d bounds using SDP constraints.\n", *nchgbds - noldchgbds);
6037  *result = SCIP_SUCCESS;
6038  }
6039  }
6040 
6041  /* In the following, we add linear constraints. This is needed only once. We assume that this is only necessary in
6042  * the main SCIP instance. The diagzeroimpl-cuts are added as basic linear constraints which are initial, as well
6043  * as separated, enforced, checked and propagated. All other linear constraints that are added below are redundant
6044  * for the SDP-constraint, and thus they are neither checked nor enforced and also not initial, so that they do
6045  * not appear in the SDP or LP relaxation. If LPs are solved, these linear constraints are separated and
6046  * propagated; if SDPs are solved, they are only propagated. */
6047  if ( SCIPgetSubscipDepth(scip) == 0 && ! conshdlrdata->sdpconshdlrdata->triedlinearconss )
6048  {
6049  int solvesdpsparam;
6050  SCIP_Bool solvesdps;
6051 
6052  SCIP_CALL( SCIPgetIntParam(scip, "misc/solvesdps", &solvesdpsparam) );
6053 
6054  if ( solvesdpsparam == 1 )
6055  solvesdps = TRUE;
6056  else
6057  solvesdps = FALSE;
6058 
6059  conshdlrdata->sdpconshdlrdata->triedlinearconss = TRUE;
6060  if ( conshdlrdata->sdpconshdlrdata->diaggezerocuts )
6061  {
6062  noldaddconss = *naddconss;
6063  noldchgbds = *nchgbds;
6064  SCIP_CALL( diagGEzero(scip, conshdlr, conss, nconss, solvesdps, naddconss, nchgbds, &infeasible) );
6065  SCIPdebugMsg(scip, "Diagonal entries: added %d constraints and changed %d bounds.\n", *naddconss - noldaddconss, *nchgbds - noldchgbds);
6066 
6067  if ( infeasible )
6068  {
6069  *result = SCIP_CUTOFF;
6070  return SCIP_OKAY;
6071  }
6072 
6073  if ( noldaddconss != *naddconss || noldchgbds != *nchgbds )
6074  {
6075  SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Added %d constraints for SDP diagonals to be nonnegative and changed %d bounds.\n", *naddconss - noldaddconss, *nchgbds - noldchgbds);
6076  *result = SCIP_SUCCESS;
6077  }
6078  }
6079 
6080  if ( *result != SCIP_CUTOFF && conshdlrdata->sdpconshdlrdata->diagzeroimplcuts )
6081  {
6082  noldaddconss = *naddconss;
6083  SCIP_CALL( diagZeroImpl(scip, conss, nconss, naddconss) );
6084  SCIPdebugMsg(scip, "Added %d constraints for implication from 0 diagonal.\n", *naddconss - noldaddconss);
6085  if ( noldaddconss != *naddconss )
6086  {
6087  SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Added %d constraints for implications on SDP diagonals.\n", *naddconss - noldaddconss);
6088  *result = SCIP_SUCCESS;
6089  }
6090  }
6091 
6092  if ( *result != SCIP_CUTOFF && conshdlrdata->sdpconshdlrdata->twominorlinconss )
6093  {
6094  noldaddconss = *naddconss;
6095  SCIP_CALL( addTwoMinorLinConstraints(scip, conss, nconss, solvesdps, naddconss) );
6096  SCIPdebugMsg(scip, "Added %d linear constraints for 2 by 2 minors.\n", *naddconss - noldaddconss);
6097  if ( noldaddconss != *naddconss )
6098  {
6099  SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Added %d linear constraints based on 2 x 2 SDP-minors.\n", *naddconss - noldaddconss);
6100  *result = SCIP_SUCCESS;
6101  }
6102  }
6103 
6104  if ( *result != SCIP_CUTOFF && conshdlrdata->sdpconshdlrdata->twominorprodconss )
6105  {
6106  noldaddconss = *naddconss;
6107  SCIP_CALL( addTwoMinorProdConstraints(scip, conss, nconss, solvesdps, naddconss) );
6108  SCIPdebugMsg(scip, "Added %d linear constraints for products of 2 by 2 minors.\n", *naddconss - noldaddconss);
6109  if ( noldaddconss != *naddconss )
6110  {
6111  SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Added %d linear constraints based on products of 2 x 2 SDP-minors.\n", *naddconss - noldaddconss);
6112  *result = SCIP_SUCCESS;
6113  }
6114  }
6115 
6116  /* add SOCP-approximation if required */
6117  if ( *result != SCIP_CUTOFF && conshdlrdata->sdpconshdlrdata->addsocrelax )
6118  {
6119  noldaddconss = *naddconss;
6120  SCIP_CALL( addTwoMinorSOCConstraints(scip, conss, nconss, solvesdps, naddconss) );
6121  SCIPdebugMsg(scip, "Added %d SOC constraints for 2 by 2 minors.\n", *naddconss - noldaddconss);
6122  if ( noldaddconss != *naddconss )
6123  *result = SCIP_SUCCESS;
6124  }
6125  }
6126 
6127  if ( SCIPgetSubscipDepth(scip) == 0 && *result != SCIP_CUTOFF && conshdlrdata->sdpconshdlrdata->quadconsrank1 )
6128  {
6129  noldaddconss = *naddconss;
6130  SCIP_CALL( addRank1QuadConss(scip, conshdlr, conss, nconss, naddconss) );
6131  SCIPdebugMsg(scip, "Added %d quadratic constraints for rank 1 constraints.\n", *naddconss - noldaddconss);
6132  if ( noldaddconss != *naddconss )
6133  *result = SCIP_SUCCESS;
6134 
6135  /* turn off upgrading in order to avoid upgrading to a rank-1 constraint again */
6136  conshdlrdata->sdpconshdlrdata->upgradequadconss = FALSE;
6137  }
6138  }
6139 
6140  /* add variable bounds based on 2x2 minors in final round */
6141  if ( SCIPisPresolveFinished(scip) && conshdlrdata->sdpconshdlrdata->twominorvarbounds && ! conshdlrdata->sdpconshdlrdata->triedvarbounds )
6142  {
6143  if ( SCIPgetSubscipDepth(scip) == 0 && *result != SCIP_CUTOFF )
6144  {
6145  int noldaddconss;
6146  int solvesdpsparam;
6147  SCIP_Bool solvesdps;
6148 
6149  SCIP_CALL( SCIPgetIntParam(scip, "misc/solvesdps", &solvesdpsparam) );
6150 
6151  if ( solvesdpsparam == 1 )
6152  solvesdps = TRUE;
6153  else
6154  solvesdps = FALSE;
6155 
6156  noldaddconss = *naddconss;
6157  SCIP_CALL( addTwoMinorVarBounds(scip, conss, nconss, solvesdps, naddconss) );
6158  SCIPdebugMsg(scip, "Added %d linear constraints for variables bounds from 2 by 2 minors.\n", *naddconss - noldaddconss);
6159  if ( noldaddconss != *naddconss )
6160  {
6161  SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Added %d linear constraints based on variable bounds from 2 x 2 SDP-minors.\n", *naddconss - noldaddconss);
6162  *result = SCIP_SUCCESS;
6163  }
6164  conshdlrdata->sdpconshdlrdata->triedvarbounds = TRUE;
6165  }
6166  }
6167 
6168  return SCIP_OKAY;
6169 }
6170 
6172 static
6173 SCIP_DECL_CONSTRANS(consTransSdp)
6174 {/*lint --e{715}*/
6175  SCIP_CONSDATA* sourcedata;
6176  SCIP_CONSDATA* targetdata;
6177  SCIP_CONSHDLRDATA* conshdlrdata;
6178 #ifndef NDEBUG
6179  int snprintfreturn; /* used to check the return code of snprintf */
6180 #endif
6181  int i;
6182  char transname[SCIP_MAXSTRLEN];
6183 
6184  sourcedata = SCIPconsGetData(sourcecons);
6185  assert( sourcedata != NULL );
6186 
6187  SCIPdebugMsg(scip, "Transforming constraint <%s>\n", SCIPconsGetName(sourcecons));
6188 
6189  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6190 
6191 #ifdef OMP
6192  SCIPdebugMsg(scip, "Setting number of threads to %d via OpenMP in Openblas.\n", conshdlrdata->sdpconshdlrdata->nthreads);
6193  omp_set_num_threads(conshdlrdata->sdpconshdlrdata->nthreads);
6194 #endif
6195 
6196  SCIP_CALL( SCIPallocBlockMemory(scip, &targetdata) );
6197 
6198  /* copy some general data */
6199  targetdata->nvars = sourcedata->nvars;
6200  targetdata->nnonz = sourcedata->nnonz;
6201  targetdata->blocksize = sourcedata->blocksize;
6202  targetdata->matrixvar = NULL;
6203  targetdata->matrixval = NULL;
6204  targetdata->matrixconst = NULL;
6205  targetdata->nsingle = 0;
6206  targetdata->tracebound = -2.0;
6207  targetdata->allmatricespsd = sourcedata->allmatricespsd;
6208  targetdata->initallmatricespsd = sourcedata->initallmatricespsd;
6209 
6210  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(targetdata->nvarnonz), sourcedata->nvarnonz, sourcedata->nvars) );
6211 
6212  /* copy the non-constant nonzeros */
6213  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(targetdata->col), sourcedata->nvars) );
6214  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(targetdata->row), sourcedata->nvars) );
6215  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(targetdata->val), sourcedata->nvars) );
6216 
6217  for (i = 0; i < sourcedata->nvars; i++)
6218  {
6219  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(targetdata->col[i]), sourcedata->col[i], sourcedata->nvarnonz[i]) );
6220  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(targetdata->row[i]), sourcedata->row[i], sourcedata->nvarnonz[i]) );
6221  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(targetdata->val[i]), sourcedata->val[i], sourcedata->nvarnonz[i]) );
6222  }
6223  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(targetdata->vars), sourcedata->nvars) );
6224  if ( sourcedata->locks != NULL )
6225  {
6226  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(targetdata->locks), sourcedata->locks, sourcedata->nvars) );
6227  }
6228  else
6229  targetdata->locks = NULL;
6230 
6231  /* copy & transform the vars array */
6232  for (i = 0; i < sourcedata->nvars; i++)
6233  {
6234  targetdata->vars[i] = SCIPvarGetTransVar(sourcedata->vars[i]);
6235  SCIP_CALL( SCIPcaptureVar(scip, targetdata->vars[i]) );
6236  }
6237 
6238  /* copy the constant nonzeros */
6239  targetdata->constnnonz = sourcedata->constnnonz;
6240 
6241  if ( sourcedata->constnnonz > 0 )
6242  {
6243  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(targetdata->constcol), sourcedata->constcol, sourcedata->constnnonz));
6244  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(targetdata->constrow), sourcedata->constrow, sourcedata->constnnonz));
6245  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(targetdata->constval), sourcedata->constval, sourcedata->constnnonz));
6246  }
6247  else
6248  {
6249  targetdata->constcol = NULL;
6250  targetdata->constrow = NULL;
6251  targetdata->constval = NULL;
6252  }
6253 
6254  /* copy the maxrhsentry */
6255  targetdata->maxrhsentry = sourcedata->maxrhsentry;
6256 
6257  /* copy rankone */
6258  targetdata->rankone = sourcedata->rankone;
6259 
6260  /* copy maxevsubmat */
6261  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(targetdata->maxevsubmat), sourcedata->maxevsubmat, 2) );
6262 
6263  /* copy addedquadcons */
6264  targetdata->addedquadcons = sourcedata->addedquadcons;
6265 
6266  /* name the transformed constraint */
6267 #ifndef NDEBUG
6268  snprintfreturn = SCIPsnprintf(transname, SCIP_MAXSTRLEN, "t_%s", SCIPconsGetName(sourcecons));
6269  assert( snprintfreturn < SCIP_MAXSTRLEN ); /* check whether the name fits into the string */
6270 #else
6271  (void) SCIPsnprintf(transname, SCIP_MAXSTRLEN, "t_%s", SCIPconsGetName(sourcecons));
6272 #endif
6273 
6274  /* create target constraint */
6275  SCIP_CALL( SCIPcreateCons(scip, targetcons, transname, conshdlr, targetdata,
6276  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
6277  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons),
6278  SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons),
6279  SCIPconsIsStickingAtNode(sourcecons)) );
6280 
6281  /* we need to compute the DIMACS tolerance (if required) at this point, because it is needed in CONSCHECK */
6282  if ( conshdlrdata->sdpconshdlrdata->usedimacsfeastol )
6283  {
6284  SCIP_VAR** vars;
6285  SCIP_Real sum = 0.0;
6286  int nvars;
6287  int v;
6288 
6289  nvars = SCIPgetNOrigVars(scip);
6290  vars = SCIPgetOrigVars(scip);
6291  for ( v = 0; v < nvars; v++ )
6292  sum += REALABS( SCIPvarGetObj(vars[v]) );
6293  conshdlrdata->dimacsfeastol = 1e-5 * (1 + sum);
6294  }
6295 
6296  return SCIP_OKAY;
6297 }
6298 
6300 static
6301 SCIP_DECL_CONSCHECK(consCheckSdp)
6302 {/*lint --e{715}*/
6303  SCIP_CONS* violcons;
6304  SCIP_CONSDATA* consdata;
6305  SCIP_CONSHDLRDATA* conshdlrdata;
6306  SCIP_VAR** linvars;
6307  SCIP_VAR* var;
6308  SCIP_SOL* bestrank1approx;
6309  SCIP_Real* fullmatrix;
6310  SCIP_Real* eigenvalues;
6311  SCIP_Real* eigenvectors;
6312  SCIP_Real* scaledeigenvectors;
6313  SCIP_Real* matrixC;
6314  SCIP_Real* matrixAj;
6315  SCIP_Real* linmatrix;
6316  SCIP_Real* rhsmatrix;
6317  SCIP_Real* lssolu;
6318  SCIP_Real* linvals;
6319  SCIP_Real* colmatrix;
6320  SCIP_Bool rank1result;
6321  SCIP_Bool stored;
6322 
6323  int c;
6324  int i;
6325  int j;
6326  int k;
6327  int l;
6328 #ifdef PRINTMATRICES
6329  int r;
6330  int s;
6331 #endif
6332  int idx;
6333  int blocksize;
6334  int nviolrank1 = 0;
6335  int nvars;
6336  int nrank1vars = 0;
6337  int linrows = 0; /* the number of rows of the linear equation system is given by the total number of entries
6338  (lower-triangular) in all violated rank-1 constraints altogether */
6339  int lincnt = 0;
6340  int nsdpvars;
6341  int* rank1considx;
6342  int* indviolrank1conss;
6343  SCIP_VAR** rank1consvars;
6344 
6345  assert( scip != NULL );
6346  assert( result != NULL );
6347  assert( conss != NULL );
6348 
6349  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6350  assert( conshdlrdata != NULL );
6351 
6352  *result = SCIP_FEASIBLE;
6353 
6354 #ifdef PRINTMATRICES
6355  SCIP_CALL( SCIPprintSol(scip, sol, NULL, FALSE) );
6356 #endif
6357 
6358  /* check positive semidefiniteness */
6359  for (i = 0; i < nconss; ++i)
6360  {
6361  SCIP_CALL( SCIPconsSdpCheckSdpCons(scip, conshdlrdata, conss[i], sol, printreason, result) );
6362 #ifdef PRINTMATRICES
6363  SCIPinfoMessage(scip, NULL, "Solution is %d for constraint %s.\n", *result, SCIPconsGetName(conss[i]) );
6364 #endif
6365  if ( *result == SCIP_INFEASIBLE )
6366  return SCIP_OKAY;
6367  }
6368 
6369  /* check if heuristic should be executed */
6370  if ( ! conshdlrdata->sdpconshdlrdata->rank1approxheur )
6371  {
6372  return SCIP_OKAY;
6373  }
6374 
6375  /* do not run in sub-SCIPs to avoid recursive reformulations due to rank 1 constraints */
6376  if ( SCIPgetSubscipDepth(scip) > 0 )
6377  return SCIP_OKAY;
6378 
6379  SCIP_CALL( SCIPallocBufferArray(scip, &indviolrank1conss, nconss) );
6380 
6381  /* check for rank-1 if necessary */
6382  SCIPdebugMsg(scip, "Check rank-1 constraints if there are any.\n");
6383  for (i = 0; i < nconss; ++i)
6384  {
6385  consdata = SCIPconsGetData(conss[i]);
6386  assert( consdata != NULL );
6387 
6388  if ( consdata->rankone )
6389  {
6390  SCIP_CALL( isMatrixRankOne(scip, conshdlrdata, conss[i], sol, &rank1result) );
6391  if ( ! rank1result )
6392  {
6393  /* save index of violated rank-1 constraint */
6394  indviolrank1conss[nviolrank1] = i;
6395  ++nviolrank1;
6396  }
6397  }
6398  }
6399 
6400  /* if there are no (violated) rank-1 constraint, we are finished. Otherwise, try to compute a feasible primal
6401  solution by computing the best rank-1 approximation for each violated rank-1 constraint and solve an LP to find a
6402  solution for the appearing variables */
6403  if ( nviolrank1 == 0 )
6404  {
6405  SCIPdebugMsg(scip, "Found no violated rank-1 constraints.\n");
6406  SCIPfreeBufferArray(scip, &indviolrank1conss);
6407  return SCIP_OKAY;
6408  }
6409 
6410  SCIPdebugMsg(scip, "Found %d violated rank-1 constraints, thus apply rank-1 approximation heuristic!\n", nviolrank1);
6411 
6412  /* we have to collect all variables appearing in violated SDPrank1-constraints first */
6413  nvars = SCIPgetNVars(scip);
6414  SCIP_CALL( SCIPallocBufferArray(scip, &rank1considx, nvars) );
6415  SCIP_CALL( SCIPallocBufferArray(scip, &rank1consvars, nvars) );
6416 
6417  for (j = 0; j < nvars; ++j)
6418  rank1considx[j] = -1;
6419 
6420  for (c = 0; c < nviolrank1; ++c)
6421  {
6422  assert( conss[indviolrank1conss[c]] != NULL );
6423 
6424  /* todo: write function to only get number of variables and variables of an SDP constraint */
6425  consdata = SCIPconsGetData(conss[indviolrank1conss[c]]);
6426  assert( consdata != NULL );
6427 
6428  nsdpvars = consdata->nvars;
6429  linrows += consdata->blocksize * (consdata->blocksize + 1) / 2;
6430 
6431  for (i = 0; i < nsdpvars; ++i)
6432  {
6433  var = consdata->vars[i];
6434  idx = SCIPvarGetProbindex(var);
6435  assert( 0 <= idx && idx < nvars );
6436  if ( rank1considx[idx] < 0 )
6437  {
6438  rank1consvars[nrank1vars] = var;
6439  rank1considx[idx] = nrank1vars++;
6440  }
6441  }
6442  }
6443 
6444  /* initialize matrix of linear equation system */
6445  SCIP_CALL( SCIPallocClearBufferArray(scip, &linmatrix, linrows * nrank1vars) );
6446  SCIP_CALL( SCIPallocClearBufferArray(scip, &rhsmatrix, MAX(linrows,nrank1vars)) );
6447 
6448  for (i = 0; i < nviolrank1; ++i)
6449  {
6450  /* get violated rank-1 constraint */
6451  violcons = conss[indviolrank1conss[i]];
6452  consdata = SCIPconsGetData(violcons);
6453 
6454  assert( consdata != NULL );
6455 
6456  blocksize = consdata->blocksize;
6457 
6458  SCIPdebugMsg(scip, "\n Start with violated rank-1 constraint %s, is %d out of %d violated rank-1 constraints.\n\n", SCIPconsGetName(violcons), i + 1, nviolrank1);
6459 
6460  /* allocate memory to store full matrix */
6461  SCIP_CALL( SCIPallocBufferArray(scip, &fullmatrix, blocksize * blocksize ) );
6462  SCIP_CALL( SCIPallocBufferArray(scip, &eigenvalues, blocksize) );
6463  SCIP_CALL( SCIPallocBufferArray(scip, &eigenvectors, blocksize * blocksize) );
6464  SCIP_CALL( SCIPallocBufferArray(scip, &matrixC, blocksize * blocksize) );
6465  SCIP_CALL( SCIPallocBufferArray(scip, &matrixAj, blocksize * blocksize) );
6466  SCIP_CALL( SCIPallocBufferArray(scip, &linvars, consdata->nvars) );
6467  SCIP_CALL( SCIPallocBufferArray(scip, &linvals, consdata->nvars) );
6468 
6469  /* compute the matrix \f$ \sum_j A_j y_j - A_0 \f$ */
6470  SCIP_CALL( computeFullSdpMatrix(scip, consdata, sol, fullmatrix) );
6471 
6472 #ifdef PRINTMATRICES
6473  /* SCIPSDP uses row-first format! */
6474  printf("Full SDP-constraint matrix Z: \n");
6475  for (j = 0; j < blocksize; ++j)
6476  {
6477  for (k = 0; k < blocksize; ++k)
6478  printf("%.5f ", fullmatrix[j*blocksize + k]);
6479  printf("\n");
6480  }
6481 
6482  /* Double-check that fullmatrix is in row-first format */
6483  printf("Full SDP-constraint matrix Z in row-first format: \n");
6484  for (j = 0; j < blocksize * blocksize; ++j)
6485  printf("%.5f ", fullmatrix[j]);
6486  printf("\n");
6487 #endif
6488 
6489  /* compute EVD */
6490  SCIP_CALL( SCIPlapackComputeEigenvectorDecomposition(SCIPbuffer(scip), blocksize, fullmatrix, eigenvalues, eigenvectors) );
6491 
6492 #ifdef PRINTMATRICES
6493  /* caution: LAPACK uses column-first format! */
6494  printf("Eigenvectors of Z: \n");
6495  for (j = 0; j < blocksize; ++j)
6496  {
6497  for (k = 0; k < blocksize; ++k)
6498  printf("%.5f ", eigenvectors[k*blocksize + j]);
6499  printf("\n");
6500  }
6501 
6502  /* Double-check that eigenvectors is in column-first format */
6503  printf("Eigenvectors of Z in column-first format: \n");
6504  for (j = 0; j < blocksize * blocksize; ++j)
6505  printf("%.5f ", eigenvectors[j]);
6506  printf("\n");
6507 
6508  printf("Eigenvalues of Z: \n");
6509  for (j = 0; j < blocksize; ++j)
6510  printf("%.5f ", eigenvalues[j]);
6511  printf("\n");
6512 #endif
6513 
6514  /* duplicate memory of eigenvectors to compute diag(0,...,0,lambda_max) * U^T */
6515  SCIP_CALL( SCIPduplicateBufferArray(scip, &scaledeigenvectors, eigenvectors, blocksize*blocksize) );
6516 
6517  /* set all eigenvalues except the largest to zero (using the property that LAPACK returns them in ascending
6518  order) */
6519  for (j = 0; j < blocksize-1; ++j)
6520  {
6521  assert( ! SCIPisFeasNegative(scip, eigenvalues[j]) ); /* otherwise constraint is not psd */
6522  eigenvalues[j] = 0.0;
6523  }
6524 
6525  /* compute diag(0,...,0,lambda_max) * U^T. Note that scaledeigenvectors on entry is U in column-first format,
6526  i.e., U^T in row-first format. Thus, on exit, scaledeigenvectors contains diag(0,...,0,lambda_max) * U^T in
6527  row-first format. */
6528  SCIP_CALL( scaleRowsMatrix(blocksize, scaledeigenvectors, eigenvalues) );
6529 
6530 #ifdef PRINTMATRICES
6531  printf("Scaled eigenvectors of Z (only keep largest eigenvalue and corresponding eigenvector) : \n");
6532  for (j = 0; j < blocksize; ++j)
6533  {
6534  for (k = 0; k < blocksize; ++k)
6535  {
6536  printf("%.5f ", scaledeigenvectors[j*blocksize + k]);
6537  }
6538  printf("\n");
6539  }
6540 
6541  /* Double-check that scaledeigenvectors is in row-first format */
6542  printf("Scaled eigenvectors of Z in row-first format: \n");
6543  for (j = 0; j < blocksize * blocksize; ++j)
6544  printf("%.5f ", scaledeigenvectors[j]);
6545  printf("\n");
6546 #endif
6547 
6548  /* compute U * [diag(0,...,0,lambda_max) * U^T]: Since eigenvectors, which contains U, already comes in LAPACK's
6549  column-first format, eigenvectors does not need to be transposed! scaledeigenvectors models
6550  [diag(0,...,0,lambda_max) * U^T in SCIPSDP's row-first format, so that scaledeigenvectors needs to be
6551  transposed for LAPACK! */
6552  SCIP_CALL( SCIPlapackMatrixMatrixMult(blocksize, blocksize, eigenvectors, FALSE, blocksize, blocksize, scaledeigenvectors,
6553  TRUE, fullmatrix) );
6554 
6555 #ifdef PRINTMATRICES
6556  printf("Best rank-1 approximation of Z: \n");
6557  for (j = 0; j < blocksize; ++j)
6558  {
6559  for (k = 0; k < blocksize; ++k)
6560  printf("%.5f ", fullmatrix[j*blocksize + k]);
6561  printf("\n");
6562  }
6563 
6564  /* Double-check that fullmatrix (best rank-1 approximation) is in row-first format */
6565  printf("Best rank-1 approximation of Z in row-first format: \n");
6566  for (j = 0; j < blocksize * blocksize; ++j)
6567  printf("%.5f ", fullmatrix[j]);
6568  printf("\n");
6569 #endif
6570 
6571  /* update linear equation system */
6572 
6573  /* compute constant matrix A_0 in row-first format*/
6574  SCIP_CALL( SCIPconsSdpGetFullConstMatrix(scip, violcons, matrixC) );
6575 
6576 #ifdef PRINTMATRICES
6577  printf("Constant matrix A_0 of SDP-constraint: \n");
6578  for (j = 0; j < blocksize; ++j)
6579  {
6580  for (k = 0; k < blocksize; ++k)
6581  printf("%.5f ", matrixC[j*blocksize + k]);
6582  printf("\n");
6583  }
6584 
6585  /* Double-check that matrixA0 is in row-first format */
6586  printf("Constant matrix A_0 of SDP-constraint in row-first format: \n");
6587  for (j = 0; j < blocksize * blocksize; ++j)
6588  printf("%.5f ", matrixC[j]);
6589  printf("\n");
6590 #endif
6591 
6592  for (j = 0; j < blocksize; ++j)
6593  {
6594  for (k = 0; k <= j; ++k)
6595  {
6596  for (l = 0; l < consdata->nvars; ++l)
6597  {
6598  /* compute matrix A_j in row-first format */
6599  SCIP_CALL( SCIPconsSdpGetFullAj(scip, violcons, l, matrixAj) );
6600 
6601 #ifdef PRINTMATRICES
6602  printf("Coefficient matrix A_%d of SDP-constraint: \n", l+1);
6603  for (r = 0; r < blocksize; ++r)
6604  {
6605  for (s = 0; s < blocksize; ++s)
6606  printf("%.5f ", matrixAj[r*blocksize + s]);
6607  printf("\n");
6608  }
6609 
6610  /* Double-check that matrixAj is in row-first format */
6611  printf("Constant matrix A_0 of SDP-constraint in row-first format: \n");
6612  for (r = 0; r < blocksize * blocksize; ++r)
6613  printf("%.5f ", matrixAj[r]);
6614  printf("\n");
6615 #endif
6616 
6617  idx = SCIPvarGetProbindex(consdata->vars[l]);
6618  idx = rank1considx[idx];
6619  assert( 0 <= idx && idx < nrank1vars );
6620  assert( lincnt <= linrows );
6621  linmatrix[lincnt * nrank1vars + idx] = matrixAj[j * blocksize + k];
6622  }
6623  rhsmatrix[lincnt] = matrixC[j * blocksize + k] + fullmatrix[j * blocksize + k];
6624  ++lincnt;
6625  }
6626  }
6627 
6628  /* free memory for full matrix, eigenvalues and eigenvectors */
6629  SCIPfreeBufferArray(scip, &linvals);
6630  SCIPfreeBufferArray(scip, &linvars);
6631  SCIPfreeBufferArray(scip, &matrixAj);
6632  SCIPfreeBufferArray(scip, &matrixC);
6633  SCIPfreeBufferArray(scip, &scaledeigenvectors);
6634  SCIPfreeBufferArray(scip, &eigenvectors);
6635  SCIPfreeBufferArray(scip, &eigenvalues);
6636  SCIPfreeBufferArray(scip, &fullmatrix);
6637  }
6638 
6639  assert( lincnt == linrows );
6640 
6641 #ifdef PRINTMATRICES
6642  printf("Matrix for linear equation system, in row-first format:\n");
6643  for (j = 0; j < linrows; ++j)
6644  {
6645  for (k = 0; k < nrank1vars; ++k)
6646  {
6647  printf("%.5f ", linmatrix[j * nrank1vars + k]);
6648  }
6649  printf("\n");
6650  }
6651 
6652  /* Double-check that linmatrix is in row-first format */
6653  printf("Matrix for linear equation system in row-first format: \n");
6654  for (r = 0; r < linrows * nrank1vars; ++r)
6655  printf("%.5f ", linmatrix[r]);
6656  printf("\n");
6657 
6658  printf("Right-hand for linear equation system:\n");
6659  for (j = 0; j < nrank1vars; ++j)
6660  {
6661  printf("%.5f ", rhsmatrix[j]);
6662  }
6663  printf("\n");
6664 #endif
6665 
6666  /* solve linear equation system with LAPACK */
6667  SCIP_CALL( SCIPallocBufferArray(scip, &lssolu, nrank1vars) );
6668 
6669  /* caution: LAPACK wants matrices in columns-first format, but SCIPSDP represents matrices in row-first format */
6670  SCIP_CALL( SCIPallocBufferArray(scip, &colmatrix, linrows * nrank1vars ) );
6671 
6672  SCIP_CALL( convertRowToColFormatFullMatrix(linrows, nrank1vars, linmatrix, colmatrix) );
6673 
6674 #ifdef PRINTMATRICES
6675  printf("Matrix for linear equation system, in col-first format:\n");
6676  for (j = 0; j < linrows; ++j)
6677  {
6678  for (l = 0; l < nrank1vars; ++l)
6679  {
6680  printf("%.5f ", colmatrix[l * linrows + j]);
6681  }
6682  printf("\n");
6683  }
6684 
6685  /* Double-check that colmatrix is in col-first format */
6686  printf("Matrix for linear equation system in col-first format: \n");
6687  for (r = 0; r < linrows * nrank1vars; ++r)
6688  printf("%.5f ", colmatrix[r]);
6689  printf("\n");
6690 #endif
6691 
6692  SCIP_CALL( SCIPlapackLinearSolve( SCIPbuffer(scip), linrows, nrank1vars, colmatrix, rhsmatrix, lssolu) );
6693 
6694  /* copy current solution */
6695  SCIP_CALL( SCIPcreateSolCopy(scip, &bestrank1approx, sol) );
6696 
6697  /* update solution with values from linear equations system solution from LAPACK */
6698  for (i = 0; i < nrank1vars; ++i)
6699  {
6700  var = rank1consvars[i];
6701  SCIP_CALL( SCIPsetSolVal(scip, bestrank1approx, var, lssolu[i]) );
6702  }
6703 
6704  SCIP_CALL( SCIPtrySolFree(scip, &bestrank1approx, FALSE, TRUE, TRUE, TRUE, TRUE, &stored) );
6705  if ( stored )
6706  SCIPdebugMsg(scip, "Best Rank-1 Approximation Heuristic found feasible primal solution\n");
6707  else
6708  SCIPdebugMsg(scip, "Primal solution found by Best Rank-1 Approximation Heuristic is not feasible!\n");
6709 
6710  SCIPfreeBufferArray(scip, &colmatrix);
6711  SCIPfreeBufferArray(scip, &lssolu);
6712  SCIPfreeBufferArray(scip, &rhsmatrix);
6713  SCIPfreeBufferArray(scip, &linmatrix);
6714  SCIPfreeBufferArray(scip, &rank1consvars);
6715  SCIPfreeBufferArray(scip, &rank1considx);
6716  SCIPfreeBufferArray(scip, &indviolrank1conss);
6717 
6718  return SCIP_OKAY;
6719 }
6720 
6725 static
6726 SCIP_DECL_CONSENFOPS(consEnfopsSdp)
6727 {/*lint --e{715}*/
6728  SCIP_CONSHDLRDATA* conshdlrdata;
6729  int i;
6730 
6731  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6732  assert( conshdlrdata != NULL );
6733 
6734  assert( scip != NULL );
6735  assert( result != NULL );
6736  assert( conss != NULL );
6737 
6738  *result = SCIP_DIDNOTRUN;
6739 
6740  if ( objinfeasible )
6741  {
6742  SCIPdebugMsg(scip, "-> pseudo solution is objective infeasible, return.\n");
6743  return SCIP_OKAY;
6744  }
6745 
6746  for (i = 0; i < nconss; ++i)
6747  {
6748  SCIP_CALL( SCIPconsSdpCheckSdpCons(scip, conshdlrdata, conss[i], NULL, FALSE, result) );
6749 
6750  if (*result == SCIP_INFEASIBLE)
6751  {
6752  /* if it is infeasible for one SDP constraint, it is infeasible for the whole problem */
6753  SCIPdebugMsg(scip, "-> pseudo solution infeasible for SDP-constraint %s, return.\n", SCIPconsGetName(conss[i]));
6754  return SCIP_OKAY;
6755  }
6756  }
6757 
6758  *result = SCIP_FEASIBLE;
6759 
6760  SCIPdebugMsg(scip, "-> pseudo solution feasible for all SDP-constraints.\n");
6761 
6762  return SCIP_OKAY;
6763 }
6764 
6765 
6768 static
6769 SCIP_DECL_CONSENFOLP(consEnfolpSdp)
6770 {/*lint --e{715}*/
6771  SCIP_CONSHDLRDATA* conshdlrdata;
6772  int c;
6773 
6774  assert( scip != NULL );
6775  assert( conshdlr != NULL );
6776  assert( conss != NULL );
6777  assert( result != NULL );
6778 
6779  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6780  assert( conshdlrdata != NULL );
6781 
6782  *result = SCIP_FEASIBLE;
6783 
6784  /* do not run if another constraint handler has declared the solution to be infeasible */
6785  if ( solinfeasible )
6786  return SCIP_OKAY;
6787 
6788  /* we first check whether the LP solution if feasible */
6789  for (c = 0; c < nconss && *result != SCIP_CUTOFF; ++c)
6790  {
6791  SCIP_RESULT separesult = SCIP_FEASIBLE;
6792 
6793  SCIP_CALL( separateSol(scip, conshdlr, conss[c], NULL, TRUE, &separesult) );
6794  assert( separesult == SCIP_FEASIBLE || separesult == SCIP_CUTOFF || separesult == SCIP_SEPARATED || separesult == SCIP_CONSADDED );
6795 
6796  if ( separesult == SCIP_CUTOFF )
6797  *result = SCIP_CUTOFF;
6798  else if ( separesult == SCIP_CONSADDED )
6799  *result = SCIP_CONSADDED;
6800  else if ( separesult == SCIP_SEPARATED )
6801  *result = SCIP_SEPARATED;
6802  }
6803 
6804  /* Below, we enforce integral solutions. If the LP is unbounded, this might not be guaranteed due to the integrality
6805  * constraint handler. In this case, we exit. The same happens if no relaxation is available or if we reached a cutoff. */
6806  if ( SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_UNBOUNDEDRAY || conshdlrdata->relaxsdp == NULL || *result == SCIP_CUTOFF )
6807  return SCIP_OKAY;
6808 
6809  /* if all integer variables have integral values, then possibly solve SDP in addtion to separation */
6810  if ( conshdlrdata->sdpconshdlrdata->enforcesdp && (*result == SCIP_SEPARATED || *result == SCIP_CONSADDED) )
6811  {
6812  SCIP_Bool cutoff;
6813  SCIP_VAR** vars;
6814  int nfixed = 0;
6815  int nintvars;
6816  int v;
6817 
6818  /* all integer variables should have integer values, because enforcing is called after the integrality constraint handler */
6819  vars = SCIPgetVars(scip);
6820  nintvars = SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip);
6821 
6822  /* check integer variables which are fixed or have integeral values (integer variables are first in list) */
6823  for (v = 0; v < nintvars; ++v)
6824  {
6825  SCIP_VAR* var;
6826 
6827  var = vars[v];
6828  assert( SCIPvarIsIntegral(var) );
6829 
6830  assert( SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, NULL, var)) );
6831  assert( SCIPisFeasIntegral(scip, SCIPvarGetLbLocal(var)) );
6832  assert( SCIPisFeasIntegral(scip, SCIPvarGetUbLocal(var)) );
6833 
6834  if ( SCIPvarGetLbLocal(var) + 0.5 > SCIPvarGetUbLocal(var) )
6835  ++nfixed;
6836  }
6837 
6838  /* solve SPD if either all integer variables are fixed or if required */
6839  if ( ! conshdlrdata->sdpconshdlrdata->onlyfixedintssdp || nfixed == nintvars )
6840  {
6841  /* start probing */
6842  SCIP_CALL( SCIPstartProbing(scip) );
6843 
6844  /* apply domain propagation (use parameter settings for maximal number of rounds) */
6845  SCIP_CALL( SCIPpropagateProbing(scip, 0, &cutoff, NULL) );
6846  if ( ! cutoff )
6847  {
6848  int freq;
6849 
6850  SCIPdebugMsg(scip, "Solving relaxation because all integer variable have integral values.\n");
6851 
6852  /* temporarily change relaxator frequency, since otherwise relaxation will not be solved */
6853  freq = SCIPrelaxGetFreq(conshdlrdata->relaxsdp);
6854  SCIP_CALL( SCIPsetIntParam(scip, "relaxing/SDP/freq", 1) );
6855 
6856  /* solve SDP */
6857  SCIP_CALL( SCIPsolveProbingRelax(scip, &cutoff) );
6858 
6859  /* reset frequency of relaxator */
6860  SCIP_CALL( SCIPsetIntParam(scip, "relaxing/SDP/freq", freq) );
6861 
6862  /* if solving was successfull */
6863  if ( SCIPrelaxSdpSolvedProbing(conshdlrdata->relaxsdp) && SCIPisRelaxSolValid(scip) )
6864  {
6865  /* if we are infeasible, we can cut off the node */
6866  if ( ! SCIPrelaxSdpIsFeasible(conshdlrdata->relaxsdp) )
6867  {
6868  SCIPdebugMsg(scip, "Cut off node in enforcing, because remaining SDP was infeasible.\n");
6869  *result = SCIP_CUTOFF;
6870  }
6871  else
6872  {
6873  SCIP_SOL* enfosol;
6874  SCIP_Bool feasible;
6875 
6876  /* if we are feasible, we check whether the solution is valid */
6877  SCIP_CALL( SCIPcreateSol(scip, &enfosol, NULL) );
6878  SCIP_CALL( SCIPlinkRelaxSol(scip, enfosol) );
6879 
6880  /* check all constraints, including integrality. Since there is an integral constraint handler,
6881  * integrality gets checked as well, so we don't need to do this manually. */
6882  SCIP_CALL( SCIPcheckSol(scip, enfosol, FALSE, TRUE, TRUE, TRUE, TRUE, &feasible) );
6883 
6884  if ( feasible )
6885  {
6886  SCIP_Bool stored;
6887 
6888  /* pass solution to SCIP */
6889  SCIP_CALL( SCIPaddSol(scip, enfosol, &stored) );
6890 
6891  /* if all integer variables are fixed, we can cut off the node, since this should be the final solution of this node */
6892  if ( stored && nintvars == nfixed )
6893  *result = SCIP_CUTOFF;
6894  }
6895  else if ( nfixed < nintvars )
6896  {
6897  /* if we have not obtained a feasible solution, we try to round it */
6898  assert( *result != SCIP_CUTOFF );
6899 
6900  for (v = 0; v < nintvars; ++v)
6901  {
6902  SCIP_Real val;
6903  SCIP_VAR* var;
6904 
6905  var = vars[v];
6906  assert( SCIPvarIsIntegral(var) );
6907 
6908  /* fix all unfixed variables */
6909  if ( SCIPvarGetLbLocal(var) + 0.5 < SCIPvarGetUbLocal(var) )
6910  {
6911  /* round relaxation value to next integer value */
6912  val = SCIPfeasFloor(scip, SCIPgetRelaxSolVal(scip, var) + 0.5);
6913 
6914  if ( ! SCIPisEQ(scip, val, SCIPvarGetUbLocal(var)) )
6915  {
6916  SCIP_CALL( SCIPchgVarUbProbing(scip, var, val) );
6917  }
6918 
6919  if ( ! SCIPisEQ(scip, val, SCIPvarGetLbLocal(var)) )
6920  {
6921  SCIP_CALL( SCIPchgVarLbProbing(scip, var, val) );
6922  }
6923  }
6924  }
6925 
6926  /* solve SDP again */
6927  SCIP_CALL( SCIPsetIntParam(scip, "relaxing/SDP/freq", 1) );
6928  SCIP_CALL( SCIPsolveProbingRelax(scip, &cutoff) );
6929  SCIP_CALL( SCIPsetIntParam(scip, "relaxing/SDP/freq", freq) );
6930 
6931  /* if solving was successfull */
6932  if ( SCIPrelaxSdpSolvedProbing(conshdlrdata->relaxsdp) && SCIPisRelaxSolValid(scip) )
6933  {
6934  if ( SCIPrelaxSdpIsFeasible(conshdlrdata->relaxsdp) )
6935  {
6936  /* if we are feasible, we check whether the solution is valid */
6937  assert( enfosol != NULL );
6938  SCIP_CALL( SCIPlinkRelaxSol(scip, enfosol) );
6939 
6940  /* Pass solution to SCIP: check all constraints, including integrality. Since there is an integral
6941  * constraint handler, integrality gets checked as well, so we don't need to do this manually. */
6942  SCIP_CALL( SCIPtrySol(scip, enfosol, FALSE, TRUE, TRUE, TRUE, TRUE, &feasible) );
6943  }
6944  }
6945  }
6946 
6947  /* We have to invalidate the relaxation solution, because SCIP will otherwise not check the relaxation solution for feasibility. */
6948  SCIP_CALL( SCIPmarkRelaxSolInvalid(scip) );
6949  SCIP_CALL( SCIPfreeSol(scip, &enfosol) );
6950  }
6951  }
6952  }
6953 
6954  /* free local problem */
6955  SCIP_CALL( SCIPendProbing(scip) );
6956  }
6957  }
6958 
6959  return SCIP_OKAY;
6960 }
6961 
6963 static
6964 SCIP_DECL_CONSENFORELAX(consEnforelaxSdp)
6965 {/*lint --e{715}*/
6966  int c;
6967 
6968  assert( scip != NULL );
6969  assert( conshdlr != NULL );
6970  assert( conss != NULL );
6971  assert( result != NULL );
6972 
6973  *result = SCIP_FEASIBLE;
6974 
6975  if ( solinfeasible )
6976  return SCIP_OKAY;
6977 
6978  /* Rounding errors might lead to infeasible relaxation solutions. We therefore perform a separation round in the hope
6979  * that this can resolve the problem. */
6980  for (c = 0; c < nconss && *result != SCIP_CUTOFF; ++c)
6981  {
6982  SCIP_RESULT separesult = SCIP_FEASIBLE;
6983 
6984  SCIP_CALL( separateSol(scip, conshdlr, conss[c], sol, TRUE, &separesult) );
6985  assert( separesult == SCIP_FEASIBLE || separesult == SCIP_CUTOFF || separesult == SCIP_SEPARATED || separesult == SCIP_CONSADDED );
6986 
6987  if ( separesult == SCIP_CUTOFF )
6988  *result = SCIP_CUTOFF;
6989  else if ( separesult == SCIP_CONSADDED )
6990  *result = SCIP_CONSADDED;
6991  else if ( separesult == SCIP_SEPARATED )
6992  *result = SCIP_SEPARATED;
6993  }
6994 
6995  return SCIP_OKAY;
6996 }
6997 
6999 static
7000 SCIP_DECL_CONSSEPASOL(consSepasolSdp)
7001 {/*lint --e{715}*/
7002  int i;
7003 
7004  assert( result != NULL );
7005  *result = SCIP_DIDNOTFIND;
7006 
7007  for (i = 0; i < nusefulconss && *result != SCIP_CUTOFF; ++i)
7008  {
7009  SCIP_RESULT separesult = SCIP_DIDNOTFIND;
7010 
7011  SCIP_CALL( separateSol(scip, conshdlr, conss[i], sol, FALSE, &separesult) );
7012  assert( separesult == SCIP_DIDNOTFIND || separesult == SCIP_CUTOFF || separesult == SCIP_SEPARATED || separesult == SCIP_CONSADDED );
7013 
7014  if ( separesult == SCIP_CUTOFF )
7015  *result = SCIP_CUTOFF;
7016  else if ( separesult == SCIP_CONSADDED )
7017  *result = SCIP_CONSADDED;
7018  else if ( separesult == SCIP_SEPARATED )
7019  *result = SCIP_SEPARATED;
7020  }
7021 
7022  return SCIP_OKAY;
7023 }
7024 
7026 static
7027 SCIP_DECL_CONSSEPALP(consSepalpSdp)
7028 {/*lint --e{715}*/
7029  int i;
7030 
7031  assert( result != NULL );
7032  *result = SCIP_DIDNOTFIND;
7033 
7034  for (i = 0; i < nusefulconss && *result != SCIP_CUTOFF; ++i)
7035  {
7036  SCIP_RESULT separesult = SCIP_DIDNOTFIND;
7037 
7038  SCIP_CALL( separateSol(scip, conshdlr, conss[i], NULL, FALSE, &separesult) );
7039 
7040  assert( separesult == SCIP_DIDNOTFIND || separesult == SCIP_CUTOFF || separesult == SCIP_SEPARATED || separesult == SCIP_CONSADDED );
7041 
7042  if ( separesult == SCIP_CUTOFF )
7043  *result = SCIP_CUTOFF;
7044  else if ( separesult == SCIP_CONSADDED )
7045  *result = SCIP_CONSADDED;
7046  else if ( separesult == SCIP_SEPARATED )
7047  *result = SCIP_SEPARATED;
7048  }
7049 
7050  return SCIP_OKAY;
7051 }
7052 
7054 static
7055 SCIP_DECL_CONSDELETE(consDeleteSdp)
7056 {/*lint --e{715}*/
7057  int i;
7058 
7059  assert( cons != NULL );
7060  assert( consdata != NULL );
7061 
7062  SCIPdebugMsg(scip, "deleting SDP constraint <%s>.\n", SCIPconsGetName(cons));
7063 
7064  /* release memory for rank one constraint */
7065  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->maxevsubmat, 2);
7066 
7067  for (i = 0; i < (*consdata)->nvars; i++)
7068  {
7069  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->val[i], (*consdata)->nvarnonz[i]);
7070  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->row[i], (*consdata)->nvarnonz[i]);
7071  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->col[i], (*consdata)->nvarnonz[i]);
7072  }
7073 
7074  /* release all variables */
7075  for (i = 0; i < (*consdata)->nvars; i++)
7076  {
7077  SCIP_CALL( SCIPreleaseVar(scip, &((*consdata)->vars[i])) );
7078  }
7079 
7080  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->vars, (*consdata)->nvars);
7081  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->locks, (*consdata)->nvars);
7082  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->constval, (*consdata)->constnnonz);
7083  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->constrow, (*consdata)->constnnonz);
7084  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->constcol, (*consdata)->constnnonz);
7085  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->val, (*consdata)->nvars);
7086  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->row, (*consdata)->nvars);
7087  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->col, (*consdata)->nvars);
7088  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->nvarnonz, (*consdata)->nvars);
7089  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->matrixval, (*consdata)->blocksize * ((*consdata)->blocksize + 1) / 2);
7090  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->matrixvar, (*consdata)->blocksize * ((*consdata)->blocksize + 1) / 2);
7091  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->matrixconst, (*consdata)->blocksize * ((*consdata)->blocksize + 1) / 2);
7092  SCIPfreeBlockMemory(scip, consdata);
7093 
7094  return SCIP_OKAY;
7095 }
7096 
7098 static
7099 SCIP_DECL_CONSFREE(consFreeSdp)
7100 {/*lint --e{715}*/
7101  SCIP_CONSHDLRDATA* conshdlrdata;
7102 
7103  SCIPdebugMsg(scip, "Freeing constraint handler <%s>.\n", SCIPconshdlrGetName(conshdlr));
7104 
7105  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7106  assert( conshdlrdata != NULL );
7107 
7108  if ( conshdlrdata->randnumgen != NULL )
7109  {
7110  SCIPfreeRandom(scip, &conshdlrdata->randnumgen);
7111  }
7112 
7113  SCIPfreeMemory(scip, &conshdlrdata);
7114  SCIPconshdlrSetData(conshdlr, NULL);
7115 
7116  return SCIP_OKAY;
7117 }
7118 
7120 static
7121 SCIP_DECL_CONSHDLRCOPY(conshdlrCopySdp)
7123  assert(scip != NULL);
7124  assert(conshdlr != NULL);
7125  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
7126 
7127  SCIP_CALL( SCIPincludeConshdlrSdp(scip) );
7128 
7129  *valid = TRUE;
7130 
7131  return SCIP_OKAY;
7132 }
7133 
7135 static
7136 SCIP_DECL_CONSHDLRCOPY(conshdlrCopySdpRank1)
7138  assert(scip != NULL);
7139  assert(conshdlr != NULL);
7140  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLRRANK1_NAME) == 0);
7141 
7142  SCIP_CALL( SCIPincludeConshdlrSdpRank1(scip) );
7143 
7144  *valid = TRUE;
7145 
7146  return SCIP_OKAY;
7147 }
7148 
7150 static
7151 SCIP_DECL_CONSCOPY(consCopySdp)
7152 {/*lint --e{715}*/
7153  char copyname[SCIP_MAXSTRLEN];
7154  SCIP_CONSDATA* sourcedata;
7155  SCIP_Bool success;
7156  SCIP_VAR** targetvars;
7157  SCIP_VAR* var;
7158  int i;
7159 #ifndef NDEBUG
7160  int snprintfreturn; /* used to check the return code of snprintf */
7161 #endif
7162 
7163  assert( scip != NULL );
7164  assert( sourcescip != NULL );
7165  assert( sourcecons != NULL );
7166  assert( valid != NULL );
7167 
7168  SCIPdebugMsg(scip, "Copying SDP constraint <%s>\n", SCIPconsGetName(sourcecons));
7169 
7170  *valid = TRUE;
7171 
7172  /* As we can only map active variables, we have to make sure, that the constraint contains no fixed or
7173  * (multi-)aggregated vars, before presolving and after presolving this should always be the case,
7174  * earlier than that we need to call fixAndAggrVars. */
7175  if ( SCIPgetStage(sourcescip) >= SCIP_STAGE_INITPRESOLVE && SCIPgetStage(sourcescip) <= SCIP_STAGE_EXITPRESOLVE )
7176  {
7177  SCIP_CALL( fixAndAggrVars(sourcescip, &sourcecons, 1, TRUE) );
7178  }
7179 
7180  sourcedata = SCIPconsGetData(sourcecons);
7181  assert( sourcedata != NULL );
7182  assert( sourcedata->rankone || strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(sourcecons)), CONSHDLR_NAME) == 0 );
7183  assert( ! sourcedata->rankone || strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(sourcecons)), CONSHDLRRANK1_NAME) == 0 );
7184 
7185  SCIP_CALL( SCIPallocBufferArray(scip, &targetvars, sourcedata->nvars) );
7186 
7187  /* map all variables in the constraint */
7188  for (i = 0; i < sourcedata->nvars; i++)
7189  {
7190  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcedata->vars[i], &var, varmap, consmap, global, &success) );
7191  if ( success )
7192  targetvars[i] = var;
7193  else
7194  *valid = FALSE;
7195  }
7196 
7197  /* name the copied constraint */
7198 #ifndef NDEBUG
7199  snprintfreturn = SCIPsnprintf(copyname, SCIP_MAXSTRLEN, "c_%s", name == NULL ? SCIPconsGetName(sourcecons) : name);
7200  assert( snprintfreturn < SCIP_MAXSTRLEN ); /* check whether the name fits into the string */
7201 #else
7202  (void) SCIPsnprintf(copyname, SCIP_MAXSTRLEN, "c_%s", name == NULL ? SCIPconsGetName(sourcecons) : name);
7203 #endif
7204 
7205  /* create the new constraint */
7206  if ( ! sourcedata->rankone )
7207  {
7208  SCIP_CALL( SCIPcreateConsSdp(scip, cons, copyname, sourcedata->nvars, sourcedata->nnonz, sourcedata->blocksize, sourcedata->nvarnonz,
7209  sourcedata->col, sourcedata->row, sourcedata->val, targetvars, sourcedata->constnnonz,
7210  sourcedata->constcol, sourcedata->constrow, sourcedata->constval, FALSE) );
7211  }
7212  else
7213  {
7214  SCIP_CALL( SCIPcreateConsSdpRank1(scip, cons, copyname, sourcedata->nvars, sourcedata->nnonz, sourcedata->blocksize, sourcedata->nvarnonz,
7215  sourcedata->col, sourcedata->row, sourcedata->val, targetvars, sourcedata->constnnonz,
7216  sourcedata->constcol, sourcedata->constrow, sourcedata->constval, FALSE) );
7217  }
7218 
7219  /* copy lock information if available */
7220  if ( sourcedata->locks != NULL )
7221  {
7222  SCIP_CONSDATA* targetdata;
7223 
7224  targetdata = SCIPconsGetData(*cons);
7225  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(targetdata->locks), sourcedata->locks, sourcedata->nvars) );
7226  targetdata->allmatricespsd = sourcedata->allmatricespsd;
7227  targetdata->initallmatricespsd = sourcedata->initallmatricespsd;
7228  }
7229 
7230  SCIPfreeBufferArray(scip, &targetvars);
7231 
7232  return SCIP_OKAY;
7233 }
7234 
7236 static
7237 SCIP_DECL_CONSPRINT(consPrintSdp)
7238 {/*lint --e{715}*/
7239 #ifdef PRINT_HUMAN_READABLE
7240  SCIP_CONSDATA* consdata;
7241  SCIP_Real* fullmatrix;
7242  int v;
7243  int i;
7244  int j;
7245 
7246  assert( scip != NULL );
7247  assert( cons != NULL );
7248 
7249  consdata = SCIPconsGetData(cons);
7250  assert( consdata != NULL );
7251 
7252  SCIP_CALL( SCIPallocBufferArray(scip, &fullmatrix, consdata->blocksize * consdata->blocksize) );
7253 
7254  /* print rank1 information */
7255  SCIPinfoMessage(scip, file, "rank-1? %d\n", consdata->rankone);
7256 
7257  /* print the non-constant matrices, for this they first have to be assembled in fullmatrix */
7258  for (v = 0; v < consdata->nvars; v++)
7259  {
7260  /* assemble the matrix */
7261 
7262  /* first initialize it with zero */
7263  for (i = 0; i < consdata->blocksize; i++)
7264  {
7265  for (j = 0; j < consdata->blocksize; j++)
7266  fullmatrix[i * consdata->blocksize + j] = 0.0; /*lint !e679*/
7267  }
7268 
7269  /* then add the nonzeros */
7270  for (i = 0; i < consdata->nvarnonz[v]; i++)
7271  {
7272  fullmatrix[consdata->row[v][i] * consdata->blocksize + consdata->col[v][i]] = consdata->val[v][i]; /* lower triangular entry */ /*lint !e679*/
7273  fullmatrix[consdata->col[v][i] * consdata->blocksize + consdata->row[v][i]] = consdata->val[v][i]; /* upper triangular entry */ /*lint !e679*/
7274  }
7275 
7276  /* print it */
7277  SCIPinfoMessage(scip, file, "+\n");
7278  for (i = 0; i < consdata->blocksize; i++)
7279  {
7280  SCIPinfoMessage(scip, file, "( ");
7281  for (j = 0; j < consdata->blocksize; j++)
7282  SCIPinfoMessage(scip, file, "%g ", fullmatrix[i * consdata->blocksize + j]); /*lint !e679*/
7283  SCIPinfoMessage(scip, file, ")\n");
7284  }
7285  SCIPinfoMessage(scip, file, "* %s\n", SCIPvarGetName(consdata->vars[v]));
7286  }
7287 
7288  /* print the constant-matrix */
7289 
7290  /* assemble the matrix */
7291 
7292  /* first initialize it with zero */
7293  for (i = 0; i < consdata->blocksize; i++)
7294  {
7295  for (j = 0; j < consdata->blocksize; j++)
7296  fullmatrix[i * consdata->blocksize + j] = 0.0; /*lint !e679*/
7297  }
7298 
7299  /* then add the nonzeros */
7300  for (i = 0; i < consdata->constnnonz; i++)
7301  {
7302  fullmatrix[consdata->constrow[i] * consdata->blocksize + consdata->constcol[i]] = consdata->constval[i]; /* lower triangular entry */ /*lint !e679*/
7303  fullmatrix[consdata->constcol[i] * consdata->blocksize + consdata->constrow[i]] = consdata->constval[i]; /* upper triangular entry */ /*lint !e679*/
7304  }
7305 
7306  /* print it */
7307  SCIPinfoMessage(scip, file, "-\n");
7308  for (i = 0; i < consdata->blocksize; i++)
7309  {
7310  SCIPinfoMessage(scip, file, "( ");
7311  for (j = 0; j < consdata->blocksize; j++)
7312  SCIPinfoMessage(scip, file, "%g ", fullmatrix[i * consdata->blocksize + j]); /*lint !e679*/
7313  SCIPinfoMessage(scip, file, ")\n");
7314  }
7315  SCIPinfoMessage(scip, file, ">= 0\n");
7316 
7317  /* print rank1 information */
7318  SCIPinfoMessage(scip, file, "rank-1? %d\n", consdata->rankone);
7319 
7320  SCIPfreeBufferArray(scip, &fullmatrix);
7321 
7322  return SCIP_OKAY;
7323 #else
7324  SCIP_CONSDATA* consdata;
7325  int i;
7326  int v;
7327 
7328  assert( scip != NULL );
7329  assert( cons != NULL );
7330 
7331  consdata = SCIPconsGetData(cons);
7332 
7333  /* print blocksize */
7334  SCIPinfoMessage(scip, file, "%d\n", consdata->blocksize);
7335 
7336  /* print rank1 information */
7337  SCIPinfoMessage(scip, file, " rank-1? %u\n", consdata->rankone);
7338 
7339  /* print A_0 if it exists */
7340  if ( consdata->constnnonz > 0 )
7341  {
7342  SCIPinfoMessage(scip, file, " A_0: ");
7343 
7344  for (i = 0; i < consdata->constnnonz; i++)
7345  {
7346  if ( i < consdata->constnnonz - 1 )
7347  SCIPinfoMessage(scip, file, "(%d,%d):%.15g, ", consdata->constrow[i], consdata->constcol[i], consdata->constval[i]);
7348  else
7349  SCIPinfoMessage(scip, file, "(%d,%d):%.15g", consdata->constrow[i], consdata->constcol[i], consdata->constval[i]);
7350  }
7351  SCIPinfoMessage(scip, file, "\n");
7352  }
7353 
7354  /* print other matrices */
7355  for (v = 0; v < consdata->nvars; v++)
7356  {
7357  SCIPinfoMessage(scip, file, " <%s>: ", SCIPvarGetName(consdata->vars[v]));
7358  for (i = 0; i < consdata->nvarnonz[v]; i++)
7359  {
7360  if ( i < consdata->nvarnonz[v] - 1 || v < consdata->nvars - 1 )
7361  SCIPinfoMessage(scip, file, "(%d,%d):%.15g, ", consdata->row[v][i], consdata->col[v][i], consdata->val[v][i]);
7362  else
7363  SCIPinfoMessage(scip, file, "(%d,%d):%.15g", consdata->row[v][i], consdata->col[v][i], consdata->val[v][i]);
7364  }
7365  /* if this is not the last variable, add a newline */
7366  if (v < consdata->nvars - 1)
7367  {
7368  SCIPinfoMessage(scip, file, "\n");
7369  }
7370  }
7371 
7372  return SCIP_OKAY;
7373 #endif
7374 }
7375 
7377 static
7378 SCIP_DECL_CONSPARSE(consParseSdp)
7379 { /*lint --e{715}*/
7380  SCIP_Bool parsesuccess;
7381  SCIP_CONSDATA* consdata = NULL;
7382  char* pos;
7383  int currentsize;
7384  int nvars;
7385  int i;
7386  int v;
7387  int rankoneint;
7388 
7389  assert( scip != NULL );
7390  assert( str != NULL );
7391 
7392  nvars = SCIPgetNVars(scip);
7393 
7394  assert( success != NULL );
7395  *success = TRUE;
7396 
7397  /* create constraint data */
7398  SCIP_CALL( SCIPallocBlockMemory(scip, &consdata) );
7399  consdata->nvars = 0;
7400  consdata->nnonz = 0;
7401  consdata->constnnonz = 0;
7402  consdata->rankone = 0;
7403  consdata->addedquadcons = FALSE;
7404  consdata->locks = NULL;
7405  consdata->matrixvar = NULL;
7406  consdata->matrixval = NULL;
7407  consdata->matrixconst = NULL;
7408  consdata->nsingle = 0;
7409  consdata->tracebound = -2.0;
7410  consdata->allmatricespsd = FALSE;
7411  consdata->initallmatricespsd = FALSE;
7412 
7413  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->nvarnonz, nvars) );
7414  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->col, nvars) );
7415  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->row, nvars) );
7416  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->val, nvars) );
7417  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->vars, nvars));
7418 
7419  consdata->constcol = NULL;
7420  consdata->constrow = NULL;
7421  consdata->constval = NULL;
7422 
7423  /* parse the blocksize */
7424  parsesuccess = SCIPstrToIntValue(str, &(consdata->blocksize), &pos);
7425  *success = *success && parsesuccess;
7426 
7427  /* skip whitespace */
7428  while ( isspace((unsigned char)*pos) )
7429  pos++;
7430 
7431  /* parse the rank1-information */
7432  if ( pos[0] == 'r' && pos[1] == 'a' && pos[2] == 'n' && pos[3] == 'k' && pos[4] == '-' && pos[5] == '1' && pos[6] == '?' )
7433  {
7434  pos += 8; /* we skip "rank1-? " */
7435  parsesuccess = SCIPstrToIntValue(pos, &rankoneint, &pos);
7436  consdata->rankone = (SCIP_Bool) rankoneint;
7437  *success = *success && parsesuccess;
7438  }
7439 
7440  /* skip whitespace */
7441  while( isspace((unsigned char)*pos) )
7442  pos++;
7443 
7444  /* check if there is a constant part */
7445  if ( pos[0] == 'A' && pos[1] == '_' && pos[2] == '0' )
7446  {
7447  pos += 5; /* we skip "A_0: " */
7448 
7449  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->constcol, PARSE_STARTSIZE) );
7450  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->constrow, PARSE_STARTSIZE) );
7451  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->constval, PARSE_STARTSIZE) );
7452 
7453  currentsize = PARSE_STARTSIZE;
7454 
7455  /* as long as there is another entry for the constant part, parse it */
7456  while (pos[0] == '(')
7457  {
7458  pos++; /* remove the '(' */
7459 
7460  /* check if we need to enlarge the arrays */
7461  if ( consdata->constnnonz == currentsize )
7462  {
7463  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->constcol, currentsize, PARSE_SIZEFACTOR * currentsize) );
7464  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->constrow, currentsize, PARSE_SIZEFACTOR * currentsize) );
7465  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->constval, currentsize, PARSE_SIZEFACTOR * currentsize) );
7466  currentsize *= PARSE_SIZEFACTOR;
7467  }
7468 
7469  parsesuccess = SCIPstrToIntValue(pos, &(consdata->constrow[consdata->constnnonz]), &pos);
7470  *success = *success && parsesuccess;
7471  assert( consdata->constrow[consdata->constnnonz] < consdata->blocksize );
7472  pos++; /* remove the ',' */
7473  parsesuccess = SCIPstrToIntValue(pos, &(consdata->constcol[consdata->constnnonz]), &pos);
7474  *success = *success && parsesuccess;
7475  assert( consdata->constcol[consdata->constnnonz] < consdata->blocksize );
7476  pos += 2; /* remove the "):" */
7477  parsesuccess = SCIPstrToRealValue(pos, &(consdata->constval[consdata->constnnonz]), &pos);
7478  *success = *success && parsesuccess;
7479  pos ++; /* remove the "," */
7480 
7481  /* if we got an entry in the upper triangular part, switch the entries for lower triangular */
7482  if ( consdata->constcol[consdata->constnnonz] > consdata->constrow[consdata->constnnonz] )
7483  {
7484  i = consdata->constcol[consdata->constnnonz];
7485  consdata->constcol[consdata->constnnonz] = consdata->constrow[consdata->constnnonz];
7486  consdata->constrow[consdata->constnnonz] = i;
7487  }
7488 
7489  consdata->constnnonz++;
7490 
7491  /* skip whitespace */
7492  while( isspace((unsigned char)*pos) )
7493  pos++;
7494  }
7495 
7496  /* resize the arrays to their final size */
7497  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->constcol, currentsize, consdata->constnnonz) );
7498  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->constrow, currentsize, consdata->constnnonz) );
7499  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->constval, currentsize, consdata->constnnonz) );
7500  }
7501 
7502  /* skip whitespace */
7503  while( isspace((unsigned char)*pos) )
7504  pos++;
7505 
7506  /* parse the non-constant part */
7507 
7508  /* while there is another variable, parse it */
7509  while ( pos[0] == '<' )
7510  {
7511  /* add the variable to consdata->vars and create the corresponding nonzero arrays */
7512  SCIP_CALL( SCIPparseVarName(scip, pos, &(consdata->vars[consdata->nvars]), &pos) );
7513  SCIP_CALL( SCIPcaptureVar(scip, consdata->vars[consdata->nvars]) );
7514 
7515  consdata->nvarnonz[consdata->nvars] = 0;
7516  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(consdata->col[consdata->nvars]), PARSE_STARTSIZE));
7517  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(consdata->row[consdata->nvars]), PARSE_STARTSIZE));
7518  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(consdata->val[consdata->nvars]), PARSE_STARTSIZE));
7519  consdata->nvars++;
7520  currentsize = PARSE_STARTSIZE;
7521 
7522  pos += 2; /* remove the ": " */
7523 
7524  /* while there is another entry, parse it */
7525  while (pos[0] == '(')
7526  {
7527  pos++; /* remove the '(' */
7528 
7529  /* check if we need to enlarge the arrays */
7530  if ( consdata->nvarnonz[consdata->nvars - 1] == currentsize )
7531  {
7532  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->col[consdata->nvars - 1], currentsize, PARSE_SIZEFACTOR * currentsize) );
7533  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->row[consdata->nvars - 1], currentsize, PARSE_SIZEFACTOR * currentsize) );
7534  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->val[consdata->nvars - 1], currentsize, PARSE_SIZEFACTOR * currentsize) );
7535  currentsize *= PARSE_SIZEFACTOR;
7536  }
7537 
7538  parsesuccess = SCIPstrToIntValue(pos, &(consdata->row[consdata->nvars - 1][consdata->nvarnonz[consdata->nvars - 1]]), &pos);
7539  *success = *success && parsesuccess;
7540  assert( consdata->row[consdata->nvars - 1][consdata->nvarnonz[consdata->nvars - 1]] < consdata->blocksize );
7541  pos++; /* remove the ',' */
7542  parsesuccess = SCIPstrToIntValue(pos, &(consdata->col[consdata->nvars - 1][consdata->nvarnonz[consdata->nvars - 1]]), &pos);
7543  *success = *success && parsesuccess;
7544  assert( consdata->col[consdata->nvars - 1][consdata->nvarnonz[consdata->nvars - 1]] < consdata->blocksize );
7545  pos += 2; /* remove the "):" */
7546  parsesuccess = SCIPstrToRealValue(pos, &(consdata->val[consdata->nvars - 1][consdata->nvarnonz[consdata->nvars - 1]]), &pos);
7547  *success = *success && parsesuccess;
7548  if ( *pos != '\0' )
7549  pos ++; /* remove the "," */
7550 
7551  /* if we got an entry in the upper triangular part, switch the entries for lower triangular */
7552  if ( consdata->col[consdata->nvars - 1][consdata->nvarnonz[consdata->nvars - 1]] >
7553  consdata->row[consdata->nvars - 1][consdata->nvarnonz[consdata->nvars - 1]] )
7554  {
7555  i = consdata->col[consdata->nvars - 1][consdata->nvarnonz[consdata->nvars - 1]];
7556  consdata->col[consdata->nvars - 1][consdata->nvarnonz[consdata->nvars - 1]] =
7557  consdata->row[consdata->nvars - 1][consdata->nvarnonz[consdata->nvars - 1]];
7558  consdata->row[consdata->nvars - 1][consdata->nvarnonz[consdata->nvars - 1]] = i;
7559  }
7560 
7561  consdata->nvarnonz[consdata->nvars - 1]++;
7562 
7563  /* skip whitespace */
7564  while( isspace((unsigned char)*pos) )
7565  pos++;
7566  }
7567 
7568  /* resize the arrays to their final size */
7569  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->col[consdata->nvars - 1], currentsize, consdata->nvarnonz[consdata->nvars - 1]) );
7570  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->row[consdata->nvars - 1], currentsize, consdata->nvarnonz[consdata->nvars - 1]) );
7571  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->val[consdata->nvars - 1], currentsize, consdata->nvarnonz[consdata->nvars - 1]) );
7572 
7573  /* skip whitespace */
7574  while ( isspace((unsigned char)*pos) )
7575  pos++;
7576  }
7577 
7578  /* resize the arrays to their final size */
7579  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->nvarnonz, nvars, consdata->nvars) );
7580  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->col, nvars, consdata->nvars) );
7581  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->row, nvars, consdata->nvars) );
7582  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->val, nvars, consdata->nvars) );
7583  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, nvars, consdata->nvars));
7584 
7585  /* compute sdpnnonz */
7586  for (v = 0; v < consdata->nvars; v++)
7587  consdata->nnonz += consdata->nvarnonz[v];
7588 
7589  /* set maxevsubmat */
7590  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->maxevsubmat, 2) );
7591  consdata->maxevsubmat[0] = -1;
7592  consdata->maxevsubmat[1] = -1;
7593 
7594  /* create the constraint */
7595  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate, local, modifiable,
7596  dynamic, removable, stickingatnode) );
7597 
7598  /* compute maximum rhs entry for later use in the DIMACS Error Norm */
7599  SCIP_CALL( setMaxRhsEntry(*cons) );
7600 
7601 #ifdef SCIP_MORE_DEBUG
7602  SCIP_CALL( SCIPprintCons(scip, *cons, NULL) );
7603 #endif
7604 
7605  return SCIP_OKAY;
7606 }
7607 
7609 static
7610 SCIP_DECL_CONSGETVARS(consGetVarsSdp)
7611 {/*lint --e{715}*/
7612  SCIP_CONSDATA* consdata;
7613  int nvars;
7614  int i;
7615 
7616  assert( scip != NULL );
7617  assert( cons != NULL );
7618  assert( vars != NULL );
7619  assert( success != NULL );
7620  assert( varssize >= 0 );
7621 
7622  consdata = SCIPconsGetData(cons);
7623  assert( consdata != NULL );
7624 
7625  nvars = consdata->nvars;
7626 
7627  if ( nvars > varssize )
7628  {
7629  SCIPdebugMsg(scip, "consGetVarsIndicator called for array of size %d, needed size %d.\n", varssize, nvars);
7630  *success = FALSE;
7631  return SCIP_OKAY;
7632  }
7633 
7634  for (i = 0; i < nvars; i++)
7635  vars[i] = consdata->vars[i];
7636 
7637  *success = TRUE;
7638 
7639  return SCIP_OKAY;
7640 }
7641 
7643 static
7644 SCIP_DECL_CONSGETNVARS(consGetNVarsSdp)
7645 {/*lint --e{715}*/
7646  SCIP_CONSDATA* consdata;
7647 
7648  assert( scip != NULL );
7649  assert( cons != NULL );
7650  assert( nvars != NULL );
7651  assert( success != NULL );
7652 
7653  consdata = SCIPconsGetData(cons);
7654  assert( consdata != NULL );
7655 
7656  *nvars = consdata->nvars;
7657  *success = TRUE;
7658 
7659  return SCIP_OKAY;
7660 }
7661 
7663 SCIP_RETCODE SCIPincludeConshdlrSdp(
7664  SCIP* scip
7665  )
7666 {
7667  SCIP_CONSHDLR* conshdlr = NULL;
7668  SCIP_CONSHDLRDATA* conshdlrdata = NULL;
7669 
7670  assert( scip != NULL );
7671 
7672  /* allocate memory for the conshdlrdata */
7673  SCIP_CALL( SCIPallocMemory(scip, &conshdlrdata) );
7674  conshdlrdata->quadconsidx = NULL;
7675  conshdlrdata->quadconsvars = NULL;
7676  conshdlrdata->nquadconsidx = 0;
7677  conshdlrdata->X = NULL;
7678  conshdlrdata->nsdpvars = 0;
7679  conshdlrdata->sdpcons = NULL;
7680  conshdlrdata->triedlinearconss = FALSE;
7681  conshdlrdata->triedvarbounds = FALSE;
7682  conshdlrdata->randnumgen = NULL;
7683  conshdlrdata->relaxsdp = NULL;
7684  conshdlrdata->sdpconshdlrdata = conshdlrdata; /* set this to itself to simplify access of parameters */
7685  conshdlrdata->dimacsfeastol = SCIP_INVALID;
7686 
7687  /* include constraint handler */
7688  SCIP_CALL( SCIPincludeConshdlrBasic(scip, &conshdlr, CONSHDLR_NAME, CONSHDLR_DESC,
7690  consEnfolpSdp, consEnfopsSdp, consCheckSdp, consLockSdp, conshdlrdata) );
7691 
7692  assert( conshdlr != NULL );
7693 
7694  /* set non-fundamental callbacks via specific setter functions */
7695  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteSdp) );
7696  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeSdp) );
7697  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopySdp, consCopySdp) );
7698  SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr,consInitpreSdp) );
7699  SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitSdp) );
7700  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreSdp) );
7701  SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolSdp) );
7702  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolSdp, CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
7703  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropSdp, CONSHDLR_PROPFREQ, FALSE, CONSHDLR_PROPTIMING) );
7704  SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropSdp) );
7705  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpSdp, consSepasolSdp, CONSHDLR_SEPAFREQ,
7707  SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxSdp) );
7708  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransSdp) );
7709  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintSdp) );
7710  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseSdp) );
7711  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsSdp) );
7712  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsSdp) );
7713 
7714  /* add parameter */
7715 #ifdef OMP
7716  SCIP_CALL( SCIPaddIntParam(scip, "constraints/SDP/threads", "number of threads used for OpenBLAS",
7717  &(conshdlrdata->nthreads), TRUE, DEFAULT_NTHREADS, 1, INT_MAX, NULL, NULL) );
7718 #endif
7719 
7720  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/SDP/propupperbounds",
7721  "Should upper bounds be propagated?",
7722  &(conshdlrdata->propupperbounds), TRUE, DEFAULT_PROPUPPERBOUNDS, NULL, NULL) );
7723 
7724  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/SDP/propubpresol",
7725  "Should upper bounds be propagated in presolving?",
7726  &(conshdlrdata->propubpresol), TRUE, DEFAULT_PROPUBPRESOL, NULL, NULL) );
7727 
7728  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/SDP/proptightenbounds",
7729  "Should tighten bounds be propagated?",
7730  &(conshdlrdata->proptightenbounds), TRUE, DEFAULT_PROPTIGHTENBOUNDS, NULL, NULL) );
7731 
7732  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/SDP/proptbprobing",
7733  "Should tighten bounds be propagated in probing?",
7734  &(conshdlrdata->proptbprobing), TRUE, DEFAULT_PROPTBPROBING, NULL, NULL) );
7735 
7736  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/SDP/tightenboundscont",
7737  "Should only bounds be tightend for continuous variables?",
7738  &(conshdlrdata->tightenboundscont), TRUE, DEFAULT_TIGHTENBOUNDSCONT, NULL, NULL) );
7739 
7740  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/SDP/tightenmatrices",
7741  "If all matrices are psd, should the matrices be tightened if possible?",
7742  &(conshdlrdata->tightenmatrices), TRUE, DEFAULT_TIGHTENMATRICES, NULL, NULL) );
7743 
7744  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/SDP/tightenbounds",
7745  "If all matrices are psd, should the bounds be tightened if possible?",
7746  &(conshdlrdata->tightenbounds), TRUE, DEFAULT_TIGHTENBOUNDS, NULL, NULL) );
7747 
7748  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/SDP/diaggezerocuts",
7749  "Should linear cuts enforcing the non-negativity of diagonal entries of SDP-matrices be added?",
7750  &(conshdlrdata->diaggezerocuts), TRUE, DEFAULT_DIAGGEZEROCUTS, NULL, NULL) );
7751 
7752  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/SDP/diagzeroimplcuts",
7753  "Should linear cuts enforcing the implications of diagonal entries of zero in SDP-matrices be added?",
7754  &(conshdlrdata->diagzeroimplcuts), TRUE, DEFAULT_DIAGZEROIMPLCUTS, NULL, NULL) );
7755 
7756  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/SDP/twominorlinconss",
7757  "Should linear cuts corresponding to 2 by 2 minors be added?",
7758  &(conshdlrdata->twominorlinconss), TRUE, DEFAULT_TWOMINORLINCONSS, NULL, NULL) );
7759 
7760  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/SDP/twominorprodconss",
7761  "Should linear cuts corresponding to products of 2 by 2 minors be added?",
7762  &(conshdlrdata->twominorprodconss), TRUE, DEFAULT_TWOMINORPRODCONSS, NULL, NULL) );
7763 
7764  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/SDP/twominorvarbounds",
7765  "Should linear cuts corresponding to variable bounds for 2 by 2 minors be added?",
7766  &(conshdlrdata->twominorvarbounds), TRUE, DEFAULT_TWOMINORVARBOUNDS, NULL, NULL) );
7767 
7768  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/SDP/quadconsrank1",
7769  "Should quadratic cons for 2x2 minors be added in the rank-1 case?",
7770  &(conshdlrdata->quadconsrank1), TRUE, DEFAULT_QUADCONSRANK1, NULL, NULL) );
7771 
7772  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/SDP/upgradequadconss",
7773  "Should quadratic constraints be upgraded to a rank 1 SDP?",
7774  &(conshdlrdata->upgradequadconss), TRUE, DEFAULT_UPGRADEQUADCONSS, NULL, NULL) );
7775 
7776  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/SDP/upgradekeepquad",
7777  "Should the quadratic constraints be kept in the problem after upgrading and the corresponding SDP constraint be added without the rank 1 constraint?",
7778  &(conshdlrdata->upgradekeepquad), TRUE, DEFAULT_UPGRADEKEEPQUAD, NULL, NULL) );
7779 
7780  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/SDP/separateonecut",
7781  "Should only one cut corresponding to the most negative eigenvalue be separated?",
7782  &(conshdlrdata->separateonecut), TRUE, DEFAULT_SEPARATEONECUT, NULL, NULL) );
7783 
7784  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/SDP/cutstopool",
7785  "Should the cuts be added to the pool?",
7786  &(conshdlrdata->cutstopool), TRUE, DEFAULT_CUTSTOPOOL, NULL, NULL) );
7787 
7788  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/SDP/sparsifycut",
7789  "Should the eigenvector cuts be sparsified?",
7790  &(conshdlrdata->sparsifycut), TRUE, DEFAULT_SPARSIFYCUT, NULL, NULL) );
7791 
7792  SCIP_CALL( SCIPaddRealParam(scip, "constraints/SDP/sparsifyfactor",
7793  "target size for sparsification in relation to number of variables",
7794  &(conshdlrdata->sparsifyfactor), TRUE, DEFAULT_SPARSIFYFACTOR, 0.0, 1.0, NULL, NULL) );
7795 
7796  SCIP_CALL( SCIPaddIntParam(scip, "constraints/SDP/sparsifytargetsize",
7797  "absolute target size for sparsification (-1: use sparsifyfactor instead)",
7798  &(conshdlrdata->sparsifytargetsize), TRUE, DEFAULT_SPARSIFYTARGETSIZE, -1, INT_MAX, NULL, NULL) );
7799 
7800  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/SDP/multiplesparsecuts",
7801  "Should multiple sparsified eigenvector cuts be added?",
7802  &(conshdlrdata->multiplesparsecuts), TRUE, DEFAULT_MULTIPLESPARSECUTS, NULL, NULL) );
7803 
7804  SCIP_CALL( SCIPaddIntParam(scip, "constraints/SDP/maxnsparsecuts",
7805  "maximal number of sparse eigenvector cuts that should be added (-1: no limit)",
7806  &(conshdlrdata->maxnsparsecuts), TRUE, DEFAULT_MAXNSPARSECUTS, -1, INT_MAX, NULL, NULL) );
7807 
7808  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/SDP/enforcesdp",
7809  "Solve SDP if we do lp-solving and have an integral solution in enforcing?",
7810  &(conshdlrdata->enforcesdp), TRUE, DEFAULT_ENFORCESDP, NULL, NULL) );
7811 
7812  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/SDP/onlyfixedintssdp",
7813  "Should solving an SDP only be applied if all integral variables are fixed (instead of having integral values)?",
7814  &(conshdlrdata->onlyfixedintssdp), TRUE, DEFAULT_ONLYFIXEDINTSSDP, NULL, NULL) );
7815 
7816  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/SDP/addsocrelax",
7817  "Should a relaxation of SOC constraints be added?",
7818  &(conshdlrdata->addsocrelax), TRUE, DEFAULT_ADDSOCRELAX, NULL, NULL) );
7819 
7820  SCIP_CALL( SCIPaddIntParam(scip, "constraints/SDP/maxnvarsquadupgd",
7821  "maximal number of quadratic constraints and appearing variables so that the QUADCONSUPGD is performed",
7822  &(conshdlrdata->maxnvarsquadupgd), TRUE, DEFAULT_MAXNVARSQUADUPGD, 0, INT_MAX, NULL, NULL) );
7823 
7824  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/SDP/rank1approxheur",
7825  "Should the heuristic that computes the best rank-1 approximation for a given solution be executed?",
7826  &(conshdlrdata->rank1approxheur), TRUE, DEFAULT_RANK1APPROXHEUR, NULL, NULL) );
7827 
7828  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/SDP/usedimacsfeastol",
7829  "Should a feasibility tolerance based on the DIMACS be used for computing negative eigenvalues?",
7830  &(conshdlrdata->usedimacsfeastol), TRUE, DEFAULT_USEDIMACSFEASTOL, NULL, NULL) );
7831 
7832  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/SDP/generaterows",
7833  "Should rows be generated (constraints otherwise)?",
7834  &(conshdlrdata->generaterows), TRUE, DEFAULT_GENERATEROWS, NULL, NULL) );
7835 
7836  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/SDP/recomputesparseev",
7837  "Should the sparse eigenvalue returned from TPower be recomputed exactly by using Lapack for the corresponding submatrix?",
7838  &(conshdlrdata->recomputesparseev), TRUE, DEFAULT_RECOMPUTESPARSEEV, NULL, NULL) );
7839 
7840  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/SDP/recomputeinitial",
7841  "Should the inital vector for TPower be computed each time before calling TPower (instead of using the original smallest eigenvector)?",
7842  &(conshdlrdata->recomputeinitial), TRUE, DEFAULT_RECOMPUTEINITIAL, NULL, NULL) );
7843 
7844  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/SDP/exacttrans",
7845  "Should the matrix be transformed with the exact maximal eigenvalue before calling TPower (instead of using estimate)?",
7846  &(conshdlrdata->exacttrans), TRUE, DEFAULT_EXACTTRANS, NULL, NULL) );
7847 
7848  return SCIP_OKAY;
7849 }
7850 
7852 SCIP_RETCODE SCIPincludeConshdlrSdpRank1(
7853  SCIP* scip
7854  )
7855 {
7856  SCIP_CONSHDLR* conshdlr = NULL;
7857  SCIP_CONSHDLR* sdpconshdlr;
7858  SCIP_CONSHDLRDATA* conshdlrdata = NULL;
7859 
7860  assert( scip != NULL );
7861 
7862  /* allocate memory for the conshdlrdata */
7863  SCIP_CALL( SCIPallocMemory(scip, &conshdlrdata) );
7864 
7865  /* only use one parameter */
7866  conshdlrdata->diaggezerocuts = FALSE;
7867  conshdlrdata->propupperbounds = FALSE;
7868  conshdlrdata->propubpresol = FALSE;
7869  conshdlrdata->proptightenbounds = FALSE;
7870  conshdlrdata->proptbprobing = FALSE;
7871  conshdlrdata->tightenboundscont = FALSE;
7872  conshdlrdata->tightenmatrices = FALSE;
7873  conshdlrdata->tightenbounds = FALSE;
7874  conshdlrdata->diagzeroimplcuts = FALSE;
7875  conshdlrdata->twominorlinconss = FALSE;
7876  conshdlrdata->twominorprodconss = FALSE;
7877  conshdlrdata->twominorvarbounds = FALSE;
7878  conshdlrdata->quadconsrank1 = FALSE;
7879  conshdlrdata->upgradequadconss = FALSE;
7880  conshdlrdata->upgradekeepquad = FALSE;
7881  conshdlrdata->separateonecut = FALSE;
7882  conshdlrdata->cutstopool = FALSE;
7883  conshdlrdata->sparsifycut = FALSE;
7884  conshdlrdata->sparsifyfactor = SCIP_INVALID;
7885  conshdlrdata->sparsifytargetsize = -1;
7886  conshdlrdata->multiplesparsecuts = FALSE;
7887  conshdlrdata->maxnsparsecuts = 0;
7888  conshdlrdata->enforcesdp = FALSE;
7889  conshdlrdata->onlyfixedintssdp = FALSE;
7890  conshdlrdata->addsocrelax = FALSE;
7891  conshdlrdata->maxnvarsquadupgd = 0;
7892  conshdlrdata->triedlinearconss = FALSE;
7893  conshdlrdata->triedvarbounds = FALSE;
7894  conshdlrdata->rank1approxheur = FALSE;
7895  conshdlrdata->generaterows = FALSE;
7896 #ifdef OMP
7897  conshdlrdata->nthreads = 0;
7898 #endif
7899  conshdlrdata->usedimacsfeastol = FALSE;
7900  conshdlrdata->recomputesparseev = FALSE;
7901  conshdlrdata->recomputeinitial = FALSE;
7902  conshdlrdata->exacttrans = FALSE;
7903 
7904  /* parameters are retrieved through the SDP constraint handler */
7905  sdpconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
7906  if ( sdpconshdlr == NULL )
7907  {
7908  SCIPerrorMessage("Needs constraint handler <%s> to work.\n", CONSHDLR_NAME);
7909  return SCIP_PLUGINNOTFOUND;
7910  }
7911  conshdlrdata->sdpconshdlrdata = SCIPconshdlrGetData(sdpconshdlr);
7912  assert( conshdlrdata->sdpconshdlrdata != NULL );
7913 
7914  conshdlrdata->quadconsidx = NULL;
7915  conshdlrdata->quadconsvars = NULL;
7916  conshdlrdata->nquadconsidx = 0;
7917  conshdlrdata->X = NULL;
7918  conshdlrdata->nsdpvars = 0;
7919  conshdlrdata->sdpcons = NULL;
7920  conshdlrdata->randnumgen = NULL;
7921  conshdlrdata->relaxsdp = NULL;
7922  conshdlrdata->dimacsfeastol = SCIP_INVALID;
7923 
7924  /* include constraint handler */
7925  SCIP_CALL( SCIPincludeConshdlrBasic(scip, &conshdlr, CONSHDLRRANK1_NAME, CONSHDLRRANK1_DESC,
7927  consEnfolpSdp, consEnfopsSdp, consCheckSdp, consLockSdp, conshdlrdata) );
7928 
7929  assert( conshdlr != NULL );
7930 
7931  /* set non-fundamental callbacks via specific setter functions */
7932  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteSdp) );
7933  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeSdp) );
7934  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopySdpRank1, consCopySdp) );
7935  SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr,consInitpreSdp) );
7936  SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitSdp) );
7937  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreSdp) );
7938  SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolSdp) );
7939  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolSdp, CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
7940  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropSdp, CONSHDLR_PROPFREQ, FALSE, CONSHDLR_PROPTIMING) );
7941  SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropSdp) );
7942  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpSdp, consSepasolSdp, CONSHDLR_SEPAFREQ,
7944  SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxSdp) );
7945  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransSdp) );
7946  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintSdp) );
7947  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseSdp) );
7948  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsSdp) );
7949  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsSdp) );
7950 
7951  /* include upgrading function for quadratic constraints */
7952 #if ( SCIP_VERSION >= 800 || ( SCIP_VERSION < 800 && SCIP_APIVERSION >= 100 ) )
7953  SCIP_CALL( SCIPincludeConsUpgradeNonlinear(scip, consQuadConsUpgdSdp, 0, TRUE, CONSHDLRRANK1_NAME) );
7954 #else
7955  SCIP_CALL( SCIPincludeQuadconsUpgrade(scip, consQuadConsUpgdSdp, 0, TRUE, CONSHDLRRANK1_NAME) );
7956 #endif
7957 
7958  return SCIP_OKAY;
7959 }
7960 
7965  int i,
7966  int j
7967  )
7968 {
7969  assert( j >= 0 );
7970  assert( i >= j );
7971 
7972  return i*(i+1)/2 + j;
7973 }
7974 
7982 SCIP_RETCODE SCIPconsSdpGetData(
7983  SCIP* scip,
7984  SCIP_CONS* cons,
7985  int* nvars,
7986  int* nnonz,
7987  int* blocksize,
7988  int* arraylength,
7989  int* nvarnonz,
7991  int** col,
7992  int** row,
7993  SCIP_Real** val,
7994  SCIP_VAR** vars,
7995  int* constnnonz,
7997  int* constcol,
7998  int* constrow,
7999  SCIP_Real* constval,
8000  SCIP_Bool* rankone,
8001  int** maxevsubmat,
8002  SCIP_Bool* addedquadcons
8003  )
8004 {
8005  SCIP_CONSDATA* consdata;
8006  int i;
8007 
8008  assert( scip != NULL );
8009  assert( cons != NULL );
8010  assert( nvars != NULL );
8011  assert( nnonz != NULL );
8012  assert( blocksize != NULL );
8013  assert( arraylength != NULL );
8014  assert( nvarnonz != NULL );
8015  assert( col != NULL );
8016  assert( row != NULL );
8017  assert( val != NULL );
8018  assert( vars != NULL );
8019  assert( constnnonz != NULL );
8020 
8021  consdata = SCIPconsGetData(cons);
8022 
8023  assert( consdata->constnnonz == 0 || ( constcol != NULL && constrow != NULL && constval != NULL ) );
8024 
8025  *nvars = consdata->nvars;
8026  *nnonz = consdata->nnonz;
8027  *blocksize = consdata->blocksize;
8028 
8029  for (i = 0; i < consdata->nvars; i++)
8030  vars[i] = consdata->vars[i];
8031 
8032  /* check that the sdp-arrays are long enough to store the information */
8033  if ( *arraylength < consdata->nvars )
8034  {
8035  SCIPdebugMsg(scip, "nvarnonz, col, row and val arrays were not long enough to store the information for cons %s, they need to be at least"
8036  "size %d, given was only length %d!\n", SCIPconsGetName(cons), consdata->nvars, *arraylength);
8037  *arraylength = consdata->nvars;
8038  }
8039  else
8040  {
8041  for (i = 0; i < consdata->nvars; i++)
8042  {
8043  nvarnonz[i] = consdata->nvarnonz[i];
8044  /* set the pointers for each variable */
8045  col[i] = consdata->col[i];
8046  row[i] = consdata->row[i];
8047  val[i] = consdata->val[i];
8048  }
8049  }
8050 
8051  /* set the constant pointers (if a constant part exists) */
8052  if ( consdata->constnnonz > 0 )
8053  {
8054  if ( consdata->constnnonz > *constnnonz )
8055  {
8056  SCIPdebugMsg(scip, "The constant nonzeros arrays were not long enough to store the information for cons %s, they need to be at least"
8057  "size %d, given was only length %d! \n", SCIPconsGetName(cons), consdata->constnnonz, *constnnonz);
8058  }
8059  else
8060  {
8061  for (i = 0; i < consdata->constnnonz; i++)
8062  {
8063  constcol[i] = consdata->constcol[i];
8064  constrow[i] = consdata->constrow[i];
8065  constval[i] = consdata->constval[i];
8066  }
8067  }
8068  }
8069 
8070  *constnnonz = consdata->constnnonz;
8071 
8072  /* set the information about rankone, the current submatrix with largest minimal eigenvalue ([-1,-1] if not yet
8073  computed), and the quadratic 2x2-minor constraints if desired */
8074  if ( rankone != NULL && maxevsubmat != NULL )
8075  {
8076  *rankone = consdata->rankone;
8077  *maxevsubmat[0] = consdata->maxevsubmat[0];
8078  *maxevsubmat[1] = consdata->maxevsubmat[1];
8079  *addedquadcons = consdata->addedquadcons;
8080  }
8081 
8082  return SCIP_OKAY;
8083 }
8084 
8089 SCIP_RETCODE SCIPconsSdpGetNNonz(
8090  SCIP* scip,
8091  SCIP_CONS* cons,
8092  int* nnonz,
8093  int* constnnonz
8094  )
8095 {
8096  SCIP_CONSDATA* consdata;
8097 
8098  assert( scip != NULL );
8099  assert( cons != NULL );
8100 
8101  consdata = SCIPconsGetData(cons);
8102  assert( consdata != NULL );
8103 
8104  if ( nnonz != NULL )
8105  *nnonz = consdata->nnonz;
8106 
8107  if ( constnnonz != NULL )
8108  *constnnonz = consdata->constnnonz;
8109 
8110  return SCIP_OKAY;
8111 }
8112 
8115  SCIP* scip,
8116  SCIP_CONS* cons
8117  )
8118 {
8119  SCIP_CONSDATA* consdata;
8120 
8121  assert( scip != NULL );
8122  assert( cons != NULL );
8123 
8124  consdata = SCIPconsGetData(cons);
8125  assert( consdata != NULL );
8126 
8127  return consdata->nvars;
8128 }
8129 
8131 SCIP_VAR** SCIPconsSdpGetVars(
8132  SCIP* scip,
8133  SCIP_CONS* cons
8134  )
8135 {
8136  SCIP_CONSDATA* consdata;
8137 
8138  assert( scip != NULL );
8139  assert( cons != NULL );
8140 
8141  consdata = SCIPconsGetData(cons);
8142  assert( consdata != NULL );
8143 
8144  return consdata->vars;
8145 }
8146 
8149  SCIP* scip,
8150  SCIP_CONS* cons
8151  )
8152 {
8153  SCIP_CONSDATA* consdata;
8154 
8155  assert( scip != NULL );
8156  assert( cons != NULL );
8157 
8158  consdata = SCIPconsGetData(cons);
8159  assert( consdata != NULL );
8160 
8161  return consdata->blocksize;
8162 }
8163 
8165 SCIP_RETCODE SCIPconsSdpGetFullAj(
8166  SCIP* scip,
8167  SCIP_CONS* cons,
8168  int j,
8169  SCIP_Real* Aj
8170  )
8171 {
8172  SCIP_CONSDATA* consdata;
8173  int blocksize;
8174  int i;
8175 
8176  assert( scip != NULL );
8177  assert( cons != NULL );
8178  assert( j >= 0 );
8179  assert( Aj != NULL );
8180 
8181  consdata = SCIPconsGetData(cons);
8182  assert( consdata != NULL );
8183  blocksize = consdata->blocksize;
8184 
8185  assert( j < consdata->nvars );
8186 
8187  for (i = 0; i < blocksize * blocksize; i++)
8188  Aj[i] = 0;
8189 
8190  for (i = 0; i < consdata->nvarnonz[j]; i++)
8191  {
8192  Aj[consdata->col[j][i] * blocksize + consdata->row[j][i]] = consdata->val[j][i]; /*lint !e679*/
8193  Aj[consdata->row[j][i] * blocksize + consdata->col[j][i]] = consdata->val[j][i]; /*lint !e679*/
8194  }
8195 
8196  return SCIP_OKAY;
8197 }
8198 
8200 SCIP_RETCODE SCIPconsSdpGetFullConstMatrix(
8201  SCIP* scip,
8202  SCIP_CONS* cons,
8203  SCIP_Real* mat
8204  )
8205 {
8206  SCIP_CONSDATA* consdata;
8207  int blocksize;
8208  int i;
8209  int j;
8210 
8211  assert( scip != NULL );
8212  assert( cons != NULL );
8213  assert( mat != NULL );
8214 
8215  consdata = SCIPconsGetData(cons);
8216  blocksize = consdata->blocksize;
8217 
8218  for (i = 0; i < blocksize; i++)
8219  {
8220  for (j = 0; j < blocksize; j++)
8221  mat[i * blocksize + j] = 0.0; /*lint !e679*/
8222  }
8223 
8224  for (i = 0; i < consdata->constnnonz; i++)
8225  {
8226  mat[consdata->constcol[i] * blocksize + consdata->constrow[i]] = consdata->constval[i]; /*lint !e679*/
8227  mat[consdata->constrow[i] * blocksize + consdata->constcol[i]] = consdata->constval[i]; /*lint !e679*/
8228  }
8229 
8230  return SCIP_OKAY;
8231 }
8232 
8235  SCIP* scip,
8236  SCIP_CONS* cons,
8237  SCIP_Real* mat
8238  )
8239 {
8240  SCIP_CONSDATA* consdata;
8241  int blocksize;
8242  int i;
8243 
8244  assert( scip != NULL );
8245  assert( cons != NULL );
8246  assert( mat != NULL );
8247 
8248  consdata = SCIPconsGetData(cons);
8249  assert( consdata != NULL );
8250 
8251  blocksize = consdata->blocksize;
8252 
8253  /* initialize the matrix with 0 */
8254  for (i = 0; i < (blocksize * (blocksize + 1)) / 2; i++)
8255  mat[i] = 0.0;
8256 
8257  for (i = 0; i < consdata->constnnonz; i++)
8258  mat[SCIPconsSdpCompLowerTriangPos(consdata->constrow[i], consdata->constcol[i])] = consdata->constval[i];
8259 
8260  return SCIP_OKAY;
8261 }
8262 
8273 SCIP_RETCODE SCIPconsSdpGuessInitialPoint(
8274  SCIP* scip,
8275  SCIP_CONS* cons,
8276  SCIP_Real* lambdastar
8277  )
8278 {
8279  SCIP_CONSDATA* consdata;
8280  SCIP_Real sparsity;
8281  SCIP_Real maxinfnorm;
8282  SCIP_Real maxconst;
8283  SCIP_Real mininfnorm;
8284  SCIP_Real maxobj;
8285  SCIP_Real maxbound;
8286  SCIP_Real primalguess;
8287  SCIP_Real dualguess;
8288  SCIP_Real compval;
8289  int blocksize;
8290  int i;
8291  int v;
8292 
8293  assert( scip != NULL );
8294  assert( cons != NULL );
8295  assert( lambdastar != NULL );
8296  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0 || strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLRRANK1_NAME) == 0 );
8297 
8298  consdata = SCIPconsGetData(cons);
8299  assert( consdata != NULL );
8300 
8301  /* If there are no nonzeros, we cannot use the usual formula, since it divides through the number of nonzeros. In this case,
8302  * however, we will not solve an SDP anyways but at most an LP (more likely the problem will be solved in local presolving,
8303  * if all variables are fixed and not only those in the SDP-part), so we just take the default value of SDPA.
8304  */
8305  if ( consdata->nnonz == 0 )
8306  {
8307  *lambdastar = 100.0;
8308  return SCIP_OKAY;
8309  }
8310 
8311  blocksize = consdata->blocksize;
8312 
8313  sparsity = consdata->nnonz / (0.5 * blocksize * (blocksize + 1));
8314 
8315  /* compute the maximum entry of the A_i */
8316  maxinfnorm = 0.0;
8317  mininfnorm = SCIPinfinity(scip);
8318  for (v = 0; v < consdata->nvars; v++)
8319  {
8320  for (i = 0; i < consdata->nvarnonz[v]; i++)
8321  {
8322  if ( SCIPisGT(scip, REALABS(consdata->val[v][i]), maxinfnorm ) )
8323  maxinfnorm = REALABS(consdata->val[v][i]);
8324  if ( SCIPisLT(scip, REALABS(consdata->val[v][i]), mininfnorm) )
8325  mininfnorm = REALABS(consdata->val[v][i]);
8326  }
8327  }
8328  maxconst = 0.0;
8329  for (i = 0; i < consdata->constnnonz; i++)
8330  {
8331  if ( SCIPisGT(scip, REALABS(consdata->constval[i]), maxconst ) )
8332  maxconst = REALABS(consdata->constval[i]);
8333  }
8334 
8335  assert( SCIPisGT(scip, mininfnorm, 0.0) );
8336 
8337  /* compute maximum b_i and bound */
8338  maxobj = 0.0;
8339  maxbound = 0.0;
8340  for (v = 0; v < consdata->nvars; v++)
8341  {
8342  if ( SCIPisGT(scip, REALABS(SCIPvarGetObj(consdata->vars[v])), maxobj) )
8343  maxobj = REALABS(SCIPvarGetObj(consdata->vars[v]));
8344  compval = SCIPisInfinity(scip, REALABS(SCIPvarGetUbGlobal(consdata->vars[v]))) ? 1e+6 : REALABS(SCIPvarGetUbGlobal(consdata->vars[v]));
8345  if ( SCIPisGT(scip, compval, maxbound) )
8346  maxbound = compval;
8347  compval = SCIPisInfinity(scip, REALABS(SCIPvarGetLbGlobal(consdata->vars[v]))) ? 1e+6 : REALABS(SCIPvarGetUbGlobal(consdata->vars[v]));
8348  if ( SCIPisGT(scip, compval, maxbound) )
8349  maxbound = compval;
8350  }
8351 
8352  /* if all variables were unbounded, we set the value to 10^6 */
8353  if ( SCIPisEQ(scip, maxbound, 0.0) )
8354  maxbound = 1E+6;
8355 
8356  /* compute primal and dual guess */
8357  primalguess = maxobj / (sparsity * mininfnorm);
8358  dualguess = sparsity * maxinfnorm * maxbound + maxconst;
8359 
8360  if ( SCIPisGT(scip, primalguess, dualguess) )
8361  *lambdastar = primalguess;
8362  else
8363  *lambdastar = dualguess;
8364 
8365  return SCIP_OKAY;
8366 }
8367 
8369 SCIP_Real SCIPconsSdpGetMaxConstEntry(
8370  SCIP* scip,
8371  SCIP_CONS* cons
8372  )
8373 {
8374  SCIP_CONSDATA* consdata;
8375 
8376  assert( scip != NULL );
8377  assert( cons != NULL );
8378 
8379  consdata = SCIPconsGetData(cons);
8380 
8381  return consdata->maxrhsentry;
8382 }
8383 
8385 SCIP_Real SCIPconsSdpGetMaxSdpCoef(
8386  SCIP* scip,
8387  SCIP_CONS* cons
8388  )
8389 {
8390  SCIP_CONSDATA* consdata;
8391  SCIP_Real maxcoef;
8392  int v;
8393  int i;
8394 
8395  assert( scip != NULL );
8396  assert( cons != NULL );
8397 
8398  consdata = SCIPconsGetData(cons);
8399 
8400  maxcoef = 0.0;
8401 
8402  for (v = 0; v < consdata->nvars; v++)
8403  {
8404  for (i = 0; i < consdata->nvarnonz[v]; i++)
8405  {
8406  if ( SCIPisGT(scip, REALABS(consdata->val[v][i]), maxcoef) )
8407  maxcoef = REALABS(consdata->val[v][i]);
8408  }
8409  }
8410 
8411  return maxcoef;
8412 }
8413 
8420  SCIP_CONS* cons
8421  )
8422 { /*lint --e{715}*/
8423  SCIP_CONSDATA* consdata;
8424  int v;
8425  int ub;
8426  int denselength;
8427 
8428  assert( cons != NULL );
8429 
8430  consdata = SCIPconsGetData(cons);
8431  assert( consdata != NULL );
8432 
8433  ub = consdata->constnnonz;
8434 
8435  for (v = 0; v < consdata->nvars; v++)
8436  ub += consdata->nvarnonz[v];
8437 
8438  denselength = consdata->blocksize * (consdata->blocksize + 1) / 2;
8439 
8440  return (ub <= denselength ? ub : denselength);
8441 }
8442 
8448  SCIP* scip,
8449  SCIP_CONS* cons,
8450  SCIP_SOL* sol,
8451  int* length,
8453  int* row,
8454  int* col,
8455  SCIP_Real* val
8456  )
8457 {
8458  SCIP_CONSDATA* consdata;
8459  int i;
8460  int v;
8461  int nnonz;
8462 
8463  assert( scip != NULL );
8464  assert( cons != NULL );
8465  assert( sol != NULL );
8466  assert( length != NULL );
8467  assert( row != NULL );
8468  assert( col != NULL );
8469  assert( val != NULL );
8470 
8471  consdata = SCIPconsGetData(cons);
8472  assert( consdata != NULL );
8473 
8474  /* initialize nnonz/row/col/val with constant arrays */
8475  nnonz = consdata->constnnonz;
8476  if ( *length < nnonz )
8477  {
8478  *length = -1;
8479  SCIPerrorMessage("Arrays not long enough in SCIPconsSdpComputeSparseSdpMatrix, length %d given, need at least %d (probably more)\n",
8480  *length, nnonz);
8481  return SCIP_ERROR;
8482  }
8483 
8484  for (i = 0; i < consdata->constnnonz; i++)
8485  {
8486  row[i] = consdata->constrow[i];
8487  col[i] = consdata->constcol[i];
8488  val[i] = -1 * consdata->constval[i];
8489  }
8490 
8491  /* add all variable arrays multiplied by corresponding solution value */
8492  for (v = 0; v < consdata->nvars; v++)
8493  {
8494  SCIP_CALL( SCIPsdpVarfixerMergeArrays(SCIPblkmem(scip), SCIPepsilon(scip), consdata->row[v], consdata->col[v], consdata->val[v], consdata->nvarnonz[v],
8495  FALSE, SCIPgetSolVal(scip, sol, consdata->vars[v]), row, col, val, &nnonz, *length) );
8496  if ( nnonz > *length )
8497  {
8498  *length = -1;
8499  SCIPerrorMessage("Arrays not long enough in SCIPconsSdpComputeSparseSdpMatrix, length %d given, need at least %d (probably more)\n",
8500  *length, nnonz);
8501  return SCIP_ERROR;
8502  }
8503  }
8504 
8505  /* update length pointer */
8506  *length = nnonz;
8507 
8508  return SCIP_OKAY;
8509 }
8510 
8512 SCIP_Bool SCIPconsSdpShouldBeRankOne(
8513  SCIP_CONS* cons
8514  )
8515 {
8516  SCIP_CONSDATA* consdata;
8517 
8518  assert( cons != NULL );
8519 
8520  consdata = SCIPconsGetData(cons);
8521  assert( consdata != NULL );
8522 
8523  return consdata->rankone;
8524 }
8525 
8527 SCIP_RETCODE SCIPconsSdpGetMaxEVSubmat(
8528  SCIP_CONS* cons,
8529  int** maxevsubmat
8531  )
8532 {
8533  SCIP_CONSDATA* consdata;
8534 
8535  assert( cons != NULL );
8536 
8537  consdata = SCIPconsGetData(cons);
8538  assert( consdata != NULL );
8539  assert( maxevsubmat != NULL );
8540 
8541  *maxevsubmat[0] = consdata->maxevsubmat[0];
8542  *maxevsubmat[1] = consdata->maxevsubmat[1];
8543 
8544  return SCIP_OKAY;
8545 }
8546 
8548 SCIP_Bool SCIPconsSdpAddedQuadCons(
8549  SCIP_CONS* cons
8550  )
8551 {
8552  SCIP_CONSDATA* consdata;
8553 
8554  assert( cons != NULL );
8555 
8556  consdata = SCIPconsGetData(cons);
8557  assert( consdata != NULL );
8558 
8559  return consdata->addedquadcons;
8560 }
8561 
8566 SCIP_RETCODE SCIPcreateConsSdp(
8567  SCIP* scip,
8568  SCIP_CONS** cons,
8569  const char* name,
8570  int nvars,
8571  int nnonz,
8572  int blocksize,
8573  int* nvarnonz,
8574  int** col,
8575  int** row,
8576  SCIP_Real** val,
8577  SCIP_VAR** vars,
8578  int constnnonz,
8579  int* constcol,
8580  int* constrow,
8581  SCIP_Real* constval,
8582  SCIP_Bool removeduplicates
8583  )
8584 {
8585  SCIP_CONSHDLR* conshdlr;
8586  SCIP_CONSDATA* consdata = NULL;
8587  int i;
8588  int j;
8589 
8590  assert( scip != NULL );
8591  assert( cons != NULL );
8592  assert( name != NULL );
8593  assert( nvars >= 0 );
8594  assert( nnonz >= 0 );
8595  assert( blocksize >= 0 );
8596  assert( constnnonz >= 0 );
8597  assert( nvars == 0 || vars != NULL );
8598  assert( nnonz == 0 || (nvarnonz != NULL && col != NULL && row != NULL && val != NULL ));
8599  assert( constnnonz == 0 || (constcol != NULL && constrow != NULL && constval != NULL ));
8600 
8601  conshdlr = SCIPfindConshdlr(scip, "SDP");
8602  if ( conshdlr == NULL )
8603  {
8604  SCIPerrorMessage("SDP constraint handler not found\n");
8605  return SCIP_PLUGINNOTFOUND;
8606  }
8607 
8608  /* create constraint data */
8609  SCIP_CALL( SCIPallocBlockMemory(scip, &consdata) );
8610  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->nvarnonz, nvars) );
8611  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->col, nvars) );
8612  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->row, nvars) );
8613  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->val, nvars) );
8614  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->constcol, constnnonz) );
8615  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->constrow, constnnonz) );
8616  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->constval, constnnonz) );
8617  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->vars, nvars) );
8618 
8619  for (i = 0; i < nvars; i++)
8620  {
8621  assert( nvarnonz[i] >= 0 );
8622 
8623  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->col[i], nvarnonz[i]));
8624  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->row[i], nvarnonz[i]));
8625  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->val[i], nvarnonz[i]));
8626  }
8627 
8628  consdata->nvars = nvars;
8629  consdata->nnonz = nnonz;
8630  consdata->constnnonz = constnnonz;
8631  consdata->blocksize = blocksize;
8632  consdata->locks = NULL;
8633  consdata->matrixvar = NULL;
8634  consdata->matrixval = NULL;
8635  consdata->matrixconst = NULL;
8636  consdata->nsingle = 0;
8637  consdata->tracebound = -2.0;
8638  consdata->allmatricespsd = FALSE;
8639  consdata->initallmatricespsd = FALSE;
8640 
8641  for (i = 0; i < nvars; i++)
8642  {
8643  consdata->nvarnonz[i] = nvarnonz[i];
8644 
8645  if ( nvarnonz[i] > 0 )
8646  {
8647  /* if duplicate matrix entries should be removed */
8648  if ( removeduplicates )
8649  {
8650  int cnt = 0;
8651  int c = 0;
8652 
8653  /* sort by rows, then columns */
8654  SCIPsdpVarfixerSortRowCol(row[i], col[i], val[i], nvarnonz[i]);
8655 
8656  while ( cnt < nvarnonz[i] )
8657  {
8658  assert( 0 <= row[i][cnt] && row[i][cnt] < blocksize );
8659  assert( 0 <= col[i][cnt] && col[i][cnt] < blocksize );
8660  assert( row[i][cnt] >= col[i][cnt] );
8661 
8662  while ( cnt < nvarnonz[i] - 1 && row[i][cnt] == row[i][cnt+1] && col[i][cnt] == col[i][cnt+1] )
8663  {
8664  if ( ! SCIPisEQ(scip, val[i][cnt], val[i][cnt+1]) )
8665  {
8666  SCIPerrorMessage("Duplicate matrix entry (%d,%d) with different value (%g vs. %g).\n", row[i][cnt], col[i][cnt], val[i][cnt], val[i][cnt+1]);
8667  return SCIP_INVALIDDATA;
8668  }
8669  ++cnt;
8670  }
8671 
8672  consdata->row[i][c] = row[i][cnt];
8673  consdata->col[i][c] = col[i][cnt];
8674  consdata->val[i][c] = val[i][cnt];
8675  ++cnt;
8676  ++c;
8677  }
8678 
8679  /* possibly correct size; a reallocation should happen rarely */
8680  if ( c < nvarnonz[i] )
8681  {
8682  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->col[i], nvarnonz[i], c));
8683  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->row[i], nvarnonz[i], c));
8684  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->val[i], nvarnonz[i], c));
8685  consdata->nvarnonz[i] = c;
8686  }
8687  }
8688  else
8689  {
8690  for (j = 0; j < nvarnonz[i]; j++)
8691  {
8692  assert( 0 <= row[i][j] && row[i][j] < blocksize );
8693  assert( 0 <= col[i][j] && col[i][j] < blocksize );
8694  assert( row[i][j] >= col[i][j] );
8695 
8696  consdata->row[i][j] = row[i][j];
8697  consdata->col[i][j] = col[i][j];
8698  consdata->val[i][j] = val[i][j];
8699  }
8700  }
8701  }
8702  }
8703 
8704  if ( constnnonz > 0 )
8705  {
8706  /* if duplicate matrix entries should be removed */
8707  if ( removeduplicates )
8708  {
8709  int cnt = 0;
8710  int c = 0;
8711 
8712  /* sort by rows, then columns */
8713  SCIPsdpVarfixerSortRowCol(constrow, constcol, constval, constnnonz);
8714 
8715  while ( cnt < constnnonz )
8716  {
8717  while ( cnt < constnnonz - 1 && constrow[cnt] == constrow[cnt+1] && constcol[cnt] == constcol[cnt+1] )
8718  {
8719  if ( ! SCIPisEQ(scip, constval[cnt], constval[cnt+1]) )
8720  {
8721  SCIPerrorMessage("Duplicate entry (%d,%d) with different value (%g vs. %g) in constant matrix.\n", constrow[cnt], constcol[cnt], constval[cnt], constval[cnt+1]);
8722  return SCIP_INVALIDDATA;
8723  }
8724  ++cnt;
8725  }
8726 
8727  assert( 0 <= constrow[cnt] && constrow[cnt] < blocksize );
8728  assert( 0 <= constcol[cnt] && constcol[cnt] < blocksize );
8729  assert( constrow[cnt] >= constcol[cnt] );
8730 
8731  consdata->constrow[c] = constrow[cnt];
8732  consdata->constcol[c] = constcol[cnt];
8733  consdata->constval[c] = constval[cnt];
8734  ++cnt;
8735  ++c;
8736  }
8737 
8738  /* possibly correct size; a reallocation should happen rarely */
8739  if ( c < constnnonz )
8740  {
8741  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->constcol, constnnonz, c) );
8742  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->constrow, constnnonz, c) );
8743  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->constval, constnnonz, c) );
8744  consdata->constnnonz = c;
8745  }
8746  }
8747  else
8748  {
8749  for (j = 0; j < constnnonz; j++)
8750  {
8751  assert( 0 <= constrow[j] && constrow[j] < blocksize );
8752  assert( 0 <= constcol[j] && constcol[j] < blocksize );
8753  assert( constrow[j] >= constcol[j] );
8754 
8755  consdata->constrow[j] = constrow[j];
8756  consdata->constcol[j] = constcol[j];
8757  consdata->constval[j] = constval[j];
8758  }
8759  }
8760  }
8761 
8762  for (i = 0; i < nvars; i++)
8763  {
8764  consdata->vars[i] = vars[i];
8765  SCIP_CALL( SCIPcaptureVar(scip, consdata->vars[i]) );
8766  }
8767  SCIPdebugMsg(scip, "creating cons %s.\n", name);
8768 
8769  consdata->rankone = FALSE;
8770 
8771  /* allocate memory for rank one constraint */
8772  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->maxevsubmat, 2) );
8773  consdata->maxevsubmat[0] = -1;
8774  consdata->maxevsubmat[1] = -1;
8775 
8776  /* quadratic 2x2-minor constraints added? */
8777  consdata->addedquadcons = FALSE;
8778 
8779  /* create constraint */
8780  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
8781 
8782  /* compute maximum rhs entry for later use in the DIMACS Error Norm */
8783  SCIP_CALL( setMaxRhsEntry(*cons) );
8784 
8785  return SCIP_OKAY;
8786 }
8787 
8788 
8793 SCIP_RETCODE SCIPcreateConsSdpRank1(
8794  SCIP* scip,
8795  SCIP_CONS** cons,
8796  const char* name,
8797  int nvars,
8798  int nnonz,
8799  int blocksize,
8800  int* nvarnonz,
8801  int** col,
8802  int** row,
8803  SCIP_Real** val,
8804  SCIP_VAR** vars,
8805  int constnnonz,
8806  int* constcol,
8807  int* constrow,
8808  SCIP_Real* constval,
8809  SCIP_Bool removeduplicates
8810  )
8811 {
8812  SCIP_CONSHDLR* conshdlr;
8813  SCIP_CONSDATA* consdata = NULL;
8814  int i;
8815  int j;
8816 
8817  assert( scip != NULL );
8818  assert( cons != NULL );
8819  assert( name != NULL );
8820  assert( nvars >= 0 );
8821  assert( nnonz >= 0 );
8822  assert( blocksize >= 0 );
8823  assert( constnnonz >= 0 );
8824  assert( nvars == 0 || vars != NULL );
8825  assert( nnonz == 0 || (nvarnonz != NULL && col != NULL && row != NULL && val != NULL ));
8826  assert( constnnonz == 0 || (constcol != NULL && constrow != NULL && constval != NULL ));
8827 
8828  conshdlr = SCIPfindConshdlr(scip, CONSHDLRRANK1_NAME);
8829  if ( conshdlr == NULL )
8830  {
8831  SCIPerrorMessage("Rank 1 SDP constraint handler not found\n");
8832  return SCIP_PLUGINNOTFOUND;
8833  }
8834 
8835  /* create constraint data */
8836  SCIP_CALL( SCIPallocBlockMemory(scip, &consdata) );
8837  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->nvarnonz, nvars) );
8838  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->col, nvars) );
8839  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->row, nvars) );
8840  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->val, nvars) );
8841  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->constcol, constnnonz) );
8842  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->constrow, constnnonz) );
8843  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->constval, constnnonz) );
8844  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->vars, nvars) );
8845 
8846  for (i = 0; i < nvars; i++)
8847  {
8848  assert( nvarnonz[i] >= 0 );
8849 
8850  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->col[i], nvarnonz[i]));
8851  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->row[i], nvarnonz[i]));
8852  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->val[i], nvarnonz[i]));
8853  }
8854 
8855  consdata->nvars = nvars;
8856  consdata->nnonz = nnonz;
8857  consdata->constnnonz = constnnonz;
8858  consdata->blocksize = blocksize;
8859  consdata->locks = NULL;
8860  consdata->matrixvar = NULL;
8861  consdata->matrixval = NULL;
8862  consdata->matrixconst = NULL;
8863  consdata->nsingle = 0;
8864  consdata->tracebound = -2.0;
8865  consdata->allmatricespsd = FALSE;
8866  consdata->initallmatricespsd = FALSE;
8867 
8868  for (i = 0; i < nvars; i++)
8869  {
8870  consdata->nvarnonz[i] = nvarnonz[i];
8871 
8872  if ( nvarnonz[i] > 0 )
8873  {
8874  /* if duplicate matrix entries should be removed */
8875  if ( removeduplicates )
8876  {
8877  int cnt = 0;
8878  int c = 0;
8879 
8880  /* sort by rows, then columns */
8881  SCIPsdpVarfixerSortRowCol(row[i], col[i], val[i], nvarnonz[i]);
8882 
8883  while ( cnt < nvarnonz[i] )
8884  {
8885  assert( 0 <= row[i][cnt] && row[i][cnt] < blocksize );
8886  assert( 0 <= col[i][cnt] && col[i][cnt] < blocksize );
8887  assert( row[i][cnt] >= col[i][cnt] );
8888 
8889  while ( cnt < nvarnonz[i] - 1 && row[i][cnt] == row[i][cnt+1] && col[i][cnt] == col[i][cnt+1] )
8890  {
8891  if ( ! SCIPisEQ(scip, val[i][cnt], val[i][cnt+1]) )
8892  {
8893  SCIPerrorMessage("Duplicate matrix entry (%d,%d) with different value (%g vs. %g).\n", row[i][cnt], col[i][cnt], val[i][cnt], val[i][cnt+1]);
8894  return SCIP_INVALIDDATA;
8895  }
8896  ++cnt;
8897  }
8898 
8899  consdata->row[i][c] = row[i][cnt];
8900  consdata->col[i][c] = col[i][cnt];
8901  consdata->val[i][c] = val[i][cnt];
8902  ++cnt;
8903  ++c;
8904  }
8905 
8906  /* possibly correct size; a reallocation should happen rarely */
8907  if ( c < nvarnonz[i] )
8908  {
8909  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->col[i], nvarnonz[i], c));
8910  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->row[i], nvarnonz[i], c));
8911  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->val[i], nvarnonz[i], c));
8912  consdata->nvarnonz[i] = c;
8913  }
8914  }
8915  else
8916  {
8917  for (j = 0; j < nvarnonz[i]; j++)
8918  {
8919  assert( 0 <= row[i][j] && row[i][j] < blocksize );
8920  assert( 0 <= col[i][j] && col[i][j] < blocksize );
8921  assert( row[i][j] >= col[i][j] );
8922 
8923  consdata->row[i][j] = row[i][j];
8924  consdata->col[i][j] = col[i][j];
8925  consdata->val[i][j] = val[i][j];
8926  }
8927  }
8928  }
8929  }
8930 
8931  if ( constnnonz > 0 )
8932  {
8933  /* if duplicate matrix entries should be removed */
8934  if ( removeduplicates )
8935  {
8936  int cnt = 0;
8937  int c = 0;
8938 
8939  /* sort by rows, then columns */
8940  SCIPsdpVarfixerSortRowCol(constrow, constcol, constval, constnnonz);
8941 
8942  while ( cnt < constnnonz )
8943  {
8944  while ( cnt < constnnonz - 1 && constrow[cnt] == constrow[cnt+1] && constcol[cnt] == constcol[cnt+1] )
8945  {
8946  if ( ! SCIPisEQ(scip, constval[cnt], constval[cnt+1]) )
8947  {
8948  SCIPerrorMessage("Duplicate entry (%d,%d) with different value (%g vs. %g) in constant matrix.\n", constrow[cnt], constcol[cnt], constval[cnt], constval[cnt+1]);
8949  return SCIP_INVALIDDATA;
8950  }
8951  ++cnt;
8952  }
8953 
8954  assert( 0 <= constrow[cnt] && constrow[cnt] < blocksize );
8955  assert( 0 <= constcol[cnt] && constcol[cnt] < blocksize );
8956  assert( constrow[cnt] >= constcol[cnt] );
8957 
8958  consdata->constrow[c] = constrow[cnt];
8959  consdata->constcol[c] = constcol[cnt];
8960  consdata->constval[c] = constval[cnt];
8961  ++cnt;
8962  ++c;
8963  }
8964 
8965  /* possibly correct size; a reallocation should happen rarely */
8966  if ( c < constnnonz )
8967  {
8968  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->constcol, constnnonz, c) );
8969  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->constrow, constnnonz, c) );
8970  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->constval, constnnonz, c) );
8971  consdata->constnnonz = c;
8972  }
8973  }
8974  else
8975  {
8976  for (j = 0; j < constnnonz; j++)
8977  {
8978  assert( 0 <= constrow[j] && constrow[j] < blocksize );
8979  assert( 0 <= constcol[j] && constcol[j] < blocksize );
8980  assert( constrow[j] >= constcol[j] );
8981 
8982  consdata->constrow[j] = constrow[j];
8983  consdata->constcol[j] = constcol[j];
8984  consdata->constval[j] = constval[j];
8985  }
8986  }
8987  }
8988 
8989  for (i = 0; i < nvars; i++)
8990  {
8991  consdata->vars[i] = vars[i];
8992  SCIP_CALL( SCIPcaptureVar(scip, consdata->vars[i]) );
8993  }
8994  SCIPdebugMsg(scip, "creating cons %s (rank 1).\n", name);
8995  consdata->rankone = TRUE;
8996 
8997  /* allocate memory for rank one constraint */
8998  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->maxevsubmat, 2) );
8999  consdata->maxevsubmat[0] = -1;
9000  consdata->maxevsubmat[1] = -1;
9001 
9002  /* quadratic 2x2-minor constraints added? */
9003  consdata->addedquadcons = FALSE;
9004 
9005  /* create constraint */
9006  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
9007 
9008  /* compute maximum rhs entry for later use in the DIMACS Error Norm */
9009  SCIP_CALL( setMaxRhsEntry(*cons) );
9010 
9011  return SCIP_OKAY;
9012 }
SCIP_Real SCIPconsSdpGetMaxConstEntry(SCIP *scip, SCIP_CONS *cons)
Definition: cons_sdp.c:8370
int SCIPconsSdpGetNVars(SCIP *scip, SCIP_CONS *cons)
Definition: cons_sdp.c:8115
static SCIP_RETCODE addMultipleSparseCuts(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_CONSDATA *consdata, SCIP_SOL *sol, int blocksize, SCIP_Real *fullmatrix, SCIP_Real *fullconstmatrix, SCIP_Real *eigenvector, SCIP_Real tol, int maxncuts, SCIP_Real *vector, SCIP_VAR **vars, SCIP_Real *vals, int *ncuts, SCIP_Bool *success, SCIP_RESULT *result)
Definition: cons_sdp.c:1036
static SCIP_DECL_CONSTRANS(consTransSdp)
Definition: cons_sdp.c:6174
int SCIPconsSdpComputeUbSparseSdpMatrixLength(SCIP_CONS *cons)
Definition: cons_sdp.c:8420
#define DEFAULT_QUADCONSRANK1
Definition: cons_sdp.c:119
SCIP_RETCODE SCIPconsSdpGetFullAj(SCIP *scip, SCIP_CONS *cons, int j, SCIP_Real *Aj)
Definition: cons_sdp.c:8166
static SCIP_RETCODE addTwoMinorProdConstraints(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool solvesdps, int *naddconss)
Definition: cons_sdp.c:2848
#define DEFAULT_MULTIPLESPARSECUTS
Definition: cons_sdp.c:129
void SCIPsdpVarfixerSortRowCol(int *row, int *col, SCIP_Real *val, int length)
Definition: SdpVarfixer.c:57
#define DEFAULT_ENFORCESDP
Definition: cons_sdp.c:131
static SCIP_RETCODE convertRowToColFormatFullMatrix(int rows, int cols, SCIP_Real *rowmatrix, SCIP_Real *colmatrix)
Definition: cons_sdp.c:235
#define CONSHDLR_PRESOLTIMING
Definition: cons_sdp.c:101
#define CONSHDLR_NAME
Definition: cons_sdp.c:83
SCIP_RETCODE SCIPsolveOneVarSDPDense(BMS_BUFMEM *bufmem, SCIP_Real obj, SCIP_Real lb, SCIP_Real ub, int blocksize, SCIP_Real *fullconstmatrix, int sdpnnonz, int *sdprow, int *sdpcol, SCIP_Real *sdpval, SCIP_Real infinity, SCIP_Real feastol, SCIP_Real *objval, SCIP_Real *optval)
static SCIP_RETCODE addRank1QuadConss(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int *naddconss)
Definition: cons_sdp.c:3263
SCIP_RETCODE SCIPincludeConshdlrSdp(SCIP *scip)
Definition: cons_sdp.c:7664
static SCIP_RETCODE multiplyConstraintMatrix(SCIP_CONS *cons, int j, SCIP_Real *v, SCIP_Real *vAv)
Definition: cons_sdp.c:697
#define DEFAULT_ONLYFIXEDINTSSDP
Definition: cons_sdp.c:132
#define PARSE_SIZEFACTOR
Definition: cons_sdp.c:105
static SCIP_DECL_CONSENFORELAX(consEnforelaxSdp)
Definition: cons_sdp.c:6965
#define DEFAULT_PROPUPPERBOUNDS
Definition: cons_sdp.c:107
SDP-relaxator.
#define CONSHDLR_NEEDSCONS
Definition: cons_sdp.c:99
SCIP_RETCODE SCIPcreateConsSdpRank1(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, int nnonz, int blocksize, int *nvarnonz, int **col, int **row, SCIP_Real **val, SCIP_VAR **vars, int constnnonz, int *constcol, int *constrow, SCIP_Real *constval, SCIP_Bool removeduplicates)
Definition: cons_sdp.c:8794
#define DEFAULT_SPARSIFYFACTOR
Definition: cons_sdp.c:127
static SCIP_RETCODE tightenBounds(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool tightenboundscont, int *nchgbds, SCIP_Bool *infeasible)
Definition: cons_sdp.c:1802
#define DEFAULT_TWOMINORPRODCONSS
Definition: cons_sdp.c:117
static SCIP_DECL_CONSDELETE(consDeleteSdp)
Definition: cons_sdp.c:7056
#define DEFAULT_SEPARATEONECUT
Definition: cons_sdp.c:124
SCIP_Bool SCIPconsSdpAddedQuadCons(SCIP_CONS *cons)
Definition: cons_sdp.c:8549
#define CONSHDLR_SEPAFREQ
Definition: cons_sdp.c:93
#define DEFAULT_CUTSTOPOOL
Definition: cons_sdp.c:125
static SCIP_RETCODE SCIPconsSdpCheckSdpCons(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool printreason, SCIP_RESULT *result)
Definition: cons_sdp.c:535
#define DEFAULT_RECOMPUTEINITIAL
Definition: cons_sdp.c:143
SCIP_RETCODE SCIPcreateConsSdp(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, int nnonz, int blocksize, int *nvarnonz, int **col, int **row, SCIP_Real **val, SCIP_VAR **vars, int constnnonz, int *constcol, int *constrow, SCIP_Real *constval, SCIP_Bool removeduplicates)
Definition: cons_sdp.c:8567
static SCIP_RETCODE sparsifyCut(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_CONSDATA *consdata, SCIP_SOL *sol, int blocksize, SCIP_Real *fullconstmatrix, SCIP_Real *eigenvector, SCIP_Real *vector, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Bool *success, SCIP_RESULT *result)
Definition: cons_sdp.c:874
static SCIP_DECL_CONSEXIT(consExitSdp)
Definition: cons_sdp.c:5645
#define DEFAULT_PROPTIGHTENBOUNDS
Definition: cons_sdp.c:109
static SCIP_DECL_CONSPROP(consPropSdp)
Definition: cons_sdp.c:5753
static SCIP_RETCODE addTwoMinorVarBounds(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool solvesdps, int *naddconss)
Definition: cons_sdp.c:2995
#define CONSHDLR_DELAYSEPA
Definition: cons_sdp.c:98
static SCIP_RETCODE checkVarsLocks(SCIP *scip, SCIP_CONS *cons)
Definition: cons_sdp.c:3756
#define CONSHDLR_EAGERFREQ
Definition: cons_sdp.c:94
#define DEFAULT_MAXNVARSQUADUPGD
Definition: cons_sdp.c:122
#define DEFAULT_DIAGGEZEROCUTS
Definition: cons_sdp.c:114
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
#define DEFAULT_TIGHTENBOUNDS
Definition: cons_sdp.c:113
SCIP_RETCODE SCIPconsSdpGetLowerTriangConstMatrix(SCIP *scip, SCIP_CONS *cons, SCIP_Real *mat)
Definition: cons_sdp.c:8235
static SCIP_DECL_CONSSEPALP(consSepalpSdp)
Definition: cons_sdp.c:7028
static SCIP_RETCODE truncatedPowerMethod(SCIP *scip, int blocksize, SCIP_Real *fullmatrix, SCIP_Real *vector, int sparsity, SCIP_Real convergencetol, SCIP_Real *eigenvector, int *support, SCIP_Real *eigenvalue)
Definition: cons_sdp.c:771
static SCIP_RETCODE setMaxRhsEntry(SCIP_CONS *cons)
Definition: cons_sdp.c:741
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)
#define DEFAULT_RANK1APPROXHEUR
Definition: cons_sdp.c:123
static SCIP_DECL_CONSCHECK(consCheckSdp)
Definition: cons_sdp.c:6302
#define CONSHDLR_DESC
Definition: cons_sdp.c:84
Constraint handler for SDP-constraints.
static SCIP_RETCODE expandSymMatrix(int size, SCIP_Real *symMat, SCIP_Real *fullMat)
Definition: cons_sdp.c:293
#define DEFAULT_PROPTBPROBING
Definition: cons_sdp.c:110
maps SCIP variables to SDP indices (the SCIP variables are given SDP indices in the order in which th...
SCIP_RETCODE SCIPconsSdpGetFullConstMatrix(SCIP *scip, SCIP_CONS *cons, SCIP_Real *mat)
Definition: cons_sdp.c:8201
static SCIP_RETCODE separateSol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool enforce, SCIP_RESULT *result)
Definition: cons_sdp.c:1391
static SCIP_RETCODE constructMatrixvar(SCIP *scip, SCIP_CONS *cons, SCIP_CONSDATA *consdata)
Definition: cons_sdp.c:441
SCIP_Real SCIPconsSdpGetMaxSdpCoef(SCIP *scip, SCIP_CONS *cons)
Definition: cons_sdp.c:8386
static SCIP_RETCODE scaleRowsMatrix(int blocksize, SCIP_Real *matrix, SCIP_Real *scale)
Definition: cons_sdp.c:266
int SCIPconsSdpCompLowerTriangPos(int i, int j)
Definition: cons_sdp.c:7965
static SCIP_RETCODE propagateUpperBounds(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool *infeasible, int *nprop)
Definition: cons_sdp.c:4344
SCIP_RETCODE SCIPconsSdpGetMaxEVSubmat(SCIP_CONS *cons, int **maxevsubmat)
Definition: cons_sdp.c:8528
SCIP_RETCODE SCIPlapackMatrixVectorMult(int nrows, int ncols, SCIP_Real *matrix, SCIP_Real *vector, SCIP_Real *result)
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
#define CONSHDLR_CHECKPRIORITY
Definition: cons_sdp.c:91
#define DEFAULT_TIGHTENBOUNDSCONT
Definition: cons_sdp.c:111
#define DEFAULT_MAXNSPARSECUTS
Definition: cons_sdp.c:130
static SCIP_DECL_CONSENFOPS(consEnfopsSdp)
Definition: cons_sdp.c:6727
SCIP_Bool SCIPconsSdpShouldBeRankOne(SCIP_CONS *cons)
Definition: cons_sdp.c:8513
#define DEFAULT_DIAGZEROIMPLCUTS
Definition: cons_sdp.c:115
SCIP_Bool SCIPrelaxSdpSolvedProbing(SCIP_RELAX *relax)
Definition: relax_sdp.c:5579
#define CONSHDLR_PROPFREQ
Definition: cons_sdp.c:92
static SCIP_RETCODE computeSdpMatrix(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_SOL *sol, SCIP_Real *matrix)
Definition: cons_sdp.c:326
static SCIP_RETCODE isMatrixRankOne(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *result)
Definition: cons_sdp.c:596
#define CONSHDLR_PROPTIMING
Definition: cons_sdp.c:102
adds the main functionality to fix/unfix/(multi-)aggregate variables by merging two three-tuple-array...
#define DEFAULT_UPGRADEQUADCONSS
Definition: cons_sdp.c:120
#define CONSHDLR_ENFOPRIORITY
Definition: cons_sdp.c:90
static SCIP_RETCODE tightenMatrices(SCIP *scip, SCIP_CONS **conss, int nconss, int *nchgcoefs)
Definition: cons_sdp.c:1694
SCIP_VAR ** SCIPconsSdpGetVars(SCIP *scip, SCIP_CONS *cons)
Definition: cons_sdp.c:8132
static SCIP_RETCODE addTwoMinorLinConstraints(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool solvesdps, int *naddconss)
Definition: cons_sdp.c:2455
static SCIP_DECL_CONSFREE(consFreeSdp)
Definition: cons_sdp.c:7100
static SCIP_DECL_CONSPRESOL(consPresolSdp)
Definition: cons_sdp.c:5900
SCIP_RETCODE SCIPincludeConshdlrSdpRank1(SCIP *scip)
Definition: cons_sdp.c:7853
static SCIP_DECL_CONSEXITPRE(consExitpreSdp)
Definition: cons_sdp.c:5663
static SCIP_DECL_CONSPRINT(consPrintSdp)
Definition: cons_sdp.c:7238
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopySdp)
Definition: cons_sdp.c:7122
static SCIP_RETCODE updateVarLocks(SCIP *scip, SCIP_CONS *cons, int v)
Definition: cons_sdp.c:3667
#define CONSHDLR_MAXPREROUNDS
Definition: cons_sdp.c:97
#define CONSHDLRRANK1_NAME
Definition: cons_sdp.c:86
static SCIP_DECL_CONSINITPRE(consInitpreSdp)
Definition: cons_sdp.c:5501
static SCIP_DECL_CONSINITSOL(consInitsolSdp)
Definition: cons_sdp.c:5717
static SCIP_DECL_CONSPARSE(consParseSdp)
Definition: cons_sdp.c:7379
#define CONSHDLRRANK1_DESC
Definition: cons_sdp.c:87
#define DEFAULT_TWOMINORVARBOUNDS
Definition: cons_sdp.c:118
static SCIP_RETCODE addTwoMinorSOCConstraints(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool solvesdps, int *naddconss)
Definition: cons_sdp.c:2606
#define DEFAULT_SPARSIFYTARGETSIZE
Definition: cons_sdp.c:128
#define DEFAULT_USEDIMACSFEASTOL
Definition: cons_sdp.c:134
static SCIP_RETCODE diagZeroImpl(SCIP *scip, SCIP_CONS **conss, int nconss, int *naddconss)
Definition: cons_sdp.c:2200
#define PARSE_STARTSIZE
Definition: cons_sdp.c:104
int SCIPconsSdpGetBlocksize(SCIP *scip, SCIP_CONS *cons)
Definition: cons_sdp.c:8149
#define DEFAULT_UPGRADEKEEPQUAD
Definition: cons_sdp.c:121
#define DEFAULT_TIGHTENMATRICES
Definition: cons_sdp.c:112
static SCIP_RETCODE diagGEzero(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_Bool solvesdps, int *naddconss, int *nchgbds, SCIP_Bool *infeasible)
Definition: cons_sdp.c:2029
static SCIP_DECL_CONSSEPASOL(consSepasolSdp)
Definition: cons_sdp.c:7001
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_RECOMPUTESPARSEEV
Definition: cons_sdp.c:142
Solve SDP with one variable.
static SCIP_RETCODE computeFullSdpMatrix(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_SOL *sol, SCIP_Real *fullmatrix)
Definition: cons_sdp.c:369
static SCIP_DECL_CONSGETVARS(consGetVarsSdp)
Definition: cons_sdp.c:7611
static SCIP_RETCODE computeAllmatricespsd(SCIP *scip, SCIP_CONS *cons)
Definition: cons_sdp.c:1645
SCIP_Bool SCIPrelaxSdpIsFeasible(SCIP_RELAX *relax)
Definition: relax_sdp.c:5596
#define CONSHDLR_SEPAPRIORITY
Definition: cons_sdp.c:89
SCIP_RETCODE SCIPlapackLinearSolve(BMS_BUFMEM *bufmem, int m, int n, SCIP_Real *A, SCIP_Real *b, SCIP_Real *x)
#define DEFAULT_ADDSOCRELAX
Definition: cons_sdp.c:133
SCIP_RETCODE SCIPconsSdpGetNNonz(SCIP *scip, SCIP_CONS *cons, int *nnonz, int *constnnonz)
Definition: cons_sdp.c:8090
#define DEFAULT_SPARSIFYCUT
Definition: cons_sdp.c:126
interface methods for eigenvector computation and matrix multiplication using openblas ...
SCIP_RETCODE SCIPlapackComputeEigenvectorsNegative(BMS_BUFMEM *bufmem, int n, SCIP_Real *A, SCIP_Real tol, int *neigenvalues, SCIP_Real *eigenvalues, SCIP_Real *eigenvectors)
static SCIP_DECL_CONSRESPROP(consRespropSdp)
Definition: cons_sdp.c:5826
static SCIP_RETCODE fixAndAggrVars(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool aggregate)
Definition: cons_sdp.c:3995
static SCIP_DECL_CONSLOCK(consLockSdp)
Definition: cons_sdp.c:5519
SCIP_RETCODE SCIPlapackComputeEigenvectorDecomposition(BMS_BUFMEM *bufmem, int n, SCIP_Real *A, SCIP_Real *eigenvalues, SCIP_Real *eigenvectors)
SCIP_RETCODE SCIPlapackComputeIthEigenvalue(BMS_BUFMEM *bufmem, SCIP_Bool geteigenvectors, int n, SCIP_Real *A, int i, SCIP_Real *eigenvalue, SCIP_Real *eigenvector)
#define DEFAULT_PROPUBPRESOL
Definition: cons_sdp.c:108
static SCIP_RETCODE move_1x1_blocks_to_lp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int *naddconss, int *ndelconss, int *nchgbds, SCIP_Bool *infeasible)
Definition: cons_sdp.c:3486
#define DEFAULT_EXACTTRANS
Definition: cons_sdp.c:144
static SCIP_DECL_CONSGETNVARS(consGetNVarsSdp)
Definition: cons_sdp.c:7645
static SCIP_DECL_CONSCOPY(consCopySdp)
Definition: cons_sdp.c:7152
#define DEFAULT_TWOMINORLINCONSS
Definition: cons_sdp.c:116
SCIP_RETCODE SCIPconsSdpGuessInitialPoint(SCIP *scip, SCIP_CONS *cons, SCIP_Real *lambdastar)
Definition: cons_sdp.c:8274
static SCIP_RETCODE analyzeConflict(SCIP *scip, SCIP_CONS *cons, int diags, int diagt, int pos, SCIP_Bool upperbound, SCIP_Bool usepos)
Definition: cons_sdp.c:4272
static SCIP_DECL_QUADCONSUPGD(consQuadConsUpgdSdp)
Definition: cons_sdp.c:5067
#define DEFAULT_GENERATEROWS
Definition: cons_sdp.c:135
static SCIP_RETCODE multiaggrVar(SCIP *scip, SCIP_CONS *cons, int v, SCIP_VAR **aggrvars, SCIP_Real *scalars, int naggrvars, SCIP_Real constant, int *savedcol, int *savedrow, SCIP_Real *savedval, int *nfixednonz, int *vararraylength)
Definition: cons_sdp.c:3821
static SCIP_RETCODE unlockVar(SCIP *scip, SCIP_CONSDATA *consdata, int v)
Definition: cons_sdp.c:3634
static SCIP_DECL_CONSENFOLP(consEnfolpSdp)
Definition: cons_sdp.c:6770