Skip to content

Add common subexpression elimination (CSE) feature - #111

Open
clinssen wants to merge 83 commits into
nest:mainfrom
clinssen:cse_feature
Open

clinssen wants to merge 83 commits into
nest:mainfrom
clinssen:cse_feature

Conversation

@clinssen

Copy link
Copy Markdown
Contributor

This PR primarily contains common sub-expression elimination code under /odetoolbox/expression_optimisation.py which is called in __init__.py to optimise the user's sympy expressions. This PR additionally contains code from #PR107 to enable analytical solving for the AMAT neuronal model.

Replaces #110.

awg2024 and others added 6 commits September 14, 2026 10:53
Modifying ignore so further pycodestyle errors don't block static checks
allow style check to fail without breaking the testing for odetoolbox
Comment thread odetoolbox/__init__.py Outdated
:param use_alternative_expM: If :python:`False`, use the sympy function ``sympy.exp`` to compute the matrix exponential. If :python:`True`, use an alternative function (see :py:func:`odetoolbox.sympy_helpers.expMt` for details). This can be useful as calls to ``sympy.exp`` can sometimes take a very large amount of time.
:param preserve_expressions: Set to True, or a list of strings corresponding to individual variable names, to disable internal rewriting of expressions, and return same output as input expression where possible. Only applies to variables specified as first-order differential equations.
:param log_level: Sets the logging threshold. Logging messages which are less severe than ``log_level`` will be ignored. Log levels can be provided as an integer or string, for example "INFO" (more messages) or "WARN" (fewer messages). For a list of valid logging levels, see https://docs.python.org/3/library/logging.html#logging-levels
:param enable_cse: Boolean flag set to False. If enabled it will perform sub-expression elimination on update_expression, propagators and singularity conditions of the generated .cpp nestml file.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: add these to documentation; note that documentation about flags contains a lot of duplication with the docstring here; any way to deduplicate?

Comment thread odetoolbox/__init__.py Outdated
:param preserve_expressions: Set to True, or a list of strings corresponding to individual variable names, to disable internal rewriting of expressions, and return same output as input expression where possible. Only applies to variables specified as first-order differential equations.
:param log_level: Sets the logging threshold. Logging messages which are less severe than ``log_level`` will be ignored. Log levels can be provided as an integer or string, for example "INFO" (more messages) or "WARN" (fewer messages). For a list of valid logging levels, see https://docs.python.org/3/library/logging.html#logging-levels
:param enable_cse: Boolean flag set to False. If enabled it will perform sub-expression elimination on update_expression, propagators and singularity conditions of the generated .cpp nestml file.
:param preserves_cse_condition_branches: Boolean flag set to false. Requires enable_cse=True for functionality. If enabled this will perform independent analysis of singularity condition branches.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flag to be removed.

Comment thread odetoolbox/analytic_integrator.py Outdated
:param solve_dict: The results dictionary returned by a call to :python:`odetoolbox.analysis()`.
:param spike_times: For each variable, used as a key, the list of times at which a spike occurs.
:param enable_caching: Allow caching of results between requested times.
:param enable_cse: Whether to consume CSE metadata containined in the solver dictionary. Disabled by default for backwards compatibility.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove flag, make implicit by searching for "CSE" keys in the dictionary.

return False


def _contains_internal_control_flow(expressions):

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: add test covering piecewise functions.

Comment thread odetoolbox/shapes.py
# a minimal subset of sympy classes and functions to avoid "from sympy import *"
_sympy_globals = {"Symbol": sympy.Symbol,
"Integer": sympy.Integer,
"Integer": sympy.Integer, # XXX TO DO: Utilise this in our LOCALS optimisation condition

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"Integer": sympy.Integer, # XXX TO DO: Utilise this in our LOCALS optimisation condition
"Integer": sympy.Integer,

connectivity[row, col] = 1

# find connected components, grouping state variables into clusters that are coupled
_, component_labels = scipy.sparse.csgraph.connected_components(

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these changes necessary or just for testing? If necessary, please spin off to a separate function and add docstring.

from .context import odetoolbox

def test_coupled_inhomogeneous_system_is_analytical():

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you use the AMAT model JSON file here instead?

Comment thread tests/cse_mixed.json Outdated
"initial_value": "2"
},
{
"expression": "x' = x**2 + exp(x + y) + sin(x + y)",

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"expression": "x' = x**2 + exp(x + y) + sin(x + y)",
"expression": "x' = -x**2 + exp(x + y) + sin(x + y)",

spike_times={},
random_seed=123,
max_step_size=max_step_size,
integration_accuracy_abs=1E-4, # accuaracy leads to number of steps simulation steps taken

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potentially increase accuracy to 1E-6 and decrease testing tolerances below.

Comment thread tests/test_json_serialisable.py Outdated
import json
import odetoolbox

def test_analysis_cse_is_json_serializable():

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be removed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants