1 /* $Id$
2  *
3  * Name:    nl2e.cpp
4  * Author:  Pietro Belotti
5  * Purpose: converts a nl expression into a Couenne expression
6  *
7  * (C) Carnegie-Mellon University, 2006-09.
8  * This file is licensed under the Eclipse Public License (EPL)
9  */
10 
11 #include "CouenneTypes.hpp"
12 
13 #include "CouenneExprVar.hpp"
14 #include "CouenneExprAbs.hpp"
15 #include "CouenneExprSum.hpp"
16 #include "CouenneExprSub.hpp"
17 #include "CouenneExprMul.hpp"
18 #include "CouenneExprDiv.hpp"
19 #include "CouenneExprInv.hpp"
20 #include "CouenneExprSin.hpp"
21 #include "CouenneExprPow.hpp"
22 #include "CouenneExprClone.hpp"
23 #include "CouenneExprLog.hpp"
24 #include "CouenneExprOpp.hpp"
25 #include "CouenneExprCos.hpp"
26 #include "CouenneExprExp.hpp"
27 
28 #include "asl.h"
29 #include "nlp.h"
30 #include "opcode.hd"
31 
32 using namespace Couenne;
33 
34 // get ASL op. code relative to function pointer passed as parameter
35 size_t getOperator (efunc *);
36 
37 
38 // warning for non-implemented functions -- return 0 constant expression
39 //expression *notimpl (const std::string &fname) {
notimpl(const std::string & fname)40 void notimpl (const std::string &fname) {
41   std::cerr << "*** Error: " << fname << " not implemented" << std::endl;
42   exit (-1);
43 }
44 
45 
46 // converts an AMPL expression (sub)tree into an expression* (sub)tree
nl2e(expr * e,const ASL * asl)47 expression *CouenneProblem::nl2e (expr *e, const ASL *asl) {
48 
49   switch (getOperator (e -> op)) {
50 
51   case OPPLUS:  return new exprSum (nl2e (e -> L.e, asl), nl2e (e -> R.e, asl));
52   case OPMINUS: return new exprSub (nl2e (e -> L.e, asl), nl2e (e -> R.e, asl));
53   case OPMULT:  return new exprMul (nl2e (e -> L.e, asl), nl2e (e -> R.e, asl));
54   case OPDIV:   return new exprDiv (nl2e (e -> L.e, asl), nl2e (e -> R.e, asl));
55   case OPREM:   notimpl ("remainder");
56   case OPPOW:   return new exprPow (nl2e (e -> L.e, asl), nl2e (e -> R.e, asl));
57   case OPLESS:  notimpl ("less");
58   case MINLIST: notimpl ("min");
59   case MAXLIST: notimpl ("max");
60   case FLOOR:   notimpl ("floor");
61   case CEIL:    notimpl ("ceil");
62   case ABS:     return new exprAbs (nl2e (e -> L.e, asl));
63   case OPUMINUS:return new exprOpp (nl2e (e -> L.e, asl));
64     //          return new exprOpp (nl2e (e -> L.e -> L.e, asl));
65   case OPIFnl:  { notimpl ("ifnl");
66 
67     // see ASL/solvers/rops.c, IfNL
68   }
69 
70   case OP_tanh: return new exprDiv
71       (new exprSub (new exprExp (nl2e (e -> L.e, asl)),
72 		    new exprExp (new exprOpp (nl2e (e->L.e, asl)))),
73        new exprSum (new exprExp (nl2e (e -> L.e, asl)),
74 		    new exprExp (new exprOpp (nl2e (e->L.e, asl)))));
75 
76   case OP_tan:
77     return new exprDiv (new exprSin (nl2e (e -> L.e, asl)), new exprCos (new exprClone (nl2e (e -> L.e, asl))));
78   case OP_sqrt:    return new exprPow (nl2e (e -> L.e, asl), new exprConst (0.5));
79   case OP_sinh:    return new exprMul (new exprConst (0.5),
80 				       new exprSub (new exprExp (nl2e (e -> L.e, asl)),
81 						    new exprExp (new exprOpp (nl2e (e->L.e, asl)))));
82   case OP_sin:     return new exprSin (nl2e (e -> L.e, asl));
83   case OP_log10:   return new exprMul (new exprConst (1.0 / log (10.0)),
84 				       new exprLog (nl2e (e -> L.e, asl)));
85   case OP_log:     return new exprLog (nl2e (e -> L.e, asl));
86   case OP_exp:     return new exprExp (nl2e (e -> L.e, asl));
87   case OP_cosh:    return new exprMul (new exprConst (0.5),
88 				       new exprSum (new exprExp (nl2e (e -> L.e, asl)),
89 						    new exprExp (new exprOpp (nl2e (e->L.e, asl)))));
90 
91   case OP_cos:   return new exprCos (nl2e (e -> L.e, asl));
92   case OP_atanh: notimpl ("atanh");
93   case OP_atan2: notimpl ("atan2");
94   case OP_atan:  notimpl ("atan");
95   case OP_asinh: notimpl ("asinh");
96   case OP_asin:  notimpl ("asin");
97   case OP_acosh: notimpl ("acosh");
98   case OP_acos:  notimpl ("acos");
99 
100   case OPSUMLIST: {
101     int i=0;
102     expression **al = new expression * [(e->R.ep - e->L.ep)];
103     for (expr **ep = e->L.ep; ep < e->R.ep; ep++)
104       al [i++] = nl2e (*ep, asl);
105     return new exprSum (al, i);
106   }
107   case OPintDIV: notimpl ("intdiv");
108   case OPprecision: notimpl ("precision");
109   case OPround:  notimpl ("round");
110   case OPtrunc:  notimpl ("trunc");
111 
112   case OP1POW: return new exprPow (nl2e (e -> L.e, asl), 		   new exprConst (((expr_n *)e->R.e)->v));
113   case OP2POW: return new exprPow (nl2e (e -> L.e, asl), 		   new exprConst (2.));
114   case OPCPOW: return new exprPow (new exprConst (((expr_n *)e->L.e)->v),  nl2e (e -> R.e, asl));
115   case OPFUNCALL: notimpl ("function call");
116   case OPNUM:     return new exprConst (((expr_n *)e)->v);
117   case OPPLTERM:  notimpl ("plterm");
118   case OPIFSYM:   notimpl ("ifsym");
119   case OPHOL:     notimpl ("hol");
120   case OPVARVAL:  {
121 
122     int j = ((expr_v *) e) -> a;
123 
124     if (j >= nOrigVars_) // common expression
125       // use base pointer otherwise the .a field returns an awkward, out-of-bound index
126       // TODO: fix! In itointqor.nl should return v51=y44 but returns v52=y44
127       //                                          v??=y39 but returns v79=y39
128       j = ((expr_v *) e) - ((const ASL_fg *) asl) -> I.var_e_;
129 
130     if (j >= nOrigVars_ + ndefined_) {
131       printf ("error: unknown variable x_%d\n", j);
132       //return new exprClone (variables_ [0]);
133       exit (-1);
134     }
135 
136     return new exprClone (variables_ [j]);
137   }
138 
139   default:
140     printf ("Couenne error: unknown operator (address %p), aborting.\n", Intcast (e -> op));
141     exit (-1);
142     //return new exprConst (0);
143   }
144 
145   return new exprConst (0.);
146 }
147