Keith
Keith

Reputation: 71

Suppyling a hessian to fmin_ncg in python

For the SciPy function fmin_ncg, is there a way of suppling the hessian and gradient as a variable rather than a function?

I'm trying to rewrite some Matlab code in python. The code involves using an optimisation routine to fit some parameters to a set of data. To do this, I've supplied the gradient and hessian. E.g in Matlab I have something like this:

fmincon(@myFunc,x0,[],[],[],[],lb,ub,[],options);

where myFunc returns 3 values: the function evaluation, the gradient, and the hessian.

However for fmin_ncg in Python it appears that the gradiant and hessian must be supplied as separate functions.

To me this seems inefficient as the code has to go through a large dataset, and there are calculations that are common to the function, the gradient and the hessian. e.g. Imagine a function f(x) = a(x)*b(x) with gradient g(x) = a(x)*c(x), hessian h(x) = a(x)*d(x) ... in Matlab I can calculate a(x) once, where as it appears that i have to calculate this three times in python.

Have I misunderstood how fmin_ncg works or is there a way around this?

Upvotes: 3

Views: 566

Answers (1)

joshayers
joshayers

Reputation: 3439

You can create a class that includes all of your functions. Each iteration, the common variables are calculated during the first function call, then are reused for the other calls. The callback feature of fmin_ncg can be used to reset the common variables at the end of each iteration.

class function(object):

   def __init__(self):
      self.commonVarsDirty = True

   def calcFunction(self,x,*args,**kwargs):
      if self.commonVarsDirty:
         self.calcCommonVars()
      return self.a*b

   def calcGradient(self,x,*args,**kwargs):
      if self.commonVarsDirty:
         self.calcCommonVars()
      return self.a*c

   def calcHessian(self,x,*args,**kwargs):
      if self.commonVarsDirty:
         self.calcCommonVars()
      return self.a*d

   def resetCommonVars(self,*args,**kwargs):
      self.commonVarsDirty = True

   def calcCommonVars(self):
      self.commonVarsDirty = False
      # calculate common variables and save them as class attributes
      self.a = 1+1

You would use it like this.

f = function()
fmin_ncg(f.calcFunction,x0,f.calcGradient,fhess=f.calcHessian,callback=f.resetCommonVars)

This adds some overhead so would only be worth it if the computation effort to calculate the common variables is significant.

Upvotes: 4

Related Questions