MicroModelicaCCompiler  4.5.3
ginac_interface.cpp
Go to the documentation of this file.
1 /*****************************************************************************
2 
3  This file is part of QSS Solver.
4 
5  QSS Solver is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  QSS Solver is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with QSS Solver. If not, see <http://www.gnu.org/licenses/>.
17 
18  ******************************************************************************/
19 
20 #include "ginac_interface.hpp"
21 
22 #include <assert.h>
23 #include <ginac/add.h>
24 #include <ginac/inifcns.h>
25 #include <ginac/mul.h>
26 #include <ginac/operators.h>
27 #include <ginac/power.h>
28 #include <ginac/print.h>
29 #include <ginac/registrar.h>
30 #include <ginac/relational.h>
31 #include <ginac/wildcard.h>
32 #include <string>
33 #include <iostream>
34 #include <list>
35 #include <sstream>
36 #include <utility>
37 
38 #include <ast/ast_builder.hpp>
39 #include "../ast/expression.hpp"
40 #include <ir/expression.hpp>
41 #include <ast/parser/parse.hpp>
42 #include "model_config.hpp"
43 #include "symbol_table.hpp"
44 #include "util.hpp"
45 
46 using namespace GiNaC;
47 using namespace MicroModelica::IR;
48 
49 namespace MicroModelica {
50 namespace Util {
51 
52 REGISTER_FUNCTION(der3, dummy())
53 
54 static ex der2_derivative(const ex& x, const ex& y, unsigned diff_param) { return der3(x); }
55 
56 REGISTER_FUNCTION(der2, derivative_func(der2_derivative))
57 
58 static ex der_derivative(const ex& x, const ex& y, unsigned diff_param) { return der2(x, y); }
59 
60 REGISTER_FUNCTION(der, derivative_func(der_derivative))
61 
62 REGISTER_FUNCTION(pre, dummy())
63 
64 void my_print_power_dflt(const power& p, const print_dflt& c, unsigned level)
65 {
66  // if the parent operator has the same or a higher precedence
67  // we need parentheses around the power
68  if (p.op(1).match(-1)) {
69  c.s << "(1/(" << p.op(0) << "))";
70  } else {
71  c.s << "((" << p.op(0) << ")^" << p.op(1) << ")";
72  }
73 }
74 
75 void my_print_mul_dflt(const mul& m, const print_dflt& c, unsigned level)
76 {
77  // get the precedence of the 'power' class
78  unsigned power_prec = m.precedence();
79  if (level >= power_prec) c.s << '(';
80  if (m.op(1).match(pow(wild(), -1))) {
81  c.s << "(" << m.op(0) << "/" << m.op(1).op(0) << ")";
82  } else if (m.op(0).match(pow(wild(), -1))) {
83  c.s << "(" << m.op(1) << "/" << m.op(0).op(0) << ")";
84  } else {
85  c.s << m.op(0) << "*" << m.op(1);
86  }
87  if (level >= power_prec) c.s << ')';
88 }
89 void my_print_add_dflt(const add& s, const print_dflt& c, unsigned level)
90 {
91  // get the precedence of the 'power' class
92  unsigned power_prec = s.precedence();
93  if (level >= power_prec) c.s << '(';
94  if (s.op(0).match(-wild()) && !s.op(1).match(-wild())) {
95  c.s << s.op(1) << "-" << s.op(0).op(0);
96  } else {
97  c.s << s.op(0) << "+" << s.op(1);
98  }
99  if (level >= power_prec) c.s << ')';
100 }
101 
102 ConvertToGiNaC::ConvertToGiNaC(Option<Expression> exp) : _replaceDer(true), _generateIndexes(false), _exp(exp) {}
103 
104 ex ConvertToGiNaC::convert(AST_Expression e, bool replaceDer, bool generateIndexes)
105 {
106  _replaceDer = replaceDer;
107  _generateIndexes = generateIndexes;
108  ex p = apply(e);
109  return p;
110 }
111 
112 static ex var_derivative(const ex& x, const ex& y, unsigned diff_param) { return der(x, y); }
113 
114 REGISTER_FUNCTION(var, derivative_func(var_derivative))
115 
116 GiNaC::symbol& ConvertToGiNaC::first() { return getSymbol(""); }
117 
118 GiNaC::symbol& ConvertToGiNaC::next() { return getSymbol(""); }
119 
120 bool ConvertToGiNaC::end() { return true; }
121 
122 map<string, GiNaC::symbol> ConvertToGiNaC::directory() { return _directory; }
123 
124 string ConvertToGiNaC::identifier(string str)
125 {
126  std::size_t found = str.find("[");
127  if (found == std::string::npos) {
128  return str;
129  } else {
130  std::size_t end = str.find("]");
131  string ret = str;
132  ret.erase(found, end);
133  return ret;
134  }
135  return "";
136 }
137 
139 {
140  switch (b) {
141  case BINOPADD:
142  return l + r;
143  case BINOPSUB:
144  return l - r;
145  case BINOPMULT:
146  return l * r;
147  case BINOPDIV:
148  return l / r;
149  case BINOPEXP:
150  return pow(l, r);
151  default:
152  cerr << "BinOp not converted to GiNaC " << b << endl;
153  return ex(0);
154  }
155 }
156 
157 symbol& ConvertToGiNaC::getSymbol(AST_Expression_Derivative der)
158 {
159  AST_Expression_ComponentReference cr = der->arguments()->front()->getAsComponentReference();
160  string s = cr->name();
161  s.insert(0, "__der_");
162  AST_Expression_ComponentReference new_cr =
164  return getSymbol(new_cr);
165 }
166 
167 symbol& ConvertToGiNaC::getSymbol(AST_Expression_ComponentReference cr)
168 {
169  string s = cr->name();
170  if (_generateIndexes) {
171  s = cr->print();
172  }
173  map<string, symbol>::iterator i = _directory.find(s);
174  if (i != _directory.end()) {
175  return i->second;
176  } else {
177  symbol c = symbol(s);
178  return _directory.insert(make_pair(s, c)).first->second;
179  }
180 }
181 
182 symbol& ConvertToGiNaC::getSymbol(string cr)
183 {
184  map<string, symbol>::iterator i = _directory.find(cr);
185  if (i != _directory.end()) {
186  return i->second;
187  } else {
188  symbol c = symbol(cr);
189  return _directory.insert(make_pair(cr, c)).first->second;
190  }
191 }
192 
194 {
195  string s = "time";
196  map<string, symbol>::iterator i = _directory.find(s);
197  return (i == _directory.end() ? _directory.insert(make_pair(s, symbol(s))).first->second : i->second);
198 }
199 
200 ex ConvertToGiNaC::foldTraverseElementUMinus(AST_Expression e) { return -convert(e->getAsUMinus()->exp(), _replaceDer, _generateIndexes); }
201 
203 {
204  if (_exp) {
205  string varName = ""; // = _exp->findVar(e);
206  return var(getSymbol(varName), getTime());
207  } else {
208  return ex(0);
209  }
210 }
211 
213 {
214  switch (e->expressionType()) {
215  case EXPREAL:
216  return ex(e->getAsReal()->val());
217  case EXPINTEGER:
218  return ex(e->getAsInteger()->val());
219  case EXPCOMPREF: {
220  Option<Variable> v = ModelConfig::instance().lookup(e->getAsComponentReference()->name());
221  if (v->isParameter() || v->isDiscrete() || v->isConstant() || v->isForType())
222  return getSymbol(e->getAsComponentReference());
223  else if (v->builtIn() && !v->name().compare("time"))
224  return getTime();
225  else
226  return var(getSymbol(e->getAsComponentReference()), getTime());
227  }
228  case EXPDERIVATIVE:
229  if (_replaceDer) {
230  return getSymbol(e->getAsDerivative());
231  } else {
232  AST_Expression ed = e->getAsDerivative()->arguments()->front();
233  switch (ed->expressionType()) {
234  case EXPCOMPREF: {
235  AST_Expression_ComponentReference cr = ed->getAsComponentReference();
236  return der(getSymbol(cr), getTime());
237  }
238  default:
239  cerr << "Derivate argument " << ed << " not converted to GiNaC" << endl;
240  return ex(0);
241  }
242  }
243  break;
244  case EXPCALL: {
245  AST_Expression_Call c = e->getAsCall();
246  if (toStr(c->name()) == "sin") {
247  return (sin(convert(AST_ListFirst(c->arguments()), _replaceDer, _generateIndexes)));
248  } else if (toStr(c->name()) == "cos") {
249  return (cos(convert(AST_ListFirst(c->arguments()), _replaceDer, _generateIndexes)));
250  } else if (toStr(c->name()) == "log") {
251  return (log(convert(AST_ListFirst(c->arguments()), _replaceDer, _generateIndexes)));
252  } else if (toStr(c->name()) == "pre") {
253  return (pre(convert(AST_ListFirst(c->arguments()), _replaceDer, _generateIndexes)));
254  } else if (toStr(c->name()) == "der2") {
255  AST_Expression ed = AST_ListFirst(c->arguments());
256  switch (ed->expressionType()) {
257  case EXPCOMPREF: {
258  AST_Expression_ComponentReference cr = ed->getAsComponentReference();
259  return der2(getSymbol(cr), getTime());
260  }
261  default:
262  cerr << "Derivate argument " << ed << " not converted to GiNaC" << endl;
263  return ex(0);
264  }
265  } else if (toStr(c->name()) == "der3") {
266  return (der3(convert(AST_ListFirst(c->arguments()), _replaceDer, _generateIndexes)));
267  } else if (toStr(c->name()) == "sum") {
268  return expressionVariable();
269  } else if (toStr(c->name()) == "product") {
270  return expressionVariable();
271  } else if (toStr(c->name()) == "min") {
272  return expressionVariable();
273  } else if (toStr(c->name()) == "max") {
274  return expressionVariable();
275  } else if (toStr(c->name()) == "__INNER_PRODUCT") {
276  return expressionVariable();
277  } else if (toStr(c->name()) == "pow") {
278  AST_ExpressionList el = c->arguments();
279  AST_Expression f = AST_ListFirst(el);
280  AST_Expression s = AST_ListElement(el, 2);
282  } else if (toStr(c->name()) == "sqrt") {
283  AST_ExpressionList el = c->arguments();
284  AST_Expression f = AST_ListFirst(el);
285  return sqrt(convert(f, _replaceDer, _generateIndexes));
286  } else if (toStr(c->name()) == "exp") {
287  return (exp(convert(AST_ListFirst(c->arguments()), _replaceDer, _generateIndexes)));
288  } else if (Utils::instance().checkGKLinkFunctions(toStr(c->name()))) {
289  return ex(0);
290  } else {
291  cerr << "Function call : " << c->name()->c_str() << " not converted to GiNaC" << endl;
292  return ex(0);
293  }
294  } break;
295  case EXPOUTPUT: {
296  AST_Expression el = AST_ListFirst(e->getAsOutput()->expressionList());
297  return ex((apply(el)));
298  }
299  default:
300  cerr << "Expression: " << e << " not converted to GiNaC" << endl;
301  return ex(0);
302  }
303 }
304 
305 AST_Expression ConvertToExpression::convert(ex exp)
306 {
307  if (Utils::instance().compileFlags().testing()) {
308  return newAST_Expression_Integer(0);
309  }
310  stringstream s(ios_base::out), der_s(ios_base::out);
311  int r;
312  set_print_func<power, print_dflt>(my_print_power_dflt);
313  s << exp;
314  AST_Expression e;
315  if (s.str().find("__der_") == 0) {
316  string ss = s.str().erase(0, 6);
317  der_s << "der(" << ss << ")";
318  e = parseExpression(der_s.str().c_str(), &r);
319  } else {
320  e = parseExpression(s.str().c_str(), &r);
321  }
322  assert(e != nullptr && r == 0);
323  return e;
324 }
325 } // namespace Util
326 } // namespace MicroModelica
MicroModelica::Util::ModelConfig::lookup
Option< Variable > lookup(std::string var_name)
Definition: model_config.hpp:125
EXPINTEGER
@ EXPINTEGER
Definition: ast_types.hpp:180
EXPOUTPUT
@ EXPOUTPUT
Definition: ast_types.hpp:182
MicroModelica::Util::ConvertToGiNaC
Definition: ginac_interface.hpp:76
toStr
#define toStr(it)
Definition: ast_builder.hpp:53
BINOPEXP
@ BINOPEXP
Definition: ast_types.hpp:154
MicroModelica::Util::ConvertToExpression::convert
static AST_Expression convert(GiNaC::ex)
Definition: ginac_interface.cpp:305
ast_builder.hpp
EXPCOMPREF
@ EXPCOMPREF
Definition: ast_types.hpp:165
ginac_interface.hpp
MicroModelica::Util::my_print_power_dflt
void my_print_power_dflt(const power &p, const print_dflt &c, unsigned level)
Definition: ginac_interface.cpp:64
expression.hpp
symbol_table.hpp
MicroModelica::Util::ConvertToGiNaC::foldTraverseElement
GiNaC::ex foldTraverseElement(AST_Expression)
Definition: ginac_interface.cpp:212
MicroModelica::Util::ConvertToGiNaC::expressionVariable
GiNaC::ex expressionVariable()
Definition: ginac_interface.cpp:202
Option
Definition: util_types.hpp:32
AST_ListElement
T1 AST_ListElement(list< T1 > *l, int n)
Definition: ast_types.hpp:229
MicroModelica::Util::ConvertToGiNaC::convert
GiNaC::ex convert(AST_Expression, bool replaceDer=true, bool generateIndexes=false)
Definition: ginac_interface.cpp:104
BINOPMULT
@ BINOPMULT
Definition: ast_types.hpp:152
AST_Expression_ComponentReference_Add
AST_Expression_ComponentReference AST_Expression_ComponentReference_Add(AST_Expression_ComponentReference cr, AST_String s, AST_ExpressionList subs)
Definition: ast_builder.cpp:236
model_config.hpp
MicroModelica::Util::der_derivative
static ex der_derivative(const ex &x, const ex &y, unsigned diff_param)
Definition: ginac_interface.cpp:58
EXPDERIVATIVE
@ EXPDERIVATIVE
Definition: ast_types.hpp:167
MicroModelica::Util::my_print_mul_dflt
void my_print_mul_dflt(const mul &m, const print_dflt &c, unsigned level)
Definition: ginac_interface.cpp:75
BINOPSUB
@ BINOPSUB
Definition: ast_types.hpp:148
EXPCALL
@ EXPCALL
Definition: ast_types.hpp:173
MicroModelica::Util::ModelConfig::instance
static ModelConfig & instance()
Definition: model_config.hpp:87
AST_Expression_Visitor< GiNaC::ex >::apply
GiNaC::ex apply(AST_Expression e)
Definition: ast_util.hpp:86
MicroModelica::Util::ConvertToGiNaC::_generateIndexes
bool _generateIndexes
Definition: ginac_interface.hpp:114
AST_ListFirst
T1 AST_ListFirst(list< T1 > *l)
Definition: ast_types.hpp:271
MicroModelica::Util::ConvertToGiNaC::getSymbol
GiNaC::symbol & getSymbol(AST_Expression_ComponentReference)
Definition: ginac_interface.cpp:167
BINOPDIV
@ BINOPDIV
Definition: ast_types.hpp:150
MicroModelica::Util::ConvertToGiNaC::first
GiNaC::symbol & first()
Definition: ginac_interface.cpp:116
newAST_Expression_ComponentReference
AST_Expression_ComponentReference newAST_Expression_ComponentReference()
Definition: ast_builder.cpp:222
MicroModelica::Util::ConvertToGiNaC::directory
map< string, GiNaC::symbol > directory()
Definition: ginac_interface.cpp:122
MicroModelica::Util::ConvertToGiNaC::_exp
Option< IR::Expression > _exp
Definition: ginac_interface.hpp:115
MicroModelica::Util::ConvertToGiNaC::next
GiNaC::symbol & next()
Definition: ginac_interface.cpp:118
MicroModelica
Definition: files.cpp:45
MicroModelica::Util::ConvertToGiNaC::_directory
map< string, GiNaC::symbol > _directory
Definition: ginac_interface.hpp:112
MicroModelica::Util::ConvertToGiNaC::_replaceDer
bool _replaceDer
Definition: ginac_interface.hpp:113
MicroModelica::Util::ConvertToGiNaC::end
bool end()
Definition: ginac_interface.cpp:120
MicroModelica::Util::Utils::instance
static Utils & instance()
Definition: util.hpp:83
BINOPADD
@ BINOPADD
Definition: ast_types.hpp:146
BinOpType
BinOpType
Definition: ast_types.hpp:137
EXPREAL
@ EXPREAL
Definition: ast_types.hpp:179
newAST_ExpressionList
AST_ExpressionList newAST_ExpressionList(AST_Expression e)
Definition: ast_builder.cpp:132
MicroModelica::Util::der2_derivative
static ex der2_derivative(const ex &x, const ex &y, unsigned diff_param)
Definition: ginac_interface.cpp:54
MicroModelica::Util::var_derivative
static ex var_derivative(const ex &x, const ex &y, unsigned diff_param)
Definition: ginac_interface.cpp:112
MicroModelica::Util::my_print_add_dflt
void my_print_add_dflt(const add &s, const print_dflt &c, unsigned level)
Definition: ginac_interface.cpp:89
MicroModelica::IR
Definition: alg_usage.cpp:47
MicroModelica::Util::ConvertToGiNaC::getTime
GiNaC::symbol & getTime()
Definition: ginac_interface.cpp:193
newAST_Expression_Integer
AST_Expression newAST_Expression_Integer(int i)
Definition: ast_builder.cpp:130
MicroModelica::Util::ConvertToGiNaC::foldTraverseElementUMinus
GiNaC::ex foldTraverseElementUMinus(AST_Expression)
Definition: ginac_interface.cpp:200
util.hpp
MicroModelica::Util::ConvertToGiNaC::identifier
string identifier(string str)
Definition: ginac_interface.cpp:124
newAST_String
AST_String newAST_String(string s)
Definition: ast_builder.cpp:57