Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
Functions
formulaparser.cpp File Reference
#include <boost/timer/timer.hpp>
#include <ored/utilities/formulaparser.hpp>
#include <qle/math/compiledformula.hpp>
#include <oret/toplevelfixture.hpp>

Go to the source code of this file.

Functions

 BOOST_AUTO_TEST_CASE (testDouble)
 
 BOOST_AUTO_TEST_CASE (testCompiledFormula)
 

Function Documentation

◆ BOOST_AUTO_TEST_CASE() [1/2]

BOOST_AUTO_TEST_CASE ( testDouble  )

Definition at line 30 of file formulaparser.cpp.

30 {
31 BOOST_TEST_MESSAGE("Testing Formula Parser with double...");
32
33 double tol = 1E-12;
34
35 // variable mapping
36 double x = 42.0, y = -2.3;
37 auto variables = [&x, &y](const std::string& s) {
38 if (s == "x")
39 return x;
40 else if (s == "y")
41 return y;
42 else
43 QL_FAIL("variable " << s << " not known.");
44 };
45 //
46
47 BOOST_CHECK_CLOSE(parseFormula<double>("3"), 3.0, tol);
48
49 BOOST_CHECK_THROW(parseFormula<double>("x"), QuantLib::Error);
50 BOOST_CHECK_THROW(parseFormula<double>("{x}"), QuantLib::Error);
51 BOOST_CHECK_THROW(parseFormula<double>("{z}", variables), QuantLib::Error);
52
53 BOOST_CHECK_CLOSE(parseFormula<double>("{x}", variables), 42.0, tol);
54
55 BOOST_CHECK_CLOSE(parseFormula<double>("3+4"), 7.0, tol);
56 BOOST_CHECK_CLOSE(parseFormula<double>("3*4"), 12.0, tol);
57 BOOST_CHECK_CLOSE(parseFormula<double>("3/4"), 0.75, tol);
58 BOOST_CHECK_CLOSE(parseFormula<double>("3-4"), -1.0, tol);
59 BOOST_CHECK_CLOSE(parseFormula<double>("-4"), -4.0, tol);
60 BOOST_CHECK_CLOSE(parseFormula<double>("3+(-4)"), -1.0, tol);
61 BOOST_CHECK_CLOSE(parseFormula<double>("-{x}", variables), -x, tol);
62
63 BOOST_CHECK_CLOSE(parseFormula<double>("abs({x})", variables), std::abs(x), tol);
64 BOOST_CHECK_CLOSE(parseFormula<double>("abs({y})", variables), std::abs(y), tol);
65
66 BOOST_CHECK_SMALL(parseFormula<double>("gtZero({y})", variables), tol);
67 BOOST_CHECK_SMALL(parseFormula<double>("geqZero({y})", variables), tol);
68 BOOST_CHECK_CLOSE(parseFormula<double>("gtZero({x})", variables), 1.0, tol);
69 BOOST_CHECK_CLOSE(parseFormula<double>("geqZero({x})", variables), 1.0, tol);
70 BOOST_CHECK_SMALL(parseFormula<double>("gtZero(0.0)", variables), tol);
71 BOOST_CHECK_CLOSE(parseFormula<double>("geqZero(0.0)", variables), 1.0, tol);
72
73 BOOST_CHECK_CLOSE(parseFormula<double>("exp({y})", variables), std::exp(y), tol);
74 BOOST_CHECK_CLOSE(parseFormula<double>("log({x})", variables), std::log(x), tol);
75
76 BOOST_CHECK_CLOSE(parseFormula<double>("max({x},{y})", variables), std::max(x, y), tol);
77 BOOST_CHECK_CLOSE(parseFormula<double>("min({x},{y})", variables), std::min(x, y), tol);
78 BOOST_CHECK_CLOSE(parseFormula<double>("pow({x},{y})", variables), std::pow(x, y), tol);
79
80 BOOST_CHECK_CLOSE(parseFormula<double>("max((2.3*({x}-{y}))-4.3,0.0)", variables),
81 std::max(2.3 * (x - y) - 4.3, 0.0), tol);
82
83 //
84 BOOST_CHECK_CLOSE(parseFormula<double>("1+2-3-4+5"), 1.0, tol);
85 BOOST_CHECK_CLOSE(parseFormula<double>("1+2-3*2*(-4)-4*2*3"), 3.0, tol);
86 BOOST_CHECK_CLOSE(parseFormula<double>("1+(2-3)*5+2*3"), 2.0, tol);
87 BOOST_CHECK_CLOSE(parseFormula<double>("(1+(2-3)*(5+2))*3"), -18.0, tol);
88
89 // performance test
90
91 boost::timer::cpu_timer timer;
92 for (Size i = 0; i < 100000; ++i) {
93 parseFormula<double>("max((2.3*({x}-{y}))-4.3,0.0)", variables);
94 }
95 timer.stop();
96 BOOST_TEST_MESSAGE("timing full parsing (100k evaluations) = " << timer.format(boost::timer::default_places, "%w")
97 << " secs.");
98}

