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 Downloaded at: http://math.nyu.edu/~atm262/files/takeover/fminsearchbnd.m
0001 function [x,fval,exitflag,output]=fminsearchbnd3(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 % Downloaded at: http://math.nyu.edu/~atm262/files/takeover/fminsearchbnd.m 0081 % 0082 % 0083 0084 % size checks 0085 xsize = size(x0); 0086 x0 = x0(:); 0087 n=length(x0); 0088 0089 if (nargin<3) || isempty(LB) 0090 LB = repmat(-inf,n,1); 0091 else 0092 LB = LB(:); 0093 end 0094 if (nargin<4) || isempty(UB) 0095 UB = repmat(inf,n,1); 0096 else 0097 UB = UB(:); 0098 end 0099 0100 if (n~=length(LB)) || (n~=length(UB)) 0101 error 'x0 is incompatible in size with either LB or UB.' 0102 end 0103 0104 % set default options if necessary 0105 if (nargin<5) || isempty(options) 0106 options = optimset('fminsearch'); 0107 end 0108 0109 % stuff into a struct to pass around 0110 params.args = varargin; 0111 params.LB = LB; 0112 params.UB = UB; 0113 params.fun = fun; 0114 params.n = n; 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.funcount = 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 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,xtrans,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(1,params.n); 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