Skip to content

Commit

Permalink
Overload Model::setParameterScale with vector<int> (#1614)
Browse files Browse the repository at this point in the history
* allow supplying a Python list to `Model.setParameterScale`
* test previously untested (due to interdependencies) Model getters and setters
  • Loading branch information
dilpath authored Dec 7, 2021
1 parent 75d94c8 commit 254990a
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 0 deletions.
71 changes: 71 additions & 0 deletions python/tests/test_swig_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
Test getters, setters, etc.
"""

import copy
import numbers

import amici
Expand Down Expand Up @@ -179,6 +180,76 @@ def test_model_instance_settings(pysb_example_presimulation_module):
])


def test_interdependent_settings(pysb_example_presimulation_module):
"""Test settings that were not tested in `test_model_instance_settings`.
`StateIsNonNegative` is still skipped, due to conservation laws in the
test model.
"""
model = pysb_example_presimulation_module.getModel()

original_settings = {
'FixedParameters': (9.0, 1.0),
'ParameterList': (0, 1, 2, 3, 4, 5),
'ParameterScale': [0, 0, 0, 0, 0, 0],
'ReinitializationStateIdxs': tuple(),
'ReinitializeFixedParameterInitialStates': False,
'StateIsNonNegative': (False, False, False),
}

expected_settings = {
'FixedParameters': (8.0, 2.0),
'ParameterList': (0, 1, 2, 3, 4),
'ParameterScale': [1, 0, 0, 0, 0, 0],
'ReinitializationStateIdxs': (0,),
'ReinitializeFixedParameterInitialStates': True,
# Skipped due to conservation laws in the test model.
# 'StateIsNonNegative': None,
}

# Some values need to be transformed to be tested in Python
# (e.g. SWIG objects). Default transformer is no transformation
# (the identity function).
getter_transformers = {
setting: (lambda x: x)
for setting in original_settings
}
getter_transformers.update({
# Convert from SWIG object.
'ParameterScale': lambda x: list(x)
})

default_settings = amici.get_model_settings(model)
for original_setting, original_setting_value in original_settings.items():
test_value = getter_transformers[original_setting](
default_settings[original_setting],
)
# The original model is as expected (to ensure the test is still
# valid).
assert test_value == original_setting_value

for setting, expected_value in expected_settings.items():
input_settings = {setting: copy.deepcopy(expected_value)}

amici.set_model_settings(model, input_settings)
output_settings = amici.get_model_settings(model)
test_value = getter_transformers[setting](
output_settings[setting]
)
# The setter works.
assert test_value == expected_value

input_settings = {setting: output_settings[setting]}
amici.set_model_settings(model, input_settings)
output_settings = amici.get_model_settings(model)
test_value = getter_transformers[setting](
output_settings[setting]
)
# (round-trip) The output of the getter can be used as input to the
# setter, and does not change the value.
assert test_value == expected_value


def test_unhandled_settings(pysb_example_presimulation_module):
"""Detect possible getters and setters that are not yet handled.
Expand Down
10 changes: 10 additions & 0 deletions swig/amici.i
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,18 @@ std::vector<amici::ParameterScaling> parameterScalingFromIntVector(std::vector<i
}
}; // namespace amici
%}
%extend amici::Model {
void setParameterScale(std::vector<int> const& intVec) {
std::vector<amici::ParameterScaling> result(intVec.size());
for (int i = 0; i < (int) result.size(); ++i) {
result[i] = static_cast<amici::ParameterScaling>(intVec[i]);
}
$self->setParameterScale(result);
}
}
namespace amici {
std::vector<amici::ParameterScaling> parameterScalingFromIntVector(std::vector<int> const& intVec);
void Model::setParameterScale(std::vector<int> const& intVec);
}
%template(ParameterScalingVector) std::vector<amici::ParameterScaling>;

Expand Down

0 comments on commit 254990a

Please sign in to comment.