Matlab二阶段单纯形法

Matlab二阶段单纯形法

  1. dcxsf.m
  2. secP.m
  3. .m(test)

dcxsf.m

% 第一阶段函数

function [X,zR] = dcxsf(A,b,cOut,outMin,cSec,secMin)
format rat  %数据以分数形式输出

%如果是求min,需要化为max = -min,此处是把系数求负,
%后续还有一步是,求出zR后,再给他求负

if outMin == 1   
    cOut = -cOut;
end
% my ny 分别为目标函数系数矩阵的行和列,此题my = 1, mn = 6;
[my ny]=size(cOut);

Ay = [];  % 存储人工变量所在列的索引,即人工变量在第几列
AyR = []; % 存储非人工变量所在列的索引
yIndex = 0;
yRIndex = 0;

%分别找出人工变量和非人工变量,然后分别存入Ay 和 AyR里
for j = 1:ny
    if cOut(j)~=0
        yIndex = yIndex + 1;
        Ay(yIndex) = j;
    else
        yRIndex = yRIndex + 1;
        AyR(yRIndex) = j;
    end
end

% my ny 分别为约束系数矩阵的行和列,此题mOutSize = 3, nOutSize = 6;
[mOutSize,nOutSize]=size(A);

% AmOut 存储基变量的索引,比如基变量之一为x3,则把3存入AmOut,用于记录那些变量是基变量
% Am1Out  存储非基变量的索引,比如非基变量之一为x4,则把4存入Am1Out,用于记录那些变量是非基变量
AmOut = zeros(mOutSize,1);
Am1Out = zeros(1,nOutSize - mOutSize);

%       x1 x2 x3 x4 x5 x6
%        1 2  1  1  0  0
%        1 2  3  0  1  0
%        2 1  5  0  0  1
%   其中x4 x5 x6 为基变量,把基变量对应索引(第几列)存入AmOut,非基变量索引存入Am1Out
%   接下来这个for就是做这个工作的

iAm1Out = 0;
%   依次遍历每列
for jj = 1:nOutSize  %jj 列数
    flag1 = 0;
    
    %   对这一列遍历行,检测是否有1,
    for ii = 1:mOutSize  %  ii 行数
        if A(ii,jj)==1 
          flag1 = ii;
        end
    end
    
    %   没有1的话则说明这列不可能是基变量所在的列,把索引(第几列)存入Am1Out中
    if flag1 == 0  %没有1
        iAm1Out = iAm1Out + 1;
        Am1Out(iAm1Out) = jj;
        continue;   %   如果能到此步,说明这一行的检测完毕,为非基变量所在的列,continue出去进行下一行的检测
    end
    
    %   再检测这一列的其他元素是不是都是0,是0则说明这一列是基变量在的列,把索引(第几列)存入AmOut
    %   如果有不是0的元素,则说明这列是非基变量在的列,把索引存入Am1Out中
    continueAll = 0;
    for ii = 1:mOutSize  %jj 行数
        if ii == flag1
            continue;
        end
        if A(ii,jj)~=0
            iAm1Out = iAm1Out + 1;
            Am1Out(iAm1Out) = jj;
            continueAll = 1;
            break;
        end
    end
    if continueAll == 1
        continue;
    end
    AmOut(flag1) = jj;
end

%   把b加入到A最后一列,方便后面的换元迭代中的运算
%        1 2  1  1  0  0 10
%        1 2  3  0  1  0 15
%        2 1  5  0  0  1 20

A = [A b];

%   G存入的是检验数,也就是书中 cj - zj , j = m+1,...,n
%   zj = ci*aij , i= 1,...,m ,j = m+1,...,n
%   求 cj ,就是从Am1Out(非基变量)中取出索引(列数),到目标函数系数矩阵cOut去找对应的系数
%   对应求ci,就是从AmOut(基变量)中取出索引,到目标函数系数矩阵cOut去找对应的系数
%   求 aij ,其中i 为行数,j为每一行非基变量的列数,到 A(约束系数矩阵)中取出相应的系数
G = zeros(1,nOutSize - mOutSize);
for j = 1:nOutSize - mOutSize
    G(j) = cOut(Am1Out(j));
    for i = 1:mOutSize
        G(j) = G(j) - cOut(AmOut(i))*A(i,Am1Out(j));
    end
