1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 from Numeric import copy, dot, sqrt
25
26 from interpolate import cubic_ext, quadratic_fafbga
27 quadratic = quadratic_fafbga
28
30 """A line search algorithm based on interpolation.
31
32 Pages 56-57, from 'Numerical Optimization' by Jorge Nocedal and Stephen J. Wright, 1999, 2nd ed.
33
34 Requires the gradient function.
35
36
37 Function options
38 ~~~~~~~~~~~~~~~~
39
40 func - The function to minimise.
41 func_prime - The function which returns the gradient vector.
42 args - The tuple of arguments to supply to the functions func and dfunc.
43 x - The parameter vector at minimisation step k.
44 f - The function value at the point x.
45 g - The function gradient vector at the point x.
46 p - The descent direction.
47 a_init - Initial step length.
48 mu - Constant determining the slope for the sufficient decrease condition (0 < mu < 1).
49 """
50
51
52 i = 1
53 f_count = 0
54 a0 = {}
55 a0['a'] = 0.0
56 a0['phi'] = f
57 a0['phi_prime'] = dot(g, p)
58
59
60 a = {}
61 a['a'] = a_init
62 a['phi'] = apply(func, (x + a['a']*p,)+args)
63 f_count = f_count + 1
64
65 if print_flag:
66 print "\n<Line search initial values>"
67 print_data("Pre (a0)", i-1, a0)
68
69
70 if a0['phi_prime'] >= 0.0:
71 raise NameError, "The gradient at point 0 of this line search is positive, ie p is not a descent direction and the line search will not work."
72
73
74 if a['phi'] <= a0['phi'] + mu * a['a'] * a0['phi_prime']:
75 return a['a'], f_count
76
77
78 a_last = copy.deepcopy(a)
79
80
81 a_new = - 0.5 * a0['phi_prime'] * a['a']**2 / (a['phi'] - a0['phi'] - a0['phi_prime']*a['a'])
82 a['a'] = a_new
83 a['phi'] = apply(func, (x + a['a']*p,)+args)
84 f_count = f_count + 1
85
86
87 if a['phi'] <= a0['phi'] + mu * a['a'] * a0['phi_prime']:
88 return a['a'], f_count
89
90 while 1:
91 if print_flag:
92 print "<Line search iteration i = " + `i` + " >"
93 print_data("Initial (a)", i, a)
94 print_data("Initial (a_last)", i, a_last)
95
96 beta1 = 1.0 / (a_last['a']**2 * a['a']**2 * (a['a'] - a_last['a']))
97 beta2 = a['phi'] - a0['phi'] - a0['phi_prime'] * a['a']
98 beta3 = a_last['phi'] - a0['phi'] - a0['phi_prime'] * a_last['a']
99
100 fact_a = beta1 * (a_last['a']**2 * beta2 - a['a']**2 * beta3)
101 fact_b = beta1 * (-a_last['a']**3 * beta2 + a['a']**3 * beta3)
102
103 a_new = {}
104 a_new['a'] = (-fact_b + sqrt(fact_b**2 - 3.0 * fact_a * a0['phi_prime'])) / (3.0 * fact_a)
105 a_new['phi'] = apply(func, (x + a_new['a']*p,)+args)
106 f_count = f_count + 1
107
108
109 if a_new['phi'] <= a0['phi'] + mu * a_new['a'] * a0['phi_prime']:
110 return a_new['a'], f_count
111
112
113 if a['a'] - a_new['a'] > 0.5 * a['a'] or 1.0 - a_new['a']/a['a'] < 0.9:
114 a_new['a'] = 0.5 * a['a']
115 a_new['phi'] = apply(func, (x + a_new['a']*p,)+args)
116 f_count = f_count + 1
117
118
119 a_last = copy.deepcopy(a)
120 a = copy.deepcopy(a_new)
121
122
124 """Temp func for debugging."""
125
126 print text + " data printout:"
127 print " Iteration: " + `k`
128 print " a: " + `a['a']`
129 print " phi: " + `a['phi']`
130 print " phi_prime: " + `a['phi_prime']`
131