LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
fminsearchbnd.m
1function [x,fval,exitflag,output] = fminsearchbnd(fun,x0,LB,UB,options,varargin)
2% FMINSEARCHBND: FMINSEARCH, but with bound constraints by transformation
3% usage: x=FMINSEARCHBND(fun,x0)
4% usage: x=FMINSEARCHBND(fun,x0,LB)
5% usage: x=FMINSEARCHBND(fun,x0,LB,UB)
6% usage: x=FMINSEARCHBND(fun,x0,LB,UB,options)
7% usage: x=FMINSEARCHBND(fun,x0,LB,UB,options,p1,p2,...)
8% usage: [x,fval,exitflag,output]=FMINSEARCHBND(fun,x0,...)
9%
10% arguments:
11% fun, x0, options - see the help for FMINSEARCH
12%
13% LB - lower bound vector or array, must be the same size as x0
14%
15% If no lower bounds exist for one of the variables, then
16% supply -inf for that variable.
17%
18% If no lower bounds at all, then LB may be left empty.
19%
20% Variables may be fixed in value by setting the corresponding
21% lower and upper bounds to exactly the same value.
22%
23% UB - upper bound vector or array, must be the same size as x0
24%
25% If no upper bounds exist for one of the variables, then
26% supply +inf for that variable.
27%
28% If no upper bounds at all, then UB may be left empty.
29%
30% Variables may be fixed in value by setting the corresponding
31% lower and upper bounds to exactly the same value.
32%
33% Notes:
34%
35% If options is supplied, then TolX will apply to the transformed
36% variables. All other FMINSEARCH parameters should be unaffected.
37%
38% Variables which are constrained by both a lower and an upper
39% bound will use a sin transformation. Those constrained by
40% only a lower or an upper bound will use a quadratic
41% transformation, and unconstrained variables will be left alone.
42%
43% Variables may be fixed by setting their respective bounds equal.
44% In this case, the problem will be reduced in size for FMINSEARCH.
45%
46% The bounds are inclusive inequalities, which admit the
47% boundary values themselves, but will not permit ANY function
48% evaluations outside the bounds. These constraints are strictly
49% followed.
50%
51% If your problem has an EXCLUSIVE (strict) constraint which will
52% not admit evaluation at the bound itself, then you must provide
53% a slightly offset bound. An example of this is a function which
54% contains the log of one of its parameters. If you constrain the
55% variable to have a lower bound of zero, then FMINSEARCHBND may
56% try to evaluate the function exactly at zero.
57%
58%
59% Example usage:
60% rosen = @(x) (1-x(1)).^2 + 105*(x(2)-x(1).^2).^2;
61%
62% fminsearch(rosen,[3 3]) % unconstrained
63% ans =
64% 1.0000 1.0000
65%
66% fminsearchbnd(rosen,[3 3],[2 2],[]) % constrained
67% ans =
68% 2.0000 4.0000
69%
70% See test_main.m for other examples of use.
71%
72%
73% See also: fminsearch, fminspleas
74%
75%
76% Author: John D'Errico
77% E-mail: woodchips@rochester.rr.com
78% Release: 4
79% Release date: 7/23/06
80
81% size checks
82xsize = size(x0);
83x0 = x0(:);
84n=length(x0);
85
86if (nargin<3) || isempty(LB)
87 LB = repmat(-inf,n,1);
88else
89 LB = LB(:);
90end
91if (nargin<4) || isempty(UB)
92 UB = repmat(inf,n,1);
93else
94 UB = UB(:);
95end
96
97if (n~=length(LB)) || (n~=length(UB))
98 error 'x0 is incompatible in size with either LB or UB.'
99end
100
101% set default options if necessary
102if (nargin<5) || isempty(options)
103 options = optimset('fminsearch');
104end
105
106% stuff into a struct to pass around
107params.args = varargin;
108params.LB = LB;
109params.UB = UB;
110params.fun = fun;
111params.n = n;
112% note that the number of parameters may actually vary if
113% a user has chosen to fix one or more parameters
114params.xsize = xsize;
115params.OutputFcn = [];
116
117% 0 --> unconstrained variable
118% 1 --> lower bound only
119% 2 --> upper bound only
120% 3 --> dual finite bounds
121% 4 --> fixed variable
122params.BoundClass = zeros(n,1);
123for i=1:n
124 k = isfinite(LB(i)) + 2*isfinite(UB(i));
125 params.BoundClass(i) = k;
126 if (k==3) && (LB(i)==UB(i))
127 params.BoundClass(i) = 4;
128 end
129end
130
131% transform starting values into their unconstrained
132% surrogates. Check for infeasible starting guesses.
133x0u = x0;
134k=1;
135for i = 1:n
136 switch params.BoundClass(i)
137 case 1
138 % lower bound only
139 if x0(i)<=LB(i)
140 % infeasible starting value. Use bound.
141 x0u(k) = 0;
142 else
143 x0u(k) = sqrt(x0(i) - LB(i));
144 end
145
146 % increment k
147 k=k+1;
148 case 2
149 % upper bound only
150 if x0(i)>=UB(i)
151 % infeasible starting value. use bound.
152 x0u(k) = 0;
153 else
154 x0u(k) = sqrt(UB(i) - x0(i));
155 end
156
157 % increment k
158 k=k+1;
159 case 3
160 % lower and upper bounds
161 if x0(i)<=LB(i)
162 % infeasible starting value
163 x0u(k) = -pi/2;
164 elseif x0(i)>=UB(i)
165 % infeasible starting value
166 x0u(k) = pi/2;
167 else
168 x0u(k) = 2*(x0(i) - LB(i))/(UB(i)-LB(i)) - 1;
169 % shift by 2*pi to avoid problems at zero in fminsearch
170 % otherwise, the initial simplex is vanishingly small
171 x0u(k) = 2*pi+asin(max(-1,min(1,x0u(k))));
172 end
173
174 % increment k
175 k=k+1;
176 case 0
177 % unconstrained variable. x0u(i) is set.
178 x0u(k) = x0(i);
179
180 % increment k
181 k=k+1;
182 case 4
183 % fixed variable. drop it before fminsearch sees it.
184 % k is not incremented for this variable.
185 end
186
187end
188% if any of the unknowns were fixed, then we need to shorten
189% x0u now.
190if k<=n
191 x0u(k:n) = [];
192end
193
194% were all the variables fixed?
195if isempty(x0u)
196 % All variables were fixed. quit immediately, setting the
197 % appropriate parameters, then return.
198
199 % undo the variable transformations into the original space
200 x = xtransform(x0u,params);
201
202 % final reshape
203 x = reshape(x,xsize);
204
205 % stuff fval with the final value
206 fval = feval(params.fun,x,params.args{:});
207
208 % fminsearchbnd was not called
209 exitflag = 0;
210
211 output.iterations = 0;
212 output.funcCount = 1;
213 output.algorithm = 'fminsearch';
214 output.message = 'All variables were held fixed by the applied bounds';
215
216 % return with no call at all to fminsearch
217 return
218end
219
220% Check for an outputfcn. If there is any, then substitute my
221% own wrapper function.
222if ~isempty(options.OutputFcn)
223 params.OutputFcn = options.OutputFcn;
224 options.OutputFcn = @outfun_wrapper;
225end
226
227% now we can call fminsearch, but with our own
228% intra-objective function.
229[xu,fval,exitflag,output] = fminsearch(@intrafun,x0u,options,params);
230
231% undo the variable transformations into the original space
232x = xtransform(xu,params);
233
234% final reshape to make sure the result has the proper shape
235x = reshape(x,xsize);
236
237% Use a nested function as the OutputFcn wrapper
238 function stop = outfun_wrapper(x,varargin);
239 % we need to transform x first
240 xtrans = xtransform(x,params);
241
242 % then call the user supplied OutputFcn
243 stop = params.OutputFcn(xtrans,varargin{1:(end-1)});
244
245 end
246
247end % mainline end
248
249% ======================================
250% ========= begin subfunctions =========
251% ======================================
252function fval = intrafun(x,params)
253% transform variables, then call original function
254
255% transform
256xtrans = xtransform(x,params);
257
258% and call fun
259fval = feval(params.fun,reshape(xtrans,params.xsize),params.args{:});
260
261end % sub function intrafun end
262
263% ======================================
264function xtrans = xtransform(x,params)
265% converts unconstrained variables into their original domains
266
267xtrans = zeros(params.xsize);
268% k allows some variables to be fixed, thus dropped from the
269% optimization.
270k=1;
271for i = 1:params.n
272 switch params.BoundClass(i)
273 case 1
274 % lower bound only
275 xtrans(i) = params.LB(i) + x(k).^2;
276
277 k=k+1;
278 case 2
279 % upper bound only
280 xtrans(i) = params.UB(i) - x(k).^2;
281
282 k=k+1;
283 case 3
284 % lower and upper bounds
285 xtrans(i) = (sin(x(k))+1)/2;
286 xtrans(i) = xtrans(i)*(params.UB(i) - params.LB(i)) + params.LB(i);
287 % just in case of any floating point problems
288 xtrans(i) = max(params.LB(i),min(params.UB(i),xtrans(i)));
289
290 k=k+1;
291 case 4
292 % fixed variable, bounds are equal, set it at either bound
293 xtrans(i) = params.LB(i);
294 case 0
295 % unconstrained variable.
296 xtrans(i) = x(k);
297
298 k=k+1;
299 end
300end
301
302end % sub function xtransform end
303
304
305
306
307