Scippy

SCIP

Solving Constraint Integer Programs

reader_scflp.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 2002-2022 Zuse Institute Berlin */
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_scflp.c
26  * @brief SCFLP reader file reader
27  * @author Stephen J. Maher
28  *
29  * This file implements the reader/parser used to read the CAP input data and builds a SCFLP instance. For more details
30  * see \ref SCFLP_READER.
31  *
32  * @page SCFLP_READER Parsing the input format
33  *
34  * In the <code>data</code> directory you find a few data files which contain each one CAP problem. These data
35  * files have the following structure:
36  * - The first line specifies the number of facilities (n) and the number of customers (m).
37  * - The next n lines specifies for each facility the setup cost and propduction capacity.
38  * - The following lines state the parameters for each of the customers.
39  * - First, the demand of customer is given.
40  * - The next set of lines states the transportation cost from each facility to the customer. Each line contains 7
41  * facilities, so there are ceil(n/7) lines for the transportation costs for each customer.
42  *
43  * For parsing that data, we implemented a reader plugin for \SCIP. A reader has several callback methods and at least
44  * one interface methods (the one including the reader into \SCIP). For our purpose we only implemented the \ref
45  * READERREAD callback and the interface method which adds the reader plugin to \SCIP.
46  *
47  * @section SCFLP_READERINCLUDE The SCIPincludeReaderScflp() interface method
48  *
49  * The interface method <code>SCIPincludeReaderScflp()</code> is called to add the reader plugin to \SCIP (see
50  * cmain.c). This means \SCIP gets informed that this reader is available for reading input files. Therefore, the
51  * function <code>SCIPincludeReader()</code> is called within this method which passes all necessary information of the
52  * reader to SCIP. This information includes the name of the reader, a description, and the file extension for which the
53  * file reader is in charge. In our case we selected the file extension "cap". This means that all files which have
54  * this file extension are passed to our reader for parsing. Besides these information the call
55  * <code>SCIPincludeReader()</code> also passes for each callback of the reader a function pointers
56  * (some of them might be NULL pointers). These function
57  * pointers are used by \SCIP to run the reader. For more information about all available reader callbacks we refer to
58  * the \ref READER "How to add file readers" tutorial. In the remaining section
59  * we restrict ourself to the callback <code>READERREAD</code> which is the only one we implemented for the SCFLP
60  * example. All other callbacks are not required for this example.
61  *
62  * @section SCFLP_READERREAD The READERREAD callback method
63  *
64  * The READERREAD callback is in charge of parsing a file and creating the problem. To see the list of arguments this
65  * functions gets see the file type_reader.h in the source of \SCIP. The following arguments are of interest in our
66  * case. First of all the \SCIP pointer, the file name, and the SCIP_RESULT pointer. The \SCIP pointer gives us the
67  * current environment. The file name states the file which we should open and parse. Last but not least, the SCIP_RESULT
68  * pointer is required to tell \SCIP if the parsing process was successfully or
69  * not. Note that in type_reader.h you also find a list of allowable result values for the SCIP_RESULT pointer and the
70  * <code>SCIP_RETCODE</code> which is the return value of this function.
71  *
72  * In the READERREAD callback, the scenarios for the stochastic program are generated. A scenario represents a different
73  * realisation of demand for each customer. The scenarios are generated by sampling demands from a normal distribution
74  * with a mean given by the deterministic demand and the standard deviation sampled from a uniform distribution with the
75  * range [0.1*mean, 0.3*mean]. The number of scenarios can be set using a runtime parameter.
76  *
77  * @subsection SCFLP_PARSING Parsing the problem
78  *
79  * The file can be opened and parsed with your favorite methods. In this case we are using the functionality provided by
80  * \SCIP since this has some nice side effects. We are using the function SCIPfopen() which can besides standard
81  * files also handle files which are packed. To find all files related to the parsing of a file, we refer to the file pub_misc.h
82  * in the source of SCIP. Parsing the data out of the file is not that hard. Please look at the code and comments
83  * therein for more details.
84  *
85  * @subsection SCFLP_CREATING Creating the problem
86  *
87  * After parsing the file the final task for the reader is to create the problem. In our case, we pass the collected data
88  * to the \ref probdata_scflp.h "main problem data plugin". For this, we use the interface methods
89  * SCIPprobdataCreate() which is provided by the
90  * problem data plugin (see probdata_scflp.c). After that, the reader sets the result value for the SCIP_RESULT
91  * pointer to <code>SCIP_SUCCESS</code> and returns with a proper <code>SCIP_RETCODE</code>.
92  */
93 
94 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
95 
96 #include <assert.h>
97 #include <string.h>
98 #include <math.h>
99 #include <stdlib.h>
100 
101 #include "probdata_scflp.h"
102 #include "reader_scflp.h"
103 
104 /**@name Reader properties
105  *
106  * @{
107  */
108 
109 #define READER_NAME "scflpreader"
110 #define READER_DESC "file reader for CAP data format and creates a SCFLP instance"
111 #define READER_EXTENSION "cap"
112 
113 
114 #define DEFAULT_USEBENDERS TRUE
115 #define DEFAULT_NUMSCENARIOS 250
116 #define DEFAULT_RANDOMSEED 1
117 #define DEFAULT_QUADCOSTS FALSE /**< should the problem be formulated with quadratic costs */
118 
119 
120 #define MAXNCOSTS 7
121 
122 struct SCIP_ReaderData
123 {
124  SCIP_Bool usebenders; /**< should Benders' decomposition be used to solve the problem */
125  int nscenarios; /**< the number of scenarios */
126  int randomseed; /**< the random seed used to generate the scenarios */
127  SCIP_Bool quadcosts; /**< should the problem be formulated with quadratic costs */
128 };
129 
130 /**@} */
131 
132 /** generates a normally distributed random number */
133 static
135  SCIP_RANDNUMGEN* randomgen, /**< the random number generator */
136  SCIP_Real mean, /**< the mean of the normal distribution */
137  SCIP_Real stdDev, /**< the standard deviation of the normal distribution */
138  SCIP_Real* spare, /**< the spare value that has been collected */
139  SCIP_Bool* hasspare /**< whether a spare value exists */
140  )
141 {
142  SCIP_Real u;
143  SCIP_Real v;
144  SCIP_Real s;
145 
146  /* if a spare exists, then it is returned */
147  if( (*hasspare) )
148  {
149  (*hasspare) = FALSE;
150  return mean + stdDev * (*spare);
151  }
152 
153  (*hasspare) = TRUE;
154  do {
155  u = SCIPrandomGetReal(randomgen, 0.0, 1.0);
156  v = SCIPrandomGetReal(randomgen, 0.0, 1.0);
157  s = u * u + v * v;
158  }
159  while( (s >= 1.0) || (s == 0.0) );
160 
161  s = sqrt(-2.0 * log(s) / s);
162  (*spare) = v * s;
163 
164  return mean + stdDev * u * s;
165 }
166 
167 
168 /** creates the reader data */
169 static
171  SCIP* scip, /**< SCIP data structure */
172  SCIP_READERDATA** readerdata /**< pointer to store the reader data */
173  )
174 {
175  assert(scip != NULL);
176  assert(readerdata != NULL);
177 
178  SCIP_CALL( SCIPallocBlockMemory(scip, readerdata) );
179  (*readerdata)->usebenders = TRUE;
180 
181  return SCIP_OKAY;
182 }
183 
184 /** frees the reader data */
185 static
187  SCIP* scip, /**< SCIP data structure */
188  SCIP_READERDATA** readerdata /**< pointer to store the reader data */
189  )
190 {
191  assert(scip != NULL);
192  assert(readerdata != NULL);
193  assert(*readerdata != NULL);
194 
195  SCIPfreeBlockMemory(scip, readerdata);
196 
197  return SCIP_OKAY;
198 }
199 
200 
201 /**@name Callback methods
202  *
203  * @{
204  */
205 
206 /** destructor of reader to free user data (called when SCIP is exiting)*/
207 static
208 SCIP_DECL_READERFREE(readerFreeScflp)
209 {
210  SCIP_READERDATA* readerdata;
211 
212  assert(scip != NULL);
213  assert(reader != NULL);
214 
215  readerdata = SCIPreaderGetData(reader);
216 
217  SCIP_CALL( readerdataFree(scip, &readerdata) );
218 
219  return SCIP_OKAY;
220 }
221 
222 
223 /** problem reading method of reader */
224 static
225 SCIP_DECL_READERREAD(readerReadScflp)
226 { /*lint --e{715}*/
227  SCIP_READERDATA* readerdata;
228 
229  SCIP_RANDNUMGEN* randomgen;
230 
231  SCIP_FILE* file;
232  SCIP_Bool error;
233 
234  char name[SCIP_MAXSTRLEN];
235  char buffer[SCIP_MAXSTRLEN];
236  SCIP_Real* fixedcost;
237  SCIP_Real* capacity;
238  SCIP_Real* detdemands;
239  SCIP_Real** demands;
240  SCIP_Real** costs;
241  int nfacilities;
242  int ncustomers;
243  int nscenarios;
244 
245  SCIP_Real facilitycost;
246  SCIP_Real facilitycap;
247  SCIP_Real demand;
248  int facility;
249  int customer;
250  int ncostlines; /* this is the number of lines that have facility costs */
251 
252  int nread;
253  int lineno;
254  int i;
255  int j;
256 
257  readerdata = SCIPreaderGetData(reader);
258 
259  /* creating the random number generator */
260  SCIP_CALL( SCIPcreateRandom(scip, &randomgen, readerdata->randomseed, FALSE) );
261 
262  nscenarios = readerdata->nscenarios;
263 
264  *result = SCIP_DIDNOTRUN;
265 
266  /* open file */
267  file = SCIPfopen(filename, "r");
268  if( file == NULL )
269  {
270  SCIPerrorMessage("cannot open file <%s> for reading\n", filename);
271  SCIPprintSysError(filename);
272  return SCIP_NOFILE;
273  }
274 
275  lineno = 0;
276  sprintf(name, "SCFLP");
277 
278  nfacilities = 0;
279  ncustomers = 0;
280 
281  /* read problem name */
282  if( !SCIPfeof(file) )
283  {
284  if( SCIPfgets(buffer, (int)sizeof(buffer), file) == NULL )
285  return SCIP_READERROR;
286 
287  /* parse dimension line */
288  nread = sscanf(buffer, " %d %d\n", &nfacilities, &ncustomers);
289  if( nread == 0 )
290  {
291  SCIPwarningMessage(scip, "invalid input line %d in file <%s>: <%s>\n", lineno, filename, buffer);
292  return SCIP_READERROR;
293  }
294 
295  SCIPdebugMsg(scip, "number of facilities = <%d> number of customers = <%d>\n", nfacilities, ncustomers);
296  }
297 
298  /* computing the number of customer cost lines */
299  ncostlines = SCIPceil(scip, (SCIP_Real)nfacilities/MAXNCOSTS);
300 
301  /* allocate buffer memory for storing the demand and the transport cost temporarily */
302  SCIP_CALL( SCIPallocBufferArray(scip, &capacity, nfacilities) );
303  SCIP_CALL( SCIPallocBufferArray(scip, &fixedcost, nfacilities) );
304 
305  for( i = 0; i < nfacilities; i++ )
306  {
307  capacity[i] = 0.0;
308  fixedcost[i] = 0.0;
309  }
310 
311  error = FALSE;
312 
313  /* read facility data */
314  facility = 0;
315  while( !SCIPfeof(file) && !error && facility < nfacilities )
316  {
317  if( SCIPfgets(buffer, (int)sizeof(buffer), file) == NULL )
318  break;
319 
320  /* parse dimension line */
321  nread = sscanf(buffer, " %lf %lf\n", &facilitycap, &facilitycost);
322  if( nread < 2 )
323  {
324  SCIPwarningMessage(scip, "invalid input line %d in file <%s>: <%s>\n", lineno, filename, buffer);
325  error = TRUE;
326  break;
327  }
328 
329  SCIPdebugMsg(scip, "facility %d capacity = <%f>, fixed cost = <%f>\n", facility, facilitycap, facilitycost);
330  capacity[facility] = facilitycap;
331  fixedcost[facility] = facilitycost;
332  facility++;
333  assert(facility <= nfacilities);
334  }
335 
336  /* allocate buffer memory for storing the demand and the transport cost temporarily */
337  SCIP_CALL( SCIPallocBufferArray(scip, &detdemands, ncustomers) );
338  SCIP_CALL( SCIPallocBufferArray(scip, &demands, ncustomers) );
339  SCIP_CALL( SCIPallocBufferArray(scip, &costs, ncustomers) );
340 
341  /* TODO: convert the 2D arrays into contiguous arrays. This has benefits from a memory management point of view. */
342  for( i = 0; i < ncustomers; i++ )
343  {
344  SCIP_CALL( SCIPallocBufferArray(scip, &costs[i], nfacilities) );
345  SCIP_CALL( SCIPallocBufferArray(scip, &demands[i], nscenarios) );
346 
347  for( j = 0; j < nfacilities; j++ )
348  costs[i][j] = 0.0;
349 
350  for( j = 0; j < nscenarios; j++ )
351  demands[i][j] = 0.0;
352 
353  detdemands[i] = 0.0;
354  }
355 
356  /* parse demands and costs */
357 
358  lineno = 0;
359  customer = 0;
360  facility = 0;
361  while( !SCIPfeof(file) && !error )
362  {
363  /* get next line */
364  if( SCIPfgets(buffer, (int)sizeof(buffer), file) == NULL )
365  break;
366 
367  if( lineno == 0 )
368  {
369  /* parse the line */
370  nread = sscanf(buffer, " %lf\n", &demand);
371  if( nread == 0 )
372  {
373  SCIPwarningMessage(scip, "invalid input line %d in file <%s>: <%s>\n", lineno, filename, buffer);
374  error = TRUE;
375  break;
376  }
377 
378  SCIPdebugMsg(scip, "customer %d demand <%f>\n", customer, demand);
379  detdemands[customer] = demand;
380  }
381  else if( lineno <= ncostlines )
382  {
383  SCIP_Real tmpcosts[MAXNCOSTS];
384  /* parse the line */
385  nread = sscanf(buffer, " %lf %lf %lf %lf %lf %lf %lf\n", &tmpcosts[0], &tmpcosts[1], &tmpcosts[2],
386  &tmpcosts[3], &tmpcosts[4], &tmpcosts[5], &tmpcosts[6]);
387 
388  if( nread == 0 )
389  {
390  SCIPwarningMessage(scip, "invalid input line %d in file <%s>: <%s>\n", lineno, filename, buffer);
391  error = TRUE;
392  break;
393  }
394 
395  for( i = 0; i < nread; i++ )
396  {
397  SCIPdebugMsg(scip, "(%d, %d) found cost <%e>\n", customer, facility, tmpcosts[i]);
398  costs[customer][facility] = tmpcosts[i]/demand;
399  facility++;
400  }
401  }
402 
403  if( lineno == ncostlines )
404  {
405  lineno = 0;
406  facility = 0;
407  customer++;
408  }
409  else
410  lineno++;
411  }
412 
413  /* if there has been no error in reading the data, then we generate the scenarios */
414  if( !error )
415  {
416  SCIP_Real mean;
417  SCIP_Real stdDev;
418  SCIP_Real spare;
419  SCIP_Bool hasspare;
420 
421  /* creating the scenario data */
422  for( i = 0; i < ncustomers; i++ )
423  {
424  mean = detdemands[i];
425  stdDev = SCIPrandomGetReal(randomgen, 0.1*mean, 0.2*mean);
426  hasspare = FALSE;
427  for( j = 0; j < nscenarios; j++ )
428  {
429  demands[i][j] = SCIPround(scip, generateGaussianNoise(randomgen, mean, stdDev, &spare, &hasspare));
430 
431  SCIPdebugMsg(scip, "Scenario %d: customer %d demand <%f>\n", j, i, demands[i][j]);
432  }
433  }
434 
435  /* create a new problem in SCIP */
436  SCIP_CALL( SCIPprobdataCreate(scip, name, costs, demands, capacity, fixedcost, ncustomers, nfacilities,
437  nscenarios, readerdata->usebenders, readerdata->quadcosts) );
438  }
439 
440  (void)SCIPfclose(file);
441 
442  for( i = ncustomers - 1; i >= 0; i-- )
443  {
444  SCIPfreeBufferArray(scip, &demands[i]);
445  SCIPfreeBufferArray(scip, &costs[i]);
446  }
447 
448  SCIPfreeBufferArray(scip, &costs);
449  SCIPfreeBufferArray(scip, &demands);
450  SCIPfreeBufferArray(scip, &detdemands);
451 
452  SCIPfreeBufferArray(scip, &fixedcost);
453  SCIPfreeBufferArray(scip, &capacity);
454 
455  /* freeing the random number generator */
456  SCIPfreeRandom(scip, &randomgen);
457 
458  if( error )
459  return SCIP_READERROR;
460 
461  *result = SCIP_SUCCESS;
462 
463  return SCIP_OKAY;
464 }
465 
466 /**@} */
467 
468 
469 /**@name Interface methods
470  *
471  * @{
472  */
473 
474 /** includes the scflp file reader in SCIP */
476  SCIP* scip /**< SCIP data structure */
477  )
478 {
479  SCIP_READERDATA* readerdata;
480  SCIP_READER* reader;
481 
482  /* create scflp reader data */
483  readerdata = NULL;
484 
485  SCIP_CALL( readerdataCreate(scip, &readerdata) );
486 
487  /* include scflp reader */
489  assert(reader != NULL);
490 
491  SCIP_CALL( SCIPsetReaderFree(scip, reader, readerFreeScflp) );
492  SCIP_CALL( SCIPsetReaderRead(scip, reader, readerReadScflp) );
493 
495  "reading/" READER_NAME "/usebenders", "Should Benders' decomposition be used to solve the problem?",
496  &readerdata->usebenders, FALSE, DEFAULT_USEBENDERS, NULL, NULL) );
497 
499  "reading/" READER_NAME "/numscenarios",
500  "the number of scenarios that will be randomly generated",
501  &readerdata->nscenarios, FALSE, DEFAULT_NUMSCENARIOS, 1, INT_MAX, NULL, NULL) );
502 
504  "reading/" READER_NAME "/randomseed",
505  "the random seed used to generate the scenarios",
506  &readerdata->randomseed, FALSE, DEFAULT_RANDOMSEED, 1, INT_MAX, NULL, NULL) );
507 
509  "reading/" READER_NAME "/quadcosts", "should the problem be formulated with quadratic costs",
510  &readerdata->quadcosts, FALSE, DEFAULT_QUADCOSTS, NULL, NULL) );
511 
512  return SCIP_OKAY;
513 }
514 
515 /**@} */
void SCIPfreeRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen)
#define MAXNCOSTS
Definition: reader_scflp.c:120
#define DEFAULT_USEBENDERS
Definition: reader_scflp.c:114
#define SCIP_MAXSTRLEN
Definition: def.h:302
#define READER_EXTENSION
Definition: reader_scflp.c:111
static SCIP_DECL_READERREAD(readerReadScflp)
Definition: reader_scflp.c:225
#define FALSE
Definition: def.h:96
#define DEFAULT_RANDOMSEED
Definition: reader_scflp.c:116
#define DEFAULT_QUADCOSTS
Definition: reader_scflp.c:117
static SCIP_Real generateGaussianNoise(SCIP_RANDNUMGEN *randomgen, SCIP_Real mean, SCIP_Real stdDev, SCIP_Real *spare, SCIP_Bool *hasspare)
Definition: reader_scflp.c:134
#define TRUE
Definition: def.h:95
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:136
SCIP_RETCODE SCIPprobdataCreate(SCIP *scip, const char *probname, int *demands, SCIP_Real *rints, SCIP_Real *rexts, int ntypes, SCIP_Real width, SCIP_Real height)
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:89
#define READER_DESC
Definition: reader_scflp.c:110
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
Definition: scip_message.c:120
#define SCIPdebugMsg
Definition: scip_message.h:78
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:83
SCIP_FILE * SCIPfopen(const char *path, const char *mode)
Definition: fileio.c:153
SCIP_READERDATA * SCIPreaderGetData(SCIP_READER *reader)
Definition: reader.c:492
#define SCIPerrorMessage
Definition: pub_message.h:64
SCFLP problem reader file reader.
#define READER_NAME
Definition: reader_scflp.c:109
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
#define NULL
Definition: lpi_spx1.cpp:164
#define SCIP_CALL(x)
Definition: def.h:393
Problem data for Stochastic Capacitated Facility Location problem.
SCIP_RETCODE SCIPcreateRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen, unsigned int initialseed, SCIP_Bool useglobalseed)
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:124
struct SCIP_ReaderData SCIP_READERDATA
Definition: type_reader.h:53
#define SCIP_Bool
Definition: def.h:93
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
SCIP_RETCODE SCIPincludeReaderScflp(SCIP *scip)
Definition: reader_scflp.c:475
void SCIPprintSysError(const char *message)
Definition: misc.c:10673
static SCIP_RETCODE readerdataFree(SCIP *scip, SCIP_READERDATA **readerdata)
Definition: reader_scflp.c:186
static SCIP_DECL_READERFREE(readerFreeScflp)
Definition: reader_scflp.c:208
static SCIP_RETCODE readerdataCreate(SCIP *scip, SCIP_READERDATA **readerdata)
Definition: reader_scflp.c:170
SCIP_Real SCIPrandomGetReal(SCIP_RANDNUMGEN *randnumgen, SCIP_Real minrandval, SCIP_Real maxrandval)
Definition: misc.c:10034
#define SCIP_Real
Definition: def.h:186
SCIP_RETCODE SCIPsetReaderRead(SCIP *scip, SCIP_READER *reader, SCIP_DECL_READERREAD((*readerread)))
Definition: scip_reader.c:195
#define DEFAULT_NUMSCENARIOS
Definition: reader_scflp.c:115
int SCIPfclose(SCIP_FILE *fp)
Definition: fileio.c:232
SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPround(SCIP *scip, SCIP_Real val)
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