计算一次,在Python类中多次使用

时间:2017-10-06 23:46:42

标签: python python-3.x oop numpy scipy

我正在尝试定义一个类,在该类中优化了许多变量的函数。通常我正在使用~500-1000个变量。在这个课程中,我需要将函数及其派生函数传递给minimize中的scipy,以找到最小化此函数的x0

以下是该概念的一个简单的工作示例,它工作正常。但正如你所看到的那样,函数(f)及其派生(df)依赖于另一个函数g(在这个例子中,它看起来很简单,可以用另一种方式编写,但实际上功能要复杂得多)。

我想知道我是否可以在每次迭代时只计算g一次,然后在该类中使用该值。考虑到fdfminimize多次更新,因此每个步骤g也应重新评估。

谢谢!

from scipy.optimize import minimize

class Minimization(object):
    '''A class to optimizae a function'''

    def __init__(self,x,y):
        self.x = x
        self.y = y
        self.p = np.array([x,y])

    def g(self,x,y):
        return x-y

    def f(self,p):
        return (self.g(*p) - 1)**2

    def df(self,p):
        fprime = 2*(self.g(*p) - 1)
        return np.array([fprime,-fprime])

    def optimize(self):
        P1 = minimize(fun=self.f, x0=self.p, args=(), method='Newton-CG',jac=self.df)
        return P1

    m = Minimization(2,4)
    m.optimize()
     #fun: 0.0
    # jac: array([ 0., -0.])
 #message: 'Optimization terminated successfully.'
  #  nfev: 3
   # nhev: 0
    # nit: 2
    #njev: 6
  #status: 0
 #success: True
  #     x: array([ 3.5,  2.5])

3 个答案:

答案 0 :(得分:1)

如果没有深入研究代码本身,这里有一个示例类来演示如何计算一次值并避免在每次调用时重新计算它。你也可以把它变成一个属性。

class StackOverflow:
     def __init__(self, value=None):
             self._value = value
     def compute_value(self):
             if self._value is None:
                     self._value = 100  # Compute value here
             return self._value

答案 1 :(得分:1)

你想要的是“记忆”。当函数g计算一个值时,它将结果存储在字典中,由参数x,y索引。每次调用g时,它都会检查字典以查看它所需的值是否已经存储在那里。如果需要重置值,请清除字典。像这样:

class Minimization(object):
    '''A class to optimizae a function'''

    def __init__(self,x,y):
        self.x = x
        self.y = y
        self.p = np.array([x,y])
        self.cache = {}  # previously computed values of g

    def g(self,x,y):
        cache_index = (x, y)
        if cache_index in self.cache:  # check cache first
            return self.cache[cache_index]
        value = x - y
        self.cache[cache_index] = value  # save for later
        return value

    def f(self,p):
        return (self.g(*p) - 1)**2

    def df(self,p):
        fprime = 2*(self.g(*p) - 1)
        return np.array([fprime,-fprime])

    def optimize(self):
        self.cache.clear()  # Blow the cache
        P1 = minimize(fun=self.f, x0=self.p, args=(), method='Newton-CG',jac=self.df)
        return P1

答案 2 :(得分:1)

为了补充Paul的答案,您可以定义一个类聚合缓存的方法,然后您将(重新)用作装饰器。

Cache

然后使用班级Minimization作为import numpy as np from scipy.optimize import minimize class Minimization(Cache):#<----------Inherits of Cache instead of object '''A class to optimizae a function''' def __init__(self,x,y): super(Minimization,self).__init__() self.x0 = x # I changed the names because as it stands, self.y0 = y # these attributes are actually used as first guesses self.p0 = np.array([x,y]) # for the resolution process @Cache._method def g(self, x, y): return x - y #@Cache._method def f(self,p): return (self.g(*p) - 1)**2 #@Cache._method def df(self,p): fprime = 2*(self.g(*p) - 1) return np.array([fprime,-fprime]) @Cache._property def optimized(self):#<----- I changed the name into optimized to make it representative of what it is, a property return minimize(fun=self.f, x0=self.p0, args=(), method='Newton-CG',jac=self.df) 的祖先,如下所示

>>> m = Minimization(2,4)
>>> # Take care to clear the cache if optimized is not called for the first time and that you changed one of its "dependencies", doing m._cache.clear().
>>> # something you may want to do is simply removing the @Cache._property decorator 
>>> m.optimized
  status: 0
 success: True
    njev: 6
    nfev: 3
     fun: 0.0
       x: array([ 3.5,  2.5])
 message: 'Optimization terminated successfully.'
    nhev: 0
     jac: array([ 0., -0.])

用例 (在Python 2.7.11和3.6.1下测试)

input="$(
sudo gdb -n -q -batch-silent \
  -ex "set logging on" \
  -ex "set logging file /dev/null" \
  -ex "set logging redirect on" \
  -ex "attach $PID" \
  -ex "set \$dlopen = (void*(*)(char*, int)) dlopen" \
  -ex "call \$dlopen(\"/$filename\", 1)" \
  -ex "detach" \
  -ex "quit"
)"