end
%   decide:找出检验数中大于0的数的索引(列数),存入decide中
decide = find(G(:)>0);
[dRow,dCol]=size(decide);
while 1
    if isempty(decide) %检验数全部小于0
        disp('第一阶段最优解')
        %   计算最优解,如果最优解等于0,进入第二阶段,如果不等于0,无可行解
        zR = 0;
        for i = 1:mOutSize
            zR = zR + cOut(AmOut(i))*A(i,nOutSize + 1);
        end
        if zR ~= 0
            disp('无可行解')
            X = [];
            zR = [];
            break;
        else
            %   如果基变量中有人工变量,删除人工变量
            %   Adelete:AmOut中记录着基变量,Ay记录着人工变量
            %   依次遍历AmOut,检验AmOut中有没有Ay中的元素,如果有的话则保存行数到Adelete中
            Adelete = [];
            deIndex = 0;
            for i = 1:mOutSize
                for iY = 1:yIndex
                    if AmOut(i) == Ay(iY)  %基中含有自由变量
                        zeroAll = 1;  %指系数全部为0
                        for iYR = 1:yRIndex             %ny - yIndex
                            if A(i,AyR(iYR)) ~= 0
                                zeroAll = 0;  %指系数有不全为0的
                                break;
                            end
                        end
                        if zeroAll == 1
                            %删除基变量中的人工变量行和人工变量列
                            deIndex = deIndex + 1;
                            Adelete(deIndex) = i;
                        else    %  zeroAll == 0
                            
                            % 此处是另外一种情况,也就是,最优解是基变量中含有人工变量,
                            % 而此时非基变量的系数不全为0,网上说这种情况还要进行换元迭代,
                            % 但那是没有具体例子进行分析,所以先放着未写,如果出现这种情况
                            % 则会disp输出'出现系数不全为0的情况',自己知道就行
                            %如果有合适的例子可以学习下就好编了
                            
                            disp('出现系数不全为0的情况')
                        end
                        break; 
                    end
                end
            end
            
            % 此处是删除人工变量所在的行
            % (其实是把除了人工变量(基变量中的人工变量)所在的行外,其他的行复制到secA里了)
            % 如果没有人工变量,就不会删除任何东西
            secA = [];
            dsAIndex = 0;
            for i = 1:mOutSize
                wIn = 0;
                for j = 1:deIndex
                    if i==Adelete(j)
                        wIn = 1;
                        break;
                    end
                end 
                if wIn == 0
                    dsAIndex = dsAIndex + 1;
                    secA(dsAIndex,:) = A(i,:);
                end
            end
            
            secb = secA(:,nOutSize+1);
            
            % 此处是删除人工变量所在的列(其实是把除了人工变量所在的列外,其他的列复制到secAA里了)
            % 人工变量都在Ay中记录着呢
            secAA = [];
            dsAAIndex = 0;
            for i = 1:nOutSize
                wIn = 0;
                for j = 1:yIndex
                    if i == Ay(j)
                        wIn = 1;
                        break;
                    end
                end 
                if wIn == 0
                    dsAAIndex = dsAAIndex + 1;
                    secAA(:,dsAAIndex) = secA(:,i);
                end
            end
           
            % 调用第二阶段的函数,基本思路与第一阶段相似
            [X,zR] = secP(secAA,secb,cSec,secMin);
            break;
        end
        
    else    %   如果检验数中有大于0的,则要换元迭代
        %进行换基运算
        %  ------------------------------------------------------------
        %  此处是遍历G,找出检验数中最大的那个,并存储他的列数
        %  decide(jMax) 就是检验数中最大的那个的列数
        jMax = 1;
        for j = 2:dRow
            if G(decide(j)) > G(decide(jMax))
                jMax = j;
            end
        end
        %  ************************************************************
        
        %  ------------------------------------------------------------
        %  此处是找出最小比值,上一步是确定换出基的列数,这步是确定换出基的行数,
        %  即是iMin
        iMin = 0;
        ratioM = inf;
        for ii = 1:mOutSize
            if A(ii,Am1Out(decide(jMax)))<=0  %不需要负的系数
                continue;
            end
            %下面条件 系数均大于0
            ratioP = A(ii,nOutSize+1)/A(ii,Am1Out(decide(jMax)));
            if ratioP < ratioM
                ratioM = ratioP;
                iMin = ii;
            end
        end
        %  ************************************************************
        
        %  ------------------------------------------------------------
        % 这个地方是对其他行进行初等变换,保证这行是类似 1 0 0 0 的形式
        A(iMin,:) = A(iMin,:)/A(iMin,Am1Out(decide(jMax)));
        for i = 1:mOutSize
            if i ~= iMin
                A(i,:) = A(i,:) - A(i,Am1Out(decide(jMax))).*A(iMin,:);
            end
        end
        %  ************************************************************
        
        %  ------------------------------------------------------------
        % 这一步是一次迭代后,更新 AmOut 和 Am1Out
        proc = AmOut(iMin);
        AmOut(iMin) = Am1Out(decide(jMax));
        Am1Out(decide(jMax)) = proc;
        %  ************************************************************
    end
    
    %  ------------------------------------------------------------
    %  再次计算检验数
    G = zeros(1,nOutSize - mOutSize);
    for j = 1:nOutSize - mOutSize
        G(j) = cOut(Am1Out(j));
        for i = 1:mOutSize
            G(j) = G(j) - cOut(AmOut(i))*A(i,Am1Out(j));
        end
    end
    decide = find(G(:)>0);
    [dRow,dCol]=size(decide);
    %  ************************************************************
    % 再次调转回头进行while循环
end

你可能感兴趣的:(Matlab二阶段单纯形法)