Scippy

SCIP

Solving Constraint Integer Programs

reader_bnd.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (c) 2002-2024 Zuse Institute Berlin (ZIB) */
7 /* */
8 /* Licensed under the Apache License, Version 2.0 (the "License"); */
9 /* you may not use this file except in compliance with the License. */
10 /* You may obtain a copy of the License at */
11 /* */
12 /* http://www.apache.org/licenses/LICENSE-2.0 */
13 /* */
14 /* Unless required by applicable law or agreed to in writing, software */
15 /* distributed under the License is distributed on an "AS IS" BASIS, */
16 /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17 /* See the License for the specific language governing permissions and */
18 /* limitations under the License. */
19 /* */
20 /* You should have received a copy of the Apache-2.0 license */
21 /* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22 /* */
23 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24 
25 /**@file reader_bnd.c
26  * @ingroup DEFPLUGINS_READER
27  * @brief file reader for variable bounds
28  * @author Ambros Gleixner
29  * @author Ingmar Vierhaus
30  * @author Benjamin Mueller
31  *
32  * This reader allows to read a file containing new bounds for variables of the current problem. Each line of the file
33  * should have format
34  *
35  * <variable name> <lower bound> <upper bound>
36  *
37  * where infinite bounds can be written as inf, +inf or -inf. Note that only a subset of the variables may appear in
38  * the file. Lines with unknown variable names are ignored.
39  * The writing functionality can be used in problem and transformed stages. Note that in transformed stage,
40  * the leading "t_" in the name of a transformed variable will not appear in the output. This way, bounds written in transformed stage
41  * can be read again in problem stage.
42  */
43 
44 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
45 
46 #include "scip/pub_fileio.h"
47 #include "scip/pub_message.h"
48 #include "scip/pub_misc.h"
49 #include "scip/pub_reader.h"
50 #include "scip/pub_var.h"
51 #include "scip/reader_bnd.h"
52 #include "scip/scip_general.h"
53 #include "scip/scip_mem.h"
54 #include "scip/scip_message.h"
55 #include "scip/scip_numerics.h"
56 #include "scip/scip_param.h"
57 #include "scip/scip_reader.h"
58 #include "scip/scip_var.h"
59 #include <string.h>
60 
61 #if !defined(_WIN32) && !defined(_WIN64)
62 #include <strings.h> /*lint --e{766}*/ /* needed for strncasecmp() */
63 #endif
64 
65 
66 #define READER_NAME "bndreader"
67 #define READER_DESC "file reader for variable bounds"
68 #define READER_EXTENSION "bnd"
69 
70 #define DEFAULT_IMPROVEONLY FALSE /**< only use improving bounds */
71 
72 
73 /** BND reader data */
74 struct SCIP_ReaderData
75 {
76  SCIP_Bool improveonly; /**< only use improving bounds */
77 };
78 
79 
80 /*
81  * Local methods of reader
82  */
83 
84 /** reads a given bound file, problem has to be in problem stage */
85 static
87  SCIP* scip, /**< SCIP data structure */
88  const char* fname, /**< name of the input file */
89  SCIP_READERDATA* readerdata /**< pointer to the data of the reader */
90  )
91 {
92  SCIP_RETCODE retcode;
93  SCIP_FILE* file;
94  SCIP_Bool error;
95  SCIP_Bool unknownvariablemessage;
96  SCIP_Bool usevartable;
97  int lineno;
98 
99  assert(scip != NULL);
100  assert(fname != NULL);
101 
102  SCIP_CALL( SCIPgetBoolParam(scip, "misc/usevartable", &usevartable) );
103 
104  if( !usevartable )
105  {
106  SCIPerrorMessage("Cannot read bounds file if vartable is disabled. Make sure parameter 'misc/usevartable' is set to TRUE.\n");
107  return SCIP_READERROR;
108  }
109 
110  /* open input file */
111  file = SCIPfopen(fname, "r");
112  if( file == NULL )
113  {
114  SCIPerrorMessage("cannot open file <%s> for reading\n", fname);
115  SCIPprintSysError(fname);
116  return SCIP_NOFILE;
117  }
118 
119  /* read the file */
120  error = FALSE;
121  unknownvariablemessage = FALSE;
122  lineno = 0;
123  while( !SCIPfeof(file) && !error )
124  {
125  char buffer[SCIP_MAXSTRLEN];
126  char varname[SCIP_MAXSTRLEN];
127  char lbstring[SCIP_MAXSTRLEN];
128  char ubstring[SCIP_MAXSTRLEN];
129  char format[SCIP_MAXSTRLEN];
130  SCIP_VAR* var;
131  SCIP_Real lb;
132  SCIP_Real ub;
133  int nread;
134  char* endptr;
135 
136  /* get next line */
137  if( SCIPfgets(buffer, (int) sizeof(buffer), file) == NULL )
138  break;
139  lineno++;
140 
141  /* parse the line */
142  (void) SCIPsnprintf(format, SCIP_MAXSTRLEN, "%%%ds %%%ds %%%ds\n", SCIP_MAXSTRLEN, SCIP_MAXSTRLEN, SCIP_MAXSTRLEN);
143  (void) sscanf(buffer, format, varname, lbstring, ubstring);
144 
145  retcode = SCIPparseVarName(scip, buffer, &var, &endptr);
146  if( retcode != SCIP_OKAY )
147  {
148  SCIPerrorMessage("Error parsing variable name in line %d of bounds file <%s>\n", lineno, fname);
149  error = TRUE;
150  break;
151  }
152 
153  (void) SCIPsnprintf(format, SCIP_MAXSTRLEN, "%%%ds %%%ds\n", SCIP_MAXSTRLEN, SCIP_MAXSTRLEN);
154  nread = sscanf(endptr, format, lbstring, ubstring);
155  if( nread < 1 )
156  {
157  SCIPerrorMessage("invalid input line %d in bounds file <%s>: <%s>\n", lineno, fname, buffer);
158  error = TRUE;
159  break;
160  }
161 
162  if( var == NULL )
163  {
164  if( !unknownvariablemessage )
165  {
166  SCIPwarningMessage(scip, "unable to parse variable name in line %d of bounds file <%s>:\n", lineno, fname);
167  SCIPwarningMessage(scip, "line is: %s", buffer);
168  SCIPwarningMessage(scip, " (further unknown variables are ignored)\n");
169  unknownvariablemessage = TRUE;
170  }
171  continue;
172  }
173 
174  /* cast the lower bound value */
175  if( strncasecmp(lbstring, "inv", 3) == 0 )
176  continue;
177  else if( strncasecmp(lbstring, "+inf", 4) == 0 || strncasecmp(lbstring, "inf", 3) == 0 )
178  lb = SCIPinfinity(scip);
179  else if( strncasecmp(lbstring, "-inf", 4) == 0 )
180  lb = -SCIPinfinity(scip);
181  else
182  {
183  nread = sscanf(lbstring, "%lf", &lb);
184  if( nread != 1 )
185  {
186  SCIPerrorMessage("invalid lower bound value <%s> for variable <%s> in line %d of bounds file <%s>\n",
187  lbstring, varname, lineno, fname);
188  error = TRUE;
189  break;
190  }
191  }
192 
193  /* cast the upper bound value */
194  if( strncasecmp(ubstring, "inv", 3) == 0 )
195  continue;
196  else if( strncasecmp(ubstring, "+inf", 4) == 0 || strncasecmp(ubstring, "inf", 3) == 0 )
197  ub = SCIPinfinity(scip);
198  else if( strncasecmp(ubstring, "-inf", 4) == 0 )
199  ub = -SCIPinfinity(scip);
200  else
201  {
202  /* coverity[secure_coding] */
203  nread = sscanf(ubstring, "%lf", &ub);
204  if( nread != 1 )
205  {
206  SCIPerrorMessage("invalid lower bound value <%s> for variable <%s> in line %d of bounds file <%s>\n",
207  ubstring, varname, lineno, fname);
208  error = TRUE;
209  break;
210  }
211  }
212 
213  if( readerdata->improveonly )
214  {
215  if( SCIPisLT(scip, lb, SCIPvarGetLbGlobal(var)) )
216  {
217  SCIPwarningMessage(scip, "not applying lower bound value %s for variable <%s> in line %d of bounds file %s,"
218  " because it does not improve existing bound of %f\n",
219  lbstring, SCIPvarGetName(var), lineno, fname, SCIPvarGetLbGlobal(var));
220  }
221  if( SCIPisGT(scip, ub, SCIPvarGetUbGlobal(var)) )
222  {
223  SCIPwarningMessage(scip, "not applying upper bound value %s for variable <%s> in line %d of bounds file %s, "
224  "because it does not improve existing bound of %f\n",
225  ubstring, SCIPvarGetName(var), lineno, fname, SCIPvarGetUbGlobal(var));
226  }
227 
228  /* collect best variable bounds */
229  lb = MAX(lb, SCIPvarGetLbGlobal(var)); /*lint !e666*/
230  ub = MIN(ub, SCIPvarGetUbGlobal(var)); /*lint !e666*/
231  }
232 
233  /* note that we don't need to check if lb > ub in SCIPchgVar{Lb,Ub} */
234  retcode = SCIPchgVarLb(scip, var, lb);
235  if( retcode != SCIP_OKAY )
236  {
237  SCIPerrorMessage("Error changing lower bound for variable <%s> in line %d of bounds file <%s>\n", varname, lineno, fname);
238  error = TRUE;
239  break;
240  }
241 
242  retcode = SCIPchgVarUb(scip, var, ub);
243  if( retcode != SCIP_OKAY )
244  {
245  SCIPerrorMessage("Error changing upper bound for variable <%s> in line %d of bounds file <%s>\n", varname, lineno, fname);
246  error = TRUE;
247  break;
248  }
249  }
250 
251  /* close input file */
252  SCIPfclose(file);
253 
254  /* return error if necessary */
255  if ( error )
256  return SCIP_READERROR;
257 
258  return SCIP_OKAY;
259 }
260 
261 
262 /*
263  * Callback methods of reader
264  */
265 
266 /** copy method for reader plugins (called when SCIP copies plugins) */
267 static
268 SCIP_DECL_READERCOPY(readerCopyBnd)
269 { /*lint --e{715}*/
270  assert(scip != NULL);
271  assert(reader != NULL);
272  assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0);
273 
274  /* call inclusion method of reader */
276 
277  return SCIP_OKAY;
278 }
279 
280 
281 /** problem reading method of reader
282  *
283  * In order to determine the type of the file, we have to open it. Thus, it has to be opened
284  * twice. This might be removed, but is likely to not hurt the performance too much.
285  */
286 static
287 SCIP_DECL_READERREAD(readerReadBnd)
288 { /*lint --e{715}*/
289  assert(reader != NULL);
290  assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0);
291  assert(result != NULL);
292 
293  *result = SCIP_DIDNOTRUN;
294 
296  {
297  SCIPerrorMessage("reading of bounds file is only possible after a problem was created\n");
298  return SCIP_READERROR;
299  }
300 
302  {
303  SCIPerrorMessage("reading of bounds file is only possible during problem creation stage\n");
304  return SCIP_READERROR;
305  }
306 
307  /* read bounds file */
308  SCIP_CALL( readBounds(scip, filename, SCIPreaderGetData(reader)) );
309 
310  *result = SCIP_SUCCESS;
311 
312  return SCIP_OKAY;
313 }
314 
315 /** outputs given bounds into a file stream */
316 static
318  SCIP* scip, /**< SCIP data structure */
319  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
320  FILE* file, /**< file stream to print into, or NULL for stdout */
321  SCIP_Real lb, /**< lower bound */
322  SCIP_Real ub /**< upper bound */
323  )
324 {
325  /* print lower bound */
326  if( SCIPisInfinity(scip, lb) )
327  SCIPmessageFPrintInfo(messagehdlr, file, "+inf ");
328  else if( SCIPisInfinity(scip, -lb) )
329  SCIPmessageFPrintInfo(messagehdlr, file, "-inf ");
330  else
331  SCIPmessageFPrintInfo(messagehdlr, file, "%.15" SCIP_REAL_FORMAT " ", lb);
332 
333  /* print upper bound */
334  if( SCIPisInfinity(scip, ub) )
335  SCIPmessageFPrintInfo(messagehdlr, file, "+inf");
336  else if( SCIPisInfinity(scip, -ub) )
337  SCIPmessageFPrintInfo(messagehdlr, file, "-inf");
338  else
339  SCIPmessageFPrintInfo(messagehdlr, file, "%.15" SCIP_REAL_FORMAT, ub);
340 }
341 
342 /** writes problem to file */
343 static
345  SCIP* scip, /**< SCIP data structure */
346  FILE* file, /**< file stream to print into, or NULL for stdout */
347  SCIP_VAR** vars, /**< array with active variables ordered binary, integer, implicit, continuous */
348  int nvars, /**< number of active variables in the problem */
349  SCIP_RESULT* result /**< pointer to store the result of the file writing call */
350  )
351 {
352  SCIP_MESSAGEHDLR* messagehdlr;
353  SCIP_Real lb;
354  SCIP_Real ub;
355  int i;
356 
357  assert(result != NULL);
358 
359  messagehdlr = SCIPgetMessagehdlr(scip);
360  *result = SCIP_SUCCESS;
361 
362  if( nvars == 0 )
363  {
364  SCIPwarningMessage(scip, "Problem has no variables, no bounds written.\n");
365  return SCIP_OKAY;
366  }
367 
368  for( i = 0; i < nvars; ++i )
369  {
370  SCIP_VAR* var;
371  const char* varname;
372 
373  var = vars[i];
374  assert( var != NULL );
375  varname = SCIPvarGetName(var);
376 
377  /* strip 't_' from varname */
378  if( SCIPvarIsTransformedOrigvar(var) && strncmp(SCIPvarGetName(var), "t_", 2) == 0)
379  {
380  varname = varname + 2;
381  }
382 
383  SCIPinfoMessage(scip, file, "<%s> ", varname);
384 
385  /* print global bounds for transformed variables, original bounds for original variables */
386  if( !SCIPvarIsTransformed(var) )
387  {
388  lb = SCIPvarGetLbOriginal(var);
389  ub = SCIPvarGetUbOriginal(var);
390  }
391  else
392  {
393  lb = SCIPvarGetLbGlobal(var);
394  ub = SCIPvarGetUbGlobal(var);
395  }
396 
397  /* print bounds into the file */
398  printBounds(scip, messagehdlr, file, lb, ub);
399  SCIPmessageFPrintInfo(messagehdlr, file, "\n");
400  }
401 
402  return SCIP_OKAY;
403 }
404 
405 /** problem writing method of reader */
406 static
407 SCIP_DECL_READERWRITE(readerWriteBnd)
408 { /*lint --e{715}*/
409  assert(reader != NULL);
410  assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0);
411 
412  SCIP_CALL( SCIPwriteBnd(scip, file, vars, nvars, result) );
413 
414  return SCIP_OKAY;
415 }
416 
417 /** destructor of reader to free reader data (called when SCIP is exiting) */
418 static
419 SCIP_DECL_READERFREE(readerFreeBnd)
420 {
421  SCIP_READERDATA* readerdata;
422 
423  assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0);
424  readerdata = SCIPreaderGetData(reader);
425  assert(readerdata != NULL);
426  SCIPfreeBlockMemory(scip, &readerdata);
427 
428  return SCIP_OKAY;
429 }
430 
431 /*
432  * bnd file reader specific interface methods
433  */
434 
435 /** includes the bnd file reader in SCIP */
437  SCIP* scip /**< SCIP data structure */
438  )
439 {
440  SCIP_READERDATA* readerdata;
441  SCIP_READER* reader;
442 
443  /* create reader data */
444  SCIP_CALL( SCIPallocBlockMemory(scip, &readerdata) );
445 
446  /* include reader */
448 
449  /* set non fundamental callbacks via setter functions */
450  SCIP_CALL( SCIPsetReaderCopy(scip, reader, readerCopyBnd) );
451  SCIP_CALL( SCIPsetReaderRead(scip, reader, readerReadBnd) );
452  SCIP_CALL( SCIPsetReaderWrite(scip, reader, readerWriteBnd) );
453  SCIP_CALL( SCIPsetReaderFree(scip, reader, readerFreeBnd) );
454 
455  /* add bnd reader parameters */
457  "reading/bndreader/improveonly", "only use improving bounds",
458  &readerdata->improveonly, FALSE, DEFAULT_IMPROVEONLY, NULL, NULL) );
459 
460  return SCIP_OKAY;
461 }
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:61
#define NULL
Definition: def.h:267
public methods for SCIP parameter handling
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:380
public methods for memory management
static SCIP_DECL_READERCOPY(readerCopyBnd)
Definition: reader_bnd.c:268
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:18079
#define SCIP_MAXSTRLEN
Definition: def.h:288
const char * SCIPreaderGetName(SCIP_READER *reader)
Definition: reader.c:557
SCIP_RETCODE SCIPparseVarName(SCIP *scip, const char *str, SCIP_VAR **var, char **endptr)
Definition: scip_var.c:533
static SCIP_RETCODE readBounds(SCIP *scip, const char *fname, SCIP_READERDATA *readerdata)
Definition: reader_bnd.c:86
#define FALSE
Definition: def.h:94
#define READER_NAME
Definition: reader_bnd.c:66
SCIP_RETCODE SCIPincludeReaderBnd(SCIP *scip)
Definition: reader_bnd.c:436
SCIP_Real SCIPinfinity(SCIP *scip)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10877
#define TRUE
Definition: def.h:93
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
public methods for problem variables
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
#define READER_DESC
Definition: reader_bnd.c:67
SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
Definition: scip_message.c:88
SCIP_RETCODE SCIPchgVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip_var.c:4678
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:89
public methods for SCIP variables
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
Definition: scip_message.c:120
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:208
file reader for variable bounds
public methods for numerical tolerances
static void printBounds(SCIP *scip, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, SCIP_Real lb, SCIP_Real ub)
Definition: reader_bnd.c:317
#define SCIP_REAL_FORMAT
Definition: def.h:176
SCIP_FILE * SCIPfopen(const char *path, const char *mode)
Definition: fileio.c:153
SCIP_READERDATA * SCIPreaderGetData(SCIP_READER *reader)
Definition: reader.c:492
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:18089
#define SCIPerrorMessage
Definition: pub_message.h:64
SCIP_Real SCIPvarGetLbOriginal(SCIP_VAR *var)
Definition: var.c:18025
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPvarGetUbOriginal(SCIP_VAR *var)
Definition: var.c:18045
SCIP_Bool SCIPvarIsTransformedOrigvar(SCIP_VAR *var)
Definition: var.c:12862
int SCIPfeof(SCIP_FILE *stream)
Definition: fileio.c:227
struct SCIP_File SCIP_FILE
Definition: pub_fileio.h:43
char * SCIPfgets(char *s, int size, SCIP_FILE *stream)
Definition: fileio.c:200
SCIP_RETCODE SCIPchgVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip_var.c:4768
static SCIP_RETCODE SCIPwriteBnd(SCIP *scip, FILE *file, SCIP_VAR **vars, int nvars, SCIP_RESULT *result)
Definition: reader_bnd.c:344
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17420
SCIP_RETCODE SCIPgetBoolParam(SCIP *scip, const char *name, SCIP_Bool *value)
Definition: scip_param.c:250
#define DEFAULT_IMPROVEONLY
Definition: reader_bnd.c:70
#define SCIP_CALL(x)
Definition: def.h:380
wrapper functions to map file i/o to standard or zlib file i/o
struct SCIP_ReaderData SCIP_READERDATA
Definition: type_reader.h:53
public data structures and miscellaneous methods
#define SCIP_Bool
Definition: def.h:91
SCIP_RETCODE SCIPincludeReaderBasic(SCIP *scip, SCIP_READER **readerptr, const char *name, const char *desc, const char *extension, SCIP_READERDATA *readerdata)
Definition: scip_reader.c:109
void SCIPprintSysError(const char *message)
Definition: misc.c:10769
#define MIN(x, y)
Definition: def.h:243
SCIP_RETCODE SCIPsetReaderWrite(SCIP *scip, SCIP_READER *reader, SCIP_DECL_READERWRITE((*readerwrite)))
Definition: scip_reader.c:219
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_RETCODE SCIPsetReaderCopy(SCIP *scip, SCIP_READER *reader, SCIP_DECL_READERCOPY((*readercopy)))
Definition: scip_reader.c:147
general public methods
#define MAX(x, y)
Definition: def.h:239
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_DECL_READERFREE(readerFreeBnd)
Definition: reader_bnd.c:419
public methods for message output
void SCIPmessageFPrintInfo(SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char *formatstr,...)
Definition: message.c:618
static SCIP_DECL_READERREAD(readerReadBnd)
Definition: reader_bnd.c:287
#define SCIP_Real
Definition: def.h:173
public methods for input file readers
public methods for message handling
SCIP_RETCODE SCIPsetReaderRead(SCIP *scip, SCIP_READER *reader, SCIP_DECL_READERREAD((*readerread)))
Definition: scip_reader.c:195
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:17562
#define READER_EXTENSION
Definition: reader_bnd.c:68
int SCIPfclose(SCIP_FILE *fp)
Definition: fileio.c:232
public methods for reader plugins
SCIP_RETCODE SCIPsetReaderFree(SCIP *scip, SCIP_READER *reader, SCIP_DECL_READERFREE((*readerfree)))
Definition: scip_reader.c:171
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:57
static SCIP_DECL_READERWRITE(readerWriteBnd)
Definition: reader_bnd.c:407