26#include <qle/math/compiledformula.hpp>
28#include <ql/errors.hpp>
29#include <ql/math/comparison.hpp>
31#include <boost/phoenix/core.hpp>
32#include <boost/phoenix/operator.hpp>
33#include <boost/spirit/include/qi.hpp>
46template <
class T> T
parseFormula(
const std::string& text,
const std::function<T(std::string)>& variableMapping = {});
50QuantExt::CompiledFormula
parseFormula(
const std::string& text, std::vector<std::string>& variables);
54inline double gtZero(
const double x) {
return x > 0.0 && !QuantLib::close_enough(x, 0.0) ? 1.0 : 0.0; }
55inline double geqZero(
const double x) {
return x > 0.0 || QuantLib::close_enough(x, 0.0) ? 1.0 : 0.0; }
56inline double max(
const double x,
const double y) {
return std::max(x, y); }
57inline double min(
const double x,
const double y) {
return std::min(x, y); }
62template <
class T> T
parseFormula(
const std::string& text,
const std::function<T(std::string)>& variableMapping) {
64 namespace fusion = boost::fusion;
65 namespace phoenix = boost::phoenix;
66 namespace qi = boost::spirit::qi;
67 namespace ascii = boost::spirit::ascii;
69 typedef std::string::const_iterator Iterator;
77 using namespace qi::labels;
79 qi::rule<Iterator, std::string(), ascii::space_type> variable;
80 qi::rule<Iterator, ascii::space_type> factor;
81 qi::rule<Iterator, ascii::space_type> term;
82 qi::rule<Iterator, ascii::space_type> expression;
84 std::stack<T> evalStack;
86 auto pushConstant = [&evalStack](
const double x) { evalStack.push(T(x)); };
87 auto pushVariable = [&variableMapping, &evalStack, &text](
const std::string& s) {
88 QL_REQUIRE(variableMapping,
"parseFormula(" << text <<
"): could not resolve variable \"" << s
89 <<
"\", because no variable mapping is given");
90 evalStack.push(variableMapping(s));
94 doUnaryOp(std::stack<T>& evalStack,
const std::function<T(T)>& op) : evalStack_(evalStack),
op_(op) {}
95 void operator()()
const {
96 QL_REQUIRE(evalStack_.size() > 0,
"parseFormula(): internal error, empty stack for unary operation");
97 T x = evalStack_.top();
102 std::stack<T>& evalStack_;
103 const std::function<T(T)>
op_;
107 doBinaryOp(std::stack<T>& evalStack,
const std::function<T(T, T)>& op) : evalStack_(evalStack),
op_(op) {}
108 void operator()()
const {
109 QL_REQUIRE(evalStack_.size() > 1,
110 "parseFormula(): internal error, stack size too small for binary operation");
111 T rhs = evalStack_.top();
113 T lhs = evalStack_.top();
115 evalStack_.push(
op_(lhs, rhs));
117 std::stack<T>& evalStack_;
118 const std::function<T(T, T)>
op_;
121 auto doNegate = doUnaryOp(evalStack, [](
const T& x) {
return -x; });
122 auto doAbs = doUnaryOp(evalStack, [](
const T& x) {
return abs(x); });
123 auto doGtZero = doUnaryOp(evalStack, [](
const T& x) {
return gtZero(x); });
124 auto doGeqZero = doUnaryOp(evalStack, [](
const T& x) {
return geqZero(x); });
125 auto doExp = doUnaryOp(evalStack, [](
const T& x) {
return exp(x); });
126 auto doLog = doUnaryOp(evalStack, [](
const T& x) {
return log(x); });
128 auto doMultiply = doBinaryOp(evalStack, [](
const T& x,
const T& y) {
return x * y; });
129 auto doDivide = doBinaryOp(evalStack, [](
const T& x,
const T& y) {
return x / y; });
130 auto doPlus = doBinaryOp(evalStack, [](
const T& x,
const T& y) {
return x + y; });
131 auto doMinus = doBinaryOp(evalStack, [](
const T& x,
const T& y) {
return x - y; });
132 auto doMax = doBinaryOp(evalStack, [](
const T& x,
const T& y) {
return max(x, y); });
133 auto doMin = doBinaryOp(evalStack, [](
const T& x,
const T& y) {
return min(x, y); });
134 auto doPow = doBinaryOp(evalStack, [](
const T& x,
const T& y) {
return pow(x, y); });
138 variable =
'{' >> lexeme[+(char_ -
'}') [_val += qi::labels::_1] ] >>
'}';
139 factor = double_ [ pushConstant ]
140 | variable [ pushVariable ]
141 |
'(' >> expression >>
')'
142 |
'-' >> factor [ doNegate ]
143 | lit(
"abs(") >> expression [ doAbs ] >>
')'
144 | lit(
"exp(") >> expression [ doExp ] >>
')'
145 | lit(
"gtZero(") >> expression [ doGtZero ] >>
')'
146 | lit(
"geqZero(") >> expression [ doGeqZero ] >>
')'
147 | lit(
"log(") >> expression [ doLog ] >>
')'
148 | lit(
"max(") >> expression >>
',' >> expression [ doMax ] >>
')'
149 | lit(
"min(") >> expression >>
',' >> expression [ doMin ] >>
')'
150 | lit(
"pow(") >> expression >>
',' >> expression [ doPow ] >>
')';
151 term = factor >> *( (
'*' >> factor) [ doMultiply ]
152 | (
'/' >> factor) [ doDivide ] );
153 expression = term >> *( (
'+' >> term) [ doPlus ]
154 | (
'-' >> term) [ doMinus ]);
158 std::string::const_iterator iter = text.begin();
159 std::string::const_iterator end = text.end();
160 bool r = phrase_parse(iter, end, expression, space);
162 if (r && iter == end) {
163 return evalStack.top();
165 std::string::const_iterator some = iter + 30;
166 std::string context(iter, (some > end) ? end : some);
167 QL_FAIL(
"parseFormula(" << text <<
"): parsing failed, stopped at \"" + context +
"...\"");
169 return evalStack.top();
RandomVariable max(RandomVariable x, const RandomVariable &y)
RandomVariable exp(RandomVariable x)
RandomVariable log(RandomVariable x)
RandomVariable pow(RandomVariable x, const RandomVariable &y)
RandomVariable abs(RandomVariable x)
RandomVariable min(RandomVariable x, const RandomVariable &y)
QuantExt::CompiledFormula parseFormula(const std::string &text, std::vector< std::string > &variables)
double geqZero(const double x)
double gtZero(const double x)
Serializable Credit Default Swap.
const std::function< RandomVariable(const RandomVariable &, const RandomVariable &)> op_