SCIP-SDP  3.2.0
objreader_sdpaind.cpp
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 
41 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
42 
43 #include "objreader_sdpaind.h"
44 
45 #include <cassert> // for assert
46 #include <cctype> // for isspace
47 #include <cstdio> // for printf
48 #include <cstdlib> // for abs /*lint !e10*//*lint !e129*/
49 #include <istream> // for istream, etc
50 #include <string> // for getline, string
51 
52 #include "BlockMemoryAllocator.h" // for BlockMemoryAllocator
53 #include "ScipStreamBuffer.h" // for ScipStreamBuffer
54 #include "scipsdp/cons_sdp.h" // for SCIPcreateConsSdp
55 
56 #include "scip/cons_linear.h" // for SCIPaddCoefLinear, etc
57 #include "scip/cons_indicator.h" // for SCIPcreateConsIndicatorLinCons
58 #include "scip/scip.h" // for SCIPinfinity, etc
59 
60 /* turn off lint warnings for whole file: */
61 /*lint --e{788,818}*/
62 
64 inline void drop_space(std::istream& line)
65 {
66  while ( std::isspace(line.peek()) || line.peek() == '(' || line.peek() == '{' || line.peek() == ')' || line.peek() == '}' || line.peek() == ',' )
67  {
68  (void) line.ignore(1);/*lint !e747*/
69  }
70 }
71 
73 inline void drop_rest_line(std::istream& s)
74 {
75  std::string tmp;
76  (void) std::getline(s, tmp);
77 }
78 
80 static
82  std::istream* file
83  )
84 {
85  char fst_col;
86  fst_col = (char) (*file).peek();
87  while (fst_col == '"' || fst_col == '*')
88  {
89  drop_rest_line(*file);
90  fst_col = (char) (*file).peek();
91  }
92 }
93 
95 static
96 SCIP_RETCODE dropSpaceNewlineError(
97  std::istream& line
98  )
99 {
100  if ( line.peek() == '\n' )
101  {
102  SCIPerrorMessage("Input File invalid, SDP/LP-block rows need to consist of five entries each, see data_format.txt.\n");
103  return SCIP_ERROR;
104  }
105 
106  while ( std::isspace(line.peek()) || line.peek() == '(' || line.peek() == '{' || line.peek() == ')' || line.peek() == '}' || line.peek() == ',' )
107  {
108  (void) line.ignore(1);/*lint !e747*/
109  if ( (char) line.peek() == '\n' )
110  {
111  SCIPerrorMessage("Input File invalid, SDP/LP-block rows need to consist of five entries each, see data_format.txt\n");
112  return SCIP_ERROR;
113  }
114  }
115  return SCIP_OKAY;
116 }
117 
119 static
120 SCIP_RETCODE checkForLineEnd(
121  std::istream& line
122  )
123 {
124  if ( line.peek() == '\n' || line.peek() == '"' || line.peek() == '*' || line.peek() == EOF )
125  return SCIP_OKAY;
126 
127  while ( std::isspace(line.peek()) || line.peek() == '(' || line.peek() == '{' || line.peek() == ')' || line.peek() == '}' || line.peek() == ',' )
128  {
129  (void) line.ignore(1);/*lint !e747*/
130 
131  if ( line.peek() == '\n' || line.peek() == '"' || line.peek() == '*' || line.peek() == EOF )
132  return SCIP_OKAY;
133  else if ( std::isspace(line.peek()) || line.peek() == '(' || line.peek() == '{' || line.peek() == ')' || line.peek() == '}' || line.peek() == ',' )
134  continue;
135  else
136  {
137  SCIPerrorMessage("Input File invalid, SDP/LP-block rows need to consist of five entries each, see data_format.txt\n");
138  return SCIP_ERROR;
139  }
140  }
141  return SCIP_OKAY;
142 }
143 
145 static
146 SCIP_RETCODE testDigit(
147  std::istream* file
148  )
149 {
150  if ( (! isdigit((*file).peek())) && (! ((*file).peek() == '-')) )
151  {
152  SCIPerrorMessage("Input File invalid, got character '%c', but only numerals allowed in SDP/LP-block rows, see data_format.txt\n", (*file).peek());
153  return SCIP_READERROR;
154  }
155 
156  return SCIP_OKAY;
157 }
158 
160 static
161 SCIP_RETCODE checkIndex(
162  const char* indexname,
163  int value,
164  int lb,
165  int ub
166  )
167 {
168  if ( value < lb )
169  {
170  SCIPerrorMessage("In an SDP/LP-block-line %s index %d was smaller than %d.\n", indexname, value, lb);
171  return SCIP_ERROR;
172  }
173  if ( value > ub )
174  {
175  SCIPerrorMessage("In an SDP/LP-block-line %s index %d was larger than given number of %ss %d.\n", indexname, value, indexname, ub);
176  return SCIP_ERROR;
177  }
178  return SCIP_OKAY;
179 }
180 
181 
182 namespace scip
183 {
192  SCIP_DECL_READERREAD(ObjReaderSDPAind::scip_read)
193  {/*lint --e{715}*/
194  int numvars; // Number of variables
195  int numblocks; // Number of all blocks (SDP + LP)
196  int numsdpblocks; // Number of SDP-blocks
197  int numlpblocks; // Number of LP-blocks
198  int alllpblocksize; // Size of all LP-blocks added
199  int* nvarnonz; // nblockvarnonz[i] gives the number of nonzeros for variable i
200 
201  assert( scip != NULL );
202  assert( filename != NULL );
203  assert( result != NULL );
204 
205  *result = SCIP_DIDNOTRUN;
206 
207  std::vector<int, BlockMemoryAllocator<int> > blockpattern =
208  std::vector<int, BlockMemoryAllocator<int> >(BlockMemoryAllocator<int>(scip)); // Vector with the sizes of all blocks
209  std::vector<SCIP_Real> object; // Objectivevector
210  std::vector<SDPBlock> blockstruct; // Blockstructure
211  LPBlock LPData; // LP Data
212  std::vector<bool> blockislp; // Is the block an LP block?
213  std::vector<int> intvars; // Indices of integer variables
214  std::vector<int> lp_block_num;
215  std::vector<int> lp_block_size;
216  int new_row_index;
217  bool lp_block_already_done;
218 
219  SCIP_FILE* scip_file = SCIPfopen(filename, "r");
220  if ( ! scip_file )
221  return SCIP_READERROR;
222 
223  // setup buffer
224  ScipStreamBuffer scip_buffer(scip, scip_file, true);
225 
226  // setup our stream from the new buffer
227  std::istream file(&scip_buffer);
228 
229  if ( ! file )
230  return SCIP_READERROR;
231  file.clear();
232 
233  dropComments(&file);
234 
235  // read numvar
236  drop_space(file);
237  file >> numvars;
238  if ( numvars < 0 )
239  {
240  SCIPerrorMessage("Number of variables is negative!\n");
241  return SCIP_READERROR;
242  }
243  drop_rest_line(file);
244 
245  dropComments(&file);
246 
247  // read numblocks
248  drop_space(file);
249  file >> numblocks;
250  if ( numblocks < 0 )
251  {
252  SCIPerrorMessage("Number of blocks is negative!\n");
253  return SCIP_READERROR;
254  }
255  drop_rest_line(file);
256 
257  numlpblocks = 0;
258  numsdpblocks = 0;
259  alllpblocksize = 0;
260 
261  dropComments(&file);
262 
263  // read block pattern
264  blockpattern = std::vector<int, BlockMemoryAllocator<int> >(numblocks, 0, BlockMemoryAllocator<int>(scip));
265  blockislp = std::vector<bool>(numblocks, false);/*lint !e747*//*lint !e732*/
266  lp_block_num = std::vector<int>(numblocks, 0);
267  lp_block_size = std::vector<int>(numblocks, 0);
268 
269  for (int j = 0; j < numblocks; ++j)
270  {
271  drop_space(file);
272  file >> blockpattern[j];/*lint !e747*//*lint !e732*/
273  if ( blockpattern[j] > 0 )/*lint !e747*//*lint !e732*/
274  {
275  numsdpblocks++;
276  blockstruct.push_back(SDPBlock(blockpattern[j]));/*lint !e747*//*lint !e732*/
277  }
278  else if ( blockpattern[j] < 0 )/*lint !e747*//*lint !e732*/
279  {
280  // LP block has a negative coefficient!
281  numlpblocks++;
282  alllpblocksize += abs(blockpattern[j]);/*lint !e747*//*lint !e732*/
283  blockislp[j] = true; /*lint !e747*//*lint !e732*//*lint !e1793*/
284  blockstruct.push_back(SDPBlock(0));
285  lp_block_num[j] = numlpblocks;/*lint !e747*//*lint !e732*/
286  lp_block_size[numlpblocks - 1] = abs(blockpattern[j]);/*lint !e747*//*lint !e732*/
287  }
288  else
289  SCIPwarningMessage(scip, "A blocklength 0 seems a bit odd, don't you think!\n");
290  }
291  assert(numblocks == numsdpblocks + numlpblocks);
292 
293  drop_rest_line(file);
294  drop_space(file);
295  dropComments(&file);
296 
297  // read objective
298  object = std::vector<SCIP_Real>(numvars, 0.0);/*lint !e747*//*lint !e732*/
299  for (int i = 0; i < numvars; ++i)
300  {
301  file >> object[i];/*lint !e747*//*lint !e732*/
302  drop_space(file);
303  }
304 
305  SCIPdebugMsg(scip, "Number of variables: %d \n", numvars);
306  SCIPdebugMsg(scip, "Number of blocks: %d \n", numblocks);
307  SCIPdebugMsg(scip, "Number of SDP-cones: %d\n", numsdpblocks);
308  SCIPdebugMsg(scip, "Number of LP-cones: %d\n", numlpblocks);
309 
310  // construct blocks
311 
312  // construct LP block
313  LPData.rows = std::vector<LProw>(alllpblocksize);/*lint !e747*//*lint !e732*/
314  LPData.numrows = alllpblocksize;
315  SCIPdebugMsg(scip, "Number of LP constraints: %d\n", alllpblocksize);
316 
317  std::string commentline;
318 
319  // read data
320  while ( ! file.eof() )
321  {
322  if ( file.peek() == '*' ) // comment
323  {
324  (void) std::getline(file, commentline);
325  if ( commentline.find("*INT") == 0 ) // if current line starts with *INT then go to Integer definitions
326  {
327  drop_space(file); // drop \newline
328  break;
329  }
330  else // usual comment line
331  {
332  drop_space(file);
333  }
334  }
335  else
336  {
337  int var_index, block_index; // block id
338  int row_index, col_index; // position in matrix
339  SCIP_Real val;
340 
341  drop_space(file);
342 
343  SCIP_CALL( testDigit(&file) );
344  file >> var_index;
345  SCIP_CALL( checkIndex("variable", var_index, 0, numvars) );
346  SCIP_CALL( dropSpaceNewlineError(file) );
347 
348  SCIP_CALL( testDigit(&file) );
349  file >> block_index;
350  SCIP_CALL( checkIndex("block", block_index, 1, numblocks) );
351  SCIP_CALL( dropSpaceNewlineError(file) );
352 
353  SCIP_CALL( testDigit(&file) );
354  file >> row_index;
355  SCIP_CALL( checkIndex("row", row_index, 1, (blockislp[block_index - 1] ? LPData.numrows : blockstruct[block_index - 1].blocksize)) );/*lint !e732*//*lint !e747*/
356  SCIP_CALL( dropSpaceNewlineError(file) );
357 
358  SCIP_CALL( testDigit(&file) );
359  file >> col_index;
360  SCIP_CALL( checkIndex("column", col_index, 1, (blockislp[block_index - 1] ? LPData.numrows : blockstruct[block_index - 1].blocksize)) );/*lint !e732*//*lint !e747*/
361  SCIP_CALL( dropSpaceNewlineError(file) );
362 
363  SCIP_CALL( testDigit(&file) );
364  file >> val;
365  SCIP_CALL( checkForLineEnd(file) );
366 
367  if ( SCIPisEQ(scip, val, 0.0) )
368  {
369  drop_rest_line(file);
370  drop_space(file);
371  continue;
372  }
373 
374  // sdp-block
375  if ( ! blockislp[block_index - 1] )/*lint !e732*//*lint !e747*/
376  {
377  if ( row_index < col_index )
378  {
379  int save_row = row_index;
380  row_index = col_index;
381  col_index = save_row;
382  }
383 
384  if ( var_index == 0 )
385  {
386  blockstruct[block_index - 1].constcolumns.push_back(col_index);/*lint !e732*//*lint !e747*/
387  blockstruct[block_index - 1].constrows.push_back(row_index);/*lint !e732*//*lint !e747*/
388  blockstruct[block_index - 1].constvalues.push_back(val);/*lint !e732*//*lint !e747*/
389  blockstruct[block_index - 1].constnum_nonzeros++;/*lint !e732*//*lint !e747*/
390  }
391  else
392  {
393  blockstruct[block_index - 1].columns.push_back(col_index);/*lint !e732*//*lint !e747*/
394  blockstruct[block_index - 1].rows.push_back(row_index);/*lint !e732*//*lint !e747*/
395  blockstruct[block_index - 1].values.push_back(val);/*lint !e732*//*lint !e747*/
396  blockstruct[block_index - 1].variables.push_back(var_index);/*lint !e732*//*lint !e747*/
397  blockstruct[block_index - 1].num_nonzeros++;/*lint !e732*//*lint !e747*/
398  }
399  SCIPdebugMsg(scip, "SDP entry: block_index: %d, row: %d, col: %d, var: %d, val: %g\n", block_index, row_index, col_index, var_index,val );/*lint !e525*/
400  }
401  // lp-block
402  else if ( blockislp[block_index - 1] )/*lint !e732*//*lint !e747*/
403  {
404  assert( row_index == col_index );
405  if ( lp_block_num[block_index - 1] == 1 ) /*lint !e732*//*lint !e747*/
406  new_row_index = row_index - 1;
407  else // we combine all lp blocks to a single one, so we add the total number of rows of earlier blocks to the row index
408  {
409  int rowoffset = 0;
410 
411  for (int b = 0; b < lp_block_num[block_index - 1] - 1; b++) /*lint !e732*//*lint !e747*/
412  rowoffset += lp_block_size[b]; /*lint !e732*//*lint !e747*/
413 
414  new_row_index = rowoffset + row_index - 1;
415  }
416  LPData.rows[new_row_index].data.push_back(std::make_pair(var_index, val));/*lint !e732*//*lint !e747*/
417  SCIPdebugMsg(scip, "LP entry: row: %d, var: %d, val: %g\n", new_row_index, var_index,val );
418  }
419 
420  drop_rest_line(file);
421  drop_space(file);
422  }
423  }
424 
425  // read integer variables
426  intvars = std::vector<int>(numvars, 0);
427 
428  std::string str;
429  (void) std::getline(file, str);
430  while ( str[0] == '*' && isdigit(str[1]) )
431  {
432  // get index of integer variable
433  int idx;
434  (void) str.erase(0, 1); /*lint !e747*/
435  idx = atoi(str.c_str());
436  SCIP_CALL( checkIndex("variable", idx, 1, numvars) );
437 
438  // in the SDPA-file the variable numbers start at 1!
439  intvars[idx - 1] = 1; /*lint !e732*//*lint !e747*/
440  SCIPdebugMsg(scip, "Variable %d is integer.\n", idx - 1);
441 
442  (void) std::getline(file, str);
443  }
444 
445  /************************/
446  /* create empty problem */
447  /************************/
448 
449  SCIP_CALL( SCIPcreateProb(scip, filename, 0, 0, 0, 0, 0, 0, 0) );
450 
451  /*****************/
452  /* add variables */
453  /*****************/
454 
455  std::vector<SCIP_VAR*> VariablesX ( numvars );/*lint !e732*//*lint !e747*/
456 
457  for (int i = 0; i < numvars; ++i)
458  {
459  SCIP_VAR* var;
460  char var_name[SCIP_MAXSTRLEN];
461 #ifndef NDEBUG
462  int snprintfreturn = SCIPsnprintf(var_name, SCIP_MAXSTRLEN, "X_%d", i);
463  assert( snprintfreturn < SCIP_MAXSTRLEN);
464 #else
465  (void) SCIPsnprintf(var_name, SCIP_MAXSTRLEN, "X_%d", i);
466 #endif
467 
468  if ( intvars[i] == 1 )/*lint !e732*//*lint !e747*/
469  {
470  SCIP_CALL( SCIPcreateVar(scip, &var, var_name, -SCIPinfinity(scip), SCIPinfinity(scip), object[i], SCIP_VARTYPE_INTEGER, TRUE, FALSE, 0, 0, 0, 0, 0));/*lint !e732*//*lint !e747*/
471  }
472  else
473  {
474  SCIP_CALL( SCIPcreateVar(scip, &var, var_name, -SCIPinfinity(scip), SCIPinfinity(scip), object[i],
475  SCIP_VARTYPE_CONTINUOUS, TRUE, FALSE, 0, 0, 0, 0, 0));/*lint !e732*//*lint !e747*/
476  }
477 
478  SCIP_CALL( SCIPaddVar(scip, var) );
479  VariablesX[i] = var;/*lint !e732*//*lint !e747*/
480 
481  /* release variable for the reader. */
482  SCIP_CALL( SCIPreleaseVar(scip, &var) );
483  }
484 
485 
486  /*********************************/
487  /* create SDP and LP constraints */
488  /*********************************/
489 
490  lp_block_already_done = false;
491  for (int bindex = 0; bindex < numblocks; ++bindex)
492  {
493  if ( ! blockislp[bindex] )/*lint !e732*//*lint !e747*/
494  {
495  int nvars;
496  int nnonz;
497  int blocksize;
498  int* varind; /* this is used to sort the nonzeroes by variable-indices and check which variables are actually included in this block */
499  int* col;
500  int* row;
501  SCIP_Real* val;
502  int** colpointer;
503  int** rowpointer;
504  SCIP_Real** valpointer;
505  SCIP_Var** vars;
506  int constnnonz;
507  int* constcol;
508  int* constrow;
509  SCIP_Real* constval;
510  int k;
511  int ind;
512  int nextindaftervar;
513  int firstindforvar;
514  SCIP_Bool varused;
515 
516  SCIPdebugMsg(scip, "Begin construction of SDP constraint for block %d.\n", bindex);
517 
518  blocksize = blockpattern[bindex];/*lint !e732*//*lint !e747*/
519  nnonz = blockstruct[bindex].num_nonzeros;/*lint !e732*//*lint !e747*/
520  ind = 0;
521 
522  /* allocate memory */
523  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &varind, blockstruct[bindex].num_nonzeros) );/*lint !e732*//*lint !e530*/
524  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &col, blockstruct[bindex].num_nonzeros) );/*lint !e732*//*lint !e530*/
525  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &row, blockstruct[bindex].num_nonzeros) );/*lint !e732*//*lint !e530*/
526  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &val, blockstruct[bindex].num_nonzeros) );/*lint !e732*//*lint !e530*/
527  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &colpointer, numvars) );/*lint !e732*//*lint !e530*/
528  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &rowpointer, numvars) );/*lint !e732*//*lint !e530*/
529  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &valpointer, numvars) );/*lint !e732*//*lint !e530*/
530  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &vars, numvars) );/*lint !e732*//*lint !e530*/
531 
532  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &constcol, blockstruct[bindex].constnum_nonzeros) );/*lint !e732*//*lint !e530*/
533  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &constrow, blockstruct[bindex].constnum_nonzeros) );/*lint !e732*//*lint !e530*/
534  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &constval, blockstruct[bindex].constnum_nonzeros) );/*lint !e732*//*lint !e530*/
535 
536  /* allocate memory for nblockvarnonz & initialize it with zero */
537  SCIP_CALL(SCIPallocBlockMemoryArray(scip, &nvarnonz, numvars));/*lint !e530*/
538  for (int i = 0; i < numvars; i++)
539  nvarnonz[i] = 0;
540 
541  /* prepare the constant arrays */
542  for (k = 0; k < blockstruct[bindex].constnum_nonzeros; ++k)/*lint !e732*//*lint !e747*/
543  {
544  if ( ! SCIPisZero(scip, blockstruct[bindex].constvalues[k]) )/*lint !e732*//*lint !e747*/
545  {
546  constcol[ind] = blockstruct[bindex].constcolumns[k] - 1;/*lint !e732*//*lint !e747*/ /* the sdpa format counts from 1 to blocksize, we want to start from 0 */
547  constrow[ind] = blockstruct[bindex].constrows[k] - 1;/*lint !e732*//*lint !e747*/
548  constval[ind] = blockstruct[bindex].constvalues[k];/*lint !e732*//*lint !e747*/
549  ind++;
550  }
551  }
552  constnnonz = ind;
553 
554  /* prepare the non-constant arrays */
555  ind = 0;
556  for (k = 0; k < nnonz; ++k)
557  {
558  if ( ! SCIPisZero(scip, blockstruct[bindex].values[k]) )/*lint !e732*//*lint !e747*/
559  {
560  varind[ind] = blockstruct[bindex].variables[k] - 1;/*lint !e732*//*lint !e747*/
561  col[ind] = blockstruct[bindex].columns[k] - 1;/*lint !e732*//*lint !e747*/
562  row[ind] = blockstruct[bindex].rows[k] - 1;/*lint !e732*//*lint !e747*/
563  val[ind] = blockstruct[bindex].values[k];/*lint !e732*//*lint !e747*/
564  ind++;
565  }
566  }
567  nnonz = ind;
568 
569  SCIPsortIntIntIntReal(varind, col, row, val, nnonz); /* sort the nonzeroes by non-decreasing variable indices */
570 
571  /* create the pointer arrays and insert used variables into vars-array */
572  nextindaftervar = 0;
573  ind = 0; /* sdp index of the current variable */
574  for (k = 0; k < numvars; k++)
575  {
576  varused = FALSE;
577  firstindforvar = nextindaftervar; /* this variable starts where the last one ended */
578  while ( nextindaftervar < nnonz && varind[nextindaftervar] == k ) /* get the first index that doesn't belong to this variable */
579  {
580  nextindaftervar++;
581  varused = TRUE;
582  nvarnonz[ind]++;
583  }
584  if (varused)
585  {
586  vars[ind] = VariablesX[k];/*lint !e732*//*lint !e747*/ /* if the variable is used, add it to the vars array */
587  colpointer[ind] = &col[firstindforvar]; /* save a pointer to the first nonzero belonging to this variable */
588  rowpointer[ind] = &row[firstindforvar];
589  valpointer[ind] = &val[firstindforvar];
590  ind++;
591  }
592  }
593 
594  assert (nextindaftervar == nnonz);
595 
596  /* this was only needed to compute the vars arrays */
597  SCIPfreeBlockMemoryArray(scip, &varind, blockstruct[bindex].num_nonzeros);/*lint !e747*/
598 
599  nvars = ind;
600 
601  SCIP_CONS* sdpcon;
602  char sdpcon_name[SCIP_MAXSTRLEN];
603 #ifndef NDEBUG
604  int snprintfreturn = SCIPsnprintf(sdpcon_name, SCIP_MAXSTRLEN, "SDP-Constraint-%d", bindex);
605  assert( snprintfreturn < SCIP_MAXSTRLEN);
606 #else
607  (void) SCIPsnprintf(sdpcon_name, SCIP_MAXSTRLEN, "SDP-Constraint-%d", bindex);
608 #endif
609  SCIP_CALL( SCIPcreateConsSdp(scip, &sdpcon, sdpcon_name, nvars, nnonz, blocksize, nvarnonz, colpointer,
610  rowpointer, valpointer, vars, constnnonz, constcol, constrow, constval) );
611 
612 #ifdef SCIP_MORE_DEBUG
613  SCIP_CALL( SCIPprintCons(scip, sdpcon, NULL) );
614 #endif
615 
616  SCIP_CALL( SCIPaddCons(scip, sdpcon) );
617 
618  SCIP_CALL( SCIPreleaseCons(scip, &sdpcon) );
619 
620  /* free the used arrays */
621  SCIPfreeBlockMemoryArray(scip, &nvarnonz, numvars);
622  SCIPfreeBlockMemoryArray(scip, &constval, blockstruct[bindex].constnum_nonzeros);/*lint !e747*/
623  SCIPfreeBlockMemoryArray(scip, &constrow, blockstruct[bindex].constnum_nonzeros);/*lint !e747*/
624  SCIPfreeBlockMemoryArray(scip, &constcol, blockstruct[bindex].constnum_nonzeros);/*lint !e747*/
625  SCIPfreeBlockMemoryArray(scip, &vars, numvars);
626  SCIPfreeBlockMemoryArray(scip, &valpointer, numvars);
627  SCIPfreeBlockMemoryArray(scip, &rowpointer, numvars);
628  SCIPfreeBlockMemoryArray(scip, &colpointer, numvars);
629  SCIPfreeBlockMemoryArray(scip, &val, blockstruct[bindex].num_nonzeros);/*lint !e747*/
630  SCIPfreeBlockMemoryArray(scip, &row, blockstruct[bindex].num_nonzeros);/*lint !e747*/
631  SCIPfreeBlockMemoryArray(scip, &col, blockstruct[bindex].num_nonzeros);/*lint !e747*/
632 
633  SCIPdebugMsg(scip, "Construction of SDP constraint for block %d completed.\n", bindex);
634  }
635  else
636  {
637  // construct lp-block only once
638  if ( ! lp_block_already_done )
639  {
640  int nindconss = 0;
641 
642  lp_block_already_done = true;
643  SCIPdebugMsg(scip, "Begin construction of LP (block %d).\n", bindex);
644 
645  for (int row_i = 0; row_i < LPData.numrows; ++row_i)
646  {
647  SCIP_CONS* LPcon;
648  char LPcon_name[SCIP_MAXSTRLEN];
649  int indicator = 0;
650 #ifndef NDEBUG
651  int snprintfreturn = SCIPsnprintf(LPcon_name, SCIP_MAXSTRLEN, "LP-Con-%d", row_i);
652  assert( snprintfreturn < SCIP_MAXSTRLEN );
653 #else
654  (void) SCIPsnprintf(LPcon_name, SCIP_MAXSTRLEN, "LP-Con-%d", row_i);
655 #endif
656 
657  // Get right hand side of the constraint
658  SCIP_Real LPlhs = 0.0;
659  for (unsigned int var_i = 0; var_i < LPData.rows[row_i].data.size(); ++var_i)/*lint !e732*//*lint !e747*/
660  {
661  if (LPData.rows[row_i].data[var_i].first == 0)/*lint !e732*//*lint !e747*/
662  {
663  LPlhs = LPData.rows[row_i].data[var_i].second;/*lint !e732*//*lint !e747*/
664  }
665  }
666 
667  /* check for indicator constraint */
668  for (unsigned int var_i = 0; var_i < LPData.rows[row_i].data.size(); ++var_i)/*lint !e732*//*lint !e747*/
669  {
670  if (LPData.rows[row_i].data[var_i].first < 0)/*lint !e732*//*lint !e747*/
671  indicator++;
672  }
673 
674  if ( indicator == 0 )
675  {
676  /* regular linear constraint */
677 
678  //Create constraint
679  SCIP_CALL( SCIPcreateConsLinear(scip, &LPcon, LPcon_name, 0, 0, 0, LPlhs, SCIPinfinity(scip), TRUE, TRUE,
680  TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE));
681 
682  SCIP_CALL( SCIPaddCons(scip, LPcon) );
683 
684  //Insert variables into constraint:
685  for (unsigned int var_i = 0; var_i < LPData.rows[row_i].data.size(); ++var_i)/*lint !e732*//*lint !e747*/
686  {
687  if (LPData.rows[row_i].data[var_i].first != 0)/*lint !e732*//*lint !e747*/
688  {
689  SCIP_CALL( SCIPaddCoefLinear(scip, LPcon, VariablesX[LPData.rows[row_i].data[var_i].first - 1], LPData.rows[row_i].data[var_i].second) );/*lint !e732*//*lint !e747*/
690  }
691  }
692  #ifdef SCIP_MORE_DEBUG
693  SCIP_CALL( SCIPprintCons(scip, LPcon, NULL) );
694  #endif
695  SCIP_CALL( SCIPreleaseCons(scip, &LPcon) );
696  }
697  else
698  {
699  SCIP_VAR* indvar = 0;
700  SCIP_VAR* slackvar = 0;
701  SCIP_CONS* indcons;
702  char cons_name[SCIP_MAXSTRLEN];
703 
704 #ifndef NDEBUG
705  snprintfreturn = SCIPsnprintf(cons_name, SCIP_MAXSTRLEN, "cons_indicator_%d", nindconss);
706  assert( snprintfreturn < SCIP_MAXSTRLEN);
707 #else
708  (void) SCIPsnprintf(cons_name, SCIP_MAXSTRLEN, "cons_indicator_%d", nindconss);
709 #endif
710 
711  /* indicator constraint */
712 
713  /* each indicator constraint should only have a single indicator variable */
714  assert( indicator <= 1 );
715 
716  //Create constraint
717  SCIP_CALL( SCIPcreateConsLinear(scip, &LPcon, LPcon_name, 0, 0, 0, LPlhs, SCIPinfinity(scip), TRUE, TRUE,
718  TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE));
719 
720  //Insert variables into constraint:
721  for (unsigned int var_i = 0; var_i < LPData.rows[row_i].data.size(); ++var_i)/*lint !e732*//*lint !e747*/
722  {
723  if ( LPData.rows[row_i].data[var_i].first > 0 )/*lint !e732*//*lint !e747*/
724  {
725  SCIP_CALL( SCIPaddCoefLinear(scip, LPcon, VariablesX[LPData.rows[row_i].data[var_i].first - 1], LPData.rows[row_i].data[var_i].second) );/*lint !e732*//*lint !e747*/
726  }
727  else if ( LPData.rows[row_i].data[var_i].first < 0 )/*lint !e732*//*lint !e747*/
728  {
729  char var_name[SCIP_MAXSTRLEN];
730  SCIP_Bool infeasible;
731 #ifndef NDEBUG
732  snprintfreturn = SCIPsnprintf(var_name, SCIP_MAXSTRLEN, "s_%d", nindconss);
733  assert( snprintfreturn < SCIP_MAXSTRLEN);
734 #else
735  (void) SCIPsnprintf(var_name, SCIP_MAXSTRLEN, "s_%d", nindconss);
736 #endif
737  nindconss++;
738 
739  /* Store indvar, note that we need to make it binary now, since otherwise the indicator constraint handler
740  * will throw an assert later and we cannot verify that it is binary now, so we print a warning. */
741  indvar = VariablesX[-1 * LPData.rows[row_i].data[var_i].first - 1];
742 #ifdef SCIP_WARN_INDICATOR
743  SCIPwarningMessage(scip, "Changing type of variable %s to binary, since it appears as an indicator variable "
744  "in constraint %s\n", SCIPvarGetName(indvar), LPcon_name);
745 #endif
746  assert( SCIPvarIsIntegral( VariablesX[-1 * LPData.rows[row_i].data[var_i].first - 1] ) );
747  SCIP_CALL( SCIPchgVarLbGlobal(scip, indvar, 0.0) );
748  SCIP_CALL( SCIPchgVarUbGlobal(scip, indvar, 1.0) );
749  SCIP_CALL( SCIPchgVarType(scip, indvar, SCIP_VARTYPE_BINARY, &infeasible) );
750 
751  /* create slack variable and add it to the constraint*/
752  SCIP_CALL( SCIPcreateVar(scip, &slackvar, var_name, 0.0, SCIPinfinity(scip), 0.0, SCIP_VARTYPE_CONTINUOUS, TRUE, FALSE, 0, 0, 0, 0, 0));/*lint !e732*//*lint !e747*/
753 
754  SCIP_CALL( SCIPaddVar(scip, slackvar) );
755 
756  /* slack variable has coefficient +1 since we have a >= 0 constraint */
757  SCIP_CALL( SCIPaddCoefLinear(scip, LPcon, slackvar, +1.0) );/*lint !e732*//*lint !e747*/
758  }
759  }
760 
761  /* add constraint */
762  assert( indvar != 0 );
763  assert( slackvar != 0 );
764  SCIP_CALL( SCIPcreateConsIndicatorLinCons( scip, &indcons, cons_name, indvar, LPcon, slackvar,
765  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
766  SCIP_CALL( SCIPaddCons(scip, LPcon) );
767  SCIP_CALL( SCIPaddCons(scip, indcons) );
768 
769 #ifdef SCIP_MORE_DEBUG
770  SCIP_CALL( SCIPprintCons(scip, indcons, NULL) );
771 #endif
772 
773  /* release both conss and the slackvar */
774  SCIP_CALL( SCIPreleaseCons(scip, &indcons) );
775  SCIP_CALL( SCIPreleaseVar(scip, &slackvar) );
776  SCIP_CALL( SCIPreleaseCons(scip, &LPcon) );
777  }
778  }
779  }
780  }
781  }
782 
783  *result = SCIP_SUCCESS;
784 
785  return SCIP_OKAY;
786  }
787 
788 }//end of namespace scip
static void dropComments(std::istream *file)
SCIP_DECL_READERREAD(ObjReaderSDPA::scip_read)
An STL allocator class using SCIP block memory.
An std::streambuf that uses SCIP I/O routines (suitable for reading)
static SCIP_RETCODE checkIndex(const char *indexname, int value, int lb, int ub)
Reader for SDPA-Files with indicator constraints (-var in linear constraint => indicator constraint w...
static SCIP_RETCODE dropSpaceNewlineError(std::istream &line)
std::vector< LProw > rows
static SCIP_RETCODE checkForLineEnd(std::istream &line)
void drop_space(std::istream &line)
Constraint handler for SDP-constraints.
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:5150
static SCIP_RETCODE testDigit(std::istream *file)
void drop_rest_line(std::istream &s)