Scippy

SCIP

Solving Constraint Integer Programs

ReaderTSP.cpp
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 ReaderTSP.cpp
26 * @brief C++ file reader for TSP data files
27 * @author Timo Berthold
28 */
29
30/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
31
32#include <iostream>
33#include <string>
34#include <sstream>
35
36#include "objscip/objscip.h"
37
38#include "scip/cons_linear.h"
39#include "scip/pub_fileio.h"
40#include <math.h>
41
42#include "ReaderTSP.h"
43#include "ProbDataTSP.h"
44#include "ConshdlrSubtour.h"
45#include "GomoryHuTree.h"
46
47using namespace tsp;
48using namespace scip;
49using namespace std;
50
51#define NINT(x) (floor(x+0.5))
52
53/** get token */
54string getToken(char*& str)
55{
56 string token;
57
58 // skip spaces and ':'
59 while( *str != '\0' && ( isspace(*str) || *str == ':') )
60 ++str;
61
62 // collect token
63 while( *str != '\0' && *str != ':' && ! isspace(*str) )
64 {
65 token += *str;
66 ++str;
67 }
68
69 // skip spaces and ':'
70 while( *str != '\0' && ( isspace(*str) || *str == ':') )
71 ++str;
72
73 return token;
74}
75
76/** parses the node list */
77SCIP_RETCODE ReaderTSP::getNodesFromFile(
78 SCIP_FILE* file, /**< file containing the data to extract */
79 double* x_coords, /**< double array to be filled with the x-coordinates of the nodes */
80 double* y_coords, /**< same for y-coordinates */
81 GRAPH* graph /**< the graph which is to be generated by the nodes */
82 )
83{
84 char str[SCIP_MAXSTRLEN];
85 int i = 0;
86 int nodenumber;
87 GRAPHNODE* node = &(graph->nodes[0]);
88
89 // extract every node out of the filestream
90 while ( i < graph->nnodes && ! SCIPfeof(file) )
91 {
92 // read next line
93 (void) SCIPfgets(str, SCIP_MAXSTRLEN, file);
94 char* s = str;
95
96 if ( ! SCIPstrToIntValue(str, &nodenumber, &s) )
97 {
98 SCIPerrorMessage("Could not read node number:\n%s\n", str);
99 return SCIP_INVALIDDATA;
100 }
101
102 if ( ! SCIPstrToRealValue(s, &x_coords[i], &s) )
103 {
104 SCIPerrorMessage("Could not read x coordinate:\n%s\n", str);
105 return SCIP_INVALIDDATA;
106 }
107
108 if ( ! SCIPstrToRealValue(s, &y_coords[i], &s) )
109 {
110 SCIPerrorMessage("Could not read x coordinate:\n%s\n", str);
111 return SCIP_INVALIDDATA;
112 }
113
114 // assign everything
115 node->id = i;
116 if( nodenumber-1 != i)
117 {
118 cout << "warning: nodenumber <" << nodenumber << "> does not match its index in node list <" << i+1
119 << ">. Node will get number " << i+1 << " when naming variables and constraints!" << endl;
120 return SCIP_INVALIDDATA;
121 }
122 node->x = x_coords[i];
123 node->y = y_coords[i];
124 node->first_edge = NULL;
125 node++;
126 i++;
127 }
128 assert( i == graph->nnodes );
129
130 return SCIP_OKAY;
131} /*lint !e1762*/
132
133/** adds a variable to both halfedges and captures it for usage in the graph */
134SCIP_RETCODE ReaderTSP::addVarToEdges(
135 SCIP* scip, /**< SCIP data structure */
136 GRAPHEDGE* edge, /**< an edge of the graph */
137 SCIP_VAR* var /**< variable corresponding to that edge */
138 )
139{
140 assert(scip != NULL);
141 assert(edge != NULL);
142 assert(var != NULL);
143
144 /* add variable to forward edge and capture it for usage in graph */
145 edge->var = var;
146 SCIP_CALL( SCIPcaptureVar(scip, edge->var) );
147
148 /* two parallel halfedges have the same variable,
149 * add variable to backward edge and capture it for usage in graph */
150 edge->back->var = edge->var;
152
153 return SCIP_OKAY;
154}
155
156/** method asserting, that the file has had the correct format and everything was set correctly */
157bool ReaderTSP::checkValid(
158 GRAPH* graph, /**< the constructed graph, schould not be NULL */
159 const std::string& name, /**< the name of the file */
160 const std::string& type, /**< the type of the problem, should be "TSP" */
161 const std::string& edgeweighttype, /**< type of the edgeweights, should be "EUC_2D", "MAX_2D", "MAN_2D",
162 * "ATT", or "GEO" */
163 int nnodes /**< dimension of the problem, should at least be one */
164 )
165{
166 // if something seems to be strange, it will be reported, that file was not valid
167 if( nnodes < 1 )
168 {
169 cout << "parse error in file <" << name << "> dimension should be greater than 0"<< endl ;
170 return false;
171 }
172
173 if (type != "TSP" )
174 {
175 cout << "parse error in file <" << name << "> type should be TSP" << endl;
176 return false;
177 }
178
179 if ( !( edgeweighttype == "EUC_2D" || edgeweighttype == "MAX_2D" || edgeweighttype == "MAN_2D"
180 || edgeweighttype == "GEO" || edgeweighttype == "ATT") )
181 {
182 cout << "parse error in file <" << name << "> unknown weight type, should be EUC_2D, MAX_2D, MAN_2D, ATT, or GEO" << endl;
183 return false;
184 }
185
186 if( graph == NULL)
187 {
188 cout << "error while reading file <" << name << ">, graph is uninitialized. ";
189 cout << "Probably NODE_COORD_SECTION is missing" << endl;
190 return false;
191 }
192
193 return true;
194} /*lint !e1762*/
195
196
197/** destructor of file reader to free user data (called when SCIP is exiting) */
198SCIP_DECL_READERFREE(ReaderTSP::scip_free)
199{ /*lint --e{715}*/
200 return SCIP_OKAY;
201}
202
203/** problem reading method of reader
204 *
205 * possible return values for *result:
206 * - SCIP_SUCCESS : the reader read the file correctly and created an appropritate problem
207 * - SCIP_DIDNOTRUN : the reader is not responsible for given input file
208 *
209 * If the reader detected an error in the input file, it should return with RETCODE SCIP_READERR or SCIP_NOFILE.
210 */
211SCIP_DECL_READERREAD(ReaderTSP::scip_read)
212{ /*lint --e{715}*/
213 SCIP_RETCODE retcode;
214
215 GRAPH* graph = NULL;
216 GRAPHNODE* node;
217 GRAPHNODE* nodestart; // the two incident nodes of an edge
218 GRAPHNODE* nodeend;
219 GRAPHEDGE* edgeforw; // two converse halfedges
220 GRAPHEDGE* edgebackw;
221 GRAPHEDGE* edge;
222
223 double* x_coords = NULL; // arrays of coordinates of the nodes
224 double* y_coords = NULL;
225
226#ifdef SCIP_DEBUG
227 double** weights = NULL;
228#endif
229
230 double x; // concrete coordinates
231 double y;
232
233 int nnodes = 0;
234 int nedges = 0;
235 int i;
236 int j;
237
238 string name = "MY_OWN_LITTLE_TSP";
239 string token;
240 string type = "TSP";
241 string edgeweighttype = "EUC_2D";
242
243 retcode = SCIP_OKAY;
244 *result = SCIP_DIDNOTRUN;
245
246 // open the file
247 SCIP_FILE* file = SCIPfopen(filename, "r");
248 if( !file )
249 return SCIP_READERROR;
250
251 // read the first lines of information
252 char str[SCIP_MAXSTRLEN];
253 (void) SCIPfgets(str, SCIP_MAXSTRLEN, file);
254
255 // get first token
256 char* s = str;
257 token = getToken(s);
258
259 while( ! SCIPfeof(file) )
260 {
261 if( token == "NAME" )
262 name = getToken(s);
263 else if( token == "TYPE" )
264 type = getToken(s);
265 else if( token == "DIMENSION" )
266 {
267 if ( ! SCIPstrToIntValue(s, &nnodes, &s) )
268 {
269 SCIPerrorMessage("Could not read number of nodes:\n%s\n", s);
270 return SCIP_INVALIDDATA;
271 }
272 nedges = nnodes * (nnodes-1);
273 }
274 else if( token == "EDGE_WEIGHT_TYPE" )
275 edgeweighttype = getToken(s);
276 else if( token == "NODE_COORD_SECTION" || token == "DISPLAY_DATA_SECTION" )
277 {
278 // there should be some nodes to construct a graph
279 if( nnodes < 1 )
280 {
281 retcode = SCIP_READERROR;
282 break;
283 }
284 // the graph is created and filled with nodes
285 else if( create_graph(nnodes, nedges, &graph) )
286 {
287 assert(x_coords == NULL);
288 assert(y_coords == NULL);
289
290 x_coords = new double[nnodes];
291 y_coords = new double[nnodes];
292 SCIP_CALL( getNodesFromFile(file, x_coords, y_coords, graph) );
293 }
294 else
295 {
296 retcode = SCIP_NOMEMORY;
297 break;
298 }
299 }
300 else if( token == "COMMENT:" || token == "COMMENT" || token == "DISPLAY_DATA_TYPE" || token == "DISPLAY_DATA_TYPE:" )
301 {
302 // do nothing
303 }
304 else if( token == "EOF" )
305 break;
306 else if( token == "" )
307 ;
308 else
309 {
310 cout << "parse error in file <" << name << "> unknown keyword <" << token << ">" << endl;
311 return SCIP_READERROR;
312 }
313 (void) SCIPfgets(str, SCIP_MAXSTRLEN, file);
314 s = str;
315 token = getToken(s);
316 }// finished parsing the input
317
318 SCIPfclose(file);
319
320 // check whether the input data was valid
321 if( ! checkValid(graph, name, type, edgeweighttype, nnodes) )
322 retcode = SCIP_READERROR;
323
324 assert(graph != NULL);
325
326 if( retcode == SCIP_OKAY )
327 {
328 edgeforw = &( graph->edges[0] ); /*lint !e613*/
329 edgebackw= &( graph->edges[nedges/2] ); /*lint !e613*/
330
331#ifdef SCIP_DEBUG
332 weights = new double* [nnodes];
333 for( i = 0; i < nnodes; ++i )
334 weights[i] = new double[nnodes];
335#endif
336
337 // construct all edges in a complete digraph
338 for( i = 0; i < nnodes; i++ )
339 {
340 nodestart = &graph->nodes[i]; /*lint !e613*/
341 for( j = i+1; j < nnodes; j++ )
342 {
343 nodeend = &graph->nodes[j]; /*lint !e613*/
344
345 // construct two 'parallel' halfedges
346 edgeforw->adjac = nodeend;
347 edgebackw->adjac = nodestart;
348 edgeforw->back = edgebackw;
349 edgebackw->back = edgeforw;
350
351 // calculate the Euclidean / Manhattan / Maximum distance of the two nodes
352 x = x_coords[(*nodestart).id] - x_coords[(*nodeend).id]; /*lint !e613*/
353 y = y_coords[(*nodestart).id] - y_coords[(*nodeend).id]; /*lint !e613*/
354 if( edgeweighttype == "EUC_2D")
355 edgeforw->length = sqrt( x*x + y*y );
356 else if( edgeweighttype == "MAX_2D")
357 edgeforw->length = MAX( ABS(x), ABS(y) );
358 else if( edgeweighttype == "MAN_2D")
359 edgeforw->length = ABS(x) + ABS(y);
360 else if( edgeweighttype == "ATT")
361 edgeforw->length = ceil( sqrt( (x*x+y*y)/10.0 ) );
362 else if( edgeweighttype == "GEO")
363 {
364 const double pi = 3.141592653589793;
365 double rads[4];
366 double coords[4];
367 double degs[4];
368 double mins[4];
369 double euler[3];
370 int k;
371
372 coords[0] = x_coords[(*nodestart).id]; /*lint !e613*/
373 coords[1] = y_coords[(*nodestart).id]; /*lint !e613*/
374 coords[2] = x_coords[(*nodeend).id]; /*lint !e613*/
375 coords[3] = y_coords[(*nodeend).id]; /*lint !e613*/
376
377 for( k = 0; k < 4; k++ )
378 {
379 degs[k] = coords[k] >= 0 ? floor(coords[k]) : ceil(coords[k]);
380 mins[k] = coords[k] - degs[k];
381 rads[k] = pi*(degs[k]+5.0*mins[k]/3.0)/180.0;
382 }
383
384 euler[0] = cos(rads[1]-rads[3]);
385 euler[1] = cos(rads[0]-rads[2]);
386 euler[2] = cos(rads[0]+rads[2]);
387 edgeforw->length = floor(6378.388 * acos(0.5*((1.0+euler[0])*euler[1]-(1.0-euler[0])*euler[2]))+1.0);
388 }
389
390 // in TSP community, it is common practice to round lengths to next integer
391 if( round_lengths_ )
392 edgeforw->length = NINT(edgeforw->length);
393
394 edgebackw->length = edgeforw->length;
395#ifdef SCIP_DEBUG
396 weights[i][j] = edgeforw->length;
397 weights[j][i] = edgebackw->length;
398#endif
399
400 // insert one of the halfedges into the edge list of the node
401 if (nodestart->first_edge == NULL)
402 {
403 nodestart->first_edge = edgeforw;
404 nodestart->first_edge->next = NULL;
405 }
406 else
407 {
408 edgeforw->next = nodestart->first_edge;
409 nodestart->first_edge = edgeforw;
410 }
411
412 // dito
413 if (nodeend->first_edge == NULL)
414 {
415 nodeend->first_edge = edgebackw;
416 nodeend->first_edge->next = NULL;
417 }
418 else
419 {
420 edgebackw->next = nodeend->first_edge;
421 nodeend->first_edge = edgebackw;
422 }
423
424 edgeforw++;
425 edgebackw++;
426 }
427 }
428 }
429
430 delete[] y_coords;
431 delete[] x_coords;
432
433 if( retcode != SCIP_OKAY )
434 {
435#ifdef SCIP_DEBUG
436 if( weights != NULL )
437 {
438 for( i = 0; i < nnodes; i++ )
439 {
440 delete[] weights[i];
441 }
442 delete[] weights;
443 }
444#endif
445 return retcode;
446 }
447
448#ifdef SCIP_DEBUG
449 printf("Matrix:\n");
450 for( i = 0; i < nnodes; i++ )
451 {
452 for( j = 0; j < nnodes; j++ )
453 printf(" %4.0f ",weights[i][j]);
454 printf("\n");
455 delete[] weights[i];
456 }
457 delete[] weights;
458#endif
459
460 // create the problem's data structure
461 SCIP_CALL( SCIPcreateObjProb(scip, name.c_str(), new ProbDataTSP(graph), TRUE) );
462
463 // add variables to problem and link them for parallel halfedges
464 for( i = 0; i < nedges/2; i++ )
465 {
466 SCIP_VAR* var;
467
468 stringstream varname;
469 edge = &graph->edges[i]; /*lint !e613*/
470
471/**! [SnippetTSPVariableCreation] */
472
473 // the variable is named after the two nodes connected by the edge it represents
474 varname << "x_e_" << edge->back->adjac->id+1 << "-" << edge->adjac->id+1;
475 SCIP_CALL( SCIPcreateVar(scip, &var, varname.str().c_str(), 0.0, 1.0, edge->length,
477
478 /* add variable to SCIP and to the graph */
479 SCIP_CALL( SCIPaddVar(scip, var) );
480 SCIP_CALL( addVarToEdges(scip, edge, var) );
481
482 /* release variable for the reader. */
483 SCIP_CALL( SCIPreleaseVar(scip, &var) );
484
485/**! [SnippetTSPVariableCreation] */
486
487 }
488
489 /* add all n node degree constraints */
490 if( nnodes >= 2 )
491 {
492 for( i = 0, node = &(graph->nodes[0]); i < nnodes; i++, node++ ) /*lint !e613*/
493 {
494/**! [SnippetTSPDegreeConstraintCreation] */
495 SCIP_CONS* cons;
496 stringstream consname;
497 consname << "deg_con_v" << node->id+1;
498
499 // a new degree constraint is created, named after a node
500 SCIP_CALL( SCIPcreateConsLinear(scip, &cons, consname.str().c_str(), 0, NULL, NULL, 2.0, 2.0,
502
503 edge = node->first_edge;
504 // sum up the values of all adjacent edges
505 while( edge != NULL )
506 {
507 SCIP_CALL( SCIPaddCoefLinear(scip, cons, edge->var, 1.0) );
508 edge = edge->next;
509 }
510
511 // add the constraint to SCIP
512 SCIP_CALL( SCIPaddCons(scip, cons) );
513 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
514/**! [SnippetTSPDegreeConstraintCreation] */
515 }
516 }
517
518/**! [SnippetTSPNosubtourConstraintCreation] */
519
520 /* last, we need a constraint forbidding subtours */
521 SCIP_CONS* cons;
522 SCIP_CALL( SCIPcreateConsSubtour(scip, &cons, "subtour", graph,
524 SCIP_CALL( SCIPaddCons(scip, cons) );
525 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
526
527/**! [SnippetTSPNosubtourConstraintCreation] */
528
529 release_graph(&graph);
530 *result = SCIP_SUCCESS;
531
532 return SCIP_OKAY;
533}
534
535/** problem writing method of reader; NOTE: if the parameter "genericnames" is TRUE, then
536 * SCIP already set all variable and constraint names to generic names; therefore, this
537 * method should always use SCIPvarGetName() and SCIPconsGetName();
538 *
539 * possible return values for *result:
540 * - SCIP_SUCCESS : the reader read the file correctly and created an appropritate problem
541 * - SCIP_DIDNOTRUN : the reader is not responsible for given input file
542 *
543 * If the reader detected an error in the writing to the file stream, it should return
544 * with RETCODE SCIP_WRITEERROR.
545 */
546SCIP_DECL_READERWRITE(ReaderTSP::scip_write)
547{ /*lint --e{715}*/
548 *result = SCIP_DIDNOTRUN;
549
550 return SCIP_OKAY;
551}
C++ constraint handler for TSP subtour elimination constraints.
SCIP_Bool create_graph(int n, int m, GRAPH **gr)
void release_graph(GRAPH **gr)
generator for global cuts in undirected graphs
C++ problem data for TSP.
SCIP_DECL_READERREAD(ReaderTSP::scip_read)
Definition: ReaderTSP.cpp:211
#define NINT(x)
Definition: ReaderTSP.cpp:51
SCIP_DECL_READERWRITE(ReaderTSP::scip_write)
Definition: ReaderTSP.cpp:546
SCIP_DECL_READERFREE(ReaderTSP::scip_free)
Definition: ReaderTSP.cpp:198
string getToken(char *&str)
Definition: ReaderTSP.cpp:54
C++ file reader for TSP data files.
SCIP_VAR ** y
Definition: circlepacking.c:64
SCIP_VAR ** x
Definition: circlepacking.c:63
Constraint handler for linear constraints in their most general form, .
#define NULL
Definition: def.h:266
#define SCIP_MAXSTRLEN
Definition: def.h:287
#define ABS(x)
Definition: def.h:234
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:238
#define SCIP_CALL(x)
Definition: def.h:373
SCIP_FILE * SCIPfopen(const char *path, const char *mode)
Definition: fileio.c:153
int SCIPfeof(SCIP_FILE *stream)
Definition: fileio.c:227
int SCIPfclose(SCIP_FILE *fp)
Definition: fileio.c:232
char * SCIPfgets(char *s, int size, SCIP_FILE *stream)
Definition: fileio.c:200
#define nnodes
Definition: gastrans.c:74
SCIP_RETCODE SCIPaddCoefLinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real val)
SCIP_RETCODE SCIPcreateConsLinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_prob.c:1668
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2770
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1174
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip_var.c:1248
SCIP_RETCODE SCIPcreateVar(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype, SCIP_Bool initial, SCIP_Bool removable, SCIP_DECL_VARDELORIG((*vardelorig)), SCIP_DECL_VARTRANS((*vartrans)), SCIP_DECL_VARDELTRANS((*vardeltrans)), SCIP_DECL_VARCOPY((*varcopy)), SCIP_VARDATA *vardata)
Definition: scip_var.c:114
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:1214
SCIP_Bool SCIPstrToIntValue(const char *str, int *value, char **endptr)
Definition: misc.c:10977
SCIP_Bool SCIPstrToRealValue(const char *str, SCIP_Real *value, char **endptr)
Definition: misc.c:11008
Definition: pqueue.h:38
SCIP_RETCODE SCIPcreateConsSubtour(SCIP *scip, SCIP_CONS **cons, const char *name, GRAPH *graph, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable)
SCIP_RETCODE SCIPcreateObjProb(SCIP *scip, const char *name, scip::ObjProbData *objprobdata, SCIP_Bool deleteobject)
C++ wrapper classes for SCIP.
wrapper functions to map file i/o to standard or zlib file i/o
struct SCIP_File SCIP_FILE
Definition: pub_fileio.h:43
#define SCIPerrorMessage
Definition: pub_message.h:64
struct GraphEdge * back
Definition: GomoryHuTree.h:70
GRAPHNODE * adjac
Definition: GomoryHuTree.h:72
SCIP_VAR * var
Definition: GomoryHuTree.h:74
double length
Definition: GomoryHuTree.h:67
struct GraphEdge * next
Definition: GomoryHuTree.h:69
struct GraphEdge * first_edge
Definition: GomoryHuTree.h:53
double y
Definition: GomoryHuTree.h:46
double x
Definition: GomoryHuTree.h:45
GRAPHNODE * nodes
Definition: GomoryHuTree.h:86
int nnodes
Definition: GomoryHuTree.h:82
GRAPHEDGE * edges
Definition: GomoryHuTree.h:87
@ SCIP_DIDNOTRUN
Definition: type_result.h:42
@ SCIP_SUCCESS
Definition: type_result.h:58
@ SCIP_READERROR
Definition: type_retcode.h:45
@ SCIP_INVALIDDATA
Definition: type_retcode.h:52
@ SCIP_NOMEMORY
Definition: type_retcode.h:44
@ SCIP_OKAY
Definition: type_retcode.h:42
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
@ SCIP_VARTYPE_BINARY
Definition: type_var.h:62