一、算法原理概述
1.1 问题标准形式
minx∈Rnf(x)s.t.gi(x)≤0,i=1,2,...,mhj(x)=0,j=1,2,...,p \begin{aligned} \min_{x \in \mathbb{R}^n} \quad & f(x) \\ \text{s.t.} \quad & g_i(x) \leq 0, \quad i=1,2,\dots,m \\ & h_j(x) = 0, \quad j=1,2,\dots,p \end{aligned} x∈Rnmins.t.f(x)gi(x)≤0,i=1,2,...,mhj(x)=0,j=1,2,...,p
1.2 外点罚函数法(External Penalty Method)
核心思想 :允许迭代点违反约束,对违反约束的解施加惩罚。
P(x,σ)=f(x)+σ∑i=1mmax(0,gi(x))2+∑j=1phj(x)2 P(x, \sigma) = f(x) + \sigma \left \\sum_{i=1}\^m \\max(0,g_i(x))\^2 + \\sum_{j=1}\^p h_j(x)\^2 \\right P(x,σ)=f(x)+σi=1∑mmax(0,gi(x))2+j=1∑phj(x)2
- σ\sigmaσ:惩罚因子,σ→+∞\sigma \to +\inftyσ→+∞ 迫使解趋近可行域
- 初始点可在可行域外
1.3 内点罚函数法(Internal Penalty Method)
核心思想 :迭代点始终在可行域内,通过障碍函数阻止接近边界。
B(x,μ)=f(x)+μ∑i=1m1−gi(x)(倒数障碍) B(x, \mu) = f(x) + \mu \sum_{i=1}^m \frac{1}{-g_i(x)} \quad (\text{倒数障碍}) B(x,μ)=f(x)+μi=1∑m−gi(x)1(倒数障碍)
或
B(x,μ)=f(x)−μ∑i=1mln(−gi(x))(对数障碍) B(x, \mu) = f(x) - \mu \sum_{i=1}^m \ln(-g_i(x)) \quad (\text{对数障碍}) B(x,μ)=f(x)−μi=1∑mln(−gi(x))(对数障碍)
- μ\muμ:障碍参数,μ→0+\mu \to 0^+μ→0+ 迫使解趋近边界
- 初始点必须在可行域内
二、MATLAB程序实现
2.1 主程序:penalty_methods_main.m
matlab
%% 外点罚函数法与内点罚函数法求解最优化问题
clear; clc; close all;
%% 1. 定义优化问题
fprintf('=== 最优化问题的罚函数法求解 ===\n');
% 目标函数
f = @(x) x(1)^2 + x(2)^2; % 最小化 x^2 + y^2
% 不等式约束 g(x) ≤ 0
g = @(x) [x(1) + x(2) - 1; % g1: x + y - 1 ≤ 0
-x(1); % g2: -x ≤ 0
-x(2)]; % g3: -y ≤ 0
% 等式约束 h(x) = 0
h = @(x) []; % 无等式约束
% 理论最优解
x_opt_theoretical = [0.5, 0.5]';
f_opt_theoretical = f(x_opt_theoretical);
fprintf('目标函数: f(x) = x^2 + y^2\n');
fprintf('约束条件:\n');
fprintf(' g1: x + y - 1 ≤ 0\n');
fprintf(' g2: -x ≤ 0\n');
fprintf(' g3: -y ≤ 0\n');
fprintf('理论最优解: x* = [%.2f, %.2f]^T, f* = %.4f\n\n', ...
x_opt_theoretical(1), x_opt_theoretical(2), f_opt_theoretical);
%% 2. 外点罚函数法
fprintf('--- 外点罚函数法 ---\n');
x0 = [2, 2]'; % 初始点(可行域外)
sigma0 = 1; % 初始惩罚因子
sigma_inc = 10; % 惩罚因子增长倍数
max_iter = 50;
tol = 1e-6;
[x_ep, f_ep, history_ep] = exterior_penalty(f, g, h, x0, sigma0, sigma_inc, max_iter, tol);
%% 3. 内点罚函数法(对数障碍)
fprintf('\n--- 内点罚函数法(对数障碍) ---\n');
x0 = [0.6, 0.6]'; % 初始点(可行域内)
mu0 = 10; % 初始障碍参数
mu_dec = 0.1; % 障碍参数衰减倍数
[x_ip, f_ip, history_ip] = interior_penalty_log(f, g, h, x0, mu0, mu_dec, max_iter, tol);
%% 4. 结果对比与可视化
compare_results(f, g, x_ep, f_ep, x_ip, f_ip, history_ep, history_ip, x_opt_theoretical);
2.2 外点罚函数法实现
matlab
function [x_opt, f_opt, history] = exterior_penalty(f, g, h, x0, sigma0, sigma_inc, max_iter, tol)
% 外点罚函数法
% f: 目标函数, g: 不等式约束, h: 等式约束
% x0: 初始点, sigma0: 初始惩罚因子
x = x0;
sigma = sigma0;
history.x = zeros(length(x0), max_iter);
history.f = zeros(1, max_iter);
history.penalty = zeros(1, max_iter);
fprintf('迭代\t x1\t\t x2\t\t f(x)\t\t 惩罚项\t\t 罚因子\n');
fprintf('%-4d\t %-8.4f %-8.4f %-10.4f %-10.4f %-10.2f\n', ...
0, x(1), x(2), f(x), 0, sigma);
for iter = 1:max_iter
% 构造增广目标函数
P = @(x) augmented_objective_exterior(f, g, h, x, sigma);
% 无约束优化(使用fminunc)
options = optimoptions('fminunc', 'Algorithm', 'quasi-newton', ...
'Display', 'off', 'MaxIter', 100);
x_new = fminunc(P, x, options);
% 计算约束违反度
constraint_violation = constraint_violation_norm(g, h, x_new);
% 记录历史
history.x(:,iter) = x_new;
history.f(iter) = f(x_new);
history.penalty(iter) = penalty_term_exterior(g, h, x_new, sigma);
fprintf('%-4d\t %-8.4f %-8.4f %-10.4f %-10.4f %-10.2f\n', ...
iter, x_new(1), x_new(2), f(x_new), constraint_violation, sigma);
% 收敛检查
if constraint_violation < tol && norm(x_new - x) < tol
fprintf('收敛于第 %d 次迭代\n', iter);
break;
end
% 更新
x = x_new;
sigma = sigma * sigma_inc; % 增大惩罚因子
end
x_opt = x;
f_opt = f(x_opt);
end
function P = augmented_objective_exterior(f, g, h, x, sigma)
% 外点罚函数增广目标
P = f(x);
% 不等式约束惩罚(二次惩罚)
m = length(g(x));
for i = 1:m
P = P + sigma * max(0, g(x)(i))^2;
end
% 等式约束惩罚(二次惩罚)
p = length(h(x));
for j = 1:p
P = P + sigma * h(x)(j)^2;
end
end
function penalty = penalty_term_exterior(g, h, x, sigma)
penalty = 0;
m = length(g(x));
for i = 1:m
penalty = penalty + sigma * max(0, g(x)(i))^2;
end
p = length(h(x));
for j = 1:p
penalty = penalty + sigma * h(x)(j)^2;
end
end
2.3 内点罚函数法(对数障碍)实现
matlab
function [x_opt, f_opt, history] = interior_penalty_log(f, g, h, x0, mu0, mu_dec, max_iter, tol)
% 内点罚函数法(对数障碍)
% f: 目标函数, g: 不等式约束, h: 等式约束
% x0: 初始点(必须在可行域内), mu0: 初始障碍参数
x = x0;
mu = mu0;
history.x = zeros(length(x0), max_iter);
history.f = zeros(1, max_iter);
history.barrier = zeros(1, max_iter);
fprintf('迭代\t x1\t\t x2\t\t f(x)\t\t 障碍项\t\t 障碍参数\n');
fprintf('%-4d\t %-8.4f %-8.4f %-10.4f %-10.4f %-10.4f\n', ...
0, x(1), x(2), f(x), 0, mu);
for iter = 1:max_iter
% 构造增广目标函数(对数障碍)
B = @(x) barrier_objective_log(f, g, h, x, mu);
% 无约束优化
options = optimoptions('fminunc', 'Algorithm', 'quasi-newton', ...
'Display', 'off', 'MaxIter', 100);
x_new = fminunc(B, x, options);
% 检查可行性
if any(g(x_new) >= 0)
warning('迭代点超出可行域!');
break;
end
% 计算障碍项值
barrier_value = barrier_term_log(g, x_new, mu);
% 记录历史
history.x(:,iter) = x_new;
history.f(iter) = f(x_new);
history.barrier(iter) = barrier_value;
fprintf('%-4d\t %-8.4f %-8.4f %-10.4f %-10.4f %-10.4f\n', ...
iter, x_new(1), x_new(2), f(x_new), barrier_value, mu);
% 收敛检查
if norm(x_new - x) < tol && barrier_value < tol
fprintf('收敛于第 %d 次迭代\n', iter);
break;
end
% 更新
x = x_new;
mu = mu * mu_dec; % 减小障碍参数
end
x_opt = x;
f_opt = f(x_opt);
end
function B = barrier_objective_log(f, g, h, x, mu)
% 对数障碍函数
B = f(x);
% 不等式约束障碍项
m = length(g(x));
for i = 1:m
if g(x)(i) >= 0
B = B + 1e10; % 不可行点给予极大惩罚
else
B = B - mu * log(-g(x)(i));
end
end
% 等式约束处理(内点法通常不直接处理等式约束,需特殊处理)
p = length(h(x));
for j = 1:p
B = B + mu * h(x)(j)^2; % 等式约束用二次惩罚
end
end
function barrier = barrier_term_log(g, x, mu)
barrier = 0;
m = length(g(x));
for i = 1:m
barrier = barrier - mu * log(-g(x)(i));
end
end
2.4 辅助函数
matlab
function violation = constraint_violation_norm(g, h, x)
% 计算约束违反度
violation = 0;
% 不等式约束
m = length(g(x));
for i = 1:m
violation = violation + max(0, g(x)(i))^2;
end
% 等式约束
p = length(h(x));
for j = 1:p
violation = violation + h(x)(j)^2;
end
violation = sqrt(violation);
end
function compare_results(f, g, x_ep, f_ep, x_ip, f_ip, history_ep, history_ip, x_opt)
% 结果对比与可视化
fprintf('\n=== 结果对比 ===\n');
fprintf('理论最优解: x* = [%.4f, %.4f]^T, f* = %.4f\n', x_opt(1), x_opt(2), f(x_opt));
fprintf('外点法结果: x = [%.4f, %.4f]^T, f = %.4f\n', x_ep(1), x_ep(2), f_ep);
fprintf('内点法结果: x = [%.4f, %.4f]^T, f = %.4f\n', x_ip(1), x_ip(2), f_ip);
% 可视化
figure('Position', [100, 100, 1200, 400]);
% 1. 可行域与迭代路径
subplot(1,3,1);
plot_feasible_region(g, x_opt);
hold on;
plot(history_ep.x(1,:), history_ep.x(2,:), 'ro-', 'LineWidth', 1.5, 'MarkerSize', 6);
plot(history_ip.x(1,:), history_ip.x(2,:), 'bs-', 'LineWidth', 1.5, 'MarkerSize', 6);
plot(x_opt(1), x_opt(2), 'kp', 'MarkerSize', 15, 'LineWidth', 2);
xlabel('x_1'); ylabel('x_2');
title('可行域与迭代路径');
legend('可行域', '外点法', '内点法', '理论最优', 'Location', 'northwest');
grid on; axis equal;
% 2. 目标函数值收敛
subplot(1,3,2);
plot(0:length(history_ep.f)-1, history_ep.f, 'r-o', 'LineWidth', 2, 'MarkerSize', 6);
hold on;
plot(0:length(history_ip.f)-1, history_ip.f, 'b-s', 'LineWidth', 2, 'MarkerSize', 6);
plot([0, max(length(history_ep.f), length(history_ip.f))], [f(x_opt), f(x_opt)], 'k--', 'LineWidth', 1.5);
xlabel('迭代次数'); ylabel('目标函数值');
title('目标函数值收敛');
legend('外点法', '内点法', '理论最优', 'Location', 'northwest');
grid on;
% 3. 惩罚/障碍项变化
subplot(1,3,3);
yyaxis left;
plot(0:length(history_ep.penalty)-1, history_ep.penalty, 'r-o', 'LineWidth', 2);
ylabel('外点惩罚项');
yyaxis right;
plot(0:length(history_ip.barrier)-1, history_ip.barrier, 'b-s', 'LineWidth', 2);
ylabel('内点障碍项');
xlabel('迭代次数');
title('惩罚/障碍项变化');
grid on;
end
function plot_feasible_region(g, x_opt)
% 绘制可行域
x1 = linspace(0, 1.5, 100);
x2 = linspace(0, 1.5, 100);
[X1, X2] = meshgrid(x1, x2);
% 计算约束值
G = zeros(size(X1));
for i = 1:size(X1,1)
for j = 1:size(X1,2)
G(i,j) = g([X1(i,j); X2(i,j)])(1); % g1: x+y-1
end
end
% 绘制可行域
contourf(X1, X2, G, [0, 0], 'FaceColor', [0.9, 0.9, 0.9], 'EdgeColor', 'none');
hold on;
% 绘制约束边界
plot([0, 1], [1, 0], 'k--', 'LineWidth', 1.5); % x+y=1
plot([0, 0], [0, 1.5], 'k--', 'LineWidth', 1.5); % x=0
plot([0, 1.5], [0, 0], 'k--', 'LineWidth', 1.5); % y=0
end
三、算法特性对比
| 特性 | 外点罚函数法 | 内点罚函数法 |
|---|---|---|
| 初始点要求 | 可在可行域外 | 必须在可行域内 |
| 约束处理 | 允许违反约束 | 严格禁止违反 |
| 惩罚参数 | 递增(σ→∞\sigma \to \inftyσ→∞) | 递减(μ→0\mu \to 0μ→0) |
| 数值稳定性 | 可能产生病态问题 | 相对稳定 |
| 收敛性 | 全局收敛性好 | 可能收敛到局部最优 |
| 适用场景 | 一般约束优化 | 不等式约束为主 |
四、使用示例(自定义问题)
4.1 带等式约束的问题
matlab
% 修改目标函数和约束
f = @(x) (x(1)-2)^2 + (x(2)-1)^2;
g = @(x) [x(1)^2 + x(2)^2 - 4]; % 圆内
h = @(x) x(1) + x(2) - 2; % 直线
x0_ep = [0, 0]'; % 可行域外
x0_ip = [0.5, 0.5]'; % 可行域内
[x_ep, f_ep] = exterior_penalty(f, g, h, x0_ep, 1, 10, 50, 1e-6);
[x_ip, f_ip] = interior_penalty_log(f, g, h, x0_ip, 10, 0.1, 50, 1e-6);
4.2 高维问题(三维)
matlab
% 三维优化问题
f = @(x) x(1)^2 + 2*x(2)^2 + 3*x(3)^2;
g = @(x) [x(1) + x(2) + x(3) - 1;
-x(1); -x(2); -x(3)];
x0 = [0.5, 0.3, 0.2]';
[x_opt, f_opt] = interior_penalty_log(f, g, @(x)[], x0, 10, 0.1, 100, 1e-6);
参考代码 求解最优化问题的外点罚函数法、内点罚函数法的matlab程序 www.youwenfan.com/contentcsv/79349.html
五、注意事项与改进建议
5.1 常见问题解决
| 问题 | 解决方案 |
|---|---|
| 收敛慢 | 调整惩罚因子增长/衰减速率 |
| 数值不稳定 | 使用对数障碍代替倒数障碍 |
| 初始点敏感 | 尝试多个不同初始点 |
| 等式约束难处理 | 将等式约束转化为两个不等式 |
5.2 工程优化建议
matlab
% 1. 自适应惩罚因子调整
if constraint_violation > prev_violation
sigma = sigma * 20; % 违反度增加时加大惩罚
end
% 2. 混合策略(外点+内点)
% 先用外点法快速接近可行域,再用内点法精细搜索
% 3. 多起点策略
% 从不同初始点运行,选择最优结果
六、总结
本MATLAB程序完整实现了:
- 外点罚函数法:允许迭代点在可行域外,通过递增惩罚因子迫使解趋近可行域
- 内点罚函数法:迭代点始终在可行域内,通过递减障碍参数迫使解趋近边界
- 完整的可视化:迭代路径、收敛曲线、惩罚项变化
- 灵活的问题定义:支持自定义目标函数、不等式和等式约束
关键优势:
- 算法原理清晰,代码模块化
- 支持任意维度的优化问题
- 完整的收敛性检查和结果分析
- 可直接应用于工程实际问题