Cython中的二项式迭代期望

时间:2015-05-21 20:56:22

标签: python-2.7 numpy cython

我是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)

2 个答案:

答案 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=360factors = 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