我想使用cython优化以下python代码:
import numpy as np
cimport numpy as np
cimport cython
#for Memoryview on a Cython array
from cython.view cimport array as cvarray
from libc.math cimport sqrt
#fix a datatype and the corresponding ctype
DTYPE = np.float64
ctypedef double DTYPE_t
#______________________________________________________________________________
@cython.boundscheck(False) # turn off bounds-checking for entire function
@cython.wraparound(False) # turn off negative index wrapping for entire function
cdef double[:] fpIter(Implicit f, double[:] y0, double tol, int maxIter):
"""
This function finds a fixpoint with a simple fixpointiteration
Input:
"""
cdef double [:] ylast
cdef double [:] y = y0
cdef int it = 0
cdef double err = 1e6
while (err > tol) and (it <= maxIter):
ylast = y
y = f.eva(ylast)
err = sqrt((y[0]-ylast[0])*(y[0]-ylast[0]) + (y[1]-ylast[1])*(y[1]-ylast[1]))
it += 1
if it >= maxIter:
print('fixpoint iteration failed')
return y
#______________________________________________________________________________
cdef class State:
cdef double c,d
cdef double[:, ::1] A, C
cdef double [::1] B
def __cinit__(self, double c, double d, double[:, ::1] A, double[::1] B, double[:, ::1] C):
self.c = c
self.d = d
self.A = A
self.B = B
self.C = C
cdef double[:] eva(self, double[:] y, double[:] u):
return None
cdef class State1(State):
@cython.boundscheck(False) # turn off bounds-checking for entire function
@cython.wraparound(False) # turn off negative index wrapping for entire function
cdef double[:] eva(self, double[:] y, double[:] u):
cdef double[::1] ret_view = np.zeros(2,dtype=DTYPE)
#represent A.dot(y) + F.eva(y) + u*B + u*C.dot(y)
ret_view[0] = (self.A[0,0]*y[0] + self.A[0,1]*y[1]) + (-1*self.d*y[0]*y[1]) \
+ (u[0]*self.B[0]) + (u[0]*(self.C[0,0]*y[0] + self.C[0,1]*y[1]))
ret_view[1] = (self.A[1,0]*y[0] + self.A[1,1]*y[1]) + (self.c*y[0]*y[1]) \
+ (u[0]*self.B[1]) + (u[0]*(self.C[1,0]*y[0] + self.C[1,1]*y[1]))
return ret_view
cdef class Implicit:
cdef double c,d,h, theta
cdef double[:, ::1] A, C
cdef double[:] B,y,u1,u2
cdef State f
def __cinit__(self,double c,double d,double[:, ::1] A,double[::1] B, \
double[:, ::1] C,double h,double theta, \
double[:] u1,double[:] u2,double[:] y, State f):
self.c = c
self.d = d
self.h = h
self.theta = theta
self.A = A
self.C = C
self.B = B
self.y = y
self.u1 = u1
self.u2 = u2
self.f = f
cdef double[:] eva(self, double[:] z):
return None
cdef class Fun(Implicit):
@cython.boundscheck(False) # turn off bounds-checking for entire function
@cython.wraparound(False) # turn off negative index wrapping for entire function
cdef double[:] eva(self, double[:] z):
cdef double[:,::1] ret_view = np.zeros((2,3),dtype=DTYPE)
#the following is like ret_view[:,0] = self.f1.eva(self.y,self.u1)
ret_view[0,0] = (self.A[0,0]*self.y[0] + self.A[0,1]*self.y[1]) + (-1*self.d*self.y[0]*self.y[1]) \
+ (self.u1[0]*self.B[0]) + (self.u1[0]*(self.C[0,0]*self.y[0] + self.C[0,1]*self.y[1]))
ret_view[1,0] = (self.A[1,0]*self.y[0] + self.A[1,1]*self.y[1]) + (self.c*self.y[0]*self.y[1]) \
+ (self.u1[0]*self.B[1]) + (self.u1[0]*(self.C[1,0]*self.y[0] + self.C[1,1]*self.y[1]))
#the following is like ret_view[:,1] = self.f1.eva(z,self.u2)
ret_view[0,1] = (self.A[0,0]*z[0] + self.A[0,1]*z[1]) + (-1*self.d*z[0]*z[1]) \
+ (self.u2[0]*self.B[0]) + (self.u2[0]*(self.C[0,0]*z[0] + self.C[0,1]*z[1]))
ret_view[1,1] = (self.A[1,0]*z[0] + self.A[1,1]*z[1]) + (self.c*z[0]*z[1]) \
+ (self.u2[0]*self.B[1]) + (self.u2[0]*(self.C[1,0]*z[0] + self.C[1,1]*z[1]))
ret_view[0,2] = self.y[0]+self.h*(self.theta*ret_view[0,0]+(1-self.theta)*ret_view[0,1])
ret_view[1,2] = self.y[1]+self.h*(self.theta*ret_view[1,0]+(1-self.theta)*ret_view[1,1])
return ret_view[:,2]
@cython.boundscheck(False) # turn off bounds-checking for entire function
@cython.wraparound(False) # turn off negative index wrapping for entire function
def thetaMethod(double[::1] t, double[::1] y0, double[:, ::1] A, double[::1] B, \
double[:, ::1] C, double c, double d, double theta, double[:, ::1] u):
#get size of y0
cdef Py_ssize_t e = y0.shape[0]
#get number of gridpoints
cdef Py_ssize_t N = t.shape[0]
#get state
cdef State f = State1(c,d,A,B,C)
#get fun for implicit part
cdef Implicit fun1
#define initial solution
y = np.zeros((e,N), dtype = DTYPE)
cdef double[:, ::1] y_view = y
y_view[:,0] = y0
#get the stepsizes inside the loop, just t[i+1]-t[i]
cdef int i
cdef double[:] tmp = np.zeros(2,dtype=DTYPE)
#if theta = 1 it is explicit, therefore fpIter is not neccessary...
if theta == 1:
#perform the loop
for i in range(N-1):
tmp = f.eva(y_view[:,i],u[:,i])
y_view[0,i+1] = y_view[0,i] + (t[i+1]-t[i])*tmp[0]
y_view[1,i+1] = y_view[1,i] + (t[i+1]-t[i])*tmp[1]
return y_view
#perform the loop
for i in range(N-1):
fun = Fun(c,d,A,B,C,(t[i+1]-t[i]),theta,u[:,i],u[:,i+1],y_view[:,i],f)
y_view[:,i+1] = fpIter(fun,y_view[:,i],1e-12,100)
return y
此代码正在使用theta方法解决ODE。由于我想使用牛顿解决最优控制问题,因此我确实经常需要解决我的ODE问题。因此,我只想优化这部分。这段代码只是整个代码的一部分。
此代码的所有内容都可以正常运行,但是性能并不十分出色。对于theta = 1(显式欧拉),我得到的东西比周围快20倍(可以),但是对于theta = 1/2(Crank-Nicolson)或theta = 0(隐式欧拉),它的速度仅快7倍。>
希望任何人都能有所帮助。谢谢
编辑:
创建HTML文件时,在初始化函数(在State和Implicit中为def__cinit__)以及我设置的循环中,我得到的东西最多
fun = Fun(c,d,A,B,C,(t[i+1]-t[i]),theta,u[:,i],u[:,i+1],y_view[:,i],f)
现在的问题是,如何使它在某种意义上变得更好。也许我应该更改函数的定义?但是如何?