classdef MOSSETracker < handle
    %MOSSETRACKER  MOSSE filter based tracker
    %
    % Correlation filter based tracking using MOSSE filters
    % (Minimum Output Sum of Squared Error), described in [Bolme2010].
    %
    % The target object appearance is modeled using adaptive correlation
    % filters, and tracking is performed via convolution.
    %
    % The filters are learnt online in an adaptive manner for visual tracking.
    %
    % ## Sources:
    %
    % * https://github.com/opencv/opencv/blob/3.3.1/samples/python/mosse.py
    %
    % ## References
    % [Bolme2010]:
    % > David S. Bolme et al.
    % > "Visual Object Tracking using Adaptive Correlation Filters"
    % > [PDF](http://www.cs.colostate.edu/~draper/papers/bolme_cvpr10.pdf)
    %

    properties
        % criteria for successful tracking, psr > min_psr
        % A value between [20,60] indicates very strong peaks,
        % less than 7 indicates bad track quality.
        min_psr = 8.0;
    end

    properties (Access = private)
        % Hanning window used when preprocessing images
        win
        % Fourier transform of 2D Gaussian shaped peak centered on target
        G
        % correlation filters/kernels
        H1
        H2
        H
        % last image of target
        last_img
        % last correlation response
        last_resp
    end

    properties (SetAccess = private)
        % center [x,y] of tracked object rectangle
        pos
        % size [w,h] of tracked object rectangle
        siz
        % Peak-to-Sidelobe Ratio (PSR)
        psr
    end

    properties (Dependent, SetAccess = private)
        % tracked object position, as a `[x y w h]` rectangle
        bbox
    end

    methods
        function obj = MOSSETracker(frame, rect)
            %MOSSETRACKER  Constructor
            %
            %     obj = MOSSETracker(frame, rect)
            %
            % ## Input
            % * __frame__ first frame with target to track
            % * __rect__ rectangle around target object `[x,y,w,h]`
            %

            % center and size of object rectangle (after DFT optimal padding)
            obj.siz = arrayfun(@(s) cv.getOptimalDFTSize(s), rect(3:4));
            obj.pos = floor((2*rect(1:2) + rect(3:4) - obj.siz) / 2);
            obj.pos = obj.pos + 0.5 * (obj.siz - 1);

            % create Hanning window of same size as rect
            obj.win = cv.createHanningWindow(obj.siz, 'Type','single');

            % create Gaussian shaped peak, centered and of same size as rect
            % (Kronecker delta with 1 at target center, 0 elsewhere)
            g = zeros(obj.siz(2), obj.siz(1), 'single');
            g(floor(end/2),floor(end/2)) = 1;
            g = cv.GaussianBlur(g, 'KSize',[-1 -1], 'SigmaX',2.0);
            g = g / max(g(:));

            % initialize correlation filters
            obj.G = cv.dft(g, 'ComplexOutput',true);
            obj.H1 = zeros(size(obj.G), class(obj.G));
            obj.H2 = zeros(size(obj.G), class(obj.G));

            % train filters on a bunch of augmented images
            % by applying small random affine perturbations
            img = cv.getRectSubPix(frame, obj.siz, obj.pos);
            for i=1:128
                a = obj.preprocess(random_warp(img));
                obj.update_kernels(a);
            end

            % process first frame
            obj.update(frame);
        end

        function update(obj, frame, rate)
            %UPDATE  Track object in new frame and update filters
            %
            %     obj.update(frame)
            %     obj.update(frame, rate)
            %
            % ## Input
            % * __frame__ new frame in which to track object
            % * __rate__ learning rate in [0,1] range, default 0.125
            %

            % crop and process image from current position
            obj.last_img = cv.getRectSubPix(frame, obj.siz, obj.pos);
            img = obj.preprocess(obj.last_img);

            % track target by correlating filter over image
            [obj.last_resp, d, obj.psr] = obj.correlate(img);

            % check that response peack is strong enough (using PSR)
            if obj.psr <= obj.min_psr
                return;
            end

            % update object position
            obj.pos = obj.pos + d;

            % crop and process image from new position
            obj.last_img = cv.getRectSubPix(frame, obj.siz, obj.pos);
            img = obj.preprocess(obj.last_img);

            % online update (filter training)
            if nargin < 3, rate = 0.125; end
            obj.update_kernels(img, rate);
        end

        function [img, f, resp] = visualize_state(obj)
            %VISUALIZE_STATE  Visualize tracker state
            %
            %     [img, f, resp] = obj.visualize_state()
            %
            % ## Output
            % * __img__ cropped object image
            % * __f__ correlation filter, 0-freq centered and 8-bit normalized
            % * __resp__ correlation response, 8-bit normalized and clipped
            %

            % image
            img = obj.last_img;

            % kernel
            f = cv.dft(obj.H, 'Inverse',true, 'Scale',true, 'RealOutput',true);
            f = circshift(f, floor(-[size(f,1) size(f,2)]/2));
            if true
                f = (f - min(f(:))) / (max(f(:)) - min(f(:)));
            else
                f = cv.normalize(f, 'NormType','MinMax');
            end
            f = uint8(255 * f);

            % response
            if true
                resp = obj.last_resp / max(obj.last_resp(:));
            else
                resp = cv.normalize(obj.last_resp, 'NormType','Inf');
            end
            resp = uint8(255 * min(max(resp, 0), 1));
        end

        function vis = draw_object(obj, vis)
            %DRAW_OBJECT  Draw current location of tracked object
            %
            %     vis = obj.draw_object(vis)
            %
            % ## Input
            % * __vis__ input image
            %
            % ## Output
            % * __vis__ output image with drawn object
            %

            clr = {'Color',[0 0 255]};
            p1 = fix(obj.pos - 0.5 * obj.siz);
            p2 = fix(obj.pos + 0.5 * obj.siz);

            % draw location
            vis = cv.rectangle(vis, p1, p2, 'Thickness',2, clr{:});
            if obj.psr > obj.min_psr
                % good track, draw center
                vis = cv.circle(vis, fix(obj.pos), 2, 'Thickness',-1, clr{:});
            else
                % bad track, draw cross
                vis = cv.line(vis, [p1; p2(1) p1(2)], [p2; p1(1) p2(2)], clr{:});
            end

            % draw PSR value
            vis = cv.putText(vis, sprintf('PSR: %.2f', obj.psr), ...
                [p1(1) p2(2)+16], 'FontFace','HersheyPlain', ...
                'Thickness',2, 'LineType','AA', clr{:});
        end

        function bbox = get.bbox(obj)
            p1 = obj.pos - 0.5 * obj.siz;
            p2 = obj.pos + 0.5 * obj.siz;
            bbox = cv.Rect.from2points(p1, p2);
        end
    end

    methods (Access = private)
        function img = preprocess(obj, img)
            %PREPROCESS  Process input frame
            %
            %     img = obj.preprocess(img)
            %
            % ## Input
            % * __img__ input image
            %
            % ## Output
            % * __img__ output processed image
            %

            % log transform, normalize, and multiply by Hanning window
            img = log(single(img) + 1);
            if true
                img = img / norm(img(:));
            elseif true
                img = cv.normalize(img, 'NormType','L2');
            else
                img = (img - mean(img(:))) / std(img(:));
            end
            img = img .* obj.win;
        end

        function [resp, d, psr] = correlate(obj, img)
            %CORRELATE  Correlate filter over image and find peak in response
            %
            %     [resp, d, psr] = obj.correlate(img)
            %
            % ## Input
            % * __img__ processed image
            %
            % ## Output
            % * __resp__ correlation response
            % * __d__ offset of peak location from center `[x,y]`
            % * __psr__ PSR value, a measure of correlation peak strength. Can
            %   be used to stop the online update if PSR is too low, which is
            %   an indication the the object is occluded or tracking has
            %   failed.
            %

            % correlation (performed in frequency domain)
            resp = cv.mulSpectrums(cv.dft(img, 'ComplexOutput',true), ...
                obj.H, 'ConjB',true);
            resp = cv.dft(resp, 'Inverse',true, 'Scale',true, 'RealOutput',true);

            % max value location in correlation response
            [mval, midx] = max(resp(:));
            [my,mx] = ind2sub(size(resp), midx);
            mloc = [mx my]; %TODO: -1 ??

            % offset from center
            d = mloc - floor([size(resp,2) size(resp,1)] / 2);

            % compute PSR
            sidelobe = cv.rectangle(resp, mloc-5, mloc+5, ...
                'Color',NaN, 'Thickness',-1);
            sidelobe = sidelobe(~isnan(sidelobe));
            psr = (mval - mean(sidelobe)) / std(sidelobe);
        end

        function update_kernels(obj, img, rate)
            %UPDATE_KERNELS  Update correlation kernels
            %
            %     obj.update_kernels(img)
            %     obj.update_kernels(img, rate)
            %
            % ## Input
            % * __img__ processed image
            % * __rate__ learning rate
            %

            F = cv.dft(img, 'ComplexOutput',true);
            H_1 = cv.mulSpectrums(obj.G, F, 'ConjB',true);
            H_2 = cv.mulSpectrums(    F, F, 'ConjB',true);

            if nargin < 3
                % initialization phase
                obj.H1 = obj.H1 + H_1;
                obj.H2 = obj.H2 + H_2;
            else
                % update phase
                obj.H1 = obj.H1 * (1 - rate) + H_1 * rate;
                obj.H2 = obj.H2 * (1 - rate) + H_2 * rate;
            end

            obj.H = complex(obj.H1(:,:,1), obj.H1(:,:,2)) ./ ...
                    complex(obj.H2(:,:,1), obj.H2(:,:,2));
            obj.H = cat(3, real(obj.H), -imag(obj.H));
        end
    end
end

function img = random_warp(img, coef)
    %RANDOM_WARP  Warp image using a random affine transformation
    %
    %     img = random_warp(img)
    %     img = random_warp(img, coef)
    %
    % ## Input
    % * __img__ input image
    %
    % ## Output
    % * __img__ output warped image
    % * __coef__ randomness coefficient, default 0.2
    %

    if nargin < 2, coef = 0.2; end
    ang = (rand() - 0.5) * coef;
    T = [cos(ang) -sin(ang); sin(ang) cos(ang)];
    T = T + (rand(2) - 0.5) * coef;

    sz = [size(img,2); size(img,1)];
    c = fix(sz / 2);
    T(:,3) = c - T * c;

    img = cv.warpAffine(img, T, 'DSize',sz, 'BorderType','Reflect');
end


function [ishappy, cutoff] = standardCheck(f, values, data, pref)
%STANDARDCHECK   Attempt to trim trailing Fourier coefficients in a TRIGTECH.
%   [ISHAPPY, CUTOFF] = STANDARDCHECK(F) uses the routine STANDARDCHOP to
%   compute a positive integer CUTOFF which represents the number of
%   coefficients of F that are deemed accurate enough to keep.  ISHAPPY is TRUE
%   if the CUTOFF value returned by STANDARDCHOP is less than LENGTH(F) and
%   FALSE otherwise.
%
%   [ISHAPPY, CUTOFF] = STANDARDCHECK(F, VALUES, DATA, PREF) allows additional
%   preferences to be passed. VALUES is a matrix of the function values of F at
%   the corresponding interpolation points. DATA.VSCALE is an approximation of
%   the maximum function value of F on a possibly larger approximation
%   interval.  PREF is a data structure used to pass in additional information,
%   e.g. a target accuracy tolerance could be passed using PREF.CHEBFUNEPS.
%
% See also CLASSICCHECK, STRICTCHECK, LOOSECHECK.

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

% Grab the coefficients of F.
coeffs = abs(f.coeffs(end:-1:1,:));
[n, m] = size(coeffs);

% Compute some values if none were given.
if ( nargin < 2 || isempty(values) )
    values = f.coeffs2vals(f.coeffs);
end

% In order to work with STANDARDCHOP, the coefficients of F are modified so that
% the entries corresponding to wave numbers k and -k appear sequentially in the
% new matrix of coefficients. These entries are also replaced by the sum of the
% absolute values of the k and -k coefficients.

% Need to handle odd/even cases separately.
isEven = mod(n, 2) == 0;
if ( isEven )
    coeffs = [coeffs(n,:) ; coeffs(n-1:-1:n/2+1,:) + coeffs(1:n/2-1,:) ; coeffs(n/2,:)];
else
    coeffs = [coeffs(n:-1:(n+1)/2+1,:) + coeffs(1:(n+1)/2-1,:) ; coeffs((n+1)/2,:)];
end
coeffs = flipud(coeffs);
coeffs = [coeffs(1,:) ; kron(coeffs(2:end,:), [1 ; 1])];

% Initialize ISHAPPY.
ishappy = false;

% Initialize CUTOFF.
cutoff = n;

% NaNs are not allowed.
if ( any(isnan(coeffs)) )
    error('CHEBFUN:TRIGTECH:standardCheck:nanEval', ...
        'Function returned NaN when evaluated.')
end

% Grab some preferences.
if ( nargin == 1 )
    pref = f.techPref();
    tol = pref.chebfuneps;
elseif ( isnumeric(pref) )
    tol = pref;
else
    tol = pref.chebfuneps;
end

% Reshape TOL.
if ( size(tol, 2) ~= m )
  tol = ones(1, m)*max(tol);
end

% Scale TOL by VSCL/||F||;
nrmf = max(abs(values), [], 1);
tol = tol.*data.vscale./nrmf;

% Loop through columns of coeffs
ishappy = false(1, m);
cutoff = zeros(1, m);
for k = 1:m

    % Call STANDARDCHOP.
    cutoff(k) = standardChop(coeffs(:,k), tol(k));

    % Check for happiness.
    ishappy(k) = ( cutoff(k) < n );

    % Divide CUTOFF by 2.
    if ( mod(cutoff(k), 2) == 0 )
        cutoff(k) = cutoff(k)/2;
    else
        cutoff(k) = (cutoff(k) - 1)/2;
    end

    % Break if unhappy.
    if ( ~ishappy(k) )
        break
    end

end

% Set outputs.
ishappy = all(ishappy);

% CUTOFF is always odd.
cutoff = 2*max(cutoff) + 1;

end


function [outImg ] = crop2divisibleSize( inImg,factor)
% *************************************************************************
% Superresolution
% crop2divisibleSize
%
% Description:
% crops the image, so that it is divisible by "factor"
%
%
% Version 1.0
%
% Created by:   Armin Kappeler
% Date:         03/04/2015
%
% *************************************************************************

%check, if dividable by upscale factor
imsize_original = size(inImg);
imsize = floor(imsize_original/factor)*factor;

if (sum(imsize==imsize_original) ~= 2) %if needed, crop
    outImg = imcrop(inImg, [1 1 imsize(2)-1 imsize(1)-1]);
else
    outImg = inImg;
end

end


function [Q_mean]=imlabelMean(M,ML)

% function [Q_mean]=imlabelMean(M,ML)
% ------------------------------------------------------------------------
%
% This function takes the mean for each of the labeled groups (NaN's
% ignored) in ML according to the intensities in M.
%
%
% Kevin Mattheus Moerman
% kevinmoerman@hotmail.com
% 2014/04/01
%------------------------------------------------------------------------

defaultMethod=1; %Hard coded for now
switch defaultMethod
    case 1 %SPARSE ARRAY BASED (more efficient for large arrays)
        labelSet=unique(ML(:));
        labelSet=labelSet(~isnan(labelSet)); %Remove the nan labelled group

        numLabels=max(labelSet);

        logic_ML_not_nan=~isnan(ML);
        nnzQ=nnz(logic_ML_not_nan);
        Iq=ML(logic_ML_not_nan);
        Jq=1:nnzQ;
        Sq=M(logic_ML_not_nan);
        sizQ=[numLabels,nnzQ];
        nnzQ=nnz(logic_ML_not_nan);
        Q=sparse(Iq,Jq,Sq,sizQ(1),sizQ(2),nnzQ);

        Q_sum=full(sum(Q,2));
        Q_voxelCount=full(sum(spones(Q),2));
        Q_mean=Q_sum./Q_voxelCount;
    case 2 %REGIONPROPS BASED
        ML(isnan(ML))=0;
        A=regionprops(ML,M,'MeanIntensity');
        Q_mean=[A.MeanIntensity];
        Q_mean=Q_mean(:);
end

%%
% _*GIBBON footer text*_
%
% License: <https://github.com/gibbonCode/GIBBON/blob/master/LICENSE>
%
% GIBBON: The Geometry and Image-based Bioengineering add-On. A toolbox for
% image segmentation, image-based modeling, meshing, and finite element
% analysis.
%
% Copyright (C) 2006-2022 Kevin Mattheus Moerman and the GIBBON contributors
%
% 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.
%
% You should have received a copy of the GNU General Public License
% along with this program.  If not, see <http://www.gnu.org/licenses/>.


function [varargout]=quad4_quad8(varargin)

% function [QUAD8,V8,VX8C]=quad4_quad8(QUAD4,V4,VXC)
%
% This function converts 4 node (e.g. linear) quadrilaterial elements into
% 8 node (e.g. quadratic) quadrilateral elements compatible with FEBio.
%
% Kevin Mattheus Moerman
% gibbon.toolbox@gmail.com
%
% 2018/10/19 Created based on tri3_tri6
%----------------------------------------------------------------------
%%

switch nargin
    case 2
        QUAD4=varargin{1};
        V4=varargin{2};
        VXC={};
    case 3
        QUAD4=varargin{1};
        V4=varargin{2};
        VXC=varargin{3};
end

%%

E=[QUAD4(:,[1 2]); QUAD4(:,[2 3]); QUAD4(:,[3 4]); QUAD4(:,[4 1])]; %Edges matrix
Es=sort(E,2); %Sorted edges matrix
[~,ind1,~]=unique(Es,'rows'); %Indices for unique edges
E=E(ind1,:); %The unique esges

numPoints = size(V4,1);
numEdges = size(E,1);

% Get indices of the three edges associated with each face
A = sparse(E(:,1),E(:,2),(1:numEdges)+numPoints,numPoints,numPoints,numEdges);
A = max(A,A'); %Copy symmetric

%Indices for A matrix
indA_12=QUAD4(:,1)+(QUAD4(:,2)-1)*numPoints;
indA_23=QUAD4(:,2)+(QUAD4(:,3)-1)*numPoints;
indA_34=QUAD4(:,3)+(QUAD4(:,4)-1)*numPoints;
indA_41=QUAD4(:,4)+(QUAD4(:,1)-1)*numPoints;

%Get indices for vertex array
indV_12=full(A(indA_12));
indV_23=full(A(indA_23));
indV_34=full(A(indA_34));
indV_41=full(A(indA_41));

%Create faces array
QUAD8=[QUAD4(:,1) QUAD4(:,2) QUAD4(:,3) QUAD4(:,4) indV_12 indV_23 indV_34 indV_41];

%Create vertex array
Vn=0.5*(V4(E(:,1),:)+V4(E(:,2),:)); %new mid-edge points
V8 = [V4; Vn]; %Join point sets

%%
varargout{1}=QUAD8;
varargout{2}=V8;

if nargout==3
    %Derive VX8C
    if ~isempty(VXC)
        VX8C=VXC;
        for q=1:1:numel(VXC)
            VX=VXC{q};
            VX_1_4=VX;
            VX_5_8=0.5*(VX(E(:,1),:)+VX(E(:,2),:)); %new mid-edge data
            VX8=[VX_1_4; VX_5_8];
            VX8C{q}=VX8;
        end
    else
        VX8C={};
    end
    varargout{3}=VX8C;
end

%%
% _*GIBBON footer text*_
%
% License: <https://github.com/gibbonCode/GIBBON/blob/master/LICENSE>
%
% GIBBON: The Geometry and Image-based Bioengineering add-On. A toolbox for
% image segmentation, image-based modeling, meshing, and finite element
% analysis.
%
% Copyright (C) 2006-2022 Kevin Mattheus Moerman and the GIBBON contributors
%
% 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.
%
% You should have received a copy of the GNU General Public License
% along with this program.  If not, see <http://www.gnu.org/licenses/>.


function ye = ubd(t, j, k, side)
%UBD	Prescribes u at inflow boundaries
% Possible values for side: 'lower', 'upper',  'left', 'right'

global geval u0 J K yu yv yseglen alpha

ye = 0;
if geval == 1		% Horizontal Poiseuille flow to the right
  if strcmp(side, 'left') == 1
    ye = u0(k*(J+1));	% Inflow profile = outflow profile
  else
    ye = 0;
  end
elseif geval == 2	% Vertical Poiseuille flow
    ye = 0;
elseif geval == 3	% Backward facing step
  if strcmp(side, 'left') == 1
    ye = 6*(yu(k) - yseglen(end)).*(yv(end) - yu(k))/(yv(end) - yseglen(end))^3;
  elseif strcmp(side, 'right') == 1
    ye = 6*(yu(k) - yv(1)).*(yv(end) - yu(k))/(yv(end) - yv(1))^3;
  else
    ye = 0;
  end
elseif geval == 4	% Driven cavity
  if strcmp(side, 'upper') == 1
    ye = 1;
  else
    ye = 0;
  end
elseif geval == 5|geval == 6	% Uniform flow under angle alpha
  ye = cos(alpha);
elseif geval == 7		% Horizontal Poiseuille flow to the left
  if strcmp(side, 'right') == 1
    ye = u0(k*(J+1));	% Inflow profile = outflow profile
  else
    ye = 0;
  end
else
  error('Wrong value in input for parameter geval')
end


function [struct_irf_record,D_draws,gamma_draws,ETA_record,It,Bu,beta_draws,sigma_draws]=...
    IRFt5_Bayesian(names,betahat,m,n,X,Y,k,p,enddate,startdate,IRFperiods,IRFt,T,arvar,q,It,Bu,lambda1,lambda3,lambda4,pref,strctident)
%%Implementation of a Bayesian Proxy VAR based on the Codes published by Caldara and Herbst (2018)
%%Implementation by Ben Schumann
%% IV identification
%Load IV and make it comparable with the reduced form errors
[EPSIV,IVcut,~,sigmahatIV,sigma_hat,inv_sigma_hat,IV,txt,~,cut1,cut2,cut3,cut4]...
    =bear.loadIV(betahat,k,n,Y,X,T,p,names,startdate,enddate,strctident,pref);

% IV routine
[beta_draws,sigma_draws,~,~,D_draws,gamma_draws,irf_storage,ETA_storage,It,Bu]=...
    bear.irfIV_MH(EPSIV,IVcut,betahat,sigmahatIV,sigma_hat,inv_sigma_hat,IV,txt,cut1,cut2,cut3,cut4,names,It,Bu,n,arvar,lambda1,lambda3,lambda4,m,p,k,q,X,Y,T,startdate,enddate,pref,strctident,IRFperiods,IRFt);

% reorganise
Acc=It-Bu;
% loop over iterations
for ii=1:Acc/strctident.Thin
    for jj=1:IRFperiods
        % loop over variables
        for kk=1:n
            % loop over shocks (only one)
            for ll=1
                %for ll=1:n
                struct_irf_record{kk,ll}(ii,jj)=irf_storage{ii,1}(kk,ll,jj);
            end
        end
    end
end

% loop over variables
for kk=1:n
    % loop over shocks (only one)
    for ll=2:n
        %for ll=1:n
        struct_irf_record{kk,ll}=zeros(Acc/strctident.Thin,IRFperiods);
    end
end

%reorganize Structural Shocks
ETA_record=cell(n,1);
for jj=1:Acc/strctident.Thin
    for kk=1:n
        ETA_record{kk,1}(jj,:)= ETA_storage{jj,1}(kk,:);
    end
end

%finally update It and Bu such that BEAR knows how many draws we kept
It = It/strctident.Thin;
Bu = Bu/strctident.Thin;


%
% output = bilateralFilter( data, edge, ...
%                          edgeMin, edgeMax, ...
%                          sigmaSpatial, sigmaRange, ...
%                          samplingSpatial, samplingRange )
%
% Bilateral and Cross-Bilateral Filter using the Bilateral Grid.
%
% Bilaterally filters the image 'data' using the edges in the image 'edge'.
% If 'data' == 'edge', then it the standard bilateral filter.
% Otherwise, it is the 'cross' or 'joint' bilateral filter.
% For convenience, you can also pass in [] for 'edge' for the normal
% bilateral filter.
%
% Note that for the cross bilateral filter, data does not need to be
% defined everywhere.  Undefined values can be set to 'NaN'.  However, edge
% *does* need to be defined everywhere.
%
% data and edge should be of the greyscale, double-precision floating point
% matrices of the same size (i.e. they should be [ height x width ])
%
% data is the only required argument
%
% edgeMin and edgeMax specifies the min and max values of 'edge' (or 'data'
% for the normal bilateral filter) and is useful when the input is in a
% range that's not between 0 and 1.  For instance, if you are filtering the
% L channel of an image that ranges between 0 and 100, set edgeMin to 0 and
% edgeMax to 100.
%
% edgeMin defaults to min( edge( : ) ) and edgeMax defaults to max( edge( : ) ).
% This is probably *not* what you want, since the input may not span the
% entire range.
%
% sigmaSpatial and sigmaRange specifies the standard deviation of the space
% and range gaussians, respectively.
% sigmaSpatial defaults to min( width, height ) / 16
% sigmaRange defaults to ( edgeMax - edgeMin ) / 10.
%
% samplingSpatial and samplingRange specifies the amount of downsampling
% used for the approximation.  Higher values use less memory but are also
% less accurate.  The default and recommended values are:
%
% samplingSpatial = sigmaSpatial
% samplingRange = sigmaRange
%
%

% Copyright (c) <2007> <Jiawen Chen, Sylvain Paris, and Fredo Durand>
%
% Permission is hereby granted, free of charge, to any person obtaining a copy
% of this software and associated documentation files (the "Software"), to deal
% in the Software without restriction, including without limitation the rights
% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
% copies of the Software, and to permit persons to whom the Software is
% furnished to do so, subject to the following conditions:
%
% The above copyright notice and this permission notice shall be included in
% all copies or substantial portions of the Software.
%
% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
% THE SOFTWARE.
%

function output = bilateralFilter( data, edge, edgeMin, edgeMax, sigmaSpatial, sigmaRange, samplingSpatial, samplingRange )

if( ndims( data ) > 2 ),
    error( 'data must be a greyscale image with size [ height, width ]' );
end

if( ~isa( data, 'double' ) ),
    error( 'data must be of class "double"' );
end

if ~exist( 'edge', 'var' ),
    edge = data;
elseif isempty( edge ),
    edge = data;
end

if( ndims( edge ) > 2 ),
    error( 'edge must be a greyscale image with size [ height, width ]' );
end

if( ~isa( edge, 'double' ) ),
    error( 'edge must be of class "double"' );
end

inputHeight = size( data, 1 );
inputWidth = size( data, 2 );

if ~exist( 'edgeMin', 'var' ),
    edgeMin = min( edge( : ) );
    %warning( 'edgeMin not set!  Defaulting to: %f\n', edgeMin );
end

if ~exist( 'edgeMax', 'var' ),
    edgeMax = max( edge( : ) );
    %warning( 'edgeMax not set!  Defaulting to: %f\n', edgeMax );
end

edgeDelta = edgeMax - edgeMin;

if ~exist( 'sigmaSpatial', 'var' ),
    %sigmaSpatial = min( inputWidth, inputHeight ) / 16;
    sigmaSpatial = min( inputWidth, inputHeight ) / 64;
    fprintf( 'Using default sigmaSpatial of: %f\n', sigmaSpatial );
end

if ~exist( 'sigmaRange', 'var' ),
    %sigmaRange = 0.1 * edgeDelta;
    sigmaRange = 0.025 * edgeDelta;
    fprintf( 'Using default sigmaRange of: %f\n', sigmaRange );
end

if ~exist( 'samplingSpatial', 'var' ),
    samplingSpatial = sigmaSpatial;
end

if ~exist( 'samplingRange', 'var' ),
    samplingRange = sigmaRange;
end

if size( data ) ~= size( edge ),
    error( 'data and edge must be of the same size' );
end

% parameters
derivedSigmaSpatial = sigmaSpatial / samplingSpatial;
derivedSigmaRange = sigmaRange / samplingRange;

paddingXY = floor( 2 * derivedSigmaSpatial ) + 1;
paddingZ = floor( 2 * derivedSigmaRange ) + 1;

% allocate 3D grid
downsampledWidth = floor( ( inputWidth - 1 ) / samplingSpatial ) + 1 + 2 * paddingXY;
downsampledHeight = floor( ( inputHeight - 1 ) / samplingSpatial ) + 1 + 2 * paddingXY;
downsampledDepth = floor( edgeDelta / samplingRange ) + 1 + 2 * paddingZ;

gridData = zeros( downsampledHeight, downsampledWidth, downsampledDepth );
gridWeights = zeros( downsampledHeight, downsampledWidth, downsampledDepth );

% compute downsampled indices
[ jj, ii ] = meshgrid( 0 : inputWidth - 1, 0 : inputHeight - 1 );

% ii =
% 0 0 0 0 0
% 1 1 1 1 1
% 2 2 2 2 2

% jj =
% 0 1 2 3 4
% 0 1 2 3 4
% 0 1 2 3 4

% so when iterating over ii( k ), jj( k )
% get: ( 0, 0 ), ( 1, 0 ), ( 2, 0 ), ... (down columns first)

di = round( ii / samplingSpatial ) + paddingXY + 1;
dj = round( jj / samplingSpatial ) + paddingXY + 1;
dz = round( ( edge - edgeMin ) / samplingRange ) + paddingZ + 1;

% perform scatter (there's probably a faster way than this)
% normally would do downsampledWeights( di, dj, dk ) = 1, but we have to
% perform a summation to do box downsampling
for k = 1 : numel( dz ),

    dataZ = data( k ); % traverses the image column wise, same as di( k )
    if ~isnan( dataZ  ),

        dik = di( k );
        djk = dj( k );
        dzk = dz( k );

        gridData( dik, djk, dzk ) = gridData( dik, djk, dzk ) + dataZ;
        gridWeights( dik, djk, dzk ) = gridWeights( dik, djk, dzk ) + 1;

    end
end

% make gaussian kernel
kernelWidth = 2 * derivedSigmaSpatial + 1;
kernelHeight = kernelWidth;
kernelDepth = 2 * derivedSigmaRange + 1;

halfKernelWidth = floor( kernelWidth / 2 );
halfKernelHeight = floor( kernelHeight / 2 );
halfKernelDepth = floor( kernelDepth / 2 );

[gridX, gridY, gridZ] = meshgrid( 0 : kernelWidth - 1, 0 : kernelHeight - 1, 0 : kernelDepth - 1 );
gridX = gridX - halfKernelWidth;
gridY = gridY - halfKernelHeight;
gridZ = gridZ - halfKernelDepth;
gridRSquared = ( gridX .* gridX + gridY .* gridY ) / ( derivedSigmaSpatial * derivedSigmaSpatial ) + ( gridZ .* gridZ ) / ( derivedSigmaRange * derivedSigmaRange );
kernel = exp( -0.5 * gridRSquared );

% convolve
blurredGridData = convn( gridData, kernel, 'same' );
blurredGridWeights = convn( gridWeights, kernel, 'same' );

% divide
blurredGridWeights( blurredGridWeights == 0 ) = -2; % avoid divide by 0, won't read there anyway
normalizedBlurredGrid = blurredGridData ./ blurredGridWeights;
normalizedBlurredGrid( blurredGridWeights < -1 ) = 0; % put 0s where it's undefined

% for debugging
% blurredGridWeights( blurredGridWeights < -1 ) = 0; % put zeros back

% upsample
[ jj, ii ] = meshgrid( 0 : inputWidth - 1, 0 : inputHeight - 1 ); % meshgrid does x, then y, so output arguments need to be reversed
% no rounding
di = ( ii / samplingSpatial ) + paddingXY + 1;
dj = ( jj / samplingSpatial ) + paddingXY + 1;
dz = ( edge - edgeMin ) / samplingRange + paddingZ + 1;

% interpn takes rows, then cols, etc
% i.e. size(v,1), then size(v,2), ...
output = interpn( normalizedBlurredGrid, di, dj, dz );


function ind = gaussian_mutate( ind, prob, domain)
%GAUSSIAN_MUTATE Summary of this function goes here
%   Detailed explanation goes here

if isstruct(ind)
    x = ind.parameter;
else
    x  = ind;
end

   parDim = length(x);
   lowend  = domain(:,1);
   highend =domain(:,2);
   sigma = (highend-lowend)./20;

   newparam = min(max(normrnd(x, sigma), lowend), highend);
   C = rand(parDim, 1)<prob;
   x(C) = newparam(C);

if isstruct(ind)
    ind.parameter = x;
else
    ind = x;
end


classdef (TestTags = {'Unit', 'SPGR', 'qMT'}) BlochSol_Test < matlab.unittest.TestCase
%% BLOCHSOL_TEST Test class for BlochSol.m
%
%   --tests--
%   test_no_pulse_mag_remains_unchanged
%       - Assert that a magnetization vector with only longitudinal values
%         remains constant for a constant pulse of 0 degree FA.
%
%   test_no_longi_mag_evol_for_transverse_initial_mag_inf_t2_t1
%       - Assert that a magnetization vector with only transverse values
%         does not accrue longitudinal magnetization for the case of
%         infinite T1 and T2 (0 deg FA).
%
%   test_magn_evols_to_equilibrium_vals
%       - Assert that an empty magnetization vector evolves to the
%         equilibrium longitudinal values (M0f and M0r) after a time
%         much greater than T1f (10x) and 0 deg FA.
%
%   test_mag_goes_to_zero_for_time_much_greater_than_t2f
%       - Assert that a magnetization vector with only transverse values
%         decays to 0 after a time much greater than T2f (x10)
%
%   test_steady_state_smaller_for_small_delta_than_big
%       - Assert that steady-state longitudinal (free) magnization is
%         smaller for the case of a small offset frequency than large
%         offset freq.
%
%   test_steady_state_larger_for_small_FA_than_big
%       - Assert that steady-state longitudinal (free) magnization is
%         larger for the case of a small flip angle (per millisec) than
%         large flip angle.
%

    properties
        Param = struct('M0f', 1,           ...
                       'M0r', 0.15,        ...
                       'R1f', 1.1,         ...
                       'R1r', 1,           ...
                       'R2f', 1/0.03,      ...
                       'R2r', 1/(12*10^-6),...
                       'kf',  4.0,         ...
                       'kr',  4.0/0.15);
    end

    methods (TestClassSetup)
    end

    methods (TestClassTeardown)
    end

    methods (Test)
        function test_no_pulse_mag_remains_unchanged(testCase)
            %% Prep
            %
            delta = 200; % On-resonance
            testCase.Param.G = computeG(delta,1/testCase.Param.R2f, 'SuperLorentzian');

            pulseDur = 10; % seconds
            pulseShape = 'hard';

            flipAngle = 0; % No pulse
            Pulse = GetPulse(flipAngle, delta, pulseDur, pulseShape);

            M0 = [0 0 1 0.15]'; % Initial magnetization, Xf Yf Zf Zr

            timeRange = linspace(0,10,1000); % in seconds

            for ii =1:length(timeRange)
               M(ii, :) = BlochSol(timeRange(ii), M0, testCase.Param, Pulse);
            end

            %                    Actual ,  Expected
            testCase.assertEqual(M(end,:), M0', 'AbsTol', 0.001);
        end

        function test_no_longi_mag_evol_for_transverse_initial_mag_inf_t2_t1(testCase)
            %% Prep
            %
            Param = testCase.Param;

            delta = 100; % Go to the rotating ref frame for this case
            Param.G = computeG(delta,1/Param.R2f, 'SuperLorentzian');

            pulseDur = 0.001; % seconds, near-instantaneous
            pulseShape = 'hard';

            flipAngle = 0;
            Pulse = GetPulse(flipAngle, delta, pulseDur, pulseShape);

            %***
            Param.R2f = 0.0001; % Assume very large T2f
            Param.R2r = 0.0001; % Assume very large T2r
            Param.R1f = 0.0001; % Assume very large T1f
            Param.R1r = 0.0001; % Assume very large T1r
            %***

            M0 = [1 0 0 0]'; % Initial magnetization, Xf Yf Zf Zr

            timeRange = linspace(0, 1, 1000); % in seconds

            for ii =1:length(timeRange)
               M(ii, :) = BlochSol(timeRange(ii), M0, Param, Pulse);
            end

            %                    Actual                     , Expected
            testCase.assertEqual([M(end,3) M(end,4)], [M0(3) M0(4)], 'AbsTol', 0.001);
        end

        function test_magn_evols_to_equilibrium_vals(testCase)
            %% Prep
            %
            Param = testCase.Param;

            delta = 100; % Go to the rotating ref frame for this case
            Param.G = computeG(delta,1/Param.R2f, 'SuperLorentzian');

            pulseDur = 0.001; % seconds, near-instantaneous
            pulseShape = 'hard';

            flipAngle = 0;
            Pulse = GetPulse(flipAngle, delta, pulseDur, pulseShape);

            M0 = [0 0 0 0]'; % Initial magnetization, Xf Yf Zf Zr

            timeRange = linspace(0, (1/Param.R1f*10), 1000); % in seconds, 10x T1f

            for ii =1:length(timeRange)
               M(ii, :) = BlochSol(timeRange(ii), M0, Param, Pulse);
            end

            %                    Actual ,  Expected
            testCase.assertEqual(M(end,:), [0 0 Param.M0f Param.M0r], 'AbsTol', 0.001);
        end

        function test_mag_goes_to_zero_for_time_much_greater_than_t2f(testCase)
            %% Prep
            %
            Param = testCase.Param;

            delta = 100; % Go to the rotating ref frame for this case
            Param.G = computeG(delta,1/Param.R2f, 'SuperLorentzian');

            pulseDur = 0.001; % seconds, near-instantaneous
            pulseShape = 'hard';

            flipAngle = 0;
            Pulse = GetPulse(flipAngle, delta, pulseDur, pulseShape);

            M0 = [1 0 0 0]'; % Initial magnetization, Xf Yf Zf Zr

            timeRange = linspace(0, (1/Param.R2f)*10, 1000); % in seconds, 10x T2f

            for ii =1:length(timeRange)
               M(ii, :) = BlochSol(timeRange(ii), M0, Param, Pulse);
            end

            %                    Actual ,  Expected
            testCase.assertEqual(M(end,1:2), [0 0], 'AbsTol', 0.001);
        end

        function test_steady_state_smaller_for_small_delta_than_big(testCase)
            %% Prep
            %
            Param1 = testCase.Param;
            Param2 = testCase.Param;

            delta1 = 100;
            delta2 = 10*delta1;

            Param1.G = computeG(delta1,1/Param1.R2f, 'SuperLorentzian');
            Param2.G = computeG(delta2,1/Param2.R2f, 'SuperLorentzian');

            pulseDur = 10; % seconds
            pulseShape = 'hard';

            flipAngle = 40; % FA per millisec
            Pulse1 = GetPulse((flipAngle*1000)*pulseDur, delta1, pulseDur, pulseShape);
            Pulse2 = GetPulse((flipAngle*1000)*pulseDur, delta2, pulseDur, pulseShape);

            M0 = [0 0 testCase.Param.M0f testCase.Param.M0r]'; % Initial magnetization, Xf Yf Zf Zr

            timeRange = linspace(0, pulseDur, 1000); % in seconds, 10x T2f

            for ii =1:length(timeRange)
               M1(ii, :) = BlochSol(timeRange(ii), M0, Param1, Pulse1);
               M2(ii, :) = BlochSol(timeRange(ii), M0, Param2, Pulse2);
            end

            %                          Small delta, Big delta
            testCase.assertLessThan(M1(end,3)  , M2(end,3));
        end

        function test_steady_state_larger_for_small_FA_than_big(testCase)
            %% Prep
            %
            Param = testCase.Param;

            delta = 1000;

            Param.G = computeG(delta,1/Param.R2f, 'SuperLorentzian');

            pulseDur = 10; % seconds
            pulseShape = 'hard';

            flipAngle1 = 40; % FA per millisec
            flipAngle2 = 2*flipAngle1 ; % FA per millisec

            Pulse1 = GetPulse((flipAngle1*1000)*pulseDur, delta, pulseDur, pulseShape);
            Pulse2 = GetPulse((flipAngle2*1000)*pulseDur, delta, pulseDur, pulseShape);

            M0 = [0 0 testCase.Param.M0f testCase.Param.M0r]'; % Initial magnetization, Xf Yf Zf Zr

            timeRange = linspace(0, pulseDur, 1000); % in seconds, 10x T2f

            for ii =1:length(timeRange)
               M1(ii, :) = BlochSol(timeRange(ii), M0, Param, Pulse1);
               M2(ii, :) = BlochSol(timeRange(ii), M0, Param, Pulse2);
            end

            %                          Small FA , Big FA
            testCase.assertGreaterThan(M1(end,3), M2(end,3));
        end
    end

end


function Y = Wavedb1Phi(X,trans)
persistent s;

level = 2;

if ~trans;
    % Phi' * X
    [Y,s] = wavedec2(X,level,'db1');
else
    Y = waverec2(X(:),s,'db1');
end


function [beta,f,y] = trainGM2()

[f,y] = sampleDetector(@detector1,1000000,8);
fprintf(2,'Fitting model...\n');
save 'samples_gm_1_2.mat' f y;
beta = logist2(y',f');
save 'beta_gm_1_2.txt' beta -ascii;

[f,y] = sampleDetector(@detector2,1000000,8);
fprintf(2,'Fitting model...\n');
save 'samples_gm_2_4.mat' f y;
beta = logist2(y',f');
save 'beta_gm_2_4.txt' beta -ascii;

[f,y] = sampleDetector(@detector3,1000000,16);
fprintf(2,'Fitting model...\n');
save 'samples_gm_4_8.mat' f y;
beta = logist2(y',f');
save 'beta_gm_4_8.txt' beta -ascii;

function [f] = detector1(im)
f = detector(im,1);

function [f] = detector2(im)
f = detector(im,2);

function [f] = detector3(im)
f = detector(im,4);

function [f] = detector(im,sigma)
[a] = detGM(im,sigma);
[b] = detGM(im,sigma*2);
a = a(:);
b = b(:);
f = [ ones(size(a)) a b ]';


function knapsack_01_test ( )

%*****************************************************************************80
%
%% KNAPSACK_01_TEST tests the KNAPSACK_01 library.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    20 August 2014
%
%  Author:
%
%    John Burkardt
%
  timestamp ( );
  fprintf ( 1, '\n' );
  fprintf ( 1, 'KNAPSACK_01_TEST\n' );
  fprintf ( 1, '  MATLAB version.\n' );
  fprintf ( 1, '  Test the KNAPSACK_01 library.\n' );

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

  return
end


function       blk_arr = Block_Matching( X, par)
% record the indexs of patches similar to the seed patch
blk_arr   =  zeros(par.nlsp, par.lenrc, 'single');
for  i  =  1 : par.lenrc
    seed = X(:, par.SelfIndex(i));
    neighbor = X(:, par.NeighborIndex(1:par.NumIndex(i), i));
    dis = sum(bsxfun(@minus, neighbor, seed).^2, 1);
    [~,ind]   =  sort(dis);
    indc        =  par.NeighborIndex( ind( 1:par.nlsp ), i );
%     indc(indc == par.SelfIndex(i)) = indc(1); % added on 08/01/2017
%     indc(1) = par.SelfIndex(i); % to make sure the first one of indc equals to off
    blk_arr(:, i) = indc;
end


%compute dtailheadang
function [data,units]=compute_dtailheadang(trx,n)
larvae=trx.exp2flies{n};
numlarvae=numel(larvae);
dtailheadang=cell(1,numlarvae);
for i=1:numlarvae
    larva=larvae(i);
    % KB: this angle distance didn't make sense to me, changed to one that
    % made sense to me
    dtailheadang{1,i}=modrange(diff(trx(larva).tailheadang),-pi,pi)./trx(larva).dt;
    % dtailheadang{1,i}=(mod1(trx(larva).tailheadang(2:end)-trx(larva).tailheadang(1:end-1),pi)-pi)./trx(larva).dt;
end

units=parseunits('rad/s');
data=dtailheadang;


function i4vec_sort_heap_a_test ( )

%*****************************************************************************80
%
%% I4VEC_SORT_HEAP_A_TEST tests I4VEC_SORT_HEAP_A.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 February 2003
%
%  Author:
%
%    John Burkardt
%
  n = 20;
  b = 0;
  c = 3 * n;

  fprintf ( 1, '\n' );
  fprintf ( 1, 'I4VEC_SORT_HEAP_A_TEST\n' );
  fprintf ( 1, '  For a vector of integers,\n' );
  fprintf ( 1, '  I4VEC_SORT_HEAP_A ascending sorts,\n' );

  seed = 123456789;

  [ a, seed ] = i4vec_uniform_ab ( n, b, c, seed );

  i4vec_print ( n, a, '  Unsorted:' );

  a = i4vec_sort_heap_a ( n, a );

  i4vec_print ( n, a, '  Ascending sorted:' );

  return
end


function [accuracy,predictlabel] = SRKDApredict(fea, gnd, model)
% SRKDApredict: Spectral Regression Kernel Discriminant Analysis Prediction
%               SRKDApredict use SRKDA as a classifier. It used the nearest
%               center rule in the SRKDA subspace for classification.
%
%       [predictlabel,accuracy,elapse] = SRKDApredict(fea, gnd, model);
%
%             Input:
%
%               fea     - data matrix. Each row is a data point.
%               gnd     - Label vector of fea.
%             model     - model trained by SRKDAtrain.m
%
%             Output:
%
%            accuracy   - classification accuracy
%         predictlabel  - predict label for fea
%
%    Examples:
%
%
% See also SRKDAtrain, KSR, KSR_caller
%
%Reference:
%
%   [1] Deng Cai, Xiaofei He, and Jiawei Han. "Speed Up Kernel Discriminant
%   Analysis", The VLDB Journal, vol. 20, no. 1, pp. 21-33, January, 2011.
%
%   [2] Deng Cai, Xiaofei He and Jiawei Han, "SRDA: An Efficient Algorithm for
%   Large Scale Discriminant Analysis" IEEE Transactions on Knowledge and
%   Data Engineering, vol. 20, no. 1, pp. 1-12, January, 2008.
%
%   [3] Deng Cai, "Spectral Regression: A Regression Framework for
%   Efficient Regularized Subspace Learning", PhD Thesis, Department of
%   Computer Science, UIUC, 2009.
%
%   version 3.0 --Jan/2012
%   version 2.0 --December/2011
%   version 1.0 --May/2006
%
%   Written by Deng Cai (dengcai AT gmail.com)
%

MAX_MATRIX_SIZE = 8000; % You can change this number based on your memory.

if ~strcmp(model.TYPE,'SRKDA')
    error('model does not match!');
end

nTrain = size(model.fea,1);
nTest = size(fea,1);
nBlock = ceil(MAX_MATRIX_SIZE*MAX_MATRIX_SIZE/nTrain);
if model.LARs
    accuracy = zeros(length(model.LassoCardi),1);
    predictlabel = zeros(nTest,length(model.LassoCardi));
    Embed_Test = cell(length(model.LassoCardi),1);
    for i=1:length(model.LassoCardi)
        Embed_Test{i} = zeros(nTest,size(model.projection{i},2));
    end
    for j = 1:ceil(nTest/nBlock)
        if j == ceil(nTest/nBlock)
            smpIdx = (j-1)*nBlock+1:nTest;
        else
            smpIdx = (j-1)*nBlock+1:j*nBlock;
        end
        KTest= constructKernel(fea(smpIdx,:),model.fea,model.options);
        if model.bSemi
            KTest = KTest*model.KtestHat;
        end
        for i=1:length(model.LassoCardi)
            if model.bSemi
                Embed_Test{i}(smpIdx,:) = KTest(:,1:model.nLabel)*model.projection{i};
            else
                Embed_Test{i}(smpIdx,:) = KTest*model.projection{i};
            end
        end
        clear KTest;
    end

    for i=1:length(model.LassoCardi)
        D = EuDist2(Embed_Test{i},model.ClassCenter{i},0);
        [dump, idx] = min(D,[],2);
        predictlabel(:,i) = model.ClassLabel(idx);
        accuracy(i) = 1 - length(find(predictlabel(:,i)-gnd))/nTest;
    end
else
    Embed_Test = zeros(nTest,size(model.projection,2));
    for i = 1:ceil(nTest/nBlock)
        if i == ceil(nTest/nBlock)
            smpIdx = (i-1)*nBlock+1:nTest;
        else
            smpIdx = (i-1)*nBlock+1:i*nBlock;
        end
        KTest= constructKernel(fea(smpIdx,:),model.fea,model.options);
        if model.bSemi
            KTest = KTest*model.KtestHat;
            Embed_Test(smpIdx,:) = KTest(:,1:model.nLabel)*model.projection;
        else
            Embed_Test(smpIdx,:) = KTest*model.projection;
        end
        clear KTest;
    end
    D = EuDist2(Embed_Test,model.ClassCenter,0);
    [dump, idx] = min(D,[],2);
    predictlabel = model.ClassLabel(idx);
    accuracy = 1 - length(find(predictlabel-gnd))/nTest;
end


function obj = addTimeVariable(obj, bounds)
    % Adds time as the NLP decision variables to the problem
    %
    % Parameters:
    %  bounds: a structed data stores the boundary information of the
    %  NLP variables @type struct

    t_var = struct();
    t_var.Name = 'T';
    t_var.Dimension = 2;
    t_var.lb = zeros(2,1);
    t_var.ub = ones(2,1);
    t_var.x0 = [0;1];
    if isfield(bounds, 't0')
        if isfield(bounds.t0,'lb')
            t_var.lb(1) = bounds.t0.lb;
        end
        if isfield(bounds.t0,'ub')
            t_var.ub(1) = bounds.t0.ub;
        end
        if isfield(bounds.t0,'x0')
            t_var.x0(1) = bounds.t0.x0;
        end
    end

    if isfield(bounds, 'tf')
        if isfield(bounds.tf,'lb')
            t_var.lb(2) = bounds.tf.lb;
        end
        if isfield(bounds.tf,'ub')
            t_var.ub(2) = bounds.tf.ub;
        end
        if isfield(bounds.tf,'x0')
            t_var.x0(2) = bounds.tf.x0;
        end
    end

    % determines the nodes at which the variables to be defined.
    if obj.Options.DistributeTimeVariable
        % time variables are defined at all nodes if distributes the weightes
        obj = addVariable(obj, 'T', 'all', t_var);

        % add an equality constraint between the time variable at
        % neighboring nodes to make sure they are same
        Ti  = SymVariable('ti',[2,1]);
        Tn  = SymVariable('tn',[2,1]);
        t_cont = SymFunction('tCont',Ti-Tn,{Ti,Tn});

        % create an array of constraints structure
        t_cstr(obj.NumNode-1) = struct();
        [t_cstr.Name] = deal(t_cont.Name);
        [t_cstr.Dimension] = deal(2);
        [t_cstr.lb] = deal(0);
        [t_cstr.ub] = deal(0);
        [t_cstr.Type] = deal('Linear');
        [t_cstr.SymFun] = deal(t_cont);
        for i=1:obj.NumNode-1
            t_cstr(i).DepVariables = [obj.OptVarTable.T(i);obj.OptVarTable.T(i+1)];
        end

        % add to the NLP constraints table
        obj = addConstraint(obj,'tCont','except-last',t_cstr);
    else
        % otherwise only define at the first node
        obj = addVariable(obj, 'T', 'first', t_var);
    end

    if isfield(bounds,'duration')
        % only impose at the first node
        T  = SymVariable('t',[2,1]);
        timeDuration = SymFunction('timeDuration',flatten(T(2)-T(1)),{T});

        if isfield(bounds.duration','lb')
            lb = bounds.duration.lb;
        else
            lb = 0;
        end
        if isfield(bounds.duration','ub')
            ub = bounds.duration.ub;
        else
            ub = inf;
        end

        addNodeConstraint(obj, timeDuration, 'T', 'first', lb, ub, 'Linear');

    end

end


function van_der_corput_test02 ( )

%*****************************************************************************80
%
%% VAN_DER_CORPUT_TEST02 tests VAN_DER_CORPUT_SEQUENCE.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    03 February 2011
%
%  Author:
%
%    John Burkardt
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'VAN_DER_CORPUT_TEST02\n' );
  fprintf ( 1, '  VAN_DER_CORPUT_SEQUENCE returns N elements\n' );
  fprintf ( 1, '  of a van der Corput sequence in the current base.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  I   R\n' );
  fprintf ( 1, '\n' );

  seed = 0;
  van_der_corput_seed_set ( seed );

  base = 2;
  van_der_corput_base_set ( base );

  n = 10;
  r = van_der_corput_sequence ( n );

  for i = 1: 10
    fprintf ( 1, '%d %f\n', seed+i-1, r(i) );
  end

  return
end


function [model, B, elapse] = USPLH_learn(A, maxbits)
%   This is a wrapper function of USPLH learning.
%
%	Usage:
%	[model, B,elapse] = USPLH_learn(A, maxbits)
%
%	      A: Rows of vectors of data points. Each row is sample point
%   maxbits: Code length
%
%     model: Used for encoding a test sample point.
%	      B: The binary code of the input data A. Each row is sample point
%    elapse: The coding time (training time).
%
%
%
%   version 2.0 --Nov/2016
%   version 1.0 --Jan/2013
%
%   Written by  Yue Lin (linyue29@gmail.com)
%               Deng Cai (dengcai AT gmail DOT com)
%

tmpT = tic;

model = trainUSPLH(A, struct('nbits',maxbits,'eta',0.125));
B = USPLH_compress(A, model);

elapse = toc(tmpT);

end


classdef Scale < dagnn.ElementWise
  properties
    size
    hasBias = true
  end

  methods

    function outputs = forward(obj, inputs, params)
      args = horzcat(inputs, params) ;
      outputs{1} = bsxfun(@times, args{1}, args{2}) ;
      if obj.hasBias
        outputs{1} = bsxfun(@plus, outputs{1}, args{3}) ;
      end
    end

    function [derInputs, derParams] = backward(obj, inputs, params, derOutputs)
      args = horzcat(inputs, params) ;
      sz = [size(args{2}) 1 1 1 1] ;
      sz = sz(1:4) ;
      dargs{1} = bsxfun(@times, derOutputs{1}, args{2}) ;
      dargs{2} = derOutputs{1} .* args{1} ;
      for k = find(sz == 1)
        dargs{2} = sum(dargs{2}, k) ;
      end
      if obj.hasBias
        dargs{3} = derOutputs{1} ;
        for k = find(sz == 1)
          dargs{3} = sum(dargs{3}, k) ;
        end
      end
      derInputs = dargs(1:numel(inputs)) ;
      derParams = dargs(numel(inputs)+(1:numel(params))) ;
    end

    function params = initParams(obj,sc)
      params{1} = ones(obj.size,'single') * sc ;
      if obj.hasBias
        params{2} = zeros(obj.size,'single') ;
      end
    end

    function obj = Scale(varargin)
      obj.load(varargin) ;
    end
  end
end


classdef LIRCMOP5 < PROBLEM
% <multi> <real> <large/none> <constrained>
% Constrained benchmark MOP with large infeasible regions

%------------------------------- Reference --------------------------------
% Z. Fan, W. Li, X. Cai, H. Huang, Y. Fang, Y. You, J. Mo, C. Wei, and E.
% Goodman, An improved epsilon constraint-handling method in MOEA/D for
% CMOPs with large infeasible regions, Soft Computing, 2019, 23:
% 12491-12510.
%------------------------------- Copyright --------------------------------
% Copyright (c) 2023 BIMK Group. You are free to use the PlatEMO for
% research purposes. All publications which use this platform or any code
% in the platform should acknowledge the use of "PlatEMO" and reference "Ye
% Tian, Ran Cheng, Xingyi Zhang, and Yaochu Jin, PlatEMO: A MATLAB platform
% for evolutionary multi-objective optimization [educational forum], IEEE
% Computational Intelligence Magazine, 2017, 12(4): 73-87".
%--------------------------------------------------------------------------

% This function is written by Wenji Li

    methods
        %% Default settings of the problem
        function Setting(obj)
            obj.M = 2;
            if isempty(obj.D); obj.D = 30; end
            obj.lower    = zeros(1,obj.D);
            obj.upper    = ones(1,obj.D);
            obj.encoding = ones(1,obj.D);
        end
        %% Calculate objective values and constraint violations
        function Population = Evaluation(obj,varargin)
            X = varargin{1};
            X = max(min(X,repmat(obj.upper,size(X,1),1)),repmat(obj.lower,size(X,1),1));
            [popsize,variable_length] = size(X);
            sum1 = zeros(popsize,1);
            sum2 = zeros(popsize,1);
            for j = 2 : variable_length
                if mod(j,2) == 1
                    sum1 = sum1+(X(:,j)-sin((0.5*j/variable_length*pi)*X(:,1))).^2;
                else
                    sum2 = sum2+(X(:,j)-cos((0.5*j/variable_length*pi)*X(:,1))).^2;
                end
            end
            gx          = 0.7057;
            PopObj(:,1) = X(:,1)+10*sum1+gx;
            PopObj(:,2) = 1-X(:,1).^0.5+10.*sum2+gx;
            Population  = SOLUTION(X,PopObj,Constraint(PopObj),varargin{2:end});
            obj.FE      = obj.FE + length(Population);
        end
        %% Generate points on the Pareto front
        function R = GetOptimum(obj,N)
            R(:,1) = linspace(0,1,N)';
            R(:,2) = 1 - sqrt(R(:,1));
            R      = R + 0.7057;
            R(any(Constraint(R)>0,2),:) = [];
        end
        %% Generate the feasible region
        function R = GetPF(obj)
            [x,y] = meshgrid(linspace(0.7057,5,400));
            fes   = all(Constraint([x(:),y(:)])<=0,2);
            z     = nan(size(x));
            z(reshape(fes,size(z)) & sqrt(x-0.7057)+y>=1.7057) = 0;
            R = {x,y,z};
        end
    end
end

function PopCon = Constraint(PopObj)
    p     = [1.6,2.5];
    q     = [1.6,2.5];
    a     = [2,2];
    b     = [4,8];
    r     = 0.1;
    theta = -0.25 * pi;
    for k = 1 : 2
        PopCon(:,k) = r - ((PopObj(:,1)-p(k))*cos(theta)-(PopObj(:,2)-q(k))*sin(theta)).^2/(a(k)^2) - ...
                      ((PopObj(:,1)-p(k))*sin(theta)+(PopObj(:,2)-q(k))*cos(theta)).^2/(b(k)^2);
    end
end


 function xs = eml_osps(x, Gb, yi, ci, ri, niter, pixmax, curv, relax0, chat)
%function xs = eml_osps(x, Gb, yi, ci, ri, niter, pixmax, curv, relax0, chat)
% E-ML-OSPS algorithm for emission Poisson problem
% (ordered subsets separable paraboloidal surrogates)
% model: Y_i ~ Poisson(c_i [G x]_i + r_i)
% in
%	x	[np,1]		initial estimate
%	Gb			Gblock object (see eml_osps_test.m)
%	yi,ci,ri [nb,na]	see em_fbp.m (for model too)
%	niter			# iterations
%	pixmax			upper constraint for pixel values
%	curv	'oc' for erdogan's optimal curvatures
%		'pc' for erdogan's fast precomputed curvatures,
%			which usually provides faster convergence,
%			but can be nonmonotone
%	relax0	[1] or [2]	relax0 or (relax0, relax_rate)
%	chat
% out
%	xs [np,niter]	updated image vectors each iteration
%
% Copyright Mar 2000, Jeff Fessler, The University of Michigan

if nargin < 3, ir_usage, end

nblock = block_ob(Gb, 'n');
starts = subset_start(nblock);

if ~isvar('ci') || isempty(ci)
	ci = ones(size(yi));
end
if ~isvar('ri') || isempty(ri)
	ri = zeros(size(yi));
end
if ~isvar('niter') || isempty(niter),	niter = 1;	end
if ~isvar('pixmax') || isempty(pixmax),	pixmax = inf;	end
if ~isvar('curv') || isempty(curv),	curv = 'oc';	end
if ~isvar('chat') || isempty(chat),	chat = true;	end

if ~isvar('relax0') || isempty(relax0)
	relax0 = 1;
end
if length(relax0) == 1
	relax_rate = 0;
elseif length(relax0) == 2
	relax_rate = relax0(2);
	relax0 = relax0(1);
else
	error relax
end

eml_check(yi, ci, ri);

[nb, na] = size(yi);

gi = sum(Gb')';		% g_i = sum_j g_ij
gi = reshape(gi, nb, na);

%
%	precomputed curvatures
%
denom = zeros(numel(x), nblock);
if streq(curv, 'pc')
	ni = eml_curvature(yi, ci, ri, [], [], curv);
	denom = Gb' * col(gi .* ni);
%	printf('ni range %g %g', min(ni(:)), max(ni(:)))
%	printf('denom range %g %g', min(denom(:)), max(denom(:)))
end

%
%	loop over iterations
%
xs = zeros(numel(x), niter);
x = max(x,0);
x = min(x,pixmax);
xs(:,1) = x;
for iter = 2:niter

	relax = 1;

	%
	% loop over subsets
	%
	for iset=1:nblock
		iblock = starts(iset);
		ia = iblock:nblock:na;

		li = Gb{iblock} * x;			% l=G*x "line integrals"
		li = reshape(li, nb, length(ia));
		yb = ci(:,ia) .* li + ri(:,ia);		% predicted meas. means

		% fix: need to be careful here with 0/0 -> 0
		dothi = ci(:,ia) .* (yi(:,ia) ./ yb - 1);

		% non-precomputed curvatures (notably, optimal curvature),
		% for ensured monotone increase
		if ~streq(curv, 'pc')
			ni = eml_curvature(yi(:,ia), ci(:,ia), ri(:,ia), li, yb, curv);
			denom = nblock * (Gb{iblock}' * col(gi(:,ia) .* ni));
		end

		grad = Gb{iblock}' * dothi(:);
		num = nblock * grad;
		x = x + relax * num ./ denom;	% relaxed update
		x = max(x,0);			% lower bound
		x = min(x,pixmax);		% upper bound
	end

	xs(:,iter) = x;
end


% Example_3_ECGC: Mesh the greater US East Coast and Gulf of Mexico region
% with a high resolution inset around New York

clearvars; clc;

addpath('..')
addpath(genpath('../utilities/'));
addpath(genpath('../datasets/'));
addpath(genpath('../m_map/'));

% WJP: 08/02/2019: Updated to demonstrate using non-box
% (arbitrary polygon's) bbox's in both outer and inner meshes

%% STEP 1: set mesh extents and set parameters for mesh.
%% The greater US East Coast and Gulf of Mexico region

bbox = [-71.6 42.7; -64 30; -80 24; -85 38; -71.6 42.7]; %polygon boubox
min_el    = 1e3;  		        % minimum resolution in meters.
max_el    = 50e3; 		        % maximum resolution in meters.
wl        = 30;                 % 60 elements resolve M2 wavelength.
dt        = 0;                  % Automatically set timestep based on nearshore res
grade     = 0.35;               % mesh grade in decimal percent.
R         = 3; 			        % Number of elements to resolve feature.

%% STEP 2: specify geographical datasets and process the geographical data
%% to be used later with other OceanMesh classes...
dem       = 'SRTM15+.nc';
coastline = 'GSHHS_f_L1';
gdat1 = geodata('shp',coastline,'dem',dem,'h0',min_el,...
                'bbox',bbox);

%% STEP 3: create an edge function class
fh1 = edgefx('geodata',gdat1,...
             'fs',R,'wl',wl,'max_el',max_el,...
             'dt',dt,'g',grade);

%% Repeat STEPS 1-3 for a high resolution domain for High Res New York Part
min_el    = 30;  		% minimum resolution in meters.
max_el    = 1e3; 		% maximum resolution in meters.
max_el_ns = 240;  		% maximum resolution nearshore.

coastline = 'PostSandyNCEI';
dem       = 'PostSandyNCEI.nc';

%polygon boubox
bbox2 = [-74.25 40.5; -73.75 40.55; -73.75 41; -74 41; -74.25 40.5];
gdat2 = geodata('shp',coastline,'dem',dem,'h0',min_el,'bbox',bbox2);

fh2 = edgefx('geodata',gdat2,'fs',R,'wl',wl,...
             'max_el',max_el,'max_el_ns',max_el_ns,...
             'dt',dt,'g',grade);

%% STEP 4: Pass your edgefx class object along with some meshing options
%% and build the mesh...
mshopts = meshgen('ef',{fh1 fh2},'bou',{gdat1 gdat2},...
                  'plot_on',1,'proj','lam');
mshopts = mshopts.build;

%% Plot and save the msh class object/write to fort.14
m = mshopts.grd; % get out the msh object
m = interp(m,{gdat1 gdat2},'mindepth',1); % interpolate bathy to the mesh with minimum depth of 1 m
m = make_bc(m,'auto',gdat1);               % make the nodestring boundary conditions
plot(m,'type','bd');  % plot mesh on native projection with boundary conditions
plot(m,'type','b');   % plot bathy on native projection
save('ECGC_w_NYHR.mat','m'); write(m,'ECGC_w_NYHR');


function v = calcSymAxis(S2F,varargin)

v = equispacedS2Grid('resolution',5*degree,'antipodal');

err = nan(size(v));

for i = 1:length(v)
  err(i) = norm(S2F - S2F.symmetrise(v(i)));
end

[~,id] = min(err);

% refine
v2 = equispacedS2Grid('resolution',0.5*degree,'maxTheta',5*degree,'center',v(id));

err = nan(size(v2));
for i = 1:length(v2)
  err(i) = norm(S2F - S2F.symmetrise(v2(i)));
end

[~,id] = min(err);
v = v2(id);


function Population = EvolveByMOEAD(Problem,Population,W,deltaG)
% Uniformity optimization by MOEA/D

%------------------------------- Copyright --------------------------------
% Copyright (c) 2023 BIMK Group. You are free to use the PlatEMO for
% research purposes. All publications which use this platform or any code
% in the platform should acknowledge the use of "PlatEMO" and reference "Ye
% Tian, Ran Cheng, Xingyi Zhang, and Yaochu Jin, PlatEMO: A MATLAB platform
% for evolutionary multi-objective optimization [educational forum], IEEE
% Computational Intelligence Magazine, 2017, 12(4): 73-87".
%--------------------------------------------------------------------------

    %% Detect the neighbours of each solution
    W = W.*repmat(max(Population.objs,[],1)-min(Population.objs,[],1),size(W,1),1);
    B = pdist2(W,W);
    [~,B] = sort(B,2);
    B = B(:,1:ceil(Problem.N/10));

    %% Associate each subproblem with one solution
    % The ideal point
    Z = min(Population.objs,[],1);
    % The value of each solution on each subproblem (modified Tchebycheff approach)
    g = zeros(Problem.N);
    for i = 1 : Problem.N
        g(i,:) = max(repmat(abs(Population(i).obj-Z),Problem.N,1)./W,[],2)';
    end
    [~,rank] = sort(g,2);
    % The index of solution which each subproblem associated with
    associate = zeros(1,Problem.N);
    for i = 1 : Problem.N
        x = find(~associate(rank(i,:)),1);
        associate(rank(i,x)) = i;
    end
    Population = Population(associate);

    %% Optimization
    for k = 1 : deltaG
        % For each solution
        for i = 1 : Problem.N
            % Choose the parents
            if rand < 0.9
                P = B(i,randperm(size(B,2)));
            else
                P = randperm(Problem.N);
            end

            % Generate an offspring
            Offspring = OperatorDE(Problem,Population(i),Population(P(1)),Population(P(2)));
            % Update the ideal point
            Z = min(Z,Offspring.obj);
            % Update the solutions in P by modified Tchebycheff approach
            g_old = max(abs(Population(P).objs-repmat(Z,length(P),1))./W(P,:),[],2);
            g_new = max(repmat(abs(Offspring.obj-Z),length(P),1)./W(P,:),[],2);
            Population(P(g_old>=g_new)) = Offspring;
        end
    end
end


% GP_COV_PP - Piecewise polynomial covariance function with compact support
% for Gaussian processes.
%
% [K, DK_LOGTHETA, DK_X2] = GP_COV_CS(X1, X2, LOGTHETA)

% Last modified 2010-10-28
% Copyright (c) Jaakko Luttinen (jaakko.luttinen@tkk.fi)

function covfunc = gp_cov_pp_proto(x1,x2)

if nargin < 2
  x2 = x1;
end

% Dimensions
d = rows(x2); % dimensionality of inputs
m = cols(x1); % number of other inputs
n = cols(x2); % number of inputs

q = 2; % PP parameter, fix to 2 for now..

% Distance matrix
D = sqrt(sq_dist(x1,x2));

covfunc = @get_covariance;

  function [K,L,M] = get_covariance(theta)

  if nargin == 0
    % Return the number of parameters and the size of the covariance matrix
    K = 1;
    L = m;
    M = n;
    return
  end

  % Threshold
  thres = theta(1); % length scale, threshold
  R = D./thres;
  I = sparse(R<1);
  NNZ = nnz(I); % number of nonzero elements

  j = floor(rows(x1)) + q + 1;
  switch q
    %%%%%%%%%%
   case 0
    error('not yet implemented for q=0')
    K(I) = (1-R(I)) .^ j;
    %%%%%%%%%%
   case 1
    error('not yet implemented for q=1')
    %%%%%%%%%%

   case 2
    a = j^2 + 4*j + 3;
    b = 3*j + 6;
    c = 3;
    z = 1/3;

    % Helper
    R2 = spalloc(m,n,NNZ);
    R2(I) = D(I).^2 ./ (thres^2);

    % Covariance matrix
    K = spalloc(m,n,NNZ);
    K(I) = z * (1-R(I)).^(j+2) .* (a*R2(I) + b*R(I) + c);

    dK_dR = spalloc(m,n,NNZ); % copy sparseness
    dK_dR(I) = -z * (j+2) * (1-R(I)).^(j+1) .* (a*R2(I) + b*R(I) + c) ...
        + z * (1-R(I)).^(j+2) .* (2*a*R(I) + b);

    % Gradient for hyperparameters
    if nargout >= 2
      % TODO 3D SPARSE MATRICES DO NOT WORK. USE CELL ARRAYS?
      dK_dlogtheta = spalloc(m,n,NNZ);
      dK_dlogtheta(I) = dK_dR(I) .* (-D(I) ./ thres);
      dK_dlogtheta = full(dK_dlogtheta); % blaaah.. :(
    end

    % Gradients for inputs x2
    if nargout >= 3
      if isempty(x2)
        error('Can''t calculate gradient: x2 not given');
      end
      % TODO 3D SPARSE MATRICES DO NOT WORK. USE CELL ARRAYS?
      % TODO: you have dK_dR and dD_dx but NOT dR_dD!!
      dK_dx2 = bsxfun(@times, reshape(full(dK_dR./thres),[1,m,n]), dD_dx2);
      % blaah the need for fullness.. :(
    end

    %%%%%%%%%%

   case 3
    error('not yet implemented for q=3')
    %%%%%%%%%%
   otherwise
    error('q not valid')
  end

  if ~issparse(K)
    error('K not sparse, it should, wtf?!');
  end

  if nargout >= 2
    L = ldlchol2chol( ldlchol(K) );
  end
  end

end


function [overlap] = check_overlap_ellipses(lnk,circles,dlnk,nglnk,ndxy,image_size,x0,y0,a0,b0,theta0)

ix0 = ceil(x0/dlnk);
iy0 = ceil(y0/dlnk);

ndx1 = ix0 - ndxy; ndx2 = ix0 + ndxy;
ndy1 = iy0 - ndxy; ndy2 = iy0 + ndxy;

ix = mod(ndx1:ndx2,nglnk);ixt = ix==0;ix(ixt)=nglnk;
iy = mod(ndy1:ndy2,nglnk);iyt = iy==0;iy(iyt)=nglnk;

a = lnk(ix,iy);
b = find(a~=0);
overlap = 0;
for k = 1:length(b)
    j = a(b(k));
    x1 = circles(j,1); y1 = circles(j,2);
    a1 = circles(j,3); b1 = circles(j,4);
    theta1 = circles(j,5);

    if x1-x0 > image_size / 2; x1 = x1 - image_size; end;
    if x0-x1 > image_size / 2; x1 = x1 + image_size; end;
    if y1-y0 > image_size / 2; y1 = y1 - image_size; end;
    if y0-y1 > image_size / 2; y1 = y1 + image_size; end;

    overlap = overlap_ellipses(x0,y0,a0,b0,theta0,x1,y1,a1,b1,theta1);
    if overlap == 1; overlap = 1; break; end;
end


% [HEIGHT] = spyrHt(INDICES)
%
% Compute height of steerable pyramid with given index matrix.

% Eero Simoncelli, 6/96.

function [ht] =  spyrHt(pind)

nbands = spyrNumBands(pind);

% Don't count lowpass, or highpass residual bands
if (size(pind,1) > 2)
  ht = (size(pind,1)-2)/nbands;
else
  ht = 0;
end


% pdfbdenoiseimagethmt.m
% written by: Duncan Po
% Date: January 14, 2004
% Clean the noisy image using the model and state probabilities of the
% noisy image. The image is assumed to be square.
% Usage: cleanimage = pdfbdenoiseimage( model, stateprob, nvar, nc, imname, imformat)
% Inputs:   model       - model of the noisy image
%           stateprob   - state probabilities of the noisy image
%           nvar        - noise variance, normalized to the image range
%                           (ie. should be between 0 and 1)
%           nc          - noise variance in contourlet domain. Input '' if
%                           unknown
%           imname      - name of the image file
%           imformat    - format of the image file (e.g. 'gif')
% Output:   cleanimage  - the denoised image

function cleanimage = pdfbdenoiseimage( model, stateprob, nvar, nc, imname, imformat)

pyrfilter = '9-7';
dirfilter = 'pkva';
nlevel = model{1}.nlevels;
for lev = 1:nlevel
    levndir(lev) = log2(length(model{1}.stdv{lev})*length(model));
end;

if nargin == 6
    coef = contourlet(pyrfilter, dirfilter, levndir, imname, imformat);
elseif nargin == 5
    coef = contourlet(pyrfilter, dirfilter, levndir, imname);
end;

% Verify image is square and obtain image dimensions
[nrow, ncol] = size(coef{2}{1});
imagestats = imfinfo(imname, imformat);
imdim = imagestats.Width;
if imdim ~= imagestats.Height
    error('Image must be square.');
end

for state = 1:size(stateprob{1}{1},2)
    for lev = 1:nlevel+1
        newstateprob{state}{lev} = [];
        covariance{state}{lev} = [];
    end;
end;

% process stateprob, and covariance so that it has the same structure as coef
for state = 1:size(stateprob{1}{1},2)
    for dir = 1:2.^levndir(1)
        for scale = 1:length(stateprob{dir})
            tempsp{scale} = stateprob{dir}{scale}(:,state);
        end;
        tempstateprob = tree2contourlet(tempsp, dir, levndir, nrow, ncol);

        for lev = 1:nlevel
            newstateprob{state}{lev+1} = [newstateprob{state}{lev+1} tempstateprob{lev}];
            for subdir = 1:length(model{dir}.stdv{lev})
               covariance{state}{lev+1} = [covariance{state}{lev+1} ...
                     {ones(size(coef{lev+1}{(dir-1)*(2.^(levndir(lev)-levndir(1)))+subdir},1),...
                        size(coef{lev+1}{(dir-1)*(2.^(levndir(lev)-levndir(1)))+subdir},2))*...
                        model{dir}.stdv{lev}{subdir}(state)*model{dir}.stdv{lev}{subdir}(state)}];
            end;
        end;
    end;
end;

% calculates the noise variance in contourlet domain
if isempty(nc)
    nc = contournc(nvar, pyrfilter, dirfilter, levndir, imdim);
end;

% computes the attenuator for each coefficient and state
for state = 1:length(covariance)
   for lev = 2:nlevel+1
      for dir = 1:length(covariance{state}{lev})
         [covrow, covcol] = size(covariance{state}{lev}{dir});
         covariance{state}{lev}{dir}=max(covariance{state}{lev}{dir}...
            -nc{lev}{dir}, zeros(covrow, covcol))./covariance{state}{lev}{dir};
      end;
   end;
end;

% multiplies each contourlet coefficient with its corresponding state probabilities
for state = 1:length(newstateprob)
   for lev = 2:nlevel+1
      for dir = 1:length(newstateprob{state}{lev})
         newcoef{state}{lev}{dir} = newstateprob{state}{lev}{dir}...
            .*coef{lev}{dir};
      end;
   end;
end;

% we don't denoise the scaling function since its SNR is high
cleancoef{1} = coef{1};

% initialize the clean coefficients
for lev = 2:nlevel+1
    for dir = 1:length(newstateprob{state}{lev})
        cleancoef{lev}{dir} = zeros(size(coef{lev}{dir},1), size(coef{lev}{dir},2));
    end;
end;

% denoise
for state = 1:length(newstateprob)
   for lev = 2:nlevel+1
      for dir = 1:length(newstateprob{state}{lev})
         cleancoef{lev}{dir}=cleancoef{lev}{dir}+covariance{state}{lev}{dir}...
            .*newcoef{state}{lev}{dir};
      end;
   end;
end;

cleanimage = pdfbrec(cleancoef, pyrfilter, dirfilter);
figure;
imshow(uint8(cleanimage));


function [label] = mne_read_label_file(filename)
%
% [label] = mne_read_label_file(filename)
%
% Reads a label file. The returned structure has the following fields
%
%     comment        comment from the first line of the label file
%     vertices       vertex indices (0 based, column 1)
%     pos            locations in meters (columns 2 - 4 divided by 1000)
%     values         values at the vertices (column 5)
%

%
%
%   Author : Matti Hamalainen, MGH Martinos Center
%   License : BSD 3-clause
%

%
% This is based on the FreeSurfer read_label routine
% SUBJECTS_DIR environment variable is not consulted for the standard location
%

me='MNE:mne_read_label_file';
if(nargin ~= 1)
   error(me,'usage: mne_read_label_file(filename)');
end

[fid,message] = fopen(filename,'r');
if (fid < 0)
   error(me,'Cannot open file %s (%s)', filename,message);
end

comment = fgets(fid) ;
line = fgets(fid) ;
nv = sscanf(line, '%d') ;
data = fscanf(fid, '%d %f %f %f %f\n') ;
data = reshape(data, 5, nv);

for k = 2:length(comment)
   if comment(k) ~= ' '
      break;
   end
end
if comment(length(comment)) == 10
   comment = comment(1:end-1);
end
label.comment  = comment(k:end);
label.vertices = int32(data(1,:));
label.pos      = 1e-3*data(2:4,:)';
label.values   = data(5,:);
fclose(fid);


%LEARNALGOMLEUCLIDEAN Simulates plain L2 distance as learning algorithm.
classdef LearnAlgoMLEuclidean < LearnAlgo

    properties
       p %parameters
       s %struct
    end

    properties (Constant)
        type = 'identity'
    end

    methods
        function obj = LearnAlgoMLEuclidean(p)
            if nargin < 1
               p = struct();
            end

            if ~isfield(p,'roccolor')
                p.roccolor = 'r';
            end

            obj.p = p;
        end

        function s = learnPairwise(obj,X,idxa,idxb,matches)
            s.M = eye(size(X,1));
            s.t = 0.0;
            s.learnAlgo = obj;
            s.roccolor = obj.p.roccolor;
        end

        function s = learn(obj,X,y)
            s.M = eye(size(X,1));
            s.t = 0.0;
            s.learnAlgo = obj;
            s.roccolor = obj.p.roccolor;
        end

        function d = dist(obj, s, X, idxa,idxb)
            d = cdistM(s.M,X,idxa,idxb);
        end
    end
end


function [data,units] = compute_darea_inmost_wing(trx,n)

flies = trx.exp2flies{n};
nflies = numel(flies);
data = cell(1,nflies);
for i = 1:nflies,
  fly = flies(i);

  dareal = diff(trx(fly).wing_areal_mm);
  darear = diff(trx(fly).wing_arear_mm);
  data{i} = dareal;
  idx = trx(fly).wing_angler(1:end-1) <= -trx(fly).wing_anglel(1:end-1);
  data{i}(idx) = darear(idx);

  data{i} = data{i} ./ trx(fly).dt;
end
units = parseunits('mm^2/s');


function [g, gdata, gprior] = mlpgrad_weighted(net, x, t, eso_w)
%MLPGRAD Evaluate gradient of error function for 2-layer network.
%
%	Description
%	G = MLPGRAD(NET, X, T) takes a network data structure NET  together
%	with a matrix X of input vectors and a matrix T of target vectors,
%	and evaluates the gradient G of the error function with respect to
%	the network weights. The error funcion corresponds to the choice of
%	output unit activation function. Each row of X corresponds to one
%	input vector and each row of T corresponds to one target vector.
%
%	[G, GDATA, GPRIOR] = MLPGRAD(NET, X, T) also returns separately  the
%	data and prior contributions to the gradient. In the case of multiple
%	groups in the prior, GPRIOR is a matrix with a row for each group and
%	a column for each weight parameter.
%
%	See also
%	MLP, MLPPAK, MLPUNPAK, MLPFWD, MLPERR, MLPBKP
%

%	Copyright (c) Ian T Nabney (1996-9)

% Check arguments for consistency
errstring = consist(net, 'mlp', x, t);
if ~isempty(errstring);
  error(errstring);
end
[y, z] = mlpfwd(net, x);
temp = y - t;
ndata = size(x, 1);
for m=1:ndata,
      delout(m,:)=eso_w(m,1)*temp(m,:);
end
clear temp;
gdata = mlpbkp(net, x, z, delout);

[g, gdata, gprior] = gbayes(net, gdata);


function [U_final, V_final, nIter_final, objhistory_final] = LCCF_Multi(K, k, W, options, U, V)
% Locally Consistant Concept Factorization (LCCF)
%
% where
%   X
% Notation:
% K ... (nSmp x nSmp) kernel matrix
% k ... number of hidden factors
% W ... weight matrix of the affinity graph
%
% options ... Structure holding all settings
%
% You only need to provide the above four inputs.
%
% X = X*U*V'
%
% References:
% [1] Deng Cai, Xiaofei He, Jiawei Han, "Locally Consistent Concept
%     Factorization for Document Clustering", IEEE Transactions on Knowledge
%     and Data Engineering, Vol. 23, No. 6, pp. 902-913, 2011.
%
%
%   version 2.0 --April/2010
%   version 1.0 --Dec./2008
%
%   Written by Deng Cai (dengcai AT gmail.com)
%

differror = options.error;
maxIter = options.maxIter;
nRepeat = options.nRepeat;
minIterOrig = options.minIter;
minIter = minIterOrig-1;
meanFitRatio = options.meanFitRatio;

alpha = options.alpha;

Norm = 2;
NormV = 1;

nSmp = size(K,1);

if alpha < 0
    alpha = 0;
end
W = alpha*W;
DCol = full(sum(W,2));
D = spdiags(DCol,0,speye(size(W,1)));
L = D - W;
if isfield(options,'NormW') && options.NormW
    D_mhalf = DCol.^-.5;

    tmpD_mhalf = repmat(D_mhalf,1,nSmp);
    L = (tmpD_mhalf.*L).*tmpD_mhalf';
    clear D_mhalf tmpD_mhalf;

    L = max(L, L');
end

if isempty(U)
    U = abs(rand(nSmp,k));
    V = abs(rand(nSmp,k));
else
    nRepeat = 1;
end
[U,V] = NormalizeUV(K, U, V, NormV, Norm);

selectInit = 1;
if nRepeat == 1
    selectInit = 0;
    minIterOrig = 0;
    minIter = 0;
    if isempty(maxIter)
        [obj_NMFhistory, obj_Laphistory] = CalculateObj(K, U, V, L);
        objhistory = obj_NMFhistory + obj_Laphistory;
        meanFit = objhistory*10;
    else
        if isfield(options,'Converge') && options.Converge
            [obj_NMFhistory, obj_Laphistory] = CalculateObj(K, U, V, L);
            objhistory = obj_NMFhistory + obj_Laphistory;
        end
    end
else
    if isfield(options,'Converge') && options.Converge
        error('Not implemented!');
    end
end

tryNo = 0;
while tryNo < nRepeat
    tmp_T = cputime;
    tryNo = tryNo+1;
    nIter = 0;
    maxErr = 1;
    while(maxErr > differror)
        % ===================== update V ========================
        KU = K*U;               % n^2k
        UKU = U'*KU;            % nk^2
        VUKU = V*UKU;           % nk^2

        if alpha > 0
            WV = W*V;
            DV = repmat(DCol,1,k).*V;

            KU = KU + WV;
            VUKU = VUKU + DV;
        end

        V = V.*(KU./max(VUKU,1e-10));
        clear WV DV KU UKU VUKU;
        % ===================== update U ========================
        KV = K*V;               % n^2k
        VV = V'*V;              % nk^2
        KUVV = K*U*VV;          % n^2k

        U = U.*(KV./max(KUVV,1e-10));
        clear KV VV KUVV;

        nIter = nIter + 1;
        if nIter > minIter
            [U,V] = NormalizeUV(K, U, V, NormV, Norm);
            if selectInit
                [obj_NMFhistory, obj_Laphistory] = CalculateObj(K, U, V, L);
                objhistory = obj_NMFhistory + obj_Laphistory;
                maxErr = 0;
            else
                if isempty(maxIter)
                    [obj_NMF, obj_Lap] = CalculateObj(K, U, V, L);
                    newobj = obj_NMF + obj_Lap;
                    objhistory = [objhistory newobj]; %#ok<AGROW>
                    meanFit = meanFitRatio*meanFit + (1-meanFitRatio)*newobj;
                    maxErr = (meanFit-newobj)/meanFit;
                else
                    if isfield(options,'Converge') && options.Converge
                        [obj_NMF, obj_Lap] = CalculateObj(K, U, V, L);
                        newobj = obj_NMF + obj_Lap;
                        objhistory = [objhistory newobj]; %#ok<AGROW>
                    end
                    maxErr = 1;
                    if nIter >= maxIter
                        maxErr = 0;
                        if isfield(options,'Converge') && options.Converge
                        else
                            objhistory = 0;
                        end
                    end
                end
            end
        end
    end

    if tryNo == 1
        U_final = U;
        V_final = V;
        nIter_final = nIter;
        objhistory_final = objhistory;
    else
        if objhistory(end) < objhistory_final(end)
            U_final = U;
            V_final = V;
            nIter_final = nIter;
            objhistory_final = objhistory;
        end
    end

    if selectInit
        if tryNo < nRepeat
            %re-start
            U = abs(rand(nSmp,k));
            V = abs(rand(nSmp,k));

            [U,V] = NormalizeUV(K, U, V, NormV, Norm);
        else
            tryNo = tryNo - 1;
            minIter = 0;
            selectInit = 0;
            U = U_final;
            V = V_final;
            objhistory = objhistory_final;
            meanFit = objhistory*10;
        end
    end
end

nIter_final = nIter_final + minIterOrig;

Norm = 2;
NormV = 0;

[U_final,V_final] = NormalizeUV(K, U_final, V_final, NormV, Norm);

%==========================================================================

function [obj_NMF, obj_Lap, dV] = CalculateObj(K, U, V, L, deltaVU, dVordU)
if ~exist('deltaVU','var')
    deltaVU = 0;
end
if ~exist('dVordU','var')
    dVordU = 1;
end
dV = [];

UK = U'*K; % n^2k
UKU = UK*U; % nk^2
VUK = V*UK; % n^2k
VV = V'*V; % nk^2
obj_NMF = sum(diag(K))-2*sum(diag(VUK))+sum(sum(UKU.*VV));
if deltaVU
    if dVordU
        dV = V*UKU - UK'+ L*V; %nk^2
    else
        dV = (VUK-K)'*V;  %n^2k
    end
end
obj_Lap = sum(sum((L*V).*V));

function [U, V] = NormalizeUV(K, U, V, NormV, Norm)
k = size(U,2);
if Norm == 2
    if NormV
        norms = max(1e-15,sqrt(sum(V.^2,1)))';
        V = V*spdiags(norms.^-1,0,k,k);
        U = U*spdiags(norms,0,k,k);
    else
        norms = max(1e-15,sqrt(sum(U.*(K*U),1)))';
        U = U*spdiags(norms.^-1,0,k,k);
        V = V*spdiags(norms,0,k,k);
    end
else
    if NormV
        norms = max(1e-15,sum(abs(V),1))';
        V = V*spdiags(norms.^-1,0,k,k);
        U = U*spdiags(norms,0,k,k);
    else
        norms = max(1e-15,sum(U.*(K*U),1))';
        U = U*spdiags(norms.^-1,0,k,k);
        V = V*spdiags(norms,0,k,k);
    end
end


classdef RegularizedExponentBestCoeffComputer < handle

   properties (Access = private)
        aValues
        bValues
        rValues
        qValues
        aValue
        bValue
        rValue
        qValue
        nA
        nB
        nR
        nQ
        nT
        error
    end

    properties (Access = private)
       errorComputer
    end

    methods (Access = public)

        function obj = RegularizedExponentBestCoeffComputer(cParams)
            obj.init(cParams);
            obj.initValues();
            obj.computeAxisValues();
        end

        function [a,b,r,q] = compute(obj)
            obj.evaluateAllSamples();
            [a,b,r,q] = obj.obtainBestParameterSample();
        end

        function [a,b,r,q] = obtainBestParameters(obj)
           a = 23.620689655172413;
           b = 1.444444444444444;
           r = 0.677777777777778;
           q = 11.322033898305085;
        end

    end

    methods (Access = private)

        function init(obj,cParams)
            obj.errorComputer = cParams.errorComputer;
            obj.nA = 30;
            obj.nB = 10;
            obj.nR = 10;
            obj.nQ = 60;
            obj.nT = obj.nA*obj.nB*obj.nR*obj.nQ;
        end

        function initValues(obj)
            obj.aValue = zeros(obj.nT,1);
            obj.bValue = zeros(obj.nT,1);
            obj.rValue = zeros(obj.nT,1);
            obj.qValue = zeros(obj.nT,1);
            obj.error = zeros(obj.nT,1);
        end

        function computeAxisValues(obj)
            obj.aValues = linspace(22,25,obj.nA);
            obj.bValues = linspace(1.2,1.6,obj.nB);
            obj.rValues = linspace(0.65,0.68,obj.nR);
            obj.qValues = linspace(11,12,obj.nQ);
        end

        function evaluateAllSamples(obj)
            iter = 1;
            for iR = 1:length(obj.rValues)
                for iQ = 1:length(obj.qValues)
                    for iB = 1:length(obj.bValues)
                        for iA = 1:length(obj.aValues)
                            obj.obtainSampleValue(iter,iA,iB,iR,iQ);
                            obj.computeError(iter);
                            iter = iter + 1;
                        end
                    end
                end
            end
        end

        function obtainSampleValue(obj,iT,iA,iB,iR,iQ)
            obj.aValue(iT) = obj.aValues(iA);
            obj.bValue(iT) = obj.bValues(iB);
            obj.rValue(iT) = obj.rValues(iR);
            obj.qValue(iT) = obj.qValues(iQ);
        end

        function  computeError(obj,iT)
           a = obj.aValue(iT);
           b = obj.bValue(iT);
           r = obj.rValue(iT);
           q = obj.qValue(iT);
           e = obj.errorComputer(a,b,r,q);
           obj.error(iT) = e;
        end

        function [a,b,r,q] = obtainBestParameterSample(obj)
            [~,ind] = min(obj.error);
            a = obj.aValue(ind);
            b = obj.bValue(ind);
            r = obj.rValue(ind);
            q = obj.qValue(ind);
        end

    end

end


function pz=lpcpp2pz(pp)
%LPCPP2PZ LPC: Convert power spectrum polynomial in cos(w) to power spectrum zeros PZ=(RP)
% pp is a polynomial such that |polyval(ra,e^jw)| = polyval(pp,cos(w))

%      Copyright (C) Mike Brookes 1998
%      Version: $Id: lpcpp2pz.m 713 2011-10-16 14:45:43Z dmb $
%
%   VOICEBOX is a MATLAB toolbox for speech processing.
%   Home page: http://www.ee.ic.ac.uk/hp/staff/dmb/voicebox/voicebox.html
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%   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 2 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.
%
%   You can obtain a copy of the GNU General Public License from
%   http://www.gnu.org/copyleft/gpl.html or by writing to
%   Free Software Foundation, Inc.,675 Mass Ave, Cambridge, MA 02139, USA.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

pz=roots(pp);


%% Testing other functions
% Create a Mesh FEM results
clear; close all;

file = 'test2d_triangle';
a.fileName = file;
s = FemDataContainer(a);
mesh = s.mesh;

%% Create functions
% AnalyticalFunction

sAF.fHandle = @(x) x(1,:,:);
sAF.ndimf   = 1;
sAF.mesh    = mesh;
xFun = AnalyticalFunction(sAF);

p1 = xFun.project('P1');
p1.plot

q = Quadrature.create(mesh,'LINEAR');
p1.evaluate(q.posgp)

% get dofs from logical analytical function?
leftCond = @(x) x(:,1) == 0;


function g = ggKernDiagGradient(kern, x, covDiag)

% GGKERNDIAGGRADIENT Compute gradient of the diagonal of GG kernel.
% FORMAT
% DESC computes the gradient of the diagonal of the kernel matrix for the
% gaussian gaussian kernel given a design matrix of inputs.
% RETURN g  : a vector containing the gradients
% ARG kern : the kernel structure for which the matrix is computed.
% ARG x : input data matrix in the form of a design matrix.
% ARG covDiag : partial derivative wrt diagonal of the covariance matrix
%
% SEEALSO : ggKernParamInit, kernDiagCompute, ggKernDiagCompute
%
% COPYRIGHT : Mauricio A. Alvarez, 2010

% KERN

grad_sigma2Latent = (kern.sensitivity^2)*sum(covDiag);
grad_sensitivity = (2*kern.sigma2Latent*kern.sensitivity)*sum(covDiag);

g = [zeros(size(kern.precisionU(:)')) zeros(size(kern.precisionG(:)')) ...
    grad_sigma2Latent grad_sensitivity];


function [mask, max_km] = closestEvents(catalog, lat, lon, depth, n)
    % closestEvents determine which N events are closest to a point (lat,lon, depth).
    % for hypocentral distance, leave depth empty.
    %  ex.  closestEvents(mycatalog, 82,-120,[],20);
    % the distance to the nth closest event
    %
    % see also eventsInRadius
    if isempty(depth)
        dists = catalog.epicentralDistanceTo(lat, lon,'kilometer');
    else
        dists = catalog.hypocentralDistanceTo(lat, lon, depth,'kilometer');
    end
    % find nth closest by grabbing from the sorted distances
    sorted_dists = sort(dists);
    max_km = sorted_dists(n);

    mask = dists_km <= max_km;
end


function [ar,ASAsellog,ASAcontrol] = sig2ar(sig,cand_order,last)
%SIG2AR AR model identification
%   [AR,SELLOG] = SIG2AR(SIG) estimates autoregressive models from the
%   data vector SIG and selects a model with optimal predictive
%   qualities. The selected model is returned in the parameter vector AR.
%   The structure SELLOG provides additional information on the selection
%   process.
%
%   SIG2AR(SIG,CAND_ORDER) selects only from candidate models whose
%   orders are entered in CAND_ORDER. CAND_ORDER must either be a row of
%   ascending orders, or a single order (in which case no true order
%   selection is performed).
%
%   Without user intervention, the mean of SIG is subtracted from the
%   data. To control the subtraction of the mean, see the help topics on
%   ASAGLOB_SUBTR_MEAN and ASAGLOB_MEAN_ADJ.
%
%   SIG2AR is an ARMASA main function.
%
%   See also: SIG2MA, SIG2ARMA, ARMASEL.

%   References: P. M. T. Broersen, Facts and Fiction in Spectral
%               Analysis, IEEE Transactions on Instrumentation and
%               Measurement, Vol. 49, No. 4, August 2000, pp. 766-772.

%Header
%=========================================================================

%Declaration of variables
%------------------------

%Declare and assign values to local variables
%according to the input argument pattern
switch nargin
case 1
   if isa(sig,'struct'), ASAcontrol=sig; sig=[];
   else, ASAcontrol=[];
   end
   cand_order=[];
case 2
   if isa(cand_order,'struct'), ASAcontrol=cand_order; cand_order=[];
   else, ASAcontrol=[];
   end
case 3
   if isa(last,'struct'), ASAcontrol=last;
   else, error(ASAerr(39))
   end
otherwise
   error(ASAerr(1,mfilename))
end

if isequal(nargin,1) & ~isempty(ASAcontrol)
      %ASAcontrol is the only input argument
   ASAcontrol.error_chk = 0;
   ASAcontrol.run = 0;
end

%Declare ASAglob variables
ASAglob = {'ASAglob_subtr_mean';'ASAglob_mean_adj'; ...
      'ASAglob_rc';'ASAglob_ar'};

%Assign values to ASAglob variables by screening the
%caller workspace
for ASAcounter = 1:length(ASAglob)
   ASAvar = ASAglob{ASAcounter};
   eval(['global ' ASAvar]);
   if evalin('caller',['exist(''' ASAvar ''',''var'')'])
      eval([ASAvar '=evalin(''caller'',ASAvar);']);
   else
      eval([ASAvar '=[];']);
   end
end

%ARMASA-function version information
%-----------------------------------

%This ARMASA-function is characterized by
%its current version,
ASAcontrol.is_version = [2000 12 30 20 0 0];
%and its compatability with versions down to,
ASAcontrol.comp_version = [2000 12 30 20 0 0];

%This function calls other functions of the ARMASA
%toolbox. The versions of these other functions must
%be greater than or equal to:
ASAcontrol.req_version.burg = [2000 12 30 20 0 0];
ASAcontrol.req_version.cic = [2000 12 30 20 0 0];
ASAcontrol.req_version.rc2arset = [2000 12 30 20 0 0];

%Checks
%------

if ~any(strcmp(fieldnames(ASAcontrol),'error_chk')) | ASAcontrol.error_chk
      %Perform standard error checks
   %Input argument format checks
   ASAcontrol.error_chk = 1;
   if ~isnum(sig)
      error(ASAerr(11,'sig'))
   elseif ~isavector(sig)
      error([ASAerr(14) ASAerr(15,'sig')])
   elseif size(sig,2)>1
      sig = sig(:);
      warning(ASAwarn(25,{'row';'sig';'column'},ASAcontrol))
   end
   if ~isempty(cand_order)
      if ~isnum(cand_order) | ~isintvector(cand_order) |...
            cand_order(1)<0 | ~isascending(cand_order)
         error(ASAerr(12,{'candidate';'cand_order'}))
      elseif size(cand_order,1)>1
         cand_order = cand_order';
         warning(ASAwarn(25,{'column';'cand_order';'row'},ASAcontrol))
      end
   end

   %Input argument value checks
   if ~isreal(sig)
      error(ASAerr(13))
   end
   if max(cand_order) > length(sig)-1
      error(ASAerr(21))
   end
end

if ~any(strcmp(fieldnames(ASAcontrol),'version_chk')) | ASAcontrol.version_chk
      %Perform version check
   ASAcontrol.version_chk = 1;

   %Make sure the requested version of this function
   %complies with its actual version
   ASAversionchk(ASAcontrol);

   %Make sure the requested versions of the called
   %functions comply with their actual versions
   burg(ASAcontrol);
   cic(ASAcontrol);
   rc2arset(ASAcontrol);
end

if ~any(strcmp(fieldnames(ASAcontrol),'run')) | ASAcontrol.run
      %Run the computational kernel
   ASAcontrol.run = 1;
   ASAcontrol.version_chk = 0;
   ASAcontrol.error_chk = 0;
   ASAtime = clock;
   ASAdate = now;

%Main
%=====================================================

%Initialization of variables
%---------------------------

if isempty(ASAglob_subtr_mean) | ASAglob_subtr_mean
   sig = sig-mean(sig);
   if isempty(ASAglob_mean_adj)
      ASAglob_mean_adj = 1;
   end
elseif isempty(ASAglob_mean_adj)
   ASAglob_mean_adj = 0;
end

n_obs = size(sig,1);

%Determination of the maximum candidate AR order
%-----------------------------------------------

if ~isempty(cand_order)
   max_order = cand_order(end);
else
   max_order = ...
      min(fix(n_obs/2),fix(200*log10(n_obs)));
   if max_order > 1000;
      max_order = 1000;
   end
end

%Estimation procedure
%--------------------

[rc,var] = burg(sig,max_order,ASAcontrol);

%AR model order selection
%------------------------

rc(1) = 0;
res = var*cumprod(1-rc.^2);
rc(1) = 1;
[cicar,pe_est] = cic(res,n_obs,cand_order,ASAcontrol);
[min_value,sel_location] = min(cicar);
if isempty(cand_order)
   cand_order = 0:max_order;
end
sel_order = cand_order(sel_location);

%Arranging output arguments
%--------------------------

ar = rc2arset(rc(1:sel_order+1),ASAcontrol);

ASAglob_rc = rc;
ASAglob_ar = ar;

if nargout>1
   ASAsellog.funct_name = mfilename;
   ASAsellog.funct_version = ASAcontrol.is_version;
   ASAsellog.date_time = ...
      [datestr(ASAdate,8) 32 datestr(ASAdate,0)];
   ASAsellog.comp_time = etime(clock,ASAtime);
   ASAsellog.ar = ar;
   ASAsellog.rcarlong = rc;
   ASAsellog.mean_adj = ASAglob_mean_adj;
   ASAsellog.cand_order = cand_order;
   ASAsellog.cic = cicar;
   ASAsellog.pe_est = pe_est;
end

%Footer
%=====================================================

else %Skip the computational kernel
   %Return ASAcontrol as the first output argument
   if nargout>1
      warning(ASAwarn(9,mfilename,ASAcontrol))
   end
   ar = ASAcontrol;
   ASAcontrol = [];
end

%Program history
%======================================================================
%
% Version                Programmer(s)          E-mail address
% -------                -------------          --------------
% former versions        P.M.T. Broersen        p.m.t.broersen@tudelft.nl
% [2000 12 30 20 0 0]    W. Wunderink           wwunderink01@freeler.nl


  function Cdiff1_test1(C)
%|function Cdiff1_test1(C)
%| private helper for Cdiff1_test
%| tests abs and power and adjoints

Cf = C(:,:);

% abs
Ca = abs(C); Caf = Ca(:,:);
jf_equal(Caf, abs(Cf))

% squared
C2 = C.^2; C2f = C2(:,:);
jf_equal(C2f, Cf.^2)

test_adjoint(C);
test_adjoint(Ca);
test_adjoint(C2);


% Test sharedmatrix mex file.
%
% Copyright (c) 2010,2011 Joshua V Dillon
% All rights reserved. (See file header for details.)

%C = sparse(rand(10000,10000).*(rand(10000,10000)>.1)); % big matrix
C = sparse(rand(100,100).*(rand(100,100)>.1)); % small matrix

shmkey=12345;

try,sharedmatrix('free',shmkey);catch,end;

shmsiz=sharedmatrix('clone',shmkey,C);clear C;
%fprintf('[shmkey shmsiz]=deal(%d,%d);\n',shmkey,shmsiz);

if exist('x','var')==1
	sharedmatrix('detach',shmkey,x);
	clear x;
end

for i=1:100
	x=sharedmatrix('attach',shmkey);
	I=randperm(size(x,2));
	a=sum(x,1);
%	pause(.5);
	sharedmatrix('detach',shmkey,x);
%	clear x;
end


function r8vec_undex_test ( )

%*****************************************************************************80
%
%% R8VEC_UNDEX_TEST tests R8VEC_UNDEX.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    26 October 2008
%
%  Author:
%
%    John Burkardt
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'R8VEC_UNDEX_TEST\n' );
  fprintf ( 1, '  R8VEC_UNDEX produces index vectors which create a sorted\n' );
  fprintf ( 1, '  list of the unique elements of an (unsorted) R8VEC, \n' );
  fprintf ( 1, '  and a map from the original vector to the (implicit) \n' );
  fprintf ( 1, '  vector of sorted unique elements.\n' );

  x_num = 9;
  x_val = [ 33.0, 55.0, 11.0, 11.0, 55.0, 33.0, 22.0, 22.0, 11.0 ];

  r8vec_print ( x_num, x_val, '  The vector X:' );

  tol = r8_epsilon ( );
  x_unique_num = r8vec_unique_count ( x_num, x_val, tol );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  Tolerance for equality is %e\n', tol );
  fprintf ( 1, '  Number of unique entries in X is %d\n', x_unique_num );

  [ undx, xdnu ] = r8vec_undex ( x_num, x_val, x_unique_num, tol );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  UNDX can be used to list the unique elements of X\n' );
  fprintf ( 1, '  in sorted order.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '     I  UNDX   X(UNDX)\n' );
  fprintf ( 1, '\n' );
  for i = 1 : x_unique_num
    fprintf ( 1, '  %4d  %4d  %8f\n', i, undx(i), x_val(undx(i)) );
  end

  xu_val(1:x_unique_num) = x_val(undx(1:x_unique_num));

  fprintf ( 1, '\n' );
  fprintf ( 1, '  UNDX can be used to created XU, a copy of X\n' );
  fprintf ( 1, '  containing only the unique elements, in sorted order.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '     I  UNDX     XU(I)\n' );
  fprintf ( 1, '\n' );
  for i = 1 : x_unique_num
    fprintf ( 1, '  %4d  %4d  %8f\n', i, undx(i), xu_val(i) );
  end

  fprintf ( 1, '\n' );
  fprintf ( 1, '  XDNU can be used to match each element of X with one of the\n' );
  fprintf ( 1, '  unique elements\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '     I  XDNU    X(I)       XU(XDNU(I))\n' );
  fprintf ( 1, '\n' );

  for i = 1 : x_num
    fprintf ( 1, '  %4d  %4d  %8f  %12f\n', i, xdnu(i), x_val(i), xu_val(xdnu(i)) );
  end

  return
end


% SUMMARY:  convert LogGamma, LogKsi to Gamma, Ksi. Subtract max to avoid
%           underflow
% AUTHOR:   QIUQIANG KONG
% Created:  17-11-2015
% Modified: 25-11-2015 Add annotation
% -----------------------------------------------------------
% input:
%   LogGamma   cell{ ln p(zn|X) }
%   LogKsi     cell{ ln p(zn,zn-1|X) }
% output:
%   Gamma      cell{ gamma }
%   Ksi        cell{ ksi }
% ===========================================================
function [Gamma, Ksi] = UniformLogGammaKsi(LogGamma, LogKsi)
obj_num = length(LogGamma);
Q = size(LogGamma{1}, 2);
for q = 1:Q
    max_gamma_ary = zeros(1, obj_num);
    max_ksi_ary = zeros(1, obj_num);
    for r = 1:obj_num
        [Nr, Q] = size(LogGamma{r});
        max_gamma_ary(r) = max(LogGamma{r}(:,q));
        max_ksi_ary(r) = max(reshape(LogKsi{r}(:,q,:), (Nr-1)*Q, 1));
    end
    max_gamma = max(max_gamma_ary);
    max_ksi = max(max_ksi_ary);

    for r = 1:obj_num
        LogGamma{r}(:,q) = LogGamma{r}(:,q) - max_gamma;
        LogKsi{r}(:,q,:) = LogKsi{r}(:,q,:) - max_ksi;
    end
end

for r = 1:obj_num
    Gamma{r} = exp(LogGamma{r});
    Ksi{r} = exp(LogKsi{r});
end
end