1function [x,fval,exitflag,output]=fminsearchcon(fun,x0,LB,UB,A,b,nonlcon,options,varargin)
2% FMINSEARCHCON: Extension of FMINSEARCHBND with general inequality constraints
3% usage: x=FMINSEARCHCON(fun,x0)
4% usage: x=FMINSEARCHCON(fun,x0,LB)
5% usage: x=FMINSEARCHCON(fun,x0,LB,UB)
6% usage: x=FMINSEARCHCON(fun,x0,LB,UB,A,b)
7% usage: x=FMINSEARCHCON(fun,x0,LB,UB,A,b,nonlcon)
8% usage: x=FMINSEARCHCON(fun,x0,LB,UB,A,b,nonlcon,options)
9% usage: x=FMINSEARCHCON(fun,x0,LB,UB,A,b,nonlcon,options,p1,p2,...)
10% usage: [x,fval,exitflag,output]=FMINSEARCHCON(fun,x0,...)
13% fun, x0, options - see the help
for FMINSEARCH
15% x0 MUST be a feasible point
for the linear and nonlinear
16% inequality constraints. If it
is not inside the bounds
17% then it will be moved to the nearest bound. If x0
is
18% infeasible
for the general constraints, then an error will
21% LB - lower bound vector or array, must be the same size as x0
23% If no lower bounds exist
for one of the variables, then
24% supply -inf
for that variable.
26% If no lower bounds at all, then LB may be left empty.
28% Variables may be fixed in value by setting the corresponding
29% lower and upper bounds to exactly the same value.
31% UB - upper bound vector or array, must be the same size as x0
33% If no upper bounds exist
for one of the variables, then
34% supply +inf
for that variable.
36% If no upper bounds at all, then UB may be left empty.
38% Variables may be fixed in value by setting the corresponding
39% lower and upper bounds to exactly the same value.
41% A,b - (OPTIONAL) Linear inequality constraint array and right
42% hand side vector. (Note: these constraints were chosen to
43% be consistent with those of fmincon.)
47% nonlcon - (OPTIONAL) general nonlinear inequality constraints
48% NONLCON must return a set of general inequality constraints.
49% These will be enforced such that nonlcon
is always <= 0.
56% If options
is supplied, then TolX will apply to the transformed
57% variables. All other FMINSEARCH parameters should be unaffected.
59% Variables which are constrained by both a lower and an upper
60% bound will use a sin transformation. Those constrained by
61% only a lower or an upper bound will use a quadratic
62% transformation, and unconstrained variables will be left alone.
64% Variables may be fixed by setting their respective bounds equal.
65% In this case, the problem will be reduced in size for FMINSEARCH.
67% The bounds are inclusive inequalities, which admit the
68% boundary values themselves, but will not permit ANY function
69% evaluations outside the bounds. These constraints are strictly
72% If your problem has an EXCLUSIVE (strict) constraint which will
73% not admit evaluation at the bound itself, then you must provide
74% a slightly offset bound. An example of this
is a function which
75% contains the log of one of its parameters. If you constrain the
76% variable to have a lower bound of zero, then FMINSEARCHCON may
77% try to evaluate the function exactly at zero.
79% Inequality constraints are enforced with an implicit penalty
80% function approach. But the constraints are tested before
81% any function evaluations are ever done, so the actual objective
82% function
is NEVER evaluated outside of the feasible region.
86% rosen = @(x) (1-x(1)).^2 + 105*(x(2)-x(1).^2).^2;
88% Fully unconstrained problem
89% fminsearchcon(rosen,[3 3])
93% lower bound constrained
94% fminsearchcon(rosen,[3 3],[2 2],[])
99% fminsearchcon(rosen,[3 3],[-inf 3],[inf,3])
103% simple linear inequality: x(1) + x(2) <= 1
104% fminsearchcon(rosen,[0 0],[],[],[1 1],.5)
109% general nonlinear inequality: sqrt(x(1)^2 + x(2)^2) <= 1
110% fminsearchcon(rosen,[0 0],[],[],[],[],@(x) norm(x)-1)
114% Of course, any combination of the above constraints
is
117% See test_main.m for other examples of use.
120% See also: fminsearch, fminspleas, fminsearchbnd
123% Author: John D'Errico
124% E-mail: woodchips@rochester.rr.com
126% Release date: 12/16/06
133if (nargin<3) || isempty(LB)
134 LB = repmat(-inf,n,1);
138if (nargin<4) || isempty(UB)
139 UB = repmat(inf,n,1);
144if (n~=length(LB)) || (n~=length(UB))
145 error 'x0
is incompatible in size with either LB or UB.'
149if (nargin<5) || isempty(A)
152if (nargin<6) || isempty(b)
157if (isempty(A)&&~isempty(b)) || (isempty(b)&&~isempty(A))
158 error 'Sizes of A and b are incompatible'
164 error 'Sizes of A and b are incompatible'
167 error 'A
is incompatible in size with x0'
171% defaults for nonlcon
172if (nargin<7) || isempty(nonlcon)
176% test for feasibility of the initial value
177% against any general inequality constraints
180 error 'Infeasible starting values (linear inequalities failed).'
184 if any(feval(nonlcon,(reshape(x0,xsize)),varargin{:})>0)
185 error 'Infeasible starting values (nonlinear inequalities failed).'
189% set default options if necessary
190if (nargin<8) || isempty(options)
191 options = optimset('fminsearch');
194% stuff into a struct to pass around
195params.args = varargin;
202params.OutputFcn = [];
206params.nonlcon = nonlcon;
208% 0 --> unconstrained variable
209% 1 --> lower bound only
210% 2 --> upper bound only
211% 3 --> dual finite bounds
212% 4 --> fixed variable
213params.BoundClass = zeros(n,1);
215 k = isfinite(LB(i)) + 2*isfinite(UB(i));
216 params.BoundClass(i) = k;
217 if (k==3) && (LB(i)==UB(i))
218 params.BoundClass(i) = 4;
222% transform starting values into their unconstrained
223% surrogates. Check for infeasible starting guesses.
227 switch params.BoundClass(i)
231 % infeasible starting value. Use bound.
234 x0u(k) = sqrt(x0(i) - LB(i));
242 % infeasible starting value. use bound.
245 x0u(k) = sqrt(UB(i) - x0(i));
251 % lower and upper bounds
253 % infeasible starting value
256 % infeasible starting value
259 x0u(k) = 2*(x0(i) - LB(i))/(UB(i)-LB(i)) - 1;
260 % shift by 2*pi to avoid problems at zero in fminsearch
261 % otherwise, the initial simplex
is vanishingly small
262 x0u(k) = 2*pi+asin(max(-1,min(1,x0u(k))));
268 % unconstrained variable. x0u(i)
is set.
274 % fixed variable. drop it before fminsearch sees it.
275 % k
is not incremented for this variable.
279% if any of the unknowns were fixed, then we need to shorten
285% were all the variables fixed?
287 % All variables were fixed. quit immediately, setting the
288 % appropriate parameters, then return.
290 % undo the variable transformations into the original space
291 x = xtransform(x0u,params);
294 x = reshape(x,xsize);
296 % stuff fval with the final value
297 fval = feval(params.fun,x,params.args{:});
299 % fminsearchbnd was not called
302 output.iterations = 0;
303 output.funcCount = 1;
304 output.algorithm =
'fminsearch';
305 output.message =
'All variables were held fixed by the applied bounds';
307 %
return with no call at all to fminsearch
311% Check
for an outputfcn. If there
is any, then substitute my
312% own wrapper function.
313if ~isempty(options.OutputFcn)
314 params.OutputFcn = options.OutputFcn;
315 options.OutputFcn = @outfun_wrapper;
318% now we can call fminsearch, but with our own
319% intra-objective function.
320[xu,fval,exitflag,output] = fminsearch(@intrafun,x0u,options,params);
322% undo the variable transformations into the original space
323x = xtransform(xu,params);
328% Use a nested function as the OutputFcn wrapper
329 function stop = outfun_wrapper(x,varargin);
330 % we need to transform x first
331 xtrans = xtransform(x,params);
333 % then call the user supplied OutputFcn
334 stop = params.OutputFcn(xtrans,varargin{1:(end-1)});
340% ======================================
341% ========= begin subfunctions =========
342% ======================================
343function fval = intrafun(x,params)
344% transform variables, test constraints, then call original function
347xtrans = xtransform(x,params);
349% test constraints before the function call
351% First,
do the linear inequality constraints,
if any
353 % Required: A*xtrans <= b
354 if any(params.A*xtrans(:) > params.b)
355 % linear inequality constraints failed. Just return inf.
361% resize xtrans to be the correct size
for the nonlcon
362% and objective function calls
363xtrans = reshape(xtrans,params.xsize);
365% Next,
do the nonlinear inequality constraints
366if ~isempty(params.nonlcon)
367 % Required: nonlcon(xtrans) <= 0
368 cons = feval(params.nonlcon,xtrans,params.args{:});
370 % nonlinear inequality constraints failed. Just return inf.
376% we survived the general inequality constraints. Only now
377%
do we evaluate the objective function.
379% append any additional parameters to the argument list
380fval = feval(params.fun,xtrans,params.args{:});
382end % sub function intrafun end
384% ======================================
385function xtrans = xtransform(x,params)
386% converts unconstrained variables into their original domains
388xtrans = zeros(1,params.n);
389% k allows some variables to be fixed, thus dropped from the
393 switch params.BoundClass(i)
396 xtrans(i) = params.LB(i) + x(k).^2;
401 xtrans(i) = params.UB(i) - x(k).^2;
405 % lower and upper bounds
406 xtrans(i) = (sin(x(k))+1)/2;
407 xtrans(i) = xtrans(i)*(params.UB(i) - params.LB(i)) + params.LB(i);
408 % just in
case of any floating point problems
409 xtrans(i) = max(params.LB(i),min(params.UB(i),xtrans(i)));
413 % fixed variable, bounds are equal, set it at either bound
414 xtrans(i) = params.LB(i);
416 % unconstrained variable.
423end % sub function xtransform end