readnl.cpp
Go to the documentation of this file.
1 /* $Id: readnl.cpp 1271 2019-02-23 17:23:59Z stefan $
2  *
3  * Name: readnl.cpp
4  * Author: Pietro Belotti
5  * Purpose: define a reader for .nl files. Adapted from ampl2ev3 by L. Liberti and S. Galli
6  *
7  * (C) Carnegie-Mellon University, 2006-10.
8  * This file is licensed under the Eclipse Public License (EPL)
9  */
10 
11 #include "asl.h"
12 
13 // Added to avoid compiler issues with gcc 6.2.1 --- see https://github.com/JuliaOpt/CoinOptServices.jl/issues/27#issuecomment-290960312
14 #undef strtod
15 
16 #include "nlp.h"
17 #include "getstub.h"
18 #include "opcode.hd"
19 
20 #include "CoinHelperFunctions.hpp"
21 #include "CoinTime.hpp"
22 
23 #include "CouenneProblem.hpp"
24 
25 #if defined HAVE_CSTDINT
26 #include "cstdint"
27 #elif defined HAVE_STDINT_H
28 #include "stdint.h"
29 #endif
30 
31 #include "CouenneTypes.hpp"
32 #include "CouenneExprSum.hpp"
33 #include "CouenneExprOpp.hpp"
34 #include "CouenneExprMul.hpp"
35 #include "CouenneExprSub.hpp"
36 #include "CouenneExprClone.hpp"
37 #include "CouenneExprGroup.hpp"
38 
39 #define OBJ_DE ((const ASL_fg *) asl) -> I.obj_de_
40 #define VAR_E ((const ASL_fg *) asl) -> I.var_e_
41 #define CON_DE ((const ASL_fg *) asl) -> I.con_de_
42 #define OBJ_sense ((const ASL_fg *) asl) -> i.objtype_
43 
44 #define THRESHOLD_OUTPUT_READNL 10000
45 
46 //#define DEBUG
47 
48 using namespace Couenne;
49 
50 // check if an expression is a null pointer or equals zero
51 inline bool is_expr_zero (expr* e)
52 {return ((e==NULL) || ((((Intcast (e->op)) == OPNUM) &&
53  (fabs (((expr_n *)e) -> v) < COUENNE_EPS)
54  // && (fabs (e -> dL) < COUENNE_EPS)
55  // *** CHECK THIS! dL is the derivative
56  )));}
57 
58 void createCommonExpr (CouenneProblem *p, const ASL *asl, int i, int which);
59 
60 // Reads a MINLP from an AMPL .nl file through the ASL methods
61 int CouenneProblem::readnl (const ASL *asl) {
62 
63  problemName_ = filename;
64 
65  // number of defined variables (aka common expressions)
66  ndefined_ = como + comc + comb + como1 + comc1;
67 
68  // see "hooking your solver to AMPL", by David M. Gay, tables 3, 4, and 5
69 
70  // nonlinear in both objectives and constraints
71  if (nlvb >= 0) {
72  for (int i = 0; i < nlvb - nlvbi; i++) addVariable (false, &domain_);
73  for (int i = 0; i < nlvbi; i++) addVariable (true, &domain_);
74  }
75 
76  // nonlinear in either objectives or constraints
77  if (nlvo > nlvc) {
78  for (int i = 0; i < nlvc - (nlvb + nlvci); i++) addVariable (false, &domain_);
79  for (int i = 0; i < nlvci; i++) addVariable (true, &domain_);
80  for (int i = 0; i < nlvo - (nlvc + nlvoi); i++) addVariable (false, &domain_);
81  for (int i = 0; i < nlvoi; i++) addVariable (true, &domain_);
82  } else {
83  for (int i = 0; i < nlvo - (nlvb + nlvoi); i++) addVariable (false, &domain_);
84  for (int i = 0; i < nlvoi; i++) addVariable (true, &domain_);
85  for (int i = 0; i < nlvc - (nlvo + nlvci); i++) addVariable (false, &domain_);
86  for (int i = 0; i < nlvci; i++) addVariable (true, &domain_);
87  }
88 
89  for (int i = 0; i < nwv; i++) addVariable(false, &domain_);//arc
90  for (int i = n_var - (CoinMax (nlvc,nlvo) +niv+nbv+nwv); i--;) addVariable(false, &domain_);//other
91  for (int i = 0; i < nbv; i++) addVariable(true, &domain_);//binary
92  for (int i = 0; i < niv; i++) addVariable(true, &domain_);//int.
93 
94  // add space for common expressions
95  for (int i = ndefined_; i--;) addVariable(false, &domain_);
96 
97  double now = CoinCpuTime ();
98 
99  if (nVars () > THRESHOLD_OUTPUT_READNL) {
100  jnlst_ -> Printf (Ipopt::J_ERROR, J_COUENNE, "Reading problem: ");
101  fflush(stdout);
102  }
103 
104  // common expressions (or defined variables) ///////////////////////////////////////
105 
106 #ifdef DEBUG
107  printf ("ndefd_ = %d\n", ndefined_);
108  printf ("tot var = %d\n", variables_ . size ());
109  printf ("c_vars_ = %d\n", ((const ASL_fg *) asl) -> i.c_vars_ );
110  printf ("comb_ = %d\n", ((const ASL_fg *) asl) -> i.comb_ );
111  printf ("combc_ = %d\n", ((const ASL_fg *) asl) -> i.combc_ );
112  printf ("comc1_ = %d\n", ((const ASL_fg *) asl) -> i.comc1_ );
113  printf ("comc_ = %d\n", ((const ASL_fg *) asl) -> i.comc_ );
114  printf ("como1_ = %d\n", ((const ASL_fg *) asl) -> i.como1_ );
115  printf ("como_ = %d\n", ((const ASL_fg *) asl) -> i.como_ );
116 #endif
117 
118  // Each has a linear and a nonlinear part (thanks to Dominique
119  // Orban: http://www.gerad.ca/~orban/drampl/def-vars.html)
120 
121  for (int i = 0; i < como + comc + comb; i++)
122  createCommonExpr (this, asl, i, 0);
123 
124  for (int i = 0; i < como1 + comc1; i++)
125  createCommonExpr (this, asl, i, 1);
126 
127  //commonexprs_ . erase (commonexprs_ . begin (), commonexprs_ . end ());
128 
129  // objective functions /////////////////////////////////////////////////////////////
130 
131  if (n_obj == 0) {
132 
133  // strange, no objective function. Add one equal to zero
134 
135  jnlst_ -> Printf (Ipopt::J_ERROR, J_COUENNE, "Couenne: warning, no objective function found\nAdded fictitious function f(x)=0\n");
136  addObjective (new exprConst (0.), "min");
137  }
138 
139  for (int i = 0; i < n_obj; i++) {
140 
142  int nterms = 0;
143 
144  // count nonzero terms in linear part
145 
146  for (ograd *objgrad = Ograd [i];
147  objgrad;
148  objgrad = objgrad -> next)
149  if (fabs (objgrad -> coef) > COUENNE_EPS)
150  nterms++;
151 
152  expression
153  *body,
154  *nl = Simplified (nl2e (OBJ_DE [i] . e, asl));
155  // *nls = nl -> simplify ();
156 
157  // if (nls) {
158  // delete nl;
159  // nl = nls;
160  // }
161 
162  if (nterms) { // have linear terms
163 
164  int *indexL = new int [nterms+1];
165  CouNumber *coeff = new CouNumber [nterms];
166 
167  for (ograd *objgrad = Ograd [i]; objgrad; objgrad = objgrad -> next)
168  if (fabs (objgrad -> coef) > COUENNE_EPS) {
169 
170  *indexL++ = objgrad -> varno;
171  *coeff++ = objgrad -> coef;
172  }
173 
174  *indexL = -1;
175 
176  indexL -= nterms;
177  coeff -= nterms;
178 
179  std::vector <std::pair <exprVar *, CouNumber> > lcoeff;
180  indcoe2vector (indexL, coeff, lcoeff);
181 
182  if (nl -> code () == COU_EXPRSUM) {
183  body = exprGroup::genExprGroup (0., lcoeff, nl -> ArgList (), nl -> nArgs ());
184  // delete node without deleting children (they are now in body)
185  nl -> ArgList (NULL);
186  delete nl;
187  }
188  else {
189 
190  expression **nll = new expression * [1];
191 
192  *nll = nl;
193 
194  // apparently, objconst (i) is included in the obj expression
195  body = exprGroup::genExprGroup (0., lcoeff, nll, 1);
196  //body = new exprGroup (objconst (i), indexL, coeff, nll, 1);
197  }
198 
199  delete [] indexL;
200  delete [] coeff;
201 
202  } else
203  // apparently, objconst (i) is included in the obj expression
204  body = nl;
205  //if (fabs (objconst (i) > COUENNE_EPS))
206  //body = new exprSum (nl, new exprConst (objconst (i)));
207  //else
208 
210 
211  expression *subst = Simplified (body); // -> simplify ();
212 
213  // if (subst) {
214  // delete body; // VALGRIND
215  // body = subst;
216  // }
217 
218  // ThirdParty/ASL/solvers/asl.h, line 336: 0 is minimization, 1 is maximization
219  addObjective (body, (OBJ_sense [i] == 0) ? "min" : "max");
220  }
221 
222  // constraints ///////////////////////////////////////////////////////////////////
223 
224  int *nterms = new int [n_con];
225 
226  // allocate space for argument list of all constraints' summations
227  // of linear and nonlinear terms
228 
229  // init array with # terms of each constraint
230  for (int i = n_con; i--;)
231  *nterms++ = 0;
232  nterms -= n_con;
233 
234  cgrad *congrad;
235 
236  // count all linear terms
237  if (A_colstarts && A_vals) // Constraints' linear info is stored in A_vals
238  for (register int j = A_colstarts [n_var]; j--;) {
239 
240  real coeff = A_vals [j];
241 
242  if (fabs (coeff) > COUENNE_EPS)
243  nterms [A_rownos [j]] ++;
244  }
245  else { // Constraints' linear info is stored in Cgrad
246  for (register int i = 0; i < n_con; i++)
247  for (congrad = Cgrad [i];
248  congrad;
249  congrad = congrad -> next)
250  if (fabs (congrad -> coef) > COUENNE_EPS)
251  nterms [i] ++;
252  }
253 
254 
255  // vectors of the linear part
256  CouNumber **coeff = new CouNumber * [n_con];
257  int **indexL = new int * [n_con];
258 
259  for (register int i = n_con; i--;)
260  *indexL++ = NULL;
261 
262  indexL -= n_con;
263 
264 
265  // set linear terms
266 
267  if (A_colstarts && A_vals) // Constraints' linear info is stored in A_vals
268  for (int j = 0; j < n_var; j++)
269  for (register int i = A_colstarts [j], k = A_colstarts [j+1] - i; k--; i++) {
270 
271  int rowno = A_rownos [i],
272  nt = nterms [rowno] --;
273 
274  CouNumber **cline = coeff + rowno;
275  int **iline = indexL + rowno;
276 
277  if (*iline==NULL) {
278  *cline = new CouNumber [nt];
279  *iline = new int [nt+1];
280  (*iline) [nt] = -1;
281  }
282 
283  (*cline) [--nt] = A_vals [i];
284  (*iline) [nt] = j;
285 
286  }
287  else { // Constraints' linear info is stored in Cgrad
288  for (int i=0; i < n_con; i++) {
289 
290  int nt = nterms [i];
291 
292  CouNumber **cline = coeff + i;
293  int **iline = indexL + i;
294 
295  *cline = new CouNumber [nt];
296  *iline = new int [nt+1];
297  (*iline) [nt] = -1;
298 
299  for (congrad = Cgrad [i]; congrad; congrad = congrad -> next)
300  if (fabs (congrad -> coef) > COUENNE_EPS) {
301  (*cline) [--nt] = congrad -> coef;
302  (*iline) [nt] = congrad -> varno;
303  }
304  }
305  }
306 
307  // set constraints' bound and sign and store nonlinear part ///////////////////////////////
308 
309  for (int i = 0; i < n_con; i++) {
310 
311  enum con_sign sign;
312  double lb, ub;
313 
314  if (Urhsx) {
315  lb = LUrhs [i];
316  ub = Urhsx [i];
317  } else {
318  int j = 2*i;
319  lb = LUrhs [j];
320  ub = LUrhs [j+1];
321  }
322 
323  // set constraint sign
324  if (lb > negInfinity)
325  if (ub < Infinity) sign = COUENNE_RNG;
326  else sign = COUENNE_GE;
327  else sign = COUENNE_LE;
328 
329  // this is an equality constraint
330  if (fabs (lb - ub) < COUENNE_EPS)
331  sign = COUENNE_EQ;
332 
333  expression
334  *body,
335  **nll = new expression * [1],
336  *nls;
337 
338  *nll = Simplified (nl2e (CON_DE [i] . e, asl));
339 
340  // nls = (*nll) -> simplify ();
341 
342  // if (nls) {
343  // delete *nll;
344  // *nll = nls;
345  // }
346 
347  if (indexL [i] && (*(indexL [i]) >= 0)) {
348 
349  int code = (*nll) -> code ();
350 
351  std::vector <std::pair <exprVar *, CouNumber> > lcoeff;
352  indcoe2vector (indexL [i], coeff [i], lcoeff);
353 
354  /*std::vector <std::pair <exprVar *, CouNumber> > lcoeff;
355  for (int i=0, *ind = indexL; *ind >= 0; *ind++, i++)
356  lcoeff.push_back (std::pair <exprVar *, CouNumber> (Var (*ind), coeff [i]));*/
357 
358  if ((code == COU_EXPRSUM) ||
359  (code == COU_EXPRGROUP)) {
360 
361  body = exprGroup::genExprGroup (0., lcoeff, (*nll) -> ArgList (), (*nll) -> nArgs ());
362  // delete node without deleting children (they are now in body)
363  (*nll) -> ArgList (NULL);
364  delete *nll;
365  delete [] nll;
366  }
367  else body = exprGroup::genExprGroup (0., lcoeff, nll, 1);
368  }
369  else {
370  body = *nll;
371  delete [] nll;
372  }
373 
374  expression *subst = Simplified (body); // or body->simplify() ?
375 
376  // -> simplify ();
377  // if (subst) {
378  // delete body; // VALGRIND
379  // body = subst;
380  // }
381 
382  // add them (and set lower-upper bound)
383  if ((lb < negInfinity) &&
384  (ub > Infinity)) {
385 
386  printf ("Free constraint %d ignored\n", i);
387 
388  } else
389 
390  // add them (and set lower-upper bound)
391  switch (sign) {
392 
393  case COUENNE_EQ: addEQConstraint (body, new exprConst (ub)); break;
394  case COUENNE_LE: addLEConstraint (body, new exprConst (ub)); break;
395  case COUENNE_GE: addGEConstraint (body, new exprConst (lb)); break;
396  case COUENNE_RNG: addRNGConstraint (body, new exprConst (lb),
397  new exprConst (ub)); break;
398  default: printf ("Could not recognize constraint\n"); return -1;
399  }
400 
401  delete [] indexL [i];
402  delete [] coeff [i];
403  }
404 
405  delete [] indexL;
406  delete [] coeff;
407 
408  // create room for problem's variables and bounds
409  CouNumber
410  *x = (CouNumber *) malloc ((n_var + ndefined_) * sizeof (CouNumber)),
411  *lb = (CouNumber *) malloc ((n_var + ndefined_) * sizeof (CouNumber)),
412  *ub = (CouNumber *) malloc ((n_var + ndefined_) * sizeof (CouNumber));
413 
414  for (int i = n_var + ndefined_; i--;) {
415  x [i] = 0.;
416  lb [i] = -COUENNE_INFINITY;
417  ub [i] = COUENNE_INFINITY;
418  }
419 
420  domain_.push (n_var + ndefined_, x, lb, ub);
421 
422  free (x); free (lb); free (ub);
423 
424  // lower and upper bounds ///////////////////////////////////////////////////////////////
425 
426  if (LUv) {
427 
428  real *Uvx_copy = Uvx;
429 
430  if (!Uvx_copy)
431  for (register int i=0; i<n_var; i++) {
432 
433  register int j = 2*i;
434 
435  Lb (i) = LUv [j];
436  Ub (i) = LUv [j+1];
437  }
438  else
439  for (register int i=n_var; i--;) {
440  Lb (i) = LUv [i];
441  Ub (i) = Uvx_copy [i];
442  }
443 
444  } else
445  for (register int i=n_var; i--;) {
446  Lb (i) = - COUENNE_INFINITY;
447  Ub (i) = COUENNE_INFINITY;
448  }
449 
450  // initial x ////////////////////////////////////////////////////////////////////
451 
452  for (register int i=n_var; i--;)
453 
454  if (X0 && havex0 [i]) X (i) = X0 [i];
455 
456  else {
457 
458  CouNumber x, l = Lb (i), u = Ub (i);
459 
460  if (l < - COUENNE_INFINITY)
461  if (u > COUENNE_INFINITY) x = 0.;
462  else x = u;
463  else if (u > COUENNE_INFINITY) x = l;
464  else x = 0.5 * (l+u);
465 
466  X (i) = x;
467  }
468 
469  for (register int i=n_var; i<ndefined_; i++) {
470 
471  X (i) = 0.;
472  Lb (i) = -COUENNE_INFINITY;
473  Ub (i) = COUENNE_INFINITY;
474  }
475 
476  delete [] nterms;
477 
478  if (nVars () > THRESHOLD_OUTPUT_READNL) {
479  jnlst_ -> Printf (Ipopt::J_ERROR, J_COUENNE, "%.1f seconds\n", CoinCpuTime () - now);
480  fflush(stdout);
481  }
482 
483  return 0;
484 }
485 
486 
487 //
488 // Common code for common expressions (aka defined variables)
489 //
490 
491 void createCommonExpr (CouenneProblem *p, const ASL *asl, int i, int which) {
492 
493  struct cexp *common = ((const ASL_fg *) asl) -> I.cexps_ + i;
494  struct cexp1 *common1 = ((const ASL_fg *) asl) -> I.cexps1_ + i;
495 
496  expression
497  *nle = Simplified (p -> nl2e (which ? common1 -> e : common -> e, asl));
498 
499  // *nls = nle -> simplify ();
500 
501  // if (nls) {
502  // delete nle;
503  // nle = nls;
504  // }
505 
506 #ifdef DEBUG
507  printf ("cexp1 %d [%d]: ", i, p -> Variables () . size ()); nle -> print (); printf (" ||| ");
508 #endif
509 
510  int nlin = which ? common1 -> nlin : common -> nlin; // Number of linear terms
511 
512  if (nlin > 0) {
513 
514  linpart *L = which ? common1 -> L : common -> L;
515 
516  std::vector <std::pair <exprVar *, CouNumber> > lcoeff;
517 
518  for (int j = 0; j < nlin; j++) {
519  //vp = (expr_v *)((char *)L->v.rp - ((char *)&ev.v - (char *)&ev));
520 
521  int indVar = ((uintptr_t) (L [j].v.rp) - (uintptr_t) VAR_E) / sizeof (expr_v);
522  CouNumber coeff = L [j]. fac;
523 
524  lcoeff.push_back (std::pair <exprVar *, CouNumber> (p -> Var (indVar), coeff));
525 
526 #ifdef DEBUG
527  Printf( " %+g x_%d (%-3d)", L [j]. fac, indVar,
528  (expr_v *) (L [j].v.rp) - VAR_E //((const ASL_fg *) asl) -> I.cexps_
529  //L [j]. v.i
530  );
531 #endif
532  }
533 
534  expression **al = new expression * [1];
535  *al = nle;
536 
537  expression *eg;
538 
539  if (lcoeff.size () == 1 &&
540  nle -> Type () == CONST &&
541  nle -> Value () == 0.) {
542 
543  CouNumber coeff = lcoeff [0].second;
544 
545  if (coeff == 1.) eg = new exprClone (lcoeff [0].first);
546  else if (coeff == -1.) eg = new exprOpp (new exprClone (lcoeff [0].first));
547  else eg = new exprMul (new exprConst (coeff), new exprClone (lcoeff [0].first));
548  } else eg = exprGroup::genExprGroup (0, lcoeff, al, 1);
549 
550  int indVar = p -> nVars () - p -> nDefVars () + p -> commonExprs () . size ();
551 
552  if (eg -> Index () != indVar) {
553 
554  expression *body = new exprSub (eg, new exprClone (p -> Var (indVar)));
555  p -> addEQConstraint (body, new exprConst (0.));
556  }
557 
558  p -> commonExprs () . push_back (new exprClone (eg));
559  }
560  else {
561 
562  int indVar = p -> nVars () - p -> nDefVars () + p -> commonExprs () . size ();
563 
564  if (nle -> Index () != indVar) {
565 
566  expression *body = new exprSub (nle, new exprClone (p -> Var (indVar)));
567  p -> addEQConstraint (body, new exprConst (0.));
568  }
569 
570  p -> commonExprs () . push_back (new exprClone (nle));
571  }
572 
573 #ifdef DEBUG
574  printf ("\n");
575 #endif
576  // addAuxiliary (nl2e (((const ASL_fg *) asl) -> I.cexps1_ [i] . e, asl));
577 }
void addLEConstraint(expression *, expression *=NULL)
Add constraint, .
int nVars() const
Total number of variables.
#define THRESHOLD_OUTPUT_READNL
Definition: readnl.cpp:44
void addObjective(expression *, const std::string &="min")
Add (non linear) objective function.
ULong L
Definition: OSdtoa.cpp:1816
class for subtraction,
class opposite,
std::string problemName_
problem name
constant-type operator
bool is_expr_zero(expr *e)
Definition: readnl.cpp:51
static char * j
Definition: OSdtoa.cpp:3622
static expression * genExprGroup(CouNumber, lincoeff &, expression **=NULL, int=0)
Generalized (static) constructor: check parameters and return a constant, a single variable...
Definition: exprGroup.cpp:50
void fint fint fint real fint real real real real real real real real real * e
Bonmin::BqpdSolver::real real
int ndefined_
Number of &quot;defined variables&quot; (aka &quot;common expressions&quot;)
void addEQConstraint(expression *, expression *=NULL)
Add equality constraint .
expression * addVariable(bool isint=false, Domain *d=NULL)
Add original variable.
Class for MINLP problems with symbolic information.
void fint fint * k
expression clone (points to another expression)
#define COUENNE_EPS
std::vector< exprVar * > variables_
Variables (original, auxiliary, and defined)
#define Intcast
Definition: OSdtoa.cpp:38
#define CON_DE
Definition: readnl.cpp:41
void createCommonExpr(CouenneProblem *p, const ASL *asl, int i, int which)
Definition: readnl.cpp:491
Domain domain_
current point and bounds;
CouNumber * Ub() const
Return vector of upper bounds.
void addGEConstraint(expression *, expression *=NULL)
Add constraint, .
double CouNumber
main number type in Couenne
expression * Simplified(expression *complicated)
Macro to return already simplified expression without having to do the if part every time simplify ()...
void addRNGConstraint(expression *, expression *=NULL, expression *=NULL)
Add range constraint, .
#define COUENNE_INFINITY
CouNumber * X() const
Return vector of variables.
con_sign
sign of constraint
void push(int dim, CouNumber *x, CouNumber *lb, CouNumber *ub, bool copy=true)
save current point and start using another
Definition: domain.cpp:166
#define VAR_E
Definition: readnl.cpp:40
JnlstPtr jnlst_
SmartPointer to the Journalist.
#define OBJ_sense
Definition: readnl.cpp:42
fint nt
void indcoe2vector(int *indexL, CouNumber *coeff, std::vector< std::pair< exprVar *, CouNumber > > &lcoeff)
translates pair (indices, coefficients) into vector with pointers to variables
Expression base class.
The in-memory representation of the variables element.
Definition: OSInstance.h:83
const Ipopt::EJournalCategory J_COUENNE(Ipopt::J_USER8)
#define OBJ_DE
Definition: readnl.cpp:39
void fint fint fint real fint real * x
class for multiplications,
CouNumber * Lb() const
Return vector of lower bounds.