fminsearchcon

PURPOSE ^

FMINSEARCHCON: Extension of FMINSEARCHBND with general inequality constraints

SYNOPSIS ^

function [x,fval,exitflag,output]=fminsearchcon(fun,x0,LB,UB,A,b,nonlcon,options,varargin)

DESCRIPTION ^

 FMINSEARCHCON: Extension of FMINSEARCHBND with general inequality constraints
 usage: x=FMINSEARCHCON(fun,x0)
 usage: x=FMINSEARCHCON(fun,x0,LB)
 usage: x=FMINSEARCHCON(fun,x0,LB,UB)
 usage: x=FMINSEARCHCON(fun,x0,LB,UB,A,b)
 usage: x=FMINSEARCHCON(fun,x0,LB,UB,A,b,nonlcon)
 usage: x=FMINSEARCHCON(fun,x0,LB,UB,A,b,nonlcon,options)
 usage: x=FMINSEARCHCON(fun,x0,LB,UB,A,b,nonlcon,options,p1,p2,...)
 usage: [x,fval,exitflag,output]=FMINSEARCHCON(fun,x0,...)
 
 arguments:
  fun, x0, options - see the help for FMINSEARCH

       x0 MUST be a feasible point for the linear and nonlinear
       inequality constraints. If it is not inside the bounds
       then it will be moved to the nearest bound. If x0 is
       infeasible for the general constraints, then an error will
       be returned.

  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.

  A,b - (OPTIONAL) Linear inequality constraint array and right
       hand side vector. (Note: these constraints were chosen to
       be consistent with those of fmincon.)

       A*x <= b

  nonlcon - (OPTIONAL) general nonlinear inequality constraints
       NONLCON must return a set of general inequality constraints.
       These will be enforced such that nonlcon is always <= 0.

       nonlcon(x) <= 0


 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 FMINSEARCHCON may
  try to evaluate the function exactly at zero.

  Inequality constraints are enforced with an implicit penalty
  function approach. But the constraints are tested before
  any function evaluations are ever done, so the actual objective
  function is NEVER evaluated outside of the feasible region.


 Example usage:
 rosen = @(x) (1-x(1)).^2 + 105*(x(2)-x(1).^2).^2;

 Fully unconstrained problem
 fminsearchcon(rosen,[3 3])
 ans =
    1.0000    1.0000

 lower bound constrained
 fminsearchcon(rosen,[3 3],[2 2],[])
 ans =
    2.0000    4.0000

 x(2) fixed at 3
 fminsearchcon(rosen,[3 3],[-inf 3],[inf,3])
 ans =
    1.7314    3.0000

 simple linear inequality: x(1) + x(2) <= 1
 fminsearchcon(rosen,[0 0],[],[],[1 1],.5)
 
 ans =
    0.6187    0.3813
 
 general nonlinear inequality: sqrt(x(1)^2 + x(2)^2) <= 1
 fminsearchcon(rosen,[0 0],[],[],[],[],@(x) norm(x)-1)
 ans =
    0.78633   0.61778

 Of course, any combination of the above constraints is
 also possible.

 See test_main.m for other examples of use.


 See also: fminsearch, fminspleas, fminsearchbnd


 Author: John D'Errico
 E-mail: woodchips@rochester.rr.com
 Release: 1.0
 Release date: 12/16/06

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SUBFUNCTIONS ^

SOURCE CODE ^

