Scippy

SCIP

Solving Constraint Integer Programs

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