Bertini 2 d882924 (2026-10-06 19:56 UTC)
Numerical algebraic geometry library (C++ core)
Loading...
Searching...
No Matches
system_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/system_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/system_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
34#include <map>
35
39
40
41
42namespace bertini {
43 namespace parsing {
44 namespace classic {
45 // a few local using statements to reduce typing etc.
47 using Node = node::Node;
48
49
50 using Var = std::shared_ptr<Variable>;
51 using Nd = std::shared_ptr<Node>;
52
77 template<typename Iterator, typename Skipper = ascii::space_type>
78 struct SystemParser : qi::grammar<Iterator, System(), Skipper>
79 {
80
81
82 SystemParser() : SystemParser::base_type(root_rule_),
83 /*initialize function_parser_ here with address of encountered_symbols*/
84 function_parser_(&encountered_symbols_)
85 {
86 namespace phx = boost::phoenix;
87 using qi::_1;
88 using qi::_2;
89 using qi::_3;
90 using qi::_4;
91 using qi::_val;
92 using qi::eps;
93 using qi::lit;
94 using boost::spirit::lexeme;
95
96
97 declarative_symbols_.add("variable_group",0);
98 declarative_symbols_.add("hom_variable_group",1);
99 declarative_symbols_.add("variable",2);
100 declarative_symbols_.add("function",3);
101 declarative_symbols_.add("constant",4);
102 declarative_symbols_.add("parameter",5);
103 declarative_symbols_.add("implicit_parameter",6);
104 declarative_symbols_.add("pathvariable",7);
105 declarative_symbols_.add("random",8);
106 declarative_symbols_.add("random_real",9);
107
108
109
110
111
112
113 special_numbers_.add("pi", node::Pi());
114 special_numbers_.add("Pi", special_numbers_.at("pi"));
115
116 special_numbers_.add("e", node::E());
117 special_numbers_.add("E", special_numbers_.at("e"));
118
119
120 special_numbers_.add("i", node::I());
121 special_numbers_.add("I", special_numbers_.at("i"));
122
123
124
125 encountered_symbols_.add("pi", special_numbers_.at("pi"));
126 encountered_symbols_.add("Pi", special_numbers_.at("pi"));
127
128 encountered_symbols_.add("e", special_numbers_.at("e"));
129 encountered_symbols_.add("E", special_numbers_.at("e"));
130
131
132 encountered_symbols_.add("i", special_numbers_.at("i"));
133 encountered_symbols_.add("I", special_numbers_.at("i"));
134
135
136
137
138
139 // Declaration blocks may appear in any number and any order, which is what
140 // Bertini 1 input looks like. What IS enforced: a second `pathvariable` is
141 // refused here, and a name declared but never defined is reported by name from
142 // EmitDeclaredFunctions once the whole input has been read (it cannot be caught
143 // earlier, since the defining line may come anywhere after the declaration).
144 // Deliberately not enforced: a definition for a name that was never declared is
145 // absorbed as a subfunction, which is what Bertini 1 does.
146 root_rule_.name("system_parsing");
147 root_rule_ =
148 *(
149 variable_group_ [phx::bind(&System::AddVariableGroup, _val, _1)]
150 |
151 hom_variable_group_ [phx::bind(&System::AddHomVariableGroup, _val, _1)]
152 |
153 variables_ [phx::bind(&System::AddUngroupedVariables, _val, _1)]
154 |
155 functions_ [phx::bind([this](std::vector<std::string> const& names){ this->CollectFunctionNames(names); }, _1)]
156 |
157 constants_ [phx::bind([this](std::vector<std::string> const& names){ this->CollectConstantNames(names); }, _1)]
158 |
159 parameters_ [phx::bind([this](std::vector<std::string> const& names){ this->CollectParameterNames(names); }, _1)]
160 |
161 implicit_parameters_ [phx::bind(&System::AddImplicitParameters, _val, _1)]
162 |
163 path_variable_ [phx::bind([this](System& s, Var const& v){ this->AddPathVariableChecked(s, v); }, _val, _1)]
164 |
165 // definition_ before subfunction_: a declared name (function/constant/
166 // parameter) lives only in encountered_functions_, not encountered_symbols_,
167 // so its definition line would otherwise be misread as a fresh subfunction.
168 // definition_ matches declared LHS names; subfunction_ catches the rest.
169 definition_
170 |
171 qi::omit[subfunction_]
172 )
173 ;
174
175
176
177
178
179 variables_.name("variables_"); hom_variable_group_.name("hom_variable_group_"); variable_group_.name("variable_group_"); implicit_parameters_.name("implicit_parameters_");
180
181
182 variables_ = "variable" > genericvargp_ > ';';
183 hom_variable_group_ = "hom_variable_group" > genericvargp_ > ';';
184 variable_group_ = "variable_group" > genericvargp_ > ';';
185 implicit_parameters_ = "implicit_parameter" > genericvargp_ > ';';
186
187
188
189 path_variable_.name("path_variable_");
190 path_variable_ = "pathvariable" > new_variable_ > ';';
191
192
193
194 genericvargp_.name("genericvargp_");
195 genericvargp_ = new_variable_ % ',';
196
197 new_variable_.name("new_variable_");
198 new_variable_ = unencountered_symbol_ [boost::phoenix::bind( [this](Var & V, std::string str)
199 {
200 MakeAndAddVariable(V,str);
201 }, _val, _1 )];
202
203
204
205 functions_.name("functions_"); constants_.name("constants_"); parameters_.name("parameters_");
206
207 functions_ = "function" > genericfuncgp_ > ';';
208 constants_ = "constant" > genericfuncgp_ > ';';
209 parameters_ = "parameter" > genericfuncgp_ > ';';
210
211
212 genericfuncgp_.name("genericfuncgp_");
213 genericfuncgp_ = new_function_ % ',';
214
215
216 new_function_.name("new_function_");
217 new_function_ = unencountered_symbol_ [boost::phoenix::bind( [this](std::string & name, std::string str)
218 {
219 MakeAndDeclareName(name,str);
220 }, _val, _1 )];
221
222
223
224
225 // this rule gets a string.
226 unencountered_symbol_.name("unencountered_symbol_");
227 unencountered_symbol_ = valid_variable_name_ - lexeme[( declarative_symbols_ | encountered_symbols_ )];
228 // i am unsure about the use of lexeme in the above rule (unencountered_symbol).
229
230
231
232
233 // get a string which fits the naming rules. Identifiers are
234 // UTF-8: they start with a Unicode letter and continue with
235 // Unicode alphanumerics or [ ] _ . The matched raw bytes are
236 // the stored name (already UTF-8). See io/parsing/unicode_ident.hpp.
237 valid_variable_name_.name("valid_variable_name_");
238 valid_variable_name_ = utf8_identifier_parser();
239
240
241
242
243 definition_.name("definition_");
244 definition_ = (encountered_functions_ > '=' > function_parser_ > ';') [phx::bind( [this](std::string const& name, const Nd & expr)
245 {
246 this->DefineNamed(name, expr);
247 },_1, _2)] ;
248
249
250 using qi::_a;
251 using qi::omit;
252 subfunction_.name("subfunction");
253 subfunction_ = unencountered_symbol_ [_a = _1] > '=' >
254 function_parser_ [phx::bind( [this](Nd & result, std::string const& name, const Nd & expr)
255 {
256 auto ne = node::NamedExpression::Make(expr, name);
257 encountered_symbols_.add(name, ne);
258 result = ne;
259 }, _val, _a, _1)]
260 > ';';
261
262
263 // debug(root_rule_);
264 //
265 //
266 //
267 // debug(functions_);
268 // debug(constants_);
269 // debug(parameters_);
270 //
271 // debug(genericfuncgp_);
272 // debug(new_function_);
273 //
274 //
275 //
276 // debug(definition_);
277 //
278 // debug(subfunction_);
279 //
280 //
281 //
282 //
283 // debug(variables_);
284 // debug(hom_variable_group_);
285 // debug(variable_group_);
286 // debug(implicit_parameters_);
287 // debug(path_variable_);
288 //
289 // debug(new_variable_);
290 // debug(genericvargp_); debug(variable_group_);
291 //
292 // debug(unencountered_symbol_);
293 //
294 // debug(valid_variable_name_);
295
296
297
298
299 // BOOST_SPIRIT_DEBUG_NODES( (unencountered_symbol_) (new_variable_) (genericvargp_))
300
301 qi::on_error<qi::fail>(
302 root_rule_,
303 phx::bind(&ReportParseError, _1, _2, _3, _4, std::string("SystemParser"))
304 );
305
306
307 }
308
309
310
311
312 private:
313
314 // rule declarations. these are member variables for the parser.
315 qi::rule<Iterator, System(), Skipper > root_rule_;
316
317
318 qi::rule<Iterator, VariableGroup(), Skipper > variable_group_, hom_variable_group_, variables_, implicit_parameters_;
319 qi::rule<Iterator, VariableGroup(), Skipper > genericvargp_;
320
321 qi::rule<Iterator, Var(), Skipper> path_variable_;
322 qi::rule<Iterator, Var()> new_variable_;
323
324
325
326
327 qi::rule<Iterator, std::vector<std::string>(), Skipper > functions_, constants_, parameters_;
328 qi::rule<Iterator, std::vector<std::string>(), Skipper > genericfuncgp_;
329 qi::rule<Iterator, Nd(), Skipper, qi::locals<std::string> > subfunction_;
330
331 qi::rule<Iterator, std::string()> new_function_;
332
333
334 qi::rule<Iterator, std::string()> unencountered_symbol_;
335
336
337 // the rule which determines valid variable names
338 qi::rule<Iterator, std::string()> valid_variable_name_;
339
340 qi::rule<Iterator, Skipper, qi::unused_type> definition_;
341
342 // symbol declarations
343 qi::symbols<char,Nd> encountered_symbols_;
344 qi::symbols<char,int> declarative_symbols_;
345 qi::symbols<char,std::string> encountered_functions_;
346 qi::symbols<char,Nd> special_numbers_;
347
348 FunctionParser<Iterator> function_parser_;
349
354 void MakeAndDeclareName(std::string & name, std::string str)
355 {
356 // A declare-then-define name (function / constant / parameter) is just a
357 // marker until its definition is parsed: record the name in
358 // encountered_functions_ so the definition_ rule can match its LHS. We do
359 // NOT add it to encountered_symbols_ yet -- the name binds to its
360 // NamedExpression only once defined (DefineNamed), at which point references
361 // to it resolve. (Define-before-use is assumed.)
362 name = str;
363 encountered_functions_.add(str, str);
364 }
365
370 void MakeAndAddVariable(Var & V, std::string str)
371 {
372 V = Variable::Make(str);
373 encountered_symbols_.add(str, V);
374 }
375
376 // Bertini-1 input declares the declare-then-define kinds first ("function f, g;",
377 // "constant c;", "parameter p;"), then defines them (and any inline subfunctions)
378 // later. We record the declared names per kind, and bind each name to an immutable
379 // NamedExpression when its definition is parsed (DefineNamed). After the whole input
380 // is parsed we emit them to the System (EmitDeclaredFunctions): the System receives
381 // bare, fully-built expressions -- no Function declaration box is ever created.
382 public:
384 void CollectFunctionNames(std::vector<std::string> const& names)
385 { for (auto const& n : names) declared_function_names_.push_back(n); }
386
387 void CollectConstantNames(std::vector<std::string> const& names)
388 { for (auto const& n : names) declared_constant_names_.push_back(n); }
389
390 void CollectParameterNames(std::vector<std::string> const& names)
391 { for (auto const& n : names) declared_parameter_names_.push_back(n); }
392
393 // Bind a declared name to its (immutable) NamedExpression: makes references to the
394 // name resolve, and records the definition for emission to the System.
396 void DefineNamed(std::string const& name, Nd const& expr)
397 {
398 auto ne = node::NamedExpression::Make(expr, name);
399 encountered_symbols_.add(name, ne);
400 definitions_[name] = ne;
401 }
402
412 {
413 if (have_path_variable_declaration_)
414 throw std::runtime_error(
415 "[SystemParser] more than one `pathvariable` declared: a system has "
416 "exactly one path variable. Declare only the one you mean.");
417 have_path_variable_declaration_ = true;
418 s.AddPathVariable(v);
419 }
420
429 {
430 for (auto const& n : declared_function_names_)
431 s.AddFunction(DefinitionOf(n, "function")->EntryNode());
432 for (auto const& n : declared_constant_names_)
433 s.AddConstant(DefinitionOf(n, "constant"));
434 for (auto const& n : declared_parameter_names_)
435 s.AddParameter(DefinitionOf(n, "parameter"));
436 }
437
438 private:
443 std::shared_ptr<node::NamedExpression> const& DefinitionOf(std::string const& name,
444 std::string const& kind) const
445 {
446 auto const found = definitions_.find(name);
447 if (found == definitions_.end())
448 throw std::runtime_error(
449 "[SystemParser] " + kind + " `" + name + "` was declared but never defined. "
450 "Every declared name needs a defining line, as in `" + name + " = ...;`.");
451 return found->second;
452 }
453
454 bool have_path_variable_declaration_ = false;
455 std::vector<std::string> declared_function_names_, declared_constant_names_, declared_parameter_names_;
456 std::map<std::string, std::shared_ptr<node::NamedExpression>> definitions_;
457 };
458
459 } // re: namespace classic
460
461 } //re: namespace parsing
462
463
464
465
466} // re: namespace bertini
The fundamental polynomial system class for Bertini2.
Definition system.hpp:106
void AddParameter(NE const &F)
Add an explicit parameter to the system.
void AddImplicitParameters(VariableGroup const &v)
Add some implicit parameters to the system.
void AddUngroupedVariables(VariableGroup const &v)
Add variables to the system which are in neither a regular variable group, nor in a homogeneous group...
void AddFunction(Nd const &F)
Add a function to the system, as a bare expression.
void AddConstant(NE const &C)
Add a constant function to the system.
void AddHomVariableGroup(VariableGroup const &v)
Add a homogeneous (projective) variable group to the system.
void AddPathVariable(Var const &v)
Add a variable as the Path Variable to a System.
void AddVariableGroup(VariableGroup const &v)
Add a variable group to the system.
static std::shared_ptr< NamedExpression > Make(Ts &&...ts)
Construct (and intern) a NamedExpression node.
Definition named_expression.hpp:57
An interface for all nodes in a function tree, and for a function object as well.
Definition node.hpp:114
Represents variable leaves in the function tree.
Definition variable.hpp:48
static std::shared_ptr< Variable > Make(Ts &&...ts)
Construct (and intern) a Variable node.
Definition variable.hpp:56
Provides the parsing rules for functions in bertini2.
std::shared_ptr< Node > E()
Construct a shared pointer to .
std::shared_ptr< Node > Pi()
Construct a shared pointer to .
std::shared_ptr< Node > I()
Construct a shared pointer to .
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
std::shared_ptr< Variable > Var
Shorthand for a shared pointer to a variable node.
Definition system_rules.hpp:50
node::Node Node
The generic expression-tree node type.
Definition system_rules.hpp:47
std::shared_ptr< Node > Nd
Shorthand for a shared pointer to a generic node.
Definition system_rules.hpp:51
node::Variable Variable
The variable node type.
Definition system_rules.hpp:46
Definition classic_utilities.hpp:40
Definition algorithm_builder.hpp:36
std::vector< std::shared_ptr< node::Variable > > VariableGroup
An ordered group of variables (the unit of homogenization / variable grouping).
Definition node.hpp:69
Provides all the include files needed to develop a parsing file that uses boost qi.
A Qi grammar parser for parsing text into function trees.
Definition function_rules.hpp:145
void EmitDeclaredFunctions(System &s) const
Emit the collected declared functions/constants/parameters to the System.
Definition system_rules.hpp:428
void CollectParameterNames(std::vector< std::string > const &names)
Record the declared parameter names.
Definition system_rules.hpp:390
void DefineNamed(std::string const &name, Nd const &expr)
Bind a declared name to its (immutable) NamedExpression definition.
Definition system_rules.hpp:396
void CollectFunctionNames(std::vector< std::string > const &names)
Record the declared function names (in declaration order).
Definition system_rules.hpp:384
SystemParser()
Definition system_rules.hpp:82
void CollectConstantNames(std::vector< std::string > const &names)
Record the declared constant names.
Definition system_rules.hpp:387
void AddPathVariableChecked(System &s, Var const &v)
Add the path variable, refusing a second declaration.
Definition system_rules.hpp:411
Provides the bertini::System class.