Scippy

    SCIP

    Solving Constraint Integer Programs

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