使用MATLAB求解線性規劃問題,並輸出單純形表,識別無界解和無窮多最優解情況

本文構建SimplexMax函數,通過構建單純型表和循環迭代,求解線性規劃問題的最優解

clc;clear;
%% 設置變量,調用函數
% 題目參數
A = [0 5 1 0 0;
     6 2 0 1 0;
     1 1 0 0 1];
b = [15; 24; 5];
c = [2 1 0 0 0];
ind = [3 4 5]

% 無界解
% A = [-2 1 1 0;
%      1 -1 0 1];
% b = [4; 2];
% c = [1 1 0 0];
% ind = [3 4];


% 無窮多最優解
% A = [-1 -1.9 1 0 0 0;
%      1 -1.9 0 1 0 0;
%      1 1.9 0 0 1 0;
%      -1 1.9 0 0 0 1];
% b = [-3.8; 3.8; 10.2; 3.8];
% c = [3 5.7 0 0 0 0];
% ind = [3 4 5 6];

[x, z, ST, ca] = SimplexMax(c, A, b, ind) % 調用下述構建的方法進行求解

delete('mysimpleMax.xlsx'); % 刪除原有的Excel表(如果存在的話)
fprintf('正在將單純形表寫入Excel...\n');
writematrix('C1','mysimpleMax.xlsx','Sheet',1,'Range','C1');
writecell({'cB','xB', 'b'},'mysimpleMax.xlsx','Sheet',1,'Range','A2');
[~,n] = size(A);
X = strcat('x', string(1:n));
writematrix(X,'mysimpleMax.xlsx','Sheet',1,'Range','D2');
writematrix(c,'mysimpleMax.xlsx','Sheet',1,'Range','D1');
writematrix(ST,'mysimpleMax.xlsx','Sheet',1,'Range','A3');
fprintf('單純性表寫入完成\n');



%% 構造解單純形法函數
function [x,z,ST,res_case] = SimplexMax(c,A,b,ind_B)
% 單純形法求解標準形線性規劃問題: max cx s.t. Ax=b x>=0
% 輸入參數: c爲目標函數係數, A爲約束方程組係數矩陣, b爲約束方程組常數項, ind_B爲初始基變量索引
% 輸出參數: x最優解, z最優目標函數值, ST存儲單純形表數據,
% res_case=0表示有最優解,res_case=1表示有無界解,res_case=2表示有無窮多解

[m,n] = size(A);              % m約束條件個數, n決策變量數
ind_N = setdiff(1:n, ind_B);  % 非基變量的索引
ST = [];
format rat
% 循環求解
iteration_round = 0; % 記錄迭代次數
while true
    x0 = zeros(n,1);
    x0(ind_B) = b;               % 初始基可行解
    cB = c(ind_B);               % 計算cB
    Sigma = zeros(1,n);          % 創建Sigma存儲檢驗數並初始化爲0
    Sigma(ind_N) = c(ind_N) - cB*A(:,ind_N);   % 計算並存入(非基變量)檢驗數
    [~, k] = max(Sigma);         % 選出最大檢驗數, 確定進基變量索引k (注:[a,b]=max(c)中,a爲c中的最大值,b爲c中最大值的index)
%     fprintf('確定進基變量索引:%d\n',k)
    Theta = b ./ A(:,k);         % 計算θ(取A的k列,使b./(A的k列))
    
    Theta(Theta == 1/0) = NaN;
    Theta(Theta <= 0) = NaN;
%     Theta(Theta<=0) = 10000;
%     [~, q] = min(Theta);         % 選出最小θ
    [~, q] = min(Theta);         % 選出最小正數θ
    el = ind_B(q);               % 確定出基變量索引el, 主元爲A(q,k)
%     fprintf('確定出基變量索引:%d\n',el)
    vals = [cB',ind_B',b,A,Theta];  % 存儲單純形表
    vals = [vals; NaN, NaN, NaN, Sigma, NaN];   % 存儲單純性表Sigma列
    [~,vals_width] = size(vals);    % 創建一個與vals等寬的空矩陣
    vals = [vals; [1:vals_width]* NaN];  % 將該行添加到vals最後作爲分隔
    ST = [ST; vals];    % 將上述構建的單純性表vals添加到ST矩陣中
    if ~any(Sigma > 0)           % 若不存在任何Sigma>0,此基可行解爲最優解
        fprintf('得到最優解');
        x = x0;
        z = c * x;
        res_case = 0;
        return
    end
    if all(A(:,k) <= 0)          %有無界解
        fprintf('有無界解');
        x = [];
        z = NaN;
        res_case = 1;
        break
    end
    if ~any(Sigma(ind_B)>0) && any(Sigma(ind_N)==0)     % 有無窮多最優解
        fprintf('有無窮多最優解')
        x = x0;
        z = c * x;
        res_case = 2;
        break
    end
    iteration_round = iteration_round + 1;
    fprintf('迭代第%d次\n',iteration_round)
    fprintf('確定進基變量索引:%d  出基變量索引: %d\n',k,el)
    % 換基
    ind_B(ind_B == el) = k;      %新的基變量索引
    ind_N = setdiff(1:n, ind_B); %非基變量索引(選取了ind_B和[1:n]的差集)
    % 更新A和b
    A(:,ind_N) = A(:,ind_B) \ A(:,ind_N);   % Q1 = inv(A(:,ind_B))  
    b = A(:,ind_B) \ b;     % b2 = inv(Q1) * b1
    A(:,ind_B) = eye(m,m);
end
end

注意:本文采用的對單純性表進行操作的方法並不是改進單純型法,如果需要使用改進單純型法進行求解請參考其他文章,並對下述操作進行改進

    % 換基
    ind_B(ind_B == el) = k;      %新的基變量索引
    ind_N = setdiff(1:n, ind_B); %非基變量索引(選取了ind_B和[1:n]的差集)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章