1 /*!
2  * \file   src/Math/DifferentiatedFunctionExpr.cxx
3  * \brief
4  *
5  * \author Thomas Helfer
6  * \date   02 oct 2007
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 <sstream>
16 #include <stdexcept>
17 
18 #include "TFEL/Raise.hxx"
19 #include "TFEL/Math/Parser/Number.hxx"
20 #include "TFEL/Math/Parser/Variable.hxx"
21 #include "TFEL/Math/Parser/BinaryOperator.hxx"
22 #include "TFEL/Math/Parser/ExternalFunctionExpr2.hxx"
23 #include "TFEL/Math/Parser/DifferentiatedFunctionExpr.hxx"
24 
25 namespace tfel {
26 
27   namespace math {
28 
29     namespace parser {
30 
DifferentiatedFunctionExpr(std::shared_ptr<ExternalFunction> ff,std::vector<std::shared_ptr<Expr>> & fargs,const std::vector<std::vector<double>::size_type> & fpvar)31       DifferentiatedFunctionExpr::DifferentiatedFunctionExpr(
32           std::shared_ptr<ExternalFunction> ff,
33           std::vector<std::shared_ptr<Expr>>& fargs,
34           const std::vector<std::vector<double>::size_type>& fpvar)
35           : f(std::move(ff)), args(fargs), pvar(fpvar) {
36         raise_if(f->getNumberOfVariables() != args.size(),
37                  "DifferentiatedFunctionExpr::DifferentiatedFunctionExpr: "
38                  "invalid number of arguments for function "
39                  "(" +
40                      std::to_string(this->args.size()) + " given, " +
41                      std::to_string(f->getNumberOfVariables()) + " required)");
42       }  // end of DifferentiatedFunctionExpr::DifferentiatedFunctionExpr
43 
44       std::shared_ptr<ExternalFunction>
getDerivative() const45       DifferentiatedFunctionExpr::getDerivative() const {
46         auto df = this->f;
47         for (const auto& p : this->pvar) {
48           df = df->differentiate(p);
49         }
50         return df;
51       }  // end of DifferentiatedFunctionExpr::getDerivative
52 
getValue() const53       double DifferentiatedFunctionExpr::getValue() const {
54         auto df = this->getDerivative();
55         decltype(this->args.size()) i = 0u;
56         for (const auto& a : this->args) {
57           const auto val = a->getValue();
58           df->setVariableValue(i, val);
59           ++i;
60         }
61         return df->getValue();
62       }  // end of DifferentiatedFunctionExpr::getValue
63 
getCxxFormula(const std::vector<std::string> &) const64       std::string DifferentiatedFunctionExpr::getCxxFormula(
65           const std::vector<std::string>&) const {
66         tfel::raise(
67             "DifferentiatedFunctionExpr::getCxxFormula: "
68             "unimplemented feature");
69       }  // end of DifferentiatedFunctionExpr::getCxxFormula
70 
checkCyclicDependency(std::vector<std::string> & names) const71       void DifferentiatedFunctionExpr::checkCyclicDependency(
72           std::vector<std::string>& names) const {
73         std::vector<std::string> v(names);
74         this->f->checkCyclicDependency(names);
75         for (const auto& a : this->args) {
76           std::vector<std::string> n(v);
77           a->checkCyclicDependency(n);
78           mergeVariablesNames(names, n);
79         }
80       }  // end of DifferentiatedFunctionExpr::checkCyclicDependency
81 
differentiate(const std::vector<double>::size_type pos,const std::vector<double> & v) const82       std::shared_ptr<Expr> DifferentiatedFunctionExpr::differentiate(
83           const std::vector<double>::size_type pos,
84           const std::vector<double>& v) const {
85         std::vector<std::shared_ptr<Expr>> nargs(this->args.size());
86         auto p = this->args.begin();
87         unsigned short i = 0;
88         if (args.empty()) {
89           return std::make_shared<Number>("0", 0.);
90         }
91         auto p4 = nargs.begin();
92         for (const auto& a : this->args) {
93           *p4 = a->clone(v);
94           ++p4;
95         }
96         auto ndf = this->getDerivative();
97         auto df_ = std::make_shared<ExternalFunctionExpr2>(
98             ndf->differentiate(i), nargs);
99         std::shared_ptr<Expr> df = std::make_shared<BinaryOperation<OpMult>>(
100             df_, (*p)->differentiate(pos, v));
101         ++p;
102         ++i;
103         while (p != this->args.end()) {
104           df_ = std::make_shared<ExternalFunctionExpr2>(ndf->differentiate(i),
105                                                         nargs);
106           std::shared_ptr<Expr> df2 = std::make_shared<BinaryOperation<OpMult>>(
107               df_, (*p)->differentiate(pos, v));
108           df = std::make_shared<BinaryOperation<OpPlus>>(df, df2);
109           ++p;
110           ++i;
111         }
112         return df;
113       }  // end of DifferentiatedFunctionExpr::differentiate
114 
clone(const std::vector<double> & v) const115       std::shared_ptr<Expr> DifferentiatedFunctionExpr::clone(
116           const std::vector<double>& v) const {
117         std::vector<std::shared_ptr<Expr>> nargs(this->args.size());
118         auto p = nargs.begin();
119         for (const auto& a : this->args) {
120           *p = a->clone(v);
121         }
122         return std::make_shared<DifferentiatedFunctionExpr>(this->f, nargs,
123                                                             this->pvar);
124       }  // end of DifferentiatedFunctionExpr::clone
125 
126       std::shared_ptr<Expr> DifferentiatedFunctionExpr::
createFunctionByChangingParametersIntoVariables(const std::vector<double> & v,const std::vector<std::string> & params,const std::map<std::string,std::vector<double>::size_type> & pos) const127           createFunctionByChangingParametersIntoVariables(
128               const std::vector<double>& v,
129               const std::vector<std::string>& params,
130               const std::map<std::string, std::vector<double>::size_type>& pos)
131               const {
132         using namespace std;
133         vector<shared_ptr<Expr>> nargs;
134         vector<string> vnames;
135         shared_ptr<ExternalFunction> nf;
136         vector<shared_ptr<Expr>>::const_iterator p;
137         vector<shared_ptr<Expr>>::iterator p2;
138         map<string, vector<double>::size_type>::const_iterator p3;
139         vector<string>::size_type i;
140         nf = this->f->createFunctionByChangingParametersIntoVariables(
141             vnames, v, params, pos);
142         raise_if(nf->getNumberOfVariables() <= this->args.size(),
143                  "ExternalFunctionExpr::getValue: "
144                  "internal error (function has less variable after "
145                  "'createFunctionByChangingParametersIntoVariables' "
146                  "than before");
147         nargs.resize(nf->getNumberOfVariables());
148         for (p = this->args.begin(), p2 = nargs.begin(); p != this->args.end();
149              ++p, ++p2) {
150           *p2 = (*p)->createFunctionByChangingParametersIntoVariables(v, params,
151                                                                       pos);
152         }
153         for (i = 0; i != vnames.size(); ++i) {
154           p3 = pos.find(vnames[i]);
155           raise_if(p3 == pos.end(),
156                    "ExternalFunctionExpr::"
157                    "createFunctionByChangingParametersIntoVariables: "
158                    "internal error (no position found for "
159                    "parameter '" +
160                        vnames[i] + "')");
161           nargs[args.size() + i] =
162               shared_ptr<Expr>(new Variable(v, p3->second));
163         }
164         return shared_ptr<Expr>(
165             new DifferentiatedFunctionExpr(nf, nargs, this->pvar));
166       }  // end of
167          // DifferentiatedFunctionExpr::createFunctionByChangingParametersIntoVariables
168 
getParametersNames(std::set<std::string> & p) const169       void DifferentiatedFunctionExpr::getParametersNames(
170           std::set<std::string>& p) const {
171         this->f->getParametersNames(p);
172         for (const auto& a : this->args) {
173           a->getParametersNames(p);
174         }
175       }  // end of DifferentiatedFunctionExpr::getParametersNames
176 
resolveDependencies(const std::vector<double> & v) const177       std::shared_ptr<Expr> DifferentiatedFunctionExpr::resolveDependencies(
178           const std::vector<double>& v) const {
179         using namespace std;
180         vector<shared_ptr<Expr>> nargs(this->args.size());
181         vector<shared_ptr<Expr>>::const_iterator p;
182         vector<shared_ptr<Expr>>::iterator p2;
183         for (p = this->args.begin(), p2 = nargs.begin(); p != this->args.end();
184              ++p, ++p2) {
185           *p2 = (*p)->resolveDependencies(v);
186         }
187         return std::make_shared<ExternalFunctionExpr2>(this->getDerivative(),
188                                                        nargs);
189       }  // end of DifferentiatedFunctionExpr::resolveDependencies
190 
191       DifferentiatedFunctionExpr::~DifferentiatedFunctionExpr() = default;
192 
193     }  // end of namespace parser
194 
195   }  // end of namespace math
196 
197 }  // end of namespace tfel
198