% Copyright 2014 Jason Heeris, jason.heeris@gmail.com
%
% This file is part of the gammatone toolkit, and is licensed under the 3-clause
% BSD license: https://github.com/detly/gammatone/blob/master/COPYING
function test_gammatonegram()
    % Need:
    %  wave
    %  fs
    %  window_time
    %  hop_time
    %  channels
    %  f_min
    %  f_max

    % Need to mock out:
    %  make_erb_filters output (elide)
    %  centre_freqs (elide)
    %  erb_filterbank (depends on X, SR, N, FMIN)

    % Ensure reproducible tests
    rand('state', [3 1 4 1 5 9 2 7]);

    gammatonegram_inputs = {
        'sawtooth_01', sawtooth(2*pi*10100*[0:22050 - 1]'/22050, 0.5), 22050, 0.025, 0.010, 64, 50; ...
        'sin220_01'  , sin(2*pi*220*[0:4800 - 1]'/48000), 48000, 0.01, 0.01, 64, 50; ...
        'sin220_02'  , sin(2*pi*220*[0:4800 - 1]'/48000), 48000, 0.025, 0.01, 32, 50; ...
        'rand_01'    , rand([1, 4410 - 1]), 44100, 0.02, 0.015, 128, 500; ...
        'rand_02'    , rand([1, 9600 - 1]), 96000, 0.01, 0.005, 256, 20; ...
        'rand_03'    , rand([1, 4800 - 1]), 48000, 0.01, 0.010, 256, 20; ...
    };

    % Mocked intermediate results for unit testing
    gammatonegram_mocks = {};

    % Actual results
    gammatonegram_results = {};

    for tnum=1:size(gammatonegram_inputs)(1)
        [name, wave, fs, twin, thop, chs, fmin] = deal(gammatonegram_inputs{tnum,:});
        res = gammatonegram( ...
                  wave, ...
                  fs, ...
                  twin, ...
                  thop, ...
                  chs, ...
                  fmin, ...
                  0, % fmax is ignored
                  0 % Don't use FFT method
              );

        % This is for mocking the output of the equivalent Python functions
        nwin     = round(twin * fs);
        hopsamps = round(thop * fs);
        f_coefs  = flipud(MakeERBFilters(fs, chs, fmin));
        x_f      = ERBFilterBank(wave, f_coefs);
        x_e      = [x_f .^ 2];
        x_e_cols = size(x_e, 2);
        ncols    = 1 + floor((x_e_cols - nwin) / hopsamps);

        % Mock out the ERB filter functions too
        fcoefs = flipud(MakeERBFilters(fs, chs, fmin));
        erb_fb_output = ERBFilterBank(wave, fcoefs);

        gammatonegram_mocks(tnum, :) = { ...
            erb_fb_output, ...
            x_e_cols ...
        };

        gammatonegram_results(tnum, :) = { ...
            res, ...
            nwin, ...
            hopsamps, ...
            ncols ...
        };

    end;

    results_file = fullfile('..', 'tests', 'data', 'test_gammatonegram_data.mat');
    save(results_file, 'gammatonegram_inputs', 'gammatonegram_mocks', 'gammatonegram_results');
end;


function c = long2intval(C)
%LONG2INTVAL  Conversion long to intval (with correct rounding)
%
%  c = long2intval(C)
%

% written  12/30/98     S.M. Rump
% modfied  02/09/00     S.M. Rump  rounding unchanged after use
% modified 04/04/04     S.M. Rump  set round to nearest for safety
% modified 04/06/05     S.M. Rump  rounding unchanged
% modified 07/31/05     S.M. Rump  header corrected
% modified 11/20/05     S.M. Rump  fast check for rounding to nearest
% modified 08/26/12     S.M. Rump  global variables removed
%

  e = 1e-30;
  if 1+e==1-e                           % fast check for rounding to nearest
    rndold = 0;
  else
    rndold = getround;
    setround(0)
  end

  INTLAB_LONG_BETA = getappdata(0,'INTLAB_LONG_BETA');
  INTLAB_LONG_LOGBETA = getappdata(0,'INTLAB_LONG_LOGBETA');
  INTLAB_LONG_ERROR = getappdata(0,'INTLAB_LONG_ERROR');

  % extra treatment of zero component
  indexzero = ( C.exponent==-inf );

  n = size(C.mantissa,1);
  % take maximum first 80 bits
  precC = size(C.mantissa,2);
  p = min( precC , ceil(80/INTLAB_LONG_LOGBETA)+1 );
  if INTLAB_LONG_ERROR
    if p<precC
      C.error = errorupdate( 1 , C.error , 0 , ...
                  1 , any(C.mantissa(:,p+1:precC)~=0,2) , C.exponent-precC );
    end
    Cerr = C.error.mant .* INTLAB_LONG_BETA.^(C.error.exp-C.exponent+p);
  else
    Cerr = 0;
  end

  factor = ( INTLAB_LONG_BETA.^(-p:-1) )';
  exppos = ( C.exponent>=0 );
  expneg = ~exppos;
  E = floor( 600/INTLAB_LONG_LOGBETA );
  F = INTLAB_LONG_BETA ^ E;

  Cmantp = C.mantissa(:,p);
  setround(-1)
  C.mantissa(:,p) = Cmantp - Cerr;
  cinf = C.mantissa(:,p:-1:1) * factor ;
  if any(exppos)
    cinf(exppos) = ( cinf(exppos)*F ) .* ...
                      ( INTLAB_LONG_BETA.^(C.exponent(exppos)-E) );
  end
  if any(expneg)
    cinf(expneg) = ( cinf(expneg)/F ) .* ...
                      ( INTLAB_LONG_BETA.^(C.exponent(expneg)+E) );
  end

  setround(1)
  C.mantissa(:,p) = Cmantp + Cerr;
  csup = C.mantissa(:,p:-1:1) * factor ;
  if any(exppos)
    csup(exppos) = ( csup(exppos)*F ) .* ...
                      ( INTLAB_LONG_BETA.^(C.exponent(exppos)-E) );
  end
  if any(expneg)
    csup(expneg) = ( csup(expneg)/F ) .* ...
                      ( INTLAB_LONG_BETA.^(C.exponent(expneg)+E) );
  end
  if INTLAB_LONG_ERROR & any(indexzero)
    csup(indexzero) = C.error.mant(indexzero) .* ...
                        INTLAB_LONG_BETA.^C.error.exp(indexzero);
    cinf(indexzero) = - csup(indexzero);
  end

  c = hull( C.sign.*cinf , C.sign.*csup );

  setround(rndold)


function [ft3] = m32ft3(m3)
% Convert volume from cubic meters to cubic feet.
% Chad Greene 2012
ft3 = m3*35.314666721;


function [Rsp,U,V]=standardUVBeamPattern(T,xyPoints,normVals,Sigma,lineParams,bounds,numPoints)
%%STANDARDUVBEAMPATTERN Compute the beam pattern of a tapered array as a
%                       function of direction given in terms of direction
%                       cosines for a narrowband linear or planar array.
%                       The beam pattern is just the sum of all of the
%                       tapered elements taken for signals in different
%                       directions. This function can output the response
%                       over all (-1,+1) u-v values or in a rectangular
%                       subset. It can also output a linear cut across the
%                       values.
%
%INPUTS: T The numSubarraysXnumElements tapering matrix of the array. If
%          there are no subarrays, then this can be a numElementsX1
%          vector of weights for every element. The weights can be complex,
%          which means that difference beams can be formed and steering can
%          be taken into account. If an empty matrix is passed, then it is
%          assumed that no tapering is used so T will be a 1XnumElements
%          vector of all ones.
% xyPoints A 1XNumDim or 2XnumDim matrix of the [x;y] locations of the
%          points in the linear or planar array. The units of the distances
%          are in terms of wavelengths for the narrowband model.
% normVals This indicates how the sum beam value should be normalized.
%          Possible values are:
%          'ArrayGain' Return the ratio of the output power to the noise
%                      power. This is the default if this parameter is
%                      omitted or an empty matrix is passed.
%          'NormPowGain' Return the power of the output normalized such
%                        that the highest value is 1.
%          'AbsPowGain' Return the power of the output. This assumes that
%                       the tapering matrix contains the true gain or loss
%                       values for the tapering and is thus not scaled by
%                       any constant value.
%          'NormRealVal' Display the normalized real component of the
%                       output value. It is normalized such that the
%                       largest absolute value is one. Note that this is
%                       not squared, so it corresponds to an output
%                       voltage, not a power.
%           'RawOutput' Provide the raw sum beam output.
%   Sigma If the array gain is desired (normVals='ArrayGain'), then this
%         parameter is used. This is the numElsXnumEls covariance matrix of
%         the noise at the individual elements in the array. If this
%         parameter is omitted or an empty matrix is passed, then the
%         identity matrix will be used.
% lineParams If xyPoints is a 2XnumDims set of points (for a planar array),
%         then if this parameter is provided and is not an empty matrix,
%         Rsp will be a 1D cut across u and v values rather than all u and
%         v values. The equation for the line along with the beam pattern
%         will be evaluated is v=lineParams.intercept+lineParams.slope*u if
%         the value lineParams.vIndep=false or the vIndep component of
%         lineParams is omitted. Otherwise, the line is
%         u=lineParams.intercept+lineParams.slope*v .
%  bounds A 2X1 (or 1X2) or a 4X1 (or 1X4) vector with the bounds in u and
%         v of the plot. For 1-dimensional plots, which are the case if
%         xyPoints is 1XnumDim or lineParams is provided and xyPoints is
%         2XnumDim, then bounds=[minVal;maxVal] for the independent
%         variable. For two-dimensional plots, then
%         bounds=[minU;maxU;minV;maxV]. If this parameter is omitted or an
%         empty matrix is passed, then [-1;1;-1;1] is used to go over all
%         possible values in u and v (or just u for a 1D plot).
% numPoints A parameter determining the size of the output matrix. For 1D
%         plots, Rsp is numPointsX1. For 2D plots, Rsp is
%         numPointsXnumPoints. If this parameter is omitted or an empty
%         matrix is passed, then a default of numPoints=125 points is used.
%
%OUTPUTS: Rsp The array beam pattern over the selected region, normalized
%             as specified. The value in entry Rsp(i,j) corresponds to the
%             U and V values U(i,j) and V(i,j). For a 1D response for a
%             linear array, Rsp(i) corresponds to U(i) and if xyPoints is
%             2XnumDims, V(i) is the corresponding v value. The value of
%             Rsp for points outside of the visible region (u^2+v^2>1)
%             is set to zero.
%           U A matrix of points corresponding to the u values of the
%             responses in Rsp.
%           V A matrix of points corresponding to the v values of the
%             responses in Rsp. For 1D responses,
%
%The idea of a beam pattern for a narrowband array is discussed in Chapter
%2.2 of [1]. The array gain is discussed in Chapter 2.6.2.
%
%EXAMPLE 1:
%Here, we find the array gain beam pattern of a 20 element 1D linear array
%with Taylor tapering and half-wavelength element spacing. When consdiering
%the array gain, it does not matter that the elements are not provided
%centered about the origin. However, the points must be centered to get the
%proper tapering values from the TaylorLinearTapering function.
% xPoints=0:0.5:9.5;
% xPoints=xPoints-mean(xPoints);
% nBar=3;
% sidelobedB=-25;
% T=TaylorLinearTapering(nBar,sidelobedB,xPoints).';
% [Rsp,U]=standardUVBeamPattern(T,xPoints);
% figure(1)
% clf
% plot(U,10*log10(Rsp),'linewidth',2)
% axis([-1 1 -30 15])
% axis square
% h1=xlabel('u');
% h2=ylabel('Array Gain');
% title('Array Power Gain in Decibels')
% set(gca,'FontSize',14,'FontWeight','bold','FontName','Times')
% set(h1,'FontSize',14,'FontWeight','bold','FontName','Times')
% set(h2,'FontSize',14,'FontWeight','bold','FontName','Times')
%
%EXAMPLE 2:
%In this example, we plot the normalized power gain of a 2D hexagonal array
%without any tapering.
% xyPoints=getShaped2DLattice([7;14],'hexagonal');
% [Rsp,U,V]=standardUVBeamPattern([],xyPoints,'NormPowGain');
% figure(2)
% clf
% surface(U,V,10*log10(Rsp),'EdgeColor','None')
% axis([-1 1 -1 1 -40 0])
% caxis([-40 0])
% colormap(jet(256))
% colorbar()
% view(45,45)
% light()
% h1=xlabel('u');
% h2=ylabel('v');
% h3=zlabel('Array Gain');
% title('Array Power Gain in Decibels')
% set(gca,'FontSize',14,'FontWeight','bold','FontName','Times')
% set(h1,'FontSize',14,'FontWeight','bold','FontName','Times')
% set(h2,'FontSize',14,'FontWeight','bold','FontName','Times')
% set(h3,'FontSize',14,'FontWeight','bold','FontName','Times')
%
%EXAMPLES 3:
%In this example, we plot the difference pattern of a circular array.
%First, we plot the normalized real value of the pattern (the pattern is
%real anyway so this is not an issue) in 2D and then we take 1D cuts of it
%in two different directions. Bayliss tapering are used to obtain the
%difference pattern.
% xyPoints=getShaped2DLattice([30;30],'circular');
% sidelobedB=-30;
% N=17;
% T=BaylissTapering(sidelobedB,N,xyPoints).';
% [Rsp,U,V]=standardUVBeamPattern(T,xyPoints,'NormRealVal');
% figure(3)
% clf
% surface(U,V,Rsp,'EdgeColor','None')
% axis([-1 1 -1 1 -1 1])
% caxis([-1 1])
% colormap(jet(256))
% colorbar()
% view(45,10)
% light()
% h1=xlabel('u');
% h2=ylabel('v');
% h3=zlabel('Real Response');
% title('Array Difference  Beam Pattern')
% set(gca,'FontSize',14,'FontWeight','bold','FontName','Times')
% set(h1,'FontSize',14,'FontWeight','bold','FontName','Times')
% set(h2,'FontSize',14,'FontWeight','bold','FontName','Times')
% set(h3,'FontSize',14,'FontWeight','bold','FontName','Times')
%
% %Now, we take a cut along to v=0 line.
% lineParams=[];
% lineParams.intercept=0;
% lineParams.slope=0;
% lineParams.vIndep=false;
%
% [Rsp,U]=standardUVBeamPattern(T,xyPoints,'NormRealVal',[],lineParams);
% figure(4)
% clf
% plot(U,Rsp,'linewidth',2)
% h1=xlabel('u');
% h2=ylabel('Real Response');
% title('Array Difference Beam Pattern')
% set(gca,'FontSize',14,'FontWeight','bold','FontName','Times')
% set(h1,'FontSize',14,'FontWeight','bold','FontName','Times')
% set(h2,'FontSize',14,'FontWeight','bold','FontName','Times')
%
% %And here we take a cut along the u=0 line.
% lineParams.vIndep=true;
%
% [Rsp,~,V]=standardUVBeamPattern(T,xyPoints,'NormRealVal',[],lineParams);
% figure(5)
% clf
% plot(V,Rsp,'linewidth',2)
% h1=xlabel('v');
% h2=ylabel('Real Response');
% title('Array Difference Beam Pattern')
% set(gca,'FontSize',14,'FontWeight','bold','FontName','Times')
% set(h1,'FontSize',14,'FontWeight','bold','FontName','Times')
% set(h2,'FontSize',14,'FontWeight','bold','FontName','Times')
%
%EXAMPLE 4:
%This is an example of using elements of a circular array with a fixed
%Taylor tapering that have been broken into subarrays. We then try to form
%the best approximation to a Bayliss difference pattern modifying only the
%subarray outputs. We also demonstrate how steering can be used to move the
%difference beam away from the center of the array.
% xyPoints=getShaped2DLattice([30;30],'circular');
% numEls=size(xyPoints,2);
% %Fixed element-level tapering.
% sidelobedB=-30;
% nBar=4;
% g=TaylorTapering(nBar,sidelobedB,xyPoints);
% %It is assumed the disjoint subarrays can be formed (no adjacency matrix
% %used).
% numLevels=3;
% N=17;
% T=double(findBaylissSubarrays(xyPoints,numLevels,sidelobedB,N));
% %We now apply the tapering to the matrix
% T=bsxfun(@times,T,g.');
%
% %The desired element-level tapering
% g=BaylissTapering(sidelobedB,N,xyPoints);
%
% %Next, we try to find the best subarray weights to approximate the desired
% %tapering. We specifically add a null at the boresight.
% g=findSubarrayWeights(T,g,ones(numEls,1));
%
% %Apply the tapering to the elements
% T=bsxfun(@times,g,T);
%
% %We also steer the array off boresight to u0. This is element-level
% %steering.
% u0=[-0.5;0.5];
% D=diag(exp(1j*2*pi*sum(bsxfun(@times,xyPoints,u0),1)));
% T=T*D;
%
% [Rsp,U,V]=standardUVBeamPattern(T,xyPoints,'NormRealVal');
% figure(3)
% clf
% surface(U,V,Rsp,'EdgeColor','None')
% axis([-1 1 -1 1 -1 1])
% caxis([-1 1])
% colormap(jet(256))
% colorbar()
% view(45,10)
% light()
% h1=xlabel('u');
% h2=ylabel('v');
% h3=zlabel('Real Response');
% title('Array Difference  Beam Pattern')
% set(gca,'FontSize',14,'FontWeight','bold','FontName','Times')
% set(h1,'FontSize',14,'FontWeight','bold','FontName','Times')
% set(h2,'FontSize',14,'FontWeight','bold','FontName','Times')
% set(h3,'FontSize',14,'FontWeight','bold','FontName','Times')
%
%REFERENCES:
%[1] H. L. Van Trees, Optimum Array Processing. New York: Wiley-
%    Interscience, 2002.
%
%August 2016 David F. Crouse, Naval Research Laboratory, Washington D.C.
%(UNCLASSIFIED) DISTRIBUTION STATEMENT A. Approved for public release.

numDim=size(xyPoints,1);
numEls=size(xyPoints,2);

if(isempty(T))
   T=ones(1,numEls);
end

if(nargin<7||isempty(numPoints))
   numPoints=125;
end

if(nargin<6||isempty(bounds))
    if(numDim==1)
        bounds=[-1;1];
    else
        bounds=[-1;1;-1;1];
    end
end

if(nargin<5||isempty(lineParams))
    if(numDim>1)
        %If a 2D plot is desired.
        uVals=linspace(bounds(1),bounds(2),numPoints);
        vVals=linspace(bounds(3),bounds(4),numPoints);
        [U,V]=meshgrid(uVals,vVals);
        Rsp=zeros(numPoints,numPoints);

        if(isvector(T))
            for curVal=1:(numPoints*numPoints)
                u=[U(curVal);V(curVal)];
                if(u'*u>1)
                    continue;
                end

                Rsp(curVal)=T*exp(-1j*2*pi*sum(bsxfun(@times,xyPoints,u),1)).';
            end
        else
            for curVal=1:(numPoints*numPoints)
                u=[U(curVal);V(curVal)];
                if(u'*u>1)
                    continue;
                end

                Rsp(curVal)=sum(sum(T*exp(-1j*2*pi*sum(bsxfun(@times,xyPoints,u),1)).'));
            end
        end
    else
        %If a 1D plot is required.
        U=linspace(bounds(1),bounds(2),numPoints)';
        V=[];

        if(isvector(T))
            Rsp=zeros(numPoints,1);
            for curVal=1:numPoints
                if(abs(U(curVal))>1)
                    continue;
                end

                Rsp(curVal)=T*exp(-1j*2*pi*xyPoints*U(curVal)).';
            end
        else
            Rsp=zeros(numPoints,1);
            for curVal=1:numPoints
                if(abs(U(curVal))>1)
                    continue;
                end

                Rsp(curVal)=sum(T*exp(-1j*2*pi*xyPoints*U(curVal)).');
            end
        end
    end
else
    %If a 1D cut across the 2D surface is desired. The
    slope=lineParams.slope;
    intercept=lineParams.intercept;
    if(isfield(lineParams,'vIndep'))
        vIndep=lineParams.vIndep;
    else
        vIndep=false;
    end

    if(vIndep==false)
        %The independent variable is u.
        U=linspace(bounds(1),bounds(2),numPoints)';
        V=zeros(numPoints,1);
        Rsp=zeros(numPoints,1);

        if(isvector(T))
            for curVal=1:numPoints
                V(curVal)=intercept+slope*U(curVal);
                uVec=[U(curVal);V(curVal)];

                if(uVec'*uVec>1)
                    continue;
                end

                Rsp(curVal)=T*exp(-1j*2*pi*sum(bsxfun(@times,xyPoints,uVec),1)).';
            end
        else
            for curVal=1:numPoints
                V(curVal)=intercept+slope*U(curVal);
                uVec=[U(curVal);V(curVal)];

                if(uVec'*uVec>1)
                    continue;
                end

                Rsp(curVal)=sum(sum(T*exp(-1j*2*pi*sum(bsxfun(@times,xyPoints,uVec),1)).'));
            end
        end
    else
        %The independent variable is v.
        V=linspace(bounds(1),bounds(2),numPoints)';
        U=zeros(numPoints,1);
        Rsp=zeros(numPoints,1);

        if(isvector(T))
             for curVal=1:numPoints
                U(curVal)=intercept+slope*V(curVal);
                uVec=[U(curVal);V(curVal)];

                if(uVec'*uVec>1)
                    continue;
                end

                Rsp(curVal)=T*exp(-1j*2*pi*sum(bsxfun(@times,xyPoints,uVec),1)).';
            end
        else
            for curVal=1:numPoints
                U(curVal)=intercept+slope*V(curVal);
                uVec=[U(curVal);V(curVal)];

                if(uVec'*uVec>1)
                    continue;
                end

                Rsp(curVal)=sum(sum(T*exp(-1j*2*pi*sum(bsxfun(@times,xyPoints,uVec),1)).'));
            end
        end
    end
end

if(nargin<3||isempty(normVals))
    normVals='ArrayGain';
end

switch(normVals)
    case 'ArrayGain'%Array power gain versus spatially white noise.
        if(nargin<4||isempty(Sigma))
           Sigma=eye(numEls,numEls);
        end

        if(isvector(T))
            Rsp=abs(Rsp).^2/sum(T*Sigma*T');
        else

            numSubarrays=size(T,1);
            e=ones(numSubarrays,1);
            %The sum sums up all of the subarray outputs.
            Rsp=abs(Rsp).^2/sum(e'*T*Sigma*T'*e);
        end
    case 'NormPowGain'%Normalized absolute array power gain
        Rsp=abs(Rsp);
        Rsp=(Rsp/max(Rsp(:))).^2;%Make it relative to the peak.
    case 'AbsPowGain'
        Rsp=abs(Rsp)^2;
    case 'NormRealVal'%Display the real component of the response.
        Rsp=real(Rsp);
        Rsp=Rsp/max(Rsp(:));%Make it relative to the peak.
    case 'RawOutput'
    otherwise
        error('Unknown plot type requested')
end
end

%LICENSE:
%
%The source code is in the public domain and not licensed or under
%copyright. The information and software may be used freely by the public.
%As required by 17 U.S.C. 403, third parties producing copyrighted works
%consisting predominantly of the material produced by U.S. government
%agencies must provide notice with such work(s) identifying the U.S.
%Government material incorporated and stating that such material is not
%subject to copyright protection.
%
%Derived works shall not identify themselves in a manner that implies an
%endorsement by or an affiliation with the Naval Research Laboratory.
%
%RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF THE
%SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY THE NAVAL
%RESEARCH LABORATORY FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE ACTIONS
%OF RECIPIENT IN THE USE OF THE SOFTWARE.


function Y = variantMultiply( psfMatData, X, padsize );
%
%           Y = variantMultiply( psfMatData, X, padsize );
%
%  This function computes the multiplication of a spatially variant
%  point spread function (PSF) times an image:
%                y = A*x
%
%  Here we assume A is made up of a several space invariant PSFs, and
%  use piece-wise constant interpolation of them to define the spatially
%  variant PSF.  That is, A has the form:
%
%       A = D1*A1 + D2*A2 + ... + Dp*Ap
%
%  Input:
%   psfMatData  -  cell array containing the matrix data of each of the
%                  individual PSFs.  This matrix data is usuall computed
%                  from onePsfMatrix.m
%            X  -  array containing the image to which the psfMatrix
%                  is to be multiplied.
%
%  Output:
%            Y  -  contains the result after PSF multiplication.
%

%  J. Nagy 1/7/02

imsize = size( X ) - 2*padsize;

%
%  We partition the image domain into regions of equal sizes,
%  according to the number of PSFs we have ...
%
nregions = size(psfMatData);
rsize = ceil(imsize ./ nregions);

%
%  In order for this to be consistent for 2-D and 3-D images, we need to make
%  sure there is a third dimension ...
%
if length(imsize) == 1
  imsize = [imsize, 1, 1];
  rsize = [rsize, 1, 1];
  nregions = [nregions, 1, 1];
  padsize = [padsize, 0, 0];
elseif length(imsize) == 2
  imsize = [imsize, 1];
  rsize = [rsize, 1];
  nregions = [nregions, 1];
  padsize = [padsize, 0];
end

%
%  Coding the rest of this will be easier if all of the image subregions
%  have the same dimensions.  If it's not, we pad with a few zeros to make
%  it so ...
%
padsize1 = rsize .* nregions - imsize;
if any( padsize1 < 0 )
  error('Something is wrong here ...')
end
X = padarray(X, padsize1, 'post');

%
%  Now we get information about beginning and ending indices of subregions
%  so we can "put" and "get" subregions correctly ...
%
[RIidx, RJidx, RKidx] = region_indices( nregions, rsize );
[EIidx, EJidx, EKidx] = eregion_indices( RIidx, RJidx, RKidx, 2*padsize );

%
%  Now loop over all the subregions ...
%
Y = zeros(imsize);
for k = 1:nregions(3)
  for j = 1:nregions(2)
    for i = 1:nregions(1)
      Xt = X(EIidx(i,1):EIidx(i,2), EJidx(j,1):EJidx(j,2), EKidx(k,1):EKidx(k,2));
      Yt = invariantMultiply( psfMatData{i,j,k}, Xt, padsize(1:length(size(X))) );
      Y(RIidx(i,1):RIidx(i,2), RJidx(j,1):RJidx(j,2), RKidx(k,1):RKidx(k,2)) = Yt;
    end
  end
end

Y = Y(1:imsize(1), 1:imsize(2), 1:imsize(3));


function f = circconv(f, g)
%CONV   Circular convolution of TRIGTECH objects.
%   H = CIRCCONV(F, G) produces the convolution of TRIGTECH objects F and G:
%                     -
%                    /
%           H(x) =   |    F(t) G(x-t) dt,  x in [-pi, pi]
%                    /
%                   -
%   Note that CIRCCONV only supports smooth periodic functions on [-pi,pi].
%
%   Example:
%     f = trigtech(@(x) exp(cos(40*pi*x)));
%     g = trigtech(@(x) exp(-(20*x).^2);
%     h = circconv(f,g);
%     plot(h);

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

% Return empty for an empty input:
if ( isempty(f) || isempty(g) )
    f = trigtech();
    return
end

% No support for array-valued trigtech objects:
if ( (size(f, 2) > 1) || (size(g, 2) > 1) )
    error('CHEBFUN:TRIGTECH:conv:array', ...
        'No support for array-valued TRIGTECH objects.');
end

% Get the sizes of the TRIGTECH objects
nf = size(f.coeffs, 1);
ng = size(g.coeffs, 1);

% Make the TRIGTECH objects the same length.
if ( nf > ng )
    % Increase the length of g (via PROLONG):
    g = prolong(g, nf);
elseif ( nf < ng )
    % Increase the length of f (via PROLONG):
    f = prolong(f, ng);
end
n = size(f.coeffs,1);

% Convolution is just multiplication of the Fourier coefficients.
% Shift g horizontally to -1.
g = circshift(g,-1);
f.values = 2/n*ifft(fft(f.values).*fft(g.values));
f.coeffs = f.vals2coeffs(f.values);

% TODO:  Why do we simplify twice?  (Once here and once below.)
f = simplify(f);

f.ishappy = f.ishappy && g.ishappy;
f.isReal = f.isReal && g.isReal;  % Are you real happy though?

f.values(:,f.isReal) = real(f.values(:,f.isReal));

if ( f.ishappy )
    f = simplify(f);
end

end


classdef BT8 < PROBLEM
% <multi> <real> <large/none>
% Benchmark MOP with bias feature

%------------------------------- Reference --------------------------------
% H. Li, Q. Zhang, and J. Deng, Biased multiobjective optimization and
% decomposition algorithm, IEEE Transactions on Cybernetics, 2017, 47(1):
% 52-66.
%------------------------------- 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".
%--------------------------------------------------------------------------

    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
        function PopObj = CalObj(obj,X)
            [N,D] = size(X);
            I1    = 2 : 2 : D;
            I2    = 3 : 2 : D;
            Y     = X - repmat(X(:,1),1,D).^(0.5+1.5*repmat(0:D-1,N,1)/(D-1));
            DY    = Y.^2 + (1-exp(-Y.^2/1e-3))/5;
            PopObj(:,1) = X(:,1)         + sum(4*DY(:,I1).^2-cos(8*pi*DY(:,I1))+1,2);
            PopObj(:,2) = 1-sqrt(X(:,1)) + sum(4*DY(:,I2).^2-cos(8*pi*DY(:,I2))+1,2);
        end
        %% Generate points on the Pareto front
        function R = GetOptimum(obj,N)
            R(:,1) = linspace(0,1,N)';
            R(:,2) = 1 - R(:,1).^0.5;
        end
        %% Generate the image of Pareto front
        function R = GetPF(obj)
            R = obj.GetOptimum(100);
        end
    end
end


function [ know, x ] = p18_sol ( n )

%*****************************************************************************80
%
%% P18_SOL returns the solution for problem 18.
%
%  Discussion:
%
%    The solution values are taken from Brent.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    26 February 2002
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer N, the order of the problem.  This value
%    is only needed for those problems with variable N.
%
%    Output, integer KNOW.
%    If KNOW is 0, then the solution is not known.
%    If KNOW is positive, then the solution is known, and is returned in X.
%
%    Output, real X(N), the solution, if known.
%
  if ( n == 2 )
    know = 1;
    x = [ 0.2113249, 0.7886751 ]';
  elseif ( n == 4 )
    know = 1;
    x = [ 0.1026728, 0.4062037, 0.5937963, 0.8973272 ]';
  elseif ( n == 6 )
    know = 1;
    x = [ 0.066877, 0.288741, 0.366682, 0.633318, ...
      0.711259, 0.933123 ]';
  elseif ( n == 8 )
    know = 1;
    x = [ 0.043153, 0.193091, 0.266329, 0.500000, ...
      0.500000, 0.733671, 0.806910, 0.956847 ]';
  else
    know = 0;
    x = zeros ( n, 1 );
  end

  return
end


function [lm lm_avg] = rcu_ach(n, delta, epsil, plow, pup);
% Compute RCU achievability bound.
% lm returns the bound valid for maximal probability of error
% lm_avg is for the average
%
% This is not a vectorized version, because the function is really slow.
% You can speed it up significantly if you provide a bracket plow, pup for the value of logm.
% For example, a smart idea is to set
% plow = gallager_ach(n, delta, epsil) and pup = converse(n,delta,epsil);

if nargin < 5
	plow = 0;
	pup = n;
end

eps_test = precise_rand(n, delta, pup);
if(eps_test < epsil)
	disp(sprintf([	'-- achiev_prand(n = %d, delta = %g, epsil = %g): eps_test = %g\n'...
			'        This is a bug? precise_rand() contradicts converse ?!?!'], ...
			n, delta, epsil, eps_test));
	error('achiev_prand');
	lm_avg = 0; lm = 0;
	return;
end

eps_test = precise_rand(n, delta, plow);
if(eps_test > epsil)
	disp(sprintf([	'-- achiev_prand(n = %d, delta = %g, epsil = %g): eps_test = %g\n'...
			'        Can not find lower bound for precise_rand() !!!!'], ...
			n, delta, epsil, eps_test));
	%error('achiev_prand');
	lm_avg = 0; lm = 0;
	return;
end

% Take into account that we are computing AVERAGE prob. of error,
% and so we need a random linear code trick to go to maximum => log M must be integer
while floor(plow) < floor(pup);
	ptest = (plow + pup)/2;
	eps_test = precise_rand(n, delta, ptest);
	if(eps_test > epsil)
		pup = ptest;
	else
		plow = ptest;
		% This is not needed as we stop on floor-test
		%if  (epsil-eps_test)< 1e-2*epsil
		%	break;
		%end
	end
end
lm_avg = plow;
lm = floor(plow);


function plotc(x,y,v,marker)
%FUNCTION PLOTC(X,Y,V,'MARKER') plots the values of v colour coded
% at the positions specified by x and y, and v (z-axis) in a 3-D axis
% system. A colourbar is added on the right side of the figure.
%
% The colorbar strectches from the minimum value of v to its
% maximum in 9 steps (10 values).
%
% The last argument is optional to define the marker being used. The
% default is a point. To use a different marker (such as circles, ...) send
% its symbol to the function (which must be enclosed in '; see example).
%
% The plot is actually a 3D plot but the orientation of the axis is set
% such that it appears to be a plane 2D plot. However, you can toggle
% between 2D and 3D view either by using the command 'view(3)' (for 3D
% view) or 'view(2)' (for 2D), or by interactively rotating the axis
% system.
%
% Example:
% Define three vectors
%    x=1:10;y=1:10;p=randn(10,1);
%    plotc(x,y,p)
%
%    x=randn(100,1);
%    y=2*x+randn(100,1);
%    p=randn(100,1);
%    plotc(x,y,p,'d')
%    view(3)
%
% Uli Theune, University of Alberta, 2004
% modified by Stephanie Contardo, British OCeanographic Data Centre, 2006
%

delete(gca)
if nargin <4
    marker='.';
end

map=colormap;
miv=min(v);
mav=max(v);
clrstep = (mav-miv)/size(map,1) ;
% Plot the points
hold on
for nc=1:size(map,1)
    iv = find(v>miv+(nc-1)*clrstep & v<=miv+nc*clrstep) ;
    plot3(x(iv),y(iv),v(iv),marker,'color',map(nc,:),'markerfacecolor',map(nc,:))
end
hold off

% Re-format the colorbar
h=colorbar;

set(h,'ylim',[1 length(map)]);
yal=linspace(1,length(map),10);
set(h,'ytick',yal);
% Create the yticklabels
ytl=linspace(miv,mav,10);
s=char(10,4);
for i=1:10
    if min(abs(ytl)) >= 0.001
        B=sprintf('%-4.3f',ytl(i));
    else
        B=sprintf('%-3.1E',ytl(i));
    end
    s(i,1:length(B))=B;
end
set(h,'yticklabel',s);
grid on
view(2)


% GSPBOX - Graphs
%
%  Specific graphs
%    gsp_swiss_roll              -  Create swiss roll graph
%    gsp_david_sensor_network    -  Create the sensor newtwork from david
%    gsp_ring                    -  Create the ring graph
%    gsp_path                    -  Create the path graph
%    gsp_airfoil                 -  Create the airfoil graph
%    gsp_comet                   -  Create the comet graph
%    gsp_erdos_renyi             -  Create a erdos renyi graph
%    gsp_minnesota               -  Create Minnesota road graph
%    gsp_low_stretch_tree        -  Create a low stretch tree graph
%    gsp_sensor                  -  Create a random sensor graph
%    gsp_random_regular          -  Create a random regular graph
%    gsp_random_ring             -  Create a random ring graph
%    gsp_full_connected          -  Create a fully connected graph
%    gsp_nn_graph                -  Create a nearest neighbors graph
%    gsp_rmse_mv_graph           -  Create a nearest neighbors graph with missing values
%    gsp_sphere                  -  Create a spherical-shaped graph
%    gsp_cube                    -  Create a cubical-shaped graph
%    gsp_2dgrid                  -  Create a 2d-grid graph
%    gsp_torus                   -  Create a torus graph
%    gsp_logo                    -  Create a GSP logo graph
%    gsp_community               -  Create a community graph
%    gsp_bunny                   -  Create a bunny graph
%    gsp_spiral                  -  Create a spiral graph
%    gsp_stochastic_block_graph  -  Create a graph with the stochastic block model
%
%  Hypergraphs
%    gsp_nn_hypergraph           -  Create an hyper nearest neighbor graph
%    gsp_hypergraph              -  Create an hypergraph
%
%  Utils
%    gsp_graph_default_parameters-  Initialise all parameters for a graph
%    gsp_graph_default_plotting_parameters-  Initialise all plotting parameters for a graph
%    gsp_graph                   -  Create a graph from a weight matrix
%    gsp_update_weights          -  Update the weights of a graph
%    gsp_update_coordinates      -  Update the coordinate of a graph
%    gsp_components              -  Cuts non connected graph into several connected ones
%    gsp_subgraph                -  Create a subgraph
%    gsp_graph_product           -  Compute graph product between two graphs
%    gsp_line_graph              -  Create the Line Graph (or edge-to-vertex dual graph) of a graph
%    gsp_jtv_graph               -  Add time information to the graph structure
%
%
%  For help, bug reports, suggestions etc. please send email to
%  gspbox 'dash' support 'at' groupes 'dot' epfl 'dot' ch
%


function Wop = normalize_standardize_threshold_wavelet_factory_1d(N,filter_options,scat_options,epsilon)

if nargin <4
    epsilon =2^(-20);
end

filters = filter_bank(N, filter_options);

ren_op=@(X)(func_output(...
            @renorm_wavelet_layer_1d,[1,2],X,epsilon));

std_op= @(X,m)(func_output(...
            @standardize_wavelet_layer_1d,[1,2],X,scat_options.sigmas{m+1}));

	for m = 0:scat_options.M
		filt_ind = min(numel(filters), m+1);
        if m<scat_options.M
		Wop{m+1} = @(X)(threshold_wavelet_layer_1d(...
            std_op(...
            ren_op(func_output(@wavelet_layer_1d,[1,2],X,...
            filters{filt_ind},scat_options)),m),scat_options.threshold));
        else
        Wop{m+1} = @(X)(threshold_wavelet_layer_1d(...
                      ren_op(func_output(@wavelet_layer_1d,[1,2],X,...
            filters{filt_ind},scat_options)),scat_options.threshold));
	end

end


function L = probitNoiseLikelihood(noise, mu, varsigma, y)

% PROBITNOISELIKELIHOOD Likelihood of the data under the PROBIT noise model.
% FORMAT
% DESC returns the likelihood of a data set under the  probit based classification noise model.
% ARG noise : the noise structure for which the likelihood is required.
% ARG mu : input mean locations for the likelihood.
% ARG varSigma : input variance locations for the likelihood.
% ARG y : target locations for the likelihood.
%
% SEEALSO : probitNoiseParamInit, probitNoiseLogLikelihood, noiseLikelihood
%
% COPYRIGHT : Neil D. Lawrence, 2004, 2005

% NOISE

D = size(y, 2);
for i = 1:D
  mu(:, i) = mu(:, i) + noise.bias(i);
end
L = cumGaussian((y.*mu)./(sqrt(noise.sigma2+varsigma)));


function [ a, seed ] = r8vec_uniform ( n, b, c, seed )

%*****************************************************************************80
%
%% R8VEC_UNIFORM returns a scaled pseudorandom R8VEC.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    21 September 2006
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Paul Bratley, Bennett Fox, Linus Schrage,
%    A Guide to Simulation,
%    Springer Verlag, pages 201-202, 1983.
%
%    Bennett Fox,
%    Algorithm 647:
%    Implementation and Relative Efficiency of Quasirandom
%    Sequence Generators,
%    ACM Transactions on Mathematical Software,
%    Volume 12, Number 4, pages 362-376, 1986.
%
%    Peter Lewis, Allen Goodman, James Miller,
%    A Pseudo-Random Number Generator for the System/360,
%    IBM Systems Journal,
%    Volume 8, pages 136-143, 1969.
%
%  Parameters:
%
%    Input, integer N, the number of entries in the vector.
%
%    Input, real B, C, the range of the pseudorandom values.
%
%    Input, integer SEED, a seed for the random number generator.
%
%    Output, real A(N), the vector of pseudorandom values.
%
%    Output, integer SEED, an updated seed for the random number generator.
%
  if ( seed == 0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'R8VEC_UNIFORM - Fatal error!\n' );
    fprintf ( 1, '  Input SEED = 0!\n' );
    error ( 'R8VEC_UNIFORM - Fatal error!' );
  end

  r = zeros ( n, 1 );

  for i = 1 : n

    k = floor ( seed / 127773 );

    seed = 16807 * ( seed - k * 127773 ) - k * 2836;

    if ( seed < 0 )
      seed = seed + 2147483647;
    end

    a(i) = b + ( c - b ) * seed * 4.656612875E-10;

  end

  return
end


classdef IMMOEA_F7 < PROBLEM
% <multi> <real> <large/none>
% Benchmark MOP for testing IM-MOEA

%------------------------------- Reference --------------------------------
% R. Cheng, Y. Jin, K. Narukawa, and B. Sendhoff, A multiobjective
% evolutionary algorithm using Gaussian process-based inverse modeling,
% IEEE Transactions on Evolutionary Computation, 2015, 19(6): 838-856.
%------------------------------- 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".
%--------------------------------------------------------------------------

    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
        function PopObj = CalObj(obj,X)
            t = X(:,2:obj.D).^(1./(1+3*repmat(2:obj.D,size(X,1),1)/obj.D)) - repmat(X(:,1),1,obj.D-1);
            g = 1 + 9*mean(t.^2,2);
            PopObj(:,1) = 1 - exp(-4*X(:,1)).*sin(6*pi*X(:,1)).^6;
            PopObj(:,2) = g.*(1-(PopObj(:,1)./g).^2);
        end
        %% Generate points on the Pareto front
        function R = GetOptimum(obj,N)
            minf1  = min(1-exp(-4*(0:1e-6:1)).*(sin(6*pi*(0:1e-6:1))).^6);
            R(:,1) = linspace(minf1,1,N)';
            R(:,2) = 1 - R(:,1).^2;
        end
        %% Generate the image of Pareto front
        function R = GetPF(obj)
            R = obj.GetOptimum(100);
        end
    end
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Spherical Harmonic Modeling and Analysis Toolkit (SPHARM-MAT) is a 3D
% shape modeling and analysis toolkit.
% It is a software package developed at Shenlab in Center for Neuroimaging,
% Indiana University (SpharmMat@gmail.com, http://www.iupui.edu/~shenlab/)
% It is available to the scientific community as copyright freeware
% under the terms of the GNU General Public Licence.
%
% Copyright 2009, 2010, ShenLab, Center for Neuroimaging, Indiana University
%
% This file is part of SPHARM-MAT.
%
% SPHARM-MAT 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.
%
% SPHARM-MAT 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 SPHARM-MAT. If not, see <http://www.gnu.org/licenses/>.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% ============================================
% utl_signmatrix
%
% Goal: create signmatrix
% max_d is max degree
%
% Li Shen
% 01/14/2007 - create

function utl_sgm(max_d)
global sgm;

for d=1:max_d
    n = 2*d+1;
    M = (-1).^(1:n^2);
    sgm{d} = reshape(M,n,n);
end

return;


function [varargout]=cunique(A)

% function [A_uni,ind1,ind2,Ac]=cunique(A)
%-------------------------------------------------------------------------
%This function is similar to MATLAB's unique function. There are three
%differences: 1) An additional 4th optional output is available providing
%the count, or number of occurances, for each element in the input array.
%2) The 2nd output mathces the size of the first input, 3) The 3rd output
%is reshaped to be the size of the input variable.
%
% See also: unique
%
% Kevin Mattheus Moerman
% gibbon.toolbox@gmail.com
%
% 2018/03/21: Created
%-------------------------------------------------------------------------

%%

[A_uni,ind1,ind2]=unique(A);

varargout{1}=A_uni;
varargout{2}=reshape(ind1,size(A_uni));
varargout{3}=reshape(ind2,size(A));

if nargout==4
    [subInd] = ind2subn(size(A_uni),ind2);
    Ac=accumarray(subInd,ones(numel(ind2),1),size(A_uni));
    Ac=reshape(Ac(ind2),size(A));
    varargout{4}=Ac;
end


function bf = cubic_spline_fourier(f, a)

% The continuous Fourier transform of a cubic spline kernel.

bf = -(- 12*a + 12*exp(-pi*f*2i) + 12*exp(pi*f*2i) + 6*a*exp(-pi*f*4i) + ...
    6*a*exp(pi*f*4i) + f.*(pi*exp(-pi*f*2i)*12i) - f.*(pi*exp(pi*f*2i)*12i) + ...
    a*f.*(pi*exp(-pi*f*2i)*16i) - a*f.*(pi*exp(pi*f*2i)*16i) + ...
    a*f.*(pi*exp(-pi*f*4i)*4i) - a*f.*(pi*exp(pi*f*4i)*4i) - 24)./(16*f.^4*pi^4);

bf(f == 0) = 1;


function ip = inner_product_cdcf(xf, yf)

% Computes the inner product between two filters.

ip_cell = cellfun(@(xf, yf) real(2*(xf(:)' * yf(:)) - reshape(xf(:,end,:), [], 1, 1)' * reshape(yf(:,end,:), [], 1, 1)), xf, yf, 'uniformoutput', false');
ip = sum(cell2mat(ip_cell));

% ip_cell = cellfun(@(xf, yf) real(xf(:)' * yf(:)), xf, yf, 'uniformoutput', false');
% ip = sum(cell2mat(ip_cell));


function Y = multiherm(X)
% Returns the Hermitian parts of the matrices in the 3D matrix X
%
% function Y = multiherm(X)
%
% Y is a 3D matrix the same size as X. Each slice Y(:, :, i) is the
% Hermitian part of the slice X(:, :, i).
%
% See also: multiprod multitransp multihconj multiscale multiskew

% This file is part of Manopt: www.manopt.org.
% Original author: Hiroyuki Sato, April 27, 2015.
% Contributors:
% Change log:

    Y = .5*(X + multihconj(X));

end


%
% read_eccen_patch.m
%
% Original Author: Bruce Fischl
% CVS Revision Info:
%    $Author: nicks $
%    $Date: 2011/03/02 00:04:12 $
%    $Revision: 1.3 $
%
% Copyright © 2011 The General Hospital Corporation (Boston, MA) "MGH"
%
% Terms and conditions for use, reproduction, distribution and contribution
% are found in the 'FreeSurfer Software License Agreement' contained
% in the file 'LICENSE' found in the FreeSurfer distribution, and here:
%
% https://surfer.nmr.mgh.harvard.edu/fswiki/FreeSurferSoftwareLicense
%
% Reporting: freesurfer@nmr.mgh.harvard.edu
%

% Should run 'left or right' scripts to set up fname_* variable,s
% and set nfig so that plotting starts in the right location.
fclose('all');
fid=fopen(fname_patch,'rt');
s = fgetl(fid);
s = fgetl(fid);
[poly,count] = sscanf(s,'%d');
numvert = poly(1);
numquad = poly(2);
vertex_coordinates = zeros(3,1);
face_index = zeros(4,1);
vertx_list = zeros(numvert,3);
face_list = zeros(numquad,5);
tic;
for vert = 1:1:(numvert),
    s = fgetl(fid);
    vertx = sscanf(s,'%d');
    s = fgetl(fid);
    vertx_coordinates = sscanf(s,'%f');
    vertx_list(vert,:) = [vertx_coordinates(1:2)' vertx];
end;
toc
tic;
for face = 1:1:(numquad),
    s = fgetl(fid);
    facenum = sscanf(s,'%d');
    s = fgetl(fid);
    face_vertx = sscanf(s,'%d');
    face_list(face,:) = [face_vertx' facenum];
end;
toc
fclose(fid);
full_vertx=zeros(max(max(vertx_list))+1,3);
full_vertx(vertx_list(:,3)+1,1)=vertx_list(:,1);
full_vertx(vertx_list(:,3)+1,2)=vertx_list(:,2);
mesh_real=File2Var(fname_real);
vertx_values=zeros(max(max(vertx_list))+1,1);
vertx_values(vertx_list(:,3)+1)=mesh_real(:,5);
mesh_imag=File2Var(fname_imag);
vertx_complex=zeros(max(max(vertx_list))+1,1);
vertx_complex(vertx_list(:,3)+1)=mesh_imag(:,5);
v_complex = vertx_values(:,1) + i*vertx_complex;
%v_phase=angle(v_complex');

strpwd=pwd;
%subplot(4,3,nfig+1);
figure;
title([strpwd((length(strpwd)-25):length(strpwd)) ' ' fname_real]);
p_eccen_handle=patch('Vertices',full_vertx,'Faces',face_list(:,1:4)+1,'FaceVertexCData',angle(v_complex),'FaceColor','interp','EdgeColor','none');
%colormap(rgb(256));
colorbar;
%tic; t_unwrap=unwrap(angle(v_complex)); toc

short_complex = mesh_real(:,5) + (i*mesh_imag(:,5));
short_unwrap=angle(short_complex);
[zmat_eccen,xvec,yvec]=ffgrid(vertx_list(:,1),vertx_list(:,2),short_unwrap,1.0,1.0);
figure;
title([strpwd((length(strpwd)-25):length(strpwd)) ' ' fname_real]);
%subplot(4,3,nfig+2);
imagesc(xvec,yvec,zmat_eccen);
axis xy;
%colormap(rgb(64));
colorbar;
%subplot(4,3,nfig+3);
figure;
title([strpwd((length(strpwd)-25):length(strpwd)) ' ' fname_real]);
contour(xvec,yvec,zmat_eccen,20);
%figure;

%ffgrid(vertx_list(:,1),vertx_list(:,2),short_unwrap,0.75,0.75);
[zmat_imag_eccen,xvec,yvec]=ffgrid(vertx_list(:,1),vertx_list(:,2),mesh_imag(:,5),1.0,1.0);
[zmat_real_eccen,xvec,yvec]=ffgrid(vertx_list(:,1),vertx_list(:,2),mesh_real(:,5),1.0,1.0);
smooth_filt = fspecial('average',3);
zmat_eccen_cplx = zmat_real_eccen + (i*zmat_imag_eccen);
zmat_imag_smooth = zmat_imag_eccen;
zmat_real_smooth = zmat_real_eccen;
maxiter=2;
for niter=1:maxiter,
  zmat_imag_smooth = filter2(smooth_filt,zmat_imag_smooth);
  zmat_real_smooth = filter2(smooth_filt,zmat_real_smooth);
end;
zmat_smooth_eccen = angle(zmat_real_smooth + (i*zmat_imag_smooth));
zmat_smooth_eccen_cplx = zmat_real_smooth + (i*zmat_imag_smooth);
%subplot(4,3,nfig+5);
figure;
title([strpwd((length(strpwd)-25):length(strpwd)) ' ' fname_real]);
imagesc(xvec,yvec,zmat_smooth_eccen); axis xy;
figure;
%subplot(4,3,nfig+6);
title([strpwd((length(strpwd)-25):length(strpwd)) ' ' fname_real]);
imcontour(xvec,yvec,zmat_smooth_eccen_cplx,20);


function [Ppad, center_pad] = padIm(P, dim, center)
%PADPSF Pad an array P with zeros to make it bigger.
%
%      Ppad = padIm(PSF, dim);
%
%  Pad P with zeros to make it an m-by-n array.
%
%  Input:
%        P  Array (matrix)
%      dim  Desired dimension of padded array.
%             If dim is a scalar, then n = m.
%  Optional Input:
%    center integer array of two values indicating location of "center"
%           of P. This is used for PSFs
%
%  Output:
%        P  Padded m-by-n array.

% Reference: See Chapter 4,
%            "Deblurring Images - Matrices, Spectra, and Filtering"
%            by P. C. Hansen, J. G. Nagy, and D. P. O'Leary,
%            SIAM, Philadelphia, 2006.

%
% Set default parameters.
%
switch nargin
    case 1
        error('Need desired dimension of padded array')
    case 3
        if length(center) == 1
            error('center should be a vector with two integers')
        else
            ci = center(1); cj = center(2);
        end
end
if length(dim) == 1
    m = dim; n = dim;
else
    m = dim(1); n = dim(2);
end
%
% Pad the with zeros.
%
[mp, np] = size(P);
Ppad = zeros(m, n);
putidx = fix((size(Ppad) - size(P))/2) + 1;
Ppad(putidx(1):putidx(1)+mp-1, putidx(2):putidx(2)+np-1) = P;

if nargin == 3
    center_pad = [ci+putidx(1)-1, cj+putidx(2)-1];
else
    center_pad = [];
end


function [Aver,p,ip] = hor_to_ver(Ahor)
%hor_to_ver   reorder matrix from horizontal to vertical
%   [Aver,p,ip] = hor_to_ver(Ahor)
%   input
%          Ahor    matrix from horizontal ordering of square grid
%   output
%          Aver    matrix from vertical ordering of square grid
%          p       horizontal to vertical permutation, xv = x(ip)
%          ip      vertical to horizontal permutation, y = yv(p)
%
%   IFISS function: HCE; 28 February 2005.
% Copyright (c) 2005 D.J. Silvester, H.C. Elman, A. Ramage

%To multiply a vector x by Aver:
%   xv = x(ip), yv = Aver*xv, y = yv(p);

N = length(Ahor);
n = sqrt(N);
p  = zeros(N,1);
ip = zeros(N,1);

for j=1:n,
   for i=1:n,
      hor = (j-1)*n+i;
      ver = (i-1)*n+j;
      ip(ver) = hor;
      p(hor) = ver;
   end
end

Aver = Ahor(ip,ip);


function B = transform_image_V1_V3(I, corners, interporation)

% B = transform_image3(I, corners, interporation)
% calculate the transformation matrix for each area

B = nan(256,256);

if notDefined('interporation'), interporation = [];  end;

% V3v
input_points = corners{4};
% base_points =  [40 20;40 35; 80 35; 80 20];
base_points =  [30 80; 15 80; 15 40; 30 40];
udata = [1 201];  vdata = [1 201];  % input coordinate system
tform = maketform('projective',input_points, base_points);
[tmp,xdata,ydata] = imtransform(I,tform,interporation,'udata',udata,...
                                                'vdata',vdata,...
                                                'xdata',udata,...
                                                'ydata',vdata,...
                                                'size',size(I),...
                                                'fill',256);
B(round(20/200*256):round(100/200*256), round(10/200*256):round(30/200*256))=tmp(round(20/200*256):round(100/200*256),round(10/200*256):round(30/200*256));

% V2v
input_points = corners{2};
% base_points =  [40 50;40 35; 80 35; 80 50];
base_points =  [30 80; 45 80; 45 40; 30 40];
udata = [1 201];  vdata = [1 201];  % input coordinate system
tform = maketform('projective',input_points, base_points);
[tmp,xdata,ydata] = imtransform(I,tform,interporation,'udata',udata,...
                                                'vdata',vdata,...
                                                'xdata',udata,...
                                                'ydata',vdata,...
                                                'size',size(I),...
                                                'fill',256);
B(round(20/200*256):round(100/200*256), round(30/200*256):round(45/200*256))=tmp(round(20/200*256):round(100/200*256),round(30/200*256):round(45/200*256));

% V1
input_points = corners{1};
% base_points =  [40 50;40 65; 80 65; 80 50];
base_points =  [75 80; 45 80; 45 40; 75 40];
udata = [1 201];  vdata = [1 201];  % input coordinate system
tform = maketform('projective',input_points, base_points);
[tmp,xdata,ydata] = imtransform(I,tform,interporation,'udata',udata,...
                                                'vdata',vdata,...
                                                'xdata',udata,...
                                                'ydata',vdata,...
                                                'size',size(I),...
                                                'fill',256);
B(round(20/200*256):round(100/200*256), round(45/200*256):round(75/200*256))=tmp(round(20/200*256):round(100/200*256),round(45/200*256):round(75/200*256));

% V2d
input_points = corners{3};
% base_points =  [40 80;40 65; 80 65; 80 80];
base_points =  [75 80; 90 80; 90 40; 75 40];
% input_points = [corners{2};mean(corners{2}(2:3,:)); mean(corners{2})];
% % base_points =  [40 80;40 65; 80 65; 80 80];
% base_points =  [90 80; 75 80; 75 40; 90 40; 75 60; 82.5 60];
udata = [1 201];  vdata = [1 201];  % input coordinate system
tform = maketform('projective',input_points, base_points);
[tmp,xdata,ydata] = imtransform(I,tform,interporation,'udata',udata,...
                                                'vdata',vdata,...
                                                'xdata',udata,...
                                                'ydata',vdata,...
                                                'size',size(I),...
                                                'fill',256);
B(round(20/200*256):round(100/200*256), round(75/200*256):round(90/200*256))=tmp(round(20/200*256):round(100/200*256),round(75/200*256):round(90/200*256));

% V3d
input_points = corners{5};
% base_points =  [40 80;40 65; 80 65; 80 80];
base_points =  [105 80; 90 80; 90 40; 105 40];
% input_points = [corners{2};mean(corners{2}(2:3,:)); mean(corners{2})];
% % base_points =  [40 80;40 65; 80 65; 80 80];
% base_points =  [90 80; 75 80; 75 40; 90 40; 75 60; 82.5 60];
udata = [1 201];  vdata = [1 201];  % input coordinate system
tform = maketform('projective',input_points, base_points);
[tmp,xdata,ydata] = imtransform(I,tform,interporation,'udata',udata,...
                                                'vdata',vdata,...
                                                'xdata',udata,...
                                                'ydata',vdata,...
                                                'size',size(I),...
                                                'fill',256);
B(round(20/200*256):round(100/200*256), round(90/200*256):round(110/200*256))=tmp(round(20/200*256):round(100/200*256),round(90/200*256):round(110/200*256));


% dallrgl - DAL with logistic loss and grouped L1 regularization
%
% Overview:
%  Solves the optimization problem:
%   [xx,bias] = argmin sum(log(1+exp(-yy.*(A*x+bias)))) + lambda*||x||_G1
%  where
%   ||x||_G1 = sum(sqrt(sum(xx(Ii).^2)))
%   (Ii is the index-set of the i-th group
%
% Syntax:
%  [xx,bias,status]=dallrgl(xx0, bias0, A, yy, lambda, <opt>)
%
% Inputs:
%  xx0    : initial solution ([nn,1] with opt.blks or [ns nc] with
%           ns*nc=nn for nc groups of size ns)
%  bias0  : initial bias (set [] if bias term is unnecessary)
%  A      : the design matrix A ([mm,nn]) or a cell array {fA, fAT, mm, nn}
%           where fA and fAT are function handles to the functions that
%           return A*x and A'*x, respectively, and mm and nn are the
%           numbers of rows and columns of A.
%  yy     : the target label vector (-1 or +1) ([mm,1])
%  lambda : the regularization constant
%  <opt>  : list of 'fieldname1', value1, 'filedname2', value2, ...
%   blks     : vector that contains the size of the groups.
%              sum(opt.blks)=nn. If omitted, opt.blks = [ns,..., ns]
%              and length(opt.blks)=nc, where nc is the number of groups.
%   stopcond : stopping condition, which can be
%              'pdg'  : Use relative primal dual gap (default)
%              'fval' : Use the objective function value
%           (see dal.m for other options)
% Outputs:
%  xx     : the final solution ([nn,1])
%  bias   : the final bias term (scalar)
%  status : various status values
%
% Example:
% m = 1024; n = [64 64]; k = round(0.1*n(1)); A=randn(m,prod(n));
% w0=randsparse(n,k); yy=sign(A*w0(:)+0.01*randn(m,1));
% lambda=0.1*max(sqrt(sum(reshape(A'*yy/2,n).^2)));
% [ww,bias,stat]=dallrgl(zeros(n), 0, A, yy, lambda);
%
% Copyright(c) 2009 Ryota Tomioka
% This software is distributed under the MIT license. See license.txt

function [ww,bias,status]=dallrgl(ww, bias, A, yy, lambda, varargin)

opt=propertylist2struct(varargin{:});
opt=set_defaults(opt,'solver','cg',...
                     'stopcond','pdg',...
                     'blks',[]);

if ~isequal(unique_bc(yy), [-1;1])
  error('yy must be a column vector of -1''s and 1''s');
end

if isempty(opt.blks)
  opt.blks=size(ww,1)*ones(1,size(ww,2));
  ww = ww(:);
end

prob.floss    = struct('p',@loss_lrp,'d',@loss_lrd,'args',{{yy}});
prob.fspec    = @gl_spec;
prob.dnorm    = @gl_dnorm;
prob.obj      = @objdalgl;
prob.softth   = @gl_softth;
prob.stopcond = opt.stopcond;
prob.ll       = min(0,yy);
prob.uu       = max(0,yy);
prob.Ac       =[];
prob.bc       =[];
prob.info     = struct('blks',opt.blks);

if isequal(opt.solver,'cg')
  prob.hessMult = @hessMultdalgl;
end

if isequal(opt.stopcond,'fval')
  opt.feval = 1;
end

if isnumeric(A)
  A = A(:,:);
  [mm,nn]=size(A);
  At=A';
  fA = struct('times',@(x)A*x,...
              'Ttimes',@(x)At*x,...
              'slice', @(I)A(:,I));
  clear At;
elseif iscell(A)
  mm = A{3};
  nn = A{4};
  fAslice = @(I)fA(sparse(I,1:length(I),ones(length(I),1), nn, length(I)));
  fA = struct('times',A{1},...
              'Ttimes',A{2},...
              'slice',fAslice);
else
  error('A must be either numeric or cell {@(x)A*x, @(y)(A''*y), mm, nn}');
end

prob.mm       = mm;
prob.nn       = nn;

if isempty(bias)
  B = [];
else
  B = ones(mm,1);
end

[ww,bias,status]=dal(prob,ww,bias,fA,B,lambda,opt);

if all(opt.blks==opt.blks(1))
  ns=opt.blks(1);
  nc=length(ww)/ns;
  ww=reshape(ww, [ns,nc]);
end


function y = m_fp_amg(x_it,aparams,qparams)
%m_fp_amg     AMG iterated pressure convection-diffusion preconditioner
%   y = m_fp_amg(x_it,aparams,qparams);
%   input
%          x_it         operand for preconditioning operator
%          aparams      structure defining coefficient matrix
%          mparams      structure defining preconditioning matrix
%   output
%          y            result of preconditioning operation
%
%   calls FEMLAB function amgsol
%   Global array variables AMGLOBA and AMGLOBF define the
%   amg data for amgsol for Ap and F respectively
%
%   IFISS function: DJS; 23 April 2005.
% Copyright (c) 2005 D.J. Silvester, H.C. Elman, A. Ramage

global AMGLOBA
global AMGLOBF

nv = length(aparams.F);
nu = nv/2;
np = size(aparams.B,1);

rv=x_it(1:nv); rp=x_it(nv+1:nv+np);

%% pressure solve
nv = length(aparams.F);
nu = nv/2;
np = size(aparams.B,1);

rv=x_it(1:nv); rp=x_it(nv+1:nv+np);
%% pressure solve
if qparams.domain==1,
   n_null = qparams.n_null;
   minor = [1:n_null-1,n_null+1:np]';
   yp = zeros(np,1);
   yp(minor) =  amgsol(rp(minor),AMGLOBA);
   zp = -qparams.Mp\(qparams.Fp*yp);
else
   zp = -(qparams.Mp)\((qparams.Fp)*((qparams.Ap)\rp));
end

%% velocity solve
rv = rv-(aparams.B')*zp;
zv = amgsol(rv,AMGLOBF);
y = [zv;zp];


% MANIPULATOR TRAJECTORY GENERATION
% Generates combined transform (rotation and translation) trajectories
% using custom time scaling from a separate trajectory.
%
% Copyright 2019 The MathWorks, Inc.

%% Setup
clear, clc, close all

% Define waypoint information
createWaypointData;

% Define IK
ik = inverseKinematics('RigidBodyTree',gen3);
ikWeights = [1 1 1 1 1 1];
ikInitGuess = gen3.homeConfiguration;

% Set up plot
plotMode = 2; % 0 = None, 1 = Trajectory, 2 = Coordinate Frames
show(gen3,gen3.homeConfiguration,'Frames','off','PreservePlot',false);
xlim([-1 1]), ylim([-1 1]), zlim([0 1.2])
hold on
if plotMode == 1
    hTraj = plot3(waypoints(1,1),waypoints(2,1),waypoints(3,1),'b.-');
end
plot3(waypoints(1,:),waypoints(2,:),waypoints(3,:),'ro','LineWidth',2);

%% Generate and follow trajectory
% Loop through segments one at a time
trajType = 'trap';
numWaypoints = size(waypoints,2);
for w = 1:numWaypoints-1

    % Get the initial and final transforms and times for the segment
    T0 = trvec2tform(waypoints(:,w)') * eul2tform(orientations(:,w)');
    Tf = trvec2tform(waypoints(:,w+1)') * eul2tform(orientations(:,w+1)');
    timeInterval = waypointTimes(w:w+1);
    trajTimes = timeInterval(1):ts:timeInterval(2);

    % Generate time scaling trajectory for the segment on the range [0 1]
    switch trajType
        case 'trap'
            [s,sd,sdd] = trapveltraj([0 1],numel(trajTimes), ...
                                     'EndTime',diff(timeInterval));
        case 'cubic'
            [s,sd,sdd] = cubicpolytraj([0 1],timeInterval,trajTimes);
        case 'quintic'
            [s,sd,sdd] = quinticpolytraj([0 1],timeInterval,trajTimes);
        otherwise
            error('Invalid trajectory type! Use ''trap'', ''cubic'', or ''quintic''');
    end

    % Find the transforms from trajectory generation
    [T,vel,acc] = transformtraj(T0,Tf,timeInterval,trajTimes, ...
                                'TimeScaling',[s;sd;sdd]);

    % Trajectory visualization for the segment
    if plotMode == 1
        eePos = tform2trvec(T);
        set(hTraj,'xdata',eePos(:,1),'ydata',eePos(:,2),'zdata',eePos(:,3));
    elseif plotMode == 2
        plotTransforms(tform2trvec(T),tform2quat(T),'FrameSize',0.05)
    end

    % Trajectory following for the segment
    for idx = 1:numel(trajTimes)
        % Solve IK
        tgtPose = T(:,:,idx);
        [config,info] = ik(eeName,tgtPose,ikWeights,ikInitGuess);
        ikInitGuess = config;

        % Show the robot
        show(gen3,config,'Frames','off','PreservePlot',false);
        title(['Trajectory at t = ' num2str(trajTimes(idx))])
        drawnow
    end

end


% script that demonstrates use of 2d scattering

clear; close all;
x = uiuc_sample;
filt_opt.J = 7;
filt_opt.L = 8;
scat_opt.oversampling = 0;
[Wop, filters] = wavelet_factory_2d(size(x), filt_opt, scat_opt);

%%
profile on;
tic;
[Sx, Ux] = scat(x, Wop);
toc;
profile off;
profile viewer;


function p_homo = homogenize(p,y);
%HOMOGENIZE Homogenize polynomial
%
% f = homogenize(p,x)

deg   = degree(p);
deg_y = degree(y);
if rem(deg,deg_y)~=0
    error('The degree of the homogenizer is not an even fraction of deg(p).');
end

if 0
    error('The homogenizer must be homogenious.');
end

p_variables = getvariables(p);
p_homo = getbasematrix(p,0)*y^(deg/deg_y);
for i = 1:length(p_variables);
    monom = recover(p_variables(i));
    if degree(monom)<deg
        power = (deg-(degree(monom)))/deg_y;
        p_homo = p_homo + getbasematrix(p,p_variables(i))*monom*y^power;
    else
       p_homo = p_homo + getbasematrix(p,p_variables(i))*monom;
   end;
end
% Reset info about conic terms
p_homo.conicinfo = [0 0];


function [gal] = km32gal(km3)
% Convert volume from cubic kilometers to US liquid gallons.
% Chad Greene 2012
gal = km3*264172052360;


function guv = evaluate_log_posterior_grad(this, uv)
%EVALUATE_LOG_POSTERIOR computes the gradient of the log-posterior
%   (negative energy) wrt the flow fields UV
%   Actually only proportional to the log posterior since the variance of neither the
%   spatial nor the data terms is considered
%
%   This is a member function of the class 'hs_optical_flow'.
%
%   Author: Deqing Sun, Department of Computer Science, Brown University
%   Contact: dqsun@cs.brown.edu
%   $Date: 2007-11-30 $
%   $Revision: $
%
% Copyright 2007-2010, Brown University, Providence, RI. USA
%
%                          All Rights Reserved
%
% All commercial use of this software, whether direct or indirect, is
% strictly prohibited including, without limitation, incorporation into in
% a commercial product, use in a commercial service, or production of other
% artifacts for commercial purposes.
%
% Permission to use, copy, modify, and distribute this software and its
% documentation for research purposes is hereby granted without fee,
% provided that the above copyright notice appears in all copies and that
% both that copyright notice and this permission notice appear in
% supporting documentation, and that the name of the author and Brown
% University not be used in advertising or publicity pertaining to
% distribution of the software without specific, written prior permission.
%
% For commercial uses contact the Technology Venture Office of Brown University
%
% THE AUTHOR AND BROWN UNIVERSITY DISCLAIM ALL WARRANTIES WITH REGARD TO
% THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
% FITNESS FOR ANY PARTICULAR PURPOSE.  IN NO EVENT SHALL THE AUTHOR OR
% BROWN UNIVERSITY BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
% DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
% PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
% ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
% THIS SOFTWARE.

% Spatial term
S       = this.spatial_filters;
gu1     = zeros(size(uv,1), size(uv,2));
gv1     = gu1;

for i = 1:length(S)

    u_ = conv2(uv(:,:,1), S{i}, 'valid');
    v_ = conv2(uv(:,:,2), S{i}, 'valid');

    Si = reshape(S{i}(end:-1:1), size(S{i}));

    if isa(this.rho_spatial_u{i}, 'robust_function')
        u_ = -reshape(deriv(this.rho_spatial_u{i}, u_(:)), size(u_));
        v_ = -reshape(deriv(this.rho_spatial_v{i}, v_(:)), size(v_));
    elseif isa(this.rho_spatial_u{i}, 'gsm_density')
        u_ = reshape(evaluate_log_grad(this.rho_spatial_u{i}, u_(:)'), size(u_));
        v_ = reshape(evaluate_log_grad(this.rho_spatial_v{i}, v_(:)'), size(v_));
    else
        error('evaluate_log_posterior: unknown rho function!');
    end;

    gu1 = gu1+conv2(u_, Si, 'full');
    gv1 = gv1+conv2(v_, Si, 'full');
end;

gu2     = zeros(size(uv,1), size(uv,2));
gv2     = gu2;

% Data term
[It Ix Iy] = partial_deriv(this.images, uv, this.interpolation_method);

if isa(this.rho_data, 'robust_function')
    temp   = -reshape(deriv(this.rho_data, It(:)), size(It));

elseif isa(this.rho_data, 'gsm_density')
    temp   = reshape(evaluate_log_grad(this.rho_data, It(:)'), size(It));
else
    error('evaluate_log_posterior: unknown rho function!');
end;

gu2     = temp.*Ix;
gv2     = temp.*Iy;

guv = cat(3, gu2+this.lambda*gu1, gv2+this.lambda*gv1);


% RESAMPLE_SCAT Resample a scattering transform.
%
% Usages
%    S = RESAMPLE_SCAT(S, res, preserve_energy)
%
% Input
%    S (cell): A scattering transform.
%    res (int): The desired resolution.
%    preserve_energy (bool, optional): If set, renormalizes each resampled
%       coefficient so that its energy (sum of squares) remains the same.
%
% Output
%    S (cell): The scattering transform with each coefficient resampled to
%       resolution res.
%
% Description
%    Each coefficient in S is resampled to have the proper resolution. If the
%    desired resolution is finer, the signal will be interpolated. If the
%    resolution is coarser, it will be downsampled.
%
% See also
%    LOG_SCAT

function S = resample_scat(S, res, preserve_energy)
	if nargin < 3
		preserve_energy = true;
	end

	if iscell(S)
		for m = 0:length(S)-1
			S{m+1} = resample_scat(S{m+1}, res, preserve_energy); % self-call
        end
		return;
    end

	for p1 = 1:length(S.signal)
		res1 = 0;
		if isfield(S.meta,'resolution')
			res1 = S.meta.resolution(p1);
		end
		sz_orig = size(S.signal{p1});
		S.signal{p1} = interpft(S.signal{p1}, 2^(-res+res1)*size(S.signal{p1},1));
		sz_new = sz_orig;
		sz_new(1) = sz_orig(1)*2^(-res+res1);
		S.signal{p1} = reshape(S.signal{p1}, sz_new);
		if preserve_energy
			S.signal{p1} = S.signal{p1}*2^(-(-res+res1)/2);
		end
		S.meta.resolution(p1) = res;
	end
end


function [kPa] = Torr2kPa(Torr)
% Convert pressure from torr to kilopascals
% Chad Greene 2012
kPa = Torr*.133322;


function A = sim_genVARModelFromEq(expr,morder)
%
% Generate VAR model coefficient matrix from text-based system of equations
% The model can then be realized using the tvarsim() function modified from
% ARfit [2].
% If the expr specification requests time-varying coefficients, then this
% function will return inline function placeholders for coefficients, which
% can be evaluated to actual coefficient matrices by sim_genTVARcoeffs().
%
% Inputs:
%
%   expr:       A cell vector containing each equation as a string (one
%               equation per cell element). See Examples for format.
%   morder:     The model order
%
% Outputs:
%
%   A:          VAR[p] model coefficients in format A=[A1,A2, ... Ap] where
%               p = morder. Ai is the M x M coefficient matrix for lag i.
%
% Example1: generate a static VAR[3] model from a (text-based) system of equations
%
% expr = { ...
%     'x1(t) = 0.9*x1(t-1)  + 0.3*x2(t-2)  + e1(t)' ...
%     'x2(t) = 1.3*x2(t-1)  + -0.8*x2(t-2) + e2(t)' ...
%     'x3(t) = 0.3*x1(t-2)  + 0.6*x2(t-1)  + e3(t)' ...
%     'x4(t) = -0.7*x4(t-3) + -0.7*x1(t-3) + 0.3*x5(t-3) + e4(t)' ...
%     'x5(t) = 1*x5(t-1)    + -0.4*x5(t-2) + 0.3*x4(t-2) + e5(t)' ...
%     };
% A = sim_genVARModelFromEq(expr,3)
% A =
%     0.9000         0         0         0         0         0    0.3000         0         0         0         0         0         0         0         0
%          0    1.3000         0         0         0         0   -0.8000         0         0         0         0         0         0         0         0
%          0    0.6000         0         0         0    0.3000         0         0         0         0         0         0         0         0         0
%          0         0         0         0         0         0         0         0         0         0   -0.7000         0         0   -0.7000    0.3000
%          0         0         0         0    1.0000         0         0         0    0.3000   -0.4000         0         0         0         0         0
%
% % Now generate some data from the model (this requires arsim.m or tvarsim.m)
%
% M   = size(A,1);        % number of variables
% Nl  = 1000;             % length of each trial
% Nr  = 100;              % number of trials
% C = eye(M);             % specify the covariance matrix
% data = zeros(M,Nl,Nr);
% for tr=1:Nr             % simulate data from VAR model
%    data(:,:,tr) = arsim(zeros(1,M),A,C,Nl)';
% end
% eegplot(data,'srate',1); % visualize the simulated data
%
%
% Example 2: generate a time-varying VAR[2] model
%
%
% See Also: tvarsim(), est_fitMVAR(), sim_genTVARcoeffs()
%
% References:
%
% [1] Mullen T (2010) The Source Information Flow Toolbox (SIFT):
%   Theoretical Handbook and User Manual. Section 6.5.1
%   Available at: http://www.sccn.ucsd.edu/wiki/Sift
% [2] Schneider T, Neumaier A (2001) Algorithm 808: ARfit---a matlab package
%   for the estimation of parameters and eigenmodes of multivariate
%   autoregressive models. ACM Transactions on Mathematical Software 27:58-65
%   http://www.gps.caltech.edu/~tapio/arfit/
%
% Author: Tim Mullen 2010, SCCN/INC, UCSD.
% Email:  tim@sccn.ucsd.edu

% This function is part of the Source Information Flow Toolbox (SIFT)
%
% 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, write to the Free Software
% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

Nvars = length(expr);

if nargin>1
    % create cell array of zeros
    A = repmat({0},Nvars,Nvars*morder);
end

fnstr ='{[\S]+}';

for i = 1:Nvars
    eq = expr{i};

    % Identify all inline functions
    % Specifically, we extract any string f(x) encapsulated by
    % curly-brackets '{f(x)}'
    [matchstr] = regexp(eq,'{[\S]+}','match');

    % replace each function with an identifier '$i' designating that the
    % ith equation will go here
    for fi=1:length(matchstr)
        eq = strtrim(strrep(eq,matchstr{fi},sprintf('$%d',fi)));
    end

    % remove all whitespace
    eq(isspace(eq))=[];
%
%     for fi=1:length(matchstr)
%         eq = [eq(1:matchstart(fi)-1) sprintf('$%d',fi) eq(matchend(fi)+1:end)];
%     end

    terms = regexp(eq,'([=+*])','split');

    row = str2double(regexp(terms{1},'(\d+)','match'));
    for k = 2:2:length(terms)-1
        vars = regexp(terms{k+1},'(\d+)','match');
        vars = str2num(char(vars));
        col = vars(1)+(vars(2)-1)*Nvars;

        if strcmpi(terms{k}(1),'$')
            % term is a function expression
            A{row,col} = matchstr{str2double(terms{k}(2))}(2:end-1);
        elseif ~isnan(str2double(terms{k}))
            % term is a number
            A{row,col} = str2double(terms{k});
        else
            % term is an expression to be directly evaluated
            A{row,col} = eval(terms{k});
        end
    end
end

% if A is all numeric, convert to standard array
if all(cellfun(@(x)isnumeric(x),A))
    A = cell2mat(A);
end


function A = four_corners(m,n)
%FOUR_CORNERS Construct a m x n sparse matrix with ones in each of its four
%corners.
%
% t = four_corners(m,n);
%
% Inputs:
%  m,n  the dimension of the matrix requested
% Outputs:
%  A  the sparse matrix with ones in their four corners
%

A = sparse(m,n);
A(1,1) = 1;
A(m,1) = 1;
A(1,n) = 1;
A(m,n) = 1;

end


function u=dimsplit(fflux,gflux,u0,x,y,T,nstep)
%%
%  Solves the equation u_t + fflux(u)_x  + gflux(u)_y = 0 by operator
%  splitting.  u0 and a must the size of x.
%
%  Output is a matrix of size [length(x),((T/dt)+1)] .
%

%% Initial setup
h=path;
path(h,'../Example2_5');
Nt=nstep;
dt=T/Nt;
dx=x(2)-x(1); m=length(x);
dy=y(2)-y(1); n=length(y);
u=zeros(m,n,Nt+1);
u(:,:,1)=u0;

%% Dimensional splitting
%  uses the LxF method in each direction.
for i=1:Nt,
	u1=LxF(fflux,u(:,:,i),dt,dx,1,'periodic');      % Conservation in x-dir
	u(:,:,i+1)=LxF(gflux,u1,dt,dy,2,'periodic');    % Conservation in y-dir
end;

path(h);


%ESTIMATERIGIDTRANSFORM  Computes an optimal affine transformation between two 2D point sets
%
%     M = cv.estimateRigidTransform(src, dst)
%     M = cv.estimateRigidTransform(src, dst, 'OptionName', optionValue, ...)
%
% ## Input
% * __src__ First input 2D point set stored in a cell array of 2-element
%   vectors `{[x,y], ...}`, or first image (8-bit numeric array, 1- or
%   3-channels).
% * __dst__ Second input 2D point set of the same size and the same type as
%   `src`, or second image (8-bit numeric array, 1- or 3-channels).
%
% ## Output
% * __M__ output 2x3 affine transformation `[A|b]` matrix (see below).
%
% ## Options
% * __FullAffine__ If true, the function finds an optimal affine transformation
%   with no additional resrictions (6 degrees of freedom). Otherwise, the
%   class of transformations to choose from is limited to combinations of
%   translation, rotation, and uniform scaling (4 degrees of freedom).
%   default false
%
% The function finds an optimal affine transform `[A|b]` (a 2x3 floating-point
% matrix) that approximates best the affine transformation between:
%
% * Two point sets
% * Two raster images. In this case, the function first finds some features in
%   the `src` image and finds the corresponding features in `dst` image. After
%   that, the problem is reduced to the first case.
%
% In case of point sets, the problem is formulated as follows: you need to
% find a 2x2 matrix `A` and 2x1 vector `b` so that:
%
%     [A*|b*] = argmin_{[A|b]} sum_{i}(|| dst{i} - A*src{i}' - b ||^2)
%
% where `src{i}` and `dst{i}` are the i-th points in `src` and `dst`,
% respectively. `[A|b]` can be either arbitrary (when `FullAffine=true`) or
% have a form of:
%
%     [ a11, a12, b1;
%      -a12, a11, b2 ]
%
% when `FullAffine=false`.
%
% See also: cv.estimateAffine2D, cv.estimateAffinePartial2D,
%  cv.getAffineTransform, cv.getPerspectiveTransform, cv.findHomography,
%  imregtform
%


function a = band(a,p,q)
%BAND         Extract band from matrix a, lower bandwidth p, upper bandwidth q
%   if parameter q is omitted, q:=p
%
%   c = band(a,p,q)
%

% written  09/28/01     S.M. Rump
% modified 04/04/04     S.M. Rump  set round to nearest for safety
%                                    improved performance
% modified 04/06/05     S.M. Rump  rounding unchanged
%

  if nargin<3
    q = p;
  end

  a = tril(triu(a,-p),q);


function [ edge_data, node_num2 ] = tet_mesh_order4_to_order10_size ( ...
  tetra_num, tetra_node1, node_num1 )

%*****************************************************************************80
%
%% TET_MESH_ORDER4_TO_ORDER10_SIZE sizes a quadratic tet mesh from a linear one.
%
%  Discussion:
%
%    A quadratic (10 node) tet mesh can be derived from a linear
%    (4 node) tet mesh by interpolating nodes at the midpoint of
%    every edge of the mesh.
%
%    The mesh is described indirectly, as the sum of individual
%    tetrahedrons.  A single physical edge may be a logical edge of
%    any number of tetrahedrons.  It is important, however, that a
%    new node be created exactly once for each edge, assigned an index,
%    and associated with every tetrahedron that shares this edge.
%
%    This routine handles that problem.
%
%    The primary amount of work occurs in sorting a list of 6 * TETRA_NUM
%    data items, one item for every edge of every tetrahedron.  Each
%    data item records, for a given tetrahedron edge, the global indices
%    of the two endpoints, the local indices of the two endpoints,
%    and the index of the tetrahedron.
%
%    Through careful sorting, it is possible to arrange this data in
%    a way that allows the proper generation of the interpolated nodes.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 November 2006
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer TETRA_NUM, the number of tetrahedrons in the
%    linear mesh.
%
%    Input, integer TETRA_NODE1(4,TETRA_NUM), the nodes that make up
%    each tetrahedron in the linear mesh.
%
%    Input, integer NODE_NUM1, the number of nodes for the linear mesh.
%
%    Output, integer EDGE_DATA(5,6*TETRA_NUM), edge data.
%
%    Output, integer NODE_NUM2, the number of nodes for the quadratic mesh.
%

%
%  Step 1.
%  From the list of nodes for tetrahedron T, of the form: (I,J,K,L)
%  construct the six edge relations:
%
%    (I,J,1,2,T)
%    (I,K,1,3,T)
%    (I,L,1,4,T)
%    (J,K,2,3,T)
%    (J,L,2,4,T)
%    (K,L,3,4,T)
%
%  In order to make matching easier, we reorder each pair of nodes
%  into ascending order.
%
  for tetra = 1 : tetra_num

    i = tetra_node1(1,tetra);
    j = tetra_node1(2,tetra);
    k = tetra_node1(3,tetra);
    l = tetra_node1(4,tetra);

    [ a, b ] = i4i4_sort_a ( i, j );

    edge_data(1:5,6*(tetra-1)+1) = [ a, b, 1, 2, tetra ]';

    [ a, b ] = i4i4_sort_a ( i, k );

    edge_data(1:5,6*(tetra-1)+2) = [ a, b, 1, 3, tetra ]';

    [ a, b ] = i4i4_sort_a ( i, l );

    edge_data(1:5,6*(tetra-1)+3) = [ a, b, 1, 4, tetra ]';

    [ a, b ] = i4i4_sort_a ( j, k );

    edge_data(1:5,6*(tetra-1)+4) = [ a, b, 2, 3, tetra ]';

    [ a, b ] = i4i4_sort_a ( j, l );

    edge_data(1:5,6*(tetra-1)+5) = [ a, b, 2, 4, tetra ]';

    [ a, b ] = i4i4_sort_a ( k, l );

    edge_data(1:5,6*(tetra-1)+6) = [ a, b, 3, 4, tetra ]';

  end
%
%  Step 2. Perform an ascending dictionary sort on the neighbor relations.
%  We only intend to sort on rows 1:2; the routine we call here
%  sorts on the full column but that won't hurt us.
%
%  What we need is to find all cases where tetrahedrons share an edge.
%  By sorting the columns of the EDGE_DATA array, we will put shared edges
%  next to each other.
%
  edge_data = i4col_sort_a ( 5, 6*tetra_num, edge_data );
%
%  Step 3. All the tetrahedrons which share an edge show up as consecutive
%  columns with identical first two entries.  Figure out how many new
%  nodes there are, and allocate space for their coordinates.
%
  node_num2 = node_num1;

  n1_old = -1;
  n2_old = -1;

  for edge = 1 : 6 * tetra_num
    n1 = edge_data(1,edge);
    n2 = edge_data(2,edge);
    if ( n1 ~= n1_old | n2 ~= n2_old )
      node_num2 = node_num2 + 1;
      n1_old = n1;
      n2_old = n2;
    end
  end

  return
end


classdef (Abstract) FilterClass
    % FilterClass:  Methods for filtering data which can be inherited by other models
    % Options:
    %   Smoothing Filter
    %     Type                 Type of filter
    %                              - gaussian
    %                              - median
    %                              - spline
    %                              - polynomial
    %     Dimension            In which dimensions to apply the filter
    %                               -2D
    %                               -3D
    %     size(x,y,z)          Extent of filter in # of voxels
    %                               For gaussian, it's FWHM
    %                               For median, it's number of voxels
    %     order                Order of the polynomial fitting and the 'amount of smoothness' for spline fitting

    properties
        % Model options
        buttons ={'PANEL','Smoothing filter',6,...
            'Type',{'polynomial','gaussian','median','spline'},...
            'Dimension',{'3D','2D'},...
            'size x',3,...
            'size y',3,...
            'size z',3,...
            'order',6};
        options = struct(); % structure filled by the buttons. Leave empty in the code
    end

    methods
        % Constructor
        function obj = FilterClass()
        end

        function  obj = UpdateFields(obj)
            % Disable/enable some options --> Add ### to the button
            % Name you want to disable
            disablelist = {'size x','size y','size z','order'};
            switch  obj.options.Smoothingfilter_Dimension
                case {'2D'}
                    disable = [false false true true];
                    obj.options.Smoothingfilter_sizez=0;
                otherwise
                    disable = [false false false true];
            end
            % for spline, only 1 value for the amount of smoothness  (user 'order' field) and 3D
            if strcmp(obj.options.Smoothingfilter_Type,{'spline'})
                disable = [true true true false];
            end
            % for polynomial, now polynomial fitting works for both 2D and
            % 3D cases
            if strcmp(obj.options.Smoothingfilter_Type,{'polynomial'})
                disable = [true true true false];

            end

            for ll = 1:length(disablelist)
                indtodisable = find(strcmp(obj.buttons,disablelist{ll}) | strcmp(obj.buttons,['##' disablelist{ll}]));
                if disable(ll)
                    obj.buttons{indtodisable} = ['##' disablelist{ll}];
                else
                    obj.buttons{indtodisable} = [disablelist{ll}];
                end
            end
        end

        function FitResult = fit(obj,data,size)
            switch obj.options.Smoothingfilter_Type
                case {'gaussian'}
                    FitResult.Filtered=obj.gaussFilt(data.Raw,size); %smoothed
                case {'median'}
                    FitResult.Filtered=obj.medianFilt(data.Raw,size); %smoothed
                case {'spline'}
                    FitResult.Filtered=obj.splineFilt(data.Raw,obj.options.Smoothingfilter_order); %smoothed
                case {'polynomial'}
                    FitResult.Filtered=obj.polyFilt(data,obj.options.Smoothingfilter_order); %smoothed
            end
        end
        % Gaussian filter
        function filtered = gaussFilt(obj,data,fwhm)
            % Apply a Gaussian filter (2D or 3D)
            % fwhm is a 2 or 3-element vector of positive numbers
            sigmaPixels = fwhm2sigma(fwhm); %Full width half max of desired gaussian kernel (in #voxels) converted to sigma of Gaussian
            if(sigmaPixels(3)==0 || strcmp(obj.options.Smoothingfilter_Dimension,'2D')) %for the 2D case
                filtered = imgaussfilt(data,sigmaPixels(1:2));
            else
                filtered = imgaussfilt3(data,sigmaPixels);

            end
        end

        %Median filter
        function filtered =medianFilt(obj,data,s)
            % Apply a median filter (2D or 3D)
            % s is a 3-element vector of positive numbers (voxels)
            if(s(3)==0 || strcmp(obj.options.Smoothingfilter_Dimension,'2D')) %for the 2D case, if the volume is 3D, have to do each slice separately
                if(ndims(data)==2)
                    filtered = medfilt2(data,s(1:2));
                else
                    filtered=zeros(size(data));
                    for i=1:size(data,3)
                        filtered(:,:,i)=medfilt2(data(:,:,i),s(1:2));
                    end
                end
            else
                filtered = medfilt3(data,s);
            end
        end

        %Spline filter
        function filtered =splineFilt(obj,data,S)
            % Apply a spline filter (2D or 3D)
            s=S(1); %just 1 values for the smoothness
            if(strcmp(obj.options.Smoothingfilter_Dimension,'2D')) %if want 2D smoothing
                if(ndims(data)==2) %if a 2D volume
                    filtered = smoothn(data,s);
                else %if a 3D volume, do each slice separately
                    filtered=zeros(size(data));
                    for i=1:size(data,3)
                        filtered(:,:,i)=smoothn(data(:,:,i),s);
                    end
                end
            else
                filtered = smoothn(data,s);
            end

            %filtered = smoothn(data,'robust');
        end

        %% Polynomial filter
        % for the fitting to work better, a mask should be provided, it's
        % one of the rare methods that needs to know what the mask was and
        % only fir in there
        function filtered=polyFilt(obj,data,order)
            % Apply a polynomial fit of the specified order (in 2D)
            if(ndims(data.Raw)==2) %if a 2D volume
                if isfield(data,'Mask') && (~isempty(data.Mask))
                    filtered = poly_fit(data.Raw,order,data.Mask);
                else
                    filtered = poly_fit(data.Raw,order);
                end
                % if a 3D volume, use 2D or 3D fit according to the selection of dimension:
                % 1. Perform each slice separately in 2D poly fit; OR
                % 2. Perform 3D poly fit
            else
                filtered=zeros(size(data.Raw));
                if strcmp(obj.options.Smoothingfilter_Dimension,'2D')
                    for i = 1:size(data.Raw,3)
                        if isfield(data,'Mask') && (~isempty(data.Mask))
                            filtered(:,:,i) = poly_fit(data.Raw(:,:,i),order,data.Mask(:,:,i));
                        else
                            filtered(:,:,i) = poly_fit(data.Raw(:,:,i),order);
                        end
                    end

                elseif isfield(data,'Mask') && (~isempty(data.Mask))
                    filtered = polyfit_3D(data.Raw,order,data.Mask);
                else
                    filtered = polyfit_3D(data.Raw,order);
                end
            end
        end

    end

end