![Logo](logo.png) |
User Guide
|
Go to the documentation of this file.
36 const std::vector<std::string>& solutions,
40 const std::string& tmp_unique_prefix)
43 , to_be_removed(&to_be_removed)
45 , n_next_equations(n_next_equations)
46 , replaced_statements_range(-1, -1) {
48 const auto ss_tmp_delimeter =
49 tmp_unique_prefix.empty()
51 : std::find_if(solutions.begin(),
53 [&tmp_unique_prefix](
const std::string& statement) {
54 return statement.substr(0, tmp_unique_prefix.size()) !=
57 tmp_statements = StatementDispenser(solutions.begin(), ss_tmp_delimeter, -1);
58 solution_statements = StatementDispenser(ss_tmp_delimeter, solutions.end(), -1);
65 const bool current_is_top_level_statement_block =
70 if (current_is_top_level_statement_block) {
71 logger->debug(
"SympyReplaceSolutionsVisitor :: visit statements. Matching policy: {}",
78 "SympyReplaceSolutionsVisitor :: not all solutions were replaced. Policy: GREEDY");
85 "SympyReplaceSolutionsVisitor :: Found ambiguous system of equations "
86 "interleaved with {} assignment statements. I do not know what equations go "
88 "equations go after the assignment statements. Either put all the equations "
89 "that need to be solved "
90 "in the form: x = f(...) and with distinct variable assignments or do not "
91 "interleave the system with assignments.",
102 new_statements.reserve(2 * old_statements.size());
103 for (
auto& old_statement: old_statements) {
104 const auto& replacement_ptr =
replacements.find(old_statement);
110 new_statements.insert(new_statements.end(),
111 replacement_ptr->second.begin(),
112 replacement_ptr->second.end());
116 logger->debug(
"SympyReplaceSolutionsVisitor :: erasing {}",
to_nmodl(old_statement));
117 for (
const auto& replacement: replacement_ptr->second) {
118 logger->debug(
"SympyReplaceSolutionsVisitor :: adding {}",
to_nmodl(replacement));
122 logger->debug(
"SympyReplaceSolutionsVisitor :: found {}, nothing to do",
124 new_statements.emplace_back(old_statement);
126 logger->debug(
"SympyReplaceSolutionsVisitor :: erasing {}",
to_nmodl(old_statement));
130 if (current_is_top_level_statement_block) {
132 std::ostringstream ss;
136 throw std::runtime_error(fmt::format(
137 "Not all solutions were replaced! Sympy returned {} equations but I could not find "
139 "for all of them. In particular, the following equations remain to be replaced "
140 "somewhere:\n{}This is "
141 "probably a bug and I invite you to report it to a developer. Possible causes:\n"
142 " - I did not do a GREEDY pass and some solutions could not be replaced by VALUE\n "
144 "returned more equations than what we expected\n - There is a bug in the GREEDY "
146 "solutions were replaced but not untagged",
164 std::shared_ptr<ast::Expression> get_lhs(
const ast::Node& node)) {
167 const auto& statement = std::static_pointer_cast<ast::Statement>(
181 logger->debug(
"SympyReplaceSolutionsVisitor :: marking for replacement {}",
195 logger->debug(
"SympyReplaceSolutionsVisitor :: marking for replacement {}",
212 logger->debug(
"SympyReplaceSolutionsVisitor :: visit {}",
to_nmodl(node));
213 auto get_lhs = [](
const ast::Node& node) -> std::shared_ptr<ast::Expression> {
221 logger->debug(
"SympyReplaceSolutionsVisitor :: visit {}",
to_nmodl(node));
222 auto get_lhs = [](
const ast::Node& node) -> std::shared_ptr<ast::Expression> {
231 logger->debug(
"SympyReplaceSolutionsVisitor :: visit {}",
to_nmodl(node));
232 auto get_lhs = [](
const ast::Node& node) -> std::shared_ptr<ast::Expression> {
241 logger->debug(
"SympyReplaceSolutionsVisitor :: visit {}",
to_nmodl(node));
246 std::static_pointer_cast<ast::VarName>(node.
get_lhs())->get_name()->get_node_name();
254 const std::vector<std::string>::const_iterator& statements_str_beg,
255 const std::vector<std::string>::const_iterator& statements_str_end,
256 const int error_on_n_flushes)
258 , error_on_n_flushes(error_on_n_flushes) {
298 for (
size_t ii = 0; ii < statements.size(); ++ii) {
299 const auto& statement = statements[ii];
301 if (statement->is_expression_statement()) {
302 const auto& e_statement =
303 std::static_pointer_cast<ast::ExpressionStatement>(statement)->get_expression();
304 if (e_statement->is_binary_expression()) {
305 const auto& bin_exp = std::static_pointer_cast<ast::BinaryExpression>(e_statement);
309 const auto& key = dependencies.first;
310 const auto& vars = dependencies.second;
312 var2statement.emplace(key, ii);
313 for (
const auto& var: vars) {
314 const auto& var_already_inserted = dependency_map.find(var);
315 if (var_already_inserted != dependency_map.end()) {
316 dependency_map[key].insert(var_already_inserted->second.begin(),
317 var_already_inserted->second.end());
318 for (
const auto& root_var: var_already_inserted->second) {
319 var2dependants[root_var].insert(ii);
322 dependency_map[key].insert(var);
323 var2dependants[var].insert(ii);
331 logger->debug(
"SympyReplaceSolutionsVisitor::StatementDispenser :: var2dependants map");
332 for (
const auto& entry: var2dependants) {
333 logger->debug(
"SympyReplaceSolutionsVisitor::StatementDispenser :: var `{}` used in:",
335 for (
const auto ii: entry.second) {
336 logger->debug(
"SympyReplaceSolutionsVisitor::StatementDispenser :: -> {}",
340 logger->debug(
"SympyReplaceSolutionsVisitor::StatementDispenser :: var2statement map");
341 for (
const auto& entry: var2statement) {
342 logger->debug(
"SympyReplaceSolutionsVisitor::StatementDispenser :: var `{}` defined in:",
344 logger->debug(
"SympyReplaceSolutionsVisitor::StatementDispenser :: -> {}",
345 to_nmodl(statements[entry.second]));
351 const std::string& var) {
352 auto ptr = var2statement.find(var);
353 bool emplaced =
false;
354 if (ptr != var2statement.end()) {
355 const auto ii = ptr->second;
356 const auto tag_ptr = tags.find(ii);
357 if (tag_ptr != tags.end()) {
358 new_statements.emplace_back(statements[ii]->clone());
363 "SympyReplaceSolutionsVisitor::StatementDispenser :: adding to replacement rule {}",
367 "SympyReplaceSolutionsVisitor::StatementDispenser :: tried adding to replacement "
368 "rule {} but statement is not "
378 const size_t n_next_statements) {
380 for (
size_t next_statement_ii = 0;
381 next_statement_ii < statements.size() && counter < n_next_statements;
382 ++next_statement_ii) {
383 const auto tag_ptr = tags.find(next_statement_ii);
384 if (tag_ptr != tags.end()) {
386 "SympyReplaceSolutionsVisitor::StatementDispenser :: adding to replacement rule {}",
387 to_nmodl(statements[next_statement_ii]));
388 new_statements.emplace_back(statements[next_statement_ii]->clone());
398 for (
const auto ii: tags) {
399 new_statements.emplace_back(statements[ii]->clone());
401 "SympyReplaceSolutionsVisitor::StatementDispenser :: adding to replacement rule {}",
405 n_flushes += (!tags.empty());
406 if (error_on_n_flushes > 0 && n_flushes >= error_on_n_flushes) {
407 throw std::runtime_error(
408 "SympyReplaceSolutionsVisitor::StatementDispenser :: State variable assignment(s) "
409 "interleaved in system "
411 "equations/differential equations. It is not allowed due to possible numerical "
412 "instability and undefined "
413 "behavior. Erase the assignment statement(s) or move them before/after the"
414 " set of equations/differential equations.");
417 const auto n_replacements = tags.size();
421 return n_replacements;
425 const std::string& var) {
426 auto ptr = var2dependants.find(var);
428 if (ptr != var2dependants.end()) {
429 for (
const auto ii: ptr->second) {
430 const auto pos = tags.insert(ii);
432 logger->debug(
"SympyReplaceSolutionsVisitor::StatementDispenser :: tagging {}",
442 logger->debug(
"SympyReplaceSolutionsVisitor::StatementDispenser :: tagging all statements");
443 for (
size_t i = 0; i < statements.size(); ++i) {
445 logger->debug(
"SympyReplaceSolutionsVisitor::StatementDispenser :: tagging {}",
const std::unordered_set< ast::Statement * > * to_be_removed
group of old statements that need replacing
Base class for all AST node.
std::string to_nmodl(const ast::Ast &node, const std::set< ast::AstNodeType > &exclude_types)
Given AST node, return the NMODL string representation.
StatementDispenser pre_solve_statements
Update state variable statements (i.e. )
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.
Represents differential equation in DERIVATIVE block.
void tag_all_statements()
Mark that all the statements need updating (probably unused)
std::vector< std::shared_ptr< Statement > > create_statements(const std::vector< std::string >::const_iterator &code_statements_beg, const std::vector< std::string >::const_iterator &code_statements_end)
Same as for create_statement but for vectors of strings.
One equation in a system of equations that collectively make a NONLINEAR block.
void build_maps()
Construct the maps var2dependants, var2statement and dependency_map for easy access and classificatio...
void visit_children(visitor::Visitor &v) override
visit children i.e.
StatementDispenser()=default
Empty ctor.
std::vector< std::shared_ptr< Statement > > StatementVector
void visit_statement_block(ast::StatementBlock &node) override
visit node of type ast::StatementBlock
size_t n_interleaves
Number of interleaves of assignment statements in between equations of the system of equations.
encapsulates code generation backend implementations
void set_statements(StatementVector &&statements)
Setter for member variable StatementBlock::statements (rvalue reference)
std::set< size_t > tags
Keeps track of what statements need updating.
std::pair< int, int > replaced_statements_range
{begin index, end index} of the added statements. -1 means that it is invalid
StatementDispenser tmp_statements
tmp statements that appear with –cse (i.e. )
Replace statements in node with pre_solve_statements, tmp_statements, and solutions.
std::pair< std::string, std::unordered_set< std::string > > statement_dependencies(const std::shared_ptr< ast::Expression > &lhs, const std::shared_ptr< ast::Expression > &rhs)
If lhs and rhs combined represent an assignment (we assume to have an "=" in between them) we extract...
void visit_lin_equation(ast::LinEquation &node) override
visit node of type ast::LinEquation
const StatementVector & get_statements() const noexcept
Getter for member variable StatementBlock::statements.
Utility functions for visitors implementation.
Count interleaves of assignment statement inside the system of equations.
void new_equation(const bool is_in_system)
Count interleaves defined as a switch false -> true for in_system.
void visit_binary_expression(ast::BinaryExpression &node) override
visit node of type ast::BinaryExpression
void visit_diff_eq_expression(ast::DiffEqExpression &node) override
visit node of type ast::DiffEqExpression
ReplacePolicy policy
Replacement policy used by the various visitors.
std::string statement_dependencies_key(const std::shared_ptr< ast::Expression > &lhs)
The result.first of statement_dependencies.
InterleavesCounter interleaves_counter
counts how many times the solution statements are interleaved with assignment expressions
size_t tag_dependant_statements(const std::string &var)
Tag all the statements that depend on var for updating.
@ GREEDY
Replace statements greedily.
const BinaryOperator & get_op() const noexcept
Getter for member variable BinaryExpression::op.
SympyReplaceSolutionsVisitor()=delete
Empty ctor.
std::unordered_map< std::shared_ptr< ast::Statement >, ast::StatementVector > replacements
Replacements found by the visitor.
StatementDispenser solution_statements
solutions that we want to replace
std::vector< std::shared_ptr< ast::Statement > > statements
Vector of statements.
Represents block encapsulating list of statements.
virtual std::shared_ptr< Ast > get_shared_ptr()
get std::shared_ptr from this pointer of the AST node
BinaryOp get_value() const noexcept
Getter for member variable BinaryOperator::value.
Implement logger based on spdlog library.
size_t emplace_back_all_tagged_statements(ast::StatementVector &new_statements)
Emplace back all the statements that are marked for updating in tags.
One equation in a system of equations tha collectively form a LINEAR block.
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.
bool is_var_assigned_here(const std::string &var) const
Check if one of the statements assigns this variable (i.e.
std::shared_ptr< Expression > get_lhs() const noexcept
Getter for member variable BinaryExpression::lhs.
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...
size_t n_next_equations
Number of solutions that match each old_statement with the greedy policy.
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.
THIS FILE IS GENERATED AT BUILD TIME AND SHALL NOT BE EDITED.
Represents binary expression in the NMODL.
@ VALUE
Replace statements matching by lhs varName.
void visit_non_lin_equation(ast::NonLinEquation &node) override
visit node of type ast::NonLinEquation
virtual Ast * get_parent() const
Parent getter.
bool in_system
Bool that keeps track if just wrote an equation of the system of equations (true) or not (false)
Auto generated AST classes declaration.
size_t n() const
Number of interleaves.