I have example code like
import numpy as np
nbins = 1301
init = np.ones(nbins*2+1)*(-1)
init[0] = 0
init[1::2] = 0
z0 = np.array(init, dtype=np.complex128, ndmin=1)
initn = z0.view(np.float64)
deltasf = np.linspace(-10, 10, nbins)
gsf = np.linspace(1, 2, nbins)
def jacobian_mbes_test(Y, t):
leny = len(Y)
J = np.zeros((leny, leny))
J[0,0] = -10
J[0,1] = 0
J[0, 2::4] = gsf
J[1,0] = 0
J[1,1] = -10
J[1,3::4] = gsf
J[2::4, 0] = gsf*Y[4::4]
J[3::4, 0] = gsf*Y[5::4]
J[4::4, 0] = -4*gsf*Y[2::4]
J[2::4, 1] = -gsf*Y[5::4]
J[3::4, 1] = gsf*Y[4::4]
J[4::4, 1] = -4*gsf*Y[3::4]
J[(range(2, leny, 4), range(2, leny, 4))] = -0.8
J[(range(3, leny, 4), range(3, leny, 4))] = -0.8
J[(range(4, leny, 4), range(4, leny, 4))] = -0.001
J[(range(5, leny, 4), range(5, leny, 4))] = -0.001
J[(range(2, leny, 4), range(3, leny, 4))] = deltas
J[(range(3, leny, 4), range(2, leny, 4))] = -deltas
J[(range(2, leny, 4), range(4, leny, 4))] = gsf*Y[0]
J[(range(2, leny, 4), range(5, leny, 4))] = -gsf*Y[1]
J[(range(3, leny, 4), range(4, leny, 4))] = gsf*Y[1]
J[(range(3, leny, 4), range(5, leny, 4))] = gsf*Y[0]
J[(range(4, leny, 4), range(2, leny, 4))] = -4*gsf*Y[0]
J[(range(4, leny, 4), range(3, leny, 4))] = -4*gsf*Y[1]
return J
which computes a Jacobian for a set of differential equations using scipy.integrate.odeint
Unfortunately the performance of the function jacobian_mbes_test
is not very good. %timeit jacobian_mbes_test(initn, 0)
gives 12.2ms even though I tried to do everything efficiently with slicing(?).
Changing the function to (since I guess the more complicated index assingment takes most time)
def jacobian_mbes_test2(Y, t):
leny = len(Y)
J = np.zeros((leny, leny))
J[0,0] = -10
J[0,1] = 0
J[0, 2::4] = gsf
J[1,0] = 0
J[1,1] = -10
J[1,3::4] = gsf
J[2::4, 0] = gsf*Y[4::4]
J[3::4, 0] = gsf*Y[5::4]
J[4::4, 0] = -4*gsf*Y[2::4]
J[2::4, 1] = -gsf*Y[5::4]
J[3::4, 1] = gsf*Y[4::4]
J[4::4, 1] = -4*gsf*Y[3::4]
return J
reduces this time to 4.6ms, which is still not great. The funny thing is that if I time these assignments outside of a function like
J = np.zeros((len(initn), len(initn))
%timeit J[4::4, 1] = -4*gsf*initn[3::4]
I get at most 10µs, so I would expect at most (!) sth like 100µs for the second function. Is there some copying around in memory going on in this function I am not aware of?
Is there some more efficient way to assign values to certain indices?