2011-07-03 1 views
3

Pour la fonction SciPy fmin_ncg, est-il un moyen de suppling hessois et gradient comme une variable plutôt qu'une fonction?Suppyling une toile de jute à fmin_ncg en python

Je suis en train de réécrire un code Matlab en python. Le code implique l'utilisation d'une routine d'optimisation pour adapter certains paramètres à un ensemble de données. Pour ce faire, j'ai fourni le dégradé et la toile de jute. Je Matlab dans par exemple quelque chose comme ceci:

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

myFunc renvoie 3 valeurs: l'évaluation de la fonction, le gradient et la toile de jute.

Cependant pour fmin_ncg en Python, il semble que le dégradé et le hessien doivent être fournis en tant que fonctions séparées.

Pour moi, cela semble inefficace que le code doit passer par un vaste ensemble de données, et il y a des calculs qui sont communs à la fonction, le gradient et la toile de jute. par exemple. Imaginez une fonction f(x) = a(x)*b(x) avec gradient g(x) = a(x)*c(x), Jute h(x) = a(x)*d(x) ... dans Matlab je peux calculer a(x) une fois, alors que il semble que je dois calculer cela trois fois en python.

Ai-je mal compris comment fmin_ncg fonctionne ou est-il un moyen de contourner cela?

+2

essayer memoization –

Répondre

4

Vous pouvez créer une classe qui inclut toutes vos fonctions. A chaque itération, les variables communes sont calculées lors du premier appel de fonction, puis réutilisées pour les autres appels. La fonction de rappel de fmin_ncg peut être utilisée pour réinitialiser les variables communes à la fin de chaque itération.

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 

Vous l'utiliseriez comme ceci. Cela ajoute un peu de temps supplémentaire, ce qui ne vaudrait que si l'effort de calcul pour calculer les variables communes est significatif.

+0

Grand, qui devrait faire l'affaire. Merci Bellamyj et David – Keith