1 ## Copyright (C) 2009 Levente Torok <TorokLev@gmail.com>
3 ## This program is free software; you can redistribute it and/or modify it under
4 ## the terms of the GNU General Public License as published by the Free Software
5 ## Foundation; either version 3 of the License, or (at your option) any later
8 ## This program is distributed in the hope that it will be useful, but WITHOUT
9 ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
13 ## You should have received a copy of the GNU General Public License along with
14 ## this program; if not, see <http://www.gnu.org/licenses/>.
17 ## @deftypefn {Function File} {[@var{s},@var{v},@var{n}]} brent_line_min ( @var{f},@var{df},@var{args},@var{ctl} )
18 ## Line minimization of f along df
20 ## Finds minimum of f on line @math{ x0 + dx*w | a < w < b } by
21 ## bracketing. a and b are passed through argument ctl.
23 ## @subheading Arguments
25 ## @item @var{f} : string : Name of function. Must return a real value
26 ## @item @var{args} : cell : Arguments passed to f or RxC : f's only argument. x0 must be at @var{args}@{ @var{ctl}(2) @}
27 ## @item @var{ctl} : 5 : (optional) Control variables, described below.
30 ## @subheading Returned values
32 ## @item @var{s} : 1 : Minimum is at x0 + s*dx
33 ## @item @var{v} : 1 : Value of f at x0 + s*dx
34 ## @item @var{nev} : 1 : Number of function evaluations
37 ## @subheading Control Variables
39 ## @item @var{ctl}(1) : Upper bound for error on s Default=sqrt(eps)
40 ## @item @var{ctl}(2) : Position of minimized argument in args Default= 1
41 ## @item @var{ctl}(3) : Maximum number of function evaluations Default= inf
42 ## @item @var{ctl}(4) : a Default=-inf
43 ## @item @var{ctl}(5) : b Default= inf
46 ## Default values will be used if ctl is not passed or if nan values are
50 function [s,gs,nev] = brent_line_min( f,dx,args,ctl )
56 # Default control variables
57 tol = 10*eps; # sqrt (eps);
63 if nargin >= 4, # Read arguments
64 if !isnan (ctl (1)), tol = ctl(1); end
65 if length (ctl)>=2 && !isnan (ctl(2)), narg = ctl(2); end
66 if length (ctl)>=3 && !isnan (ctl(3)), maxev = ctl(3); end
67 if length (ctl)>=4 && !isnan (ctl(4)), a = ctl(4); end
68 if length (ctl)>=5 && !isnan (ctl(5)), b = ctl(5); end
70 end # Otherwise, use defaults, def'd above
72 if a>b, tmp=a; a=b; b=tmp; end
74 if narg > length (args),
75 printf ("brent_line_min : narg==%i > length (args)==%i",\
88 N = R*C; # Size of argument
90 gs0 = gs = feval (f, args);
95 if all (dx==0), return; end # Trivial case
97 # If any of the bounds is infinite, find
98 # finite bounds that bracket minimum
99 if !isfinite (a) || !isfinite (b),
100 if !isfinite (a) && !isfinite (b),
101 [a,b, ga,gb, n] = __bracket_min (f, dx, narg, args);
102 elseif !isfinite (a),
103 [a,b, ga,gb, n] = __semi_bracket (f, -dx, -b, narg, args);
104 tmp = a; a = -b; b = -tmp;
105 tmp = ga; ga = gb; gb = tmp;
107 [a,b, ga,gb, n] = __semi_bracket (f, dx, a, narg, args);
111 args{narg} = x+a*dx; ga = feval( f, args );
112 args{narg} = x+b*dx; gb = feval( f, args );
114 end # End of finding bracket for minimum
116 if a > b, # Check assumptions
117 printf ("brent_line_min : a > b\n");
122 args{narg} = x+ s*dx; gs = feval( f, args );
126 printf ("[a,s,b]=[%.3e,%.3e,%.3e], [ga,gs,gb]=[%.3e,%.3e,%.3e]\n",\
132 while ( b-a > maxerr ) && nev < maxev,
134 if gs > ga && gs > gb, # Check assumptions
135 printf ("brent_line_min : gs > ga && gs > gb\n");
139 if ga == gb && gb == gs, break end
141 # Don't trust poly_2_ex for glued points
142 # (see test_poly_2_ex).
144 ## if min (b-s, s-a) > 10*seps,
146 # If s is not glued to a or b and does not
148 ## mydet = sum (l([2 3 1]).*f([3 1 2])-l([3 1 2]).*f([2 3 1]))
149 mydet = sum ([s b a].*[gb ga gs] - [b a s].*[gs gb ga]);
150 if min (b-s, s-a) > 10*seps && abs (mydet) > 10*seps && \
151 (t = poly_2_ex ([a,s,b], [ga, gs, gb])) < b && t > a,
153 # t has already been set
156 ## printf ("brent_line_min : t is not in ]a,b[\n");
160 # Otherwise, reduce the biggest of the
161 # intervals, but not too much
163 t = max (0.5*(a+s), s-100*seps);
165 t = min (0.5*(s+b), s+100*seps);
168 if abs (t-s) < 0.51*maxerr,
169 #sayif (verbose, "ungluing t and s\n");
170 t = s + (1 - 2*(s-a > b-s))*0.49*maxerr ;
173 if a > s || s > b, # Check assumptions
174 printf ("brent_line_min : a > s || s > b\n");
180 gt = feval( f, args );
184 printf ("t = %.3e, gt = %.3e\n",t,gt);
187 if t<s, # New point is in ]a,s[
189 if gt > ga + seps, # Check assumptions
190 printf ("brent_line_min : gt > ga\n");
200 else # New point is in ]s,b[
201 if gt > gb + seps, # Check assumptions
202 printf ("brent_line_min : gt > gb\n");
215 printf ("[a,s,b]=[%.3e,%.3e,%.3e], [ga,gs,gb]=[%.3e,%.3e,%.3e]\n",\
223 args{narg} = x + s2*dx; gs2 = feval (f, args );
231 printf ("brent_line_min : goes uphill by %8.3e\n",gs-gs0);