


FMINSEARCHBND: FMINSEARCH, but with bound constraints by transformation
usage: x=FMINSEARCHBND(fun,x0)
usage: x=FMINSEARCHBND(fun,x0,LB)
usage: x=FMINSEARCHBND(fun,x0,LB,UB)
usage: x=FMINSEARCHBND(fun,x0,LB,UB,options)
usage: x=FMINSEARCHBND(fun,x0,LB,UB,options,p1,p2,...)
usage: [x,fval,exitflag,output]=FMINSEARCHBND(fun,x0,...)
arguments:
fun, x0, options - see the help for FMINSEARCH
LB - lower bound vector or array, must be the same size as x0
If no lower bounds exist for one of the variables, then
supply -inf for that variable.
If no lower bounds at all, then LB may be left empty.
Variables may be fixed in value by setting the corresponding
lower and upper bounds to exactly the same value.
UB - upper bound vector or array, must be the same size as x0
If no upper bounds exist for one of the variables, then
supply +inf for that variable.
If no upper bounds at all, then UB may be left empty.
Variables may be fixed in value by setting the corresponding
lower and upper bounds to exactly the same value.
Notes:
If options is supplied, then TolX will apply to the transformed
variables. All other FMINSEARCH parameters should be unaffected.
Variables which are constrained by both a lower and an upper
bound will use a sin transformation. Those constrained by
only a lower or an upper bound will use a quadratic
transformation, and unconstrained variables will be left alone.
Variables may be fixed by setting their respective bounds equal.
In this case, the problem will be reduced in size for FMINSEARCH.
The bounds are inclusive inequalities, which admit the
boundary values themselves, but will not permit ANY function
evaluations outside the bounds. These constraints are strictly
followed.
If your problem has an EXCLUSIVE (strict) constraint which will
not admit evaluation at the bound itself, then you must provide
a slightly offset bound. An example of this is a function which
contains the log of one of its parameters. If you constrain the
variable to have a lower bound of zero, then FMINSEARCHBND may
try to evaluate the function exactly at zero.
Example usage:
rosen = @(x) (1-x(1)).^2 + 105*(x(2)-x(1).^2).^2;
fminsearch(rosen,[3 3]) % unconstrained
ans =
1.0000 1.0000
fminsearchbnd(rosen,[3 3],[2 2],[]) % constrained
ans =
2.0000 4.0000
See test_main.m for other examples of use.
See also: fminsearch, fminspleas
Author: John D'Errico
E-mail: woodchips@rochester.rr.com
Release: 4
Release date: 7/23/06


