使用cython优化theta方法

时间:2019-03-17 13:23:03

标签: python cython

我想使用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)

现在的问题是,如何使它在某种意义上变得更好。也许我应该更改函数的定义?但是如何?

0 个答案:

没有答案