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