Skip to content

Support sympy 1.11 to 1.14 - #306

Open
kwabenantim wants to merge 29 commits into
masterfrom
285-support-sympy-114
Open

Support sympy 1.11 to 1.14#306
kwabenantim wants to merge 29 commits into
masterfrom
285-support-sympy-114

Conversation

@kwabenantim

@kwabenantim kwabenantim commented Jul 15, 2026

Copy link
Copy Markdown
Member

Description

Add support for newer versions of sympy

  • Use expr.replace() instead of expr.subs() where appropriate due to subs strictly requiring Sympy objects in 1.12+.
  • Made changes required for Float/Integer equality comparisons in sympy 1.13+.
  • Bumped minimum Python to 3.10 and upgraded dependencies to 3.10+ compatible ones.
  • Removed 33 legacy _alt and _python36 reference code variants.
  • Added 58 version dependent reference code variants:
    • 19 sympy_1_11 variants due to coefficient folding in diff.
    • 2 sympy_1_13 variants due to extracting negative Float exponents in Add.
    • 32 sympy_1_14 variants due to disabling Float exponent extractions in Add.
    • 5 python_3_11 variants due to a different ionic current sum ordering in Python3.10 + Pint 0.24, resulting from a Float(1.0) passing into coefficients e.g. 1.0 * HeartConfig::Instance()->GetCapacitance() in _get_ionic_vars. The 1.0 disappears in a different Python or Pint version.
  • Added helpers for version-referenced tests.
  • Added all supported sympy versions on CI.

Note

The added regenerate_reference(..) in conftest.py currently piggy-backs on the tests to generate reference files. It could possibly be moved into a separate "infra scripts" folder, but it might not be worth creating an infra section for just the one case. Also, it automatically labels variants with the sympy version used to generate them as this causes the majority of differences, so some manual renaming may be needed if e.g. the Python version is the cause of the difference.

Motivation and Context

Fixes #285

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Documentation checklist

  • I have updated all documentation in the code where necessary.
  • I have checked spelling in all (new) comments and documentation.
  • I have added a note to RELEASE.md if relevant (new feature, breaking change, or notable bug fix).
  • I have updated version & citation.txt & citation.cff version.

Testing

  • Testing is done automatically and codecov shows test coverage
  • This cannot be tested automatically

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR updates chaste_codegen to work with newer SymPy releases by broadening dependency constraints, adapting placeholder math-function substitution for SymPy’s stricter sympification behavior, and updating tests/reference outputs to support per-SymPy-version “golden” files.

Changes:

  • Updated setup.py dependency minimums/maximums (including SymPy, Pint, NetworkX, etc.) to target newer ecosystems.
  • Added SymPy-version-aware reference selection and updated Jacobian tests to use it, alongside new --sympy_X_Y reference variants.
  • Regenerated/adjusted stored reference models and removed legacy Python 3.6 reference artifacts.

Reviewed changes