0001 function [x,fval,exitflag,output] = fminsearchbnd(fun,x0,LB,UB,options,varargin) 0002 % FMINSEARCHBND: FMINSEARCH, but with bound constraints by transformation 0003 % usage: x=FMINSEARCHBND(fun,x0) 0004 % usage: x=FMINSEARCHBND(fun,x0,LB) 0005 % usage: x=FMINSEARCHBND(fun,x0,LB,UB) 0006 % usage: x=FMINSEARCHBND(fun,x0,LB,UB,options) 0007 % usage: x=FMINSEARCHBND(fun,x0,LB,UB,options,p1,p2,...) 0008 % usage: [x,fval,exitflag,output]=FMINSEARCHBND(fun,x0,...) 0009 % 0010 % arguments: 0011 % fun, x0, options - see the help for FMINSEARCH 0012 % 0013 % LB - lower bound vector or array, must be the same size as x0 0014 % 0015 % If no lower bounds exist for one of the variables, then 0016 % supply -inf for that variable. 0017 % 0018 % If no lower bounds at all, then LB may be left empty. 0019 % 0020 % Variables may be fixed in value by setting the corresponding 0021 % lower and upper bounds to exactly the same value. 0022 % 0023 % UB - upper bound vector or array, must be the same size as x0 0024 % 0025 % If no upper bounds exist for one of the variables, then 0026 % supply +inf for that variable. 0027 % 0028 % If no upper bounds at all, then UB may be left empty. 0029 % 0030 % Variables may be fixed in value by setting the corresponding 0031 % lower and upper bounds to exactly the same value. 0032 % 0033 % Notes: 0034 % 0035 % If options is supplied, then TolX will apply to the transformed 0036 % variables. All other FMINSEARCH parameters should be unaffected. 0037 % 0038 % Variables which are constrained by both a lower and an upper 0039 % bound will use a sin transformation. Those constrained by 0040 % only a lower or an upper bound will use a quadratic 0041 % transformation, and unconstrained variables will be left alone. 0042 % 0043 % Variables may be fixed by setting their respective bounds equal. 0044 % In this case, the problem will be reduced in size for FMINSEARCH. 0045 % 0046 % The bounds are inclusive inequalities, which admit the 0047 % boundary values themselves, but will not permit ANY function 0048 % evaluations outside the bounds. These constraints are strictly 0049 % followed. 0050 % 0051 % If your problem has an EXCLUSIVE (strict) constraint which will 0052 % not admit evaluation at the bound itself, then you must provide 0053 % a slightly offset bound. An example of this is a function which 0054 % contains the log of one of its parameters. If you constrain the 0055 % variable to have a lower bound of zero, then FMINSEARCHBND may 0056 % try to evaluate the function exactly at zero. 0057 % 0058 % 0059 % Example usage: 0060 % rosen = @(x) (1-x(1)).^2 + 105*(x(2)-x(1).^2).^2; 0061 % 0062 % fminsearch(rosen,[3 3]) % unconstrained 0063 % ans = 0064 % 1.0000 1.0000 0065 % 0066 % fminsearchbnd(rosen,[3 3],[2 2],[]) % constrained 0067 % ans = 0068 % 2.0000 4.0000 0069 % 0070 % See test_main.m for other examples of use. 0071 % 0072 % 0073 % See also: fminsearch, fminspleas 0074 % 0075 % 0076 % Author: John D'Errico 0077 % E-mail: woodchips@rochester.rr.com 0078 % Release: 4 0079 % Release date: 7/23/06 0080 0081 % size checks 0082 xsize = size(x0); 0083 x0 = x0(:); 0084 n=length(x0); 0085 0086 if (nargin<3) || isempty(LB) 0087 LB = repmat(-inf,n,1); 0088 else 0089 LB = LB(:); 0090 end 0091 if (nargin<4) || isempty(UB) 0092 UB = repmat(inf,n,1); 0093 else 0094 UB = UB(:); 0095 end 0096 0097 if (n~=length(LB)) || (n~=length(UB)) 0098 error 'x0 is incompatible in size with either LB or UB.' 0099 end 0100 0101 % set default options if necessary 0102 if (nargin<5) || isempty(options) 0103 options = optimset('fminsearch'); 0104 end 0105 0106 % stuff into a struct to pass around 0107 params.args = varargin; 0108 params.LB = LB; 0109 params.UB = UB; 0110 params.fun = fun; 0111 params.n = n; 0112 % note that the number of parameters may actually vary if 0113 % a user has chosen to fix one or more parameters 0114 params.xsize = xsize; 0115 params.OutputFcn = []; 0116 0117 % 0 --> unconstrained variable 0118 % 1 --> lower bound only 0119 % 2 --> upper bound only 0120 % 3 --> dual finite bounds 0121 % 4 --> fixed variable 0122 params.BoundClass = zeros(n,1); 0123 for i=1:n 0124 k = isfinite(LB(i)) + 2*isfinite(UB(i)); 0125 params.BoundClass(i) = k; 0126 if (k==3) && (LB(i)==UB(i)) 0127 params.BoundClass(i) = 4; 0128 end 0129 end 0130 0131 % transform starting values into their unconstrained 0132 % surrogates. Check for infeasible starting guesses. 0133 x0u = x0; 0134 k=1; 0135 for i = 1:n 0136 switch params.BoundClass(i) 0137 case 1 0138 % lower bound only 0139 if x0(i)<=LB(i) 0140 % infeasible starting value. Use bound. 0141 x0u(k) = 0; 0142 else 0143 x0u(k) = sqrt(x0(i) - LB(i)); 0144 end 0145 0146 % increment k 0147 k=k+1; 0148 case 2 0149 % upper bound only 0150 if x0(i)>=UB(i) 0151 % infeasible starting value. use bound. 0152 x0u(k) = 0; 0153 else 0154 x0u(k) = sqrt(UB(i) - x0(i)); 0155 end 0156 0157 % increment k 0158 k=k+1; 0159 case 3 0160 % lower and upper bounds 0161 if x0(i)<=LB(i) 0162 % infeasible starting value 0163 x0u(k) = -pi/2; 0164 elseif x0(i)>=UB(i) 0165 % infeasible starting value 0166 x0u(k) = pi/2; 0167 else 0168 x0u(k) = 2*(x0(i) - LB(i))/(UB(i)-LB(i)) - 1; 0169 % shift by 2*pi to avoid problems at zero in fminsearch 0170 % otherwise, the initial simplex is vanishingly small 0171 x0u(k) = 2*pi+asin(max(-1,min(1,x0u(k)))); 0172 end 0173 0174 % increment k 0175 k=k+1; 0176 case 0 0177 % unconstrained variable. x0u(i) is set. 0178 x0u(k) = x0(i); 0179 0180 % increment k 0181 k=k+1; 0182 case 4 0183 % fixed variable. drop it before fminsearch sees it. 0184 % k is not incremented for this variable. 0185 end 0186 0187 end 0188 % if any of the unknowns were fixed, then we need to shorten 0189 % x0u now. 0190 if k<=n 0191 x0u(k:n) = []; 0192 end 0193 0194 % were all the variables fixed? 0195 if isempty(x0u) 0196 % All variables were fixed. quit immediately, setting the 0197 % appropriate parameters, then return. 0198 0199 % undo the variable transformations into the original space 0200 x = xtransform(x0u,params); 0201 0202 % final reshape 0203 x = reshape(x,xsize); 0204 0205 % stuff fval with the final value 0206 fval = feval(params.fun,x,params.args{:}); 0207 0208 % fminsearchbnd was not called 0209 exitflag = 0; 0210 0211 output.iterations = 0; 0212 output.funcCount = 1; 0213 output.algorithm = 'fminsearch'; 0214 output.message = 'All variables were held fixed by the applied bounds'; 0215 0216 % return with no call at all to fminsearch 0217 return 0218 end 0219 0220 % Check for an outputfcn. If there is any, then substitute my 0221 % own wrapper function. 0222 if ~isempty(options.OutputFcn) 0223 params.OutputFcn = options.OutputFcn; 0224 options.OutputFcn = @outfun_wrapper; 0225 end 0226 0227 % now we can call fminsearch, but with our own 0228 % intra-objective function. 0229 [xu,fval,exitflag,output] = fminsearch(@intrafun,x0u,options,params); 0230 0231 % undo the variable transformations into the original space 0232 x = xtransform(xu,params); 0233 0234 % final reshape to make sure the result has the proper shape 0235 x = reshape(x,xsize); 0236 0237 % Use a nested function as the OutputFcn wrapper 0238 function stop = outfun_wrapper(x,varargin); 0239 % we need to transform x first 0240 xtrans = xtransform(x,params); 0241 0242 % then call the user supplied OutputFcn 0243 stop = params.OutputFcn(xtrans,varargin{1:(end-1)}); 0244 0245 end 0246 0247 end % mainline end 0248 0249 % ====================================== 0250 % ========= begin subfunctions ========= 0251 % ====================================== 0252 function fval = intrafun(x,params) 0253 % transform variables, then call original function 0254 0255 % transform 0256 xtrans = xtransform(x,params); 0257 0258 % and call fun 0259 fval = feval(params.fun,reshape(xtrans,params.xsize),params.args{:}); 0260 0261 end % sub function intrafun end 0262 0263 % ====================================== 0264 function xtrans = xtransform(x,params) 0265 % converts unconstrained variables into their original domains 0266 0267 xtrans = zeros(params.xsize); 0268 % k allows some variables to be fixed, thus dropped from the 0269 % optimization. 0270 k=1; 0271 for i = 1:params.n 0272 switch params.BoundClass(i) 0273 case 1 0274 % lower bound only 0275 xtrans(i) = params.LB(i) + x(k).^2; 0276 0277 k=k+1; 0278 case 2 0279 % upper bound only 0280 xtrans(i) = params.UB(i) - x(k).^2; 0281 0282 k=k+1; 0283 case 3 0284 % lower and upper bounds 0285 xtrans(i) = (sin(x(k))+1)/2; 0286 xtrans(i) = xtrans(i)*(params.UB(i) - params.LB(i)) + params.LB(i); 0287 % just in case of any floating point problems 0288 xtrans(i) = max(params.LB(i),min(params.UB(i),xtrans(i))); 0289 0290 k=k+1; 0291 case 4 0292 % fixed variable, bounds are equal, set it at either bound 0293 xtrans(i) = params.LB(i); 0294 case 0 0295 % unconstrained variable. 0296 xtrans(i) = x(k); 0297 0298 k=k+1; 0299 end 0300 end 0301 0302 end % sub function xtransform end 0303 0304 0305 0306 0307