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 Float64, dot, identity
25
26 from base_classes import Line_search, Min
27
28
29 -def coordinate_descent(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.1, full_output=0, print_flag=0, print_prefix=""):
30 """Back-and-forth coordinate descent minimisation."""
31
32 if print_flag:
33 if print_flag >= 2:
34 print print_prefix
35 print print_prefix
36 print print_prefix + "Back-and-forth coordinate descent minimisation"
37 print print_prefix + "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
38 min = Coordinate_descent(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
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 back-and-forth coordinate descent minimisation specific functions.
49
50 Unless you know what you are doing, you should call the function 'coordinate_descent' rather
51 than using this class.
52 """
53
54
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
67 self.a0 = a0
68
69
70 self.mu = mu
71 self.eta = eta
72
73
74 self.init_failure = 0
75
76
77 self.line_search_options(min_options)
78 self.setup_line_search()
79
80
81 self.f_count = 0
82 self.g_count = 0
83 self.h_count = 0
84
85
86 self.warning = None
87
88
89 self.setup_conv_tests()
90
91
92 self.fk, self.f_count = apply(self.func, (self.xk,)+self.args), self.f_count + 1
93 self.dfk, self.g_count = apply(self.dfunc, (self.xk,)+self.args), self.g_count + 1
94
95
96 self.cd_dir = identity(len(self.xk), Float64)
97 self.n = 0
98 self.back = 0
99
100
102 """The new parameter function.
103
104 Find the search direction, do a line search, and get xk+1 and fk+1.
105 """
106
107
108 if dot(self.dfk, self.cd_dir[self.n]) > 0.0:
109 self.pk = -self.cd_dir[self.n]
110 else:
111 self.pk = self.cd_dir[self.n]
112
113
114 self.line_search()
115
116
117 self.xk_new = self.xk + self.alpha * self.pk
118 self.fk_new, self.f_count = apply(self.func, (self.xk_new,)+self.args), self.f_count + 1
119 self.dfk_new, self.g_count = apply(self.dfunc, (self.xk_new,)+self.args), self.g_count + 1
120
121
122 self.cd_dir[self.n] = self.alpha * self.pk
123
124
126 """Function to update the function value, gradient vector, and Hessian matrix."""
127
128
129 if not self.back:
130 if self.n < len(self.xk) - 1:
131 self.n = self.n + 1
132 else:
133 self.back = 1
134 self.n = self.n - 1
135 else:
136 if self.n > 0:
137 self.n = self.n - 1
138 else:
139 self.back = 0
140 self.n = self.n + 1
141 if self.print_flag >= 2:
142 print self.print_prefix + "back_flag: " + `self.back`
143 print self.print_prefix + "n: " + `self.n`
144
145
146 self.fk_last = self.fk
147 self.dfk_last = self.dfk * 1.0
148
149
150 self.xk = self.xk_new * 1.0
151 self.fk = self.fk_new
152 self.dfk = self.dfk_new * 1.0
153