LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
fminsearchcon.m
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,...)
11%
12% arguments:
13% fun, x0, options - see the help for FMINSEARCH
14%
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
19% be returned.
20%
21% LB - lower bound vector or array, must be the same size as x0
22%
23% If no lower bounds exist for one of the variables, then
24% supply -inf for that variable.
25%
26% If no lower bounds at all, then LB may be left empty.
27%
28% Variables may be fixed in value by setting the corresponding
29% lower and upper bounds to exactly the same value.
30%
31% UB - upper bound vector or array, must be the same size as x0
32%
33% If no upper bounds exist for one of the variables, then
34% supply +inf for that variable.
35%
36% If no upper bounds at all, then UB may be left empty.
37%
38% Variables may be fixed in value by setting the corresponding
39% lower and upper bounds to exactly the same value.
40%
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.)
44%
45% A*x <= b
46%
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.
50%
51% nonlcon(x) <= 0
52%
53%
54% Notes:
55%
56% If options is supplied, then TolX will apply to the transformed
57% variables. All other FMINSEARCH parameters should be unaffected.
58%
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.
63%
64% Variables may be fixed by setting their respective bounds equal.
65% In this case, the problem will be reduced in size for FMINSEARCH.
66%
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
70% followed.
71%
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.
78%
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.
83%
84%
85% Example usage:
86% rosen = @(x) (1-x(1)).^2 + 105*(x(2)-x(1).^2).^2;
87%
88% Fully unconstrained problem
89% fminsearchcon(rosen,[3 3])
90% ans =
91% 1.0000 1.0000
92%
93% lower bound constrained
94% fminsearchcon(rosen,[3 3],[2 2],[])
95% ans =
96% 2.0000 4.0000
97%
98% x(2) fixed at 3
99% fminsearchcon(rosen,[3 3],[-inf 3],[inf,3])
100% ans =
101% 1.7314 3.0000
102%
103% simple linear inequality: x(1) + x(2) <= 1
104% fminsearchcon(rosen,[0 0],[],[],[1 1],.5)
105%
106% ans =
107% 0.6187 0.3813
108%
109% general nonlinear inequality: sqrt(x(1)^2 + x(2)^2) <= 1
110% fminsearchcon(rosen,[0 0],[],[],[],[],@(x) norm(x)-1)
111% ans =
112% 0.78633 0.61778
113%
114% Of course, any combination of the above constraints is
115% also possible.
116%
117% See test_main.m for other examples of use.
118%
119%
120% See also: fminsearch, fminspleas, fminsearchbnd
121%
122%
123% Author: John D'Errico
124% E-mail: woodchips@rochester.rr.com
125% Release: 1.0
126% Release date: 12/16/06
127
128% size checks
129xsize = size(x0);
130x0 = x0(:);
131n=length(x0);
132
133if (nargin<3) || isempty(LB)
134 LB = repmat(-inf,n,1);
135else
136 LB = LB(:);
137end
138if (nargin<4) || isempty(UB)
139 UB = repmat(inf,n,1);
140else
141 UB = UB(:);
142end
143
144if (n~=length(LB)) || (n~=length(UB))
145 error 'x0 is incompatible in size with either LB or UB.'
146end
147
148% defaults for A,b
149if (nargin<5) || isempty(A)
150 A = [];
151end
152if (nargin<6) || isempty(b)
153 b = [];
154end
155nA = [];
156nb = [];
157if (isempty(A)&&~isempty(b)) || (isempty(b)&&~isempty(A))
158 error 'Sizes of A and b are incompatible'
159elseif ~isempty(A)
160 nA = size(A);
161 b = b(:);
162 nb = size(b,1);
163 if nA(1)~=nb
164 error 'Sizes of A and b are incompatible'
165 end
166 if nA(2)~=n
167 error 'A is incompatible in size with x0'
168 end
169end
170
171% defaults for nonlcon
172if (nargin<7) || isempty(nonlcon)
173 nonlcon = [];
174end
175
176% test for feasibility of the initial value
177% against any general inequality constraints
178if ~isempty(A)
179 if any(A*x0>b)
180 error 'Infeasible starting values (linear inequalities failed).'
181 end
182end
183if ~isempty(nonlcon)
184 if any(feval(nonlcon,(reshape(x0,xsize)),varargin{:})>0)
185 error 'Infeasible starting values (nonlinear inequalities failed).'
186 end
187end
188
189% set default options if necessary
190if (nargin<8) || isempty(options)
191 options = optimset('fminsearch');
192end
193
194% stuff into a struct to pass around
195params.args = varargin;
196params.LB = LB;
197params.UB = UB;
198params.fun = fun;
199params.n = n;
200params.xsize = xsize;
201
202params.OutputFcn = [];
203
204params.A = A;
205params.b = b;
206params.nonlcon = nonlcon;
207
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);
214for i=1:n
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;
219 end
220end
221
222% transform starting values into their unconstrained
223% surrogates. Check for infeasible starting guesses.
224x0u = x0;
225k=1;
226for i = 1:n
227 switch params.BoundClass(i)
228 case 1
229 % lower bound only
230 if x0(i)<=LB(i)
231 % infeasible starting value. Use bound.
232 x0u(k) = 0;
233 else
234 x0u(k) = sqrt(x0(i) - LB(i));
235 end
236
237 % increment k
238 k=k+1;
239 case 2
240 % upper bound only
241 if x0(i)>=UB(i)
242 % infeasible starting value. use bound.
243 x0u(k) = 0;
244 else
245 x0u(k) = sqrt(UB(i) - x0(i));
246 end
247
248 % increment k
249 k=k+1;
250 case 3
251 % lower and upper bounds
252 if x0(i)<=LB(i)
253 % infeasible starting value
254 x0u(k) = -pi/2;
255 elseif x0(i)>=UB(i)
256 % infeasible starting value
257 x0u(k) = pi/2;
258 else
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))));
263 end
264
265 % increment k
266 k=k+1;
267 case 0
268 % unconstrained variable. x0u(i) is set.
269 x0u(k) = x0(i);
270
271 % increment k
272 k=k+1;
273 case 4
274 % fixed variable. drop it before fminsearch sees it.
275 % k is not incremented for this variable.
276 end
277
278end
279% if any of the unknowns were fixed, then we need to shorten
280% x0u now.
281if k<=n
282 x0u(k:n) = [];
283end
284
285% were all the variables fixed?
286if isempty(x0u)
287 % All variables were fixed. quit immediately, setting the
288 % appropriate parameters, then return.
289
290 % undo the variable transformations into the original space
291 x = xtransform(x0u,params);
292
293 % final reshape
294 x = reshape(x,xsize);
295
296 % stuff fval with the final value
297 fval = feval(params.fun,x,params.args{:});
298
299 % fminsearchbnd was not called
300 exitflag = 0;
301
302 output.iterations = 0;
303 output.funcCount = 1;
304 output.algorithm = 'fminsearch';
305 output.message = 'All variables were held fixed by the applied bounds';
306
307 % return with no call at all to fminsearch
308 return
309end
310
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;
316end
317
318% now we can call fminsearch, but with our own
319% intra-objective function.
320[xu,fval,exitflag,output] = fminsearch(@intrafun,x0u,options,params);
321
322% undo the variable transformations into the original space
323x = xtransform(xu,params);
324
325% final reshape
326x = reshape(x,xsize);
327
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);
332
333 % then call the user supplied OutputFcn
334 stop = params.OutputFcn(xtrans,varargin{1:(end-1)});
335
336 end
337
338end % mainline end
339
340% ======================================
341% ========= begin subfunctions =========
342% ======================================
343function fval = intrafun(x,params)
344% transform variables, test constraints, then call original function
345
346% transform
347xtrans = xtransform(x,params);
348
349% test constraints before the function call
350
351% First, do the linear inequality constraints, if any
352if ~isempty(params.A)
353 % Required: A*xtrans <= b
354 if any(params.A*xtrans(:) > params.b)
355 % linear inequality constraints failed. Just return inf.
356 fval = inf;
357 return
358 end
359end
360
361% resize xtrans to be the correct size for the nonlcon
362% and objective function calls
363xtrans = reshape(xtrans,params.xsize);
364
365% Next, do the nonlinear inequality constraints
366if ~isempty(params.nonlcon)
367 % Required: nonlcon(xtrans) <= 0
368 cons = feval(params.nonlcon,xtrans,params.args{:});
369 if any(cons(:) > 0)
370 % nonlinear inequality constraints failed. Just return inf.
371 fval = inf;
372 return
373 end
374end
375
376% we survived the general inequality constraints. Only now
377% do we evaluate the objective function.
378
379% append any additional parameters to the argument list
380fval = feval(params.fun,xtrans,params.args{:});
381
382end % sub function intrafun end
383
384% ======================================
385function xtrans = xtransform(x,params)
386% converts unconstrained variables into their original domains
387
388xtrans = zeros(1,params.n);
389% k allows some variables to be fixed, thus dropped from the
390% optimization.
391k=1;
392for i = 1:params.n
393 switch params.BoundClass(i)
394 case 1
395 % lower bound only
396 xtrans(i) = params.LB(i) + x(k).^2;
397
398 k=k+1;
399 case 2
400 % upper bound only
401 xtrans(i) = params.UB(i) - x(k).^2;
402
403 k=k+1;
404 case 3
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)));
410
411 k=k+1;
412 case 4
413 % fixed variable, bounds are equal, set it at either bound
414 xtrans(i) = params.LB(i);
415 case 0
416 % unconstrained variable.
417 xtrans(i) = x(k);
418
419 k=k+1;
420 end
421end
422
423end % sub function xtransform end
424
425
426
427
428