半定规划(Semidefinite Programming, SDP)是数学优化的一个重要分支,涉及在半正定矩阵锥上进行的凸优化问题。以下是使用 MATLAB 求解半定规划的多种方法,包括专用工具箱和手动实现。
一、使用 CVX 工具箱(推荐方法)
CVX 是斯坦福大学开发的优化建模系统,可高效求解半定规划问题。
安装 CVX
- 访问 http://cvxr.com/cvx/
- 下载并解压到 MATLAB 路径
- 运行
cvx_setup
基本求解示例
matlab
% 求解半定规划问题:
% min C • X
% s.t. A_i • X = b_i, i=1..m
% X ≽ 0
cvx_begin sdp
variable X(2,2) symmetric % 定义对称半正定变量
minimize( trace([1,0;0,2]*X) ) % 目标函数: C=[1,0;0,2]
subject to
trace([1,0;0,1]*X) == 1; % 约束1: A1=I, b1=1
trace([0,1;1,0]*X) == 0.5; % 约束2: A2=[0,1;1,0], b2=0.5
X >= 0; % 半正定约束
cvx_end
% 显示结果
disp('最优解 X:');
disp(X);
disp(['最优值: ', num2str(cvx_optval)]);
实际应用示例:最大割问题
matlab
% 最大割问题的SDP松弛
n = 5; % 顶点数
W = rand(n,n); % 权重矩阵
W = (W + W')/2; % 确保对称
W = W - diag(diag(W)); % 对角线归零
cvx_begin sdp
variable X(n,n) symmetric
maximize( sum(sum(W.*X)) ) % 目标函数
subject to
diag(X) == ones(n,1); % 对角线为1
X >= 0; % 半正定约束
cvx_end
% 随机舍入得到整数解
[U,S,V] = svd(X);
v = sign(U(:,1));
cut_value = sum(W(v > 0, v < 0));
disp(['最大割值: ', num2str(cut_value)]);
二、使用 YALMIP 工具箱
YALMIP 是另一个强大的优化建模工具箱,支持多种求解器。
安装 YALMIP
- 从 https://github.com/yalmip/YALMIP 下载
- 添加到 MATLAB 路径
求解示例
matlab
% 求解相同问题
n = 2;
C = [1,0;0,2];
A1 = eye(2); b1 = 1;
A2 = [0,1;1,0]; b2 = 0.5;
% 定义模型
X = sdpvar(n,n,'symmetric');
Constraints = [X >= 0, ...
trace(A1*X) == b1, ...
trace(A2*X) == b2];
Objective = trace(C*X);
% 求解
options = sdpsettings('solver','sedumi'); % 选择求解器
optimize(Constraints, Objective, options);
% 获取结果
X_opt = value(X);
obj_val = value(Objective);
disp('最优解:'); disp(X_opt);
disp(['最优值: ', num2str(obj_val)]);
三、使用 SeDuMi 求解器(底层接口)
对于需要更高控制精度的场景,可直接调用 SeDuMi 求解器。
matlab
% 问题描述:
% min C•X
% s.t. A_i•X = b_i
% X ≽ 0
% 定义数据
C = [1,0;0,2]; % 目标矩阵
A1 = eye(2); b1 = 1; % 约束1
A2 = [0,1;1,0]; b2 = 0.5; % 约束2
% 组合约束矩阵
A = [A1(:)'; A2(:)']; % 按列堆叠
b = [b1; b2];
% 调用 SeDuMi
K.s = size(C,1); % 半定块维度
options = sedumi(A,b,C,[],[],[],K);
X_sol = full(options.x); % 解向量
X_mat = reshape(X_sol, size(C)); % 重构矩阵
% 显示结果
disp('最优解矩阵:');
disp(X_mat);
disp(['最优值: ', num2str(trace(C*X_mat))]);
四、手动实现内点法(教育目的)
理解算法原理,可手动实现简化版内点法:
matlab
function [X, obj] = simple_sdp_solver(C, A_list, b_list, mu0, tol, max_iter)
% 参数设置
n = size(C,1); % 矩阵维度
m = length(b_list); % 约束数量
mu = mu0; % 初始障碍参数
X = eye(n); % 初始解
for iter = 1:max_iter
% 1. 计算梯度
grad = C;
for i = 1:m
grad = grad - (trace(A_list{i}*X) - b_list{i}) * A_list{i};
end
% 2. 牛顿步长计算(简化版)
% 实际实现需要求解牛顿方程:F'(X)[ΔX] = -F(X)
% 这里使用简化更新
dX = -grad / norm(grad, 'fro');
% 3. 线搜索
alpha = 0.1;
new_X = X + alpha * dX;
% 4. 投影到可行集(保持半正定)
[U, S, V] = svd(new_X);
S(S < 0) = 0; % 投影到半正定锥
new_X = U*S*V';
% 5. 更新障碍参数
mu = 0.1 * mu;
% 6. 检查收敛
if norm(new_X - X, 'fro') < tol
break;
end
X = new_X;
end
% 计算目标值
obj = trace(C*X);
end
% 使用示例
C = [1,0;0,2];
A_list = {eye(2), [0,1;1,0]};
b_list = [1; 0.5];
[X, obj] = simple_sdp_solver(C, A_list, b_list, 10, 1e-5, 100);
disp('手动求解结果:');
disp(X);
disp(['目标值: ', num2str(obj)]);
参考代码 求解半定规划的matlab代码 www.youwenfan.com/contentcst/63203.html
五、常见问题与解决方案
-
问题不可行
matlabcvx_begin sdp % ... 问题定义 ... cvx_end if strfind(cvx_status, 'Infeasible') disp('问题不可行!尝试放松约束'); end -
数值稳定性问题
- 缩放数据使矩阵元素量级相近
- 使用
sdpsettings('verbose',1)查看求解细节 - 尝试不同求解器:
'sedumi'、'sdpt3'、'mosek'
-
大型问题求解
- 使用稀疏矩阵格式
- 考虑分解技术
- 使用专门的大规模SDP求解器
六、应用场景
- 组合优化:最大割、图着色、社区发现
- 控制系统:Lyapunov稳定性分析、鲁棒控制
- 信号处理:波束成形、传感器网络定位
- 量子信息:量子态层析、纠缠见证
- 金融工程:投资组合优化、风险管理
七、性能优化技巧
-
热启动:对相似问题使用上次解作为初始点
matlaboptions = sdpsettings('solver','sedumi','usex0',1); optimize(Constraints, Objective, options); -
并行计算 :对多个SDP问题使用
parformatlabparfor i = 1:N result{i} = solve_sdp(problem{i}); end -
GPU加速:使用支持GPU的求解器(如Mosek)
matlaboptions = sdpsettings('solver','mosek','MOSEK.GPU',true); -
低秩近似:当解预期为低秩时
matlabcvx_begin sdp variable X(n,n) semidefinite dual variable lambda; minimize(trace(C*X)) subject to % ... 约束 ... cvx_end
总结
MATLAB 提供了多种求解半定规划的方法:
- CVX:最简便易用,适合大多数应用
- YALMIP:更灵活,支持更多求解器
- 直接调用求解器:SeDuMi、SDPT3、MOSEK 等
- 手动实现:有助于理解算法原理