User Guide
sympy_replace_solutions_visitor.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2023 Blue Brain Project, EPFL.
3  * See the top-level LICENSE file for details.
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #pragma once
9 
10 /**
11  * \file
12  * \brief \copybrief nmodl::visitor::SympyReplaceSolutionsVisitor
13  */
14 
15 #include "visitors/ast_visitor.hpp"
16 
17 #include <algorithm>
18 #include <set>
19 #include <string>
20 #include <unordered_map>
21 #include <unordered_set>
22 #include <vector>
23 
24 namespace nmodl {
25 namespace visitor {
26 
27 /**
28  * @addtogroup visitor_classes
29  * @{
30  */
31 
32 
33 /**
34  * \class SympyReplaceSolutionsVisitor
35  * \brief Replace statements in \p node with pre_solve_statements, tmp_statements, and solutions
36  *
37  * The goal is to replace statements with solutions in place. In this way we can allow (to
38  * some extent) the use of control flow blocks and assignments. \ref pre_solve_statements are added
39  * in front of the replaced statements in case their variable needs updating. \ref
40  StatementDispenser
41  * keeps track of what needs updating. Let's start with some nomenclature:
42  *
43  * - statement: a line in the .mod file. It can be a diff_eq_expression, binary_expression, or
44  * linEquation
45  * - old_Statement: line in the staementBlock that must be replaced with the solution
46  * - solution_statements/ new_statement: a nmodl-statement (always binary expression) provided by
47  sympy that
48  * assigns a variable
49  * - pre_solve_Statements: statements that update the variables (i.e. x = old_x)
50  * - tmp_statements: assignment of temporary variables in the solution generated by sympy in case
51  * --cse. (i.e. \f$ tmp = f (...) \f$
52  *
53  * We employ a multi-step approach:
54  *
55  * - try to replace the old_statements (not binary_expressions) and in "assignment form: \f$ x =
56  * f(...) \f$" with the corresponding solution matching by variable (i.e. x in \f$ x = f(...) \f$)
57  * - try to replace the old_Statements with a greedy approach. When we find a
58  * diff_eq_expression/linEquation that needs replacing we take the next solution that was not yet
59  * used
60  * - add all the remaining solutions at the end
61  *
62  * Let's finish with an example (that are usually better than blabbling around).
63  *
64  * Imagine we have this derivative block in the ast (before SympyReplaceSolutionsVisitor passes):
65  *
66  * \code{.mod}
67  * DERIVATIVE d {
68  * LOCAL a, old_x, old_y, old_z, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7
69  * b = 1
70  * x' = x + y + a + b
71  * if ( x == 0) {
72  * a = a + 1
73  * # x = x + 1 // this would be an error. Explained later
74  * }
75  * y' = x + y + a
76  * z' = y + a
77  * x = x + 1
78  * }
79  * \endcode
80  *
81  * where SympySolverVisitor already added variables in the LOCAL declaration.
82  *
83  * Sympy solver visitor also provides:
84  *
85  * - pre-solve statements:
86  *
87  * \code{.mod}
88  * old_x = x
89  * old_y = y
90  * old_z = z
91  * \endcode
92  *
93  * - tmp statements:
94  *
95  * \code{.mod}
96  * tmp0 = 2.0*dt
97  * tmp1 = 1.0/(tmp0-1.0)
98  * tmp2 = pow(dt, 2)
99  * tmp3 = b*tmp2
100  * tmp4 = dt*old_x
101  * tmp5 = a*dt
102  * tmp6 = dt*old_y
103  * tmp7 = tmp5+tmp6
104  * \endcode
105  *
106  * - solutions:
107  *
108  * \code{.mod}
109  * x = -tmp1*(b*dt+old_x-tmp3-tmp4+tmp7)
110  * y = -tmp1*(old_y+tmp3+tmp4+tmp5-tmp6)
111  * z = -tmp1*(-a*tmp2+b*pow(dt, 3)+old_x*tmp2-old_y*tmp2-old_z*tmp0+old_z+tmp7)
112  * \endcode
113  *
114  * SympySolveVisitor works in this way:
115  *
116  * \code{.mod}
117  * DERIVATIVE d { // nothing to do
118  *
119  * LOCAL a, old_x, old_y, old_z, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7 // nothing to do
120  *
121  * b = 1 // initial statement, nothing to do
122  *
123  * x' = x + y + a + b -> old_x = x // before printing this solution let's
124  * old_y = y // flush the pre solve statements
125  * old_z = z // mark down that we did this
126  *
127  * tmp0 = 2.0*dt // we also flush the tmp statements
128  * tmp1 = 1.0/(tmp0-1.0)
129  * tmp2 = pow(dt, 2)
130  * tmp3 = b*tmp2
131  * tmp4 = dt*old_x
132  * tmp5 = a*dt
133  * tmp6 = dt*old_y
134  * tmp7 = tmp5+tmp6
135  *
136  * x = -tmp1*(b*dt+old_x-tmp3-tmp4+tmp7) // finally, the solution
137  *
138  * if ( x == 0) { // nothing to do
139  * a = a + 1 // mark down the tmp statements and pre solve statements
140  * // that contain 'a' in the rhs as in need for an update
141  *
142  * // x = x + 1 // the same as before but for 'x'. In particular a pre
143  * // solve statement is marked for updating. This will
144  * // produce an error later in the code
145  * } // nothing to do
146  *
147  * y' = x + y + a -> // old_x = x // here, if 'x = x + 1' were not commented, the
148  * // code would try to print this line an throw an
149  * // error since the pre solve statements were already
150  * // printed once
151  * tmp5 = a*dt // flush the tmp statements that need updating. In
152  * tmp7 = tmp5+tmp6 // our example, all the tmp statements that
153  * // directly or indirectly depend on a
154  * // for performance, we print only the ones that need updating
155  *
156  * z' = y + a -> z = -tmp1*(-a*tmp2+b*pow(dt, 3)+old_x*tmp2-old_y*tmp2-old_z*tmp0+old_z+tmp7)
157  * // nothing is marked for updating (among pre solve statements and tmp
158  * // statements): just print the solution
159  *
160  * x = x + 1 // nothing to do
161  * } // nothing to do
162  * \endcode
163  *
164  * Last notes:
165  *
166  * For linEquations or NonLinEquations association of the solution with a particular statement could
167  * be impossible. For example \f$ ~ x + y = 0 \f$ does not have a simple variable in the lhs. Thus,
168  * an association with a particular solution statement is not possible. Thus we do 2 runs where we
169  * first match everything we can by value and then we associate everything we can in a greedy way.
170  *
171  * For large system of equations the code sets up the J matrix and F vector to be sent to eigen for
172  * the Newton method which will solve a bunch of J x = F for each time step). In this case it is
173  always safe to
174  * replace greedy because sympy does not sort the equations in the matrix/vector. In addition, cse
175  is disabled by
176  * default. Thus, there is a 1:1 correspondence of an equation of the original mod file and a row of
177  the matrix and
178  * an element of F. So if we have:
179  *
180  * \code{.mod}
181  * LINEAR lin {
182  * ~ x = ...
183  * a = a + 1
184  * ~ y = ...
185  * ~ z = ...
186  * ~ w = ...
187  * }
188  * \endcode
189  *
190  * We get the vector F and matrix J
191  *
192  * \code
193  * F = [0, J = [0, 4, 8, 12,
194  * 1, 1, 5, 9, 13,
195  * 2, 2, 6, 10, 14,
196  * 3] 3, 7, 11, 15]
197  * \endcode
198  *
199  * Where the numbers indicate their column-wise index. The solution replacement becomes:
200  *
201  * \code
202  * ~ x = ... -> F[0] = ...
203  * J[0] = ...
204  * J[4] = ...
205  * J[8] = ...
206  * J[12] = ...
207  * a = a + 1
208  * ~ y = ... -> ...
209  * \endcode
210  *
211  */
213  public:
214  enum class ReplacePolicy {
215  VALUE = 0, //!< Replace statements matching by lhs varName
216  GREEDY = 1, //!< Replace statements greedily
217  };
218  /// Empty ctor
219  SympyReplaceSolutionsVisitor() = delete;
220 
221  /// Default constructor
222  SympyReplaceSolutionsVisitor(const std::vector<std::string>& pre_solve_statements,
223  const std::vector<std::string>& solutions,
224  const std::unordered_set<ast::Statement*>& to_be_removed,
225  const ReplacePolicy policy,
226  size_t n_next_equations,
227  const std::string& tmp_unique_prefix);
228 
229  /// idx (in the new statementVector) of the first statement that was added. -1 if nothing was
230  /// added
231  inline int replaced_statements_begin() const {
232  return replaced_statements_range.first;
233  }
234  /// idx (in the new statementVector) of the last statement that was added. -1 if nothing was
235  /// added
236  inline int replaced_statements_end() const {
237  return replaced_statements_range.second;
238  }
239 
240  void visit_statement_block(ast::StatementBlock& node) override;
241  void visit_diff_eq_expression(ast::DiffEqExpression& node) override;
242  void visit_lin_equation(ast::LinEquation& node) override;
243  void visit_non_lin_equation(ast::NonLinEquation& node) override;
244  void visit_binary_expression(ast::BinaryExpression& node) override;
245 
246 
247  private:
248  /** \brief Try to replace a statement
249  *
250  * \param node it can be Diff_Eq_Expression/LinEquation/NonLinEquation
251  * \param get_lhs method with witch we may get the lhs (in case we need it)
252  */
254  const ast::Node& node,
255  std::shared_ptr<ast::Expression> get_lhs(const ast::Node& node));
256 
257  /**
258  * \struct InterleavesCounter
259  * \brief Count interleaves of assignment statement inside the system of equations
260  *
261  * Example:
262  *
263  * \code
264  * \\ not in the system, n = 0, is_in_system = false
265  * ~ x + y = 0 \\ system, in_system switch false -> true, n = 1
266  * ~ y = a + 1 \\ system, no switch, nothing to do
267  * a = ... \\ no system, in_system switch true -> false, nothing to do
268  * ~ z = x + y + z \\ system, in_system switch false -> true, n = 2
269  * \endcode
270  *
271  * Number of interleaves: n-1 = 1
272  */
274  /// Count interleaves defined as a switch false -> true for \ref in_system
275  void new_equation(const bool is_in_system);
276 
277  /// Number of interleaves. We need to remove the first activation of the switch except if
278  /// there were no switches
279  inline size_t n() const {
280  return n_interleaves == 0 ? 0 : n_interleaves - 1;
281  }
282 
283  private:
284  /**
285  * \brief Number of interleaves of assignment statements in between equations of the system
286  * of equations
287  *
288  * This is equivalent to the number of switches false -> true of \ref in_system minus the
289  * very first one (if the system exists).
290  */
291  size_t n_interleaves = 0;
292 
293  /// Bool that keeps track if just wrote an equation of the system of equations (true) or not
294  /// (false)
295  bool in_system = false;
296  };
297 
298 
299  /**
300  * \struct StatementDispenser
301  * \brief Sorts and maps statements to variables keeping track of what needs updating
302  *
303  * This is a multi-purpose object that:
304  *
305  * - keeps track of what was already updated
306  * - decides what statements need updating in case there was a variable assignment (i.e. \f$ a =
307  * 3 \f$)
308  * - builds the statements from a vector of strings
309  *
310  */
312  /// Empty ctor
313  StatementDispenser() = default;
314 
315  /// Standard ctor
316  StatementDispenser(const std::vector<std::string>::const_iterator& statements_str_beg,
317  const std::vector<std::string>::const_iterator& statements_str_end,
318  const int error_on_n_flushes);
319 
320  /// Construct the maps \ref var2dependants, \ref var2statement and \ref dependency_map
321  /// for easy access and classification of the statements
322  void build_maps();
323 
324  /// Check if one of the statements assigns this variable (i.e. \f$ x' = f(x, y, x) \f$) and
325  /// is still tagged
326  inline bool is_var_assigned_here(const std::string& var) const {
327  const auto it = var2statement.find(var);
328  return it != var2statement.end() && tags.find(it->second) != tags.end();
329  }
330 
331  /**
332  * \brief Look for \p var in \ref var2statement and emplace back that statement in \p
333  * new_statements
334  *
335  * If there is no \p var key in \ref var2statement, return false
336  */
338  const std::string& var);
339 
340 
341  /// Emplace back the next \p n_next_statements solutions in \ref statements that is marked
342  /// for updating in \ref tags
344  const size_t n_next_statements);
345 
346  /// Emplace back all the statements that are marked for updating in \ref tags
348 
349  /**
350  * \brief Tag all the statements that depend on \p var for updating
351  *
352  * This is necessary when an assignment has invalidated this variable
353  */
354  size_t tag_dependant_statements(const std::string& var);
355 
356  /// Mark that all the statements need updating (probably unused)
357  void tag_all_statements();
358 
359  /**
360  * \brief x (key) : f(a, b, c, ...) (values)
361  *
362  * Given a certain variable (map key) we get all the (root) variables on which this variable
363  * depends on (values)
364  *
365  * For example, imagine we have these assignments:
366  *
367  * \code
368  * tmp = b
369  * x = a + tmp + exp(a)
370  * \endcode
371  *
372  * \ref dependency_map is:
373  *
374  * - tmp : b
375  * - x : a, b
376  *
377  */
378  std::unordered_map<std::string, std::unordered_set<std::string>> dependency_map;
379 
380  /**
381  * \brief a (key) : f(..., a, ...), g(..., a, ...), h(..., a, ...), ... (values)
382  *
383  * This the "reverse" of \ref dependency_map. Given a certain variable it provides
384  * the statements that depend on it. It is a set because we want to print them in
385  * order and we do not want duplicates. The value is the index in \ref statements or \ref
386  * tags
387  *
388  * For example:
389  *
390  * \code
391  * tmp = b // statement 0
392  * x = a + tmp + exp(a) // statement 1
393  * \endcode
394  *
395  * \ref var2dependants is:
396  *
397  * - a : 1
398  * - b : 0, 1
399  *
400  */
401  std::unordered_map<std::string, std::set<size_t>> var2dependants;
402 
403  /**
404  * \brief a (key) : a = f(...) (value)
405  *
406  * Given a certain variable we get the statement where that variable is defined
407  *
408  * For example:
409  *
410  * \code{.mod}
411  * tmp = b // statement 0
412  * x = a + tmp + exp(a) // statement 1
413  * \endcode
414  *
415  * \ref var2dependants is:
416  *
417  * - tmp : 0
418  * - x : 1
419  *
420  */
421  std::unordered_map<std::string, size_t> var2statement;
422 
423  /// Vector of statements
424  std::vector<std::shared_ptr<ast::Statement>> statements;
425 
426  /**
427  * \brief Keeps track of what statements need updating
428  *
429  * The elements of this set are the indexes of the \ref statements vector that need
430  * updating. It is a set because we need to be able to easily find them by value and we need
431  * them ordered to pick "the next one"
432  */
433  std::set<size_t> tags;
434 
435  /**
436  * \brief Max number of times a statement was printed using an \ref
437  * emplace_back_all_tagged_statements command
438  *
439  * This is useful to check if, during updates, a variable was assigned.
440  *
441  * For example:
442  *
443  * \code{.mod}
444  * x' = a
445  * x = a + 1
446  * y' = b
447  * \endcode
448  *
449  * In this sequence of statements \f$ x \f$ was assigned within variable updates. This
450  * sequence of statements could lead to instability/wrong results for derivimplicit methods.
451  * Better to prevent this entirely. It can still be assigned at the end/beginning
452  */
453  size_t n_flushes = 0;
454 
455  /// Emit error when \ref n_flushes reaches this number. -1 disables the error entirely
457  };
458 
459  /// Update state variable statements (i.e. \f$old_x = x \f$)
461 
462  /// tmp statements that appear with --cse (i.e. \f$tmp0 = a \f$)
464 
465  /// solutions that we want to replace
467 
468  /**
469  * \brief Replacements found by the visitor
470  *
471  * The keys are the old_statements that need replacing with the new ones (the
472  * value). Since there are \ref pre_solve_statements and \ref tmp_statements; it is in general
473  * a replacement of 1 : n statements
474  */
475  std::unordered_map<std::shared_ptr<ast::Statement>, ast::StatementVector> replacements;
476 
477  /// Used to notify to visit_statement_block was called by the user (or another visitor) or
478  /// re-called in a nested block
480 
481  /// Replacement policy used by the various visitors
483 
484  /// Number of solutions that match each old_statement with the greedy policy
486 
487  /// group of old statements that need replacing
488  const std::unordered_set<ast::Statement*>* to_be_removed;
489 
490  /// counts how many times the solution statements are interleaved with assignment expressions
492 
493  /// {begin index, end index} of the added statements. -1 means that it is invalid
494  std::pair<int, int> replaced_statements_range = {-1, -1};
495 };
496 
497 /** @} */ // end of visitor_classes
498 
499 } // namespace visitor
500 } // namespace nmodl
nmodl::visitor::SympyReplaceSolutionsVisitor::to_be_removed
const std::unordered_set< ast::Statement * > * to_be_removed
group of old statements that need replacing
Definition: sympy_replace_solutions_visitor.hpp:488
nmodl::visitor::SympyReplaceSolutionsVisitor::ReplacePolicy
ReplacePolicy
Definition: sympy_replace_solutions_visitor.hpp:214
nmodl::ast::Node
Base class for all AST node.
Definition: node.hpp:40
nmodl::visitor::SympyReplaceSolutionsVisitor::pre_solve_statements
StatementDispenser pre_solve_statements
Update state variable statements (i.e. )
Definition: sympy_replace_solutions_visitor.hpp:460
nmodl::visitor::SympyReplaceSolutionsVisitor::try_replace_tagged_statement
void try_replace_tagged_statement(const ast::Node &node, std::shared_ptr< ast::Expression > get_lhs(const ast::Node &node))
Try to replace a statement.
Definition: sympy_replace_solutions_visitor.cpp:162
nmodl::ast::DiffEqExpression
Represents differential equation in DERIVATIVE block.
Definition: diff_eq_expression.hpp:38
nmodl::visitor::SympyReplaceSolutionsVisitor::replaced_statements_end
int replaced_statements_end() const
idx (in the new statementVector) of the last statement that was added.
Definition: sympy_replace_solutions_visitor.hpp:236
nmodl::visitor::SympyReplaceSolutionsVisitor
Replace statements in node with pre_solve_statements, tmp_statements, and solutions.
Definition: sympy_replace_solutions_visitor.hpp:212
nmodl::visitor::SympyReplaceSolutionsVisitor::StatementDispenser::tag_all_statements
void tag_all_statements()
Mark that all the statements need updating (probably unused)
Definition: sympy_replace_solutions_visitor.cpp:441
nmodl::visitor::SympyReplaceSolutionsVisitor::StatementDispenser::error_on_n_flushes
int error_on_n_flushes
Emit error when n_flushes reaches this number. -1 disables the error entirely.
Definition: sympy_replace_solutions_visitor.hpp:456
nmodl::ast::NonLinEquation
One equation in a system of equations that collectively make a NONLINEAR block.
Definition: non_lin_equation.hpp:38
nmodl::visitor::SympyReplaceSolutionsVisitor::StatementDispenser::build_maps
void build_maps()
Construct the maps var2dependants, var2statement and dependency_map for easy access and classificatio...
Definition: sympy_replace_solutions_visitor.cpp:297
nmodl::visitor::SympyReplaceSolutionsVisitor::replaced_statements_begin
int replaced_statements_begin() const
idx (in the new statementVector) of the first statement that was added.
Definition: sympy_replace_solutions_visitor.hpp:231
nmodl::visitor::SympyReplaceSolutionsVisitor::StatementDispenser::StatementDispenser
StatementDispenser()=default
Empty ctor.
nmodl::ast::StatementVector
std::vector< std::shared_ptr< Statement > > StatementVector
Definition: ast_decl.hpp:302
nmodl::visitor::SympyReplaceSolutionsVisitor::visit_statement_block
void visit_statement_block(ast::StatementBlock &node) override
visit node of type ast::StatementBlock
Definition: sympy_replace_solutions_visitor.cpp:64
nmodl::visitor::SympyReplaceSolutionsVisitor::InterleavesCounter::n_interleaves
size_t n_interleaves
Number of interleaves of assignment statements in between equations of the system of equations.
Definition: sympy_replace_solutions_visitor.hpp:291
nmodl
encapsulates code generation backend implementations
Definition: ast_common.hpp:26
nmodl::visitor::SympyReplaceSolutionsVisitor::StatementDispenser::tags
std::set< size_t > tags
Keeps track of what statements need updating.
Definition: sympy_replace_solutions_visitor.hpp:433
nmodl::visitor::SympyReplaceSolutionsVisitor::replaced_statements_range
std::pair< int, int > replaced_statements_range
{begin index, end index} of the added statements. -1 means that it is invalid
Definition: sympy_replace_solutions_visitor.hpp:494
nmodl::visitor::SympyReplaceSolutionsVisitor::tmp_statements
StatementDispenser tmp_statements
tmp statements that appear with –cse (i.e. )
Definition: sympy_replace_solutions_visitor.hpp:463
nmodl::visitor::SympyReplaceSolutionsVisitor::StatementDispenser::var2statement
std::unordered_map< std::string, size_t > var2statement
a (key) : a = f(...) (value)
Definition: sympy_replace_solutions_visitor.hpp:421
nmodl::visitor::SympyReplaceSolutionsVisitor::visit_lin_equation
void visit_lin_equation(ast::LinEquation &node) override
visit node of type ast::LinEquation
Definition: sympy_replace_solutions_visitor.cpp:220
nmodl::visitor::SympyReplaceSolutionsVisitor::StatementDispenser
Sorts and maps statements to variables keeping track of what needs updating.
Definition: sympy_replace_solutions_visitor.hpp:311
nmodl::visitor::SympyReplaceSolutionsVisitor::InterleavesCounter
Count interleaves of assignment statement inside the system of equations.
Definition: sympy_replace_solutions_visitor.hpp:273
nmodl::visitor::SympyReplaceSolutionsVisitor::StatementDispenser::var2dependants
std::unordered_map< std::string, std::set< size_t > > var2dependants
a (key) : f(..., a, ...), g(..., a, ...), h(..., a, ...), ...
Definition: sympy_replace_solutions_visitor.hpp:401
nmodl::visitor::SympyReplaceSolutionsVisitor::InterleavesCounter::new_equation
void new_equation(const bool is_in_system)
Count interleaves defined as a switch false -> true for in_system.
Definition: sympy_replace_solutions_visitor.cpp:28
nmodl::visitor::SympyReplaceSolutionsVisitor::visit_binary_expression
void visit_binary_expression(ast::BinaryExpression &node) override
visit node of type ast::BinaryExpression
Definition: sympy_replace_solutions_visitor.cpp:240
nmodl::visitor::SympyReplaceSolutionsVisitor::visit_diff_eq_expression
void visit_diff_eq_expression(ast::DiffEqExpression &node) override
visit node of type ast::DiffEqExpression
Definition: sympy_replace_solutions_visitor.cpp:211
nmodl::visitor::SympyReplaceSolutionsVisitor::policy
ReplacePolicy policy
Replacement policy used by the various visitors.
Definition: sympy_replace_solutions_visitor.hpp:482
nmodl::visitor::AstVisitor
Concrete visitor for all AST classes.
Definition: ast_visitor.hpp:37
nmodl::visitor::SympyReplaceSolutionsVisitor::interleaves_counter
InterleavesCounter interleaves_counter
counts how many times the solution statements are interleaved with assignment expressions
Definition: sympy_replace_solutions_visitor.hpp:491
nmodl::visitor::SympyReplaceSolutionsVisitor::StatementDispenser::n_flushes
size_t n_flushes
Max number of times a statement was printed using an emplace_back_all_tagged_statements command.
Definition: sympy_replace_solutions_visitor.hpp:453
nmodl::visitor::SympyReplaceSolutionsVisitor::StatementDispenser::tag_dependant_statements
size_t tag_dependant_statements(const std::string &var)
Tag all the statements that depend on var for updating.
Definition: sympy_replace_solutions_visitor.cpp:424
nmodl::visitor::SympyReplaceSolutionsVisitor::ReplacePolicy::GREEDY
@ GREEDY
Replace statements greedily.
nmodl::visitor::SympyReplaceSolutionsVisitor::SympyReplaceSolutionsVisitor
SympyReplaceSolutionsVisitor()=delete
Empty ctor.
nmodl::visitor::SympyReplaceSolutionsVisitor::replacements
std::unordered_map< std::shared_ptr< ast::Statement >, ast::StatementVector > replacements
Replacements found by the visitor.
Definition: sympy_replace_solutions_visitor.hpp:475
nmodl::visitor::SympyReplaceSolutionsVisitor::solution_statements
StatementDispenser solution_statements
solutions that we want to replace
Definition: sympy_replace_solutions_visitor.hpp:466
nmodl::visitor::SympyReplaceSolutionsVisitor::StatementDispenser::statements
std::vector< std::shared_ptr< ast::Statement > > statements
Vector of statements.
Definition: sympy_replace_solutions_visitor.hpp:424
nmodl::ast::StatementBlock
Represents block encapsulating list of statements.
Definition: statement_block.hpp:53
nmodl::visitor::SympyReplaceSolutionsVisitor::StatementDispenser::emplace_back_all_tagged_statements
size_t emplace_back_all_tagged_statements(ast::StatementVector &new_statements)
Emplace back all the statements that are marked for updating in tags.
Definition: sympy_replace_solutions_visitor.cpp:396
nmodl::ast::LinEquation
One equation in a system of equations tha collectively form a LINEAR block.
Definition: lin_equation.hpp:38
nmodl::visitor::SympyReplaceSolutionsVisitor::StatementDispenser::try_emplace_back_tagged_statement
bool try_emplace_back_tagged_statement(ast::StatementVector &new_statements, const std::string &var)
Look for var in var2statement and emplace back that statement in new_statements.
Definition: sympy_replace_solutions_visitor.cpp:349
nmodl::visitor::SympyReplaceSolutionsVisitor::StatementDispenser::is_var_assigned_here
bool is_var_assigned_here(const std::string &var) const
Check if one of the statements assigns this variable (i.e.
Definition: sympy_replace_solutions_visitor.hpp:326
nmodl::visitor::SympyReplaceSolutionsVisitor::is_top_level_statement_block
bool is_top_level_statement_block
Used to notify to visit_statement_block was called by the user (or another visitor) or re-called in a...
Definition: sympy_replace_solutions_visitor.hpp:479
nmodl::visitor::SympyReplaceSolutionsVisitor::n_next_equations
size_t n_next_equations
Number of solutions that match each old_statement with the greedy policy.
Definition: sympy_replace_solutions_visitor.hpp:485
nmodl::visitor::SympyReplaceSolutionsVisitor::StatementDispenser::emplace_back_next_tagged_statements
size_t emplace_back_next_tagged_statements(ast::StatementVector &new_statements, const size_t n_next_statements)
Emplace back the next n_next_statements solutions in statements that is marked for updating in tags.
Definition: sympy_replace_solutions_visitor.cpp:376
nmodl::ast::BinaryExpression
Represents binary expression in the NMODL.
Definition: binary_expression.hpp:52
nmodl::visitor::SympyReplaceSolutionsVisitor::ReplacePolicy::VALUE
@ VALUE
Replace statements matching by lhs varName.
nmodl::visitor::SympyReplaceSolutionsVisitor::StatementDispenser::dependency_map
std::unordered_map< std::string, std::unordered_set< std::string > > dependency_map
x (key) : f(a, b, c, ...) (values)
Definition: sympy_replace_solutions_visitor.hpp:378
nmodl::visitor::SympyReplaceSolutionsVisitor::visit_non_lin_equation
void visit_non_lin_equation(ast::NonLinEquation &node) override
visit node of type ast::NonLinEquation
Definition: sympy_replace_solutions_visitor.cpp:230
nmodl::visitor::SympyReplaceSolutionsVisitor::InterleavesCounter::in_system
bool in_system
Bool that keeps track if just wrote an equation of the system of equations (true) or not (false)
Definition: sympy_replace_solutions_visitor.hpp:295
nmodl::visitor::SympyReplaceSolutionsVisitor::InterleavesCounter::n
size_t n() const
Number of interleaves.
Definition: sympy_replace_solutions_visitor.hpp:279
ast_visitor.hpp
Concrete visitor for all AST classes.