SCIP-SDP  3.2.0
sdpsolchecker.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of SCIPSDP - a solving framework for mixed-integer */
4 /* semidefinite programs based on SCIP. */
5 /* */
6 /* Copyright (C) 2011-2013 Discrete Optimization, TU Darmstadt */
7 /* EDOM, FAU Erlangen-Nürnberg */
8 /* 2014-2020 Discrete Optimization, TU Darmstadt */
9 /* */
10 /* */
11 /* This program is free software; you can redistribute it and/or */
12 /* modify it under the terms of the GNU Lesser General Public License */
13 /* as published by the Free Software Foundation; either version 3 */
14 /* of the License, or (at your option) any later version. */
15 /* */
16 /* This program is distributed in the hope that it will be useful, */
17 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
18 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
19 /* GNU Lesser General Public License for more details. */
20 /* */
21 /* You should have received a copy of the GNU Lesser General Public License */
22 /* along with this program; if not, write to the Free Software */
23 /* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.*/
24 /* */
25 /* */
26 /* Based on SCIP - Solving Constraint Integer Programs */
27 /* Copyright (C) 2002-2020 Zuse Institute Berlin */
28 /* SCIP is distributed under the terms of the SCIP Academic Licence, */
29 /* see file COPYING in the SCIP distribution. */
30 /* */
31 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
32 
38 /*#define SCIP_DEBUG*/
39 
40 #include "sdpi/sdpsolchecker.h"
41 #include "sdpi/lapack_interface.h"
42 #include "scip/pub_message.h" /* for debug and error message */
43 
45 #define BMS_CALL(x) do \
46  { \
47  if( NULL == (x) ) \
48  { \
49  SCIPerrorMessage("No memory in function call.\n"); \
50  return SCIP_NOMEMORY; \
51  } \
52  } \
53  while( FALSE )
54 
59  BMS_BUFMEM* bufmem,
60  int nvars,
61  SCIP_Real* lb,
62  SCIP_Real* ub,
63  int nsdpblocks,
64  int* sdpblocksizes,
65  int* sdpnblockvars,
66  int sdpconstnnonz,
67  int* sdpconstnblocknonz,
69  int** sdpconstrow,
70  int** sdpconstcol,
71  SCIP_Real** sdpconstval,
72  int sdpnnonz,
73  int** sdpnblockvarnonz,
75  int** sdpvar,
77  int*** sdprow,
78  int*** sdpcol,
79  SCIP_Real*** sdpval,
80  int** indchanges,
82  int* nremovedinds,
83  int* blockindchanges,
84  int nlpcons,
85  int noldlpcons,
86  SCIP_Real* lplhs,
87  SCIP_Real* lprhs,
88  int* rownactivevars,
89  int lpnnonz,
90  int* lprow,
91  int* lpcol,
92  SCIP_Real* lpval,
93  SCIP_Real* solvector,
94  SCIP_Real feastol,
95  SCIP_Real epsilon,
96  SCIP_Bool* infeasible
97 )
98 {/*lint --e{818}*/
99  int i;
100  int j;
101  int b;
102  int v;
103  int ind;
104 
105  assert( bufmem != NULL );
106  assert( lb != NULL );
107  assert( ub != NULL );
108  assert( nsdpblocks >= 0 );
109  assert( nsdpblocks == 0 || sdpblocksizes != NULL );
110  assert( nsdpblocks == 0 || sdpnblockvars != NULL );
111  assert( sdpconstnnonz >= 0 );
112  assert( nsdpblocks == 0 || sdpconstnnonz == 0 || sdpconstnblocknonz != NULL );
113  assert( nsdpblocks == 0 || sdpconstnnonz == 0 || sdpconstrow != NULL );
114  assert( nsdpblocks == 0 || sdpconstnnonz == 0 || sdpconstcol != NULL );
115  assert( nsdpblocks == 0 || sdpconstnnonz == 0 || sdpconstval != NULL );
116  assert( sdpnnonz >= 0 );
117  assert( nsdpblocks == 0 || sdpnblockvarnonz != NULL );
118  assert( nsdpblocks == 0 || sdpvar != NULL );
119  assert( nsdpblocks == 0 || sdprow != NULL );
120  assert( nsdpblocks == 0 || sdpcol != NULL );
121  assert( nsdpblocks == 0 || sdpval != NULL );
122  assert( nsdpblocks == 0 || indchanges != NULL );
123  assert( nsdpblocks == 0 || nremovedinds != NULL );
124  assert( nsdpblocks == 0 || blockindchanges != NULL );
125  assert( nlpcons >= 0 );
126  assert( noldlpcons >= nlpcons );
127  assert( nlpcons == 0 || lplhs != NULL );
128  assert( nlpcons == 0 || lprhs != NULL );
129  assert( nlpcons == 0 || rownactivevars != NULL );
130  assert( lpnnonz >= 0 );
131  assert( nlpcons == 0 || lprow != NULL );
132  assert( nlpcons == 0 || lpcol != NULL );
133  assert( nlpcons == 0 || lpval != NULL );
134  assert( solvector != NULL );
135  assert( feastol >= 0 );
136  assert( infeasible != NULL );
137 
138  /* check variable bounds */
139  for (i = 0; i < nvars; i++)
140  {
141  if ( solvector[i] < lb[i] - feastol || solvector[i] > ub[i] + feastol )
142  {
143  SCIPdebugMessage("solution found infeasible (feastol=%f) for variable bounds: x[%d] = %f <|= [%f, %f]\n",
144  feastol, i, solvector[i], lb[i], ub[i]);
145  *infeasible = TRUE;
146  return SCIP_OKAY;
147  }
148  }
149 
150  /* check linear constraints (since DSDP sorts the lp-arrays by cols, we cannot expect them to be sorted) */
151  if ( nlpcons > 0 )
152  {
153  SCIP_Real* lpconsvals;
154 
155  BMS_CALL( BMSallocBufferMemoryArray(bufmem, &lpconsvals, noldlpcons) );
156 
157  /* initialize all rows with zero */
158  for (i = 0; i < noldlpcons; i++)
159  lpconsvals[i] = 0;
160 
161  /* compute the values of all rows */
162  for (i = 0; i < lpnnonz; i++)
163  {
164  if ( lb[lpcol[i]] < ub[lpcol[i]] - epsilon ) /* fixed variables are already included in lhs/rhs */
165  lpconsvals[lprow[i]] += solvector[lpcol[i]] * lpval[i];
166  }
167 
168  /* check all active constraints for feasibility */
169  ind = 0; /* used to iterate over active constraints */
170  for (i = 0; i < noldlpcons; i++)
171  {
172  if ( rownactivevars[i] > 1 )
173  {
174  if ( lpconsvals[i] < lplhs[ind] - feastol || lpconsvals[i] > lprhs[ind] + feastol)
175  {
176  SCIPdebugMessage("solution found infeasible (feastol=%f) for lp constraint: LP-%d = %f <|= [%f,%f]\n",
177  feastol, i, lpconsvals[i], lplhs[ind], lprhs[ind]);
178  BMSfreeBufferMemoryArray(bufmem, &lpconsvals);
179  *infeasible = TRUE;
180  return SCIP_OKAY;
181  }
182 
183  ind++;
184  }
185  }
186  BMSfreeBufferMemoryArray(bufmem, &lpconsvals);
187  }
188 
189  /* check sdp constraints */
190  if ( nsdpblocks > 0 )
191  {
192  SCIP_Real* fullsdpmatrix;
193  SCIP_Real eigenvalue;
194  int maxblocksize = 0;
195 
196  /* allocate memory */
197  if ( nsdpblocks == 1 )
198  maxblocksize = sdpblocksizes[0] - nremovedinds[0];
199  else
200  {
201  /* calculate maximum size of any SDP block to not have to reallocate memory in between */
202  for (b = 0; b < nsdpblocks; b++)
203  {
204  maxblocksize = ((sdpblocksizes[b] - nremovedinds[b]) > maxblocksize) ? sdpblocksizes[b] - nremovedinds[b] : maxblocksize;
205  }
206  }
207 
208  BMS_CALL( BMSallocBufferMemoryArray(bufmem, &fullsdpmatrix, maxblocksize * maxblocksize) );/*lint !e647*/
209 
210  for (b = 0; b < nsdpblocks; b++)
211  {
212  if ( blockindchanges[b] > -1 )
213  {
214  /* initialize lower triangular part of fullsdpmatrix with zero */
215  for (i = 0; i < sdpblocksizes[b] - nremovedinds[b]; i++)
216  {
217  for (j = 0; j <= i; j++)
218  {
219  fullsdpmatrix[i * (sdpblocksizes[b] - nremovedinds[b]) + j] = 0.0; /*lint !e679*/
220  }
221  }
222 
223  /* iterate over all non-fixed variables and add the corresponding nonzeros */
224  for (v = 0; v < sdpnblockvars[b]; v++)
225  {
226  if ( lb[sdpvar[b][v]] < ub[sdpvar[b][v]] - epsilon )
227  {
228  for (i = 0; i < sdpnblockvarnonz[b][v]; i++)
229  {
230  fullsdpmatrix[((sdprow[b][v][i] - indchanges[b][sdprow[b][v][i]]) * (sdpblocksizes[b] - nremovedinds[b])) +
231  sdpcol[b][v][i] - indchanges[b][sdpcol[b][v][i]]] += solvector[sdpvar[b][v]] * sdpval[b][v][i];/*lint !e679*/
232  }
233  }
234  }
235 
236  /* add constant matrix */
237  for (i = 0; i < sdpconstnblocknonz[b]; i++)
238  {
239  fullsdpmatrix[((sdpconstrow[b][i] - indchanges[b][sdpconstrow[b][i]]) * (sdpblocksizes[b] - nremovedinds[b])) +
240  sdpconstcol[b][i] - indchanges[b][sdpconstcol[b][i]]] -= sdpconstval[b][i];/*lint !e679*/
241  }
242 
243  /* extend to full symmetric matrix for LAPACK */
244  for (i = 0; i < sdpblocksizes[b] - nremovedinds[b]; i++)
245  {
246  for (j = 0; j < i; j++)
247  {
248  fullsdpmatrix[j * (sdpblocksizes[b] - nremovedinds[b]) + i] = fullsdpmatrix[i * (sdpblocksizes[b] - nremovedinds[b]) + j];/*lint !e679*/
249  }
250  }
251 
252  /* compute smallest eigenvalue using LAPACK */
253  SCIP_CALL( SCIPlapackComputeIthEigenvalue(bufmem, FALSE, sdpblocksizes[b] - nremovedinds[b], fullsdpmatrix, 1, &eigenvalue, NULL) );
254 
255  if ( eigenvalue < - feastol )
256  {
257  SCIPdebugMessage("solution found infeasible (feastol=%.10f) for sdp constraint %d, smallest eigenvector %.10f\n",
258  feastol, b, eigenvalue);
259  BMSfreeBufferMemoryArray(bufmem, &fullsdpmatrix);
260  *infeasible = TRUE;
261  return SCIP_OKAY;
262  }
263  }
264  }
265 
266  BMSfreeBufferMemoryArray(bufmem, &fullsdpmatrix);
267  }
268 
269  *infeasible = FALSE;
270  return SCIP_OKAY;
271 }
#define BMS_CALL(x)
Definition: sdpsolchecker.c:45
SCIP_EXPORT SCIP_RETCODE SCIPlapackComputeIthEigenvalue(BMS_BUFMEM *bufmem, SCIP_Bool geteigenvectors, int n, SCIP_Real *A, int i, SCIP_Real *eigenvalue, SCIP_Real *eigenvector)
SCIP_RETCODE SCIPsdpSolcheckerCheck(BMS_BUFMEM *bufmem, int nvars, SCIP_Real *lb, SCIP_Real *ub, int nsdpblocks, int *sdpblocksizes, int *sdpnblockvars, int sdpconstnnonz, int *sdpconstnblocknonz, int **sdpconstrow, int **sdpconstcol, SCIP_Real **sdpconstval, int sdpnnonz, int **sdpnblockvarnonz, int **sdpvar, int ***sdprow, int ***sdpcol, SCIP_Real ***sdpval, int **indchanges, int *nremovedinds, int *blockindchanges, int nlpcons, int noldlpcons, SCIP_Real *lplhs, SCIP_Real *lprhs, int *rownactivevars, int lpnnonz, int *lprow, int *lpcol, SCIP_Real *lpval, SCIP_Real *solvector, SCIP_Real feastol, SCIP_Real epsilon, SCIP_Bool *infeasible)
Definition: sdpsolchecker.c:58
checks a given SDP solution for feasibility
interface methods for eigenvector computation and matrix multiplication using openblas ...