% test_dijkstra.m

% Author: Ramon Casero <rcasero@gmail.com>
% Copyright © 2012, 2015 University of Oxford
% Version: 0.3.3
%
% University of Oxford means the Chancellor, Masters and Scholars of
% the University of Oxford, having an administrative office at
% Wellington Square, Oxford OX1 2JD, UK.
%
% This file is part of Gerardus.
%
% 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. The offer of this
% program under the terms of the License is subject to the License
% being interpreted in accordance with English Law and subject to any
% action against the University of Oxford being under the jurisdiction
% of the English Courts.
%
% You should have received a copy of the GNU General Public License
% along with this program.  If not, see
% <http://www.gnu.org/licenses/>.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Basic Dijkstra

% distance matrix to describe the graph in
% http://en.wikipedia.org/wiki/Dijkstra's_algorithm
% (saved to matlab/test/Dijkstra_Animation_wikipedia.gif)

d = [...
    %  1   2   3   4   5   6
       0   7   9   0   0  14; ...
       7   0  10  15   0   0; ...
       9  10   0  11   0   2; ...
       0  15  11   0   6   0; ...
       0   0   0   6   0   9; ...
      14   0   2   0   9   0];

% run disjkstra's algorithm on first node
[dd, p] = dijkstra(sparse(d'), 1)

% dd' =
%
%      0     7     9    20    20    11
%
% p' =
%
%      0     1     1     3     6     3

% query several source nodes at the same time
[dd, p] = dijkstra(sparse(d'), [1 3 6])

% dd' =
%
%     0     7     9    20    20    11
%     9    10     0    11    11     2
%    11    12     2    13     9     0
%
% p' =
%
%      0     1     1     3     6     3
%      3     3     0     3     6     3
%      3     3     6     3     6     0

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Dijkstra with limited number of targets

% query a source node, but we are only interested in the path to a single
% target node
[dd, p] = dijkstra(sparse(d'), 1, 3)

% dd' =
%
%     0     7     9    20   Inf    11
%
% p' =
%
%      0     1     1     3   NaN     3

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Dijkstra with piggyback

% secondary distance matrix. The algorithm will ignore this distances in
% terms of searching for shortest-paths, but will create another distance
% output adding the values in D2 while following the path given by D

d2 = [...
    %  1   2   3   4   5   6
       0  10   7   0   0   6; ...
      10   0   2  11   0   0; ...
       7   2   0   9   0   9; ...
       0  11   9   0  14   0; ...
       0   0   0  14   0  15; ...
       6   0   9   0  15   0];

[dd, p, dd2] = dijkstra(sparse(d'), 1:6, 1:6, sparse(d2))

% dd2 =
%
%      0    10     7    16    31    16
%     10     0     2    11    25    11
%      7     2     0     9    24     9
%     16    11     9     0    14    18
%     31    26    24    14     0    15
%     16    11     9    18    15     0

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Dijkstra with non-symmetric input matrix

% we start with a symmetric matrix
d = [...
    %  1   2   3   4   5   6
       0   7   9   0   0  14; ...
       7   0  10  15   0   0; ...
       9  10   0  11   0   2; ...
       0  15  11   0   6   0; ...
       0   0   0   6   0   9; ...
      14   0   2   0   9   0];

% the path from 1 to 5 is 1, 3, 6, 5, and has cost 20
[dd, p] = dijkstra(sparse(d'), 1);
dd(5)
graphpred2path(p', 5)

% in the opposite direction, same path, 5, 6, 3, 1
[dd, p] = dijkstra(sparse(d'), 5);
dd(1)
graphpred2path(p', 1)

% change the distance from 6 to 5 to be very expensive, so that the best
% path now is 1, 3, 4, 5, with cost 26
d(6, 5) = 20;
[dd, p] = dijkstra(sparse(d'), 1);
dd(5)
graphpred2path(p', 5)

% note that in the opposite direction nothing has changed, because the
% matrix is asymmetric
[dd, p] = dijkstra(sparse(d'), 5);
dd(1)
graphpred2path(p', 1)


function ydata = tsne_d(D, labels, no_dims, perplexity)
%TSNE_D Performs symmetric t-SNE on the pairwise Euclidean distance matrix D
%
%   mappedX = tsne_d(D, labels, no_dims, perplexity)
%   mappedX = tsne_d(D, labels, initial_solution, perplexity)
%
% The function performs symmetric t-SNE on the NxN pairwise Euclidean
% distance matrix D to construct an embedding with no_dims dimensions
% (default = 2). An initial solution obtained from an other dimensionality
% reduction technique may be specified in initial_solution.
% The perplexity of the Gaussian kernel that is employed can be specified
% through perplexity (default = 30). The labels of the data are not used
% by t-SNE itself, however, they are used to color intermediate plots.
% Please provide an empty labels matrix [] if you don't want to plot
% results during the optimization.
% The data embedding is returned in mappedX.
%
%
% (C) Laurens van der Maaten, 2010
% University of California, San Diego

    if ~exist('labels', 'var')
        labels = [];
    end
    if ~exist('no_dims', 'var') || isempty(no_dims)
        no_dims = 2;
    end
    if ~exist('perplexity', 'var') || isempty(perplexity)
        perplexity = 30;
    end

    % First check whether we already have an initial solution
    if numel(no_dims) > 1
        initial_solution = true;
        ydata = no_dims;
        no_dims = size(ydata, 2);
    else
        initial_solution = false;
    end

    % Compute joint probabilities
    D = D / max(D(:));                                                      % normalize distances
    P = d2p(D .^ 2, perplexity, 1e-5);                                      % compute affinities using fixed perplexity

    % Run t-SNE
    if initial_solution
        ydata = tsne_p(P, labels, ydata);
    else
        ydata = tsne_p(P, labels, no_dims);
    end


% composit.m        September 2, 2013

% sun-synchronous, repeating ground track,
% frozen orbit design - Kozai J2 perturbations

% Orbital Mechanics with MATLAB

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

clear all;

global j2 j3 mu req omega argper fi xldot xqp

% astrodynamic and utility constants

j2 = 0.00108263;
j3 = -0.00000254;
mu = 398600.4415;
req = 6378.14;
omega = 0.000072921151467;

pi2 = 2.0 * pi;
dtr = pi / 180.0;
rtd = 180.0 / pi;

x = zeros(3, 1);

clc; home;

fprintf('\n                    program composit');

fprintf('\n\n < sun-synchronous, repeating ground track, frozen orbits >\n\n');

% request initial guesses

while(1)

   fprintf('\nplease input an initial guess for the semimajor axis (kilometers)\n');

   x(1) = input('? ');

   if (x(1) > 0.0)
      break;
   end

end

while(1)

   fprintf('\nplease input an initial guess for the eccentricity (non-dimensional)');
   fprintf('\n(0 <= eccentricity < 1)\n');

   x(2) = input('? ');

   if (x(2) >= 0.0 && x(2) < 1.0)
      break;
   end

end

while(1)

    fprintf('\nplease input an initial guess for the inclination (degrees)');
    fprintf('\n(90 < inclination <= 180)\n');

    x(3) = input('? ');

    if (x(3) > 90.0 && x(3) <= 180.0)
       break;
    end

end

x(3) = x(3) * dtr;

while(1)

   fprintf('\nplease input the number of integer orbits in the repeat cycle\n');

   norbits = input('? ');

   if (norbits > 1)
      break;
   end

end

while(1)

   fprintf('\nplease input the number of integer days in the repeat cycle\n');

   ndays = input('? ');

   if (ndays > 0)
      break;
   end

end

% compute repetition factor

xqp = norbits / ndays;

% fundamental interval

fi = pi2 / xqp;

% required nodal regression rate

xldot = (360.0 / 365.25) * dtr / 86400.0;

argper = 90.0 * dtr;

% solve system of nonlinear equations

n = 3;

maxiter = 200;

[xf, niter, icheck] = snle ('compfunc', x, n, maxiter);

sma = xf(1);

ecc = xf(2);

inc = rtd * xf(3);

% keplerian period

tkepler = pi2 * sqrt(sma ^ 3 / mu);

tnode = pi2 * (1.0 / xqp) / (omega - xldot);

% print results

clc; home;

fprintf('\n                    program composit');

fprintf('\n\n < sun-synchronous, repeating ground track, frozen orbits >\n\n');

fprintf('mean semimajor axis                %12.4f  kilometers \n\n', sma);

fprintf('mean eccentricity                  %12.10f \n\n', ecc);

fprintf('mean orbital inclination           %12.4f  degrees \n\n', inc);

fprintf('mean argument of perigee           %12.4f  degrees \n\n', argper*rtd);

fprintf('keplerian period                   %12.4f  minutes \n\n', tkepler/60);

fprintf('nodal period                       %12.4f  minutes \n\n', tnode/60);

fprintf('number of orbits in repeat cycle   %12.4f  \n\n', norbits);

fprintf('number of days in repeat cycle     %12.4f  \n\n', ndays);

fprintf('ground trace repetition factor     %12.4f  \n\n', xqp);


function ABCtranslate = abc2num(S)
%ABC2NUM convert a spreadsheet label string to corresponding column number.
%   ABC2NUM(S) returns the number corresponding to the spreadsheet column
%   represented by the string, S.
%
%   The input string, S, may contain the ascii letters A-Z, in the format
%   commonly employed  by spreadsheet programs such as Calc and Microsoft
%   Excel. Other characters, including lower case letters, a-z, are
%   ignored.
%
%   Examples
%       S = 'CS';
%       abc2num(S)  returns  97
%
%     See also num2abc, num2str, str2num, char.

alphabetStrings = ['[A,B,C,D,E,F,G,'...
                   'H,I,J,K,L,M,N,'...
                   'O,P,Q,R,S,T,U,'...
                   'V,W,X,Y,Z]'];

n = regexp(S,alphabetStrings,'start');
ascii = zeros(size(n));
for i=1:length(n)
    ascii(i) = double(S(n(i)));
end
digits = ascii - 64;

ABCtranslate = polyval(flipdim(digits,1),26);

%==========================================================================
%abc2num.m
%Function that converts a spreadsheet column label to a number.
%--------------------------------------------------------------------------
%author:  David Sedarsky
%date:    February, 2012


function f = f01_f0 ( n, x, y )

%*****************************************************************************80
%
%% F01_F0 returns the value of function 1.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    29 January 2012
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer N, the number of evaluation points.
%
%    Input, real X(N,1), Y(N,1), the evalution points.
%
%    Output, real F(N,1), the function values.
%
  f(1:n,1) = ...
      0.75 * exp ( - ( ( 9.0 * x(1:n,1) - 2.0 ).^2            ...
                     + ( 9.0 * y(1:n,1) - 2.0 ).^2 ) / 4.0 )  ...
    + 0.75 * exp ( - ( ( 9.0 * x(1:n,1) + 1.0 ).^2 ) / 49.0   ...
                     - ( 9.0 * y(1:n,1) + 1.0 ) / 10.0 )      ...
    + 0.5  * exp ( - ( ( 9.0 * x(1:n,1) - 7.0 ).^2            ...
                     + ( 9.0 * y(1:n,1) - 3.0 ).^2 ) / 4.0 )  ...
    - 0.2  * exp ( - (   9.0 * x(1:n,1) - 4.0 ).^2            ...
                     - ( 9.0 * y(1:n,1) - 7.0 ).^2 );

  return
end


%solve the inverse of matrix M,and MOut is the outcome Matrix.
function [MOut] = InverseM(M)
[nRow,nCol] = size(M);
is = zeros(nRow,1);
js = zeros(nRow,1);
fDet = 1.0;
f = 1;
for k = 1:nRow
    fMax = 0;
    for i = k:nRow
        for j = k:nRow
            f1 = abs(M(i,j));
            if f1 > fMax
                fMax = f1;
                is(k,1) = i;
                js(k,1) = j;
            end
        end
    end
    if abs(fMax) < 0.0001
        disp('Error happen 0.0001');
    end
    if is(k,1) ~= k
        f = -f;
        for i = 1:nRow
            [M(k,i),M(is(k,1),i)] = swap(M(k,i),M(is(k,1),i));
        end
    end
    if js(k,1) ~= k
        f = -f;
        for i = 1:nRow
            [M(i,k),M(i,js(k,1))] = swap(M(i,k),M(i,js(k,1)));
        end
    end
    fDet = fDet*M(k,k);
    M(k,k) = 1/M(k,k);
    for j = 1:nRow
        if j ~= k
            M(k,j) = M(k,j)*M(k,k);
        end
    end
    for i = 1:nRow
        if i ~= k
            for j = 1:nRow
                if j ~= k
                    M(i,j) = M(i,j) - M(i,k)*M(k,j);
                end
            end
        end
    end
    for i = 1:nRow
        if i ~= k
            M(i,k) = M(i,k)*(-M(k,k));
        end
    end
end
for k = nRow:-1:1
    if js(k,1) ~= k
        for i = 1:nRow
            [M(k,i),M(js(k,1),i)] = swap(M(k,i),M(js(k,1),i));
        end
    end
    if is(k,1) ~= k
        for i = 1:nRow
            [M(i,k),M(i,is(k,1))] = swap(M(i,k),M(i,is(k,1)));
        end
    end
end
MOut = M;
clear M;


function [out] = interflow_10(S,p1,p2,p3)
%interflow_10

% Copyright (C) 2019, 2021 Wouter J.M. Knoben, Luca Trotter
% This file is part of the Modular Assessment of Rainfall-Runoff Models
% Toolbox (MARRMoT).
% MARRMoT is a free software (GNU GPL v3) and distributed WITHOUT ANY
% WARRANTY. See <https://www.gnu.org/licenses/> for details.

% Flux function
% ------------------
% Description:  Scaled linear interflow if storage exceeds a threshold
% Constraints:  f = 0, for S < p2
% @(Inputs):    p1   - time coefficient [d-1]
%               p2   - threshold for flow generation [mm]
%               p3   - linear scaling parameter [-]
%               S    - current storage [mm]

out = p1*max(0,S-p2)/(p3);

end


function [epo_X, epo_Y] = feature_extraction_FFT(epo)

chan = {'PO3','POz','PO4','O1','Oz','O2'};

epo = proc_selectChannels(epo, chan);
epo = proc_selectIval(epo, [0 4000]);  % [0 4000]
dataset = permute(epo.x, [3,1,2]);

[tr, dp, ch] = size(dataset); % tr: trial, dp: time, ch: channel

nominal = [];
for i=1:size(epo.y,2)
    nominal(i) = find(epo.y(:,i),1)-1;
end

%% Fast Fourier Transform (FFT)
X_arr=[]; % make empty array
for k=1:tr % trials
    x=squeeze(dataset(k, :,:)); % data
    N=length(x);    % get the number of points
    kv=0:N-1;        % create a vector from 0 to N-1
    T=N/epo.fs;         % get the frequency interval
    freq=kv/T;       % create the frequency range
    X=fft(x)/N*2;   % normalize the data
    cutOff = ceil(N/2); % get the only positive frequency

    % take only the first half of the spectrum
    X=abs(X(1:cutOff,:)); % absolute values to cut off
    freq = freq(1:cutOff); % frequency to cut off
    XX = permute(X,[3 1 2]);
    X_arr=[X_arr; XX]; % save in array
end

%% frequency band
% f_gt = [11 7 5];  % 5.45, 8.75, 12
f_last = find( freq > 30, 1); % freq < 30Hz
X_arr = X_arr(:,1:f_last,:); %

%% get features
epo_X = permute(X_arr,[2,3,4,1]);
epo_Y = nominal;


function value = i4_divp ( i, j )

%*****************************************************************************80
%
%% I4_DIVP returns the smallest multiple of J greater than or equal to I.
%
%  Example:
%
%    I  J  VALUE
%
%    0  4    0
%    1  4    1
%    2  4    1
%    3  4    1
%    4  4    1
%    5  4    2
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    01 May 2004
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer I, the number to be analyzed.
%
%    Input, integer J, the number, multiples of which will
%    be compared against I.  J may not be zero.
%
%    Output, integer VALUE, the smallest multiple of J that
%    is greater than or equal to I.
%
  if ( j ~= 0 )
    value = 1 + floor ( ( i - 1 ) / j );
  else
    value = 0;
    fprintf ( 1, '\n' );
    fprintf ( 1, 'I4_DIVP - Fatal error!\n' );
    fprintf ( 1, '  The input value of J was zero!\n' );
    error ( 'I4_DIVP - Fatal error!\n' );
  end

  return
end


function res = ball(size, varargin)
%BALL Generate a ball in a matrix in 2 or 3 dimensions
%
% parameters
%  size: radius of the ball, center exclude
%  dim:  dimensions of the ball (2 or 3)
%
% author : Gaetan Lehmann
%

%	HISTORY
%	13/03/2007: update doc (DL)

if ~isempty(varargin)
    dim = varargin{1};
else
    dim = 2;
end

if dim == 2
    if length(size) == 1
        xSize = size;
        ySize = size;
    else
        xSize = size(1);
        ySize = size(2);
    end

    realXSize = xSize*2+1;
    realYSize = ySize*2+1;

    res = zeros([realXSize, realYSize]);
    center = [xSize ySize] + 1;
    radius2 = ([xSize ySize] + 0.5) .^ 2;

    for x = 1:realXSize
        for y = 1:realYSize
            d = [x y] - center;
            d2 = d .^ 2;
            if sum(d2./radius2) <= 1
                res(x, y) = 1;
            end
        end
    end
else
    if length(size) == 1
        xSize = size;
        ySize = size;
        zSize = size;
    else
        xSize = size(1);
        ySize = size(2);
        zSize = size(3);
    end

    realXSize = xSize*2+1;
    realYSize = ySize*2+1;
    realZSize = zSize*2+1;

    res = zeros([realXSize, realYSize, realZSize]);
    center = [xSize ySize zSize] + 1;
    radius2 = ([xSize ySize zSize] + 0.5) .^ 2;

    for x = 1:realXSize
        for y = 1:realYSize
            for z = 1:realZSize
                d = [x y z] - center;
                d2 = d .^ 2;
                if sum(d2./radius2) <= 1
                    res(x, y, z) = 1;
                end
            end
        end
    end
end


%% 1D Heat Transfer LBM D1Q2
% by Manuel Diaz
clc; clear; %close all;

%% Domain Grid
L = 30;    % Length
n = 30;    % Nodes
dx = L/n; dt = 1;
x  = 1:dx:L;

%% Initial Condition
f1 = zeros(1,n);
f2 = zeros(1,n);
rho= zeros(1,n); % initial value of the dependent variable rho = T(x,t)
feq1= zeros(1,n);
feq2= zeros(1,n);

%% Constants
csq   = (dx^2)/(dt^2);
alpha = 0.25;
omega = 1/(alpha/(dt*csq)+0.5);
w     = [1/2,1/2];
cx    = [  1, -1];
cy    = [  0,  0];
links = [  1,  2];
tEnd  = 200; % time steps
tPlot = 10;
frames= tEnd/tPlot;
count = 0;

%% Movie Parameters
tPlot = 10; frames= tEnd/tPlot; count = 0;
figure(1)
colordef white

%% Boundary Conditions
twall = 1;

%% Main Loop
for cycle = 1:tEnd;
    % Collision process
    rho = f1+f2;

    % even that for this case k1=k2=1/2m then feq1=feq2=feq
    feq1 = 0.5*rho;
    feq2 = 0.5*rho;

    f1 = (1-omega) * f1 + omega * feq1;
    f2 = (1-omega) * f2 + omega * feq2;
    % Streaming process
    f1 = stream2d( f1 , [cy(1),cx(1)]);
    f2 = stream2d( f2 , [cy(2),cx(2)]);

%   % Original streaming process in A.A.Mohamad
%     for i = 2:n-1;  % Double streaming in one loop
%         f1(n-i+1) = f1(n-i);  % Streaming
%         f2( i-1 ) = f2( i );  % Streaming
%     end

    % Boundary condition
    f1(1) = twall-f2(1);    %Dirichlet BC
    f1(n) = f1(n-1);        %Neumann BC
    f2(n) = f2(n-1);        %Neumann BC

    % Visualization every tPlot
    if mod(cycle,tPlot) == 1
        count = count + 1;
        plot(x,rho,'.');
        title '1D Heat Equation using LBM D1Q2'
        xlabel 'x cell'
        ylabel 'Temperature'
        M(count)=getframe;
    end

    % Animated gif file
    if mod(cycle,tPlot) == 1
        F = getframe;
        if count == 1
            [im,map] = rgb2ind(F.cdata,256,'nodither');
            im(1,1,1,tEnd/tPlot) = 0;
        end
        im(:,:,1,count) = rgb2ind(F.cdata,map,'nodither');
    end
end

%% Make pretty figures
%plot(x,rho,'.');

%% Make Movie
movie(M,3,10); % movie(M,n,fps)

%% Export to Gif
imwrite(im,map,'heat_eq_d1q2.gif','DelayTime',0,'LoopCount',3)


function [RHSdiv, RHSdivx, RHSdivy] = divergenceTerm2D(F)
% This function calculates the divergence of a field using its face
% average flux vector facevariable, which is a face vector
%
% SYNOPSIS:
%   [RHSdiv, RHSdivx, RHSdivy] = divergenceTerm2D(F)
%
% PARAMETERS:
%
%
% RETURNS:
%
%
% EXAMPLE:
%
% SEE ALSO:
%

% extract data from the mesh structure
Nx = F.domain.dims(1);
Ny = F.domain.dims(2);
G=reshape(1:(Nx+2)*(Ny+2), Nx+2, Ny+2);
DX = repmat(F.domain.cellsize.x(2:end-1), 1, Ny);
DY = repmat(F.domain.cellsize.y(2:end-1)', Nx, 1);

% define the vector of cell index
row_index = reshape(G(2:Nx+1,2:Ny+1),Nx*Ny,1); % main diagonal (only internal cells)

% reassign the east, west, north, and south flux vectors for the
% code readability
Fe = F.xvalue(2:Nx+1,:);		Fw = F.xvalue(1:Nx,:);
Fn = F.yvalue(:,2:Ny+1);       Fs = F.yvalue(:,1:Ny);

% compute the divergence
div_x = (Fe - Fw)./DX;
div_y = (Fn - Fs)./DY;

% define the RHS Vector
RHSdiv = zeros((Nx+2)*(Ny+2),1);
RHSdivx = zeros((Nx+2)*(Ny+2),1);
RHSdivy = zeros((Nx+2)*(Ny+2),1);

% assign the values of the RHS vector
RHSdiv(row_index) = reshape(div_x+div_y,Nx*Ny,1);
RHSdivx(row_index) = reshape(div_x,Nx*Ny,1);
RHSdivy(row_index) = reshape(div_y,Nx*Ny,1);


function [loc_assort_pos,loc_assort_neg] = local_assortativity_wu_sign(W)
%LOCAL_ASSORTATIVITY_WU_SIGN     Local Assortativity
%
%   [loc_assort_pos,loc_assort_neg] = local_assortativity_wu_sign(W);
%
%   Local Assortativity measures the extent to which nodes are connected to
%   nodes of similar strength (vs. higher or lower strength). Adapted from
%   Thedchanamoorthy et al. (2014)'s formula to allow weighted/signed
%   networks (node degree replaced with node strength). Note, output values
%   sum to total assortativity.
%
%   Inputs:     W,        undirected connection matrix with positive and
%                         negative weights
%
%   Output:     loc_assort_pos, local assortativity from positive weights
%
%               loc_assort_neg, local assortativity from negative weights
%
%   Reference: Thedchanamoorthy G, Piraveenan M, Kasthuriratna D,
%              Senanayake U. Proc Comp Sci (2014) 29:2449-2461.
%
%
%   Jeff Spielberg, Boston University

%   Modification History:
%   May 2015: Original

W(1:(size(W,1)+1):end) = 0;
r_pos = assortativity_wei(W.*(W>0),0);
r_neg = assortativity_wei(-W.*(W<0),0);
[str_pos,str_neg] = strengths_und_sign(W);
loc_assort_pos = nan(size(W,1),1);
loc_assort_neg = nan(size(W,1),1);

for curr_node = 1:size(W,1)
    [~,j_pos] = find(W(curr_node,:)>0);
    loc_assort_pos(curr_node,1) = sum(abs(str_pos(j_pos)-str_pos(curr_node)))/str_pos(curr_node);

    [~,j_neg] = find(W(curr_node,:)<0);
    loc_assort_neg(curr_node,1) = sum(abs(str_neg(j_neg)-str_neg(curr_node)))/str_neg(curr_node);
end

loc_assort_pos = ((r_pos+1)/size(W,1))-(loc_assort_pos/sum(loc_assort_pos));
loc_assort_neg = ((r_neg+1)/size(W,1))-(loc_assort_neg/sum(loc_assort_neg));


function [R, tau] = CholeskyMultIdentity(H)
%  Implements Cholesky with added multiple of the identity.  This attempts to
%  to find a scalar tau > 0 such that H + tau * I is sufficiently positive
%  definite, where I is the identity matrix.

global numFact  % Number of Cholesky factorizations attempted.

%  First, we intially try a Cholesky factorization.
[R, fail] = chol(H);
numFact = numFact + 1;
%  If it does not fail, we're done.
if fail == 0
    tau = 0;
    return;
end

%  If the initial Cholesky factorization fails, we attempt to find a scalar
%  tau > 0 such that H + tau * I is sufficiently positive definite.
beta = 0.001;  % Heuristic for increasing tau.
min_H_diag = min(diag(H));  % Smallest diagonal of H.

%  If smallest diagonal of H is positive, set tau to 0; otherwise, set to
%  nonnegative version of the smallest diagonal plus the beta heuristic.
if min_H_diag > 0
    tau = 0;
else
    tau = -min_H_diag + beta;
end

I = eye(size(H,1));  % Identity matrix.

%  Repeatedly add a tau-multiple of the identity to H until the Cholesky
%  factorization succeeds.  Upon each failure, double tau.
while 1
    [R, fail] = chol(H + tau * I);
    numFact = numFact + 1;
    if fail == 0
        return;
    else
        %  NOTE:  In order to decrease number of factorizations, we may want to
        %         increase tau by a factor of 10 instead of 2.
        tau = max(2*tau, beta);
    end
end
end


function counter=population(i,j,k,order)
%-fanDTasia ToolBox------------------------------------------------------------------
% This Matlab script is part of the fanDTasia ToolBox: a Matlab library for Diffusion
% Weighted MRI (DW-MRI) Processing, Diffusion Tensor (DTI) Estimation, High-order
% Diffusion Tensor Analysis, Tensor ODF estimation, Visualization and more.
%
% A Matlab Tutorial on DW-MRI can be found in:
% http://www.cise.ufl.edu/~abarmpou/lab/fanDTasia/tutorial.php
%
%-CITATION---------------------------------------------------------------------------
% If you use this software please cite the following work:
% A. Barmpoutis and B.C. Vemuri, "A Unified Framework for Estimating Diffusion Tensors
% of any order with Symmetric Positive-Definite Constraints",
% In the Proceedings of ISBI, 2010
%
%-DESCRIPTION------------------------------------------------------------------------
% This function computes how many identical copies of a tensor coefficient appear in
% a fully symmetric high order tensor in 3 variables of spesific order.
%
%-USE--------------------------------------------------------------------------------
% counter=population(i,j,k,order)
%
% order: is the order of the symmetric tensor in 3 variables (x,y,z)
% i,j,k: is a triplet that represent the coefficient which is weighted by the monomial
% x^i*y^j*z^k, where i+j+k=order
%
%-DISCLAIMER-------------------------------------------------------------------------
% You can use this source code for non commercial research and educational purposes
% only without licensing fees and is provided without guarantee or warrantee expressed
% or implied. You cannot repost this file without prior written permission from the
% authors. If you use this software please cite the following work:
% A. Barmpoutis and B.C. Vemuri, "A Unified Framework for Estimating Diffusion Tensors
% of any order with Symmetric Positive-Definite Constraints", In Proc. of ISBI, 2010.
%
%-AUTHOR-----------------------------------------------------------------------------
% Angelos Barmpoutis, PhD
% Computer and Information Science and Engineering Department
% University of Florida, Gainesville, FL 32611, USA
% abarmpou at cise dot ufl dot edu
%------------------------------------------------------------------------------------

    size=3^order;
    counter=0;
    for z=0:size-1
        c=populationBasis(z,order,[0 0 0]);
        if (c(1)==i)&(c(2)==j)&(c(3)==k)
            counter=counter+1;
        end
    end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function ret=populationBasis(i,order,c)
	if order==0
        ret=c;
    else
	    j=mod(i,3);
	    c(j+1)=c(j+1)+1;
	    ret=populationBasis((i-j)/3,order-1,c);
    end


function x = r8sp_cg ( n, nz_num, row, col, a, b, x )

%*****************************************************************************80
%
%% R8SP_CG uses the conjugate gradient method on an R8SP system.
%
%  Discussion:
%
%    The R8SP storage format stores the row, column and value of each nonzero
%    entry of a sparse matrix.
%
%    It is possible that a pair of indices (I,J) may occur more than
%    once.  Presumably, in this case, the intent is that the actual value
%    of A(I,J) is the sum of all such entries.  This is not a good thing
%    to do, but I seem to have come across this in MATLAB.
%
%    The R8SP format is used by CSPARSE ("sparse triplet"), DLAP/SLAP
%    ("nonsymmetric SLAP triad"), by MATLAB, and by SPARSEKIT ("COO" format).
%
%    The matrix A must be a positive definite symmetric matrix.
%
%    The method is designed to reach the solution after N computational
%    steps.  However, roundoff may introduce unacceptably large errors for
%    some problems.  In such a case, calling the routine again, using
%    the computed solution as the new starting estimate, should improve
%    the results.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    02 June 2014
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Frank Beckman,
%    The Solution of Linear Equations by the Conjugate Gradient Method,
%    in Mathematical Methods for Digital Computers,
%    edited by John Ralston, Herbert Wilf,
%    Wiley, 1967,
%    ISBN: 0471706892,
%    LC: QA76.5.R3.
%
%  Parameters:
%
%    Input, integer N, the order of the matrix.
%    N must be positive.
%
%    Input, integer NZ_NUM, the number of nonzero elements in
%    the matrix.
%
%    Input, integer ROW(NZ_NUM), COL(NZ_NUM), the row and
%    column indices of the nonzero elements.
%
%    Input, real A(NZ_NUM), the nonzero elements of the matrix.
%
%    Input, real B(N), the right hand side vector.
%
%    Input/output, real X(N).
%    On input, an estimate for the solution, which may be 0.
%    On output, the approximate solution vector.
%
  b = b(:);
  x = x(:);
%
%  Initialize
%    AP = A * x,
%    R  = b - A * x,
%    P  = b - A * x.
%
  ap = r8sp_mv ( n, n, nz_num, row, col, a, x );

  r(1:n,1) = b(1:n,1) - ap(1:n,1);
  p(1:n,1) = b(1:n,1) - ap(1:n,1);
%
%  Do the N steps of the conjugate gradient method.
%
  for it = 1 : n
%
%  Compute the matrix*vector product AP=A*P.
%
    ap = r8sp_mv ( n, n, nz_num, row, col, a, p );
%
%  Compute the dot products
%    PAP = P*AP,
%    PR  = P*R
%  Set
%    ALPHA = PR / PAP.
%
    pap = p' * ap;
    pr = p' * r;

    if ( pap == 0.0 )
      return
    end

    alpha = pr / pap;
%
%  Set
%    X = X + ALPHA * P
%    R = R - ALPHA * AP.
%
    x(1:n,1) = x(1:n,1) + alpha * p(1:n,1);
    r(1:n,1) = r(1:n,1) - alpha * ap(1:n,1);
%
%  Compute the vector dot product
%    RAP = R*AP
%  Set
%    BETA = - RAP / PAP.
%
    rap = r' * ap;

    beta = - rap / pap;
%
%  Update the perturbation vector
%    P = R + BETA * P.
%
    p(1:n,1) = r(1:n,1) + beta * p(1:n,1);

  end

  return
end


function [Q,J,F,T,I,V,E] = spinv(A,varargin)
  % SPINV Compute a sparse factorization of the Moore-Penrose pseudoinverse A⁺
  % of a sparse matrix A.  This is useful for solving
  % under-and-over-constrained systems Ax = b: where A is m by n with
  % rank r < min(m,n). Then to solve the system:
  %
  %     x = E*(V*(I'*(T'\(F'*(J'*(Q'*b))))))
  %
  % Note: Store these sparse factors and sovle using the routine above **with
  % parentheses**. Do not precompute A⁺ as it will be dense.
  %
  % Inputs:
  %   A  m by n sparse
  %   Optional:
  %     'Epsilon' followed by epsilon used to determine rank from qr {1e-15}
  % Outputs:
  %   Q  m by m sparse orthogonal matrix
  %   J  m by r sparse rectangular identity matrix
  %   F  r by r sparse permutation matrix
  %   T  r by r sparse triangular matrix (diagonal?)
  %   I  r by n sparse rectangular identity matrix
  %   V  n by n sparse orthogonal matrix
  %   E  n by n sparse permutation matrix
  %
  % Example:
  %   % over and under determined system of 3 variables
  %   A = [1 0 0;1 0 0;0 1 1;0 1 1];
  %   b = [4;5;6;7];
  %   % Compute facotrization of sparse pseudo inverse
  %   [Q,J,F,T,I,V,E] = spinv(A);
  %   % Compute minimum norm best fit
  %   xs = E*(V*(I'*(T'\(F'*(J'*(Q'*b))))));
  %   % Compare to Tikhonov regularization
  %   xt = (A'*A+1e-10*speye(3,3))\(A'*b);
  %

  % default values
  epsilon = 1e-15;
  % Map of parameter names to variable names
  params_to_variables = containers.Map( {'Epsilon'}, {'epsilon'});
  v = 1;
  while v <= numel(varargin)
    param_name = varargin{v};
    if isKey(params_to_variables,param_name)
      assert(v+1<=numel(varargin));
      v = v+1;
      % Trick: use feval on anonymous function to use assignin to this workspace
      feval(@()assignin('caller',params_to_variables(param_name),varargin{v}));
    else
      error('Unsupported parameter: %s',varargin{v});
    end
    v=v+1;
  end
  % http://www.irisa.fr/sage/wg-statlin/WORKSHOPS/LEMASSOL05/SLIDES/QR/Guyomarch.pdf

  % dimensions of A
  m = size(A,1);
  n = size(A,2);
  % QR factorization of AE
  [Q,R,E] = qr(A);
  % We have that:
  %     AE = QR
  % rank
  r = find(any(abs(R)>epsilon,2),1,'last');
  % Only keep upper, non-zero block
  R1R2 = R(1:r,:);
  J = speye(m,r);
  % We have that:
  %    AE = Q*J*R1R2
  % QR factorization of R1R2'
  [V,Tfull,F] = qr(R1R2');
  % This means:
  %    R1R2'F = V*Tfull
  % only keep upper, non-zero block
  T = Tfull(1:r,:);
  I = speye(r,n);
  % and now:
  %    R1R2'F = V*I'*T
  %    R1R2' = V*I'*T*F'
  % Now we have that
  %     AE = Q*J*F*T'*I*V'
  % We want to solve:
  %     Ax = b
  %     AEE'x = b
  %     E'x = (Q*J*F*T'*I*V')⁺b
  %     x = E*(Q*J*F*T'*I*V')⁺b
  %     x = E*(V*(I'*(T'\(F'*(J'*(Q'*b))))))
  %
end


clear;
clc;

addpath('../../utils/');

lambda1 = 1;
lambda2 = 1;

opts.tol = 10^-4;
opts.max_iter = 1000;
opts.tFlag = 1;
opts.init = 0;

sample_size_arr = [500 500 500 500 500];
task_num = length(sample_size_arr);
dimension = 200;

X = cell(task_num, 1);
Y = cell(task_num, 1);
W = rand(dimension, task_num);
for t = 1 :task_num
    % sampling
    X{t} = rand(sample_size_arr(t), dimension);
    %Y{t} = X{t} * W(:, t) + rand(sample_size_arr(t), 1) * 0.01;
    Y{t} = X{t} * W(:, t);
end

tic;
[W_1inf,fun_val,iter_1inf] = Least_Dirty(X,Y,lambda1,lambda2, opts);
toc;

plot(fun_val);


function varargout = trigonometric(X)
% Trigonometric function
%
%   TRIGONOMETRIC([x1, x2, ..., xn]) returns the value of the
%   trigonometric fnuction at the specified points. All [xi] may be
%   vectors.
%
%   The global minimum is
%
%               f(x1, x2, ..., xn) = f(0, 0, ..., 0) = 0.

% Author: Rody P.S. Oldenhuis
% Delft University of Technology
% E-mail: oldenhuis@dds.nl
% Last edited 28/Feb/2009

    % if no input is given, return dimensions, bounds and minimum
    if (nargin == 0)
        varargout{1} = inf;  % # dims
        varargout{2} = -inf; % LB
        varargout{3} = +inf; % LB
        varargout{4} = 0; % solution
        varargout{5} = 0; % function value at solution

    % otherwise, output function value
    else

        % create basevectors
        n = size(X, 2);
        i = repmat(1:n, size(X, 1), 1);

        % compute cosine only once
        cosX = cos(X);

        % compute intermediate sum
        sumcosX = repmat(sum(cosX, 2), 1, n);

        % output rowsum
        varargout{1} = sum( (n + i.*(1 - cosX) - sin(X) - sumcosX).^2, 2);

    end

end


function [fr,th_val,phi_val] = tess_parametrize(vert, th_val, phi_val, p)
% TESS_PARAMETRIZE_NEW: Get a parametric representation of a closed and non-overlapping surface.
%
% USAGE:  tess_parametrize(vert, th_val, phi_val, p)
%         tess_parametrize(vert, th_val, phi_val)
%
% INPUTS:
%    - vert    : x,y,z coordinates of the surface to parametrize
%    - th_val  : Row array of theta values
%    - phi_val : Row array of phi values
%    - p       : Pad the function of p values in both direction with circular values

% @=============================================================================
% This function is part of the Brainstorm software:
% https://neuroimage.usc.edu/brainstorm
%
% Copyright (c) University of Southern California & McGill University
% This software is distributed under the terms of the GNU General Public License
% as published by the Free Software Foundation. Further details on the GPLv3
% license can be found at http://www.gnu.org/copyleft/gpl.html.
%
% FOR RESEARCH PURPOSES ONLY. THE SOFTWARE IS PROVIDED "AS IS," AND THE
% UNIVERSITY OF SOUTHERN CALIFORNIA AND ITS COLLABORATORS DO NOT MAKE ANY
% WARRANTY, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, NOR DO THEY ASSUME ANY
% LIABILITY OR RESPONSIBILITY FOR THE USE OF THIS SOFTWARE.
%
% For more information type "brainstorm license" at command prompt.
% =============================================================================@
%
% Authors: Francois Tadel, 2011

% Parse inputs
if (nargin < 4) || isempty(p)
    p = 0;
end

% Convert surface to spherical coordinates
[th,phi,r] = cart2sph(vert(:,1), vert(:,2), vert(:,3));
% Replicate the values to get a full coverage at the edges
th  = [th;  th;        th;        th+2*pi;  th+2*pi;  th+2*pi;   th-2*pi;  th-2*pi;  th-2*pi  ];
phi = [phi; phi+2*pi;  phi-2*pi;  phi;      phi+2*pi; phi-2*pi;  phi;      phi+2*pi; phi-2*pi ];
r   = [r;   r;         r;         r;        r;        r;         r;        r;        r        ];

% Build grid of (theta,phi) values
[fth, fphi] = meshgrid(th_val, phi_val);
% Estimate radius values for all those points
fr = griddata(th, phi, r, fth, fphi);

% Pad function with circular values, to avoid edge irregularities
if (p > 0)
    fr_pad  = bst_pad(fr, [0  p], 'circular');
    fr_pad  = bst_pad(fr_pad, [p  0], 'mirror');
    fr = fr_pad;
    th_val  = [th_val(end-p+1:end)-2*pi,  th_val,  th_val(1:p)+2*pi];
    phi_val = [phi_val(end-p+1:end)-2*pi, phi_val, phi_val(1:p)+2*pi];
end


addpath ./propack
addpath ./yima_rpca
addpath ./lib

X = rand(1000, 1000);
k = 20;

tic;[U1 s1 V1] = svdex(X, k, struct('svd_solver', 'svd'));t1 = toc;
tic;[U2 s2 V2] = svdex(X, k, struct('svd_solver', 'svds'));t2 = toc;
tic;[U3 s3 V3] = svdex(X, k, struct('svd_solver', 'lansvd', 'init', randn(size(X,1),1)));t3 = toc;
figure; plot(1:k,s1,'r', 1:k,s2,'g^', 1:k,s3,'bv');
fprintf('Time:\n     svd=%fs\n    svds=%fs\n  lansvd=%fs\n',t1,t2,t3);

Y1 = bsxfun(@times, U1, s1')*V1';
err1 = max(abs(X(:) - Y1(:)));
Y2 = bsxfun(@times, U2, s2')*V2';
err2 = max(abs(X(:) - Y2(:)));
Y3 = bsxfun(@times, U3, s3')*V3';
err3 = max(abs(X(:) - Y3(:)));
fprintf('Error:\n     svd=%f\n    svds=%f\n  lansvd=%f\n',err1,err2,err3);


function value = r8_lgic ( a, x, alx )

%*****************************************************************************80
%
%% R8_LGIC evaluates the log complementary incomplete gamma function for large X.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    16 September 2011
%
%  Author:
%
%    Original FORTRAN77 version by Wayne Fullerton.
%    MATLAB version by John Burkardt.
%
%  Reference:
%
%    Wayne Fullerton,
%    Portable Special Function Routines,
%    in Portability of Numerical Software,
%    edited by Wayne Cowell,
%    Lecture Notes in Computer Science, Volume 57,
%    Springer 1977,
%    ISBN: 978-3-540-08446-4,
%    LC: QA297.W65.
%
%  Parameters:
%
%    Input, real A, the parameter.
%
%    Input, real X, the argument.
%
%    Input, real ALX, the logarithm of X.
%
%    Output, real VALUE, the log complementary incomplete
%    gamma function.
%
  persistent eps

  if ( isempty ( eps ) )
    eps = 0.5 * r8_mach ( 3 );
  end

  xpa = x + 1.0 - a;
  xma = x - 1.0 - a;

  r = 0.0;
  p = 1.0;
  s = p;
  for k = 1 : 300
    fk = k;
    t = fk * ( a - fk ) * ( 1.0 + r );
    r = - t / ( ( xma + 2.0 * fk ) * ( xpa + 2.0 * fk ) + t );
    p = r * p;
    s = s + p;
    if ( abs ( p ) < eps * s )
      value = a * alx - x + log ( s / xpa );
      return
    end
  end

  fprintf ( 1, '\n' );
  fprintf ( 1, 'R8_LGIC - Fatal error!\n' );
  fprintf ( 1, '  No convergence in 300 iterations.\n' );

  error ( 'R8_LGIC - Fatal error!' )
end


classdef SPX_ShortTermFourierTransform < handle

properties(SetAccess=private)
    % Length of block
    BlockLength
    % Number of samples in overlaps
    OverlappedSamplesCount
    % FFT length
    FFTLength
    % Window type
    WindowType
    % Window
    Window
end

methods
    function self  = SPX_ShortTermFourierTransform(...
        blockLength, overlappedSamples, fftLength, windowType)
        self.BlockLength  = blockLength;
        self.OverlappedSamplesCount = overlappedSamples;
        self.FFTLength = fftLength;
        self.WindowType = windowType;
        if strcmp(windowType, 'hamming')
            self.Window = hamming(blockLength)';
        elseif strcmp(windowType,'blackman')
            self.Window = blackman(blockLength)';
        else
            error('Unsupported window type');
        end
    end

    function [ spec, timePoints]  = run(self, signal)
        blockLength = self.BlockLength;
        overlappedSamples = self.OverlappedSamplesCount;
        N = length(signal);
        NBlocks = spx.dsp.overlapped_blocks_count(N, blockLength...
            , overlappedSamples);
        w = self.Window;
        shift = blockLength - overlappedSamples;
        fftLength = self.FFTLength;
        start = 0;
        for ii=1:NBlocks
            % Let's identify the start and end of the block
            range = start + (1:blockLength);
            % Let's read off the block and apply windowing
            x = signal(range) .* w;
            % Identify normalized start time for this block
            timePoints(ii) = start +1;
            % Compute fft of this
            Xf  = fft(x, fftLength);
            spec(:, ii) = Xf;
            start = start + shift;
        end
    end
end

end


function [gx,dgdx,dgdp] = g_rigid2D(x,P,u,in)
% apply rigid body 2D spatial transform (rotation and translation)
% function [gx,dgdx,dgdp] = g_rigid2D(x,P,u,in)
% IN:
%   - x: [useless]
%   - P: the 3 rigid body transform parameters
%   - u: [useless]
%   - in: contains the original image (in.Y)
% OUT:
%   - gx: vectorized transformed image
%   - dgdx: []
%   - dgdp: gradient of the image wrt to transform parameters

gx = applyRT(P,in);

% the numerical derivation is done here because of interpolation errors:
dgdx = [];
dgdp = zeros(size(gx,1),3);
I = eye(3);
for i=1:3
    dgdp(:,i) = applyRT(P+I(:,i),in) - gx;
end
dgdp = dgdp';

function gx = applyRT(P,in)

tx = P(1);
ty = P(2);
th = P(3);
T = [ 1 0 tx
      0 1 ty
      0 0 1  ];
R = [ cos(th) -sin(th) 0
      sin(th) cos(th)  0
      0       0        1  ];
[nx,ny] = size(in.Y);
[xg,yg] = meshgrid(-nx/2+1:nx/2,-ny/2+1:ny/2);
Txy = T*[xg(:)';yg(:)';ones(1,nx*ny)];
RTxy = R*[Txy(1,:);Txy(2,:);ones(1,nx*ny)];
RTx = reshape(RTxy(1,:)',nx,ny);
RTy = reshape(RTxy(2,:)',nx,ny);
gx = griddata(RTx,RTy,in.Y,xg,yg,'cubic');
gx = gx(:);
gx(isnan(gx)) = 0;


function pass = test_vdpIVP(~)

%% Setup
vdpFun = @(mu) @(u) diff(u, 2) - mu.*(1-u.^2).*diff(u) + u;
dom = [0 10];
bcFun =  @(u) [u-2; diff(u)];
opts = odeset('abstol', 1e5*eps, 'reltol', 100*eps);
tol = 1e-10;

%% Solve with CHEBOPs, compare with standard MATLAB, mu = 1
N = chebop(vdpFun(1), dom);
N.lbc = bcFun;
u = N\0;
uend = u(dom(end));
sol =ode45(@vdp1, dom, [2 0], opts);
yend = deval(sol, dom(end)); yend = yend(1);
err(1) = abs(uend - yend);

%% Solve with CHEBOPs, compare with standard MATLAB, mu = 1000
N = chebop(vdpFun(1000), dom);
N.lbc = bcFun;
u = N\0;
uend = u(dom(end));
sol =ode45(@vdp1000, dom, [2 0], opts);
yend = deval(sol, dom(end)); yend = yend(1);
err(2) = abs(uend - yend);

%% Happy?
pass = err < tol;


function determ = r8mat_gedet ( a, n, pivot )

%*****************************************************************************80
%
%% R8MAT_GEDET computes the determinant of a matrix factored by R8MAT_GEFA.
%
%  Discussion:
%
%    This is a modified version of the LINPACK routine DGEDI.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    21 October 2007
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Jack Dongarra, Cleve Moler, Jim Bunch, Pete Stewart,
%    LINPACK User's Guide,
%    SIAM, (Society for Industrial and Applied Mathematics),
%    3600 University City Science Center,
%    Philadelphia, PA, 19104-2688.
%    ISBN 0-89871-172-X
%
%  Parameters:
%
%    Input, real A(N,N), the LU factors computed by R8MAT_GEFA.
%
%    Input, integer N, the order of the matrix.
%    N must be positive.
%
%    Input, integer PIVOT(N), as computed by R8MAT_GEFA.
%
%    Output, real DETERM, the determinant of the matrix.
%
  diag = r8mat_diag_get_vector ( n, a );

  determ = prod ( diag(1:n) );

  for i = 1 : n
    if ( pivot(i) ~= i )
      determ = - determ;
    end
  end

  return
end


function test_values_test ( )

%*****************************************************************************80
%
%% TEST_VALUES_TEST tests the TEST_VALUES library.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    07 February 2015
%
%  Author:
%
%    John Burkardt
%
  timestamp ( );
  fprintf ( 1, '\n' );
  fprintf ( 1, 'TEST_VALUES_TEST\n' );
  fprintf ( 1, '  MATLAB version.\n' );
  fprintf ( 1, '  Test the TEST_VALUES library.\n' );

  abram0_values_test ( );
  abram1_values_test ( );
  abram2_values_test ( );
  agm_values_test ( );
  airy_ai_values_test ( );
  airy_ai_int_values_test ( );
  airy_ai_prime_values_test ( );
  airy_bi_values_test ( );
  airy_bi_int_values_test ( );
  airy_bi_prime_values_test ( );
  airy_cai_values_test ( );
  airy_cbi_values_test ( );
  airy_gi_values_test ( );
  airy_hi_values_test ( );
  arccos_values_test ( );
  arccosh_values_test ( );
  arcsin_values_test ( );
  arcsinh_values_test ( );
  arctan_values_test ( );
  arctan_int_values_test ( );
  arctan2_values_test ( );
  arctanh_values_test ( );

  bei0_values_test ( );
  bei1_values_test ( );
  bell_values_test ( );
  ber0_values_test ( );
  ber1_values_test ( );
  bernoulli_number_values_test ( );
  bernoulli_poly_values_test ( );
  bernstein_poly_01_values_test ( );
  bessel_i0_values_test ( );
  bessel_i0_int_values_test ( );
  bessel_i0_spherical_values_test ( );
  bessel_i1_values_test ( );
  bessel_i1_spherical_values_test ( );
  bessel_in_values_test ( );
  bessel_ix_values_test ( );
  bessel_j0_values_test ( );
  bessel_j0_int_values_test ( );
  bessel_j0_spherical_values_test ( );
  bessel_j1_values_test ( );
  bessel_j1_spherical_values_test ( );
  bessel_jn_values_test ( );
  bessel_jx_values_test ( );
  bessel_k0_values_test ( );
  bessel_k0_int_values_test ( );
  bessel_k1_values_test ( );
  bessel_kn_values_test ( );
  bessel_kx_values_test ( );
  bessel_y0_values_test ( );
  bessel_y0_int_values_test ( );
  bessel_y0_spherical_values_test ( );
  bessel_y1_values_test ( );
  bessel_y1_spherical_values_test ( );
  bessel_yn_values_test ( );
  bessel_yx_values_test ( );
  beta_values_test ( );
  beta_cdf_values_test ( );
  beta_inc_values_test ( );
  beta_log_values_test ( );
  beta_noncentral_cdf_values_test ( );
  binomial_values_test ( );
  binomial_cdf_values_test ( );
  bivariate_normal_cdf_values_test ( );

  catalan_values_test ( );
  cauchy_cdf_values_test ( );
  cbrt_values_test ( );
  cheby_t_poly_values_test ( );
  cheby_u_poly_values_test ( );
  cheby_v_poly_values_test ( );
  cheby_w_poly_values_test ( );
  chi_values_test ( );
  chi_square_cdf_values_test ( );
  chi_square_noncentral_cdf_values_test ( );
  ci_values_test ( )
  cin_values_test ( );
  cinh_values_test ( );
  clausen_values_test ( );
  clebsch_gordan_values_test ( );
  collatz_count_values_test ( );
  cos_values_test ( );
  cos_degree_values_test ( );
  cos_power_int_values_test ( );
  cosh_values_test ( );
  cot_values_test ( );
  cp_values_test ( );

  dawson_values_test ( );
  debye1_values_test ( );
  debye2_values_test ( );
  debye3_values_test ( );
  debye4_values_test ( );
  dedekind_sum_values_test ( );
  dielectric_values_test ( );
  dilogarithm_values_test ( );

  e1_values_test ( );
  ei_values_test ( );
  elliptic_ea_values_test ( );
  elliptic_em_values_test ( );
  elliptic_ka_values_test ( );
  elliptic_km_values_test ( );
  erf_values_test ( );
  erfc_values_test ( );
  euler_number_values_test ( );
  euler_poly_values_test ( );
  exp_values_test ( );
  exp3_int_values_test ( );
  exponential_cdf_values_test ( );
  extreme_values_cdf_values_test ( );

  f_cdf_values_test ( );
  f_noncentral_cdf_values_test ( );
  fresnel_cos_values_test ( );
  fresnel_sin_values_test ( );
  frobenius_number_data_values_test ( );
  frobenius_number_order_values_test ( );
  frobenius_number_order2_values_test ( );

  gamma_values_test ( );
  gamma_cdf_values_test ( );
  gamma_inc_values_test ( );
  gamma_inc_p_values_test ( );
  gamma_inc_q_values_test ( );
  gamma_inc_tricomi_values_test ( );
  gamma_log_values_test ( );
  gegenbauer_poly_values_test ( );
  geometric_cdf_values_test ( );
  goodwin_values_test ( );
  gud_values_test ( );

  hermite_function_values_test ( );
  hermite_poly_phys_values_test ( );
  hermite_poly_prob_values_test ( );
  hyper_1f1_values_test ( );
  hyper_2f1_values_test ( );
  hypergeometric_cdf_values_test ( );
  hypergeometric_pdf_values_test ( );
  hypergeometric_u_values_test ( );

  i0ml0_values_test ( );
  i1ml1_values_test ( );
  i4_factorial_values_test ( );
  i4_factorial2_values_test ( );
  i4_fall_values_test ( );
  i4_rise_values_test ( );
  int_values_test ( );

  jacobi_cn_values_test ( );
  jacobi_dn_values_test ( );
  jacobi_poly_values_test ( );
  jacobi_sn_values_test ( );
  jed_ce_values_test ( );
  jed_mjd_values_test ( );
  jed_rd_values_test ( );
  jed_weekday_values_test ( );

  kei0_values_test ( );
  kei1_values_test ( );
  ker0_values_test ( );
  ker1_values_test ( );

  laguerre_associated_values_test ( );
  laguerre_general_values_test ( );
  laguerre_polynomial_values_test ( );
  lambert_w_values_test ( );
  laplace_cdf_values_test ( );
  legendre_associated_values_test ( );
  legendre_associated_normalized_values_test ( );
  legendre_associated_normalized_sphere_values_test ( );
  legendre_poly_values_test ( );
  legendre_function_q_values_test ( );
  lerch_values_test ( );
  lobachevsky_values_test ( );
  lobatto_polynomial_values_test ( );
  lobatto_polynomial_derivatives_test ( );
  log_values_test ( );
  log_normal_cdf_values_test ( );
  log_series_cdf_values_test ( );
  log10_values_test ( );
  logarithmic_integral_values_test ( );
  logistic_cdf_values_test ( );

  mertens_values_test ( );
  moebius_values_test ( );

  negative_binomial_cdf_values_test ( );
  nine_j_values_test ( );
  normal_cdf_values_test ( );
  normal_01_cdf_values_test ( );

  omega_values_test ( );
  owen_values_test ( );

  partition_count_values_test ( );
  partition_distinct_count_values_test ( );
  phi_values_test ( );
  pi_values_test ( );
  poisson_cdf_values_test ( );
  polylogarithm_values_test ( );
  prandtl_values_test ( );
  prime_values_test ( );
  psat_values_test ( );
  psi_values_test ( );

  r8_factorial_values_test ( );
  r8_factorial_log_values_test ( );
  r8_factorial2_values_test ( );
  r8_fall_values_test ( );
  r8_rise_values_test ( );
  rayleigh_cdf_values_test ( );

  secvir_values_test ( );
  shi_values_test ( );
  si_values_test ( );
  sigma_values_test ( );
  sin_values_test ( );
  sin_degree_values_test ( );
  sin_power_int_values_test ( );
  sinh_values_test ( );
  six_j_values_test ( );
  sound_values_test ( );
  sphere_unit_area_values_test ( );
  sphere_unit_volume_values_test ( );
  spherical_harmonic_values_test ( );
  sqrt_values_test ( );
  stirling1_values_test ( );
  stirling2_values_test ( );
  stromgen_values_test ( );
  struve_h0_values_test ( );
  struve_h1_values_test ( );
  struve_l0_values_test ( );
  struve_l1_values_test ( );
  student_cdf_values_test ( );
  student_noncentral_cdf_values_test ( );
  subfactorial_values_test ( );
  surten_values_test ( );
  synch1_values_test ( );
  synch2_values_test ( );

  tan_values_test ( );
  tanh_values_test ( );
  tau_values_test ( );
  thercon_values_test ( );
  three_j_values_test ( );
  tran02_values_test ( );
  tran03_values_test ( );
  tran04_values_test ( );
  tran05_values_test ( );
  tran06_values_test ( );
  tran07_values_test ( );
  tran08_values_test ( );
  tran09_values_test ( );
  trigamma_values_test ( );
  truncated_normal_ab_cdf_values_test ( );
  truncated_normal_ab_pdf_values_test ( );
  truncated_normal_a_cdf_values_test ( );
  truncated_normal_a_pdf_values_test ( );
  truncated_normal_b_cdf_values_test ( );
  truncated_normal_b_pdf_values_test ( );
  tsat_values_test ( );

  van_der_corput_values_test ( );
  viscosity_values_test ( );
  von_mises_cdf_values_test ( );

  weekday_values_test ( );
  weibull_cdf_values_test ( );

  zeta_values_test ( );
%
%  Terminate.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'TEST_VALUES_TEST\n' );
  fprintf ( 1, '  Normal end of execution.\n' );
  fprintf ( 1, '\n' );
  timestamp ( );

  return
end


function triangulation_test25 ( )

%*****************************************************************************80
%
%% TEST25 tests TRIANGULATION_ORDER6_BOUNDARY_NODE, TRIANGULATION_ORDER6_PLOT.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    24 August 2006
%
%  Author:
%
%    John Burkardt
%
  file_name = 'triangulation_order6_plot.eps';
  dim_num = 2;
  node_show = 2;
  triangle_show = 2;

  fprintf ( 1, '\n' );
  fprintf ( 1, 'TEST25\n' );
  fprintf ( 1, '  TRIANGULATION_ORDER6_BOUNDARY_COUNT counts the boundary\n' );
  fprintf ( 1, '    edges in an arbitrary triangulation.\n' );
  fprintf ( 1, '  TRIANGULATION_ORDER6_PLOT plots the triangulation.\n' );

  [ node_num, triangle_num, hole_num ] = ...
    triangulation_order6_example1_size ( );

  [ node_xy, triangle_node, triangle_neighbor ] = ...
    triangulation_order6_example1 ( node_num, triangle_num );
%
%  Make the plot.
%
  triangulation_order6_plot ( file_name, node_num, node_xy, triangle_num, ...
    triangle_node, node_show, triangle_show );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  An Encapsulated PostScript image of this\n' );
  fprintf ( 1, '  triangulation is in "%s".\n', file_name );

  node_boundary = triangulation_order6_boundary_node ( node_num, triangle_num, ...
    triangle_node );

  fprintf ( 1, '\n' );
  fprintf ( 1, '    Node  BN?\n' );
  fprintf ( 1, '\n' );

  for i = 1 : node_num
    fprintf ( 1, '  %6d  %1d\n', i, node_boundary(i) );
  end

  return
end


function [ n_data, x, fx ] = sin_values ( n_data )

%*****************************************************************************80
%
%% SIN_VALUES returns some values of the sine function.
%
%  Discussion:
%
%    In Mathematica, the function can be evaluated by:
%
%      Sin[x]
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    13 June 2007
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Milton Abramowitz, Irene Stegun,
%    Handbook of Mathematical Functions,
%    National Bureau of Standards, 1964,
%    ISBN: 0-486-61272-4,
%    LC: QA47.A34.
%
%    Stephen Wolfram,
%    The Mathematica Book,
%    Fourth Edition,
%    Cambridge University Press, 1999,
%    ISBN: 0-521-64314-7,
%    LC: QA76.95.W65.
%
%  Parameters:
%
%    Input/output, integer N_DATA.  The user sets N_DATA to 0 before the
%    first call.  On each call, the routine increments N_DATA by 1, and
%    returns the corresponding data; when there is no more data, the
%    output value of N_DATA will be 0 again.
%
%    Output, real X, the argument of the function.
%
%    Output, real FX, the value of the function.
%
  n_max = 13;

  fx_vec = [ ...
     0.00000000000000000000, ...
     0.25881904510252076235, ...
     0.47942553860420300027, ...
     0.50000000000000000000, ...
     0.70710678118654752440, ...
     0.84147098480789650665, ...
     0.86602540378443864676, ...
     1.00000000000000000000, ...
     0.90929742682568169540, ...
     0.14112000805986722210, ...
     0.00000000000000000000, ...
    -0.75680249530792825137, ...
    -0.95892427466313846889 ];

  x_vec = [ ...
    0.0000000000000000000, ...
    0.26179938779914943654, ...
    0.50000000000000000000, ...
    0.52359877559829887308, ...
    0.78539816339744830962, ...
    1.0000000000000000000, ...
    1.0471975511965977462, ...
    1.5707963267948966192, ...
    2.0000000000000000000, ...
    3.0000000000000000000, ...
    3.1415926535897932385, ...
    4.0000000000000000000, ...
    5.0000000000000000000  ];

  if ( n_data < 0 )
    n_data = 0;
  end

  n_data = n_data + 1;

  if ( n_max < n_data )
    n_data = 0;
    x = 0.0;
    fx = 0.0;
  else
    x = x_vec(n_data);
    fx = fx_vec(n_data);
  end

  return
end


function geometry_test024 ( )

%*****************************************************************************80
%
%% TEST024 tests DUAL_SHAPE_3D;
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 February 2003
%
%  Author:
%
%    John Burkardt
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'TEST024\n' );
  fprintf ( 1, '  DUAL_SHAPE_3D finds the dual of a polyhedron.\n' );
%
%  Get the dodecahedron shape.
%
  [ point_num1, edge_num1, face_num1, face_order_max1 ] = dodec_size_3d ( );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  Number of points =   %d\n', point_num1 );
  fprintf ( 1, '  Number of edges =    %d\n', edge_num1 );
  fprintf ( 1, '  Number of faces =    %d\n', face_num1 );
  fprintf ( 1, '  Maximum face order = %d\n', face_order_max1 );

  [ point_coord1, face_order1, face_point1 ] = dodec_shape_3d ( point_num1, ...
    face_num1, face_order_max1 );
%
%  Get the dual.
%
  [ point_num2, edge_num2, face_num2, face_order_max2 ] = dual_size_3d ( ...
    point_num1, edge_num1, face_num1, face_order_max1, point_coord1, ...
    face_order1, face_point1 );

  [ point_coord2, face_order2, face_point2 ] = dual_shape_3d ( point_num1, ...
    face_num1, face_order_max1, point_coord1, face_order1, face_point1, ...
    point_num2, face_num2, face_order_max2 );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  Number of points =   %d\n', point_num2 );
  fprintf ( 1, '  Number of edges =    %d\n', edge_num2 );
  fprintf ( 1, '  Number of faces =    %d\n', face_num2 );
  fprintf ( 1, '  Maximum face order = %d\n', face_order_max2 );

  shape_print_3d ( point_num2, face_num2, face_order_max2, ...
    point_coord2, face_order2, face_point2 );

  return
end


function varargout = gallery2(name)
%CHEB.GALLERY2   Chebfun2 example functions.
%   F = CHEB.GALLERY2(NAME) returns a chebfun2 corresponding to NAME. See the
%   listing below for available names.
%
%   For example,  plot(cheb.gallery2('peaks'))  plots the classic MATLAB peaks
%   function represented as a chebfun2. For details of how each function is
%   constructed, try type +cheb/gallery2 or edit cheb.gallery2.
%
%   [F,FA] = CHEB.GALLERY2(NAME) also returns the anonymous function FA used to
%   define the function.
%
%   CHEB.GALLERY2 with no input argument returns a function selected at
%   random from the gallery.
%
%   CHEB.GALLERY2 with no output argument creates a plot of the selected
%   function.
%
%   airyreal     Real part of Airy Ai function
%   airycomplex  Imaginary part of Airy Ai function
%   bump         2D C-infinity function with compact support
%   challenge    Function from SIAM 100-digit challenge
%   peaks        Classic MATLAB peaks function
%   rosenbrock   Challenging test function in optimization
%   roundpeg     Approx characteristic function of a disk, rank 45
%   smokering    A halo, hoop, or hole
%   squarepeg    Approx characteristic function of a square, rank 1
%   tiltedpeg    A tilted variant of squarepeg, rank 100
%   waffle       Function with horizontal and vertical ridges
%
%   Gallery functions are subject to change in future releases of Chebfun.
%
% See also CHEB.GALLERY, CHEB.GALLERYTRIG, CHEB.GALLERY3, CHEB.GALLERYDISK, CHEB.GALLERYSPHERE.

% Copyright 2017 by The University of Oxford and The Chebfun Developers.
% See http://www.chebfun.org/ for Chebfun information.

% If the user did not supply an input, return a function selected at
% random from the gallery.
if ( nargin == 0 )
    names = {'airyreal', 'airycomplex', 'challenge', 'bump', 'peaks', ...
        'rosenbrock', 'roundpeg', 'smokering', 'squarepeg', 'tiltedpeg', ...
        'waffle'};
    name = names{randi(length(names))};
end

% The main switch statement.
switch lower(name)

    % Real part of Airy Ai function:
    case 'airyreal'
        fa = @(z) real(airy(z));
        f = chebfun2(fa, [-10 10 0 1]);

    % Imaginary part of Airy Ai function:
    case 'airycomplex'
        fa = @(z) airy(z);
        f = chebfun2(fa, [-10 10 -5 5]);

    % Two-dimensional bump function:
    case 'bump'
        fa = @(x,y) (x.^2 + y.^2 < 1).*exp(-(x.^2 + y.^2 < 1)./ ...
            (1 - x.^2 - y.^2));
        f = chebfun2(fa, [-1 1 -1 1]*2);

    % Function from SIAM 100-digit challenge:
    case 'challenge'
        fa = @(x,y) exp(sin(50*x)) + sin(60*exp(y)) + sin(70*sin(x)) + ...
            sin(sin(80*y)) - sin(10*(x+y)) + (x.^2+y.^2)./4;
        f = chebfun2(fa);

    % The classic MATLAB peaks function:
    case 'peaks'
        fa = @(x,y) 3*(1-x).^2.*exp(-x.^2 - (y+1).^2) ...
            - 10*(x/5 - x.^3 - y.^5).*exp(-x.^2 - y.^2) ...
            - 1/3*exp(-(x+1).^2 - y.^2);
        f = chebfun2(fa, [-3 3 -3 3]);

    % A challenging test function in optimization:
    case 'rosenbrock'
        fa = @(x,y) (1-x).^2 + 100*(y-x.^2).^2;
        f = chebfun2(fa, [-2 2 -1 3]);

    % Approximately the characteristic function of a disk:
    case 'roundpeg'
        fa = @(x,y) 1./(1+((2*x).^2+(2*y).^2).^10);
        f = chebfun2(fa);

    % A halo, hoop, or hole:
    case 'smokering'
        fa = @(x,y) exp(-100*(x.^2 - x.*y + 2*y.^2 - 1/2).^2);
        f = chebfun2(fa);

    % Approximately the characteristic function of a square:
    case 'squarepeg'
        fa = @(x,y) 1./((1+(2*x).^20).*(1+(2*y).^20));
        f = chebfun2(fa);

    % A tilted version of squarepeg:
    case 'tiltedpeg'
        fa = @(x,y) 1./((1+(2*x+.4*y).^20).*(1+(2*y-.4*x).^20));
        f = chebfun2(fa);

    % A function with horizontal and vertical ridges:
    case 'waffle'
        fa = @(x,y) 1./(1 + 1e3*((x.^2-.25).^2.*(y.^2-.25).^2));
        f = chebfun2(fa);

    % Raise an error if the input is unknown.
    otherwise
        error('CHEB:GALLERY2:unknown:unknownFunction', ...
            'Unknown function.')
end

% Only return something if there is an output argument.
if ( nargout > 0 )
    varargout = {f, fa};
else
    % Otherwise, plot the function.
    plot(f)
    title([name ', rank = ' num2str(length(f))])
end

end


% Initialize
clear all; close all; clc;
png_export = true;
pdf_export = false;
% Create the directory for storing images
[status_code,message,message_id] = mkdir('bin');

% A Dirac DCT dictionary
dict = spx.dict.simple.dirac_dct_mtx(16);
spx.graphics.display.dictionary_atoms_as_images(dict, struct('title', 'Dirac DCT Dictionary'));
if png_export
export_fig bin\dirac_dct_mtx.png -r120 -nocrop;
end
if pdf_export
export_fig bin\dirac_dct_mtx.pdf;
end

% A Gaussian dictionary
dict = spx.dict.simple.gaussian_mtx(16, 64);
spx.graphics.display.dictionary_atoms_as_images(dict, struct('title', 'Gaussian Dictionary'));
if png_export
export_fig bin\gaussian_mtx.png -r120 -nocrop;
end
if pdf_export
export_fig bin\gaussian_mtx.pdf;
end

% A Rademacher dictionary
dict = spx.dict.simple.rademacher_mtx(16, 64);
spx.graphics.display.dictionary_atoms_as_images(dict, struct('title', 'Rademacher Dictionary'));
if png_export
export_fig bin\rademacher_mtx.png -r120 -nocrop;
end
if pdf_export
export_fig bin\rademacher_mtx.pdf;
end


function res = normF2(A)
	%% ================== File info ==========================
	% Author		: Tiep Vu (http://www.personal.psu.edu/thv102/)
	% Time created	: Tue Jan 26 22:33:47 2016
	% Last modified	: Tue Jan 26 22:33:48 2016
	% Description	: square of the Frobenius Norm of A
	%% ================== end File info ==========================
	res = norm(A, 'fro')^2;
end


function [lp,dlp] = priorT(mu,s2,nu,x)

% Univariate Student's t hyperparameter prior distribution.
% Compute log-likelihood and its derivative or draw a random sample.
% The prior distribution is parameterized as:
%
%   p(x) = ( 1 + (x-mu)^2/(s2*(nu-2)) )^(-(nu+1)/2) / Z, where
%      Z = gamma(nu/2) * sqrt(pi*(nu-2)*s2) / gamma((nu+1)/2),
%
% mu(1x1) is the mean parameter, s2(1x1) is the variance parameter,
% nu(1x1) > 2 is the degrees of freedom parameter and x(1xN) contains query
% hyperparameters for prior evaluation.
%
% For more help on design of priors, try "help priorDistributions".
%
% Copyright (c) by Roman Garnett and Hannes Nickisch, 2014-10-16.
%
% See also PRIORDISTRIBUTIONS.M.

if nargin<3, error('mu, s2 and nu parameters need to be provided'), end
if ~(isscalar(mu)&&isscalar(s2)&&isscalar(nu))
  error('mu, s2 and nu parameters need to be scalars')
end
if nargin<4, lp = mu + sqrt(s2*(nu-2)/priorGamma(nu/2,2))*randn; return, end

lZ = gammaln((nu+1)/2)-gammaln(nu/2)-log(pi*(nu-2)*s2)/2;
lp = -(nu+1)/2*log(1+(x-mu).^2/(s2*(nu-2))) + lZ;
dlp = (nu+1)*(mu-x)./(mu^2-2*mu*x+s2*(nu-2)+x.^2);


function cvx_optval = norm_largest( x, k )

%NORM_LARGEST Sum of the k largest magnitudes of a vector.
%   NORM_LARGEST( X, k ) computes the 'largest-k' norm; that is, it computes
%   the sum of the magnitudes of the k largest elements in X. X must
%   be a vector, and k must be a real scalar.
%
%   Disciplined convex programming information:
%       NORM_LARGEST is convex and nonmonotonic of X, though it is monotonic for
%       positive values of X. So when used in CVX expressions, X must be affine,
%       monomial, or posynomial. k must be a real scalar constant.

if ~any( size( x ) ~= 1 ),
    cvx_throw( 'The first argument must be a vector.' );
elseif ~isnumeric( k ) || ~isreal( k ) || length( k ) ~= 1,
    cvx_throw( 'Third argument must be a scalar.' );
else
    cvx_optval = sum_largest( abs( x ), k );
end

% Copyright 2005-2014 CVX Research, Inc.
% See the file LICENSE.txt for full copyright information.
% The command 'cvx_where' will show where this file is located.


function value = diaedg ( x0, y0, x1, y1, x2, y2, x3, y3 )

%*****************************************************************************80
%
%% DIAEDG chooses a diagonal edge.
%
%  Discussion:
%
%    The routine determines whether 0--2 or 1--3 is the diagonal edge
%    that should be chosen, based on the circumcircle criterion, where
%    (X0,Y0), (X1,Y1), (X2,Y2), (X3,Y3) are the vertices of a simple
%    quadrilateral in counterclockwise order.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    07 February 2005
%
%  Author:
%
%    Original FORTRAN77 version by Barry Joe,
%    MATLAB version by John Burkardt
%
%  Reference:
%
%    Barry Joe,
%    GEOMPACK - a software package for the generation of meshes
%    using geometric algorithms,
%    Advances in Engineering Software,
%    Volume 13, pages 325-331, 1991.
%
%  Parameters:
%
%    Input, real X0, Y0, X1, Y1, X2, Y2, X3, Y3, the
%    coordinates of the vertices of a quadrilateral, given in
%    counter clockwise order.
%
%    Output, integer VALUE, chooses a diagonal:
%    +1, if diagonal edge 02 is chosen;
%    -1, if diagonal edge 13 is chosen;
%     0, if the four vertices are cocircular.
%
  tol = 100.0 * eps;

  dx10 = x1 - x0;
  dy10 = y1 - y0;
  dx12 = x1 - x2;
  dy12 = y1 - y2;
  dx30 = x3 - x0;
  dy30 = y3 - y0;
  dx32 = x3 - x2;
  dy32 = y3 - y2;

  tola = tol * max ( abs ( dx10 ), ...
               max ( abs ( dy10 ), ...
               max ( abs ( dx30 ), abs ( dy30 ) )));

  tolb = tol * max ( abs ( dx12 ), ...
               max ( abs ( dy12 ), ...
               max ( abs ( dx32 ), abs ( dy32 ) )));

  ca = dx10 * dx30 + dy10 * dy30;
  cb = dx12 * dx32 + dy12 * dy32;

  if ( tola < ca & tolb < cb )

    value = -1;

  elseif ( ca < -tola & cb < -tolb )

    value = 1;

  else

    tola = max ( tola, tolb );
    s = ( dx10 * dy30 - dx30 * dy10 ) * cb ...
      + ( dx32 * dy12 - dx12 * dy32 ) * ca;

    if ( tola < s )
      value = -1;
    elseif ( s < -tola )
      value = 1;
    else
      value = 0;
    end

  end

  return
end


function Test_fixedrankembeddedfactory()
% Given partial observation of a low rank matrix, attempts to complete it.
%
% function low_rank_matrix_completion()
%
% This example demonstrates how to use the geometry factory for the
% embedded submanifold of fixed-rank matrices, fixedrankembeddedfactory.
% This geometry is described in the paper
% "Low-rank matrix completion by Riemannian optimization"
% Bart Vandereycken - SIAM Journal on Optimization, 2013.
%
% This can be a starting point for many optimization problems of the form
%
% minimize f(X) such that rank(X) = k, size(X) = [m, n].
%
% Input:  None. This example file generate random data.
%
% Output: None.

% This file is part of Manopt and is copyrighted. See the license file.
%
% Main author: Nicolas Boumal, July 15, 2014
% Contributors:
%
% Change log:
%

    % Choose the size of the problem:
    % We will complete a matrix of size mxn of rank k.
    m = 2000;
    n = 5000;
    k = 10;
    % Generate a random mxn matrix A of rank k
    L = randn(m, k);
    R = randn(n, k);
    A = L*R';
    % Generate a random mask for observed entries: P(i, j) = 1 if the entry
    % (i, j) of A is observed, and 0 otherwise.
    fraction = 4 * k*(m+n-k)/(m*n);
    P = sparse(rand(m, n) <= fraction);
    % Hence, we know the nonzero entries in PA:
    PA = P.*A;

    % Pick the manifold of matrices of size mxn of fixed rank k.
    problem.M = fixedrankembeddedfactory(m, n, k);

    % Define the problem cost function. The input X is a structure with
    % fields U, S, V representing a rank k matrix as U*S*V'.
    % f(X) = 1/2 * || P.*(X-A) ||^2
    problem.cost = @cost;
    function f = cost(X)
        % Note that it is very much inefficient to explicitly construct the
        % matrix X in this way. Seen as we only need to know the entries
        % of Xmat corresponding to the mask P, it would be far more
        % efficient to compute those only.
        Xmat = X.U*X.S*X.V';
        f = .5*norm( P.*Xmat - PA , 'fro')^2;
    end

    % Define the Euclidean gradient of the cost function, that is, the
    % gradient of f(X) seen as a standard function of X.
    % nabla f(X) = P.*(X-A)
    problem.egrad = @egrad;
    function G = egrad(X)
        % Same comment here about Xmat.
        Xmat = X.U*X.S*X.V';
        G = P.*Xmat - PA;
    end

    % Define the Euclidean Hessian of the cost at X, along H, where H is
    % represented as a tangent vector.
    % nabla^2 f(X)[Xdot] = P.*Xdot
    % (This is the directional derivative of nabla f(X) at X along Xdot.)
    problem.ehess = @euclidean_hessian;
    function ehess = euclidean_hessian(X, H)
        % The function tangent2ambient transforms H (a tangent vector) into
        % its equivalent ambient vector representation. The output is a
        % structure with fields U, S, V such that U*S*V' is an mxn matrix
        % corresponding to the tangent vector H. Note that there are no
        % additional guarantees about U, S and V. In particular, U and V
        % are not orthonormal.
        ambient_H = problem.M.tangent2ambient(X, H);
        Xdot = ambient_H.U*ambient_H.S*ambient_H.V';
        % Same comment here about explicitly constructing the ambient
        % vector as an mxn matrix Xdot: we only need its entries
        % corresponding to the mask P, and this could be computed
        % efficiently.
        ehess = P.*Xdot;
    end

    % Check consistency of the gradient and the Hessian. Useful if you
    % adapt this example for a now cost function and you would like to make
    % sure there is no mistake.
    % warning('off', 'manopt:fixedrankembeddedfactory:exp');
    % checkgradient(problem); pause;
    % checkhessian(problem); pause;

    % Compute an initial guess. Points on the manifold are represented as
    % structures with three fields: U, S and V. U and V need to be
    % orthonormal, S needs to be diagonal.
    [U, S, V] = svds(PA, k);
    X0.U = U;
    X0.S = S;
    X0.V = V;

    % Minimize the cost function using Riemannian trust-regions, starting
    % from the initial guess X0.
    options.stopfun = @stopifclosedfigure;
    X = trustregions(problem, X0, options);

    % The reconstructed matrix is X, represented as a structure with fields
    % U, S and V.
    Xmat = X.U*X.S*X.V';
    fprintf('||X-A||_F = %g\n', norm(Xmat - A, 'fro'));

    % If the problem has a small enough dimension, we may (for analysis
    % purposes) compute the spectrum of the Hessian at a point X. This may
    % help in studying the conditioning of a problem.
    if problem.M.dim() < 100
        fprintf('Computing the spectrum of the Hessian...');
        s = hessianspectrum(problem, X);
        hist(s);
    end

end


% Figure 6.2: Penalty function approximation
% Section 6.1.2
% Boyd & Vandenberghe "Convex Optimization"
% Original by Lieven Vandenberghe
% Adapted for CVX Argyris Zymnis - 10/2005
%
% Comparison of the ell1, ell2, deadzone-linear and log-barrier
% penalty functions for the approximation problem:
%       minimize phi(A*x-b),
%
% where phi(x) is the penalty function
% Log-barrier will be implemented in the future version of CVX

% Generate input data
randn('state',0);
m=100; n=30;
A = randn(m,n);
b = randn(m,1);

% ell_1 approximation
% minimize   ||Ax+b||_1
disp('ell-one approximation');
cvx_begin
    variable x1(n)
    minimize(norm(A*x1+b,1))
cvx_end

% ell_2 approximation
% minimize ||Ax+b||_2
disp('ell-2');
x2=-A\b;

% deadzone penalty approximation
% minimize sum(deadzone(Ax+b,0.5))
% deadzone(y,z) = max(abs(y)-z,0)
dz = 0.5;
disp('deadzone penalty');
cvx_begin
    variable xdz(n)
    minimize(sum(max(abs(A*xdz+b)-dz,0)))
cvx_end

% log-barrier penalty approximation
%
% minimize -sum log(1-(ai'*x+bi)^2)

disp('log-barrier')

% parameters for Newton Method & line search
alpha=.01; beta=.5;

% minimize linfty norm to get starting point
cvx_begin
    variable xlb(n)
    minimize norm(A*xlb+b,Inf)
cvx_end
linf = cvx_optval;
A = A/(1.1*linf);
b = b/(1.1*linf);

for iters = 1:50

   yp = 1 - (A*xlb+b);  ym = (A*xlb+b) + 1;
   f = -sum(log(yp)) - sum(log(ym));
   g = A'*(1./yp) - A'*(1./ym);
   H = A'*diag(1./(yp.^2) + 1./(ym.^2))*A;
   v = -H\g;
   fprime = g'*v;
   ntdecr = sqrt(-fprime);
   if (ntdecr < 1e-5), break; end;

   t = 1;
   newx = xlb + t*v;
   while ((min(1-(A*newx +b)) < 0) || (min((A*newx +b)+1) < 0))
       t = beta*t;
       newx = xlb + t*v;
   end;
   newf = -sum(log(1 - (A*newx+b))) - sum(log(1+(A*newx+b)));
   while (newf > f + alpha*t*fprime)
       t = beta*t;
       newx = xlb + t*v;
       newf = -sum(log(1-(A*newx+b))) - sum(log(1+(A*newx+b)));
   end;
   xlb = xlb+t*v;
end

% Plot histogram of residuals

ss = max(abs([A*x1+b; A*x2+b; A*xdz+b;  A*xlb+b]));
tt = -ceil(ss):0.05:ceil(ss);  % sets center for each bin
[N1,hist1] = hist(A*x1+b,tt);
[N2,hist2] = hist(A*x2+b,tt);
[N3,hist3] = hist(A*xdz+b,tt);
[N4,hist4] = hist(A*xlb+b,tt);

range_max=2.0;  rr=-range_max:1e-2:range_max;

figure(1), clf, hold off
subplot(4,1,1),
bar(hist1,N1);
hold on
plot(rr, abs(rr)*40/3, '-');
ylabel('p=1')
axis([-range_max range_max 0 40]);
hold off

subplot(4,1,2),
bar(hist2,N2);
hold on;
plot(rr,2*rr.^2),
ylabel('p=2')
axis([-range_max range_max 0 11]);
hold off

subplot(4,1,3),
bar(hist3,N3);
hold on
plot(rr,30/3*max(0,abs(rr)-dz))
ylabel('Deadzone')
axis([-range_max range_max 0 25]);
hold off

subplot(4,1,4),
bar(hist4,N4);
rr_lb=linspace(-1+(1e-6),1-(1e-6),600);
hold on
plot(rr_lb, -3*log(1-rr_lb.^2),rr,2*rr.^2,'--')
axis([-range_max range_max 0 11]);
ylabel('Log barrier'),
xlabel('r')
hold off


function [x, c, funVal, ValueL]=LogisticC(A, y, z, opts)
%
%%
% Function LogisticC
%      Logistic Loss with the L1 ball constraint
%
%% Problem
%
%  min  f(x,c) = \sum_i - weight_i * log (p_i) + 1/2 rsL2 * ||x||_2^2
%  s.alpha. \|x\|_1 <=z
%
%  a_i denotes a training sample,
%      and a_i' corresponds to the i-th row of the data matrix A
%
%  y_i (either 1 or -1) is the response
%
%  p_i= 1/ (1+ exp(-y_i (x' * a_i + c) ) ) denotes the probability
%
%  weight_i denotes the weight for the i-th sample
%
%% Input parameters:
%
%  A-         Matrix of size m x n
%                A can be a dense matrix
%                         a sparse matrix
%                         or a DCT matrix
%  y -        Response vector (of size mx1)
%  z -        Radius of the L1 ball
%  opts-      Optional inputs (default value: opts=[])
%
%% Output parameters:
%  x-         The obtained weight of size n x 1
%  c-         The obtained intercept (scalar)
%  funVal-    Function value during iterations
%
%% Copyright (C) 2009-2010 Jun Liu, and Jieping Ye
%
% You are suggested to first read the Manual.
%
% For any problem, please contact with Jun Liu via j.liu@asu.edu
%
%% Related papers
%
% [1]  Jun Liu, Jianhui Chen, and Jieping Ye, Large-Scale Sparse Logistic
%      Regression, KDD 2009
%
% [2]  Jun Liu and Jieping Ye, Efficient Euclidean Projections
%      in Linear Time, ICML 2009.
%
%% Related functions
%
%  sll_opts, initFactor, pathSolutionLeast,
%  LogisticR, nnLogisticR, nnLogisticC,
%  eplb
%
%%

%% Verify and initialize the parameters
%%
if (nargin <3)
    error('\n Inputs: A, y and z should be specified!\n');
end

[m,n]=size(A);

if (length(y) ~=m)
    error('\n Check the length of y!\n');
end

if (z<=0)
    error('\n z should be positive!\n');
end

opts=sll_opts(opts); % run sll_opts to set default values (flags)

%% Detailed initialization
%% Normalization

% Please refer to sll_opts for the definitions of mu, nu and nFlag
%
% If .nFlag =1, the input matrix A is normalized to
%                     A= ( A- repmat(mu, m,1) ) * diag(nu)^{-1}
%
% If .nFlag =2, the input matrix A is normalized to
%                     A= diag(nu)^{-1} * ( A- repmat(mu, m,1) )
%
% Such normalization is done implicitly
%     This implicit normalization is suggested for the sparse matrix
%                                    but not for the dense matrix
%

if (opts.nFlag~=0)
    if (isfield(opts,'mu'))
        mu=opts.mu;
        if(size(mu,2)~=n)
            error('\n Check the input .mu');
        end
    else
        mu=mean(A,1);
    end

    if (opts.nFlag==1)
        if (isfield(opts,'nu'))
            nu=opts.nu;
            if(size(nu,1)~=n)
                error('\n Check the input .nu!');
            end
        else
            nu=(sum(A.^2,1)/m).^(0.5); nu=nu';
        end
    else % .nFlag=2
        if (isfield(opts,'nu'))
            nu=opts.nu;
            if(size(nu,1)~=m)
                error('\n Check the input .nu!');
            end
        else
            nu=(sum(A.^2,2)/n).^(0.5);
        end
    end

    ind_zero=find(abs(nu)<= 1e-10);    nu(ind_zero)=1;
    % If some values in nu is typically small, it might be that,
    % the entries in a given row or column in A are all close to zero.
    % For numerical stability, we set the corresponding value to 1.
end

if (~issparse(A)) && (opts.nFlag~=0)
    fprintf('\n -----------------------------------------------------');
    fprintf('\n The data is not sparse or not stored in sparse format');
    fprintf('\n The code still works.');
    fprintf('\n But we suggest you to normalize the data directly,');
    fprintf('\n for achieving better efficiency.');
    fprintf('\n -----------------------------------------------------');
end

%% Group & Others

% The parameter 'weight' contains the weight for each training sample.
% See the definition of the problem above.
% The summation of the weights for all the samples equals to 1.
if (isfield(opts,'sWeight'))
    sWeight=opts.sWeight;

    if ( length(sWeight)~=2 || sWeight(1) <=0 || sWeight(2) <= 0)
        error('\n Check opts.sWeight, which contains two positive values');
    end

    % we process the weight, so that the summation of the weights for all
    % the samples is 1.

    p_flag=(y==1);                  % the indices of the postive samples
    m1=sum(p_flag) * sWeight(1);    % the total weight for the positive samples
    m2=sum(~p_flag) * sWeight(2);   % the total weight for the positive samples

    weight(p_flag,1)=sWeight(1)/(m1+m2);
    weight(~p_flag,1)=sWeight(2)/(m1+m2);
else
    weight=ones(m,1)/m;             % if not specified, we apply equal weight
end

%% Starting point initialization

% L2 norm regularization
if isfield(opts,'rsL2')
    rsL2=opts.rsL2;
    if (rsL2<0)
        error('\n opts.rsL2 should be nonnegative!');
    end
else
    rsL2=0;
end

% initialize a starting point
if opts.init==2
    x=zeros(n,1); c=0;
else
    if isfield(opts,'x0')
        x=opts.x0;
        if (length(x)~=n)
            error('\n Check the input .x0');
        end
    else
        x=zeros(n,1);
    end

    if isfield(opts,'c0')
        c=opts.c0;
    else
        c=0;
    end
end

% compute A x
if (opts.nFlag==0)
    Ax=A* x;
elseif (opts.nFlag==1)
    invNu=x./nu; mu_invNu=mu * invNu;
    Ax=A*invNu -repmat(mu_invNu, m, 1);
else
    Ax=A*x-repmat(mu*x, m, 1);    Ax=Ax./nu;
end

%% The main program

%% Nemirovski's line search

if (opts.lFlag==0)

    lambda0=0;
    % a guess of the root

    bFlag=0; % this flag tests whether the gradient step only changes a little

    L=1/m + rsL2; % the intial guess of the Lipschitz continuous gradient

    weighty=weight.*y;
    % the product between weight and y

    % assign xp with x, and Axp with Ax
    xp=x; Axp=Ax; xxp=zeros(n,1);
    cp=c;         ccp=0;

    %% The Armijo Goldstein line search schemes + accelearted gradient descent

    alphap=0; alpha=1;

    for iterStep=1:opts.maxIter
        % --------------------------- step 1 ---------------------------
        % compute search point s based on xp and x (with beta)
        beta=(alphap-1)/alpha;    s=x + beta* xxp;  sc=c + beta* ccp;

        % --------------------------- step 2 ---------------------------
        % line search for L and compute the new approximate solution x

        % compute As=A*s
        As=Ax + beta* (Ax-Axp);

        % aa= - diag(y) * (A * s + sc)
        aa=- y.*(As+ sc);

        % fun_s is the logistic loss at the search point
        bb=max(aa,0);
        fun_s= weight' * ( log( exp(-bb) +  exp(aa-bb) ) + bb )+...
            rsL2/2 * s'*s;

        % compute prob=[p_1;p_2;...;p_m]
        prob=1./( 1+ exp(aa) );

        % b= - diag(y.* weight) * (1 - prob)
        b= -weighty.*(1-prob);

        gc=sum(b); % the gradient of c

        % compute g= AT b, the gradient of x
        if (opts.nFlag==0)
            g=A'*b;
        elseif (opts.nFlag==1)
            g=A'*b - sum(b) * mu';  g=g./nu;
        else
            invNu=b./nu;              g=A'*invNu-sum(invNu)*mu';
        end

        g=g+ rsL2 * s;  % add the squared L2 norm regularization term

        % copy x and Ax to xp and Axp
        xp=x;    Axp=Ax;
        cp=c;

        while (1)
            % let s walk in a step in the antigradient of s to get v
            % and then do the Lq/L1-norm regularized projection
            v=s-g/L;  c= sc- gc/L;

            % projection
            [x, lambda, zf_step]=eplb(v, n, z, lambda0);
            lambda0=lambda;

            v=x-s;  % the difference between the new approximate solution x
            % and the search point s

            % compute A x
            if (opts.nFlag==0)
                Ax=A* x;
            elseif (opts.nFlag==1)
                invNu=x./nu; mu_invNu=mu * invNu;
                Ax=A*invNu -repmat(mu_invNu, m, 1);
            else
                Ax=A*x-repmat(mu*x, m, 1);     Ax=Ax./nu;
            end

            % aa= - diag(y) * (A * x + c)
            aa=- y.*(Ax+ c);

            % fun_x is the logistic loss at the new approximate solution
            bb=max(aa,0);
            fun_x= weight'* ( log( exp(-bb) +  exp(aa-bb) ) + bb )+...
                rsL2/2 * x'*x;

            r_sum= (v'*v + (c-sc)^2) / 2;
            l_sum=fun_x - fun_s - v'* g - (c-sc)* gc;

            if (r_sum <=1e-20)
                bFlag=1; % this shows that, the gradient step makes little improvement
                break;
            end

            % the condition is fun_x <= fun_s + v'* g + c * gc
            %                           + L/2 * (v'*v + (c-sc)^2 )
            if(l_sum <= r_sum * L)
                break;
            else
                L=max(2*L, l_sum/r_sum);
                %fprintf('\n L=%e, r_sum=%e',L, r_sum);
            end
        end

        % --------------------------- step 3 ---------------------------
        % update alpha and alphap, and check whether converge
        alphap=alpha; alpha= (1+ sqrt(4*alpha*alpha +1))/2;

        ValueL(iterStep)=L;
        % store values for L

        xxp=x-xp;    ccp=c-cp;
        funVal(iterStep)=fun_x;

        if (bFlag)
            % fprintf('\n The program terminates as the gradient step changes the solution very small.');
            break;
        end

        switch(opts.tFlag)
            case 0
                if iterStep>=2
                    if (abs( funVal(iterStep) - funVal(iterStep-1) ) <= opts.tol)
                        break;
                    end
                end
            case 1
                if iterStep>=2
                    if (abs( funVal(iterStep) - funVal(iterStep-1) ) <=...
                            opts.tol* funVal(iterStep-1))
                        break;
                    end
                end
            case 2
                if ( funVal(iterStep)<= opts.tol)
                    break;
                end
            case 3
                norm_xxp=sqrt(xxp'*xxp);
                if ( norm_xxp <=opts.tol)
                    break;
                end
            case 4
                norm_xp=sqrt(xp'*xp);    norm_xxp=sqrt(xxp'*xxp);
                if ( norm_xxp <=opts.tol * max(norm_xp,1))
                    break;
                end
            case 5
                if iterStep>=opts.maxIter
                    break;
                end
        end
    end
end

%% adaptive line search

if (opts.lFlag==1)

    lambda0=0;
    % a guess of the root

    bFlag=0; % this flag tests whether the gradient step only changes a little

    L=1/m + rsL2; % the intial guess of the Lipschitz continuous gradient

    gamma=1;
    % we shall set the value of gamma = L,
    % and L is appropriate for the starting point

    weighty=weight.*y;
    % the product between weight and y

    % assign xp with x, and Axp with Ax
    xp=x; Axp=Ax; xxp=zeros(n,1);
    cp=c;         ccp=0;

    for iterStep=1:opts.maxIter
        while (1)
            if (iterStep~=1)
                alpha= (-gamma+ sqrt(gamma*gamma + 4* L * gamma)) / (2*L);
                beta= (gamma - gamma* alphap) / (alphap * gamma + alphap* L * alpha);
                % beta is the coefficient for generating search point s

                s=x + beta* xxp;  sc=c + beta* ccp;
                As=Ax + beta* (Ax-Axp);
            else
                alpha= (-1+ sqrt(5)) / 2;  beta=0;
                s=x; sc= c;
                As=Ax;
            end

            % aa= - diag(y) * (A * s + sc)
            aa=- y.*(As+ sc);

            % fun_s is the logistic loss at the search point
            bb=max(aa,0);
            fun_s= weight' * ( log( exp(-bb) +  exp(aa-bb) ) + bb )+...
                rsL2/2 * s'*s;

            % compute prob=[p_1;p_2;...;p_m]
            prob=1./( 1+ exp(aa) );

            % b= - diag(y.* weight) * (1 - prob)
            b= -weighty.*(1-prob);

            gc=sum(b); % the gradient of c

            % compute g= AT b, the gradient of x
            if (opts.nFlag==0)
                g=A'*b;
            elseif (opts.nFlag==1)
                g=A'*b - sum(b) * mu';  g=g./nu;
            else
                invNu=b./nu;              g=A'*invNu-sum(invNu)*mu';
            end

            g=g+ rsL2 * s;  % add the squared L2 norm regularization term

            % let s walk in a step in the antigradient of s to get v
            % and then do the Lq/L1-norm regularized projection
            v=s-g/L;  cnew= sc- gc/L;

            % projection
            [xnew, lambda, zf_step]=eplb(v, n, z, lambda0);
            lambda0=lambda;

            v=xnew-s;  % the difference between the new approximate solution x
            % and the search point s

            % compute A xnew
            if (opts.nFlag==0)
                Axnew=A* xnew;
            elseif (opts.nFlag==1)
                invNu=xnew./nu; mu_invNu=mu * invNu;
                Axnew=A*invNu -repmat(mu_invNu, m, 1);
            else
                Axnew=A*xnew-repmat(mu*xnew, m, 1);     Axnew=Axnew./nu;
            end

            % aa= - diag(y) * (A * x + c)
            aa=- y.*(Axnew+ cnew);

            % fun_x is the logistic loss at the new approximate solution
            bb=max(aa,0);
            fun_x= weight'* ( log( exp(-bb) +  exp(aa-bb) ) + bb )+...
                rsL2/2 * xnew'*xnew;

            r_sum= (v'*v + (cnew-sc)^2) / 2;
            l_sum=fun_x - fun_s - v'* g - (cnew-sc)* gc;

            if (r_sum <=1e-20)
                bFlag=1; % this shows that, the gradient step makes little improvement
                break;
            end

            % the condition is fun_x <= fun_s + v'* g + c * gc
            %                           + L/2 * (v'*v + (c-sc)^2 )
            if(l_sum <= r_sum * L)
                break;
            else
                L=max(2*L, l_sum/r_sum);
                %fprintf('\n L=%e, r_sum=%e',L, r_sum);
            end
        end

        gamma=L* alpha* alpha;    alphap=alpha;
        % update gamma, and alphap

        ValueL(iterStep)=L;
        % store values for L

        tao=L * r_sum / l_sum;
        if (tao >=5)
            L=L*0.8;
        end
        % decrease the value of L

        xp=x;     x=xnew; xxp=x-xp;
        Axp=Ax;   Ax=Axnew;
        cp=c;     c=cnew; ccp=c-cp;
        % update x and Ax with xnew and Axnew

        funVal(iterStep)=fun_x;

        if (bFlag)
            % fprintf('\n The program terminates as the gradient step changes the solution very small.');
            break;
        end

        switch(opts.tFlag)
            case 0
                if iterStep>=2
                    if (abs( funVal(iterStep) - funVal(iterStep-1) ) <= opts.tol)
                        break;
                    end
                end
            case 1
                if iterStep>=2
                    if (abs( funVal(iterStep) - funVal(iterStep-1) ) <=...
                            opts.tol* funVal(iterStep-1))
                        break;
                    end
                end
            case 2
                if ( funVal(iterStep)<= opts.tol)
                    break;
                end
            case 3
                norm_xxp=sqrt(xxp'*xxp);
                if ( norm_xxp <=opts.tol)
                    break;
                end
            case 4
                norm_xp=sqrt(xp'*xp);    norm_xxp=sqrt(xxp'*xxp);
                if ( norm_xxp <=opts.tol * max(norm_xp,1))
                    break;
                end
            case 5
                if iterStep>=opts.maxIter
                    break;
                end
        end
    end
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  In this script, we perform phase transition analysis
%  of Orthogonal matching pursuit.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
close all;
clear all;
clc;
rng('default');
% Create the directory for storing results
[status_code,message,message_id] = mkdir('bin');
target_file_path = 'bin/mmv_phase_transition_snr_40db_s_16.mat';
N = 256;
S = 16;
pta = spx.pursuit.PhaseTransitionAnalysis(N);
pta.SNR = 40;
% pta.NumTrials = 100;
dict_model = @(M, N) spx.dict.simple.gaussian_dict(M, N);
data_model = @(N, K) spx.data.synthetic.SparseSignalGenerator(N, K, S).gaussian;
recovery_solver = @(Phi, K, y) spx.pursuit.joint.CoSaMP(Phi, K).solve(y).Z;
pta.run(dict_model, data_model, recovery_solver);
pta.save_results(target_file_path);


%P2.9a
%T1[x(n)]=2^x(n)
n=[0:200];x=cos(0.2*pi*n)+0.5*cos(0.6*pi*n);
t1=2.^x
[x1,n1]=sigshift(t1,n,50); %x(n-k) -> k=50
[x2,n2]=sigfold(t1,n); %x(-n)
[x3,n3]=sigfold(x1,n1); %x(k-n)
[rxx,nrxx]=conv_m(t1,n,x2,n2);
[rxk,nrkx]=conv_m(x1,n1,x3,n3);
[y,m]=sigadd(rxx,nrxx,0.1*rxk,nrkx);
figure(1);
subplot(3,1,1); stem(m,y,'k');title('Autocorrelation ryy');xlabel('m');

%T2[x(n)]=3x(n)+4
n=[0:200];x=cos(0.2*pi*n)+0.5*cos(0.6*pi*n);
t2=3*x+4
[x1,n1]=sigshift(t2,n,50); %x(n-k) -> k=50
[x2,n2]=sigfold(t2,n); %x(-n)
[x3,n3]=sigfold(x1,n1); %x(k-n)
[rxx,nrxx]=conv_m(t2,n,x2,n2);
[rxk,nrkx]=conv_m(x1,n1,x3,n3);
[y,m]=sigadd(rxx,nrxx,0.1*rxk,nrkx);
subplot(3,1,2); stem(m,y,'k');title('Autocorrelation ryy');xlabel('m');

%T3[x(n)]=x(n)+2x(n-1)-x(n-2)
n=[0:200];x=cos(0.2*pi*n)+0.5*cos(0.6*pi*n);
[xa,nxa]=sigshift(x,n,1);
[xb,nxb]=sigshift(x,n,2);
[xa,nxa]=sigadd(2*xa,nxa,-1*xb,nxb);
[t3,n]=sigadd(x,n,xa,nxa)
[x1,n1]=sigshift(t3,n,50); %x(n-k) -> k=50
[x2,n2]=sigfold(t3,n); %x(-n)
[x3,n3]=sigfold(x1,n1); %x(k-n)
[rxx,nrxx]=conv_m(t3,n,x2,n2);
[rxk,nrkx]=conv_m(x1,n1,x3,n3);
[y,m]=sigadd(rxx,nrxx,0.1*rxk,nrkx);
subplot(3,1,3); stem(m,y,'k');title('Autocorrelation ryy');xlabel('m');

%P2.9b
%T1[x(n)]=2^x(n)
%x(n)=random sequence
nrand=[0:100];xrand=rand(size(nrand));
t1=2.^xrand
[x1,n1]=sigshift(t1,n,50); %x(n-k) k=50
[x2,n2]=sigfold(t1,n); %x(-n)
[x3,n3]=sigfold(x1,n1); %x(k-n)
[rxx,nrxx]=conv_m(t1,n,x2,n2);
[rxk,nrkx]=conv_m(x1,n1,x3,n3);
[y,m]=sigadd(rxx,nrxx,0.1*rxk,nrkx);
figure(2);
subplot(3,1,1); stem(m,y,'k');title('Autocorrelation ryy');xlabel('m');

%T2[x(n)]=3x(n)+4
%x(n)=random sequence
nrand=[0:100];xrand=rand(size(nrand));
t2=3*xrand+4
[x1,n1]=sigshift(t2,n,50); %x(n-k) -> k=50
[x2,n2]=sigfold(t2,n); %x(-n)
[x3,n3]=sigfold(x1,n1); %x(k-n)
[rxx,nrxx]=conv_m(t2,n,x2,n2);
[rxk,nrkx]=conv_m(x1,n1,x3,n3);
[y,m]=sigadd(rxx,nrxx,0.1*rxk,nrkx);
subplot(3,1,2); stem(m,y,'k');title('Autocorrelation ryy');xlabel('m');

%T3[x(n)]=x(n)+2x(n-1)-x(n-2)
%x(n)=Random Sequence
nrand=[0:100];xrand=rand(size(nrand));
[xa,nxa]=sigshift(xrand,nrand,1);
[xb,nxb]=sigshift(xrand,nrand,2);
[xa,nxa]=sigadd(2*xa,nxa,-1*xb,nxb);
[t3,n]=sigadd(xrand,nrand,xa,nxa);
[x1,n1]=sigshift(t3,n,50); %x(n-k) -> k=50
[x2,n2]=sigfold(t3,n); %x(-n)
[x3,n3]=sigfold(x1,n1); %x(k-n)
[rxx,nrxx]=conv_m(t3,n,x2,n2);
[rxk,nrkx]=conv_m(x1,n1,x3,n3);
[y,m]=sigadd(rxx,nrxx,0.1*rxk,nrkx);
subplot(3,1,3); stem(m,y,'k');title('Autocorrelation ryy');xlabel('m');

%P2.9c
%T1[x(n)]=2^x(n)
%x(n)=Gaussian random sequence
nrand=[0:100];xrand=randn(size(nrand))
t1=2.^xrand
[x1,n1]=sigshift(t1,n,50); %x(n-k) k=50
[x2,n2]=sigfold(t1,n); %x(-n)
[x3,n3]=sigfold(x1,n1); %x(k-n)
[rxx,nrxx]=conv_m(t1,n,x2,n2);
[rxk,nrkx]=conv_m(x1,n1,x3,n3);
[y,m]=sigadd(rxx,nrxx,0.1*rxk,nrkx);
figure(3);
subplot(3,1,1); stem(m,y,'k');title('Autocorrelation ryy');xlabel('m');

%T2[x(n)]=3x(n)+4
%x(n)=Gaussian random sequence
nrand=[0:100];xrand=randn(size(nrand))
t2=3*xrand+4
[x1,n1]=sigshift(t2,n,50); %x(n-k) -> k=50
[x2,n2]=sigfold(t2,n); %x(-n)
[x3,n3]=sigfold(x1,n1); %x(k-n)
[rxx,nrxx]=conv_m(t2,n,x2,n2);
[rxk,nrkx]=conv_m(x1,n1,x3,n3);
[y,m]=sigadd(rxx,nrxx,0.1*rxk,nrkx);
subplot(3,1,2); stem(m,y,'k');title('Autocorrelation ryy');xlabel('m');

%T3[x(n)]=x(n)+2x(n-1)-x(n-2)
%x(n)=Gaussian Random Sequence
nrand=[0:100];xrand=randn(size(nrand));
[xa,nxa]=sigshift(xrand,nrand,1);
[xb,nxb]=sigshift(xrand,nrand,2);
[xa,nxa]=sigadd(2*xa,nxa,-1*xb,nxb);
[t3,n]=sigadd(xrand,nrand,xa,nxa);
[x1,n1]=sigshift(t3,n,50); %x(n-k) -> k=50
[x2,n2]=sigfold(t3,n); %x(-n)
[x3,n3]=sigfold(x1,n1); %x(k-n)
[rxx,nrxx]=conv_m(t3,n,x2,n2);
[rxk,nrkx]=conv_m(x1,n1,x3,n3);
[y,m]=sigadd(rxx,nrxx,0.1*rxk,nrkx);
subplot(3,1,3); stem(m,y,'k');title('Autocorrelation ryy');xlabel('m');


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function [Eigen_Vector,Eigen_Value]=Find_K_Max_Gen_Eigen(Matrix1,Matrix2,Eigen_NUM)

[NN,NN]=size(Matrix1);
[V,S]=eig(Matrix1,Matrix2); %Note this is equivalent to; [V,S]=eig(St,SL); also equivalent to [V,S]=eig(Sn,St); %

S=diag(S);
[S,index]=sort(S);

Eigen_Vector=zeros(NN,Eigen_NUM);
Eigen_Value=zeros(1,Eigen_NUM);

p=NN;
for t=1:Eigen_NUM
    Eigen_Vector(:,t)=V(:,index(p));
    Eigen_Value(t)=S(p);
    p=p-1;
end


% ZCA & l1-norm operation
function output = whitening_norm(features)
    features = im2double(features);
%     output = features;
    output = zca(features);
    output = l1_norm(output);
%     output = l2_norm(output);
%     output = nuclear(output);
end

% l1-norm
function output = l1_norm(features)
    [h,w,c] = size(features);
    output = zeros(h, w);
    unit = 5;
    % padding
    pad = (unit-1)/2;
    feature_temp = zeros(h+unit-1, w+unit-1, c);
    feature_temp(1+pad:h+pad, 1+pad:w+pad, :) = features;
    for i=1+pad:h+pad
        for j=1+pad:w+pad
            temp = feature_temp(i-pad:i+pad, j-pad:j+pad, :);
            norm = sum(sum(sum(abs(temp),3)))/(unit*unit);
            output(i-pad, j-pad) = norm;
        end
    end
end

% l2-norm
function output = l2_norm(features)
    [h,w,c] = size(features);
    output = zeros(h, w);
    unit = 5;
    % padding
    pad = (unit-1)/2;
    feature_temp = zeros(h+unit-1, w+unit-1, c);
    feature_temp(1+pad:h+pad, 1+pad:w+pad, :) = features;
    for i=1+pad:h+pad
        for j=1+pad:w+pad
            temp = feature_temp(i-pad:i+pad, j-pad:j+pad, :);
            temp = temp.*temp;
            norm = sum(sum(sqrt(sum(temp,3))))/(unit*unit);
            output(i-pad, j-pad) = norm;
        end
    end
end

% nuclear-norm
function output = nuclear(features)
    [h,w,c] = size(features);
    output = zeros(h, w);
    unit = 5;
    % padding
    pad = (unit-1)/2;
    feature_temp = zeros(h+unit-1, w+unit-1, c);
    feature_temp(1+pad:h+pad, 1+pad:w+pad, :) = features;
    for i=1+pad:h+pad
        for j=1+pad:w+pad
            temp = reshape(feature_temp(i-pad:i+pad, j-pad:j+pad, :), [unit*unit c]);
            [U, S, V] = svd(temp, 'econ');
            nu_norm = sum(diag(S));
            output(i-pad, j-pad) = nu_norm;
        end
    end

end


%{
Author: Deepti Ghadiyaram

Description: Given an input RGB image, this method extracts the 564 FRIQUEE
features proposed in [1] in three different color spaces.

1. We first convert the given input image into different color spaces -
LAB, LMS, and HSI.

2. We then extract the required components from each of these color spaces
eg: Hue and Saturation components, M and S components.

3. We also compute the chroma map from the A and B components of the image
in LAB color space.

Input: a MXNX3 array upon reading any image.

Output: Features extracted in luminance, chroma, LMS color components of the
image.

Dependencies: This method depends on the following methods:
computeSigmaMap.m
divisiveNormalization.m
%}
function feat = DoGFeat(imGray)

    %Get the sigma map of the image.
    sigmaMap = computeSigmaMap(imGray);

    % Construct two Gaussian windows where sig2 = 1.5*sig1;
    k=1.5;

    window1 = fspecial('gaussian',7,7/6);
    window1 = window1/sum(sum(window1));

    window2 = fspecial('gaussian',7,7*k/6);
    window2 = window2/sum(sum(window2));

    %Compute DOG of the sigmaMap
    DoGSigma= filter2((window1-window2), sigmaMap, 'same');

    %Compute the sigmaMap of DoGSigma
    DoGSigma1 = computeSigmaMap(DoGSigma);

    %DNT of DOG of sigma.
    divNormDoGSigma = divisiveNormalization(DoGSigma);

    %shape, variance, skewness.
    [alpha,lsigma] = estimateggdparam(divNormDoGSigma(:));

    % Apply DNT on DoGSigma1
    divNormDoGSigma1 = divisiveNormalization(DoGSigma1);

    % The model features are the GGD parameters of divNormDoGSigma (DNT of
    % dogSigma)
    modelFeats = [alpha lsigma];

    % The sample statistical features are extracted from both
    % divNormDoGSigma and divNormDoGSigma1
    sampleFeats = [skewness(divNormDoGSigma(:)) kurtosis(divNormDoGSigma(:)) skewness(divNormDoGSigma1(:)) kurtosis(divNormDoGSigma1(:))];

    feat = [modelFeats sampleFeats];
end