简体   繁体   English

记住Python方法中的单个参数

[英]Memoize a single argument in Python method

I've written a Numpy implementation that uses the Cox-de Boor recursive algorithm to compute B-spline basis functions. 我编写了一个使用Cox-de Boor递归算法来计算B样条基函数的Numpy实现。 I would like to memoize the object instance for a given order , but leave the function callable with respect to xi . 我想memoize给定order的对象实例,但相对于xi保留可调用的功能。

In other words, after the object is instantiated, the recursive function should be "set", but remain callable at xi . 换句话说,在实例化对象之后,应“设置”递归函数,但在xi可调用它。 I really need this for speed, as I will be calling the function many times and do not want to reconstruct the recursive function over-and-over. 我确实需要这样做以提高速度,因为我将多次调用该函数,并且不想一遍又一遍地构造递归函数。

Here is the current implementation: 这是当前的实现:

import numpy as np

#Turn off divide by zero warning because we explicitly check for it
np.seterr(divide='ignore')

class Bspline():

    def __init__(self, knot_vector, order):

        self.knot_vector = knot_vector
        self.p = order


    def __basis0(self, xi):

        return np.where(np.all([self.knot_vector[:-1] <=  xi, 
                            xi < self.knot_vector[1:]],axis=0), 1.0, 0.0)

    def __basis(self, xi, p):

        if p == 0:
            return self.__basis0(xi)
        else:
            basis_p_minus_1 = self.__basis(xi, p - 1)

            first_term_numerator = xi - self.knot_vector[:-p] 
            first_term_denominator = self.knot_vector[p:] - self.knot_vector[:-p]

            second_term_numerator = self.knot_vector[(p + 1):] - xi
            second_term_denominator = self.knot_vector[(p + 1):] - self.knot_vector[1:-p]

            first_term = np.where(first_term_denominator > 1.0e-12, 
                              first_term_numerator / first_term_denominator, 0)
            second_term = np.where(second_term_denominator > 1.0e-12,
                               second_term_numerator / second_term_denominator, 0)

            return  first_term[:-1] * basis_p_minus_1[:-1] + second_term * basis_p_minus_1[1:]


    def __call__(self, xi):

        return self.__basis(xi, self.p)

and is used as 并用作

knot_vector = np.array([0,0,0,0,0,1,2,2,3,3,3,4,4,4,4,5,5,5,5,5])
basis = Bspline(knot_vector,4)
basis(1.2)

which returns the basis functions evaluated at 1.2 . 它返回在1.2求值的基函数。 However, I need to call this function many times and as it is written now, the recursive function is reconstructed for every call, and this is not necessary as the recursion level is set at instantiation as 4 但是,我需要多次调用此函数,并且如现在所写,每次调用都将重构递归函数,这是不必要的,因为递归级别在实例化时设置为4

It's very easy to memoize anything using functools.lru_cache in Python3, or, in Python2.7 using something like this : 这很容易使用,以memoize的任何functools.lru_cache在Python3使用类似的,或在Python2.7 这个

class Bspline(object):
    ...

    # Python2.7
    @memoize
    # or, Python3*
    @functools.lru_cache()
    def op(self, args):
        return self._internal_op(xi)

Create a dictionary that saves the results of the function and then check to see if that value is in the dict before calling the function again. 创建一个保存该函数结果的字典,然后在再次调用该函数之前检查该值是否在字典中。 Something similar to this should work depending on your setup. 与此类似的东西应该可以工作,具体取决于您的设置。

results = {}
for value in values:
    if results.get(value):
        answer = results[value]
    else:
        answer = basis(value)
        results[value] = answer
        print(answer)  # or just display the results dict once you are done

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM