Permalink
Fetching contributors…
Cannot retrieve contributors at this time
120 lines (105 sloc) 4.48 KB
function doubly_stochastic_denoising()
% Find a doubly stochastic matrix closest to a given matrix, in Frobenius norm.
%
% This example demonstrates how to use the geometry factories for the
% doubly stochastic multinomial manifold:
% multinomialdoublystochasticfactory and
% multinomialsymmetricfactory (for the symmetric case.)
%
% The file is based on developments in the research paper
% A. Douik and B. Hassibi, "Manifold Optimization Over the Set
% of Doubly Stochastic Matrices: A Second-Order Geometry"
% ArXiv:1802.02628, 2018.
%
% Link to the paper: https://arxiv.org/abs/1802.02628.
%
% Please cite the Manopt paper as well as the research paper:
% @Techreport{Douik2018Manifold,
% Title = {Manifold Optimization Over the Set of Doubly Stochastic
% Matrices: {A} Second-Order Geometry},
% Author = {Douik, A. and Hassibi, B.},
% Journal = {Arxiv preprint ArXiv:1802.02628},
% Year = {2018}
% }
%
% This can be a starting point for many optimization problems of the form:
%
% minimize f(X) such that X is a doubly stochastic matrix (symmetric or not)
%
% Input: None. This example file generates random data.
%
% Output: None.
%
% This file is part of Manopt: www.manopt.org.
% Original author: Ahmed Douik, March 15, 2018.
% Contributors:
% Change log:
%% Generate input data
n = 100;
sigma = 1/n^2;
% Generate a doubly stochastic matrix using the Sinkhorn algorithm
B = doubly_stochastic(abs(randn(n, n)));
% Add noise to the matrix
A = max(B + sigma*randn(n, n), 0.01);
%% Setup an optimization problem for denoising
% Manifold initialization: pick the symmetric or non-symmetric case
symmetric_case = true;
if ~symmetric_case
manifold = multinomialdoublystochasticfactory(n);
else
% Input must also be symmetric (otherwhise, gradient must be adapted.)
A = (A+A')/2;
manifold = multinomialsymmetricfactory(n);
end
problem.M = manifold;
% Specify cost function and derivatives
problem.cost = @(X) 0.5*norm(A-X, 'fro')^2;
problem.egrad = @(X) X - A; % Euclidean gradient
problem.ehess = @(X, U) U; % Euclidean Hessian
% Check consistency of the gradient and the Hessian. Useful if you
% adapt this example for a new cost function and you would like to make
% sure there is no mistake. These checks are optional of course.
warning('off', 'manopt:multinomialdoublystochasticfactory:exp');
warning('off', 'manopt:multinomialsymmetricfactory:exp');
figure();
checkgradient(problem); % Check the gradient
figure();
checkhessian(problem); % Check the hessian. This test usually fails
% due to the use of a first order retraction,
% unless the test is performed at a critical point.
%% Solve
% A first order algorithm
% Minimize the cost function using the Conjugate Gradients algorithm.
[X1, ~, info, ~] = conjugategradient(problem);
S1 = [info.gradnorm] ; % Collecting the Gradient information
% Computing the distance between the original, noiseless matrix and the
% found solution
fprintf('||X-B||_F^2 = %g\n', norm(X1 - B, 'fro')^2);
% A second order algorithm
% Minimize the cost function using the trust-regions method.
[X2, ~, info, ~] = trustregions(problem);
S2 = [info.gradnorm] ; % Collecting the Gradient information
% Computing the distance between the original, noiseless matrix and the
% found solution
fprintf('||X-B||_F^2 = %g\n', norm(X2 - B, 'fro')^2);
%% Display
figure() ;
semilogy(S1, 'red', 'Marker', '*', 'LineWidth', 2, ...
'DisplayName', 'Conjugate Gradient Algorithm');
hold on ;
semilogy(S2, 'blue', 'Marker', '+', 'LineWidth', 2, ...
'DisplayName', 'Trust Regions Method');
set(gca, 'YGrid', 'on', 'XGrid', 'on');
xlabel('Number of Iteration', 'FontSize', 16);
ylabel('Norm of Gradient', 'FontSize', 16);
legend1 = legend('show');
set(legend1, 'FontSize', 16);
% This Hessian test is performed at a computed solution, which is
% expected to be a critical point. Thus we expect the slope test to
% succeed. It could fail if the solution X1 has entries very close to
% zero, so that numerical issues might come up. This is because de
% Fisher metric on the multinomial manifold involves division by the
% entries of X.
figure();
checkhessian(problem, X1);
end