Package minimise :: Module bfgs
[hide private]
[frames] | no frames]

Source Code for Module minimise.bfgs

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2003 Edward d'Auvergne                                        # 
  4  #                                                                             # 
  5  # This file is part of the program relax.                                     # 
  6  #                                                                             # 
  7  # relax is free software; you can redistribute it and/or modify               # 
  8  # it under the terms of the GNU General Public License as published by        # 
  9  # the Free Software Foundation; either version 2 of the License, or           # 
 10  # (at your option) any later version.                                         # 
 11  #                                                                             # 
 12  # relax is distributed in the hope that it will be useful,                    # 
 13  # but WITHOUT ANY WARRANTY; without even the implied warranty of              # 
 14  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               # 
 15  # GNU General Public License for more details.                                # 
 16  #                                                                             # 
 17  # You should have received a copy of the GNU General Public License           # 
 18  # along with relax; if not, write to the Free Software                        # 
 19  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA   # 
 20  #                                                                             # 
 21  ############################################################################### 
 22   
 23   
 24  from Numeric import Float64, dot, identity, matrixmultiply, outerproduct 
 25   
 26  from base_classes import Line_search, Min 
 27   
 28   
29 -def bfgs(func=None, dfunc=None, args=(), x0=None, min_options=None, func_tol=1e-25, grad_tol=None, maxiter=1e6, a0=1.0, mu=0.0001, eta=0.9, full_output=0, print_flag=0, print_prefix=""):
30 """Quasi-Newton BFGS minimisation.""" 31 32 if print_flag: 33 if print_flag >= 2: 34 print print_prefix 35 print print_prefix 36 print print_prefix + "Quasi-Newton BFGS minimisation" 37 print print_prefix + "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" 38 min = Bfgs(func, dfunc, args, x0, min_options, func_tol, grad_tol, maxiter, a0, mu, eta, full_output, print_flag, print_prefix) 39 if min.init_failure: 40 print print_prefix + "Initialisation of minimisation has failed." 41 return None 42 results = min.minimise() 43 return results
44 45
46 -class Bfgs(Line_search, Min):
47 - def __init__(self, func, dfunc, args, x0, min_options, func_tol, grad_tol, maxiter, a0, mu, eta, full_output, print_flag, print_prefix):
48 """Class for Quasi-Newton BFGS minimisation specific functions. 49 50 Unless you know what you are doing, you should call the function 'bfgs' rather than using 51 this class. 52 """ 53 54 # Function arguments. 55 self.func = func 56 self.dfunc = dfunc 57 self.args = args 58 self.xk = x0 59 self.func_tol = func_tol 60 self.grad_tol = grad_tol 61 self.maxiter = maxiter 62 self.full_output = full_output 63 self.print_flag = print_flag 64 self.print_prefix = print_prefix 65 66 # Set a0. 67 self.a0 = a0 68 69 # Line search constants for the Wolfe conditions. 70 self.mu = mu 71 self.eta = eta 72 73 # Initialisation failure flag. 74 self.init_failure = 0 75 76 # Setup the line search options and algorithm. 77 self.line_search_options(min_options) 78 self.setup_line_search() 79 80 # Initialise the function, gradient, and Hessian evaluation counters. 81 self.f_count = 0 82 self.g_count = 0 83 self.h_count = 0 84 85 # Initialise the warning string. 86 self.warning = None 87 88 # Set the convergence test function. 89 self.setup_conv_tests() 90 91 # BFGS setup function. 92 self.setup_bfgs() 93 94 # Set the update function. 95 self.update = self.update_bfgs
96 97
98 - def new_param_func(self):
99 """The new parameter function. 100 101 Find the search direction, do a line search, and get xk+1 and fk+1. 102 """ 103 104 # Calculate the BFGS direction. 105 self.pk = -matrixmultiply(self.Hk, self.dfk) 106 107 # Line search. 108 self.line_search() 109 110 # Find the new parameter vector and function value at that point. 111 self.xk_new = self.xk + self.alpha * self.pk 112 self.fk_new, self.f_count = apply(self.func, (self.xk_new,)+self.args), self.f_count + 1 113 self.dfk_new, self.g_count = apply(self.dfunc, (self.xk_new,)+self.args), self.g_count + 1 114 115 # Debugging. 116 if self.print_flag >= 2: 117 print self.print_prefix + "pk: " + `self.pk` 118 print self.print_prefix + "alpha: " + `self.alpha` 119 print self.print_prefix + "xk: " + `self.xk` 120 print self.print_prefix + "xk+1: " + `self.xk_new` 121 print self.print_prefix + "fk: " + `self.fk` 122 print self.print_prefix + "fk+1: " + `self.fk_new`
123 124
125 - def setup_bfgs(self):
126 """Setup function. 127 128 Create the identity matrix I and calculate the function, gradient and initial BFGS inverse 129 Hessian matrix. 130 """ 131 132 # Set the Identity matrix I. 133 self.I = identity(len(self.xk), Float64) 134 135 # The initial BFGS function value, gradient vector, and BFGS approximation to the inverse Hessian matrix. 136 self.fk, self.f_count = apply(self.func, (self.xk,)+self.args), self.f_count + 1 137 self.dfk, self.g_count = apply(self.dfunc, (self.xk,)+self.args), self.g_count + 1 138 self.Hk = self.I * 1.0
139 140
141 - def update_bfgs(self):
142 """Function to update the function value, gradient vector, and the BFGS matrix.""" 143 144 # sk and yk. 145 sk = self.xk_new - self.xk 146 yk = self.dfk_new - self.dfk 147 dot_yk_sk = dot(yk, sk) 148 149 # rho k. 150 if dot_yk_sk == 0: 151 self.warning = "The BFGS matrix is indefinite. This should not occur." 152 rk = 1e99 153 else: 154 rk = 1.0 / dot_yk_sk 155 156 # Preconditioning. 157 if self.k == 0: 158 self.Hk = dot_yk_sk / dot(yk, yk) * self.I 159 160 self.Hk = matrixmultiply(self.I - rk*outerproduct(sk, yk), self.Hk) 161 self.Hk = matrixmultiply(self.Hk, self.I - rk*outerproduct(yk, sk)) 162 self.Hk = self.Hk + rk*outerproduct(sk, sk) 163 164 # Shift xk+1 data to xk. 165 self.xk = self.xk_new * 1.0 166 self.fk = self.fk_new 167 self.dfk = self.dfk_new * 1.0
168