Skip to content

Commit

Permalink
Remove weave and theano from ScipyOdeSimulator (#482)
Browse files Browse the repository at this point in the history
* Remove weave and theano from ScipyOdeSimulator

Remove legacy weave and theano support from ScipyOdeSimulator.
The Python exporter has also been updated to use Cython
rather than weave.
  • Loading branch information
alubbock committed Jan 30, 2020
1 parent b4a5d86 commit 5c22a1e
Show file tree
Hide file tree
Showing 11 changed files with 110 additions and 253 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ before_install:
- bash miniconda.sh -b -p $HOME/miniconda
- export PATH="$HOME/miniconda/bin:$PATH"
- conda install --yes -c conda-forge python="$PYVER"
numpy scipy matplotlib sympy nose h5py pexpect pandas theano networkx
numpy scipy matplotlib sympy nose h5py pexpect pandas networkx
pydot codecov mock cython
- if [[ $PYVER != 3.8 ]]; then conda install --yes -c SBMLTeam python-libsbml; else pip install python-libsbml; fi
# libroadrunner is not currently available for Python 3.8
Expand Down
3 changes: 1 addition & 2 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ install:

# Majority of dependencies can be installed with Anaconda
- conda install -c conda-forge "numpy>=1.14" scipy matplotlib sympy
networkx nose h5py pandas theano mkl pydot mock cython
- if "%PYTHON_VERSION%"=="2.7" (conda install -c conda-forge weave)
networkx nose h5py pandas mkl pydot mock cython

- conda install -c SBMLTeam python-libsbml

Expand Down
2 changes: 1 addition & 1 deletion doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
'sympy.printing', 'sympy.printing.mathml',
'sympy.printing.lambdarepr', 'numpy',
'scipy', 'scipy.integrate', 'scipy.constants', 'scipy.sparse',
'h5py', 'theano', 'theano.tensor', 'dateutil',
'h5py', 'dateutil',
'dateutil.parser', 'networkx', 'networkx.algorithms',
'networkx.algorithms.isomorphism',
'networkx.algorithms.isomorphism.vf2userfunc',
Expand Down
70 changes: 36 additions & 34 deletions doc/examples/robertson_standalone.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,37 +14,38 @@
import distutils.errors


_use_inline = False
# try to inline a C statement to see if inline is functional
_use_cython = False
# try to inline a C statement to see if Cython is functional
try:
import weave
weave.inline('int i;', force=1)
_use_inline = True
import Cython
except ImportError:
pass
except distutils.errors.CompileError:
pass
Cython = None
if Cython:
from Cython.Compiler.Errors import CompileError
try:
Cython.inline('x = 1', force=True, quiet=True)
_use_cython = True
except (CompileError,
distutils.errors.CompileError,
ValueError):
pass

Parameter = collections.namedtuple('Parameter', 'name value')
Observable = collections.namedtuple('Observable', 'name species coefficients')
Initial = collections.namedtuple('Initial', 'param_index species_index')


class Model(object):

def __init__(self):
self.y = None
self.yobs = None
self.integrator = scipy.integrate.ode(self.ode_rhs)
self.integrator.set_integrator('vode', method='bdf',
with_jacobian=True)
self.y0 = numpy.empty(3)
self.ydot = numpy.empty(3)
self.sim_param_values = numpy.empty(6)
self.parameters = [None] * 6
self.observables = [None] * 3
self.initials = [None] * 3

self.parameters[0] = Parameter('k1', 0.040000000000000001)
self.parameters[1] = Parameter('k2', 30000000)
self.parameters[2] = Parameter('k3', 10000)
Expand All @@ -60,27 +61,28 @@ def __init__(self):
self.initials[1] = Initial(4, 1)
self.initials[2] = Initial(5, 2)

if _use_inline:

def ode_rhs(self, t, y, p):
ydot = self.ydot
weave.inline(r'''
ydot[0] = y[1]*y[2]*p[2] + (y[0]*p[0])*(-1);
ydot[1] = y[0]*p[0] + (pow(y[1], 2)*p[1])*(-1) + (y[1]*y[2]*p[2])*(-1);
ydot[2] = pow(y[1], 2)*p[1];
''', ['ydot', 't', 'y', 'p'])
return ydot

else:

def ode_rhs(self, t, y, p):
ydot = self.ydot
ydot[0] = y[1]*y[2]*p[2] + (y[0]*p[0])*(-1)
ydot[1] = y[0]*p[0] + (pow(y[1], 2)*p[1])*(-1) + (y[1]*y[2]*p[2])*(-1)
ydot[2] = pow(y[1], 2)*p[1]
return ydot


code_eqs = '''
ydot[0] = (y[0]*p[0])*(-1.0) + (y[1]*y[2]*p[2])*1.0
ydot[1] = (y[0]*p[0])*1.0 + (pow(y[1], 2)*p[1])*(-1.0) + (y[1]*y[2]*p[2])*(-1.0)
ydot[2] = (pow(y[1], 2)*p[1])*1.0
'''
if _use_cython:

def ode_rhs(t, y, p):
ydot = self.ydot
Cython.inline(code_eqs, quiet=True)
return ydot

else:

def ode_rhs(t, y, p):
ydot = self.ydot
exec(code_eqs)
return ydot

self.integrator = scipy.integrate.ode(ode_rhs)
self.integrator.set_integrator('vode', method='bdf', with_jacobian=True)

def simulate(self, tspan, param_values=None, view=False):
if param_values is not None:
# accept vector of parameter values as an argument
Expand Down
11 changes: 5 additions & 6 deletions doc/faq.rst
Original file line number Diff line number Diff line change
Expand Up @@ -71,16 +71,15 @@ Simulation

* How can I speed up my `ScipyOdeSimulator` simulation?

**Check the weave library is installed.** `weave` is a Python library
**Check the cython library is installed.** `cython` is a Python library
which converts your system of ordinary differential equations (ODEs) to
C code, which is faster to execute than pure Python code. You can check
if `weave` is installed by trying to import it at the Python prompt::
if `cython` is installed by trying to import it at the Python prompt::

import weave
import cython

If no `ImportError` appears, `weave` is available. Note that `weave` is
only available for Python 2. We are working on an alternative for Python
3 using `Cython <http://cython.org>`_.
If no `ImportError` appears, `cython` is available. Otherwise, you'll
need to install it using `pip` or `conda`.

When running large numbers of simulations, consider using the
`CupSodaSimulator` if you have an NVIDIA graphics card (GPU) available.
Expand Down
8 changes: 1 addition & 7 deletions doc/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -71,19 +71,14 @@ Recommended additional software
The following software is not required for the basic operation of PySB, but
provides extra capabilities and features when installed.

* `cython`_ or `weave`_
* `cython`_
Cython is a package for compiling Python code into C code on the fly. It
is used by :class:`pysb.simulator.ScipyOdeSimulator` to greatly improve the
speed of ODE integration. PySB will detect and use Cython automatically,
if available. To install with Anaconda, type
:command:`conda install cython`.
With pip, type :command:`pip install cython`.

Weave performs the same job as Cython, and is slightly faster in some
circumstances. It is only available on Python 2. To install with Anaconda,
type :command:`conda install -c conda-forge weave`. With pip, type
:command:`pip install weave`.

* `matplotlib`_

This Python package allows you to plot the results of your simulations. It
Expand Down Expand Up @@ -209,4 +204,3 @@ https://hub.docker.com/r/jupyter/scipy-notebook/
.. _BioNetGen: http://www.bionetgen.org/
.. _Perl: http://www.perl.org/
.. _Cython: http://cython.org/
.. _weave: https://pypi.python.org/pypi/weave
52 changes: 33 additions & 19 deletions pysb/export/python.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,16 +124,21 @@ def export(self):
import distutils.errors
"""))
output.write(pad(r"""
_use_inline = False
# try to inline a C statement to see if inline is functional
_use_cython = False
# try to inline a C statement to see if Cython is functional
try:
import weave
weave.inline('int i;', force=1)
_use_inline = True
import Cython
except ImportError:
pass
except distutils.errors.CompileError:
pass
Cython = None
if Cython:
from Cython.Compiler.Errors import CompileError
try:
Cython.inline('x = 1', force=True, quiet=True)
_use_cython = True
except (CompileError,
distutils.errors.CompileError,
ValueError):
pass
Parameter = collections.namedtuple('Parameter', 'name value')
Observable = collections.namedtuple('Observable', 'name species coefficients')
Expand All @@ -152,9 +157,6 @@ def export(self):
def __init__(self):
self.y = None
self.yobs = None
self.integrator = scipy.integrate.ode(self.ode_rhs)
self.integrator.set_integrator('vode', method='bdf',
with_jacobian=True)
self.y0 = numpy.empty(%(num_species)d)
self.ydot = numpy.empty(%(num_species)d)
self.sim_param_values = numpy.empty(%(num_params)d)
Expand All @@ -181,20 +183,32 @@ def __init__(self):
output.write("self.initials[%d] = Initial(%d, %d)\n" % ic_data)
output.write("\n")

output.write(" if _use_inline:\n")
output.write(" " * 8)
if 'math.' in code_eqs:
code_eqs = 'import math\n' + code_eqs
output.write('code_eqs = \'\'\'\n%s\n\'\'\'\n' %
code_eqs.replace(';', ''))

output.write(" " * 8)
output.write("if _use_cython:\n")
output.write(pad(r"""
def ode_rhs(self, t, y, p):
def ode_rhs(t, y, p):
ydot = self.ydot
weave.inline(r'''%s''', ['ydot', 't', 'y', 'p'])
Cython.inline(code_eqs, quiet=True)
return ydot
""", 8) % ('\n' + pad(code_eqs, 16) + ' ' * 16))
output.write(" else:\n")
""", 12))
output.write(" else:\n")
output.write(pad(r"""
def ode_rhs(self, t, y, p):
def ode_rhs(t, y, p):
ydot = self.ydot
%s
exec(code_eqs)
return ydot
""", 8) % pad('\n' + code_eqs, 12).replace(';','').strip())
""", 12))
output.write(" " * 8)
output.write('self.integrator = scipy.integrate.ode(ode_rhs)\n')
output.write(" " * 8)
output.write("self.integrator.set_integrator('vode', method='bdf', "
"with_jacobian=True)\n")

# note the simulate method is fixed, i.e. it doesn't require any templating
output.write(pad(r"""
Expand Down

0 comments on commit 5c22a1e

Please sign in to comment.