function [SD1, SD2, SD1_SD2_ratio] = EvalPoincareOnWindows(rr, t_rr, HRVparams, tWin, sqi)

%   OVERVIEW:
%       Calculates SD1 SD2 and SD1_SD2_ratio features from Poincare plot
%       for each defined windows
%   INPUT
%       rr           - (seconds) rr intervals
%       t_rr         - (seconds)  time stamp of rr intervals
%       HRVparams    - struct of settings for hrv_toolbox analysis
%       sqi          - Signal Quality Index; Requires a matrix with
%                      at least two columns. Column 1 should be
%                      timestamps of each sqi measure, and Column 2
%                      should be SQI on a scale from 0 to 1.
%       tWin         - Starting time of each windows to analyze
%
%   OUTPUTS:
%       SD1           : (ms) standard  deviation  of  projection  of  the
%                       PP  on  the line perpendicular to the line of
%                       identity (y=-x)
%       SD2           : (ms) standard deviation of the projection of the PP
%                       on the line of identity (y=x)
%       SD1_SD2_ratio : (ms) SD1/SD2 ratio
%
%
%   Written by: Giulia Da Poian <giulia.dap@gmail.com>
%	REPO:
%       https://github.com/cliffordlab/PhysioNet-Cardiovascular-Signal-Toolbox
%	COPYRIGHT (C) 2016
%   LICENSE:
%       This software is offered freely and without warranty under
%       the GNU (v3 or later) public license. See license file for
%       more information
%

% Make vector a column
rr = rr(:);

if nargin < 4
    error('no data provided')
end
if nargin <5 || isempty(sqi)
    sqi(:,1) = t_rr;
    sqi(:,2) = ones(length(t_rr),1);
end

windowlength = HRVparams.windowlength;
SQI_th = HRVparams.sqi.LowQualityThreshold;        % SQI threshold
WinQuality_th = HRVparams.RejectionThreshold; % Low quality windows threshold

% Preallocation (all NaN)

SD1 = ones(length(tWin),1)*NaN;
SD2 = ones(length(tWin),1)*NaN;
SD1_SD2_ratio = ones(length(tWin),1)*NaN;

% Run PoincareMetrics by Windows
% Loop through each window of RR data
for i_win = 1:length(tWin)
    if ~isnan(tWin(i_win))
        % Isolate data in this window
        sqi_win = sqi( sqi(:,1) >= tWin(i_win) & sqi(:,1) < tWin(i_win) + windowlength,:);
        nn_win = rr( t_rr >= tWin(i_win) & t_rr < tWin(i_win) + windowlength );
        lowqual_idx = find(sqi_win(:,2) < SQI_th);         % Analysis of SQI for the window
        % If enough data has an adequate SQI, perform the calculations
        if numel(lowqual_idx)/length(sqi_win(:,2)) < WinQuality_th
            [SD1(i_win), SD2(i_win), SD1_SD2_ratio(i_win)] = PoincareMetrics(nn_win);
        end % end of conditional statements run when SQI is adequate
    end % end of check for sufficient data
end % end of loop through windows

end % end of function


% Script to reproduce the experiments leading to the results provided in the
% Table 2 of the paper "Deep Scattering Spectrum" by J. Andén and S. Mallat.

% M=2 scattering

run_name = 'DSS_Table2_GTZAN_m2';

N=5*2^17;

src=gtzan_src('/path/to/gtzan');

fparam.filter_type = {'gabor_1d','morlet_1d'};
fparam.Q = [8 2];
fparam.J = T_to_J(8192,fparam);

options.M = 2;

Wop = wavelet_factory_1d(N, fparam, options);

feature_fun = {@(x)(format_scat(log_scat(renorm_scat(scat(x,Wop)))))};

db = prepare_database(src,feature_fun);
db.features = single(db.features);
db = svm_calc_kernel(db,'gaussian','square',1:2:size(db.features,2));

rs = RandStream.create('mt19937ar','Seed',floor(pi*1e9));
RandStream.setGlobalStream(rs);
[train_set{1}, test_set{1}] = create_partition([src.objects.class], 0.9);
for k = 2:10
	[train_set{k}, test_set{k}] = ...
		next_fold([src.objects.class], train_set{k-1}, test_set{k-1});
end

optt.kernel_type = 'gaussian';
optt.C = 2.^[0:4:8];
optt.gamma = 2.^[-16:4:-8];
optt.search_depth = 3;
optt.full_test_kernel = 1;

for k = 1:10
	[dev_err_grid,C_grid,gamma_grid] = ...
		svm_adaptive_param_search(db,train_set{k},[],optt);

	[dev_err(k),ind] = min(mean(dev_err_grid{end},2));
	C(k) = C_grid{end}(ind);
	gamma(k) = gamma_grid{end}(ind);

	optt1 = optt;
	optt1.C = C(k);
	optt1.gamma = gamma(k);

	model = svm_train(db,train_set{k},optt1);
	labels(:,k) = svm_test(db,model,test_set{k});
	err(k) = classif_err(labels(:,k),test_set{k},db.src);

	fprintf('dev err = %f, test err = %f\n',dev_err(k),err(k));

	save([run_name '.mat'],'labels','dev_err','err','C','gamma');
end


function [output, Greg] = dftregistration_min_max_3d(buf1ft,buf2ft,usfac,min_shift,max_shift,phase_flag)
% function [output Greg] = dftregistration(buf1ft,buf2ft,usfac);
% Efficient subpixel image registration by crosscorrelation. This code
% gives the same precision as the FFT upsampled cross correlation in a
% small fraction of the computation time and with reduced memory
% requirements. It obtains an initial estimate of the crosscorrelation peak
% by an FFT and then refines the shift estimation by upsampling the DFT
% only in a small neighborhood of that estimate by means of a
% matrix-multiply DFT. With this procedure all the image points are used to
% compute the upsampled crosscorrelation.
% Manuel Guizar - Dec 13, 2007
%
% Rewrote all code not authored by either Manuel Guizar or Jim Fienup
% Manuel Guizar - May 13, 2016
%
% Modified by Eftychios A. Pnevmatikakis to include upper bound on possible
% shifts - November 1, 2016
%
% Citation for this algorithm:
% Manuel Guizar-Sicairos, Samuel T. Thurman, and James R. Fienup,
% "Efficient subpixel image registration algorithms," Opt. Lett. 33,
% 156-158 (2008).
%
% Inputs
% buf1ft    Fourier transform of reference image,
%           DC in (1,1)   [DO NOT FFTSHIFT]
% buf2ft    Fourier transform of image to register,
%           DC in (1,1) [DO NOT FFTSHIFT]
% usfac     Upsampling factor (integer). Images will be registered to
%           within 1/usfac of a pixel. For example usfac = 20 means the
%           images will be registered within 1/20 of a pixel. (default = 1)
% min_shift Minimum shift in each dimension (3x1 vector). (default = -Inf, no min)
% max_shift Maximum shift in each dimension (3x1 vector). (default = Inf, no max)
%
% Outputs
% output =  [error,diffphase,net_row_shift,net_col_shift]
% error     Translation invariant normalized RMS error between f and g
% diffphase     Global phase difference between the two images (should be
%               zero if images are non-negative).
% net_row_shift net_col_shift   Pixel shifts between images
% Greg      (Optional) Fourier transform of registered version of buf2ft,
%           the global phase difference is compensated for.
%
%
% Copyright (c) 2016, Manuel Guizar Sicairos, James R. Fienup, University of Rochester
% All rights reserved.
%
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are
% met:
%
%     * Redistributions of source code must retain the above copyright
%       notice, this list of conditions and the following disclaimer.
%     * Redistributions in binary form must reproduce the above copyright
%       notice, this list of conditions and the following disclaimer in
%       the documentation and/or other materials provided with the distribution
%     * Neither the name of the University of Rochester nor the names
%       of its contributors may be used to endorse or promote products derived
%       from this software without specific prior written permission.
%
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
% POSSIBILITY OF SUCH DAMAGE.

if ~exist('phase_flag','var')
    phase_flag = true;
end

if ~exist('usfac','var')
    usfac = 1;
end

if ~exist('max_shift','var')
    max_shift = Inf(1,3);
end

if ~exist('min_shift','var');
    min_shift = -max_shift;
end

if isscalar(max_shift); max_shift = max_shift*[1,1,1]; end
if isscalar(min_shift); min_shift = min_shift*[1,1,1]; end

[nr,nc,np]=size(buf2ft);
Nr = ifftshift(-fix(nr/2):ceil(nr/2)-1);
Nc = ifftshift(-fix(nc/2):ceil(nc/2)-1);
Np = ifftshift(-fix(np/2):ceil(np/2)-1);

buf_prod = buf1ft.*conj(buf2ft);
if usfac == 0
    % Simple computation of error and phase difference without registration
    CCmax = sum(buf1ft(:).*conj(buf2ft(:)));
    row_shift = 0;
    col_shift = 0;
    pln_shift = 0;
elseif usfac == 1
    % Single pixel registration
    if phase_flag
        buf_prod = buf_prod./abs(buf_prod);
    end
    CC = ifftn(buf_prod);
    CCabs = abs(CC);
    [~,ind] = max(CCabs(:));
    [row_shift, col_shift, pln_shift] = ind2sub([nr,nc,np],ind);
    %[row_shift, col_shift] = find(CCabs == max(CCabs(:)));
    if Nr(row_shift) > max_shift(1) || Nc(col_shift) > max_shift(2) || Np(pln_shift) > max_shift(3) || Nr(row_shift) < min_shift(1) || Nc(col_shift) < min_shift(2) || Np(pln_shift) < min_shift(3)
        CCabs2 = CCabs;
        CCabs2(Nr>max_shift(1),:,:) = 0;
        CCabs2(:,Nc>max_shift(2),:) = 0;
        CCabs2(:,:,Np>max_shift(3)) = 0;
        CCabs2(Nr<min_shift(1),:,:) = 0;
        CCabs2(:,Nc<max_shift(2),:) = 0;
        CCabs2(:,:,Np<max_shift(3)) = 0;
        [~,ind] = max(CCabs2(:));
        [row_shift, col_shift, pln_shift] = ind2sub([nr,nc,np],ind);
        %[row_shift, col_shift] = find(CCabs == max(CCabs2(:)),1,'first');
    end
    CCmax = CC(row_shift,col_shift,pln_shift)*nr*nc*np;
    % Now change shifts so that they represent relative shifts and not indices
    row_shift = Nr(row_shift);
    col_shift = Nc(col_shift);
    pln_shift = Np(pln_shift);
elseif usfac > 1
    % Start with usfac == 2
    buf_pad = FTpad3d(buf_prod,[2*nr,2*nc,2*np]);
    if phase_flag
        buf_pad = buf_pad./(abs(buf_pad)+1e-10);
    end
    CC = ifftn(buf_pad);
    CCabs = abs(CC);
    [~,ind] = max(CCabs(:));
    [row_shift, col_shift, pln_shift] = ind2sub([2*nr,2*nc,2*np],ind);
    %[row_shift, col_shift] = find(CCabs == max(CCabs(:)),1,'first');
    % Now change shifts so that they represent relative shifts and not indices
    Nr2 = ifftshift(-fix(nr):ceil(nr)-1);
    Nc2 = ifftshift(-fix(nc):ceil(nc)-1);
    Np2 = ifftshift(-fix(np):ceil(np)-1);
    if Nr2(row_shift)/2 > max_shift(1) || Nc2(col_shift)/2 > max_shift(2) || Np2(pln_shift)/2 > max_shift(3) || Nr2(row_shift)/2 < min_shift(1) || Nc2(col_shift)/2 < min_shift(2) || Np2(pln_shift)/2 < min_shift(3)
        CCabs2 = CCabs;
        CCabs2(Nr2/2>max_shift(1),:,:) = 0;
        CCabs2(:,Nc2/2>max_shift(2),:) = 0;
        CCabs2(:,:,Np2/2>max_shift(3)) = 0;
        CCabs2(Nr2/2<min_shift(1),:,:) = 0;
        CCabs2(:,Nc2/2<min_shift(2),:) = 0;
        CCabs2(:,:,Np2/2<min_shift(3)) = 0;
        [~,ind] = max(CCabs2(:));
        [row_shift, col_shift, pln_shift] = ind2sub([2*nr,2*nc,2*np],ind);
        %CCabs2 = CCabs(abs(Nr)<=max_shift(1),abs(Nc)<=max_shift(2));
        %[row_shift, col_shift] = find(CCabs == max(CCabs2(:)),1,'first');
    end
    CCmax = CC(row_shift,col_shift,pln_shift)*nr*nc*np;
    row_shift = Nr2(row_shift)/2;
    col_shift = Nc2(col_shift)/2;
    pln_shift = Np2(pln_shift)/2;
    % If upsampling > 2, then refine estimate with matrix multiply DFT
    if usfac > 2,
        %%% DFT computation %%%
        % Initial shift estimate in upsampled grid
        row_shift = round(row_shift*usfac)/usfac;
        col_shift = round(col_shift*usfac)/usfac;
        pln_shift = round(pln_shift*usfac)/usfac;
        dftshift = fix(ceil(usfac*1.5)/2); %% Center of output array at dftshift+1
        % Matrix multiply DFT around the current shift estimate
        CC = conj(dftups3d(buf2ft.*conj(buf1ft),ceil(usfac*1.5),ceil(usfac*1.5),ceil(usfac*1.5),usfac,...
            dftshift-row_shift*usfac,dftshift-col_shift*usfac,dftshift-pln_shift*usfac));
        % Locate maximum and map back to original pixel grid
        CCabs = abs(CC);
        [~,ind] = max(CCabs(:));
        [rloc, cloc, ploc] = ind2sub(size(CC),ind);
        %[rloc, cloc] = find(CCabs == max(CCabs(:)),1,'first');
        CCmax = CC(rloc,cloc,ploc);
        rloc = rloc - dftshift - 1;
        cloc = cloc - dftshift - 1;
        ploc = ploc - dftshift - 1;
        row_shift = row_shift + rloc/usfac;
        col_shift = col_shift + cloc/usfac;
        pln_shift = pln_shift + ploc/usfac;
    end

    % If its only one row or column the shift along that dimension has no
    % effect. Set to zero.
    if nr == 1
        row_shift = 0;
    end
    if nc == 1
        col_shift = 0;
    end
    if np == 1
        pln_shift = 0;
    end
