No BSD License  

Highlights from
EliminateConstraints

from EliminateConstraints by Andrew Jackson
Eliminates variables from a problem with linear equality constraints to give an unconstrained proble

[C,d]=eliminateConstraints(A,b)
function [C,d]=eliminateConstraints(A,b)
% function [C,d]=eliminateConstraints(A,b) eliminates variables from
% problem with linear equality constraints to give an unconstrained
% problem. This is useful e.g. when solving a problem with linear
% constraints and a nonlinear objective or further nonlinear constraints;
% eliminating the linear constraints makes the problem easier.
%
% Where the original constrained problem has:
% - variable vector x (length n).
% - linear constraint A*x=b, where the matrix A and vector b are
%     eliminateConstraints's arguments.
% 
% And the final unconstrained problem has:
% - variable vector y (length p).
% - an x satisfying the original constraint can be generated by x=C*y+d,
%     where the matrix C and vector d are returned by eliminateConstraints.
% 
% Inputs:
% - A (an m*n matrix of real numbers)
% - b (a  m*1 vector of real numbers)
%
% - C (an n*p matrix of real numbers)
% - d (a  n*1 vector of real numbers)
%
% Hopefully, p<n, so the unconstrained problem is smaller than the
% constrained problem.
%
% The functionality provided by eliminateConstraints is trivial for small
% matricies.  For larger matrices, it can be done using MATLAB's various
% matrix decompositions.  However, as far as the author is aware, there is
% no trivial MATLAB solution for the case where A is very large and sparse,
% so we require a C which is also sparse without using any very large full
% matrices.
%
% The case for which this was developed automatically creates a
% well-defined problem, so only minimal validation and error checking has
% been implemented at this stage.

%% validate input
if nargin~=2
    error('Must specify A & b')
end
if size(A,1)~=size(b,1)
    error('A & b must have the same number of rows')
end

%% set up
if issparse(A)
    C=sparse(1:size(A,2),1:size(A,2),1,size(A,2),size(A,2));
else
    C=eye(size(A,2));
end
if issparse(b)
    d=sparse(size(A,2),1);
else
    d=zeros(size(A,2),1);
end

independent=true(size(A,2),1);

curA=A;
curb=b;

%% process
for curRow=1:size(A,1)
    newDependent=find(curA(curRow,:) & independent');
    if isempty(newDependent)
        %check that this row is consistent with the others
        if nnz(curA(curRow,:)*C)~=0 || curA(curRow,:)*d~=curb(curRow)
            error(['Row ',num2str(curRow),' is inconsistent with some previous row; perhaps the problem was ill-defined?'])
        end
    else
        [temp,I]=max(curA(curRow,newDependent));
        newDependent=newDependent(I);
        %create a new dependent variable
        newC=-curA(curRow,:)/curA(curRow,newDependent);
        newC(newDependent)=0;
        newd=curb(curRow)/curA(curRow,newDependent);
        
        d=d+C(:,newDependent)*newd;
        C1=C;
        C1(:,newDependent)=0;
        C=C1+C(:,newDependent)*newC;
        
        curb=curb-curA(:,newDependent)*newd;
        A1=curA;
        A1(:,newDependent)=0;
        curA=A1+curA(:,newDependent)*newC;
        
        independent(newDependent)=false;
    end
end
C=C(:,independent);

%% check
if max(max(A*C))>1e-6 || min(min(A*C))<-1e-6
    error('The output is not valid (A*C~=0).  Perhaps the original problem was ill-defined?')
end
if max(A*d-b)>1e-6 || min(A*d-b)<-1e-6
    error('The output is not valid (A*d~=b).  Perhaps the original problem was ill-defined?')
end

Contact us at files@mathworks.com