SCIP-SDP  4.0.0
solveonevarsdp.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of SCIPSDP - a solving framework for mixed-integer */
4 /* semidefinite programs based on SCIP. */
5 /* */
6 /* Copyright (C) 2011-2013 Discrete Optimization, TU Darmstadt */
7 /* EDOM, FAU Erlangen-Nürnberg */
8 /* 2014-2021 Discrete Optimization, TU Darmstadt */
9 /* */
10 /* */
11 /* This program is free software; you can redistribute it and/or */
12 /* modify it under the terms of the GNU Lesser General Public License */
13 /* as published by the Free Software Foundation; either version 3 */
14 /* of the License, or (at your option) any later version. */
15 /* */
16 /* This program is distributed in the hope that it will be useful, */
17 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
18 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
19 /* GNU Lesser General Public License for more details. */
20 /* */
21 /* You should have received a copy of the GNU Lesser General Public License */
22 /* along with this program; if not, write to the Free Software */
23 /* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.*/
24 /* */
25 /* */
26 /* Based on SCIP - Solving Constraint Integer Programs */
27 /* Copyright (C) 2002-2021 Zuse Institute Berlin */
28 /* SCIP is distributed under the terms of the SCIP Academic Licence, */
29 /* see file COPYING in the SCIP distribution. */
30 /* */
31 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
32 
38 #include "scip/pub_misc.h"
39 #include "sdpi/solveonevarsdp.h"
40 #include "sdpi/lapack_interface.h"
41 
43 #define BMS_CALL(x) do \
44  { \
45  if( NULL == (x) ) \
46  { \
47  SCIPerrorMessage("No memory in function call\n"); \
48  return SCIP_NOMEMORY; \
49  } \
50  } \
51  while( FALSE )
52 
53 
55 static
56 SCIP_RETCODE SCIPoneVarFeasible(
57  BMS_BUFMEM* bufmem,
58  int blocksize,
59  SCIP_Real* tmpmatrix,
60  SCIP_Real* fullconstmatrix,
61  SCIP_Real* fullmatrix,
62  SCIP_Real alpha,
63  SCIP_Real* eigenvalue,
64  SCIP_Real* eigenvector
65  )
66 {
67  int i;
68 
69  assert( fullconstmatrix != NULL );
70  assert( fullmatrix != NULL );
71  assert( eigenvalue != NULL );
72 
73  /* compute linear combination */
74  for (i = 0; i < blocksize * blocksize; ++i)
75  tmpmatrix[i] = alpha * fullmatrix[i] - fullconstmatrix[i];
76 
77  if ( eigenvector != NULL )
78  {
79  SCIP_CALL( SCIPlapackComputeIthEigenvalue(bufmem, TRUE, blocksize, tmpmatrix, 1, eigenvalue, eigenvector) );
80  }
81  else
82  {
83  SCIP_CALL( SCIPlapackComputeIthEigenvalue(bufmem, FALSE, blocksize, tmpmatrix, 1, eigenvalue, NULL) );
84  }
85 
86  return SCIP_OKAY;
87 }
88 
89 
91 static
93  int sdpnnonz,
94  int* sdprow,
95  int* sdpcol,
96  SCIP_Real* sdpval,
97  SCIP_Real* eigenvector,
98  SCIP_Real* supergradient
99  )
100 {
101  int r;
102  int c;
103  int i;
104 
105  assert( supergradient != NULL );
106 
107  *supergradient = 0.0;
108  for (i = 0; i < sdpnnonz; ++i)
109  {
110  r = sdprow[i];
111  c = sdpcol[i];
112 
113  *supergradient += sdpval[i] * eigenvector[r] * eigenvector[c];
114  if ( r != c )
115  *supergradient += sdpval[i] * eigenvector[c] * eigenvector[r];
116  }
117 }
118 
120 SCIP_RETCODE SCIPsolveOneVarSDP(
121  BMS_BUFMEM* bufmem,
122  SCIP_Real obj,
123  SCIP_Real lb,
124  SCIP_Real ub,
125  int blocksize,
126  int sdpconstnnonz,
127  int* sdpconstrow,
128  int* sdpconstcol,
129  SCIP_Real* sdpconstval,
130  int sdpnnonz,
131  int* sdprow,
132  int* sdpcol,
133  SCIP_Real* sdpval,
134  SCIP_Real infinity,
135  SCIP_Real feastol,
136  SCIP_Real* objval,
137  SCIP_Real* optval
138  )
139 {
140  SCIP_Real* fullconstmatrix;
141  SCIP_Real* fullmatrix;
142  SCIP_Real* tmpmatrix;
143  SCIP_Real* eigenvector = NULL;
144  SCIP_Real eigenvalue;
145  SCIP_Real supergradient = SCIP_INVALID;
146  SCIP_Real mu;
147  int r;
148  int c;
149  int i;
150 
151  assert( sdpconstnnonz == 0 || sdpconstrow != NULL );
152  assert( sdpconstnnonz == 0 || sdpconstcol != NULL );
153  assert( sdpconstnnonz == 0 || sdpconstval != NULL );
154  assert( sdpnnonz == 0 || sdprow != NULL );
155  assert( sdpnnonz == 0 || sdpcol != NULL );
156  assert( sdpnnonz == 0 || sdpval != NULL );
157  assert( objval != NULL );
158  assert( optval != NULL );
159 
160  *objval = SCIP_INVALID;
161  *optval = SCIP_INVALID;
162 
163  /* can currently only treat the case with finite lower and upper bounds */
164  if ( lb <= -infinity )
165  return SCIP_OKAY;
166  if ( ub >= infinity )
167  return SCIP_OKAY;
168 
169  /* can currently only treat nonnegative objective functions */
170  if ( obj < 0.0 )
171  return SCIP_OKAY;
172 
173  SCIPdebugMessage("Solve SDP with one variable (obj = %g, lb = %g, ub = %g).\n", obj, lb, ub);
174 
175  /* fill in full matrices */
176  BMS_CALL( BMSallocClearBufferMemoryArray(bufmem, &fullconstmatrix, blocksize * blocksize) );
177  BMS_CALL( BMSallocClearBufferMemoryArray(bufmem, &fullmatrix, blocksize * blocksize) );
178  BMS_CALL( BMSallocBufferMemoryArray(bufmem, &tmpmatrix, blocksize * blocksize) );
179  BMS_CALL( BMSallocBufferMemoryArray(bufmem, &eigenvector, blocksize) );
180 
181  for (i = 0; i < sdpconstnnonz; ++i)
182  {
183  r = sdpconstrow[i];
184  c = sdpconstcol[i];
185  assert( fullconstmatrix[r * blocksize + c] == 0.0 );
186  assert( fullconstmatrix[c * blocksize + r] == 0.0 );
187  fullconstmatrix[r * blocksize + c] = sdpconstval[i];
188  fullconstmatrix[c * blocksize + r] = sdpconstval[i];
189  }
190 
191  for (i = 0; i < sdpnnonz; ++i)
192  {
193  r = sdprow[i];
194  c = sdpcol[i];
195  assert( fullmatrix[r * blocksize + c] == 0.0 );
196  assert( fullmatrix[c * blocksize + r] == 0.0 );
197  fullmatrix[r * blocksize + c] = sdpval[i];
198  fullmatrix[c * blocksize + r] = sdpval[i];
199  }
200 
201  /* check upper bound */
202  SCIP_CALL( SCIPoneVarFeasible(bufmem, blocksize, tmpmatrix, fullconstmatrix, fullmatrix, ub, &eigenvalue, eigenvector) );
203  SCIPdebugMessage("ub = %g, minimal eigenvalue: %g\n", ub, eigenvalue);
204 
205  /* if matrix is not psd */
206  if ( eigenvalue < -feastol )
207  {
208  /* compute supergradient value */
209  computeSupergradient(sdpnnonz, sdprow, sdpcol, sdpval, eigenvector, &supergradient);
210 
211  /* if supergradient is positive, then the problem is infeasible, because the minimal eigenvalue is increasing and we are not psd */
212  if ( supergradient > 0.0 )
213  {
214  SCIPdebugMessage("Problem is infeasible (minimal eigenvalue: %g, supergradient = %g).\n", eigenvalue, supergradient);
215  *objval = infinity;
216  *optval = ub;
217 
218  goto TERMINATE;
219  }
220  }
221 
222  /* otherwise check lower bound */
223  SCIP_CALL( SCIPoneVarFeasible(bufmem, blocksize, tmpmatrix, fullconstmatrix, fullmatrix, lb, &eigenvalue, eigenvector) );
224 
225  /* if matrix is psd, then the lower bound is optimal */
226  if ( eigenvalue >= -feastol )
227  {
228  SCIPdebugMessage("Lower bound is optimal.\n");
229  *objval = obj * lb;
230  *optval = lb;
231 
232  goto TERMINATE;
233  }
234  else
235  {
236  /* compute supergradient value */
237  computeSupergradient(sdpnnonz, sdprow, sdpcol, sdpval, eigenvector, &supergradient);
238 
239  /* if supergradient not positive, then the problem is infeasible because the eigenvalue is decreasing and we are not psd */
240  if ( supergradient <= 0.0 )
241  {
242  SCIPdebugMessage("Problem is infeasible (minimal eigenvalue: %g, supergradient: %g).\n", eigenvalue, supergradient);
243  *objval = infinity;
244  *optval = lb;
245 
246  goto TERMINATE;
247  }
248  }
249  assert( supergradient != SCIP_INVALID );
250  SCIPdebugMessage("lb = %g, minimal eigenvalue: %g, supergradient: %g\n", lb, eigenvalue, supergradient);
251 
252  /* Invariant of the loop: the lower bound is not psd and the supergradient is positive */
253  assert( eigenvector != NULL );
254  assert( eigenvalue < -feastol );
255  assert( supergradient > 0.0 );
256  mu = lb;
257  while ( eigenvalue < -feastol && supergradient > 0.0 )
258  {
259  assert( eigenvalue < -feastol );
260  assert( supergradient > 0.0 );
261 
262  /* Compute estimate based on where the supergradient would reach -feastol/2.0 based on the supergradient inequality
263  * f(mu) \leq f(muold) + (mu - muold) g. We use feastol/2.0 to avoid little rounding errors. */
264  mu = mu - (feastol / 2.0 + eigenvalue) / supergradient;
265 
266  /* Stop if we are larger than ub. In this case the problem is infeasible, since eigenvalue < -feastol by the while
267  * condition. Infeasibility is detected below. */
268  if ( mu > ub )
269  break;
270 
271  /* compute eigenvalue and eigenvector */
272  SCIP_CALL( SCIPoneVarFeasible(bufmem, blocksize, tmpmatrix, fullconstmatrix, fullmatrix, mu, &eigenvalue, eigenvector) );
273 
274  /* update supergradient */
275  computeSupergradient(sdpnnonz, sdprow, sdpcol, sdpval, eigenvector, &supergradient);
276 
277  SCIPdebugMessage("mu = %.15g in [%.15g, %.15g], minimal eigenvalue: %g, supergradient: %g.\n", mu, lb, ub, eigenvalue, supergradient);
278  }
279 
280  /* check whether we are infeasible */
281  if ( eigenvalue < -feastol )
282  {
283  SCIPdebugMessage("Problem infeasible; detected at %.15g in [%.15g, %.15g], minimal eigenvalue: %g, supergradient: %g.\n", mu, lb, ub, eigenvalue, supergradient);
284  *objval = infinity;
285  *optval = mu;
286  }
287  else
288  {
289  SCIPdebugMessage("Solution is %.15g in [%.15g, %.15g], minimal eigenvalue: %g, supergradient: %g.\n", mu, lb, ub, eigenvalue, supergradient);
290  *objval = obj * mu;
291  *optval = mu;
292  }
293 
294  TERMINATE:
295  BMSfreeBufferMemoryArray(bufmem, &eigenvector);
296  BMSfreeBufferMemoryArray(bufmem, &tmpmatrix);
297  BMSfreeBufferMemoryArray(bufmem, &fullmatrix);
298  BMSfreeBufferMemoryArray(bufmem, &fullconstmatrix);
299 
300  return SCIP_OKAY;
301 }
302 
303 
306  BMS_BUFMEM* bufmem,
307  SCIP_Real obj,
308  SCIP_Real lb,
309  SCIP_Real ub,
310  int blocksize,
311  SCIP_Real* fullconstmatrix,
312  int sdpnnonz,
313  int* sdprow,
314  int* sdpcol,
315  SCIP_Real* sdpval,
316  SCIP_Real infinity,
317  SCIP_Real feastol,
318  SCIP_Real* objval,
319  SCIP_Real* optval
320  )
321 {
322  SCIP_Real* fullmatrix;
323  SCIP_Real* tmpmatrix;
324  SCIP_Real* eigenvector = NULL;
325  SCIP_Real eigenvalue;
326  SCIP_Real supergradient = SCIP_INVALID;
327  SCIP_Real mu;
328  int r;
329  int c;
330  int i;
331 
332  assert( fullconstmatrix != NULL );
333  assert( sdpnnonz == 0 || sdprow != NULL );
334  assert( sdpnnonz == 0 || sdpcol != NULL );
335  assert( sdpnnonz == 0 || sdpval != NULL );
336  assert( objval != NULL );
337  assert( optval != NULL );
338 
339  *objval = SCIP_INVALID;
340  *optval = SCIP_INVALID;
341 
342  /* can currently only treat the case with finite lower and upper bounds */
343  if ( lb <= -infinity )
344  return SCIP_OKAY;
345  if ( ub >= infinity )
346  return SCIP_OKAY;
347 
348  /* can currently only treat nonnegative objective functions */
349  if ( obj < 0.0 )
350  return SCIP_OKAY;
351 
352  SCIPdebugMessage("Solve SDP with one variable (obj = %g, lb = %g, ub = %g).\n", obj, lb, ub);
353 
354  /* fill in full matrices */
355  BMS_CALL( BMSallocClearBufferMemoryArray(bufmem, &fullmatrix, blocksize * blocksize) );
356  BMS_CALL( BMSallocBufferMemoryArray(bufmem, &tmpmatrix, blocksize * blocksize) );
357  BMS_CALL( BMSallocBufferMemoryArray(bufmem, &eigenvector, blocksize) );
358 
359  for (i = 0; i < sdpnnonz; ++i)
360  {
361  r = sdprow[i];
362  c = sdpcol[i];
363  assert( fullmatrix[r * blocksize + c] == 0.0 );
364  assert( fullmatrix[c * blocksize + r] == 0.0 );
365  fullmatrix[r * blocksize + c] = sdpval[i];
366  fullmatrix[c * blocksize + r] = sdpval[i];
367  }
368 
369  /* check upper bound */
370  SCIP_CALL( SCIPoneVarFeasible(bufmem, blocksize, tmpmatrix, fullconstmatrix, fullmatrix, ub, &eigenvalue, eigenvector) );
371  SCIPdebugMessage("ub = %g, minimal eigenvalue: %g\n", ub, eigenvalue);
372 
373  /* if matrix is not psd */
374  if ( eigenvalue < -feastol )
375  {
376  /* compute supergradient value */
377  computeSupergradient(sdpnnonz, sdprow, sdpcol, sdpval, eigenvector, &supergradient);
378 
379  /* if supergradient is positive, then the problem is infeasible, because the minimal eigenvalue is increasing and we are not psd */
380  if ( supergradient > 0.0 )
381  {
382  SCIPdebugMessage("Problem is infeasible (minimal eigenvalue: %g, supergradient = %g).\n", eigenvalue, supergradient);
383  *objval = infinity;
384  *optval = ub;
385 
386  goto TERMINATE;
387  }
388  }
389 
390  /* otherwise check lower bound */
391  SCIP_CALL( SCIPoneVarFeasible(bufmem, blocksize, tmpmatrix, fullconstmatrix, fullmatrix, lb, &eigenvalue, eigenvector) );
392 
393  /* if matrix is psd, then the lower bound is optimal */
394  if ( eigenvalue >= -feastol )
395  {
396  SCIPdebugMessage("Lower bound is optimal.\n");
397  *objval = obj * lb;
398  *optval = lb;
399 
400  goto TERMINATE;
401  }
402  else
403  {
404  /* compute supergradient value */
405  computeSupergradient(sdpnnonz, sdprow, sdpcol, sdpval, eigenvector, &supergradient);
406 
407  /* if supergradient not positive, then the problem is infeasible because the eigenvalue is decreasing and we are not psd */
408  if ( supergradient <= 0.0 )
409  {
410  SCIPdebugMessage("Problem is infeasible (minimal eigenvalue: %g, supergradient: %g).\n", eigenvalue, supergradient);
411  *objval = infinity;
412  *optval = lb;
413 
414  goto TERMINATE;
415  }
416  }
417  assert( supergradient != SCIP_INVALID );
418  SCIPdebugMessage("lb = %g, minimal eigenvalue: %g, supergradient: %g\n", lb, eigenvalue, supergradient);
419 
420  /* Invariant of the loop: the lower bound is not psd and the supergradient is positive */
421  assert( eigenvector != NULL );
422  assert( eigenvalue < -feastol );
423  assert( supergradient > 0.0 );
424  mu = lb;
425  while ( eigenvalue < -feastol && supergradient > 0.0 )
426  {
427  assert( eigenvalue < -feastol );
428  assert( supergradient > 0.0 );
429 
430  /* Compute estimate based on where the supergradient would reach -feastol/2.0 based on the supergradient inequality
431  * f(mu) \leq f(muold) + (mu - muold) g. We use feastol/2.0 to avoid little rounding errors. */
432  mu = mu - (feastol / 2.0 + eigenvalue) / supergradient;
433 
434  /* Stop if we are larger than ub. In this case the problem is infeasible, since eigenvalue < -feastol by the while
435  * condition. Infeasibility is detected below. */
436  if ( mu > ub )
437  break;
438 
439  /* compute eigenvalue and eigenvector */
440  SCIP_CALL( SCIPoneVarFeasible(bufmem, blocksize, tmpmatrix, fullconstmatrix, fullmatrix, mu, &eigenvalue, eigenvector) );
441 
442  /* update supergradient */
443  computeSupergradient(sdpnnonz, sdprow, sdpcol, sdpval, eigenvector, &supergradient);
444 
445  SCIPdebugMessage("mu = %.15g in [%.15g, %.15g], minimal eigenvalue: %g, supergradient: %g.\n", mu, lb, ub, eigenvalue, supergradient);
446  }
447 
448  /* check whether we are infeasible */
449  if ( eigenvalue < -feastol )
450  {
451  SCIPdebugMessage("Problem infeasible; detected at %.15g in [%.15g, %.15g], minimal eigenvalue: %g, supergradient: %g.\n", mu, lb, ub, eigenvalue, supergradient);
452  *objval = infinity;
453  *optval = mu;
454  }
455  else
456  {
457  SCIPdebugMessage("Solution is %.15g in [%.15g, %.15g], minimal eigenvalue: %g, supergradient: %g.\n", mu, lb, ub, eigenvalue, supergradient);
458  *objval = obj * mu;
459  *optval = mu;
460  }
461 
462  TERMINATE:
463  BMSfreeBufferMemoryArray(bufmem, &eigenvector);
464  BMSfreeBufferMemoryArray(bufmem, &tmpmatrix);
465  BMSfreeBufferMemoryArray(bufmem, &fullmatrix);
466 
467  return SCIP_OKAY;
468 }
SCIP_RETCODE SCIPsolveOneVarSDP(BMS_BUFMEM *bufmem, SCIP_Real obj, SCIP_Real lb, SCIP_Real ub, int blocksize, int sdpconstnnonz, int *sdpconstrow, int *sdpconstcol, SCIP_Real *sdpconstval, int sdpnnonz, int *sdprow, int *sdpcol, SCIP_Real *sdpval, SCIP_Real infinity, SCIP_Real feastol, SCIP_Real *objval, SCIP_Real *optval)
SCIP_RETCODE SCIPsolveOneVarSDPDense(BMS_BUFMEM *bufmem, SCIP_Real obj, SCIP_Real lb, SCIP_Real ub, int blocksize, SCIP_Real *fullconstmatrix, int sdpnnonz, int *sdprow, int *sdpcol, SCIP_Real *sdpval, SCIP_Real infinity, SCIP_Real feastol, SCIP_Real *objval, SCIP_Real *optval)
#define BMS_CALL(x)
static SCIP_RETCODE SCIPoneVarFeasible(BMS_BUFMEM *bufmem, int blocksize, SCIP_Real *tmpmatrix, SCIP_Real *fullconstmatrix, SCIP_Real *fullmatrix, SCIP_Real alpha, SCIP_Real *eigenvalue, SCIP_Real *eigenvector)
Solve SDP with one variable.
interface methods for eigenvector computation and matrix multiplication using openblas ...
SCIP_RETCODE SCIPlapackComputeIthEigenvalue(BMS_BUFMEM *bufmem, SCIP_Bool geteigenvectors, int n, SCIP_Real *A, int i, SCIP_Real *eigenvalue, SCIP_Real *eigenvector)
static void computeSupergradient(int sdpnnonz, int *sdprow, int *sdpcol, SCIP_Real *sdpval, SCIP_Real *eigenvector, SCIP_Real *supergradient)