我是Cython的新手。如何将名为Values的Python函数转换为Cython?因为因子= 2和i = 60,我的大Linux盒子需要2.8秒。目标是1秒,因子= 2且i = 360。
这是代码。谢谢!
import numpy as np
import itertools
class Numeraire:
def __init__(self, rate):
self.rate = rate
def __call__(self, timenext, time, state):
return np.exp(-self.rate*(timenext - time))
def Values(values, i1, i0=0, numeraire=Numeraire(0.)):
factors=len(values.shape)
norm=0.5**factors
for i in np.arange(i1-1, i0-1, -1):
for j in itertools.product(np.arange(i+1), repeat=factors):
value = 0.
for k in itertools.product(np.arange(2), repeat=factors):
value += values[tuple(np.array(j) + np.array(k))]
values[j] = value*norm*numeraire(i+1, i, j)
return values
factors = 2
i = 60
values = np.ones([i+1]*factors)
Values(values, i, numeraire=Numeraire(0.05/12))
print values[(0,)*factors], np.exp(-0.05/12*i)
答案 0 :(得分:2)
Before using Cython, you should optimize your code with Numpy. Here, vectorizing the third and second inner for
loops, yields a x40 speed-up,
In [1]: import numpy as np
...: import itertools
...:
...: # define Numaire and Values functions from the question above
...:
...: def Values2(values, i1, i0=0, numeraire=Numeraire(0.)):
...: factors=len(values.shape)
...: norm=0.5**factors
...: k = np.array(list(itertools.product(np.arange(2), repeat=factors)))
...: for i in np.arange(i1-1, i0-1, -1):
...: j = np.array(list(itertools.product(np.arange(i+1), repeat=factors)))
...: mask_all = j[:,:,np.newaxis] + k.T[np.newaxis, :, :]
...: mask_x, mask_y = np.swapaxes(mask_all, 2, 1).reshape(-1, 2).T
...:
...: values_tmp = values[mask_x, mask_y].reshape((j.shape[0], k.shape[0]))
...: values_tmp = values_tmp.sum(axis=1)
...: values[j[:,0], j[:,1]] = values_tmp*norm*numeraire(i+1, i, j)
...: return values
...:
...: factors = 2
...: i = 60
...: values = lambda : np.ones([i+1]*factors)
...: print values()[(0,)*factors], np.exp(-0.05/12*i)
...:
...: res = Values(values(), i, numeraire=Numeraire(0.05/12))
...: res2 = Values2(values(), i, numeraire=Numeraire(0.05/12))
...: np.testing.assert_allclose(res, res2)
...:
...: %timeit Values(values(), i, numeraire=Numeraire(0.05/12))
...: %timeit Values2(values(), i, numeraire=Numeraire(0.05/12))
...:
1.0 0.778800783071
1 loops, best of 3: 1.26 s per loop
10 loops, best of 3: 31.8 ms per loop
The next step would be to replace the line,
j = np.array(list(itertools.product(np.arange(i+1), repeat=factors)
with it's Numpy equivalent, taken from this answer(不太漂亮),
def itertools_product_numpy(some_list, some_length):
return some_list[np.rollaxis(
np.indices((len(some_list),) * some_length), 0, some_length + 1)
.reshape(-1, some_length)]
k = itertools_product_numpy(np.arange(i+1), factors)
这导致整体x160加速,我的笔记本电脑上的代码在i=360
和factors = 2
上运行1.2秒。
在最后一个版本中,如果你将它移植到Cython,我不会认为你会加快速度,因为只剩下一个循环而且它只有~360次迭代。相反,应该执行一些微调的Python / Numpy优化以进一步提高速度。
或者,您可以尝试将Cython应用于原始实现。但是因为它基于itertools.product
,在循环中重复调用时速度很慢,Cython不会帮助那里。
答案 1 :(得分:2)
这是我的最新答案(没有Cython!),在private void comboLTActionPerformed(java.awt.event.ActionEvent evt) {
String lt = comboLT.getSelectedItem().toString();
if (lt == "Purchase")
{
UploadPurchaseData anotherFrame = new UploadPurchaseData();
anotherFrame.pack();
anotherFrame.setVisible(true);
}
,factor=2
案例中以125毫秒运行。
i=360