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-2026 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 and writer
    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 * TODO:
    34 * - writing of logical constraints (and, or, xor)
    35 * - writing of SOS constraints (into suffixes)
    36 */
    37
    38/*--+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    39
    40#include <string>
    41#include <sstream>
    42#include <vector>
    43#include <map>
    44#include <cstdlib>
    45#ifdef _WIN32
    46#include <windows.h> // to be able to do the includes below
    47#include <io.h> // for _mktemp_s
    48#include <direct.h> // for _mkdir
    49#include <fileapi.h> // for GetTempPath
    50#ifdef max
    51#undef max // undo definition of max in windows.h
    52#endif
    53#ifdef min
    54#undef min // undo definition of min in windows.h
    55#endif
    56#ifdef IGNORE
    57#undef IGNORE // undo definition of IGNORE in windows.h
    58#endif
    59#else
    60#include <unistd.h> // for mkdtemp on macOS
    61#endif
    62
    63#include "scip/reader_nl.h"
    64#include "scip/cons_linear.h"
    65#include "scip/cons_setppc.h"
    66#include "scip/cons_logicor.h"
    67#include "scip/cons_knapsack.h"
    68#include "scip/cons_varbound.h"
    69#include "scip/cons_nonlinear.h"
    70#include "scip/cons_sos1.h"
    71#include "scip/cons_sos2.h"
    72#include "scip/cons_and.h"
    73#include "scip/cons_or.h"
    74#include "scip/cons_xor.h"
    75#include "scip/expr_var.h"
    76#include "scip/expr_value.h"
    77#include "scip/expr_sum.h"
    78#include "scip/expr_product.h"
    79#include "scip/expr_pow.h"
    80#include "scip/expr_log.h"
    81#include "scip/expr_exp.h"
    82#include "scip/expr_trig.h"
    83#include "scip/expr_abs.h"
    84
    85// disable -Wshadow warnings for upcoming includes of AMPL/MP
    86// disable -Wimplicit-fallthrough as I don't want to maintain extra comments in AMPL/MP code to suppress these
    87#ifdef __GNUC__
    88#pragma GCC diagnostic ignored "-Wshadow"
    89#if __GNUC__ >= 7
    90#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
    91#endif
    92#endif
    93
    94#include "mp/nl-reader.h"
    95#include "mp/nl-writer2.hpp"
    96#include "mp/nl-opcodes.h"
    97
    98#define READER_NAME "nlreader"
    99#define READER_DESC "AMPL .nl file reader"
    100#define READER_EXTENSION "nl"
    101
    102// a variant of SCIP_CALL that throws a std::logic_error if not SCIP_OKAY
    103// (using cast to long long to work around issues with old MSVC)
    104#define SCIP_CALL_THROW(x) \
    105 do \
    106 { \
    107 SCIP_RETCODE throw_retcode; \
    108 if( ((throw_retcode) = (x)) != SCIP_OKAY ) \
    109 throw std::logic_error("Error <" + std::to_string((long long)throw_retcode) + "> in function call at reader_nl.cpp:" + std::to_string(__LINE__)); \
    110 } \
    111 while( false )
    112
    113/*
    114 * Data structures
    115 */
    116
    117/// problem data stored in SCIP
    118struct SCIP_ProbNlData
    119{
    120 char* filenamestub; /**< name of input file, without .nl extension; array is long enough to hold 5 extra chars */
    121 int filenamestublen; /**< length of filenamestub string */
    122
    123 int amplopts[mp::MAX_AMPL_OPTIONS]; /**< AMPL options from .nl header */
    124 int namplopts; /**< number of AMPL options from .nl header */
    125
    126 SCIP_VAR** vars; /**< variables in the order given by AMPL */
    127 int nvars; /**< number of variables */
    128
    129 SCIP_CONS** conss; /**< constraints in the order given by AMPL */
    130 int nconss; /**< number of constraints */
    131
    132 SCIP_Bool islp; /**< whether problem is an LP (only linear constraints, only continuous vars) */
    133};
    134typedef struct SCIP_ProbNlData SCIP_PROBNLDATA;
    135
    136/*
    137 * Local methods
    138 */
    139
    140// forward declaration
    141static SCIP_DECL_PROBDELORIG(probdataDelOrigNl);
    142
    143/// implementation of AMPL/MPs NLHandler that constructs a SCIP problem while a .nl file is read
    144class AMPLProblemHandler : public mp::NLHandler<AMPLProblemHandler, SCIP_EXPR*>
    145{
    146private:
    147 SCIP* scip;
    148 SCIP_PROBNLDATA* probdata;
    149
    150 // variable expressions corresponding to nonlinear variables
    151 // created in OnHeader() and released in destructor
    152 // for reuse of var-expressions in OnVariableRef()
    153 std::vector<SCIP_EXPR*> varexprs;
    154
    155 // linear parts for nonlinear constraints
    156 // first collect and then add to constraints in EndInput()
    157 std::vector<std::vector<std::pair<SCIP_Real, SCIP_VAR*> > > nlconslin;
    158
    159 // expression that represents a nonlinear objective function
    160 // used to create a corresponding constraint in EndInput(), unless NULL
    161 SCIP_EXPR* objexpr;
    162
    163 // common expressions (defined variables from statements like "var xsqr = x^2;" in an AMPL model)
    164 // they are constructed by BeginCommonExpr/EndCommonExpr below and are referenced by index in OnCommonExprRef
    165 std::vector<SCIP_EXPR*> commonexprs;
    166
    167 // collect expressions that need to be released eventually
    168 // this are all expression that are returned to the AMPL/MP code in AMPLProblemHandler::OnXyz() functions
    169 // they need to be released exactly once, but after they are used in another expression or a constraint
    170 // as AMPL/MP may reuse expressions (common subexpressions), we don't release an expression when it is used
    171 // as a child or when constructing a constraint, but first collect them all and then release in destructor
    172 // alternatively, one could encapsulate SCIP_EXPR* into a small class that handles proper reference counting
    173 std::vector<SCIP_EXPR*> exprstorelease;
    174
    175 // count on variables or constraints added for logical expressions
    176 int logiccount;
    177
    178 // SOS constraints
    179 // collected while handling suffixes in SuffixHandler
    180 // sosvars maps the SOS index (can be negative) to the indices of the variables in the SOS
    181 // sosweights gives for each variable its weight in the SOS it appears in (if any)
    182 std::map<int, std::vector<int> > sosvars;
    183 std::vector<int> sosweights;
    184
    185 // initial solution, if any
    186 SCIP_SOL* initsol;
    187
    188 // opened files with column/variable and row/constraint names, or NULL
    189 fmt::File* colfile;
    190 fmt::File* rowfile;
    191
    192 // get name from names strings, if possible
    193 // returns whether a name has been stored
    194 bool nextName(
    195 const char*& namesbegin, /**< current pointer into names string, or NULL */
    196 const char* namesend, /**< pointer to end of names string */
    197 char* name /**< buffer to store name, should have length SCIP_MAXSTRLEN */
    198 )
    199 {
    200 if( namesbegin == NULL )
    201 return false;
    202
    203 // copy namesbegin into name until newline or namesend
    204 // updates namesbegin
    205 int nchars = 0;
    206 while( namesbegin != namesend )
    207 {
    208 if( nchars == SCIP_MAXSTRLEN )
    209 {
    210 SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL, "name too long when parsing names file");
    211 // do no longer read names from this string (something seems awkward)
    212 namesbegin = NULL;
    213 return false;
    214 }
    215 if( *namesbegin == '\n' )
    216 {
    217 *name = '\0';
    218 ++namesbegin;
    219 return true;
    220 }
    221 *(name++) = *(namesbegin++);
    222 ++nchars;
    223 }
    224
    225 SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL, "missing newline when parsing names file");
    226 return false;
    227 }
    228
    229 /// returns variable or value for given expression
    230 ///
    231 /// if expression is variable, ensure that it is a binary variable and set var
    232 /// if expression is value, then set val to whether value is nonzero and set var to NULL
    233 /// otherwise throw UnsupportedError exception
    234 void LogicalExprToVarVal(
    235 LogicalExpr expr,
    236 SCIP_VAR*& var,
    237 SCIP_Bool& val
    238 )
    239 {
    240 assert(expr != NULL);
    241
    242 if( SCIPisExprVar(scip, expr) )
    243 {
    244 var = SCIPgetVarExprVar(expr);
    246 {
    247 SCIP_Bool infeas;
    248 SCIP_Bool tightened;
    250 assert(!infeas);
    251 SCIP_CALL_THROW( SCIPtightenVarLbGlobal(scip, var, 0.0, TRUE, &infeas, &tightened) );
    252 assert(!infeas);
    253 SCIP_CALL_THROW( SCIPtightenVarUbGlobal(scip, var, 1.0, TRUE, &infeas, &tightened) );
    254 assert(!infeas);
    255 }
    256 val = FALSE; // for scan-build
    257
    258 return;
    259 }
    260
    261 if( SCIPisExprValue(scip, expr) )
    262 {
    263 var = NULL;
    264 val = SCIPgetValueExprValue(expr) != 0.0;
    265 return;
    266 }
    267
    268 OnUnhandled("logical expression must be binary or constant");
    269 }
    270
    271public:
    272 /// constructor
    273 ///
    274 /// initializes SCIP problem and problem data
    276 SCIP* scip_, ///< SCIP data structure
    277 const char* filename ///< name of .nl file that is read
    278 )
    279 : scip(scip_),
    280 probdata(NULL),
    281 objexpr(NULL),
    282 logiccount(0),
    283 initsol(NULL),
    284 colfile(NULL),
    285 rowfile(NULL)
    286 {
    287 assert(scip != NULL);
    288 assert(filename != NULL);
    289
    291
    292 /* get name of input file without file extension (if any) */
    293 const char* extstart = strrchr(const_cast<char*>(filename), '.');
    294 if( extstart != NULL )
    295 probdata->filenamestublen = extstart - filename;
    296 else
    297 probdata->filenamestublen = strlen(filename);
    298 assert(probdata->filenamestublen > 0);
    299 SCIP_CALL_THROW( SCIPallocBlockMemoryArray(scip, &probdata->filenamestub, probdata->filenamestublen + 5) );
    300 memcpy(probdata->filenamestub, filename, probdata->filenamestublen);
    301 probdata->filenamestub[probdata->filenamestublen] = '\0';
    302
    303 /* derive probname from name of input file without path and extension */
    304 const char* probname = strrchr(probdata->filenamestub, '/');
    305 if( probname == NULL )
    306 probname = probdata->filenamestub;
    307 else
    308 ++probname;
    309
    310 // initialize empty SCIP problem
    311 SCIP_CALL_THROW( SCIPcreateProb(scip, probname, probdataDelOrigNl, NULL, NULL, NULL, NULL, NULL, reinterpret_cast<SCIP_PROBDATA*>(probdata)) );
    312
    313 // try to open files with variable and constraint names
    314 // temporarily add ".col" and ".row", respectively, to filenamestub
    315 try
    316 {
    317 probdata->filenamestub[probdata->filenamestublen] = '.';
    318 probdata->filenamestub[probdata->filenamestublen+1] = 'c';
    319 probdata->filenamestub[probdata->filenamestublen+2] = 'o';
    320 probdata->filenamestub[probdata->filenamestublen+3] = 'l';
    321 probdata->filenamestub[probdata->filenamestublen+4] = '\0';
    322 colfile = new fmt::File(probdata->filenamestub, fmt::File::RDONLY);
    323
    324 probdata->filenamestub[probdata->filenamestublen+1] = 'r';
    325 probdata->filenamestub[probdata->filenamestublen+3] = 'w';
    326 rowfile = new fmt::File(probdata->filenamestub, fmt::File::RDONLY);
    327 }
    328 catch( const fmt::SystemError& e )
    329 {
    330 // probably a file open error, probably because file not found
    331 // ignore, we can make up our own names
    332 }
    333 probdata->filenamestub[probdata->filenamestublen] = '\0';
    334 }
    335
    338
    339 /// destructor
    340 ///
    341 /// only asserts that cleanup() has been called, as we cannot throw an exception or return a SCIP_RETCODE here
    343 {
    344 // exprs and linear constraint arrays should have been cleared up in cleanup()
    345 assert(varexprs.empty());
    346 assert(exprstorelease.empty());
    347
    348 delete colfile;
    349 delete rowfile;
    350 }
    351
    352 /// process header of .nl files
    353 ///
    354 /// create and add variables, allocate constraints
    356 const mp::NLHeader& h ///< header data
    357 )
    358 {
    359 char name[SCIP_MAXSTRLEN];
    360 int nnlvars;
    361
    362 assert(probdata->vars == NULL);
    363 assert(probdata->conss == NULL);
    364
    365 probdata->namplopts = h.num_ampl_options;
    366 BMScopyMemoryArray(probdata->amplopts, h.ampl_options, h.num_ampl_options);
    367
    368 // read variable and constraint names from file, if available, into memory
    369 // if not available, we will get varnamesbegin==NULL and consnamesbegin==NULL
    370 mp::MemoryMappedFile<> mapped_colfile;
    371 if( colfile != NULL )
    372 mapped_colfile.map(*colfile, "colfile");
    373 const char* varnamesbegin = mapped_colfile.start();
    374 const char* varnamesend = mapped_colfile.start() + mapped_colfile.size();
    375
    376 mp::MemoryMappedFile<> mapped_rowfile;
    377 if( rowfile != NULL )
    378 mapped_rowfile.map(*rowfile, "rowfile");
    379 const char* consnamesbegin = mapped_rowfile.start();
    380 const char* consnamesend = mapped_rowfile.start() + mapped_rowfile.size();
    381
    382 probdata->nvars = h.num_vars;
    383 SCIP_CALL_THROW( SCIPallocBlockMemoryArray(scip, &probdata->vars, probdata->nvars) );
    384
    385 // number of nonlinear variables
    386 nnlvars = MAX(h.num_nl_vars_in_cons, h.num_nl_vars_in_objs);
    387 varexprs.resize(nnlvars);
    388
    389 // create variables
    390 // create variable expressions for nonlinear variables
    391 for( int i = 0; i < h.num_vars; ++i )
    392 {
    393 SCIP_VARTYPE vartype;
    394 // Nonlinear variables in both constraints and objective
    395 if( i < h.num_nl_vars_in_both - h.num_nl_integer_vars_in_both )
    396 vartype = SCIP_VARTYPE_CONTINUOUS;
    397 else if( i < h.num_nl_vars_in_both )
    398 vartype = SCIP_VARTYPE_INTEGER;
    399 // Nonlinear variables in constraints
    400 else if( i < h.num_nl_vars_in_cons - h.num_nl_integer_vars_in_cons )
    401 vartype = SCIP_VARTYPE_CONTINUOUS;
    402 else if( i < h.num_nl_vars_in_cons )
    403 vartype = SCIP_VARTYPE_INTEGER;
    404 // Nonlinear variables in objective
    405 else if( i < h.num_nl_vars_in_objs - h.num_nl_integer_vars_in_objs )
    406 vartype = SCIP_VARTYPE_CONTINUOUS;
    407 else if( i < h.num_nl_vars_in_objs )
    408 vartype = SCIP_VARTYPE_INTEGER;
    409 // Linear variables
    410 else if( i < h.num_vars - h.num_linear_binary_vars - h.num_linear_integer_vars )
    411 vartype = SCIP_VARTYPE_CONTINUOUS;
    412 else if( i < h.num_vars - h.num_linear_integer_vars )
    413 vartype = SCIP_VARTYPE_BINARY;
    414 else
    415 vartype = SCIP_VARTYPE_INTEGER;
    416
    417 if( !nextName(varnamesbegin, varnamesend, name) )
    418 {
    419 // make up name if no names file or could not be read
    420 switch( vartype )
    421 {
    423 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "b%d", i);
    424 break;
    426 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "i%d", i);
    427 break;
    429 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "x%d", i);
    430 break;
    431 // coverity[deadcode]
    432 default:
    433 SCIPABORT();
    434 break;
    435 }
    436 }
    437
    438 SCIP_CALL_THROW( SCIPcreateVarBasic(scip, &probdata->vars[i], name,
    439 vartype == SCIP_VARTYPE_BINARY ? 0.0 : -SCIPinfinity(scip),
    440 vartype == SCIP_VARTYPE_BINARY ? 1.0 : SCIPinfinity(scip),
    441 0.0, vartype) );
    442 SCIP_CALL_THROW( SCIPaddVar(scip, probdata->vars[i]) );
    443
    444 if( i < nnlvars )
    445 {
    446 SCIP_CALL_THROW( SCIPcreateExprVar(scip, &varexprs[i], probdata->vars[i], NULL, NULL) );
    447 }
    448 }
    449
    450 // alloc some space for algebraic constraints
    451 probdata->nconss = h.num_algebraic_cons;
    452 SCIP_CALL_THROW( SCIPallocBlockMemoryArray(scip, &probdata->conss, probdata->nconss) );
    453 nlconslin.resize(h.num_nl_cons);
    454
    455 // create empty nonlinear constraints
    456 // use expression == 0, because nonlinear constraint don't like to be without an expression
    457 SCIP_EXPR* dummyexpr;
    458 SCIP_CALL_THROW( SCIPcreateExprValue(scip, &dummyexpr, 0.0, NULL, NULL) );
    459 for( int i = 0; i < h.num_nl_cons; ++i )
    460 {
    461 // make up name if no names file or could not be read
    462 if( !nextName(consnamesbegin, consnamesend, name) )
    463 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nlc%d", i);
    464
    465 SCIP_CALL_THROW( SCIPcreateConsBasicNonlinear(scip, &probdata->conss[i], name, dummyexpr, -SCIPinfinity(scip), SCIPinfinity(scip)) );
    466 }
    467 SCIP_CALL_THROW( SCIPreleaseExpr(scip, &dummyexpr) );
    468
    469 // create empty linear constraints
    470 for( int i = h.num_nl_cons; i < h.num_algebraic_cons; ++i )
    471 {
    472 if( !nextName(consnamesbegin, consnamesend, name) )
    473 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "lc%d", i);
    475 }
    476
    477 if( h.num_nl_cons == 0 && h.num_logical_cons == 0 && h.num_integer_vars() == 0 )
    478 probdata->islp = true;
    479
    480 // alloc space for common expressions
    481 commonexprs.resize(h.num_common_exprs());
    482 }
    483
    484 /// receive notification of a number in a nonlinear expression
    486 double value ///< value
    487 )
    488 {
    489 SCIP_EXPR* expr;
    490
    492
    493 // remember that we have to release this expr
    494 exprstorelease.push_back(expr);
    495
    496 return expr;
    497 }
    498
    499 /// receive notification of a variable reference in a nonlinear expression
    501 int variableIndex ///< AMPL index of variable
    502 )
    503 {
    504 assert(variableIndex >= 0);
    505 assert(variableIndex < (int)varexprs.size());
    506 assert(varexprs[variableIndex] != NULL);
    507
    508 return varexprs[variableIndex];
    509 }
    510
    511 /// receive notification of a unary expression
    513 mp::expr::Kind kind, ///< expression operator
    514 SCIP_EXPR* child ///< argument
    515 )
    516 {
    517 SCIP_EXPR* expr;
    518
    519 assert(child != NULL);
    520
    521 switch( kind )
    522 {
    523 case mp::expr::MINUS:
    524 {
    525 SCIP_Real minusone = -1.0;
    526 SCIP_CALL_THROW( SCIPcreateExprSum(scip, &expr, 1, &child, &minusone, 0.0, NULL, NULL) );
    527 break;
    528 }
    529
    530 case mp::expr::ABS:
    531 SCIP_CALL_THROW( SCIPcreateExprAbs(scip, &expr, child, NULL, NULL) );
    532 break;
    533
    534 case mp::expr::POW2:
    535 SCIP_CALL_THROW( SCIPcreateExprPow(scip, &expr, child, 2.0, NULL, NULL) );
    536 break;
    537
    538 case mp::expr::SQRT:
    539 SCIP_CALL_THROW( SCIPcreateExprPow(scip, &expr, child, 0.5, NULL, NULL) );
    540 break;
    541
    542 case mp::expr::LOG:
    543 SCIP_CALL_THROW( SCIPcreateExprLog(scip, &expr, child, NULL, NULL) );
    544 break;
    545
    546 case mp::expr::LOG10: // 1/log(10)*log(child)
    547 {
    548 SCIP_EXPR* logexpr;
    549 SCIP_Real factor = 1.0/log(10.0);
    550 SCIP_CALL_THROW( SCIPcreateExprLog(scip, &logexpr, child, NULL, NULL) );
    551 SCIP_CALL_THROW( SCIPcreateExprSum(scip, &expr, 1, &logexpr, &factor, 0.0, NULL, NULL) );
    553 break;
    554 }
    555
    556 case mp::expr::EXP:
    557 SCIP_CALL_THROW( SCIPcreateExprExp(scip, &expr, child, NULL, NULL) );
    558 break;
    559
    560 case mp::expr::SIN:
    561 SCIP_CALL_THROW( SCIPcreateExprSin(scip, &expr, child, NULL, NULL) );
    562 break;
    563
    564 case mp::expr::COS:
    565 SCIP_CALL_THROW( SCIPcreateExprCos(scip, &expr, child, NULL, NULL) );
    566 break;
    567
    568 default:
    569 OnUnhandled(mp::expr::str(kind));
    570 return NULL;
    571 }
    572
    573 // remember that we have to release this expr
    574 exprstorelease.push_back(expr);
    575
    576 return expr;
    577 }
    578
    579 /// receive notification of a binary expression
    581 mp::expr::Kind kind, ///< expression operand
    582 SCIP_EXPR* firstChild, ///< first argument
    583 SCIP_EXPR* secondChild ///< second argument
    584 )
    585 {
    586 SCIP_EXPR* expr;
    587 SCIP_EXPR* children[2] = { firstChild, secondChild };
    588
    589 assert(firstChild != NULL);
    590 assert(secondChild != NULL);
    591
    592 switch( kind )
    593 {
    594 case mp::expr::ADD:
    595 SCIP_CALL_THROW( SCIPcreateExprSum(scip, &expr, 2, children, NULL, 0.0, NULL, NULL) );
    596 break;
    597
    598 case mp::expr::SUB:
    599 {
    600 SCIP_Real coefs[2] = { 1.0, -1.0 };
    601 SCIP_CALL_THROW( SCIPcreateExprSum(scip, &expr, 2, children, coefs, 0.0, NULL, NULL) );
    602 break;
    603 }
    604
    605 case mp::expr::MUL:
    606 SCIP_CALL_THROW( SCIPcreateExprProduct(scip, &expr, 2, children, 1.0, NULL, NULL) );
    607 break;
    608
    609 case mp::expr::DIV:
    610 SCIP_CALL_THROW( SCIPcreateExprPow(scip, &children[1], secondChild, -1.0, NULL, NULL) );
    611 SCIP_CALL_THROW( SCIPcreateExprProduct(scip, &expr, 2, children, 1.0, NULL, NULL) );
    612 SCIP_CALL_THROW( SCIPreleaseExpr(scip, &children[1]) );
    613 break;
    614
    615 case mp::expr::POW_CONST_BASE:
    616 case mp::expr::POW_CONST_EXP:
    617 case mp::expr::POW:
    618 // with some .nl files, we seem to get mp::expr::POW even if base or exponent is constant,
    619 // so do not rely on kind but better check expr type
    620 if( SCIPisExprValue(scip, secondChild) )
    621 {
    622 SCIP_CALL_THROW( SCIPcreateExprPow(scip, &expr, firstChild, SCIPgetValueExprValue(secondChild), NULL, NULL) );
    623 break;
    624 }
    625
    626 if( SCIPisExprValue(scip, firstChild) && SCIPgetValueExprValue(firstChild) > 0.0 )
    627 {
    628 // reformulate constant^y as exp(y*log(constant)), if constant > 0.0
    629 // if constant < 0, we create an expression and let cons_nonlinear figure out infeasibility somehow
    630 SCIP_EXPR* prod;
    631
    632 SCIP_Real coef = log(SCIPgetValueExprValue(firstChild)); // log(firstChild)
    633 SCIP_CALL_THROW( SCIPcreateExprSum(scip, &prod, 1, &secondChild, &coef, 0.0, NULL, NULL) ); // log(firstChild)*secondChild
    634 SCIP_CALL_THROW( SCIPcreateExprExp(scip, &expr, prod, NULL, NULL) ); // expr(log(firstChild)*secondChild)
    635
    637 break;
    638 }
    639
    640 {
    641 // reformulate x^y as exp(y*log(x))
    642 SCIP_EXPR* prod;
    643
    644 assert(SCIPisExprValue(scip, secondChild));
    645
    646 SCIP_CALL_THROW( SCIPcreateExprLog(scip, &children[0], firstChild, NULL, NULL) ); // log(firstChild)
    647 SCIP_CALL_THROW( SCIPcreateExprProduct(scip, &prod, 2, children, 1.0, NULL, NULL) ); // log(firstChild)*secondChild
    648 SCIP_CALL_THROW( SCIPcreateExprExp(scip, &expr, prod, NULL, NULL) ); // expr(log(firstChild)*secondChild)
    649
    651 SCIP_CALL_THROW( SCIPreleaseExpr(scip, &children[0]) );
    652 break;
    653 }
    654
    655 default:
    656 OnUnhandled(mp::expr::str(kind));
    657 return NULL;
    658 }
    659
    660 // remember that we have to release this expr
    661 exprstorelease.push_back(expr);
    662
    663 return expr;
    664 }
    665
    666 /// handler to create a list of terms in a sum
    667 ///
    668 /// NumericArgHandler is copied around, so it keeps only a pointer (with reference counting) to actual data
    670 {
    671 public:
    672 std::shared_ptr<std::vector<SCIP_EXPR*> > v;
    673
    674 /// constructor
    676 int num_args ///< number of terms to expect
    677 )
    678 : v(new std::vector<SCIP_EXPR*>())
    679 {
    680 v->reserve(num_args);
    681 }
    682
    683 /// adds term to sum
    684 void AddArg(
    685 SCIP_EXPR* term ///< term to add
    686 )
    687 {
    688 v->push_back(term);
    689 }
    690 };
    691
    692 /// receive notification of the beginning of a summation
    694 int num_args ///< number of terms to expect
    695 )
    696 {
    697 NumericArgHandler h(num_args);
    698 return h;
    699 }
    700
    701 /// receive notification of the end of a summation
    703 NumericArgHandler handler ///< handler that handled the sum
    704 )
    705 {
    706 SCIP_EXPR* expr;
    707 SCIP_CALL_THROW( SCIPcreateExprSum(scip, &expr, (int)handler.v->size(), handler.v->data(), NULL, 0.0, NULL, NULL) );
    708 // remember that we have to release this expr
    709 exprstorelease.push_back(expr);
    710 return expr;
    711 }
    712
    713 /// receive notification of an objective type and the nonlinear part of an objective expression
    714 void OnObj(
    715 int objectiveIndex, ///< index of objective
    716 mp::obj::Type type, ///< objective sense
    717 SCIP_EXPR* nonlinearExpression ///< nonlinear part of objective function
    718 )
    719 {
    720 if( objectiveIndex >= 1 )
    721 OnUnhandled("multiple objective functions");
    722
    724
    725 assert(objexpr == NULL);
    726
    727 if( nonlinearExpression != NULL && SCIPisExprValue(scip, nonlinearExpression) )
    728 {
    729 // handle objective constant by adding a fixed variable for it
    730 SCIP_VAR* objconstvar;
    731 SCIP_Real objconst = SCIPgetValueExprValue(nonlinearExpression);
    732
    733 SCIP_CALL_THROW( SCIPcreateVarBasic(scip, &objconstvar, "objconstant", objconst, objconst, 1.0, SCIP_VARTYPE_CONTINUOUS) );
    734 SCIP_CALL_THROW( SCIPaddVar(scip, objconstvar) );
    735 SCIP_CALL_THROW( SCIPreleaseVar(scip, &objconstvar) );
    736 }
    737 else
    738 {
    739 objexpr = nonlinearExpression;
    740 }
    741 }
    742
    743 /// receive notification of an algebraic constraint expression
    745 int constraintIndex, ///< index of constraint
    746 SCIP_EXPR* expr ///< nonlinear part of constraint
    747 )
    748 {
    749 if( expr != NULL )
    750 {
    751 SCIP_CALL_THROW( SCIPchgExprNonlinear(scip, probdata->conss[constraintIndex], expr) );
    752 }
    753 }
    754
    755 /// receives notification of a logical constraint expression
    757 int index,
    758 LogicalExpr expr
    759 )
    760 {
    761 if( expr != NULL )
    762 {
    763 SCIP_CONS* cons;
    764 SCIP_CALL_THROW( SCIPcreateConsBasicNonlinear(scip, &cons, "logiccons", expr, 1.0, 1.0) );
    767 }
    768 }
    769
    770 /// handles linear part of a common expression
    771 /// sets up a sum expression, if the linear part isn't empty
    773 {
    774 private:
    775 AMPLProblemHandler& amplph;
    776 SCIP_EXPR* commonexpr;
    777
    778 public:
    779 /// constructor
    781 AMPLProblemHandler& amplph_, ///< problem handler
    782 int index, ///< index of common expression
    783 int num_linear_terms///< number of terms to expect
    784 )
    785 : amplph(amplph_),
    786 commonexpr(NULL)
    787 {
    788 if( num_linear_terms > 0 )
    789 {
    790 SCIP_CALL_THROW( SCIPcreateExprSum(amplph.scip, &commonexpr, 0, NULL, NULL, 0.0, NULL, NULL) );
    791 amplph.commonexprs[index] = commonexpr;
    792 amplph.exprstorelease.push_back(commonexpr);
    793 }
    794 }
    795
    796 /// receives notification of a term in the linear expression
    798 int var_index, ///< AMPL index of variable
    799 double coef ///< variable coefficient
    800 )
    801 {
    802 assert(commonexpr != NULL);
    803
    804 if( coef == 0.0 )
    805 return;
    806
    807 if( var_index < (int)amplph.varexprs.size() )
    808 {
    809 SCIP_CALL_THROW( SCIPappendExprSumExpr(amplph.scip, commonexpr, amplph.varexprs[var_index], coef) );
    810 }
    811 else
    812 {
    813 // the index variable is linear (not sure this can happen here)
    814 assert(var_index < amplph.probdata->nvars);
    815 SCIP_EXPR* varexpr;
    816 SCIP_CALL_THROW( SCIPcreateExprVar(amplph.scip, &varexpr, amplph.probdata->vars[var_index], NULL, NULL) );
    817 SCIP_CALL_THROW( SCIPappendExprSumExpr(amplph.scip, commonexpr, varexpr, coef) );
    818 SCIP_CALL_THROW( SCIPreleaseExpr(amplph.scip, &varexpr) );
    819 }
    820 }
    821 };
    822
    823 /// receive notification of the beginning of a common expression (defined variable)
    825 int index, ///< index of common expression
    826 int num_linear_terms ///< number of terms to expect
    827 )
    828 {
    829 assert(index >= 0);
    830 assert(index < (int)commonexprs.size());
    831
    832 return LinearExprHandler(*this, index, num_linear_terms);
    833 }
    834
    835 /// receive notification of the end of a common expression
    837 int index, ///< index of common expression
    838 SCIP_EXPR* expr, ///< nonlinear part of common expression
    839 int /* position */ ///< argument that doesn't seem to have any purpose
    840 )
    841 {
    842 if( commonexprs[index] != NULL )
    843 {
    844 // add expr, if any, to linear part
    845 if( expr != NULL )
    846 {
    847 SCIP_CALL_THROW( SCIPappendExprSumExpr(scip, commonexprs[index], expr, 1.0) );
    848 }
    849 }
    850 else if( expr != NULL )
    851 {
    852 commonexprs[index] = expr;
    853 }
    854 }
    855
    856 /// receive notification of a common expression (defined variable) reference
    858 int expr_index ///< index of common expression
    859 )
    860 {
    861 assert(expr_index >= 0);
    862 assert(expr_index < (int)commonexprs.size());
    863 assert(commonexprs[expr_index] != NULL);
    864 return commonexprs[expr_index];
    865 }
    866
    867 /// receive notification of variable bounds
    869 int variableIndex, ///< AMPL index of variable
    870 double variableLB, ///< variable lower bound
    871 double variableUB ///< variable upper bound
    872 )
    873 {
    874 assert(variableIndex >= 0);
    875 assert(variableIndex < probdata->nvars);
    876
    877 // as far as I see, ampl::mp gives -inf, +inf for no-bounds, which is always beyond SCIPinfinity()
    878 // we ignore bounds outside [-scipinfinity,scipinfinity] here
    879 // for binary variables, we also ignore bounds outside [0,1]
    880 SCIP_Bool binary = (SCIPvarGetType(probdata->vars[variableIndex]) == SCIP_VARTYPE_BINARY);
    881 if( variableLB > (binary ? 0.0 : -SCIPinfinity(scip)) )
    882 {
    883 SCIP_CALL_THROW( SCIPchgVarLbGlobal(scip, probdata->vars[variableIndex], variableLB) );
    884 }
    885 if( variableUB < (binary ? 1.0 : SCIPinfinity(scip)) )
    886 {
    887 SCIP_CALL_THROW( SCIPchgVarUbGlobal(scip, probdata->vars[variableIndex], variableUB) );
    888 }
    889 }
    890
    891 /// receive notification of constraint sides
    893 int index, ///< AMPL index of constraint
    894 double lb, ///< constraint left-hand-side
    895 double ub ///< constraint right-hand-side
    896 )
    897 {
    898 assert(index >= 0);
    899 assert(index < probdata->nconss);
    900
    901 // nonlinear constraints are first
    902 if( index < (int)nlconslin.size() )
    903 {
    904 if( !SCIPisInfinity(scip, -lb) )
    905 {
    906 SCIP_CALL_THROW( SCIPchgLhsNonlinear(scip, probdata->conss[index], lb) );
    907 }
    908 if( !SCIPisInfinity(scip, ub) )
    909 {
    910 SCIP_CALL_THROW( SCIPchgRhsNonlinear(scip, probdata->conss[index], ub) );
    911 }
    912 }
    913 else
    914 {
    915 /* there are asserts in cons_linear.c:chgLhs/chgRhs to forbid changing a side
    916 * from one infinity to another; to workaround this, we change the side to 0.0 first
    917 */
    918 if( !SCIPisInfinity(scip, -lb) )
    919 {
    920 if( SCIPisInfinity(scip, lb) )
    921 {
    922 SCIP_CALL_THROW( SCIPchgLhsLinear(scip, probdata->conss[index], 0.0) );
    923 }
    924 SCIP_CALL_THROW( SCIPchgLhsLinear(scip, probdata->conss[index], lb) );
    925 }
    926 if( !SCIPisInfinity(scip, ub) )
    927 {
    928 if( SCIPisInfinity(scip, -ub) )
    929 {
    930 SCIP_CALL_THROW( SCIPchgRhsLinear(scip, probdata->conss[index], 0.0) );
    931 }
    932 SCIP_CALL_THROW( SCIPchgRhsLinear(scip, probdata->conss[index], ub) );
    933 }
    934 }
    935 }
    936
    937 /// receive notification of the initial value for a variable
    939 int var_index, ///< AMPL index of variable
    940 double value ///< initial primal value of variable
    941 )
    942 {
    943 if( initsol == NULL )
    944 {
    945 SCIP_CALL_THROW( SCIPcreateSol(scip, &initsol, NULL) );
    946 }
    947
    948 SCIP_CALL_THROW( SCIPsetSolVal(scip, initsol, probdata->vars[var_index], value) );
    949 }
    950
    951 /// receives notification of the initial value for a dual variable
    953 int /* con_index */, ///< AMPL index of constraint
    954 double /* value */ ///< initial dual value of constraint
    955 )
    956 {
    957 // ignore initial dual value
    958 }
    959
    960 /// receives notification of Jacobian column sizes
    961 ColumnSizeHandler OnColumnSizes()
    962 {
    963 /// use ColumnSizeHandler from upper class, which does nothing
    964 return ColumnSizeHandler();
    965 }
    966
    967 /// handling of suffices for variable and constraint flags and SOS constraints
    968 ///
    969 /// regarding SOS in AMPL, see https://discuss.ampl.com/t/how-can-i-use-the-solver-s-special-ordered-sets-feature/45
    970 /// we pass the .ref suffix as weight to the SOS constraint handlers
    971 /// for a SOS2, the weights determine the order of variables in the set
    972 template<typename T> class SuffixHandler
    973 {
    974 private:
    975 AMPLProblemHandler& amplph;
    976
    977 // type of suffix that is handled, or IGNORE if unsupported suffix
    978 enum
    979 {
    980 IGNORE,
    981 CONSINITIAL,
    982 CONSSEPARATE,
    983 CONSENFORCE,
    984 CONSCHECK,
    985 CONSPROPAGATE,
    986 CONSDYNAMIC,
    987 CONSREMOVABLE,
    988 VARINITIAL,
    989 VARREMOVABLE,
    990 VARSOSNO,
    991 VARREF,
    992 } suffix;
    993
    994 public:
    995 /// constructor
    997 AMPLProblemHandler& amplph_, ///< problem handler
    998 fmt::StringRef name, ///< name of suffix
    999 mp::suf::Kind kind ///< whether suffix applies to var, cons, etc
    1000 )
    1001 : amplph(amplph_),
    1002 suffix(IGNORE)
    1003 {
    1004 switch( kind )
    1005 {
    1006 case mp::suf::Kind::CON:
    1007 if( strncmp(name.data(), "initial", name.size()) == 0 )
    1008 {
    1009 suffix = CONSINITIAL;
    1010 }
    1011 else if( strncmp(name.data(), "separate", name.size()) == 0 )
    1012 {
    1013 suffix = CONSSEPARATE;
    1014 }
    1015 else if( strncmp(name.data(), "enforce", name.size()) == 0 )
    1016 {
    1017 suffix = CONSENFORCE;
    1018 }
    1019 else if( strncmp(name.data(), "check", name.size()) == 0 )
    1020 {
    1021 suffix = CONSCHECK;
    1022 }
    1023 else if( strncmp(name.data(), "propagate", name.size()) == 0 )
    1024 {
    1025 suffix = CONSPROPAGATE;
    1026 }
    1027 else if( strncmp(name.data(), "dynamic", name.size()) == 0 )
    1028 {
    1029 suffix = CONSDYNAMIC;
    1030 }
    1031 else if( strncmp(name.data(), "removable", name.size()) == 0 )
    1032 {
    1033 suffix = CONSREMOVABLE;
    1034 }
    1035 else
    1036 {
    1037 SCIPverbMessage(amplph.scip, SCIP_VERBLEVEL_HIGH, NULL, "Unknown constraint suffix <%.*s>. Ignoring.\n", (int)name.size(), name.data());
    1038 }
    1039 break;
    1040
    1041 case mp::suf::Kind::CON_BIT:
    1042 SCIPverbMessage(amplph.scip, SCIP_VERBLEVEL_HIGH, NULL, "Unknown constraint bit suffix <%.*s>. Ignoring.\n", (int)name.size(), name.data());
    1043 break;
    1044
    1045 case mp::suf::Kind::VAR:
    1046 {
    1047 if( strncmp(name.data(), "initial", name.size()) == 0 )
    1048 {
    1049 suffix = VARINITIAL;
    1050 }
    1051 else if( strncmp(name.data(), "removable", name.size()) == 0 )
    1052 {
    1053 suffix = VARREMOVABLE;
    1054 }
    1055 else if( strncmp(name.data(), "sosno", name.size()) == 0 )
    1056 {
    1057 // SOS membership
    1058 suffix = VARSOSNO;
    1059 }
    1060 else if( strncmp(name.data(), "ref", name.size()) == 0 )
    1061 {
    1062 // SOS weights
    1063 suffix = VARREF;
    1064 amplph.sosweights.resize(amplph.probdata->nvars, 0);
    1065 }
    1066 else
    1067 {
    1068 SCIPverbMessage(amplph.scip, SCIP_VERBLEVEL_HIGH, NULL, "Unknown variable suffix <%.*s>. Ignoring.\n", (int)name.size(), name.data());
    1069 }
    1070 break;
    1071
    1072 case mp::suf::Kind::VAR_BIT:
    1073 SCIPverbMessage(amplph.scip, SCIP_VERBLEVEL_HIGH, NULL, "Unknown variable bit suffix <%.*s>. Ignoring.\n", (int)name.size(), name.data());
    1074 break;
    1075
    1076 case mp::suf::Kind::OBJ:
    1077 SCIPverbMessage(amplph.scip, SCIP_VERBLEVEL_HIGH, NULL, "Unknown objective suffix <%.*s>. Ignoring.\n", (int)name.size(), name.data());
    1078 break;
    1079
    1080 case mp::suf::Kind::OBJ_BIT:
    1081 SCIPverbMessage(amplph.scip, SCIP_VERBLEVEL_HIGH, NULL, "Unknown objective bit suffix <%.*s>. Ignoring.\n", (int)name.size(), name.data());
    1082 break;
    1083
    1085 SCIPverbMessage(amplph.scip, SCIP_VERBLEVEL_HIGH, NULL, "Unknown problem suffix <%.*s>. Ignoring.\n", (int)name.size(), name.data());
    1086 break;
    1087
    1088 case mp::suf::Kind::PROB_BIT:
    1089 SCIPverbMessage(amplph.scip, SCIP_VERBLEVEL_HIGH, NULL, "Unknown problem bit suffix <%.*s>. Ignoring.\n", (int)name.size(), name.data());
    1090 break;
    1091 }
    1092 }
    1093 }
    1094
    1096 int index, ///< index of variable, constraint, etc
    1097 T value ///< value of suffix
    1098 )
    1099 {
    1100 assert(index >= 0);
    1101 switch( suffix )
    1102 {
    1103 case IGNORE :
    1104 return;
    1105
    1106 case CONSINITIAL:
    1107 SCIP_CALL_THROW( SCIPsetConsInitial(amplph.scip, amplph.probdata->conss[index], value == 1) );
    1108 break;
    1109
    1110 case CONSSEPARATE:
    1111 SCIP_CALL_THROW( SCIPsetConsSeparated(amplph.scip, amplph.probdata->conss[index], value == 1) );
    1112 break;
    1113
    1114 case CONSENFORCE:
    1115 SCIP_CALL_THROW( SCIPsetConsEnforced(amplph.scip, amplph.probdata->conss[index], value == 1) );
    1116 break;
    1117
    1118 case CONSCHECK:
    1119 SCIP_CALL_THROW( SCIPsetConsChecked(amplph.scip, amplph.probdata->conss[index], value == 1) );
    1120 break;
    1121
    1122 case CONSPROPAGATE:
    1123 SCIP_CALL_THROW( SCIPsetConsPropagated(amplph.scip, amplph.probdata->conss[index], value == 1) );
    1124 break;
    1125
    1126 case CONSDYNAMIC:
    1127 SCIP_CALL_THROW( SCIPsetConsDynamic(amplph.scip, amplph.probdata->conss[index], value == 1) );
    1128 break;
    1129
    1130 case CONSREMOVABLE:
    1131 SCIP_CALL_THROW( SCIPsetConsRemovable(amplph.scip, amplph.probdata->conss[index], value == 1) );
    1132 break;
    1133
    1134 case VARINITIAL:
    1135 assert(index < amplph.probdata->nvars);
    1136 SCIP_CALL_THROW( SCIPvarSetInitial(amplph.probdata->vars[index], value == 1) );
    1137 break;
    1138
    1139 case VARREMOVABLE:
    1140 assert(index < amplph.probdata->nvars);
    1141 SCIP_CALL_THROW( SCIPvarSetRemovable(amplph.probdata->vars[index], value == 1) );
    1142 break;
    1143
    1144 case VARSOSNO:
    1145 // remember that variable index belongs to SOS identified by value
    1146 amplph.sosvars[(int)value].push_back(index);
    1147 break;
    1148
    1149 case VARREF:
    1150 // remember that variable index has weight value
    1151 amplph.sosweights[index] = (int)value;
    1152 break;
    1153 }
    1154 }
    1155 };
    1156
    1158 /// receive notification of an integer suffix
    1160 fmt::StringRef name, ///< suffix name, not null-terminated
    1161 mp::suf::Kind kind, ///< suffix kind
    1162 int /*num_values*/ ///< number of values to expect
    1163 )
    1164 {
    1165 return IntSuffixHandler(*this, name, kind);
    1166 }
    1167
    1169 /// receive notification of a double suffix
    1171 fmt::StringRef name, ///< suffix name, not null-terminated
    1172 mp::suf::Kind kind, ///< suffix kind
    1173 int /*num_values*/ ///< number of values to expect
    1174 )
    1175 {
    1176 return DblSuffixHandler(*this, name, kind);
    1177 }
    1178
    1179 /// handles receiving the linear part of an objective or constraint
    1180 ///
    1181 /// for objective, set the objective-coefficient of the variable
    1182 /// for linear constraints, add to the constraint
    1183 /// for nonlinear constraints, add to nlconslin vector; adding to constraint later
    1185 {
    1186 private:
    1187 AMPLProblemHandler& amplph;
    1188 int constraintIndex;
    1189
    1190 public:
    1191 // constructor for constraint
    1193 AMPLProblemHandler& amplph_, ///< problem handler
    1194 int constraintIndex_///< constraint index
    1195 )
    1196 : amplph(amplph_),
    1197 constraintIndex(constraintIndex_)
    1198 {
    1199 assert(constraintIndex_ >= 0);
    1200 assert(constraintIndex_ < amplph.probdata->nconss);
    1201 }
    1202
    1203 // constructor for linear objective
    1205 AMPLProblemHandler& amplph_ ///< problem handler
    1206 )
    1207 : amplph(amplph_),
    1208 constraintIndex(-1)
    1209 { }
    1210
    1212 int variableIndex, ///< AMPL index of variable
    1213 double coefficient ///< coefficient of variable
    1214 )
    1215 {
    1216 assert(variableIndex >= 0);
    1217 assert(variableIndex < amplph.probdata->nvars);
    1218
    1219 if( coefficient == 0.0 )
    1220 return;
    1221
    1222 if( constraintIndex < 0 )
    1223 {
    1224 SCIP_CALL_THROW( SCIPchgVarObj(amplph.scip, amplph.probdata->vars[variableIndex], coefficient) );
    1225 }
    1226 else if( constraintIndex < (int)amplph.nlconslin.size() )
    1227 {
    1228 amplph.nlconslin[constraintIndex].push_back(std::pair<SCIP_Real, SCIP_VAR*>(coefficient, amplph.probdata->vars[variableIndex]));
    1229 }
    1230 else
    1231 {
    1232 SCIP_CONS* lincons = amplph.probdata->conss[constraintIndex];
    1233 SCIP_CALL_THROW( SCIPaddCoefLinear(amplph.scip, lincons, amplph.probdata->vars[variableIndex], coefficient) );
    1234 }
    1235 }
    1236 };
    1237
    1239
    1240 /// receive notification of the linear part of an objective
    1242 int objectiveIndex, ///< index of objective
    1243 int /* numLinearTerms *////< number of terms to expect
    1244 )
    1245 {
    1246 if( objectiveIndex >= 1 )
    1247 OnUnhandled("multiple objective functions");
    1248
    1249 return LinearObjHandler(*this);
    1250 }
    1251
    1253
    1254 /// receive notification of the linear part of a constraint
    1256 int constraintIndex, ///< index of constraint
    1257 int /* numLinearTerms *////< number of terms to expect
    1258 )
    1259 {
    1260 return LinearConHandler(*this, constraintIndex);
    1261 }
    1262
    1263 /// receives notification of a `Boolean value <mp::expr::BOOL>`
    1264 LogicalExpr OnBool(
    1265 bool value
    1266 )
    1267 {
    1268 SCIP_EXPR* expr;
    1269
    1270 SCIP_CALL_THROW( SCIPcreateExprValue(scip, &expr, value ? 1.0 : 0.0, NULL, NULL) );
    1271
    1272 // remember that we have to release this expr
    1273 exprstorelease.push_back(expr);
    1274
    1275 return expr;
    1276 }
    1277
    1278 /// receives notification of a `logical not <mp::expr::NOT>`
    1279 LogicalExpr OnNot(
    1280 LogicalExpr arg
    1281 )
    1282 {
    1283 SCIP_EXPR* expr;
    1284 SCIP_VAR* var;
    1285 SCIP_Bool val;
    1286
    1287 LogicalExprToVarVal(arg, var, val);
    1288 if( var != NULL )
    1289 {
    1290 SCIP_CALL_THROW( SCIPgetNegatedVar(scip, var, &var) );
    1292 }
    1293 else
    1294 {
    1295 SCIP_CALL_THROW( SCIPcreateExprValue(scip, &expr, val ? 1.0 : 0.0, NULL, NULL) );
    1296 }
    1297
    1298 // remember that we have to release this expr
    1299 exprstorelease.push_back(expr);
    1300
    1301 return expr;
    1302 }
    1303
    1304 /// receives notification of a `binary logical expression <mp::expr::FIRST_BINARY_LOGICAL>`
    1305 LogicalExpr OnBinaryLogical(
    1306 mp::expr::Kind kind,
    1307 LogicalExpr lhs,
    1308 LogicalExpr rhs
    1309 )
    1310 {
    1311 SCIP_VAR* lhsvar = NULL;
    1312 SCIP_VAR* rhsvar = NULL;
    1313 SCIP_Bool lhsval;
    1314 SCIP_Bool rhsval;
    1315 SCIP_EXPR* expr;
    1316
    1317 assert(lhs != NULL);
    1318 assert(rhs != NULL);
    1319
    1320 LogicalExprToVarVal(lhs, lhsvar, lhsval);
    1321 LogicalExprToVarVal(rhs, rhsvar, rhsval);
    1322
    1323 switch( kind )
    1324 {
    1325 case mp::expr::OR:
    1326 {
    1327 if( lhsvar == NULL && rhsvar == NULL )
    1328 {
    1329 SCIP_CALL_THROW( SCIPcreateExprValue(scip, &expr, lhsval != 0.0 || rhsval != 0.0 ? 1.0 : 0.0, NULL, NULL) );
    1330 exprstorelease.push_back(expr);
    1331 break;
    1332 }
    1333
    1334 if( (lhsvar == NULL && lhsval != 0.0) || (rhsvar == NULL && rhsval != 0.0) )
    1335 {
    1336 /* nonzero or rhs == 1, lhs or nonzero == 1 */
    1338 exprstorelease.push_back(expr);
    1339 break;
    1340 }
    1341
    1342 if( lhsvar == NULL )
    1343 {
    1344 /* zero or rhs == rhs */
    1345 assert(lhsval == 0.0);
    1346 expr = rhs;
    1347 break;
    1348 }
    1349
    1350 if( rhsvar == NULL )
    1351 {
    1352 /* lhs or zero == lhs */
    1353 assert(rhsval == 0.0);
    1354 expr = lhs;
    1355 break;
    1356 }
    1357
    1358 /* create new resvar and constraint resvar = lhsvar or rhsvar */
    1359 SCIP_VAR* vars[2];
    1360 SCIP_VAR* resvar;
    1361 SCIP_CONS* cons;
    1362
    1363 std::string name = std::string("_logic") + std::to_string((long long)logiccount++);
    1364 SCIP_CALL_THROW( SCIPcreateVarBasic(scip, &resvar, name.c_str(), 0.0, 1.0, 0.0, SCIP_VARTYPE_BINARY) );
    1365 SCIP_CALL_THROW( SCIPaddVar(scip, resvar) );
    1366 SCIP_CALL_THROW( SCIPcreateExprVar(scip, &expr, resvar, NULL, NULL) );
    1367 exprstorelease.push_back(expr);
    1368
    1369 vars[0] = lhsvar;
    1370 vars[1] = rhsvar;
    1371 name += "def";
    1372 SCIP_CALL_THROW( SCIPcreateConsBasicOr(scip, &cons, name.c_str(), resvar, 2, vars) );
    1374
    1375 SCIP_CALL_THROW( SCIPreleaseVar(scip, &resvar) );
    1377
    1378 break;
    1379 }
    1380
    1381 case mp::expr::AND:
    1382 {
    1383 if( lhsvar == NULL && rhsvar == NULL )
    1384 {
    1385 SCIP_CALL_THROW( SCIPcreateExprValue(scip, &expr, lhsval != 0.0 && rhsval != 0.0 ? 1.0 : 0.0, NULL, NULL) );
    1386 exprstorelease.push_back(expr);
    1387 break;
    1388 }
    1389
    1390 if( (lhsvar == NULL && lhsval == 0.0) || (rhsvar == NULL && rhsval == 0.0) )
    1391 {
    1392 /* zero and rhs == 0, lhs and zero == 0 */
    1394 exprstorelease.push_back(expr);
    1395 break;
    1396 }
    1397
    1398 if( lhsvar == NULL )
    1399 {
    1400 /* nonzero and rhs == rhs */
    1401 assert(lhsval != 0.0);
    1402 expr = rhs;
    1403 break;
    1404 }
    1405
    1406 if( rhsvar == NULL )
    1407 {
    1408 /* lhs and nonzero == lhs */
    1409 assert(rhsval != 0.0);
    1410 expr = lhs;
    1411 break;
    1412 }
    1413
    1414 /* create new resvar and constraint resvar = lhsvar and rhsvar */
    1415 SCIP_VAR* vars[2];
    1416 SCIP_VAR* resvar;
    1417 SCIP_CONS* cons;
    1418
    1419 std::string name = std::string("_logic") + std::to_string((long long)logiccount++);
    1420 SCIP_CALL_THROW( SCIPcreateVarBasic(scip, &resvar, name.c_str(), 0.0, 1.0, 0.0, SCIP_VARTYPE_BINARY) );
    1421 SCIP_CALL_THROW( SCIPaddVar(scip, resvar) );
    1422 SCIP_CALL_THROW( SCIPcreateExprVar(scip, &expr, resvar, NULL, NULL) );
    1423 exprstorelease.push_back(expr);
    1424
    1425 vars[0] = lhsvar;
    1426 vars[1] = rhsvar;
    1427 name += "def";
    1428 SCIP_CALL_THROW( SCIPcreateConsBasicAnd(scip, &cons, name.c_str(), resvar, 2, vars) );
    1430
    1431 SCIP_CALL_THROW( SCIPreleaseVar(scip, &resvar) );
    1433
    1434 break;
    1435 }
    1436
    1437 case mp::expr::IFF:
    1438 {
    1439 // the IFF operator returns 1 if both operands are nonzero or both are zero and returns zero otherwise
    1440 // so this is lhs == rhs
    1441 if( lhsvar == NULL && rhsvar == NULL )
    1442 {
    1443 SCIP_CALL_THROW( SCIPcreateExprValue(scip, &expr, lhsval == rhsval ? 1.0 : 0.0, NULL, NULL) );
    1444 exprstorelease.push_back(expr);
    1445 break;
    1446 }
    1447
    1448 if( lhsvar == NULL )
    1449 {
    1450 std::swap(lhs, rhs);
    1451 std::swap(lhsval, rhsval);
    1452 std::swap(lhsvar, rhsvar);
    1453 }
    1454 assert(lhsvar != NULL);
    1455
    1456 if( rhsvar == NULL )
    1457 {
    1458 // expression is lhsvar == true
    1459 // so we return lhsvar or ~lhsvar
    1460 if( rhsval == TRUE )
    1461 {
    1462 expr = lhs;
    1463 }
    1464 else
    1465 {
    1466 SCIP_CALL_THROW( SCIPgetNegatedVar(scip, lhsvar, &lhsvar) );
    1467 SCIP_CALL_THROW( SCIPcreateExprVar(scip, &expr, lhsvar, NULL, NULL) );
    1468 exprstorelease.push_back(expr);
    1469 }
    1470 break;
    1471 }
    1472
    1473 // expressions is lhsvar == rhsvar
    1474 // we create a new variable auxvar and add a constraint xor(auxvar, lhsvar, rhsvar, TRUE)
    1475 // to ensure auxvar = (lhsvar == rhsvar)
    1476 SCIP_VAR* vars[3];
    1477 SCIP_CONS* cons;
    1478 std::string name = std::string("_logic") + std::to_string((long long)logiccount++);
    1479 SCIP_CALL_THROW( SCIPcreateVarBasic(scip, &vars[0], name.c_str(), 0.0, 1.0, 0.0, SCIP_VARTYPE_BINARY) );
    1480 SCIP_CALL_THROW( SCIPaddVar(scip, vars[0]) );
    1481 SCIP_CALL_THROW( SCIPcreateExprVar(scip, &expr, vars[0], NULL, NULL) );
    1482 exprstorelease.push_back(expr);
    1483
    1484 vars[1] = lhsvar;
    1485 vars[2] = rhsvar;
    1486 name += "def";
    1487 SCIP_CALL_THROW( SCIPcreateConsBasicXor(scip, &cons, name.c_str(), TRUE, 3, vars) );
    1489
    1490 SCIP_CALL_THROW( SCIPreleaseVar(scip, &vars[0]) );
    1492
    1493 break;
    1494 }
    1495
    1496 default:
    1497 OnUnhandled(mp::expr::str(kind));
    1498 return NULL;
    1499 }
    1500
    1501 return expr;
    1502 }
    1503
    1504 /// receives notification of a `relational expression <mp::expr::FIRST_RELATIONAL>`
    1505 /// we only handle equality or inequality between binary variables and boolean values here
    1506 LogicalExpr OnRelational(
    1507 mp::expr::Kind kind,
    1508 NumericExpr lhs,
    1509 NumericExpr rhs
    1510 )
    1511 {
    1512 SCIP_VAR* lhsvar = NULL;
    1513 SCIP_VAR* rhsvar = NULL;
    1514 SCIP_Bool lhsval;
    1515 SCIP_Bool rhsval;
    1516 SCIP_EXPR* expr;
    1517
    1518 assert(lhs != NULL);
    1519 assert(rhs != NULL);
    1520
    1521 LogicalExprToVarVal(lhs, lhsvar, lhsval);
    1522 LogicalExprToVarVal(rhs, rhsvar, rhsval);
    1523
    1524 switch( kind )
    1525 {
    1526 case mp::expr::EQ:
    1527 case mp::expr::NE:
    1528 {
    1529 bool isne = (kind == mp::expr::NE);
    1530 if( lhsvar == NULL && rhsvar == NULL )
    1531 {
    1532 SCIP_CALL_THROW( SCIPcreateExprValue(scip, &expr, lhsval == rhsval ? (isne ? 0.0 : 1.0) : (isne ? 1.0 : 0.0), NULL, NULL) );
    1533 exprstorelease.push_back(expr);
    1534 break;
    1535 }
    1536
    1537 if( lhsvar == NULL )
    1538 {
    1539 std::swap(lhs, rhs);
    1540 std::swap(lhsval, rhsval);
    1541 std::swap(lhsvar, rhsvar);
    1542 }
    1543 assert(lhsvar != NULL);
    1544
    1545 if( rhsvar == NULL )
    1546 {
    1547 // expression is lhsvar == true or lhsvar == false if EQ
    1548 // so we return lhsvar or ~lhsvar, opposite if NE
    1549 if( rhsval == (isne ? FALSE : TRUE) )
    1550 {
    1551 expr = lhs;
    1552 }
    1553 else
    1554 {
    1555 SCIP_CALL_THROW( SCIPgetNegatedVar(scip, lhsvar, &lhsvar) );
    1556 SCIP_CALL_THROW( SCIPcreateExprVar(scip, &expr, lhsvar, NULL, NULL) );
    1557 exprstorelease.push_back(expr);
    1558 }
    1559 break;
    1560 }
    1561
    1562 // expressions is lhsvar == rhsvar or lhsvar != rhsvar
    1563 // we create a new variable auxvar and add a constraint xor(auxvar, lhsvar, rhsvar, isne ? FALSE : TRUE)
    1564 // to ensure auxvar = (lhsvar == rhsvar) or auxvar = (lhsvar != rhsvar)
    1565
    1566 SCIP_VAR* vars[3];
    1567 SCIP_CONS* cons;
    1568 std::string name = std::string("_logic") + std::to_string((long long)logiccount++);
    1569 SCIP_CALL_THROW( SCIPcreateVarBasic(scip, &vars[0], name.c_str(), 0.0, 1.0, 0.0, SCIP_VARTYPE_BINARY) );
    1570 SCIP_CALL_THROW( SCIPaddVar(scip, vars[0]) );
    1571 SCIP_CALL_THROW( SCIPcreateExprVar(scip, &expr, vars[0], NULL, NULL) );
    1572 exprstorelease.push_back(expr);
    1573
    1574 vars[1] = lhsvar;
    1575 vars[2] = rhsvar;
    1576 name += "def";
    1577 SCIP_CALL_THROW( SCIPcreateConsBasicXor(scip, &cons, name.c_str(), isne ? FALSE : TRUE, 3, vars) );
    1579
    1580 SCIP_CALL_THROW( SCIPreleaseVar(scip, &vars[0]) );
    1582
    1583 break;
    1584 }
    1585
    1586 default:
    1587 OnUnhandled(mp::expr::str(kind));
    1588 return NULL;
    1589 }
    1590
    1591 return expr;
    1592 }
    1593
    1594 /// receive notification of the end of the input
    1595 ///
    1596 /// - setup all nonlinear constraints and add them to SCIP
    1597 /// - add linear constraints to SCIP (should be after nonlinear ones to respect order in .nl file)
    1598 /// - add initial solution, if initial values were given
    1600 {
    1601 // turn nonlinear objective into constraint
    1602 // min f(x) -> min z s.t. f(x) - z <= 0
    1603 // max f(x) -> max z s.t. 0 <= f(x) - z
    1604 if( objexpr != NULL )
    1605 {
    1606 SCIP_CONS* objcons;
    1607 SCIP_VAR* objvar;
    1608
    1610 SCIP_CALL_THROW( SCIPaddVar(scip, objvar) );
    1611
    1612 SCIP_CALL_THROW( SCIPcreateConsBasicNonlinear(scip, &objcons, "objcons", objexpr,
    1615 SCIP_CALL_THROW( SCIPaddLinearVarNonlinear(scip, objcons, objvar, -1.0) );
    1616 SCIP_CALL_THROW( SCIPaddCons(scip, objcons) );
    1617
    1618 if( initsol != NULL )
    1619 {
    1620 /* compute value for objvar in initial solution from other variable values */
    1621 SCIP_CALL_THROW( SCIPevalExpr(scip, objexpr, initsol, 0) );
    1622 if( SCIPexprGetEvalValue(objexpr) != SCIP_INVALID )
    1623 {
    1624 SCIPsetSolVal(scip, initsol, objvar, SCIPexprGetEvalValue(objexpr));
    1625 }
    1626 else
    1627 {
    1628 SCIPwarningMessage(scip, "Objective function could not be evaluated in initial point. Domain error.");
    1629 }
    1630 }
    1631
    1632 SCIP_CALL_THROW( SCIPreleaseCons(scip, &objcons) );
    1633 SCIP_CALL_THROW( SCIPreleaseVar(scip, &objvar) );
    1634 }
    1635
    1636 // add linear terms to expressions of nonlinear constraints (should be ok to do this one-by-one for now)
    1637 for( size_t i = 0; i < nlconslin.size(); ++i )
    1638 {
    1639 for( size_t j = 0; j < nlconslin[i].size(); ++j )
    1640 {
    1641 SCIP_CALL_THROW( SCIPaddLinearVarNonlinear(scip, probdata->conss[i], nlconslin[i][j].second, nlconslin[i][j].first) );
    1642 }
    1643 }
    1644
    1645 // add constraints
    1646 for( int i = 0; i < probdata->nconss; ++i )
    1647 {
    1648 SCIP_CALL_THROW( SCIPaddCons(scip, probdata->conss[i]) );
    1649 }
    1650
    1651 // add SOS constraints
    1652 std::vector<SCIP_VAR*> setvars; // variables in one SOS
    1653 std::vector<SCIP_Real> setweights; // weights for one SOS
    1654 if( !sosvars.empty() )
    1655 {
    1656 setvars.resize(probdata->nvars);
    1657 probdata->islp = false;
    1658 }
    1659 if( !sosweights.empty() )
    1660 setweights.resize(probdata->nvars);
    1661 for( std::map<int, std::vector<int> >::iterator sosit(sosvars.begin()); sosit != sosvars.end(); ++sosit )
    1662 {
    1663 assert(sosit->first != 0);
    1664 assert(!sosit->second.empty());
    1665
    1666 // a negative SOS identifier means SOS2
    1667 bool issos2 = sosit->first < 0;
    1668
    1669 if( issos2 && sosweights.empty() )
    1670 {
    1671 // if no .ref suffix was given for a SOS2 constraint, then we consider this as an error
    1672 // since the weights determine the order
    1673 // for a SOS1, the weights only specify branching preference, so can treat them as optional
    1674 OnUnhandled("SOS2 requires variable .ref suffix");
    1675 }
    1676
    1677 for( size_t i = 0; i < sosit->second.size(); ++i )
    1678 {
    1679 int varidx = sosit->second[i];
    1680 setvars[i] = probdata->vars[varidx]; /* cppcheck-suppress unreadVariable */
    1681
    1682 if( issos2 && sosweights[varidx] == 0 )
    1683 // 0 is the default if no ref was given for a variable; we don't allow this for SOS2
    1684 OnUnhandled("Missing .ref value for SOS2 variable");
    1685 if( !sosweights.empty() )
    1686 setweights[i] = (SCIP_Real)sosweights[varidx];
    1687 }
    1688
    1689 SCIP_CONS* cons;
    1690 char name[20];
    1691 if( !issos2 )
    1692 {
    1693 (void) SCIPsnprintf(name, 20, "sos1_%d", sosit->first);
    1694 SCIP_CALL_THROW( SCIPcreateConsBasicSOS1(scip, &cons, name, sosit->second.size(), setvars.data(), setweights.empty() ? NULL : setweights.data()) );
    1695 }
    1696 else
    1697 {
    1698 (void) SCIPsnprintf(name, 20, "sos2_%d", -sosit->first);
    1699 SCIP_CALL_THROW( SCIPcreateConsBasicSOS2(scip, &cons, name, sosit->second.size(), setvars.data(), setweights.data()) );
    1700 }
    1703 }
    1704
    1705 // add initial solution
    1706 if( initsol != NULL )
    1707 {
    1708 SCIP_Bool stored;
    1709 SCIP_CALL_THROW( SCIPaddSolFree(scip, &initsol, &stored) );
    1710 }
    1711
    1712 // release expressions
    1714 }
    1715
    1716 /// releases expressions and linear constraints from data
    1717 ///
    1718 /// should be called if there was an error while reading the .nl file
    1719 /// this is not in the destructor, because we want to return SCIP_RETCODE
    1721 {
    1722 // release initial sol (in case EndInput() wasn't called)
    1723 if( initsol != NULL )
    1724 {
    1725 SCIP_CALL( SCIPfreeSol(scip, &initsol) );
    1726 }
    1727
    1728 // release created expressions (they should all be used in other expressions or constraints now)
    1729 while( !exprstorelease.empty() )
    1730 {
    1731 SCIP_CALL( SCIPreleaseExpr(scip, &exprstorelease.back()) );
    1732 exprstorelease.pop_back();
    1733 }
    1734
    1735 // release variable expressions (they should all be used in other expressions or constraints now)
    1736 while( !varexprs.empty() )
    1737 {
    1738 SCIP_CALL( SCIPreleaseExpr(scip, &varexprs.back()) );
    1739 varexprs.pop_back();
    1740 }
    1741
    1742 return SCIP_OKAY;
    1743 }
    1744};
    1745
    1746class SCIPNLFeeder : public mp::NLFeeder<SCIPNLFeeder, SCIP_EXPR*>
    1747{
    1748private:
    1749 SCIP* scip; ///< SCIP data structure (problem to write)
    1750 const char* probname; ///< problem name
    1751 SCIP_OBJSENSE objsense; ///< objective sense
    1752 SCIP_Real objscale; ///< objective scale
    1753 SCIP_Real objoffset; ///< objective offset
    1754 SCIP_VAR** activevars; ///< active variables
    1755 int nactivevars; ///< number of active variables
    1756 SCIP_VAR** fixedvars; ///< fixed variables
    1757 int nfixedvars; ///< number of fixed variables
    1758 SCIP_CONS** allconss; ///< all constraints given to writer
    1759 int nallconss; ///< number of all constraints
    1760
    1761 bool nlcomments; ///< whether to write nl files with comments
    1762 SCIP_Bool genericnames; ///< are generic names used
    1763
    1764 SCIP_CONSHDLR* conshdlr_nonlinear; ///< nonlinear constraints handler
    1765 SCIP_CONSHDLR* conshdlr_linear; ///< linear constraints handler
    1766 SCIP_CONSHDLR* conshdlr_setppc; ///< setppc constraints handler
    1767 SCIP_CONSHDLR* conshdlr_logicor; ///< logicor constraints handler
    1768 SCIP_CONSHDLR* conshdlr_knapsack; ///< knapsack constraints handler
    1769 SCIP_CONSHDLR* conshdlr_varbound; ///< varbound constraints handlers
    1770
    1771 mp::NLHeader nlheader; ///< NL header with various counts
    1772 SCIP_VAR** vars; ///< variables in AMPL order
    1773 int nvars; ///< number of variables (= nactivevars)
    1774 SCIP_HASHMAP* var2idx; ///< map variable to AMPL index
    1775 SCIP_CONS** algconss; ///< algebraic constraints that will be written, permuted in AMPL order
    1776 SCIP_Real* algconsslhs; ///< left hand side of algebraic constraints
    1777 SCIP_Real* algconssrhs; ///< right hand side of algebraic constraints
    1778 int nalgconss; ///< number of algebraic constraint we will actually write
    1779 SCIP_VAR** aggconss; ///< fixed variable for which aggregation constraints need to be written
    1780 int naggconss; ///< number of fixed variables for which aggregation constraints are written
    1781
    1782 /** variable types by which variables need to be ordered for .nl
    1783 * (names are taken from pyomo nl writer, with those for nonlinear objective removed)
    1784 */
    1785 typedef enum
    1786 {
    1787 ConNonlinearVars = 0, /* only in cons */
    1788 ConNonlinearVarsInt = 1, /* only in cons */
    1789 LinearVars = 2,
    1790 LinearVarsBool = 3,
    1791 LinearVarsInt = 4
    1792 } NlVarType;
    1793
    1794 /** checks variable types and other properties for nlheader;
    1795 * sets up variables permutation
    1796 */
    1797 void analyseVariables()
    1798 {
    1799 NlVarType* vartype = NULL;
    1800 SCIP_HASHMAP* var2expr = NULL;
    1801
    1802 int nlvars_cons = 0;
    1803 int binvars_lin = 0;
    1804 int intvars_lin = 0;
    1805 int discrvars_nlcons = 0;
    1806
    1807 nlheader.max_var_name_len = 0;
    1808
    1809 /* number of nonzeros in objective gradient */
    1810 nlheader.num_obj_nonzeros = 0;
    1811
    1812 if( conshdlr_nonlinear != NULL )
    1813 var2expr = SCIPgetVarExprHashmapNonlinear(conshdlr_nonlinear);
    1814
    1815 SCIP_CALL_THROW( SCIPallocBufferArray(scip, &vartype, nactivevars + nfixedvars) );
    1816
    1817 /* collect statistics on variables; determine variable types */
    1818 for( int i = 0; i < nactivevars + nfixedvars; ++i )
    1819 {
    1820 SCIP_VAR* var = (i < nactivevars ? activevars[i] : fixedvars[i-nactivevars]);
    1821 SCIP_Bool isdiscrete;
    1822 SCIP_Bool isnonlinear = FALSE;
    1823
    1824 if( SCIPvarGetObj(var) != 0.0 )
    1825 ++nlheader.num_obj_nonzeros;
    1826
    1827 isdiscrete = SCIPvarGetType(var) <= SCIP_VARTYPE_INTEGER;
    1828
    1829 /* we think of a variable as nonlinear if cons_nonlinear has a SCIP_EXPR* for this variable
    1830 * this is usually an overestimation, since also variables that appear only linearly in nonlinear constraints
    1831 * are regarded as nonlinear this way
    1832 * we also consider variables as nonlinear when only its negation appears in a nonlinear constraint,
    1833 * since we will write out the negation of var as 1-var into the nl file
    1834 */
    1835 if( var2expr != NULL )
    1836 {
    1837 isnonlinear = SCIPhashmapExists(var2expr, (void*)var);
    1838 if( !isnonlinear && SCIPvarGetNegatedVar(var) != NULL )
    1839 isnonlinear = SCIPhashmapExists(var2expr, (void*)SCIPvarGetNegatedVar(var));
    1840 }
    1841
    1842 /* this is how Pyomo counts vars (nlvars_* = nlvb,c,o) when writing NL
    1843 * https://github.com/Pyomo/pyomo/blob/main/pyomo/repn/plugins/ampl/ampl_.py#L1202
    1844 * this, together with the ominous line below, seems to correspond to what AMPL writes
    1845 */
    1846 if( isnonlinear )
    1847 {
    1848 /* nonlinear (in constraints only, as this is SCIP) */
    1849 ++nlvars_cons;
    1850 if( isdiscrete )
    1851 {
    1852 ++discrvars_nlcons;
    1853 vartype[i] = ConNonlinearVarsInt;
    1854 }
    1855 else
    1856 vartype[i] = ConNonlinearVars;
    1857 }
    1858 else
    1859 {
    1860 /* linear */
    1861 if( isdiscrete )
    1862 {
    1863 /* for compatibility with AMPL generated nl files, count integer with 0/1 bounds as binary, too */
    1865 {
    1866 ++binvars_lin;
    1867 vartype[i] = LinearVarsBool;
    1868 }
    1869 else
    1870 {
    1871 ++intvars_lin;
    1872 vartype[i] = LinearVarsInt;
    1873 }
    1874 }
    1875 else
    1876 vartype[i] = LinearVars;
    1877 }
    1878
    1879 if( !genericnames )
    1880 {
    1881 int namelen = (int)strlen(SCIPvarGetName(var));
    1882 if( namelen > nlheader.max_var_name_len )
    1883 nlheader.max_var_name_len = namelen;
    1884 }
    1885 }
    1886
    1887 /* setup var permutation */
    1888 assert(vars == NULL);
    1889 SCIP_CALL_THROW( SCIPallocBlockMemoryArray(scip, &vars, nactivevars + nfixedvars) );
    1890 SCIP_CALL_THROW( SCIPhashmapCreate(&var2idx, SCIPblkmem(scip), nactivevars + nfixedvars) );
    1891 nvars = 0;
    1892 for( int vtype = ConNonlinearVars; vtype <= LinearVarsInt; ++vtype )
    1893 for( int i = 0; i < nactivevars + nfixedvars; ++i )
    1894 if( vartype[i] == (NlVarType)vtype )
    1895 {
    1896 vars[nvars] = (i < nactivevars ? activevars[i] : fixedvars[i-nactivevars]);
    1897 SCIP_CALL_THROW( SCIPhashmapInsertInt(var2idx, (void*)vars[nvars], nvars) );
    1898 ++nvars;
    1899 }
    1900 assert(nvars == nactivevars + nfixedvars);
    1901
    1902 SCIPfreeBufferArray(scip, &vartype);
    1903
    1904 nlheader.num_vars = nvars;
    1905
    1906 /* number of nonlinear variables
    1907 * setting num_nl_vars_in_objs = nlvars_cons looks odd, but makes the generated nl files
    1908 * consistent with what AMPL or Pyomo writes
    1909 */
    1910 nlheader.num_nl_vars_in_cons = nlvars_cons;
    1911 nlheader.num_nl_vars_in_objs = nlvars_cons;
    1912 nlheader.num_nl_vars_in_both = 0;
    1913
    1914 /* number of linear network variables */
    1915 nlheader.num_linear_net_vars = 0;
    1916
    1917 /* number of linear binary and integer variables */
    1918 nlheader.num_linear_binary_vars = binvars_lin;
    1919 nlheader.num_linear_integer_vars = intvars_lin;
    1920
    1921 /* number of integer nonlinear variables */
    1922 nlheader.num_nl_integer_vars_in_both = 0;
    1923 nlheader.num_nl_integer_vars_in_cons = discrvars_nlcons;
    1924 nlheader.num_nl_integer_vars_in_objs = 0;
    1925 }
    1926
    1927 /** checks constraint types and other properties for nlheader;
    1928 * sets up constraints permutation
    1929 */
    1930 void analyzeConstraints()
    1931 {
    1932 /* collect algebraic constraints and their side: for AMPL, nonlinear comes before linear */
    1933 SCIP_CALL_THROW( SCIPallocBlockMemoryArray(scip, &algconss, nallconss) );
    1934 SCIP_CALL_THROW( SCIPallocBlockMemoryArray(scip, &algconsslhs, nallconss) );
    1935 SCIP_CALL_THROW( SCIPallocBlockMemoryArray(scip, &algconssrhs, nallconss) );
    1936
    1937 nalgconss = 0;
    1938 if( nlheader.num_nl_vars_in_cons > 0 )
    1939 {
    1940 for( int i = 0; i < nallconss; ++i )
    1941 {
    1942 SCIP_CONS* cons = allconss[i];
    1943 if( SCIPconsGetHdlr(cons) == conshdlr_nonlinear )
    1944 {
    1945 algconss[nalgconss] = cons;
    1946 algconsslhs[nalgconss] = SCIPgetLhsNonlinear(cons);
    1947 algconssrhs[nalgconss] = SCIPgetRhsNonlinear(cons);
    1948 ++nalgconss;
    1949 }
    1950 }
    1951 }
    1952 /* total number of nonlinear constraints */
    1953 nlheader.num_nl_cons = nalgconss;
    1954
    1955 /* pick constraints we recognize as linear
    1956 * count ranged and equality constraints
    1957 * check constraint name lengths (if not skipped due to being generic)
    1958 * count number of variables in constraints
    1959 */
    1960 nlheader.num_ranges = 0; /* number of ranged constraints */
    1961 nlheader.num_eqns = 0; /* number of equality constraints */
    1962 nlheader.max_con_name_len = 0; /* maximal length of constraints' names */
    1963 nlheader.num_con_nonzeros = 0; /* number of nonzeros in constraints' Jacobian */
    1964 for( int i = 0; i < nallconss; ++i )
    1965 {
    1966 SCIP_CONS* cons = allconss[i];
    1967 SCIP_CONSHDLR* conshdlr = SCIPconsGetHdlr(cons);
    1968 SCIP_Real lhs;
    1969 SCIP_Real rhs;
    1970
    1971 if( conshdlr == conshdlr_nonlinear )
    1972 {
    1973 lhs = SCIPgetLhsNonlinear(cons);
    1974 rhs = SCIPgetRhsNonlinear(cons);
    1975 }
    1976 else
    1977 {
    1978 /* negated variables may not show up in fixedvars
    1979 * so we instead replace the negation when providing the coefficients of the linear constraint
    1980 * this means additional constants to subtract from lhs/rhs
    1981 */
    1982 if( conshdlr == conshdlr_linear )
    1983 {
    1984 int nconsvars = SCIPgetNVarsLinear(scip, cons);
    1985 SCIP_VAR** consvars = SCIPgetVarsLinear(scip, cons);
    1986 SCIP_Real* conscoefs = SCIPgetValsLinear(scip, cons);
    1987 SCIP_Real negconstant = 0.0;
    1988 for( int v = 0; v < nconsvars; ++v )
    1989 if( SCIPvarIsNegated(consvars[v]) )
    1990 negconstant += conscoefs[v];
    1991
    1992 lhs = SCIPgetLhsLinear(scip, cons);
    1993 if( !SCIPisInfinity(scip, -lhs) )
    1994 lhs -= negconstant;
    1995
    1996 rhs = SCIPgetRhsLinear(scip, cons);
    1997 if( !SCIPisInfinity(scip, rhs) )
    1998 rhs -= negconstant;
    1999 }
    2000 else if( conshdlr == conshdlr_setppc )
    2001 {
    2002 int nconsvars = SCIPgetNVarsSetppc(scip, cons);
    2003 SCIP_VAR** consvars = SCIPgetVarsSetppc(scip, cons);
    2004 SCIP_Real negconstant = 0.0;
    2005 for( int v = 0; v < nconsvars; ++v )
    2006 if( SCIPvarIsNegated(consvars[v]) )
    2007 negconstant += 1.0;
    2008
    2009 switch( SCIPgetTypeSetppc(scip, cons) )
    2010 {
    2012 lhs = 1.0 - negconstant;
    2013 rhs = 1.0 - negconstant;
    2014 break;
    2016 lhs = 1.0 - negconstant;
    2017 rhs = SCIPinfinity(scip);
    2018 break;
    2020 lhs = -SCIPinfinity(scip);
    2021 rhs = 1.0 - negconstant;
    2022 break;
    2023 default:
    2024 throw mp::UnsupportedError("Unexpected SETPPC type");
    2025 }
    2026 }
    2027 else if( conshdlr == conshdlr_logicor )
    2028 {
    2029 int nconsvars = SCIPgetNVarsLogicor(scip, cons);
    2030 SCIP_VAR** consvars = SCIPgetVarsLogicor(scip, cons);
    2031 SCIP_Real negconstant = 0.0;
    2032 for( int v = 0; v < nconsvars; ++v )
    2033 if( SCIPvarIsNegated(consvars[v]) )
    2034 negconstant += 1.0;
    2035
    2036 lhs = 1.0 - negconstant;
    2037 rhs = SCIPinfinity(scip);
    2038 }
    2039 else if( conshdlr == conshdlr_knapsack )
    2040 {
    2041 int nconsvars = SCIPgetNVarsKnapsack(scip, cons);
    2042 SCIP_VAR** consvars = SCIPgetVarsKnapsack(scip, cons);
    2043 SCIP_Longint* weights = SCIPgetWeightsKnapsack(scip, cons);
    2044 SCIP_Longint negweights = 0.0;
    2045 for( int v = 0; v < nconsvars; ++v )
    2046 if( SCIPvarIsNegated(consvars[v]) )
    2047 negweights += weights[v];
    2048
    2049 lhs = -SCIPinfinity(scip);
    2050 rhs = (SCIP_Real)(SCIPgetCapacityKnapsack(scip, cons) - negweights);
    2051 }
    2052 else if( conshdlr == conshdlr_varbound )
    2053 {
    2054 /* lhs <= var + vbdcoef*vbdvar <= rhs */
    2055 SCIP_Real negconstant = 0.0;
    2057 negconstant = 1.0;
    2059 negconstant += SCIPgetVbdcoefVarbound(scip, cons);
    2060
    2061 lhs = SCIPgetLhsVarbound(scip, cons);
    2062 if( !SCIPisInfinity(scip, -lhs) )
    2063 lhs -= negconstant;
    2064
    2065 rhs = SCIPgetRhsVarbound(scip, cons);
    2066 if( !SCIPisInfinity(scip, rhs) )
    2067 rhs -= negconstant;
    2068 }
    2069 else
    2070 {
    2071 SCIPwarningMessage(scip, "constraint <%s> of type <%s> cannot be printed in requested format\n", SCIPconsGetName(cons), SCIPconshdlrGetName(conshdlr));
    2072 continue;
    2073 }
    2074 algconss[nalgconss] = cons;
    2075 algconsslhs[nalgconss] = lhs;
    2076 algconssrhs[nalgconss] = rhs;
    2077 ++nalgconss;
    2078 }
    2079
    2080 if( !SCIPisInfinity(scip, -lhs) && !SCIPisInfinity(scip, rhs) )
    2081 {
    2082 if( SCIPisEQ(scip, lhs, rhs) )
    2083 ++nlheader.num_eqns;
    2084 else
    2085 ++nlheader.num_ranges;
    2086 }
    2087
    2088 if( !genericnames )
    2089 {
    2090 int namelen = (int)strlen(SCIPconsGetName(allconss[i]));
    2091 if( namelen > nlheader.max_con_name_len )
    2092 nlheader.max_con_name_len = namelen;
    2093 }
    2094
    2095 SCIP_Bool success;
    2096 int nvarsincons;
    2097 SCIP_CALL_THROW( SCIPgetConsNVars(scip, cons, &nvarsincons, &success) );
    2098 if( !success )
    2099 {
    2100 /* this should never happen */
    2101 SCIPwarningMessage(scip, "could not get number of variable from constraint handler <%s>; nonzero count in nl file will be wrong\n", SCIPconshdlrGetName(conshdlr));
    2102 }
    2103 else
    2104 {
    2105 nlheader.num_con_nonzeros += nvarsincons;
    2106 }
    2107 }
    2108 assert(nalgconss <= nallconss);
    2109
    2110 /* now add counts for aggregation constraints (definition of fixedvars that are aggregated, multiaggregated, or negated) */
    2111 SCIP_CALL_THROW( SCIPallocBlockMemoryArray(scip, &aggconss, nfixedvars) );
    2112 naggconss = 0;
    2113 for( int i = 0; i < nfixedvars; ++i )
    2114 {
    2115 SCIP_VAR* var = fixedvars[i];
    2116
    2117 switch( SCIPvarGetStatus(var) )
    2118 {
    2120 continue;
    2121
    2124 nlheader.num_con_nonzeros += 2;
    2125 break;
    2126
    2128 nlheader.num_con_nonzeros += SCIPvarGetMultaggrNVars(var) + 1;
    2129 break;
    2130
    2131 default:
    2132 SCIPerrorMessage("unexpected variable status %d of fixed variable <%s>\n", SCIPvarGetStatus(var), SCIPvarGetName(var));
    2134 }
    2135
    2136 if( !genericnames )
    2137 {
    2138 // AMPL constraint will be named aggr_<varname>
    2139 int namelen = (int)strlen(SCIPvarGetName(var)) + 5;
    2140 if( namelen > nlheader.max_con_name_len )
    2141 nlheader.max_con_name_len = namelen;
    2142 }
    2143
    2144 aggconss[naggconss] = var;
    2145 ++naggconss;
    2146
    2147 ++nlheader.num_eqns;
    2148 }
    2149
    2150 nlheader.num_algebraic_cons = nalgconss + naggconss;
    2151 nlheader.num_logical_cons = 0;
    2152
    2153 /* no complementarity conditions */
    2154 nlheader.num_compl_conds = 0;
    2155 nlheader.num_nl_compl_conds = 0;
    2156 nlheader.num_compl_dbl_ineqs = 0;
    2157 nlheader.num_compl_vars_with_nz_lb = 0;
    2158
    2159 /** no network constraints */
    2160 nlheader.num_nl_net_cons = 0;
    2161 nlheader.num_linear_net_cons = 0;
    2162 }
    2163
    2164 /* gets AMPL index of variable (using var2idx) */
    2165 int getVarAMPLIndex(
    2166 SCIP_VAR* var
    2167 )
    2168 {
    2169 int varidx = SCIPhashmapGetImageInt(var2idx, (void*)var);
    2170 assert(varidx >= 0);
    2171 assert(varidx != INT_MAX);
    2172 assert(varidx < nvars);
    2173 assert(vars[varidx] == var);
    2174 return varidx;
    2175 }
    2176
    2177public:
    2178 /// Constructor
    2180 SCIP* scip_, ///< SCIP data structure
    2181 const char* probname_, ///< problem name
    2182 SCIP_OBJSENSE objsense_, ///< objective sense
    2183 SCIP_Real objscale_, ///< objective scale
    2184 SCIP_Real objoffset_, ///< objective offset
    2185 SCIP_VAR** vars_, ///< active variables
    2186 int nvars_, ///< number of active variables
    2187 SCIP_VAR** fixedvars_, ///< fixed variables
    2188 int nfixedvars_, ///< number of fixed variables
    2189 SCIP_CONS** conss_, ///< constraints
    2190 int nconss_, ///< number of constraints
    2191 SCIP_Bool nlbinary_, ///< whether to write binary or text nl
    2192 SCIP_Bool nlcomments_, ///< whether to include comments into nl
    2193 SCIP_Bool genericnames_ ///< are generic names used
    2194 )
    2195 : scip(scip_),
    2196 probname(probname_),
    2197 objsense(objsense_),
    2198 objscale(objscale_),
    2199 objoffset(objoffset_),
    2200 activevars(vars_),
    2201 nactivevars(nvars_),
    2202 fixedvars(fixedvars_),
    2203 nfixedvars(nfixedvars_),
    2204 allconss(conss_),
    2205 nallconss(nconss_),
    2206 nlcomments(nlcomments_),
    2207 genericnames(genericnames_),
    2208 vars(NULL),
    2209 nvars(0),
    2210 var2idx(NULL),
    2211 algconss(NULL),
    2212 algconsslhs(NULL),
    2213 algconssrhs(NULL),
    2214 nalgconss(0),
    2215 aggconss(NULL),
    2216 naggconss(0)
    2217 {
    2218 nlheader.format = nlbinary_ ? mp::NLHeader::BINARY : mp::NLHeader::TEXT;
    2219
    2220 conshdlr_nonlinear = SCIPfindConshdlr(scip, "nonlinear");
    2221 conshdlr_linear = SCIPfindConshdlr(scip, "linear");
    2222 conshdlr_setppc = SCIPfindConshdlr(scip, "setppc");
    2223 conshdlr_logicor = SCIPfindConshdlr(scip, "logicor");
    2224 conshdlr_knapsack = SCIPfindConshdlr(scip, "knapsack");
    2225 conshdlr_varbound = SCIPfindConshdlr(scip, "varbound");
    2226 }
    2227
    2229 {
    2230 SCIPfreeBlockMemoryArrayNull(scip, &aggconss, nfixedvars);
    2231 SCIPfreeBlockMemoryArrayNull(scip, &algconssrhs, nallconss);
    2232 SCIPfreeBlockMemoryArrayNull(scip, &algconsslhs, nallconss);
    2233 SCIPfreeBlockMemoryArrayNull(scip, &algconss, nallconss);
    2234 SCIPfreeBlockMemoryArrayNull(scip, &vars, nactivevars + nfixedvars);
    2235 if( var2idx != NULL )
    2236 SCIPhashmapFree(&var2idx);
    2237 }
    2238
    2239 /** Provide NLHeader.
    2240 *
    2241 * This method is called first.
    2242 *
    2243 * NLHeader summarizes the model and provides some technical parameters,
    2244 * such as text/binary NL format.
    2245 */
    2246 mp::NLHeader Header()
    2247 {
    2248 analyseVariables();
    2249 analyzeConstraints();
    2250
    2251 nlheader.prob_name = probname;
    2252
    2253 /* number of objectives
    2254 * if objective is all zero in SCIP, then just don't write any objective to nl
    2255 */
    2256 if( nlheader.num_obj_nonzeros == 0 && objoffset == 0.0 )
    2257 nlheader.num_objs = 0;
    2258 else
    2259 nlheader.num_objs = 1;
    2260 nlheader.num_nl_objs = 0;
    2261
    2262 /* number of functions */
    2263 nlheader.num_funcs = 0;
    2264
    2265 /* it would have been nice to handle fixed variables as common expressions,
    2266 * but as common expression are handled like nonlinear expressions,
    2267 * this would turn any linear constraint with fixed variables into common expressions
    2268 */
    2269 nlheader.num_common_exprs_in_both = 0;
    2270 nlheader.num_common_exprs_in_cons = 0;
    2271 nlheader.num_common_exprs_in_objs = 0;
    2272 nlheader.num_common_exprs_in_single_cons = 0;
    2273 nlheader.num_common_exprs_in_single_objs = 0;
    2274
    2275 return nlheader;
    2276 }
    2277
    2278 /// NL comments?
    2279 bool WantNLComments() const
    2280 {
    2281 return nlcomments;
    2282 }
    2283
    2284 /// currently we do not want to write size of each column in Jacobian
    2285 /// (i.e., number of constraints each variable appears in)
    2287 {
    2288 return 0;
    2289 }
    2290
    2292 int
    2293 ) const
    2294 {
    2295 return objsense == SCIP_OBJSENSE_MAXIMIZE ? 1 : 0;
    2296 }
    2297
    2298 template <class ObjGradWriter>
    2300 int i,
    2301 ObjGradWriter& gw
    2302 )
    2303 {
    2304 assert(i == 0);
    2305
    2306 if( nlheader.num_obj_nonzeros == 0 )
    2307 return;
    2308
    2309 auto gvw = gw.MakeVectorWriter(nlheader.num_obj_nonzeros);
    2310 for( int v = 0; v < nvars; ++v )
    2311 {
    2312 SCIP_Real coef = SCIPvarGetObj(vars[v]);
    2313 if( coef != 0.0 )
    2314 gvw.Write(v, objscale * coef);
    2315 }
    2316 }
    2317
    2318 template <class ObjExprWriter>
    2320 int i,
    2321 ObjExprWriter& ew
    2322 )
    2323 {
    2324 assert(i == 0);
    2325 ew.NPut(objscale * objoffset);
    2326 }
    2327
    2328 template <class VarBoundsWriter>
    2330 VarBoundsWriter& vbw
    2331 ) const
    2332 {
    2333 for( int v = 0; v < nvars; ++v )
    2334 {
    2335 SCIP_Real lb = SCIPvarGetLbGlobal(vars[v]);
    2336 SCIP_Real ub = SCIPvarGetUbGlobal(vars[v]);
    2337
    2338 if( SCIPisInfinity(scip, -lb) )
    2339 lb = -INFINITY;
    2340
    2341 if( SCIPisInfinity(scip, ub) )
    2342 ub = INFINITY;
    2343
    2344 vbw.WriteLbUb(lb, ub);
    2345 }
    2346 }
    2347
    2348 template <class ConBoundsWriter>
    2350 ConBoundsWriter& cbw
    2351 )
    2352 {
    2353 for( int c = 0; c < nalgconss; ++c )
    2354 {
    2355 AlgConRange bnd;
    2356 bnd.L = SCIPisInfinity(scip, -algconsslhs[c]) ? -INFINITY : algconsslhs[c];
    2357 bnd.U = SCIPisInfinity(scip, algconssrhs[c]) ? INFINITY : algconssrhs[c];
    2358 cbw.WriteAlgConRange(bnd);
    2359 }
    2360
    2361 for( int v = 0; v < naggconss; ++v )
    2362 {
    2363 SCIP_VAR* var = aggconss[v];
    2364 AlgConRange bnd;
    2365
    2366 switch( SCIPvarGetStatus(var) )
    2367 {
    2369 bnd.L = SCIPvarGetAggrConstant(var);
    2370 break;
    2371
    2373 bnd.L = SCIPvarGetNegationConstant(var);
    2374 break;
    2375
    2377 bnd.L = SCIPvarGetMultaggrConstant(var);
    2378 break;
    2379
    2380 default:
    2381 SCIPerrorMessage("unexpected variable status %d of aggregated variable <%s>\n", SCIPvarGetStatus(var), SCIPvarGetName(var));
    2383 }
    2384
    2385 bnd.U = bnd.L;
    2386 cbw.WriteAlgConRange(bnd);
    2387 }
    2388 }
    2389
    2390 /* this is for the comments in .nl files if comments enabled */
    2391 const char* ConDescription(
    2392 int i
    2393 )
    2394 {
    2395 if( i < nalgconss )
    2396 return SCIPconsGetName(algconss[i]);
    2397
    2398 assert(i < nalgconss + naggconss);
    2399 return SCIPvarGetName(aggconss[i-nalgconss]);
    2400 }
    2401
    2402 template <class ConLinearExprWriter>
    2404 int i,
    2405 ConLinearExprWriter& clw
    2406 )
    2407 {
    2408 if( i < nlheader.num_nl_cons )
    2409 return;
    2410
    2411 if( i < nalgconss )
    2412 {
    2413 SCIP_CONS* cons = algconss[i];
    2414 SCIP_CONSHDLR* conshdlr = SCIPconsGetHdlr(cons);
    2415
    2416 if( conshdlr == conshdlr_linear )
    2417 {
    2418 SCIP_Real* conscoefs = SCIPgetValsLinear(scip, cons);
    2419 SCIP_VAR** consvars = SCIPgetVarsLinear(scip, cons);
    2420 int nconsvars = SCIPgetNVarsLinear(scip, cons);
    2421
    2422 /* if we write 0 coefficients, then this gives an error when reading
    2423 * (nl-reader.h: NLReader<Reader, Handler>::ReadLinearExpr(): ReadUInt(1, ...)
    2424 * says that the expected number of coefs is at least 1)
    2425 */
    2426 if( nconsvars == 0 )
    2427 return;
    2428
    2429 auto vw = clw.MakeVectorWriter(nconsvars);
    2430 for( int v = 0; v < nconsvars; ++v )
    2431 if( SCIPvarIsNegated(consvars[v]) )
    2432 vw.Write(getVarAMPLIndex(SCIPvarGetNegationVar(consvars[v])), -conscoefs[v]);
    2433 else
    2434 vw.Write(getVarAMPLIndex(consvars[v]), conscoefs[v]);
    2435
    2436 return;
    2437 }
    2438
    2439 if( conshdlr == conshdlr_setppc )
    2440 {
    2441 SCIP_VAR** consvars = SCIPgetVarsSetppc(scip, cons);
    2442 int nconsvars = SCIPgetNVarsSetppc(scip, cons);
    2443
    2444 if( nconsvars == 0 )
    2445 return;
    2446
    2447 auto vw = clw.MakeVectorWriter(nconsvars);
    2448 for( int v = 0; v < nconsvars; ++v )
    2449 if( SCIPvarIsNegated(consvars[v]) )
    2450 vw.Write(getVarAMPLIndex(SCIPvarGetNegationVar(consvars[v])), -1.0);
    2451 else
    2452 vw.Write(getVarAMPLIndex(consvars[v]), 1.0);
    2453
    2454 return;
    2455 }
    2456
    2457 if( conshdlr == conshdlr_logicor )
    2458 {
    2459 SCIP_VAR** consvars = SCIPgetVarsLogicor(scip, cons);
    2460 int nconsvars = SCIPgetNVarsLogicor(scip, cons);
    2461
    2462 if( nconsvars == 0 )
    2463 return;
    2464
    2465 auto vw = clw.MakeVectorWriter(nconsvars);
    2466 for( int v = 0; v < nconsvars; ++v )
    2467 if( SCIPvarIsNegated(consvars[v]) )
    2468 vw.Write(getVarAMPLIndex(SCIPvarGetNegationVar(consvars[v])), -1.0);
    2469 else
    2470 vw.Write(getVarAMPLIndex(consvars[v]), 1.0);
    2471
    2472 return;
    2473 }
    2474
    2475 if( conshdlr == conshdlr_knapsack )
    2476 {
    2477 SCIP_Longint* weights = SCIPgetWeightsKnapsack(scip, cons);
    2478 SCIP_VAR** consvars = SCIPgetVarsKnapsack(scip, cons);
    2479 int nconsvars = SCIPgetNVarsKnapsack(scip, cons);
    2480
    2481 if( nconsvars == 0 )
    2482 return;
    2483
    2484 auto vw = clw.MakeVectorWriter(nconsvars);
    2485 for( int v = 0; v < nconsvars; ++v )
    2486 if( SCIPvarIsNegated(consvars[v]) )
    2487 vw.Write(getVarAMPLIndex(SCIPvarGetNegationVar(consvars[v])), -(SCIP_Real)weights[v]);
    2488 else
    2489 vw.Write(getVarAMPLIndex(consvars[v]), (SCIP_Real)weights[v]);
    2490
    2491 return;
    2492 }
    2493
    2494 assert(conshdlr == conshdlr_varbound);
    2495
    2496 auto vw = clw.MakeVectorWriter(2);
    2498 vw.Write(getVarAMPLIndex(SCIPvarGetNegationVar(SCIPgetVarVarbound(scip, cons))), -1.0);
    2499 else
    2500 vw.Write(getVarAMPLIndex(SCIPgetVarVarbound(scip, cons)), 1.0);
    2501
    2503 vw.Write(getVarAMPLIndex(SCIPvarGetNegationVar(SCIPgetVbdvarVarbound(scip, cons))), -SCIPgetVbdcoefVarbound(scip, cons));
    2504 else
    2505 vw.Write(getVarAMPLIndex(SCIPgetVbdvarVarbound(scip, cons)), SCIPgetVbdcoefVarbound(scip, cons));
    2506
    2507 return;
    2508 }
    2509
    2510 assert(i < nalgconss + naggconss);
    2511 SCIP_VAR* var = aggconss[i-nalgconss];
    2512
    2513 switch( SCIPvarGetStatus(var) )
    2514 {
    2516 {
    2517 /* var - aggrscalar*aggrvar = aggrconstant */
    2518 auto vw = clw.MakeVectorWriter(2);
    2519 vw.Write(getVarAMPLIndex(var), 1.0);
    2520 vw.Write(getVarAMPLIndex(SCIPvarGetAggrVar(var)), -SCIPvarGetAggrScalar(var));
    2521 break;
    2522 }
    2523
    2525 {
    2526 /* var + negationvar = negationconstant */
    2527 auto vw = clw.MakeVectorWriter(2);
    2528 vw.Write(getVarAMPLIndex(var), 1.0);
    2529 vw.Write(getVarAMPLIndex(SCIPvarGetNegationVar(var)), 1.0);
    2530 break;
    2531 }
    2532
    2534 {
    2535 /* var - sum_i aggrscalar_i aggrvar_i = aggrconstant */
    2536 auto vw = clw.MakeVectorWriter(SCIPvarGetMultaggrNVars(var) + 1);
    2537 vw.Write(getVarAMPLIndex(var), 1.0);
    2538 for( int v = 0; v < SCIPvarGetMultaggrNVars(var); ++v )
    2539 vw.Write(getVarAMPLIndex(SCIPvarGetMultaggrVars(var)[v]), -SCIPvarGetMultaggrScalars(var)[v]);
    2540 break;
    2541 }
    2542
    2543 default:
    2544 {
    2545 SCIPerrorMessage("unexpected variable status %d of aggregated variable <%s>\n", SCIPvarGetStatus(var), SCIPvarGetName(var));
    2547 }
    2548 }
    2549 }
    2550
    2551 template <class ConExprWriter>
    2553 int i,
    2554 ConExprWriter& ew
    2555 )
    2556 {
    2557 if( i >= nlheader.num_nl_cons )
    2558 {
    2559 ew.NPut(0.0);
    2560 return;
    2561 }
    2562
    2563 // will store an error message if some expr couldn't be handled
    2564 std::stringstream unhandledexprmsg;
    2565
    2566 SCIP_EXPR* rootexpr = SCIPgetExprNonlinear(algconss[i]);
    2567
    2568 SCIP_EXPRITER* it;
    2570
    2573
    2574 for( SCIP_EXPR* expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    2575 {
    2576 switch( SCIPexpriterGetStageDFS(it) )
    2577 {
    2579 {
    2580 // retrieve the ConExprWriter of parent expr
    2581 ConExprWriter* parentew;
    2582 if( expr == rootexpr )
    2583 parentew = &ew;
    2584 else
    2585 parentew = (ConExprWriter*)SCIPexpriterGetExprUserData(it, SCIPexpriterGetParentDFS(it)).ptrval;
    2586 assert(parentew != NULL);
    2587
    2588 ConExprWriter* newew = NULL;
    2589
    2590 if( SCIPisExprVar(scip, expr) )
    2591 {
    2592 SCIP_VAR* var = SCIPgetVarExprVar(expr); /* cppcheck-suppress dangerousTypeCast */
    2593 if( SCIPvarIsNegated(var) )
    2594 {
    2595 ConExprWriter ew2(parentew->OPut2(mp::nl::SUB));
    2596 ew2.NPut(SCIPvarGetNegationConstant(var));
    2597 ew2.VPut(getVarAMPLIndex(SCIPvarGetNegatedVar(var)), SCIPvarGetName(SCIPvarGetNegatedVar(var)));
    2598 }
    2599 else
    2600 {
    2601 parentew->VPut(getVarAMPLIndex(var), SCIPvarGetName(var));
    2602 }
    2603 }
    2604 else if( SCIPisExprValue(scip, expr) )
    2605 {
    2606 parentew->NPut(SCIPgetValueExprValue(expr));
    2607 }
    2608 else if( SCIPisExprSum(scip, expr) )
    2609 {
    2610 int nargs = SCIPexprGetNChildren(expr);
    2611 assert(nargs > 0);
    2612
    2613 if( SCIPgetConstantExprSum(expr) != 0.0 )
    2614 {
    2615 if( nargs == 0 )
    2616 {
    2617 parentew->NPut(SCIPgetConstantExprSum(expr));
    2618 SCIP_EXPRITER_USERDATA userdata;
    2619 userdata.ptrval = NULL;
    2620 SCIPexpriterSetCurrentUserData(it, userdata);
    2621 break;
    2622 }
    2623
    2624 ++nargs;
    2625 }
    2626
    2627 // we will need to store two ConExprWriter's for sum or add
    2628 // one for the sum, and one for multiplication (coef*expr) of the currently considered child
    2629 // the one for the sum will go second, so in the child, we don't need to check for case of sum
    2630 // there is no default constructor for ConExprWriter, so we only alloc mem and then use replacement-new
    2632
    2633 if( nargs == 1 )
    2634 {
    2635 assert(SCIPgetConstantExprSum(expr) == 0.0); // handled above
    2636 // skip the SUM and attach only a MUL, which will be done in VISITINGCHILD
    2637 // so we put the parentew to which the MUL should be attached into newew[1]
    2638 memcpy((void*)(newew+1), (void*)parentew, sizeof(ConExprWriter));
    2639 }
    2640 else if( nargs == 2 )
    2641 {
    2642 new (newew+1) ConExprWriter(parentew->OPut2(mp::nl::ADD));
    2643 }
    2644 else
    2645 {
    2646 new (newew+1) ConExprWriter(parentew->OPutN(mp::nl::SUM, nargs));
    2647 }
    2648
    2649 if( SCIPgetConstantExprSum(expr) != 0.0 )
    2650 newew[1].NPut(SCIPgetConstantExprSum(expr));
    2651 }
    2652 else if( SCIPisExprProduct(scip, expr) )
    2653 {
    2654 int nargs = SCIPexprGetNChildren(expr);
    2655 assert(nargs > 0);
    2656
    2657 // in VISITEDCHILD we will take care of turning a product of more than 2 factors
    2658 // into a recursion of multiplications
    2659 newew = new ConExprWriter(parentew->OPut2(mp::nl::MUL));
    2660
    2661 // nargs should be >= 2, but theoretically could be 1
    2662 // we will then write this as 1*arg for simplicity
    2663 if( nargs == 1 )
    2664 newew->NPut(1.0);
    2665 }
    2666 else if( SCIPisExprPower(scip, expr) )
    2667 {
    2668 if( SCIPgetExponentExprPow(expr) == 2.0 )
    2669 newew = new ConExprWriter(parentew->OPut1(mp::nl::POW2));
    2670 else if( SCIPgetExponentExprPow(expr) == 0.5 )
    2671 newew = new ConExprWriter(parentew->OPut1(mp::nl::SQRT));
    2672 else
    2673 newew = new ConExprWriter(parentew->OPut2(mp::nl::POW_CONST_EXP));
    2674 }
    2675 else if( SCIPisExprLog(scip, expr) )
    2676 {
    2677 newew = new ConExprWriter(parentew->OPut1(mp::nl::LOG));
    2678 }
    2679 else if( SCIPisExprExp(scip, expr) )
    2680 {
    2681 newew = new ConExprWriter(parentew->OPut1(mp::nl::EXP));
    2682 }
    2683 else if( SCIPisExprAbs(scip, expr) )
    2684 {
    2685 newew = new ConExprWriter(parentew->OPut1(mp::nl::ABS));
    2686 }
    2687 else if( SCIPisExprSin(scip, expr) )
    2688 {
    2689 newew = new ConExprWriter(parentew->OPut1(mp::nl::SIN));
    2690 }
    2691 else if( SCIPisExprCos(scip, expr) )
    2692 {
    2693 newew = new ConExprWriter(parentew->OPut1(mp::nl::COS));
    2694 }
    2695 else
    2696 {
    2697 // entropy, signpower, or unrecognized handler
    2698 unhandledexprmsg << "Cannot represent <" << SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)) << "> expression in constraint <" << SCIPconsGetName(algconss[i]) << "> in .nl" << std::endl;
    2699
    2700 // this is to make the assert in the destructor of parentew pass, which asserts that all arguments were written
    2701 parentew->NPut(0.0);
    2702
    2703 // skip children and move on to LEAVEEXPR directly, thus skipping this subexpression
    2704 // (we still set userdata.ptrval = NULL next, so LEAVEEXPR will do delete NULL (which is well defined))
    2706 }
    2707
    2708 SCIP_EXPRITER_USERDATA userdata;
    2709 userdata.ptrval = newew;
    2710 SCIPexpriterSetCurrentUserData(it, userdata);
    2711
    2712 break;
    2713 }
    2714
    2716 {
    2717 if( SCIPisExprSum(scip, expr) )
    2718 {
    2719 int childidx = SCIPexpriterGetChildIdxDFS(it);
    2720 SCIP_Real coef = SCIPgetCoefsExprSum(expr)[childidx];
    2721
    2722 ConExprWriter* ews = (ConExprWriter*)SCIPexpriterGetCurrentUserData(it).ptrval;
    2723
    2724 if( coef != 1.0 )
    2725 {
    2726 // if coef, then create MUL and store ExprWriter in ews[0]
    2727 new (ews) ConExprWriter(ews[1].OPut2(mp::nl::MUL));
    2728 ews[0].NPut(coef);
    2729 }
    2730 else
    2731 {
    2732 // if trivial coef, then only move ews[1] (ExprWriter for SUM/ADD) to ews[0] (implementation forbids copy)
    2733 // cannot use move-assignment, because it asserts that destination and source have same nlw_, but my destination is not initialized
    2734 //ews[0] = std::move(ews[1]);
    2735 memcpy((void*)ews, (void*)(ews+1), sizeof(ConExprWriter));
    2736 }
    2737 }
    2738 break;
    2739 }
    2740
    2742 {
    2743 if( SCIPisExprSum(scip, expr) )
    2744 {
    2745 int childidx = SCIPexpriterGetChildIdxDFS(it);
    2746
    2747 ConExprWriter* ews = (ConExprWriter*)SCIPexpriterGetCurrentUserData(it).ptrval;
    2748
    2749 if( SCIPgetCoefsExprSum(expr)[childidx] != 1.0 )
    2750 {
    2751 // destructor for ExprWriter that was stored for MUL
    2752 ews->~ConExprWriter();
    2753 }
    2754 else
    2755 {
    2756 // move ExprWrite for SUM back into 2nd position
    2757 //ews[1] = std::move(ews[0]);
    2758 memcpy((void*)(ews+1), (void*)ews, sizeof(ConExprWriter));
    2759 }
    2760 }
    2761 else if( SCIPisExprProduct(scip, expr) )
    2762 {
    2763 ConExprWriter* ew2 = (ConExprWriter*)SCIPexpriterGetCurrentUserData(it).ptrval;
    2764
    2765 int childidx = SCIPexpriterGetChildIdxDFS(it);
    2766 int nchildren = SCIPexprGetNChildren(expr);
    2767 if( childidx < nchildren-2 )
    2768 {
    2769 // if there is more than one more factor coming (so we are in product with > 2 factors)
    2770 // then add another MUL to the current ew2 and make the new ConExprWriter the current ew2
    2771 ConExprWriter* newew = new ConExprWriter(ew2->OPut2(mp::nl::MUL));
    2772 delete ew2;
    2773
    2774 SCIP_EXPRITER_USERDATA userdata;
    2775 userdata.ptrval = newew;
    2776 SCIPexpriterSetCurrentUserData(it, userdata);
    2777 }
    2778 }
    2779
    2780 break;
    2781 }
    2782
    2784 {
    2785 ConExprWriter* ews = (ConExprWriter*)SCIPexpriterGetCurrentUserData(it).ptrval;
    2786 if( SCIPisExprSum(scip, expr) )
    2787 {
    2788 if( SCIPgetConstantExprSum(expr) == 0.0 && SCIPexprGetNChildren(expr) == 1 )
    2789 {
    2790 // continuation of nargs==1 in ENTEREXPR: copy the modified newew[1] into parentew
    2791 ConExprWriter* parentew;
    2792 if( expr == rootexpr )
    2793 parentew = &ew;
    2794 else
    2795 parentew = (ConExprWriter*)SCIPexpriterGetExprUserData(it, SCIPexpriterGetParentDFS(it)).ptrval;
    2796 assert(parentew != NULL);
    2797
    2798 memcpy((void*)parentew, (void*)(ews+1), sizeof(ConExprWriter));
    2799 }
    2800 else
    2801 {
    2802 // destructor for ExprWriter for SUM/ADD
    2803 ews[1].~ConExprWriter();
    2804 }
    2806 }
    2807 else
    2808 {
    2809 // write exponent of power (if not 0.5 or 2)
    2810 if( SCIPisExprPower(scip, expr) && SCIPgetExponentExprPow(expr) != 0.5 && SCIPgetExponentExprPow(expr) != 2.0 )
    2811 ews->NPut(SCIPgetExponentExprPow(expr));
    2812
    2813 delete ews;
    2814 }
    2815 break;
    2816 }
    2817 }
    2818 }
    2819
    2820 SCIPfreeExpriter(&it);
    2821
    2822 if( unhandledexprmsg.tellp() > 0 )
    2823 throw mp::UnsupportedError(unhandledexprmsg.str());
    2824 }
    2825
    2826 template <class RowObjNameWriter>
    2828 RowObjNameWriter& wrt
    2829 ) const
    2830 {
    2831 if( !wrt || genericnames )
    2832 return;
    2833
    2834 for( int c = 0; c < nalgconss; ++c )
    2835 wrt << SCIPconsGetName(algconss[c]);
    2836
    2837 for( int v = 0; v < naggconss; ++v )
    2838 {
    2839 std::string aggname("aggr_");
    2840 aggname += SCIPvarGetName(aggconss[v]);
    2841 wrt << aggname.c_str();
    2842 }
    2843
    2844 wrt << "obj";
    2845 }
    2846
    2847 template <class ColNameWriter>
    2849 ColNameWriter& wrt
    2850 ) const
    2851 {
    2852 if( !wrt || genericnames )
    2853 return;
    2854
    2855 for( int v = 0; v < nvars; ++v )
    2856 wrt << SCIPvarGetName(vars[v]);
    2857 }
    2858};
    2859
    2860/*
    2861 * Callback methods of probdata
    2862 */
    2863
    2864/** frees user data of original problem (called when the original problem is freed) */
    2865static
    2866SCIP_DECL_PROBDELORIG(probdataDelOrigNl)
    2867{
    2868 SCIP_PROBNLDATA* probnldata = reinterpret_cast<SCIP_PROBNLDATA*>(*probdata);
    2869 int i;
    2870
    2871 assert(probnldata != NULL);
    2872 assert(probnldata->vars != NULL || probnldata->nvars == 0);
    2873 assert(probnldata->conss != NULL || probnldata->nconss == 0);
    2874
    2875 for( i = 0; i < probnldata->nconss; ++i )
    2876 {
    2877 SCIP_CALL( SCIPreleaseCons(scip, &probnldata->conss[i]) );
    2878 }
    2879 SCIPfreeBlockMemoryArrayNull(scip, &probnldata->conss, probnldata->nconss);
    2880
    2881 for( i = 0; i < probnldata->nvars; ++i )
    2882 {
    2883 SCIP_CALL( SCIPreleaseVar(scip, &probnldata->vars[i]) );
    2884 }
    2885 SCIPfreeBlockMemoryArrayNull(scip, &probnldata->vars, probnldata->nvars);
    2886
    2887 SCIPfreeBlockMemoryArrayNull(scip, &probnldata->filenamestub, probnldata->filenamestublen+5);
    2888
    2889 SCIPfreeMemory(scip, reinterpret_cast<SCIP_PROBNLDATA**>(probdata));
    2890
    2891 return SCIP_OKAY;
    2892}
    2893
    2894/*
    2895 * Callback methods of reader
    2896 */
    2897
    2898/** copy method for reader plugins (called when SCIP copies plugins) */
    2899static
    2901{ /*lint --e{715}*/
    2902 assert(scip != NULL);
    2903
    2905
    2906 return SCIP_OKAY;
    2907}
    2908
    2909/** problem reading method of reader */
    2910static
    2912{ /*lint --e{715}*/
    2913 assert(scip != NULL);
    2914 assert(reader != NULL);
    2915 assert(filename != NULL);
    2916 assert(result != NULL);
    2917
    2918 *result = SCIP_DIDNOTRUN;
    2919
    2920 try
    2921 {
    2922 // try to read the .nl file and setup SCIP problem
    2923 AMPLProblemHandler handler(scip, filename);
    2924 try
    2925 {
    2926 mp::ReadNLFile(filename, handler);
    2927 }
    2928 catch( const mp::UnsupportedError& e )
    2929 {
    2930 SCIPerrorMessage("unsupported construct in AMPL .nl file %s: %s\n", filename, e.what());
    2931
    2932 SCIP_CALL( handler.cleanup() );
    2933
    2934 return SCIP_READERROR;
    2935 }
    2936 catch( const mp::Error& e )
    2937 {
    2938 // some other error from ampl/mp, maybe invalid .nl file
    2939 SCIPerrorMessage("%s\n", e.what());
    2940
    2941 SCIP_CALL( handler.cleanup() );
    2942
    2943 return SCIP_READERROR;
    2944 }
    2945 catch( const fmt::SystemError& e )
    2946 {
    2947 // probably a file open error, probably because file not found
    2948 SCIPerrorMessage("%s\n", e.what());
    2949
    2950 SCIP_CALL( handler.cleanup() );
    2951
    2952 return SCIP_NOFILE;
    2953 }
    2954 catch( const std::bad_alloc& e )
    2955 {
    2956 SCIPerrorMessage("Out of memory: %s\n", e.what());
    2957
    2958 SCIP_CALL( handler.cleanup() );
    2959
    2960 return SCIP_NOMEMORY;
    2961 }
    2962 }
    2963 catch( const std::exception& e )
    2964 {
    2965 SCIPerrorMessage("%s\n", e.what());
    2966 return SCIP_ERROR;
    2967 }
    2968
    2969 *result = SCIP_SUCCESS;
    2970
    2971 return SCIP_OKAY;
    2972}
    2973
    2974#ifdef _WIN32
    2975#define PATHSEP "\\"
    2976#else
    2977#define PATHSEP "/"
    2978#endif
    2979
    2980/** problem writing method of reader */
    2981static
    2983{ /*lint --e{715}*/
    2984 mp::WriteNLResult writerresult;
    2985 SCIP_Bool binary;
    2986 SCIP_Bool comments;
    2987 char* tempdir = NULL;
    2988 char* tempnamestub = NULL;
    2989 char* tempname = NULL;
    2990 FILE* tempfile = NULL;
    2991 int templen;
    2993
    2994 *result = SCIP_DIDNOTRUN;
    2995
    2996 SCIP_CALL( SCIPgetBoolParam(scip, "reading/" READER_NAME "/binary", &binary) );
    2997 SCIP_CALL( SCIPgetBoolParam(scip, "reading/" READER_NAME "/comments", &comments) );
    2998
    2999 SCIPNLFeeder nlf(scip,
    3000 name, objsense, objscale, objoffset,
    3001 vars, nvars, fixedvars, nfixedvars,
    3002 conss, nconss,
    3003 binary, comments, genericnames);
    3004
    3005 try
    3006 {
    3007 /* we need to give the NLWriter a filename, but can only rely on the FILE* from SCIP
    3008 * so we let the NLWriter write to a temporary file and then copy its content to file;
    3009 * if we also have a filename, then we do the same for the row/col files
    3010 */
    3011 mp::NLUtils nlutils;
    3012 char buf[1024];
    3013 int n;
    3014
    3015 /* construct a temporary directory in /tmp/scipnlwrite-XXXXXX */
    3016#ifdef _WIN32
    3017 TCHAR systemtmp[MAX_PATH + 1];
    3018 DWORD gettemprc = GetTempPathA(MAX_PATH + 1, systemtmp);
    3019 if( gettemprc == 0 || gettemprc > MAX_PATH + 1 )
    3020 {
    3021 SCIPerrorMessage("Cannot get name of directory for temporary files: error %d\n", errno);
    3023 goto TERMINATE;
    3024 }
    3025#else
    3026 const char* systemtmp = getenv("TMPDIR");
    3027 if( systemtmp == NULL )
    3028 systemtmp = "/tmp";
    3029#endif
    3030 templen = strlen(systemtmp) + 30;
    3031 SCIP_CALL( SCIPallocBufferArray(scip, &tempdir, templen) );
    3032 (void) SCIPsnprintf(tempdir, templen, "%s" PATHSEP "scipnlwrite-XXXXXX", systemtmp);
    3033
    3034#ifdef _WIN32
    3035 if( _mktemp_s(tempdir, templen) )
    3036 {
    3037 SCIPerrorMessage("Cannot generate name for temporary directory from template <%s>: error %d\n", tempdir, errno);
    3039 goto TERMINATE;
    3040 }
    3041 if( _mkdir(tempdir) )
    3042 {
    3043 SCIPerrorMessage("Cannot create temporary directory with name <%s>: error %d\n", tempdir, errno);
    3045 goto TERMINATE;
    3046 }
    3047#else
    3048 if( mkdtemp(tempdir) == NULL )
    3049 {
    3050 SCIPerrorMessage("Cannot generate temporary directory from template <%s>: error %d\n", tempdir, errno);
    3052 goto TERMINATE;
    3053 }
    3054#endif
    3055
    3056 /* stub for temporary file: /tmp/scipnlwrite-XXXXXX/prob */
    3057 SCIP_CALL( SCIPallocBufferArray(scip, &tempnamestub, templen) );
    3058 (void) SCIPsnprintf(tempnamestub, templen, "%s" PATHSEP "prob", tempdir);
    3059
    3060 SCIPdebugMsg(scip, "Temporary file stub for NL writing: %s\n", tempnamestub);
    3061
    3062 writerresult = mp::WriteNLFile(tempnamestub, nlf, nlutils);
    3063
    3064 /* name of nl file that was (possibly) written: tempnamestub + .nl */
    3065 SCIP_CALL( SCIPallocBufferArray(scip, &tempname, templen) );
    3066 (void) SCIPsnprintf(tempname, templen, "%s.nl", tempnamestub);
    3067
    3068 switch( writerresult.first )
    3069 {
    3070 case NLW2_WriteNL_OK:
    3071 break;
    3072 case NLW2_WriteNL_CantOpen:
    3073 SCIPerrorMessage("%s\n", writerresult.second.c_str());
    3075 goto TERMINATE;
    3076 case NLW2_WriteNL_Failed:
    3077 SCIPerrorMessage("%s\n", writerresult.second.c_str());
    3078 rc = SCIP_WRITEERROR;
    3079 goto TERMINATE;
    3080 case NLW2_WriteNL_Unset:
    3081 default:
    3082 SCIPerrorMessage("%s\n", writerresult.second.c_str());
    3083 rc = SCIP_ERROR;
    3084 goto TERMINATE;
    3085 }
    3086
    3087 /* copy temporary file into file */
    3088 tempfile = fopen(tempname, "rb");
    3089 if( tempfile == NULL )
    3090 {
    3091 SCIPerrorMessage("Cannot open temporary file <%s> for reading: error %d\n", tempname, errno);
    3092 return SCIP_NOFILE;
    3093 }
    3094
    3095 while( (n=fread(buf, 1, sizeof(buf), tempfile)) != 0 )
    3096 fwrite(buf, 1, n, file != NULL ? file : stdout);
    3097
    3098 fclose(tempfile);
    3099
    3100 /* move col/row files */
    3101 if( !genericnames && filename != NULL )
    3102 {
    3103 char* filename2 = NULL;
    3104 FILE* file2;
    3105 int filenamelen;
    3106
    3107 /* before overwriting tempname, remove .nl file */
    3108 remove(tempname);
    3109
    3110 /* make filename2 same as filename, but with .nl removed, if present */
    3111 filenamelen = strlen(filename);
    3112 SCIP_CALL( SCIPallocBufferArray(scip, &filename2, filenamelen + 5) );
    3113 memcpy(filename2, filename, filenamelen+1);
    3114 if( SCIPstrcasecmp(filename + (filenamelen-3), ".nl") == 0 )
    3115 {
    3116 filename2[filenamelen-3] = '\0';
    3117 filenamelen -= 3;
    3118 }
    3119
    3120 /* copy row file from temporary to current location */
    3121 SCIPsnprintf(tempname, templen, "%s.row", tempnamestub);
    3122 strcpy(filename2 + filenamelen, ".row");
    3123
    3124 tempfile = fopen(tempname, "rb");
    3125 if( tempfile == NULL )
    3126 {
    3127 SCIPerrorMessage("Cannot open temporary file <%s> for reading: error %d\n", tempname, errno);
    3128 return SCIP_NOFILE;
    3129 }
    3130 file2 = fopen(filename2, "wb");
    3131 if( file2 == NULL )
    3132 {
    3133 SCIPerrorMessage("Cannot open file <%s> for writing: error %d\n", filename2, errno);
    3134 return SCIP_FILECREATEERROR;
    3135 }
    3136
    3137 while( (n=fread(buf, 1, sizeof(buf), tempfile)) != 0 )
    3138 fwrite(buf, 1, n, file2);
    3139
    3140 fclose(file2);
    3141 fclose(tempfile);
    3142 remove(tempname); /* remove .row file */
    3143
    3144 /* copy col file from temporary to current location */
    3145 SCIPsnprintf(tempname, templen, "%s.col", tempnamestub);
    3146 strcpy(filename2 + filenamelen, ".col");
    3147
    3148 tempfile = fopen(tempname, "rb");
    3149 if( tempfile == NULL )
    3150 {
    3151 SCIPerrorMessage("Cannot open temporary file <%s> for reading: error %d\n", tempname, errno);
    3152 return SCIP_NOFILE;
    3153 }
    3154 file2 = fopen(filename2, "wb");
    3155 if( file2 == NULL )
    3156 {
    3157 SCIPerrorMessage("Cannot open file <%s> for writing: error %d\n", filename2, errno);
    3158 return SCIP_FILECREATEERROR;
    3159 }
    3160
    3161 while( (n=fread(buf, 1, sizeof(buf), tempfile)) != 0 )
    3162 fwrite(buf, 1, n, file2);
    3163
    3164 fclose(file2);
    3165 fclose(tempfile);
    3166 /* .col file will be removed further down */
    3167
    3168 SCIPfreeBufferArray(scip, &filename2);
    3169 }
    3170
    3171 *result = SCIP_SUCCESS;
    3172
    3173 TERMINATE: ;
    3174 }
    3175 catch( const mp::UnsupportedError& e )
    3176 {
    3177 SCIPerrorMessage("constraint not writable as AMPL .nl: %s\n", e.what());
    3178 rc = SCIP_WRITEERROR;
    3179 }
    3180 catch( const mp::Error& e )
    3181 {
    3182 // some other error from ampl/mp
    3183 SCIPerrorMessage("%s\n", e.what());
    3184 rc = SCIP_WRITEERROR;
    3185 }
    3186 catch( const fmt::SystemError& e )
    3187 {
    3188 // probably a file open error
    3189 SCIPerrorMessage("%s\n", e.what());
    3191 }
    3192 catch( const std::bad_alloc& e )
    3193 {
    3194 SCIPerrorMessage("Out of memory: %s\n", e.what());
    3195 rc = SCIP_NOMEMORY;
    3196 }
    3197 catch( const std::exception& e )
    3198 {
    3199 SCIPerrorMessage("%s\n", e.what());
    3200 rc = SCIP_ERROR;
    3201 }
    3202
    3203 /* remove file with tempname, or fail trying */
    3204 if( tempname != NULL )
    3205 {
    3206 remove(tempname);
    3207 SCIPfreeBufferArray(scip, &tempname);
    3208 }
    3209
    3210 SCIPfreeBufferArrayNull(scip, &tempnamestub);
    3211
    3212 if( tempdir != NULL )
    3213 {
    3214 remove(tempdir);
    3215 SCIPfreeBufferArray(scip, &tempdir);
    3216 }
    3217
    3218 return rc;
    3219}
    3220
    3221/*
    3222 * reader specific interface methods
    3223 */
    3224
    3225/** includes the AMPL .nl file reader in SCIP */
    3227 SCIP* scip /**< SCIP data structure */
    3228 )
    3229{
    3230 SCIP_READER* reader = NULL;
    3231
    3232 /* include reader */
    3234 assert(reader != NULL);
    3235
    3236 /* set non fundamental callbacks via setter functions */
    3237 SCIP_CALL( SCIPsetReaderCopy(scip, reader, readerCopyNl) );
    3238 SCIP_CALL( SCIPsetReaderRead(scip, reader, readerReadNl) );
    3239 SCIP_CALL( SCIPsetReaderWrite(scip, reader, readerWriteNl) );
    3240
    3241 /* add nl reader parameters for writing routines */
    3243 "reading/" READER_NAME "/binary", "should nl files be written in binary format",
    3244 NULL, FALSE, FALSE, NULL, NULL) );
    3246 "reading/" READER_NAME "/comments", "should comments be written to nl files",
    3247 NULL, FALSE, FALSE, NULL, NULL) );
    3248
    3249 SCIP_CALL( SCIPincludeExternalCodeInformation(scip, "AMPL/MP 4.0.4", "AMPL .nl file reader library (github.com/ampl/mp)") );
    3250
    3251 return SCIP_OKAY;
    3252}
    3253
    3254/** writes AMPL solution file
    3255 *
    3256 * problem must have been read with .nl reader
    3257 */
    3259 SCIP* scip /**< SCIP data structure */
    3260 )
    3261{
    3262 SCIP_PROBNLDATA* probdata;
    3263
    3264 assert(scip != NULL);
    3265
    3266 probdata = reinterpret_cast<SCIP_PROBNLDATA*>(SCIPgetProbData(scip));
    3267 if( probdata == NULL )
    3268 {
    3269 SCIPerrorMessage("No AMPL nl file read. Cannot write AMPL solution.\n");
    3270 return SCIP_ERROR;
    3271 }
    3272
    3273 probdata->filenamestub[probdata->filenamestublen] = '.';
    3274 probdata->filenamestub[probdata->filenamestublen+1] = 's';
    3275 probdata->filenamestub[probdata->filenamestublen+2] = 'o';
    3276 probdata->filenamestub[probdata->filenamestublen+3] = 'l';
    3277 probdata->filenamestub[probdata->filenamestublen+4] = '\0';
    3278
    3279 FILE* solfile = fopen(probdata->filenamestub, "w");
    3280 if( solfile == NULL )
    3281 {
    3282 SCIPerrorMessage("could not open file <%s> for writing\n", probdata->filenamestub);
    3283 probdata->filenamestub[probdata->filenamestublen] = '\0';
    3284
    3285 return SCIP_WRITEERROR;
    3286 }
    3287 probdata->filenamestub[probdata->filenamestublen] = '\0';
    3288
    3289 // see ampl/mp:sol.h:WriteSolFile() (seems buggy, https://github.com/ampl/mp/issues/135) and asl/writesol.c for solution file format
    3290 SCIP_CALL( SCIPprintStatus(scip, solfile) );
    3291 SCIPinfoMessage(scip, solfile, "\n\n");
    3292
    3293 SCIPinfoMessage(scip, solfile, "Options\n%d\n", probdata->namplopts);
    3294 for( int i = 0; i < probdata->namplopts; ++i )
    3295 SCIPinfoMessage(scip, solfile, "%d\n", probdata->amplopts[i]);
    3296
    3297 bool haveprimal = SCIPgetBestSol(scip) != NULL;
    3298 bool havedual = probdata->islp && SCIPgetStage(scip) == SCIP_STAGE_SOLVED && !SCIPhasPerformedPresolve(scip);
    3299
    3300 SCIPinfoMessage(scip, solfile, "%d\n%d\n", probdata->nconss, havedual ? probdata->nconss : 0);
    3301 SCIPinfoMessage(scip, solfile, "%d\n%d\n", probdata->nvars, haveprimal ? probdata->nvars : 0);
    3302
    3304
    3305 if( havedual )
    3306 for( int c = 0; c < probdata->nconss; ++c )
    3307 {
    3308 SCIP_CONS* transcons;
    3309 SCIP_Real dualval;
    3310
    3311 /* dual solution is created by LP solver and therefore only available for linear constraints */
    3312 SCIP_CALL( SCIPgetTransformedCons(scip, probdata->conss[c], &transcons) );
    3313 assert(transcons == NULL || strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(transcons)), "linear") == 0);
    3314
    3315 if( transcons == NULL )
    3316 dualval = 0.0;
    3318 dualval = SCIPgetDualsolLinear(scip, transcons);
    3319 else
    3320 dualval = -SCIPgetDualsolLinear(scip, transcons);
    3321 assert(dualval != SCIP_INVALID);
    3322
    3323 SCIPinfoMessage(scip, solfile, "%.17g\n", dualval);
    3324 }
    3325
    3326 if( haveprimal )
    3327 for( int i = 0; i < probdata->nvars; ++i )
    3328 SCIPinfoMessage(scip, solfile, "%.17g\n", SCIPgetSolVal(scip, SCIPgetBestSol(scip), probdata->vars[i]));
    3329
    3330 /* AMPL solve status codes are at https://mp.ampl.com/details.html#_CPPv4N2mp3sol6StatusE
    3331 * (mp::sol::Status enum in amplmp/include/mp/common.h)
    3332 */
    3333 int solve_result_num = mp::sol::FAILURE;
    3334 switch( SCIPgetStatus(scip) )
    3335 {
    3337 break;
    3340 if( haveprimal )
    3341 solve_result_num = mp::sol::LIMIT_FEAS_INTERRUPT;
    3342 else
    3343 solve_result_num = mp::sol::LIMIT_NO_FEAS_INTERRUPT;
    3344 break;
    3348 if( haveprimal )
    3349 solve_result_num = mp::sol::LIMIT_FEAS_NODES;
    3350 else
    3351 solve_result_num = mp::sol::LIMIT_NO_FEAS_NODES;
    3352 break;
    3354 if( haveprimal )
    3355 solve_result_num = mp::sol::LIMIT_FEAS_TIME;
    3356 else
    3357 solve_result_num = mp::sol::LIMIT_NO_FEAS_TIME;
    3358 break;
    3360 if( haveprimal )
    3361 solve_result_num = mp::sol::LIMIT_FEAS_SOFTMEM;
    3362 else
    3363 solve_result_num = mp::sol::LIMIT_NO_FEAS_SOFTMEM;
    3364 break;
    3366 /* there is no enum value for gaplimit, so use "work limit" */
    3367 if( haveprimal )
    3368 solve_result_num = mp::sol::LIMIT_FEAS_WORK;
    3369 else
    3370 solve_result_num = mp::sol::LIMIT_NO_FEAS_WORK;
    3371 break;
    3373 solve_result_num = mp::sol::LIMIT_FEAS_BESTOBJ;
    3374 break;
    3376 if( haveprimal )
    3377 solve_result_num = mp::sol::LIMIT_FEAS_BESTBND;
    3378 else
    3379 solve_result_num = mp::sol::LIMIT_NO_FEAS_BESTBND;
    3380 break;
    3382 if( haveprimal )
    3383 solve_result_num = mp::sol::LIMIT_FEAS_NUMSOLS;
    3384 else /* reach solution limit without solution? */
    3385 solve_result_num = mp::sol::LIMIT_NO_FEAS;
    3386 break;
    3389 /* rare SCIP specific limits that don't map to an AMPL status */
    3390 if( haveprimal )
    3391 solve_result_num = mp::sol::LIMIT_FEAS;
    3392 else
    3393 solve_result_num = mp::sol::LIMIT_NO_FEAS;
    3394 break;
    3396 solve_result_num = mp::sol::SOLVED;
    3397 break;
    3399 solve_result_num = mp::sol::INFEASIBLE;
    3400 break;
    3402 if( haveprimal )
    3403 solve_result_num = mp::sol::UNBOUNDED_FEAS;
    3404 else
    3405 solve_result_num = mp::sol::UNBOUNDED_NO_FEAS;
    3406 break;
    3408 solve_result_num = mp::sol::LIMIT_INF_UNB;
    3409 break;
    3410 }
    3411 SCIPinfoMessage(scip, solfile, "objno 0 %d\n", solve_result_num);
    3412
    3413 if( fclose(solfile) != 0 )
    3414 {
    3415 SCIPerrorMessage("could not close solution file after writing\n");
    3416 return SCIP_WRITEERROR;
    3417 }
    3418
    3419 return SCIP_OKAY;
    3420}
    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:797
    LinearExprHandler(AMPLProblemHandler &amplph_, int index, int num_linear_terms)
    constructor
    Definition: reader_nl.cpp:780
    LinearPartHandler(AMPLProblemHandler &amplph_)
    Definition: reader_nl.cpp:1204
    void AddTerm(int variableIndex, double coefficient)
    Definition: reader_nl.cpp:1211
    LinearPartHandler(AMPLProblemHandler &amplph_, int constraintIndex_)
    Definition: reader_nl.cpp:1192
    NumericArgHandler(int num_args)
    constructor
    Definition: reader_nl.cpp:675
    void AddArg(SCIP_EXPR *term)
    adds term to sum
    Definition: reader_nl.cpp:684
    std::shared_ptr< std::vector< SCIP_EXPR * > > v
    Definition: reader_nl.cpp:672
    void SetValue(int index, T value)
    Definition: reader_nl.cpp:1095
    SuffixHandler(AMPLProblemHandler &amplph_, fmt::StringRef name, mp::suf::Kind kind)
    constructor
    Definition: reader_nl.cpp:996
    implementation of AMPL/MPs NLHandler that constructs a SCIP problem while a .nl file is read
    Definition: reader_nl.cpp:145
    void EndCommonExpr(int index, SCIP_EXPR *expr, int)
    receive notification of the end of a common expression
    Definition: reader_nl.cpp:836
    LinearPartHandler LinearObjHandler
    Definition: reader_nl.cpp:1238
    NumericArgHandler BeginSum(int num_args)
    receive notification of the beginning of a summation
    Definition: reader_nl.cpp:693
    void OnAlgebraicCon(int constraintIndex, SCIP_EXPR *expr)
    receive notification of an algebraic constraint expression
    Definition: reader_nl.cpp:744
    LinearPartHandler OnLinearObjExpr(int objectiveIndex, int)
    receive notification of the linear part of an objective
    Definition: reader_nl.cpp:1241
    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:1305
    LogicalExpr OnNot(LogicalExpr arg)
    receives notification of a logical not <mp::expr::NOT>
    Definition: reader_nl.cpp:1279
    SCIP_EXPR * OnBinary(mp::expr::Kind kind, SCIP_EXPR *firstChild, SCIP_EXPR *secondChild)
    receive notification of a binary expression
    Definition: reader_nl.cpp:580
    SCIP_EXPR * OnNumber(double value)
    receive notification of a number in a nonlinear expression
    Definition: reader_nl.cpp:485
    LogicalExpr OnRelational(mp::expr::Kind kind, NumericExpr lhs, NumericExpr rhs)
    Definition: reader_nl.cpp:1506
    SuffixHandler< int > IntSuffixHandler
    Definition: reader_nl.cpp:1157
    LinearExprHandler BeginCommonExpr(int index, int num_linear_terms)
    receive notification of the beginning of a common expression (defined variable)
    Definition: reader_nl.cpp:824
    AMPLProblemHandler(const AMPLProblemHandler &)=delete
    LinearConHandler OnLinearConExpr(int constraintIndex, int)
    receive notification of the linear part of a constraint
    Definition: reader_nl.cpp:1255
    void OnInitialValue(int var_index, double value)
    receive notification of the initial value for a variable
    Definition: reader_nl.cpp:938
    SCIP_EXPR * OnVariableRef(int variableIndex)
    receive notification of a variable reference in a nonlinear expression
    Definition: reader_nl.cpp:500
    AMPLProblemHandler(SCIP *scip_, const char *filename)
    Definition: reader_nl.cpp:275
    ColumnSizeHandler OnColumnSizes()
    receives notification of Jacobian column sizes
    Definition: reader_nl.cpp:961
    AMPLProblemHandler & operator=(const AMPLProblemHandler &)=delete
    LinearPartHandler LinearConHandler
    Definition: reader_nl.cpp:1252
    void OnVarBounds(int variableIndex, double variableLB, double variableUB)
    receive notification of variable bounds
    Definition: reader_nl.cpp:868
    SCIP_EXPR * OnCommonExprRef(int expr_index)
    receive notification of a common expression (defined variable) reference
    Definition: reader_nl.cpp:857
    ~AMPLProblemHandler() override
    Definition: reader_nl.cpp:342
    void OnHeader(const mp::NLHeader &h)
    Definition: reader_nl.cpp:355
    void OnLogicalCon(int index, LogicalExpr expr)
    receives notification of a logical constraint expression
    Definition: reader_nl.cpp:756
    DblSuffixHandler OnDblSuffix(fmt::StringRef name, mp::suf::Kind kind, int)
    receive notification of a double suffix
    Definition: reader_nl.cpp:1170
    void OnConBounds(int index, double lb, double ub)
    receive notification of constraint sides
    Definition: reader_nl.cpp:892
    IntSuffixHandler OnIntSuffix(fmt::StringRef name, mp::suf::Kind kind, int)
    receive notification of an integer suffix
    Definition: reader_nl.cpp:1159
    LogicalExpr OnBool(bool value)
    receives notification of a Boolean value <mp::expr::BOOL>
    Definition: reader_nl.cpp:1264
    SCIP_EXPR * OnUnary(mp::expr::Kind kind, SCIP_EXPR *child)
    receive notification of a unary expression
    Definition: reader_nl.cpp:512
    SCIP_EXPR * EndSum(NumericArgHandler handler)
    receive notification of the end of a summation
    Definition: reader_nl.cpp:702
    void OnInitialDualValue(int, double)
    receives notification of the initial value for a dual variable
    Definition: reader_nl.cpp:952
    SCIP_RETCODE cleanup()
    Definition: reader_nl.cpp:1720
    SuffixHandler< SCIP_Real > DblSuffixHandler
    Definition: reader_nl.cpp:1168
    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:714
    void FeedConExpression(int i, ConExprWriter &ew)
    Definition: reader_nl.cpp:2552
    SCIPNLFeeder(SCIP *scip_, const char *probname_, SCIP_OBJSENSE objsense_, SCIP_Real objscale_, SCIP_Real objoffset_, SCIP_VAR **vars_, int nvars_, SCIP_VAR **fixedvars_, int nfixedvars_, SCIP_CONS **conss_, int nconss_, SCIP_Bool nlbinary_, SCIP_Bool nlcomments_, SCIP_Bool genericnames_)
    Constructor.
    Definition: reader_nl.cpp:2179
    void FeedObjGradient(int i, ObjGradWriter &gw)
    Definition: reader_nl.cpp:2299
    void FeedVarBounds(VarBoundsWriter &vbw) const
    Definition: reader_nl.cpp:2329
    void FeedObjExpression(int i, ObjExprWriter &ew)
    Definition: reader_nl.cpp:2319
    bool WantNLComments() const
    NL comments?
    Definition: reader_nl.cpp:2279
    void FeedRowAndObjNames(RowObjNameWriter &wrt) const
    Definition: reader_nl.cpp:2827
    int WantColumnSizes() const
    Definition: reader_nl.cpp:2286
    void FeedLinearConExpr(int i, ConLinearExprWriter &clw)
    Definition: reader_nl.cpp:2403
    void FeedConBounds(ConBoundsWriter &cbw)
    Definition: reader_nl.cpp:2349
    const char * ConDescription(int i)
    Definition: reader_nl.cpp:2391
    void FeedColNames(ColNameWriter &wrt) const
    Definition: reader_nl.cpp:2848
    mp::NLHeader Header()
    Definition: reader_nl.cpp:2246
    int ObjType(int) const
    Definition: reader_nl.cpp:2291
    Constraint handler for AND constraints, .
    struct Problem PROBLEM
    Constraint handler for knapsack constraints of the form , x binary and .
    Constraint handler for linear constraints in their most general form, .
    Constraint handler for logicor constraints (equivalent to set covering, but algorithms are suited fo...
    constraint handler for nonlinear constraints specified by algebraic expressions
    Constraint handler for "or" constraints, .
    Constraint handler for the set partitioning / packing / covering constraints .
    constraint handler for SOS type 1 constraints
    constraint handler for SOS type 2 constraints
    Constraint handler for variable bound constraints .
    unsigned short Type
    Definition: cons_xor.c:131
    Constraint handler for XOR constraints, .
    #define NULL
    Definition: def.h:257
    #define SCIP_MAXSTRLEN
    Definition: def.h:278
    #define SCIP_Longint
    Definition: def.h:150
    #define SCIP_INVALID
    Definition: def.h:187
    #define SCIP_Bool
    Definition: def.h:100
    #define SCIP_Real
    Definition: def.h:165
    #define ABS(x)
    Definition: def.h:225
    #define TRUE
    Definition: def.h:102
    #define FALSE
    Definition: def.h:103
    #define MAX(x, y)
    Definition: def.h:229
    #define SCIPABORT()
    Definition: def.h:336
    #define SCIP_CALL(x)
    Definition: def.h:364
    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)
    int SCIPgetNVarsKnapsack(SCIP *scip, SCIP_CONS *cons)
    SCIP_Real SCIPgetVbdcoefVarbound(SCIP *scip, SCIP_CONS *cons)
    int SCIPgetNVarsLogicor(SCIP *scip, SCIP_CONS *cons)
    SCIP_Real SCIPgetRhsLinear(SCIP *scip, SCIP_CONS *cons)
    SCIP_VAR ** SCIPgetVarsLinear(SCIP *scip, SCIP_CONS *cons)
    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:6093
    SCIP_Real SCIPgetLhsLinear(SCIP *scip, SCIP_CONS *cons)
    SCIP_RETCODE SCIPchgLhsNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_Real lhs)
    SCIP_HASHMAP * SCIPgetVarExprHashmapNonlinear(SCIP_CONSHDLR *conshdlr)
    int SCIPgetNVarsLinear(SCIP *scip, SCIP_CONS *cons)
    SCIP_RETCODE SCIPcreateConsBasicOr(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *resvar, int nvars, SCIP_VAR **vars)
    Definition: cons_or.c:2293
    SCIP_RETCODE SCIPchgRhsNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_Real rhs)
    SCIP_Real * SCIPgetValsLinear(SCIP *scip, SCIP_CONS *cons)
    SCIP_RETCODE SCIPcreateConsBasicSOS1(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *weights)
    Definition: cons_sos1.c:10730
    SCIP_VAR * SCIPgetVbdvarVarbound(SCIP *scip, SCIP_CONS *cons)
    int SCIPgetNVarsSetppc(SCIP *scip, SCIP_CONS *cons)
    Definition: cons_setppc.c:9683
    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_VAR ** SCIPgetVarsSetppc(SCIP *scip, SCIP_CONS *cons)
    Definition: cons_setppc.c:9701
    SCIP_EXPR * SCIPgetExprNonlinear(SCIP_CONS *cons)
    SCIP_Real SCIPgetRhsNonlinear(SCIP_CONS *cons)
    SCIP_VAR * SCIPgetVarVarbound(SCIP *scip, SCIP_CONS *cons)
    SCIP_RETCODE SCIPcreateConsBasicNonlinear(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_EXPR *expr, SCIP_Real lhs, SCIP_Real rhs)
    SCIP_Longint * SCIPgetWeightsKnapsack(SCIP *scip, SCIP_CONS *cons)
    SCIP_Longint SCIPgetCapacityKnapsack(SCIP *scip, SCIP_CONS *cons)
    SCIP_Real SCIPgetLhsVarbound(SCIP *scip, SCIP_CONS *cons)
    SCIP_SETPPCTYPE SCIPgetTypeSetppc(SCIP *scip, SCIP_CONS *cons)
    Definition: cons_setppc.c:9719
    SCIP_VAR ** SCIPgetVarsLogicor(SCIP *scip, SCIP_CONS *cons)
    SCIP_Real SCIPgetRhsVarbound(SCIP *scip, SCIP_CONS *cons)
    SCIP_VAR ** SCIPgetVarsKnapsack(SCIP *scip, SCIP_CONS *cons)
    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_Real SCIPgetLhsNonlinear(SCIP_CONS *cons)
    SCIP_RETCODE SCIPcreateConsBasicSOS2(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *weights)
    Definition: cons_sos2.c:2690
    @ SCIP_SETPPCTYPE_PARTITIONING
    Definition: cons_setppc.h:87
    @ SCIP_SETPPCTYPE_COVERING
    Definition: cons_setppc.h:89
    @ SCIP_SETPPCTYPE_PACKING
    Definition: cons_setppc.h:88
    SCIP_RETCODE SCIPcreateExprVar(SCIP *scip, SCIP_EXPR **expr, SCIP_VAR *var, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
    Definition: expr_var.c:397
    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:1431
    SCIP_Bool SCIPisExprAbs(SCIP *scip, SCIP_EXPR *expr)
    Definition: expr_abs.c:546
    SCIP_RETCODE SCIPcreateExprCos(SCIP *scip, SCIP_EXPR **expr, SCIP_EXPR *child, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
    Definition: expr_trig.c:1451
    SCIP_RETCODE SCIPcreateExprAbs(SCIP *scip, SCIP_EXPR **expr, SCIP_EXPR *child, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
    Definition: expr_abs.c:528
    SCIP_Bool SCIPisExprLog(SCIP *scip, SCIP_EXPR *expr)
    Definition: expr_log.c:648
    SCIP_RETCODE SCIPappendExprSumExpr(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPR *child, SCIP_Real childcoef)
    Definition: expr_sum.c:1154
    SCIP_Bool SCIPisExprExp(SCIP *scip, SCIP_EXPR *expr)
    Definition: expr_exp.c:529
    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:511
    SCIP_Bool SCIPisExprCos(SCIP *scip, SCIP_EXPR *expr)
    Definition: expr_trig.c:1481
    SCIP_Bool SCIPisExprSin(SCIP *scip, SCIP_EXPR *expr)
    Definition: expr_trig.c:1470
    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:1117
    SCIP_RETCODE SCIPcreateExprValue(SCIP *scip, SCIP_EXPR **expr, SCIP_Real value, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
    Definition: expr_value.c:274
    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:3186
    SCIP_Bool SCIPhasPerformedPresolve(SCIP *scip)
    Definition: scip_general.c:738
    SCIP_RETCODE SCIPprintStatus(SCIP *scip, FILE *file)
    Definition: scip_general.c:639
    SCIP_STATUS SCIPgetStatus(SCIP *scip)
    Definition: scip_general.c:562
    SCIP_STAGE SCIPgetStage(SCIP *scip)
    Definition: scip_general.c:444
    SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
    Definition: scip_prob.c:1907
    SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
    Definition: scip_prob.c:3274
    SCIP_PROBDATA * SCIPgetProbData(SCIP *scip)
    Definition: scip_prob.c:1139
    SCIP_RETCODE SCIPsetObjsense(SCIP *scip, SCIP_OBJSENSE objsense)
    Definition: scip_prob.c:1417
    SCIP_OBJSENSE SCIPgetObjsense(SCIP *scip)
    Definition: scip_prob.c:1400
    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:119
    void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
    Definition: misc.c:3095
    int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
    Definition: misc.c:3304
    SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
    Definition: misc.c:3061
    SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
    Definition: misc.c:3466
    SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
    Definition: misc.c:3179
    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
    #define SCIPdebugMsg
    Definition: scip_message.h:78
    void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
    Definition: scip_message.c:120
    SCIP_RETCODE SCIPgetBoolParam(SCIP *scip, const char *name, SCIP_Bool *value)
    Definition: scip_param.c:250
    SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:57
    const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:4320
    SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
    Definition: scip_cons.c:940
    SCIP_RETCODE SCIPgetConsNVars(SCIP *scip, SCIP_CONS *cons, int *nvars, SCIP_Bool *success)
    Definition: scip_cons.c:2621
    SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
    Definition: cons.c:8413
    SCIP_RETCODE SCIPsetConsSeparated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool separate)
    Definition: scip_cons.c:1296
    SCIP_RETCODE SCIPsetConsDynamic(SCIP *scip, SCIP_CONS *cons, SCIP_Bool dynamic)
    Definition: scip_cons.c:1449
    SCIP_RETCODE SCIPsetConsInitial(SCIP *scip, SCIP_CONS *cons, SCIP_Bool initial)
    Definition: scip_cons.c:1271
    SCIP_RETCODE SCIPsetConsEnforced(SCIP *scip, SCIP_CONS *cons, SCIP_Bool enforce)
    Definition: scip_cons.c:1321
    const char * SCIPconsGetName(SCIP_CONS *cons)
    Definition: cons.c:8393
    SCIP_RETCODE SCIPsetConsRemovable(SCIP *scip, SCIP_CONS *cons, SCIP_Bool removable)
    Definition: scip_cons.c:1474
    SCIP_RETCODE SCIPgetTransformedCons(SCIP *scip, SCIP_CONS *cons, SCIP_CONS **transcons)
    Definition: scip_cons.c:1674
    SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
    Definition: scip_cons.c:1173
    SCIP_RETCODE SCIPsetConsPropagated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool propagate)
    Definition: scip_cons.c:1371
    SCIP_RETCODE SCIPsetConsChecked(SCIP *scip, SCIP_CONS *cons, SCIP_Bool check)
    Definition: scip_cons.c:1346
    const char * SCIPexprhdlrGetName(SCIP_EXPRHDLR *exprhdlr)
    Definition: expr.c:545
    SCIP_RETCODE SCIPevalExpr(SCIP *scip, SCIP_EXPR *expr, SCIP_SOL *sol, SCIP_Longint soltag)
    Definition: scip_expr.c:1661
    int SCIPexprGetNChildren(SCIP_EXPR *expr)
    Definition: expr.c:3872
    SCIP_Real SCIPgetExponentExprPow(SCIP_EXPR *expr)
    Definition: expr_pow.c:3449
    SCIP_Bool SCIPisExprProduct(SCIP *scip, SCIP_EXPR *expr)
    Definition: scip_expr.c:1490
    SCIP_Bool SCIPexpriterIsEnd(SCIP_EXPRITER *iterator)
    Definition: expriter.c:969
    SCIP_EXPR * SCIPexpriterSkipDFS(SCIP_EXPRITER *iterator)
    Definition: expriter.c:930
    SCIP_Bool SCIPisExprSum(SCIP *scip, SCIP_EXPR *expr)
    Definition: scip_expr.c:1479
    SCIP_Real * SCIPgetCoefsExprSum(SCIP_EXPR *expr)
    Definition: expr_sum.c:1554
    SCIP_EXPRITER_USERDATA SCIPexpriterGetCurrentUserData(SCIP_EXPRITER *iterator)
    Definition: expriter.c:756
    SCIP_Bool SCIPisExprValue(SCIP *scip, SCIP_EXPR *expr)
    Definition: scip_expr.c:1468
    SCIP_RETCODE SCIPreleaseExpr(SCIP *scip, SCIP_EXPR **expr)
    Definition: scip_expr.c:1443
    SCIP_EXPR * SCIPexpriterGetCurrent(SCIP_EXPRITER *iterator)
    Definition: expriter.c:683
    void SCIPexpriterSetStagesDFS(SCIP_EXPRITER *iterator, SCIP_EXPRITER_STAGE stopstages)
    Definition: expriter.c:664
    SCIP_Bool SCIPisExprVar(SCIP *scip, SCIP_EXPR *expr)
    Definition: scip_expr.c:1457
    SCIP_RETCODE SCIPcreateExpriter(SCIP *scip, SCIP_EXPRITER **iterator)
    Definition: scip_expr.c:2362
    SCIP_EXPR * SCIPexpriterGetParentDFS(SCIP_EXPRITER *iterator)
    Definition: expriter.c:740
    SCIP_Real SCIPgetValueExprValue(SCIP_EXPR *expr)
    Definition: expr_value.c:298
    void SCIPexpriterSetCurrentUserData(SCIP_EXPRITER *iterator, SCIP_EXPRITER_USERDATA userdata)
    Definition: expriter.c:806
    SCIP_Bool SCIPisExprPower(SCIP *scip, SCIP_EXPR *expr)
    Definition: scip_expr.c:1501
    SCIP_Real SCIPexprGetEvalValue(SCIP_EXPR *expr)
    Definition: expr.c:3946
    SCIP_EXPR * SCIPexpriterGetNext(SCIP_EXPRITER *iterator)
    Definition: expriter.c:858
    SCIP_Real SCIPgetConstantExprSum(SCIP_EXPR *expr)
    Definition: expr_sum.c:1569
    SCIP_VAR * SCIPgetVarExprVar(SCIP_EXPR *expr)
    Definition: expr_var.c:423
    int SCIPexpriterGetChildIdxDFS(SCIP_EXPRITER *iterator)
    Definition: expriter.c:707
    void SCIPfreeExpriter(SCIP_EXPRITER **iterator)
    Definition: scip_expr.c:2376
    SCIP_EXPRITER_STAGE SCIPexpriterGetStageDFS(SCIP_EXPRITER *iterator)
    Definition: expriter.c:696
    SCIP_RETCODE SCIPexpriterInit(SCIP_EXPRITER *iterator, SCIP_EXPR *expr, SCIP_EXPRITER_TYPE type, SCIP_Bool allowrevisit)
    Definition: expriter.c:501
    SCIP_EXPRITER_USERDATA SCIPexpriterGetExprUserData(SCIP_EXPRITER *iterator, SCIP_EXPR *expr)
    Definition: expriter.c:790
    SCIP_EXPRHDLR * SCIPexprGetHdlr(SCIP_EXPR *expr)
    Definition: expr.c:3895
    SCIP_RETCODE SCIPincludeExternalCodeInformation(SCIP *scip, const char *name, const char *description)
    Definition: scip_general.c:777
    #define SCIPallocClearMemory(scip, ptr)
    Definition: scip_mem.h:62
    BMS_BLKMEM * SCIPblkmem(SCIP *scip)
    Definition: scip_mem.c:57
    #define SCIPallocClearBufferArray(scip, ptr, num)
    Definition: scip_mem.h:126
    #define SCIPallocBufferArray(scip, ptr, num)
    Definition: scip_mem.h:124
    #define SCIPfreeBufferArray(scip, ptr)
    Definition: scip_mem.h:136
    #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
    #define SCIPfreeBufferArrayNull(scip, ptr)
    Definition: scip_mem.h:137
    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_RETCODE SCIPsetReaderWrite(SCIP *scip, SCIP_READER *reader, SCIP_DECL_READERWRITE((*readerwrite)))
    Definition: scip_reader.c:219
    SCIP_SOL * SCIPgetBestSol(SCIP *scip)
    Definition: scip_sol.c:2986
    SCIP_RETCODE SCIPcreateSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
    Definition: scip_sol.c:514
    SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
    Definition: scip_sol.c:1250
    SCIP_RETCODE SCIPaddSolFree(SCIP *scip, SCIP_SOL **sol, SCIP_Bool *stored)
    Definition: scip_sol.c:3914
    SCIP_RETCODE SCIPprintSol(SCIP *scip, SCIP_SOL *sol, FILE *file, SCIP_Bool printzeros)
    Definition: scip_sol.c:2351
    SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
    Definition: scip_sol.c:1569
    SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
    Definition: scip_sol.c:1763
    SCIP_Real SCIPinfinity(SCIP *scip)
    SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Real SCIPvarGetNegationConstant(SCIP_VAR *var)
    Definition: var.c:23921
    SCIP_Real SCIPvarGetMultaggrConstant(SCIP_VAR *var)
    Definition: var.c:23875
    SCIP_VAR * SCIPvarGetNegatedVar(SCIP_VAR *var)
    Definition: var.c:23900
    SCIP_RETCODE SCIPtightenVarUbGlobal(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
    Definition: scip_var.c:8257
    SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
    Definition: var.c:23418
    SCIP_Real SCIPvarGetAggrConstant(SCIP_VAR *var)
    Definition: var.c:23803
    SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
    Definition: var.c:23932
    SCIP_Real SCIPvarGetAggrScalar(SCIP_VAR *var)
    Definition: var.c:23780
    SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
    Definition: var.c:23485
    SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
    Definition: var.c:24174
    SCIP_RETCODE SCIPvarSetInitial(SCIP_VAR *var, SCIP_Bool initial)
    Definition: var.c:23386
    const char * SCIPvarGetName(SCIP_VAR *var)
    Definition: var.c:23299
    SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
    Definition: scip_var.c:1887
    SCIP_RETCODE SCIPchgVarLbGlobal(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
    Definition: scip_var.c:6141
    SCIP_RETCODE SCIPchgVarType(SCIP *scip, SCIP_VAR *var, SCIP_VARTYPE vartype, SCIP_Bool *infeasible)
    Definition: scip_var.c:10113
    SCIP_RETCODE SCIPgetNegatedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **negvar)
    Definition: scip_var.c:2166
    SCIP_VAR ** SCIPvarGetMultaggrVars(SCIP_VAR *var)
    Definition: var.c:23838
    int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
    Definition: var.c:23826
    SCIP_RETCODE SCIPvarSetRemovable(SCIP_VAR *var, SCIP_Bool removable)
    Definition: var.c:23402
    SCIP_Bool SCIPvarIsNegated(SCIP_VAR *var)
    Definition: var.c:23475
    SCIP_RETCODE SCIPchgVarUbGlobal(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
    Definition: scip_var.c:6230
    SCIP_VAR * SCIPvarGetNegationVar(SCIP_VAR *var)
    Definition: var.c:23910
    SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
    Definition: var.c:24152
    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:184
    SCIP_RETCODE SCIPchgVarObj(SCIP *scip, SCIP_VAR *var, SCIP_Real newobj)
    Definition: scip_var.c:5372
    SCIP_Real * SCIPvarGetMultaggrScalars(SCIP_VAR *var)
    Definition: var.c:23850
    SCIP_RETCODE SCIPtightenVarLbGlobal(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
    Definition: scip_var.c:8026
    SCIP_VAR * SCIPvarGetAggrVar(SCIP_VAR *var)
    Definition: var.c:23768
    int SCIPstrcasecmp(const char *s1, const char *s2)
    Definition: misc.c:10863
    int SCIPsnprintf(char *t, int len, const char *s,...)
    Definition: misc.c:10827
    #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:3226
    struct SCIP_ProbNlData SCIP_PROBNLDATA
    Definition: reader_nl.cpp:134
    static SCIP_DECL_PROBDELORIG(probdataDelOrigNl)
    Definition: reader_nl.cpp:2866
    #define READER_DESC
    Definition: reader_nl.cpp:99
    static SCIP_DECL_READERWRITE(readerWriteNl)
    Definition: reader_nl.cpp:2982
    #define READER_EXTENSION
    Definition: reader_nl.cpp:100
    #define SCIP_CALL_THROW(x)
    Definition: reader_nl.cpp:104
    SCIP_RETCODE SCIPwriteSolutionNl(SCIP *scip)
    Definition: reader_nl.cpp:3258
    static SCIP_DECL_READERCOPY(readerCopyNl)
    Definition: reader_nl.cpp:2900
    #define READER_NAME
    Definition: reader_nl.cpp:98
    static SCIP_DECL_READERREAD(readerReadNl)
    Definition: reader_nl.cpp:2911
    #define PATHSEP
    Definition: reader_nl.cpp:2977
    AMPL .nl file reader and writer.
    #define SCIP_EXPRITER_VISITINGCHILD
    Definition: type_expr.h:695
    @ SCIP_EXPRITER_DFS
    Definition: type_expr.h:718
    #define SCIP_EXPRITER_VISITEDCHILD
    Definition: type_expr.h:696
    #define SCIP_EXPRITER_LEAVEEXPR
    Definition: type_expr.h:697
    #define SCIP_EXPRITER_ALLSTAGES
    Definition: type_expr.h:698
    #define SCIP_EXPRITER_ENTEREXPR
    Definition: type_expr.h:694
    @ SCIP_VERBLEVEL_HIGH
    Definition: type_message.h:61
    @ SCIP_VERBLEVEL_FULL
    Definition: type_message.h:62
    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
    enum SCIP_Objsense SCIP_OBJSENSE
    Definition: type_prob.h:50
    @ SCIP_DIDNOTRUN
    Definition: type_result.h:42
    @ SCIP_SUCCESS
    Definition: type_result.h:58
    @ SCIP_FILECREATEERROR
    Definition: type_retcode.h:48
    @ 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:43
    @ SCIP_STATUS_TOTALNODELIMIT
    Definition: type_stat.h:50
    @ SCIP_STATUS_BESTSOLLIMIT
    Definition: type_stat.h:60
    @ SCIP_STATUS_SOLLIMIT
    Definition: type_stat.h:59
    @ SCIP_STATUS_UNBOUNDED
    Definition: type_stat.h:45
    @ SCIP_STATUS_UNKNOWN
    Definition: type_stat.h:42
    @ SCIP_STATUS_PRIMALLIMIT
    Definition: type_stat.h:57
    @ SCIP_STATUS_GAPLIMIT
    Definition: type_stat.h:56
    @ SCIP_STATUS_USERINTERRUPT
    Definition: type_stat.h:47
    @ SCIP_STATUS_TERMINATE
    Definition: type_stat.h:48
    @ SCIP_STATUS_INFORUNBD
    Definition: type_stat.h:46
    @ SCIP_STATUS_STALLNODELIMIT
    Definition: type_stat.h:52
    @ SCIP_STATUS_TIMELIMIT
    Definition: type_stat.h:54
    @ SCIP_STATUS_INFEASIBLE
    Definition: type_stat.h:44
    @ SCIP_STATUS_NODELIMIT
    Definition: type_stat.h:49
    @ SCIP_STATUS_DUALLIMIT
    Definition: type_stat.h:58
    @ SCIP_STATUS_MEMLIMIT
    Definition: type_stat.h:55
    @ SCIP_STATUS_RESTARTLIMIT
    Definition: type_stat.h:62
    @ SCIP_VARTYPE_INTEGER
    Definition: type_var.h:65
    @ SCIP_VARTYPE_CONTINUOUS
    Definition: type_var.h:71
    @ SCIP_VARTYPE_BINARY
    Definition: type_var.h:64
    @ SCIP_VARSTATUS_FIXED
    Definition: type_var.h:54
    @ SCIP_VARSTATUS_MULTAGGR
    Definition: type_var.h:56
    @ SCIP_VARSTATUS_NEGATED
    Definition: type_var.h:57
    @ SCIP_VARSTATUS_AGGREGATED
    Definition: type_var.h:55
    enum SCIP_Vartype SCIP_VARTYPE
    Definition: type_var.h:73