├── 2D_experiment ├── auxillary │ ├── normalize.m │ ├── orth_proj.m │ ├── dist_2D.m │ ├── match_cirshift.m │ ├── gen_data_2D.m │ ├── multi_conv_2D.m │ └── cconvfft2.m ├── func │ ├── func_simple.m │ ├── func_l1_2D.m │ ├── func_l4_2D.m │ ├── func_huber_2D.m │ └── func_huber_2D_joint.m ├── algorithms │ ├── linesearch_2D.m │ ├── rounding_2D.m │ └── grad_descent_2D.m └── test_2D.m ├── auxillary ├── orth_proj.m ├── reversal.m ├── dist.m ├── dist_a.m ├── linesearch_new.m ├── multi_conv.m ├── gen_data.m ├── rounding.m └── circulant.m ├── 1D_experiment ├── auxillary │ ├── orth_proj.m │ ├── reversal.m │ ├── dist.m │ ├── dist_a.m │ ├── linesearch_new.m │ ├── multi_conv.m │ ├── gen_data.m │ ├── rounding.m │ └── circulant.m ├── func │ ├── func_simple.m │ ├── func_l1.m │ ├── func_l4.m │ └── func_huber.m ├── algorithms │ └── grad_descent.m └── convergence.m ├── func ├── func_simple.m ├── func_l1.m ├── func_l4.m └── func_huber.m ├── landscape_plot ├── func │ ├── func_simple.m │ ├── func_l4.m │ ├── func_l1.m │ └── func_huber.m ├── auxillary │ ├── multi_conv.m │ └── gen_data.m └── plot_landscape.m ├── README.md ├── algorithms └── grad_descent.m └── ReadMe.txt /2D_experiment/auxillary/normalize.m: -------------------------------------------------------------------------------- 1 | % normalization of a vector Z 2 | 3 | function Z_n = normalize(Z) 4 | 5 | norm_Z = norm(Z(:)); 6 | Z_n = Z / norm_Z; 7 | 8 | end -------------------------------------------------------------------------------- /auxillary/orth_proj.m: -------------------------------------------------------------------------------- 1 | % projection of v to the orthgonal complement of u 2 | % z = v - u* (u'*v) 3 | % 4 | 5 | function z = orth_proj(u,v) 6 | u = u / norm(u); 7 | z = v - u* (u'*v); 8 | end -------------------------------------------------------------------------------- /1D_experiment/auxillary/orth_proj.m: -------------------------------------------------------------------------------- 1 | % projection of v to the orthgonal complement of u 2 | % z = v - u* (u'*v) 3 | % 4 | 5 | function z = orth_proj(u,v) 6 | u = u / norm(u); 7 | z = v - u* (u'*v); 8 | end -------------------------------------------------------------------------------- /auxillary/reversal.m: -------------------------------------------------------------------------------- 1 | % reversal operator reverses each column of Y 2 | % for each column of Y_R, 3 | % y_ri = [y_i1, y_im, y_i(m-1), ..., y_i2]' 4 | 5 | function Y_R = reversal(Y) 6 | 7 | Y_R = [Y(1,:);Y(end:-1:2,:)]; 8 | 9 | end -------------------------------------------------------------------------------- /1D_experiment/auxillary/reversal.m: -------------------------------------------------------------------------------- 1 | % reversal operator reverses each column of Y 2 | % for each column of Y_R, 3 | % y_ri = [y_i1, y_im, y_i(m-1), ..., y_i2]' 4 | 5 | function Y_R = reversal(Y) 6 | 7 | Y_R = [Y(1,:);Y(end:-1:2,:)]; 8 | 9 | end -------------------------------------------------------------------------------- /auxillary/dist.m: -------------------------------------------------------------------------------- 1 | function err = dist(a_0, a) 2 | 3 | % % normalization 4 | % a_0 = normc(a_0); a = normc(a); 5 | 6 | n = length(a_0); 7 | % compute correlations 8 | cor = cconv(a_0,a,n); 9 | err = 1 - max(abs(cor))/norm(cor,'fro') ; 10 | 11 | end -------------------------------------------------------------------------------- /1D_experiment/auxillary/dist.m: -------------------------------------------------------------------------------- 1 | function err = dist(a_0, a) 2 | 3 | % % normalization 4 | % a_0 = normc(a_0); a = normc(a); 5 | 6 | n = length(a_0); 7 | % compute correlations 8 | cor = cconv(a_0,a,n); 9 | err = 1 - max(abs(cor))/norm(cor,'fro') ; 10 | 11 | end -------------------------------------------------------------------------------- /func/func_simple.m: -------------------------------------------------------------------------------- 1 | classdef func_simple < handle 2 | % Define interface of simple closed convex function Psi(x) 3 | methods (Abstract) 4 | [fval, grad] = oracle(Psi, x) 5 | % Return function value Psi(x), and a gradient 6 | 7 | end 8 | end -------------------------------------------------------------------------------- /2D_experiment/auxillary/orth_proj.m: -------------------------------------------------------------------------------- 1 | % projection of V onto orthogonal complement of U 2 | % P = V - innerprod(U,V)*U / ||U||_F^2 ; 3 | 4 | function P = orth_proj(U,V) 5 | 6 | norm_U_2 = sum(U(:).^2); 7 | 8 | P = V - sum(U(:).*V(:)) * U / norm_U_2; 9 | 10 | end -------------------------------------------------------------------------------- /1D_experiment/func/func_simple.m: -------------------------------------------------------------------------------- 1 | classdef func_simple < handle 2 | % Define interface of simple closed convex function Psi(x) 3 | methods (Abstract) 4 | [fval, grad] = oracle(Psi, x) 5 | % Return function value Psi(x), and a gradient 6 | 7 | end 8 | end -------------------------------------------------------------------------------- /2D_experiment/func/func_simple.m: -------------------------------------------------------------------------------- 1 | classdef func_simple < handle 2 | % Define interface of simple closed convex function Psi(x) 3 | methods (Abstract) 4 | [fval, grad] = oracle(Psi, x) 5 | % Return function value Psi(x), and a gradient 6 | 7 | end 8 | end -------------------------------------------------------------------------------- /landscape_plot/func/func_simple.m: -------------------------------------------------------------------------------- 1 | classdef func_simple < handle 2 | % Define interface of simple closed convex function Psi(x) 3 | methods (Abstract) 4 | [fval, grad] = oracle(Psi, x) 5 | % Return function value Psi(x), and a gradient 6 | 7 | end 8 | end -------------------------------------------------------------------------------- /2D_experiment/auxillary/dist_2D.m: -------------------------------------------------------------------------------- 1 | function err = dist_2D(A_0, A) 2 | 3 | % % normalization 4 | % a_0 = normc(a_0); a = normc(a); 5 | 6 | % n = length(a_0); 7 | % compute correlations 8 | % cor = cconv(A_0,A); 9 | cor = cconvfft2(A_0,A); 10 | err = 1 - max(abs(cor(:)))/norm(cor,'fro') ; 11 | 12 | end -------------------------------------------------------------------------------- /auxillary/dist_a.m: -------------------------------------------------------------------------------- 1 | function err = dist_a(a_0, a) 2 | 3 | % % normalization 4 | a_0 = normc(a_0); a = normc(a); 5 | 6 | n = length(a_0); 7 | % compute correlations 8 | A = a_0; 9 | for i =1:n-1 10 | A = [A circshift(a_0,i)]; 11 | end 12 | A = [A -A]; 13 | 14 | err = min(sqrt(sum((repmat(a,1,2*n) - A).^2))); 15 | 16 | end -------------------------------------------------------------------------------- /1D_experiment/auxillary/dist_a.m: -------------------------------------------------------------------------------- 1 | function err = dist_a(a_0, a) 2 | 3 | % % normalization 4 | a_0 = normc(a_0); a = normc(a); 5 | 6 | n = length(a_0); 7 | % compute correlations 8 | A = a_0; 9 | for i =1:n-1 10 | A = [A circshift(a_0,i)]; 11 | end 12 | A = [A -A]; 13 | 14 | err = min(sqrt(sum((repmat(a,1,2*n) - A).^2))); 15 | 16 | end -------------------------------------------------------------------------------- /auxillary/linesearch_new.m: -------------------------------------------------------------------------------- 1 | function [q_new,tau] = linesearch_new( f, q, fval, grad,tau) 2 | % line search parameters 3 | beta = 0.8; 4 | eta = 1e-3; 5 | tau = 2*tau; % initial stepsize 6 | tau_threshold = 1e-15; 7 | 8 | grad_norm = sum(grad.^2); 9 | q_new = normc(q - tau*grad); 10 | 11 | 12 | while( f.oracle(q_new) > fval - eta * tau * grad_norm && tau>tau_threshold ) 13 | tau = tau * beta; 14 | q_new = normc(q - tau*grad); 15 | end 16 | 17 | 18 | end 19 | 20 | -------------------------------------------------------------------------------- /auxillary/multi_conv.m: -------------------------------------------------------------------------------- 1 | % Y = [y_1, y_2, ..., y_p] 2 | % C = [c_1, c_2, ..., c_p] 3 | % 4 | % if flag = 0, Q is a vector 5 | % c_i = conv( y_i, Q) 6 | % 7 | % if flag = 1, Q is a matrix of the same size of Y 8 | % c_i = conv( y_i, q_i) 9 | % 10 | function C = multi_conv(Y, Q, flag) 11 | [~,p] = size(Y); 12 | if(flag == 0) 13 | C = real(ifft( bsxfun(@times, fft(Y), fft(Q)) )); 14 | end 15 | 16 | if(flag == 1) 17 | C = real( ifft( fft(Y) .* fft(Q) ) ); 18 | end 19 | 20 | end -------------------------------------------------------------------------------- /1D_experiment/auxillary/linesearch_new.m: -------------------------------------------------------------------------------- 1 | function [q_new,tau] = linesearch_new( f, q, fval, grad,tau) 2 | % line search parameters 3 | beta = 0.8; 4 | eta = 1e-3; 5 | tau = 2*tau; % initial stepsize 6 | tau_threshold = 1e-15; 7 | 8 | grad_norm = sum(grad.^2); 9 | q_new = normc(q - tau*grad); 10 | 11 | 12 | while( f.oracle(q_new) > fval - eta * tau * grad_norm && tau>tau_threshold ) 13 | tau = tau * beta; 14 | q_new = normc(q - tau*grad); 15 | end 16 | 17 | 18 | end 19 | 20 | -------------------------------------------------------------------------------- /landscape_plot/auxillary/multi_conv.m: -------------------------------------------------------------------------------- 1 | % Y = [y_1, y_2, ..., y_p] 2 | % C = [c_1, c_2, ..., c_p] 3 | % 4 | % if flag = 0, Q is a vector 5 | % c_i = conv( y_i, Q) 6 | % 7 | % if flag = 1, Q is a matrix of the same size of Y 8 | % c_i = conv( y_i, q_i) 9 | % 10 | function C = multi_conv(Y, Q, flag) 11 | [~,p] = size(Y); 12 | if(flag == 0) 13 | C = real(ifft( fft(Y) .* repmat(fft(Q),1,p) )); 14 | end 15 | 16 | if(flag == 1) 17 | C = real( ifft( fft(Y) .* fft(Q) ) ); 18 | end 19 | 20 | end -------------------------------------------------------------------------------- /1D_experiment/auxillary/multi_conv.m: -------------------------------------------------------------------------------- 1 | % Y = [y_1, y_2, ..., y_p] 2 | % C = [c_1, c_2, ..., c_p] 3 | % 4 | % if flag = 0, Q is a vector 5 | % c_i = conv( y_i, Q) 6 | % 7 | % if flag = 1, Q is a matrix of the same size of Y 8 | % c_i = conv( y_i, q_i) 9 | % 10 | function C = multi_conv(Y, Q, flag) 11 | [~,p] = size(Y); 12 | if(flag == 0) 13 | C = real(ifft( bsxfun(@times, fft(Y), fft(Q)) )); 14 | end 15 | 16 | if(flag == 1) 17 | C = real( ifft( fft(Y) .* fft(Q) ) ); 18 | end 19 | 20 | end -------------------------------------------------------------------------------- /2D_experiment/algorithms/linesearch_2D.m: -------------------------------------------------------------------------------- 1 | function [Z_new,tau] = linesearch_2D( f, Z, fval, Grad, tau) 2 | % line search parameters 3 | beta = 0.8; 4 | eta = 1e-3; 5 | tau = 2*tau; % initial stepsize 6 | tau_threshold = 1e-12; 7 | 8 | Grad_norm = sum(Grad(:).^2); 9 | Z_new = normalize( Z - tau * Grad ); 10 | 11 | 12 | while( f.oracle(Z_new) > fval - eta * tau * Grad_norm && tau>tau_threshold ) 13 | tau = tau * beta; 14 | Z_new = normalize(Z - tau*Grad); 15 | end 16 | 17 | 18 | end 19 | 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MCS-BD 2 | 3 | The code is for the following paper: 4 | ``A Nonconvex Approach for Exact and Efficient Multichannel Sparse Blind Deconvolution'', 5 | Qing Qu, Xiao Li and Zhihui Zhu. 6 | 7 | We have include: 8 | ▪ landscape plot which will reproduce Figure 1 of our paper, run ‘plot_landscape.m’. 9 | ▪ 1D experiments which will reproduce Figure 3 of our paper, run ‘convergence.m’ 10 | ▪ 2D experiments which includes the 2D extension of the 1D experiments, run ‘test_2D.m’. 11 | 12 | If the code is useful to you, please cite our paper. 13 | -------------------------------------------------------------------------------- /2D_experiment/auxillary/match_cirshift.m: -------------------------------------------------------------------------------- 1 | function [ A_hat,Index ] = match_cirshift( A0, A_hat ); 2 | 3 | %A_hat, preconditioned inverse kernel 4 | %A0, underlying kernel 5 | 6 | [m,n] = size(A_hat); 7 | 8 | Index = [1 1]; 9 | maximum = 0; 10 | 11 | for I = 1:m 12 | for J = 1:n 13 | A_shift = circshift(A_hat,[I J]); 14 | cor2 = trace(abs(A0)' * abs(A_shift)); 15 | if cor2 > maximum 16 | Index = [I,J]; 17 | maximum = cor2; 18 | end 19 | end 20 | end 21 | A_hat = circshift(A_hat,Index); 22 | 23 | end 24 | 25 | -------------------------------------------------------------------------------- /auxillary/gen_data.m: -------------------------------------------------------------------------------- 1 | % the function to generate simulated data 2 | % y_i = conv(a, x_i) + noise 3 | 4 | 5 | function [ Y, a, X] = gen_data(n, p, opts) 6 | 7 | X = zeros(n,p); 8 | 9 | % generate the kernel 10 | a = normc(randn(n,1)); 11 | 12 | % generate the data 13 | switch lower(opts.x_type) 14 | case 'bernoulli-gaussian' 15 | X = randn(n,p) .* (rand(n,p)<=opts.theta); 16 | case 'bernoulli-radmacher' 17 | X = (rand(n,p)<=opts.theta) .* (double(rand(n,p)<0.5) -0.5)*2 ; 18 | end 19 | 20 | Y = multi_conv( X, a, 0); 21 | 22 | Y = Y + opts.noise_level * randn(n,p); 23 | 24 | end -------------------------------------------------------------------------------- /1D_experiment/auxillary/gen_data.m: -------------------------------------------------------------------------------- 1 | % the function to generate simulated data 2 | % y_i = conv(a, x_i) + noise 3 | 4 | 5 | function [ Y, a, X] = gen_data(n, p, opts) 6 | 7 | X = zeros(n,p); 8 | 9 | % generate the kernel 10 | a = normc(randn(n,1)); 11 | 12 | % generate the data 13 | switch lower(opts.x_type) 14 | case 'bernoulli-gaussian' 15 | X = randn(n,p) .* (rand(n,p)<=opts.theta); 16 | case 'bernoulli-radmacher' 17 | X = (rand(n,p)<=opts.theta) .* (double(rand(n,p)<0.5) -0.5)*2 ; 18 | end 19 | 20 | Y = multi_conv( X, a, 0); 21 | 22 | Y = Y + opts.noise_level * randn(n,p); 23 | 24 | end -------------------------------------------------------------------------------- /2D_experiment/algorithms/rounding_2D.m: -------------------------------------------------------------------------------- 1 | function [ Z ] = rounding_2D( f, U, opts) 2 | 3 | %rounding using projected subgradient descent 4 | % Z = size(Y_p); 5 | % Obj = @(h)sum(sum( abs(fft(ifft(Y_p).*repmat(ifft(h),1,p))) )); 6 | Z = U; %initialization 7 | 8 | tau = 1; rho = 0.85; tau_threshold = 1e-15; tol = 0.1; 9 | funcval = []; 10 | 11 | for iter = 1 : opts.MaxIter 12 | 13 | [fval, Grad] = f.oracle(Z); 14 | 15 | % update: projected subgradient 16 | Z_new = Z - tau * orth_proj(U, Grad); 17 | 18 | fval_new = f.oracle(Z_new); 19 | 20 | if fval < fval_new && tau > tau_threshold 21 | tau = tau * rho; 22 | elseif fval - tol > fval_new && tau > tau_threshold 23 | Z = Z_new; %update 24 | % funcval = [funcval obj_new]; 25 | else 26 | Z = Z_new; %update 27 | return; 28 | end 29 | end 30 | % plot(funcval) 31 | 32 | end 33 | 34 | -------------------------------------------------------------------------------- /landscape_plot/func/func_l4.m: -------------------------------------------------------------------------------- 1 | classdef func_l4 < func_simple 2 | properties 3 | Y % an n by p observation matrix 4 | end 5 | 6 | methods 7 | function f = func_l4(Y) 8 | f.Y = Y; 9 | end 10 | 11 | % 0th and 1st order oracle 12 | function [fval, grad] = oracle(f, q) 13 | [n,p] = size(f.Y); 14 | 15 | % Return function value f(x) = sum_{i=1}^p ||C_{y_i}q||_4^4 16 | z = multi_conv(f.Y, q, 0); 17 | fval = - 1/(n*p) * sum(z(:).^4); 18 | 19 | if nargout <= 1; return; end 20 | 21 | % compute the Riemannian gradient 22 | grad = 4/(n*p) * sum( multi_conv( reversal(f.Y), z.^3, 1) , 2); 23 | grad = - orth_proj(q, grad); 24 | end 25 | 26 | 27 | end 28 | end 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /landscape_plot/func/func_l1.m: -------------------------------------------------------------------------------- 1 | classdef func_l1 < func_simple 2 | properties 3 | Y % an n by p observation matrix 4 | end 5 | 6 | methods 7 | function f = func_l1(Y) 8 | f.Y = Y; 9 | end 10 | 11 | % 0th and 1st order oracle 12 | function [fval, grad] = oracle(f, q) 13 | [n,p] = size(f.Y); 14 | 15 | % Return function value f(x) = sum_{i=1}^p ||C_{y_i}q||_1 16 | z = multi_conv(f.Y, q, 0); 17 | fval = 1/(n*p) * norm(z(:),1); 18 | 19 | if nargout <= 1; return; end 20 | 21 | % compute the Riemannian subgradient 22 | grad = 1/(n*p) * sum( multi_conv( reversal(f.Y), ... 23 | sign(z), 1) , 2); 24 | grad = orth_proj(q, grad); 25 | end 26 | 27 | 28 | end 29 | end 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /func/func_l1.m: -------------------------------------------------------------------------------- 1 | classdef func_l1 < func_simple 2 | properties 3 | Y % an n by p observation matrix 4 | end 5 | 6 | methods 7 | function f = func_l1(Y) 8 | f.Y = Y; 9 | end 10 | 11 | % 0th and 1st order oracle 12 | function [fval, grad] = oracle(f, q) 13 | [n,p] = size(f.Y); 14 | 15 | % Return function value f(x) = sum_{i=1}^p ||C_{y_i}q||_1 16 | z = multi_conv(f.Y, q, 0); 17 | fval = 1/(n*p) * norm(z(:),1); 18 | 19 | if nargout <= 1; return; end 20 | 21 | % compute the Riemannian subgradient 22 | grad = 1/(n*p) * sum( multi_conv( reversal(f.Y), ... 23 | sign(multi_conv(f.Y, q, 0)), 1) , 2); 24 | grad = orth_proj(q, grad); 25 | end 26 | 27 | 28 | end 29 | end 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /1D_experiment/func/func_l1.m: -------------------------------------------------------------------------------- 1 | classdef func_l1 < func_simple 2 | properties 3 | Y % an n by p observation matrix 4 | end 5 | 6 | methods 7 | function f = func_l1(Y) 8 | f.Y = Y; 9 | end 10 | 11 | % 0th and 1st order oracle 12 | function [fval, grad] = oracle(f, q) 13 | [n,p] = size(f.Y); 14 | 15 | % Return function value f(x) = sum_{i=1}^p ||C_{y_i}q||_1 16 | z = multi_conv(f.Y, q, 0); 17 | fval = 1/(n*p) * norm(z(:),1); 18 | 19 | if nargout <= 1; return; end 20 | 21 | % compute the Riemannian subgradient 22 | grad = 1/(n*p) * sum( multi_conv( reversal(f.Y), ... 23 | sign(multi_conv(f.Y, q, 0)), 1) , 2); 24 | grad = orth_proj(q, grad); 25 | end 26 | 27 | 28 | end 29 | end 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /func/func_l4.m: -------------------------------------------------------------------------------- 1 | classdef func_l4 < func_simple 2 | properties 3 | Y % an n by p observation matrix 4 | end 5 | 6 | methods 7 | function f = func_l4(Y) 8 | f.Y = Y; 9 | end 10 | 11 | % 0th and 1st order oracle 12 | function [fval, grad] = oracle(f, q) 13 | [n,p] = size(f.Y); 14 | 15 | % Return function value f(x) = sum_{i=1}^p ||C_{y_i}q||_4^4 16 | z = multi_conv(f.Y, q, 0); 17 | fval = - 1/(n*p) * sum(z(:).^4); 18 | 19 | if nargout <= 1; return; end 20 | 21 | % compute the Riemannian gradient 22 | tmp = multi_conv(f.Y, q, 0); 23 | grad = - 4/(n*p) * sum( multi_conv( reversal(f.Y), tmp.^3, 1) , 2); 24 | grad = orth_proj(q, grad); 25 | end 26 | 27 | 28 | end 29 | end 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /1D_experiment/func/func_l4.m: -------------------------------------------------------------------------------- 1 | classdef func_l4 < func_simple 2 | properties 3 | Y % an n by p observation matrix 4 | end 5 | 6 | methods 7 | function f = func_l4(Y) 8 | f.Y = Y; 9 | end 10 | 11 | % 0th and 1st order oracle 12 | function [fval, grad] = oracle(f, q) 13 | [n,p] = size(f.Y); 14 | 15 | % Return function value f(x) = sum_{i=1}^p ||C_{y_i}q||_4^4 16 | z = multi_conv(f.Y, q, 0); 17 | fval = - 1/(n*p) * sum(z(:).^4); 18 | 19 | if nargout <= 1; return; end 20 | 21 | % compute the Riemannian gradient 22 | tmp = multi_conv(f.Y, q, 0); 23 | grad = - 4/(n*p) * sum( multi_conv( reversal(f.Y), tmp.^3, 1) , 2); 24 | grad = orth_proj(q, grad); 25 | end 26 | 27 | 28 | end 29 | end 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /2D_experiment/func/func_l1_2D.m: -------------------------------------------------------------------------------- 1 | classdef func_l1_2D < func_simple 2 | properties 3 | Y % an n by p observation matrix 4 | end 5 | 6 | methods 7 | function f = func_l1_2D(Y) 8 | f.Y = Y; 9 | end 10 | 11 | % 0th and 1st order oracle 12 | function [fval, grad] = oracle(f, Z) 13 | [n(1),n(2),p] = size(f.Y); 14 | 15 | % Return function value f(x) = sum_{i=1}^p ||C_{y_i}q||_1 16 | C = multi_conv_2D(f.Y, Z); 17 | fval = 1/(n(1)*n(2)*p) * norm(C(:),1); 18 | 19 | if nargout <= 1; return; end 20 | 21 | % compute the Riemannian subgradient 22 | grad = 1/(n(1)*n(2)*p) * ... 23 | sum( multi_conv_2D( f.Y, sign(C), 'adj-left') , 3); 24 | % grad = orth_proj(Z, grad); 25 | end 26 | 27 | 28 | end 29 | end 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /2D_experiment/func/func_l4_2D.m: -------------------------------------------------------------------------------- 1 | classdef func_l4_2D < func_simple 2 | properties 3 | Y % an n by p observation matrix 4 | end 5 | 6 | methods 7 | function f = func_l4_2D(Y) 8 | f.Y = Y; 9 | end 10 | 11 | % 0th and 1st order oracle 12 | function [fval, grad] = oracle(f, Z) 13 | [n(1),n(2),p] = size(f.Y); 14 | 15 | % Return function value f(x) = sum_{i=1}^p ||C_{y_i}q||_4^4 16 | C = multi_conv_2D(f.Y, Z); 17 | fval = - 1/(n(1)*n(2)*p) * sum(C(:).^4); 18 | 19 | if nargout <= 1; return; end 20 | 21 | % compute the Riemannian gradient 22 | grad = - 4/(n(1)*n(2)*p) * ... 23 | sum( multi_conv_2D( f.Y, C.^3, 'adj-left'), 3); 24 | % grad = orth_proj(Z, grad); 25 | end 26 | 27 | 28 | end 29 | end 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /landscape_plot/auxillary/gen_data.m: -------------------------------------------------------------------------------- 1 | % the function to generate simulated data 2 | % y_i = conv(a, x_i) + noise 3 | 4 | 5 | function [ Y, a, X] = gen_data(n, p, opts) 6 | 7 | X = zeros(n,p); 8 | Y = zeros(n,p); 9 | 10 | % generate the kernel 11 | a = normc(randn(n,1)); 12 | 13 | % generate the data 14 | switch lower(opts.x_type) 15 | case 'bernoulli-gaussian' 16 | X = randn(n,p) .* (rand(n,p)<=opts.theta); 17 | case 'bernoulli-radmacher' 18 | X = (rand(n,p)<=opts.theta) .* (double(rand(n,p)<0.5) -0.5)*2 ; 19 | end 20 | 21 | Y = multi_conv( X, a, 0); 22 | 23 | % for k = 1:p 24 | % switch lower(opts.x_type) 25 | % case 'bernoulli-gaussian' 26 | % X(:,k) = randn(n,1) .* (rand(n,1)<=opts.theta); 27 | % case 'bernoulli-radmacher' 28 | % X(:,k) = (rand(m,1)<=opts.theta) .* (double(rand(m,1)<0.5) -0.5)*2 ; 29 | % end 30 | % 31 | % Y(:,k) = cconv(a, X(:,k),n); 32 | % end 33 | 34 | Y = Y + opts.noise_level * randn(n,p); 35 | 36 | end -------------------------------------------------------------------------------- /2D_experiment/auxillary/gen_data_2D.m: -------------------------------------------------------------------------------- 1 | % the function to generate simulated data 2 | % y_i = conv(a, x_i) + noise 3 | 4 | 5 | function [ Y, A, X] = gen_data_2D(n, p, opts) 6 | 7 | X = zeros([n,p]); 8 | Y = zeros([n,p]); 9 | 10 | % generate the kernel 11 | A = randn(n); A = A / norm(A,'fro'); 12 | 13 | % generate the data 14 | switch lower(opts.x_type) 15 | case 'bernoulli-gaussian' 16 | X = randn([n,p]) .* (rand([n,p])<=opts.theta); 17 | case 'bernoulli-radmacher' 18 | X = (rand([n,p])<=opts.theta) .* (double(rand([n,p])<0.5) -0.5)*2 ; 19 | end 20 | 21 | Y = multi_conv_2D( A, X); 22 | 23 | % for k = 1:p 24 | % switch lower(opts.x_type) 25 | % case 'bernoulli-gaussian' 26 | % X(:,k) = randn(n,1) .* (rand(n,1)<=opts.theta); 27 | % case 'bernoulli-radmacher' 28 | % X(:,k) = (rand(m,1)<=opts.theta) .* (double(rand(m,1)<0.5) -0.5)*2 ; 29 | % end 30 | % 31 | % Y(:,k) = cconv(a, X(:,k),n); 32 | % end 33 | 34 | Y = Y + opts.noise_level * randn([n,p]); 35 | 36 | end 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /auxillary/rounding.m: -------------------------------------------------------------------------------- 1 | function [ q, dist2a ] = rounding( r,Y_p,opts); 2 | 3 | %rounding using projected subgradient descent 4 | [n,p] = size(Y_p); 5 | Obj = @(h) 1/(n*p) *sum(sum( abs(fft(ifft(Y_p).*repmat(ifft(h),1,p))) )); 6 | q_0 = r; %initialization 7 | q = q_0; 8 | mu = 1; rho = 0.85; mu_threshold = 1e-15; 9 | dist2a = []; 10 | iter = 1; 11 | while iter <= 1e2 12 | grad = 1/(n*p) * sum( multi_conv( reversal(Y_p),sign(multi_conv(Y_p, q, 0)), 1) , 2); 13 | %temporary update 14 | q_new = q - mu*grad; 15 | %projection 16 | q_new = q_new - (r'*q_new -1) /norm(q_new,'fro')^2 *r; 17 | obj_old = Obj(q); obj_new = Obj(q_new); 18 | grad_norm = norm(grad)^2; 19 | alpha = 1e-3; 20 | if obj_old <= obj_new && mu>mu_threshold 21 | mu = mu*rho; 22 | elseif obj_old > obj_new && mu>mu_threshold 23 | q = q_new; %update 24 | iter = iter +1; 25 | if nargin > 2 26 | precond_q = real(ifft( opts.precond .* fft(q))); 27 | a_bar = normc(precond_q); a_bar = normc(real(ifft(1./fft(a_bar)))); 28 | dist2a = [dist2a dist_a(opts.a_0,a_bar)]; 29 | end 30 | elseif mu < mu_threshold 31 | q = q_new; %update 32 | return; 33 | end 34 | 35 | end 36 | 37 | end 38 | 39 | 40 | -------------------------------------------------------------------------------- /1D_experiment/auxillary/rounding.m: -------------------------------------------------------------------------------- 1 | function [ q, dist2a ] = rounding( r,Y_p,opts); 2 | 3 | %rounding using projected subgradient descent 4 | [n,p] = size(Y_p); 5 | Obj = @(h) 1/(n*p) *sum(sum( abs(fft(ifft(Y_p).*repmat(ifft(h),1,p))) )); 6 | q_0 = r; %initialization 7 | q = q_0; 8 | mu = 1; rho = 0.85; mu_threshold = 1e-15; 9 | dist2a = []; 10 | iter = 1; 11 | while iter <= 1e2 12 | grad = 1/(n*p) * sum( multi_conv( reversal(Y_p),sign(multi_conv(Y_p, q, 0)), 1) , 2); 13 | %temporary update 14 | q_new = q - mu*grad; 15 | %projection 16 | q_new = q_new - (r'*q_new -1) /norm(q_new,'fro')^2 *r; 17 | obj_old = Obj(q); obj_new = Obj(q_new); 18 | grad_norm = norm(grad)^2; 19 | alpha = 1e-3; 20 | if obj_old <= obj_new && mu>mu_threshold 21 | mu = mu*rho; 22 | elseif obj_old > obj_new && mu>mu_threshold 23 | q = q_new; %update 24 | iter = iter +1; 25 | if nargin > 2 26 | precond_q = real(ifft( opts.precond .* fft(q))); 27 | a_bar = normc(precond_q); a_bar = normc(real(ifft(1./fft(a_bar)))); 28 | dist2a = [dist2a dist_a(opts.a_0,a_bar)]; 29 | end 30 | elseif mu < mu_threshold 31 | q = q_new; %update 32 | return; 33 | end 34 | 35 | end 36 | 37 | end 38 | 39 | 40 | -------------------------------------------------------------------------------- /2D_experiment/auxillary/multi_conv_2D.m: -------------------------------------------------------------------------------- 1 | % A = {A_1,A_2, ..., A_p} 2 | % C = {C_1,C_2, ..., C_p} 3 | % 4 | % if flag = 0, B is a matrix 5 | % C_i = conv( A_i, B) 6 | % 7 | % if flag = 1, B is a tensor of the same size of A 8 | % C_i = conv( A_i, B_i) 9 | % 10 | function C = multi_conv_2D(A, B, varargin) 11 | 12 | numvararg = numel(varargin); 13 | 14 | if numvararg > 1 15 | error('Too many input arguments.'); 16 | end 17 | 18 | [~,~,p] = size(A); 19 | 20 | 21 | A_hat = fft2(A); B_hat = fft2(B); 22 | 23 | % if numvararg >= 1 && ~isempty(varargin{1}) 24 | % if strcmp(varargin{1}, 'multi-left') 25 | % A_hat = repmat( A_hat, 1, 1, p); 26 | % elseif strcmp(varargin{1}, 'multi-right') 27 | % B_hat = repmat( B_hat, 1, 1, p); 28 | % else 29 | % 30 | % end 31 | % end 32 | 33 | if numvararg >= 1 && ~isempty(varargin{1}) 34 | 35 | if strcmp(varargin{1}, 'adj-left') 36 | A_hat = conj(A_hat); 37 | elseif strcmp(varargin{1}, 'adj-right') 38 | B_hat = conj(B_hat); 39 | elseif strcmp(varargin{1}, 'adj-both') 40 | A_hat = conj(A_hat); 41 | B_hat = conj(B_hat); 42 | else 43 | 44 | end 45 | end 46 | 47 | C = real( ifft2( bsxfun(@times, A_hat, B_hat) ) ); 48 | % C = real( ifft2( A_hat .* B_hat ) ); 49 | 50 | end 51 | 52 | -------------------------------------------------------------------------------- /2D_experiment/auxillary/cconvfft2.m: -------------------------------------------------------------------------------- 1 | function [ C ] = cconvfft2( A, B, varargin ) 2 | %CCONVFFT2 FFT implementation of 2D cyclic convolution 3 | % C = cconvfft(A, B) convolves A and B using the larger size 4 | % 5 | % C = cconvfft(A, B, N) convolves A and B using size N 6 | % 7 | % C = cconvfft(A, B, N, adj) convolves A and B using size N, adj is a 8 | % string chosen from: 'left', right', or 'both'. Choosing 'left' convoles 9 | % B with the adjoint kernel of A, and vice versa. Choosing 'both' 10 | % convolves the adjoint kernels of both A and B. 11 | % 12 | % Both N and adj can be left empty. 13 | 14 | numvararg = numel(varargin); 15 | 16 | if numvararg > 2 17 | error('Too many input arguments.'); 18 | end 19 | 20 | N = max(size(A), size(B)); 21 | if numvararg >= 1 && ~isempty(varargin{1}) 22 | N = varargin{1}; 23 | end 24 | 25 | A_hat = fft2(A,N(1),N(2)); 26 | B_hat = fft2(B,N(1),N(2)); 27 | if numvararg >= 2 && ~isempty(varargin{2}) 28 | if strcmp(varargin{2}, 'left') 29 | A_hat = conj(A_hat); 30 | elseif strcmp(varargin{2}, 'right') 31 | B_hat = conj(B_hat); 32 | elseif strcmp(varargin{2}, 'both') 33 | A_hat = conj(A_hat); 34 | B_hat = conj(B_hat); 35 | else 36 | end 37 | end 38 | 39 | C = ifft2( A_hat .* B_hat ); 40 | 41 | end 42 | 43 | -------------------------------------------------------------------------------- /landscape_plot/func/func_huber.m: -------------------------------------------------------------------------------- 1 | classdef func_huber < func_simple 2 | properties 3 | Y % an n by p observation matrix 4 | mu % smoothing parameter 5 | end 6 | 7 | methods 8 | function f = func_huber(Y, mu) 9 | f.Y = Y; 10 | f.mu = mu; 11 | end 12 | 13 | % 0th and 1st order oracle 14 | function [fval, grad] = oracle(f, q) 15 | [n,p] = size(f.Y); 16 | 17 | % Return function value f(x) 18 | z = multi_conv(f.Y, q, 0); 19 | fval = 1/(n*p) * huber(z, f.mu); 20 | 21 | if nargout <= 1; return; end 22 | 23 | % compute the Riemannian gradient 24 | 25 | grad = 1/(n*p) * sum( multi_conv( reversal(f.Y), ... 26 | huber_grad(z, f.mu), 1), 2); 27 | grad = orth_proj(q, grad); 28 | 29 | end 30 | 31 | 32 | end 33 | end 34 | 35 | % evaluate the function value of huber 36 | function f_val = huber(z, mu) 37 | 38 | h = abs(z) .* (abs(z)>=mu) + (mu/2 + z.^2/2/mu) .* (abs(z)=mu) + (z/mu) .* (abs(z)=mu) + (mu/2 + z.^2/2/mu) .* (abs(z)=mu) + (z/mu) .* (abs(z)=mu) + (mu/2 + z.^2/2/mu) .* (abs(z)=mu) + (z/mu) .* (abs(z)=mu) + (mu/2 + z.^2/2/mu) .* (abs(z)=mu) + (z/mu) .* (abs(z)=mu) + (mu/2 + z.^2/2/mu) .* (abs(z)=mu) + (z/mu) .* (abs(z) 1e2 21 | grad = 1e2*grad/norm(grad); 22 | end 23 | % print result 24 | F_val(iter) = fval; 25 | precond_q = real(ifft( opts.precond .* fft(q))); 26 | a_bar = normc(precond_q); a_bar = normc(real(ifft(1./fft(a_bar)))); 27 | dist2a(iter) = dist_a(opts.a_0,a_bar); 28 | 29 | 30 | if(opts.isprint) 31 | fprintf('iter = %d, f_val = %f, err = %f ...\n',... 32 | iter, F_val(iter), Err(iter)); 33 | end 34 | 35 | % take a Riemannian gradient step 36 | if(opts.islinesearch) 37 | [q_new,linesearch_tau] = linesearch_new(f, q, fval, grad,linesearch_tau); 38 | tau_stack = [tau_stack linesearch_tau]; 39 | else 40 | q_new = normc(q - tau * grad); 41 | end 42 | 43 | 44 | q = q_new; 45 | 46 | 47 | %re-initialization 48 | if iter == opts.MaxIter 49 | if Numinitzed < opts.NumReinit 50 | iter = 0; 51 | q = normc(randn(size(q)) ); 52 | Numinitzed = Numinitzed +1; 53 | end 54 | end 55 | 56 | iter = iter + 1; 57 | end 58 | % figure; plot(F_val) 59 | % figure;semilogy(tau_stack) 60 | 61 | end -------------------------------------------------------------------------------- /1D_experiment/algorithms/grad_descent.m: -------------------------------------------------------------------------------- 1 | function [q, F_val, Err,dist2a] = grad_descent(f, opts) 2 | % f: a function object that implements [fval, grad] = f.oracle(x) 3 | q = opts.q_init; 4 | 5 | tau = opts.tau; %preset stepsize 6 | linesearch_tau = 0.1; 7 | 8 | F_val = zeros(opts.MaxIter,1); 9 | Err = zeros(opts.MaxIter,1); 10 | dist2a = zeros(opts.MaxIter,1); 11 | 12 | tau_stack = []; 13 | 14 | Numinitzed = 1; 15 | iter = 1; 16 | while iter <= opts.MaxIter 17 | 18 | [fval, grad] = f.oracle(q); 19 | 20 | if norm(grad) > 1e2 21 | grad = 1e2*grad/norm(grad); 22 | end 23 | % print result 24 | F_val(iter) = fval; 25 | precond_q = real(ifft( opts.precond .* fft(q))); 26 | a_bar = normc(precond_q); a_bar = normc(real(ifft(1./fft(a_bar)))); 27 | dist2a(iter) = dist_a(opts.a_0,a_bar); 28 | 29 | 30 | if(opts.isprint) 31 | fprintf('iter = %d, f_val = %f, err = %f ...\n',... 32 | iter, F_val(iter), Err(iter)); 33 | end 34 | 35 | % take a Riemannian gradient step 36 | if(opts.islinesearch) 37 | [q_new,linesearch_tau] = linesearch_new(f, q, fval, grad,linesearch_tau); 38 | tau_stack = [tau_stack linesearch_tau]; 39 | else 40 | q_new = normc(q - tau * grad); 41 | end 42 | 43 | 44 | q = q_new; 45 | 46 | 47 | %re-initialization 48 | if iter == opts.MaxIter 49 | if Numinitzed < opts.NumReinit 50 | iter = 0; 51 | q = normc(randn(size(q)) ); 52 | Numinitzed = Numinitzed +1; 53 | end 54 | end 55 | 56 | iter = iter + 1; 57 | end 58 | % figure; plot(F_val) 59 | % figure;semilogy(tau_stack) 60 | 61 | end -------------------------------------------------------------------------------- /ReadMe.txt: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf830 2 | {\fonttbl\f0\fnil\fcharset0 HelveticaNeue;\f1\fmodern\fcharset0 Courier;\f2\fnil\fcharset0 LucidaGrande; 3 | } 4 | {\colortbl;\red255\green255\blue255;\red0\green0\blue0;\red0\green0\blue0;} 5 | {\*\expandedcolortbl;;\cssrgb\c0\c0\c0;\csgenericrgb\c0\c0\c0;} 6 | {\*\listtable{\list\listtemplateid1\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{square\}}{\leveltext\leveltemplateid1\'01\uc0\u9642 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listname ;}\listid1}} 7 | {\*\listoverridetable{\listoverride\listid1\listoverridecount0\ls1}} 8 | \margl1440\margr1440\vieww10800\viewh8400\viewkind0 9 | \deftab720 10 | \pard\pardeftab720\partightenfactor0 11 | 12 | \f0\fs36 \cf2 \expnd0\expndtw0\kerning0 13 | The code is for the following paper: \ 14 | \pard\pardeftab720\partightenfactor0 15 | 16 | \f1 \cf3 \kerning1\expnd0\expndtw0 ``A Nonconvex Approach for Exact and Efficient Multichannel Sparse Blind Deconvolution'',\ 17 | Qing Qu, Xiao Li and Zhihui Zhu. 18 | \fs24 \ 19 | \ 20 | 21 | \fs36 We have include: \ 22 | \pard\tx220\tx720\pardeftab720\li720\fi-720\partightenfactor0 23 | \ls1\ilvl0\cf3 {\listtext 24 | \f2 \uc0\u9642 25 | \f1 }landscape plot which will reproduce Figure 1 of our paper, run \'91plot_landscape.m\'92. \ 26 | {\listtext 27 | \f2 \uc0\u9642 28 | \f1 }1D experiments which will reproduce Figure 3 of our paper, run \'91convergence.m\'92\ 29 | {\listtext 30 | \f2 \uc0\u9642 31 | \f1 }2D experiments which includes the 2D extension of the 1D experiments, run \'91test_2D.m\'92.\ 32 | \pard\tx720\pardeftab720\partightenfactor0 33 | \cf3 \ 34 | If the code is useful to you, please cite our paper. 35 | \fs24 \ 36 | \ 37 | } -------------------------------------------------------------------------------- /2D_experiment/algorithms/grad_descent_2D.m: -------------------------------------------------------------------------------- 1 | function [Z, F_val, Err] = grad_descent_2D(f, opts) 2 | % f: a function object that implements [fval, grad] = f.oracle(x) 3 | Z = opts.Z_init; 4 | 5 | tau = opts.tau; %preset stepsize 6 | linesearch_tau = 0.1; 7 | 8 | F_val = zeros(opts.MaxIter,1); 9 | Err = zeros(opts.MaxIter,1); 10 | 11 | tau_stack = []; 12 | 13 | Numinitzed = 1; 14 | iter = 1; 15 | while iter <= opts.MaxIter 16 | 17 | [fval, Grad] = f.oracle(Z); 18 | 19 | Grad = orth_proj(Z, Grad); % compute Riemannian gradient 20 | 21 | if norm(Grad(:)) > 1e2 22 | Grad = 1e2 * Grad / norm( Grad(:) ); 23 | end 24 | 25 | % print result 26 | F_val(iter) = fval; 27 | 28 | if(opts.isprint) 29 | fprintf('iter = %d, f_val = %f, err = %f ...\n',... 30 | iter, F_val(iter), Err(iter)); 31 | end 32 | 33 | % take a Riemannian gradient step 34 | if(opts.islinesearch) 35 | [Z_new,linesearch_tau] = linesearch_2D(f, Z, fval, Grad, linesearch_tau); 36 | tau_stack = [tau_stack linesearch_tau]; 37 | else 38 | Z_new = normalize(Z - tau * Grad); 39 | end 40 | 41 | 42 | 43 | if(opts.truth) 44 | Z_p = real(ifft2( V.* fft2(Z_new))); 45 | Err(iter) = dist_2D(opts.A_0, Z_p); 46 | if(Err(iter) <= opts.tol) 47 | return; 48 | end 49 | end 50 | 51 | Z = Z_new; 52 | 53 | if(opts.truth) 54 | %re-initialization 55 | if iter == opts.MaxIter 56 | if Numinitzed < opts.NumReinit 57 | iter = 0; 58 | Z = normc(randn(size(Z)) ); 59 | Numinitzed = Numinitzed +1; 60 | end 61 | end 62 | end 63 | 64 | iter = iter + 1; 65 | end 66 | % figure; plot(F_val) 67 | % figure;semilogy(diff_q) 68 | 69 | end -------------------------------------------------------------------------------- /2D_experiment/test_2D.m: -------------------------------------------------------------------------------- 1 | %% 2 | %========================================================================== 3 | %This Demo solves the 2D multi-chanel blind deconvolution problem in the 4 | %following paper: 5 | % 6 | %``A Nonconvex Approach for Exact and Efficient Multichannel Sparse Blind 7 | % Deconvolution'', 8 | %Qing Qu, Xiao Li, Zhihui Zhu. 9 | % 10 | %where it aims to recovers both the channel $A$ and sparse signals 11 | %${X_i}_{i=1}^p$ from the measurements $Y_i$. These three terms are 12 | %linked by the gemerative model: 13 | % 14 | % $$ Y_i = A * X_i, i = 1,...,p $$ 15 | %where '*' represents 2D circulant convolution, the same applies to the sequel. 16 | % 17 | %This Demo solves the following optimization problem using Riemannian 18 | %gradient descent 19 | % 20 | % $$ min_{Z} 1/n^2p sum_{i=1}^p H_mu(\overline_{Y}_i*Z), s.t. \|Z\|_F = 1 $$ 21 | %where $\overline_{Y}_i$ denotes the preconditioned version of $Y_i$, $H_mu$ 22 | %represents huber function with parameter $mu$. Suppose the algorithm 23 | %returns the optimal solution of the above problem: $Z^\star$, then the 24 | %target kernel and the sparse signals are recovered by 25 | % 26 | % $$ A^\star = F^{-1}( 1./ ( F(V * Z^\star) ) ), X_i^\star = (Y_i*V)*Z^\star $$ 27 | %where $F(.)$ represents fourier tranform. 28 | %========================================================================== 29 | 30 | %% 31 | clc;close all;clear all; 32 | 33 | folder = fileparts(which(mfilename)); 34 | addpath(genpath(folder)); 35 | 36 | %% setting parameters for the problem 37 | n = [10,10]; % size of the kernel 38 | p = 100; % number of samples 39 | gen_opts.x_type = 'bernoulli-gaussian'; % sparsity pattern 40 | gen_opts.noise_level = 0; % no noise 41 | gen_opts.theta = 0.2; % sparsity level 42 | mu = 1e-2; % the smoothing parameter for huber 43 | 44 | %% setting parameter for the algorithm 45 | opts.islinesearch = true; 46 | opts.isprint = false; 47 | opts.tol = 1e-10; 48 | opts.tau = 1e-2; 49 | opts.MaxIter = 2e2; 50 | opts.rounding = true; 51 | opts.NumReinit = 1; 52 | opts.truth = false; 53 | opts.rounding = false; 54 | 55 | Z_init = randn(n); 56 | opts.Z_init = Z_init / norm( Z_init(:) ); 57 | 58 | loss_type = 'huber'; % choose l1, huber, l4 59 | 60 | %% generate and preprocess the data 61 | [ Y, A_0, X_0] = gen_data_2D(n, p, gen_opts); % generate the data 62 | 63 | % precondition of the data 64 | V = (1/(n(1)*n(2)*p) * sum( abs(fft2(Y)).^2,3) ).^(-1/2); 65 | Y_p = ifft2( bsxfun(@times, fft2(Y), V) ); 66 | opts.V = V; 67 | opts.A_0 = A_0; 68 | 69 | switch lower(loss_type) 70 | case 'l1' 71 | f = func_l1_2D(Y_p); 72 | case 'huber' 73 | f = func_huber_2D(Y_p, mu); 74 | case 'l4' 75 | f = func_l4_2D(Y_p); 76 | end 77 | 78 | %% solving the problem 79 | 80 | % phase-1: gradient descent 81 | [Z_r, F_val, Err] = grad_descent_2D(f, opts); 82 | precond_Z = real(ifft2( V.* fft2(Z_r))); 83 | dist_2D(A_0,precond_Z) 84 | 85 | 86 | 87 | % phase-2: rounding 88 | if opts.rounding 89 | opts_r.MaxIter = 2e2; 90 | R = Z_r; 91 | f = func_l1_2D(Y_p); 92 | Z = rounding_2D(f, R, opts_r); 93 | precond_Z = real(ifft2( V.* fft2(Z))); 94 | dist_2D(A_0,precond_Z) 95 | else 96 | Z = Z_r; 97 | end 98 | 99 | 100 | %% show the results 101 | precond_Z = real(ifft2( V.* fft2(Z))); 102 | figure 103 | imagesc(abs(cconvfft2(precond_Z, A_0))) 104 | colormap(gray(255)); 105 | cbh = colorbar; set(cbh,'YTick',[0,1]) 106 | -------------------------------------------------------------------------------- /landscape_plot/plot_landscape.m: -------------------------------------------------------------------------------- 1 | clc;close all; clear all; 2 | 3 | addpath(genpath(pwd)); 4 | 5 | % rng(1,'twister'); % fix the seed for random number generation 6 | 7 | % parameter settings 8 | isprint = true; 9 | 10 | gen_opts.x_type = 'bernoulli-gaussian'; 11 | gen_opts.noise_level = 0; % no noise 12 | gen_opts.theta = 0.2; % sparsity level 13 | 14 | % tVec = 0:.01:1; 15 | % thetaVec = 0:.01:2*pi; 16 | % numPts = length(tVec) * length(thetaVec); 17 | 18 | mu = 0.01;% smoothing parameters 19 | p = 100;% number of samples 20 | n = 3; 21 | 22 | 23 | 24 | % generate random data 25 | 26 | [ Y, a, X] = gen_data( n, p, gen_opts); 27 | 28 | q1 = real(ifft((fft(a)).^(-1))); q1 = q1/norm(q1); 29 | q2 = circshift(q1,1); 30 | q3 = circshift(q1,2); 31 | 32 | f_l1 = func_l1(Y); 33 | f_huber = func_huber(Y,mu); 34 | f_l4 = func_l4(Y); 35 | 36 | ss = 1; 37 | % precondition matrix 38 | 39 | precond = sqrt(gen_opts.theta *n*p) * ... 40 | (sum(abs(ifft(Y)).^2 , 2)).^(-1/2); % preconditioning vector 41 | 42 | precond_i = precond.^(-1); 43 | 44 | q1_p = ifft( precond.^(-1) .* fft(q1) ); q1_p = q1_p /norm(q1_p); 45 | q2_p = circshift(q1_p,1); 46 | q3_p = circshift(q1_p,2); 47 | 48 | Y_p = fft( ifft(Y) .* repmat(precond,1,p) ); % preconditioned Y 49 | 50 | f_l1_p = func_l1(Y_p); 51 | f_huber_p = func_huber(Y_p,mu); 52 | f_l4_p = func_l4(Y_p); 53 | 54 | 55 | % generate spherical coordinate 56 | U = eye(n); 57 | 58 | R = [0:.01:.75, .75:.005:.95, .95:.0005:.99, .99:.0001:1]; 59 | T = 0:.005:(2*pi+.05); 60 | 61 | rm = max(R); 62 | 63 | X = R' * cos(T); 64 | Y = R' * sin(T); 65 | Z = sqrt(max(1 - X.^2 - Y.^2,0)); 66 | 67 | X = [X; X]; 68 | Y = [Y; Y]; 69 | Z = [Z; -Z]; 70 | 71 | [x_1, x_2] = size(X); 72 | 73 | fnVals = zeros([x_1, x_2, 3]); % record function value without preconditioning 74 | fnVals_p = zeros([x_1, x_2, 3]); % record function value with preconditioning 75 | 76 | % record function value 77 | 78 | for i = 1 : x_1 79 | for j = 1 : x_2 80 | 81 | % print itermediate steps 82 | if(isprint == true) 83 | % fprintf('L_x1 = %d, x1 = %d, L_x2 = %d, x2 = %d...\n',... 84 | % x_1, i, x_2, j); 85 | end 86 | 87 | q = [X(i,j); Y(i,j); Z(i,j)]; 88 | 89 | % evaluate l1, huber, l4 loss value 90 | fnVals(i,j,1) = f_l1.oracle(q); 91 | fnVals(i,j,2) = f_huber.oracle(q); 92 | fnVals(i,j,3) = f_l4.oracle(q); 93 | 94 | 95 | % evaluate preconditioned l1, huber, l4 loss value 96 | fnVals_p(i,j,1) = f_l1_p.oracle(q); 97 | fnVals_p(i,j,2) = f_huber_p.oracle(q); 98 | fnVals_p(i,j,3) = f_l4_p.oracle(q); 99 | 100 | end 101 | end 102 | 103 | % normalize the function value 104 | for t = 1:3 105 | tmp_min = fnVals(:,:,t); 106 | fnVals(:,:,t) = fnVals(:,:,t) - min(tmp_min(:)); 107 | tmp_max = fnVals(:,:,t); 108 | fnVals(:,:,t) = fnVals(:,:,t) / max(tmp_max(:)); 109 | 110 | tmp_min = fnVals_p(:,:,t); 111 | fnVals_p(:,:,t) = fnVals_p(:,:,t) - min(tmp_min(:)); 112 | tmp_max = fnVals_p(:,:,t); 113 | fnVals_p(:,:,t) = fnVals_p(:,:,t) / max(tmp_max(:)); 114 | 115 | end 116 | 117 | % save('data.mat','q1','q2','q3','q1_p','q2_p','q3_p','X','Y','Z','fnVals','fnVals_p'); 118 | 119 | % plot the landscape over 3D sphere 120 | r = 1.005; 121 | Marker = 25; 122 | text = {'l1','huber','l4'}; 123 | text_p = {'l1-p','huber-p','l4-p'}; 124 | 125 | for t = 1:3 126 | figure; 127 | surf(X,Y,Z,fnVals(:,:,t),'EdgeAlpha',0); 128 | axis off; axis equal; 129 | title(text{t}); 130 | 131 | hold on; 132 | plot3(r*q1(1),r*q1(2),r*q1(3),'r.','MarkerSize',Marker); 133 | plot3(r*q2(1),r*q2(2),r*q2(3),'r.','MarkerSize',Marker); 134 | plot3(r*q3(1),r*q3(2),r*q3(3),'r.','MarkerSize',Marker); 135 | plot3(-r*q1(1),-r*q1(2),-r*q1(3),'r.','MarkerSize',Marker); 136 | plot3(-r*q2(1),-r*q2(2),-r*q2(3),'r.','MarkerSize',Marker); 137 | plot3(-r*q3(1),-r*q3(2),-r*q3(3),'r.','MarkerSize',Marker); 138 | 139 | figure; 140 | surf(X,Y,Z,fnVals_p(:,:,t),'EdgeAlpha',0); 141 | axis off; axis equal; 142 | title(text_p{t}); 143 | 144 | hold on; 145 | 146 | plot3(r*q1_p(1),r*q1_p(2),r*q1_p(3),'r.','MarkerSize',Marker); 147 | plot3(r*q2_p(1),r*q2_p(2),r*q2_p(3),'r.','MarkerSize',Marker); 148 | plot3(r*q3_p(1),r*q3_p(2),r*q3_p(3),'r.','MarkerSize',Marker); 149 | plot3(-r*q1_p(1),-r*q1_p(2),-r*q1_p(3),'r.','MarkerSize',Marker); 150 | plot3(-r*q2_p(1),-r*q2_p(2),-r*q2_p(3),'r.','MarkerSize',Marker); 151 | plot3(-r*q3_p(1),-r*q3_p(2),-r*q3_p(3),'r.','MarkerSize',Marker); 152 | 153 | end 154 | 155 | 156 | % figure(1); 157 | % 158 | % r = 1.005; 159 | % Marker = 15; 160 | % 161 | % hold on; 162 | % surf(X,Y,Z,F_val,'EdgeAlpha',0); 163 | % axis off; axis equal; 164 | % 165 | % plot3(r*u1'*a0,r*u2'*a0,r*u3'*a0,'r.','MarkerSize',Marker); 166 | % plot3(r*u1'*a1,r*u2'*a1,r*u3'*a1,'r.','MarkerSize',Marker); 167 | % plot3(r*u1'*a2,r*u2'*a2,r*u3'*a2,'r.','MarkerSize',Marker); 168 | % plot3(-r*u1'*a0,-r*u2'*a0,-r*u3'*a0,'r.','MarkerSize',Marker); 169 | % plot3(-r*u1'*a1,-r*u2'*a1,-r*u3'*a1,'r.','MarkerSize',Marker); 170 | % plot3(-r*u1'*a2,-r*u2'*a2,-r*u3'*a2,'r.','MarkerSize',Marker); 171 | 172 | 173 | 174 | 175 | 176 | 177 | -------------------------------------------------------------------------------- /auxillary/circulant.m: -------------------------------------------------------------------------------- 1 | function C = circulant(vec,direction) 2 | %CIRCULANT Circulant Matrix. 3 | % CIRCULANT(V,DIR) generates a square circulant matrix using the vector V 4 | % as the first row of the result if V is a row vector or as the first 5 | % column of the result if V is a column vector. V may be any numeric data 6 | % type or a character string. 7 | % DIR is an optional input argument that describes the circular shift 8 | % direction. If DIR = 1, the shift is forward. If DIR = -1, the shift is 9 | % backward. If DIR is not provided, DIR = 1 is used. 10 | % 11 | % References: 12 | % http://en.wikipedia.org/wiki/Circulant_matrix 13 | % http://mathworld.wolfram.com/CirculantMatrix.html 14 | % 15 | % Example: 16 | % A backwards (-1) shift, result is a symmetric 17 | % matrix. 18 | % 19 | % circulant([2 3 5 7 11 13],-1) 20 | % 21 | % ans = 22 | % 2 3 5 7 11 13 23 | % 3 5 7 11 13 2 24 | % 5 7 11 13 2 3 25 | % 7 11 13 2 3 5 26 | % 11 13 2 3 5 7 27 | % 13 2 3 5 7 11 28 | % 29 | % Example: 30 | % A forwards (+1) shifted circulant matrix, 31 | % built using the first row defined by vec. 32 | % 33 | % circulant([2 3 5 7 11],1) 34 | % 35 | % ans = 36 | % 2 3 5 7 11 37 | % 11 2 3 5 7 38 | % 7 11 2 3 5 39 | % 5 7 11 2 3 40 | % 3 5 7 11 2 41 | % 42 | % Example: 43 | % A postively shifted circulant matrix, built 44 | % from vec as the first column. 45 | % 46 | % circulant([2;3;5;7;11],1) 47 | % ans = 48 | % 2 11 7 5 3 49 | % 3 2 11 7 5 50 | % 5 3 2 11 7 51 | % 7 5 3 2 11 52 | % 11 7 5 3 2 53 | % 54 | % Example: 55 | % A negative shift applied to build a character 56 | % circulant matrix. 57 | % 58 | % circulant('abcdefghij',-1) 59 | % 60 | % ans = 61 | % abcdefghij 62 | % bcdefghija 63 | % cdefghijab 64 | % defghijabc 65 | % efghijabcd 66 | % fghijabcde 67 | % ghijabcdef 68 | % hijabcdefg 69 | % ijabcdefgh 70 | % jabcdefghi 71 | % 72 | % See also: toeplitz, hankel 73 | % 74 | % Author: John D'Errico 75 | % (The help was re-written to be more clear 76 | % and concise by Duane Hanselman.) 77 | % e-mail: woodchips@rochester.rr.com 78 | % Release: 1.1 79 | % Release date: 2/3/09 80 | 81 | 82 | % error checks 83 | if (nargin<1) || (nargin > 2) 84 | error('circulant takes only one or two input arguments') 85 | end 86 | 87 | if (nargin < 2) || isempty(direction) 88 | direction = 1; 89 | elseif ~ismember(direction,[1,-1]) 90 | error('direction must be either +1 or -1 if it is supplied') 91 | end 92 | 93 | % verify that vec is a vector or a scalar 94 | if ~isvector(vec) 95 | error('vec must be a vector') 96 | elseif length(vec) == 1 97 | % vec was a scalar 98 | C = vec; 99 | return 100 | end 101 | 102 | % how long is vec? 103 | n = length(vec); 104 | n1 = n-1; 105 | 106 | if direction == -1 107 | % negative circular shift. 108 | 109 | % create the circulant matrix. Yeah, I know, 110 | % it only takes one line using bsxfun. 111 | % 112 | % Alternatively, it can be done as a hankel 113 | % matrix variant. I like the bsxfun construct 114 | % the best, and it is 40% faster than a call 115 | % to Hankel. Even my repmat version is faster 116 | % than the hankel solution. 117 | % 118 | % C = vec(hankel(1:n,circshift(1:n,[0 1])))); 119 | % 120 | % For anyone who really wants a slight speed 121 | % bump, uncomment the bsxfun version below 122 | % instead, and comment out the repmat version 123 | % below. I considered putting in a test to see 124 | % if bsxfun exists, but the test itself wastes 125 | % more time on small vectors compared to the 126 | % small additional time the repmat version 127 | % requires. 128 | % 129 | % C = vec(mod(bsxfun(@plus,(0:n1)',0:n1),n)+1); 130 | % 131 | % The fact is, there are still too many users 132 | % around that don't have a new enough release 133 | % that includes bsxfun. Since the repmat 134 | % solution here is absolutely trivial, 135 | % I'll be friendly and use it instead. I also 136 | % did a very quick test, and even for vectors 137 | % of length 500, there was only a 10% time 138 | % penalty for the use of repmat versus bsxfun 139 | % here. 140 | C = repmat(0:n1,n,1); 141 | C = vec(mod(C+C',n)+1); 142 | else 143 | % positive circular shift. We end up as a 144 | % call to toeplitz here. This variant too can 145 | % be sped up using bsxfun. Here the speedup 146 | % is roughly 20% over toeplitz for vectors of 147 | % length 500. Again though, for small vectors, 148 | % the test just to see if bsxfun exists takes 149 | % more time than the call to toeplits. 150 | 151 | % if bsxfun exists and you really want that 152 | % speed bump, just swap in the following block 153 | % of code: 154 | 155 | % if size(vec,1) == 1 156 | % % vec was a row vector, so it defines 157 | % % the first row of C. 158 | % C = vec(mod(bsxfun(@plus,(0:-1:(-n1))',0:n1),n)+1); 159 | % else 160 | % % vec must be a column vector, so it 161 | % % defines the first column of C. 162 | % C = vec(mod(bsxfun(@plus,(0:n1)',0:-1:(-n1)),n)+1); 163 | % end 164 | 165 | % assuming no bsxfun 166 | 167 | % was vec a row or column vector? 168 | if size(vec,1) == 1 169 | % vec was a row vector, so it defines 170 | % the first row of C. 171 | rind = 1:n; 172 | cind = n + 2 - rind' ; 173 | cind(cind == (n+1)) = 1; 174 | else 175 | % vec was a column vector, so it defines 176 | % the first column of C. 177 | cind = (1:n)'; 178 | rind = n + 2 - cind'; 179 | rind(rind == (n+1)) = 1; 180 | end 181 | % once the first row and column is given, 182 | % just call toeplitz 183 | C = vec(toeplitz(cind,rind)); 184 | 185 | end 186 | 187 | -------------------------------------------------------------------------------- /1D_experiment/auxillary/circulant.m: -------------------------------------------------------------------------------- 1 | function C = circulant(vec,direction) 2 | %CIRCULANT Circulant Matrix. 3 | % CIRCULANT(V,DIR) generates a square circulant matrix using the vector V 4 | % as the first row of the result if V is a row vector or as the first 5 | % column of the result if V is a column vector. V may be any numeric data 6 | % type or a character string. 7 | % DIR is an optional input argument that describes the circular shift 8 | % direction. If DIR = 1, the shift is forward. If DIR = -1, the shift is 9 | % backward. If DIR is not provided, DIR = 1 is used. 10 | % 11 | % References: 12 | % http://en.wikipedia.org/wiki/Circulant_matrix 13 | % http://mathworld.wolfram.com/CirculantMatrix.html 14 | % 15 | % Example: 16 | % A backwards (-1) shift, result is a symmetric 17 | % matrix. 18 | % 19 | % circulant([2 3 5 7 11 13],-1) 20 | % 21 | % ans = 22 | % 2 3 5 7 11 13 23 | % 3 5 7 11 13 2 24 | % 5 7 11 13 2 3 25 | % 7 11 13 2 3 5 26 | % 11 13 2 3 5 7 27 | % 13 2 3 5 7 11 28 | % 29 | % Example: 30 | % A forwards (+1) shifted circulant matrix, 31 | % built using the first row defined by vec. 32 | % 33 | % circulant([2 3 5 7 11],1) 34 | % 35 | % ans = 36 | % 2 3 5 7 11 37 | % 11 2 3 5 7 38 | % 7 11 2 3 5 39 | % 5 7 11 2 3 40 | % 3 5 7 11 2 41 | % 42 | % Example: 43 | % A postively shifted circulant matrix, built 44 | % from vec as the first column. 45 | % 46 | % circulant([2;3;5;7;11],1) 47 | % ans = 48 | % 2 11 7 5 3 49 | % 3 2 11 7 5 50 | % 5 3 2 11 7 51 | % 7 5 3 2 11 52 | % 11 7 5 3 2 53 | % 54 | % Example: 55 | % A negative shift applied to build a character 56 | % circulant matrix. 57 | % 58 | % circulant('abcdefghij',-1) 59 | % 60 | % ans = 61 | % abcdefghij 62 | % bcdefghija 63 | % cdefghijab 64 | % defghijabc 65 | % efghijabcd 66 | % fghijabcde 67 | % ghijabcdef 68 | % hijabcdefg 69 | % ijabcdefgh 70 | % jabcdefghi 71 | % 72 | % See also: toeplitz, hankel 73 | % 74 | % Author: John D'Errico 75 | % (The help was re-written to be more clear 76 | % and concise by Duane Hanselman.) 77 | % e-mail: woodchips@rochester.rr.com 78 | % Release: 1.1 79 | % Release date: 2/3/09 80 | 81 | 82 | % error checks 83 | if (nargin<1) || (nargin > 2) 84 | error('circulant takes only one or two input arguments') 85 | end 86 | 87 | if (nargin < 2) || isempty(direction) 88 | direction = 1; 89 | elseif ~ismember(direction,[1,-1]) 90 | error('direction must be either +1 or -1 if it is supplied') 91 | end 92 | 93 | % verify that vec is a vector or a scalar 94 | if ~isvector(vec) 95 | error('vec must be a vector') 96 | elseif length(vec) == 1 97 | % vec was a scalar 98 | C = vec; 99 | return 100 | end 101 | 102 | % how long is vec? 103 | n = length(vec); 104 | n1 = n-1; 105 | 106 | if direction == -1 107 | % negative circular shift. 108 | 109 | % create the circulant matrix. Yeah, I know, 110 | % it only takes one line using bsxfun. 111 | % 112 | % Alternatively, it can be done as a hankel 113 | % matrix variant. I like the bsxfun construct 114 | % the best, and it is 40% faster than a call 115 | % to Hankel. Even my repmat version is faster 116 | % than the hankel solution. 117 | % 118 | % C = vec(hankel(1:n,circshift(1:n,[0 1])))); 119 | % 120 | % For anyone who really wants a slight speed 121 | % bump, uncomment the bsxfun version below 122 | % instead, and comment out the repmat version 123 | % below. I considered putting in a test to see 124 | % if bsxfun exists, but the test itself wastes 125 | % more time on small vectors compared to the 126 | % small additional time the repmat version 127 | % requires. 128 | % 129 | % C = vec(mod(bsxfun(@plus,(0:n1)',0:n1),n)+1); 130 | % 131 | % The fact is, there are still too many users 132 | % around that don't have a new enough release 133 | % that includes bsxfun. Since the repmat 134 | % solution here is absolutely trivial, 135 | % I'll be friendly and use it instead. I also 136 | % did a very quick test, and even for vectors 137 | % of length 500, there was only a 10% time 138 | % penalty for the use of repmat versus bsxfun 139 | % here. 140 | C = repmat(0:n1,n,1); 141 | C = vec(mod(C+C',n)+1); 142 | else 143 | % positive circular shift. We end up as a 144 | % call to toeplitz here. This variant too can 145 | % be sped up using bsxfun. Here the speedup 146 | % is roughly 20% over toeplitz for vectors of 147 | % length 500. Again though, for small vectors, 148 | % the test just to see if bsxfun exists takes 149 | % more time than the call to toeplits. 150 | 151 | % if bsxfun exists and you really want that 152 | % speed bump, just swap in the following block 153 | % of code: 154 | 155 | % if size(vec,1) == 1 156 | % % vec was a row vector, so it defines 157 | % % the first row of C. 158 | % C = vec(mod(bsxfun(@plus,(0:-1:(-n1))',0:n1),n)+1); 159 | % else 160 | % % vec must be a column vector, so it 161 | % % defines the first column of C. 162 | % C = vec(mod(bsxfun(@plus,(0:n1)',0:-1:(-n1)),n)+1); 163 | % end 164 | 165 | % assuming no bsxfun 166 | 167 | % was vec a row or column vector? 168 | if size(vec,1) == 1 169 | % vec was a row vector, so it defines 170 | % the first row of C. 171 | rind = 1:n; 172 | cind = n + 2 - rind' ; 173 | cind(cind == (n+1)) = 1; 174 | else 175 | % vec was a column vector, so it defines 176 | % the first column of C. 177 | cind = (1:n)'; 178 | rind = n + 2 - cind'; 179 | rind(rind == (n+1)) = 1; 180 | end 181 | % once the first row and column is given, 182 | % just call toeplitz 183 | C = vec(toeplitz(cind,rind)); 184 | 185 | end 186 | 187 | -------------------------------------------------------------------------------- /1D_experiment/convergence.m: -------------------------------------------------------------------------------- 1 | %========================================================================== 2 | %This Demo solves the 1D multi-chanel blind deconvolution problem in the 3 | %following paper: 4 | % 5 | %``A Nonconvex Approach for Exact and Efficient Multichannel Sparse Blind 6 | % Deconvolution'', 7 | %Qing Qu, Xiao Li, Zhihui Zhu. 8 | % 9 | %where it aims to recovers both the channel $a$ and sparse signals 10 | %${x_i}_{i=1}^p$ from the measurements $y_i$. These three terms are 11 | %linked by the gemerative model: 12 | % 13 | % $$ y_i = a * x_i, i = 1,...,p $$ 14 | %where '*' represents circulant convolution. 15 | % 16 | %This Demo solves the following optimization problem using Riemannian 17 | %gradient descent 18 | % 19 | % $$ min_{q} 1/np sum_{i=1}^p H_mu(C_{y_i}Pq), s.t. \|q\| = 1 $$ 20 | %where $C_{y_i}$ denotes the circulant matrix of vector $y_i$, $H_mu$ 21 | %represents huber function with parameter $mu$, and $P$ indicates 22 | %preconditioning matrix introduce in our paper. Suppose the algorithm 23 | %returns the optimal solution of the above problem: $q^r$, we apply a 24 | %refining rounding processing which solves 25 | % 26 | % $$ min_{q} 1/np sum_{i=1}^p \|C_{y_i}Pq\|_1, s.t. q_r^Tq = 1 $$ 27 | %Suppose the optimal solution of the above problem is given by $q^\star$, 28 | %then the kernel and the sparse signals are recovered by 29 | % 30 | % $$ a^\star = F^{-1}( 1./ ( F(Pq^\star) ) ), x_i^\star = C_{y_i}Pq^\star $$ 31 | %where $F(.)$ represents fourier tranform. 32 | %========================================================================== 33 | 34 | 35 | 36 | 37 | close all;clear; 38 | 39 | folder = fileparts(which(mfilename)); 40 | addpath(genpath(folder)); 41 | % randn('seed',2019); 42 | % rand('seed',2019); 43 | 44 | 45 | % setup parameters 46 | 47 | % experiment parameters 48 | gen_opts.x_type = 'bernoulli-gaussian'; 49 | p = 50; 50 | n = 200; 51 | gen_opts.theta = .25; % sparsity 52 | gen_opts.noise_level = 0; 53 | 54 | 55 | % algorithm parameters 56 | opts.islinesearch = true; 57 | opts.isprint = false; 58 | opts.tol = 1e-12; 59 | opts.tau = 1e-3; 60 | opts.MaxIter = 1e2; 61 | opts.NumReinit = 1; 62 | 63 | 64 | alg = { 'l1', 'huber-0.5','huber-0.05','huber-0.005','l4' }; 65 | 66 | 67 | % generate the data 68 | [ Y, a_0, X_0] = gen_data(n, p, gen_opts); 69 | 70 | % generate the initialization and precondition matrix 71 | 72 | precond = sqrt(gen_opts.theta *n*p) * ... 73 | (sum(abs(ifft(Y)).^2 , 2)).^(-1/2); % preconditioning vector 74 | 75 | % Y_p = fft( ifft(Y) .* repmat(precond,1,p) ); % preconditioned Y 76 | Y_p = fft( bsxfun(@times, ifft(Y), precond) ); 77 | 78 | opts.precond = precond; 79 | opts.a_0 = a_0; 80 | 81 | % random initialization 82 | opts.q_init = normc(randn(n,1) ); 83 | 84 | dist2a = zeros(opts.MaxIter,length(alg)); 85 | Err2a = zeros(opts.MaxIter,length(alg)); 86 | 87 | mu = .1/n; %parameter for huber 88 | for k = 1:length(alg) 89 | switch lower(alg{k}) 90 | 91 | case 'l1' 92 | opts.MaxIter = 2e2; 93 | f = func_l1(Y_p); 94 | [r_l1, F_val1,Err,error_l1] = grad_descent( f, opts); 95 | 96 | case 'huber-1' 97 | opts.MaxIter = 1e2; 98 | mu = 1; 99 | f = func_huber(Y_p,mu); 100 | [r_huber_1, F_val2,Err,dist2a(:,k)] = grad_descent( f, opts); 101 | 102 | case 'huber-0.5' 103 | opts.MaxIter = 1e2; 104 | mu = 5e-1; 105 | f = func_huber(Y_p,mu); 106 | [r_huber_2, F_val2,Err,dist2a(:,k)] = grad_descent( f, opts); 107 | case 'huber-0.05' 108 | opts.MaxIter = 1e2; 109 | mu = 5e-2; 110 | f = func_huber(Y_p,mu); 111 | [r_huber_3, F_val2,Err,dist2a(:,k)] = grad_descent( f, opts); 112 | case 'huber-0.005' 113 | opts.MaxIter = 1e2; 114 | mu = 5e-3; 115 | f = func_huber(Y_p,mu); 116 | [r_huber_4, F_val2,Err,dist2a(:,k)] = grad_descent( f, opts); 117 | 118 | case 'l4' 119 | opts.MaxIter = 1e2; 120 | f = func_l4(Y_p); 121 | [r_l4, F_val3,Err,dist2a(:,k)] = grad_descent( f, opts); 122 | 123 | end 124 | end 125 | 126 | %refining process 127 | for k = 1:length(alg) 128 | switch lower(alg{k}) 129 | 130 | case 'l1' 131 | 132 | case 'huber-1' 133 | [q_huber_1,Err2a(:,k)] = rounding( r_huber_1,Y_p,opts); 134 | 135 | case 'huber-0.5' 136 | [q_huber_2,Err2a(:,k)] = rounding( r_huber_2,Y_p,opts); 137 | 138 | case 'huber-0.05' 139 | [q_huber_3,Err2a(:,k)] = rounding( r_huber_3,Y_p,opts); 140 | 141 | case 'huber-0.005' 142 | [q_huber_4,Err2a(:,k)] = rounding( r_huber_4,Y_p,opts); 143 | 144 | case 'l4' 145 | [q_l4,Err2a(:,k)] = rounding( r_l4,Y_p,opts); 146 | 147 | end 148 | end 149 | 150 | 151 | %over all error 152 | Error = [dist2a ; Err2a]; 153 | Error(:,1) = error_l1; 154 | 155 | 156 | 157 | Markers = {'-+','-o','-*','-x','-v'}; 158 | % Colors = {'r','g','b','c','k'}; 159 | legen ={'$\ell^1$-loss','Huber-loss, $\mu=5\times 10^{-1}$','Huber-loss, $\mu=5\times 10^{-2}$',... 160 | 'Huber-loss,$\mu=5\times 10^{-3}$','$\ell^4$-loss'}; 161 | 162 | T = [1:2*opts.MaxIter]; 163 | T_s = [1:10:2*opts.MaxIter]; 164 | 165 | figure; 166 | hold on; 167 | for k = 1:length(alg) 168 | plot(T,log(Error(:,k)),Markers{k},'LineWidth',2.5,... 169 | 'MarkerIndices', 1:10:length(T),'MarkerSize',8); 170 | end 171 | 172 | g = legend(legen); 173 | set(g,'FontSize',16); set(g,'Interpreter','latex'); 174 | 175 | grid on; 176 | set(gca, 'FontName', 'Times New Roman','FontSize',14); 177 | 178 | xlabel('Iteration Number','Interpreter','latex','FontSize',16); 179 | ylabel('$\log ( \min \{||${\boldmath$a$}$_\star-${\boldmath$a$}$ ||\;,||${\boldmath$a$}$_\star + ${\boldmath$a$}$ || \} )$',... 180 | 'Interpreter','latex','FontSize',16); 181 | box on; 182 | 183 | ylim([-25,1]); 184 | --------------------------------------------------------------------------------