end

if 0
    rg00 = sum(abs(buf1ft(:)).^2);
    rf00 = sum(abs(buf2ft(:)).^2);
    error = 1.0 - abs(CCmax).^2/(rg00*rf00);
    error = sqrt(abs(error));
else
    error = 0;
end
diffphase = angle(CCmax);

output=[error,diffphase,row_shift,col_shift,pln_shift];

% Compute registered version of buf2ft
if (nargout > 1)&&(usfac > 0)
    [Nc,Nr,Np] = meshgrid(Nc,Nr,Np);
    Greg = buf2ft.*exp(1i*2*pi*(-row_shift*Nr/nr-col_shift*Nc/nc-pln_shift*Np/np));
    Greg = Greg*exp(1i*diffphase);
elseif (nargout > 1)&&(usfac == 0)
    Greg = buf2ft*exp(1i*diffphase);
end
return

function out=dftups3d(in,nor,noc,nop,usfac,roff,coff,poff)
% function out=dftups(in,nor,noc,usfac,roff,coff);
% Upsampled DFT by matrix multiplies, can compute an upsampled DFT in just
% a small region.
% usfac         Upsampling factor (default usfac = 1)
% [nor,noc]     Number of pixels in the output upsampled DFT, in
%               units of upsampled pixels (default = size(in))
% roff, coff    Row and column offsets, allow to shift the output array to
%               a region of interest on the DFT (default = 0)
% Recieves DC in upper left corner, image center must be in (1,1)
% Manuel Guizar - Dec 13, 2007
% Modified from dftus, by J.R. Fienup 7/31/06

% This code is intended to provide the same result as if the following
% operations were performed
%   - Embed the array "in" in an array that is usfac times larger in each
%     dimension. ifftshift to bring the center of the image to (1,1).
%   - Take the FFT of the larger array
%   - Extract an [nor, noc] region of the result. Starting with the
%     [roff+1 coff+1] element.

% It achieves this result by computing the DFT in the output array without
% the need to zeropad. Much faster and memory efficient than the
% zero-padded FFT approach if [nor noc] are much smaller than [nr*usfac nc*usfac]

[nr,nc,np]=size(in);
% Set defaults
if exist('roff', 'var')~=1, roff=0;  end
if exist('coff', 'var')~=1, coff=0;  end
if exist('poff', 'var')~=1, poff=0;  end
if exist('usfac','var')~=1, usfac=1; end
if exist('noc',  'var')~=1, noc=nc;  end
if exist('nor',  'var')~=1, nor=nr;  end
if exist('nop',  'var')~=1, nop=np;  end

