Bertini 2 d882924 (2026-10-06 19:56 UTC)
Numerical algebraic geometry library (C++ core)
Loading...
Searching...
No Matches
function_rules.hpp
Go to the documentation of this file.
1//This file is part of Bertini 2.
2//
3//bertini2/io/parsers.hpp is free software: you can redistribute it and/or modify
4//it under the terms of the GNU General Public License as published by
5//the Free Software Foundation, either version 3 of the License, or
6//(at your option) any later version.
7//
8//bertini2/io/parsing/function_rules.hpp is distributed in the hope that it will be useful,
9//but WITHOUT ANY WARRANTY; without even the implied warranty of
10//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11//GNU General Public License for more details.
12//
13//You should have received a copy of the GNU General Public License
14//along with bertini2/io/parsing/function_rules.hpp. If not, see <http://www.gnu.org/licenses/>.
15//
16// Copyright(C) Bertini2 Development Team
17//
18// See <http://www.gnu.org/licenses/> for a copy of the license,
19// as well as COPYING. Bertini2 is provided with permitted
20// additional terms in the b2/licenses/ directory.
21
22
28
29#pragma once
30
31
32
33
35
38
41
44
46
47
48
49// see the following link for reading from arbitrary streams without putting the content into a std::string first
50//http://boost-spirit.com/home/articles/qi-example/tracking-the-input-position-while-parsing/
51
52
53
54namespace {
55 // this solution for *lazy* make shared comes from the SO forum, asked by polytheme, answered by user sehe.
56 // https://stackoverflow.com/questions/21516201/how-to-create-boost-phoenix-make-shared
57 // post found using google search terms `phoenix construct shared_ptr`
58 // the code has been adapted slightly to fit the naming conventions of this project.
59 template <typename T>
60 struct MakeSharedFunctor
61 {
62 template <typename... A>
63 struct result
64 {
65 typedef std::shared_ptr<T> type;
66 };
67
68 template <typename... A>
69 typename result<A...>::type operator()(A&&... a) const
70 {
71 return T::Make(std::forward<A>(a)...);
72 }
73 };
74
75 template <typename T>
76 using make_shared_ = boost::phoenix::function<MakeSharedFunctor<T> >;
77}
78
79
80
81
82
83
84
86//
87// the following code adapts the trig functions and other special functions to be phoenix-callable.
88//
90
91// http://www.boost.org/doc/libs/1_58_0/libs/phoenix/doc/html/phoenix/modules/function/adapting_functions.html
92
93//
94// form is as follows:
95//
96//BOOST_PHOENIX_ADAPT_FUNCTION(
97// RETURN_TYPE
98// , LAZY_FUNCTION
99// , FUNCTION
100// , FUNCTION_ARITY
101// )
102
103
104
106BOOST_PHOENIX_ADAPT_FUNCTION(std::shared_ptr<bertini::node::Node>, cos_lazy, cos, 1);
107BOOST_PHOENIX_ADAPT_FUNCTION(std::shared_ptr<bertini::node::Node>, sin_lazy, sin, 1);
108BOOST_PHOENIX_ADAPT_FUNCTION(std::shared_ptr<bertini::node::Node>, tan_lazy, tan, 1);
109
110BOOST_PHOENIX_ADAPT_FUNCTION(std::shared_ptr<bertini::node::Node>, log_lazy, log, 1);
111BOOST_PHOENIX_ADAPT_FUNCTION(std::shared_ptr<bertini::node::Node>, exp_lazy, exp, 1);
112BOOST_PHOENIX_ADAPT_FUNCTION(std::shared_ptr<bertini::node::Node>, sqrt_lazy, sqrt, 1);
114
115
116
117
118
119
120
121namespace bertini {
122 namespace parsing {
123 namespace classic {
124
125
126
127 namespace qi = ::boost::spirit::qi;
128 namespace ascii = ::boost::spirit::ascii;
129
130
131
132
133
143 template<typename Iterator>
144 struct FunctionParser : qi::grammar<Iterator, std::shared_ptr<node::Node>(), boost::spirit::ascii::space_type>
145 {
146 using Node = node::Node;
150
152 FunctionParser(qi::symbols<char,std::shared_ptr<Node> > * encountered_symbols) : FunctionParser::base_type(root_rule_,"FunctionParser")
153 {
154 namespace phx = boost::phoenix;
155 using qi::_1;
156 using qi::_2;
157 using qi::_3;
158 using qi::_4;
159 using qi::_val;
160 using qi::eps;
161 using qi::lit;
162
163 using std::pow;
164 using ::pow;
165
166 root_rule_.name("function_");
167 // Return the bare parsed expression (no Function wrapper): the System parser names
168 // it (a NamedExpression for subfunctions) or stores it directly (top-level functions).
169 root_rule_ = expression_ [ _val = _1];
170
171
173 expression_.name("expression_");
174 expression_ =
175 term_ [_val = _1]
176 >> *( (lit('+') > term_ [_val += _1])
177 | (lit('-') > term_ [_val -= _1])
178 )
179 ;
180
181 term_.name("term_");
182 term_ =
183 factor_ [_val = _1]
184 >> *( (lit('*') > factor_ [_val *= _1])
185 | (lit('/') > factor_ [_val /= _1])
186 )
187 ;
188
189 factor_.name("factor_");
190 factor_ =
191 exp_elem_ [_val = _1]
192 >> *(lit('^') // any number of ^somethings
193 > exp_elem_ [ phx::bind( []
194 (std::shared_ptr<Node> & B, std::shared_ptr<Node> P)
195 {
196 B = pow(B,P);
197 },
198 _val,_1)] )
199 ;
200
201 exp_elem_.name("exp_elem_");
202 exp_elem_ =
203 // The negative lookahead keeps a known symbol from matching a
204 // prefix of a longer identifier (e.g. `e` inside `exp`, or `x`
205 // inside `xy`). It must use the UTF-8 continuation predicate so
206 // a following Unicode letter (e.g. `α` after a known `Ω`) also
207 // blocks the match -- a bare ASCII !qi::alnum would not.
208 (symbol_ >> utf8_ident_boundary_parser()) [_val = _1]
209 | ( '(' > expression_ [_val = _1] > ')' ) // using the > expectation here.
210 // unary +/- bind a single factor_, NOT the whole expression_: "-y+x" is
211 // (-y)+x, and "-x^2" is -(x^2). (Binding expression_ here made a leading
212 // minus greedily negate everything after it.)
213 | (lit('-') > factor_ [_val = -_1])
214 | (lit('+') > factor_ [_val = _1])
215 | (lit("sin") > '(' > expression_ [_val = sin_lazy(_1)] > ')' )
216 | (lit("cos") > '(' > expression_ [_val = cos_lazy(_1)] > ')' )
217 | (lit("tan") > '(' > expression_ [_val = tan_lazy(_1)] > ')' )
218 | (lit("exp") > '(' > expression_ [_val = exp_lazy(_1)] > ')' )
219 | (lit("log") > '(' > expression_ [_val = log_lazy(_1)] > ')' )
220 | (lit("sqrt") > '(' > expression_ [_val = sqrt_lazy(_1)] > ')' )
221 ;
222
223
224
225
226
227
228
229
230 symbol_.name("symbol_");
231 symbol_ %=
232 (*encountered_symbols) // the star here is the dereferencing of the encountered_symbols parameter to the constructor.
233 |
234 number_
235 ;
236
237
238
239
240
241
242
243
244
245
246
247 number_.name("number_");
248 number_ =
249 mpfr_rules_.long_number_string_ [ _val = make_shared_<Complex>()(_1) ]
250 |
251 mpfr_rules_.integer_string_ [ _val = make_shared_<Integer>()(_1) ];
252
253
254
255
256
257
258
259
260 qi::on_error<qi::fail>(
261 root_rule_,
262 phx::bind(&ReportParseError, _1, _2, _3, _4, std::string("FunctionParser"))
263 );
264
265
266
267
268
269 // debug(root_rule_);
270 // debug(expression_);
271 // debug(term_);
272 // debug(factor_);
273 // debug(exp_elem_);
274 // debug(number_);
275 // debug(number_with_no_point_);
276 // debug(number_with_digits_after_point_);
277 // debug(number_with_digits_before_point_);
278 // debug(exponent_notation_);
279 }
280
281
282
283
284
285
287 qi::rule<Iterator, std::shared_ptr<Node>(), ascii::space_type > root_rule_;
288 // the rule for kicking the entire thing off
289
290 qi::rule<Iterator, std::shared_ptr<Node>(), ascii::space_type> expression_, term_, factor_, exp_elem_;
291 // rules for how to turn +-*/^ into operator nodes.
292
293
294
295 qi::rule<Iterator, std::shared_ptr<Node>(), ascii::space_type > symbol_;
296 // any of the variables and numbers will be symbols.
297
298 qi::rule<Iterator, std::shared_ptr<Node>(), ascii::space_type > variable_; // finds a previously encountered number, and associates the correct variable node with it.
299
300 // the number_ rule wants to find strings from the various other number_ rules, and produces a Number node
301 qi::rule<Iterator, std::shared_ptr<Node>(), ascii::space_type > number_;
302
303 parsing::rules::LongNum<Iterator> mpfr_rules_;
305 };
306
307 } // re: namespace classic
308
309 } // re: namespace parsing
310
311} // re: namespace bertini
Provides the artithmetic Node types, such as Sum and Power.
A complex-number literal node in an expression tree.
Definition number.hpp:254
Signed real Integer storage in an expression tree.
Definition number.hpp:143
An interface for all nodes in a function tree, and for a function object as well.
Definition node.hpp:114
The Rational number type for Bertini2 expression trees.
Definition number.hpp:379
A user-named expression node: prints as its name, evaluates to its expression.
Definition classic_utilities.hpp:41
void ReportParseError(std::string::const_iterator begin, std::string::const_iterator end, std::string::const_iterator err_pos, boost::spirit::info const &what, std::string const &parser_name)
Report a parse error (via FormatParseError) to the log, for use in a Spirit on_error handler.
Definition qi_files.hpp:199
Definition classic_utilities.hpp:40
Definition algorithm_builder.hpp:36
complex_dbl pow(const complex_dbl &z, int power)
Compute +,- integral powers of a std::complex<double> number.
Definition double_extensions.hpp:92
Defines the abstract Node base class.
Provides the Number Node types, including Rational, Complex, and Integer.
Provides the parsersing rules for numbers in bertini2.
Provides all the include files needed to develop a parsing file that uses boost qi.
node::Complex Complex
The complex-number node type.
Definition function_rules.hpp:147
FunctionParser(qi::symbols< char, std::shared_ptr< Node > > *encountered_symbols)
Construct the function parser, given the table of already-encountered symbols.
Definition function_rules.hpp:152
node::Integer Integer
The integer node type.
Definition function_rules.hpp:148
node::Node Node
The generic expression-tree node type.
Definition function_rules.hpp:146
node::Rational Rational
The rational-number node type.
Definition function_rules.hpp:149
Provides the abstract TrigOperator, and the concrete types such as SinOperator.
Provides the Variable Node class.