2019-06-19 14:34:30 +02:00
|
|
|
/*
|
|
|
|
* Copyright © 2005 Ondra Kamenik
|
|
|
|
* Copyright © 2019 Dynare Team
|
|
|
|
*
|
|
|
|
* This file is part of Dynare.
|
|
|
|
*
|
|
|
|
* Dynare is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* Dynare is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with Dynare. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
2019-01-08 17:12:05 +01:00
|
|
|
|
|
|
|
#include "utils/cc/pascal_triangle.hh"
|
|
|
|
#include "utils/cc/exception.hh"
|
|
|
|
|
|
|
|
#include "parser_exception.hh"
|
|
|
|
#include "location.hh"
|
|
|
|
#include "formula_parser.hh"
|
|
|
|
#include "formula_tab.hh"
|
|
|
|
|
|
|
|
#include <cmath>
|
2019-04-19 17:09:04 +02:00
|
|
|
#include <algorithm>
|
2019-01-08 17:12:05 +01:00
|
|
|
|
|
|
|
using namespace ogp;
|
|
|
|
|
|
|
|
extern location_type fmla_lloc;
|
|
|
|
|
|
|
|
FormulaParser::FormulaParser(const FormulaParser &fp, Atoms &a)
|
|
|
|
: otree(fp.otree), atoms(a), formulas(fp.formulas), ders()
|
|
|
|
{
|
|
|
|
// create derivatives
|
2019-04-19 17:09:04 +02:00
|
|
|
for (const auto &der : fp.ders)
|
|
|
|
ders.push_back(std::make_unique<FormulaDerivatives>(*der));
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
FormulaParser::differentiate(int max_order)
|
|
|
|
{
|
2019-04-19 17:09:04 +02:00
|
|
|
ders.clear();
|
2019-01-08 17:12:05 +01:00
|
|
|
vector<int> vars;
|
|
|
|
vars = atoms.variables();
|
2019-01-09 15:44:26 +01:00
|
|
|
for (int formula : formulas)
|
2019-04-19 17:09:04 +02:00
|
|
|
ders.push_back(std::make_unique<FormulaDerivatives>(otree, vars, formula, max_order));
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
const FormulaDerivatives &
|
|
|
|
FormulaParser::derivatives(int i) const
|
|
|
|
{
|
2019-04-19 17:09:04 +02:00
|
|
|
if (i < static_cast<int>(ders.size()))
|
2019-01-08 17:12:05 +01:00
|
|
|
return *(ders[i]);
|
|
|
|
else
|
|
|
|
throw ogu::Exception(__FILE__, __LINE__,
|
|
|
|
"Wrong formula index in FormulaParser::derivatives");
|
|
|
|
return *(ders[0]); // just because of compiler
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
FormulaParser::add_formula(int t)
|
|
|
|
{
|
|
|
|
formulas.push_back(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
FormulaParser::add_binary(code_t code, int t1, int t2)
|
|
|
|
{
|
|
|
|
return otree.add_binary(code, t1, t2);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
FormulaParser::add_unary(code_t code, int t)
|
|
|
|
{
|
|
|
|
return otree.add_unary(code, t);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2019-04-24 14:52:30 +02:00
|
|
|
FormulaParser::add_nulary(const string &str)
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
|
|
|
int t = -1;
|
|
|
|
try
|
|
|
|
{
|
|
|
|
t = atoms.check(str);
|
|
|
|
}
|
|
|
|
catch (const ParserException &e)
|
|
|
|
{
|
|
|
|
throw ParserException(e, fmla_lloc.off);
|
|
|
|
}
|
|
|
|
if (t == -1)
|
|
|
|
{
|
|
|
|
t = otree.add_nulary();
|
|
|
|
atoms.assign(str, t);
|
|
|
|
}
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
FormulaParser::add_subst_formulas(const map<int, int> &subst, const FormulaParser &fp)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < fp.nformulas(); i++)
|
|
|
|
{
|
|
|
|
int f = add_substitution(fp.formula(i), subst, fp);
|
|
|
|
add_formula(f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
FormulaParser::substitute_formulas(const map<int, int> &smap)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < nformulas(); i++)
|
|
|
|
{
|
|
|
|
// make substitution and replace the formula for it
|
|
|
|
int f = add_substitution(formulas[i], smap);
|
|
|
|
formulas[i] = f;
|
|
|
|
// update the derivatives if any
|
2019-04-19 17:09:04 +02:00
|
|
|
if (i < static_cast<int>(ders.size()) && ders[i])
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
|
|
|
int order = ders[i]->get_order();
|
2019-04-19 17:09:04 +02:00
|
|
|
ders[i] = std::make_unique<FormulaDerivatives>(otree, atoms.variables(), formulas[i], order);
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Global symbols for passing info to parser. */
|
|
|
|
FormulaParser *fparser;
|
|
|
|
|
|
|
|
/** The declarations of functions defined in formula_ll.cc and
|
|
|
|
* formula_tab.cc generated from formula.lex and formula.y */
|
2019-04-24 14:52:30 +02:00
|
|
|
void *fmla__scan_string(const char *);
|
2019-01-08 17:12:05 +01:00
|
|
|
void fmla__destroy_buffer(void *);
|
|
|
|
int fmla_parse();
|
|
|
|
extern location_type fmla_lloc;
|
|
|
|
|
|
|
|
/** This makes own copy of provided data, sets the buffer for the
|
|
|
|
* parser with fmla_scan_buffer, and launches fmla_parse(). Note that
|
|
|
|
* the pointer returned from fmla_scan_buffer must be freed at the
|
|
|
|
* end. */
|
|
|
|
void
|
2019-04-24 14:52:30 +02:00
|
|
|
FormulaParser::parse(const string &stream)
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
|
|
|
fmla_lloc.off = 0;
|
|
|
|
fmla_lloc.ll = 0;
|
2019-04-24 14:52:30 +02:00
|
|
|
void *p = fmla__scan_string(stream.c_str());
|
2019-01-08 17:12:05 +01:00
|
|
|
fparser = this;
|
|
|
|
fmla_parse();
|
|
|
|
fmla__destroy_buffer(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-04-24 14:52:30 +02:00
|
|
|
FormulaParser::error(string mes) const
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
2019-04-24 14:52:30 +02:00
|
|
|
throw ParserException(std::move(mes), fmla_lloc.off);
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
FormulaParser::last_formula() const
|
|
|
|
{
|
|
|
|
int res = -1;
|
2019-01-09 15:44:26 +01:00
|
|
|
for (int formula : formulas)
|
2019-04-19 17:09:04 +02:00
|
|
|
res = std::max(res, formula);
|
2019-01-08 17:12:05 +01:00
|
|
|
return std::max(res, otree.get_last_nulary());
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
FormulaParser::pop_last_formula()
|
|
|
|
{
|
|
|
|
if (formulas.size() == 0)
|
|
|
|
return -1;
|
|
|
|
int t = formulas.back();
|
|
|
|
if (formulas.size() == ders.size())
|
2019-04-19 17:09:04 +02:00
|
|
|
ders.pop_back();
|
2019-01-08 17:12:05 +01:00
|
|
|
formulas.pop_back();
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
FormulaParser::print() const
|
|
|
|
{
|
|
|
|
atoms.print();
|
2019-01-09 15:44:26 +01:00
|
|
|
for (int formula : formulas)
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
2019-04-24 14:52:30 +02:00
|
|
|
std::cout << "formula " << formula << ":\n";
|
2019-01-09 15:44:26 +01:00
|
|
|
otree.print_operation(formula);
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
for (unsigned int i = 0; i < ders.size(); i++)
|
|
|
|
{
|
2019-04-24 14:52:30 +02:00
|
|
|
std::cout << "derivatives for the formula " << formulas[i] << ":\n";
|
2019-01-08 17:12:05 +01:00
|
|
|
ders[i]->print(otree);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** This constructor makes a vector of indices for formulas
|
|
|
|
* corresponding to derivatives of the given formula. The formula is
|
|
|
|
* supposed to belong to the provided tree, the created derivatives
|
|
|
|
* are added to the tree.
|
|
|
|
*
|
|
|
|
* The algorithm is as follows. todo: update description of the
|
|
|
|
* algorithm
|
|
|
|
*/
|
|
|
|
FormulaDerivatives::FormulaDerivatives(OperationTree &otree,
|
|
|
|
const vector<int> &vars, int f, int max_order)
|
|
|
|
: nvar(vars.size()), order(max_order)
|
|
|
|
{
|
|
|
|
FoldMultiIndex fmi_zero(nvar);
|
|
|
|
tder.push_back(f);
|
|
|
|
indices.push_back(fmi_zero);
|
|
|
|
unsigned int last_order_beg = 0;
|
|
|
|
unsigned int last_order_end = tder.size();
|
|
|
|
|
|
|
|
for (int k = 1; k <= order; k++)
|
|
|
|
{
|
|
|
|
// interval <last_order_beg,last_order_end) is guaranteed
|
|
|
|
// here to contain at least one item
|
|
|
|
for (unsigned int run = last_order_beg; run < last_order_end; run++)
|
|
|
|
{
|
|
|
|
// shift one order from the run
|
|
|
|
FoldMultiIndex fmi(indices[run], 1);
|
|
|
|
// set starting variable from the run, note that if k=1,
|
|
|
|
// the shift order ctor of fmi will set it to zero
|
|
|
|
int ivar_start = fmi[k-1];
|
|
|
|
for (int ivar = ivar_start; ivar < nvar; ivar++, fmi.increment())
|
|
|
|
{
|
|
|
|
int der = otree.add_derivative(tder[run], vars[ivar]);
|
|
|
|
if (der != OperationTree::zero)
|
|
|
|
{
|
|
|
|
tder.push_back(der);
|
|
|
|
indices.push_back(fmi);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// set new last_order_beg and last_order_end
|
|
|
|
last_order_beg = last_order_end;
|
|
|
|
last_order_end = tder.size();
|
|
|
|
// if there was no new derivative, break out from the loop
|
|
|
|
if (last_order_beg >= last_order_end)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// build ind2der map
|
|
|
|
for (unsigned int i = 0; i < indices.size(); i++)
|
2019-04-19 17:09:04 +02:00
|
|
|
ind2der.emplace(indices[i], i);
|
2019-01-08 17:12:05 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-04-19 17:09:04 +02:00
|
|
|
FormulaDerivatives::FormulaDerivatives(const FormulaDerivatives &fd) = default;
|
2019-01-08 17:12:05 +01:00
|
|
|
|
|
|
|
int
|
|
|
|
FormulaDerivatives::derivative(const FoldMultiIndex &mi) const
|
|
|
|
{
|
|
|
|
if (mi.order() > order)
|
|
|
|
throw ogu::Exception(__FILE__, __LINE__,
|
|
|
|
"Wrong order of multi-index in FormulaDerivatives::derivative");
|
|
|
|
if (mi.nv() != nvar)
|
|
|
|
throw ogu::Exception(__FILE__, __LINE__,
|
|
|
|
"Wrong multi-index variables in FormulaDerivatives::derivative");
|
|
|
|
|
2019-01-09 15:51:19 +01:00
|
|
|
auto it = ind2der.find(mi);
|
2019-01-08 17:12:05 +01:00
|
|
|
if (it == ind2der.end())
|
|
|
|
return OperationTree::zero;
|
|
|
|
else
|
2019-04-19 17:09:04 +02:00
|
|
|
return tder[it->second];
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
FormulaDerivatives::print(const OperationTree &otree) const
|
|
|
|
{
|
2019-01-09 15:44:26 +01:00
|
|
|
for (const auto & it : ind2der)
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
2019-04-24 14:52:30 +02:00
|
|
|
std::cout << "derivative ";
|
2019-01-09 15:44:26 +01:00
|
|
|
it.first.print();
|
2019-04-24 14:52:30 +02:00
|
|
|
std::cout << " is formula " << tder[it.second] << '\n';
|
2019-01-09 15:44:26 +01:00
|
|
|
otree.print_operation(tder[it.second]);
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
FormulaCustomEvaluator::eval(const AtomValues &av, FormulaEvalLoader &loader)
|
|
|
|
{
|
|
|
|
etree.reset_all();
|
|
|
|
av.setValues(etree);
|
|
|
|
for (unsigned int i = 0; i < terms.size(); i++)
|
|
|
|
{
|
|
|
|
double res = etree.eval(terms[i]);
|
2019-04-19 17:09:04 +02:00
|
|
|
loader.load(static_cast<int>(i), res);
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
FoldMultiIndex::FoldMultiIndex(int nv)
|
2019-04-19 17:09:04 +02:00
|
|
|
: nvar(nv), ord(0), data(std::make_unique<int[]>(ord))
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
FoldMultiIndex::FoldMultiIndex(int nv, int ordd, int ii)
|
2019-04-19 17:09:04 +02:00
|
|
|
: nvar(nv), ord(ordd), data(std::make_unique<int[]>(ord))
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
|
|
|
for (int i = 0; i < ord; i++)
|
|
|
|
data[i] = ii;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Note that a monotone sequence mapped by monotone mapping yields a
|
|
|
|
* monotone sequence. */
|
|
|
|
FoldMultiIndex::FoldMultiIndex(int nv, const FoldMultiIndex &mi, const vector<int> &mp)
|
2019-04-19 17:09:04 +02:00
|
|
|
: nvar(nv), ord(mi.ord), data(std::make_unique<int[]>(ord))
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
|
|
|
for (int i = 0; i < ord; i++)
|
|
|
|
{
|
|
|
|
if (i < ord-1 && mp[i+1] < mp[i])
|
|
|
|
throw ogu::Exception(__FILE__, __LINE__,
|
|
|
|
"Mapping not monotone in FoldMultiIndex constructor");
|
|
|
|
if (mp[mi[i]] >= nv || mp[mi[i]] < 0)
|
|
|
|
throw ogu::Exception(__FILE__, __LINE__,
|
|
|
|
"Mapping out of bounds in FoldMultiIndex constructor");
|
|
|
|
data[i] = mp[mi[i]];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
FoldMultiIndex::FoldMultiIndex(const FoldMultiIndex &fmi, int new_orders)
|
|
|
|
: nvar(fmi.nvar),
|
|
|
|
ord(fmi.ord+new_orders),
|
2019-04-19 17:09:04 +02:00
|
|
|
data(std::make_unique<int[]>(ord))
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
2019-04-19 17:09:04 +02:00
|
|
|
std::copy_n(fmi.data.get(), fmi.ord, data.get());
|
2019-01-08 17:12:05 +01:00
|
|
|
int new_item = (fmi.ord > 0) ? fmi.data[fmi.ord-1] : 0;
|
|
|
|
for (int i = fmi.ord; i < ord; i++)
|
2019-04-19 17:09:04 +02:00
|
|
|
data[i] = new_item;
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
FoldMultiIndex::FoldMultiIndex(const FoldMultiIndex &fmi)
|
|
|
|
: nvar(fmi.nvar),
|
|
|
|
ord(fmi.ord),
|
2019-04-19 17:09:04 +02:00
|
|
|
data(std::make_unique<int[]>(ord))
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
2019-04-19 17:09:04 +02:00
|
|
|
std::copy_n(fmi.data.get(), ord, data.get());
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
const FoldMultiIndex &
|
|
|
|
FoldMultiIndex::operator=(const FoldMultiIndex &fmi)
|
|
|
|
{
|
|
|
|
if (ord != fmi.ord)
|
2019-04-19 17:09:04 +02:00
|
|
|
data = std::make_unique<int[]>(fmi.ord);
|
2019-01-08 17:12:05 +01:00
|
|
|
|
|
|
|
ord = fmi.ord;
|
|
|
|
nvar = fmi.nvar;
|
2019-04-19 17:09:04 +02:00
|
|
|
std::copy_n(fmi.data.get(), ord, data.get());
|
2019-01-08 17:12:05 +01:00
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
FoldMultiIndex::operator<(const FoldMultiIndex &fmi) const
|
|
|
|
{
|
|
|
|
if (nvar != fmi.nvar)
|
|
|
|
ogu::Exception(__FILE__, __LINE__,
|
|
|
|
"Different nvar in FoldMultiIndex::operator<");
|
|
|
|
|
|
|
|
if (ord < fmi.ord)
|
|
|
|
return true;
|
|
|
|
if (ord > fmi.ord)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
while (i < ord && data[i] == fmi.data[i])
|
|
|
|
i++;
|
|
|
|
if (i == ord)
|
|
|
|
return false;
|
|
|
|
else
|
|
|
|
return data[i] < fmi.data[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
FoldMultiIndex::operator==(const FoldMultiIndex &fmi) const
|
|
|
|
{
|
|
|
|
bool res = true;
|
|
|
|
res = res && (nvar == fmi.nvar) && (ord == fmi.ord);
|
|
|
|
if (res)
|
|
|
|
for (int i = 0; i < ord; i++)
|
|
|
|
if (data[i] != fmi.data[i])
|
|
|
|
return false;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
FoldMultiIndex::increment()
|
|
|
|
{
|
|
|
|
if (ord == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
int k = ord-1;
|
|
|
|
data[k]++;
|
|
|
|
while (k > 0 && data[k] == nvar)
|
|
|
|
{
|
|
|
|
data[k] = 0;
|
|
|
|
data[--k]++;
|
|
|
|
}
|
|
|
|
for (int kk = 1; kk < ord; kk++)
|
|
|
|
if (data[kk-1] > data[kk])
|
|
|
|
data[kk] = data[kk-1];
|
|
|
|
}
|
|
|
|
|
|
|
|
// For description of an algorithm for calculation of folded offset,
|
|
|
|
// see Tensor Library Documentation, Ondra Kamenik, 2005, description
|
|
|
|
// of FTensor::getOffsetRecurse().
|
|
|
|
int
|
|
|
|
FoldMultiIndex::offset() const
|
|
|
|
{
|
|
|
|
// make copy for the recursions
|
2019-04-19 17:09:04 +02:00
|
|
|
auto tmp = std::make_unique<int[]>(ord);
|
|
|
|
std::copy_n(data.get(), ord, tmp.get());
|
2019-01-08 17:12:05 +01:00
|
|
|
// call the recursive algorithm
|
2019-04-19 17:09:04 +02:00
|
|
|
int res = offset_recurse(tmp.get(), ord, nvar);
|
2019-01-08 17:12:05 +01:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
FoldMultiIndex::print() const
|
|
|
|
{
|
2019-04-24 14:52:30 +02:00
|
|
|
std::cout << "[";
|
2019-01-08 17:12:05 +01:00
|
|
|
for (int i = 0; i < ord; i++)
|
2019-04-24 14:52:30 +02:00
|
|
|
std::cout << data[i] << ' ';
|
|
|
|
std::cout << "]";
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
FoldMultiIndex::offset_recurse(int *data, int len, int nv)
|
|
|
|
{
|
|
|
|
if (len == 0)
|
|
|
|
return 0;
|
|
|
|
// calculate length of initial constant indices
|
|
|
|
int prefix = 1;
|
|
|
|
while (prefix < len && data[0] == data[prefix])
|
|
|
|
prefix++;
|
|
|
|
|
|
|
|
int m = data[0];
|
2019-02-19 15:57:19 +01:00
|
|
|
int s1 = PascalTriangle::noverk(nv+len-1, len) - PascalTriangle::noverk(nv-m+len-1, len);
|
2019-01-08 17:12:05 +01:00
|
|
|
|
|
|
|
// cancel m from the rest of the sequence
|
|
|
|
for (int i = prefix; i < len; i++)
|
|
|
|
data[i] -= m;
|
|
|
|
|
|
|
|
// calculate offset of the remaining sequence
|
|
|
|
int s2 = offset_recurse(data+prefix, len-prefix, nv-m);
|
|
|
|
// return the sum
|
|
|
|
return s1+s2;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
ltfmi::operator()(const FoldMultiIndex &i1, const FoldMultiIndex &i2) const
|
|
|
|
{
|
|
|
|
return i1 < i2;
|
|
|
|
}
|
|
|
|
|
|
|
|
FormulaDerEvaluator::FormulaDerEvaluator(const FormulaParser &fp)
|
|
|
|
: etree(fp.otree, -1)
|
|
|
|
{
|
2019-04-19 17:09:04 +02:00
|
|
|
for (const auto &der : fp.ders)
|
|
|
|
ders.push_back(der.get());
|
2019-01-08 17:12:05 +01:00
|
|
|
|
|
|
|
der_atoms = fp.atoms.variables();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
FormulaDerEvaluator::eval(const AtomValues &av, FormulaDerEvalLoader &loader, int order)
|
|
|
|
{
|
|
|
|
if (ders.size() == 0)
|
|
|
|
return;
|
|
|
|
int maxorder = ders[0]->order;
|
|
|
|
|
|
|
|
if (order > maxorder)
|
|
|
|
throw ogu::Exception(__FILE__, __LINE__,
|
|
|
|
"Wrong order in FormulaDerEvaluator::eval");
|
|
|
|
|
|
|
|
etree.reset_all();
|
|
|
|
av.setValues(etree);
|
|
|
|
|
2019-04-19 17:09:04 +02:00
|
|
|
auto vars = std::make_unique<int[]>(order);
|
2019-01-08 17:12:05 +01:00
|
|
|
|
|
|
|
for (unsigned int i = 0; i < ders.size(); i++)
|
|
|
|
{
|
2019-04-19 17:09:04 +02:00
|
|
|
for (const auto &it : ders[i]->ind2der)
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
2019-04-19 17:09:04 +02:00
|
|
|
const FoldMultiIndex &mi = it.first;
|
2019-01-08 17:12:05 +01:00
|
|
|
if (mi.order() == order)
|
|
|
|
{
|
|
|
|
// set vars from multiindex mi and variables
|
|
|
|
for (int k = 0; k < order; k++)
|
|
|
|
vars[k] = der_atoms[mi[k]];
|
|
|
|
// evaluate
|
2019-04-19 17:09:04 +02:00
|
|
|
double res = etree.eval(ders[i]->tder[it.second]);
|
2019-01-08 17:12:05 +01:00
|
|
|
// load
|
2019-04-19 17:09:04 +02:00
|
|
|
loader.load(i, order, vars.get(), res);
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
FormulaDerEvaluator::eval(const vector<int> &mp, const AtomValues &av,
|
|
|
|
FormulaDerEvalLoader &loader, int order)
|
|
|
|
{
|
|
|
|
etree.reset_all();
|
|
|
|
av.setValues(etree);
|
|
|
|
|
|
|
|
int nvar_glob = der_atoms.size();
|
|
|
|
int nvar = mp.size();
|
2019-04-19 17:09:04 +02:00
|
|
|
auto vars = std::make_unique<int[]>(order);
|
2019-01-08 17:12:05 +01:00
|
|
|
|
|
|
|
for (unsigned int i = 0; i < ders.size(); i++)
|
|
|
|
{
|
|
|
|
FoldMultiIndex mi(nvar, order);
|
|
|
|
do
|
|
|
|
{
|
|
|
|
// find index of the derivative in the tensor
|
|
|
|
FoldMultiIndex mi_glob(nvar_glob, mi, mp);
|
|
|
|
int der = ders[i]->derivative(mi_glob);
|
|
|
|
if (der != OperationTree::zero)
|
|
|
|
{
|
|
|
|
// set vars from the global multiindex
|
|
|
|
for (int k = 0; k < order; k++)
|
|
|
|
vars[k] = der_atoms[mi_glob[k]];
|
|
|
|
// evaluate derivative
|
|
|
|
double res = etree.eval(der);
|
|
|
|
// load
|
2019-04-19 17:09:04 +02:00
|
|
|
loader.load(i, order, vars.get(), res);
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
mi.increment();
|
|
|
|
}
|
|
|
|
while (!mi.past_the_end());
|
|
|
|
}
|
|
|
|
}
|