% parforloop functions for Covariance regularization simulation
%
%Inputs
%   Xa: Dependent variable matrix of dimensions Na x Ta-1.
%   Za: Independent variable matrix of dimensions Na x Ta-1.
%   RegA1: string with the regularization target for the coef.
%   RegSigma1: A string with the regularization cov target.
%   F: Number of hyperparameters for the coeffient reg.
%   deltas: A vector of length Na with hyperparameters for the covariance matrix.
%   Na: A scalar value representing the number of agents.
%   Ta: A scalar value representing the number of time steps.
%   realCof: structure with true parameters.
%   target: String for FEVD target.
%   H: A scalar value for the horizon of the FEVD.
%
%Outputs
%   oraclenorm: A scalar containing the oracle norm to the real FEVD.
%   Areg: estimated coeffient output. Potentially needed to carry over to
%       another simulation
%   oraclenormStruct: Oracle norm to the structural FEVD
%Functionality
%   The function performs the regularisation of the covariance matrix and
%   returns the oracle norm to the real FEVD. 
%
% Author: Ruben Hipp, 2021

function [oraclenorm, Areg, oraclenormStruct] = parforloopSig(Xa,Za,RegSigma1,deltas,Na,Ta,Rule,real,target,H,EstLast)

Areal=real.A;

% Regularization of the Covariance matrix
% reuse the coefficient estimation from another method in order to optimize
% the code, if provided
if nargin < 12
    [Est.Ahat, Est.Areg, Est.Sighat, Est.SigReg] = RegularizeSig(Xa,Za,RegSigma1,deltas,Na,Ta,Rule,Areal);
else
    [Est.Ahat, Est.Areg, Est.Sighat, Est.SigReg] = RegularizeSig(Xa,Za,RegSigma1,deltas,Na,Ta,Rule,Areal,EstLast);
end

Areg = Est.Areg;

% calculate FEVDs
D = FEVD(Est,real,H,target);

% calculate norm to the real FEVDs
norms = evaluate(D);
normPlotReg = squeeze(norms.relNorm);
normPlotRegStruct = squeeze(norms.relNormStruct);

% remove multiple solutions for best norms
[~, minReg] = min(normPlotReg); % Target variable for selection of "oracle". Note that later it will be compared to the structural FEVD.
if length(minReg)>1
    minReg = min(minReg);
end

%% Display if border solution is selected for the hyperparameter grid
if contains(RegSigma1,'Sample-Cov') || contains(RegSigma1,'Ledoit-Wolf') 
else
if minReg == 1
    disp([' Minimum grid reached for ' RegSigma1])
elseif minReg == length(normPlotReg)
    disp([' Maximum grid reached for ' RegSigma1])
elseif contains(RegSigma1,'Threshold')
    lengthEta = size(D.Reg,5)/length(deltas);
    if rem(minReg,lengthEta) == 0
        disp(' Border solution I = max(eta)')
    elseif rem(minReg,lengthEta) == 1
%         disp(' Border solution I = min(eta)')
    elseif minReg <= lengthEta
        disp(' Border solution I = min(delta)')
    elseif minReg > size(D.Reg,5)-lengthEta
        disp(' Border solution I = max(delta)')
    end
end
end

%% Output generation
oraclenorm = unique(normPlotReg(minReg));

oraclenormStruct = unique(normPlotRegStruct(minReg));


end