Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Structured equations with equation templates #1244

Draft
wants to merge 20 commits into
base: master
Choose a base branch
from
Draft
Changes from 1 commit
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
ff28463
Dummy implementation for discussion
mstimberg Oct 13, 2020
27c2cb8
Example using templates
mstimberg Oct 15, 2020
76c5d42
WIP: exploring a few more options for modular template equations
mstimberg Oct 22, 2020
3f2d253
Better support nested equations/expressions
mstimberg Oct 23, 2020
d0945bf
Merge Equations and EquationTemplate
mstimberg Oct 23, 2020
74341eb
Merge Expression and ExpressionTemplate
mstimberg Oct 23, 2020
bd5b5e8
Fix a minor replacement bug
mstimberg Oct 23, 2020
9b8ed84
Use the template approach for all currents in Rothman&Manis example
mstimberg Oct 23, 2020
1d58e0e
fix a few replacement bugs
mstimberg Oct 26, 2020
068fdb5
Give access to template identifiers in expressions/equations
mstimberg Oct 26, 2020
ab7d29a
WIP: replace dependencies in order
mstimberg Oct 26, 2020
f934614
Refactor/simplify equation substitution code
mstimberg Oct 28, 2020
e20fb64
Fix a minor replacement issue
mstimberg Oct 28, 2020
f294931
Raise an error for an unused replacement argument
mstimberg Oct 29, 2020
2820567
Raise a warning for ambiguous replacements
mstimberg Oct 29, 2020
a2085e0
Make Expression substitution consistent with Equations
mstimberg Oct 29, 2020
ecee6cb
Raise an error if templates are used in NeuronGroup/Synapses
mstimberg Oct 29, 2020
a0d0f24
Fix replacements with equations without expressions (i.e. parameters)
mstimberg Nov 3, 2020
28e3f46
Store original equations before substitution
mstimberg Dec 31, 2020
deb9139
Merge branch 'master' into equation_template
mstimberg Dec 31, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Give access to template identifiers in expressions/equations
mstimberg committed Oct 26, 2020
commit 068fdb5e41103f4c424d6fd82f4a80b95cd9bb01
1 change: 1 addition & 0 deletions brian2/equations/codestrings.py
Original file line number Diff line number Diff line change
@@ -34,6 +34,7 @@ def __init__(self, code):

# : Set of identifiers in the code string
self.identifiers = get_identifiers(code)
self.template_identifiers = get_identifiers(code, only_template=True)

code = property(lambda self: self._code,
doc='The code string')
13 changes: 13 additions & 0 deletions brian2/equations/equations.py
Original file line number Diff line number Diff line change
@@ -445,6 +445,14 @@ def __init__(self, type, varname, dimensions, var_type=FLOAT, expr=None,
if not self.expr is None else set([]),
doc='All identifiers in the RHS of this equation.')

template_identifiers = property(lambda self: (self.expr.template_identifiers
if not self.expr is None else set([])) |
get_identifiers(self.varname, only_template=True),
doc='All template identifiers used in this equation (including as part of the variable '
'name.')

template = property(lambda self: len(self.template_identifiers) > 0)

stochastic_variables = property(lambda self: {variable for variable in self.identifiers
if variable =='xi' or variable.startswith('xi_')},
doc='Stochastic variables in the RHS of this equation')
@@ -970,6 +978,11 @@ def _get_stochastic_type(self):
doc=('Set of all identifiers used in the equations, '
'excluding the variables defined in the equations'))

template_identifiers = property(lambda self: set().union(*[eq.template_identifiers for
eq in self._equations.values()]),
doc=('Set of all template identifiers (placeholders) used in the'
'equations, including as part of the variable names.'))

stochastic_variables = property(lambda self: {variable for variable in self.identifiers
if variable =='xi' or variable.startswith('xi_')})

21 changes: 15 additions & 6 deletions brian2/utils/stringtools.py
Original file line number Diff line number Diff line change
@@ -152,7 +152,7 @@ def replace(s, substitutions):
KEYWORDS = {'and', 'or', 'not', 'True', 'False'}


def get_identifiers(expr, include_numbers=False):
def get_identifiers(expr, include_numbers=False, only_template=False):
'''
Return all the identifiers in a given string ``expr``, that is everything
that matches a programming language variable like expression, which is
@@ -164,7 +164,9 @@ def get_identifiers(expr, include_numbers=False):
The string to analyze
include_numbers : bool, optional
Whether to include number literals in the output. Defaults to ``False``.

only_template : bool, optional
Whether to only return template_identifiers, i.e. identifiers enclosed
by curly braces. Defaults to ``False``
Returns
-------
identifiers : set
@@ -174,21 +176,28 @@ def get_identifiers(expr, include_numbers=False):
--------
>>> expr = '3-a*_b+c5+8+f(A - .3e-10, tau_2)*17'
>>> ids = get_identifiers(expr)
>>> print(sorted(list(ids)))
>>> print(sorted(ids))
['A', '_b', 'a', 'c5', 'f', 'tau_2']
>>> ids = get_identifiers(expr, include_numbers=True)
>>> print(sorted(list(ids)))
>>> print(sorted(ids))
['.3e-10', '17', '3', '8', 'A', '_b', 'a', 'c5', 'f', 'tau_2']
>>> template_expr = '{name}_{suffix} = a*{name}_{suffix} + b'
>>> template_ids = get_identifiers(template_expr, only_template=True)
>>> print(sorted(template_ids))
['name', 'suffix']
'''
identifiers = set(re.findall(r'\b[A-Za-z_][A-Za-z0-9_]*\b', expr))
template_identifiers = set(re.findall(r'[{][A-Za-z_][A-Za-z0-9_]*[}]', expr))
template_identifiers = set(re.findall(r'(?:[{])([A-Za-z_][A-Za-z0-9_]*)(?:[}])', expr))
if include_numbers:
# only the number, not a + or -
numbers = set(re.findall(r'(?<=[^A-Za-z_])[0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?|^[0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?',
expr))
else:
numbers = set()
return (identifiers - KEYWORDS) | template_identifiers | numbers
if only_template:
return template_identifiers
else:
return (identifiers - KEYWORDS) | template_identifiers | numbers


def strip_empty_lines(s):