SCIP-SDP  3.0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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-2017 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-2017 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 
44 /* #define SCIP_DEBUG*/
45 /* #define SCIP_MORE_DEBUG *//* shows all cuts added and prints constraint after parsing */
46 /* #define PRINT_HUMAN_READABLE *//* change the output of PRINTCONS to a better readable format (dense instead of sparse), WHICH CAN NO LONGER BE PARSED */
47 
48 #include "cons_sdp.h"
49 
50 #include <assert.h> /*lint !e451*/
51 #include <string.h> /* for NULL, strcmp */
52 #include <ctype.h> /* for isspace */
53 
54 #include "sdpi/lapack.h"
55 
56 #include "scipsdp/SdpVarmapper.h"
57 #include "scipsdp/SdpVarfixer.h"
58 
59 #include "scip/cons_linear.h" /* for SCIPcreateConsLinear */
60 #include "scip/scip.h" /* for SCIPallocBufferArray, etc */
61 
62 #ifdef OMP
63 #include "omp.h" /* for changing the number of threads */
64 #endif
65 
66 /* turn off lint warnings for whole file: */
67 /*lint --e{788,818}*/
68 
69 #define CONSHDLR_NAME "SDP"
70 #define CONSHDLR_DESC "SDP constraints of the form \\sum_{j} A_j y_j - A_0 psd"
71 #define CONSHDLR_SEPAPRIORITY +1000000
72 #define CONSHDLR_ENFOPRIORITY -2000000
73 #define CONSHDLR_CHECKPRIORITY -2000000
74 #define CONSHDLR_SEPAFREQ 1
75 #define CONSHDLR_EAGERFREQ 100
77 #define CONSHDLR_MAXPREROUNDS -1
78 #define CONSHDLR_DELAYSEPA FALSE
79 #define CONSHDLR_NEEDSCONS TRUE
81 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_FAST
82 #define PARSE_STARTSIZE 1
83 #define PARSE_SIZEFACTOR 10
84 #define DEFAULT_DIAGGEZEROCUTS TRUE
85 #define DEFAULT_DIAGZEROIMPLCUTS TRUE
86 #ifdef OMP
87 #define DEFAULT_NTHREADS 1
88 #endif
89 
91 struct SCIP_ConsData
92 {
93  int nvars;
94  int nnonz;
95  int blocksize;
96  int* nvarnonz;
97  int** col;
98  int** row;
99  SCIP_Real** val;
100  SCIP_VAR** vars;
101  int constnnonz;
102  int* constcol;
103  int* constrow;
104  SCIP_Real* constval;
105  SCIP_Real maxrhsentry;
106 };
107 
109 struct SCIP_ConshdlrData
110 {
111  int neigveccuts;
112  SCIP_Bool diaggezerocuts;
113  int ndiaggezerocuts;
114  int n1x1blocks;
115  SCIP_Bool diagzeroimplcuts;
116 #ifdef OMP
117  int nthreads;
118 #endif
119 };
120 
121 #ifndef NDEBUG
122 
125 static
127  int i,
128  int j
129  )
130 {
131  assert( j >= 0 );
132  assert( i >= j );
133 
134  return i*(i+1)/2 + j;
135 }
136 #else
137 #define compLowerTriangPos(i, j) (i*(i+1)/2 + j)
138 #endif
139 
141 static
142 SCIP_RETCODE expandSymMatrix(
143  int size,
144  SCIP_Real* symMat,
145  SCIP_Real* fullMat
146  )
147 {
148  int i;
149  int j;
150  int ind = 0;
151 
152  assert( size >= 0 );
153  assert( symMat != NULL );
154  assert( fullMat != NULL );
155 
156  /* traverse the lower triangular part in the order of the indices and copy the values to both lower and upper triangular part */
157  for (i = 0; i < size; i++)
158  {
159  for (j = 0; j <= i; j++)
160  {
161  assert( ind == compLowerTriangPos(i,j) );
162  fullMat[i*size + j] = symMat[ind]; /*lint !e679*/
163  fullMat[j*size + i] = symMat[ind]; /*lint !e679*/
164  ind++;
165  }
166  }
167 
168  return SCIP_OKAY;
169 }
170 
174 static
175 SCIP_RETCODE computeSdpMatrix(
176  SCIP* scip,
177  SCIP_CONS* cons,
178  SCIP_SOL* y,
179  SCIP_Real* matrix
180  )
181 {
182  SCIP_CONSDATA* consdata;
183  SCIP_Real yval;
184  int blocksize;
185  int nvars;
186  int ind;
187  int i;
188 
189  assert( cons != NULL );
190  assert( matrix != NULL );
191 
192  consdata = SCIPconsGetData(cons);
193  nvars = consdata->nvars;
194  blocksize = consdata->blocksize;
195 
196  /* initialize the matrix with 0 */
197  for (i = 0; i < (blocksize * (blocksize + 1))/2; i++)
198  matrix[i] = 0.0;
199 
200  /* add the non-constant-part */
201  for (i = 0; i < nvars; i++)
202  {
203  yval = SCIPgetSolVal(scip, y, consdata->vars[i]);
204  for (ind = 0; ind < consdata->nvarnonz[i]; ind++)
205  matrix[compLowerTriangPos(consdata->row[i][ind], consdata->col[i][ind])] += yval * consdata->val[i][ind];
206  }
207 
208  /* substract the constant part */
209  for (ind = 0; ind < consdata->constnnonz; ind++)
210  matrix[compLowerTriangPos(consdata->constrow[ind], consdata->constcol[ind])] -= consdata->constval[ind];
211 
212  return SCIP_OKAY;
213 }
214 
216 static
217 SCIP_RETCODE multiplyConstraintMatrix(
218  SCIP_CONS* cons,
219  int j,
220  SCIP_Real* v,
221  SCIP_Real* vAv
222  )
223 {
224  SCIP_CONSDATA* consdata;
225  int i;
226 
227  assert( cons != NULL );
228  assert( j >= 0 );
229  assert( vAv != NULL );
230 
231  consdata = SCIPconsGetData(cons);
232  assert( consdata != NULL );
233 
234  assert( j < consdata->nvars );
235 
236  /* initialize the product with 0 */
237  *vAv = 0.0;
238 
239  for (i = 0; i < consdata->nvarnonz[j]; i++)
240  {
241  if (consdata->col[j][i] == consdata->row[j][i])
242  *vAv += v[consdata->col[j][i]] * consdata->val[j][i] * v[consdata->row[j][i]];
243  else
244  {
245  /* Multiply by 2, because the matrix is symmetric and there is one identical contribution each from lower and upper triangular part. */
246  *vAv += 2.0 * v[consdata->col[j][i]] * consdata->val[j][i] * v[consdata->row[j][i]];
247  }
248  }
249 
250  return SCIP_OKAY;
251 }
252 
256 static
257 SCIP_RETCODE setMaxRhsEntry(
258  SCIP_CONS* cons
259  )
260 {
261  SCIP_CONSDATA* consdata;
262  SCIP_Real max;
263  int i;
264 
265  consdata = SCIPconsGetData(cons);
266  assert( consdata != NULL );
267 
268  /* initialize max with zero (this is used if there is no constant-matrix) */
269  max = 0.0;
270 
271  /* iterate over the entries of the constant matrix, updating max if a higher absolute value is found */
272  for (i = 0; i < consdata->constnnonz; i++)
273  {
274  if ( REALABS(consdata->constval[i]) > max )
275  max = REALABS(consdata->constval[i]);
276  }
277 
278  consdata->maxrhsentry = max;
279 
280  return SCIP_OKAY;
281 }
282 
283 
289 static
290 SCIP_RETCODE cutUsingEigenvector(
291  SCIP* scip,
292  SCIP_CONS* cons,
293  SCIP_SOL* sol,
294  SCIP_Real* coeff,
295  SCIP_Real* lhs
296  )
297 {
298  SCIP_CONSDATA* consdata;
299  SCIP_Real* eigenvalues = NULL;
300  SCIP_Real* matrix = NULL;
301  SCIP_Real* fullmatrix = NULL;
302  SCIP_Real* fullconstmatrix = NULL;
303  SCIP_Real* eigenvector = NULL;
304  SCIP_Real* output_vector = NULL;
305  int blocksize;
306  int j;
307 
308  assert( cons != NULL );
309  assert( lhs != NULL );
310 
311  *lhs = 0.0;
312 
313  consdata = SCIPconsGetData(cons);
314  assert( consdata != NULL );
315 
316  blocksize = consdata->blocksize;
317 
318  SCIP_CALL( SCIPallocBufferArray(scip, &eigenvalues, blocksize) );
319  SCIP_CALL( SCIPallocBufferArray(scip, &matrix, (blocksize * (blocksize+1))/2 ) ); /*lint !e647*/
320  SCIP_CALL( SCIPallocBufferArray(scip, &fullmatrix, blocksize * blocksize ) ); /*lint !e647*/
321  SCIP_CALL( SCIPallocBufferArray(scip, &fullconstmatrix, blocksize * blocksize) ); /*lint !e647*/
322  SCIP_CALL( SCIPallocBufferArray(scip, &eigenvector, blocksize) );
323  SCIP_CALL( SCIPallocBufferArray(scip, &output_vector, blocksize) );
324 
325  /* compute the matrix \f$ \sum_j A_j y_j - A_0 \f$ */
326  SCIP_CALL( computeSdpMatrix(scip, cons, sol, matrix) );
327 
328  /* expand it because LAPACK wants the full matrix instead of the lower triangular part */
329  SCIP_CALL( expandSymMatrix(blocksize, matrix, fullmatrix) );
330 
331  SCIP_CALL( SCIPlapackComputeIthEigenvalue(SCIPbuffer(scip), TRUE, blocksize, fullmatrix, 1, eigenvalues, eigenvector) );
332 
333  /* get full constant matrix */
334  SCIP_CALL( SCIPconsSdpGetFullConstMatrix(scip, cons, fullconstmatrix) );
335 
336  /* multiply eigenvector with constant matrix to get lhs (after multiplying again with eigenvector from the left) */
337  SCIP_CALL( SCIPlapackMatrixVectorMult(blocksize, blocksize, fullconstmatrix, eigenvector, output_vector) );
338 
339  for (j = 0; j < blocksize; ++j)
340  *lhs += eigenvector[j] * output_vector[j];
341 
342  /* 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 */
343  for (j = 0; j < consdata->nvars; ++j)
344  {
345  SCIP_CALL( multiplyConstraintMatrix(cons, j, eigenvector, &coeff[j]) );
346  }
347 
348  SCIPfreeBufferArray(scip, &output_vector);
349  SCIPfreeBufferArray(scip, &eigenvector);
350  SCIPfreeBufferArray(scip, &fullconstmatrix);
351  SCIPfreeBufferArray(scip, &fullmatrix);
352  SCIPfreeBufferArray(scip, &matrix);
353  SCIPfreeBufferArray(scip, &eigenvalues);
354 
355  return SCIP_OKAY;
356 }
357 
359 SCIP_RETCODE SCIPconsSdpCheckSdpCons(
360  SCIP* scip,
361  SCIP_CONS* cons,
362  SCIP_SOL* sol,
363  SCIP_Bool checkintegrality,
364  SCIP_Bool checklprows,
365  SCIP_Bool printreason,
366  SCIP_RESULT* result
367  )
368 { /*lint --e{715}*/
369  SCIP_CONSDATA* consdata;
370  int blocksize;
371  SCIP_Real check_value;
372  SCIP_Real eigenvalue;
373  SCIP_Real* matrix = NULL;
374  SCIP_Real* fullmatrix = NULL;
375 
376  assert( scip != NULL );
377  assert( cons != NULL );
378  assert( result != NULL );
379  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), "SDP") == 0);
380 
381  consdata = SCIPconsGetData(cons);
382  assert( consdata != NULL );
383  blocksize = consdata->blocksize;
384 
385  SCIP_CALL( SCIPallocBufferArray(scip, &matrix, (blocksize * (blocksize+1)) / 2) ); /*lint !e647*/
386  SCIP_CALL( SCIPallocBufferArray(scip, &fullmatrix, blocksize * blocksize) ); /*lint !e647*/
387  SCIP_CALL( computeSdpMatrix(scip, cons, sol, matrix) );
388  SCIP_CALL( expandSymMatrix(blocksize, matrix, fullmatrix) );
389 
390  SCIP_CALL( SCIPlapackComputeIthEigenvalue(SCIPbuffer(scip), FALSE, blocksize, fullmatrix, 1, &eigenvalue, NULL) );
391 
392  /* This enables checking the second DIMACS Error Norm: err=max{0, -lambda_min(x)/(1+maximumentry of rhs)}, in that case it also needs
393  * to be changed in the sdpi (and implemented there first), when checking feasibility of problems where all variables are fixed */
394 #ifdef DIMACS
395  check_value = (-eigenvalue) / (1.0 + consdata->maxrhsentry);
396 #else
397  check_value = -eigenvalue;
398 #endif
399 
400  if ( SCIPisFeasLE(scip, check_value, 0.0) )
401  *result = SCIP_FEASIBLE;
402  else
403  {
404  *result = SCIP_INFEASIBLE;
405 #ifdef SCIP_DEBUG
406  if ( printreason )
407  {
408  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
409  SCIP_CALL( SCIPprintSol(scip, sol, NULL, FALSE) );
410  SCIPinfoMessage(scip, NULL, "non psd matrix (eigenvalue %f, dimacs error norm = %f).\n", eigenvalue, check_value);
411  }
412 #endif
413  }
414 
415  SCIPfreeBufferArray(scip, &fullmatrix);
416  SCIPfreeBufferArray(scip, &matrix);
417 
418  return SCIP_OKAY;
419 }
420 
422 static
423 SCIP_RETCODE separateSol(
424  SCIP* scip,
425  SCIP_CONSHDLR* conshdlr,
426  SCIP_CONS* cons,
427  SCIP_SOL* sol,
428  SCIP_RESULT* result
429  )
430 {
431  char cutname[SCIP_MAXSTRLEN];
432  SCIP_CONSDATA* consdata;
433  SCIP_CONSHDLRDATA* conshdlrdata;
434  SCIP_Real lhs = 0.0;
435  SCIP_Real* coeff = NULL;
436  SCIP_COL** cols;
437  SCIP_Real* vals;
438  SCIP_ROW* row;
439  int nvars;
440  int j;
441  int len;
442 #ifndef NDEBUG
443  int snprintfreturn; /* this is used to assert that the SCIP string concatenation works */
444 #endif
445 
446  assert( cons != NULL );
447 
448  consdata = SCIPconsGetData(cons);
449  assert( consdata != NULL );
450 
451  nvars = consdata->nvars;
452  SCIP_CALL( SCIPallocBufferArray(scip, &coeff, nvars ) );
453 
454  SCIP_CALL( cutUsingEigenvector(scip, cons, sol, coeff, &lhs) );
455 
456  SCIP_CALL( SCIPallocBufferArray(scip, &cols, nvars ) );
457  SCIP_CALL( SCIPallocBufferArray(scip, &vals, nvars ) );
458 
459  len = 0;
460  for (j = 0; j < nvars; ++j)
461  {
462  if ( SCIPisZero(scip, coeff[j]) )
463  continue;
464 
465  cols[len] = SCIPvarGetCol(SCIPvarGetProbvar(consdata->vars[j]));
466  vals[len] = coeff[j];
467  ++len;
468  }
469 
470  conshdlrdata = SCIPconshdlrGetData(conshdlr);
471  assert( conshdlrdata != NULL );
472 
473 #ifndef NDEBUG
474  snprintfreturn = SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "sepa_eig_sdp_%d", ++(conshdlrdata->neigveccuts));
475  assert( snprintfreturn < SCIP_MAXSTRLEN ); /* check whether name fit into string */
476 #else
477  (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "sepa_eig_sdp_%d", ++(conshdlrdata->neigveccuts));
478 #endif
479  SCIP_CALL( SCIPcreateRowCons(scip, &row, conshdlr, cutname , len, cols, vals, lhs, SCIPinfinity(scip), FALSE, FALSE, TRUE) );
480 
481  if ( SCIPisCutEfficacious(scip, sol, row) )
482  {
483  SCIP_Bool infeasible;
484 #ifdef SCIP_MORE_DEBUG
485  SCIPinfoMessage(scip, NULL, "Added cut %s: ", cutname);
486  SCIPinfoMessage(scip, NULL, "%f <= ", lhs);
487  for (j = 0; j < len; j++)
488  SCIPinfoMessage(scip, NULL, "+ (%f)*%s", vals[j], SCIPvarGetName(SCIPcolGetVar(cols[j])));
489  SCIPinfoMessage(scip, NULL, "\n");
490 #endif
491 
492  SCIP_CALL( SCIPaddCut(scip, sol, row, FALSE, &infeasible) );
493  if ( infeasible )
494  *result = SCIP_CUTOFF;
495  else
496  *result = SCIP_SEPARATED;
497  SCIP_CALL( SCIPresetConsAge(scip, cons) );
498  }
499 
500  SCIP_CALL( SCIPreleaseRow(scip, &row) );
501 
502  SCIPfreeBufferArray(scip, &vals);
503  SCIPfreeBufferArray(scip, &cols);
504  SCIPfreeBufferArray(scip, &coeff);
505 
506  return SCIP_OKAY;
507 }
508 
512 static
513 SCIP_RETCODE diagGEzero(
514  SCIP* scip,
515  SCIP_CONS** conss,
516  int nconss,
517  int* naddconss
518  )
519 {
520  char cutname[SCIP_MAXSTRLEN];
521  SCIP_CONSDATA* consdata;
522  SCIP_Real* matrix;
523  SCIP_Real* cons_array;
524  SCIP_Real* lhs_array;
525  SCIP_Real rhs;
526  int blocksize;
527  int nvars;
528  int i;
529  int j;
530  int k;
531  int c;
532 #ifndef NDEBUG
533  int snprintfreturn; /* used to check if sdnprintf worked */
534 #endif
535 
536  for (c = 0; c < nconss; ++c)
537  {
538  SCIP_CONSHDLR* conshdlr;
539 
540  conshdlr = SCIPconsGetHdlr(conss[c]);
541  assert( conshdlr != NULL );
542 #ifndef NDEBUG
543  assert( strcmp(SCIPconshdlrGetName(conshdlr), "SDP") == 0);
544 #endif
545 
546  consdata = SCIPconsGetData(conss[c]);
547  assert( consdata != NULL );
548 
549  blocksize = consdata->blocksize;
550  nvars = consdata->nvars;
551  rhs = SCIPinfinity(scip);
552 
553  SCIP_CALL( SCIPallocBufferArray(scip, &matrix, (blocksize * (blocksize + 1)) / 2) ); /*lint !e647*/
554  SCIP_CALL( SCIPconsSdpGetLowerTriangConstMatrix(scip, conss[c], matrix) );
555 
556  SCIP_CALL( SCIPallocBufferArray(scip, &cons_array, blocksize * nvars) ); /*lint !e647*/
557  SCIP_CALL( SCIPallocBufferArray(scip, &lhs_array, blocksize) );
558 
559  /* the lhs is the (k,k)-entry of the constant matrix */
560  for (k = 0; k < blocksize; ++k)
561  lhs_array[k] = matrix[compLowerTriangPos(k,k)];
562 
563  /* get the (k,k)-entry of every matrix A_j */
564  for (j = 0; j < nvars; ++j)
565  {
566  for (k = 0; k < blocksize; ++k)
567  {
568  /* initialize these with 0 */
569  cons_array[k * nvars + j] = 0.0; /*lint !e679*/
570  }
571 
572  /* go through the nonzeros of A_j and look for diagonal entries */
573  for (i = 0; i < consdata->nvarnonz[j]; i++)
574  {
575  if ( consdata->col[j][i] == consdata->row[j][i] )
576  cons_array[consdata->col[j][i] * nvars + j] = consdata->val[j][i]; /*lint !e679*/
577  }
578  }
579 
580  /* add the LP-cuts to SCIP */
581  for (k = 0; k < blocksize; ++k)
582  {
583  SCIP_CONS* cons;
584  SCIP_CONSHDLRDATA* conshdlrdata;
585 
586  conshdlrdata = SCIPconshdlrGetData(conshdlr);
587 #ifndef NDEBUG
588  snprintfreturn = SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "diag_ge_zero_%d", ++(conshdlrdata->ndiaggezerocuts));
589  assert( snprintfreturn < SCIP_MAXSTRLEN );
590 #else
591  (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "diag_ge_zero_%d", ++(conshdlrdata->ndiaggezerocuts));
592 #endif
593 
594 #ifdef SCIP_MORE_DEBUG
595  SCIPinfoMessage(scip, NULL, "Added lp-constraint %s: ", cutname);
596  SCIPinfoMessage(scip, NULL, "%f <= ", lhs_array[k]);
597  for (i = 0; i < consdata->nvars; i++)
598  {
599  if ( ! SCIPisZero(scip, cons_array[k * consdata->nvars + i]) )
600  SCIPinfoMessage(scip, NULL, "+ (%f)*%s", cons_array[k * consdata->nvars + i], SCIPvarGetName(consdata->vars[i]));
601  }
602  SCIPinfoMessage(scip, NULL, "\n");
603 #endif
604 
605  SCIP_CALL( SCIPcreateConsLinear(scip, &cons, cutname, consdata->nvars, consdata->vars, cons_array + k * consdata->nvars, lhs_array[k], rhs,
606  TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE) ); /*lint !e679*/
607 
608  SCIP_CALL( SCIPaddCons(scip, cons) );
609  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
610  ++(*naddconss);
611  }
612 
613  SCIPfreeBufferArray(scip, &lhs_array);
614  SCIPfreeBufferArray(scip, &cons_array);
615  SCIPfreeBufferArray(scip, &matrix);
616  }
617 
618  return SCIP_OKAY;
619 }
620 
628 static
629 SCIP_RETCODE diagZeroImpl(
630  SCIP* scip,
631  SCIP_CONS** conss,
632  int nconss,
633  int* naddconss
634  )
635 {
636  char cutname[SCIP_MAXSTRLEN];
637  /* if entry k is >= 0, gives the number of non-diagonal nonzero-entries in row k of the constant matrix (and the number
638  * of entries in constnonzeroentries), if -1 C_kk =!= 0 (which means we didnot allocate memory for diagvars), if -2
639  * either A_jk =!= 0 for all j with C_jk =!= 0 or A_kk =!= 0 for some continuous variable (which means we did allocate
640  * memory for diagvars but cannot use the cut */
641  int* nconstnonzeroentries;
642  int** constnonzeroentries;
643  SCIP_CONSDATA* consdata;
644  SCIP_CONS* cons;
645  SCIP_VAR** vars;
646  SCIP_Real* vals;
647  int** diagvars;
648  int* ndiagvars;
649  int blocksize;
650  int i;
651  int j;
652  int nvars;
653  int v;
654  int k;
655  int l;
656  SCIP_Bool anycutvalid;
657 #ifndef NDEBUG
658  int snprintfreturn;
659 #endif
660 
661  assert( scip != NULL );
662  assert( conss != NULL );
663  assert( nconss >= 0 );
664  assert( naddconss != NULL );
665 
666  for (i = 0; i < nconss; ++i)
667  {
668  assert( conss[i] != NULL );
669  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(conss[i])), "SDP") == 0 );
670 
671  consdata = SCIPconsGetData(conss[i]);
672  assert( consdata != NULL );
673 
674  blocksize = consdata->blocksize;
675  nvars = consdata->nvars;
676  SCIP_CALL( SCIPallocBufferArray(scip, &nconstnonzeroentries, blocksize) );
677  SCIP_CALL( SCIPallocBufferArray(scip, &constnonzeroentries, blocksize) );
678  for (j = 0; j < blocksize; j++)
679  {
680  nconstnonzeroentries[j] = 0;
681  SCIP_CALL( SCIPallocBufferArray(scip, &constnonzeroentries[j], blocksize) );
682  }
683 
684  /* iterate over all nonzeros of the constant matrix and check which diagonal and non-diagonal entries are nonzero */
685  for (j = 0; j < consdata->constnnonz; j++)
686  {
687  /* if it is a nondiagonal-entry we add this row/column to the constnonzeroentries entries unless we already found a
688  * diagonal entry for this row/column */
689  if ( (consdata->constcol[j] != consdata->constrow[j]) )
690  {
691  assert( ! SCIPisZero(scip, consdata->constval[j]) );
692  if ( nconstnonzeroentries[consdata->constcol[j]] >= 0 )
693  {
694  constnonzeroentries[consdata->constcol[j]][nconstnonzeroentries[consdata->constcol[j]]] = consdata->constrow[j];
695  nconstnonzeroentries[consdata->constcol[j]]++;
696  }
697  if ( nconstnonzeroentries[consdata->constrow[j]] >= 0 )
698  {
699  constnonzeroentries[consdata->constrow[j]][nconstnonzeroentries[consdata->constrow[j]]] = consdata->constcol[j];
700  nconstnonzeroentries[consdata->constrow[j]]++;
701  }
702  }
703  /* if we find a diagonal entry in the constant matrix, we remember that we cannot add a cut for this index */
704  else
705  {
706  assert( ! SCIPisZero(scip, consdata->constval[j]) );
707  nconstnonzeroentries[consdata->constcol[j]] = -1;
708  }
709  }
710 
711  /* diagvars[j] is an array with all variables with a diagonal entry (j,j) in the corresponding matrix, if nconstnonzeroentries[j] =!= -1 or NULL otherwise
712  * the outer array goes over all rows to ease the access, but only for those that are really needed memory will be allocated */
713  SCIP_CALL( SCIPallocBufferArray(scip, &diagvars, blocksize) );
714  SCIP_CALL( SCIPallocBufferArray(scip, &ndiagvars, blocksize) );
715  anycutvalid = FALSE;
716  for (j = 0; j < blocksize; ++j)
717  {
718  ndiagvars[j] = 0;
719  if ( nconstnonzeroentries[j] > 0 )
720  {
721  SCIP_CALL( SCIPallocBufferArray(scip, &(diagvars[j]), nvars) );
722  anycutvalid = TRUE;
723  }
724  }
725 
726  /* if no cuts are valid for this block, we free all memory and continue with the next block */
727  if ( ! anycutvalid )
728  {
729  SCIPfreeBufferArray(scip, &ndiagvars);
730  SCIPfreeBufferArray(scip, &diagvars);
731  for (j = blocksize - 1; j >= 0; j--)
732  {
733  SCIPfreeBufferArray(scip, &constnonzeroentries[j]);
734  }
735  SCIPfreeBufferArray(scip, &constnonzeroentries);
736  SCIPfreeBufferArray(scip, &nconstnonzeroentries);
737  continue;
738  }
739 
740  /* find all variables with corresponding diagonal entries for a row with nonzero non-diagonal constant entry, also check for entries
741  * that prevent the cut from being valid */
742  for (v = 0; v < nvars; v++)
743  {
744  for (j = 0; j < consdata->nvarnonz[v]; j++)
745  {
746  /* if it is a diagonal entry for an index that might have a valid cut, we add the variable to the corresponding array if it
747  * is an integer variable and mark the cut invalid otherwise */
748  if ( (consdata->col[v][j] == consdata->row[v][j]) && (nconstnonzeroentries[consdata->col[v][j]] > 0) )
749  {
750  if ( SCIPvarIsIntegral(consdata->vars[v]) )
751  {
752  assert( ! SCIPisEQ(scip, consdata->val[v][j], 0.0) );
753  diagvars[consdata->col[v][j]][ndiagvars[consdata->col[v][j]]] = v;
754  ndiagvars[consdata->col[v][j]]++;
755  }
756  else
757  {
758  nconstnonzeroentries[consdata->col[v][j]] = -2;
759  }
760  }
761  /* If it is a non-diagonal entry, we can no longer use this entry for a cut. If the last entry is removed for a column/row,
762  * mark this column/row invalid (but we still have to free memory later, so we have to set it to -2 instead of 0) */
763  else if ( consdata->col[v][j] != consdata->row[v][j] )
764  {
765  if ( nconstnonzeroentries[consdata->col[v][j]] > 0 )
766  {
767  /* search for the corresponding row-entry in constnonzeroentries */
768  for (k = 0; k < nconstnonzeroentries[consdata->col[v][j]]; k++)
769  {
770  if ( constnonzeroentries[consdata->col[v][j]][k] == consdata->row[v][j] )
771  {
772  /* if there are remaining entries, we shift them back */
773  if ( nconstnonzeroentries[consdata->col[v][j]] > k + 1 )
774  {
775  for (l = k + 1; l < nconstnonzeroentries[consdata->col[v][j]]; l++)
776  constnonzeroentries[consdata->col[v][j]][l - 1] = constnonzeroentries[consdata->col[v][j]][l];
777  }
778  nconstnonzeroentries[consdata->col[v][j]]--;
779  /* if this was the last entry for this index, we mark it invalid */
780  if ( nconstnonzeroentries[consdata->col[v][j]] == 0 )
781  nconstnonzeroentries[consdata->col[v][j]] = -2;
782  break; /* we should not have another entry for this combination of row and column */
783  }
784  }
785  }
786  /* do the same for the row */
787  if ( nconstnonzeroentries[consdata->row[v][j]] > 0 )
788  {
789  /* search for the corresponding row-entry in constnonzeroentries */
790  for (k = 0; k < nconstnonzeroentries[consdata->row[v][j]]; k++)
791  {
792  if ( constnonzeroentries[consdata->row[v][j]][k] == consdata->col[v][j] )
793  {
794  /* if there are remaining entries, we shift them back */
795  if ( nconstnonzeroentries[consdata->row[v][j]] > k + 1 )
796  {
797  for (l = k + 1; l < nconstnonzeroentries[consdata->row[v][j]]; l++)
798  constnonzeroentries[consdata->row[v][j]][l - 1] = constnonzeroentries[consdata->row[v][j]][l];
799  }
800  nconstnonzeroentries[consdata->row[v][j]]--;
801  /* if this was the last entry for this index, we mark it invalid */
802  if ( nconstnonzeroentries[consdata->row[v][j]] == 0 )
803  nconstnonzeroentries[consdata->row[v][j]] = -2;
804  break; /* we should not have another entry for this combination of row and column */
805  }
806  }
807  }
808  }
809  }
810  }
811 
812  for (j = 0; j < blocksize; ++j)
813  {
814  if ( nconstnonzeroentries[j] > 0 )
815  {
816  SCIP_CALL( SCIPallocBufferArray(scip, &vals, ndiagvars[j]) );
817  SCIP_CALL( SCIPallocBufferArray(scip, &vars, ndiagvars[j]) );
818 
819  /* get the corresponding SCIP variables and set all coefficients to 1 */
820  for (v = 0; v < ndiagvars[j]; ++v)
821  {
822  vars[v] = consdata->vars[diagvars[j][v]];
823  vals[v] = 1.0;
824  }
825 #ifndef NDEBUG
826  snprintfreturn = SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "diag_zero_impl_block_%d_row_%d", i, j);
827  assert( snprintfreturn < SCIP_MAXSTRLEN ); /* check whether name fits into string */
828 #else
829  (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "diag_zero_impl_block_%d_row_%d", i, j);
830 #endif
831 
832 #ifdef SCIP_MORE_DEBUG
833  SCIPinfoMessage(scip, NULL, "Added lp-constraint %s: ", cutname);
834  SCIPinfoMessage(scip, NULL, "1 <=");
835  for (l = 0; l < ndiagvars[j]; l++)
836  SCIPinfoMessage(scip, NULL, " + (%f)*%s", vals[l], SCIPvarGetName(vars[l]));
837  SCIPinfoMessage(scip, NULL, "\n");
838 #endif
839 
840  /* add the linear constraint sum_j 1.0 * diagvars[j] >= 1.0 */
841  SCIP_CALL(SCIPcreateConsLinear(scip, &cons, cutname , ndiagvars[j], vars, vals, 1.0, SCIPinfinity(scip), TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE));
842  SCIP_CALL(SCIPaddCons(scip, cons));
843  SCIP_CALL(SCIPreleaseCons(scip, &cons));
844  (*naddconss)++;
845 
846  SCIPfreeBufferArray(scip, &vars);
847  SCIPfreeBufferArray(scip, &vals);
848  }
849  if ( nconstnonzeroentries[j] == -2 || nconstnonzeroentries[j] > 0 )
850  {
851  SCIPfreeBufferArray(scip, &diagvars[j]);
852  }
853  }
854 
855  SCIPfreeBufferArray(scip, &ndiagvars);
856  SCIPfreeBufferArray(scip, &diagvars);
857  for (j = blocksize - 1; j >= 0; j--)
858  {
859  SCIPfreeBufferArray(scip, &constnonzeroentries[j]);
860  }
861  SCIPfreeBufferArray(scip, &constnonzeroentries);
862  SCIPfreeBufferArray(scip, &nconstnonzeroentries);
863  }
864 
865  return SCIP_OKAY;
866 }
867 
869 static
870 SCIP_RETCODE move_1x1_blocks_to_lp(
871  SCIP* scip,
872  SCIP_CONS** conss,
873  int nconss,
874  int* naddconss,
875  int* ndelconss,
876  SCIP_RESULT* result
877  )
878 {
879  char cutname[SCIP_MAXSTRLEN];
880  SCIP_CONSHDLR* hdlr;
881  SCIP_CONSDATA* consdata;
882  SCIP_CONSHDLRDATA* conshdlrdata;
883  SCIP_CONS* cons;
884  SCIP_VAR** vars;
885  SCIP_Real* coeffs;
886  SCIP_Real rhs;
887  int nnonz;
888  int nvars;
889  int i;
890  int j;
891  int count;
892  int var;
893 #ifndef NDEBUG
894  int snprintfreturn; /* used to assert the return code of snprintf */
895 #endif
896 
897  assert( result != NULL );
898  *result = SCIP_SUCCESS;
899 
900  for (i = 0; i < nconss; ++i)
901  {
902  hdlr = SCIPconsGetHdlr(conss[i]);
903  assert(hdlr != NULL);
904 
905 #ifndef NDEBUG
906  assert( strcmp(SCIPconshdlrGetName(hdlr), "SDP") == 0);
907 #endif
908 
909  consdata = SCIPconsGetData(conss[i]);
910  assert( consdata != NULL );
911 
912  /* if there is a 1x1 SDP-Block */
913  if ( consdata->blocksize == 1 )
914  {
915  nvars = consdata->nvars;
916  nnonz = consdata->nnonz;
917  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
918  SCIP_CALL( SCIPallocBufferArray(scip, &coeffs, nnonz) );
919 
920  /* get all lhs-entries */
921  count = 0;
922 
923  for (var = 0; var < nvars; var++)
924  {
925  assert( consdata->nvarnonz[var] <= 1 ); /* in a 1x1 block there may be at most one entry per variable */
926 
927  for (j = 0; j < consdata->nvarnonz[var]; j++)
928  {
929  assert( consdata->col[var][j] == 0 && consdata->row[var][j] == 0 ); /* if the block is size one, all entries should have row and col equal to 0 */
930  coeffs[count] = consdata->val[var][j];
931  vars[count] = consdata->vars[var];
932  count++;
933  }
934  }
935 
936  /* get rhs */
937  assert( consdata->constnnonz <= 1 ); /* the 1x1 constant matrix may only have one entry */
938 
939  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 */
940 
941  /* if there is more than one left-hand-side-entry, add a linear constraint, otherwise update the variable bound */
942  if ( count > 1 )
943  {
944  /* add new linear cons */
945  conshdlrdata = SCIPconshdlrGetData(hdlr);
946 #ifndef NDEBUG
947  snprintfreturn = SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "1x1block_%d", ++(conshdlrdata->n1x1blocks));
948  assert( snprintfreturn < SCIP_MAXSTRLEN ); /* check whether name fits into string */
949 #else
950  (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "1x1block_%d", ++(conshdlrdata->n1x1blocks));
951 #endif
952 
953 #ifdef SCIP_MORE_DEBUG
954  SCIPinfoMessage(scip, NULL, "Added lp-constraint %s: ", cutname);
955  for (i = 0; i < consdata->nvars; i++)
956  SCIPinfoMessage(scip, NULL, "+ (%f)*%s", coeffs[i], SCIPvarGetName(vars[i]));
957  SCIPinfoMessage(scip, NULL, " <= %f \n", rhs);
958 #endif
959 
960  SCIP_CALL( SCIPcreateConsLinear(scip, &cons, cutname, consdata->nvars, vars, coeffs, rhs, SCIPinfinity(scip),
961  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE) );
962 
963  SCIP_CALL( SCIPaddCons(scip, cons) );
964  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
965 
966  (*naddconss)++;
967  }
968  else
969  {
970  /* we compare this new variable with the current (local) bounds, we don't do an epsilon check here, because 10^(-21)*x >= 10^(-19) for
971  * epsilon = 10^(-20) would be infeasible then, even though it only says x >= 100 */
972  if ( coeffs[0] > 0.0 )
973  {
974  /* this gives a lower bound, if it is bigger than the current one, we need to update it */
975  if ( SCIPisFeasGT(scip, rhs / coeffs[0], SCIPvarGetLbLocal(vars[0])) )
976  {
977  /* check if the changed bound renders the problem infeasible */
978  if( SCIPisFeasGT(scip, rhs / coeffs[0], SCIPvarGetUbLocal(vars[0])) )
979  {
980  SCIPdebugMessage("Problem detected to be infeasible during presolving, 1x1-SDP-constraint %s caused change"
981  "of lower bound for variable %s from %f to %f, which is bigger than upper bound of %f\n",
982  SCIPconsGetName(conss[i]), SCIPvarGetName(vars[0]), SCIPvarGetLbLocal(vars[0]), rhs / coeffs[0],
983  SCIPvarGetUbLocal(vars[0]));
984 
985  *result = SCIP_CUTOFF;
986 
987  /* delete old 1x1 sdpcone */
988  SCIP_CALL( SCIPdelCons(scip, conss[i]) );
989  (*ndelconss)++;
990 
991  SCIPfreeBufferArray(scip, &coeffs);
992  SCIPfreeBufferArray(scip, &vars);
993 
994  return SCIP_OKAY; /* the node is infeasible, we don't care for the other constraints */
995  }
996 
997  SCIPdebugMessage("Changing lower bound of variable %s from %f to %f because of 1x1-SDP-constraint %s!\n",
998  SCIPvarGetName(vars[0]), SCIPvarGetLbLocal(vars[0]), rhs / coeffs[0], SCIPconsGetName(conss[i]));
999  SCIP_CALL( SCIPchgVarLb(scip, vars[0], rhs / coeffs[0]) );
1000  }
1001  else
1002  {
1003  SCIPdebugMessage("Deleting 1x1-SDP-constraint %s, new lower bound %f for variable %s no improvement over old bound %f!\n",
1004  SCIPconsGetName(conss[i]), rhs / coeffs[0], SCIPvarGetName(vars[0]), SCIPvarGetLbLocal(vars[0]));
1005  }
1006  }
1007  else if ( coeffs[0] < 0.0 )
1008  {
1009  /* this gives an upper bound, if it is lower than the current one, we need to update it */
1010  if (SCIPisFeasLT(scip, rhs / coeffs[0], SCIPvarGetUbLocal(vars[0])))
1011  {
1012  /* check if the changed bound renders the problem infeasible */
1013  if( SCIPisFeasLT(scip, rhs / coeffs[0], SCIPvarGetLbLocal(vars[0])) )
1014  {
1015  SCIPdebugMessage("Problem detected to be infeasible during presolving, 1x1-SDP-constraint %s caused change"
1016  "of upper bound for variable %s from %f to %f, which is less than lower bound of %f\n",
1017  SCIPconsGetName(conss[i]), SCIPvarGetName(vars[0]), SCIPvarGetUbLocal(vars[0]), rhs / coeffs[0],
1018  SCIPvarGetLbLocal(vars[0]));
1019 
1020  *result = SCIP_CUTOFF;
1021 
1022  /* delete old 1x1 sdpcone */
1023  SCIP_CALL( SCIPdelCons(scip, conss[i]) );
1024  (*ndelconss)++;
1025 
1026  SCIPfreeBufferArray(scip, &coeffs);
1027  SCIPfreeBufferArray(scip, &vars);
1028 
1029  return SCIP_OKAY; /* the node is infeasible, we don't care for the other constraints */
1030  }
1031 
1032  SCIPdebugMessage("Changing upper bound of variable %s from %f to %f because of 1x1-SDP-constraint %s!\n",
1033  SCIPvarGetName(vars[0]), SCIPvarGetUbLocal(vars[0]), -rhs / coeffs[0], SCIPconsGetName(conss[i]));
1034  SCIP_CALL( SCIPchgVarUb(scip, vars[0], rhs / coeffs[0]) );
1035  }
1036  else
1037  {
1038  SCIPdebugMessage("Deleting 1x1-SDP-constraint %s, new upper bound %f for variable %s no improvement over old bound %f!\n",
1039  SCIPconsGetName(conss[i]), rhs / coeffs[0], SCIPvarGetName(vars[0]), SCIPvarGetUbLocal(vars[0]));
1040  }
1041  }
1042  else
1043  {
1044  SCIPdebugMessage("Detected 1x1 SDP-block without any nonzero coefficients \n");
1045  if ( SCIPisFeasGT(scip, rhs, 0.0) )
1046  {
1047  SCIPdebugMessage("Detected infeasibility in 1x1 SDP-block without any nonzero coefficients but with strictly positive rhs\n");
1048  *result = SCIP_CUTOFF;
1049 
1050  /* delete old 1x1 sdpcone */
1051  SCIP_CALL( SCIPdelCons(scip, conss[i]) );
1052  (*ndelconss)++;
1053 
1054  SCIPfreeBufferArray(scip, &coeffs);
1055  SCIPfreeBufferArray(scip, &vars);
1056 
1057  return SCIP_OKAY; /* the node is infeasible, we don't care for the other constraints */
1058  }
1059  }
1060  }
1061 
1062  /* delete old 1x1 sdpcone */
1063  SCIP_CALL( SCIPdelCons(scip, conss[i]) );
1064  (*ndelconss)++;
1065 
1066  SCIPfreeBufferArray(scip, &coeffs);
1067  SCIPfreeBufferArray(scip, &vars);
1068  }
1069  }
1070  return SCIP_OKAY;
1071 }
1072 
1074 static
1075 SCIP_RETCODE multiaggrVar(
1076  SCIP* scip,
1077  SCIP_CONS* cons,
1078  int* v,
1079  SCIP_VAR** aggrvars,
1080  SCIP_Real* scalars,
1081  int naggrvars,
1082  SCIP_Real constant,
1083  int* savedcol,
1084  int* savedrow,
1085  SCIP_Real* savedval,
1086  int* nfixednonz,
1087  int* vararraylength
1088  )
1089 {
1090  int i;
1091  SCIP_CONSDATA* consdata;
1092  int startind;
1093  int aggrind;
1094  int aggrtargetlength;
1095  int globalnvars;
1096  int aggrconsind;
1097  SCIP_Real epsilon;
1098 
1099  assert( scip != NULL );
1100  assert( cons != NULL );
1101  assert( scalars != NULL );
1102  assert( naggrvars > 0 );
1103  assert( savedcol != NULL );
1104  assert( savedrow != NULL );
1105  assert( savedval != NULL );
1106  assert( nfixednonz != NULL );
1107 
1108  consdata = SCIPconsGetData(cons);
1109  assert( consdata != NULL );
1110 
1111  SCIP_CALL( SCIPgetRealParam(scip, "numerics/epsilon", &epsilon) );
1112 
1113  /* save the current nfixednonz-index, all entries starting from here will need to be added to the variables this is aggregated to */
1114  startind = *nfixednonz;
1115 
1116  if ( SCIPisEQ(scip, constant, 0.0) )
1117  {
1118  /* if there is no constant part, we just save the nonzeros to add them to the variables they are aggregated to, we do this to be able to remove
1119  * the nonzero-arrays for this variable to be able to fill it with a newly inserted variable, as copying all variables, if we created an empty
1120  * gap in the variable arrays, will be more time consuming then copying all variables (as we will usually have more variables than nonzeros per
1121  * variable */
1122  for (i = 0; i < consdata->nvarnonz[*v]; i++)
1123  {
1124  savedcol[*nfixednonz] = consdata->col[*v][i];
1125  savedrow[*nfixednonz] = consdata->row[*v][i];
1126  savedval[*nfixednonz] = consdata->val[*v][i];
1127  (*nfixednonz)++;
1128  }
1129  }
1130  else
1131  {
1132  for (i = 0; i < consdata->nvarnonz[*v]; i++)
1133  {
1134  savedcol[*nfixednonz] = consdata->col[*v][i];
1135  savedrow[*nfixednonz] = consdata->row[*v][i];
1136  savedval[*nfixednonz] = consdata->val[*v][i] * constant;
1137  (*nfixednonz)++;
1138  }
1139  }
1140  assert( *nfixednonz - startind == consdata->nvarnonz[*v] );
1141 
1142  /* sort them by nondecreasing row and then col to make the search for already existing entries easier (this is done here, because it
1143  * only needs to be done once and not for each variable this is multiaggregated to), we add startind to the pointers to only start where we started
1144  * inserting, the number of elements added to the saved arrays for this variable is nfixednonz - startind */
1145  SCIPsdpVarfixerSortRowCol(savedrow + startind, savedcol + startind, savedval + startind, *nfixednonz - startind);
1146 
1147  /* free the memory for the entries of the aggregated variable */
1148  SCIPfreeBlockMemoryArray(scip, &(consdata->val[*v]), consdata->nvarnonz[*v]);
1149  SCIPfreeBlockMemoryArray(scip, &(consdata->row[*v]), consdata->nvarnonz[*v]);
1150  SCIPfreeBlockMemoryArray(scip, &(consdata->col[*v]), consdata->nvarnonz[*v]);
1151 
1152  /* fill the empty spot of the (multi-)aggregated variable with the last variable of this constraint (as they don't have to be sorted) */
1153  SCIP_CALL( SCIPreleaseVar(scip, &consdata->vars[*v]) );
1154  consdata->col[*v] = consdata->col[consdata->nvars - 1];
1155  consdata->row[*v] = consdata->row[consdata->nvars - 1];
1156  consdata->val[*v] = consdata->val[consdata->nvars - 1];
1157  consdata->nvarnonz[*v] = consdata->nvarnonz[consdata->nvars - 1];
1158  consdata->vars[*v] = consdata->vars[consdata->nvars - 1];
1159  (consdata->nvars)--;
1160  (*v)--; /* we need to check again if the variable we just shifted to this position also needs to be (multi-)aggregated */
1161 
1162  /* iterate over all variables this was aggregated to and insert the corresponding nonzeros */
1163  for (aggrind = 0; aggrind < naggrvars; aggrind++)
1164  {
1165  /* check if the variable already exists in this block */
1166  aggrconsind = -1;
1167  for (i = 0; i < consdata->nvars; i++)
1168  {
1169  if ( consdata->vars[i] == aggrvars[aggrind] )
1170  {
1171  aggrconsind = i;
1172  break;
1173  }
1174  }
1175 
1176  if ( aggrconsind > -1 )
1177  {
1178  /* if the varialbe to aggregate to is already part of this sdp-constraint, just add the nonzeros of the old variable to it */
1179 
1180  /* resize the arrays to the maximally needed length */
1181  aggrtargetlength = consdata->nvarnonz[aggrconsind] + *nfixednonz - startind;
1182  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(consdata->row[aggrconsind]), consdata->nvarnonz[aggrconsind], aggrtargetlength) );
1183  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(consdata->col[aggrconsind]), consdata->nvarnonz[aggrconsind], aggrtargetlength) );
1184  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(consdata->val[aggrconsind]), consdata->nvarnonz[aggrconsind], aggrtargetlength) );
1185 
1186  if ( SCIPisEQ(scip, constant, 0.0) )
1187  {
1188  /* in this case we saved the original values in savedval, we add startind to the pointers to only add those from
1189  * the current variable, the number of entries is the current position minus the position whre we started */
1190  SCIP_CALL( SCIPsdpVarfixerMergeArrays(SCIPblkmem(scip), epsilon, savedrow + startind, savedcol + startind, savedval + startind,
1191  *nfixednonz - startind, TRUE, scalars[aggrind], consdata->row[aggrconsind], consdata->col[aggrconsind],
1192  consdata->val[aggrconsind], &(consdata->nvarnonz[aggrconsind]), aggrtargetlength) );
1193  }
1194  else
1195  {
1196  /* in this case we saved the original values * constant, so we now have to divide by constant, we add startind to the pointers
1197  * to only add those from the current variable, the number of entries is the current position minus the position whre we started */
1198  SCIP_CALL( SCIPsdpVarfixerMergeArrays(SCIPblkmem(scip), epsilon, savedrow + startind, savedcol + startind, savedval + startind,
1199  *nfixednonz - startind, TRUE, scalars[aggrind] / constant, consdata->row[aggrconsind], consdata->col[aggrconsind],
1200  consdata->val[aggrconsind], &(consdata->nvarnonz[aggrconsind]), aggrtargetlength) );
1201  }
1202 
1203  /* shrink them again if nonzeros could be combined */
1204  assert( consdata->nvarnonz[aggrconsind] <= aggrtargetlength );
1205  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(consdata->row[aggrconsind]), aggrtargetlength, consdata->nvarnonz[aggrconsind]) );
1206  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(consdata->col[aggrconsind]), aggrtargetlength, consdata->nvarnonz[aggrconsind]) );
1207  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(consdata->val[aggrconsind]), aggrtargetlength, consdata->nvarnonz[aggrconsind]) );
1208  }
1209  else
1210  {
1211  /* the variable has to be added to this constraint */
1212 
1213  SCIPdebugMessage("adding variable %s to SDP constraint %s because of (multi-)aggregation\n", SCIPvarGetName(aggrvars[aggrind]), SCIPconsGetName(cons));
1214 
1215  /* check if we have to enlarge the arrays */
1216  if ( consdata->nvars == *vararraylength )
1217  {
1218  globalnvars = SCIPgetNVars(scip);
1219 
1220  /* we don't want to enlarge this by one for every variable added, so we immediately set it to the maximum possible size */
1221  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->col, *vararraylength, globalnvars) );
1222  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->row, *vararraylength, globalnvars) );
1223  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->val, *vararraylength, globalnvars) );
1224  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->nvarnonz, *vararraylength, globalnvars) );
1225  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, *vararraylength, globalnvars) );
1226  *vararraylength = globalnvars;
1227  }
1228 
1229  /* we insert this variable at the last position, as the ordering doesn't matter */
1230  SCIP_CALL( SCIPcaptureVar(scip, aggrvars[aggrind]) );
1231  consdata->vars[consdata->nvars] = aggrvars[aggrind];
1232 
1233  /* as there were no nonzeros thus far, we can just duplicate the saved arrays to get the nonzeros for the new variable */
1234  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(consdata->col[consdata->nvars]), savedcol + startind, *nfixednonz - startind) ); /*lint !e776*/
1235  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(consdata->row[consdata->nvars]), savedrow + startind, *nfixednonz - startind) ); /*lint !e776*/
1236 
1237  /* if scalars[aggrind] = constant, we would multiply with 1, if constant = 0, we didn't divide by constant, so in these cases, we can just
1238  * memcopy the array of nonzero-values */
1239  /* TODO: only checking scalar and constant for feas-equality might lead to big differences, if the nonzeros they are multiplied with are big,
1240  * e.g. scalar = 0, constant = 10^(-6), nonzero = 10^(10) leads to new nonzero of 10^4 instead of 0 */
1241  if ( SCIPisEQ(scip, scalars[aggrind], constant) || SCIPisEQ(scip, constant, 0.0) )
1242  {
1243  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(consdata->val[consdata->nvars]), savedval + startind, *nfixednonz - startind) ); /*lint !e776*/
1244  consdata->nvarnonz[consdata->nvars] = *nfixednonz - startind; /* as there were no nonzeros thus far, the number of nonzeros equals
1245  * the number of nonzeros of the aggregated variable */
1246  }
1247  else /* we have to multiply all entries by scalar before inserting them */
1248  {
1249  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(consdata->val[consdata->nvars]), *nfixednonz - startind) );
1250 
1251  consdata->nvarnonz[consdata->nvars] = 0;
1252 
1253  for (i = 0; i < *nfixednonz - startind; i++)
1254  {
1255  /* if both scalar and savedval are small this might become too small */
1256  if ( (scalars[i] / constant) * savedval[startind + i] >= epsilon ) /*lint !e679*/
1257  {
1258  consdata->val[consdata->nvars][consdata->nvarnonz[consdata->nvars]] = (scalars[i] / constant) * savedval[startind + i]; /*lint !e679*/
1259  consdata->nvarnonz[consdata->nvars]++;
1260  }
1261  }
1262  }
1263 
1264  if ( consdata->nvarnonz[consdata->nvars] > 0 ) /* if scalar and all savedvals were to small */
1265  consdata->nvars++;
1266  }
1267  }
1268 
1269  /* if the constant part is zero, we may delete the nonzero-entries from the saved arrays (by resetting the nfixednonz entry to where
1270  * it started, so that these entries will be overwritten */
1271  if ( SCIPisEQ(scip, constant, 0.0) )
1272  *nfixednonz = startind;
1273 
1274  return SCIP_OKAY;
1275 }
1276 
1277 
1279 static
1280 SCIP_RETCODE fixAndAggrVars(
1281  SCIP* scip,
1282  SCIP_CONS** conss,
1283  int nconss,
1284  SCIP_Bool aggregate
1285  )
1286 {
1287  SCIP_CONSDATA* consdata;
1288  int i;
1289  int nfixednonz;
1290  int* savedcol;
1291  int* savedrow;
1292  SCIP_Real* savedval;
1293  int c;
1294  int v;
1295  int arraylength;
1296  SCIP_VAR* var;
1297  SCIP_VAR** aggrvars;
1298  SCIP_Real scalar;
1299  SCIP_Real* scalars;
1300  int naggrvars;
1301  SCIP_Real constant;
1302  int requiredsize;
1303  int globalnvars;
1304  int vararraylength;
1305  SCIP_Bool negated;
1306  SCIP_Real epsilon;
1307 
1308 
1309  /* loop over all variables once, add all fixed to savedrow/col/val, for all multiaggregated variables, if constant-scalar =!= 0, add
1310  * constant-scalar * entry to savedrow/col/val and call mergeArrays for all aggrvars for savedrow[startindex of this var] and scalar/constant-scalar,
1311  * if constant-scalar = 0, add 1*entry to savedrow/col/val, call mergeArrays for all aggrvars for savedrow[startindex of this var] and scalar and later
1312  * reduze the saved size of savedrow/col/val by the number of nonzeros of the mutliagrregated variable to not add them to the constant part later */
1313 
1314  assert( scip != NULL );
1315  assert( conss != NULL );
1316  assert( nconss >= 0 );
1317 
1318  SCIPdebugMessage("Calling fixAndAggrVars with aggregate = %u\n", aggregate);
1319 
1320  SCIP_CALL( SCIPgetRealParam(scip, "numerics/epsilon", &epsilon) );
1321 
1322  for (c = 0; c < nconss; ++c)
1323  {
1324  assert( conss[c] != NULL );
1325  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(conss[c])), "SDP") == 0);
1326 
1327  consdata = SCIPconsGetData(conss[c]);
1328  assert( consdata != NULL );
1329 
1330  /* allocate memory to save nonzeros that need to be fixed */
1331  SCIP_CALL( SCIPallocBufferArray(scip, &savedcol, consdata->nnonz) );
1332  SCIP_CALL( SCIPallocBufferArray(scip, &savedrow, consdata->nnonz) );
1333  SCIP_CALL( SCIPallocBufferArray(scip, &savedval, consdata->nnonz) );
1334 
1335  /* initialize this with zero for each block */
1336  nfixednonz = 0;
1337 
1338  vararraylength = consdata->nvars;
1339  globalnvars = SCIPgetNVars(scip);
1340 
1341  for (v = 0; v < consdata->nvars; v++)/*lint --e{850}*/
1342  {
1343  negated = FALSE;
1344  /* if the variable is negated, get the negation var */
1345  if ( SCIPvarIsBinary(consdata->vars[v]) && SCIPvarIsNegated(consdata->vars[v]) )
1346  {
1347  negated = TRUE;
1348  var = SCIPvarGetNegationVar(consdata->vars[v]);
1349  }
1350  else
1351  var = consdata->vars[v];
1352 
1353  /* check if the variable is fixed in SCIP */
1354  if ( SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED || SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)))
1355  {
1356  assert( SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)) );
1357 
1358  SCIPdebugMessage("Globally fixing Variable %s to value %f !\n", SCIPvarGetName(var), SCIPvarGetLbGlobal(var));
1359 
1360  if ( ((! negated) && (! SCIPisEQ(scip, SCIPvarGetLbGlobal(var), 0.0))) || (negated && SCIPisEQ(scip, SCIPvarGetLbGlobal(var), 0.0)) )
1361  {
1362  /* the nonzeros are saved to later be inserted into the constant part (this is only done after all nonzeros of fixed variables have been
1363  * 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
1364  * variable) */
1365  for (i = 0; i < consdata->nvarnonz[v]; i++)
1366  {
1367  savedcol[nfixednonz] = consdata->col[v][i];
1368  savedrow[nfixednonz] = consdata->row[v][i];
1369  /* 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 */
1370  if ( ! negated )
1371  savedval[nfixednonz] = consdata->val[v][i] * SCIPvarGetLbGlobal(var);
1372  else
1373  savedval[nfixednonz] = consdata->val[v][i]; /* if it is the negation of a variable fixed to zero, this variable is fixed to one */
1374 
1375  nfixednonz++;
1376  consdata->nnonz--;
1377  }
1378  }
1379  else
1380  {
1381  /* if the variable is fixed to zero, the nonzeros will just vanish, so we only reduce the number of nonzeros */
1382  consdata->nnonz -= consdata->nvarnonz[v];
1383  }
1384  /* free the memory of the corresponding entries in col/row/val */
1385  SCIPfreeBlockMemoryArrayNull(scip, &(consdata->val[v]), consdata->nvarnonz[v]);
1386  SCIPfreeBlockMemoryArrayNull(scip, &(consdata->row[v]), consdata->nvarnonz[v]);
1387  SCIPfreeBlockMemoryArrayNull(scip, &(consdata->col[v]), consdata->nvarnonz[v]);
1388 
1389  /* 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) */
1390  SCIP_CALL( SCIPreleaseVar(scip, &(consdata->vars[v])) );
1391  consdata->col[v] = consdata->col[consdata->nvars - 1];
1392  consdata->row[v] = consdata->row[consdata->nvars - 1];
1393  consdata->val[v] = consdata->val[consdata->nvars - 1];
1394  consdata->nvarnonz[v] = consdata->nvarnonz[consdata->nvars - 1];
1395  consdata->vars[v] = consdata->vars[consdata->nvars - 1];
1396  consdata->nvars--;
1397  v--; /* we need to check again if the variable we just shifted to this position also needs to be fixed */
1398  }
1399  else if ( (SCIPvarGetStatus(var) == SCIP_VARSTATUS_AGGREGATED ||
1400  SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR)
1401  && aggregate )
1402  {
1403  SCIP_CALL( SCIPallocBufferArray(scip, &aggrvars, globalnvars) );
1404  SCIP_CALL( SCIPallocBufferArray(scip, &scalars, globalnvars) );
1405 
1406  /* this is how they should be initialized before calling SCIPgetProbvarLinearSum */
1407  if (! negated)
1408  {
1409  aggrvars[0] = consdata->vars[v];
1410  naggrvars = 1;
1411  constant = 0.0;
1412  scalars[0] = 1.0;
1413  }
1414  else
1415  {
1416  /* if this variable is the negation of var, than we look for a representation of 1-var */
1417  aggrvars[0] = consdata->vars[v];
1418  naggrvars = 1;
1419  constant = 1.0;
1420  scalars[0] = -1.0;
1421  }
1422 
1423  /* get the variables this var was aggregated to */
1424  SCIP_CALL( SCIPgetProbvarLinearSum(scip, aggrvars, scalars, &naggrvars, globalnvars, &constant, &requiredsize, TRUE) );
1425  assert( requiredsize <= globalnvars ); /* requiredsize is the number of empty spots in aggrvars needed, globalnvars is the number
1426  * of spots we provided */
1427 
1428  /* Debugmessages for the (multi-)aggregation */
1429 #ifdef SCIP_DEBUG
1430  if ( SCIPvarGetStatus(consdata->vars[v]) == SCIP_VARSTATUS_AGGREGATED )
1431  SCIPdebugMessage("aggregating variable %s to ", SCIPvarGetName(var));
1432  else
1433  SCIPdebugMessage("multiaggregating variable %s to ", SCIPvarGetName(var));
1434  for (i = 0; i < naggrvars; i++)
1435  SCIPdebugMessage("+ (%f2) * %s ", scalars[i], SCIPvarGetName(aggrvars[i]));
1436  SCIPdebugMessage("+ (%f2) \n", constant);
1437 #endif
1438 
1439  /* 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
1440  * was (multi-)aggregated to */
1441  SCIP_CALL( multiaggrVar(scip, conss[c], &v, aggrvars, scalars, naggrvars, constant, savedcol, savedrow, savedval, &nfixednonz, &vararraylength) );
1442 
1443  SCIPfreeBufferArray(scip, &aggrvars);
1444  SCIPfreeBufferArray(scip, &scalars);
1445  }
1446  else if ( negated && (SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN)
1447  && aggregate)
1448  {
1449  /* if var1 is the negation of var2, then this is equivalent to it being aggregated to -var2 + 1 = 1 - var2 */
1450 
1451  SCIPdebugMessage("Changing variable %s to negation of variable %s !\n", SCIPvarGetName(consdata->vars[v]), SCIPvarGetName(var));
1452 
1453  scalar = -1.0;
1454 
1455  SCIP_CALL( multiaggrVar(scip, conss[c], &v, &var, &scalar, 1, 1.0, savedcol, savedrow, savedval, &nfixednonz, &vararraylength) );
1456  }
1457  }
1458 
1459  /* shrink the variable arrays if they were enlarged too much (or more vars were removed than added) */
1460  assert( consdata->nvars <= vararraylength );
1461  if ( consdata->nvars < vararraylength )
1462  {
1463  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->col, vararraylength, consdata->nvars) );
1464  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->row, vararraylength, consdata->nvars) );
1465  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->val, vararraylength, consdata->nvars) );
1466  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->nvarnonz, vararraylength, consdata->nvars) );
1467  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, vararraylength, consdata->nvars) );
1468  }
1469 
1470  /* allocate the maximally needed memory for inserting the fixed variables into the constant part */
1471  arraylength = consdata->constnnonz + nfixednonz;
1472  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(consdata->constcol), consdata->constnnonz, arraylength) );
1473  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(consdata->constrow), consdata->constnnonz, arraylength) );
1474  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(consdata->constval), consdata->constnnonz, arraylength) );
1475 
1476  /* insert the fixed variables into the constant arrays, as we have +A_i but -A_0 we mutliply them by -1 */
1477  SCIP_CALL( SCIPsdpVarfixerMergeArrays(SCIPblkmem(scip), epsilon, savedrow, savedcol, savedval, nfixednonz, FALSE, -1.0, consdata->constrow,
1478  consdata->constcol, consdata->constval, &(consdata->constnnonz), arraylength) );
1479 
1480  assert( consdata->constnnonz <= arraylength ); /* the allocated memory should always be sufficient */
1481 
1482  /* shrink the arrays if nonzeros could be combined */
1483  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(consdata->constcol), arraylength, consdata->constnnonz) );
1484  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(consdata->constrow), arraylength, consdata->constnnonz) );
1485  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(consdata->constval), arraylength, consdata->constnnonz) );
1486 
1487  /* free the saved arrays */
1488  SCIPfreeBufferArray(scip, &savedval);
1489  SCIPfreeBufferArray(scip, &savedrow);
1490  SCIPfreeBufferArray(scip, &savedcol);
1491 
1492  /* recompute sdpnnonz */
1493  consdata->nnonz = 0;
1494  for (v = 0; v < consdata->nvars; v++)
1495  consdata->nnonz += consdata->nvarnonz[v];
1496  }
1497 
1498  return SCIP_OKAY;
1499 }
1500 
1502 static
1503 SCIP_RETCODE EnforceConstraint(
1504  SCIP* scip,
1505  SCIP_CONSHDLR* conshdlr,
1506  SCIP_CONS** conss,
1507  int nconss,
1508  SCIP_SOL* sol,
1509  SCIP_RESULT* result
1510  )
1511 {
1512  char cutname[SCIP_MAXSTRLEN];
1513  SCIP_CONSDATA* consdata;
1514  SCIP_CONSHDLRDATA* conshdlrdata;
1515  SCIP_Bool all_feasible = TRUE;
1516  SCIP_Bool separated = FALSE;
1517  SCIP_ROW* row;
1518  SCIP_Bool infeasible;
1519  SCIP_Real lhs;
1520  SCIP_Real* coeff;
1521  SCIP_Real rhs;
1522  int nvars;
1523  int i;
1524  int j;
1525 #ifndef NDEBUG
1526  int snprintfreturn; /* used to check the return code of snprintf */
1527 #endif
1528 
1529  *result = SCIP_FEASIBLE;
1530 
1531  for (i = 0; i < nconss; ++i)
1532  {
1533  consdata = SCIPconsGetData(conss[i]);
1534  SCIP_CALL( SCIPconsSdpCheckSdpCons(scip, conss[i], sol, 0, 0, 0, result) );
1535  if ( *result == SCIP_FEASIBLE )
1536  continue;
1537 
1538  all_feasible = FALSE;
1539 
1540  nvars = consdata->nvars;
1541  lhs = 0.0;
1542  coeff = NULL;
1543 
1544  SCIP_CALL( SCIPallocBufferArray(scip, &coeff, nvars) );
1545  SCIP_CALL( cutUsingEigenvector(scip, conss[i], sol, coeff, &lhs) );
1546 
1547  rhs = SCIPinfinity(scip);
1548  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1549 
1550 #ifndef NDEBUG
1551  snprintfreturn = SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "sepa_eig_sdp_%d", ++(conshdlrdata->neigveccuts));
1552  assert( snprintfreturn < SCIP_MAXSTRLEN ); /* check whether the name fits into the string */
1553 #else
1554  (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "sepa_eig_sdp_%d", ++(conshdlrdata->neigveccuts));
1555 #endif
1556 
1557  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, conshdlr, cutname , lhs, rhs, FALSE, FALSE, TRUE) );
1558  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
1559 
1560  for (j = 0; j < nvars; ++j)
1561  {
1562  SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->vars[j], coeff[j]) );
1563  }
1564 
1565  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
1566 
1567 #ifdef SCIP_MORE_DEBUG
1568  SCIPinfoMessage(scip, NULL, "Added cut %s: ", cutname);
1569  SCIPinfoMessage(scip, NULL, "%f <= ", lhs);
1570  for (j = 0; j < nvars; j++)
1571  SCIPinfoMessage(scip, NULL, "+ (%f)*%s", coeff[j], SCIPvarGetName(consdata->vars[j]));
1572  SCIPinfoMessage(scip, NULL, "\n");
1573 #endif
1574 
1575  SCIP_CALL( SCIPaddCut(scip, sol, row, FALSE, &infeasible) );
1576 
1577  if ( infeasible )
1578  {
1579  *result = SCIP_CUTOFF;
1580 
1581  SCIP_CALL( SCIPreleaseRow(scip, &row) );
1582  SCIPfreeBufferArray(scip, &coeff);
1583 
1584  return SCIP_OKAY;
1585  }
1586  else
1587  {
1588  SCIP_CALL( SCIPaddPoolCut(scip, row) );
1589 
1590  SCIP_CALL( SCIPresetConsAge(scip, conss[i]) );
1591  *result = SCIP_SEPARATED;
1592  separated = TRUE;
1593  }
1594  SCIP_CALL( SCIPreleaseRow(scip, &row) );
1595  SCIPfreeBufferArray(scip, &coeff);
1596  }
1597 
1598  if ( all_feasible )
1599  return SCIP_OKAY;
1600 
1601  if ( separated )
1602  *result = SCIP_SEPARATED;
1603 
1604  return SCIP_OKAY;
1605 }
1606 
1608 static
1609 SCIP_DECL_CONSINITPRE(consInitpreSdp)
1610 {/*lint --e{715}*/
1611  SCIP_CONSHDLRDATA* conshdlrdata;
1612 
1613  assert( conshdlr != NULL );
1614 
1615  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1616  assert( conshdlrdata != NULL );
1617 
1618  conshdlrdata->neigveccuts = 0; /* this is used to give the eigenvector-cuts distinguishable names */
1619  conshdlrdata->ndiaggezerocuts = 0; /* this is used to give the diagGEzero-cuts distinguishable names */
1620  conshdlrdata->n1x1blocks = 0; /* this is used to give the lp constraints resulting from 1x1 sdp-blocks distinguishable names */
1621 
1622  return SCIP_OKAY;
1623 }
1624 
1626 static
1627 SCIP_DECL_CONSLOCK(consLockSdp)
1628 {/*lint --e{715}*/
1629  SCIP_Real* Aj;
1630  SCIP_CONSDATA* consdata;
1631  int blocksize;
1632  int var;
1633  int nvars;
1634  SCIP_Real eigenvalue;
1635 
1636  consdata = SCIPconsGetData(cons);
1637  assert( consdata != NULL );
1638  blocksize = consdata->blocksize;
1639  nvars = consdata->nvars;
1640 
1641  SCIP_CALL( SCIPallocBufferArray(scip, &Aj, blocksize * blocksize) ); /*lint !e647*/
1642 
1643  for (var = 0; var < nvars; var++)
1644  {
1645  SCIP_CALL( SCIPconsSdpGetFullAj(scip, cons, var, Aj) );
1646 
1647  /* compute the smallest eigenvalue */
1648  SCIP_CALL( SCIPlapackComputeIthEigenvalue(SCIPbuffer(scip), FALSE, blocksize, Aj, 1, &eigenvalue, NULL) );
1649  if ( SCIPisNegative(scip, eigenvalue) )
1650  {
1651  /* as the lowest eigenvalue is negative, the matrix is not positive semidefinite, so adding more of it can remove positive
1652  * semidefiniteness of the SDP-matrix */
1653  SCIP_CALL( SCIPaddVarLocks(scip, consdata->vars[var], nlocksneg, nlockspos) );
1654  }
1655 
1656  /* if the smallest eigenvalue is already positive, we don't need to compute the biggest one */
1657  if ( SCIPisPositive(scip, eigenvalue) )
1658  {
1659  /* as an eigenvalue is positive, the matrix is not negative semidefinite, so substracting more of it can remove positive
1660  * semidefiniteness of the SDP-matrix */
1661  SCIP_CALL( SCIPaddVarLocks(scip, consdata->vars[var], nlockspos, nlocksneg) );
1662  }
1663  else
1664  {
1665  /* compute the biggest eigenvalue */
1666  SCIP_CALL( SCIPlapackComputeIthEigenvalue(SCIPbuffer(scip), FALSE, blocksize, Aj, blocksize, &eigenvalue, NULL) );
1667  if ( SCIPisPositive(scip, eigenvalue) )
1668  {
1669  /* as the biggest eigenvalue is positive, the matrix is not negative semidefinite, so substracting more of it can remove positive
1670  * semidefiniteness of the SDP-matrix */
1671  SCIP_CALL( SCIPaddVarLocks(scip, consdata->vars[var], nlockspos, nlocksneg) );
1672  }
1673  }
1674  }
1675 
1676  SCIPfreeBufferArray(scip, &Aj);
1677 
1678  return SCIP_OKAY;
1679 }
1680 
1682 static
1683 SCIP_DECL_CONSEXITPRE(consExitpreSdp)
1684 {/*lint --e{715}*/
1685  assert( scip != NULL );
1686 
1687  if ( conss == NULL )
1688  return SCIP_OKAY;
1689 
1690  SCIP_CALL( fixAndAggrVars(scip, conss, nconss, TRUE) );
1691 
1692  return SCIP_OKAY;
1693 }
1694 
1696 static
1697 SCIP_DECL_CONSPRESOL(consPresolSdp)
1698 {/*lint --e{715}*/
1699  SCIP_CONSHDLRDATA* conshdlrdata;
1700 
1701  assert( conshdlr != NULL );
1702  assert( result != 0 );
1703 
1704  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1705  assert( conshdlrdata != NULL );
1706 
1707  if ( nrounds == 0 )
1708  {
1709  SCIP_CALL( move_1x1_blocks_to_lp(scip, conss, nconss, naddconss, ndelconss, result) );
1710  if ( conshdlrdata->diaggezerocuts )
1711  {
1712  SCIP_CALL( diagGEzero(scip, conss, nconss, naddconss) );
1713  }
1714  if ( conshdlrdata->diagzeroimplcuts )
1715  {
1716  SCIP_CALL( diagZeroImpl(scip, conss, nconss, naddconss) );
1717  }
1718  }
1719 
1720  return SCIP_OKAY;
1721 }
1722 
1724 static
1725 SCIP_DECL_CONSTRANS(consTransSdp)
1726 {/*lint --e{715}*/
1727  SCIP_CONSDATA* sourcedata;
1728  SCIP_CONSDATA* targetdata;
1729 #ifdef OMP
1730  SCIP_CONSHDLRDATA* conshdlrdata;
1731 #endif
1732 #ifndef NDEBUG
1733  int snprintfreturn; /* used to check the return code of snprintf */
1734 #endif
1735  int i;
1736  char transname[SCIP_MAXSTRLEN];
1737 
1738  sourcedata = SCIPconsGetData(sourcecons);
1739  assert( sourcedata != NULL );
1740 
1741  SCIPdebugMessage("Transforming constraint <%s>\n", SCIPconsGetName(sourcecons));
1742 
1743 #ifdef OMP
1744  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1745  SCIPdebugMessage("Setting number of threads to %d via OpenMP in Openblas.\n", conshdlrdata->nthreads);
1746  omp_set_num_threads(conshdlrdata->nthreads);
1747 #endif
1748 
1749  SCIP_CALL( SCIPallocBlockMemory(scip, &targetdata) );
1750 
1751  /* copy some general data */
1752  targetdata->nvars = sourcedata->nvars;
1753  targetdata->nnonz = sourcedata->nnonz;
1754  targetdata->blocksize = sourcedata->blocksize;
1755 
1756  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(targetdata->nvarnonz), sourcedata->nvarnonz, sourcedata->nvars) );
1757 
1758  /* copy the non-constant nonzeros */
1759  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(targetdata->col), sourcedata->nvars) );
1760  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(targetdata->row), sourcedata->nvars) );
1761  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(targetdata->val), sourcedata->nvars) );
1762 
1763  for (i = 0; i < sourcedata->nvars; i++)
1764  {
1765  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(targetdata->col[i]), sourcedata->col[i], sourcedata->nvarnonz[i]) );
1766  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(targetdata->row[i]), sourcedata->row[i], sourcedata->nvarnonz[i]) );
1767  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(targetdata->val[i]), sourcedata->val[i], sourcedata->nvarnonz[i]) );
1768  }
1769  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(targetdata->vars), sourcedata->nvars));
1770 
1771  /* copy & transform the vars array */
1772  for (i = 0; i < sourcedata->nvars; i++)
1773  {
1774  targetdata->vars[i] = SCIPvarGetTransVar(sourcedata->vars[i]);
1775  SCIP_CALL( SCIPcaptureVar(scip, targetdata->vars[i]) );
1776  }
1777 
1778  /* copy the constant nonzeros */
1779  targetdata->constnnonz = sourcedata->constnnonz;
1780 
1781  if ( sourcedata->constnnonz > 0 )
1782  {
1783  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(targetdata->constcol), sourcedata->constcol, sourcedata->constnnonz));
1784  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(targetdata->constrow), sourcedata->constrow, sourcedata->constnnonz));
1785  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(targetdata->constval), sourcedata->constval, sourcedata->constnnonz));
1786  }
1787  else
1788  {
1789  targetdata->constcol = NULL;
1790  targetdata->constrow = NULL;
1791  targetdata->constval = NULL;
1792  }
1793 
1794  /* copy the maxrhsentry */
1795  targetdata->maxrhsentry = sourcedata->maxrhsentry;
1796 
1797  /* name the transformed constraint */
1798 #ifndef NDEBUG
1799  snprintfreturn = SCIPsnprintf(transname, SCIP_MAXSTRLEN, "t_%s", SCIPconsGetName(sourcecons));
1800  assert( snprintfreturn < SCIP_MAXSTRLEN ); /* check whether the name fits into the string */
1801 #else
1802  (void) SCIPsnprintf(transname, SCIP_MAXSTRLEN, "t_%s", SCIPconsGetName(sourcecons));
1803 #endif
1804 
1805  /* create target constraint */
1806  SCIP_CALL( SCIPcreateCons(scip, targetcons, transname, conshdlr, targetdata,
1807  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
1808  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons),
1809  SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons),
1810  SCIPconsIsStickingAtNode(sourcecons)) );
1811 
1812  return SCIP_OKAY;
1813 }
1814 
1816 static
1817 SCIP_DECL_CONSCHECK(consCheckSdp)
1818 {/*lint --e{715}*/
1819  int i;
1820 
1821  assert( scip != NULL );
1822  assert( result != NULL );
1823 
1824  *result = SCIP_FEASIBLE;
1825 
1826  for (i = 0; i < nconss; ++i)
1827  {
1828  SCIP_CALL( SCIPconsSdpCheckSdpCons(scip, conss[i], sol, checkintegrality, checklprows, printreason, result) );
1829  if ( *result == SCIP_INFEASIBLE )
1830  return SCIP_OKAY;
1831  }
1832 
1833  return SCIP_OKAY;
1834 }
1835 
1840 static
1841 SCIP_DECL_CONSENFOPS(consEnfopsSdp)
1842 {/*lint --e{715}*/
1843  int i;
1844 
1845  assert( scip != NULL );
1846  assert( result != NULL );
1847  assert( conss != NULL );
1848 
1849  *result = SCIP_DIDNOTRUN;
1850 
1851  if ( objinfeasible )
1852  {
1853  SCIPdebugMessage("-> pseudo solution is objective infeasible, return.\n");
1854  return SCIP_OKAY;
1855  }
1856 
1857  for (i = 0; i < nconss; ++i)
1858  {
1859  SCIP_CALL( SCIPconsSdpCheckSdpCons(scip, conss[i], NULL, 0, 0, 0, result) );
1860 
1861  if (*result == SCIP_INFEASIBLE)
1862  {
1863  /* if it is infeasible for one SDP constraint, it is infeasible for the whole problem */
1864  SCIPdebugMessage("-> pseudo solution infeasible for SDP-constraint %s, return.\n", SCIPconsGetName(conss[i]));
1865  return SCIP_OKAY;
1866  }
1867  }
1868 
1869  SCIPdebugMessage("-> pseudo solution feasible for all SDP-constraints.\n");
1870 
1871  return SCIP_OKAY;
1872 }
1873 
1874 
1877 static
1878 SCIP_DECL_CONSENFOLP(consEnfolpSdp)
1879 {/*lint --e{715}*/
1880  assert( scip != NULL );
1881  assert( conshdlr != NULL );
1882  assert( conss != NULL );
1883  assert( result != NULL );
1884 
1885  return EnforceConstraint(scip, conshdlr, conss, nconss, NULL, result);
1886 }
1887 
1890 static
1891 SCIP_DECL_CONSENFORELAX(consEnforelaxSdp)
1892 {/*lint --e{715}*/
1893  assert( scip != NULL );
1894  assert( conshdlr != NULL );
1895  assert( conss != NULL );
1896  assert( result != NULL );
1897 
1898  return EnforceConstraint(scip, conshdlr, conss, nconss, sol, result);
1899 }
1900 
1902 static
1903 SCIP_DECL_CONSSEPASOL(consSepasolSdp)
1904 {/*lint --e{715}*/
1905  int i;
1906 
1907  assert( result != NULL );
1908  *result = SCIP_DIDNOTFIND;
1909 
1910  for (i = 0; i < nusefulconss; ++i)
1911  {
1912  SCIP_CALL( separateSol(scip, conshdlr, conss[i], sol, result) );
1913  }
1914 
1915  return SCIP_OKAY;
1916 }
1917 
1919 static
1920 SCIP_DECL_CONSSEPALP(consSepalpSdp)
1921 {/*lint --e{715}*/
1922  int i;
1923 
1924  assert( result != NULL );
1925  *result = SCIP_DIDNOTFIND;
1926 
1927  for (i = 0; i < nusefulconss; ++i)
1928  {
1929  SCIP_CALL( separateSol(scip, conshdlr, conss[i], NULL, result) );
1930  }
1931 
1932  return SCIP_OKAY;
1933 }
1934 
1936 static
1937 SCIP_DECL_CONSDELETE(consDeleteSdp)
1938 {/*lint --e{715}*/
1939  int i;
1940 
1941  assert( cons != NULL );
1942  assert( consdata != NULL );
1943 
1944  SCIPdebugMessage("deleting SDP constraint <%s>.\n", SCIPconsGetName(cons));
1945 
1946  for (i = 0; i < (*consdata)->nvars; i++)
1947  {
1948  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->val[i], (*consdata)->nvarnonz[i]);
1949  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->row[i], (*consdata)->nvarnonz[i]);
1950  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->col[i], (*consdata)->nvarnonz[i]);
1951  }
1952 
1953  /* release all variables */
1954  for (i = 0; i < (*consdata)->nvars; i++)
1955  {
1956  SCIP_CALL( SCIPreleaseVar(scip, &((*consdata)->vars[i])) );
1957  }
1958 
1959  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->vars, (*consdata)->nvars);
1960  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->constval, (*consdata)->constnnonz);
1961  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->constrow, (*consdata)->constnnonz);
1962  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->constcol, (*consdata)->constnnonz);
1963  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->val, (*consdata)->nvars);
1964  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->row, (*consdata)->nvars);
1965  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->col, (*consdata)->nvars);
1966  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->nvarnonz, (*consdata)->nvars);
1967  SCIPfreeBlockMemory(scip, consdata);
1968 
1969  return SCIP_OKAY;
1970 }
1971 
1973 static
1974 SCIP_DECL_CONSFREE(consFreeSdp)
1975 {/*lint --e{715}*/
1976  SCIP_CONSHDLRDATA* conshdlrdata;
1977 
1978  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1979  assert( conshdlrdata != NULL );
1980 
1981  SCIPfreeMemory(scip, &conshdlrdata);
1982  SCIPconshdlrSetData(conshdlr, NULL);
1983 
1984  return SCIP_OKAY;
1985 }
1986 
1988 static
1989 SCIP_DECL_CONSHDLRCOPY(conshdlrCopySdp)
1991  assert(scip != NULL);
1992  assert(conshdlr != NULL);
1993  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
1994 
1995  SCIP_CALL( SCIPincludeConshdlrSdp(scip) );
1996 
1997  *valid = TRUE;
1998 
1999  return SCIP_OKAY;
2000 }
2001 
2003 static
2004 SCIP_DECL_CONSCOPY(consCopySdp)
2005 {/*lint --e{715}*/
2006  SCIP_CONSDATA* sourcedata;
2007  SCIP_Bool success;
2008  SCIP_VAR** targetvars;
2009  SCIP_VAR* var;
2010  int i;
2011 
2012  assert( scip != NULL );
2013  assert( sourcescip != NULL );
2014  assert( sourcecons != NULL );
2015  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(sourcecons)), CONSHDLR_NAME) == 0 );
2016  assert( valid != NULL );
2017 
2018  SCIPdebugMessage("Copying SDP constraint <%s>\n", SCIPconsGetName(sourcecons));
2019 
2020  *valid = TRUE;
2021 
2022  /* as we can only map active variables, we have to make sure, that the constraint contains no fixed or (multi-)aggregated vars, after
2023  * exitpresolve (stage 6) this should always be the case, earlier than that we need to call fixAndAggrVars */
2024  if ( SCIPgetStage(sourcescip) <= SCIP_STAGE_EXITPRESOLVE )
2025  {
2026  SCIP_CALL( fixAndAggrVars(sourcescip, &sourcecons, 1, TRUE) );
2027  }
2028 
2029  sourcedata = SCIPconsGetData(sourcecons);
2030  assert( sourcedata != NULL );
2031 
2032  SCIP_CALL( SCIPallocBufferArray(scip, &targetvars, sourcedata->nvars) );
2033 
2034  /* map all variables in the constraint */
2035  for (i = 0; i < sourcedata->nvars; i++)
2036  {
2037  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcedata->vars[i], &var, varmap, consmap, global, &success) );
2038  if ( success )
2039  targetvars[i] = var;
2040  else
2041  *valid = FALSE;
2042  }
2043 
2044  /* create the new constraint, using an adjusted source name if no new name was given */
2045  if ( name )
2046  {
2047 #ifndef NDEBUG
2048  int snprintfreturn; /* used to check the return code of snprintf */
2049 #endif
2050  char copyname[SCIP_MAXSTRLEN];
2051 
2052  /* name the copied constraint */
2053  #ifndef NDEBUG
2054  snprintfreturn = SCIPsnprintf(copyname, SCIP_MAXSTRLEN, "c_%s", name);
2055  assert( snprintfreturn < SCIP_MAXSTRLEN ); /* check whether the name fits into the string */
2056  #else
2057  (void) SCIPsnprintf(copyname, SCIP_MAXSTRLEN, "c_%s", name);
2058  #endif
2059  SCIP_CALL( SCIPcreateConsSdp( scip, cons, copyname, sourcedata->nvars, sourcedata->nnonz, sourcedata->blocksize, sourcedata->nvarnonz,
2060  sourcedata->col, sourcedata->row, sourcedata->val, targetvars, sourcedata->constnnonz,
2061  sourcedata->constcol, sourcedata->constrow, sourcedata->constval) );
2062  }
2063  else
2064  {
2065 #ifndef NDEBUG
2066  int snprintfreturn; /* used to check the return code of snprintf */
2067 #endif
2068  char copyname[SCIP_MAXSTRLEN];
2069 
2070  /* name the copied constraint */
2071  #ifndef NDEBUG
2072  snprintfreturn = SCIPsnprintf(copyname, SCIP_MAXSTRLEN, "c_%s", SCIPconsGetName(sourcecons));
2073  assert( snprintfreturn < SCIP_MAXSTRLEN ); /* check whether the name fits into the string */
2074  #else
2075  (void) SCIPsnprintf(copyname, SCIP_MAXSTRLEN, "c_%s", SCIPconsGetName(sourcecons));
2076  #endif
2077  SCIP_CALL( SCIPcreateConsSdp( scip, cons, SCIPconsGetName(sourcecons), sourcedata->nvars, sourcedata->nnonz, sourcedata->blocksize,
2078  sourcedata->nvarnonz, sourcedata->col, sourcedata->row, sourcedata->val, targetvars, sourcedata->constnnonz,
2079  sourcedata->constcol, sourcedata->constrow, sourcedata->constval) );
2080  }
2081 
2082  SCIPfreeBufferArray(scip, &targetvars);
2083 
2084  return SCIP_OKAY;
2085 }
2086 
2088 static
2089 SCIP_DECL_CONSPRINT(consPrintSdp)
2090 {/*lint --e{715}*/
2091 #ifdef PRINT_HUMAN_READABLE
2092  SCIP_CONSDATA* consdata;
2093  SCIP_Real* fullmatrix;
2094  int v;
2095  int i;
2096  int j;
2097 
2098  assert( scip != NULL );
2099  assert( cons != NULL );
2100 
2101  consdata = SCIPconsGetData(cons);
2102  assert( consdata != NULL );
2103 
2104  SCIP_CALL( SCIPallocBufferArray(scip, &fullmatrix, consdata->blocksize * consdata->blocksize) );
2105 
2106  /* print the non-constant matrices, for this they first have to be assembled in fullmatrix */
2107  for (v = 0; v < consdata->nvars; v++)
2108  {
2109  /* assemble the matrix */
2110 
2111  /* first initialize it with zero */
2112  for (i = 0; i < consdata->blocksize; i++)
2113  {
2114  for (j = 0; j < consdata->blocksize; j++)
2115  fullmatrix[i * consdata->blocksize + j] = 0.0; /*lint !e679*/
2116  }
2117 
2118  /* then add the nonzeros */
2119  for (i = 0; i < consdata->nvarnonz[v]; i++)
2120  {
2121  fullmatrix[consdata->row[v][i] * consdata->blocksize + consdata->col[v][i]] = consdata->val[v][i]; /* lower triangular entry */ /*lint !e679*/
2122  fullmatrix[consdata->col[v][i] * consdata->blocksize + consdata->row[v][i]] = consdata->val[v][i]; /* upper triangular entry */ /*lint !e679*/
2123  }
2124 
2125  /* print it */
2126  SCIPinfoMessage(scip, file, "+\n");
2127  for (i = 0; i < consdata->blocksize; i++)
2128  {
2129  SCIPinfoMessage(scip, file, "( ");
2130  for (j = 0; j < consdata->blocksize; j++)
2131  SCIPinfoMessage(scip, file, "%f ", fullmatrix[i * consdata->blocksize + j]); /*lint !e679*/
2132  SCIPinfoMessage(scip, file, ")\n");
2133  }
2134  SCIPinfoMessage(scip, file, "* %s\n", SCIPvarGetName(consdata->vars[v]));
2135  }
2136 
2137  /* print the constant-matrix */
2138 
2139  /* assemble the matrix */
2140 
2141  /* first initialize it with zero */
2142  for (i = 0; i < consdata->blocksize; i++)
2143  {
2144  for (j = 0; j < consdata->blocksize; j++)
2145  fullmatrix[i * consdata->blocksize + j] = 0.0; /*lint !e679*/
2146  }
2147 
2148  /* then add the nonzeros */
2149  for (i = 0; i < consdata->constnnonz; i++)
2150  {
2151  fullmatrix[consdata->constrow[i] * consdata->blocksize + consdata->constcol[i]] = consdata->constval[i]; /* lower triangular entry */ /*lint !e679*/
2152  fullmatrix[consdata->constcol[i] * consdata->blocksize + consdata->constrow[i]] = consdata->constval[i]; /* upper triangular entry */ /*lint !e679*/
2153  }
2154 
2155  /* print it */
2156  SCIPinfoMessage(scip, file, "-\n");
2157  for (i = 0; i < consdata->blocksize; i++)
2158  {
2159  SCIPinfoMessage(scip, file, "( ");
2160  for (j = 0; j < consdata->blocksize; j++)
2161  SCIPinfoMessage(scip, file, "%f ", fullmatrix[i * consdata->blocksize + j]); /*lint !e679*/
2162  SCIPinfoMessage(scip, file, ")\n");
2163  }
2164  SCIPinfoMessage(scip, file, ">=0\n");
2165 
2166  SCIPfreeBufferArray(scip, &fullmatrix);
2167 
2168  return SCIP_OKAY;
2169 #else
2170  SCIP_CONSDATA* consdata;
2171  int i;
2172  int v;
2173 
2174  assert( scip != NULL );
2175  assert( cons != NULL );
2176 
2177  consdata = SCIPconsGetData(cons);
2178 
2179  /* print blocksize */
2180  SCIPinfoMessage(scip, file, "%d\n", consdata->blocksize);
2181 
2182  /* print A_0 if it exists */
2183  if ( consdata->constnnonz > 0 )
2184  {
2185  SCIPinfoMessage(scip, file, "A_0: ");
2186 
2187  for (i = 0; i < consdata->constnnonz; i++)
2188  {
2189  SCIPinfoMessage(scip, file, "(%d,%d):%f, ", consdata->constrow[i], consdata->constcol[i], consdata->constval[i]);
2190  }
2191  SCIPinfoMessage(scip, file, "\n");
2192  }
2193 
2194  /* print other matrices */
2195  for (v = 0; v < consdata->nvars; v++)
2196  {
2197  SCIPinfoMessage(scip, file, "<%s>: ", SCIPvarGetName(consdata->vars[v]));
2198  for (i = 0; i < consdata->nvarnonz[v]; i++)
2199  {
2200  SCIPinfoMessage(scip, file, "(%d,%d):%f, ", consdata->row[v][i], consdata->col[v][i], consdata->val[v][i]);
2201  }
2202  /* if this is not the last variable, add a newline */
2203  if (v < consdata->nvars - 1)
2204  {
2205  SCIPinfoMessage(scip, file, "\n");
2206  }
2207  }
2208 
2209  return SCIP_OKAY;
2210 #endif
2211 }
2212 
2214 static
2215 SCIP_DECL_CONSPARSE(consParseSdp)
2216 { /*lint --e{715}*/
2217  SCIP_Bool parsesuccess;
2218  SCIP_CONSDATA* consdata = NULL;
2219  char* pos;
2220  int currentsize;
2221  int nvars;
2222  int i;
2223 
2224  assert( scip != NULL );
2225  assert( str != NULL );
2226 
2227  nvars = SCIPgetNVars(scip);
2228 
2229  assert( success != NULL );
2230  *success = TRUE;
2231 
2232  /* create constraint data */
2233  SCIP_CALL( SCIPallocBlockMemory(scip, &consdata) );
2234  consdata->nvars = 0;
2235  consdata->nnonz = 0;
2236  consdata->constnnonz = 0;
2237  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->nvarnonz, nvars) );
2238  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->col, nvars) );
2239  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->row, nvars) );
2240  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->val, nvars) );
2241  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->vars, nvars));
2242  consdata->constcol = NULL;
2243  consdata->constrow = NULL;
2244  consdata->constval = NULL;
2245 
2246  /* parse the blocksize */
2247  parsesuccess = SCIPstrToIntValue(str, &(consdata->blocksize), &pos);
2248  *success = *success && parsesuccess;
2249 
2250  /* skip whitespace */
2251  while( isspace((unsigned char)*pos) )
2252  pos++;
2253 
2254  /* check if there is a constant part */
2255  if ( pos[0] == 'A' && pos[1] == '_' && pos[2] == '0' )
2256  {
2257  pos += 5; /* we skip "A_0: " */
2258 
2259  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->constcol, PARSE_STARTSIZE) );
2260  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->constrow, PARSE_STARTSIZE) );
2261  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->constval, PARSE_STARTSIZE) );
2262 
2263  currentsize = PARSE_STARTSIZE;
2264 
2265  /* as long as there is another entry for the constant part, parse it */
2266  while (pos[0] == '(')
2267  {
2268  pos++; /* remove the '(' */
2269 
2270  /* check if we need to enlarge the arrays */
2271  if ( consdata->constnnonz == currentsize )
2272  {
2273  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->constcol, currentsize, PARSE_SIZEFACTOR * currentsize) );
2274  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->constrow, currentsize, PARSE_SIZEFACTOR * currentsize) );
2275  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->constval, currentsize, PARSE_SIZEFACTOR * currentsize) );
2276  currentsize *= PARSE_SIZEFACTOR;
2277  }
2278 
2279  parsesuccess = SCIPstrToIntValue(pos, &(consdata->constrow[consdata->constnnonz]), &pos);
2280  *success = *success && parsesuccess;
2281  assert( consdata->constrow[consdata->constnnonz] < consdata->blocksize );
2282  pos++; /* remove the ',' */
2283  parsesuccess = SCIPstrToIntValue(pos, &(consdata->constcol[consdata->constnnonz]), &pos);
2284  *success = *success && parsesuccess;
2285  assert( consdata->constcol[consdata->constnnonz] < consdata->blocksize );
2286  pos += 2; /* remove the "):" */
2287  parsesuccess = SCIPstrToRealValue(pos, &(consdata->constval[consdata->constnnonz]), &pos);
2288  *success = *success && parsesuccess;
2289  pos ++; /* remove the "," */
2290 
2291  /* if we got an entry in the upper triangular part, switch the entries for lower triangular */
2292  if ( consdata->constcol[consdata->constnnonz] > consdata->constrow[consdata->constnnonz] )
2293  {
2294  i = consdata->constcol[consdata->constnnonz];
2295  consdata->constcol[consdata->constnnonz] = consdata->constrow[consdata->constnnonz];
2296  consdata->constrow[consdata->constnnonz] = i;
2297  }
2298 
2299  consdata->constnnonz++;
2300 
2301  /* skip whitespace */
2302  while( isspace((unsigned char)*pos) )
2303  pos++;
2304  }
2305 
2306  /* resize the arrays to their final size */
2307  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->constcol, currentsize, consdata->constnnonz) );
2308  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->constrow, currentsize, consdata->constnnonz) );
2309  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->constval, currentsize, consdata->constnnonz) );
2310  }
2311 
2312  /* skip whitespace */
2313  while( isspace((unsigned char)*pos) )
2314  pos++;
2315 
2316  /* parse the non-constant part */
2317 
2318  /* while there is another variable, parse it */
2319  while (pos[0] == '<')
2320  {
2321  /* add the variable to consdata->vars and create the corresponding nonzero arrays */
2322  SCIP_CALL( SCIPparseVarName(scip, pos, &(consdata->vars[consdata->nvars]), &pos) );
2323  SCIP_CALL( SCIPcaptureVar(scip, consdata->vars[consdata->nvars]) );
2324 
2325  consdata->nvarnonz[consdata->nvars] = 0;
2326  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(consdata->col[consdata->nvars]), PARSE_STARTSIZE));
2327  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(consdata->row[consdata->nvars]), PARSE_STARTSIZE));
2328  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(consdata->val[consdata->nvars]), PARSE_STARTSIZE));
2329  consdata->nvars++;
2330  currentsize = PARSE_STARTSIZE;
2331 
2332  pos += 2; /* remove the ": " */
2333 
2334  /* while there is another entry, parse it */
2335  while (pos[0] == '(')
2336  {
2337  pos++; /* remove the '(' */
2338 
2339  /* check if we need to enlarge the arrays */
2340  if ( consdata->nvarnonz[consdata->nvars - 1] == currentsize )
2341  {
2342  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->col[consdata->nvars - 1], currentsize, PARSE_SIZEFACTOR * currentsize) );
2343  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->row[consdata->nvars - 1], currentsize, PARSE_SIZEFACTOR * currentsize) );
2344  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->val[consdata->nvars - 1], currentsize, PARSE_SIZEFACTOR * currentsize) );
2345  currentsize *= PARSE_SIZEFACTOR;
2346  }
2347 
2348  parsesuccess = SCIPstrToIntValue(pos, &(consdata->row[consdata->nvars - 1][consdata->nvarnonz[consdata->nvars - 1]]), &pos);
2349  *success = *success && parsesuccess;
2350  assert( consdata->row[consdata->nvars - 1][consdata->nvarnonz[consdata->nvars - 1]] < consdata->blocksize );
2351  pos++; /* remove the ',' */
2352  parsesuccess = SCIPstrToIntValue(pos, &(consdata->col[consdata->nvars - 1][consdata->nvarnonz[consdata->nvars - 1]]), &pos);
2353  *success = *success && parsesuccess;
2354  assert( consdata->col[consdata->nvars - 1][consdata->nvarnonz[consdata->nvars - 1]] < consdata->blocksize );
2355  pos += 2; /* remove the "):" */
2356  parsesuccess = SCIPstrToRealValue(pos, &(consdata->val[consdata->nvars - 1][consdata->nvarnonz[consdata->nvars - 1]]), &pos);
2357  *success = *success && parsesuccess;
2358  pos ++; /* remove the "," */
2359 
2360  /* if we got an entry in the upper triangular part, switch the entries for lower triangular */
2361  if ( consdata->col[consdata->nvars - 1][consdata->nvarnonz[consdata->nvars - 1]] >
2362  consdata->row[consdata->nvars - 1][consdata->nvarnonz[consdata->nvars - 1]] )
2363  {
2364  i = consdata->col[consdata->nvars - 1][consdata->nvarnonz[consdata->nvars - 1]];
2365  consdata->col[consdata->nvars - 1][consdata->nvarnonz[consdata->nvars - 1]] =
2366  consdata->row[consdata->nvars - 1][consdata->nvarnonz[consdata->nvars - 1]];
2367  consdata->row[consdata->nvars - 1][consdata->nvarnonz[consdata->nvars - 1]] = i;
2368  }
2369 
2370  consdata->nvarnonz[consdata->nvars - 1]++;
2371 
2372  /* skip whitespace */
2373  while( isspace((unsigned char)*pos) )
2374  pos++;
2375  }
2376 
2377  /* resize the arrays to their final size */
2378  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->col[consdata->nvars - 1], currentsize, consdata->nvarnonz[consdata->nvars - 1]) );
2379  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->row[consdata->nvars - 1], currentsize, consdata->nvarnonz[consdata->nvars - 1]) );
2380  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->val[consdata->nvars - 1], currentsize, consdata->nvarnonz[consdata->nvars - 1]) );
2381 
2382  /* skip whitespace */
2383  while( isspace((unsigned char)*pos) )
2384  pos++;
2385  }
2386 
2387  /* create the constraint */
2388  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate, local, modifiable,
2389  dynamic, removable, stickingatnode) );
2390 
2391  /* compute maximum rhs entry for later use in the DIMACS Error Norm */
2392  SCIP_CALL( setMaxRhsEntry(*cons) );
2393 
2394 #ifdef SCIP_MORE_DEBUG
2395  SCIP_CALL( SCIPprintCons(scip, *cons, NULL) );
2396 #endif
2397 
2398  return SCIP_OKAY;
2399 }
2400 
2402 static
2403 SCIP_DECL_CONSGETVARS(consGetVarsSdp)
2404 {/*lint --e{715}*/
2405  SCIP_CONSDATA* consdata;
2406  int nvars;
2407  int i;
2408 
2409  assert( scip != NULL );
2410  assert( cons != NULL );
2411  assert( vars != NULL );
2412  assert( success != NULL );
2413  assert( varssize >= 0 );
2414 
2415  consdata = SCIPconsGetData(cons);
2416  assert( consdata != NULL );
2417 
2418  nvars = consdata->nvars;
2419 
2420  if ( nvars > varssize )
2421  {
2422  SCIPdebugMessage("consGetVarsIndicator called for array of size %d, needed size %d.\n", varssize, nvars);
2423  *success = FALSE;
2424  return SCIP_OKAY;
2425  }
2426 
2427  for (i = 0; i < nvars; i++)
2428  vars[i] = consdata->vars[i];
2429 
2430  *success = TRUE;
2431 
2432  return SCIP_OKAY;
2433 }
2434 
2436 static
2437 SCIP_DECL_CONSGETNVARS(consGetNVarsSdp)
2438 {/*lint --e{715}*/
2439  SCIP_CONSDATA* consdata;
2440 
2441  assert( scip != NULL );
2442  assert( cons != NULL );
2443  assert( nvars != NULL );
2444  assert( success != NULL );
2445 
2446  consdata = SCIPconsGetData(cons);
2447  assert( consdata != NULL );
2448 
2449  *nvars = consdata->nvars;
2450  *success = TRUE;
2451 
2452  return SCIP_OKAY;
2453 }
2454 
2456 SCIP_RETCODE SCIPincludeConshdlrSdp(
2457  SCIP* scip
2458  )
2459 {
2460  SCIP_CONSHDLR* conshdlr = NULL;
2461  SCIP_CONSHDLRDATA* conshdlrdata = NULL;
2462 
2463  assert( scip != 0 );
2464 
2465  /* allocate memory for the conshdlrdata */
2466  SCIP_CALL( SCIPallocMemory(scip, &conshdlrdata) );
2467 
2468  /* include constraint handler */
2469  SCIP_CALL( SCIPincludeConshdlrBasic(scip, &conshdlr, CONSHDLR_NAME, CONSHDLR_DESC,
2471  consEnfolpSdp, consEnfopsSdp, consCheckSdp, consLockSdp, conshdlrdata) );
2472 
2473  assert( conshdlr != NULL );
2474 
2475  /* set non-fundamental callbacks via specific setter functions */
2476  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteSdp) );
2477  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeSdp) );
2478  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopySdp, consCopySdp) );
2479  SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr,consInitpreSdp) );
2480  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreSdp) );
2481  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolSdp, CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
2482  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpSdp, consSepasolSdp, CONSHDLR_SEPAFREQ,
2484  SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxSdp) );
2485  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransSdp) );
2486  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintSdp) );
2487  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseSdp) );
2488  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsSdp) );
2489  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsSdp) );
2490 
2491  /* add parameter */
2492 #ifdef OMP
2493  SCIP_CALL( SCIPaddIntParam(scip, "constraints/SDP/threads", "number of threads used for OpenBLAS",
2494  &(conshdlrdata->nthreads), TRUE, DEFAULT_NTHREADS, 1, INT_MAX, NULL, NULL) );
2495 #endif
2496  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/SDP/diaggezerocuts",
2497  "Should linear cuts enforcing the non-negativity of diagonal entries of SDP-matrices be added?",
2498  &(conshdlrdata->diaggezerocuts), TRUE, DEFAULT_DIAGGEZEROCUTS, NULL, NULL) );
2499  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/SDP/diagzeroimplcuts",
2500  "Should linear cuts enforcing the implications of diagonal entries of zero in SDP-matrices be added?",
2501  &(conshdlrdata->diagzeroimplcuts), TRUE, DEFAULT_DIAGZEROIMPLCUTS, NULL, NULL) );
2502 
2503  return SCIP_OKAY;
2504 }
2505 
2512 SCIP_RETCODE SCIPconsSdpGetData(
2513  SCIP* scip,
2514  SCIP_CONS* cons,
2515  int* nvars,
2516  int* nnonz,
2517  int* blocksize,
2518  int* arraylength,
2519  int* nvarnonz,
2521  int** col,
2522  int** row,
2523  SCIP_Real** val,
2524  SCIP_VAR** vars,
2525  int* constnnonz,
2527  int* constcol,
2528  int* constrow,
2529  SCIP_Real* constval
2530  )
2531 {
2532  SCIP_CONSDATA* consdata;
2533  const char* name;
2534  int i;
2535 
2536  assert( scip != NULL );
2537  assert( cons != NULL );
2538  assert( nvars != NULL );
2539  assert( nnonz != NULL );
2540  assert( blocksize != NULL );
2541  assert( arraylength != NULL );
2542  assert( nvarnonz != NULL );
2543  assert( col != NULL );
2544  assert( row != NULL );
2545  assert( val != NULL );
2546  assert( vars != NULL );
2547  assert( constnnonz != NULL );
2548 
2549  consdata = SCIPconsGetData(cons);
2550  name = SCIPconsGetName(cons);
2551 
2552  assert( consdata->constnnonz == 0 || ( constcol != NULL && constrow != NULL && constval != NULL ) );
2553 
2554  *nvars = consdata->nvars;
2555  *nnonz = consdata->nnonz;
2556  *blocksize = consdata->blocksize;
2557 
2558  for (i = 0; i < consdata->nvars; i++)
2559  vars[i] = consdata->vars[i];
2560 
2561  /* check that the sdp-arrays are long enough to store the information */
2562  if ( *arraylength < consdata->nvars )
2563  {
2564  SCIPdebugMessage("nvarnonz, col, row and val arrays were not long enough to store the information for cons %s, they need to be at least"
2565  "size %d, given was only length %d! \n", name, consdata->nvars, *arraylength);
2566  *arraylength = consdata->nvars;
2567  }
2568  else
2569  {
2570  for (i = 0; i < consdata->nvars; i++)
2571  {
2572  nvarnonz[i] = consdata->nvarnonz[i];
2573  /* set the pointers for each variable */
2574  col[i] = consdata->col[i];
2575  row[i] = consdata->row[i];
2576  val[i] = consdata->val[i];
2577  }
2578  }
2579 
2580  /* set the constant pointers (if a constant part exists) */
2581  if ( consdata->constnnonz > 0 )
2582  {
2583  if ( consdata->constnnonz > *constnnonz )
2584  {
2585  SCIPdebugMessage("The constant nonzeros arrays were not long enough to store the information for cons %s, they need to be at least"
2586  "size %d, given was only length %d! \n", name, consdata->constnnonz, *constnnonz);
2587  }
2588  else
2589  {
2590  for (i = 0; i < consdata->constnnonz; i++)
2591  {
2592  constcol[i] = consdata->constcol[i];
2593  constrow[i] = consdata->constrow[i];
2594  constval[i] = consdata->constval[i];
2595  }
2596  }
2597  }
2598 
2599  *constnnonz = consdata->constnnonz;
2600 
2601  return SCIP_OKAY;
2602 }
2603 
2608 SCIP_RETCODE SCIPconsSdpGetNNonz(
2609  SCIP* scip,
2610  SCIP_CONS* cons,
2611  int* nnonz,
2612  int* constnnonz
2613  )
2614 {
2615  SCIP_CONSDATA* consdata;
2616 
2617  assert( scip != NULL );
2618  assert( cons != NULL );
2619 
2620  consdata = SCIPconsGetData(cons);
2621  assert( consdata != NULL );
2622 
2623  if ( nnonz != NULL )
2624  *nnonz = consdata->nnonz;
2625 
2626  if ( constnnonz != NULL )
2627  *constnnonz = consdata->constnnonz;
2628 
2629  return SCIP_OKAY;
2630 }
2631 
2634  SCIP* scip,
2635  SCIP_CONS* cons
2636  )
2637 {
2638  SCIP_CONSDATA* consdata;
2639 
2640  assert( scip != NULL );
2641  assert( cons != NULL );
2642 
2643  consdata = SCIPconsGetData(cons);
2644  assert( consdata != NULL );
2645 
2646  return consdata->blocksize;
2647 }
2648 
2650 SCIP_RETCODE SCIPconsSdpGetFullAj(
2651  SCIP* scip,
2652  SCIP_CONS* cons,
2653  int j,
2654  SCIP_Real* Aj
2655  )
2656 {
2657  SCIP_CONSDATA* consdata;
2658  int blocksize;
2659  int i;
2660 
2661  assert( scip != NULL );
2662  assert( cons != NULL );
2663  assert( j >= 0 );
2664  assert( Aj != NULL );
2665 
2666  consdata = SCIPconsGetData(cons);
2667  assert( consdata != NULL );
2668  blocksize = consdata->blocksize;
2669 
2670  assert( j < consdata->nvars );
2671 
2672  for (i = 0; i < blocksize * blocksize; i++)
2673  Aj[i] = 0;
2674 
2675  for (i = 0; i < consdata->nvarnonz[j]; i++)
2676  {
2677  Aj[consdata->col[j][i] * blocksize + consdata->row[j][i]] = consdata->val[j][i]; /*lint !e679*/
2678  Aj[consdata->row[j][i] * blocksize + consdata->col[j][i]] = consdata->val[j][i]; /*lint !e679*/
2679  }
2680 
2681  return SCIP_OKAY;
2682 }
2683 
2685 SCIP_RETCODE SCIPconsSdpGetFullConstMatrix(
2686  SCIP* scip,
2687  SCIP_CONS* cons,
2688  SCIP_Real* mat
2689  )
2690 {
2691  SCIP_CONSDATA* consdata;
2692  int blocksize;
2693  int i;
2694  int j;
2695 
2696  assert( scip != NULL );
2697  assert( cons != NULL );
2698  assert( mat != NULL );
2699 
2700  consdata = SCIPconsGetData(cons);
2701  blocksize = consdata->blocksize;
2702 
2703  for (i = 0; i < blocksize; i++)
2704  {
2705  for (j = 0; j < blocksize; j++)
2706  mat[i * blocksize + j] = 0.0; /*lint !e679*/
2707  }
2708 
2709  for (i = 0; i < consdata->constnnonz; i++)
2710  {
2711  mat[consdata->constcol[i] * blocksize + consdata->constrow[i]] = consdata->constval[i]; /*lint !e679*/
2712  mat[consdata->constrow[i] * blocksize + consdata->constcol[i]] = consdata->constval[i]; /*lint !e679*/
2713  }
2714 
2715  return SCIP_OKAY;
2716 }
2717 
2720  SCIP* scip,
2721  SCIP_CONS* cons,
2722  SCIP_Real* mat
2723  )
2724 {
2725  SCIP_CONSDATA* consdata;
2726  int blocksize;
2727  int i;
2728 
2729  assert( scip != NULL );
2730  assert( cons != NULL );
2731  assert( mat != NULL );
2732 
2733  consdata = SCIPconsGetData(cons);
2734  assert( consdata != NULL );
2735 
2736  blocksize = consdata->blocksize;
2737 
2738  /* initialize the matrix with 0 */
2739  for (i = 0; i < (blocksize * (blocksize + 1)) / 2; i++)
2740  mat[i] = 0.0;
2741 
2742  for (i = 0; i < consdata->constnnonz; i++)
2743  mat[compLowerTriangPos(consdata->constrow[i], consdata->constcol[i])] = consdata->constval[i];
2744 
2745  return SCIP_OKAY;
2746 }
2747 
2758 SCIP_RETCODE SCIPconsSdpGuessInitialPoint(
2759  SCIP* scip,
2760  SCIP_CONS* cons,
2761  SCIP_Real* lambdastar
2762  )
2763 {
2764  SCIP_CONSDATA* consdata;
2765  SCIP_Real sparsity;
2766  SCIP_Real maxinfnorm;
2767  SCIP_Real maxconst;
2768  SCIP_Real mininfnorm;
2769  SCIP_Real maxobj;
2770  SCIP_Real maxbound;
2771  SCIP_Real primalguess;
2772  SCIP_Real dualguess;
2773  SCIP_Real compval;
2774  int blocksize;
2775  int i;
2776  int v;
2777 
2778  assert( scip != NULL );
2779  assert( cons != NULL );
2780  assert( lambdastar != NULL );
2781  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0 );
2782 
2783  consdata = SCIPconsGetData(cons);
2784  assert( consdata != NULL );
2785 
2786  /* If there are no nonzeros, we cannot use the usual formula, since it divides through the number of nonzeros. In this case,
2787  * however, we will not solve an SDP anyways but at most an LP (more likely the problem will be solved in local presolving,
2788  * if all variables are fixed and not only those in the SDP-part), so we just take the default value of SDPA.
2789  */
2790  if ( consdata->nnonz == 0 )
2791  {
2792  *lambdastar = 100.0;
2793  return SCIP_OKAY;
2794  }
2795 
2796  blocksize = consdata->blocksize;
2797 
2798  sparsity = consdata->nnonz / (0.5 * blocksize * (blocksize + 1));
2799 
2800  /* compute the maximum entry of the A_i */
2801  maxinfnorm = 0.0;
2802  mininfnorm = SCIPinfinity(scip);
2803  for (v = 0; v < consdata->nvars; v++)
2804  {
2805  for (i = 0; i < consdata->nvarnonz[v]; i++)
2806  {
2807  if ( SCIPisGT(scip, REALABS(consdata->val[v][i]), maxinfnorm ) )
2808  maxinfnorm = REALABS(consdata->val[v][i]);
2809  if ( SCIPisLT(scip, REALABS(consdata->val[v][i]), mininfnorm) )
2810  mininfnorm = REALABS(consdata->val[v][i]);
2811  }
2812  }
2813  maxconst = 0.0;
2814  for (i = 0; i < consdata->constnnonz; i++)
2815  {
2816  if ( SCIPisGT(scip, REALABS(consdata->constval[i]), maxconst ) )
2817  maxconst = REALABS(consdata->constval[i]);
2818  }
2819 
2820  assert( SCIPisGT(scip, mininfnorm, 0.0) );
2821 
2822  /* compute maximum b_i and bound */
2823  maxobj = 0.0;
2824  maxbound = 0.0;
2825  for (v = 0; v < consdata->nvars; v++)
2826  {
2827  if ( SCIPisGT(scip, REALABS(SCIPvarGetObj(consdata->vars[v])), maxobj) )
2828  maxobj = REALABS(SCIPvarGetObj(consdata->vars[v]));
2829  compval = SCIPisInfinity(scip, REALABS(SCIPvarGetUbGlobal(consdata->vars[v]))) ? 1e+6 : REALABS(SCIPvarGetUbGlobal(consdata->vars[v]));
2830  if ( SCIPisGT(scip, compval, maxbound) )
2831  maxbound = compval;
2832  compval = SCIPisInfinity(scip, REALABS(SCIPvarGetLbGlobal(consdata->vars[v]))) ? 1e+6 : REALABS(SCIPvarGetUbGlobal(consdata->vars[v]));
2833  if ( SCIPisGT(scip, compval, maxbound) )
2834  maxbound = compval;
2835  }
2836 
2837  /* if all variables were unbounded, we set the value to 10^6 */
2838  if ( SCIPisEQ(scip, maxbound, 0.0) )
2839  maxbound = 1E+6;
2840 
2841  /* compute primal and dual guess */
2842  primalguess = maxobj / (sparsity * mininfnorm);
2843  dualguess = sparsity * maxinfnorm * maxbound + maxconst;
2844 
2845  if ( SCIPisGT(scip, primalguess, dualguess) )
2846  *lambdastar = primalguess;
2847  else
2848  *lambdastar = dualguess;
2849 
2850  return SCIP_OKAY;
2851 }
2852 
2854 SCIP_RETCODE SCIPcreateConsSdp(
2855  SCIP* scip,
2856  SCIP_CONS** cons,
2857  const char* name,
2858  int nvars,
2859  int nnonz,
2860  int blocksize,
2861  int* nvarnonz,
2862  int** col,
2863  int** row,
2864  SCIP_Real** val,
2865  SCIP_VAR** vars,
2866  int constnnonz,
2867  int* constcol,
2868  int* constrow,
2869  SCIP_Real* constval
2870  )
2871 {
2872  SCIP_CONSHDLR* conshdlr;
2873  SCIP_CONSDATA* consdata = NULL;
2874  int i;
2875  int j;
2876 
2877  assert( scip != NULL );
2878  assert( cons != NULL );
2879  assert( name != NULL );
2880  assert( nvars >= 0 );
2881  assert( nnonz >= 0 );
2882  assert( blocksize >= 0 );
2883  assert( constnnonz >= 0 );
2884  assert( nvars == 0 || vars != NULL );
2885  assert( nnonz == 0 || (nvarnonz != NULL && col != NULL && row != NULL && val != NULL ));
2886  assert( constnnonz == 0 || (constcol != NULL && constrow != NULL && constval != NULL ));
2887 
2888  conshdlr = SCIPfindConshdlr(scip, "SDP");
2889  if ( conshdlr == NULL )
2890  {
2891  SCIPerrorMessage("SDP constraint handler not found\n");
2892  return SCIP_PLUGINNOTFOUND;
2893  }
2894 
2895  /* create constraint data */
2896  SCIP_CALL( SCIPallocBlockMemory(scip, &consdata) );
2897  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->nvarnonz, nvars) );
2898  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->col, nvars) );
2899  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->row, nvars) );
2900  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->val, nvars) );
2901  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->constcol, constnnonz) );
2902  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->constrow, constnnonz) );
2903  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->constval, constnnonz) );
2904  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->vars, nvars));
2905 
2906  for (i = 0; i < nvars; i++)
2907  {
2908  assert( nvarnonz[i] >= 0 );
2909 
2910  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->col[i], nvarnonz[i]));
2911  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->row[i], nvarnonz[i]));
2912  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->val[i], nvarnonz[i]));
2913  }
2914 
2915  consdata->nvars = nvars;
2916  consdata->nnonz = nnonz;
2917  consdata->constnnonz = constnnonz;
2918  consdata->blocksize = blocksize;
2919 
2920  for (i = 0; i < nvars; i++)
2921  {
2922  consdata->nvarnonz[i] = nvarnonz[i];
2923 
2924  for (j = 0; j < nvarnonz[i]; j++)
2925  {
2926  assert( col[i][j] >= 0 );
2927  assert( col[i][j] < blocksize );
2928  assert( row[i][j] >= 0 );
2929  assert( row[i][j] < blocksize );
2930 
2931  consdata->col[i][j] = col[i][j];
2932  consdata->row[i][j] = row[i][j];
2933  consdata->val[i][j] = val[i][j];
2934  }
2935  }
2936 
2937  for (i = 0; i < constnnonz; i++)
2938  {
2939  consdata->constcol[i] = constcol[i];
2940  consdata->constrow[i] = constrow[i];
2941  consdata->constval[i] = constval[i];
2942  }
2943 
2944  for (i = 0; i < nvars; i++)
2945  {
2946  consdata->vars[i] = vars[i];
2947  SCIP_CALL( SCIPcaptureVar(scip, consdata->vars[i]) );
2948  }
2949  SCIPdebugMessage("creating cons %s\n", name);
2950  /* create constraint */
2951  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE) );
2952 
2953  /* compute maximum rhs entry for later use in the DIMACS Error Norm */
2954  SCIP_CALL( setMaxRhsEntry(*cons) );
2955 
2956  return SCIP_OKAY;
2957 }
static SCIP_DECL_CONSTRANS(consTransSdp)
Definition: cons_sdp.c:1726
EXTERN SCIP_RETCODE SCIPlapackMatrixVectorMult(int nrows, int ncols, SCIP_Real *matrix, SCIP_Real *vector, SCIP_Real *result)
Definition: lapack_dsdp.c:215
EXTERN SCIP_RETCODE SCIPlapackComputeIthEigenvalue(BMS_BUFMEM *bufmem, SCIP_Bool geteigenvectors, int n, SCIP_Real *A, int i, SCIP_Real *eigenvalue, SCIP_Real *eigenvector)
static SCIP_RETCODE separateSol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_RESULT *result)
Definition: cons_sdp.c:424
SCIP_RETCODE SCIPconsSdpGetFullAj(SCIP *scip, SCIP_CONS *cons, int j, SCIP_Real *Aj)
Definition: cons_sdp.c:2651
void SCIPsdpVarfixerSortRowCol(int *row, int *col, SCIP_Real *val, int length)
Definition: SdpVarfixer.c:50
#define CONSHDLR_PRESOLTIMING
Definition: cons_sdp.c:82
#define CONSHDLR_NAME
Definition: cons_sdp.c:69
SCIP_RETCODE SCIPincludeConshdlrSdp(SCIP *scip)
Definition: cons_sdp.c:2457
static SCIP_RETCODE multiplyConstraintMatrix(SCIP_CONS *cons, int j, SCIP_Real *v, SCIP_Real *vAv)
Definition: cons_sdp.c:218
#define PARSE_SIZEFACTOR
Definition: cons_sdp.c:84
static SCIP_DECL_CONSENFORELAX(consEnforelaxSdp)
Definition: cons_sdp.c:1892
#define CONSHDLR_NEEDSCONS
Definition: cons_sdp.c:80
static SCIP_RETCODE diagGEzero(SCIP *scip, SCIP_CONS **conss, int nconss, int *naddconss)
Definition: cons_sdp.c:514
static SCIP_DECL_CONSDELETE(consDeleteSdp)
Definition: cons_sdp.c:1938
#define CONSHDLR_SEPAFREQ
Definition: cons_sdp.c:74
#define CONSHDLR_DELAYSEPA
Definition: cons_sdp.c:79
static SCIP_RETCODE computeSdpMatrix(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *y, SCIP_Real *matrix)
Definition: cons_sdp.c:176
#define CONSHDLR_EAGERFREQ
Definition: cons_sdp.c:75
static SCIP_RETCODE move_1x1_blocks_to_lp(SCIP *scip, SCIP_CONS **conss, int nconss, int *naddconss, int *ndelconss, SCIP_RESULT *result)
Definition: cons_sdp.c:871
#define DEFAULT_DIAGGEZEROCUTS
Definition: cons_sdp.c:85
SCIP_RETCODE SCIPconsSdpGetLowerTriangConstMatrix(SCIP *scip, SCIP_CONS *cons, SCIP_Real *mat)
Definition: cons_sdp.c:2720
static SCIP_DECL_CONSSEPALP(consSepalpSdp)
Definition: cons_sdp.c:1921
static SCIP_RETCODE setMaxRhsEntry(SCIP_CONS *cons)
Definition: cons_sdp.c:258
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:1076
static SCIP_DECL_CONSCHECK(consCheckSdp)
Definition: cons_sdp.c:1818
#define CONSHDLR_DESC
Definition: cons_sdp.c:70
Constraint handler for SDP-constraints.
static SCIP_RETCODE expandSymMatrix(int size, SCIP_Real *symMat, SCIP_Real *fullMat)
Definition: cons_sdp.c:143
class that maps SCIP variables to SDP indices (the SCIP variables are given SDP indices in the order ...
SCIP_RETCODE SCIPconsSdpGetFullConstMatrix(SCIP *scip, SCIP_CONS *cons, SCIP_Real *mat)
Definition: cons_sdp.c:2686
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)
Definition: cons_sdp.c:2855
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)
Definition: cons_sdp.c:2513
#define CONSHDLR_CHECKPRIORITY
Definition: cons_sdp.c:73
static SCIP_DECL_CONSENFOPS(consEnfopsSdp)
Definition: cons_sdp.c:1842
#define DEFAULT_DIAGZEROIMPLCUTS
Definition: cons_sdp.c:86
static int compLowerTriangPos(int i, int j)
Definition: cons_sdp.c:127
adds the main functionality to fix/unfix/(multi-)aggregate variables by merging two three-tuple-array...
#define CONSHDLR_ENFOPRIORITY
Definition: cons_sdp.c:72
static SCIP_DECL_CONSFREE(consFreeSdp)
Definition: cons_sdp.c:1975
static SCIP_DECL_CONSPRESOL(consPresolSdp)
Definition: cons_sdp.c:1698
static SCIP_DECL_CONSEXITPRE(consExitpreSdp)
Definition: cons_sdp.c:1684
static SCIP_DECL_CONSPRINT(consPrintSdp)
Definition: cons_sdp.c:2090
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopySdp)
Definition: cons_sdp.c:1990
#define CONSHDLR_MAXPREROUNDS
Definition: cons_sdp.c:78
static SCIP_DECL_CONSINITPRE(consInitpreSdp)
Definition: cons_sdp.c:1610
static SCIP_DECL_CONSPARSE(consParseSdp)
Definition: cons_sdp.c:2216
SCIP_RETCODE SCIPconsSdpCheckSdpCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool checkintegrality, SCIP_Bool checklprows, SCIP_Bool printreason, SCIP_RESULT *result)
Definition: cons_sdp.c:360
static SCIP_RETCODE diagZeroImpl(SCIP *scip, SCIP_CONS **conss, int nconss, int *naddconss)
Definition: cons_sdp.c:630
#define PARSE_STARTSIZE
Definition: cons_sdp.c:83
int SCIPconsSdpGetBlocksize(SCIP *scip, SCIP_CONS *cons)
Definition: cons_sdp.c:2634
static SCIP_DECL_CONSSEPASOL(consSepasolSdp)
Definition: cons_sdp.c:1904
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:88
static SCIP_RETCODE EnforceConstraint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_RESULT *result)
Definition: cons_sdp.c:1504
static SCIP_DECL_CONSGETVARS(consGetVarsSdp)
Definition: cons_sdp.c:2404
#define CONSHDLR_SEPAPRIORITY
Definition: cons_sdp.c:71
SCIP_RETCODE SCIPconsSdpGetNNonz(SCIP *scip, SCIP_CONS *cons, int *nnonz, int *constnnonz)
Definition: cons_sdp.c:2609
static SCIP_RETCODE fixAndAggrVars(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool aggregate)
Definition: cons_sdp.c:1281
static SCIP_DECL_CONSLOCK(consLockSdp)
Definition: cons_sdp.c:1628
char name[SCIP_MAXSTRLEN]
static SCIP_DECL_CONSGETNVARS(consGetNVarsSdp)
Definition: cons_sdp.c:2438
static SCIP_DECL_CONSCOPY(consCopySdp)
Definition: cons_sdp.c:2005
interface methods for eigenvector computation and matrix multiplication using different versions of L...
SCIP_RETCODE SCIPconsSdpGuessInitialPoint(SCIP *scip, SCIP_CONS *cons, SCIP_Real *lambdastar)
Definition: cons_sdp.c:2759
static SCIP_RETCODE cutUsingEigenvector(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real *coeff, SCIP_Real *lhs)
Definition: cons_sdp.c:291
static SCIP_DECL_CONSENFOLP(consEnfolpSdp)
Definition: cons_sdp.c:1879