利用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