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  * \param get_rhs method with witch we may get the rhs (in case we need it)
253  */
255  const ast::Node& node,
256  std::shared_ptr<ast::Expression> get_lhs(const ast::Node& node),
257  std::shared_ptr<ast::Expression> get_rhs(const ast::Node& node));
258 
259  /**
260  * \struct InterleavesCounter
261  * \brief Count interleaves of assignment statement inside the system of equations
262  *
263  * Example:
264  *
265  * \code
266  * \\ not in the system, n = 0, is_in_system = false
267  * ~ x + y = 0 \\ system, in_system switch false -> true, n = 1
268  * ~ y = a + 1 \\ system, no switch, nothing to do
269  * a = ... \\ no system, in_system switch true -> false, nothing to do
270  * ~ z = x + y + z \\ system, in_system switch false -> true, n = 2
271  * \endcode
272  *
273  * Number of interleaves: n-1 = 1
274  */
276  /// Count interleaves defined as a switch false -> true for \ref in_system
277  void new_equation(const bool is_in_system);
278 
279  /// Number of interleaves. We need to remove the first activation of the switch except if
280  /// there were no switches
281  inline size_t n() const {
282  return n_interleaves == 0 ? 0 : n_interleaves - 1;
283  }
284 
285  private:
286  /**
287  * \brief Number of interleaves of assignment statements in between equations of the system
288  * of equations
289  *
290  * This is equivalent to the number of switches false -> true of \ref in_system minus the
291  * very first one (if the system exists).
292  */
293  size_t n_interleaves = 0;
294 
295  /// Bool that keeps track if just wrote an equation of the system of equations (true) or not
296  /// (false)
297  bool in_system = false;
298  };
299 
300 
301  /**
302  * \struct StatementDispenser
303  * \brief Sorts and maps statements to variables keeping track of what needs updating
304  *
305  * This is a multi-purpose object that:
306  *
307  * - keeps track of what was already updated
308  * - decides what statements need updating in case there was a variable assignment (i.e. \f$ a =
309  * 3 \f$)
310  * - builds the statements from a vector of strings
311  *
312  */
314  /// Empty ctor
315  StatementDispenser() = default;
316 
317  /// Standard ctor
318  StatementDispenser(const std::vector<std::string>::const_iterator& statements_str_beg,
319  const std::vector<std::string>::const_iterator& statements_str_end,
320  const int error_on_n_flushes);
321 
322  /// Construct the maps \ref var2dependants, \ref var2statement and \ref dependency_map
323  /// for easy access and classification of the statements
324  void build_maps();
325 
326  /// Check if one of the statements assigns this variable (i.e. \f$ x' = f(x, y, x) \f$) and
327  /// is still tagged
328  inline bool is_var_assigned_here(const std::string& var) const {
329  const auto it = var2statement.find(var);
330  return it != var2statement.end() && tags.find(it->second) != tags.end();
331  }
332 
333  /**
334  * \brief Look for \p var in \ref var2statement and emplace back that statement in \p
335  * new_statements
336  *
337  * If there is no \p var key in \ref var2statement, return false
338  */
340  const std::string& var);
341 
342 
343  /// Emplace back the next \p n_next_statements solutions in \ref statements that is marked
344  /// for updating in \ref tags
346  const size_t n_next_statements);
347 
348  /// Emplace back all the statements that are marked for updating in \ref tags
350 
351  /**
352  * \brief Tag all the statements that depend on \p var for updating
353  *
354  * This is necessary when an assignment has invalidated this variable
355  */
356  size_t tag_dependant_statements(const std::string& var);
357 
358  /// Mark that all the statements need updating (probably unused)
359  void tag_all_statements();
360 
361  /**
362  * \brief x (key) : f(a, b, c, ...) (values)
363  *
364  * Given a certain variable (map key) we get all the (root) variables on which this variable
365  * depends on (values)
366  *
367  * For example, imagine we have these assignments:
368  *
369  * \code
370  * tmp = b
371  * x = a + tmp + exp(a)
372  * \endcode
373  *
374  * \ref dependency_map is:
375  *
376  * - tmp : b
377  * - x : a, b
378  *
379  */
380  std::unordered_map<std::string, std::unordered_set<std::string>> dependency_map;
381 
382  /**
383  * \brief a (key) : f(..., a, ...), g(..., a, ...), h(..., a, ...), ... (values)
384  *
385  * This the "reverse" of \ref dependency_map. Given a certain variable it provides
386  * the statements that depend on it. It is a set because we want to print them in
387  * order and we do not want duplicates. The value is the index in \ref statements or \ref
388  * tags
389  *
390  * For example:
391  *
392  * \code
393  * tmp = b // statement 0
394  * x = a + tmp + exp(a) // statement 1
395  * \endcode
396  *
397  * \ref var2dependants is:
398  *
399  * - a : 1
400  * - b : 0, 1
401  *
402  */
403  std::unordered_map<std::string, std::set<size_t>> var2dependants;
404 
405  /**
406  * \brief a (key) : a = f(...) (value)
407  *
408  * Given a certain variable we get the statement where that variable is defined
409  *
410  * For example:
411  *
412  * \code{.mod}
413  * tmp = b // statement 0
414  * x = a + tmp + exp(a) // statement 1
415  * \endcode
416  *
417  * \ref var2dependants is:
418  *
419  * - tmp : 0
420  * - x : 1
421  *
422  */
423  std::unordered_map<std::string, size_t> var2statement;
424 
425  /// Vector of statements
426  std::vector<std::shared_ptr<ast::Statement>> statements;
427 
428  /**
429  * \brief Keeps track of what statements need updating
430  *
431  * The elements of this set are the indexes of the \ref statements vector that need
432  * updating. It is a set because we need to be able to easily find them by value and we need
433  * them ordered to pick "the next one"
434  */
435  std::set<size_t> tags;
436 
437  /**
438  * \brief Max number of times a statement was printed using an \ref
439  * emplace_back_all_tagged_statements command
440  *
441  * This is useful to check if, during updates, a variable was assigned.
442  *
443  * For example:
444  *
445  * \code{.mod}
446  * x' = a
447  * x = a + 1
448  * y' = b
449  * \endcode
450  *
451  * In this sequence of statements \f$ x \f$ was assigned within variable updates. This
452  * sequence of statements could lead to instability/wrong results for derivimplicit methods.
453  * Better to prevent this entirely. It can still be assigned at the end/beginning
454  */
455  size_t n_flushes = 0;
456 
457  /// Emit error when \ref n_flushes reaches this number. -1 disables the error entirely
459  };
460 
461  /// Update state variable statements (i.e. \f$old_x = x \f$)
463 
464  /// tmp statements that appear with --cse (i.e. \f$tmp0 = a \f$)
466 
467  /// solutions that we want to replace
469 
470  /**
471  * \brief Replacements found by the visitor
472  *
473  * The keys are the old_statements that need replacing with the new ones (the
474  * value). Since there are \ref pre_solve_statements and \ref tmp_statements; it is in general
475  * a replacement of 1 : n statements
476  */
477  std::unordered_map<std::shared_ptr<ast::Statement>, ast::StatementVector> replacements;
478 
479  /// Used to notify to visit_statement_block was called by the user (or another visitor) or
480  /// re-called in a nested block
482 
483  /// Replacement policy used by the various visitors
485 
486  /// Number of solutions that match each old_statement with the greedy policy
488 
489  /// group of old statements that need replacing
490  const std::unordered_set<ast::Statement*>* to_be_removed;
491 
492  /// counts how many times the solution statements are interleaved with assignment expressions
494 
495  /// {begin index, end index} of the added statements. -1 means that it is invalid
496  std::pair<int, int> replaced_statements_range = {-1, -1};
497 };
498 
499 /** @} */ // end of visitor_classes
500 
501 } // namespace visitor
502 } // 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:490
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:462
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:455
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:458
nmodl::ast::NonLinEquation
TODO.
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:311
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:298
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:293
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:435
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:496
nmodl::visitor::SympyReplaceSolutionsVisitor::tmp_statements
StatementDispenser tmp_statements
tmp statements that appear with –cse (i.e. )
Definition: sympy_replace_solutions_visitor.hpp:465
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), std::shared_ptr< ast::Expression > get_rhs(const ast::Node &node))
Try to replace a statement.
Definition: sympy_replace_solutions_visitor.cpp:162
nmodl::visitor::SympyReplaceSolutionsVisitor::StatementDispenser::var2statement
std::unordered_map< std::string, size_t > var2statement
a (key) : a = f(...) (value)
Definition: sympy_replace_solutions_visitor.hpp:423
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:226
nmodl::visitor::SympyReplaceSolutionsVisitor::StatementDispenser
Sorts and maps statements to variables keeping track of what needs updating.
Definition: sympy_replace_solutions_visitor.hpp:313
nmodl::visitor::SympyReplaceSolutionsVisitor::InterleavesCounter
Count interleaves of assignment statement inside the system of equations.
Definition: sympy_replace_solutions_visitor.hpp:275
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:403
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:254
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:213
nmodl::visitor::SympyReplaceSolutionsVisitor::policy
ReplacePolicy policy
Replacement policy used by the various visitors.
Definition: sympy_replace_solutions_visitor.hpp:484
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:493
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:455
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:438
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:477
nmodl::visitor::SympyReplaceSolutionsVisitor::solution_statements
StatementDispenser solution_statements
solutions that we want to replace
Definition: sympy_replace_solutions_visitor.hpp:468
nmodl::visitor::SympyReplaceSolutionsVisitor::StatementDispenser::statements
std::vector< std::shared_ptr< ast::Statement > > statements
Vector of statements.
Definition: sympy_replace_solutions_visitor.hpp:426
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:410
nmodl::ast::LinEquation
TODO.
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:363
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:328
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:481
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:487
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:390
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:380
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:240
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:297
nmodl::visitor::SympyReplaceSolutionsVisitor::InterleavesCounter::n
size_t n() const
Number of interleaves.
Definition: sympy_replace_solutions_visitor.hpp:281
ast_visitor.hpp
Concrete visitor for all AST classes.