◆ BOOST_AUTO_TEST_CASE() [2/2]

BOOST_AUTO_TEST_CASE ( testCompiledFormula  )

Definition at line 100 of file formulaparser.cpp.

100 {
101 BOOST_TEST_MESSAGE("Testing Formula Parser with CompiledFormula...");
102
103 double tol = 1E-12;
104
105 double x = 42.0, y = -2.3;
106 std::vector<std::string> variables;
107
108 QuantExt::CompiledFormula f = parseFormula("((2*{x})+3)/{y}", variables);
109 BOOST_REQUIRE(variables.size() == 2);
110 BOOST_CHECK_EQUAL(variables[0], "x");
111 BOOST_CHECK_EQUAL(variables[1], "y");
112 BOOST_CHECK_CLOSE(f({x, y}), (2.0 * x + 3.0) / y, tol);
113
114 f = parseFormula("{x}-{y}", variables);
115 BOOST_REQUIRE(variables.size() == 2);
116 BOOST_CHECK_EQUAL(variables[0], "x");
117 BOOST_CHECK_EQUAL(variables[1], "y");
118 BOOST_CHECK_CLOSE(f({x, y}), x - y, tol);
119
120 f = parseFormula("-{y}", variables);
121 BOOST_REQUIRE(variables.size() == 1);
122 BOOST_CHECK_EQUAL(variables[0], "y");
123 BOOST_CHECK_CLOSE(f({y}), -y, tol);
124
125 f = parseFormula("{x}/{y}", variables);
126 BOOST_REQUIRE(variables.size() == 2);
127 BOOST_CHECK_EQUAL(variables[0], "x");
128 BOOST_CHECK_EQUAL(variables[1], "y");
129 BOOST_CHECK_CLOSE(f({x, y}), x / y, tol);
130
131 f = parseFormula("max({x},{y})", variables);
132 BOOST_REQUIRE(variables.size() == 2);
133 BOOST_CHECK_EQUAL(variables[0], "x");
134 BOOST_CHECK_EQUAL(variables[1], "y");
135 BOOST_CHECK_CLOSE(f({x, y}), std::max(x, y), tol);
136
137 f = parseFormula("min({x},{y})", variables);
138 BOOST_REQUIRE(variables.size() == 2);
139 BOOST_CHECK_EQUAL(variables[0], "x");
140 BOOST_CHECK_EQUAL(variables[1], "y");
141 BOOST_CHECK_CLOSE(f({x, y}), std::min(x, y), tol);
142
143 f = parseFormula("pow({x},{y})", variables);
144 BOOST_REQUIRE(variables.size() == 2);
145 BOOST_CHECK_EQUAL(variables[0], "x");
146 BOOST_CHECK_EQUAL(variables[1], "y");
147 BOOST_CHECK_CLOSE(f({x, y}), std::pow(x, y), tol);
148
149 f = parseFormula("abs({y})", variables);
150 BOOST_REQUIRE(variables.size() == 1);
151 BOOST_CHECK_EQUAL(variables[0], "y");
152 BOOST_CHECK_CLOSE(f({y}), std::abs(y), tol);
153
154 f = parseFormula("gtZero({x})", variables);
155 BOOST_REQUIRE(variables.size() == 1);
156 BOOST_CHECK_EQUAL(variables[0], "x");
157 BOOST_CHECK_CLOSE(f({x}), 1.0, tol);
158 BOOST_CHECK_SMALL(f({y}), tol);
159 BOOST_CHECK_SMALL(f({0.0}), tol);
160
161 f = parseFormula("geqZero({x})", variables);
162 BOOST_REQUIRE(variables.size() == 1);
163 BOOST_CHECK_EQUAL(variables[0], "x");
164 BOOST_CHECK_CLOSE(f({x}), 1.0, tol);
165 BOOST_CHECK_SMALL(f({y}), tol);
166 BOOST_CHECK_CLOSE(f({0.0}), 1.0, tol);
167
168 f = parseFormula("exp({y})", variables);
169 BOOST_REQUIRE(variables.size() == 1);
170 BOOST_CHECK_EQUAL(variables[0], "y");
171 BOOST_CHECK_CLOSE(f({y}), std::exp(y), tol);
172
173 f = parseFormula("log({x})", variables);
174 BOOST_REQUIRE(variables.size() == 1);
175 BOOST_CHECK_EQUAL(variables[0], "x");
176 BOOST_CHECK_CLOSE(f({x}), std::log(x), tol);
177
178 // performance test
179
180 f = parseFormula("max((2.3*({x}-{y}))-4.3,0.0)", variables);
181 boost::timer::cpu_timer timer;
182 double dummy = 0.0;
183 std::vector<Real> v(2);
184 for (Size i = 0; i < 100000; ++i) {
185 v[0] = static_cast<double>(i) / static_cast<double>(10000);
186 v[1] = static_cast<double>(100000 - i) / static_cast<double>(10000);
187 dummy += f(v);
188 }
189 BOOST_TEST_MESSAGE("dummy = " << dummy);
190 timer.stop();
191 BOOST_TEST_MESSAGE("timing precompiled formula (100k evalulations) = "
192 << timer.format(boost::timer::default_places, "%w") << " secs.");
193
194 timer.start();
195 dummy = 0.0;
196 for (Size i = 0; i < 100000; ++i) {
197 Real x = static_cast<double>(i) / static_cast<double>(10000);
198 Real y = static_cast<double>(100000 - i) / static_cast<double>(10000);
199 dummy += std::max((2.3 * (x - y)) - 4.3, 0.0);
200 }
201 BOOST_TEST_MESSAGE("dummy = " << dummy);
202 timer.stop();
203 BOOST_TEST_MESSAGE("timing native (100k evaluations) = " << timer.format(boost::timer::default_places, "%w")
204 << " secs.");
205 // muparser benchmark, if installed; to make this run you need to add
206 // #include <muParser.h>
207 // at the beginning of this file and alos link against the muparser library
208 // sample results (mac book pro 2015 i7)
209 // timing precompiled formula (100k evalulations) = 0.00332
210 // timing muparser = 0.002974
211
212 // double val_x = 0.0, val_y = 0.0;
213 // mu::Parser p;
214 // p.DefineVar("x", &val_x);
215 // p.DefineVar("y", &val_y);
216 // p.SetExpr("max((2.3*(x-y))-4.3,0.0)");
217
218 // timer.start();
219 // dummy = 0.0;
220 // for (Size i = 0; i < 100000; ++i) {
221 // val_x = static_cast<double>(i) / static_cast<double>(10000);
222 // val_y = static_cast<double>(100000 - i) / static_cast<double>(10000);
223 // dummy += p.Eval();
224 // }
225 // timer.stop();
226
227 // BOOST_TEST_MESSAGE("timing muparser = " << timer.format(boost::timer::default_places, "%w") << " secs.");
228}
QuantExt::CompiledFormula parseFormula(const std::string &text, std::vector< std::string > &variables)
+ Here is the call graph for this function: