MATLAB实现分支定界法求解整数规划

利用MATLAB实现分支定界法求解整数规划

classdef Model < matlab.mixin.Copyable
    properties
        intcon
        lb
        ub
        solver
        Aineq
        bineq
        Aeq
        beq
        f0
        f
        options
    end

    methods
        function obj = Model(prob)
            problem = prob.prob2struct;
            prob_cell = struct2cell(problem);
            [obj.intcon, obj.lb, obj.ub, obj.solver, obj.Aineq, obj.bineq, ...
                obj.Aeq, obj.beq, obj.f0, obj.f, obj.options] = prob_cell{:};
        end
    end

    methods
        function [x, fvl, status] = solve(obj)
            obj.options = optimset(Display="off");
            [x, fvl, status] = linprog(obj.f, ...
                obj.Aineq, obj.bineq,...
                obj.Aeq, obj.beq,...
                obj.lb, obj.ub, ...
                obj.options);
            if status > 0
                fprintf("x_curve = %s\n", mat2str(x'));
                fprintf("v_curve = %f\n", fvl);
            end
        end
    end

end

主程序

clear;clc;close all
n = 4;
eps = 1e-6;
x = optimvar("x", n, Type="continuous",LowerBound=0,UpperBound=1);
prob = optimproblem(Description="12-4");
prob.ObjectiveSense = "min";
prob.Objective = 7*x(1) + 12*x(2) + 5*x(3) + 14*x(4);
prob.Constraints.C1 = 300*x(1) + 600*x(2) + 500*x(3) + 1600*x(4) >= 700;


%% Step 0: 初始化: 
t = 0;             % 初始化解的索引为0
v_hat = inf;       % 不存在已知可行解,模型求最小,因此v为正无穷
x_hat = [];
mdl = Model(prob);
active_mdl = [mdl]; %#ok
active_level = [0]; %#ok
while true
    %% Step 1:  停止
    if isempty(active_mdl)
        if isempty(x_hat)
            disp("模型不可行");
        else
            fprintf("最优解: %s\n", mat2str(x_hat'));
            fprintf("目标值: %d\n", v_hat);
        end
        break
    end
    %% Step 2: 松弛
    
    % 尝试求解一个与x(t)对应的候选问题的线性规划松弛模型
    % 按照深度优先的原则,找出最深的节点
    max_node_index = find(active_level == max(active_level));
    % 具有相同深度的节点可能有两个,我们设定先择固定1的那个
    % 一般在分支的时候,我们依次加入固定0,固定1,因此1的索引靠后
    select_model = active_mdl(max_node_index(end));
    % 求解该模型
    fprintf("t=%d, 松弛求解\n", t);
    [x_curve, v_curve, flag] = select_model.solve;
    
    %% Step 3: 通过不可行终止
    % 如果线性规划模型不可行
    if flag < 1
        % 部分解x(t)没有完全形式,终止x(t)
        active_mdl(max_node_index(end)) = [];
        active_level(max_node_index(end)) = [];
        % t<-t+1
        fprintf("t=%d, 通过不可行终止\n", t);
        t = t + 1;
        % 返回步骤1
        continue
    end
    
    %% Step 4: 通过定界终止
    % 模型为最小化模型,如果v~ > v_^    
    if v_curve > v_hat
        % 则部分解x(t)最有可行的完全形式不能使最佳解更优
        active_mdl(max_node_index(end)) = [];
        active_level(max_node_index(end)) = [];
        % t<-t+1
        fprintf("t=%d, 通过定界终止\n", t);
        t = t + 1;
        % 返回步骤1
        continue
    end

    %% Step 5: 通过求解终止
    % 当线性规划松弛模型的最优解满足模型中所有的二元约束
    % 这个最优解就是部分解的最优可行完全形式

    idx = find(abs(x_curve - round(x_curve)) > eps, 1);
    if isempty(idx)
        % 保存这个解为最新的最佳解
        x_hat = round(x_curve);
        v_hat = v_curve;
        % 终止               
        active_mdl(max_node_index(end)) = [];
        active_level(max_node_index(end)) = [];
        % t<-t+1
        fprintf("t=%d, 通过求解终止\n", t);
        t = t + 1;
        % 返回步骤1
        continue
    end
    
    %% Step 6 分支
    fprintf("t=%d, 分支\n", t);
    % 选择线性规划松弛最优解中某些分数的自由二元约束分量x_p
    % 选择哪个变量进行分支,有很多不同策略,这里按照顺序来计算
    p = idx(1);
    % x_p固定为0
    new_mdl_l = copy(select_model);
    new_mdl_l.ub(p) = floor(x_curve(p));
    new_mdl_r = copy(select_model);
    new_mdl_r.lb(p) = ceil(x_curve(p));
    level = t + 1;
    active_mdl = [active_mdl, new_mdl_l, new_mdl_r]; %#ok
    active_level = [active_level, level, level]; %#ok
    t = t + 1;
    % 终止
    active_mdl(max_node_index(end)) = [];
    active_level(max_node_index(end)) = [];

end


你可能感兴趣的:(运筹学算法,matlab,开发语言)