Skip to content

Commit 8a8c3d3

Browse files
authored
Merge pull request #439 from gyorilab/simplify_report
Implement feature to check effect of model simplification
2 parents b7a7bd7 + 1a02ec8 commit 8a8c3d3

File tree

2 files changed

+112
-3
lines changed

2 files changed

+112
-3
lines changed

mira/metamodel/ops.py

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""Operations for template models."""
22
import logging
33
from copy import deepcopy
4-
from collections import defaultdict, Counter
4+
from collections import defaultdict
55
import itertools as itt
66
from typing import Callable, Collection, Iterable, List, Mapping, Optional, \
77
Tuple, Type, Union
@@ -10,13 +10,13 @@
1010

1111
from .template_model import TemplateModel, Initial, Parameter, Observable
1212
from .templates import *
13-
from .comparison import get_dkg_refinement_closure
1413
from .units import Unit
1514
from .utils import SympyExprStr
1615

1716
__all__ = [
1817
"stratify",
1918
"simplify_rate_laws",
19+
"check_simplify_rate_laws",
2020
"aggregate_parameters",
2121
"get_term_roles",
2222
"counts_to_dimensionless",
@@ -571,6 +571,67 @@ def simplify_rate_laws(template_model: TemplateModel):
571571
return template_model
572572

573573

574+
def check_simplify_rate_laws(template_model: TemplateModel) -> \
575+
Mapping[str, Union[str, int, TemplateModel]]:
576+
"""Return a summary of what changes upon rate law simplification
577+
578+
Parameters
579+
----------
580+
template_model :
581+
A template model
582+
583+
Returns
584+
-------
585+
:
586+
A dictionary with the result of the check under the `result` key.
587+
The result can be one of the following:
588+
- {'result': 'NO_GROUP_CONTROLLERS'}: If there are no templates with
589+
grouped controllers
590+
- {'result': 'NO_CHANGE'}: If the model does contain templates with
591+
grouped controllers but simplification does not change the model.
592+
- {'result': 'NO_CHANGE_IN_MAX_CONTROLLERS',
593+
'max_controller_count': n}: If the model is simplified but the
594+
maximum number of controllers remains the same so it might not be
595+
worth doing the simplification. In this case the max controller
596+
count in the model is returned. The simplified model
597+
itself is also returned.
598+
- {'result': 'MEANINGFUL_CHANGE',
599+
'max_controller_decrease': n}: If the model is simplified and the
600+
maximum number of controllers also meaningfully changes. In this
601+
case the decrease in the maximum controller count is returned.
602+
The simplified model itself is also returned.
603+
"""
604+
if not any(isinstance(template, (GroupedControlledConversion,
605+
GroupedControlledProduction,
606+
GroupedControlledDegradation))
607+
for template in template_model.templates):
608+
return {'result': 'NO_GROUP_CONTROLLERS'}
609+
simplified_model = simplify_rate_laws(template_model)
610+
old_template_count = len(template_model.templates)
611+
new_template_count = len(simplified_model.templates)
612+
if old_template_count == new_template_count:
613+
return {'result': 'NO_CHANGE'}
614+
615+
def max_controller_count(template_model):
616+
max_count = 0
617+
for template in template_model.templates:
618+
if hasattr(template, 'controllers'):
619+
max_count = max(len(template.get_controllers()), max_count)
620+
elif hasattr(template, 'controller'):
621+
max_count = max(1, max_count)
622+
return max_count
623+
624+
old_max_count = max_controller_count(template_model)
625+
new_max_count = max_controller_count(simplified_model)
626+
if old_max_count == new_max_count:
627+
return {'result': 'NO_CHANGE_IN_MAX_CONTROLLERS',
628+
'max_controller_count': old_max_count,
629+
'simplified_model': simplified_model}
630+
return {'result': 'MEANINGFUL_CHANGE',
631+
'max_controller_decrease': old_max_count - new_max_count,
632+
'simplified_model': simplified_model}
633+
634+
574635
def aggregate_parameters(template_model: TemplateModel) -> TemplateModel:
575636
"""Return a template model after aggregating parameters for mass-action
576637
rate laws.
@@ -630,6 +691,7 @@ def aggregate_parameters(template_model: TemplateModel) -> TemplateModel:
630691
return template_model
631692

632693

694+
633695
def simplify_rate_law(template: Template,
634696
parameters: Mapping[str, Parameter]) \
635697
-> Union[List[Template], None]:

tests/test_ops.py

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from mira.metamodel import *
1111
from mira.metamodel.ops import stratify, simplify_rate_law, \
1212
counts_to_dimensionless, add_observable_pattern, \
13-
get_observable_for_concepts
13+
get_observable_for_concepts, check_simplify_rate_laws
1414
from mira.examples.sir import cities, sir, sir_2_city, sir_parameterized
1515
from mira.examples.concepts import infected, susceptible
1616
from mira.examples.chime import sviivr
@@ -696,3 +696,50 @@ def test_stratify_initials_parameters():
696696
assert set(tm3.parameters) == {'alpha', 'S0_old', 'S0_young'}
697697
assert tm3.parameters['S0_old'].value == 500
698698
assert tm3.parameters['S0_young'].value == 500
699+
700+
701+
def test_check_simplify():
702+
a, b, c, A, B, C, D = sympy.symbols('a b c A B C D')
703+
704+
# No group controllers at all so nothing to simplify
705+
assert check_simplify_rate_laws(
706+
TemplateModel(
707+
templates=[NaturalProduction(outcome=Concept(name='A'),
708+
rate_law=SympyExprStr(a * A))],
709+
)
710+
) == {'result': 'NO_GROUP_CONTROLLERS'}
711+
712+
# No simplification possible due to form of rate law
713+
template = GroupedControlledDegradation(
714+
subject=Concept(name='A'),
715+
controllers=[Concept(name='B'), Concept(name='C')],
716+
rate_law=SympyExprStr(b * B/C * A + a),
717+
)
718+
parameters = {'a': Parameter(name='a', value=1),
719+
'b': Parameter(name='b', value=1),
720+
'c': Parameter(name='c', value=1)}
721+
tm = TemplateModel(templates=[template],
722+
parameters=parameters)
723+
res = check_simplify_rate_laws(tm)
724+
assert res['result'] == 'NO_CHANGE'
725+
726+
# Meaningful simplification with decrease in max controller count
727+
template.rate_law = SympyExprStr((b * B + c * C) * A)
728+
res = check_simplify_rate_laws(tm)
729+
assert res['result'] == 'MEANINGFUL_CHANGE'
730+
assert res['max_controller_decrease'] == 1
731+
732+
# Some simplification happens but the max controller
733+
# count cannot be decreased due to a second template
734+
# with 3 controllers that cannot be simplified
735+
template2 = GroupedControlledDegradation(
736+
subject=Concept(name='A'),
737+
controllers=[Concept(name='B'), Concept(name='C'),
738+
Concept(name='D')],
739+
rate_law=SympyExprStr(b * B/C*D * A + a),
740+
)
741+
tm = TemplateModel(templates=[template, template2],
742+
parameters=parameters)
743+
res = check_simplify_rate_laws(tm)
744+
assert res['result'] == 'NO_CHANGE_IN_MAX_CONTROLLERS'
745+
assert res['max_controller_count'] == 3

0 commit comments

Comments
 (0)