Params.poolSize = 0
MY_DATA_FOLDER = "../"

% Init Matlab parallel pool.
if (Params.poolSize > 0)  % Note: parfor doesn't work on Octave. 
    pool = parpool('local',Params.poolSize);
end;

dim_set        = [500,1000,2000,5000,1e4]

lambda         = 0.35*25;
time_total_set = [];
time_ll_set    = [];
nnz_set        = [];

for i = 1:length(dim_set)

    [Y,X_star_base]                    = load_data(MY_DATA_FOLDER,"trid",dim_set(i),true);
    [elapsedTotal,elapsedLL,X,permute] = run_SNETCH(Y,lambda,Params.poolSize );

    X_star                = X_star_base(permute,permute);
    nnz_set(end+1)        = nnz(X)/size(X,1)
    time_total_set(end+1) = elapsedTotal
    time_ll_set(end+1)    = elapsedLL

end

disp("--trid--")
nnz_set
time_total_set
time_ll_set

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
lambda         =  0.2*25;
time_total_set = [];
time_ll_set    = [];
nnz_set        = [];

for i = 1:length(dim_set)

    [Y,X_star_base]                    = load_data(MY_DATA_FOLDER,"clus",dim_set(i),true);
    [elapsedTotal,elapsedLL,X,permute] = run_SNETCH(Y,lambda,Params.poolSize );

    X_star                = X_star_base(permute,permute);
    nnz_set(end+1)        = nnz(X)/size(X,1)
    time_total_set(end+1) = elapsedTotal
    time_ll_set(end+1)    = elapsedLL

end

disp("--clus--")
nnz_set
time_total_set
time_ll_set

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Cleanup (clean path, parpool, etc.).
if (Params.poolSize > 0)
    delete(pool);
end;

function [elapsedTotal,elapsedLL,Ueval,permute]=run_SNETCH(Y,lambda,poolSize)

    N = size(Y,1)

    Y=Y';

    % Threshold for convergence (calculated as sum(dL.^2)). 
    dLthreshold = 0.1.^6; 

    % Max number of iterations.
    numIterations = 100;

    % Set true to normalize covariance matrix (to correlation matrix).
    Params.normalizeCovariance = true;

    % Set true to enable Minimal degree reordering preprocessing step. 
    Params.columnReordering = true;

    evalc('feature(''numcores'')')


    %% ----- INIT ----

    % Cholesky matrix (parameter to be optimized).
    L = speye(N); % initially identity

    disp('Calculating active set...');
    tic;

    % Precalculated (multilevel) active set.
    activeSet = covLambda(Y, lambda);

    % Starting active set.
    activeSet0 = activeSet{1};

    % Time needed to find starting active set.
    elapsedTimePreproc = toc;

    disp('Starting optimization...');
    tic

    permute = 1:N;

    % Column reordering.
    if(Params.columnReordering)
        permute = symamd(activeSet0); 

 %       U = U(reorderedCols, reorderedCols);

        Y = Y(:,permute);
        
        for i=1:length(activeSet)
        activeSet{i} = activeSet{i}(permute, permute);
        end;
    end;

    elapsedTimeReordering = toc;
    tic

    %% ------ OPTIMIZATION ----

    % Main optimization procedure.
    if (poolSize > 0)  % Note: parfor doesn't work on Octave. 
        [L,iterations, dL] = SNETCHpar(Y, L, lambda, numIterations, dLthreshold, activeSet); 
    else
        [L,iterations, dL] = SNETCH(Y, L, lambda, numIterations, dLthreshold, activeSet); 
    end;


    % Time spent doing coordinate descent.
    elapsedTime = toc;

    % Total time.
    elapsedTotal = elapsedTime + elapsedTimePreproc + elapsedTimeReordering;

    % Calculate precision matrix.
    tic;
    Ueval = L*L';
    elapsedLL = toc;
end

function [Y,X_star] = load_data(MY_DATA_FOLDER,type, p, normalize)

    fprintf("# Loading Data: type=%s p=%d", type, p);

    filename_base = MY_DATA_FOLDER+"/squic_test_db/n_500/";

    if(type=="clus")
        file     = filename_base + "Clusters"+ p+".mat";
    else
        file     = filename_base + "Trid"+ p+".mat";
    end

    data   = load(file);


    if (normalize)
        sd_inv = 1./sqrt(var(data.Y',1));
        Y   = data.Y .* sd_inv';
        X_star = data.Theta;
    else
        Y = data.Y;
        X_star=data.Theta;
    end

end