Copilot reviewed 20 out of 72 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
setup.py Bumps runtime dependency constraints to support newer SymPy and related packages.
docs/index.rst Updates contributor instructions for dependency bumps and versioned reference files.
dev-requirements/dev.txt Updates pinned dev dependency versions (notably Pint).
chaste_codegen/tests/test_jacobian.py Switches Jacobian tests to SymPy-versioned reference reading.
chaste_codegen/tests/conftest.py Adds SymPy-versioned reference selection and optional reference regeneration mode.
chaste_codegen/model_with_conversions.py Uses subs_math_func_placeholders to avoid SymPy subs sympification issues.
chaste_codegen/_math_functions.py Documents correct placeholder substitution approach for SymPy >= 1.12.
chaste_codegen/data/tests/test_jacobian_matrix_2.txt_python36 Removes legacy Python 3.6-specific expected output.
chaste_codegen/data/tests/test_jacobian_matrix_2.txt_alt Removes alternate legacy expected output format.
chaste_codegen/data/tests/test_jacobian_matrix_2--sympy_1_13.txt Adds SymPy 1.13-specific Jacobian matrix expected output.
chaste_codegen/data/tests/test_jacobian_matrix_2--sympy_1_11.txt Adds SymPy 1.11-specific Jacobian matrix expected output.
chaste_codegen/data/tests/test_jacobian_matrix_1.txt_python36 Removes legacy Python 3.6-specific expected output.
chaste_codegen/data/tests/test_jacobian_matrix_1.txt_alt Removes alternate legacy expected output format.
chaste_codegen/data/tests/test_jacobian_matrix_1--sympy_1_11.txt Adds SymPy 1.11-specific Jacobian matrix expected output.
chaste_codegen/data/tests/test_jacobian_equations_2.txt_python36 Removes legacy Python 3.6-specific expected output.
chaste_codegen/data/tests/test_jacobian_equations_2.txt_alt Removes alternate legacy expected output format.
chaste_codegen/data/tests/test_jacobian_equations_2.txt Updates baseline expected output to match newer SymPy behavior.
chaste_codegen/data/tests/test_jacobian_equations_1.txt_python36 Removes legacy Python 3.6-specific expected output.
chaste_codegen/data/tests/test_jacobian_equations_1.txt_alt Removes alternate legacy expected output format.
chaste_codegen/data/tests/test_jacobian_equations_1.txt Updates baseline expected output to match newer SymPy behavior.
chaste_codegen/data/tests/chaste_reference_models/RLopt/hodgkin_huxley_squid_axon_model_1952_modified--sympy_1_13.cpp Updates generated reference output for SymPy 1.13 behavior.
chaste_codegen/data/tests/chaste_reference_models/RL/hodgkin_huxley_squid_axon_model_1952_modified--sympy_1_13.cpp Adds generated reference output for SymPy 1.13 (RL model type).
chaste_codegen/data/tests/chaste_reference_models/Opt/test_luo_rudy_1991_with_range_cap_dimensionless.cpp_python36 Removes legacy Python 3.6 generated reference output.
chaste_codegen/data/tests/chaste_reference_models/Opt/hodgkin_huxley_squid_axon_model_1952_modified--sympy_1_13.cpp Updates generated reference output for SymPy 1.13 behavior.
chaste_codegen/data/tests/chaste_reference_models/Opt/beeler_reuter_model_1977_lookup_tables.cpp_python36 Removes legacy Python 3.6 generated reference output.
chaste_codegen/data/tests/chaste_reference_models/GRL2Opt/hodgkin_huxley_squid_axon_model_1952_modified--sympy_1_13.cpp Updates generated reference output for SymPy 1.13 behavior.
chaste_codegen/data/tests/chaste_reference_models/GRL2/hodgkin_huxley_squid_axon_model_1952_modified--sympy_1_13.cpp Updates generated reference output for SymPy 1.13 behavior.
chaste_codegen/data/tests/chaste_reference_models/GRL1Opt/beeler_reuter_model_1977--sympy_1_11.cpp Updates generated reference output for SymPy 1.11 behavior.
chaste_codegen/data/tests/chaste_reference_models/GRL1/hodgkin_huxley_squid_axon_model_1952_modified--sympy_1_13.cpp Updates generated reference output for SymPy 1.13 behavior.
chaste_codegen/data/tests/chaste_reference_models/Cvode_with_jacobian/hodgkin_huxley_squid_axon_model_1952_modified--sympy_1_13.cpp Adds generated reference output for SymPy 1.13 (Cvode + Jacobian).
chaste_codegen/data/tests/chaste_reference_models/Cvode_with_jacobian/hodgkin_huxley_squid_axon_model_1952_modified--sympy_1_11.cpp Updates generated reference output for SymPy 1.11 behavior.
chaste_codegen/data/tests/chaste_reference_models/Cvode_opt_with_jacobian/hodgkin_huxley_squid_axon_model_1952_modified--sympy_1_13.cpp Adds generated reference output for SymPy 1.13 (Cvode opt + Jacobian).
chaste_codegen/data/tests/chaste_reference_models/Cvode_opt_with_jacobian/hodgkin_huxley_squid_axon_model_1952_modified--sympy_1_11.cpp Updates generated reference output for SymPy 1.11 behavior.
chaste_codegen/data/tests/chaste_reference_models/CVODE_DATA_CLAMP_OPT/hodgkin_huxley_squid_axon_model_1952_modified--sympy_1_13.cpp Updates generated reference output for SymPy 1.13 behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread docs/index.rst Outdated
Comment thread docs/index.rst Outdated
Comment thread docs/index.rst
Comment thread setup.py
Comment thread setup.py Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 26 out of 86 changed files in this pull request and generated 2 comments.

