Skip to content

sympy solver runs out of memory when using symbol in exp()

An answer to this question on Stack Overflow.

Question

I am attempting to learn how to use sympy, so I've picked off a simple problem to attempt. when I attempt to use Sympy's solver to solve e^(-(ln(2)/8) * t) - 10^-6 eventually my repl crashes with an out of memory error. It seem to be something with how it interprets the exp() method that I am not quite sure what I am doing wrong.

from math import log as ln
from sympy import exp as e, symbols as sym, solve
t = sym('t')
hl = 8.0197
k = ln(2)/hl #lambda 
expression = e(-k * t) -10**-6
# 10^6 = e^(-k * t)
days = solve(,t)
print(days)

It should solve to ~159.5, but as noted it causes the repl to crash. with “ipython3” terminated by signal SIGSEGV (Address boundary error)

Answer

10**-6 is a suspiciously small number.

Since floating-point numbers are scary, we can solve a similar problem to the one you pose using nice, safe integers:

from math import log as ln
import sympy
from sympy import symbols as sym
t  = sym('t')
hl = 8.0197
k  = 4
expression = sympy.exp(-k * t) - 3
days = sympy.solve(expression,t)
print(days)

This instantly returns:

[log(3**(3/4)/3) + I*pi, log(3**(3/4)/3), log(-3**(3/4)*I/3), log(3**(3/4)*I/3)]

So we know right away that the problem has something to do with the use of floating-point numbers. As it turns out, this is a known problem in SymPy. Note that since there are four possible solutions to the equation, however much work it takes to handle the floating-point numbers is quadrupled.

Since working with floating-point numbers can result in lost precision, especially if the dynamic range of the numbers is large, SymPy converts floating-point inputs into exact fractional representations. This can result in really big numbers that slow calculations down.

The solution is to avoid floating-point numbers when possible and, more generally, to solve the equation symbolically and substitute afterwards:

from math import log as ln
import sympy
from sympy import symbols as sym
t = sym('t')
k = sym('k')
c = sym('c')
expression = sympy.exp(-k * t) - c
days = sympy.solve(expression,t)
print(days)

This gives:

[log(1/c)/k]

Which can be evaluated using

hl   = 8.0197
kval = ln(2)/hl #lambda 
days[0].subs([(k,kval), (c, 10**-6)])

which gives

159.845200455409