%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Copyright (C) 2020 Zaiwen Wen, Haoyang Liu, Jiang Hu
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program. If not, see .
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 实例:次梯度法解 LASSO 问题
% 考虑 LASSO 问题
%
% $$ \displaystyle \min_x \frac{1}{2}\|Ax-b\|_2^2+\mu\|x\|_1. $$
%
% 这里,利用固定正则化系数 $\mu$ 的次梯度法进行求解,比较不同步长的效果。
%% 构造 LASSO 优化问题
% 设定随机种子。
clear;
seed = 97006855;
ss = RandStream('mt19937ar','Seed',seed);
RandStream.setGlobalStream(ss);
%%%
% 构造 LASSO 优化问题
%
% $$ \displaystyle\min_x \frac{1}{2}\|Ax-b\|_2^2+\mu\|x\|_1. $$
%
%
% 生成随机的矩阵 $A$ 和向量 $u$ 以使得 $b=Au$。
m = 512;
n = 1024;
A = randn(m, n);
u = sprandn(n, 1, 0.1);
b = A * u;
%%%
% 实验选取固定的正则化系数 $\mu=1$。随机迭代初始点。
mu = 1;
x0 = u + 1e-1 * randn(n, 1);
%% 求解 LASSO 优化问题
%%%
% 首先在更严格的停机准则下进行试验,将收敛时得到的历史最优函数值作为真实的最优值的参考 $f^*$。
opts_g = struct();
opts_g.maxit = 50000;
opts_g.alpha0 = 1e-6;
opts_g.step_type = 'fixed';
[x_g, out_g] = l1_subgrad(u, A, b, mu, opts_g);
f_star = out_g.f_hist_best(end);
%%%
% 取步长为 $0.0005$ 进行试验。
opts = struct();
opts.maxit = 3000;
opts.alpha0 = 0.0005;
opts.step_type = 'fixed';
[x, out] = l1_subgrad(x0, A, b, mu, opts);
data1 = (out.f_hist - f_star) / f_star;
data1_best = (out.f_hist_best - f_star) / f_star;
%%%
% 取步长为 $0.0002$ 进行试验。
opts.alpha0 = 0.0002;
[x, out] = l1_subgrad(x0, A, b, mu, opts);
data2 = (out.f_hist - f_star) / f_star;
data2_best = (out.f_hist_best - f_star) / f_star;
%%%
% 取步长为 $0.0001$ 进行试验。
opts.alpha0 = 0.0001;
[x, out] = l1_subgrad(x0, A, b, mu, opts);
data3 = (out.f_hist - f_star) / f_star;
data3_best = (out.f_hist_best - f_star) / f_star;
%%%
% 取步长为 $0.002$ 开始的消失步长 $0.002/\sqrt{k}$ 进行试验。
opts.step_type = 'diminishing';
opts.alpha0 = 0.002;
[x, out] = l1_subgrad(x0, A, b, mu, opts);
data4 = (out.f_hist - f_star) / f_star;
data4_best = (out.f_hist_best - f_star) / f_star;
%% 结果可视化
% 首先可视化每一步迭代得到的目标函数值的相对误差,即 ${\left(f(x^k)-f^*\right)}/{f^*}$。
fig = figure;
semilogy(0:length(data1)-1, data1, '-', 'Color',[0.2 0.1 0.99], 'LineWidth',2);
hold on
semilogy(0:length(data2)-1, data2, '--','Color',[0.99 0.1 0.2], 'LineWidth',1.2);
hold on
semilogy(0:length(data3)-1, data3, '-.','Color',[0.99 0.1 0.99], 'LineWidth',1.5);
hold on
semilogy(0:length(data4)-1, data4, ':','Color',[0.5 0.2 0.1], 'LineWidth',1.8);
legend('0.0005', '0.0002', '0.0001', '消失步长');
ylabel('$(f(x^k) - f^*)/f^*$', 'fontsize', 14, 'interpreter', 'latex');
xlabel('迭代步');
print(fig, '-depsc','f.eps');
%%%
% 展示第 $k$ 步迭代的历史最优目标函数值的相对误差,即 ${\left(\hat{f}(x^k)-f^*\right)}/{f^*}$。
fig = figure;
semilogy(0:length(data1_best)-1, data1_best, '-', 'Color',[0.2 0.1 0.99], 'LineWidth',2);
hold on
semilogy(0:length(data2_best)-1, data2_best, '--','Color',[0.99 0.1 0.2], 'LineWidth',1.2);
hold on
semilogy(0:length(data3_best)-1, data3_best, '-.','Color',[0.99 0.1 0.99], 'LineWidth',1.5);
hold on
semilogy(0:length(data4_best)-1, data4_best, ':','Color',[0.5 0.2 0.1], 'LineWidth',1.8);
legend('0.0005', '0.0002', '0.0001', '消失步长');
ylabel('$(\hat{f}(x^k) - f^*)/f^*$', 'fontsize', 14, 'interpreter', 'latex');
xlabel('迭代步');
print(fig, '-depsc','f_best.eps');
%% 结果分析
% 上图展示了在不使用连续化策略的情况下,不同步长的次梯度法对 LASSO 问题的收敛性。
% 不同的固定步长会在 $3000$ 步内均达到次优解,且步长越小得到的次优解越小,并未收敛到最优值。
% 而对于消失步长,算法最终收敛。
%
% 另外,从左图中我们看出,次梯度法本身是非单调方法,在收敛过程之中目标函数值或有上升。
%% 参考页面
% 次梯度法解 LASSO 问题的算法详见
% ,使用连续化策略的次梯度法见 。
%
% 此页面的源代码请见: <../download_code/lasso_subgrad/demo.m demo.m>。
%% 版权声明
% 此页面为《最优化:建模、算法与理论》、《最优化计算方法》配套代码。
% 代码作者:文再文、刘浩洋、户将,代码整理与页面制作:杨昊桐。
%
% 著作权所有 (C) 2020 文再文、刘浩洋、户将