%tp3d =  @(x,y,z) reshape(kron(y(:),x(:))*z(:)',length(x),length(y),length(z));

% Compute kernels and obtain DFT by matrix products
%kernc=exp((-1i*2*pi/(nc*usfac))*( ifftshift(0:nc-1).' - floor(nc/2) )*( (0:noc-1) - coff ));
kernc=exp((-1i*2*pi/(nc*usfac))*((0:noc-1).' - coff) * (ifftshift(0:nc-1) - floor(nc/2)) );
kernr=exp((-1i*2*pi/(nr*usfac))*((0:nor-1).' - roff) * (ifftshift(0:nr-1) - floor(nr/2)) );
kernp=exp((-1i*2*pi/(np*usfac))*((0:nop-1).' - poff) * (ifftshift(0:np-1) - floor(np/2)) );

%kernc = exp((-1i*2*pi/(nc*usfac))*tp3d(ifftshift(0:nc-1) - floor(nc/2),(0:noc-1)-coff,(0:noc-1)-coff));
%kernr = exp((-1i*2*pi/(nr*usfac))*tp3d((0:nor-1)-roff,ifftshift(0:nr-1) - floor(nr/2),(0:nor-1)-roff));
%kernp = exp((-1i*2*pi/(np*usfac))*tp3d((0:nop-1)-poff,(0:nop-1)-poff,ifftshift(0:np-1) - floor(np/2)));
out = reshape(kernr*reshape(in,nr,[]),nor,nc,np);
out = permute(out,[2,1,3]);
out = reshape(kernc*reshape(out,nc,[]),noc,nor,np);
out = permute(out,[2,1,3]);
out = permute(out,[3,2,1]);
out = reshape(kernp*reshape(out,np,[]),noc,nor,nop);
out = permute(out,[3,2,1]);

%out=kernr*in*kernc;
return

function [ imFTout ] = FTpad3d(imFT,outsize)
% imFTout = FTpad3d(imFT,outsize)
% Pads or crops the Fourier transform to the desired ouput size. Taking
% care that the zero frequency is put in the correct place for the output
% for subsequent FT or IFT. Can be used for Fourier transform based
% interpolation, i.e. dirichlet kernel interpolation.
%
%   Inputs
% imFT      - Input complex array with DC in [1,1,1]
% outsize   - Output size of array [ny nx np]
%
%   Outputs
% imout   - Output complex image with DC in [1,1,1]
% Manuel Guizar - 2014.06.02
% modified by Eftychios A. Pnevmatikakis to include 3d analysis and max
% shifts - 2016.11.03

Nout = outsize;
Nin = size(imFT);
imFT = fftshift(imFT);
center = floor(size(imFT)/2)+1;
imFTout = zeros(outsize);
centerout = floor(size(imFTout)/2)+1;

% imout(centerout(1)+[1:Nin(1)]-center(1),centerout(2)+[1:Nin(2)]-center(2)) ...
%     = imFT;
cenout_cen = centerout - center;

imFTout(max(cenout_cen(1)+1,1):min(cenout_cen(1)+Nin(1),Nout(1)),max(cenout_cen(2)+1,1):min(cenout_cen(2)+Nin(2),Nout(2)),max(cenout_cen(3)+1,1):min(cenout_cen(3)+Nin(3),Nout(3))) ...
    = imFT(max(-cenout_cen(1)+1,1):min(-cenout_cen(1)+Nout(1),Nin(1)),max(-cenout_cen(2)+1,1):min(-cenout_cen(2)+Nout(2),Nin(2)),max(-cenout_cen(3)+1,1):min(-cenout_cen(3)+Nout(3),Nin(3)));

%imFTout2 = padarray(imFT,cenout_cen,0,'pre');
%imFTout = padarray(imFTout2,cenout_cen-mod(size(imFT),2),0,'post');
imFTout = ifftshift(imFTout)*Nout(1)*Nout(2)*Nout(3)/(Nin(1)*Nin(2)*Nin(3));
return


function [Zm]=SVD_filter(Z,P,T)

%Computer SVD
[U,S,V] = svd(Z);

%Normalising singular values
Ss=diag(S)-min(diag(S));
Ss=Ss./max(Ss);

%Creating smoothening parameters
p_max=P(1); %1=No blurring
p_min=P(2); %0=straight line fit
p=(Ss.*(p_max-p_min))+p_min; %Scale towards singular values

Zm=nan(size(Z));
for i=1:1:size(U,2)
    v=V(:,i); u=U(:,i); s=S(i,i); %components
    if Ss(i)<=T %Filter after threshold
        us = csaps(1:numel(u),u,p(i),1:numel(u))'; %Smooth u
        vs = csaps(1:numel(v),v,p(i),1:numel(v))'; %Smooth v
    else
        vs=v; us=u; %Keep unsmoothened
    end
    z=us*s*vs'; %sub-data
    Zm(:,:,i)=z;
end
Zm=sum(Zm,3);

%%
% _*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/>.


% TEST_MAXWELL_CUBE_H_DRCHLT: data function for Dirichlet boundary condition.

function h = test_maxwell_cube_h_drchlt (x, y, z, ind)

  h = zeros ([3, size(x)]);
  switch (ind)
    case 1
      h(2,:,:) = -exp(z) .* cos(x);
      h(3,:,:) = exp(x) .* cos(y);
    case 2
      h(2,:,:) = exp(z) .* cos(x);
      h(3,:,:) = -exp(x) .* cos(y);
    case 3
      h(1,:,:) = exp(z) .* cos(x);
      h(3,:,:) = -sin(y) .* z;
    case 4
      h(1,:,:) = -exp(z) .* cos(x);
      h(3,:,:) = sin(y) .* z;
    case 5
      h(1,:,:) = -exp(x) .* cos(y);
      h(2,:,:) = sin(y) .* z;
    case 6
      h(1,:,:) = exp(x) .* cos(y);
      h(2,:,:) = -sin(y) .* z;
    otherwise
      error ('h_drchlt: unknown reference number')
  end

end


function [ vx, vy ] = basisd_serene ( xq, yq, xw, ys, xe, yn, xx, yy )

%*****************************************************************************80
%
%% BASISD_SERENE differentiates the serendipity basis functions.
%
%  Discussion:
%
%    This procedure assumes that a serendipity element has been defined,
%    whose sides are parallel to coordinate axes.
%
%    The local element numbering is
%
%      YN  3--2--1
%       |  |     |
%       |  4     8
%       |  |     |
%      YS  5--6--7
%       |
%       +--XW---XE--
%
%    We note that each basis function can be written as the product of
%    three linear terms, which never result in an x^2y^2 term.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    29 June 2014
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, real XQ, YQ, the evaluation point.
%
%    Input, real XW, YS, the coordinates of the lower left corner.
%
%    Input, real XE, YN, the coordinates of the upper right corner.
%
%    Input, real XX(8), YY(8), the coordinates of the 8 nodes.
%
%    Output, real VX(8), VY(8), the derivatives of the basis functions
%    at (XQ,YQ) with respect to X and Y.
%
  vx = zeros(8,1);
  vy = zeros(8,1);

  vx(1) = ...
      not1d ( xq, xw, xx(1) ) ...
    * not1 ( yq, ys, yy(1) ) ...
    * not2 ( xq, yq, xx(8), yy(8), xx(2), yy(2), xx(1), yy(1) ) ...
    + not1 ( xq, xw, xx(1) ) ...
    * not1 ( yq, ys, yy(1) ) ...
    * not2dx ( xq, yq, xx(8), yy(8), xx(2), yy(2), xx(1), yy(1) );

  vy(1) = ...
      not1 ( xq, xw, xx(1) ) ...
    * not1d ( yq, ys, yy(1) ) ...
    * not2 ( xq, yq, xx(8), yy(8), xx(2), yy(2), xx(1), yy(1) ) ...
    + not1 ( xq, xw, xx(1) ) ...
    * not1 ( yq, ys, yy(1) ) ...
    * not2dy ( xq, yq, xx(8), yy(8), xx(2), yy(2), xx(1), yy(1) );

  vx(2) = ...
      not1d ( xq, xw, xx(2) ) ...
    * not1 ( xq, xe, xx(2) ) ...
    * not1 ( yq, ys, yy(2) ) ...
    + not1 ( xq, xw, xx(2) ) ...
    * not1d ( xq, xe, xx(2) ) ...
    * not1 ( yq, ys, yy(2) );

  vy(2) = ...
      not1 ( xq, xw, xx(2) ) ...
    * not1 ( xq, xe, xx(2) ) ...
    * not1d ( yq, ys, yy(2) );

  vx(3) = ...
      not1d ( xq, xe, xx(3) ) ...
    * not1 ( yq, ys, yy(3) ) ...
    * not2 ( xq, yq, xx(2), yy(2), xx(4), yy(4), xx(3), yy(3) ) ...
    + not1 ( xq, xe, xx(3) ) ...
    * not1 ( yq, ys, yy(3) ) ...
    * not2dx ( xq, yq, xx(2), yy(2), xx(4), yy(4), xx(3), yy(3) );

  vy(3) = not1 ( xq, xe, xx(3) ) ...
    * not1d ( yq, ys, yy(3) ) ...
    * not2 ( xq, yq, xx(2), yy(2), xx(4), yy(4), xx(3), yy(3) ) ...
    + not1 ( xq, xe, xx(3) ) ...
    * not1 ( yq, ys, yy(3) ) ...
    * not2dy ( xq, yq, xx(2), yy(2), xx(4), yy(4), xx(3), yy(3) );

  vx(4) = ...
      not1d ( xq, xe, xx(4) ) ...
    * not1 ( yq, yn, yy(4) ) ...
    * not1 ( yq, ys, yy(4) );

  vy(4) = ...
      not1 ( xq, xe, xx(4) ) ...
    * not1d ( yq, yn, yy(4) ) ...
    * not1 ( yq, ys, yy(4) ) ...
    + not1 ( xq, xe, xx(4) ) ...
    * not1 ( yq, yn, yy(4) ) ...
    * not1d ( yq, ys, yy(4) );

  vx(5) = ...
      not1d ( xq, xe, xx(5) ) ...
    * not1 ( yq, yn, yy(5) ) ...
    * not2 ( xq, yq, xx(4), yy(4), xx(6), yy(6), xx(5), yy(5) ) ...
    + not1 ( xq, xe, xx(5) ) ...
    * not1 ( yq, yn, yy(5) ) ...
    * not2dx ( xq, yq, xx(4), yy(4), xx(6), yy(6), xx(5), yy(5) );

  vy(5) = ...
      not1 ( xq, xe, xx(5) ) ...
    * not1d ( yq, yn, yy(5) ) ...
    * not2 ( xq, yq, xx(4), yy(4), xx(6), yy(6), xx(5), yy(5) ) ...
    + not1 ( xq, xe, xx(5) ) ...
    * not1 ( yq, yn, yy(5) ) ...
    * not2dy ( xq, yq, xx(4), yy(4), xx(6), yy(6), xx(5), yy(5) );

  vx(6) = ...
      not1d ( xq, xe, xx(6) ) ...
    * not1 ( xq, xw, xx(6) ) ...
    * not1 ( yq, yn, yy(6) ) ...
    + not1 ( xq, xe, xx(6) ) ...
    * not1d ( xq, xw, xx(6) ) ...
    * not1 ( yq, yn, yy(6) );

  vy(6) = ...
      not1 ( xq, xe, xx(6) ) ...
    * not1 ( xq, xw, xx(6) ) ...
    * not1d ( yq, yn, yy(6) );

  vx(7) = ...
      not1d ( xq, xw, xx(7) ) ...
    * not1 ( yq, yn, yy(7) ) ...
    * not2 ( xq, yq, xx(6), yy(6), xx(8), yy(8), xx(7), yy(7) ) ...
    + not1 ( xq, xw, xx(7) ) ...
    * not1 ( yq, yn, yy(7) ) ...
    * not2dx ( xq, yq, xx(6), yy(6), xx(8), yy(8), xx(7), yy(7) );

  vy(7) = ...
      not1 ( xq, xw, xx(7) ) ...
    * not1d ( yq, yn, yy(7) ) ...
    * not2 ( xq, yq, xx(6), yy(6), xx(8), yy(8), xx(7), yy(7) ) ...
    + not1 ( xq, xw, xx(7) ) ...
    * not1 ( yq, yn, yy(7) ) ...
    * not2dy ( xq, yq, xx(6), yy(6), xx(8), yy(8), xx(7), yy(7) );

  vx(8) = ...
      not1 ( yq, ys, yy(8) ) ...
    * not1 ( yq, yn, yy(8) ) ...
    * not1d ( xq, xw, xx(8) );

  vy(8) = ...
      not1d ( yq, ys, yy(8) ) ...
    * not1 ( yq, yn, yy(8) ) ...
    * not1 ( xq, xw, xx(8) ) ...
    + not1 ( yq, ys, yy(8) ) ...
    * not1d ( yq, yn, yy(8) ) ...
    * not1 ( xq, xw, xx(8) );

  return
end


function dydt=DouPenODE(t,y,m1,m2,a1,a2,L1,I1,I2,k1,k2,g)
dydt=[
    y(3,:);
    y(4,:);
    (-(I2*k1*y(3,:) + I2*k2*y(3,:) - I2*k2*y(4,:) + a2^2*k1*m2*y(3,:) + a2^2*k2*m2*y(3,:) - a2^2*k2*m2*y(4,:) + L1*a2^3*m2^2*y(4,:).^2.*sin(y(1,:) - y(2,:)) - (L1*a2^2*g*m2^2*sin(y(1,:)))/2 - I2*L1*g*m2*sin(y(1,:)) - (L1*a2^2*g*m2^2*sin(y(1,:) - 2*y(2,:)))/2 - I2*a1*g*m1*sin(y(1,:)) + (L1^2*a2^2*m2^2*y(3,:).^2.*sin(2*y(1,:) - 2*y(2,:)))/2 + L1*a2*k2*m2*y(3,:).*cos(y(1,:) - y(2,:)) - L1*a2*k2*m2*y(4,:).*cos(y(1,:) - y(2,:)) - a1*a2^2*g*m1*m2*sin(y(1,:)) + I2*L1*a2*m2*y(4,:).^2.*sin(y(1,:) - y(2,:)))./(I1*I2 + L1^2*a2^2*m2^2 + I2*L1^2*m2 + I2*a1^2*m1 + I1*a2^2*m2 - L1^2*a2^2*m2^2*cos(y(1,:) - y(2,:)).^2 + a1^2*a2^2*m1*m2));
    ((I1*k2*y(3,:) - I1*k2*y(4,:) + L1^2*k2*m2*y(3,:) - L1^2*k2*m2*y(4,:) + a1^2*k2*m1*y(3,:) - a1^2*k2*m1*y(4,:) + L1^3*a2*m2^2*y(3,:).^2.*sin(y(1,:) - y(2,:)) + L1^2*a2*g*m2^2*sin(y(2,:)) + I1*a2*g*m2*sin(y(2,:)) + (L1^2*a2^2*m2^2*y(4,:).^2.*sin(2*y(1,:) - 2*y(2,:)))/2 + L1*a2*k1*m2*y(3,:).*cos(y(1,:) - y(2,:)) + L1*a2*k2*m2*y(3,:).*cos(y(1,:) - y(2,:)) - L1*a2*k2*m2*y(4,:).*cos(y(1,:) - y(2,:)) - L1^2*a2*g*m2^2*cos(y(1,:) - y(2,:)).*sin(y(1,:)) + a1^2*a2*g*m1*m2*sin(y(2,:)) + I1*L1*a2*m2*y(3,:).^2.*sin(y(1,:) - y(2,:)) + L1*a1^2*a2*m1*m2*y(3,:).^2.*sin(y(1,:) - y(2,:)) - L1*a1*a2*g*m1*m2*cos(y(1,:) - y(2,:)).*sin(y(1,:)))./(I1*I2 + L1^2*a2^2*m2^2 + I2*L1^2*m2 + I2*a1^2*m1 + I1*a2^2*m2 - L1^2*a2^2*m2^2*cos(y(1,:) - y(2,:)).^2 + a1^2*a2^2*m1*m2))];


% interp_table_test.m

hr = inline('(1-abs(t/(J/2))) .* (abs(t) <= J/2)', 't', 'J');
hi = inline('(1-abs(t/(J/2))).^2 .* (abs(t) <= J/2)', 't', 'J');

% 1D
if 0
	L = 10;
	J = 6;
	s = [-J/2*L:J/2*L]'/L;
	hs = hr(s, J) + 1i * hi(s, J);
	if length(hs) ~= J*L+1, error 'size', end

	clf, subplot(211)
	plot(s, real(hs), 'c.-', s, imag(hs), 'y.-')

	K = 20;
	ck = zeros(K,1);
	ck(2+1) = 1;
	%ck = complexify(ck);
	tm = linspace(-2*K, 2*K, 2001)';
	fm = interp1_table_mex(ck, hs, int32(J), int32(L), tm);

	subplot(212)
	plot(tm, real(fm), 'c.-', tm, imag(fm), 'y.-')
end

% 2D
if 0
	L = [2^5 2^4];
	J = [6 4];
	s1 = [-J(1)/2*L(1):J(1)/2*L(1)]'/L(1);
	s2 = [-J(2)/2*L(2):J(2)/2*L(2)]'/L(2);
	h1 = 0*hr(s1, J(1)) + 1i * hi(s1, J(1));
	h2 = 0*hr(s2, J(2)) + 1i * hi(s2, J(2));
%	h1 = complexify(h1);
%	h2 = complexify(h2);

	clf, subplot(211)
	plot(	s1, real(h1), 'c.-', s1, imag(h1), 'y.-', ...
		s2, real(h2), 'g.-', s2, imag(h2), 'm.-')

	K = [8 12];
	ck = zeros(K);
	ck(0+1, 0+1) = -1i;
%	ck = complexify(ck);
	t1 = linspace(-2*K(1), 2*K(1), 201)';
	t2 = linspace(-2*K(2), 2*K(2), 199)';
	t1 = linspace(0, K(1), 201)';
	t2 = linspace(0, K(2), 199)';
	[tt1 tt2] = ndgrid(t1, t2);
	tm = [tt1(:) tt2(:)];
%	tic
	fm = interp2_table_mex(ck, h1, h2, int32(J), int32(L), tm);
%	toc
	fm = reshape(fm, size(tt1));

	im(121, t1, t2, real(fm), 'real'), cbar
	im(122, t1, t2, imag(fm), 'imag'), cbar
end

% 3D
if 1
	L = [2^5 2^4 2^6];
	J = [5 3 4];
	s1 = [-J(1)/2*L(1):J(1)/2*L(1)]'/L(1);
	s2 = [-J(2)/2*L(2):J(2)/2*L(2)]'/L(2);
	s3 = [-J(3)/2*L(3):J(3)/2*L(3)]'/L(3);
	h1 = 1 * hr(s1, J(1)) + 0i * hi(s1, J(1));
	h2 = 1 * hr(s2, J(2)) + 0i * hi(s2, J(2));
	h3 = 1 * hr(s3, J(3)) + 0i * hi(s3, J(3));
	h1 = complexify(h1);
	h2 = complexify(h2);
	h3 = complexify(h3);

	clf, subplot(211)
	plot(	s1, real(h1), 'c.-', s1, imag(h1), 'y.-', ...
		s2, real(h2), 'g.-', s2, imag(h2), 'm.-', ...
		s3, real(h3), 'y.-', s3, imag(h3), 'w.-')

	K = [8 12 4];
	ck = zeros(K);
	ck(0+1, 0+1) = 1i;
	ck = complexify(ck);
	t1 = linspace(-2*K(1), 2*K(1), 69)';
	t2 = linspace(-2*K(2), 2*K(2), 89)';
	t3 = linspace(-2*K(3), 2*K(3), 9)';
%	t1 = linspace(0, K(1), 201)';
%	t2 = linspace(0, K(2), 199)';
	t3 = [-1 0 1];
	[tt1 tt2 tt3] = ndgrid(t1, t2, t3);
	tm = [tt1(:) tt2(:) tt3(:)];
	tic
	fm = interp3_table_mex(ck, h1, h2, h3, int32(J), int32(L), tm);
	toc
	fm = reshape(fm, size(tt1));

	im(121, t1, t2, real(fm), 'real'), cbar
	im(122, t1, t2, imag(fm), 'imag'), cbar
	if length(t3) == 1 % compare to 2D
		f2 = interp2_table_mex(ck, h1, h2, ...
			int32(J(1:2)), int32(L(1:2)), tm(:,1:2));
		f2 = reshape(f2, size(tt1));
		max_percent_diff(f2, fm)
	end
end


% VL_DEMO_SLICT  Demo: SLIC superpixels

prefix = fullfile(vl_root,'figures','demo') ;
randn('state',0) ;
rand('state',0) ;
figure(1) ; clf ;

% --------------------------------------------------------------------
%                                                        Load a figure
% --------------------------------------------------------------------

im = imread(fullfile(vl_root,'data','roofs1.jpg')) ;
im = im2single(im) ;
im = im(1:128,end-128+1:end,:) ;

figure(1) ; clf ;
image(im) ;
axis equal off tight ;
vl_demo_print('slic_image') ;

% --------------------------------------------------------------------
%                                    Create various SLIC segmentations
% --------------------------------------------------------------------

regionSizes = [10 30] ;
regularizers = [0.01 0.1 1] ;

figure(2) ; clf ;
for i = 1:numel(regionSizes)
  for j = 1:numel(regularizers)
    regionSize = regionSizes(i) ;
    regularizer = regularizers(j) ;
    segments = vl_slic(im, regionSize, regularizer, 'verbose') ;

    % overaly segmentation
    [sx,sy]=vl_grad(double(segments), 'type', 'forward') ;
    s = find(sx | sy) ;
    imp = im ;
    imp([s s+numel(im(:,:,1)) s+2*numel(im(:,:,1))]) = 0 ;

    vl_tightsubplot(numel(regionSizes),numel(regularizers), (i-1)*numel(regularizers) + j) ;
    imagesc(imp) ; axis image off ; hold on ;
    text(5,5,sprintf('regionSize:%.2g\nregularizer:%.2g', regionSize, regularizer), ...
         'Background', 'white','VerticalAlignment','top')
  end
end

vl_demo_print('slic_segmentation') ;


function [g,info] = gabwin(g,a,M,varargin);
%GABWIN  Compute a Gabor window from text or cell array
%   Usage: [g,info] = gabwin(g,a,M,L);
%
%   `[g,info]=gabwin(g,a,M,L)` computes a window that fits well with the
%   specified number of channels *M*, time shift *a* and transform length
%   *L*. The window itself is specified by a text description or a cell array
%   containing additional parameters.
%
%   The window can be specified directly as a vector of numerical
%   values. In this case, `gabwin` only checks assumptions about transform
%   sizes etc.
%
%   `[g,info]=gabwin(g,a,M)` does the same, but the window must be a FIR
%   window, as the transform length is unspecified.
%
%   `gabwin(g,a,M,L,lt)` or `gabwin(g,a,M,[],lt)` does as above but for a
%   non-separable lattice specified by *lt*. Please see the help of
%   |matrix2latticetype| for a precise description of the parameter *lt*.
%
%   The window can be specified as one of the following text strings:
%
%     'gauss'      Gaussian window fitted to the lattice,
%                  i.e. $tfr=a\cdot M/L$.
%
%     'dualgauss'  Canonical dual of Gaussian window.
%
%     'tight'      Tight window generated from a Gaussian.
%
%   In these cases, a long window is generated with a length of *L*.
%
%   It is also possible to specify one of the window names from |firwin|. In
%   such a case, `gabwin` will generate the specified FIR window with a length
%   of *M*.
%
%   The window can also be specified as cell array. The possibilities are:
%
%     `{'gauss',...}`
%         Additional parameters are passed to |pgauss|. When no additional
%         parameters are passed, the window is generated according to the
%         defaults in |pgauss|.
%
%     `{'dual',...}`
%         Canonical dual window of whatever follows. See the examples below.
%
%     `{'tight',...}`
%         Canonical tight window of whatever follows.
%
%   It is also possible to specify one of the window names from |firwin| as
%   the first field in the cell array. In this case, the remaining
%   entries of the cell array are passed directly to |firwin|.
%
%   Some examples: To compute a Gaussian window of length *L* fitted for a
%   system with time-shift *a* and *M* channels use::
%
%     g=gabwin('gauss',a,M,L);
%
%   To compute Gaussian window with equal time and frequency support
%   irrespective of *a* and *M*::
%
%     g=gabwin({'gauss'},a,M,L);
%
%   To compute the canonical dual of a Gaussian window fitted for a
%   system with time-shift *a* and *M* channels::
%
%     gd=gabwin('gaussdual',a,M,L);
%
%   To compute the canonical tight window of the Gaussian window fitted
%   for the system::
%
%     gd=gabwin({'tight','gauss'},a,M,L);
%
%   To compute the dual of a Hann window of length 20::
%
%     g=gabwin({'dual',{'hann',20}},a,M,L);
%
%   The structure *info* provides some information about the computed
%   window:
%
%     `info.gauss`
%        True if the window is a Gaussian.
%
%     `info.tfr`
%        Time/frequency support ratio of the window. Set whenever it makes sense.
%
%     `info.wasrow`
%        Input was a row window
%
%     `info.isfir`
%        Input is an FIR window
%
%     `info.isdual`
%        Output is the dual window of the auxiliary window.
%
%     `info.istight`
%        Output is known to be a tight window.
%
%     `info.auxinfo`
%        Info about auxiliary window.
%
%     `info.gl`
%        Length of window.
%
%   See also: pgauss, firwin, wilwin

% Assert correct input.
if nargin<3
  error('%s: Too few input parameters.',upper(mfilename));
end;

definput.keyvals.L=[];
definput.keyvals.lt=[0 1];
definput.keyvals.callfun='GABWIN';
definput.flags.phase={'freqinv','timeinv'};
[~,kv,L,lt]=ltfatarghelper({'L','lt'},definput,varargin,'gabwin');

[g,info] = comp_window(g,a,M,L,lt,kv.callfun);


function y=teager(x,d,m)
%TEAGER calculate teager energy waveform Y=(X,D,M)
%
%  Inputs:  x         speech signal
%           d         dimension to apply filter along [default 1st non-singleton]
%           m         Normally Y has the same length as X and the first
%                     and last output samples are extrapolated. Setting m='x'
%                     supresses this extrapolation and Y will be two
%                     samples shorter than X
%
% Outputs:  Y         output signal: y(n)=abs(x(n))^2 - x(n+1)*conj(x(n-1))
%
% Calculates the Teager energy waveform [1]. The following waveforms give
% a constant output (independent of n) where A, B, C are real constants:
%  (a) x(n) = A*sin(B*n+C)    -->   y(n) = (A*sin(B))^2
%  (b) x(n) = A*n + B         -->   y(n) = A^2
%  (c) x(n) = A*exp(j(B*n+C)) -->   y(n) = A^2*(1-exp(2jB))
%  (d) x(n) = A*exp(B*n+C)    -->   y(n) = 0
%
% Reference:
%  [1]	J. Kaiser. On a simple algorithm to calculate the energy of a signal.
%       In Proc IEEE Intl Conf Acoustics, Speech and Signal Processing,
%       pages 381384, vol.1, Apr. 1990. doi: 10.1109/ICASSP.1990.115702.

%      Copyright (C) Mike Brookes 1997
%      Version: $Id: teager.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.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
e=size(x);
p=prod(e);
if nargin<2             % if no dimension given, find the first non-singleton
    d=find(e>1,1);
    if ~numel(d)
        d=1;
    end
end
k=e(d);                 % size of active dimension
q=p/k;                  % size of remainder
if d==1
    z=reshape(x,k,q);
else
    z=shiftdim(x,d-1);
    r=size(z);
    z=reshape(z,k,q);
end
if nargin>2 && any(m=='x')
    y=z(2:k-1,:).*conj(z(2:k-1,:))-z(3:k,:).*conj(z(1:k-2,:));
    k=k-2;              % we have lost two elements
elseif k>=4
    y=zeros(k,q);
    y(2:k-1,:)=z(2:k-1,:).*conj(z(2:k-1,:))-z(3:k,:).*conj(z(1:k-2,:));
    y(1,:)=2*y(2,:)-y(3,:);             % linearly interpolate the end points
    y(k,:)=2*y(k-1,:)-y(k-2,:);
elseif k==3
    y=repmat(x(2,:).*conj(x(2,:))-x(3,:).*conj(x(1,:)),3,1);
else
    y=zeros(k,q);
end
if d==1
    e(d)=k;
    y=reshape(y,e);
else
    r(1)=k;
    y=shiftdim(reshape(y,r),length(e)+1-d);
end


function n = cube_arbq_size ( degree )

%*****************************************************************************80
%
%% CUBE_ARBQ_SIZE returns the size of quadrature rule for a cube.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    08 July 2014
%
%  Author:
%
%    John Burkardt.
%
%  Reference:
%
%    Hong Xiao, Zydrunas Gimbutas,
%    A numerical algorithm for the construction of efficient quadrature
%    rules in two and higher dimensions,
%    Computers and Mathematics with Applications,
%    Volume 59, 2010, pages 663-676.
%
%  Parameters:
%
%    Input, integer DEGREE, the desired degree of exactness.
%    1 <= DEGREE <= 15.
%
%    Output, integer N, the number of points in the
%    corresponding rule.
%
  n_save = [ ...
      1,   4,   6,  10,  13, ...
     22,  26,  42,  50,  73, ...
     84, 116, 130, 172, 190 ];

  if ( degree < 1 | 15 < degree )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'CUBE_ARBQ_SIZE - Fatal error!\n' );
    fprintf ( 1, '  Illegal value of DEGREE.\n' );
    error ( 'CUBE_ARBQ_SIZE - Fatal error!' );
  end

  n = n_save ( degree );

  return
end


% pivot_setup.m // Jon Lee
% set up a pivoting example

clear all;

global A b c m n beta eta

try
    reply = input('NAME of NAME.m file holding input? [pivot_input]: ', 's');
    if isempty(reply)
       reply = 'pivot_input';
       end
catch
    reply = 'pivot_input'; % need catch for execution on MathWorks Cloud
end
eval(reply);

if (size(b) ~= m)
    display('size(b) does not match number of rows of A')
    return
end
if (size(c) ~= n)
    display('size(c) does not match number of columns of A')
    return
end
if(size(setdiff(beta,1:n)) > 0)
    display('beta has elements not in 1,2,...,n')
    return
end
if(size(setdiff(eta,1:n)) > 0)
    display('eta has elements not in 1,2,...,n')
    return
end
if (size(beta) ~= m)
    display('size(beta) does not match number of rows of A')
    return
end
if (size(eta) ~= n-m)
    display('size(eta) does not match number of cols minus number of rows of A')
    return
end

display('Available quantites: A, b, c, m, n, beta, eta');
display('Seems like a good time to run pivot_algebra');


function [pp, err] = MitsunagaNayarCRFFull(stack_samples, stack_exposure, N, maxIterations)
%
%       [pp, err] = MitsunagaNayarCRFFull(stack, stack_exposure, N, nSamples, sampling_strategy)
%
%       This function computes camera response function using Mitsunaga and
%       Nayar method.
%
%        Input:
%           -stack_samples: a stack of samples from LDR images
%           -nSamples: number of samples for computing the CRF
%           -N: polynomial degree of the inverse CRF
%           -maxIterations:
%
%        Output:
%           -pp: a polynomial encoding the inverse CRF
%           -err: the error
%
%     Copyright (C) 2016  Francesco Banterle
%
%     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/>.
%

if(~exist('maxIterations', 'var'))
    maxIterations = -1;
end

threshold = 1e-4;

col = size(stack_samples, 3);

Q = length(stack_exposure);

Mmax = 1.0;

%recovering the CRF
function d = MN_d(c, q1, q2, n)

    M_q   = stack_samples(:, q1, c);
    M_q_p = stack_samples(:, q2, c);

    indx = find(M_q > 0.0 & M_q_p > 0.0);

    d = M_q(indx).^n - R(q1, q2) * (M_q_p(indx).^n);
end

pp = zeros(N + 1, col);
pp_prev = zeros(N + 1, col);

x = (0:255) / 255;

err = 0.0;

R0 = ones(Q - 1, Q - 1);
for q1=1:(Q - 1)
    for q2=1:(Q - 1)
        if(q1 ~= q2)
            R0(q1, q2) = stack_exposure(q1) / stack_exposure(q2);
        end
    end
end

for c=1:col

    R = R0;

    bLoop = 1;
    iter = 0;

    while(bLoop)
        A = zeros(N, N);
        b = zeros(N, 1);

        for i=1:N
            %init A
            for j=1:N
                for q1=1:(Q - 1)
                    for q2=1:(Q - 1)
                        if(q1 ~= q2)
                            delta  = MN_d(c, q1, q2, j - 1) - MN_d(c, q1, q2, N);
                            A(i,j) = A(i,j) + sum(MN_d(c, q1, q2, i - 1) .* delta);
                        end
                    end
                end
            end

            %init b
            for q1=1:(Q - 1)
                for q2=1:(Q - 1)
                    if(q1 ~= q2)
                        b(i) = b(i) - sum(Mmax * MN_d(c, q1, q2, i - 1) .* MN_d(c, q1, q2, N));
                    end
                end
            end
        end

        coeff = A \ b;
        coeff_n = Mmax - sum(coeff);

        pp(:,c) = flip([coeff; coeff_n]);

        f_1 = polyval(pp(:,c),      x);
        f_2 = polyval(pp_prev(:,c), x);
        bLoop = max(abs(f_1 - f_2) > threshold);

        bLoop = bLoop & (iter < maxIterations);

        if(bLoop)
            pp_prev = pp;

            %update R
            for q=1:(Q - 1)
                for q2=1:(Q - 1)
                    if(q1 ~= q2)
                        s1 = stack_samples(:, q1    , c);
                        s2 = stack_samples(:, q2, c);

                        indx = find(s1 > 0.0 & s2 > 0.0);

                        e1 = polyval(pp(:,c), s1(indx));
                        e2 = polyval(pp(:,c), s2(indx));
                        R(q1, q2) = sum(e1) / sum(e2);
                    end
                end
            end

            iter = iter + 1;
        end
    end

    %compute err
    for q1=1:(Q - 1)
        for q2=1:(Q - 1)
            if(q1 ~= q2)
                s1 = stack_samples(:, q1, c);
                s2 = stack_samples(:, q2, c);

                indx = find(s1 > 0.0 & s2 > 0.0);

                e1 = polyval(pp(:, c), s1(indx));
                e2 = polyval(pp(:, c), s2(indx));
                err = err + sum((e1 - R(q1, q2) * e2).^2);
            end
        end
    end
end

end


function yp = p13_fun ( neqn, t, y )

%*****************************************************************************80
%
%% P13_FUN evaluates the function for problem P13.
%
%  Discussion:
%
%    10 equations.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    18 February 2013
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Wayne Enright, John Pryce,
%    Algorithm 648,
%    ACM Transactions on Mathematical Software,
%    Volume 13, Number 1, pages 28-34.
%
%  Parameters:
%
%    Input, integer NEQN, the number of equations.
%
%    Input, real T, Y(NEQN), the arguments of the derivative
%    function.
%
%    Output, real YP(NEQN), the value of the derivative function.
%
  yp = zeros ( neqn, 1 );

  yp(1)        =             - 2.0 * y(1) + y(2);
  yp(2:neqn-1) = y(1:neqn-2) - 2.0 * y(2:neqn-1) + y(3:neqn);
  yp(neqn)     = y(neqn-1)   - 2.0 * y(neqn);

  return
end


function str = mean2str(m,s,n,varargin)

%mean2str - Convert mean or median and SEM (or confidence interval) to string.
%
%  USAGE
%
%    s = mean2str(m,s,n,<options>)
%
%    m              mean or median
%    s              standard error (see sem or semedian) or confidence interval
%    n              optional number of observations
%    <options>      optional list of property-value pairs (see table below)
%
%    =========================================================================
%     Properties    Values
%    -------------------------------------------------------------------------
%     'precision'   number of digits (default = 3)
%     'split'       split the output in two cells, e.g. for small figures
%                   (default = 'off')
%    =========================================================================

% Copyright (C) 2013 by Michaël Zugaro
%
% 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.

% Default values
precision = 3;
split = 'off';

% Check parameters
if nargin < 2,
  error('Incorrect number of parameters (type ''help mean2str'' for details).');
end
if ~isdscalar(m),
  error('Incorrect mean or median (type ''help mean2str'' for details).');
end
if ~isdscalar(s) && ~isdvector(s,'<=','#2'),
  error('Incorrect SEM or confidence interval (type ''help mean2str'' for details).');
end

% Optional number of observations
if nargin < 3,
	n = [];
elseif ischar(n),
	varargin = {n,varargin{:}};
	n = [];
elseif ~isiscalar(n,'>0'),
  error('Incorrect number of observations (type ''help mean2str'' for details).');
end

% Parse parameter list
for i = 1:2:length(varargin),
  if ~ischar(varargin{i}),
    error(['Parameter ' num2str(i+2) ' is not a property (type ''help mean2str'' for details).']);
  end
  switch(lower(varargin{i})),
    case 'precision',
      precision = varargin{i+1};
      if ~isiscalar(precision,'>0'),
        error('Incorrect value for property ''precision'' (type ''help mean2str'' for details).');
      end
    case 'split',
      split = lower(varargin{i+1});
      if ~isstring_FMAT(split,'on','off'),
        error('Incorrect value for property ''split'' (type ''help mean2str'' for details).');
      end
    otherwise,
      error(['Unknown property ''' num2str(varargin{i}) ''' (type ''help mean2str'' for details).']);
  end
end

format = ['%.' int2str(precision) 'f'];
if isdscalar(s),
	str = [sprintf(format,m) ' +- '  sprintf(format,s)];
else
	str = [sprintf(format,m) ' [' sprintf(format,s(1)) ',' sprintf(format,s(2)) ']'];
end
if ~isempty(n),
	if strcmp(split,'on'),
		str = {str,['(N=' int2str(n) ')']};
	else
		str = [str ' (N=' int2str(n) ')'];
	end
end


function update_weights_adagrad()
    global config mem;
    for m = 1:length(config.weights)
        config.his_grad{m} = config.his_grad{m} + mem.grads{m} .* mem.grads{m};
        config.weights{m} = config.weights{m} - config.learning_rate * (mem.grads{m} ./ (config.fudge_factor + sqrt(config.his_grad{m})));
    end
end


function [D,entropies] = findKLDivergences(data)
%finds the KL-divergences (D) and entropies between all rows in 'data'

    N = length(data(:,1));
    logData = log(data);
    logData(isinf(logData) | isnan(logData)) = 0;

    entropies = -sum(data.*logData,2);

    D = - data * logData';
    D = bsxfun(@minus,D,entropies);

    D = D ./ log(2);
    D(1:(N+1):end) = 0;


function y = generalized_charbonnier(x, sigma, type)
%CHARBONNIER  GENERALIZED_Charbonnier robust function.
%   CHARBONNIER(X, SIGMA, TYPE) evaluates the Charbonnier robust function
%   with sigma SIGMA at point(s) X.
%   TYPE selects the evaluation type:
%    - 0: function value
%    - 1: first derivative
%    - 2: second derivative
%
%   This is a private member function of the class 'robust_function'.
%
% Authors: Deqing Sun, Department of Computer Science, Brown University
%          Stefan Roth, Department of Computer Science, TU Darmstadt
% Contact: dqsun@cs.brown.edu, sroth@cs.tu-darmstadt.de
% $Date: $
% $Revision: $

% Copyright 2004-2007, Brown University, Providence, RI. USA
% Copyright 2007-2010 TU Darmstadt, Darmstadt, Germany.
%
%                          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.

  sig  = sigma(1);
  a    = sigma(2);

  switch (type)
   case 0
    y = (sig^2 + x.^2).^a;
   case 1
    y = 2*a*x.*(sig^2 + x.^2).^(a-1);
    %y = x ./ sqrt(1 + x.^2 / sigma^2);
   case 2
    y = 2*a*(sig^2 + x.^2).^(a-1);
  end


% test for steerable transform

n = 512;
name = 'turbulence';
name = 'barb';
name = 'disk';
name = 'lena';
M = load_image(name,n);

k = 4;
options.nb_orientations = k;
J = 4;
Jmax = log2(n)-1;
Jmin = Jmax-J+1;
MW = perform_steerable_transform(M,Jmin,options);
M2 = perform_steerable_transform(MW,Jmin,options);

save_image = 1;
rep = ['results/steerable/'];

% reconstruction error
disp(['--> Reconstruction error: ' num2str(psnr(M,M2)) 'dB']);

if ~exist(rep)
    mkdir(rep);
end

% display and save the images
m = 0;
clf;
warning off;
for j=1:J
    for s=1:k
        m = m+1;
        A = MW{m+1};
        % A = rescale_wavelet_coefs(M,eta);
        str = ['j' num2str(j) '-s' num2str(s)];
        imageplot(A, str, k,J,m)
        if save_image
            imwrite(rescale(MW{m+1}), [rep name '-' str '.png'], 'png');
%            imwrite(rescale(MW{m+1}), [rep name '-' str '.jpg'], 'jpg');
        end
    end
end
colormap gray(256);

if save_image
    imwrite(rescale(M), [rep name '-original.png'], 'png');
    imwrite(rescale(MW{1}), [rep name '-high.png'], 'png');
    imwrite(rescale(MW{end}), [rep name '-low.png'], 'png');
end
warning on;


function q = wrap2 ( m, q )

%*****************************************************************************80
%
%% WRAP2 is a circular wrap of the pointer offset Q.
%
%  Discussion:
%
%    Input values of Q between 0 and M are 'legal'.
%    Values of Q below 0 are incremented by M + 1 until they are legal.
%    Values of Q above M are decremented by M + 1 until they become legal.
%    The legal value is the output value of the function.
%
%  Example:
%
%    M  Qin  Qout
%
%    3  -5   3
%    3  -4   0
%    3  -3   1
%    3  -2   2
%    3  -1   3
%    3   0   0
%    3   1   1
%    3   2   2
%    3   3   3
%    3   4   0
%    3   5   1
%    3   6   2
%    3   7   3
%    3   8   0
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    31 May 2010
%
%  Author:
%
%    Original C version by Sophocles Orfanidis.
%    This MATLAB version by John Burkardt.
%
%  Reference:
%
%    Sophocles Orfanidis,
%    Introduction to Signal Processing,
%    Prentice-Hall, 1995,
%    ISBN: 0-13-209172-0,
%    LC: TK5102.5.O246.
%
%  Parameters:
%
%    Input, integer M, the maximum acceptable value for outputs.
%    M must be at least 0.
%
%    Input, integer Q, the value to be wrapped.
%
%    Output, integer Q, the wrapped value.
%
  if ( m < 0 )
    fprintf ( 2, '\n' );
    fprintf ( 2, 'WRAP2 - Fatal error!\n' );
    fprintf ( 2, '  M < 0.\n' );
    error ( 'WRAP2 - Fatal error!' );
  end
%
%  When Q = M + 1, it wraps to Q = 0.
%
  while ( m < q )
    q = q - m - 1;
  end
%
%  When Q = - 1, it wraps to Q = M.
%
  while ( q < 0 )
    q = q + m + 1;
  end

  return
end


function stroud_test26 ( )

%*****************************************************************************80
%
%% TEST26 tests QMULT_1D.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    06 April 2009
%
%  Author:
%
%    John Burkardt
%
  num = function_1d_num ( );

  a = -1.0;
  b = 1.0;

  fprintf ( 1, '\n' );
  fprintf ( 1, 'TEST26\n' );
  fprintf ( 1, '  QMULT_1D approximates an integral on a\n' );
  fprintf ( 1, '    one-dimensional interval.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  We use the interval:\n' );
  fprintf ( 1, '  A = %f\n', a );
  fprintf ( 1, '  B = %f\n', b );
  fprintf ( 1, '\n' );
  fprintf ( 1, '    F(X)     QMULT_1D\n' );
  fprintf ( 1, '\n' );

  for i = 1 : num

    function_1d_set ( 'SET', i );

    result = qmult_1d ( 'function_1d', a, b );

    fname = function_1d_name ( i );

    fprintf ( 1, '  %s  %12f\n', fname, result );

  end

  return
end


function c8_atan_test ( )

%*****************************************************************************80
%
%% C8_ATAN_TEST tests C8_ATAN.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    11 February 2015
%
%  Author:
%
%    John Burkardt
%
  seed = 123456678;

  fprintf ( 1, '\n' );
  fprintf ( 1, 'C8_ATAN_TEST\n' );
  fprintf ( 1, '  C8_ATAN computes the inverse tangent of a C8.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, ...
    '       C1=C8_UNIFORM_01          C2 = C8_ATAN(C1)           C3 = C8_TAN(C2)\n' );
  fprintf ( 1, '     ---------------------     ---------------------     ---------------------\n' );
  fprintf ( 1, '\n' );

  for test = 1 : 10

    [ c1, seed ] = c8_uniform_01 ( seed );

    c2 = c8_atan ( c1 );

    c3 = c8_tan ( c2 );

    fprintf ( 1, '  (%12f  %12f)  (%12f  %12f)  (%12f  %12f)\n', ...
      real ( c1 ), imag ( c1 ), real ( c2 ), imag ( c2 ), real ( c3 ), imag ( c3 ) );

  end

  return
end


function [node,elem,indexMap] = rmisopoint(node,elem,gflag)
%% RMISOPOINT remove isolate points
%
% [node,elem] = rmisopoint(node,elem) rmove isolate points in the
% triangulation (node,elem). Isolate points are interiori vertices with
% valence 3 and boundary vertices with valence 2. Here the valence of a
% vertex is defined as the triangles containing that vertex.
%
% [node,elem,indexMap] = rmisopoint(node,elem) also return the index map
% between the input and output vertices. Since some vertices could be
% deleted in the procedure, the indexMap is important for the interpolation
% of functions defined on these vertices. See nodeinterpolate.
%
% Example
%   load airfoilperturb
%   [node,elem] = rmisopoint(node,elem);
%
% See also  bdsmoothing, edgeswap, nodeinterpolate
%
% Copyright (C) Long Chen. See COPYRIGHT.txt for details.

N = size(node,1); NT = size(elem,1);
%% Find boundary nodes
bdNode = findboundary(elem);
isBdNode = false(N,1);
isBdNode(bdNode) = true;
isIntNode = ~isBdNode;
intNode = find(~isBdNode);

%% Compute valence and find isolate points
valence = accumarray(elem(:),ones(3*NT,1),[N 1]);
isIsoNode = false(N,1);
isIsoNode(bdNode(valence(isBdNode)==2)) = true;
isIsoNode(intNode(valence(isIntNode)==3)) = true;
isoNode = find(isIsoNode);

%% Construct node star of isolated points
isIsoElem = isIsoNode(elem(:,1))|isIsoNode(elem(:,2))|isIsoNode(elem(:,3));
isoElem = find(isIsoElem);
tt = elem(isIsoElem,:);
q = simpqual(node,tt);
Ntt = size(tt,1);
tt2v = sparse([1:Ntt,1:Ntt,1:Ntt], tt(1:Ntt,:), 1, Ntt, N);

%% Remove isolate points
for i = 1:length(isoNode)
    pi = isoNode(i);
    ring = find(tt2v(:,pi));
    qi = min(q(ring));
    if qi>0.65  % don't remove this point
        isIsoNode(isoNode(i)) = false;
    else % remove this isolate point
        allpt = tt(ring,:);
        linkpt = setdiff(unique(allpt(:)),pi);
        if isIntNode(pi) % interior isolate points
            newt = fixorder(node,linkpt');
            tt(ring(1),:) = newt;
            tt(ring(2:end),:) = 0;
            % isoElem is used as an index mapping from tt to t
            elem(isoElem(ring(1)),:) = newt;
            elem(isoElem(ring(2:end)),1) = 0;
        elseif (isBdNode(pi) && isempty(find(linkpt == 0,1)))
        % Corner/feature points could be isolate nodes. Remove these
        % points will change the shape (and thus the area) of the mesh.
            newt = fixorder(node,linkpt');
            newarea = simplexvolume(node,newt);
            oldarea = sum(simplexvolume(node,tt(ring,:)));
            newq = simpqual(node,newt);
            if (abs(newarea-oldarea)/oldarea < 1e-3) && (newq>qi)
                tt(ring(1),:) = newt;
                q(ring(1)) = newq;
                tt(ring(2:end),:) = 0;
                elem(isoElem(ring(1)),:) = newt;
                elem(isoElem(ring(2:end)),1) = 0;
            else
                isIsoNode(isoNode(i)) = false;
            end
        else % linkpt contains 0, which means some triangles are deleted
            isIsoNode(isoNode(i)) = false;
        end
    end
end
%% Graph
if (nargin>2) && (gflag == 1)
    showmesh(node,elem);
    hold on; findnode(node,isIsoNode,'noindex','color','r')
end
%% Clean up
elem((elem(:,1) == 0),:) = [];
node(isIsoNode,:) = [];
indexMap = zeros(N,1);
indexMap(~isIsoNode)= 1:size(node,1);
elem = indexMap(elem);


function i4vec_frac_test ( )

%*****************************************************************************80
%
%% I4VEC_FRAC_TEST tests I4VEC_FRAC;
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 April 2009
%
%  Author:
%
%    John Burkardt
%
  n = 10;
  b = 1;
  c = 2 * n;
  seed = 123456789;

  fprintf ( 1, '\n' );
  fprintf ( 1, 'I4VEC_FRAC_TEST\n' );
  fprintf ( 1, '  I4VEC_FRAC: K-th smallest integer vector entry.\n' );
  fprintf ( 1, '  Using initial random number seed = %d\n', seed );

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

  i4vec_print ( n, a, '  The array to search:' );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  Fractile    Value\n' );
  fprintf ( 1, '\n' );

  for k = 1 : floor ( n / 2 ) : n

    afrac = i4vec_frac ( n, a, k );

    fprintf ( 1, '  %6d  %6d\n', k, afrac );

  end

  return
end


function [ amin, amax ] = r8vec_range_2 ( n, a, amin, amax )

%*****************************************************************************80
%
%% R8VEC_RANGE_2 updates a range to include a new array.
%
%  Discussion:
%
%    Given a range AMIN to AMAX, and an array A, the routine will
%    decrease AMIN if necessary, or increase AMAX if necessary, so that
%    every entry of A is between AMIN and AMAX.
%
%    However, AMIN will not be increased, nor AMAX decreased.
%
%    This routine may be used to compute the maximum and minimum of a
%    collection of arrays one at a time.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 May 2005
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer N, the number of entries in the array.
%
%    Input, real A(N), the array.
%
%    Input, real AMIN, AMAX, the current legal range of values for A.
%
%    Output, real AMIN, AMAX, unchanged, or else "widened" so that all entries
%    of A are within the range.
%
  amax = max ( amax, max ( a(1:n) ) );
  amin = min ( amin, min ( a(1:n) ) );

  return
end


function [BC,side,r] = voxel_grid(V,side,varargin)
  % VOXEL_GRID Prepare a voxel grid around a set of points V
  %
  % [BC,side,r] = voxel_grid(V,side,varargin)
  %
  % Inputs:
  %   V  #V by 3 list of input point positions
  %   side  either:
  %     scalar specifying how many steps along the x-coordinate of V's bounding
  %     box
  %          or
  %     3 list specifying how many steps in x, y, and z coordinates of V's
  %       bounding box
  %   Optional:
  %     'Pad' followed by the number of "extra cells" to add on all six sides
  %       of the grid (pad_count).
  % Outputs:
  %   BC  prod(side+2*pad_count) by 3 list of cell centers
  %   side  number of cells on each side: side+2*pad_count
  %   r  size of step in each direciton
  %
  % See also: voxelize

  pad_count = 0;
  % default values
  % Map of parameter names to variable names
  params_to_variables = containers.Map( ...
    {'Pad'}, ...
    {'pad_count'});
  v = 1;
  while v <= numel(varargin)
    param_name = varargin{v};
    if isKey(params_to_variables,param_name)
      assert(v+1<=numel(varargin));
      v = v+1;
      % Trick: use feval on anonymous function to use assignin to this workspace
      feval(@()assignin('caller',params_to_variables(param_name),varargin{v}));
    else
      error('Unsupported parameter: %s',varargin{v});
    end
    v=v+1;
  end

  dim = size(V,2);

  assert(all(side>(pad_count*2+1)),'side should be > 2*pad_count+1');
  side = side-pad_count*2;
  switch numel(side)
  case 3
    side(1) = side(1);
    side(2) = side(2);
    side(3) = side(3);
    NV = min(V);
    XV = max(V);
    r = [XV-NV]./([side(1) side(2) side(3)] - 1);
  case 1
    % Enclose bounding box in regular mesh
    side(1) = side(1);
    NV = min(V);
    XV = max(V);
    for d = 2:dim
      side(d) = ceil(side(1) * (XV(d)-NV(d))/(XV(1)-NV(1)));
    end
    r = max((XV-NV)./(side-1));
    % recenter
    old_cen = 0.5*(XV + NV);
    XV = NV + r*(side-1);
    cen = 0.5*(XV + NV);
    XV = XV + old_cen - cen;
    NV = NV + old_cen - cen;
  otherwise
    error('side should be scalar or triplet');
  end
  assert(all(side==ceil(side)),'All side values should be integer');

  side = side+pad_count*2;
  old_cen = 0.5*(XV + NV);
  XV = NV+r.*(side-1);
  cen = 0.5*(XV + NV);
  XV = XV + old_cen - cen;
  NV = NV + old_cen - cen;

  r = (XV-NV)./(side-1);

  switch dim
  case 3
    [X,Y,Z] = meshgrid( ...
      NV(1)+linspace(0,1,side(1))*(XV(1)-NV(1)), ...
      NV(2)+linspace(0,1,side(2))*(XV(2)-NV(2)), ...
      NV(3)+linspace(0,1,side(3))*(XV(3)-NV(3)));
    % barycenters of cells
    BC = [X(:) Y(:) Z(:)];
  case 2
    [X,Y] = meshgrid( ...
      NV(1)+linspace(0,1,side(1))*(XV(1)-NV(1)), ...
      NV(2)+linspace(0,1,side(2))*(XV(2)-NV(2)));
    % barycenters of cells
    BC = [X(:) Y(:)];
  end

end


%% test modulate for all oasis functions.
col = {[0 114 178],[0 158 115], [213 94 0],[230 159 0],...
    [86 180 233], [204 121 167], [64 224 208], [240 228 66]}; % colors
plot_cvx = false;

%% example 3: foopsi, convolution kernel
g = [1.7, -0.712];         % AR coefficient
noise = 1;
T = 3000;
framerate = 30;
firerate = 0.5;
b = 0;              % baseline
N = 20;              % number of trials
seed = 3;          % seed for genrating random variables
[Y, trueC, trueS] = gen_data(g, noise, T, framerate, firerate, b, N, seed);
y = Y(1,:);
true_c = trueC(1,:);  %#ok<*NASGU>
true_s = trueS(1,:);
taus = ar2exp(g);
w = 200;
taus = ar2exp(g);
ht = exp2kernel(taus, w);
% case 1: use the difference of two exponential functions to construct a
% kernel
lambda = 0.1;
[c_oasis, s_oasis] = deconvolveCa(y, 'exp2', taus, 'foopsi', 'lambda', lambda, ...
    'shift', 100, 'window', 200);  %#ok<*ASGLU>

figure('name', 'FOOPSI, exp2, known: g, lambda', 'papersize', [15, 4]);
show_results;

% case 2: use the kernel directly
lambda = 0.1;
[c_oasis, s_oasis] = deconvolveCa(y, 'kernel', ht, 'foopsi', 'lambda', ...
    lambda, 'shift', 100, 'window', 200);  %#ok<*ASGLU>

figure('name', 'FOOPSI, kernel, known: g, lambda', 'papersize', [15, 4]);
show_results;

%% case 3: estimate the time constants
lambda = 0;
taus = ar2exp(g);
[c_oasis, s_oasis, options] = deconvolveCa(y, 'exp2', 'foopsi', 'lambda', lambda, ...
    'shift', 100, 'window', 200, 'smin', 0.5);  %#ok<*ASGLU>

figure('name', 'FOOPSI, exp2, known: g, lambda', 'papersize', [15, 4]);
show_results;


%DEMO_BAYESIANOPTIMIZATION1  A demonstration program for Bayesian
%                            optimization in 1 dimension
%
% The set of BO demos
%  Part 1:  this file
%  One dimensional example
%
%  Part 2:  see demo_bayesoptimization2
%  Two dimensional example
%
%  Part 3:  see demo_bayesoptimization3
%  Two dimensional example with constraints
%  * The implementation of constraints follows Gelbart et al. (2014)
%
%  References:
%    Jones, D., Schonlau, M., & Welch, W. (1998). Efficient global
%    optimization of expensive black-box functions. Journal of Global
%    Optimization, 13(4), 455-492. doi:10.1023/a:1008306431147
%
%    Michael A. Gelbart, Jasper Snoek, and Ryan P. Adams
%    (2014). Bayesian Optimization with Unknown Constraints.
%    http://arxiv.org/pdf/1403.5607v1.pdf
%
%    Snoek, J., Larochelle, H, Adams, R. P. (2012). Practical Bayesian
%    Optimization of Machine Learning Algorithms. NIPS 25
%
%  Copyright (c) 2015-2017 Jarno Vanhatalo

% This software is distributed under the GNU General Public
% License (version 3 or later); please refer to the file
% License.txt, included with the software, for details.

%%  Part 1:
%  One dimensional example
% For testing purposes:
stack = dbstack;
if (~isempty(stack) && (strcmp(stack(end).name, 'runtestset') || strcmp(stack(end).name, 'runtests'))) test = 1; else test = 0; end;

% Construct a function to be optimized
xl = linspace(0,10,100)';
fx = @(x) 0.6*x -0.1*x.^2 + sin(2*x);

% construct GP
cfse = gpcf_sexp('lengthScale',1,'magnSigma2',1,'magnSigma2_prior',prior_sqrtt('s2',10^2));
lik = lik_gaussian('sigma2', 0.001, 'sigma2_prior', prior_fixed);
gp = gp_set('cf', {cfse}, 'lik', lik);

% ----- conduct Bayesian optimization -----
% draw initial point

% Set the options for optimizer of the acquisition function
optimf = @fmincon;
optdefault=struct('GradObj','on','LargeScale','off','Algorithm','SQP','TolFun',1e-6,'TolX',1e-3);
opt=optimset(optdefault);
lb=0;     % lower bound of the input space
ub=10;    % upper bound of the input space

% draw initial point
rng(3)
x = 10*rand;
y = fx(x);

figure, % figure for visualization
i1 = 1;
maxiter = 15;
improv = inf;   % improvement between two successive query points
while i1 < maxiter && improv>1e-6
%while i1 < maxiter

    % Train the GP model for objective function and calculate variables
    % that are needed when calculating the Expected improvement
    % (Acquisition function)
    if i1>1
        gp = gp_optim(gp,x,y);
    end
    [K, C] = gp_trcov(gp,x);
    invC = inv(C);
    a = C\y;
    fmin = min( fx(x) );

    % Calculate EI and posterior of the function for visualization purposes
    EI = expectedimprovement_eg(xl, gp, x, a, invC, fmin);
    [Ef,Varf] = gp_pred(gp, x, y, xl);

    % optimize acquisition function
    %    Note! Opposite to the standard notation we minimize negative Expected
    %    Improvement since Matlab optimizers seek for functions minimum
    % Here we use multiple starting points for the optimization so that we
    % don't crash into suboptimal mode
    fh_eg = @(x_new) expectedimprovement_eg(x_new, gp, x, a, invC, fmin); % The function handle to the Expected Improvement function
    indbest = find(y == fmin);
    xstart = [linspace(0.5,9.5,5) x(indbest)+0.1*randn(1,2)];
    for s1=1:length(xstart)
        x_new(s1) = optimf(fh_eg, xstart(s1), [], [], [], [], lb, ub, [], opt);
    end
    EIs = expectedimprovement_eg(x_new(:), gp, x, a, invC, fmin);
    x_new = x_new( find(EIs==min(EIs),1) ); % pick up the point where Expected Improvement is maximized

    % put new sample point to the list of evaluation points
    x(end+1) = x_new;
    y(end+1) = fx(x(end));  % calculate the function value at query point
    x=x(:);y=y(:);

    % visualize
    clf
    subplot(2,1,1),hold on, title('function to be optimized and GP fit')
    %plot(xl,fx(xl))
    box on
    plot(xl,fx(xl),'r')
    % The function evaluations so far
    plot(x(1:end-1),y(1:end-1), 'ko')
    % The new sample location
    plot(x(end),y(end), 'ro')
    % the posterior of the function
    plot(xl,Ef, 'k')
    plot(xl,Ef + 2*sqrt(Varf), 'k--')
    plot(xl,Ef - 2*sqrt(Varf), 'k--')
    legend('objective function', 'function evaluations', 'next query point', 'GP mean', 'GP 95% interval','location','southwest')
    % The expected information
    subplot(2,1,2)
    plot(xl,EI, 'r'), hold on
    plot(x(end),0, 'r*')
    plot(x(end)*[1 1],ylim, 'r--')
    title('acquisition function')

    improv = abs(y(end) - y(end-1));
    i1=i1+1;

    if test == 0
        pause
    end
end
%subplot(2,1,1)
%plot(xl,fx(xl),'r')


%% Machine Learning Online Class
%  Exercise 6 | Support Vector Machines
%
%  Instructions
%  ------------
%
%  This file contains code that helps you get started on the
%  exercise. You will need to complete the following functions:
%
%     gaussianKernel.m
%     dataset3Params.m
%     processEmail.m
%     emailFeatures.m
%
%  For this exercise, you will not need to change any code in this file,
%  or any other files other than those mentioned above.
%

%% Initialization
clear ; close all; clc

%% =============== Part 1: Loading and Visualizing Data ================
%  We start the exercise by first loading and visualizing the dataset.
%  The following code will load the dataset into your environment and plot
%  the data.
%

fprintf('Loading and Visualizing Data ...\n')

% Load from ex6data1:
% You will have X, y in your environment
load('ex6data1.mat');

% Plot training data
plotData(X, y);

%fprintf('Program paused. Press enter to continue.\n');
%pause;

%% ==================== Part 2: Training Linear SVM ====================
%  The following code will train a linear SVM on the dataset and plot the
%  decision boundary learned.
%

% Load from ex6data1:
% You will have X, y in your environment
load('ex6data1.mat');

fprintf('\nTraining Linear SVM ...\n')

% You should try to change the C value below and see how the decision
% boundary varies (e.g., try C = 1000)
C = 0.1;
model = svmTrain(X, y, C, @linearKernel, 1e-3, 20);
visualizeBoundaryLinear(X, y, model);

%fprintf('Program paused. Press enter to continue.\n');
%pause;

%% =============== Part 3: Implementing Gaussian Kernel ===============
%  You will now implement the Gaussian kernel to use
%  with the SVM. You should complete the code in gaussianKernel.m
%
fprintf('\nEvaluating the Gaussian Kernel ...\n')

x1 = [1 2 1]; x2 = [0 4 -1]; sigma = 2;
sim = gaussianKernel(x1, x2, sigma);

fprintf(['Gaussian Kernel between x1 = [1; 2; 1], x2 = [0; 4; -1], sigma = 0.5 :' ...
         '\n\t%f\n(this value should be about 0.324652)\n'], sim);

%fprintf('Program paused. Press enter to continue.\n');
%pause;

%% =============== Part 4: Visualizing Dataset 2 ================
%  The following code will load the next dataset into your environment and
%  plot the data.
%

fprintf('Loading and Visualizing Data ...\n')

% Load from ex6data2:
% You will have X, y in your environment
load('ex6data2.mat');

% Plot training data
plotData(X, y);

fprintf('Program paused. Press enter to continue.\n');
pause;

%% ========== Part 5: Training SVM with RBF Kernel (Dataset 2) ==========
%  After you have implemented the kernel, we can now use it to train the
%  SVM classifier.
%
fprintf('\nTraining SVM with RBF Kernel (this may take 1 to 2 minutes) ...\n');

% Load from ex6data2:
% You will have X, y in your environment
load('ex6data2.mat');

% SVM Parameters
C = 1; sigma = 0.1;

% We set the tolerance and max_passes lower here so that the code will run
% faster. However, in practice, you will want to run the training to
% convergence.
model = svmTrain(X, y, C, @(x1, x2) gaussianKernel(x1, x2, sigma));
visualizeBoundary(X, y, model);

fprintf('Program paused. Press enter to continue.\n');
pause;

%% =============== Part 6: Visualizing Dataset 3 ================
%  The following code will load the next dataset into your environment and
%  plot the data.
%

fprintf('Loading and Visualizing Data ...\n')

% Load from ex6data3:
% You will have X, y in your environment
load('ex6data3.mat');

% Plot training data
plotData(X, y);

fprintf('Program paused. Press enter to continue.\n');
pause;

%% ========== Part 7: Training SVM with RBF Kernel (Dataset 3) ==========

%  This is a different dataset that you can use to experiment with. Try
%  different values of C and sigma here.
%

% Load from ex6data3:
% You will have X, y in your environment
load('ex6data3.mat');

% Try different SVM Parameters here
[C, sigma] = dataset3Params(X, y, Xval, yval);

% Train the SVM
model = svmTrain(X, y, C, @(x1, x2) gaussianKernel(x1, x2, sigma));
visualizeBoundary(X, y, model);

fprintf('Program paused. Press enter to continue.\n');
pause;


function pass = test_dot(pref)
% Test DOT
if ( nargin == 0 )
    pref = chebfunpref;
end
tol = 50*pref.cheb3Prefs.chebfun3eps;

% Check definition:
F = chebfun3v(@(x,y,z) cos(x), @(x,y,z) sin(y), @(x,y,z) exp(z));
G = chebfun3v(@(x,y,z) x, @(x,y,z) y, @(x,y,z) z);
dotF1 = dot(F, G);
dotF2 = F' * G;
pass(1) = norm(dotF1 - dotF2) < tol;

% Check definition again:
F = chebfun3v(@(x,y,z) cos(x), @(x,y,z) sin(y), @(x,y,z) x.*y);
G = chebfun3v(@(x,y,z) x, @(x,y,z) y, @(x,y,z) z);
dotF1 = dot(F, G);
dotF2 = F' * G;
pass(2) = norm(dotF1 - dotF2) < tol;

end


function sw = BLanalyticalCoreyFoam(mug, muw)
%BLANALYTICAL Analytical solution of Buckley-Leverett equation
% Written by Ali A. Eftekhari
% See the license file
%muw = 10e-3;
%muo = 10e-3;
u = 1e-6/(pi()*0.038^2/4)/60;
phi = 0.2;
k = 2e-12; %[m^2]
sw_end = .5;
fmmob = 1.01889e+05;
fmdry = 1.20000e-01;
epdry = 5.0000e+03;
swc = 0.07;
sw_in = swc;
sgr = 0.0;
krg0 = 1;
ng = 2;
krw0 = 1;
nw = 2;
sws = @(sw)((sw>swc).*(sw-swc)/(1-sgr-swc));
kr = @(sw)(krg0*(1-sws(sw)).^ng);
% fm = @(sw)((sw>fmdry).*(1+fmmob*(0.5+atan(epdry.*(sw-fmdry))/pi()))+(sw<=fmdry));
fm = @(sw)(1+fmmob*(0.5+atan(epdry.*(sw-fmdry))/pi()));
krg = @(sw)(kr(sw)./fm(sw));
krw = @(sw)(krw0*sws(sw).^nw);
dkrwdsw = @(sw)(nw*krw0*(1/(1-sgr-swc))*sws(sw).^(nw-1));
dkrdsw = @(sw)((-krg0*ng*(1-sws(sw)).^(ng-1))/(-swc-sgr+1));
% fm = @(sw)((sw>fmdry).*(1+fmmob*(0.5+atan(epdry.*(sw-fmdry))/pi()))+(sw<=fmdry));
dfmdsw = @(sw)(((epdry*fmmob)./(pi*(epdry^2*(sw-fmdry).^2+1))));
% dfmdsw = @(sw)((epdry*fmmob)./(pi*(epdry^2*(sw-fmdry).^2+1)));
dkrgdsw = @(sw)((dkrdsw(sw).*fm(sw)-dfmdsw(sw).*kr(sw))./fm(sw).^2);
fw = @(sw)((krw(sw)/muw)./(krw(sw)/muw+krg(sw)/mug));
dfwdsw = @(sw)((dkrwdsw(sw)/muw.*(krw(sw)/muw+krg(sw)/mug)- ...
    (dkrwdsw(sw)/muw+dkrgdsw(sw)/mug).*krw(sw)/muw)./ ...
    (krg(sw)/mug+krw(sw)/muw).^2);
s = linspace(swc,1,1000);
figure(1)
subplot(2,2,1);
plot(s, krw(s), s, kr(s), s, krg(s));
xlabel('S_w'); ylabel('rel perms'); legend('liq', 'gas', 'foam');
F = @(sw)(dfwdsw(sw)-(fw(sw_end)-fw(sw))/(sw_end-sw));
sw_shock = fzero(F, [swc+eps,0.3]);
subplot(2,2,2);
plot(s, fw(s), [sw_shock sw_end], [fw(sw_shock) fw(sw_end)]);
xlabel('S_w'); ylabel('f_w');
% plot(s, fw(s), [sw_end sw_shock], [fw(sw_end) fw(sw_shock)]);
s1 = linspace(sw_in, sw_shock, 50);
xt_s1 = u/phi*dfwdsw(s1);
xt_s = u/phi*dfwdsw(s);
xt_shock = u/phi*dfwdsw(sw_shock);
subplot(2,2,3);
plot(xt_s, s, '--', ...
    [xt_s1 xt_shock xt_shock max(xt_s)], [s1 sw_shock sw_end sw_end])
xlabel('x/t [m/s]'); ylabel('S_w');
subplot(2,2,4);
plot([xt_s1 xt_shock xt_shock 10*xt_shock], [s1 sw_shock sw_end sw_end])
xlabel('x/t [m/s]'); ylabel('S_w');
sw_prf = [s1 sw_shock sw_end sw_end];
xt_prf = [xt_s1 xt_shock xt_shock max(xt_s)];
sw = @(xt)([interp1(xt_s1, s1, xt(xt<xt_shock)) sw_end*xt(xt>=xt_shock)]);
% Now I can use the data to calculate the pressure drop across my domain
L = 0.17; % [m]
t = eps:20:5*40*60; % [s] time
dp = zeros(1,length(t));
for i =1:length(t)
    x = 0:0.001:L;
    xt = x/t(i);
    dp(i) = trapz(x, u./(k*(krg(sw(xt))/mug+krw(sw(xt))/muw)));

end
figure(2);plot(t/60, dp/1e5, '.')
xlabel('time [min]'); ylabel('pressure drop [bar]');
end


function accuracy = lcdrc(TrainSet, TestSet, train_num, test_num, class_num, reduce_dimension, options)
% Linear collaborative discriminant regression classificatoin (LCDRC) algorithm
%
% Inputs:
%       TrainSet            train sets of size dxn, where d is dimension and n is number of sets
%       TestSet             test sets of size dxn, where d is dimension and n is number of sets
%       test_num            numner of test sets
%       class_num           numner of classes
%       options             options
% Output:
%       accuracy            classification accurary
%
% References:
%       X. Qu, S. Kim, R. Cui and H. J. Kim,
%       "Linear collaborative discriminant regression classification for face recognition,"
%       J. Visual Communication Image Represetation, vol.31, pp. 312-319, 2015.
%
%
% Created by H.Kasai on July 04, 2017

    % extract options
    if ~isfield(options, 'verbose')
        verbose = false;
    else
        verbose = options.verbose;
    end

    if verbose
        fprintf('# LCDRC: calculate projection matrix U ...');
    end
    Eb = 0;
    Ew = 0;
    for j = 1 : train_num

        j_class = TrainSet.y(1, j);

        % calcuate Ew
        intra_class_index = find(TrainSet.y == j_class);
        intra_class_index(intra_class_index == j) = [];
        X_intra_wo_j = TrainSet.X(:, intra_class_index);                                    % X^{intra}
        alpha_intra = X_intra_wo_j * pinv(X_intra_wo_j' * X_intra_wo_j) * X_intra_wo_j';    % alpha^{intra} in Eq.(2)
        error_intra = TrainSet.X(:,j) - alpha_intra * TrainSet.X(:,j);
        Ew = Ew + error_intra * error_intra';

        % calcuate Eb
        inter_class_index = find(TrainSet.y ~= j_class);
        X_inter = TrainSet.X(:, inter_class_index);%                                        % X^{iner}
        alpha_inter= X_inter * pinv(X_inter' * X_inter) * X_inter';                         % alpha^{inter} in Eq.(2)
        error_inter = TrainSet.X(:,j) - alpha_inter * TrainSet.X(:,j);
        Eb = Eb + error_inter * error_inter';
    end

    % calc
    Ew = Ew/train_num;
    Eb = Eb/train_num;
    lambda = 0.001;
    Ew = Ew + lambda*eye(size(Ew,2));

    [V, ~] = eig(Eb, Ew);
    for i = 1:reduce_dimension
        U(:,i) = V(:,size(V,2)+1-i);                                                        % Eq.(13)
    end
    if verbose
        fprintf('done\n');
    end

    % reduce dimention
    TrainSet.X_red  = U' * TrainSet.X;
    TestSet.X_red   = U' * TestSet.X;

    % prepare projection matrix (hat matrix)
    H = cell(1, class_num);
    for i = 1 : class_num
        class_index = find(TrainSet.y == i);

        X_i = TrainSet.X_red(:, class_index);           % Eq.(1)
        alpha_i = pinv(X_i' * X_i) *  X_i';                  % Eq.(2) exept y (beta_i = inv(X_i' * X_i) * X_i')
        H{i} = X_i * alpha_i;                           % Eq.(3) exept y

        if verbose
            fprintf('# LCDRC: calc Hi for class : %03d/%03d (samples: %03d)\n', i, class_num, length(class_index));
        end
    end

    % prepare predicted label array
    identity = zeros(1, test_num);

    % predict the class
    for j = 1 : test_num

        dis = zeros(1, class_num);
        y = TestSet.X_red(:, j);
        for i = 1 : class_num
            y_pred = H{i} * y;
            dis(1, i) = norm(y - y_pred);               % Eq.(5)
        end
        [~, label] = min(dis);                          % Eq.(6)
        identity(j) = label;

        if verbose
            correct = (label == TestSet.y(1, j));
            fprintf('# LCDRC: test:%03d, predict class: %03d --> ground truth :%03d (%d)\n', j, label, TestSet.y(1, j), correct);
        end
    end

    % calculate accuracy
    correct_num = sum(identity == TestSet.y);
    accuracy = correct_num / test_num;
end


function out = DN_HistogramMode(y,numBins,doSimple,doPlot)
% DN_HistogramMode      Mode of a data vector.
%
% Measures the mode of the data vector using histograms with a given number
% of bins.
%
%---INPUTS:
%
% y, the input data vector.
% numBins, the number of bins to use in the histogram.
% doSimple, whether to use a simple binning method (linearly spaced bins).
% doPlot, whether to show a plot of what was computed.

% ------------------------------------------------------------------------------
% Copyright (C) 2020, Ben D. Fulcher <ben.d.fulcher@gmail.com>,
% <http://www.benfulcher.com>
%
% If you use this code for your research, please cite the following two papers:
%
% (1) B.D. Fulcher and N.S. Jones, "hctsa: A Computational Framework for Automated
% Time-Series Phenotyping Using Massive Feature Extraction, Cell Systems 5: 527 (2017).
% DOI: 10.1016/j.cels.2017.10.001
%
% (2) B.D. Fulcher, M.A. Little, N.S. Jones, "Highly comparative time-series
% analysis: the empirical structure of time series and their methods",
% J. Roy. Soc. Interface 10(83) 20130048 (2013).
% DOI: 10.1098/rsif.2013.0048
%
% This function 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/>.
% ------------------------------------------------------------------------------

%-------------------------------------------------------------------------------
% Check inputs and set defaults:
%-------------------------------------------------------------------------------
if nargin < 2
    numBins = 'auto';
end
if nargin < 3
    doSimple = true;
end
if nargin < 4
    doPlot = false;
end
%-------------------------------------------------------------------------------

% Compute the histogram from the data:
if isnumeric(numBins)
    if doSimple
        [N,binEdges] = BF_SimpleBinner(y,numBins);
    else
        [N,binEdges] = histcounts(y,numBins);
    end
elseif ischar(numBins)
    [N,binEdges] = histcounts(y,'BinMethod',numBins);
else
    error('Unknown format for numBins');
end

% Compute bin centers from bin edges:
binCenters = mean([binEdges(1:end-1); binEdges(2:end)]);

% Mean position of maximums (if multiple):
out = mean(binCenters(N == max(N)));

% Plot a summary of what was computed:
if doPlot
    histogram('BinEdges',binEdges,'BinCounts',N,'EdgeColor','k','FaceColor',0.6*ones(1,3));
    hold('on');
    plot(out*ones(2,1),[0,max(N)],'r','LineWidth',2);
    hold('off')
end

end


function determ = pascal2_determinant ( n )

%*****************************************************************************80
%
%% PASCAL2_DETERMINANT returns the determinant of the PASCAL2 matrix.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    18 October 2007
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer N, the order of A.
%
%    Output, real DETERM, the determinant.
%
  determ = 1.0;

  return
end


function [y,arg]=spmax2(row,col,val1,val2,N)
% MATLAB version
% [y,arg]=spmax2(row,col,val1,val2,N)
% is equivalent to [y,arg]=spmax(x)
% where x has N cols and is given by val1+val2 in position(row,col). If val1==-INF => entry disregarded
% -INF in y signify that column was empty.
y=-inf*ones(1,N);
arg=zeros(1,N);
val1=val1(:);
val2=val2(:);
interesting=find(val1~=-inf);
val=val1(interesting)+val2(interesting);
col=col(interesting);
row=row(interesting);
for i=1:N,
   sel=find(col==i);
   if ~isempty(sel),
      [y(i),arg(i)]=max(val(sel));
      arg(i)=row(sel(arg(i)));
   end
end


function volr = volresize_t2(vol, k, varargin)
    % volresize(vol, k, {interp_type}
    interp_type = 1;
    if nargin >= 3
        interp_type = varargin{1};
    end
    if numel(k) == 1
        k = k * [1,1,1];
    end

    newsz = round(k.*size(vol));

    tmp = zeros(max(newsz, size(vol)));
    tmp(1:size(vol,1), 1:size(vol,2), 1:size(vol,3)) = vol;
    [n1, n2, n3] = ndgrid(1:size(tmp,1), 1:size(tmp,2), 1:size(tmp,3));

    k=1./k;
    d = 1 - k;
    T = cat(4, k(1) * n1 - n1 + d(1), k(2) * n2 - n2 + d(2), k(3) * n3 - n3  + d(3));

    volr = imdeform3(tmp, T, interp_type);

    volr = volr(1:newsz(1), 1:newsz(2), 1:newsz(3));
end


function H=calcSpherHessian(x,systemType,useHalfRange,lTx,lRx,M)
%%CALCSPHERHESSIAN Calculate the Hessian matrix (a matrix of second partial
%          derivatives) for a monostatic or bistatic spherical measurement,
%          ignoring atmospheric effects, with respect to 3D Cartesian
%          position.
%
%INPUTS: x The 3X1 position of the target in Cartesian coordinates in the
%          order [x;y;z].
% systemType An optional parameter specifying the axis from which the
%          angles are measured in radians. Possible values are
%          0 (The default if omitted) Azimuth is measured
%            counterclockwise from the x-axis in the x-y plane. Elevation
%            is measured up from the x-y plane (towards the z-axis). This
%            is consistent with common spherical coordinate systems for
%            specifying longitude (azimuth) and geocentric latitude
%            (elevation).
%          1 Azimuth is measured counterclockwise from the z-axis in the
%            z-x plane. Elevation is measured up from the z-x plane
%            (towards the y-axis). This is consistent with some spherical
%            coordinate systems that use the z axis as the boresight
%            direction of the radar.
%          2 This is the same as 0 except instead of being given
%            elevation, one desires the angle away from the z-axis, which
%            is (pi/2-elevation).
%          3 This is the same as 0 except azimuth is measured clockwise
%            from the y-axis in the x-y plane instead of counterclockwise
%            from the x-axis. This coordinate system often arises when
%            given "bearings" in a local East-North-Up coordinate system,
%            where the bearing directions are measured East of North.
% useHalfRange An optional boolean value specifying whether the bistatic
%          (round-trip) range value has been divided by two. This normally
%          comes up when operating in monostatic mode (the most common
%          type of spherical coordinate system), so that the range
%          reported is a one-way range (or just half a bistatic range).
%          The default if this parameter is not provided is false if lTx
%          is provided and true if it is omitted (monostatic).
%      lTx The 3X1 transmitter position in the global coordinate system
%          with [x;y;z] components. If omitted or an empty matrix is
%          passed, then a vector of zeros is used.
%      lRx The 3X1 receiver position in the global coordinate system
%          with [x;y;z] components. If omitted or an empty matrix is
%          passed, then a vector of zeros is used.
%        M A rotation matrix from the global Coordinate system to the
%          orientation of the coordinate system at the receiver. This is
%          only necessary if UV direction components are desired. If
%          omitted, it is assumed to be the identity matrix.
%
%OUTPUTS: H The 3X3X3 Hessian matrix, where H(:,:,1) is the Hessian for the
%           range component, H(:,:,2) is the Hessian for the azimuth
%           component, and H(:,:,3) is the Hessian for the elevation
%           component. The ordering of the derivatives in each matrix is:
%                  [d^2/(dxdx), d^2/(dxdy), d^2/(dxdz);
%                   d^2/(dydx), d^2/(dydy), d^2/(dydz);
%                   d^2/(dzdx), d^2/(dzdy), d^2/(dzdz)];
%          note that each matrix is symmetric (i.e.
%                   d^2/(dydx)=d^2/(dxdy) ).
%
%This function just calls rangeHessian and spherAngHessian.
%
%June 2017 David F.Crouse, Naval Research Laboratory, Washington D.C.
%(UNCLASSIFIED) DISTRIBUTION STATEMENT A. Approved for public release.

if(nargin<6||isempty(M))
   M=eye(3,3);
end

if((nargin<4||isempty(lTx))&&(nargin<3||isempty(useHalfRange)))
    useHalfRange=true;
elseif(nargin<3||isempty(useHalfRange))
    useHalfRange=false;
end

if(nargin<5||isempty(lRx))
    lRx=zeros(3,1);
end

if(nargin<4||isempty(lTx))
    lTx=zeros(3,1);
end

if(nargin<2||isempty(systemType))
    systemType=0;
end

H=zeros(3,3,3);
H(:,:,1)=rangeHessian(x,useHalfRange,lTx,lRx);
H(:,:,2:3)=spherAngHessian(x,systemType,lRx,M);
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 [ t, det, info ] = ctrdi ( t, ldt, n, job )

%*****************************************************************************80
%
%% CTRDI computes the determinant and inverse of a complex triangular matrix.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    08 May 2007
%
%  Author:
%
%    MATLAB version by John Burkardt
%
%  Reference:
%
%    Jack Dongarra, Jim Bunch, Cleve Moler, Pete Stewart,
%    LINPACK User's Guide,
%    SIAM, 1979,
%    ISBN13: 978-0-898711-72-1,
%    LC: QA214.L56.
%
%  Parameters:
%
%    Input, complex T(LDT,N), the triangular matrix.  The zero
%    elements of the matrix are not referenced, and the corresponding
%    elements of the array can be used to store other information.
%
%    Input, integer LDT, the leading dimension of T.
%
%    Input, integer N, the order of the matrix.
%
%    Input, integer JOB.
%    010, no determinant,    inverse, matrix is lower triangular.
%    011, no determinant,    inverse, matrix is upper triangular.
%    100,    determinant, no inverse.
%    110,    determinant,    inverse, matrix is lower triangular.
%    111,    determinant,    inverse, matrix is upper triangular.
%
%    Output, complex T(LDT,N), if an inverse was requested, then T has
%    been overwritten by its inverse.
%
%    Output, complex DET(2), the determinant of the original matrix,
%    if requested.  Otherwise not referenced.
%    Determinant = DET(1) * 10.0**DET(2) with 1.0 <= cabs1 ( DET(1) ) < 10.0
%    or DET(1) == 0.0.  Also, DET(2) is strictly real.
%
%    Output, integer INFO.
%    0, an inverse was requested and the matrix is nonsingular.
%    K, an inverse was requested, but the K-th diagonal element
%    of T is zero.
%
  det = [];
  info = 0;

  if ( floor ( job / 100 ) ~= 0 )

    det(1) = 1.0;
    det(2) = 0.0;

    for i = 1 : n

      det(1) = det(1) * t(i,i);

      if ( cabs1 ( det(1) ) == 0.0 )
        break
      end

      while ( cabs1 ( det(1) ) < 1.0 )
        det(1) = det(1) * 10.0;
        det(2) = det(2) - 1.0;
      end

      while ( 10.0 <= cabs1 ( det(1) ) )
        det(1) = det(1) / 10.0;
        det(2) = det(2) + 1.0;
      end

    end

  end
%
%  Compute inverse of upper triangular matrix.
%
  if ( mod ( floor ( job / 10 ), 10 ) ~= 0 )

    if ( mod ( job, 10 ) ~= 0 )

      info = 0;

      for k = 1 : n

        if ( cabs1 ( t(k,k) ) == 0.0 )
          info = k;
          break
        end

        t(k,k) = 1.0 / t(k,k);
        temp = -t(k,k);
        t(1:k-1,k) = t(1:k-1,k) * temp;

        for j = k+1 : n
          temp = t(k,j);
          t(k,j) = 0.0;
          t(1:k,j) = t(1:k,j) + temp * t(1:k,k);
        end

      end
%
%  Compute inverse of lower triangular matrix.
%
    else

      info = 0;

      for k = n : -1: 1

        if ( cabs1 ( t(k,k) ) == 0.0 )
          info = k;
          break
        end

        t(k,k) = 1.0 / t(k,k);

        if ( k ~= n )
          temp = -t(k,k);
          t(k+1:n,k) = t(k+1:n,k) * temp;
        end

        for j = 1 : k-1
          temp = t(k,j);
          t(k,j) = 0.0;
          t(k:n,j) = t(k:n,j) + temp * t(k:n,k);
        end

      end

    end

  end

  return
end


function [cmap]=buildcmap(colors)
% [cmap]=buildcmap(colors)
%
% This function can be used to build your own custom colormaps. Imagine if
% you want to display rainfall distribution map. You want a colormap which
% ideally brings rainfall in mind, which is not achiveved by colormaps such
% as winter, cool or jet and such. A gradient of white to blue will do the
% task, but you might also use a more complex gradient (such as
% white+blue+red or colors='wbr'). This function can be use to build any
% colormap using main colors rgbcmyk. In image processing, w (white) can be
% used as the first color so that in the output, the background (usually
% with 0 values) appears white. In the example of rainfall map, 'wb' will
% produce a rainfall density map where the background (if its DN values are
% 0) will appear as white.
%
% Inputs:
%  colors: string (char) of color codes, any sequence of rgbcmywk
%  representing different colors (such as 'b' for blue) is acceptable. If a
%  gradient of white to blue is needed, colors would be 'wb'; a rainbow of
%  white+blue+red+green would be 'wbrg'.
%
% Example:
%  [cmap]=buildcmap('wygbr');
% %try the output cmap:
% im=imread('cameraman.tif');
% imshow(im), colorbar
% colormap(cmap) %will use the output colormap
%
% First version: 14 Feb. 2013
% sohrabinia.m@gmail.com
%--------------------------------------------------------------------------

if nargin<1
    colors='wrgbcmyk';
end

if ~ischar(colors)
    error(['Error! colors must be a variable of type char with '...
        'color-names, such as ''r'', ''g'', etc., '...
        'type ''help buildcmap'' for more info']);
end

ncolors=length(colors)-1;

bins=round(255/ncolors);
% diff1=255-bins*ncolors;

vec=zeros(300,3);

switch colors(1)
    case 'w'
        vec(1,:)=1;
    case 'r'
        vec(1,:)=[1 0 0];
    case 'g'
        vec(1,:)=[0 1 0];
    case 'b'
        vec(1,:)=[0 0 1];
    case 'c'
        vec(1,:)=[0 1 1];
    case 'm'
        vec(1,:)=[1 0 1];
    case 'y'
        vec(1,:)=[1 1 0];
    case 'k'
        vec(1,:)=[0 0 0];
end

for i=1:ncolors
 beG=(i-1)*bins+1;
 enD=i*bins+1; %beG,enD
 switch colors(i+1)
     case 'w'
         vec(beG:enD,1)=linspace(vec(beG,1),1,bins+1)';
         vec(beG:enD,2)=linspace(vec(beG,2),1,bins+1)';
         vec(beG:enD,3)=linspace(vec(beG,3),1,bins+1)';%colors(i+1),beG,enD,
     case 'r'
         vec(beG:enD,1)=linspace(vec(beG,1),1,bins+1)';
         vec(beG:enD,2)=linspace(vec(beG,2),0,bins+1)';
         vec(beG:enD,3)=linspace(vec(beG,3),0,bins+1)';%colors(i+1),beG,enD
     case 'g'
         vec(beG:enD,1)=linspace(vec(beG,1),0,bins+1)';
         vec(beG:enD,2)=linspace(vec(beG,2),1,bins+1)';
         vec(beG:enD,3)=linspace(vec(beG,3),0,bins+1)';%colors(i+1),beG,enD
     case 'b'
         vec(beG:enD,1)=linspace(vec(beG,1),0,bins+1)';
         vec(beG:enD,2)=linspace(vec(beG,2),0,bins+1)';
         vec(beG:enD,3)=linspace(vec(beG,3),1,bins+1)';%colors(i+1),beG,enD
     case 'c'
         vec(beG:enD,1)=linspace(vec(beG,1),0,bins+1)';
         vec(beG:enD,2)=linspace(vec(beG,2),1,bins+1)';
         vec(beG:enD,3)=linspace(vec(beG,3),1,bins+1)';%colors(i+1),beG,enD
     case 'm'
         vec(beG:enD,1)=linspace(vec(beG,1),1,bins+1)';
         vec(beG:enD,2)=linspace(vec(beG,2),0,bins+1)';
         vec(beG:enD,3)=linspace(vec(beG,3),1,bins+1)';
     case 'y'
         vec(beG:enD,1)=linspace(vec(beG,1),1,bins+1)';
         vec(beG:enD,2)=linspace(vec(beG,2),1,bins+1)';
         vec(beG:enD,3)=linspace(vec(beG,3),0,bins+1)';
     case 'k'
         vec(beG:enD,1)=linspace(vec(beG,1),0,bins+1)';
         vec(beG:enD,2)=linspace(vec(beG,2),0,bins+1)';
         vec(beG:enD,3)=linspace(vec(beG,3),0,bins+1)';
 end
end
cmap=vec(1:bins*ncolors,:);
end %end of buildcmap