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-2023 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/expr_var.h"
46 #include "scip/expr_value.h"
47 #include "scip/expr_sum.h"
48 #include "scip/expr_product.h"
49 #include "scip/expr_pow.h"
50 #include "scip/expr_log.h"
51 #include "scip/expr_exp.h"
52 #include "scip/expr_trig.h"
53 #include "scip/expr_abs.h"
54 
55 // disable -Wshadow warnings for upcoming includes of AMPL/MP
56 // disable -Wimplicit-fallthrough as I don't want to maintain extra comments in AMPL/MP code to suppress these
57 #ifdef __GNUC__
58 #pragma GCC diagnostic ignored "-Wshadow"
59 #if __GNUC__ >= 7
60 #pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
61 #endif
62 #endif
63 
64 #include "mp/nl-reader.h"
65 
66 #define READER_NAME "nlreader"
67 #define READER_DESC "AMPL .nl file reader"
68 #define READER_EXTENSION "nl"
69 
70 // a variant of SCIP_CALL that throws a std::logic_error if not SCIP_OKAY
71 // (using cast to long long to work around issues with old MSVC)
72 #define SCIP_CALL_THROW(x) \
73  do \
74  { \
75  SCIP_RETCODE throw_retcode; \
76  if( ((throw_retcode) = (x)) != SCIP_OKAY ) \
77  throw std::logic_error("Error <" + std::to_string((long long)throw_retcode) + "> in function call"); \
78  } \
79  while( false )
80 
81 /*
82  * Data structures
83  */
84 
85 /// problem data stored in SCIP
86 struct SCIP_ProbData
87 {
88  char* filenamestub; /**< name of input file, without .nl extension; array is long enough to hold 5 extra chars */
89  int filenamestublen; /**< length of filenamestub string */
90 
91  int amplopts[mp::MAX_AMPL_OPTIONS]; /**< AMPL options from .nl header */
92  int namplopts; /**< number of AMPL options from .nl header */
93 
94  SCIP_VAR** vars; /**< variables in the order given by AMPL */
95  int nvars; /**< number of variables */
96 
97  SCIP_CONS** conss; /**< constraints in the order given by AMPL */
98  int nconss; /**< number of constraints */
99 
100  SCIP_Bool islp; /**< whether problem is an LP (only linear constraints, only continuous vars) */
101 };
102 
103 /*
104  * Local methods
105  */
106 
107 // forward declaration
108 static SCIP_DECL_PROBDELORIG(probdataDelOrigNl);
109 
110 /// implementation of AMPL/MPs NLHandler that constructs a SCIP problem while a .nl file is read
111 class AMPLProblemHandler : public mp::NLHandler<AMPLProblemHandler, SCIP_EXPR*>
112 {
113 private:
114  SCIP* scip;
115  SCIP_PROBDATA* probdata;
116 
117  // variable expressions corresponding to nonlinear variables
118  // created in OnHeader() and released in destructor
119  // for reuse of var-expressions in OnVariableRef()
120  std::vector<SCIP_EXPR*> varexprs;
121 
122  // linear parts for nonlinear constraints
123  // first collect and then add to constraints in EndInput()
124  std::vector<std::vector<std::pair<SCIP_Real, SCIP_VAR*> > > nlconslin;
125 
126  // expression that represents a nonlinear objective function
127  // used to create a corresponding constraint in EndInput(), unless NULL
128  SCIP_EXPR* objexpr;
129 
130  // common expressions (defined variables from statements like "var xsqr = x^2;" in an AMPL model)
131  // they are constructed by BeginCommonExpr/EndCommonExpr below and are referenced by index in OnCommonExprRef
132  std::vector<SCIP_EXPR*> commonexprs;
133 
134  // collect expressions that need to be released eventually
135  // this are all expression that are returned to the AMPL/MP code in AMPLProblemHandler::OnXyz() functions
136  // they need to be released exactly once, but after they are used in another expression or a constraint
137  // as AMPL/MP may reuse expressions (common subexpressions), we don't release an expression when it is used
138  // as a child or when constructing a constraint, but first collect them all and then release in destructor
139  // alternatively, one could encapsulate SCIP_EXPR* into a small class that handles proper reference counting
140  std::vector<SCIP_EXPR*> exprstorelease;
141 
142  // SOS constraints
143  // collected while handling suffixes in SuffixHandler
144  // sosvars maps the SOS index (can be negative) to the indices of the variables in the SOS
145  // sosweights gives for each variable its weight in the SOS it appears in (if any)
146  std::map<int, std::vector<int> > sosvars;
147  std::vector<int> sosweights;
148 
149  // initial solution, if any
150  SCIP_SOL* initsol;
151 
152  // opened files with column/variable and row/constraint names, or NULL
153  fmt::File* colfile;
154  fmt::File* rowfile;
155 
156  // get name from names strings, if possible
157  // returns whether a name has been stored
158  bool nextName(
159  const char*& namesbegin, /**< current pointer into names string, or NULL */
160  const char* namesend, /**< pointer to end of names string */
161  char* name /**< buffer to store name, should have length SCIP_MAXSTRLEN */
162  )
163  {
164  if( namesbegin == NULL )
165  return false;
166 
167  // copy namesbegin into name until newline or namesend
168  // updates namesbegin
169  int nchars = 0;
170  while( namesbegin != namesend )
171  {
172  if( nchars == SCIP_MAXSTRLEN )
173  {
174  SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL, "name too long when parsing names file");
175  // do no longer read names from this string (something seems awkward)
176  namesbegin = NULL;
177  return false;
178  }
179  if( *namesbegin == '\n' )
180  {
181  *name = '\0';
182  ++namesbegin;
183  return true;
184  }
185  *(name++) = *(namesbegin++);
186  ++nchars;
187  }
188 
189  SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL, "missing newline when parsing names file");
190  return false;
191  }
192 
193 public:
194  /// constructor
195  ///
196  /// initializes SCIP problem and problem data
198  SCIP* scip_, ///< SCIP data structure
199  const char* filename ///< name of .nl file that is read
200  )
201  : scip(scip_),
202  probdata(NULL),
203  objexpr(NULL),
204  initsol(NULL),
205  colfile(NULL),
206  rowfile(NULL)
207  {
208  assert(scip != NULL);
209  assert(filename != NULL);
210 
211  SCIP_CALL_THROW( SCIPallocClearMemory(scip, &probdata) );
212 
213  /* get name of input file without file extension (if any) */
214  const char* extstart = strrchr(const_cast<char*>(filename), '.');
215  if( extstart != NULL )
216  probdata->filenamestublen = extstart - filename;
217  else
218  probdata->filenamestublen = strlen(filename);
219  assert(probdata->filenamestublen > 0);
220  SCIP_CALL_THROW( SCIPallocBlockMemoryArray(scip, &probdata->filenamestub, probdata->filenamestublen + 5) );
221  memcpy(probdata->filenamestub, filename, probdata->filenamestublen);
222  probdata->filenamestub[probdata->filenamestublen] = '\0';
223 
224  /* derive probname from name of input file without path and extension */
225  const char* probname = strrchr(probdata->filenamestub, '/');
226  if( probname == NULL )
227  probname = probdata->filenamestub;
228  else
229  ++probname;
230 
231  // initialize empty SCIP problem
232  SCIP_CALL_THROW( SCIPcreateProb(scip, probname, probdataDelOrigNl, NULL, NULL, NULL, NULL, NULL, probdata) );
233 
234  // try to open files with variable and constraint names
235  // temporarily add ".col" and ".row", respectively, to filenamestub
236  try
237  {
238  probdata->filenamestub[probdata->filenamestublen] = '.';
239  probdata->filenamestub[probdata->filenamestublen+1] = 'c';
240  probdata->filenamestub[probdata->filenamestublen+2] = 'o';
241  probdata->filenamestub[probdata->filenamestublen+3] = 'l';
242  probdata->filenamestub[probdata->filenamestublen+4] = '\0';
243  colfile = new fmt::File(probdata->filenamestub, fmt::File::RDONLY);
244 
245  probdata->filenamestub[probdata->filenamestublen+1] = 'r';
246  probdata->filenamestub[probdata->filenamestublen+3] = 'w';
247  rowfile = new fmt::File(probdata->filenamestub, fmt::File::RDONLY);
248  }
249  catch( const fmt::SystemError& e )
250  {
251  // probably a file open error, probably because file not found
252  // ignore, we can make up our own names
253  }
254  probdata->filenamestub[probdata->filenamestublen] = '\0';
255  }
256 
257  AMPLProblemHandler(const AMPLProblemHandler&) = delete;
258  AMPLProblemHandler& operator=(const AMPLProblemHandler&) = delete;
259 
260  /// destructor
261  ///
262  /// only asserts that cleanup() has been called, as we cannot throw an exception or return a SCIP_RETCODE here
264  {
265  // exprs and linear constraint arrays should have been cleared up in cleanup()
266  assert(varexprs.empty());
267  assert(exprstorelease.empty());
268 
269  delete colfile;
270  delete rowfile;
271  }
272 
273  /// process header of .nl files
274  ///
275  /// create and add variables, allocate constraints
276  void OnHeader(
277  const mp::NLHeader& h ///< header data
278  )
279  {
280  char name[SCIP_MAXSTRLEN];
281  int nnlvars;
282 
283  assert(probdata->vars == NULL);
284  assert(probdata->conss == NULL);
285 
286  probdata->namplopts = h.num_ampl_options;
287  BMScopyMemoryArray(probdata->amplopts, h.ampl_options, h.num_ampl_options);
288 
289  // read variable and constraint names from file, if available, into memory
290  // if not available, we will get varnamesbegin==NULL and consnamesbegin==NULL
291  mp::MemoryMappedFile<> mapped_colfile;
292  if( colfile != NULL )
293  mapped_colfile.map(*colfile, "colfile");
294  const char* varnamesbegin = mapped_colfile.start();
295  const char* varnamesend = mapped_colfile.start() + mapped_colfile.size();
296 
297  mp::MemoryMappedFile<> mapped_rowfile;
298  if( rowfile != NULL )
299  mapped_rowfile.map(*rowfile, "rowfile");
300  const char* consnamesbegin = mapped_rowfile.start();
301  const char* consnamesend = mapped_rowfile.start() + mapped_rowfile.size();
302 
303  probdata->nvars = h.num_vars;
304  SCIP_CALL_THROW( SCIPallocBlockMemoryArray(scip, &probdata->vars, probdata->nvars) );
305 
306  // number of nonlinear variables
307  nnlvars = MAX(h.num_nl_vars_in_cons, h.num_nl_vars_in_objs);
308  varexprs.resize(nnlvars);
309 
310  // create variables
311  // create variable expressions for nonlinear variables
312  for( int i = 0; i < h.num_vars; ++i )
313  {
314  SCIP_VARTYPE vartype;
315  // Nonlinear variables in both constraints and objective
316  if( i < h.num_nl_vars_in_both - h.num_nl_integer_vars_in_both )
317  vartype = SCIP_VARTYPE_CONTINUOUS;
318  else if( i < h.num_nl_vars_in_both )
319  vartype = SCIP_VARTYPE_INTEGER;
320  // Nonlinear variables in constraints
321  else if( i < h.num_nl_vars_in_cons - h.num_nl_integer_vars_in_cons )
322  vartype = SCIP_VARTYPE_CONTINUOUS;
323  else if( i < h.num_nl_vars_in_cons )
324  vartype = SCIP_VARTYPE_INTEGER;
325  // Nonlinear variables in objective
326  else if( i < h.num_nl_vars_in_objs - h.num_nl_integer_vars_in_objs )
327  vartype = SCIP_VARTYPE_CONTINUOUS;
328  else if( i < h.num_nl_vars_in_objs )
329  vartype = SCIP_VARTYPE_INTEGER;
330  // Linear variables
331  else if( i < h.num_vars - h.num_linear_binary_vars - h.num_linear_integer_vars )
332  vartype = SCIP_VARTYPE_CONTINUOUS;
333  else if( i < h.num_vars - h.num_linear_integer_vars )
334  vartype = SCIP_VARTYPE_BINARY;
335  else
336  vartype = SCIP_VARTYPE_INTEGER;
337 
338  if( !nextName(varnamesbegin, varnamesend, name) )
339  {
340  // make up name if no names file or could not be read
341  switch( vartype )
342  {
343  case SCIP_VARTYPE_BINARY :
344  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "b%d", i);
345  break;
346  case SCIP_VARTYPE_INTEGER :
347  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "i%d", i);
348  break;
350  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "x%d", i);
351  break;
352  // coverity[deadcode]
353  default:
354  SCIPABORT();
355  break;
356  }
357  }
358 
359  SCIP_CALL_THROW( SCIPcreateVarBasic(scip, &probdata->vars[i], name,
360  vartype == SCIP_VARTYPE_BINARY ? 0.0 : -SCIPinfinity(scip),
361  vartype == SCIP_VARTYPE_BINARY ? 1.0 : SCIPinfinity(scip),
362  0.0, vartype) );
363  SCIP_CALL_THROW( SCIPaddVar(scip, probdata->vars[i]) );
364 
365  if( i < nnlvars )
366  {
367  SCIP_CALL_THROW( SCIPcreateExprVar(scip, &varexprs[i], probdata->vars[i], NULL, NULL) );
368  }
369  }
370 
371  // alloc some space for constraints
372  probdata->nconss = h.num_algebraic_cons;
373  SCIP_CALL_THROW( SCIPallocBlockMemoryArray(scip, &probdata->conss, probdata->nconss) );
374  nlconslin.resize(h.num_nl_cons);
375 
376  // create empty nonlinear constraints
377  // use expression == 0, because nonlinear constraint don't like to be without an expression
378  SCIP_EXPR* dummyexpr;
379  SCIP_CALL_THROW( SCIPcreateExprValue(scip, &dummyexpr, 0.0, NULL, NULL) );
380  for( int i = 0; i < h.num_nl_cons; ++i )
381  {
382  // make up name if no names file or could not be read
383  if( !nextName(consnamesbegin, consnamesend, name) )
384  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nlc%d", i);
385 
386  SCIP_CALL_THROW( SCIPcreateConsBasicNonlinear(scip, &probdata->conss[i], name, dummyexpr, -SCIPinfinity(scip), SCIPinfinity(scip)) );
387  }
388  SCIP_CALL_THROW( SCIPreleaseExpr(scip, &dummyexpr) );
389 
390  // create empty linear constraints
391  for( int i = h.num_nl_cons; i < h.num_algebraic_cons; ++i )
392  {
393  if( !nextName(consnamesbegin, consnamesend, name) )
394  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "lc%d", i);
395  SCIP_CALL_THROW( SCIPcreateConsBasicLinear(scip, &probdata->conss[i], name, 0, NULL, NULL, -SCIPinfinity(scip), SCIPinfinity(scip)) );
396  }
397 
398  if( h.num_nl_cons == 0 && h.num_integer_vars() == 0 )
399  probdata->islp = true;
400 
401  // alloc space for common expressions
402  commonexprs.resize(h.num_common_exprs());
403  }
404 
405  /// receive notification of a number in a nonlinear expression
407  double value ///< value
408  )
409  {
410  SCIP_EXPR* expr;
411 
412  SCIP_CALL_THROW( SCIPcreateExprValue(scip, &expr, value, NULL, NULL) );
413 
414  // remember that we have to release this expr
415  exprstorelease.push_back(expr);
416 
417  return expr;
418  }
419 
420  /// receive notification of a variable reference in a nonlinear expression
422  int variableIndex ///< AMPL index of variable
423  )
424  {
425  assert(variableIndex >= 0);
426  assert(variableIndex < (int)varexprs.size());
427  assert(varexprs[variableIndex] != NULL);
428 
429  return varexprs[variableIndex];
430  }
431 
432  /// receive notification of a unary expression
434  mp::expr::Kind kind, ///< expression operator
435  SCIP_EXPR* child ///< argument
436  )
437  {
438  SCIP_EXPR* expr;
439 
440  assert(child != NULL);
441 
442  switch( kind )
443  {
444  case mp::expr::MINUS:
445  {
446  SCIP_Real minusone = -1.0;
447  SCIP_CALL_THROW( SCIPcreateExprSum(scip, &expr, 1, &child, &minusone, 0.0, NULL, NULL) );
448  break;
449  }
450 
451  case mp::expr::ABS:
452  SCIP_CALL_THROW( SCIPcreateExprAbs(scip, &expr, child, NULL, NULL) );
453  break;
454 
455  case mp::expr::POW2:
456  SCIP_CALL_THROW( SCIPcreateExprPow(scip, &expr, child, 2.0, NULL, NULL) );
457  break;
458 
459  case mp::expr::SQRT:
460  SCIP_CALL_THROW( SCIPcreateExprPow(scip, &expr, child, 0.5, NULL, NULL) );
461  break;
462 
463  case mp::expr::LOG:
464  SCIP_CALL_THROW( SCIPcreateExprLog(scip, &expr, child, NULL, NULL) );
465  break;
466 
467  case mp::expr::LOG10: // 1/log(10)*log(child)
468  {
469  SCIP_EXPR* logexpr;
470  SCIP_Real factor = 1.0/log(10.0);
471  SCIP_CALL_THROW( SCIPcreateExprLog(scip, &logexpr, child, NULL, NULL) );
472  SCIP_CALL_THROW( SCIPcreateExprSum(scip, &expr, 1, &logexpr, &factor, 0.0, NULL, NULL) );
473  SCIP_CALL_THROW( SCIPreleaseExpr(scip, &logexpr) );
474  break;
475  }
476 
477  case mp::expr::EXP:
478  SCIP_CALL_THROW( SCIPcreateExprExp(scip, &expr, child, NULL, NULL) );
479  break;
480 
481  case mp::expr::SIN:
482  SCIP_CALL_THROW( SCIPcreateExprSin(scip, &expr, child, NULL, NULL) );
483  break;
484 
485  case mp::expr::COS:
486  SCIP_CALL_THROW( SCIPcreateExprCos(scip, &expr, child, NULL, NULL) );
487  break;
488 
489  default:
490  OnUnhandled(mp::expr::str(kind));
491  return NULL;
492  }
493 
494  // remember that we have to release this expr
495  exprstorelease.push_back(expr);
496 
497  return expr;
498  }
499 
500  /// receive notification of a binary expression
502  mp::expr::Kind kind, ///< expression operand
503  SCIP_EXPR* firstChild, ///< first argument
504  SCIP_EXPR* secondChild ///< second argument
505  )
506  {
507  SCIP_EXPR* expr;
508  SCIP_EXPR* children[2] = { firstChild, secondChild };
509 
510  assert(firstChild != NULL);
511  assert(secondChild != NULL);
512 
513  switch( kind )
514  {
515  case mp::expr::ADD:
516  SCIP_CALL_THROW( SCIPcreateExprSum(scip, &expr, 2, children, NULL, 0.0, NULL, NULL) );
517  break;
518 
519  case mp::expr::SUB:
520  {
521  SCIP_Real coefs[2] = { 1.0, -1.0 };
522  SCIP_CALL_THROW( SCIPcreateExprSum(scip, &expr, 2, children, coefs, 0.0, NULL, NULL) );
523  break;
524  }
525 
526  case mp::expr::MUL:
527  SCIP_CALL_THROW( SCIPcreateExprProduct(scip, &expr, 2, children, 1.0, NULL, NULL) );
528  break;
529 
530  case mp::expr::DIV:
531  SCIP_CALL_THROW( SCIPcreateExprPow(scip, &children[1], secondChild, -1.0, NULL, NULL) );
532  SCIP_CALL_THROW( SCIPcreateExprProduct(scip, &expr, 2, children, 1.0, NULL, NULL) );
533  SCIP_CALL_THROW( SCIPreleaseExpr(scip, &children[1]) );
534  break;
535 
536  case mp::expr::POW_CONST_BASE:
537  case mp::expr::POW_CONST_EXP:
538  case mp::expr::POW:
539  // with some .nl files, we seem to get mp::expr::POW even if base or exponent is constant,
540  // so do not rely on kind but better check expr type
541  if( SCIPisExprValue(scip, secondChild) )
542  {
543  SCIP_CALL_THROW( SCIPcreateExprPow(scip, &expr, firstChild, SCIPgetValueExprValue(secondChild), NULL, NULL) );
544  break;
545  }
546 
547  if( SCIPisExprValue(scip, firstChild) && SCIPgetValueExprValue(firstChild) > 0.0 )
548  {
549  // reformulate constant^y as exp(y*log(constant)), if constant > 0.0
550  // if constant < 0, we create an expression and let cons_nonlinear figure out infeasibility somehow
551  SCIP_EXPR* prod;
552 
553  SCIP_Real coef = log(SCIPgetValueExprValue(firstChild)); // log(firstChild)
554  SCIP_CALL_THROW( SCIPcreateExprSum(scip, &prod, 1, &secondChild, &coef, 0.0, NULL, NULL) ); // log(firstChild)*secondChild
555  SCIP_CALL_THROW( SCIPcreateExprExp(scip, &expr, prod, NULL, NULL) ); // expr(log(firstChild)*secondChild)
556 
557  SCIP_CALL_THROW( SCIPreleaseExpr(scip, &prod) );
558  break;
559  }
560 
561  {
562  // reformulate x^y as exp(y*log(x))
563  SCIP_EXPR* prod;
564 
565  assert(SCIPisExprValue(scip, secondChild));
566 
567  SCIP_CALL_THROW( SCIPcreateExprLog(scip, &children[0], firstChild, NULL, NULL) ); // log(firstChild)
568  SCIP_CALL_THROW( SCIPcreateExprProduct(scip, &prod, 2, children, 1.0, NULL, NULL) ); // log(firstChild)*secondChild
569  SCIP_CALL_THROW( SCIPcreateExprExp(scip, &expr, prod, NULL, NULL) ); // expr(log(firstChild)*secondChild)
570 
571  SCIP_CALL_THROW( SCIPreleaseExpr(scip, &prod) );
572  SCIP_CALL_THROW( SCIPreleaseExpr(scip, &children[0]) );
573  break;
574  }
575 
576  default:
577  OnUnhandled(mp::expr::str(kind));
578  return NULL;
579  }
580 
581  // remember that we have to release this expr
582  exprstorelease.push_back(expr);
583 
584  return expr;
585  }
586 
587  /// handler to create a list of terms in a sum
588  ///
589  /// NumericArgHandler is copied around, so it keeps only a pointer (with reference counting) to actual data
591  {
592  public:
593  std::shared_ptr<std::vector<SCIP_EXPR*> > v;
594 
595  /// constructor
597  int num_args ///< number of terms to expect
598  )
599  : v(new std::vector<SCIP_EXPR*>())
600  {
601  v->reserve(num_args);
602  }
603 
604  /// adds term to sum
605  void AddArg(
606  SCIP_EXPR* term ///< term to add
607  )
608  {
609  v->push_back(term);
610  }
611  };
612 
613  /// receive notification of the beginning of a summation
615  int num_args ///< number of terms to expect
616  )
617  {
618  NumericArgHandler h(num_args);
619  return h;
620  }
621 
622  /// receive notification of the end of a summation
624  NumericArgHandler handler ///< handler that handled the sum
625  )
626  {
627  SCIP_EXPR* expr;
628  SCIP_CALL_THROW( SCIPcreateExprSum(scip, &expr, (int)handler.v->size(), handler.v->data(), NULL, 0.0, NULL, NULL) );
629  // remember that we have to release this expr
630  exprstorelease.push_back(expr);
631  return expr;
632  }
633 
634  /// receive notification of an objective type and the nonlinear part of an objective expression
635  void OnObj(
636  int objectiveIndex, ///< index of objective
637  mp::obj::Type type, ///< objective sense
638  SCIP_EXPR* nonlinearExpression ///< nonlinear part of objective function
639  )
640  {
641  if( objectiveIndex >= 1 )
642  OnUnhandled("multiple objective functions");
643 
645 
646  assert(objexpr == NULL);
647 
648  if( nonlinearExpression != NULL && SCIPisExprValue(scip, nonlinearExpression) )
649  {
650  // handle objective constant by adding a fixed variable for it
651  SCIP_VAR* objconstvar;
652  SCIP_Real objconst = SCIPgetValueExprValue(nonlinearExpression);
653 
654  SCIP_CALL_THROW( SCIPcreateVarBasic(scip, &objconstvar, "objconstant", objconst, objconst, 1.0, SCIP_VARTYPE_CONTINUOUS) );
655  SCIP_CALL_THROW( SCIPaddVar(scip, objconstvar) );
656  SCIP_CALL_THROW( SCIPreleaseVar(scip, &objconstvar) );
657  }
658  else
659  {
660  objexpr = nonlinearExpression;
661  }
662  }
663 
664  /// receive notification of an algebraic constraint expression
666  int constraintIndex, ///< index of constraint
667  SCIP_EXPR* expr ///< nonlinear part of constraint
668  )
669  {
670  if( expr != NULL )
671  {
672  SCIP_CALL_THROW( SCIPchgExprNonlinear(scip, probdata->conss[constraintIndex], expr) );
673  }
674  }
675 
676  /// handles linear part of a common expression
677  /// sets up a sum expression, if the linear part isn't empty
679  {
680  private:
681  AMPLProblemHandler& amplph;
682  SCIP_EXPR* commonexpr;
683 
684  public:
685  /// constructor
687  AMPLProblemHandler& amplph_, ///< problem handler
688  int index, ///< index of common expression
689  int num_linear_terms///< number of terms to expect
690  )
691  : amplph(amplph_),
692  commonexpr(NULL)
693  {
694  if( num_linear_terms > 0 )
695  {
696  SCIP_CALL_THROW( SCIPcreateExprSum(amplph.scip, &commonexpr, 0, NULL, NULL, 0.0, NULL, NULL) );
697  amplph.commonexprs[index] = commonexpr;
698  amplph.exprstorelease.push_back(commonexpr);
699  }
700  }
701 
702  /// receives notification of a term in the linear expression
703  void AddTerm(
704  int var_index, ///< AMPL index of variable
705  double coef ///< variable coefficient
706  )
707  {
708  assert(commonexpr != NULL);
709 
710  if( coef == 0.0 )
711  return;
712 
713  if( var_index < (int)amplph.varexprs.size() )
714  {
715  SCIP_CALL_THROW( SCIPappendExprSumExpr(amplph.scip, commonexpr, amplph.varexprs[var_index], coef) );
716  }
717  else
718  {
719  // the index variable is linear (not sure this can happen here)
720  assert(var_index < amplph.probdata->nvars);
721  SCIP_EXPR* varexpr;
722  SCIP_CALL_THROW( SCIPcreateExprVar(amplph.scip, &varexpr, amplph.probdata->vars[var_index], NULL, NULL) );
723  SCIP_CALL_THROW( SCIPappendExprSumExpr(amplph.scip, commonexpr, varexpr, coef) );
724  SCIP_CALL_THROW( SCIPreleaseExpr(amplph.scip, &varexpr) );
725  }
726  }
727  };
728 
729  /// receive notification of the beginning of a common expression (defined variable)
731  int index, ///< index of common expression
732  int num_linear_terms ///< number of terms to expect
733  )
734  {
735  assert(index >= 0);
736  assert(index < (int)commonexprs.size());
737 
738  return LinearExprHandler(*this, index, num_linear_terms);
739  }
740 
741  /// receive notification of the end of a common expression
743  int index, ///< index of common expression
744  SCIP_EXPR* expr, ///< nonlinear part of common expression
745  int /* position */ ///< argument that doesn't seem to have any purpose
746  )
747  {
748  if( commonexprs[index] != NULL )
749  {
750  // add expr, if any, to linear part
751  if( expr != NULL )
752  {
753  SCIP_CALL_THROW( SCIPappendExprSumExpr(scip, commonexprs[index], expr, 1.0) );
754  }
755  }
756  else if( expr != NULL )
757  {
758  commonexprs[index] = expr;
759  }
760  }
761 
762  /// receive notification of a common expression (defined variable) reference
764  int expr_index ///< index of common expression
765  )
766  {
767  assert(expr_index >= 0);
768  assert(expr_index < (int)commonexprs.size());
769  assert(commonexprs[expr_index] != NULL);
770  return commonexprs[expr_index];
771  }
772 
773  /// receive notification of variable bounds
775  int variableIndex, ///< AMPL index of variable
776  double variableLB, ///< variable lower bound
777  double variableUB ///< variable upper bound
778  )
779  {
780  assert(variableIndex >= 0);
781  assert(variableIndex < probdata->nvars);
782 
783  // as far as I see, ampl::mp gives -inf, +inf for no-bounds, which is always beyond SCIPinfinity()
784  // we ignore bounds outside [-scipinfinity,scipinfinity] here
785  // for binary variables, we also ignore bounds outside [0,1]
786  if( variableLB > (SCIPvarGetType(probdata->vars[variableIndex]) == SCIP_VARTYPE_BINARY ? 0.0 : -SCIPinfinity(scip)) )
787  {
788  SCIP_CALL_THROW( SCIPchgVarLbGlobal(scip, probdata->vars[variableIndex], variableLB) );
789  }
790  if( variableUB < (SCIPvarGetType(probdata->vars[variableIndex]) == SCIP_VARTYPE_BINARY ? 1.0 : SCIPinfinity(scip)) )
791  {
792  SCIP_CALL_THROW( SCIPchgVarUbGlobal(scip, probdata->vars[variableIndex], variableUB) );
793  }
794  }
795 
796  /// receive notification of constraint sides
798  int index, ///< AMPL index of constraint
799  double lb, ///< constraint left-hand-side
800  double ub ///< constraint right-hand-side
801  )
802  {
803  assert(index >= 0);
804  assert(index < probdata->nconss);
805 
806  // nonlinear constraints are first
807  if( index < (int)nlconslin.size() )
808  {
809  if( !SCIPisInfinity(scip, -lb) )
810  {
811  SCIP_CALL_THROW( SCIPchgLhsNonlinear(scip, probdata->conss[index], lb) );
812  }
813  if( !SCIPisInfinity(scip, ub) )
814  {
815  SCIP_CALL_THROW( SCIPchgRhsNonlinear(scip, probdata->conss[index], ub) );
816  }
817  }
818  else
819  {
820  if( !SCIPisInfinity(scip, -lb) )
821  {
822  SCIP_CALL_THROW( SCIPchgLhsLinear(scip, probdata->conss[index], lb) );
823  }
824  if( !SCIPisInfinity(scip, ub) )
825  {
826  SCIP_CALL_THROW( SCIPchgRhsLinear(scip, probdata->conss[index], ub) );
827  }
828  }
829  }
830 
831  /// receive notification of the initial value for a variable
833  int var_index, ///< AMPL index of variable
834  double value ///< initial primal value of variable
835  )
836  {
837  if( initsol == NULL )
838  {
839  SCIP_CALL_THROW( SCIPcreateSol(scip, &initsol, NULL) );
840  }
841 
842  SCIP_CALL_THROW( SCIPsetSolVal(scip, initsol, probdata->vars[var_index], value) );
843  }
844 
845  /// receives notification of the initial value for a dual variable
847  int /* con_index */, ///< AMPL index of constraint
848  double /* value */ ///< initial dual value of constraint
849  )
850  {
851  // ignore initial dual value
852  }
853 
854  /// receives notification of Jacobian column sizes
855  ColumnSizeHandler OnColumnSizes()
856  {
857  /// use ColumnSizeHandler from upper class, which does nothing
858  return ColumnSizeHandler();
859  }
860 
861  /// handling of suffices for variable and constraint flags and SOS constraints
862  ///
863  /// regarding SOS in AMPL, see https://ampl.com/faqs/how-can-i-use-the-solvers-special-ordered-sets-feature/
864  /// we pass the .ref suffix as weight to the SOS constraint handlers
865  /// for a SOS2, the weights determine the order of variables in the set
866  template<typename T> class SuffixHandler
867  {
868  private:
869  AMPLProblemHandler& amplph;
870 
871  // type of suffix that is handled, or IGNORE if unsupported suffix
872  enum
873  {
874  IGNORE,
875  CONSINITIAL,
876  CONSSEPARATE,
877  CONSENFORCE,
878  CONSCHECK,
879  CONSPROPAGATE,
880  CONSDYNAMIC,
881  CONSREMOVABLE,
882  VARINITIAL,
883  VARREMOVABLE,
884  VARSOSNO,
885  VARREF,
886  } suffix;
887 
888  public:
889  /// constructor
891  AMPLProblemHandler& amplph_, ///< problem handler
892  fmt::StringRef name, ///< name of suffix
893  mp::suf::Kind kind ///< whether suffix applies to var, cons, etc
894  )
895  : amplph(amplph_),
896  suffix(IGNORE)
897  {
898  switch( kind )
899  {
900  case mp::suf::Kind::CON:
901  if( strncmp(name.data(), "initial", name.size()) == 0 )
902  {
903  suffix = CONSINITIAL;
904  }
905  else if( strncmp(name.data(), "separate", name.size()) == 0 )
906  {
907  suffix = CONSSEPARATE;
908  }
909  else if( strncmp(name.data(), "enforce", name.size()) == 0 )
910  {
911  suffix = CONSENFORCE;
912  }
913  else if( strncmp(name.data(), "check", name.size()) == 0 )
914  {
915  suffix = CONSCHECK;
916  }
917  else if( strncmp(name.data(), "propagate", name.size()) == 0 )
918  {
919  suffix = CONSPROPAGATE;
920  }
921  else if( strncmp(name.data(), "dynamic", name.size()) == 0 )
922  {
923  suffix = CONSDYNAMIC;
924  }
925  else if( strncmp(name.data(), "removable", name.size()) == 0 )
926  {
927  suffix = CONSREMOVABLE;
928  }
929  else
930  {
931  SCIPverbMessage(amplph.scip, SCIP_VERBLEVEL_HIGH, NULL, "Unknown constraint suffix <%.*s>. Ignoring.\n", (int)name.size(), name.data());
932  }
933  break;
934 
935  case mp::suf::Kind::VAR:
936  {
937  if( strncmp(name.data(), "initial", name.size()) == 0 )
938  {
939  suffix = VARINITIAL;
940  }
941  else if( strncmp(name.data(), "removable", name.size()) == 0 )
942  {
943  suffix = VARREMOVABLE;
944  }
945  else if( strncmp(name.data(), "sosno", name.size()) == 0 )
946  {
947  // SOS membership
948  suffix = VARSOSNO;
949  }
950  else if( strncmp(name.data(), "ref", name.size()) == 0 )
951  {
952  // SOS weights
953  suffix = VARREF;
954  amplph.sosweights.resize(amplph.probdata->nvars, 0);
955  }
956  else
957  {
958  SCIPverbMessage(amplph.scip, SCIP_VERBLEVEL_HIGH, NULL, "Unknown variable suffix <%.*s>. Ignoring.\n", (int)name.size(), name.data());
959  }
960  break;
961 
962  case mp::suf::Kind::OBJ:
963  SCIPverbMessage(amplph.scip, SCIP_VERBLEVEL_HIGH, NULL, "Unknown objective suffix <%.*s>. Ignoring.\n", (int)name.size(), name.data());
964  break;
965 
967  SCIPverbMessage(amplph.scip, SCIP_VERBLEVEL_HIGH, NULL, "Unknown problem suffix <%.*s>. Ignoring.\n", (int)name.size(), name.data());
968  break;
969  }
970  }
971  }
972 
973  void SetValue(
974  int index, ///< index of variable, constraint, etc
975  T value ///< value of suffix
976  )
977  {
978  assert(index >= 0);
979  switch( suffix )
980  {
981  case IGNORE :
982  return;
983 
984  case CONSINITIAL:
985  SCIP_CALL_THROW( SCIPsetConsInitial(amplph.scip, amplph.probdata->conss[index], value == 1) );
986  break;
987 
988  case CONSSEPARATE:
989  SCIP_CALL_THROW( SCIPsetConsSeparated(amplph.scip, amplph.probdata->conss[index], value == 1) );
990  break;
991 
992  case CONSENFORCE:
993  SCIP_CALL_THROW( SCIPsetConsEnforced(amplph.scip, amplph.probdata->conss[index], value == 1) );
994  break;
995 
996  case CONSCHECK:
997  SCIP_CALL_THROW( SCIPsetConsChecked(amplph.scip, amplph.probdata->conss[index], value == 1) );
998  break;
999 
1000  case CONSPROPAGATE:
1001  SCIP_CALL_THROW( SCIPsetConsPropagated(amplph.scip, amplph.probdata->conss[index], value == 1) );
1002  break;
1003 
1004  case CONSDYNAMIC:
1005  SCIP_CALL_THROW( SCIPsetConsDynamic(amplph.scip, amplph.probdata->conss[index], value == 1) );
1006  break;
1007 
1008  case CONSREMOVABLE:
1009  SCIP_CALL_THROW( SCIPsetConsRemovable(amplph.scip, amplph.probdata->conss[index], value == 1) );
1010  break;
1011 
1012  case VARINITIAL:
1013  assert(index < amplph.probdata->nvars);
1014  SCIP_CALL_THROW( SCIPvarSetInitial(amplph.probdata->vars[index], value == 1) );
1015  break;
1016 
1017  case VARREMOVABLE:
1018  assert(index < amplph.probdata->nvars);
1019  SCIP_CALL_THROW( SCIPvarSetRemovable(amplph.probdata->vars[index], value == 1) );
1020  break;
1021 
1022  case VARSOSNO:
1023  // remember that variable index belongs to SOS identified by value
1024  amplph.sosvars[(int)value].push_back(index);
1025  break;
1026 
1027  case VARREF:
1028  // remember that variable index has weight value
1029  amplph.sosweights[index] = (int)value;
1030  break;
1031  }
1032  }
1033  };
1034 
1036  /// receive notification of an integer suffix
1037  IntSuffixHandler OnIntSuffix(
1038  fmt::StringRef name, ///< suffix name, not null-terminated
1039  mp::suf::Kind kind, ///< suffix kind
1040  int /*num_values*/ ///< number of values to expect
1041  )
1042  {
1043  return IntSuffixHandler(*this, name, kind);
1044  }
1045 
1047  /// receive notification of a double suffix
1048  DblSuffixHandler OnDblSuffix(
1049  fmt::StringRef name, ///< suffix name, not null-terminated
1050  mp::suf::Kind kind, ///< suffix kind
1051  int /*num_values*/ ///< number of values to expect
1052  )
1053  {
1054  return DblSuffixHandler(*this, name, kind);
1055  }
1056 
1057  /// handles receiving the linear part of an objective or constraint
1058  ///
1059  /// for objective, set the objective-coefficient of the variable
1060  /// for linear constraints, add to the constraint
1061  /// for nonlinear constraints, add to nlconslin vector; adding to constraint later
1063  {
1064  private:
1065  AMPLProblemHandler& amplph;
1066  int constraintIndex;
1067 
1068  public:
1069  // constructor for constraint
1071  AMPLProblemHandler& amplph_, ///< problem handler
1072  int constraintIndex_///< constraint index
1073  )
1074  : amplph(amplph_),
1075  constraintIndex(constraintIndex_)
1076  {
1077  assert(constraintIndex_ >= 0);
1078  assert(constraintIndex_ < amplph.probdata->nconss);
1079  }
1080 
1081  // constructor for linear objective
1083  AMPLProblemHandler& amplph_ ///< problem handler
1084  )
1085  : amplph(amplph_),
1086  constraintIndex(-1)
1087  { }
1088 
1089  void AddTerm(
1090  int variableIndex, ///< AMPL index of variable
1091  double coefficient ///< coefficient of variable
1092  )
1093  {
1094  assert(variableIndex >= 0);
1095  assert(variableIndex < amplph.probdata->nvars);
1096 
1097  if( coefficient == 0.0 )
1098  return;
1099 
1100  if( constraintIndex < 0 )
1101  {
1102  SCIP_CALL_THROW( SCIPchgVarObj(amplph.scip, amplph.probdata->vars[variableIndex], coefficient) );
1103  }
1104  else if( constraintIndex < (int)amplph.nlconslin.size() )
1105  {
1106  amplph.nlconslin[constraintIndex].push_back(std::pair<SCIP_Real, SCIP_VAR*>(coefficient, amplph.probdata->vars[variableIndex]));
1107  }
1108  else
1109  {
1110  SCIP_CONS* lincons = amplph.probdata->conss[constraintIndex];
1111  SCIP_CALL_THROW( SCIPaddCoefLinear(amplph.scip, lincons, amplph.probdata->vars[variableIndex], coefficient) );
1112  }
1113  }
1114  };
1115 
1117 
1118  /// receive notification of the linear part of an objective
1120  int objectiveIndex, ///< index of objective
1121  int /* numLinearTerms *////< number of terms to expect
1122  )
1123  {
1124  if( objectiveIndex >= 1 )
1125  OnUnhandled("multiple objective functions");
1126 
1127  return LinearObjHandler(*this);
1128  }
1129 
1131 
1132  /// receive notification of the linear part of a constraint
1133  LinearConHandler OnLinearConExpr(
1134  int constraintIndex, ///< index of constraint
1135  int /* numLinearTerms *////< number of terms to expect
1136  )
1137  {
1138  return LinearConHandler(*this, constraintIndex);
1139  }
1140 
1141  /// receive notification of the end of the input
1142  ///
1143  /// - setup all nonlinear constraints and add them to SCIP
1144  /// - add linear constraints to SCIP (should be after nonlinear ones to respect order in .nl file)
1145  /// - add initial solution, if initial values were given
1146  void EndInput()
1147  {
1148  // turn nonlinear objective into constraint
1149  // min f(x) -> min z s.t. f(x) - z <= 0
1150  // max f(x) -> max z s.t. 0 <= f(x) - z
1151  if( objexpr != NULL )
1152  {
1153  SCIP_CONS* objcons;
1154  SCIP_VAR* objvar;
1155 
1156  SCIP_CALL_THROW( SCIPcreateVarBasic(scip, &objvar, "nlobjvar", -SCIPinfinity(scip), SCIPinfinity(scip), 1.0, SCIP_VARTYPE_CONTINUOUS) );
1157  SCIP_CALL_THROW( SCIPaddVar(scip, objvar) );
1158 
1159  SCIP_CALL_THROW( SCIPcreateConsBasicNonlinear(scip, &objcons, "objcons", objexpr,
1160  SCIPgetObjsense(scip) == SCIP_OBJSENSE_MINIMIZE ? -SCIPinfinity(scip) : 0.0,
1161  SCIPgetObjsense(scip) == SCIP_OBJSENSE_MAXIMIZE ? SCIPinfinity(scip) : 0.0) );
1162  SCIP_CALL_THROW( SCIPaddLinearVarNonlinear(scip, objcons, objvar, -1.0) );
1163  SCIP_CALL_THROW( SCIPaddCons(scip, objcons) );
1164 
1165  SCIP_CALL_THROW( SCIPreleaseCons(scip, &objcons) );
1166  SCIP_CALL_THROW( SCIPreleaseVar(scip, &objvar) );
1167  }
1168 
1169  // add linear terms to expressions of nonlinear constraints (should be ok to do this one-by-one for now)
1170  for( size_t i = 0; i < nlconslin.size(); ++i )
1171  {
1172  for( size_t j = 0; j < nlconslin[i].size(); ++j )
1173  {
1174  SCIP_CALL_THROW( SCIPaddLinearVarNonlinear(scip, probdata->conss[i], nlconslin[i][j].second, nlconslin[i][j].first) );
1175  }
1176  }
1177 
1178  // add constraints
1179  for( int i = 0; i < probdata->nconss; ++i )
1180  {
1181  SCIP_CALL_THROW( SCIPaddCons(scip, probdata->conss[i]) );
1182  }
1183 
1184  // add SOS constraints
1185  std::vector<SCIP_VAR*> setvars; // variables in one SOS
1186  std::vector<SCIP_Real> setweights; // weights for one SOS
1187  if( !sosvars.empty() )
1188  {
1189  setvars.resize(probdata->nvars);
1190  probdata->islp = false;
1191  }
1192  if( !sosweights.empty() )
1193  setweights.resize(probdata->nvars);
1194  for( std::map<int, std::vector<int> >::iterator sosit(sosvars.begin()); sosit != sosvars.end(); ++sosit )
1195  {
1196  assert(sosit->first != 0);
1197  assert(!sosit->second.empty());
1198 
1199  // a negative SOS identifier means SOS2
1200  bool issos2 = sosit->first < 0;
1201 
1202  if( issos2 && sosweights.empty() )
1203  {
1204  // if no .ref suffix was given for a SOS2 constraint, then we consider this as an error
1205  // since the weights determine the order
1206  // for a SOS1, the weights only specify branching preference, so can treat them as optional
1207  OnUnhandled("SOS2 requires variable .ref suffix");
1208  }
1209 
1210  for( size_t i = 0; i < sosit->second.size(); ++i )
1211  {
1212  int varidx = sosit->second[i];
1213  setvars[i] = probdata->vars[varidx];
1214 
1215  if( issos2 && sosweights[varidx] == 0 )
1216  // 0 is the default if no ref was given for a variable; we don't allow this for SOS2
1217  OnUnhandled("Missing .ref value for SOS2 variable");
1218  if( !sosweights.empty() )
1219  setweights[i] = (SCIP_Real)sosweights[varidx];
1220  }
1221 
1222  SCIP_CONS* cons;
1223  char name[20];
1224  if( !issos2 )
1225  {
1226  (void) SCIPsnprintf(name, 20, "sos1_%d", sosit->first);
1227  SCIP_CALL_THROW( SCIPcreateConsBasicSOS1(scip, &cons, name, sosit->second.size(), setvars.data(), setweights.empty() ? NULL : setweights.data()) );
1228  }
1229  else
1230  {
1231  (void) SCIPsnprintf(name, 20, "sos2_%d", -sosit->first);
1232  SCIP_CALL_THROW( SCIPcreateConsBasicSOS2(scip, &cons, name, sosit->second.size(), setvars.data(), setweights.data()) );
1233  }
1234  SCIP_CALL_THROW( SCIPaddCons(scip, cons) );
1235  SCIP_CALL_THROW( SCIPreleaseCons(scip, &cons) );
1236  }
1237 
1238  // add initial solution
1239  if( initsol != NULL )
1240  {
1241  SCIP_Bool stored;
1242  SCIP_CALL_THROW( SCIPaddSolFree(scip, &initsol, &stored) );
1243  }
1244 
1245  // release expressions
1246  SCIP_CALL_THROW( cleanup() );
1247  }
1248 
1249  /// releases expressions and linear constraints from data
1250  ///
1251  /// should be called if there was an error while reading the .nl file
1252  /// this is not in the destructor, because we want to return SCIP_RETCODE
1254  {
1255  // release initial sol (in case EndInput() wasn't called)
1256  if( initsol != NULL )
1257  {
1258  SCIP_CALL( SCIPfreeSol(scip, &initsol) );
1259  }
1260 
1261  // release created expressions (they should all be used in other expressions or constraints now)
1262  while( !exprstorelease.empty() )
1263  {
1264  SCIP_CALL( SCIPreleaseExpr(scip, &exprstorelease.back()) );
1265  exprstorelease.pop_back();
1266  }
1267 
1268  // release variable expressions (they should all be used in other expressions or constraints now)
1269  while( !varexprs.empty() )
1270  {
1271  SCIP_CALL( SCIPreleaseExpr(scip, &varexprs.back()) );
1272  varexprs.pop_back();
1273  }
1274 
1275  return SCIP_OKAY;
1276  }
1277 };
1278 
1279 
1280 /*
1281  * Callback methods of probdata
1282  */
1283 
1284 /** frees user data of original problem (called when the original problem is freed) */
1285 static
1286 SCIP_DECL_PROBDELORIG(probdataDelOrigNl)
1287 {
1288  int i;
1289 
1290  assert((*probdata)->vars != NULL || (*probdata)->nvars == 0);
1291  assert((*probdata)->conss != NULL || (*probdata)->conss == 0);
1292 
1293  for( i = 0; i < (*probdata)->nconss; ++i )
1294  {
1295  SCIP_CALL( SCIPreleaseCons(scip, &(*probdata)->conss[i]) );
1296  }
1297  SCIPfreeBlockMemoryArrayNull(scip, &(*probdata)->conss, (*probdata)->nconss);
1298 
1299  for( i = 0; i < (*probdata)->nvars; ++i )
1300  {
1301  SCIP_CALL( SCIPreleaseVar(scip, &(*probdata)->vars[i]) );
1302  }
1303  SCIPfreeBlockMemoryArrayNull(scip, &(*probdata)->vars, (*probdata)->nvars);
1304 
1305  SCIPfreeBlockMemoryArrayNull(scip, &(*probdata)->filenamestub, (*probdata)->filenamestublen+5);
1306 
1307  SCIPfreeMemory(scip, probdata);
1308 
1309  return SCIP_OKAY;
1310 }
1311 
1312 /*
1313  * Callback methods of reader
1314  */
1315 
1316 /** copy method for reader plugins (called when SCIP copies plugins) */
1317 static
1319 { /*lint --e{715}*/
1320  assert(scip != NULL);
1321 
1323 
1324  return SCIP_OKAY;
1325 }
1326 
1327 /** problem reading method of reader */
1328 static
1330 { /*lint --e{715}*/
1331  assert(scip != NULL);
1332  assert(reader != NULL);
1333  assert(filename != NULL);
1334  assert(result != NULL);
1335 
1336  try
1337  {
1338  // try to read the .nl file and setup SCIP problem
1339  AMPLProblemHandler handler(scip, filename);
1340  try
1341  {
1342  mp::ReadNLFile(filename, handler);
1343  }
1344  catch( const mp::UnsupportedError& e )
1345  {
1346  SCIPerrorMessage("unsupported construct in AMPL .nl file %s: %s\n", filename, e.what());
1347 
1348  SCIP_CALL( handler.cleanup() );
1349 
1350  return SCIP_READERROR;
1351  }
1352  catch( const mp::Error& e )
1353  {
1354  // some other error from ampl/mp, maybe invalid .nl file
1355  SCIPerrorMessage("%s\n", e.what());
1356 
1357  SCIP_CALL( handler.cleanup() );
1358 
1359  return SCIP_READERROR;
1360  }
1361  catch( const fmt::SystemError& e )
1362  {
1363  // probably a file open error, probably because file not found
1364  SCIPerrorMessage("%s\n", e.what());
1365 
1366  SCIP_CALL( handler.cleanup() );
1367 
1368  return SCIP_NOFILE;
1369  }
1370  catch( const std::bad_alloc& e )
1371  {
1372  SCIPerrorMessage("Out of memory: %s\n", e.what());
1373 
1374  SCIP_CALL( handler.cleanup() );
1375 
1376  return SCIP_NOMEMORY;
1377  }
1378  }
1379  catch( const std::exception& e )
1380  {
1381  SCIPerrorMessage("%s\n", e.what());
1382  return SCIP_ERROR;
1383  }
1384 
1385  *result = SCIP_SUCCESS;
1386 
1387  return SCIP_OKAY;
1388 }
1389 
1390 /*
1391  * reader specific interface methods
1392  */
1393 
1394 /** includes the AMPL .nl file reader in SCIP */
1396  SCIP* scip /**< SCIP data structure */
1397 )
1398 {
1399  SCIP_READER* reader = NULL;
1400 
1401  /* include reader */
1403  assert(reader != NULL);
1404 
1405  /* set non fundamental callbacks via setter functions */
1406  SCIP_CALL( SCIPsetReaderCopy(scip, reader, readerCopyNl) );
1407  SCIP_CALL( SCIPsetReaderRead(scip, reader, readerReadNl) );
1408 
1409  SCIP_CALL( SCIPincludeExternalCodeInformation(scip, "AMPL/MP 4e2d45c4", "AMPL .nl file reader library (github.com/ampl/mp)") );
1410 
1411  return SCIP_OKAY;
1412 }
1413 
1414 /** writes AMPL solution file
1415  *
1416  * problem must have been read with .nl reader
1417  */
1419  SCIP* scip /**< SCIP data structure */
1420  )
1421 {
1422  SCIP_PROBDATA* probdata;
1423 
1424  assert(scip != NULL);
1425 
1426  probdata = SCIPgetProbData(scip);
1427  if( probdata == NULL )
1428  {
1429  SCIPerrorMessage("No AMPL nl file read. Cannot write AMPL solution.\n");
1430  return SCIP_ERROR;
1431  }
1432 
1433  probdata->filenamestub[probdata->filenamestublen] = '.';
1434  probdata->filenamestub[probdata->filenamestublen+1] = 's';
1435  probdata->filenamestub[probdata->filenamestublen+2] = 'o';
1436  probdata->filenamestub[probdata->filenamestublen+3] = 'l';
1437  probdata->filenamestub[probdata->filenamestublen+4] = '\0';
1438 
1439  FILE* solfile = fopen(probdata->filenamestub, "w");
1440  if( solfile == NULL )
1441  {
1442  SCIPerrorMessage("could not open file <%s> for writing\n", probdata->filenamestub);
1443  probdata->filenamestub[probdata->filenamestublen] = '\0';
1444 
1445  return SCIP_WRITEERROR;
1446  }
1447  probdata->filenamestub[probdata->filenamestublen] = '\0';
1448 
1449  // see ampl/mp:sol.h:WriteSolFile() (seems buggy, https://github.com/ampl/mp/issues/135) and asl/writesol.c for solution file format
1450  SCIP_CALL( SCIPprintStatus(scip, solfile) );
1451  SCIPinfoMessage(scip, solfile, "\n\n");
1452 
1453  SCIPinfoMessage(scip, solfile, "Options\n%d\n", probdata->namplopts);
1454  for( int i = 0; i < probdata->namplopts; ++i )
1455  SCIPinfoMessage(scip, solfile, "%d\n", probdata->amplopts[i]);
1456 
1457  bool haveprimal = SCIPgetBestSol(scip) != NULL;
1458  bool havedual = probdata->islp && SCIPgetStage(scip) == SCIP_STAGE_SOLVED && !SCIPhasPerformedPresolve(scip);
1459 
1460  SCIPinfoMessage(scip, solfile, "%d\n%d\n", probdata->nconss, havedual ? probdata->nconss : 0);
1461  SCIPinfoMessage(scip, solfile, "%d\n%d\n", probdata->nvars, haveprimal ? probdata->nvars : 0);
1462 
1463  SCIPdebug( SCIPprintSol(scip, SCIPgetBestSol(scip), NULL, TRUE); )
1464 
1465  if( havedual )
1466  for( int c = 0; c < probdata->nconss; ++c )
1467  {
1468  SCIP_CONS* transcons;
1469  SCIP_Real dualval;
1470 
1471  /* dual solution is created by LP solver and therefore only available for linear constraints */
1472  SCIP_CALL( SCIPgetTransformedCons(scip, probdata->conss[c], &transcons) );
1473  assert(transcons == NULL || strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(transcons)), "linear") == 0);
1474 
1475  if( transcons == NULL )
1476  dualval = 0.0;
1477  else if( SCIPgetObjsense(scip) == SCIP_OBJSENSE_MINIMIZE )
1478  dualval = SCIPgetDualsolLinear(scip, transcons);
1479  else
1480  dualval = -SCIPgetDualsolLinear(scip, transcons);
1481  assert(dualval != SCIP_INVALID);
1482 
1483  SCIPinfoMessage(scip, solfile, "%.17g\n", dualval);
1484  }
1485 
1486  if( haveprimal )
1487  for( int i = 0; i < probdata->nvars; ++i )
1488  SCIPinfoMessage(scip, solfile, "%.17g\n", SCIPgetSolVal(scip, SCIPgetBestSol(scip), probdata->vars[i]));
1489 
1490  /* AMPL solve status codes are at http://www.ampl.com/NEW/statuses.html
1491  * number string interpretation
1492  * 0 - 99 solved optimal solution found
1493  * 100 - 199 solved? optimal solution indicated, but error likely
1494  * 200 - 299 infeasible constraints cannot be satisfied
1495  * 300 - 399 unbounded objective can be improved without limit
1496  * 400 - 499 limit stopped by a limit that you set (such as on iterations)
1497  * 500 - 599 failure stopped by an error condition in the solver routines
1498  */
1499  int solve_result_num;
1500  switch( SCIPgetStatus(scip) )
1501  {
1502  case SCIP_STATUS_UNKNOWN:
1503  solve_result_num = 500;
1504  break;
1506  solve_result_num = 450;
1507  break;
1508  case SCIP_STATUS_NODELIMIT:
1509  solve_result_num = 400;
1510  break;
1512  solve_result_num = 401;
1513  break;
1515  solve_result_num = 402;
1516  break;
1517  case SCIP_STATUS_TIMELIMIT:
1518  solve_result_num = 403;
1519  break;
1520  case SCIP_STATUS_MEMLIMIT:
1521  solve_result_num = 404;
1522  break;
1523  case SCIP_STATUS_GAPLIMIT:
1524  solve_result_num = 405;
1525  break;
1526  case SCIP_STATUS_SOLLIMIT:
1527  solve_result_num = 406;
1528  break;
1530  solve_result_num = 407;
1531  break;
1532  case SCIP_STATUS_OPTIMAL:
1533  solve_result_num = 0;
1534  break;
1536  solve_result_num = 200;
1537  break;
1538  case SCIP_STATUS_UNBOUNDED:
1539  solve_result_num = 300;
1540  break;
1541  case SCIP_STATUS_INFORUNBD:
1542  solve_result_num = 299;
1543  break;
1544  default:
1545  /* solve_result_num = 500; */
1546  SCIPerrorMessage("invalid status code <%d>\n", SCIPgetStatus(scip));
1547  (void) fclose(solfile);
1548  return SCIP_INVALIDDATA;
1549  }
1550  SCIPinfoMessage(scip, solfile, "objno 0 %d\n", solve_result_num);
1551 
1552  if( fclose(solfile) != 0 )
1553  {
1554  SCIPerrorMessage("could not close solution file after writing\n");
1555  return SCIP_WRITEERROR;
1556  }
1557 
1558  return SCIP_OKAY;
1559 }
static SCIP_DECL_READERCOPY(readerCopyNl)
Definition: reader_nl.cpp:1318
SCIP_RETCODE SCIPchgVarLbGlobal(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip_var.c:4943
#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:3175
SCIP_EXPR * OnCommonExprRef(int expr_index)
receive notification of a common expression (defined variable) reference
Definition: reader_nl.cpp:763
LinearExprHandler(AMPLProblemHandler &amplph_, int index, int num_linear_terms)
constructor
Definition: reader_nl.cpp:686
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:365
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:635
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:1048
void OnConBounds(int index, double lb, double ub)
receive notification of constraint sides
Definition: reader_nl.cpp:797
IntSuffixHandler OnIntSuffix(fmt::StringRef name, mp::suf::Kind kind, int)
receive notification of an integer suffix
Definition: reader_nl.cpp:1037
#define SCIP_MAXSTRLEN
Definition: def.h:302
SCIP_RETCODE SCIPaddSolFree(SCIP *scip, SCIP_SOL **sol, SCIP_Bool *stored)
Definition: scip_sol.c:3025
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:197
void AddTerm(int var_index, double coef)
receives notification of a term in the linear expression
Definition: reader_nl.cpp:703
SCIP_RETCODE SCIPsetConsPropagated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool propagate)
Definition: scip_cons.c:1317
static SCIP_DECL_READERREAD(readerReadNl)
Definition: reader_nl.cpp:1329
LinearPartHandler OnLinearObjExpr(int objectiveIndex, int)
receive notification of the linear part of an objective
Definition: reader_nl.cpp:1119
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip_var.c:1248
LinearPartHandler LinearObjHandler
Definition: reader_nl.cpp:1116
SCIP_Real SCIPinfinity(SCIP *scip)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10788
SCIP_RETCODE SCIPchgRhsNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_Real rhs)
#define TRUE
Definition: def.h:95
#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:774
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:846
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:1116
SCIP_RETCODE SCIPchgVarUbGlobal(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip_var.c:5032
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:1079
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:1395
void EndCommonExpr(int index, SCIP_EXPR *expr, int)
receive notification of the end of a common expression
Definition: reader_nl.cpp:742
SCIP_RETCODE SCIPsetConsSeparated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool separate)
Definition: scip_cons.c:1242
#define READER_DESC
Definition: reader_nl.cpp:67
#define READER_NAME
Definition: reader_nl.cpp:66
SCIP_RETCODE SCIPsetObjsense(SCIP *scip, SCIP_OBJSENSE objsense)
Definition: scip_prob.c:1250
void OnHeader(const mp::NLHeader &h)
Definition: reader_nl.cpp:276
SCIP_RETCODE SCIPsetConsRemovable(SCIP *scip, SCIP_CONS *cons, SCIP_Bool removable)
Definition: scip_cons.c:1420
SuffixHandler< SCIP_Real > DblSuffixHandler
Definition: reader_nl.cpp:1046
#define READER_EXTENSION
Definition: reader_nl.cpp:68
#define SCIPerrorMessage
Definition: pub_message.h:64
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4182
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2778
SCIP_Real SCIPgetDualsolLinear(SCIP *scip, SCIP_CONS *cons)
LinearPartHandler(AMPLProblemHandler &amplph_)
Definition: reader_nl.cpp:1082
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:483
ColumnSizeHandler OnColumnSizes()
receives notification of Jacobian column sizes
Definition: reader_nl.cpp:855
SCIP_RETCODE SCIPsetConsChecked(SCIP *scip, SCIP_CONS *cons, SCIP_Bool check)
Definition: scip_cons.c:1292
SCIP_RETCODE SCIPsetConsDynamic(SCIP *scip, SCIP_CONS *cons, SCIP_Bool dynamic)
Definition: scip_cons.c:1395
SCIP_Bool SCIPisExprValue(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1432
void SetValue(int index, T value)
Definition: reader_nl.cpp:973
#define NULL
Definition: lpi_spx1.cpp:164
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:1089
#define SCIP_CALL(x)
Definition: def.h:394
SuffixHandler< int > IntSuffixHandler
Definition: reader_nl.cpp:1035
SCIP_RETCODE SCIPprintStatus(SCIP *scip, FILE *file)
Definition: scip_general.c:506
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
SCIP_RETCODE SCIPgetTransformedCons(SCIP *scip, SCIP_CONS *cons, SCIP_CONS **transcons)
Definition: scip_cons.c:1620
#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:2466
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:4513
SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
Definition: scip_sol.c:1221
logarithm expression handler
#define SCIP_Bool
Definition: def.h:93
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:665
SCIP_RETCODE SCIPreleaseExpr(SCIP *scip, SCIP_EXPR **expr)
Definition: scip_expr.c:1407
constraint handler for nonlinear constraints specified by algebraic expressions
unsigned short Type
Definition: cons_xor.c:130
struct Problem PROBLEM
handler for sin expressions
#define MAX(x, y)
Definition: tclique_def.h:92
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8110
SCIP_RETCODE SCIPchgLhsNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_Real lhs)
SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip_sol.c:985
LinearExprHandler BeginCommonExpr(int index, int num_linear_terms)
receive notification of the beginning of a common expression (defined variable)
Definition: reader_nl.cpp:730
static SCIP_DECL_PROBDELORIG(probdataDelOrigNl)
Definition: reader_nl.cpp:1286
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:136
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:614
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:10531
constant value expression handler
SCIP_RETCODE SCIPwriteSolutionNl(SCIP *scip)
Definition: reader_nl.cpp:1418
SuffixHandler(AMPLProblemHandler &amplph_, fmt::StringRef name, mp::suf::Kind kind)
constructor
Definition: reader_nl.cpp:890
AMPL .nl file reader.
SCIP_EXPR * EndSum(NumericArgHandler handler)
receive notification of the end of a summation
Definition: reader_nl.cpp:623
void OnInitialValue(int var_index, double value)
receive notification of the initial value for a variable
Definition: reader_nl.cpp:832
product expression handler
#define SCIPfreeMemory(scip, ptr)
Definition: scip_mem.h:78
SCIP_RETCODE cleanup()
Definition: reader_nl.cpp:1253
SCIP_SOL * SCIPgetBestSol(SCIP *scip)
Definition: scip_sol.c:2313
struct SCIP_ProbData SCIP_PROBDATA
Definition: type_prob.h:53
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_prob.c:1676
SCIP_PROBDATA * SCIPgetProbData(SCIP *scip)
Definition: scip_prob.c:972
SCIP_RETCODE SCIPsetConsEnforced(SCIP *scip, SCIP_CONS *cons, SCIP_Bool enforce)
Definition: scip_cons.c:1267
LinearPartHandler(AMPLProblemHandler &amplph_, int constraintIndex_)
Definition: reader_nl.cpp:1070
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:1119
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:421
#define SCIP_CALL_THROW(x)
Definition: reader_nl.cpp:72
SCIP_EXPR * OnUnary(mp::expr::Kind kind, SCIP_EXPR *child)
receive notification of a unary expression
Definition: reader_nl.cpp:433
LinearPartHandler LinearConHandler
Definition: reader_nl.cpp:1130
#define SCIP_Real
Definition: def.h:186
implementation of AMPL/MPs NLHandler that constructs a SCIP problem while a .nl file is read ...
Definition: reader_nl.cpp:111
LinearConHandler OnLinearConExpr(int constraintIndex, int)
receive notification of the linear part of a constraint
Definition: reader_nl.cpp:1133
void AddArg(SCIP_EXPR *term)
adds term to sum
Definition: reader_nl.cpp:605
constraint handler for SOS type 1 constraints
SCIP_RETCODE SCIPvarSetInitial(SCIP_VAR *var, SCIP_Bool initial)
Definition: var.c:17351
#define SCIP_INVALID
Definition: def.h:206
std::shared_ptr< std::vector< SCIP_EXPR * > > v
Definition: reader_nl.cpp:593
NumericArgHandler(int num_args)
constructor
Definition: reader_nl.cpp:596
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:17429
SCIP_OBJSENSE SCIPgetObjsense(SCIP *scip)
Definition: scip_prob.c:1233
SCIP_EXPR * OnNumber(double value)
receive notification of a number in a nonlinear expression
Definition: reader_nl.cpp:406
SCIP_RETCODE SCIPincludeExternalCodeInformation(SCIP *scip, const char *name, const char *description)
Definition: scip_general.c:713
sum expression handler
enum SCIP_Vartype SCIP_VARTYPE
Definition: type_var.h:69
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:674
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:111
SCIP_EXPR * OnBinary(mp::expr::Kind kind, SCIP_EXPR *firstChild, SCIP_EXPR *secondChild)
receive notification of a binary expression
Definition: reader_nl.cpp:501
SCIP_RETCODE SCIPvarSetRemovable(SCIP_VAR *var, SCIP_Bool removable)
Definition: var.c:17367
#define SCIPABORT()
Definition: def.h:366
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1361
exponential expression handler
SCIP_RETCODE SCIPcreateSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip_sol.c:328
SCIP_RETCODE SCIPsetConsInitial(SCIP *scip, SCIP_CONS *cons, SCIP_Bool initial)
Definition: scip_cons.c:1217
SCIP_RETCODE SCIPprintSol(SCIP *scip, SCIP_SOL *sol, FILE *file, SCIP_Bool printzeros)
Definition: scip_sol.c:1775