0001 function [x,fval,exitflag,output]=fminsearchcon(fun,x0,LB,UB,A,b,nonlcon,options,varargin)
0002 % FMINSEARCHCON: Extension of FMINSEARCHBND with general inequality constraints
0003 % usage: x=FMINSEARCHCON(fun,x0)
0004 % usage: x=FMINSEARCHCON(fun,x0,LB)
0005 % usage: x=FMINSEARCHCON(fun,x0,LB,UB)
0006 % usage: x=FMINSEARCHCON(fun,x0,LB,UB,A,b)
0007 % usage: x=FMINSEARCHCON(fun,x0,LB,UB,A,b,nonlcon)
0008 % usage: x=FMINSEARCHCON(fun,x0,LB,UB,A,b,nonlcon,options)
0009 % usage: x=FMINSEARCHCON(fun,x0,LB,UB,A,b,nonlcon,options,p1,p2,...)
0010 % usage: [x,fval,exitflag,output]=FMINSEARCHCON(fun,x0,...)
0011 %
0012 % arguments:
0013 %  fun, x0, options - see the help for FMINSEARCH
0014 %
0015 %       x0 MUST be a feasible point for the linear and nonlinear
0016 %       inequality constraints. If it is not inside the bounds
0017 %       then it will be moved to the nearest bound. If x0 is
0018 %       infeasible for the general constraints, then an error will
0019 %       be returned.
0020 %
0021 %  LB - lower bound vector or array, must be the same size as x0
0022 %
0023 %       If no lower bounds exist for one of the variables, then
0024 %       supply -inf for that variable.
0025 %
0026 %       If no lower bounds at all, then LB may be left empty.
0027 %
0028 %       Variables may be fixed in value by setting the corresponding
0029 %       lower and upper bounds to exactly the same value.
0030 %
0031 %  UB - upper bound vector or array, must be the same size as x0
0032 %
0033 %       If no upper bounds exist for one of the variables, then
0034 %       supply +inf for that variable.
0035 %
0036 %       If no upper bounds at all, then UB may be left empty.
0037 %
0038 %       Variables may be fixed in value by setting the corresponding
0039 %       lower and upper bounds to exactly the same value.
0040 %
0041 %  A,b - (OPTIONAL) Linear inequality constraint array and right
0042 %       hand side vector. (Note: these constraints were chosen to
0043 %       be consistent with those of fmincon.)
0044 %
0045 %       A*x <= b
0046 %
0047 %  nonlcon - (OPTIONAL) general nonlinear inequality constraints
0048 %       NONLCON must return a set of general inequality constraints.
0049 %       These will be enforced such that nonlcon is always <= 0.
0050 %
0051 %       nonlcon(x) <= 0
0052 %
0053 %
0054 % Notes:
0055 %
0056 %  If options is supplied, then TolX will apply to the transformed
0057 %  variables. All other FMINSEARCH parameters should be unaffected.
0058 %
0059 %  Variables which are constrained by both a lower and an upper
0060 %  bound will use a sin transformation. Those constrained by
0061 %  only a lower or an upper bound will use a quadratic
0062 %  transformation, and unconstrained variables will be left alone.
0063 %
0064 %  Variables may be fixed by setting their respective bounds equal.
0065 %  In this case, the problem will be reduced in size for FMINSEARCH.
0066 %
0067 %  The bounds are inclusive inequalities, which admit the
0068 %  boundary values themselves, but will not permit ANY function
0069 %  evaluations outside the bounds. These constraints are strictly
0070 %  followed.
0071 %
0072 %  If your problem has an EXCLUSIVE (strict) constraint which will
0073 %  not admit evaluation at the bound itself, then you must provide
0074 %  a slightly offset bound. An example of this is a function which
0075 %  contains the log of one of its parameters. If you constrain the
0076 %  variable to have a lower bound of zero, then FMINSEARCHCON may
0077 %  try to evaluate the function exactly at zero.
0078 %
0079 %  Inequality constraints are enforced with an implicit penalty
0080 %  function approach. But the constraints are tested before
0081 %  any function evaluations are ever done, so the actual objective
0082 %  function is NEVER evaluated outside of the feasible region.
0083 %
0084 %
0085 % Example usage:
0086 % rosen = @(x) (1-x(1)).^2 + 105*(x(2)-x(1).^2).^2;
0087 %
0088 % Fully unconstrained problem
0089 % fminsearchcon(rosen,[3 3])
0090 % ans =
0091 %    1.0000    1.0000
0092 %
0093 % lower bound constrained
0094 % fminsearchcon(rosen,[3 3],[2 2],[])
0095 % ans =
0096 %    2.0000    4.0000
0097 %
0098 % x(2) fixed at 3
0099 % fminsearchcon(rosen,[3 3],[-inf 3],[inf,3])
0100 % ans =
0101 %    1.7314    3.0000
0102 %
0103 % simple linear inequality: x(1) + x(2) <= 1
0104 % fminsearchcon(rosen,[0 0],[],[],[1 1],.5)
0105 %
0106 % ans =
0107 %    0.6187    0.3813
0108 %
0109 % general nonlinear inequality: sqrt(x(1)^2 + x(2)^2) <= 1
0110 % fminsearchcon(rosen,[0 0],[],[],[],[],@(x) norm(x)-1)
0111 % ans =
0112 %    0.78633   0.61778
0113 %
0114 % Of course, any combination of the above constraints is
0115 % also possible.
0116 %
0117 % See test_main.m for other examples of use.
0118 %
0119 %
0120 % See also: fminsearch, fminspleas, fminsearchbnd
0121 %
0122 %
0123 % Author: John D'Errico
0124 % E-mail: woodchips@rochester.rr.com
0125 % Release: 1.0
0126 % Release date: 12/16/06
0127 
0128 % size checks
0129 xsize = size(x0);
0130 x0 = x0(:);
0131 n=length(x0);
0132 
0133 if (nargin<3) || isempty(LB)
0134   LB = repmat(-inf,n,1);
0135 else
0136   LB = LB(:);
0137 end
0138 if (nargin<4) || isempty(UB)
0139   UB = repmat(inf,n,1);
0140 else
0141   UB = UB(:);
0142 end
0143 
0144 if (n~=length(LB)) || (n~=length(UB))
0145   error 'x0 is incompatible in size with either LB or UB.'
0146 end
0147 
0148 % defaults for A,b
0149 if (nargin<5) || isempty(A)
0150   A = [];
0151 end
0152 if (nargin<6) || isempty(b)
0153   b = [];
0154 end
0155 nA = [];
0156 nb = [];
0157 if (isempty(A)&&~isempty(b)) || (isempty(b)&&~isempty(A)) 
0158   error 'Sizes of A and b are incompatible'
0159 elseif ~isempty(A)
0160   nA = size(A);
0161   b = b(:);
0162   nb = size(b,1);
0163   if nA(1)~=nb  
0164     error 'Sizes of A and b are incompatible'
0165   end
0166   if nA(2)~=n
0167     error 'A is incompatible in size with x0'
0168   end
0169 end
0170 
0171 % defaults for nonlcon
0172 if (nargin<7) || isempty(nonlcon)
0173   nonlcon = [];
0174 end
0175 
0176 % test for feasibility of the initial value
0177 % against any general inequality constraints
0178 if ~isempty(A)
0179   if any(A*x0>b)
0180     error 'Infeasible starting values (linear inequalities failed).'
0181   end
0182 end
0183 if ~isempty(nonlcon)
0184   if any(feval(nonlcon,(reshape(x0,xsize)),varargin{:})>0)
0185     error 'Infeasible starting values (nonlinear inequalities failed).'
0186   end
0187 end
0188 
0189 % set default options if necessary
0190 if (nargin<8) || isempty(options)
0191   options = optimset('fminsearch');
0192 end
0193 
0194 % stuff into a struct to pass around
0195 params.args = varargin;
0196 params.LB = LB;
0197 params.UB = UB;
0198 params.fun = fun;
0199 params.n = n;
0200 params.xsize = xsize;
0201 
0202 params.OutputFcn = [];
0203 
0204 params.A = A;
0205 params.b = b;
0206 params.nonlcon = nonlcon;
0207 
0208 % 0 --> unconstrained variable
0209 % 1 --> lower bound only
0210 % 2 --> upper bound only
0211 % 3 --> dual finite bounds
0212 % 4 --> fixed variable
0213 params.BoundClass = zeros(n,1);
0214 for i=1:n
0215   k = isfinite(LB(i)) + 2*isfinite(UB(i));
0216   params.BoundClass(i) = k;
0217   if (k==3) && (LB(i)==UB(i))
0218     params.BoundClass(i) = 4;
0219   end
0220 end
0221 
0222 % transform starting values into their unconstrained
0223 % surrogates. Check for infeasible starting guesses.
0224 x0u = x0;
0225 k=1;
0226 for i = 1:n
0227   switch params.BoundClass(i)
0228     case 1
0229       % lower bound only
0230       if x0(i)<=LB(i)
0231         % infeasible starting value. Use bound.
0232         x0u(k) = 0;
0233       else
0234         x0u(k) = sqrt(x0(i) - LB(i));
0235       end
0236       
0237       % increment k
0238       k=k+1;
0239     case 2
0240       % upper bound only
0241       if x0(i)>=UB(i)
0242         % infeasible starting value. use bound.
0243         x0u(k) = 0;
0244       else
0245         x0u(k) = sqrt(UB(i) - x0(i));
0246       end
0247       
0248       % increment k
0249       k=k+1;
0250     case 3
0251       % lower and upper bounds
0252       if x0(i)<=LB(i)
0253         % infeasible starting value
0254         x0u(k) = -pi/2;
0255       elseif x0(i)>=UB(i)
0256         % infeasible starting value
0257         x0u(k) = pi/2;
0258       else
0259         x0u(k) = 2*(x0(i) - LB(i))/(UB(i)-LB(i)) - 1;
0260         % shift by 2*pi to avoid problems at zero in fminsearch
0261         % otherwise, the initial simplex is vanishingly small
0262         x0u(k) = 2*pi+asin(max(-1,min(1,x0u(k))));
0263       end
0264       
0265       % increment k
0266       k=k+1;
0267     case 0
0268       % unconstrained variable. x0u(i) is set.
0269       x0u(k) = x0(i);
0270       
0271       % increment k
0272       k=k+1;
0273     case 4
0274       % fixed variable. drop it before fminsearch sees it.
0275       % k is not incremented for this variable.
0276   end
0277   
0278 end
0279 % if any of the unknowns were fixed, then we need to shorten
0280 % x0u now.
0281 if k<=n
0282   x0u(k:n) = [];
0283 end
0284 
0285 % were all the variables fixed?
0286 if isempty(x0u)
0287   % All variables were fixed. quit immediately, setting the
0288   % appropriate parameters, then return.
0289   
0290   % undo the variable transformations into the original space
0291   x = xtransform(x0u,params);
0292   
0293   % final reshape
0294   x = reshape(x,xsize);
0295   
0296   % stuff fval with the final value
0297   fval = feval(params.fun,x,params.args{:});
0298   
0299   % fminsearchbnd was not called
0300   exitflag = 0;
0301   
0302   output.iterations = 0;
0303   output.funcCount = 1;
0304   output.algorithm = 'fminsearch';
0305   output.message = 'All variables were held fixed by the applied bounds';
0306   
0307   % return with no call at all to fminsearch
0308   return
0309 end
0310 
0311 % Check for an outputfcn. If there is any, then substitute my
0312 % own wrapper function.
0313 if ~isempty(options.OutputFcn)
0314   params.OutputFcn = options.OutputFcn;
0315   options.OutputFcn = @outfun_wrapper;
0316 end
0317 
0318 % now we can call fminsearch, but with our own
0319 % intra-objective function.
0320 [xu,fval,exitflag,output] = fminsearch(@intrafun,x0u,options,params);
0321 
0322 % undo the variable transformations into the original space
0323 x = xtransform(xu,params);
0324 
0325 % final reshape
0326 x = reshape(x,xsize);
0327 
0328 % Use a nested function as the OutputFcn wrapper
0329   function stop = outfun_wrapper(x,varargin);
0330     % we need to transform x first
0331     xtrans = xtransform(x,params);
0332     
0333     % then call the user supplied OutputFcn
0334     stop = params.OutputFcn(xtrans,varargin{1:(end-1)});
0335     
0336   end
0337 
0338 end % mainline end
0339 
0340 % ======================================
0341 % ========= begin subfunctions =========
0342 % ======================================
0343 function fval = intrafun(x,params)
0344 % transform variables, test constraints, then call original function
0345 
0346 % transform
0347 xtrans = xtransform(x,params);
0348 
0349 % test constraints before the function call
0350 
0351 % First, do the linear inequality constraints, if any
0352 if ~isempty(params.A)
0353   % Required: A*xtrans <= b
0354   if any(params.A*xtrans(:) > params.b)
0355     % linear inequality constraints failed. Just return inf.
0356     fval = inf;
0357     return
0358   end
0359 end
0360 
0361 % resize xtrans to be the correct size for the nonlcon
0362 % and objective function calls
0363 xtrans = reshape(xtrans,params.xsize);
0364 
0365 % Next, do the nonlinear inequality constraints
0366 if ~isempty(params.nonlcon)
0367   % Required: nonlcon(xtrans) <= 0
0368   cons = feval(params.nonlcon,xtrans,params.args{:});
0369   if any(cons(:) > 0)
0370     % nonlinear inequality constraints failed. Just return inf.
0371     fval = inf;
0372     return
0373   end
0374 end
0375 
0376 % we survived the general inequality constraints. Only now
0377 % do we evaluate the objective function.
0378 
0379 % append any additional parameters to the argument list
0380 fval = feval(params.fun,xtrans,params.args{:});
0381 
0382 end % sub function intrafun end
0383 
0384 % ======================================
0385 function xtrans = xtransform(x,params)
0386 % converts unconstrained variables into their original domains
0387 
0388 xtrans = zeros(1,params.n);
0389 % k allows some variables to be fixed, thus dropped from the
0390 % optimization.
0391 k=1;
0392 for i = 1:params.n
0393   switch params.BoundClass(i)
0394     case 1
0395       % lower bound only
0396       xtrans(i) = params.LB(i) + x(k).^2;
0397       
0398       k=k+1;
0399     case 2
0400       % upper bound only
0401       xtrans(i) = params.UB(i) - x(k).^2;
0402       
0403       k=k+1;
0404     case 3
0405       % lower and upper bounds
0406       xtrans(i) = (sin(x(k))+1)/2;
0407       xtrans(i) = xtrans(i)*(params.UB(i) - params.LB(i)) + params.LB(i);
0408       % just in case of any floating point problems
0409       xtrans(i) = max(params.LB(i),min(params.UB(i),xtrans(i)));
0410       
0411       k=k+1;
0412     case 4
0413       % fixed variable, bounds are equal, set it at either bound
0414       xtrans(i) = params.LB(i);
0415     case 0
0416       % unconstrained variable.
0417       xtrans(i) = x(k);
0418       
0419       k=k+1;
0420   end
0421 end
0422 
0423 end % sub function xtransform end
0424 
0425 
0426 
0427 
0428

Generated on Thu 10-Dec-2020 17:34:27 by m2html © 2005