wolffd@0
|
1 function [x, options, flog, pointlog] = conjgrad(f, x, options, gradf, ...
|
wolffd@0
|
2 varargin)
|
wolffd@0
|
3 %CONJGRAD Conjugate gradients optimization.
|
wolffd@0
|
4 %
|
wolffd@0
|
5 % Description
|
wolffd@0
|
6 % [X, OPTIONS, FLOG, POINTLOG] = CONJGRAD(F, X, OPTIONS, GRADF) uses a
|
wolffd@0
|
7 % conjugate gradients algorithm to find the minimum of the function
|
wolffd@0
|
8 % F(X) whose gradient is given by GRADF(X). Here X is a row vector and
|
wolffd@0
|
9 % F returns a scalar value. The point at which F has a local minimum
|
wolffd@0
|
10 % is returned as X. The function value at that point is returned in
|
wolffd@0
|
11 % OPTIONS(8). A log of the function values after each cycle is
|
wolffd@0
|
12 % (optionally) returned in FLOG, and a log of the points visited is
|
wolffd@0
|
13 % (optionally) returned in POINTLOG.
|
wolffd@0
|
14 %
|
wolffd@0
|
15 % CONJGRAD(F, X, OPTIONS, GRADF, P1, P2, ...) allows additional
|
wolffd@0
|
16 % arguments to be passed to F() and GRADF().
|
wolffd@0
|
17 %
|
wolffd@0
|
18 % The optional parameters have the following interpretations.
|
wolffd@0
|
19 %
|
wolffd@0
|
20 % OPTIONS(1) is set to 1 to display error values; also logs error
|
wolffd@0
|
21 % values in the return argument ERRLOG, and the points visited in the
|
wolffd@0
|
22 % return argument POINTSLOG. If OPTIONS(1) is set to 0, then only
|
wolffd@0
|
23 % warning messages are displayed. If OPTIONS(1) is -1, then nothing is
|
wolffd@0
|
24 % displayed.
|
wolffd@0
|
25 %
|
wolffd@0
|
26 % OPTIONS(2) is a measure of the absolute precision required for the
|
wolffd@0
|
27 % value of X at the solution. If the absolute difference between the
|
wolffd@0
|
28 % values of X between two successive steps is less than OPTIONS(2),
|
wolffd@0
|
29 % then this condition is satisfied.
|
wolffd@0
|
30 %
|
wolffd@0
|
31 % OPTIONS(3) is a measure of the precision required of the objective
|
wolffd@0
|
32 % function at the solution. If the absolute difference between the
|
wolffd@0
|
33 % objective function values between two successive steps is less than
|
wolffd@0
|
34 % OPTIONS(3), then this condition is satisfied. Both this and the
|
wolffd@0
|
35 % previous condition must be satisfied for termination.
|
wolffd@0
|
36 %
|
wolffd@0
|
37 % OPTIONS(9) is set to 1 to check the user defined gradient function.
|
wolffd@0
|
38 %
|
wolffd@0
|
39 % OPTIONS(10) returns the total number of function evaluations
|
wolffd@0
|
40 % (including those in any line searches).
|
wolffd@0
|
41 %
|
wolffd@0
|
42 % OPTIONS(11) returns the total number of gradient evaluations.
|
wolffd@0
|
43 %
|
wolffd@0
|
44 % OPTIONS(14) is the maximum number of iterations; default 100.
|
wolffd@0
|
45 %
|
wolffd@0
|
46 % OPTIONS(15) is the precision in parameter space of the line search;
|
wolffd@0
|
47 % default 1E-4.
|
wolffd@0
|
48 %
|
wolffd@0
|
49 % See also
|
wolffd@0
|
50 % GRADDESC, LINEMIN, MINBRACK, QUASINEW, SCG
|
wolffd@0
|
51 %
|
wolffd@0
|
52
|
wolffd@0
|
53 % Copyright (c) Ian T Nabney (1996-2001)
|
wolffd@0
|
54
|
wolffd@0
|
55 % Set up the options.
|
wolffd@0
|
56 if length(options) < 18
|
wolffd@0
|
57 error('Options vector too short')
|
wolffd@0
|
58 end
|
wolffd@0
|
59
|
wolffd@0
|
60 if(options(14))
|
wolffd@0
|
61 niters = options(14);
|
wolffd@0
|
62 else
|
wolffd@0
|
63 niters = 100;
|
wolffd@0
|
64 end
|
wolffd@0
|
65
|
wolffd@0
|
66 % Set up options for line search
|
wolffd@0
|
67 line_options = foptions;
|
wolffd@0
|
68 % Need a precise line search for success
|
wolffd@0
|
69 if options(15) > 0
|
wolffd@0
|
70 line_options(2) = options(15);
|
wolffd@0
|
71 else
|
wolffd@0
|
72 line_options(2) = 1e-4;
|
wolffd@0
|
73 end
|
wolffd@0
|
74
|
wolffd@0
|
75 display = options(1);
|
wolffd@0
|
76
|
wolffd@0
|
77 % Next two lines allow conjgrad to work with expression strings
|
wolffd@0
|
78 f = fcnchk(f, length(varargin));
|
wolffd@0
|
79 gradf = fcnchk(gradf, length(varargin));
|
wolffd@0
|
80
|
wolffd@0
|
81 % Check gradients
|
wolffd@0
|
82 if (options(9))
|
wolffd@0
|
83 feval('gradchek', x, f, gradf, varargin{:});
|
wolffd@0
|
84 end
|
wolffd@0
|
85
|
wolffd@0
|
86 options(10) = 0;
|
wolffd@0
|
87 options(11) = 0;
|
wolffd@0
|
88 nparams = length(x);
|
wolffd@0
|
89 fnew = feval(f, x, varargin{:});
|
wolffd@0
|
90 options(10) = options(10) + 1;
|
wolffd@0
|
91 gradnew = feval(gradf, x, varargin{:});
|
wolffd@0
|
92 options(11) = options(11) + 1;
|
wolffd@0
|
93 d = -gradnew; % Initial search direction
|
wolffd@0
|
94 br_min = 0;
|
wolffd@0
|
95 br_max = 1.0; % Initial value for maximum distance to search along
|
wolffd@0
|
96 tol = sqrt(eps);
|
wolffd@0
|
97
|
wolffd@0
|
98 j = 1;
|
wolffd@0
|
99 if nargout >= 3
|
wolffd@0
|
100 flog(j, :) = fnew;
|
wolffd@0
|
101 if nargout == 4
|
wolffd@0
|
102 pointlog(j, :) = x;
|
wolffd@0
|
103 end
|
wolffd@0
|
104 end
|
wolffd@0
|
105
|
wolffd@0
|
106 while (j <= niters)
|
wolffd@0
|
107
|
wolffd@0
|
108 xold = x;
|
wolffd@0
|
109 fold = fnew;
|
wolffd@0
|
110 gradold = gradnew;
|
wolffd@0
|
111
|
wolffd@0
|
112 gg = gradold*gradold';
|
wolffd@0
|
113 if (gg == 0.0)
|
wolffd@0
|
114 % If the gradient is zero then we are done.
|
wolffd@0
|
115 options(8) = fnew;
|
wolffd@0
|
116 return;
|
wolffd@0
|
117 end
|
wolffd@0
|
118
|
wolffd@0
|
119 % This shouldn't occur, but rest of code depends on d being downhill
|
wolffd@0
|
120 if (gradnew*d' > 0)
|
wolffd@0
|
121 d = -d;
|
wolffd@0
|
122 if options(1) >= 0
|
wolffd@0
|
123 warning('search direction uphill in conjgrad');
|
wolffd@0
|
124 end
|
wolffd@0
|
125 end
|
wolffd@0
|
126
|
wolffd@0
|
127 line_sd = d./norm(d);
|
wolffd@0
|
128 [lmin, line_options] = feval('linemin', f, xold, line_sd, fold, ...
|
wolffd@0
|
129 line_options, varargin{:});
|
wolffd@0
|
130 options(10) = options(10) + line_options(10);
|
wolffd@0
|
131 options(11) = options(11) + line_options(11);
|
wolffd@0
|
132 % Set x and fnew to be the actual search point we have found
|
wolffd@0
|
133 x = xold + lmin * line_sd;
|
wolffd@0
|
134 fnew = line_options(8);
|
wolffd@0
|
135
|
wolffd@0
|
136 % Check for termination
|
wolffd@0
|
137 if (max(abs(x - xold)) < options(2) & max(abs(fnew - fold)) < options(3))
|
wolffd@0
|
138 options(8) = fnew;
|
wolffd@0
|
139 return;
|
wolffd@0
|
140 end
|
wolffd@0
|
141
|
wolffd@0
|
142 gradnew = feval(gradf, x, varargin{:});
|
wolffd@0
|
143 options(11) = options(11) + 1;
|
wolffd@0
|
144
|
wolffd@0
|
145 % Use Polak-Ribiere formula to update search direction
|
wolffd@0
|
146 gamma = ((gradnew - gradold)*(gradnew)')/gg;
|
wolffd@0
|
147 d = (d .* gamma) - gradnew;
|
wolffd@0
|
148
|
wolffd@0
|
149 if (display > 0)
|
wolffd@0
|
150 fprintf(1, 'Cycle %4d Function %11.6f\n', j, line_options(8));
|
wolffd@0
|
151 end
|
wolffd@0
|
152
|
wolffd@0
|
153 j = j + 1;
|
wolffd@0
|
154 if nargout >= 3
|
wolffd@0
|
155 flog(j, :) = fnew;
|
wolffd@0
|
156 if nargout == 4
|
wolffd@0
|
157 pointlog(j, :) = x;
|
wolffd@0
|
158 end
|
wolffd@0
|
159 end
|
wolffd@0
|
160 end
|
wolffd@0
|
161
|
wolffd@0
|
162 % If we get here, then we haven't terminated in the given number of
|
wolffd@0
|
163 % iterations.
|
wolffd@0
|
164
|
wolffd@0
|
165 options(8) = fold;
|
wolffd@0
|
166 if (options(1) >= 0)
|
wolffd@0
|
167 disp(maxitmess);
|
wolffd@0
|
168 end
|