Comment thread docs/index.rst Outdated
Comment thread chaste_codegen/tests/conftest.py Outdated
@codecov

codecov Bot commented Jul 20, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (7878bf3) to head (f0d6978).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff            @@
##            master      #306   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           30        30           
  Lines         1789      1789           
=========================================
  Hits          1789      1789           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@kwabenantim
kwabenantim marked this pull request as ready for review July 21, 2026 16:58
@kwabenantim
kwabenantim requested a review from Copilot July 21, 2026 16:58

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 32 out of 102 changed files in this pull request and generated 4 comments.

Comment thread docs/index.rst Outdated
Comment thread docs/index.rst Outdated
Comment thread docs/index.rst Outdated
Comment thread .github/workflows/pytest.yml
mirams and others added 5 commits July 21, 2026 20:51
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

@MichaelClerx MichaelClerx left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Quick look at the first model files shows what looks like big differences in code.

Are these significant? And is this the best way to test if we have to manually review 100 files?

const double var_background_currents__E_Ca = 0.5 * var_membrane__R * var_membrane__T * log(mParameters[1] / var_chaste_interface__intracellular_ion_concentrations__Ca_i) / var_membrane__F; // millivolt
const double var_Ca_independent_transient_outward_K_current__i_sus = (((var_environment__CT == 1) && (var_environment__PM == 0)) ? (0.098000000000000004 + 0.0014 * var_chaste_interface__membrane__V) : (((var_environment__CT == 0) && (var_environment__PM == 1)) ? (0.16799999999999998 + 0.0023999999999999998 * var_chaste_interface__membrane__V) : (0.070000000000000007 + 0.001 * var_chaste_interface__membrane__V))); // picoA
const double var_Ca_independent_transient_outward_K_current__i_to = (((var_environment__CT == 1) && (var_environment__PM == 0)) ? (0.20000000000000001 * (0.40000000000000002 + 0.59999999999999998 * pow(var_chaste_interface__Ca_independent_transient_outward_K_current_s3_gate__s3, 6)) * (-var_Ca_independent_transient_outward_K_current__E_K + var_chaste_interface__membrane__V) * (0.58999999999999997 * pow(var_chaste_interface__Ca_independent_transient_outward_K_current_s1_gate__s1, 3) + 0.40999999999999998 * pow(var_chaste_interface__Ca_independent_transient_outward_K_current_s2_gate__s2, 3)) * var_Ca_independent_transient_outward_K_current__g_to * var_chaste_interface__Ca_independent_transient_outward_K_current_r_gate__r) : (((var_environment__CT == 0) && (var_environment__PM == 1)) ? (0.34999999999999998 * (0.40000000000000002 + 0.59999999999999998 * pow(var_chaste_interface__Ca_independent_transient_outward_K_current_s3_gate__s3, 6)) * (-var_Ca_independent_transient_outward_K_current__E_K + var_chaste_interface__membrane__V) * (0.58999999999999997 * pow(var_chaste_interface__Ca_independent_transient_outward_K_current_s1_gate__s1, 3) + 0.40999999999999998 * pow(var_chaste_interface__Ca_independent_transient_outward_K_current_s2_gate__s2, 3)) * var_Ca_independent_transient_outward_K_current__g_to * var_chaste_interface__Ca_independent_transient_outward_K_current_r_gate__r) : ((0.40000000000000002 + 0.59999999999999998 * pow(var_chaste_interface__Ca_independent_transient_outward_K_current_s3_gate__s3, 6)) * (-var_Ca_independent_transient_outward_K_current__E_K + var_chaste_interface__membrane__V) * (0.58999999999999997 * pow(var_chaste_interface__Ca_independent_transient_outward_K_current_s1_gate__s1, 3) + 0.40999999999999998 * pow(var_chaste_interface__Ca_independent_transient_outward_K_current_s2_gate__s2, 3)) * var_Ca_independent_transient_outward_K_current__g_to * var_chaste_interface__Ca_independent_transient_outward_K_current_r_gate__r))); // picoA
const double var_Ca_independent_transient_outward_K_current__i_sus = (((var_environment__CT == 1) && (var_environment__PM == 0)) ? (0.098000000000000004 + 0.0014 * var_chaste_interface__membrane__V) : (((var_environment__PM == 1) && (var_environment__CT == 0)) ? (0.16799999999999998 + 0.0023999999999999998 * var_chaste_interface__membrane__V) : (0.070000000000000007 + 0.001 * var_chaste_interface__membrane__V))); // picoA

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Is this just pseudo-random differences? Or were we e.g. sorting before but not now? Would be nice to avoid reviewing a 100 models 😅

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good point! Sorry about the number of new reference files. In this particular one, it looks like I've managed to confuse git into thinking an old python 3.6 alternative reference (which has been deleted) was renamed to a newly added alternative reference generated with sympy 1.14.

