www.gusucode.com > mbcdesign 工具箱 matlab 源码程序 > mbcdesign/@conbase/bringInside.m

    function X = bringInside(con, X)
%BRINGINSIDE Move a set of points so they are all inside the constraint.
%
%  Y = BRINGINSIDE(CON, X) is the data set X but with any points outside the
%  constraint CON projected into the constraint.
%  If X(i,:) is inside the constraint, then Y(i,:) = X(i,:).
%  If X(i,:) is outside the constraint, then Y(:,i) will be the closest point to
%  X(i,:) that is inside (on the boundary of) the constraint.
%
%  If for any point X(i,:) the algorithm can not find an interior point
%  then NaN will be returned for that point. 
%
%  See also CONBASE, CONBASE/ISINSIDE, CONBASE/CONSTRAINTDISTANCE.

%  Copyright 2004-2016 The MathWorks, Inc.

% For each point x = X(i,:) we need to solve the following problem
%                                    
%              minimize   || y - x ||_2^2
%                 y
%              subject to constraintDistance( CON, y ) <= 0
%
% Because we have a nice simple objective function, if CON is a linear
% constraint then we can use LSQLIN. However if CON is non-linear then we must
% use FMINCON as this is the only routine that supports non-lienar constraints.
%
% Note that X(i,:) defines the _objective_ for each iteration. There for the
% optimization functions that we set-up take in this point. We also use this
% point as the start point, x0, for each optimization.
%
% The constraint object, CON, defines the constraint for the optimizations and
% therefore this is fixed over all iterations.
%
% The choice of norm is a scaled 2-norm. The norm is scaled to reflect the
% ranges of the input variables so that the norm along any edge of bounding
% box is constant.
%         || y - x ||_s^2 = || S * (y - x) ||_2^2
% where S = diag( 1./(cif.Max - cif.Min ) )


% Number of points
NP = size( X, 1 );

if islinear( con )
    optimFun = i_makeLinearOptimFun( con );
else
    optimFun = i_makeNonlinearOptimFun( con );
end

% Only process points that are outside the constraint
in = isInside( con, X, true( 1, NP ) );
for i = find( ~in )
    X(i,:) = optimFun( X(i,:) );
end

end 

function S = i_objectiveScaleFactor( con )
cif = getInputFactors( con );
S = diag( 1./(cif.Max - cif.Min ) );
end 

function optimFun = i_makeLinearOptimFun( con )
% Setup for the linear optimization routine

% Optimization options
options = i_lsqlinOptions();

% Constraint
[A, b] = getLinearForm( con );

% Set-up for objective function
S = i_objectiveScaleFactor( con );

% Optimization function
optimFun = @n_lsqlin;
    function y = n_lsqlin( x )
        % If symmetry makes you happy, imagine we have defined 
        % >> objective = @( y ) ||(y - x)*S||_2^2;
        % and then used this in place of the first two arguments to LSQLIN

        % [x, norm, resd, flag]=LSQLIN( C, d,   A, b, Aeq, beq, lb, ub, x0, options )
        [y,   ~,    ~,  flag] = lsqlin( S, x*S, A, b, [],  [],  [], [], x,  options );
        if flag <= 0
            % Falied to converge
            y = NaN( size( y ) );
        end
    end
end 

function optimFun = i_makeNonlinearOptimFun( con )
% Setup for the non-linear optimization routine
%
% We need to use the same objective function but we have non-linear
% constraints. Therefore we need to use fmincon

% Optimization options
options = i_fminconOptions();

% Constraint
    function [c, ceq] = n_constraint( y )
        c = constraintDistance( con, y );
        ceq = [];
    end

% Optimization function
S = i_objectiveScaleFactor( con );
optimFun = @n_fmincon;
    function y = n_fmincon( x )
        objective = @( y ) sum( ((y - x)*S).^2, 2 );

        % [x, fval, flag]=fmincon( fun,       x0, A,  b,  Aeq, beq, lb, ub, nonlcon,       options )
        [y, ~,    flag] = fmincon( objective, x,  [], [], [],  [],  [], [], @( y )n_constraint( y ), options );
        if flag <= 0
            % Falied to converge
            y = NaN( size( y ) );
        end
    end
end 

function options = i_fminconOptions()
options = i_optimset( 'fmincon', ...
    'Display', 'none', ...
    'Algorithm', 'interior-point' );
end 

function options = i_lsqlinOptions()
options = i_optimset( 'lsqlin', ...
    'Display', 'none', ...
    'Algorithm', 'interior-point' );
end 

function options = i_optimset( optimFunction, varargin )
options = optimset( optimFunction );
options = optimset( options, varargin{:} );
end