1 /*!
2  * \file   src/Math/EvaluatorTExpr.cxx
3  * \brief
4  *
5  * \author Thomas Helfer
6  * \date   13 jan 2009
7  * \copyright Copyright (C) 2006-2018 CEA/DEN, EDF R&D. All rights
8  * reserved.
9  * This project is publicly released under either the GNU GPL Licence
10  * or the CECILL-A licence. A copy of thoses licences are delivered
11  * with the sources of TFEL. CEA or EDF may also distribute this
12  * project under specific licensing conditions.
13  */
14 
15 #include <stdexcept>
16 #include "TFEL/Raise.hxx"
17 #include "TFEL/Math/Evaluator.hxx"
18 
19 namespace tfel {
20 
21   namespace math {
22 
23     Evaluator::TExpr::~TExpr() = default;
24 
25     Evaluator::TLogicalExpr::~TLogicalExpr() = default;
26 
TNegLogicalExpr(const std::shared_ptr<Evaluator::TLogicalExpr> e_)27     Evaluator::TNegLogicalExpr::TNegLogicalExpr(
28         const std::shared_ptr<Evaluator::TLogicalExpr> e_)
29         : e(e_) {}  // end of Evaluator::TNegLogicalExpr::TNegLogicalExpr
30 
reduce()31     void Evaluator::TNegLogicalExpr::reduce() {
32       this->e->reduce();
33     }  // end of Evaluator::TNegLogicalExpr::reduce
34 
35     std::shared_ptr<tfel::math::parser::LogicalExpr>
analyse()36     Evaluator::TNegLogicalExpr::analyse() {
37       using namespace tfel::math::parser;
38       return std::shared_ptr<LogicalExpr>(
39           new NegLogicalExpression(this->e->analyse()));
40     }  // end of struct Evaluator::TNegLogicalExpr
41 
42     Evaluator::TNegLogicalExpr::~TNegLogicalExpr() = default;
43 
TNegation(std::shared_ptr<Evaluator::TExpr> e)44     Evaluator::TNegation::TNegation(std::shared_ptr<Evaluator::TExpr> e)
45         : expr(std::move(e)) {}  // end of Evaluator::TNegation::TNegation
46 
isOperator() const47     bool Evaluator::TNegation::isOperator() const { return false; }
48 
analyse()49     parser::ExprPtr Evaluator::TNegation::analyse() {
50       using namespace tfel::math::parser;
51       return ExprPtr(new Negation(this->expr->analyse()));
52     }
53 
reduce()54     void Evaluator::TNegation::reduce() { this->expr->reduce(); }
55 
56     Evaluator::TNegation::~TNegation() noexcept = default;
57 
TOperator(const std::string & t_)58     Evaluator::TOperator::TOperator(const std::string& t_)
59         : type(t_) {
60     }  // end of Evaluator::TOperator::TOperator(const std::string& t_)
61 
getOperatorType() const62     std::string Evaluator::TOperator::getOperatorType() const {
63       return this->type;
64     }  // end of Evaluator::TOperator::getOperatorType() const
65 
isOperator() const66     bool Evaluator::TOperator::isOperator() const {
67       return true;
68     }  // end of Evaluator::TOperator::isOperator() const
69 
reduce()70     void Evaluator::TOperator::reduce() {
71     }  // end of Evaluator::TOperator::reduce()
72 
analyse()73     parser::ExprPtr Evaluator::TOperator::analyse() {
74       raise("Evaluator::TOperator : invalid call");
75     }  // end of Evaluator::TOperator::analyse()
76 
77     Evaluator::TOperator::~TOperator() noexcept = default;
78 
TBinaryOperation(std::shared_ptr<Evaluator::TExpr> a_,const std::shared_ptr<TOperator> op_,std::shared_ptr<Evaluator::TExpr> b_)79     Evaluator::TBinaryOperation::TBinaryOperation(
80         std::shared_ptr<Evaluator::TExpr> a_,
81         const std::shared_ptr<TOperator> op_,
82         std::shared_ptr<Evaluator::TExpr> b_)
83         : a(std::move(a_)),
84           op(op_),
85           b(std::move(b_)) {
86     }  // end of Evaluator::TBinaryOperation::TBinaryOperation
87 
isOperator() const88     bool Evaluator::TBinaryOperation::isOperator() const {
89       return false;
90     }  // end of Evaluator::TBinaryOperation::isOperator() const
91 
reduce()92     void Evaluator::TBinaryOperation::reduce() {
93       a->reduce();
94       b->reduce();
95     }  // end of Evaluator::TBinaryOperation::reduce()
96 
analyse()97     parser::ExprPtr Evaluator::TBinaryOperation::analyse() {
98       using namespace tfel::math::parser;
99       if (op->getOperatorType() == "+") {
100         return ExprPtr(new BinaryOperation<OpPlus>(a->analyse(), b->analyse()));
101       } else if (op->getOperatorType() == "-") {
102         return ExprPtr(
103             new BinaryOperation<OpMinus>(a->analyse(), b->analyse()));
104       } else if (op->getOperatorType() == "*") {
105         return ExprPtr(new BinaryOperation<OpMult>(a->analyse(), b->analyse()));
106       } else if (op->getOperatorType() == "/") {
107         return ExprPtr(new BinaryOperation<OpDiv>(a->analyse(), b->analyse()));
108       } else if (op->getOperatorType() == "**") {
109         return ExprPtr(
110             new BinaryOperation<OpPower>(a->analyse(), b->analyse()));
111       }
112       raise(
113           "Evaluator::TBinaryOperation : "
114           "invalid operation type  '" +
115           op->getOperatorType() + "'");
116     }  // end of Evaluator::TBinaryOperation::analyse()
117 
118     Evaluator::TBinaryOperation::~TBinaryOperation() = default;
119 
TVariable(const std::string & name,Evaluator & e)120     Evaluator::TVariable::TVariable(const std::string& name, Evaluator& e)
121         : vars(e.variables),
122           pos(e.registerVariable(name)) {
123     }  // end of Evaluator::TVariable::TVariable
124 
TVariable(const std::vector<double>::size_type ppos,std::vector<double> & vvars)125     Evaluator::TVariable::TVariable(const std::vector<double>::size_type ppos,
126                                     std::vector<double>& vvars)
127         : vars(vvars), pos(ppos) {}
128 
isOperator() const129     bool Evaluator::TVariable::isOperator() const { return false; }
130 
reduce()131     void Evaluator::TVariable::reduce() {}
132 
analyse()133     parser::ExprPtr Evaluator::TVariable::analyse() {
134       using namespace tfel::math::parser;
135       return ExprPtr(new Variable(this->vars, this->pos));
136     }
137 
138     Evaluator::TVariable::~TVariable() = default;
139 
isOperator() const140     bool Evaluator::TGroup::isOperator() const { return false; }
141 
add(std::shared_ptr<Evaluator::TExpr> const e)142     void Evaluator::TGroup::add(std::shared_ptr<Evaluator::TExpr> const e) {
143       this->subExpr.push_back(e);
144     }  // end of Evaluator::TGroup::add
145 
reduce()146     void Evaluator::TGroup::reduce() {
147       auto p = this->subExpr.begin();
148       auto pe = this->subExpr.end();
149       while (p != pe) {
150         (*p)->reduce();
151         ++p;
152       }
153       // ok, this is the tricky part
154       // operator** has the highest priority
155       this->reduce("**");
156       // treating operator/
157       this->reduce("/");
158       // treating operator*
159       this->reduce("*");
160       // treating operator* -
161       this->reduce("-");
162       // operator+ has the lowest priority
163       this->reduce("+");
164     }
165 
analyse()166     parser::ExprPtr Evaluator::TGroup::analyse() {
167       raise_if(this->subExpr.size() != 1u,
168                "TGroup::analyse: "
169                "tgroup has not been reduced.");
170       return (this->subExpr[0])->analyse();
171     }
172 
173     Evaluator::TGroup::~TGroup() = default;
174 
reduce(const std::string & op)175     void Evaluator::TGroup::reduce(const std::string& op) {
176       using namespace tfel::math::parser;
177       auto throw_if = [](const bool b, const std::string& m) {
178         raise_if(b, "Evaluator::TGroup::reduce: " + m);
179       };
180       auto p = this->subExpr.begin();
181       while (p != this->subExpr.end()) {
182         if ((*p)->isOperator()) {
183           auto o = std::make_shared<TOperator>(
184               static_cast<const TOperator&>(*(p->get())));
185           if (o->getOperatorType() == op) {
186             auto next = std::next(p);
187             if (p == this->subExpr.begin()) {
188               throw_if(op != "-",
189                        "group began with an operator ('" + op + "')");
190               throw_if(next == this->subExpr.end(),
191                        "group ends by operator '" + op + "'");
192               throw_if((*next)->isOperator(), "group two successive operators");
193               *next = std::shared_ptr<Evaluator::TExpr>(new TNegation(*next));
194               this->subExpr.erase(p);
195               p = this->subExpr.begin();
196             } else {
197               auto previous = std::prev(p);
198               throw_if(next == this->subExpr.end(),
199                        "group ends by operator '" + op + "'");
200               if ((*previous)->isOperator()) {
201                 throw_if(op != "-", "group two successive operators");
202                 const auto po = std::shared_ptr<TOperator>(
203                     dynamic_cast<TOperator*>(previous->get()));
204                 throw_if(po->getOperatorType() != "+",
205                          "group two successive operators");
206                 throw_if((*next)->isOperator(),
207                          "group three successive operators");
208                 *p = std::shared_ptr<Evaluator::TExpr>(new TNegation(*next));
209                 p = this->subExpr.erase(next);
210                 --p;
211               } else {
212                 if ((*next)->isOperator()) {
213                   throw_if(op == "-", "group two successive operators");
214                   const auto no = dynamic_cast<TOperator*>(next->get());
215                   throw_if(no->getOperatorType() != "-",
216                            "group two successive operators");
217                   auto nnext = std::next(next);
218                   throw_if(nnext == this->subExpr.end(),
219                            "group ends by operator '" + op + "'");
220                   throw_if((*nnext)->isOperator(),
221                            "group two successive operators");
222                   *nnext =
223                       std::shared_ptr<Evaluator::TExpr>(new TNegation(*nnext));
224                   next = this->subExpr.erase(next);
225                   p = next - 1;
226                   previous = next - 2;
227                 }
228                 *previous = std::shared_ptr<Evaluator::TExpr>(
229                     new TBinaryOperation(*previous, o, *next));
230                 ++next;
231                 p = this->subExpr.erase(p, next);
232                 --p;
233               }
234             }
235           }
236         }
237         ++p;
238       }
239     }  // end of Evaluator::TGroup::reduce
240 
TFunction(Evaluator::FunctionGenerator f_,std::shared_ptr<Evaluator::TExpr> g_)241     Evaluator::TFunction::TFunction(Evaluator::FunctionGenerator f_,
242                                     std::shared_ptr<Evaluator::TExpr> g_)
243         : f(f_), arg(std::move(g_)) {}
244 
isOperator() const245     bool Evaluator::TFunction::isOperator() const { return false; }
246 
analyse()247     parser::ExprPtr Evaluator::TFunction::analyse() {
248       return (this->f)(this->arg->analyse());
249     }
250 
reduce()251     void Evaluator::TFunction::reduce() { this->arg->reduce(); }
252 
253     Evaluator::TFunction::~TFunction() = default;
254 
TBinaryFunction(Evaluator::BinaryFunctionGenerator f_,std::shared_ptr<Evaluator::TExpr> a1_,std::shared_ptr<Evaluator::TExpr> a2_)255     Evaluator::TBinaryFunction::TBinaryFunction(
256         Evaluator::BinaryFunctionGenerator f_,
257         std::shared_ptr<Evaluator::TExpr> a1_,
258         std::shared_ptr<Evaluator::TExpr> a2_)
259         : f(f_), arg1(std::move(a1_)), arg2(std::move(a2_)) {}
260 
isOperator() const261     bool Evaluator::TBinaryFunction::isOperator() const { return false; }
262 
analyse()263     parser::ExprPtr Evaluator::TBinaryFunction::analyse() {
264       return (this->f)(this->arg1->analyse(), this->arg2->analyse());
265     }
266 
reduce()267     void Evaluator::TBinaryFunction::reduce() {
268       this->arg1->reduce();
269       this->arg2->reduce();
270     }
271 
272     Evaluator::TBinaryFunction::~TBinaryFunction() = default;
273 
TNumber(const std::string & s,const double v)274     Evaluator::TNumber::TNumber(const std::string& s, const double v)
275         : str(s), value(v) {}
276 
isOperator() const277     bool Evaluator::TNumber::isOperator() const { return false; }
278 
analyse()279     parser::ExprPtr Evaluator::TNumber::analyse() {
280       using namespace tfel::math::parser;
281       return ExprPtr(new Number(this->str, this->value));
282     }
283 
reduce()284     void Evaluator::TNumber::reduce() {}
285 
TExternalFunctionExpr(const std::string & fname,std::vector<std::shared_ptr<Evaluator::TExpr>> & fargs,std::shared_ptr<tfel::math::parser::ExternalFunctionManager> & m)286     Evaluator::TExternalFunctionExpr::TExternalFunctionExpr(
287         const std::string& fname,
288         std::vector<std::shared_ptr<Evaluator::TExpr>>& fargs,
289         std::shared_ptr<tfel::math::parser::ExternalFunctionManager>& m)
290         : name(fname),
291           args(fargs),
292           manager(m) {}  // end of TExternalFunctionExpr
293 
isOperator() const294     bool Evaluator::TExternalFunctionExpr::isOperator() const { return false; }
295 
analyse()296     parser::ExprPtr Evaluator::TExternalFunctionExpr::analyse() {
297       using namespace tfel::math::parser;
298       auto r = std::vector<ExprPtr>{};
299       for (auto& a : this->args) {
300         r.push_back(a->analyse());
301       }
302       return ExprPtr(new ExternalFunctionExpr(name, r, this->manager));
303     }
304 
reduce()305     void Evaluator::TExternalFunctionExpr::reduce() {
306       for (auto& a : this->args) {
307         a->reduce();
308       }
309     }
310 
311     Evaluator::TExternalFunctionExpr::~TExternalFunctionExpr() noexcept =
312         default;
313 
TDifferentiatedFunctionExpr(std::shared_ptr<ExternalFunction> ff,std::vector<std::shared_ptr<Evaluator::TExpr>> & fargs,const std::vector<std::vector<double>::size_type> & fvar)314     Evaluator::TDifferentiatedFunctionExpr::TDifferentiatedFunctionExpr(
315         std::shared_ptr<ExternalFunction> ff,
316         std::vector<std::shared_ptr<Evaluator::TExpr>>& fargs,
317         const std::vector<std::vector<double>::size_type>& fvar)
318         : f(std::move(ff)),
319           args(fargs),
320           var(fvar) {}  // end of TDifferentiatedFunctionExpr
321 
isOperator() const322     bool Evaluator::TDifferentiatedFunctionExpr::isOperator() const {
323       return false;
324     }
325 
analyse()326     parser::ExprPtr Evaluator::TDifferentiatedFunctionExpr::analyse() {
327       using namespace tfel::math::parser;
328       auto r = std::vector<ExprPtr>{};
329       for (const auto& a : this->args) {
330         r.push_back(a->analyse());
331       }
332       return ExprPtr(new DifferentiatedFunctionExpr(this->f, r, this->var));
333     }
334 
reduce()335     void Evaluator::TDifferentiatedFunctionExpr::reduce() {
336       for (auto& a : this->args) {
337         a->reduce();
338       }
339     }
340 
TConditionalExpr(std::shared_ptr<Evaluator::TLogicalExpr> c_,std::shared_ptr<Evaluator::TExpr> a_,std::shared_ptr<Evaluator::TExpr> b_)341     Evaluator::TConditionalExpr::TConditionalExpr(
342         std::shared_ptr<Evaluator::TLogicalExpr> c_,
343         std::shared_ptr<Evaluator::TExpr> a_,
344         std::shared_ptr<Evaluator::TExpr> b_)
345         : c(std::move(c_)),
346           a(std::move(a_)),
347           b(std::move(b_)) {
348     }  // end of Evaluator::TConditionalExpr::TConditionalExpr
349 
isOperator() const350     bool Evaluator::TConditionalExpr::isOperator() const {
351       return false;
352     }  // end of Evaluator::TConditionalExpr::isOperator
353 
reduce()354     void Evaluator::TConditionalExpr::reduce() {
355       this->c->reduce();
356       this->a->reduce();
357       this->b->reduce();
358     }  // end of Evaluator::TConditionalExpr::reduce
359 
analyse()360     parser::ExprPtr Evaluator::TConditionalExpr::analyse() {
361       using namespace tfel::math::parser;
362       return ExprPtr(new ConditionalExpr(this->c->analyse(), this->a->analyse(),
363                                          this->b->analyse()));
364     }  // end of Evaluator::TConditionalExpr::analyse
365 
366     Evaluator::TDifferentiatedFunctionExpr::
367         ~TDifferentiatedFunctionExpr() noexcept = default;
368 
369     Evaluator::TConditionalExpr::~TConditionalExpr() = default;
370 
TExternalOperator(const Evaluator::ExternalFunctionGenerator f_,const std::vector<std::string> & param_,std::vector<std::shared_ptr<Evaluator::TExpr>> & a_)371     Evaluator::TExternalOperator::TExternalOperator(
372         const Evaluator::ExternalFunctionGenerator f_,
373         const std::vector<std::string>& param_,
374         std::vector<std::shared_ptr<Evaluator::TExpr>>& a_)
375         : f(f_),
376           param(param_),
377           args(a_) {}  // end of Evaluator::TExternalOperator::TExternalOperator
378 
isOperator() const379     bool Evaluator::TExternalOperator::isOperator() const {
380       return false;
381     }  // end of Evaluator::TExternalOperator::isOperator() const
382 
analyse()383     parser::ExprPtr Evaluator::TExternalOperator::analyse() {
384       using namespace tfel::math::parser;
385       auto r = std::vector<ExprPtr>{};
386       for (auto& a : this->args) {
387         r.push_back(a->analyse());
388       }
389       return (*(this->f))(this->param, r);
390     }  // end of Evaluator::TExternalOperator::analyse()
391 
reduce()392     void Evaluator::TExternalOperator::reduce() {
393       for (auto& a : this->args) {
394         a->reduce();
395       }
396     }  // end of Evaluator::TExternalOperator::reduce()
397 
398     Evaluator::TExternalOperator::~TExternalOperator() = default;
399 
400   }  // end of namespace math
401 
402 }  // end of namespace tfel
403