It might be worth adding in some numerical tests to check things.

@kwabenantim kwabenantim Jul 22, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This ordering is pre-existing between the python 3.6 variant and the original reference as well.

const double var_x10 = 1 / (1.3999999999999999 + var_x9 + 0.80000000000000004 * var_chaste_interface__Ca_handling_by_the_SR__Ca_up);
const double var_x11 = (var_x9 - 0.32000000000000006 * var_chaste_interface__Ca_handling_by_the_SR__Ca_up) / pow((0.00041999999999999996 + 0.00023999999999999998 * var_chaste_interface__Ca_handling_by_the_SR__Ca_up + var_chaste_interface__intracellular_ion_concentrations__Ca_i), 2);
const double var_x12 = 0.23999999999999999 * exp(-1.6000000000000001 + 0.080000000000000002 * var_chaste_interface__membrane__V);
const double var_x8 = 1.3999999999999999 + 0.80000000000000004 * var_chaste_interface__Ca_handling_by_the_SR__Ca_up + 3333.3333333333335 * var_chaste_interface__intracellular_ion_concentrations__Ca_i;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

These look like real differences. What's going on?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This is also pre-existing between Python 3.6 and the main reference, although it's a bit different there as well with:

const double var_x8 = 1 / (1.3999999999999999 + 0.80000000000000004 * var_chaste_interface__Ca_handling_by_the_SR__Ca_up + 3333.3333333333335 * var_chaste_interface__intracellular_ion_concentrations__Ca_i);

Probably needs numerical testing.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Might just be re-organising the temporary variables to represent different bits of calculation for some reason. I think the numerical tests are done within Chaste, so could try and run it with this branch if that's possible?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

rJacobian[1][13] = 0.0;
rJacobian[2][0] = 0.0;
rJacobian[2][1] = 0.0;
rJacobian[2][2] = 1.0 - (mDt * (-var_x12 - var_x17));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

What's happening here?

@kwabenantim kwabenantim Jul 22, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This also seems to be pre-existing between the Python 3.6 version and the main reference, although the original main reference has something slightly different:

rJacobian[2][2] = 1.0 - (mDt * (-var_x16));

I think these may be due to a stale Python 3.6 alternative version, but definitely worth putting in some numerical testing!

@kwabenantim

Copy link
Copy Markdown
Member Author

Quick look at the first model files shows what looks like big differences in code.

Are these significant? And is this the best way to test if we have to manually review 100 files?

Thanks @MichaelClerx . These particular changes are pre-existing and don't appear to be significant. I am getting all the generated reference models to run through numerical testing, so we probably don't need to review all of those manually.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support sympy 1.11 - 1.14

4 participants