Skip to content

Commit 3b25598

Browse files
authored
Faster substitutions with smart_subs_dict II (#3030)
Flatten out expressions first to avoid expensive repeated substitutions in matrices. For my current benchmark, this yields another 10x improvement compared to #3025.
1 parent b0b2684 commit 3b25598

File tree

1 file changed

+19
-9
lines changed

1 file changed

+19
-9
lines changed

python/sdist/amici/importers/utils.py

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -422,20 +422,30 @@ def smart_subs_dict(
422422
Substituted symbolic expression
423423
"""
424424
if field is None:
425-
s = [(eid, expr) for eid, expr in subs.items()]
425+
s = list(subs.items())
426426
else:
427427
s = [(eid, expr[field]) for eid, expr in subs.items()]
428428

429-
if reverse:
429+
if not reverse:
430+
# counter-intuitive, but we need to reverse the order for reverse=False
430431
s.reverse()
431432

432433
with sp.evaluate(False):
433-
for old, new in s:
434-
# note that substitution may change free symbols, so we have to do
435-
# this recursively
436-
if sym.has(old):
437-
sym = sym.xreplace({old: new})
438-
434+
# The new expressions may themselves contain symbols to be substituted.
435+
# We flatten them out first, so that the substitutions in `sym` can be
436+
# performed simultaneously, which is usually more efficient than
437+
# repeatedly substituting into `sym`.
438+
# TODO(performance): This could probably be made more efficient by
439+
# combining with toposort used to order `subs` in the first place.
440+
# Some substitutions could be combined, and some terms not present in
441+
# `sym` could be skipped.
442+
for i in range(len(s) - 1):
443+
for j in range(i + 1, len(s)):
444+
if s[j][1].has(s[i][0]):
445+
s[j] = s[j][0], s[j][1].xreplace({s[i][0]: s[i][1]})
446+
447+
s = dict(s)
448+
sym = sym.xreplace(s)
439449
return sym
440450

441451

@@ -450,7 +460,7 @@ def smart_subs(element: sp.Expr, old: sp.Symbol, new: sp.Expr) -> sp.Expr:
450460
to be substituted
451461
452462
:param new:
453-
subsitution value
463+
substitution value
454464
455465
:return:
456466
substituted expression

0 commit comments

Comments
 (0)