如何很好地使用Cython更快地求解微分方程? [英] How can I use Cython well to solve a differential equation faster?

查看:97
本文介绍了如何很好地使用Cython更快地求解微分方程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想减少Scipy的odeint解微分
方程所需的时间。

I would like to lower the time Scipy's odeint takes for solving a differential equation.

要练习,我使用了科学计算中的Python 作为模板。因为odeint使用函数 f 作为参数,所以我将此函数编写为静态类型的Cython版本,并希望
的odeint运行时间会大大减少。

To practice, I used the example covered in Python in scientific computations as template. Because odeint takes a function f as argument, I wrote this function as a statically typed Cython version and hoped the running time of odeint would decrease significantly.

函数 f 包含在名为 ode.pyx 如下:

import numpy as np
cimport numpy as np
from libc.math cimport sin, cos

def f(y, t, params):
  cdef double theta = y[0], omega = y[1]
  cdef double Q = params[0], d = params[1], Omega = params[2]
  cdef double derivs[2]
  derivs[0] = omega
  derivs[1] = -omega/Q + np.sin(theta) + d*np.cos(Omega*t)
  return derivs

def fCMath(y, double t, params):
  cdef double theta = y[0], omega = y[1]
  cdef double Q = params[0], d = params[1], Omega = params[2]
  cdef double derivs[2]
  derivs[0] = omega
  derivs[1] = -omega/Q + sin(theta) + d*cos(Omega*t)
  return derivs

然后我创建一个文件 setup.py 来构成函数:

I then create a file setup.py to complie the function:

from distutils.core import setup
from Cython.Build import cythonize

setup(ext_modules=cythonize('ode.pyx'))

求解微分方程的脚本(还包含 f 的Python
版本)称为 solveODE.py ,其外观为:

The script solving the differential equation (also containing the Python version of f) is called solveODE.py and looks as:

import ode
import numpy as np
from scipy.integrate import odeint
import time

def f(y, t, params):
    theta, omega = y
    Q, d, Omega = params
    derivs = [omega,
             -omega/Q + np.sin(theta) + d*np.cos(Omega*t)]
    return derivs

params = np.array([2.0, 1.5, 0.65])
y0 = np.array([0.0, 0.0])
t = np.arange(0., 200., 0.05)

start_time = time.time()
odeint(f, y0, t, args=(params,))
print("The Python Code took: %.6s seconds" % (time.time() - start_time))

start_time = time.time()
odeint(ode.f, y0, t, args=(params,))
print("The Cython Code took: %.6s seconds ---" % (time.time() - start_time))

start_time = time.time()
odeint(ode.fCMath, y0, t, args=(params,))
print("The Cython Code incorpoarting two of DavidW_s suggestions took: %.6s seconds ---" % (time.time() - start_time))

然后我运行:

python setup.py build_ext --inplace
python solveODE.py 

在终端中。

python版本的时间约为0.055秒,
,而Cython版本的时间约为0.04秒。

The time for the python version is approximately 0.055 seconds, whilst the Cython version takes roughly 0.04 seconds.

有人建议我改进使用Cython求解
微分方程的尝试,最好不要修改odeint例程本身吗?

Does somebody have a recommendation to improve on my attempt of solving the differential equation, preferably without tinkering with the odeint routine itself, with Cython?

编辑

我将DavidW的建议合并到了两个文件中。 c> ode.pyx solveODE.py 只需大约0.015秒即可运行带有这些建议的代码。

I incorporated DavidW's suggestion in the two files ode.pyx and solveODE.py It took only roughly 0.015 seconds to run the code with these suggestions.

推荐答案

最简单的更改(可能会为您带来很多好处)是使用C数学库 sin cos 用于对单个数字(而不是数字)进行运算。调用 numpy 以及花费时间来解决它不是一个数组的代价相当高。

The easiest change to make (which will probably gain you a lot) is to use the C math library sin and cos for operations on single numbers instead of number. The call to numpy and the time spent working out that it isn't an array is fairly costly.

from libc.math cimport sin, cos

    # later
    -omega/Q + sin(theta) + d*cos(Omega*t)

我很想为输入 d (无需更改接口即可轻松键入其他任何输入):

I'd be tempted to assign a type to the input d (none of the other inputs are easily typed without changing the interface):

def f(y, double t, params):

我想我也将像在Python版本中一样返回一个列表。我认为使用C数组不会带来很多收益。

I think I'd also just return a list like you do in your Python version. I don't think you gain a lot by using a C array.

这篇关于如何很好地使用Cython更快地求解微分方程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