Scippy

SCIP

Solving Constraint Integer Programs

reader_nl.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 reader_nl.cpp
26 * @ingroup DEFPLUGINS_READER
27 * @brief AMPL .nl file reader
28 * @author Stefan Vigerske
29 *
30 * For documentation on ampl::mp, see https://ampl.github.io and https://www.zverovich.net/2014/09/19/reading-nl-files.html.
31 * For documentation on .nl files, see https://ampl.com/REFS/hooking2.pdf.
32 */
33
34/*--+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
35
36#include <string>
37#include <vector>
38#include <map>
39
40#include "scip/reader_nl.h"
41#include "scip/cons_linear.h"
42#include "scip/cons_nonlinear.h"
43#include "scip/cons_sos1.h"
44#include "scip/cons_sos2.h"
45#include "scip/cons_and.h"
46#include "scip/cons_or.h"
47#include "scip/cons_xor.h"
48#include "scip/expr_var.h"
49#include "scip/expr_value.h"
50#include "scip/expr_sum.h"
51#include "scip/expr_product.h"
52#include "scip/expr_pow.h"
53#include "scip/expr_log.h"
54#include "scip/expr_exp.h"
55#include "scip/expr_trig.h"
56#include "scip/expr_abs.h"
57
58// disable -Wshadow warnings for upcoming includes of AMPL/MP
59// disable -Wimplicit-fallthrough as I don't want to maintain extra comments in AMPL/MP code to suppress these
60#ifdef __GNUC__
61#pragma GCC diagnostic ignored "-Wshadow"
62#if __GNUC__ >= 7
63#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
64#endif
65#endif
66
67#include "mp/nl-reader.h"
68
69#define READER_NAME "nlreader"
70#define READER_DESC "AMPL .nl file reader"
71#define READER_EXTENSION "nl"
72
73// a variant of SCIP_CALL that throws a std::logic_error if not SCIP_OKAY
74// (using cast to long long to work around issues with old MSVC)
75#define SCIP_CALL_THROW(x) \
76 do \
77 { \
78 SCIP_RETCODE throw_retcode; \
79 if( ((throw_retcode) = (x)) != SCIP_OKAY ) \
80 throw std::logic_error("Error <" + std::to_string((long long)throw_retcode) + "> in function call"); \
81 } \
82 while( false )
83
84/*
85 * Data structures
86 */
87
88/// problem data stored in SCIP
89struct SCIP_ProbData
90{
91 char* filenamestub; /**< name of input file, without .nl extension; array is long enough to hold 5 extra chars */
92 int filenamestublen; /**< length of filenamestub string */
93
94 int amplopts[mp::MAX_AMPL_OPTIONS]; /**< AMPL options from .nl header */
95 int namplopts; /**< number of AMPL options from .nl header */
96
97 SCIP_VAR** vars; /**< variables in the order given by AMPL */
98 int nvars; /**< number of variables */
99
100 SCIP_CONS** conss; /**< constraints in the order given by AMPL */
101 int nconss; /**< number of constraints */
102
103 SCIP_Bool islp; /**< whether problem is an LP (only linear constraints, only continuous vars) */
104};
105
106/*
107 * Local methods
108 */
109
110// forward declaration
111static SCIP_DECL_PROBDELORIG(probdataDelOrigNl);
112
113/// implementation of AMPL/MPs NLHandler that constructs a SCIP problem while a .nl file is read
114class AMPLProblemHandler : public mp::NLHandler<AMPLProblemHandler, SCIP_EXPR*>
115{
116private:
117 SCIP* scip;
118 SCIP_PROBDATA* probdata;
119
120 // variable expressions corresponding to nonlinear variables
121 // created in OnHeader() and released in destructor
122 // for reuse of var-expressions in OnVariableRef()
123 std::vector<SCIP_EXPR*> varexprs;
124
125 // linear parts for nonlinear constraints
126 // first collect and then add to constraints in EndInput()
127 std::vector<std::vector<std::pair<SCIP_Real, SCIP_VAR*> > > nlconslin;
128
129 // expression that represents a nonlinear objective function
130 // used to create a corresponding constraint in EndInput(), unless NULL
131 SCIP_EXPR* objexpr;
132
133 // common expressions (defined variables from statements like "var xsqr = x^2;" in an AMPL model)
134 // they are constructed by BeginCommonExpr/EndCommonExpr below and are referenced by index in OnCommonExprRef
135 std::vector<SCIP_EXPR*> commonexprs;
136
137 // collect expressions that need to be released eventually
138 // this are all expression that are returned to the AMPL/MP code in AMPLProblemHandler::OnXyz() functions
139 // they need to be released exactly once, but after they are used in another expression or a constraint
140 // as AMPL/MP may reuse expressions (common subexpressions), we don't release an expression when it is used
141 // as a child or when constructing a constraint, but first collect them all and then release in destructor
142 // alternatively, one could encapsulate SCIP_EXPR* into a small class that handles proper reference counting
143 std::vector<SCIP_EXPR*> exprstorelease;
144
145 // count on variables or constraints added for logical expressions
146 int logiccount;
147
148 // SOS constraints
149 // collected while handling suffixes in SuffixHandler
150 // sosvars maps the SOS index (can be negative) to the indices of the variables in the SOS
151 // sosweights gives for each variable its weight in the SOS it appears in (if any)
152 std::map<int, std::vector<int> > sosvars;
153 std::vector<int> sosweights;
154
155 // initial solution, if any
156 SCIP_SOL* initsol;
157
158 // opened files with column/variable and row/constraint names, or NULL
159 fmt::File* colfile;
160 fmt::File* rowfile;
161
162 // get name from names strings, if possible
163 // returns whether a name has been stored
164 bool nextName(
165 const char*& namesbegin, /**< current pointer into names string, or NULL */
166 const char* namesend, /**< pointer to end of names string */
167 char* name /**< buffer to store name, should have length SCIP_MAXSTRLEN */
168 )
169 {
170 if( namesbegin == NULL )
171 return false;
172
173 // copy namesbegin into name until newline or namesend
174 // updates namesbegin
175 int nchars = 0;
176 while( namesbegin != namesend )
177 {
178 if( nchars == SCIP_MAXSTRLEN )
179 {
180 SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL, "name too long when parsing names file");
181 // do no longer read names from this string (something seems awkward)
182 namesbegin = NULL;
183 return false;
184 }
185 if( *namesbegin == '\n' )
186 {
187 *name = '\0';
188 ++namesbegin;
189 return true;
190 }
191 *(name++) = *(namesbegin++);
192 ++nchars;
193 }
194
195 SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL, "missing newline when parsing names file");
196 return false;
197 }
198
199 /// returns variable or value for given expression
200 ///
201 /// if expression is variable, ensure that it is a binary variable and set var
202 /// if expression is value, then set val to whether value is nonzero and set var to NULL
203 /// otherwise throw UnsupportedError exception
204 void LogicalExprToVarVal(
205 LogicalExpr expr,
206 SCIP_VAR*& var,
207 SCIP_Bool& val
208 )
209 {
210 assert(expr != NULL);
211
212 if( SCIPisExprVar(scip, expr) )
213 {
214 var = SCIPgetVarExprVar(expr);
216 {
217 SCIP_Bool infeas;
218 SCIP_Bool tightened;
220 assert(!infeas);
221 SCIP_CALL_THROW( SCIPtightenVarLbGlobal(scip, var, 0.0, TRUE, &infeas, &tightened) );
222 assert(!infeas);
223 SCIP_CALL_THROW( SCIPtightenVarUbGlobal(scip, var, 1.0, TRUE, &infeas, &tightened) );
224 assert(!infeas);
225 }
226 val = FALSE; // for scan-build
227
228 return;
229 }
230
231 if( SCIPisExprValue(scip, expr) )
232 {
233 var = NULL;
234 val = SCIPgetValueExprValue(expr) != 0.0;
235 return;
236 }
237
238 OnUnhandled("logical expression must be binary or constant");
239 }
240
241public:
242 /// constructor
243 ///
244 /// initializes SCIP problem and problem data
246 SCIP* scip_, ///< SCIP data structure
247 const char* filename ///< name of .nl file that is read
248 )
249 : scip(scip_),
250 probdata(NULL),
251 objexpr(NULL),
252 logiccount(0),
253 initsol(NULL),
254 colfile(NULL),
255 rowfile(NULL)
256 {
257 assert(scip != NULL);
258 assert(filename != NULL);
259
261
262 /* get name of input file without file extension (if any) */
263 const char* extstart = strrchr(const_cast<char*>(filename), '.');
264 if( extstart != NULL )
265 probdata->filenamestublen = extstart - filename;
266 else
267 probdata->filenamestublen = strlen(filename);
268 assert(probdata->filenamestublen > 0);
269 SCIP_CALL_THROW( SCIPallocBlockMemoryArray(scip, &probdata->filenamestub, probdata->filenamestublen + 5) );
270 memcpy(probdata->filenamestub, filename, probdata->filenamestublen);
271 probdata->filenamestub[probdata->filenamestublen] = '\0';
272
273 /* derive probname from name of input file without path and extension */
274 const char* probname = strrchr(probdata->filenamestub, '/');
275 if( probname == NULL )
276 probname = probdata->filenamestub;
277 else
278 ++probname;
279
280 // initialize empty SCIP problem
281 SCIP_CALL_THROW( SCIPcreateProb(scip, probname, probdataDelOrigNl, NULL, NULL, NULL, NULL, NULL, probdata) );
282
283 // try to open files with variable and constraint names
284 // temporarily add ".col" and ".row", respectively, to filenamestub
285 try
286 {
287 probdata->filenamestub[probdata->filenamestublen] = '.';
288 probdata->filenamestub[probdata->filenamestublen+1] = 'c';
289 probdata->filenamestub[probdata->filenamestublen+2] = 'o';
290 probdata->filenamestub[probdata->filenamestublen+3] = 'l';
291 probdata->filenamestub[probdata->filenamestublen+4] = '\0';
292 colfile = new fmt::File(probdata->filenamestub, fmt::File::RDONLY);
293
294 probdata->filenamestub[probdata->filenamestublen+1] = 'r';
295 probdata->filenamestub[probdata->filenamestublen+3] = 'w';
296 rowfile = new fmt::File(probdata->filenamestub, fmt::File::RDONLY);
297 }
298 catch( const fmt::SystemError& e )
299 {
300 // probably a file open error, probably because file not found
301 // ignore, we can make up our own names
302 }
303 probdata->filenamestub[probdata->filenamestublen] = '\0';
304 }
305
308
309 /// destructor
310 ///
311 /// only asserts that cleanup() has been called, as we cannot throw an exception or return a SCIP_RETCODE here
313 {
314 // exprs and linear constraint arrays should have been cleared up in cleanup()
315 assert(varexprs.empty());
316 assert(exprstorelease.empty());
317
318 delete colfile;
319 delete rowfile;
320 }
321
322 /// process header of .nl files
323 ///
324 /// create and add variables, allocate constraints
326 const mp::NLHeader& h ///< header data
327 )
328 {
329 char name[SCIP_MAXSTRLEN];
330 int nnlvars;
331
332 assert(probdata->vars == NULL);
333 assert(probdata->conss == NULL);
334
335 probdata->namplopts = h.num_ampl_options;
336 BMScopyMemoryArray(probdata->amplopts, h.ampl_options, h.num_ampl_options);
337
338 // read variable and constraint names from file, if available, into memory
339 // if not available, we will get varnamesbegin==NULL and consnamesbegin==NULL
340 mp::MemoryMappedFile<> mapped_colfile;
341 if( colfile != NULL )
342 mapped_colfile.map(*colfile, "colfile");
343 const char* varnamesbegin = mapped_colfile.start();
344 const char* varnamesend = mapped_colfile.start() + mapped_colfile.size();
345
346 mp::MemoryMappedFile<> mapped_rowfile;
347 if( rowfile != NULL )
348 mapped_rowfile.map(*rowfile, "rowfile");
349 const char* consnamesbegin = mapped_rowfile.start();
350 const char* consnamesend = mapped_rowfile.start() + mapped_rowfile.size();
351
352 probdata->nvars = h.num_vars;
353 SCIP_CALL_THROW( SCIPallocBlockMemoryArray(scip, &probdata->vars, probdata->nvars) );
354
355 // number of nonlinear variables
356 nnlvars = MAX(h.num_nl_vars_in_cons, h.num_nl_vars_in_objs);
357 varexprs.resize(nnlvars);
358
359 // create variables
360 // create variable expressions for nonlinear variables
361 for( int i = 0; i < h.num_vars; ++i )
362 {
363 SCIP_VARTYPE vartype;
364 // Nonlinear variables in both constraints and objective
365 if( i < h.num_nl_vars_in_both - h.num_nl_integer_vars_in_both )
366 vartype = SCIP_VARTYPE_CONTINUOUS;
367 else if( i < h.num_nl_vars_in_both )
368 vartype = SCIP_VARTYPE_INTEGER;
369 // Nonlinear variables in constraints
370 else if( i < h.num_nl_vars_in_cons - h.num_nl_integer_vars_in_cons )
371 vartype = SCIP_VARTYPE_CONTINUOUS;
372 else if( i < h.num_nl_vars_in_cons )
373 vartype = SCIP_VARTYPE_INTEGER;
374 // Nonlinear variables in objective
375 else if( i < h.num_nl_vars_in_objs - h.num_nl_integer_vars_in_objs )
376 vartype = SCIP_VARTYPE_CONTINUOUS;
377 else if( i < h.num_nl_vars_in_objs )
378 vartype = SCIP_VARTYPE_INTEGER;
379 // Linear variables
380 else if( i < h.num_vars - h.num_linear_binary_vars - h.num_linear_integer_vars )
381 vartype = SCIP_VARTYPE_CONTINUOUS;
382 else if( i < h.num_vars - h.num_linear_integer_vars )
383 vartype = SCIP_VARTYPE_BINARY;
384 else
385 vartype = SCIP_VARTYPE_INTEGER;
386
387 if( !nextName(varnamesbegin, varnamesend, name) )
388 {
389 // make up name if no names file or could not be read
390 switch( vartype )
391 {
393 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "b%d", i);
394 break;
396 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "i%d", i);
397 break;
399 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "x%d", i);
400 break;
401 // coverity[deadcode]
402 default:
403 SCIPABORT();
404 break;
405 }
406 }
407
408 SCIP_CALL_THROW( SCIPcreateVarBasic(scip, &probdata->vars[i], name,
409 vartype == SCIP_VARTYPE_BINARY ? 0.0 : -SCIPinfinity(scip),
410 vartype == SCIP_VARTYPE_BINARY ? 1.0 : SCIPinfinity(scip),
411 0.0, vartype) );
412 SCIP_CALL_THROW( SCIPaddVar(scip, probdata->vars[i]) );
413
414 if( i < nnlvars )
415 {
416 SCIP_CALL_THROW( SCIPcreateExprVar(scip, &varexprs[i], probdata->vars[i], NULL, NULL) );
417 }
418 }
419
420 // alloc some space for algebraic constraints
421 probdata->nconss = h.num_algebraic_cons;
422 SCIP_CALL_THROW( SCIPallocBlockMemoryArray(scip, &probdata->conss, probdata->nconss) );
423 nlconslin.resize(h.num_nl_cons);
424
425 // create empty nonlinear constraints
426 // use expression == 0, because nonlinear constraint don't like to be without an expression
427 SCIP_EXPR* dummyexpr;
428 SCIP_CALL_THROW( SCIPcreateExprValue(scip, &dummyexpr, 0.0, NULL, NULL) );
429 for( int i = 0; i < h.num_nl_cons; ++i )
430 {
431 // make up name if no names file or could not be read
432 if( !nextName(consnamesbegin, consnamesend, name) )
433 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nlc%d", i);
434
435 SCIP_CALL_THROW( SCIPcreateConsBasicNonlinear(scip, &probdata->conss[i], name, dummyexpr, -SCIPinfinity(scip), SCIPinfinity(scip)) );
436 }
437 SCIP_CALL_THROW( SCIPreleaseExpr(scip, &dummyexpr) );
438
439 // create empty linear constraints
440 for( int i = h.num_nl_cons; i < h.num_algebraic_cons; ++i )
441 {
442 if( !nextName(consnamesbegin, consnamesend, name) )
443 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "lc%d", i);
445 }
446
447 if( h.num_nl_cons == 0 && h.num_logical_cons == 0 && h.num_integer_vars() == 0 )
448 probdata->islp = true;
449
450 // alloc space for common expressions
451 commonexprs.resize(h.num_common_exprs());
452 }
453
454 /// receive notification of a number in a nonlinear expression
456 double value ///< value
457 )
458 {
459 SCIP_EXPR* expr;
460
462
463 // remember that we have to release this expr
464 exprstorelease.push_back(expr);
465
466 return expr;
467 }
468
469 /// receive notification of a variable reference in a nonlinear expression
471 int variableIndex ///< AMPL index of variable
472 )
473 {
474 assert(variableIndex >= 0);
475 assert(variableIndex < (int)varexprs.size());
476 assert(varexprs[variableIndex] != NULL);
477
478 return varexprs[variableIndex];
479 }
480
481 /// receive notification of a unary expression
483 mp::expr::Kind kind, ///< expression operator
484 SCIP_EXPR* child ///< argument
485 )
486 {
487 SCIP_EXPR* expr;
488
489 assert(child != NULL);
490
491 switch( kind )
492 {
493 case mp::expr::MINUS:
494 {
495 SCIP_Real minusone = -1.0;
496 SCIP_CALL_THROW( SCIPcreateExprSum(scip, &expr, 1, &child, &minusone, 0.0, NULL, NULL) );
497 break;
498 }
499
500 case mp::expr::ABS:
501 SCIP_CALL_THROW( SCIPcreateExprAbs(scip, &expr, child, NULL, NULL) );
502 break;
503
504 case mp::expr::POW2:
505 SCIP_CALL_THROW( SCIPcreateExprPow(scip, &expr, child, 2.0, NULL, NULL) );
506 break;
507
508 case mp::expr::SQRT:
509 SCIP_CALL_THROW( SCIPcreateExprPow(scip, &expr, child, 0.5, NULL, NULL) );
510 break;
511
512 case mp::expr::LOG:
513 SCIP_CALL_THROW( SCIPcreateExprLog(scip, &expr, child, NULL, NULL) );
514 break;
515
516 case mp::expr::LOG10: // 1/log(10)*log(child)
517 {
518 SCIP_EXPR* logexpr;
519 SCIP_Real factor = 1.0/log(10.0);
520 SCIP_CALL_THROW( SCIPcreateExprLog(scip, &logexpr, child, NULL, NULL) );
521 SCIP_CALL_THROW( SCIPcreateExprSum(scip, &expr, 1, &logexpr, &factor, 0.0, NULL, NULL) );
523 break;
524 }
525
526 case mp::expr::EXP:
527 SCIP_CALL_THROW( SCIPcreateExprExp(scip, &expr, child, NULL, NULL) );
528 break;
529
530 case mp::expr::SIN:
531 SCIP_CALL_THROW( SCIPcreateExprSin(scip, &expr, child, NULL, NULL) );
532 break;
533
534 case mp::expr::COS:
535 SCIP_CALL_THROW( SCIPcreateExprCos(scip, &expr, child, NULL, NULL) );
536 break;
537
538 default:
539 OnUnhandled(mp::expr::str(kind));
540 return NULL;
541 }
542
543 // remember that we have to release this expr
544 exprstorelease.push_back(expr);
545
546 return expr;
547 }
548
549 /// receive notification of a binary expression
551 mp::expr::Kind kind, ///< expression operand
552 SCIP_EXPR* firstChild, ///< first argument
553 SCIP_EXPR* secondChild ///< second argument
554 )
555 {
556 SCIP_EXPR* expr;
557 SCIP_EXPR* children[2] = { firstChild, secondChild };
558
559 assert(firstChild != NULL);
560 assert(secondChild != NULL);
561
562 switch( kind )
563 {
564 case mp::expr::ADD:
565 SCIP_CALL_THROW( SCIPcreateExprSum(scip, &expr, 2, children, NULL, 0.0, NULL, NULL) );
566 break;
567
568 case mp::expr::SUB:
569 {
570 SCIP_Real coefs[2] = { 1.0, -1.0 };
571 SCIP_CALL_THROW( SCIPcreateExprSum(scip, &expr, 2, children, coefs, 0.0, NULL, NULL) );
572 break;
573 }
574
575 case mp::expr::MUL:
576 SCIP_CALL_THROW( SCIPcreateExprProduct(scip, &expr, 2, children, 1.0, NULL, NULL) );
577 break;
578
579 case mp::expr::DIV:
580 SCIP_CALL_THROW( SCIPcreateExprPow(scip, &children[1], secondChild, -1.0, NULL, NULL) );
581 SCIP_CALL_THROW( SCIPcreateExprProduct(scip, &expr, 2, children, 1.0, NULL, NULL) );
582 SCIP_CALL_THROW( SCIPreleaseExpr(scip, &children[1]) );
583 break;
584
585 case mp::expr::POW_CONST_BASE:
586 case mp::expr::POW_CONST_EXP:
587 case mp::expr::POW:
588 // with some .nl files, we seem to get mp::expr::POW even if base or exponent is constant,
589 // so do not rely on kind but better check expr type
590 if( SCIPisExprValue(scip, secondChild) )
591 {
592 SCIP_CALL_THROW( SCIPcreateExprPow(scip, &expr, firstChild, SCIPgetValueExprValue(secondChild), NULL, NULL) );
593 break;
594 }
595
596 if( SCIPisExprValue(scip, firstChild) && SCIPgetValueExprValue(firstChild) > 0.0 )
597 {
598 // reformulate constant^y as exp(y*log(constant)), if constant > 0.0
599 // if constant < 0, we create an expression and let cons_nonlinear figure out infeasibility somehow
600 SCIP_EXPR* prod;
601
602 SCIP_Real coef = log(SCIPgetValueExprValue(firstChild)); // log(firstChild)
603 SCIP_CALL_THROW( SCIPcreateExprSum(scip, &prod, 1, &secondChild, &coef, 0.0, NULL, NULL) ); // log(firstChild)*secondChild
604 SCIP_CALL_THROW( SCIPcreateExprExp(scip, &expr, prod, NULL, NULL) ); // expr(log(firstChild)*secondChild)
605
607 break;
608 }
609
610 {
611 // reformulate x^y as exp(y*log(x))
612 SCIP_EXPR* prod;
613
614 assert(SCIPisExprValue(scip, secondChild));
615
616 SCIP_CALL_THROW( SCIPcreateExprLog(scip, &children[0], firstChild, NULL, NULL) ); // log(firstChild)
617 SCIP_CALL_THROW( SCIPcreateExprProduct(scip, &prod, 2, children, 1.0, NULL, NULL) ); // log(firstChild)*secondChild
618 SCIP_CALL_THROW( SCIPcreateExprExp(scip, &expr, prod, NULL, NULL) ); // expr(log(firstChild)*secondChild)
619
621 SCIP_CALL_THROW( SCIPreleaseExpr(scip, &children[0]) );
622 break;
623 }
624
625 default:
626 OnUnhandled(mp::expr::str(kind));
627 return NULL;
628 }
629
630 // remember that we have to release this expr
631 exprstorelease.push_back(expr);
632
633 return expr;
634 }
635
636 /// handler to create a list of terms in a sum
637 ///
638 /// NumericArgHandler is copied around, so it keeps only a pointer (with reference counting) to actual data
640 {
641 public:
642 std::shared_ptr<std::vector<SCIP_EXPR*> > v;
643
644 /// constructor
646 int num_args ///< number of terms to expect
647 )
648 : v(new std::vector<SCIP_EXPR*>())
649 {
650 v->reserve(num_args);
651 }
652
653 /// adds term to sum
654 void AddArg(
655 SCIP_EXPR* term ///< term to add
656 )
657 {
658 v->push_back(term);
659 }
660 };
661
662 /// receive notification of the beginning of a summation
664 int num_args ///< number of terms to expect
665 )
666 {
667 NumericArgHandler h(num_args);
668 return h;
669 }
670
671 /// receive notification of the end of a summation
673 NumericArgHandler handler ///< handler that handled the sum
674 )
675 {
676 SCIP_EXPR* expr;
677 SCIP_CALL_THROW( SCIPcreateExprSum(scip, &expr, (int)handler.v->size(), handler.v->data(), NULL, 0.0, NULL, NULL) );
678 // remember that we have to release this expr
679 exprstorelease.push_back(expr);
680 return expr;
681 }
682
683 /// receive notification of an objective type and the nonlinear part of an objective expression
684 void OnObj(
685 int objectiveIndex, ///< index of objective
686 mp::obj::Type type, ///< objective sense
687 SCIP_EXPR* nonlinearExpression ///< nonlinear part of objective function
688 )
689 {
690 if( objectiveIndex >= 1 )
691 OnUnhandled("multiple objective functions");
692
694
695 assert(objexpr == NULL);
696
697 if( nonlinearExpression != NULL && SCIPisExprValue(scip, nonlinearExpression) )
698 {
699 // handle objective constant by adding a fixed variable for it
700 SCIP_VAR* objconstvar;
701 SCIP_Real objconst = SCIPgetValueExprValue(nonlinearExpression);
702
703 SCIP_CALL_THROW( SCIPcreateVarBasic(scip, &objconstvar, "objconstant", objconst, objconst, 1.0, SCIP_VARTYPE_CONTINUOUS) );
704 SCIP_CALL_THROW( SCIPaddVar(scip, objconstvar) );
705 SCIP_CALL_THROW( SCIPreleaseVar(scip, &objconstvar) );
706 }
707 else
708 {
709 objexpr = nonlinearExpression;
710 }
711 }
712
713 /// receive notification of an algebraic constraint expression
715 int constraintIndex, ///< index of constraint
716 SCIP_EXPR* expr ///< nonlinear part of constraint
717 )
718 {
719 if( expr != NULL )
720 {
721 SCIP_CALL_THROW( SCIPchgExprNonlinear(scip, probdata->conss[constraintIndex], expr) );
722 }
723 }
724
725 /// receives notification of a logical constraint expression
727 int index,
728 LogicalExpr expr
729 )
730 {
731 if( expr != NULL )
732 {
733 SCIP_CONS* cons;
734 SCIP_CALL_THROW( SCIPcreateConsBasicNonlinear(scip, &cons, "logiccons", expr, 1.0, 1.0) );
737 }
738 }
739
740 /// handles linear part of a common expression
741 /// sets up a sum expression, if the linear part isn't empty
743 {
744 private:
745 AMPLProblemHandler& amplph;
746 SCIP_EXPR* commonexpr;
747
748 public:
749 /// constructor
751 AMPLProblemHandler& amplph_, ///< problem handler
752 int index, ///< index of common expression
753 int num_linear_terms///< number of terms to expect
754 )
755 : amplph(amplph_),
756 commonexpr(NULL)
757 {
758 if( num_linear_terms > 0 )
759 {
760 SCIP_CALL_THROW( SCIPcreateExprSum(amplph.scip, &commonexpr, 0, NULL, NULL, 0.0, NULL, NULL) );
761 amplph.commonexprs[index] = commonexpr;
762 amplph.exprstorelease.push_back(commonexpr);
763 }
764 }
765
766 /// receives notification of a term in the linear expression
768 int var_index, ///< AMPL index of variable
769 double coef ///< variable coefficient
770 )
771 {
772 assert(commonexpr != NULL);
773
774 if( coef == 0.0 )
775 return;
776
777 if( var_index < (int)amplph.varexprs.size() )
778 {
779 SCIP_CALL_THROW( SCIPappendExprSumExpr(amplph.scip, commonexpr, amplph.varexprs[var_index], coef) );
780 }
781 else
782 {
783 // the index variable is linear (not sure this can happen here)
784 assert(var_index < amplph.probdata->nvars);
785 SCIP_EXPR* varexpr;
786 SCIP_CALL_THROW( SCIPcreateExprVar(amplph.scip, &varexpr, amplph.probdata->vars[var_index], NULL, NULL) );
787 SCIP_CALL_THROW( SCIPappendExprSumExpr(amplph.scip, commonexpr, varexpr, coef) );
788 SCIP_CALL_THROW( SCIPreleaseExpr(amplph.scip, &varexpr) );
789 }
790 }
791 };
792
793 /// receive notification of the beginning of a common expression (defined variable)
795 int index, ///< index of common expression
796 int num_linear_terms ///< number of terms to expect
797 )
798 {
799 assert(index >= 0);
800 assert(index < (int)commonexprs.size());
801
802 return LinearExprHandler(*this, index, num_linear_terms);
803 }
804
805 /// receive notification of the end of a common expression
807 int index, ///< index of common expression
808 SCIP_EXPR* expr, ///< nonlinear part of common expression
809 int /* position */ ///< argument that doesn't seem to have any purpose
810 )
811 {
812 if( commonexprs[index] != NULL )
813 {
814 // add expr, if any, to linear part
815 if( expr != NULL )
816 {
817 SCIP_CALL_THROW( SCIPappendExprSumExpr(scip, commonexprs[index], expr, 1.0) );
818 }
819 }
820 else if( expr != NULL )
821 {
822 commonexprs[index] = expr;
823 }
824 }
825
826 /// receive notification of a common expression (defined variable) reference
828 int expr_index ///< index of common expression
829 )
830 {
831 assert(expr_index >= 0);
832 assert(expr_index < (int)commonexprs.size());
833 assert(commonexprs[expr_index] != NULL);
834 return commonexprs[expr_index];
835 }
836
837 /// receive notification of variable bounds
839 int variableIndex, ///< AMPL index of variable
840 double variableLB, ///< variable lower bound
841 double variableUB ///< variable upper bound
842 )
843 {
844 assert(variableIndex >= 0);
845 assert(variableIndex < probdata->nvars);
846
847 // as far as I see, ampl::mp gives -inf, +inf for no-bounds, which is always beyond SCIPinfinity()
848 // we ignore bounds outside [-scipinfinity,scipinfinity] here
849 // for binary variables, we also ignore bounds outside [0,1]
850 if( variableLB > (SCIPvarGetType(probdata->vars[variableIndex]) == SCIP_VARTYPE_BINARY ? 0.0 : -SCIPinfinity(scip)) )
851 {
852 SCIP_CALL_THROW( SCIPchgVarLbGlobal(scip, probdata->vars[variableIndex], variableLB) );
853 }
854 if( variableUB < (SCIPvarGetType(probdata->vars[variableIndex]) == SCIP_VARTYPE_BINARY ? 1.0 : SCIPinfinity(scip)) )
855 {
856 SCIP_CALL_THROW( SCIPchgVarUbGlobal(scip, probdata->vars[variableIndex], variableUB) );
857 }
858 }
859
860 /// receive notification of constraint sides
862 int index, ///< AMPL index of constraint
863 double lb, ///< constraint left-hand-side
864 double ub ///< constraint right-hand-side
865 )
866 {
867 assert(index >= 0);
868 assert(index < probdata->nconss);
869
870 // nonlinear constraints are first
871 if( index < (int)nlconslin.size() )
872 {
873 if( !SCIPisInfinity(scip, -lb) )
874 {
875 SCIP_CALL_THROW( SCIPchgLhsNonlinear(scip, probdata->conss[index], lb) );
876 }
877 if( !SCIPisInfinity(scip, ub) )
878 {
879 SCIP_CALL_THROW( SCIPchgRhsNonlinear(scip, probdata->conss[index], ub) );
880 }
881 }
882 else
883 {
884 if( !SCIPisInfinity(scip, -lb) )
885 {
886 SCIP_CALL_THROW( SCIPchgLhsLinear(scip, probdata->conss[index], lb) );
887 }
888 if( !SCIPisInfinity(scip, ub) )
889 {
890 SCIP_CALL_THROW( SCIPchgRhsLinear(scip, probdata->conss[index], ub) );
891 }
892 }
893 }
894
895 /// receive notification of the initial value for a variable
897 int var_index, ///< AMPL index of variable
898 double value ///< initial primal value of variable
899 )
900 {
901 if( initsol == NULL )
902 {
903 SCIP_CALL_THROW( SCIPcreateSol(scip, &initsol, NULL) );
904 }
905
906 SCIP_CALL_THROW( SCIPsetSolVal(scip, initsol, probdata->vars[var_index], value) );
907 }
908
909 /// receives notification of the initial value for a dual variable
911 int /* con_index */, ///< AMPL index of constraint
912 double /* value */ ///< initial dual value of constraint
913 )
914 {
915 // ignore initial dual value
916 }
917
918 /// receives notification of Jacobian column sizes
919 ColumnSizeHandler OnColumnSizes()
920 {
921 /// use ColumnSizeHandler from upper class, which does nothing
922 return ColumnSizeHandler();
923 }
924
925 /// handling of suffices for variable and constraint flags and SOS constraints
926 ///
927 /// regarding SOS in AMPL, see https://ampl.com/faqs/how-can-i-use-the-solvers-special-ordered-sets-feature/
928 /// we pass the .ref suffix as weight to the SOS constraint handlers
929 /// for a SOS2, the weights determine the order of variables in the set
930 template<typename T> class SuffixHandler
931 {
932 private:
933 AMPLProblemHandler& amplph;
934
935 // type of suffix that is handled, or IGNORE if unsupported suffix
936 enum
937 {
938 IGNORE,
939 CONSINITIAL,
940 CONSSEPARATE,
941 CONSENFORCE,
942 CONSCHECK,
943 CONSPROPAGATE,
944 CONSDYNAMIC,
945 CONSREMOVABLE,
946 VARINITIAL,
947 VARREMOVABLE,
948 VARSOSNO,
949 VARREF,
950 } suffix;
951
952 public:
953 /// constructor
955 AMPLProblemHandler& amplph_, ///< problem handler
956 fmt::StringRef name, ///< name of suffix
957 mp::suf::Kind kind ///< whether suffix applies to var, cons, etc
958 )
959 : amplph(amplph_),
960 suffix(IGNORE)
961 {
962 switch( kind )
963 {
964 case mp::suf::Kind::CON:
965 if( strncmp(name.data(), "initial", name.size()) == 0 )
966 {
967 suffix = CONSINITIAL;
968 }
969 else if( strncmp(name.data(), "separate", name.size()) == 0 )
970 {
971 suffix = CONSSEPARATE;
972 }
973 else if( strncmp(name.data(), "enforce", name.size()) == 0 )
974 {
975 suffix = CONSENFORCE;
976 }
977 else if( strncmp(name.data(), "check", name.size()) == 0 )
978 {
979 suffix = CONSCHECK;
980 }
981 else if( strncmp(name.data(), "propagate", name.size()) == 0 )
982 {
983 suffix = CONSPROPAGATE;
984 }
985 else if( strncmp(name.data(), "dynamic", name.size()) == 0 )
986 {
987 suffix = CONSDYNAMIC;
988 }
989 else if( strncmp(name.data(), "removable", name.size()) == 0 )
990 {
991 suffix = CONSREMOVABLE;
992 }
993 else
994 {
995 SCIPverbMessage(amplph.scip, SCIP_VERBLEVEL_HIGH, NULL, "Unknown constraint suffix <%.*s>. Ignoring.\n", (int)name.size(), name.data());
996 }
997 break;
998
999 case mp::suf::Kind::CON_BIT:
1000 SCIPverbMessage(amplph.scip, SCIP_VERBLEVEL_HIGH, NULL, "Unknown constraint bit suffix <%.*s>. Ignoring.\n", (int)name.size(), name.data());
1001 break;
1002
1003 case mp::suf::Kind::VAR:
1004 {
1005 if( strncmp(name.data(), "initial", name.size()) == 0 )
1006 {
1007 suffix = VARINITIAL;
1008 }
1009 else if( strncmp(name.data(), "removable", name.size()) == 0 )
1010 {
1011 suffix = VARREMOVABLE;
1012 }
1013 else if( strncmp(name.data(), "sosno", name.size()) == 0 )
1014 {
1015 // SOS membership
1016 suffix = VARSOSNO;
1017 }
1018 else if( strncmp(name.data(), "ref", name.size()) == 0 )
1019 {
1020 // SOS weights
1021 suffix = VARREF;
1022 amplph.sosweights.resize(amplph.probdata->nvars, 0);
1023 }
1024 else
1025 {
1026 SCIPverbMessage(amplph.scip, SCIP_VERBLEVEL_HIGH, NULL, "Unknown variable suffix <%.*s>. Ignoring.\n", (int)name.size(), name.data());
1027 }
1028 break;
1029
1030 case mp::suf::Kind::VAR_BIT:
1031 SCIPverbMessage(amplph.scip, SCIP_VERBLEVEL_HIGH, NULL, "Unknown variable bit suffix <%.*s>. Ignoring.\n", (int)name.size(), name.data());
1032 break;
1033
1034 case mp::suf::Kind::OBJ:
1035 SCIPverbMessage(amplph.scip, SCIP_VERBLEVEL_HIGH, NULL, "Unknown objective suffix <%.*s>. Ignoring.\n", (int)name.size(), name.data());
1036 break;
1037
1038 case mp::suf::Kind::OBJ_BIT:
1039 SCIPverbMessage(amplph.scip, SCIP_VERBLEVEL_HIGH, NULL, "Unknown objective bit suffix <%.*s>. Ignoring.\n", (int)name.size(), name.data());
1040 break;
1041
1043 SCIPverbMessage(amplph.scip, SCIP_VERBLEVEL_HIGH, NULL, "Unknown problem suffix <%.*s>. Ignoring.\n", (int)name.size(), name.data());
1044 break;
1045
1046 case mp::suf::Kind::PROB_BIT:
1047 SCIPverbMessage(amplph.scip, SCIP_VERBLEVEL_HIGH, NULL, "Unknown problem bit suffix <%.*s>. Ignoring.\n", (int)name.size(), name.data());
1048 break;
1049 }
1050 }
1051 }
1052
1054 int index, ///< index of variable, constraint, etc
1055 T value ///< value of suffix
1056 )
1057 {
1058 assert(index >= 0);
1059 switch( suffix )
1060 {
1061 case IGNORE :
1062 return;
1063
1064 case CONSINITIAL:
1065 SCIP_CALL_THROW( SCIPsetConsInitial(amplph.scip, amplph.probdata->conss[index], value == 1) );
1066 break;
1067
1068 case CONSSEPARATE:
1069 SCIP_CALL_THROW( SCIPsetConsSeparated(amplph.scip, amplph.probdata->conss[index], value == 1) );
1070 break;
1071
1072 case CONSENFORCE:
1073 SCIP_CALL_THROW( SCIPsetConsEnforced(amplph.scip, amplph.probdata->conss[index], value == 1) );
1074 break;
1075
1076 case CONSCHECK:
1077 SCIP_CALL_THROW( SCIPsetConsChecked(amplph.scip, amplph.probdata->conss[index], value == 1) );
1078 break;
1079
1080 case CONSPROPAGATE:
1081 SCIP_CALL_THROW( SCIPsetConsPropagated(amplph.scip, amplph.probdata->conss[index], value == 1) );
1082 break;
1083
1084 case CONSDYNAMIC:
1085 SCIP_CALL_THROW( SCIPsetConsDynamic(amplph.scip, amplph.probdata->conss[index], value == 1) );
1086 break;
1087
1088 case CONSREMOVABLE:
1089 SCIP_CALL_THROW( SCIPsetConsRemovable(amplph.scip, amplph.probdata->conss[index], value == 1) );
1090 break;
1091
1092 case VARINITIAL:
1093 assert(index < amplph.probdata->nvars);
1094 SCIP_CALL_THROW( SCIPvarSetInitial(amplph.probdata->vars[index], value == 1) );
1095 break;
1096
1097 case VARREMOVABLE:
1098 assert(index < amplph.probdata->nvars);
1099 SCIP_CALL_THROW( SCIPvarSetRemovable(amplph.probdata->vars[index], value == 1) );
1100 break;
1101
1102 case VARSOSNO:
1103 // remember that variable index belongs to SOS identified by value
1104 amplph.sosvars[(int)value].push_back(index);
1105 break;
1106
1107 case VARREF:
1108 // remember that variable index has weight value
1109 amplph.sosweights[index] = (int)value;
1110 break;
1111 }
1112 }
1113 };
1114
1116 /// receive notification of an integer suffix
1118 fmt::StringRef name, ///< suffix name, not null-terminated
1119 mp::suf::Kind kind, ///< suffix kind
1120 int /*num_values*/ ///< number of values to expect
1121 )
1122 {
1123 return IntSuffixHandler(*this, name, kind);
1124 }
1125
1127 /// receive notification of a double suffix
1129 fmt::StringRef name, ///< suffix name, not null-terminated
1130 mp::suf::Kind kind, ///< suffix kind
1131 int /*num_values*/ ///< number of values to expect
1132 )
1133 {
1134 return DblSuffixHandler(*this, name, kind);
1135 }
1136
1137 /// handles receiving the linear part of an objective or constraint
1138 ///
1139 /// for objective, set the objective-coefficient of the variable
1140 /// for linear constraints, add to the constraint
1141 /// for nonlinear constraints, add to nlconslin vector; adding to constraint later
1143 {
1144 private:
1145 AMPLProblemHandler& amplph;
1146 int constraintIndex;
1147
1148 public:
1149 // constructor for constraint
1151 AMPLProblemHandler& amplph_, ///< problem handler
1152 int constraintIndex_///< constraint index
1153 )
1154 : amplph(amplph_),
1155 constraintIndex(constraintIndex_)
1156 {
1157 assert(constraintIndex_ >= 0);
1158 assert(constraintIndex_ < amplph.probdata->nconss);
1159 }
1160
1161 // constructor for linear objective
1163 AMPLProblemHandler& amplph_ ///< problem handler
1164 )
1165 : amplph(amplph_),
1166 constraintIndex(-1)
1167 { }
1168
1170 int variableIndex, ///< AMPL index of variable
1171 double coefficient ///< coefficient of variable
1172 )
1173 {
1174 assert(variableIndex >= 0);
1175 assert(variableIndex < amplph.probdata->nvars);
1176
1177 if( coefficient == 0.0 )
1178 return;
1179
1180 if( constraintIndex < 0 )
1181 {
1182 SCIP_CALL_THROW( SCIPchgVarObj(amplph.scip, amplph.probdata->vars[variableIndex], coefficient) );
1183 }
1184 else if( constraintIndex < (int)amplph.nlconslin.size() )
1185 {
1186 amplph.nlconslin[constraintIndex].push_back(std::pair<SCIP_Real, SCIP_VAR*>(coefficient, amplph.probdata->vars[variableIndex]));
1187 }
1188 else
1189 {
1190 SCIP_CONS* lincons = amplph.probdata->conss[constraintIndex];
1191 SCIP_CALL_THROW( SCIPaddCoefLinear(amplph.scip, lincons, amplph.probdata->vars[variableIndex], coefficient) );
1192 }
1193 }
1194 };
1195
1197
1198 /// receive notification of the linear part of an objective
1200 int objectiveIndex, ///< index of objective
1201 int /* numLinearTerms *////< number of terms to expect
1202 )
1203 {
1204 if( objectiveIndex >= 1 )
1205 OnUnhandled("multiple objective functions");
1206
1207 return LinearObjHandler(*this);
1208 }
1209
1211
1212 /// receive notification of the linear part of a constraint
1214 int constraintIndex, ///< index of constraint
1215 int /* numLinearTerms *////< number of terms to expect
1216 )
1217 {
1218 return LinearConHandler(*this, constraintIndex);
1219 }
1220
1221 /// receives notification of a `Boolean value <mp::expr::BOOL>`
1222 LogicalExpr OnBool(
1223 bool value
1224 )
1225 {
1226 SCIP_EXPR* expr;
1227
1228 SCIP_CALL_THROW( SCIPcreateExprValue(scip, &expr, value ? 1.0 : 0.0, NULL, NULL) );
1229
1230 // remember that we have to release this expr
1231 exprstorelease.push_back(expr);
1232
1233 return expr;
1234 }
1235
1236 /// receives notification of a `logical not <mp::expr::NOT>`
1237 LogicalExpr OnNot(
1238 LogicalExpr arg
1239 )
1240 {
1241 SCIP_EXPR* expr;
1242 SCIP_VAR* var;
1243 SCIP_Bool val;
1244
1245 LogicalExprToVarVal(arg, var, val);
1246 if( var != NULL )
1247 {
1248 SCIP_CALL_THROW( SCIPgetNegatedVar(scip, var, &var) );
1250 }
1251 else
1252 {
1253 SCIP_CALL_THROW( SCIPcreateExprValue(scip, &expr, val ? 1.0 : 0.0, NULL, NULL) );
1254 }
1255
1256 // remember that we have to release this expr
1257 exprstorelease.push_back(expr);
1258
1259 return expr;
1260 }
1261
1262 /// receives notification of a `binary logical expression <mp::expr::FIRST_BINARY_LOGICAL>`
1263 LogicalExpr OnBinaryLogical(
1264 mp::expr::Kind kind,
1265 LogicalExpr lhs,
1266 LogicalExpr rhs
1267 )
1268 {
1269 SCIP_VAR* lhsvar = NULL;
1270 SCIP_VAR* rhsvar = NULL;
1271 SCIP_Bool lhsval;
1272 SCIP_Bool rhsval;
1273 SCIP_EXPR* expr;
1274
1275 assert(lhs != NULL);
1276 assert(rhs != NULL);
1277
1278 LogicalExprToVarVal(lhs, lhsvar, lhsval);
1279 LogicalExprToVarVal(rhs, rhsvar, rhsval);
1280
1281 switch( kind )
1282 {
1283 case mp::expr::OR:
1284 {
1285 if( lhsvar == NULL && rhsvar == NULL )
1286 {
1287 SCIP_CALL_THROW( SCIPcreateExprValue(scip, &expr, lhsval != 0.0 || rhsval != 0.0 ? 1.0 : 0.0, NULL, NULL) );
1288 exprstorelease.push_back(expr);
1289 break;
1290 }
1291
1292 if( (lhsvar == NULL && lhsval != 0.0) || (rhsvar == NULL && rhsval != 0.0) )
1293 {
1294 /* nonzero or rhs == 1, lhs or nonzero == 1 */
1296 exprstorelease.push_back(expr);
1297 break;
1298 }
1299
1300 if( lhsvar == NULL )
1301 {
1302 /* zero or rhs == rhs */
1303 assert(lhsval == 0.0);
1304 expr = rhs;
1305 break;
1306 }
1307
1308 if( rhsvar == NULL )
1309 {
1310 /* lhs or zero == lhs */
1311 assert(rhsval == 0.0);
1312 expr = lhs;
1313 break;
1314 }
1315
1316 /* create new resvar and constraint resvar = lhsvar or rhsvar */
1317 SCIP_VAR* vars[2];
1318 SCIP_VAR* resvar;
1319 SCIP_CONS* cons;
1320
1321 std::string name = std::string("_logic") + std::to_string((long long)logiccount++);
1322 SCIP_CALL_THROW( SCIPcreateVarBasic(scip, &resvar, name.c_str(), 0.0, 1.0, 0.0, SCIP_VARTYPE_BINARY) );
1323 SCIP_CALL_THROW( SCIPaddVar(scip, resvar) );
1324 SCIP_CALL_THROW( SCIPcreateExprVar(scip, &expr, resvar, NULL, NULL) );
1325 exprstorelease.push_back(expr);
1326
1327 vars[0] = lhsvar;
1328 vars[1] = rhsvar;
1329 name += "def";
1330 SCIP_CALL_THROW( SCIPcreateConsBasicOr(scip, &cons, name.c_str(), resvar, 2, vars) );
1332
1333 SCIP_CALL_THROW( SCIPreleaseVar(scip, &resvar) );
1335
1336 break;
1337 }
1338
1339 case mp::expr::AND:
1340 {
1341 if( lhsvar == NULL && rhsvar == NULL )
1342 {
1343 SCIP_CALL_THROW( SCIPcreateExprValue(scip, &expr, lhsval != 0.0 && rhsval != 0.0 ? 1.0 : 0.0, NULL, NULL) );
1344 exprstorelease.push_back(expr);
1345 break;
1346 }
1347
1348 if( (lhsvar == NULL && lhsval == 0.0) || (rhsvar == NULL && rhsval == 0.0) )
1349 {
1350 /* zero and rhs == 0, lhs and zero == 0 */
1352 exprstorelease.push_back(expr);
1353 break;
1354 }
1355
1356 if( lhsvar == NULL )
1357 {
1358 /* nonzero and rhs == rhs */
1359 assert(lhsval != 0.0);
1360 expr = rhs;
1361 break;
1362 }
1363
1364 if( rhsvar == NULL )
1365 {
1366 /* lhs and nonzero == lhs */
1367 assert(rhsval != 0.0);
1368 expr = lhs;
1369 break;
1370 }
1371
1372 /* create new resvar and constraint resvar = lhsvar and rhsvar */
1373 SCIP_VAR* vars[2];
1374 SCIP_VAR* resvar;
1375 SCIP_CONS* cons;
1376
1377 std::string name = std::string("_logic") + std::to_string((long long)logiccount++);
1378 SCIP_CALL_THROW( SCIPcreateVarBasic(scip, &resvar, name.c_str(), 0.0, 1.0, 0.0, SCIP_VARTYPE_BINARY) );
1379 SCIP_CALL_THROW( SCIPaddVar(scip, resvar) );
1380 SCIP_CALL_THROW( SCIPcreateExprVar(scip, &expr, resvar, NULL, NULL) );
1381 exprstorelease.push_back(expr);
1382
1383 vars[0] = lhsvar;
1384 vars[1] = rhsvar;
1385 name += "def";
1386 SCIP_CALL_THROW( SCIPcreateConsBasicAnd(scip, &cons, name.c_str(), resvar, 2, vars) );
1388
1389 SCIP_CALL_THROW( SCIPreleaseVar(scip, &resvar) );
1391
1392 break;
1393 }
1394
1395 case mp::expr::IFF:
1396 {
1397 // the IFF operator returns 1 if both operands are nonzero or both are zero and returns zero otherwise
1398 // so this is lhs == rhs
1399 if( lhsvar == NULL && rhsvar == NULL )
1400 {
1401 SCIP_CALL_THROW( SCIPcreateExprValue(scip, &expr, lhsval == rhsval ? 1.0 : 0.0, NULL, NULL) );
1402 exprstorelease.push_back(expr);
1403 break;
1404 }
1405
1406 if( lhsvar == NULL )
1407 {
1408 std::swap(lhs, rhs);
1409 std::swap(lhsval, rhsval);
1410 std::swap(lhsvar, rhsvar);
1411 }
1412 assert(lhsvar != NULL);
1413
1414 if( rhsvar == NULL )
1415 {
1416 // expression is lhsvar == true
1417 // so we return lhsvar or ~lhsvar
1418 if( rhsval == TRUE )
1419 {
1420 expr = lhs;
1421 }
1422 else
1423 {
1424 SCIP_CALL_THROW( SCIPgetNegatedVar(scip, lhsvar, &lhsvar) );
1425 SCIP_CALL_THROW( SCIPcreateExprVar(scip, &expr, lhsvar, NULL, NULL) );
1426 exprstorelease.push_back(expr);
1427 }
1428 break;
1429 }
1430
1431 // expressions is lhsvar == rhsvar
1432 // we create a new variable auxvar and add a constraint xor(auxvar, lhsvar, rhsvar, TRUE)
1433 // to ensure auxvar = (lhsvar == rhsvar)
1434 SCIP_VAR* vars[3];
1435 SCIP_CONS* cons;
1436 std::string name = std::string("_logic") + std::to_string((long long)logiccount++);
1437 SCIP_CALL_THROW( SCIPcreateVarBasic(scip, &vars[0], name.c_str(), 0.0, 1.0, 0.0, SCIP_VARTYPE_BINARY) );
1438 SCIP_CALL_THROW( SCIPaddVar(scip, vars[0]) );
1439 SCIP_CALL_THROW( SCIPcreateExprVar(scip, &expr, vars[0], NULL, NULL) );
1440 exprstorelease.push_back(expr);
1441
1442 vars[1] = lhsvar;
1443 vars[2] = rhsvar;
1444 name += "def";
1445 SCIP_CALL_THROW( SCIPcreateConsBasicXor(scip, &cons, name.c_str(), TRUE, 3, vars) );
1447
1448 SCIP_CALL_THROW( SCIPreleaseVar(scip, &vars[0]) );
1450
1451 break;
1452 }
1453
1454 default:
1455 OnUnhandled(mp::expr::str(kind));
1456 return NULL;
1457 }
1458
1459 return expr;
1460 }
1461
1462 /// receives notification of a `relational expression <mp::expr::FIRST_RELATIONAL>`
1463 /// we only handle equality or inequality between binary variables and boolean values here
1464 LogicalExpr OnRelational(
1465 mp::expr::Kind kind,
1466 NumericExpr lhs,
1467 NumericExpr rhs
1468 )
1469 {
1470 SCIP_VAR* lhsvar = NULL;
1471 SCIP_VAR* rhsvar = NULL;
1472 SCIP_Bool lhsval;
1473 SCIP_Bool rhsval;
1474 SCIP_EXPR* expr;
1475
1476 assert(lhs != NULL);
1477 assert(rhs != NULL);
1478
1479 LogicalExprToVarVal(lhs, lhsvar, lhsval);
1480 LogicalExprToVarVal(rhs, rhsvar, rhsval);
1481
1482 switch( kind )
1483 {
1484 case mp::expr::EQ:
1485 case mp::expr::NE:
1486 {
1487 bool isne = (kind == mp::expr::NE);
1488 if( lhsvar == NULL && rhsvar == NULL )
1489 {
1490 SCIP_CALL_THROW( SCIPcreateExprValue(scip, &expr, lhsval == rhsval ? (isne ? 0.0 : 1.0) : (isne ? 1.0 : 0.0), NULL, NULL) );
1491 exprstorelease.push_back(expr);
1492 break;
1493 }
1494
1495 if( lhsvar == NULL )
1496 {
1497 std::swap(lhs, rhs);
1498 std::swap(lhsval, rhsval);
1499 std::swap(lhsvar, rhsvar);
1500 }
1501 assert(lhsvar != NULL);
1502
1503 if( rhsvar == NULL )
1504 {
1505 // expression is lhsvar == true or lhsvar == false if EQ
1506 // so we return lhsvar or ~lhsvar, opposite if NE
1507 if( rhsval == (isne ? FALSE : TRUE) )
1508 {
1509 expr = lhs;
1510 }
1511 else
1512 {
1513 SCIP_CALL_THROW( SCIPgetNegatedVar(scip, lhsvar, &lhsvar) );
1514 SCIP_CALL_THROW( SCIPcreateExprVar(scip, &expr, lhsvar, NULL, NULL) );
1515 exprstorelease.push_back(expr);
1516 }
1517 break;
1518 }
1519
1520 // expressions is lhsvar == rhsvar or lhsvar != rhsvar
1521 // we create a new variable auxvar and add a constraint xor(auxvar, lhsvar, rhsvar, isne ? FALSE : TRUE)
1522 // to ensure auxvar = (lhsvar == rhsvar) or auxvar = (lhsvar != rhsvar)
1523
1524 SCIP_VAR* vars[3];
1525 SCIP_CONS* cons;
1526 std::string name = std::string("_logic") + std::to_string((long long)logiccount++);
1527 SCIP_CALL_THROW( SCIPcreateVarBasic(scip, &vars[0], name.c_str(), 0.0, 1.0, 0.0, SCIP_VARTYPE_BINARY) );
1528 SCIP_CALL_THROW( SCIPaddVar(scip, vars[0]) );
1529 SCIP_CALL_THROW( SCIPcreateExprVar(scip, &expr, vars[0], NULL, NULL) );
1530 exprstorelease.push_back(expr);
1531
1532 vars[1] = lhsvar;
1533 vars[2] = rhsvar;
1534 name += "def";
1535 SCIP_CALL_THROW( SCIPcreateConsBasicXor(scip, &cons, name.c_str(), isne ? FALSE : TRUE, 3, vars) );
1537
1538 SCIP_CALL_THROW( SCIPreleaseVar(scip, &vars[0]) );
1540
1541 break;
1542 }
1543
1544 default:
1545 OnUnhandled(mp::expr::str(kind));
1546 return NULL;
1547 }
1548
1549 return expr;
1550 }
1551
1552 /// receive notification of the end of the input
1553 ///
1554 /// - setup all nonlinear constraints and add them to SCIP
1555 /// - add linear constraints to SCIP (should be after nonlinear ones to respect order in .nl file)
1556 /// - add initial solution, if initial values were given
1558 {
1559 // turn nonlinear objective into constraint
1560 // min f(x) -> min z s.t. f(x) - z <= 0
1561 // max f(x) -> max z s.t. 0 <= f(x) - z
1562 if( objexpr != NULL )
1563 {
1564 SCIP_CONS* objcons;
1565 SCIP_VAR* objvar;
1566
1568 SCIP_CALL_THROW( SCIPaddVar(scip, objvar) );
1569
1570 SCIP_CALL_THROW( SCIPcreateConsBasicNonlinear(scip, &objcons, "objcons", objexpr,
1573 SCIP_CALL_THROW( SCIPaddLinearVarNonlinear(scip, objcons, objvar, -1.0) );
1574 SCIP_CALL_THROW( SCIPaddCons(scip, objcons) );
1575
1576 if( initsol != NULL )
1577 {
1578 /* compute value for objvar in initial solution from other variable values */
1579 SCIP_CALL_THROW( SCIPevalExpr(scip, objexpr, initsol, 0) );
1580 if( SCIPexprGetEvalValue(objexpr) != SCIP_INVALID )
1581 {
1582 SCIPsetSolVal(scip, initsol, objvar, SCIPexprGetEvalValue(objexpr));
1583 }
1584 else
1585 {
1586 SCIPwarningMessage(scip, "Objective function could not be evaluated in initial point. Domain error.");
1587 }
1588 }
1589
1590 SCIP_CALL_THROW( SCIPreleaseCons(scip, &objcons) );
1591 SCIP_CALL_THROW( SCIPreleaseVar(scip, &objvar) );
1592 }
1593
1594 // add linear terms to expressions of nonlinear constraints (should be ok to do this one-by-one for now)
1595 for( size_t i = 0; i < nlconslin.size(); ++i )
1596 {
1597 for( size_t j = 0; j < nlconslin[i].size(); ++j )
1598 {
1599 SCIP_CALL_THROW( SCIPaddLinearVarNonlinear(scip, probdata->conss[i], nlconslin[i][j].second, nlconslin[i][j].first) );
1600 }
1601 }
1602
1603 // add constraints
1604 for( int i = 0; i < probdata->nconss; ++i )
1605 {
1606 SCIP_CALL_THROW( SCIPaddCons(scip, probdata->conss[i]) );
1607 }
1608
1609 // add SOS constraints
1610 std::vector<SCIP_VAR*> setvars; // variables in one SOS
1611 std::vector<SCIP_Real> setweights; // weights for one SOS
1612 if( !sosvars.empty() )
1613 {
1614 setvars.resize(probdata->nvars);
1615 probdata->islp = false;
1616 }
1617 if( !sosweights.empty() )
1618 setweights.resize(probdata->nvars);
1619 for( std::map<int, std::vector<int> >::iterator sosit(sosvars.begin()); sosit != sosvars.end(); ++sosit )
1620 {
1621 assert(sosit->first != 0);
1622 assert(!sosit->second.empty());
1623
1624 // a negative SOS identifier means SOS2
1625 bool issos2 = sosit->first < 0;
1626
1627 if( issos2 && sosweights.empty() )
1628 {
1629 // if no .ref suffix was given for a SOS2 constraint, then we consider this as an error
1630 // since the weights determine the order
1631 // for a SOS1, the weights only specify branching preference, so can treat them as optional
1632 OnUnhandled("SOS2 requires variable .ref suffix");
1633 }
1634
1635 for( size_t i = 0; i < sosit->second.size(); ++i )
1636 {
1637 int varidx = sosit->second[i];
1638 setvars[i] = probdata->vars[varidx];
1639
1640 if( issos2 && sosweights[varidx] == 0 )
1641 // 0 is the default if no ref was given for a variable; we don't allow this for SOS2
1642 OnUnhandled("Missing .ref value for SOS2 variable");
1643 if( !sosweights.empty() )
1644 setweights[i] = (SCIP_Real)sosweights[varidx];
1645 }
1646
1647 SCIP_CONS* cons;
1648 char name[20];
1649 if( !issos2 )
1650 {
1651 (void) SCIPsnprintf(name, 20, "sos1_%d", sosit->first);
1652 SCIP_CALL_THROW( SCIPcreateConsBasicSOS1(scip, &cons, name, sosit->second.size(), setvars.data(), setweights.empty() ? NULL : setweights.data()) );
1653 }
1654 else
1655 {
1656 (void) SCIPsnprintf(name, 20, "sos2_%d", -sosit->first);
1657 SCIP_CALL_THROW( SCIPcreateConsBasicSOS2(scip, &cons, name, sosit->second.size(), setvars.data(), setweights.data()) );
1658 }
1661 }
1662
1663 // add initial solution
1664 if( initsol != NULL )
1665 {
1666 SCIP_Bool stored;
1667 SCIP_CALL_THROW( SCIPaddSolFree(scip, &initsol, &stored) );
1668 }
1669
1670 // release expressions
1672 }
1673
1674 /// releases expressions and linear constraints from data
1675 ///
1676 /// should be called if there was an error while reading the .nl file
1677 /// this is not in the destructor, because we want to return SCIP_RETCODE
1679 {
1680 // release initial sol (in case EndInput() wasn't called)
1681 if( initsol != NULL )
1682 {
1683 SCIP_CALL( SCIPfreeSol(scip, &initsol) );
1684 }
1685
1686 // release created expressions (they should all be used in other expressions or constraints now)
1687 while( !exprstorelease.empty() )
1688 {
1689 SCIP_CALL( SCIPreleaseExpr(scip, &exprstorelease.back()) );
1690 exprstorelease.pop_back();
1691 }
1692
1693 // release variable expressions (they should all be used in other expressions or constraints now)
1694 while( !varexprs.empty() )
1695 {
1696 SCIP_CALL( SCIPreleaseExpr(scip, &varexprs.back()) );
1697 varexprs.pop_back();
1698 }
1699
1700 return SCIP_OKAY;
1701 }
1702};
1703
1704
1705/*
1706 * Callback methods of probdata
1707 */
1708
1709/** frees user data of original problem (called when the original problem is freed) */
1710static
1711SCIP_DECL_PROBDELORIG(probdataDelOrigNl)
1712{
1713 int i;
1714
1715 assert((*probdata)->vars != NULL || (*probdata)->nvars == 0);
1716 assert((*probdata)->conss != NULL || (*probdata)->conss == 0);
1717
1718 for( i = 0; i < (*probdata)->nconss; ++i )
1719 {
1720 SCIP_CALL( SCIPreleaseCons(scip, &(*probdata)->conss[i]) );
1721 }
1722 SCIPfreeBlockMemoryArrayNull(scip, &(*probdata)->conss, (*probdata)->nconss);
1723
1724 for( i = 0; i < (*probdata)->nvars; ++i )
1725 {
1726 SCIP_CALL( SCIPreleaseVar(scip, &(*probdata)->vars[i]) );
1727 }
1728 SCIPfreeBlockMemoryArrayNull(scip, &(*probdata)->vars, (*probdata)->nvars);
1729
1730 SCIPfreeBlockMemoryArrayNull(scip, &(*probdata)->filenamestub, (*probdata)->filenamestublen+5);
1731
1732 SCIPfreeMemory(scip, probdata);
1733
1734 return SCIP_OKAY;
1735}
1736
1737/*
1738 * Callback methods of reader
1739 */
1740
1741/** copy method for reader plugins (called when SCIP copies plugins) */
1742static
1744{ /*lint --e{715}*/
1745 assert(scip != NULL);
1746
1748
1749 return SCIP_OKAY;
1750}
1751
1752/** problem reading method of reader */
1753static
1755{ /*lint --e{715}*/
1756 assert(scip != NULL);
1757 assert(reader != NULL);
1758 assert(filename != NULL);
1759 assert(result != NULL);
1760
1761 try
1762 {
1763 // try to read the .nl file and setup SCIP problem
1764 AMPLProblemHandler handler(scip, filename);
1765 try
1766 {
1767 mp::ReadNLFile(filename, handler);
1768 }
1769 catch( const mp::UnsupportedError& e )
1770 {
1771 SCIPerrorMessage("unsupported construct in AMPL .nl file %s: %s\n", filename, e.what());
1772
1773 SCIP_CALL( handler.cleanup() );
1774
1775 return SCIP_READERROR;
1776 }
1777 catch( const mp::Error& e )
1778 {
1779 // some other error from ampl/mp, maybe invalid .nl file
1780 SCIPerrorMessage("%s\n", e.what());
1781
1782 SCIP_CALL( handler.cleanup() );
1783
1784 return SCIP_READERROR;
1785 }
1786 catch( const fmt::SystemError& e )
1787 {
1788 // probably a file open error, probably because file not found
1789 SCIPerrorMessage("%s\n", e.what());
1790
1791 SCIP_CALL( handler.cleanup() );
1792
1793 return SCIP_NOFILE;
1794 }
1795 catch( const std::bad_alloc& e )
1796 {
1797 SCIPerrorMessage("Out of memory: %s\n", e.what());
1798
1799 SCIP_CALL( handler.cleanup() );
1800
1801 return SCIP_NOMEMORY;
1802 }
1803 }
1804 catch( const std::exception& e )
1805 {
1806 SCIPerrorMessage("%s\n", e.what());
1807 return SCIP_ERROR;
1808 }
1809
1810 *result = SCIP_SUCCESS;
1811
1812 return SCIP_OKAY;
1813}
1814
1815/*
1816 * reader specific interface methods
1817 */
1818
1819/** includes the AMPL .nl file reader in SCIP */
1821 SCIP* scip /**< SCIP data structure */
1822)
1823{
1824 SCIP_READER* reader = NULL;
1825
1826 /* include reader */
1828 assert(reader != NULL);
1829
1830 /* set non fundamental callbacks via setter functions */
1831 SCIP_CALL( SCIPsetReaderCopy(scip, reader, readerCopyNl) );
1832 SCIP_CALL( SCIPsetReaderRead(scip, reader, readerReadNl) );
1833
1834 SCIP_CALL( SCIPincludeExternalCodeInformation(scip, "AMPL/MP 690e9e7", "AMPL .nl file reader library (github.com/ampl/mp)") );
1835
1836 return SCIP_OKAY;
1837}
1838
1839/** writes AMPL solution file
1840 *
1841 * problem must have been read with .nl reader
1842 */
1844 SCIP* scip /**< SCIP data structure */
1845 )
1846{
1847 SCIP_PROBDATA* probdata;
1848
1849 assert(scip != NULL);
1850
1851 probdata = SCIPgetProbData(scip);
1852 if( probdata == NULL )
1853 {
1854 SCIPerrorMessage("No AMPL nl file read. Cannot write AMPL solution.\n");
1855 return SCIP_ERROR;
1856 }
1857
1858 probdata->filenamestub[probdata->filenamestublen] = '.';
1859 probdata->filenamestub[probdata->filenamestublen+1] = 's';
1860 probdata->filenamestub[probdata->filenamestublen+2] = 'o';
1861 probdata->filenamestub[probdata->filenamestublen+3] = 'l';
1862 probdata->filenamestub[probdata->filenamestublen+4] = '\0';
1863
1864 FILE* solfile = fopen(probdata->filenamestub, "w");
1865 if( solfile == NULL )
1866 {
1867 SCIPerrorMessage("could not open file <%s> for writing\n", probdata->filenamestub);
1868 probdata->filenamestub[probdata->filenamestublen] = '\0';
1869
1870 return SCIP_WRITEERROR;
1871 }
1872 probdata->filenamestub[probdata->filenamestublen] = '\0';
1873
1874 // see ampl/mp:sol.h:WriteSolFile() (seems buggy, https://github.com/ampl/mp/issues/135) and asl/writesol.c for solution file format
1875 SCIP_CALL( SCIPprintStatus(scip, solfile) );
1876 SCIPinfoMessage(scip, solfile, "\n\n");
1877
1878 SCIPinfoMessage(scip, solfile, "Options\n%d\n", probdata->namplopts);
1879 for( int i = 0; i < probdata->namplopts; ++i )
1880 SCIPinfoMessage(scip, solfile, "%d\n", probdata->amplopts[i]);
1881
1882 bool haveprimal = SCIPgetBestSol(scip) != NULL;
1883 bool havedual = probdata->islp && SCIPgetStage(scip) == SCIP_STAGE_SOLVED && !SCIPhasPerformedPresolve(scip);
1884
1885 SCIPinfoMessage(scip, solfile, "%d\n%d\n", probdata->nconss, havedual ? probdata->nconss : 0);
1886 SCIPinfoMessage(scip, solfile, "%d\n%d\n", probdata->nvars, haveprimal ? probdata->nvars : 0);
1887
1889
1890 if( havedual )
1891 for( int c = 0; c < probdata->nconss; ++c )
1892 {
1893 SCIP_CONS* transcons;
1894 SCIP_Real dualval;
1895
1896 /* dual solution is created by LP solver and therefore only available for linear constraints */
1897 SCIP_CALL( SCIPgetTransformedCons(scip, probdata->conss[c], &transcons) );
1898 assert(transcons == NULL || strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(transcons)), "linear") == 0);
1899
1900 if( transcons == NULL )
1901 dualval = 0.0;
1903 dualval = SCIPgetDualsolLinear(scip, transcons);
1904 else
1905 dualval = -SCIPgetDualsolLinear(scip, transcons);
1906 assert(dualval != SCIP_INVALID);
1907
1908 SCIPinfoMessage(scip, solfile, "%.17g\n", dualval);
1909 }
1910
1911 if( haveprimal )
1912 for( int i = 0; i < probdata->nvars; ++i )
1913 SCIPinfoMessage(scip, solfile, "%.17g\n", SCIPgetSolVal(scip, SCIPgetBestSol(scip), probdata->vars[i]));
1914
1915 /* AMPL solve status codes are at https://mp.ampl.com/details.html#_CPPv4N2mp3sol6StatusE
1916 * (mp::sol::Status enum in amplmp/include/mp/common.h)
1917 */
1918 int solve_result_num = mp::sol::FAILURE;
1919 switch( SCIPgetStatus(scip) )
1920 {
1922 break;
1925 if( haveprimal )
1926 solve_result_num = mp::sol::LIMIT_FEAS_INTERRUPT;
1927 else
1928 solve_result_num = mp::sol::LIMIT_NO_FEAS_INTERRUPT;
1929 break;
1933 if( haveprimal )
1934 solve_result_num = mp::sol::LIMIT_FEAS_NODES;
1935 else
1936 solve_result_num = mp::sol::LIMIT_NO_FEAS_NODES;
1937 break;
1939 if( haveprimal )
1940 solve_result_num = mp::sol::LIMIT_FEAS_TIME;
1941 else
1942 solve_result_num = mp::sol::LIMIT_NO_FEAS_TIME;
1943 break;
1945 if( haveprimal )
1946 solve_result_num = mp::sol::LIMIT_FEAS_SOFTMEM;
1947 else
1948 solve_result_num = mp::sol::LIMIT_NO_FEAS_SOFTMEM;
1949 break;
1951 /* there is no enum value for gaplimit, so use "work limit" */
1952 if( haveprimal )
1953 solve_result_num = mp::sol::LIMIT_FEAS_WORK;
1954 else
1955 solve_result_num = mp::sol::LIMIT_NO_FEAS_WORK;
1956 break;
1958 solve_result_num = mp::sol::LIMIT_FEAS_BESTOBJ;
1959 break;
1961 if( haveprimal )
1962 solve_result_num = mp::sol::LIMIT_FEAS_BESTBND;
1963 else
1964 solve_result_num = mp::sol::LIMIT_NO_FEAS_BESTBND;
1965 break;
1967 if( haveprimal )
1968 solve_result_num = mp::sol::LIMIT_FEAS_NUMSOLS;
1969 else /* reach solution limit without solution? */
1970 solve_result_num = mp::sol::LIMIT_NO_FEAS;
1971 break;
1974 /* rare SCIP specific limits that don't map to an AMPL status */
1975 if( haveprimal )
1976 solve_result_num = mp::sol::LIMIT_FEAS;
1977 else
1978 solve_result_num = mp::sol::LIMIT_NO_FEAS;
1979 break;
1981 solve_result_num = mp::sol::SOLVED;
1982 break;
1984 solve_result_num = mp::sol::INFEASIBLE;
1985 break;
1987 if( haveprimal )
1988 solve_result_num = mp::sol::UNBOUNDED_FEAS;
1989 else
1990 solve_result_num = mp::sol::UNBOUNDED_NO_FEAS;
1991 break;
1993 solve_result_num = mp::sol::LIMIT_INF_UNB;
1994 break;
1995 }
1996 SCIPinfoMessage(scip, solfile, "objno 0 %d\n", solve_result_num);
1997
1998 if( fclose(solfile) != 0 )
1999 {
2000 SCIPerrorMessage("could not close solution file after writing\n");
2001 return SCIP_WRITEERROR;
2002 }
2003
2004 return SCIP_OKAY;
2005}
SCIP_VAR * h
Definition: circlepacking.c:68
void AddTerm(int var_index, double coef)
receives notification of a term in the linear expression
Definition: reader_nl.cpp:767
LinearExprHandler(AMPLProblemHandler &amplph_, int index, int num_linear_terms)
constructor
Definition: reader_nl.cpp:750
LinearPartHandler(AMPLProblemHandler &amplph_)
Definition: reader_nl.cpp:1162
void AddTerm(int variableIndex, double coefficient)
Definition: reader_nl.cpp:1169
LinearPartHandler(AMPLProblemHandler &amplph_, int constraintIndex_)
Definition: reader_nl.cpp:1150
NumericArgHandler(int num_args)
constructor
Definition: reader_nl.cpp:645
void AddArg(SCIP_EXPR *term)
adds term to sum
Definition: reader_nl.cpp:654
std::shared_ptr< std::vector< SCIP_EXPR * > > v
Definition: reader_nl.cpp:642
void SetValue(int index, T value)
Definition: reader_nl.cpp:1053
SuffixHandler(AMPLProblemHandler &amplph_, fmt::StringRef name, mp::suf::Kind kind)
constructor
Definition: reader_nl.cpp:954
implementation of AMPL/MPs NLHandler that constructs a SCIP problem while a .nl file is read
Definition: reader_nl.cpp:115
void EndCommonExpr(int index, SCIP_EXPR *expr, int)
receive notification of the end of a common expression
Definition: reader_nl.cpp:806
LinearPartHandler LinearObjHandler
Definition: reader_nl.cpp:1196
NumericArgHandler BeginSum(int num_args)
receive notification of the beginning of a summation
Definition: reader_nl.cpp:663
void OnAlgebraicCon(int constraintIndex, SCIP_EXPR *expr)
receive notification of an algebraic constraint expression
Definition: reader_nl.cpp:714
LinearPartHandler OnLinearObjExpr(int objectiveIndex, int)
receive notification of the linear part of an objective
Definition: reader_nl.cpp:1199
LogicalExpr OnBinaryLogical(mp::expr::Kind kind, LogicalExpr lhs, LogicalExpr rhs)
receives notification of a binary logical expression <mp::expr::FIRST_BINARY_LOGICAL>
Definition: reader_nl.cpp:1263
LogicalExpr OnNot(LogicalExpr arg)
receives notification of a logical not <mp::expr::NOT>
Definition: reader_nl.cpp:1237
SCIP_EXPR * OnBinary(mp::expr::Kind kind, SCIP_EXPR *firstChild, SCIP_EXPR *secondChild)
receive notification of a binary expression
Definition: reader_nl.cpp:550
SCIP_EXPR * OnNumber(double value)
receive notification of a number in a nonlinear expression
Definition: reader_nl.cpp:455
LogicalExpr OnRelational(mp::expr::Kind kind, NumericExpr lhs, NumericExpr rhs)
Definition: reader_nl.cpp:1464
SuffixHandler< int > IntSuffixHandler
Definition: reader_nl.cpp:1115
LinearExprHandler BeginCommonExpr(int index, int num_linear_terms)
receive notification of the beginning of a common expression (defined variable)
Definition: reader_nl.cpp:794
AMPLProblemHandler(const AMPLProblemHandler &)=delete
LinearConHandler OnLinearConExpr(int constraintIndex, int)
receive notification of the linear part of a constraint
Definition: reader_nl.cpp:1213
void OnInitialValue(int var_index, double value)
receive notification of the initial value for a variable
Definition: reader_nl.cpp:896
SCIP_EXPR * OnVariableRef(int variableIndex)
receive notification of a variable reference in a nonlinear expression
Definition: reader_nl.cpp:470
AMPLProblemHandler(SCIP *scip_, const char *filename)
Definition: reader_nl.cpp:245
ColumnSizeHandler OnColumnSizes()
receives notification of Jacobian column sizes
Definition: reader_nl.cpp:919
AMPLProblemHandler & operator=(const AMPLProblemHandler &)=delete
LinearPartHandler LinearConHandler
Definition: reader_nl.cpp:1210
void OnVarBounds(int variableIndex, double variableLB, double variableUB)
receive notification of variable bounds
Definition: reader_nl.cpp:838
SCIP_EXPR * OnCommonExprRef(int expr_index)
receive notification of a common expression (defined variable) reference
Definition: reader_nl.cpp:827
void OnHeader(const mp::NLHeader &h)
Definition: reader_nl.cpp:325
void OnLogicalCon(int index, LogicalExpr expr)
receives notification of a logical constraint expression
Definition: reader_nl.cpp:726
DblSuffixHandler OnDblSuffix(fmt::StringRef name, mp::suf::Kind kind, int)
receive notification of a double suffix
Definition: reader_nl.cpp:1128
void OnConBounds(int index, double lb, double ub)
receive notification of constraint sides
Definition: reader_nl.cpp:861
IntSuffixHandler OnIntSuffix(fmt::StringRef name, mp::suf::Kind kind, int)
receive notification of an integer suffix
Definition: reader_nl.cpp:1117
LogicalExpr OnBool(bool value)
receives notification of a Boolean value <mp::expr::BOOL>
Definition: reader_nl.cpp:1222
SCIP_EXPR * OnUnary(mp::expr::Kind kind, SCIP_EXPR *child)
receive notification of a unary expression
Definition: reader_nl.cpp:482
SCIP_EXPR * EndSum(NumericArgHandler handler)
receive notification of the end of a summation
Definition: reader_nl.cpp:672
void OnInitialDualValue(int, double)
receives notification of the initial value for a dual variable
Definition: reader_nl.cpp:910
SCIP_RETCODE cleanup()
Definition: reader_nl.cpp:1678
SuffixHandler< SCIP_Real > DblSuffixHandler
Definition: reader_nl.cpp:1126
void OnObj(int objectiveIndex, mp::obj::Type type, SCIP_EXPR *nonlinearExpression)
receive notification of an objective type and the nonlinear part of an objective expression
Definition: reader_nl.cpp:684
Constraint handler for AND constraints, .
struct Problem PROBLEM
Constraint handler for linear constraints in their most general form, .
constraint handler for nonlinear constraints specified by algebraic expressions
Constraint handler for "or" constraints, .
constraint handler for SOS type 1 constraints
constraint handler for SOS type 2 constraints
unsigned short Type
Definition: cons_xor.c:131
Constraint handler for XOR constraints, .
#define NULL
Definition: def.h:267
#define SCIP_MAXSTRLEN
Definition: def.h:288
#define SCIP_INVALID
Definition: def.h:193
#define SCIP_Bool
Definition: def.h:91
#define SCIP_Real
Definition: def.h:173
#define ABS(x)
Definition: def.h:235
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:239
#define SCIPABORT()
Definition: def.h:346
#define SCIP_CALL(x)
Definition: def.h:374
absolute expression handler
exponential expression handler
logarithm expression handler
power and signed power expression handlers
product expression handler
sum expression handler
handler for sin expressions
constant value expression handler
variable expression handler
SCIP_Real SCIPgetDualsolLinear(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPaddLinearVarNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
SCIP_RETCODE SCIPchgRhsLinear(SCIP *scip, SCIP_CONS *cons, SCIP_Real rhs)
SCIP_RETCODE SCIPaddCoefLinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real val)
SCIP_RETCODE SCIPcreateConsBasicXor(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_Bool rhs, int nvars, SCIP_VAR **vars)
Definition: cons_xor.c:6004
SCIP_RETCODE SCIPchgLhsNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_Real lhs)
SCIP_RETCODE SCIPcreateConsBasicOr(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *resvar, int nvars, SCIP_VAR **vars)
Definition: cons_or.c:2265
SCIP_RETCODE SCIPchgRhsNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_Real rhs)
SCIP_RETCODE SCIPcreateConsBasicSOS1(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *weights)
Definition: cons_sos1.c:10700
SCIP_RETCODE SCIPcreateConsBasicLinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs)
SCIP_RETCODE SCIPcreateConsBasicNonlinear(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_EXPR *expr, SCIP_Real lhs, SCIP_Real rhs)
SCIP_RETCODE SCIPcreateConsBasicAnd(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *resvar, int nvars, SCIP_VAR **vars)
Definition: cons_and.c:5180
SCIP_RETCODE SCIPchgExprNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_EXPR *expr)
SCIP_RETCODE SCIPchgLhsLinear(SCIP *scip, SCIP_CONS *cons, SCIP_Real lhs)
SCIP_RETCODE SCIPcreateConsBasicSOS2(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *weights)
Definition: cons_sos2.c:2661
SCIP_RETCODE SCIPcreateExprVar(SCIP *scip, SCIP_EXPR **expr, SCIP_VAR *var, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: expr_var.c:390
SCIP_RETCODE SCIPcreateExprProduct(SCIP *scip, SCIP_EXPR **expr, int nchildren, SCIP_EXPR **children, SCIP_Real coefficient, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
SCIP_RETCODE SCIPcreateExprSin(SCIP *scip, SCIP_EXPR **expr, SCIP_EXPR *child, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: expr_trig.c:1430
SCIP_RETCODE SCIPcreateExprCos(SCIP *scip, SCIP_EXPR **expr, SCIP_EXPR *child, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: expr_trig.c:1450
SCIP_RETCODE SCIPcreateExprAbs(SCIP *scip, SCIP_EXPR **expr, SCIP_EXPR *child, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: expr_abs.c:528
SCIP_RETCODE SCIPappendExprSumExpr(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPR *child, SCIP_Real childcoef)
Definition: expr_sum.c:1151
SCIP_RETCODE SCIPcreateExprLog(SCIP *scip, SCIP_EXPR **expr, SCIP_EXPR *child, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: expr_log.c:630
SCIP_RETCODE SCIPcreateExprExp(SCIP *scip, SCIP_EXPR **expr, SCIP_EXPR *child, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: expr_exp.c:510
SCIP_RETCODE SCIPcreateExprSum(SCIP *scip, SCIP_EXPR **expr, int nchildren, SCIP_EXPR **children, SCIP_Real *coefficients, SCIP_Real constant, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: expr_sum.c:1114
SCIP_RETCODE SCIPcreateExprValue(SCIP *scip, SCIP_EXPR **expr, SCIP_Real value, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: expr_value.c:270
SCIP_RETCODE SCIPcreateExprPow(SCIP *scip, SCIP_EXPR **expr, SCIP_EXPR *child, SCIP_Real exponent, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: expr_pow.c:3193
SCIP_Bool SCIPhasPerformedPresolve(SCIP *scip)
Definition: scip_general.c:695
SCIP_RETCODE SCIPprintStatus(SCIP *scip, FILE *file)
Definition: scip_general.c:521
SCIP_STATUS SCIPgetStatus(SCIP *scip)
Definition: scip_general.c:498
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:380
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_PROBDATA * SCIPgetProbData(SCIP *scip)
Definition: scip_prob.c:964
SCIP_RETCODE SCIPsetObjsense(SCIP *scip, SCIP_OBJSENSE objsense)
Definition: scip_prob.c:1242
SCIP_OBJSENSE SCIPgetObjsense(SCIP *scip)
Definition: scip_prob.c:1225
SCIP_RETCODE SCIPcreateProb(SCIP *scip, const char *name, SCIP_DECL_PROBDELORIG((*probdelorig)), SCIP_DECL_PROBTRANS((*probtrans)), SCIP_DECL_PROBDELTRANS((*probdeltrans)), SCIP_DECL_PROBINITSOL((*probinitsol)), SCIP_DECL_PROBEXITSOL((*probexitsol)), SCIP_DECL_PROBCOPY((*probcopy)), SCIP_PROBDATA *probdata)
Definition: scip_prob.c:117
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:208
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip_message.c:225
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
Definition: scip_message.c:120
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4197
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8234
SCIP_RETCODE SCIPsetConsSeparated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool separate)
Definition: scip_cons.c:1297
SCIP_RETCODE SCIPsetConsDynamic(SCIP *scip, SCIP_CONS *cons, SCIP_Bool dynamic)
Definition: scip_cons.c:1450
SCIP_RETCODE SCIPsetConsInitial(SCIP *scip, SCIP_CONS *cons, SCIP_Bool initial)
Definition: scip_cons.c:1272
SCIP_RETCODE SCIPsetConsEnforced(SCIP *scip, SCIP_CONS *cons, SCIP_Bool enforce)
Definition: scip_cons.c:1322
SCIP_RETCODE SCIPsetConsRemovable(SCIP *scip, SCIP_CONS *cons, SCIP_Bool removable)
Definition: scip_cons.c:1475
SCIP_RETCODE SCIPgetTransformedCons(SCIP *scip, SCIP_CONS *cons, SCIP_CONS **transcons)
Definition: scip_cons.c:1675
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1174
SCIP_RETCODE SCIPsetConsPropagated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool propagate)
Definition: scip_cons.c:1372
SCIP_RETCODE SCIPsetConsChecked(SCIP *scip, SCIP_CONS *cons, SCIP_Bool check)
Definition: scip_cons.c:1347
SCIP_RETCODE SCIPevalExpr(SCIP *scip, SCIP_EXPR *expr, SCIP_SOL *sol, SCIP_Longint soltag)
Definition: scip_expr.c:1635
SCIP_Bool SCIPisExprValue(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1442
SCIP_RETCODE SCIPreleaseExpr(SCIP *scip, SCIP_EXPR **expr)
Definition: scip_expr.c:1417
SCIP_Bool SCIPisExprVar(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1431
SCIP_Real SCIPgetValueExprValue(SCIP_EXPR *expr)
Definition: expr_value.c:294
SCIP_Real SCIPexprGetEvalValue(SCIP_EXPR *expr)
Definition: expr.c:3934
SCIP_VAR * SCIPgetVarExprVar(SCIP_EXPR *expr)
Definition: expr_var.c:416
SCIP_RETCODE SCIPincludeExternalCodeInformation(SCIP *scip, const char *name, const char *description)
Definition: scip_general.c:734
#define SCIPallocClearMemory(scip, ptr)
Definition: scip_mem.h:62
#define SCIPfreeMemory(scip, ptr)
Definition: scip_mem.h:78
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:93
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:111
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 SCIPsetReaderCopy(SCIP *scip, SCIP_READER *reader, SCIP_DECL_READERCOPY((*readercopy)))
Definition: scip_reader.c:147
SCIP_RETCODE SCIPsetReaderRead(SCIP *scip, SCIP_READER *reader, SCIP_DECL_READERREAD((*readerread)))
Definition: scip_reader.c:195
SCIP_SOL * SCIPgetBestSol(SCIP *scip)
Definition: scip_sol.c:2169
SCIP_RETCODE SCIPcreateSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip_sol.c:184
SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip_sol.c:841
SCIP_RETCODE SCIPaddSolFree(SCIP *scip, SCIP_SOL **sol, SCIP_Bool *stored)
Definition: scip_sol.c:2855
SCIP_RETCODE SCIPprintSol(SCIP *scip, SCIP_SOL *sol, FILE *file, SCIP_Bool printzeros)
Definition: scip_sol.c:1631
SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
Definition: scip_sol.c:1077
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1217
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_RETCODE SCIPtightenVarUbGlobal(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:6348
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:17584
SCIP_RETCODE SCIPvarSetInitial(SCIP_VAR *var, SCIP_Bool initial)
Definition: var.c:17506
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip_var.c:1248
SCIP_RETCODE SCIPchgVarLbGlobal(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip_var.c:4943
SCIP_RETCODE SCIPchgVarType(SCIP *scip, SCIP_VAR *var, SCIP_VARTYPE vartype, SCIP_Bool *infeasible)
Definition: scip_var.c:8176
SCIP_RETCODE SCIPgetNegatedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **negvar)
Definition: scip_var.c:1527
SCIP_RETCODE SCIPvarSetRemovable(SCIP_VAR *var, SCIP_Bool removable)
Definition: var.c:17522
SCIP_RETCODE SCIPchgVarUbGlobal(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip_var.c:5032
SCIP_RETCODE SCIPcreateVarBasic(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype)
Definition: scip_var.c:194
SCIP_RETCODE SCIPchgVarObj(SCIP *scip, SCIP_VAR *var, SCIP_Real newobj)
Definition: scip_var.c:4513
SCIP_RETCODE SCIPtightenVarLbGlobal(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:6228
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10877
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:134
Definition: pqueue.h:38
#define SCIPerrorMessage
Definition: pub_message.h:64
#define SCIPdebug(x)
Definition: pub_message.h:93
SCIP_RETCODE SCIPincludeReaderNl(SCIP *scip)
Definition: reader_nl.cpp:1820
static SCIP_DECL_PROBDELORIG(probdataDelOrigNl)
Definition: reader_nl.cpp:1711
#define READER_DESC
Definition: reader_nl.cpp:70
#define READER_EXTENSION
Definition: reader_nl.cpp:71
#define SCIP_CALL_THROW(x)
Definition: reader_nl.cpp:75
SCIP_RETCODE SCIPwriteSolutionNl(SCIP *scip)
Definition: reader_nl.cpp:1843
static SCIP_DECL_READERCOPY(readerCopyNl)
Definition: reader_nl.cpp:1743
#define READER_NAME
Definition: reader_nl.cpp:69
static SCIP_DECL_READERREAD(readerReadNl)
Definition: reader_nl.cpp:1754
AMPL .nl file reader.
@ SCIP_VERBLEVEL_HIGH
Definition: type_message.h:56
@ SCIP_VERBLEVEL_FULL
Definition: type_message.h:57
struct SCIP_ProbData SCIP_PROBDATA
Definition: type_prob.h:53
@ SCIP_OBJSENSE_MAXIMIZE
Definition: type_prob.h:47
@ SCIP_OBJSENSE_MINIMIZE
Definition: type_prob.h:48
@ SCIP_SUCCESS
Definition: type_result.h:58
@ SCIP_NOFILE
Definition: type_retcode.h:47
@ SCIP_READERROR
Definition: type_retcode.h:45
@ SCIP_WRITEERROR
Definition: type_retcode.h:46
@ SCIP_NOMEMORY
Definition: type_retcode.h:44
@ SCIP_OKAY
Definition: type_retcode.h:42
@ SCIP_ERROR
Definition: type_retcode.h:43
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
@ SCIP_STAGE_SOLVED
Definition: type_set.h:54
@ SCIP_STATUS_OPTIMAL
Definition: type_stat.h:61
@ SCIP_STATUS_TOTALNODELIMIT
Definition: type_stat.h:45
@ SCIP_STATUS_BESTSOLLIMIT
Definition: type_stat.h:57
@ SCIP_STATUS_SOLLIMIT
Definition: type_stat.h:56
@ SCIP_STATUS_UNBOUNDED
Definition: type_stat.h:63
@ SCIP_STATUS_UNKNOWN
Definition: type_stat.h:42
@ SCIP_STATUS_PRIMALLIMIT
Definition: type_stat.h:54
@ SCIP_STATUS_GAPLIMIT
Definition: type_stat.h:53
@ SCIP_STATUS_USERINTERRUPT
Definition: type_stat.h:43
@ SCIP_STATUS_TERMINATE
Definition: type_stat.h:65
@ SCIP_STATUS_INFORUNBD
Definition: type_stat.h:64
@ SCIP_STATUS_STALLNODELIMIT
Definition: type_stat.h:48
@ SCIP_STATUS_TIMELIMIT
Definition: type_stat.h:51
@ SCIP_STATUS_INFEASIBLE
Definition: type_stat.h:62
@ SCIP_STATUS_NODELIMIT
Definition: type_stat.h:44
@ SCIP_STATUS_DUALLIMIT
Definition: type_stat.h:55
@ SCIP_STATUS_MEMLIMIT
Definition: type_stat.h:52
@ SCIP_STATUS_RESTARTLIMIT
Definition: type_stat.h:60
@ SCIP_VARTYPE_INTEGER
Definition: type_var.h:63
@ SCIP_VARTYPE_CONTINUOUS
Definition: type_var.h:71
@ SCIP_VARTYPE_BINARY
Definition: type_var.h:62
enum SCIP_Vartype SCIP_VARTYPE
Definition: type_var.h:73