DiODeProject/MuMoT

model2.showODEs(method='vanKampen') -> IndexError: list index out of range

Opened this issue · 7 comments

Encountered when using Python 3.6 or 3.7 and latest acceptable versions of dependencies: see CI runs for #376

Reproduced with sympy 1.5.x but not 1.4.y.

With sympy 1.4 these lines after line 2893 in models.py:

                    ODE_1 = solve(ode1, Derivative(PhiDict[nvec[0]], t), dict=True)
                    ODE_2 = solve(ode2, Derivative(PhiDict[nvec[1]], t), dict=True)

result in [{Derivative(Phi_A, t): -Phi_A**2*r_{A} - Phi_A*Phi_B*r_{A} - Phi_A*Phi_B*s - Phi_A*a_{A} - Phi_A*g_{A} + Phi_A*r_{A} - Phi_B*g_{A} + g_{A}}] and [{Derivative(Phi_B, t): -Phi_A*Phi_B*r_{B} - Phi_A*Phi_B*s - Phi_A*g_{B} - Phi_B**2*r_{B} - Phi_B*a_{B} - Phi_B*g_{B} + Phi_B*r_{B} + g_{B}}] being assigned when running model2.showODEs(method='vanKampen') in the user guide Notebook.

But with Sympy 1.5.1 only empty lists are returned from the solve() calls.

This appears to be due to

Vlist_lhs, Vlist_rhs, substring = _get_orderedLists_vKE(stoich)

assigning different values to Vlist_lhs for the two sympy versions.

(The latest docs for Sympy indicate that both the API and implementation of solve() are a bit of a mess and people should switch to using solveset() instead: https://docs.sympy.org/latest/modules/solvers/solveset.html)

Exploring further, with Sympy 1.4 simplify(-sqrt(\overline{V})*Derivative(Phi_A, t)*Derivative(P(eta_A, eta_B, eta_U, t), eta_A)) appears to just return its argument, whereas with SymPy 1.5.0 and 1.5.1 simplify returns 0 (sympy.core.numbers.Zero).

@jarmarshall Can you identify anything in the SymPy 1.5 or 1.5.1 release notes that might explain this?

I don't see how that could ever be simplified to 0 with the assumptions SymPy has access to, so think it must be a bug...

The following (fairly) minimal working example recreates the problem for me in terms of different behaviour between sympy v1.4 and 1.5, so I will raise an issue on sympy's GitHub:

from sympy import simplify, sqrt, symbols, Symbol, Derivative, Function
V = Symbol(r'\overline{V}', real=True, constant=True)
ea = Symbol('eta_A')
eb = Symbol('eta_B')
eu = Symbol('eta_U')
pa = Symbol('Phi_A')
t = symbols('t')
P = Function('P')
simplify(expr = -sqrt(V)*Derivative(pa, t)*Derivative(P(ea, eb, eu, t), ea))

Hmmm... checking a bit further, it's the simplification of the derivative of pa wrt t that returns 0 - presumably it treated the derivative as something it knew nothing about before, whereas now it assumes it is of the form pa*t^0 - need to check if this is a documented change before raising the issue...

OK, my thinking is evolving on this - since the simplification is apparently happening inside a call to solve we need to figure out what we should actually be doing now - maybe that is an option for solve, maybe it is replacing with solveset, or maybe it is actually switching to dsolve...
I think this is our only remaining upper-bounded package dependency, and 1.5.* is pretty recent so 1.4 should be good for a while longer - are there any other downsides with sticking with 1.4 for a while longer until this is figured out?

Not that I know of. Given SymPy 1.5 was released in December 2019 I agree that pinning sympy <1.5 makes sense for the pending MuMoT release.

The task of comparing solve / dsolve / solveset and deciding on a way forward would definitely be suited to someone who's worked with SymPy much more than I have.