function tricost(varargin)
%TRICOST draw quality-metrics for a 2-simplex triangulation
%embedded in the two-dimensional plane.
%   TRICOST(VERT,EDGE,TRIA,TNUM) draws histograms of quality
%   metrics for the triangulation.
%   VERT is a V-by-2 array of XY coordinates in the triangu-
%   lation, EDGE is an array of constrained edges, TRIA is a
%   T-by-3 array of triangles, and TNUM is a T-by-1 array of
%   part indices. Each row of TRIA and EDGE define an eleme-
%   nt. VERT(TRIA(II,1),:), VERT(TRIA(II,2),:) and VERT(TRIA
%   (II,3),:) are the coordinates of the II-TH triangle. The
%   edges in EDGE are defined in a similar manner. NUM is an
%   array of part indexing, such that TNUM(II) is the index
%   of the part in which the II-TH triangle resides.
%
%   TRICOST(...,HVRT) additionally draws histograms of rela-
%   tive edge-length, indicating conformance to the spacing
%   constraints. HVRT is a V-by-1 array of spacing informat-
%   ion, per an evaluation of the mesh-size function at the
%   mesh vertices VERT.
%
%   See also REFINE2, SMOOTH2

%-----------------------------------------------------------
%   Darren Engwirda : 2017 --
%   Email           : de2363@columbia.edu
%   Last updated    : 09/07/2018
%-----------------------------------------------------------

    vert = [] ; conn = [] ; tria = [] ;
    tnum = [] ; hvrt = [] ;

%---------------------------------------------- extract args
    if (nargin>=+1), vert = varargin{1}; end
    if (nargin>=+2), conn = varargin{2}; end
    if (nargin>=+3), tria = varargin{3}; end
    if (nargin>=+4), tnum = varargin{4}; end
    if (nargin>=+5), hvrt = varargin{5}; end

%---------------------------------------------- basic checks
    if ( ~isnumeric(vert) || ...
         ~isnumeric(conn) || ...
         ~isnumeric(tria) || ...
         ~isnumeric(tnum) || ...
         ~isnumeric(hvrt) )
        error('tricost:incorrectInputClass' , ...
            'Incorrect input class.') ;
    end

%---------------------------------------------- basic checks
    if (ndims(vert) ~= +2 || ...
        ndims(conn) ~= +2 || ...
        ndims(tria) ~= +2 )
        error('tricost:incorrectDimensions' , ...
            'Incorrect input dimensions.');
    end
    if (size(vert,2)~= +2 || ...
        size(conn,2) < +2 || ...
        size(tria,2) < +3 )
        error('tricost:incorrectDimensions' , ...
            'Incorrect input dimensions.');
    end

    nvrt = size(vert,1) ;
    ntri = size(tria,1) ;

%---------------------------------------------- basic checks
    if (min(min(conn(:,1:2))) < +1 || ...
            max(max(conn(:,1:2))) > nvrt )
        error('tricost:invalidInputs', ...
            'Invalid EDGE input array.') ;
    end

    if (min(min(tria(:,1:3))) < +1 || ...
            max(max(tria(:,1:3))) > nvrt )
        error('tricost:invalidInputs', ...
            'Invalid TRIA input array.') ;
    end

%-- borrowed from the JIGSAW library!

%-- draw sub-axes directly -- sub-plot gives
%-- silly inconsistent ax spacing...!

    axpos31 = [.125,.750,.800,.150] ;
    axpos32 = [.125,.450,.800,.150] ;
    axpos33 = [.125,.150,.800,.150] ;

    axpos41 = [.125,.835,.800,.135] ;
    axpos42 = [.125,.590,.800,.135] ;
    axpos43 = [.125,.345,.800,.135] ;
    axpos44 = [.125,.100,.800,.135] ;

%-- draw cost histograms for 2-tria elements
    figure;
    set(gcf,'color','w','units','normalized', ...
        'position',[.05,.10,.30,.30]);
    if (~isempty(hvrt))

%-- have size-func data
    axes('position',axpos41); hold on;
    scrhist(triscr2(vert,tria),'tria3');
    axes('position',axpos42); hold on;
    anghist(triang2(vert,tria),'tria3');
    axes('position',axpos43); hold on;
    hfnhist(relhfn2(vert, ...
                    tria,hvrt),'tria3');
    axes('position',axpos44); hold on;
    deghist(trideg2(vert,tria),'tria3');

    else

%-- null size-func data
    axes('position',axpos31); hold on;
    scrhist(triscr2(vert,tria),'tria3');
    axes('position',axpos32); hold on;
    anghist(triang2(vert,tria),'tria3');
    axes('position',axpos33); hold on;
    deghist(trideg2(vert,tria),'tria3');

    end

end

function [mf] = mad(ff)
%MAD return mean absolute deviation (from the mean).

    mf = mean(abs(ff-mean(ff))) ;

end

function deghist(dd,ty)
%DEGHIST draw histogram for "degree" quality-metric.

    dd = dd(:);
    be = 1:max(dd);
    hc = histc(dd,be);

    r = [.85,.00,.00] ; y = [1.0,.95,.00] ;
    g = [.00,.90,.00] ; k = [.60,.60,.60] ;

    bar(be,hc,1.05,'facecolor',k,'edgecolor',k);

    axis tight;
    set(gca,'ycolor', get(gca,'color'),'ytick',[],...
        'xtick',2:2:12,'layer','top','fontsize',...
            14,'linewidth',2.,'ticklength',[.025,.025],...
                'box','off','xlim',[0,12]);

    switch (ty)
    case 'tria4'

    if ( ~(exist('OCTAVE_VERSION','builtin') > +0) )
        text(-.225,0,'$|d|_{\tau}$',...
            'horizontalalignment','right',...
                'fontsize',22,'interpreter','latex') ;
    else
        text(-.225,0, '|d|_{\tau}' ,...
            'horizontalalignment','right',...
                'fontsize',22,'interpreter',  'tex') ;
    end

    case 'tria3'

    if ( ~(exist('OCTAVE_VERSION','builtin') > +0) )
        text(-.225,0,'$|d|_{f}$',...
            'horizontalalignment','right',...
                'fontsize',22,'interpreter','latex') ;
    else
        text(-.225,0, '|d|_{\tau}' ,...
            'horizontalalignment','right',...
                'fontsize',22,'interpreter',  'tex') ;
    end

    end

end

function anghist(ad,ty)
%ANGHIST draw histogram for "angle" quality-metric.

    ad = ad(:);
    be = linspace(0.,180.,91);
    bm =(be(1:end-1)+be(2:end))/2.;
    hc = histc(ad,be);

    switch (ty)
    case 'tria4'
        poor = bm <  10.  | bm >= 160. ;
        okay =(bm >= 10.  & bm <  20. )| ...
              (bm >= 140. & bm <  160.);
        good =(bm >= 20.  & bm <  30. )| ...
              (bm >= 120. & bm <  140.);
        best = bm >= 30.  & bm <  120. ;

    case 'tria3'
        poor = bm <  15.  | bm >= 150. ;
        okay =(bm >= 15.  & bm <  30. )| ...
              (bm >= 120. & bm <  150.);
        good =(bm >= 30.  & bm <  45. )| ...
              (bm >= 90.  & bm <  120.);
        best = bm >= 45.  & bm <  90.  ;

    end

    r = [.85,.00,.00] ; y = [1.0,.95,.00] ;
    g = [.00,.90,.00] ; k = [.60,.60,.60] ;

    bar(bm(poor),hc(poor),1.05,...
        'facecolor',r,'edgecolor',r) ;
    bar(bm(okay),hc(okay),1.05,...
        'facecolor',y,'edgecolor',y) ;
    bar(bm(good),hc(good),1.05,...
        'facecolor',g,'edgecolor',g) ;
    bar(bm(best),hc(best),1.05,...
        'facecolor',k,'edgecolor',k) ;

    axis tight;
    set(gca,'ycolor', get(gca,'color'),'ytick',[],...
        'xtick',0:30:180,'layer','top','fontsize',...
            14,'linewidth',2.,'ticklength',[.025,.025],...
                'box','off','xlim',[0.,180.]) ;

    mina = max(1.000,min(ad)); %%!! so that axes don't obscure!
    maxa = min(179.0,max(ad));

    bara = mean(ad(:));
    mada = mad (ad(:));

    line([ mina, mina],...
        [0,max(hc)],'color','r','linewidth',1.5);
    line([ maxa, maxa],...
        [0,max(hc)],'color','r','linewidth',1.5);

    if ( mina > 25.0)
        text(mina-1.8,.90*max(hc),num2str(min(ad),'%16.1f'),...
            'horizontalalignment',...
                'right','fontsize',15) ;
    else
        text(mina+1.8,.90*max(hc),num2str(min(ad),'%16.1f'),...
            'horizontalalignment',...
                'left' ,'fontsize',15) ;
    end

    if ( maxa < 140.)
        text(maxa+1.8,.90*max(hc),num2str(max(ad),'%16.1f'),...
            'horizontalalignment',...
                'left' ,'fontsize',15) ;
    else
        text(maxa-1.8,.90*max(hc),num2str(max(ad),'%16.1f'),...
            'horizontalalignment',...
                'right','fontsize',15) ;
    end

    if ( maxa < 100.)

    if ( ~(exist('OCTAVE_VERSION','builtin') > +0) )
        text(maxa-16.,.45*max(hc),...
        '$\bar{\sigma}_{\theta}\!= $',...
            'horizontalalignment', 'left',...
                'fontsize',16,'interpreter','latex') ;

        text(maxa+1.8,.45*max(hc),num2str(mad(ad),'%16.2f'),...
            'horizontalalignment',...
                'left' ,'fontsize',15) ;
    end

    else

    if ( ~(exist('OCTAVE_VERSION','builtin') > +0) )
        text(maxa-16.,.45*max(hc),...
        '$\bar{\sigma}_{\theta}\!= $',...
            'horizontalalignment', 'left',...
                'fontsize',16,'interpreter','latex') ;

        text(maxa+1.8,.45*max(hc),num2str(mad(ad),'%16.3f'),...
            'horizontalalignment',...
                'left' ,'fontsize',15) ;
    end

    end

    switch (ty)
    case 'tria4'

    if ( ~(exist('OCTAVE_VERSION','builtin') > +0) )
        text(-9.0,0.0,'$\theta_{\tau}$',...
            'horizontalalignment','right',...
                'fontsize',22,'interpreter','latex') ;
    else
        text(-9.0,0.0, '\theta_{\tau}' ,...
            'horizontalalignment','right',...
                'fontsize',22,'interpreter',  'tex') ;
    end

    case 'tria3'

    if ( ~(exist('OCTAVE_VERSION','builtin') > +0) )
        text(-9.0,0.0,'$\theta_{f}$',...
            'horizontalalignment','right',...
                'fontsize',22,'interpreter','latex') ;
    else
        text(-9.0,0.0, '\theta_{f}' ,...
            'horizontalalignment','right',...
                'fontsize',22,'interpreter',  'tex') ;
    end

    end

end

function scrhist(sc,ty)
%SCRHIST draw histogram for "score" quality-metric.

    sc = sc(:);
    be = linspace(0.,1.,101);
    bm = (be(1:end-1)+be(2:end)) / 2.;
    hc = histc(sc,be);

    switch (ty)
    case{'tria4','dual4'}
        poor = bm <  .25 ;
        okay = bm >= .25 & bm <  .50 ;
        good = bm >= .50 & bm <  .75 ;
        best = bm >= .75 ;

    case{'tria3','dual3'}
        poor = bm <  .30 ;
        okay = bm >= .30 & bm <  .60 ;
        good = bm >= .60 & bm <  .90 ;
        best = bm >= .90 ;

    end

    r = [.85,.00,.00] ; y = [1.0,.95,.00] ;
    g = [.00,.90,.00] ; k = [.60,.60,.60] ;

    bar(bm(poor),hc(poor),1.05,...
        'facecolor',r,'edgecolor',r) ;
    bar(bm(okay),hc(okay),1.05,...
        'facecolor',y,'edgecolor',y) ;
    bar(bm(good),hc(good),1.05,...
        'facecolor',g,'edgecolor',g) ;
    bar(bm(best),hc(best),1.05,...
        'facecolor',k,'edgecolor',k) ;

    axis tight;
    set(gca,'ycolor', get(gca,'color'),'ytick',[],...
        'xtick',.0:.2:1.,'layer','top','fontsize',...
            14,'linewidth',2.,'ticklength',[.025,.025],...
                'box','off','xlim',[0.,1.]) ;

    mins = max(0.010,min(sc)); %%!! so that axes don't obscure!
    maxs = min(0.990,max(sc));

    line([ mins, mins],...
        [0,max(hc)],'color','r','linewidth',1.5);
    line([mean(sc),mean(sc)],...
        [0,max(hc)],'color','r','linewidth',1.5);

    if ( mins > .4)
        text(mins-.01,.9*max(hc),num2str(min(sc),'%16.3f'),...
            'horizontalalignment',...
                'right','fontsize',15) ;
    else
        text(mins+.01,.9*max(hc),num2str(min(sc),'%16.3f'),...
            'horizontalalignment',...
                'left' ,'fontsize',15) ;
    end

    if ( mean(sc) > mins + .150)
    text(mean(sc)-.01,.9*max(hc),num2str(mean(sc),'%16.3f'),...
        'horizontalalignment','right','fontsize',15) ;
    end

    switch (ty)
    case 'tria4'

    if ( ~(exist('OCTAVE_VERSION','builtin') > +0) )
        text(-.04,0.0, ...
        '$\mathcal{Q}^{\mathcal{T}}_{\tau}$',...
            'horizontalalignment','right',...
                'fontsize',22,'interpreter','latex') ;
    else
        text(-.04,0.0,'Q^{t}_{\tau}',...
            'horizontalalignment','right',...
                'fontsize',22,'interpreter',  'tex') ;
    end

    case 'tria3'

    if ( ~(exist('OCTAVE_VERSION','builtin') > +0) )
        text(-.04,0.0, ...
        '$\mathcal{Q}^{\mathcal{T}}_{f}$',...
            'horizontalalignment','right',...
                'fontsize',22,'interpreter','latex') ;
    else
        text(-.04,0.0,'Q^{t}_{f}',...
            'horizontalalignment','right',...
                'fontsize',22,'interpreter',  'tex') ;
    end

    case 'dual4'

    if ( ~(exist('OCTAVE_VERSION','builtin') > +0) )
        text(-.04,0.0, ...
        '$\mathcal{Q}^{\mathcal{D}}_{\tau}$',...
            'horizontalalignment','right',...
                'fontsize',22,'interpreter','latex') ;
    else
        text(-.04,0.0,'Q^{d}_{\tau}',...
            'horizontalalignment','right',...
                'fontsize',22,'interpreter',  'tex') ;
    end

    case 'dual3'

    if ( ~(exist('OCTAVE_VERSION','builtin') > +0) )
        text(-.04,0.0, ...
        '$\mathcal{Q}^{\mathcal{D}}_{f}$',...
            'horizontalalignment','right',...
                'fontsize',22,'interpreter','latex') ;
    else
        text(-.04,0.0,'Q^{d}_{f}',...
            'horizontalalignment','right',...
                'fontsize',22,'interpreter',  'tex') ;
    end

    end

end

function hfnhist(hf,ty)
%HFNHIST draw histogram for "hfunc" quality-metric.

    be = linspace(0.,2.,101);
    bm = (be(1:end-1)+be(2:end)) / 2.;
    hc = histc(hf,be);

    poor = bm <  .40 | bm >= 1.6  ;
    okay =(bm >= .40 & bm <  .60 )| ...
          (bm >= 1.4 & bm <  1.6 );
    good =(bm >= .60 & bm <  .80 )| ...
          (bm >= 1.2 & bm <  1.4 );
    best = bm >= .80 & bm <  1.2 ;

    r = [.85,.00,.00] ; y = [1.0,.95,.00] ;
    g = [.00,.90,.00] ; k = [.60,.60,.60] ;

    bar(bm(poor),hc(poor),1.05,...
        'facecolor',r,'edgecolor',r) ;
    bar(bm(okay),hc(okay),1.05,...
        'facecolor',y,'edgecolor',y) ;
    bar(bm(good),hc(good),1.05,...
        'facecolor',g,'edgecolor',g) ;
    bar(bm(best),hc(best),1.05,...
        'facecolor',k,'edgecolor',k) ;

    axis tight;
    set(gca,'ycolor', get(gca,'color'),'ytick',[],...
        'xtick',.0:.5:2.,'layer','top','fontsize',...
            14,'linewidth',2.,'ticklength',[.025,.025],...
                'box','off','xlim',[0.,2.]);

    line([max(hf),max(hf)],...
        [0,max(hc)],'color','r','linewidth',1.5);

    text(max(hf)+.02,.90*max(hc),num2str(max(hf),'%16.2f'),...
        'horizontalalignment','left','fontsize',15) ;

    if ( ~(exist('OCTAVE_VERSION','builtin') > +0) )

    text(max(hf)-.18,.45*max(hc),'$\bar{\sigma}_{h}\! = $',...
        'horizontalalignment','left',...
            'fontsize',16,'interpreter','latex') ;

    text(max(hf)+.02,.45*max(hc),num2str(mad(hf),'%16.2f'),...
        'horizontalalignment','left','fontsize',15) ;

    end

    if ( ~(exist('OCTAVE_VERSION','builtin') > +0) )

    text(-0.10,0.0,'$h_{r}$','horizontalalignment','right',...
        'fontsize',22,'interpreter','latex') ;

    else

    text(-0.10,0.0, 'h_{r}' ,'horizontalalignment','right',...
        'fontsize',22,'interpreter',  'tex') ;

    end

end


function varargout = drawOrientedBox(box, varargin)
%DRAWORIENTEDBOX Draw centered oriented rectangle.
%
%   Syntax
%   drawOrientedBox(BOX)
%   drawOrientedBox(BOX, 'PropertyName', propertyvalue, ...)
%
%   Description
%   drawOrientedBox(OBOX)
%   Draws an oriented rectangle (or bounding box) on the current axis.
%   OBOX is a 1-by-5 row vector containing box center, dimension (length
%   and width) and orientation (in degrees):
%   OBOX = [CX CY LENGTH WIDTH THETA].
%
%   When OBOX is a N-by-5 array, the N boxes are drawn.
%
%   drawOrientedBox(AX, ...)
%   Specifies the axis to draw to point in. AX should be a handle to a axis
%   object. By default, display on current axis.
%
%   HB = drawOrientedBox(...)
%   Returns a handle to the created graphic object(s). Object style can be
%   modified using syntaw like:
%   set(HB, 'color', 'g', 'linewidth', 2);
%
%   Example
%     % draw an ellipse together with its oriented box
%     elli = [30 40 60 30 20];
%     figure;
%     drawEllipse(elli, 'linewidth', 2, 'color', 'g');
%     hold on
%     box = [30 40 120 60 20];
%     drawOrientedBox(box, 'color', 'k');
%     axis equal;
%
%   See also
%     orientedBox, drawPolygon, drawRect, drawBox, drawCenteredEdge
%

% ------
% Author: David Legland
% E-mail: david.legland@inrae.fr
% Created: 2011-05-09, using Matlab 7.9.0.529 (R2009b)
% Copyright 2011-2022 INRA - Cepia Software Platform

%% Parses input arguments

% extract handle of axis to draw on
if isAxisHandle(box)
    ax = box;
    box = varargin{1};
    varargin(1) = [];
else
    ax = gca;
end

if length(varargin) > 4 && sum(cellfun(@isnumeric, varargin(1:4))) == 4
    % input given as separate arguments
    cx  = box;
    cy  = varargin{1};
    hl   = varargin{2} / 2;
    hw   = varargin{3} / 2;
    theta   = varargin{4};
    varargin = varargin(5:end);

else
    % input given as packed array
    cx  = box(:,1);
    cy  = box(:,2);
    hl   = box(:,3) / 2;
    hw   = box(:,4) / 2;
    theta = box(:,5);
end

%% Draw each box

% allocate memory for graphical handle
hr = zeros(length(cx), 1);

% iterate on oriented boxes
for i = 1:length(cx)
    % pre-compute angle data
    cot = cosd(theta(i));
    sit = sind(theta(i));

    % x and y shifts
    lc = hl(i) * cot;
    ls = hl(i) * sit;
    wc = hw(i) * cot;
    ws = hw(i) * sit;

    % coordinates of box vertices
    vx = cx(i) + [-lc + ws; lc + ws ; lc - ws ; -lc - ws ; -lc + ws];
    vy = cy(i) + [-ls - wc; ls - wc ; ls + wc ; -ls + wc ; -ls - wc];

    % draw polygons
    hr(i) = plot(ax, vx, vy, varargin{:});
end

%% Format output

if nargout > 0
    varargout = {hr};
end


function a = reshape(a,varargin)
%RESHAPE      Reshape for slope vectors/matrices
%
%   r = reshape(a,vector)  or  r = reshape(a,n1,n2,...)
%
% functionality as Matlab function reshape
%

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

  index = reshape(1:prod(a.size),varargin{:});
  a.size = size(index);


function Cs = WENStoClockwise(D);
% WENStoClockwise: Converts a data structure where wedge orientations
%                  are organized by cardinal point (in the order West
%                  East North South) into another structure with
%                  orientations starting from top left wedge and
%                  increasing in a clockwise fashion.
%
% See Also
%   SeparateAngles, DetailCurveCoeff, ClockwisetoWENS

   [nq,nw,nl,ns] = size(D);
   Cs = cell(1,nq*nw);
   cnt = 1;

    for w = 1:nw
      Cs{cnt} = squeeze(D(3,w,:,:)); cnt = cnt+1;
    end
    for w=nw:-1:1
      Cs{cnt} = squeeze(D(2,w,:,:)).'; cnt = cnt + 1;
    end
    for w=1:nw
      Cs{cnt} = squeeze(D(4,w,:,:)); cnt = cnt+1;
    end
    for w=nw:-1:1
      Cs{cnt} = squeeze(D(1,w,:,:)).'; cnt = cnt + 1;
    end


% Test file for trigtech/fliplr.m

function pass = test_fliplr(pref)

% Get preferences.
if ( nargin < 1 )
    pref = trigtech.techPref();
end

testclass = trigtech();

%%
% Conduct a few very straightforward tests.

f = testclass.make(@(x) cos(pi*x), [], pref);
pass(1) = isequal(f, fliplr(f));

f = testclass.make(@(x) [sin(pi*x) cos(pi*x)], [], pref);
g = testclass.make(@(x) [cos(pi*x) sin(pi*x)], [], pref);
pass(2) = isequal(fliplr(f), g);

end


function nullStats = GiveMeSimpleNullStats(groupLabels,numNulls,cfnParams,meanOverFolds)
% Returns simple permutation-based null samples
%-------------------------------------------------------------------------------

% Check inputs and set defaults:
if nargin < 4
    meanOverFolds = true;
end

%-------------------------------------------------------------------------------
numDataSamples = length(groupLabels);

if meanOverFolds
    nullStats = zeros(numNulls,1);
else
    nullStats = zeros(numNulls,cfnParams.numFolds);
end

for i = 1:numNulls
    shuffledLabels = groupLabels(randperm(numDataSamples));

    % One repeat of 10-fold cross validation using the shuffled labels:
    cvFolds = cvpartition(groupLabels,'KFold',cfnParams.numFolds,'Stratify',true);
    nullAcc_k = zeros(cfnParams.numFolds,1);
    for k = 1:cfnParams.numFolds
        yTrue = groupLabels(cvFolds.test(k));
        yPredict = shuffledLabels(cvFolds.test(k));
        nullAcc_k(k) = BF_LossFunction(yTrue,yPredict,cfnParams.whatLoss,cfnParams.classLabels);
    end

    % Agglomerate over folds:
    if meanOverFolds
        nullStats(i) = mean(nullAcc_k);
    else
        nullStats(i,:) = nullAcc_k;
    end
end

end


function [llh] = tapas_ti_llh(y, x, u, theta, ptheta)
%% General method to iterate across chains and subjects
%
% aponteeduardo@gmail.com
% copyright (C) 2016
%

fllh = ptheta.method_llh;

ns = size(theta, 1);
nc = size(theta, 2);

llh = zeros(1, nc);

for i = 1:nc
    tllh = zeros(ns, 1);
    for j = 1:ns
        tllh(j) = fllh(y{j, i}, x{j, i}, u{j, i}, theta{j, i}, ptheta);
    end
    llh(i) = sum(tllh);
end

%if any(llh < 1000)
%    keyboard
%end

end


function calpak_test0005 ( )

%*****************************************************************************80
%
%% CALPAK_TEST0005 tests CWS_TO_JED_GPS and JED_TO_CWS_GPS.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    09 June 2012
%
%  Author:
%
%    John Burkardt
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'CALPAK_TEST0005\n' );
  fprintf ( 1, '  For the GPS calendar:\n' );
  fprintf ( 1, '  JED_TO_CWS_GPS: JED -> CWS.\n' );
  fprintf ( 1, '  CWS_TO_JED_GPS: CWS -> JED.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '   JED (in)       CWS                            JED (out)\n' );
  fprintf ( 1, '\n' );

  jed_epoch = epoch_to_jed_gps ( );

  i = 0;

  while ( 1 )

    i = i + 1;
    jed1 = jed_test ( i );

    if ( jed1 < 0.0 )
      break
    end

    if ( jed_epoch <= jed1 )

      [ c2, w2, sec2 ] = jed_to_cws_gps ( jed1 );

      s2 = cws_to_s_gps ( c2, w2, sec2 );

      jed3 = cws_to_jed_gps ( c2, w2, sec2 );

      fprintf ( 1, '  %11.2f     %s  %11.2f\n', jed1, s2, jed3 );

    end

  end

  return
end


% SP_GET_CELLS: Compute the indices of the cells within the support of a list of tensor-product B-spline function.
%
% [cell_indices, indices_per_function] = sp_get_cells (space, msh, indices)
%
% INPUT:
%    space:   object defining the space of discrete functions (see sp_multipatch)
%    msh:     object defining the domain partition and the quadrature rule (see msh_multipatch)
%    indices: indices of the functions.
%
% OUTPUT:
%    cell_indices: indices of the cells within the support of the basis functions.
%    indices_per_function: indices of the cells within the support of each basis function.
%
% Copyright (C) 2015, 2016 Rafael Vazquez
%
%    This program is free software: you can redistribute it and/or modify
%    it under the terms of the GNU General Public License as published by
%    the Free Software Foundation, either version 3 of the License, or
%    (at your option) any later version.

%    This program is distributed in the hope that it will be useful,
%    but WITHOUT ANY WARRANTY; without even the implied warranty of
%    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%    GNU General Public License for more details.
%
%    You should have received a copy of the GNU General Public License
%    along with this program.  If not, see <http://www.gnu.org/licenses/>.

function [cell_indices, indices_per_function] = sp_get_cells (space, msh, fun_indices)

fun_indices = fun_indices(:).';

indices_per_function = cell (numel (fun_indices), 1);
cell_indices = [];

Nelem = cumsum ([0 msh.nel_per_patch]);
for iptc = 1:space.npatch
  [~, patch_indices, local_funs] = intersect (space.gnum{iptc}, fun_indices);
  if (~isempty (patch_indices))
    patch_indices = patch_indices(:).';
    [aux_cell_indices, ind_per_fun] = sp_get_cells (space.sp_patch{iptc}, msh.msh_patch{iptc}, patch_indices);

    cell_indices = union (cell_indices, Nelem(iptc)+aux_cell_indices);

    if (nargout == 2)
      local_funs = local_funs(:).';
      for ifun = 1:numel(patch_indices)
        indices_per_function{local_funs(ifun)} = union (indices_per_function{local_funs(ifun)}, Nelem(iptc)+ind_per_fun{ifun});
      end
    end
  end
end


%% Dataset Basics (setting sample attributes)
%
%
% #   For CoSMoMVPA's copyright information and license terms,   #
% #   see the COPYING file distributed with CoSMoMVPA.           #

% Set the targets and the chunks
%
% There are 10 runs with 6 volumes per run. The runs are vertically stacked one
% above the other. The six volumes in each run correspond to the stimuli:
% 'monkey','lemur','mallard','warbler','ladybug','lunamoth', in that order. Add
% numeric targets labels (samples atribute) such that 1 corresponds to 'monkey',
% 2 corresponds to 'lemur', etc. Then add numeric chunks (another samples
% attribute) so that 1 corresponds to run1, 2 corresponds to run2, etc.

config=cosmo_config();
data_path=fullfile(config.tutorial_data_path,'ak6','s01');

%% Load the dataset 'glm_T_stats_perrun.nii' masked with 'brain_mask.nii'
% >@@>
mask_fn = fullfile(data_path, 'brain_mask.nii');
data_fn = fullfile(data_path, 'glm_T_stats_perrun.nii');
ds=cosmo_fmri_dataset(data_fn, 'mask', mask_fn);
% <@@<
%% set targets
%remember that targets are part of ds.sa and that they are stored in a
%column vector
% >@@>
ds.sa.targets = repmat(1:6, [1, 10])'; %10 times labels 1 to 6, column vector
% <@@<
%% set chunks
%remember that chunks are part of ds.sa and that they are stored in a
%column vector
% >@@>
chunks = repmat(1:10, [6, 1]);
chunks = chunks(:); %flatten matrix to a column vector
ds.sa.chunks = chunks;
% <@@<

%% Show the results

%% print the dataset
fprintf('\nDataset:\n')
cosmo_disp(ds)

%% print the sample attributes
fprintf('\nSample attributes (in full):\n')
cosmo_disp(ds.sa,'edgeitems',Inf); %'edgeitems determine how much of a
                                   % matrix is displayed. Try different values.

%% print targets and chunks next to each other
fprintf('\nTargets and chunks attributes (in full):\n')
nsamples=size(ds.samples,1);
fprintf('sample #   target   chunk\n');
index_target_chunks=[(1:nsamples)', ds.sa.targets,ds.sa.chunks];
cosmo_disp(index_target_chunks,'edgeitems',Inf);


function [O ,O2, DzDw1 , DzDw2 ] = xmid(I1, I2, Y, gamma, Rho, DzDy)
%% Reconstruction layer in the middle of the network.
%% This layer has two parameters: H_{l} = sum_{m=1}^{s} gamma_{l,m}B_{m};  \rho_{l}
%% This layer has two inputs: I1 = z ; I2 = \beta
%% Copyright (c) 2017 Yan Yang
%% All rights reserved.

%% network setting
config;
fN = nnconfig.FilterNumber;
fS = nnconfig.FilterSize;
pad = nnconfig.Padding;
gp = nnconfig.EnableGPU;
s = fS*fS-1;

B=filter_base( );
for i=1:fN
    H(:,:,i) = reshape( B * gamma( : ,  i) , fS ,fS);
end
HT = rot90(H,2);
load('./mask.mat')
mask = logical( ifftshift(mask) );
Denom1 = zeros(256 , 256) ; Denom1(mask) = 1 ;
[m ,n] = size(Y);
Denom2=zeros(m,m);

for k=1:fN
    prd = sqrt(Rho(k));
    Denom2 = Denom2 + abs( psf2otf (prd * H(:,:,k),[m,n])).^2;
end
Denom = Denom1+Denom2;
Denom(find(Denom == 0)) = 1e-6;
Q2=1./Denom;

if nargin == 5
    Pr=zeros(m,n);
    for i = 1:fN
        tp1 = I1(:,:,i) - I2(:,:,i);
        tp2 = imfilter(double(tp1),double(HT(:,:,i)),'same','circular','conv');
        Pr= Pr+Rho(i)*tp2;
    end
    O = real( ifft2(( fft2 ( Pr ) + Y ) .* Q2));
end

if nargin == 6

    if gp
        Hp = gpuArray(H);
        [Bj1p,PSp] = FBASE(B);
        Q2=gpuArray(Q2);
        DzDy=gpuArray(DzDy);
        H1p=gpuArray(HT);
        Y=gpuArray(Y);
        Ds = gpuArray(zeros(m,m));
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  O1 O2
        A = (-1)*( Q2 .* Q2);
        Trans1 =  ifft2(Q2.*fft2(DzDy));
        Trans1 = real(Trans1);
        Trans=gather(Trans1);
        PadT = padImage_g(Trans,[pad,pad],'circular');
        PadT = gpuArray(PadT);
        for i = 1:fN
            S = conv2(PadT,Hp(:,:,i),'valid');
            S = gather(S);
            O(:,:,i) = Rho(i)*S;
            O2(:,:,i) = (-1)*Rho(i)*S;
            tp5 = I1(:,:,i)-I2(:,:,i);
            aaa = padImage_g( tp5,[pad,pad],'circular');
            aaa = gpuArray(aaa);
            tp52 = conv2(aaa,H1p(:,:,i),'valid');
            Ds= Ds +Rho(i) *tp52;
        end
        Njj = fft2(Ds)+Y;
        for i = 1:fN
            PS1 = psf2otf(Hp(:,:,i), [m,m]);
            tp5 = I1(:,:,i)-I2(:,:,i);
            Padtp = padImage_g(tp5,[pad,pad],'circular');
            Padtp = gpuArray(Padtp);
            tp54 = conv2(Padtp,H1p(:,:,i),'valid');
            tp54 = fft2(tp54);
            Nii2 = abs(PS1).^2 ;
            tp1 = A.* Nii2 .*Njj;
            tp2 = Q2.*tp54;
            tp1 = ifft2(tp1);
            tp2 = ifft2(tp2);
            temp = DzDy.*(tp1+tp2);
            temp = real(gather(temp));
            DzDw2(i) = sum(temp(:));
            for  j = 1 : s
                PS3 = 2*(PSp(:,:,j).*PS1);
                tp6 = A.*PS3.*Njj;
                PS3 = ifft2(tp6);
                DS = conv2(Padtp,Bj1p(:,:,j),'valid');
                DS = fft2(DS);
                DS = Q2.*DS;
                DS = ifft2(DS);
                PfN = DzDy.*(PS3+DS);
                SSS = real(PfN*Rho(i));
                DzDw1(j,i) = sum(SSS(:));
            end

        end
        DzDw1=gather(DzDw1);
    else
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  O1, O2
        for k = 1:fN
            Trans =  ifft2(Q2.*fft2(DzDy));
            S = imfilter(double(Trans),double(H(:,:,k)),'same','circular','conv');
            O(:,:,k) = Rho(k)*S;
            O2(:,:,k) = (-1)*Rho(k)*S;
        end
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% DzDw1
        A=(-1)* Q2 .* Q2;
        Ds=zeros(m,m);
        for i=1:fN
            tp1 = I1(:,:,i)-I2(:,:,i);
            tp3=Rho(i) * imfilter(double(tp1) ,double(HT(:,:,i)),'same','circular','conv');
            Ds= Ds +tp3;
        end
        Njj=fft2(Ds)+Y;
        for i=1:fN
            for j=1:s
                Bj=reshape(B(:,j),fS,fS);
                Bj1=rot90(Bj,2);
                PS=psf2otf(Bj1, [m,m]);
                PS1=psf2otf(H(:,:,i), [m,m]);
                PS3=2*PS.*PS1;
                PS3=DzDy.*ifft2(Rho(i)*A.*PS3.*Njj);
                tp1=I1(:,:,i)-I2(:,:,i);
                DS= imfilter(double(tp1) ,double(Bj1),'same','circular','conv');
                DS=DzDy.*ifft2(Rho(i)*Q2.*fft2(DS));
                DzDw1(j,i)=sum(sum(PS3+DS));
            end
        end
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% DzDw2
        for k=1:fN
            Nii =abs(psf2otf(H(:,:,k),[m,n])).^2 ;
            tp1=I1(:,:,k) - I2(:,:,k);
            tp4 = imfilter(double(tp1),double(HT(:,:,k)),'same','circular','conv');
            tp4 =fft2(tp4);
            temp1=DzDy.*ifft2(A.*Nii.*Njj );
            temp2=DzDy.*ifft2( Q2.*tp4);
            temp=sum(temp1(:))+sum(temp2(:));
            DzDw2(k)=temp;
        end
    end
end
end


%  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 should have received a copy of the GNU General Public License
%  along with this program; if not, write to the Free Software
%  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
%function tfrscalt
%TFRSCALT Unit test for the time-frequency representation TFRSCALO.

%	O. Lemoine - June 1996.

% We test each property of the corresponding TFR :

N=128;

% Covariance by translation in time
t1=60; t2=70; f=0.3; W=0;
sig1=amgauss(N,t1).*fmconst(N,f,t1);
sig2=amgauss(N,t2).*fmconst(N,f,t2);
tfr1=tfrscalo(sig1,1:N,W,0.1,0.4,128);
tfr2=tfrscalo(sig2,1:N,W,0.1,0.4,128);
[tr,tc]=size(tfr1);
nu=round(f*(tc-1)*2)+1;
tfr=tfr1-tfr2(:,modulo((1:tc)-t1+t2,tc));
if any(any(abs(tfr)>sqrt(eps))),
 error('tfrscalo test 1 failed');
end

% Covariance by dilation
t=N/2; f=0.2; T=2*sqrt(N); a=2; W=8;
sig1=amgauss(N,t,T).*fmconst(N,f,t);
sig2=amgauss(a*N,a*t,T*a).*fmconst(a*N,f/a,a*t);
[tfr1,t1,f1]=tfrscalo(sig1,1:N  ,W,0.01,0.49,N);
[tfr2,t2,f2]=tfrscalo(sig2,1:a*N,W,0.01,0.49,N);
Max1=max(max(tfr1)); Max2=max(max(tfr2));
[I1,J1]=find(tfr1==Max1); [I2,J2]=find(tfr2==Max2);
if abs(f1(I1)-a*f2(I2))>1e-2 | J2~=a*J1,
 error('tfrscalo test 2 failed');
end

% Reality of the TFR
sig=noisecg(N); W=5;
tfr=tfrscalo(sig,1:N,W,0.01,0.5,N);
if sum(any(abs(imag(tfr))>sqrt(eps)))~=0,
 error('tfrscalo test 3 failed');
end

% Energy conservation
sig=fmsin(N,.1,.4); W=6; Nf=2*N ;
[tfr,t,f]=tfrscalo(sig,1:N,W,0.01,0.49,Nf);
Es=norm(sig)^2/Nf;
Etfr=integ2d(tfr,t,f)/N;
if abs(Es-Etfr)>sqrt(eps),
 error('tfrscalo test 4 failed');
end

% Positivity
if any(any(tfr<0)),
 error('tfrscalo test 5 failed');
end

% Same energy in the time-scale plane for 2 gaussian atoms at different scales
sig=amgauss(256).*(fmconst(256,.15)+fmconst(256,.35));
[tfr,t,f]=tfrscalo(sig,1:256,12,.01,.49,512);
int1=integ2d(tfr(1:430,:),t,f(1:430));
int2=integ2d(tfr(431:512,:),t,f(431:512));
if abs(int1-int2)>1e-4,
 error('tfrscalo test 6 failed');
end

N=127;

% Covariance by dilation
t=round(N/2); f=0.2; T=2*sqrt(N); a=2; W=8;
sig1=amgauss(N,t,T).*fmconst(N,f,t);
sig2=amgauss(a*N,a*t,T*a).*fmconst(a*N,f/a,a*t);
[tfr1,t1,f1]=tfrscalo(sig1,1:N  ,W,0.01,0.49,N);
[tfr2,t2,f2]=tfrscalo(sig2,1:a*N,W,0.01,0.49,N);
Max1=max(max(tfr1)); Max2=max(max(tfr2));
[I1,J1]=find(tfr1==Max1); [I2,J2]=find(tfr2==Max2);
if abs(f1(I1(1))-a*f2(I2))>1e-2 | J2~=a*J1(1)+1,
 error('tfrscalo test 7 failed');
end

% Reality of the TFR
sig=noisecg(N); W=5;
tfr=tfrscalo(sig,1:N,W,0.01,0.5,N);
if sum(any(abs(imag(tfr))>sqrt(eps)))~=0,
 error('tfrscalo test 8 failed');
end

% Energy conservation
sig=fmsin(N,.1,.4); W=6; Nf=2*N+1 ;
[tfr,t,f]=tfrscalo(sig,1:N,W,0.01,0.49,Nf);
SP = fft(hilbert(sig));
indmin = 1+round(0.01*(N-2));
indmax = 1+round(0.49*(N-2));
SPana = SP(indmin:indmax);
Es=SPana'*SPana/Nf;
Etfr=integ2d(tfr,t,f);
if abs(Es-Etfr)>1e-3,
 error('tfrscalo test 9 failed');
end

% Positivity
if any(any(tfr<0)),
 error('tfrscalo test 10 failed');
end

% Same energy in the time-scale plane for 2 gaussian atoms at different scales
sig=amgauss(N).*(fmconst(N,.15)+fmconst(N,.35));
[tfr,t,f]=tfrscalo(sig,1:N,12,.01,.49,2*N+1);
int1=integ2d(tfr(1:210,:),t,f(1:210));
int2=integ2d(tfr(211:255,:),t,f(211:255));
if abs(int1-int2)>5e-4,
 error('tfrscalo test 11 failed');
end


function huffman_demo2
%HUFFMAN_DEMO2
%   This demo shows compression-decompression of different data.

%   $Author: Giuseppe Ridino' $
%   $Revision: 1.0 $  $Date: 02-Jul-2004 16:47:25 $

fprintf('\n')
disp('This is an example of function using Huffman compression-decompression')
disp('Press a key to continue...')
pause
fprintf('\n')

fprintf('\n')
disp('The string below will be compressed and decompressed')
disp('using norm2huff and huff2norm functions')
disp('Press a key to continue...')
pause
fprintf('\n')

data1 = 'This is a string demo. It will be compressed using norm2huff function.'

fprintf('\n')
disp('Now we will compress and decompress it.')
disp('But pay attention that data mut be converted to uint8!')
disp('Press a key to continue...')
pause
fprintf('\n')

% string data
data1 = uint8(data1);
[zipped1,info1] = norm2huff(data1)
unzipped1 = char(huff2norm(zipped1,info1))

isOK = isequal(data1,unzipped1)

whos data1 zipped1 unzipped1

bar(frequency(data1)); axis tight

%  random data1
fprintf('\n')
disp('Now we will try to compress a random sequence of 1000 bytes')
disp('Press a key to continue...')
pause
fprintf('\n')

data3 = uint8(256*rand(1,1000));
[zipped3,info3] = norm2huff(data3);
unzipped3 = huff2norm(zipped3,info3);

isOK = isequal(data3,unzipped3)

whos data3 zipped3 unzipped3

bar(frequency(data3)); axis tight

fprintf('\n')
disp('It is not well compressed. Why?')
disp('This is because the sequence is normally random!')
disp('Press a key to continue...')
pause
fprintf('\n')

%  random data2
fprintf('\n')
disp('Now we will try to compress a random sequence of 1000 bytes but not normally distributed')
disp('Press a key to continue...')
pause
fprintf('\n')

data4 = uint8(256*rand(1,1000).^3);
[zipped4,info4] = norm2huff(data4);
unzipped4 = huff2norm(zipped4,info4);

isOK = isequal(data4,unzipped4)

whos data4 zipped4 unzipped4

bar(frequency(data4)); axis tight

fprintf('\n')
disp('As the distribution is not uniform, the compression ratio is a bit more significant')
disp('Press a key to continue...')
pause
fprintf('\n')

% TERMINATED
fprintf('\n')
disp('#### FINISH ####')


%SETLABELS Reset labels of dataset or mapping
%
%   A = SETLABELS(A,LABELS,J)
%   W = SETLABELS(W,LABELS,J)
%
% INPUT
%   A          Input dataset, size [M,K]
%   W          Input mapping (classifier), size [K,C]
%   LABELS     Desired labels. M or length(J) labels for a dataset.
%              C or length(J) labels for a mapping.
% OUTPUT
%   A          Dataset with reset labels
%   W          Mapping with reset labels
%
% DESCRIPTION
% The labels of the dataset A are reset by LABELS. If supplied, the
% index vector J defines the objects for wich LABELS applies. If in
% LABELS just a single label is given all the objects defined by J
% are given that label. If LABELS is empty ([]) or NaN all the objects
% defined by J are marked as unlabeled.
%
% If A has soft labels (label type is 'soft') or has no labels but
% targets (label type is 'targets'), these soft labels or targets are
% replaced by LABELS, provided it has the right size.
%
% For soft labels and targets supplied to relabel a dataset, LABELS may be
% supplied as a dataset of which the data are used for the soft labels or
% targets and the feature labels are used to set LABLIST of A.
%
% The labels stored in a classifier mapping W are assigned as feature
% labels of the resulting dataset D in case a dataset B is applied to W:
% D = A*W.
%
% SEE ALSO (PRTools Guide)
% DATASETS, MAPPINGS, MULTI_LABELING


% rundesignsim
clear;
figure;
index = 1;
name = input('Enter the name of the output variable and files ');
eval([name ' = zeros(10,10);'])

% set initial frequency of rests
	H = findobj('Tag', 'E2');
	freqConditions = str2num(get(H(1), 'String'));
	freqConditions = num2str([freqConditions(1:4) .01]);
	set(H,'String',freqConditions);

	% set initial ISI
	H = findobj('Tag', 'E4'); % ISI
	ISI = str2num(get(H(1), 'String'));
	ISI = num2str(1);
	set(H,'String',ISI);

myISI = .1:.2:4;
myFC = .01:.1:.81;

for RR = 1:size(myISI,2)
	% set ISI
	H = findobj('Tag', 'E4'); % ISI
	ISI = str2num(get(H(1), 'String'));
	ISI = num2str(myISI(RR));
	set(H(1),'String',ISI);

	for CC = 1:size(myFC,2)
		disp(['Starting model ' num2str(index)])

		% set rest frequency
		H = findobj('Tag', 'E2');
		freqConditions = str2num(get(H(1), 'String'));
		freqConditions(end) = myFC(CC);
		freqConditions(1:end-1) = (1 - myFC(CC)) / (size(freqConditions,2)-1)
		freqConditions = num2str(freqConditions);
		set(H(1),'String',freqConditions);

		disp(['FREQC and ISI are:	' get(H(1),'String') ' and ' get(findobj('Tag','E4'),'String')])
		designsim_gui_script

		H = findobj('Tag','SIMplot');
		if ~isempty(H)
			figure(H)
			close
		end

		disp(['mean is ' num2str(mean(SIM.rnd.t))])
		eval([name '(RR,CC) = mean(SIM.rnd.t);']);
		eval([name 'HP(RR,CC) = mean(SIM.rnd.HPt);']);
		eval([name 'HL(RR,CC) = mean(SIM.rnd.HLt);']);
		eval([name '(1:10,1:10)'])
		eval(['save ' name num2str(index) ' ' name ' SIM'])
		index = index + 1;
	end
end

eval(['save ' name])
eval(['surf(' name ')']); colormap(copper)
eval(['set(gca,''XTick'',1:size(' name ',2))'])
set(gca,'XTickLabel',myFC)
eval(['set(gca,''YTick'',1:size(' name ',1))'])
set(gca,'YTickLabel',myISI)
xlabel('Proportion of blank intervals','FontSize',18)
ylabel('ITI in s','FontSize',18)
title('Surface map of ITI vs. proportion of blank intervals','FontSize',18)


function out = PP_ModelFit(y,model,order,randomSeed)
% PP_ModelFit   Investigates whether AR model fit improves with different preprocessings.
%
% After performing the range of transformations to the time series, returns the
% in-sample root-mean-square (RMS) prediction errors for an AR model on each
% transformed time series as a ratio of the RMS prediction error of the original
% time series.
%
% PP_PreProcess.m is used to perform the preprocessings
%
% The AR model is fitted using the function ar and pe from Matlab's System
% Identification Toolbox
%
% Transformations performed include:
% (i) incremental differencing,
% (ii) filtering of the power spectral density function,
% (iii) removal of piece-wise polynomial trends, and
% (iv) rank mapping the values of the time series to a Gaussian distribution.
%
%---INPUTS:
%
% y, the input time series
% model, the time-series model to fit to the transformed time series (currently
%           'ar' is the only option)
%
% order, the order of the AR model to fit to the data
%
% randomSeed, whether (and how) to reset the random seed, using BF_ResetSeed

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

% ------------------------------------------------------------------------------
%% Preliminaries
% ------------------------------------------------------------------------------
N = length(y); % length of the time series

% ------------------------------------------------------------------------------
%% Inputs
% ------------------------------------------------------------------------------
% Model: the model to fit preprocessed time series to
if nargin < 2 || isempty(model)
    model = 'ar';
end

% order: the order of model to fit
if nargin < 3 || isempty(order)
    order = 2;
end

% randomSeed: how to treat the randomization
if nargin < 4
    randomSeed = []; % default
end

% ------------------------------------------------------------------------------
%% Apply a range of preprocessings
% ------------------------------------------------------------------------------
yp = PP_PreProcess(y,'',[],[],[],randomSeed);
% Returns a structure, yp, with a range of time series in it, each a different
% transformation of the original, y.
%% ____________________FIT MODEL TO ALL:_______________________ %%

fields = fieldnames(yp);
numFields = length(fields);
% statstore = struct('fpes',{});

for i = 1:numFields
    % for each preprocessing, fit the model
    data = yp.(fields{i});
    % data is the current preprocessed data

    switch model % SO MANY OPTIONS! ;-)
        case 'ar'
            %% Check that a System Identification Toolbox license is available
            BF_CheckToolbox('identification_toolbox')

            data = zscore(data); % zscore the data from this preprocessing
            m = ar(data,order); % fit the model

            % Get statistics on fit
            %     () FPE
            statstore.fpe(i) = m.EstimationInfo.FPE;
            %     () in-sample prediction error
            e = pe(m,data);
            statstore.rmserr(i) = sqrt(mean(e.^2));
            statstore.mabserr(i) = mean(abs(e));
            statstore.ac1(i) = CO_AutoCorr(e,1,'Fourier');

        otherwise
            error('Unknown model ''%s''',model);
    end
end

% ------------------------------------------------------------------------------
%% Return statistics on statistics
% ------------------------------------------------------------------------------
% actually often as you make more stationary and remove trends it becomes
% harder to predict because these trends are very easy to predict, and
% making the series whiter will obviously decrease its predictability.

% (1) ratio of fpe of preprocessed to unprocessed time series
% I think just this is ok.
% for i=2:numFields
%     eval(['out.fperat_' fields{i} ' = ' num2str(statstore.fpe(i)/statstore.fpe(1)) ';']);
% end

% No, I'll just do in-sample rms error, for a single model no point fpeing
for i = 2:numFields
    out.(sprintf('rmserrrat_%s',fields{i})) = statstore.rmserr(i)/statstore.rmserr(1);
end
% In fact, greater error in this case means a better detrending in some
% sense -- it's remobed more of the 'obvious' linear structure (assuming
% that's the aim).

% could also return statistics on other things like prediction error, but
% not alot of point, I think.

%
%     function ydt =  SUB_remps(y,n,method)
%         % Removes the first n (proportion) of power spectrum
%         % Based on my deseasonalize1.m code
%
%
%         %% Take the Fourier Transform
%
%         Ny = length(y); % number of samples in y
% %         t = linspace(0,1,Ny); % time vector
%         NFFT = 2^nextpow2(Ny); % next power of 2
%         Fy = fft(y,NFFT); % fast fourier transform of y
%         Fy1 = Fy(1:NFFT/2+1);
% %         f = 1/2*linspace(0,1,NFFT/2+1); % frequency vector
%
%         %% Remove this range
%         % set it to (mean of the rest) across this range
%         switch method
%             case 'lf'
%                 cullr = 1:floor(length(Fy1)*n);
%             case 'biggest'
%                 cullr = find(abs(Fy1)>quantile(abs(Fy1),n));
%         end
%
%         meanrest = mean(abs(Fy1(setxor(1:end,cullr))));
% %         meanrest = 0;
%         FyF = Fy;
%         FyF(cullr)=meanrest;
%         FyF(end-cullr+2)=meanrest;
%
%
%         % PLOT
% %         plot(abs(Fy)),hold on; plot(abs(FyF),'--r'); hold off
% %         input('Here''s the filtered one...')
% %         plot(abs(FyF),'k');
% %         input('Again on it''s own...')
%
%
%         %% Inverse Fourier Transform
%         ydt = ifft(FyF,NFFT);
%         ydt = zscore(ydt(1:Ny)); % crop to desired length
%
%
%         % PLOT
% %         plot(zscore(ydt),'b'); hold on; plot(y,'r'); hold off;
% %         input(['Mean difference is ' num2str(mean(y-ydt))])
%
%     end
%
%     function ydt = SUB_rempt(y,order,nbits)
%         N = length(y);
%         ydt = zeros(N,1);
%         bits = round(linspace(0,N,nbits+1));
%         for k=1:nbits
%             r = bits(k)+1 : bits(k+1); % range defined by adjacent 'bits'
%             x = (1:length(r))'; % faux x-range
%             ybit = y(r); % y-range
%             p = polyfit(x,ybit,order);
%             ydt(r) = ybit-polyval(p,x);
%         end
%         ydt = zscore(ydt);
% %         plot(y,'b'); hold on; plot(ydt,'r');
% %         input('here we are')
%     end

end


function tests = test_ft_connectivity_pdc

% MEM 1gb
% WALLTIME 00:10:00
% DEPENDENCY ft_connectivity_pdc

if nargout
  % assume that this is called by RUNTESTS
  tests = functiontests(localfunctions);
else
  % assume that this is called from the command line
  func = localfunctions;
  for i=1:numel(func)
    fprintf('evaluating %s\n', func2str(func{i}));
    feval(func{i});
  end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function test_rpt_chan_chan_freq(testCase)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

nrpt   = 10;
nchan  = 3;
nfreq  = 4;
H      = randn(nrpt, nchan, nchan, nfreq);

dat = randn(nchan,1000);
noisecov = cov(dat');

result = {};
result{end+1} = ft_connectivity_pdc(H, 'noisecov', []);
result{end+1} = ft_connectivity_pdc(H, 'noisecov', noisecov);

% all iterations were done with (slightly) different options, hence the results should not be equal
for i=1:numel(result)
  for j=(i+1):numel(result)
    assert(~isequaln(result{i}, result{j}), 'the results %d and %d should not be equal', i, j);
  end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function test_rpt_chan_chan_freq_time(testCase)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

nrpt   = 10;
nchan  = 3;
nfreq  = 4;
ntime  = 5;
H      = randn(nrpt, nchan, nchan, nfreq, ntime);

dat = randn(nchan,1000);
noisecov = cov(dat');

result = {};
result{end+1} = ft_connectivity_pdc(H, 'noisecov', []);
result{end+1} = ft_connectivity_pdc(H, 'noisecov', noisecov);

% all iterations were done with (slightly) different options, hence the results should not be equal
for i=1:numel(result)
  for j=(i+1):numel(result)
    assert(~isequaln(result{i}, result{j}), 'the results %d and %d should not be equal', i, j);
  end
end


function printx(x,rtk)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Copyright (C) 2020-2025, by Kai Chen, All rights reserved.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
global glc
opt=rtk.opt; nf=rtk.NF;

fprintf('pos   = ');fprintf('%14.5f %14.5f %14.5f',x(1),x(2),x(3));fprintf('\n');

if rtk.NP==9
    fprintf('vel   = ');fprintf('%9.5f%9.5f%9.5f',x(4),x(5),x(6));fprintf('\n');
    fprintf('acc   = ');fprintf('%9.5f%9.5f%9.5f',x(7),x(8),x(9));fprintf('\n');
end

if rtk.NI>0
    fprintf('iono  = ');
    for i=1:glc.MAXSAT
        if abs(x(rtk.ii+i))>=1e-6,fprintf('%9.5f',x(rtk.ii+i));end
    end
    fprintf('\n');
end

if rtk.NT>0
    fprintf('trop  = ');
    if opt.tropopt==glc.TROPOPT_EST
        fprintf('%9.5f',x(rtk.itr+1));
        fprintf('%9.5f',x(rtk.itb+1));
    else
        fprintf('%9.5f',x(rtk.itr+1));
        fprintf('%9.5f',x(rtk.itr+2));
        fprintf('%9.5f',x(rtk.itr+3));
        fprintf('%9.5f',x(rtk.itb+1));
        fprintf('%9.5f',x(rtk.itb+2));
        fprintf('%9.5f',x(rtk.itb+3));
    end
    fprintf('\n');
end

if rtk.NL>0
    fprintf('glo   = ');
    fprintf('%9.5f',x(rtk.il+1)); fprintf('%9.5f',x(rtk.il+2));
    fprintf('\n');
end

if rtk.NB>0
    fprintf('bias1 = ');
    for i=1:glc.MAXSAT
        if abs(x(rtk.ib+i))>=1e-6,fprintf('%10.5f',x(rtk.ib+i));end
    end
    fprintf('\n');
    if nf>=2
        fprintf('bias2 = ');
        for i=1:glc.MAXSAT
            if abs(x(rtk.ib+glc.MAXSAT+i))>=1e-6
                fprintf('%10.5f',x(rtk.ib+glc.MAXSAT+i));
            end
        end
        fprintf('\n');
    end
    if nf>=3
        fprintf('bias3 = ');
        for i=1:glc.MAXSAT
            if abs(x(rtk.ib+glc.MAXSAT*2+i))>=1e-6
                fprintf('%10.5f',x(rtk.ib+glc.MAXSAT*2+i));
            end
        end
        fprintf('\n');
    end
end

return


function net = fixduplicates(net, x, y)

% FIXDUPLICATES
%
% Ensure that identical support vector of each class have identical Lagrange
% multipliers.
%
%    net = fixduplicates(net, x, y)
%
% where x and y are the training data.  The strip or compact methods must not
% previously have been applied to this network.

%
% File        : @svc/fixduplicates.m
%
% Date        : Tuesday 12th September 2000
%
% Author      : Dr Gavin C. Cawley
%
% Description : Part of an object-oriented implementation of Vapnik's Support
%               Vector Machine, as described in [1].
%
% References  : [1] V.N. Vapnik,
%                   "The Nature of Statistical Learning Theory",
%                   Springer-Verlag, New York, ISBN 0-387-94559-8,
%                   1995.
%
% History     : 07/07/2000 - v1.00
%               12/09/2000 - v1.01 minor improvements to comments and help
%                                  message
%               16/09/2000 - v1.10 fixed a bug requiring the training data
%                                  to be provided as parameters
%
% Copyright   : (c) Dr Gavin C. Cawley, September 2000
%
%    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 should have received a copy of the GNU General Public License
%    along with this program; if not, write to the Free Software
%    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
%

[foo, i, j] = unique(x, 'rows');

for k = unique(j)'

   idx1 = find(j == k);

   idx2 = find(y(idx1) > 0);

   if ~isempty(idx2)
      net.w(idx1(idx2)) = mean(net.w(idx1(idx2)));
   end

   idx2 = find(y(idx1) < 0);

   if ~isempty(idx2)
      net.w(idx1(idx2)) = mean(net.w(idx1(idx2)));
   end

end

% bye bye...


function [opts] = IPM_SC ( ipts , par)
% ========================================================================
% Spaese Coding of FDDL, Version 1.0
% Copyright(c) 2011  Meng YANG, Lei Zhang, Xiangchu Feng and David Zhang
% All Rights Reserved.
%
% -----------------------------------------------------------------------
% Permission to use, copy, or modify this software and its documentation
% for educational and research purposes only and without fee is here
% granted, provided that this copyright notice and the original authors'
% names appear on all copies and supporting documentation. This program
% shall not be used, rewritten, or adapted as the basis of a commercial
% software or hardware product without first obtaining permission of the
% authors. The authors make no representations about the suitability of
% this software for any purpose. It is provided "as is" without express
% or implied warranty.
%----------------------------------------------------------------------
%
% This is an implementation of the algorithm to do sparse coding
%
% Please refer to the following paper
%
% Meng Yang, Lei Zhang, Xiangchu Feng, and David Zhang,"Fisher Discrimination
% Dictionary Learning for Sparse Representation", In IEEE Int. Conf. on
% Computer Vision, 2011.
% L. Rosasco, A. Verri, M. Santoro, S. Mosci, and S. Villa. Iterative
% Projection Methods for Structured Sparsity Regularization. MIT Technical
% Reports, MIT-CSAIL-TR-2009-050,CBCL-282, 2009.
% J. Bioucas-Dias, M. Figueiredo, ?A new TwIST: two-step iterative shrinkage
% /thresholding  algorithms for image restoration?, IEEE Transactions on
% Image Processing, December 2007.
%----------------------------------------------------------------------
%
%  Inputs :   (1) ipts :    the structre of input data
%                    .D     the dictionary
%                    .tau1    parameter of l1-norm energy of coefficient
%                    .y     the testing sample
%             (2) par :     the struture of input parameters
%                    .eigenv
%
% Outputs:    (1) opts :    the structure of output data
%                    .A     the coefficient matrix
%                    .ert   the total energy sequence
%
%---------------------------------------------------------------------

ipts.cT         =      1e+10;  % stop criterion
ipts.citeT      =      1e-6;   % stop criterion
par.nIter       =      200;    % maximal iteration number
par.cRatio      =      1.05;
ipts.initM      =      'zero'; % coefficiet initialization method

switch lower(ipts.initM)
    case {'zero'}
        x(:,1)  =  zeros(size(ipts.D,2),1);
    case {'transpose'}
        x(:,1)  =  ipts.D'*ipts.y;
    case {'pinv'}
        x(:,1)  =  pinv(ipts.D)*ipts.y;
    otherwise
        error('Nonknown method!');
end

A         =         ipts.D;
tau1      =         ipts.tau1;
y         =         ipts.y;
nIter     =         par.nIter;
if ~isfield(par,{'eigenv'})
c         =         par.cRatio*find_max_eigenv(A'*A);
else
c         =         par.cRatio*par.eigenv ;
end

%%%%%%%%%%%%%%%%%%%%
% TWIST parameter
%%%%%%%%%%%%%%%%%%%%
for_ever           =         1;
IST_iters          =         0;
TwIST_iters        =         0;
sparse_sign        =         1;
verbose            =         1;
enforceMonotone    =         1;
lam1               =         1e-4;   %default eigenvalues
lamN               =         1;      %default eigenvalues
rho0               =         (1-lam1/lamN)/(1+lam1/lamN);
alpha              =         2/(1+sqrt(1-rho0^2));        %default,user can set
beta               =         alpha*2/(lam1+lamN);         %default,user can set

%%%%%%%%%%%%%%%%%%%
%main loop
%%%%%%%%%%%%%%%%%%%
xm2       =      x(:,1);
xm1       =      x(:,1);
prev_f    =      norm(y-A*x(:,1),2)^2+...
                    tau1*norm(x(:,1),1);
for n_it = 2 : nIter;

   ert(n_it-1)      =       norm(y-A*x(:,n_it-1),2)^2+...
        tau1*norm(x(:,n_it-1),1);
   fprintf('Iteration:%f  Total gap:%f\n',n_it,ert(n_it-1));

    while for_ever
       % IST(IPM) estimate
       v        =       1/c*A'*(y-A*xm1)+xm1;
       x_temp   =      soft(v,tau1/c/2);

       if (IST_iters >= 2) | ( TwIST_iters ~= 0)
            % set to zero the past when the present is zero
            % suitable for sparse inducing priors
            if sparse_sign
                mask    =   (x_temp ~= 0);
                xm1     =   xm1.* mask;
                xm2     =   xm2.* mask;
            end
            % two-step iteration
            xm2    =   (alpha-beta)*xm1 + (1-alpha)*xm2 + beta*x_temp;
            % compute residual
            f      =   norm(y-A*xm2,2)^2+...
                       tau1*norm(xm2,1);
            if (f > prev_f) & (enforceMonotone)
                TwIST_iters   =  0;  % do a IST(IPM) iteration if monotonocity fails
            else
                TwIST_iters =   TwIST_iters+1; % TwIST iterations
                IST_iters   =    0;
                x_temp      =   xm2;
                if mod(TwIST_iters,10000) ==0
                   c = 0.9*c;
                end
                break;  % break loop while
            end
        else
            f     =     norm(y-A*x_temp,2)^2+...
                        tau1*norm(x_temp,1);
            if f > prev_f
                % if monotonicity  fails here  is  because
                % max eig (A'A) > 1. Thus, we increase our guess
                % of max_svs
                c         =    2*c;
                if verbose
%                     fprintf('Incrementing c=%2.2e\n',c);
                end
                if  c > ipts.cT
                    break;  % break loop while
                end
                IST_iters = 0;
                TwIST_iters = 0;
            else
                TwIST_iters = TwIST_iters + 1;
                break;  % break loop while
            end
        end
    end

    citerion      =   abs(f-prev_f)/prev_f;
    if citerion < ipts.citeT | c > ipts.cT
%        fprintf('Stop!\n c=%2.2e\n citerion=%2.2e\n',c,citerion);
       break;
    end

    xm2           =   xm1;
    xm1           =   x_temp;
    x(:,n_it)   =   x_temp;
    prev_f        =   f;
end

opts.x     =       x(:,end);
opts.ert   =       ert;


function varargout = clickpoint(varargin)
% VL_CLICKPOINT  Select a point by clicking
%   SEL = VL_CLICKPOINT(V) let the user vl_click a point in the current
%   figure and returns the index v of the closest point (in Euclidean
%   norm) in the collection V. The 2xK matrix V has a a column for
%   each point.
%
%   The user can abort the operation by pressing any key. In this case
%   the function returns the empty matrix.
%
%   VL_CLICKPOINT(V,N) selects N points in a row. The user can stop the
%   selection at any time by pressing any key. In this case the
%   partial selection is returned. This can be used in combination
%   with N=inf to get an arbitrary number of points.
%
%   VL_CLICKPOINT() accepts the following options:
%
%   PlotMarker:: [0]
%     Put a marker as points are selected. The markers are deleted on
%     exiting the function.
%
%   See also: VL_CLICK(), VL_HELP().
[varargout{1:nargout}] = vl_clickpoint(varargin{:});


%% Copyright (C) 2015, 2016, 2019 Colin B. Macdonald
%%
%% This file is part of OctSymPy.
%%
%% OctSymPy 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 software 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 software; see the file COPYING.
%% If not, see <http://www.gnu.org/licenses/>.

%% -*- texinfo -*-
%% @documentencoding UTF-8
%% @deftypemethod  @@sym {} min (@var{a})
%% @deftypemethodx @@sym {} min (@var{a}, @var{b})
%% @deftypemethodx @@sym {} min (@var{a}, [], @var{dim})
%% @deftypemethodx @@sym {[@var{r}, @var{I}] =} min (@dots{})
%% Return minimum value of a symbolic vector or vectors.
%%
%% Example:
%% @example
%% @group
%% min(sym(1), sym(2))
%%   @result{} (sym) 1
%% m = min([1 sym(pi)/4 6])
%%   @result{} m = (sym)
%%       π
%%       ─
%%       4
%% [m, I] = min([sym(1) 0 6])
%%   @result{} m = (sym) 0
%%   @result{} I = 2
%% @end group
%% @end example
%%
%% @seealso{@@sym/max}
%% @end deftypemethod

function [z, I] = min(A, B, dim)

  if (nargout <= 1)
    if (nargin == 1)
      if (isvector(A))
        z = pycall_sympy__ ('return Min(*_ins[0])', A);
      else
        z = min(A, [], 1);
      end
    elseif (nargin == 2)
      z = elementwise_op('Min', sym(A), sym(B));
    elseif (nargin == 3)
      assert (isempty (B))
      assert (logical(dim == 1) || logical(dim == 2))

      cmd = { '(A, dim) = _ins'
              'if not A.is_Matrix:'
              '    A = sp.Matrix([A])'
              'if dim == 0:'
              '    if A.rows == 0:'
              '        return A'
              '    return Matrix([[Min(*A.col(i)) for i in range(0, A.cols)]])'
              'elif dim == 1:'
              '    if A.cols == 0:'
              '        return A'
              '    return Matrix([Min(*A.row(i)) for i in range(0, A.rows)])' };
      z = pycall_sympy__ (cmd, A, dim - 1);
    else
      print_usage ();
    end
    return
  end

  % We have second output: need the index of the minimum, can't use "Min"
  if (nargin == 1)
    if (isvector(A))
      cmd = { 'A = _ins[0]'
              'val, idx = min((val, idx) for (idx, val) in enumerate(A))'
              'return val, idx+1' };
      [z, I] = pycall_sympy__ (cmd, A);
    else
      [z, I] = min(A, [], 1);
    end
  elseif (nargin == 3)
    assert (isempty (B))
    assert (logical(dim == 1) || logical(dim == 2))

    cmd = { '(A, dim) = _ins'
            'def myargmin(z):'
            '    return min((val, idx) for (idx, val) in enumerate(z))'
            'if not A.is_Matrix:'
            '    A = sp.Matrix([A])'
            'if dim == 0:'
            '    if (A.cols == 0):'
            '        return (Matrix(0, 0, []), Matrix(0, 0, []))'
            '    if (A.rows == 0):'
            '        return (A, A)'
            '    val_idx_pairs = [myargmin(A.col(i)) for i in range(0, A.cols)]'
            '    m, I = zip(*val_idx_pairs)'
            '    return (Matrix([m]), Matrix([I]))'
            'elif dim == 1:'
            '    if (A.rows == 0):'
            '        return (Matrix(0,0,[]), Matrix(0,0,[]))'
            '    if (A.cols == 0):'
            '        return (A, A)'
            '    val_idx_pairs = [myargmin(A.row(i)) for i in range(0, A.rows)]'
            '    m, I = zip(*val_idx_pairs)'
            '    return (Matrix(m), Matrix(I))' };

    [z, I] = pycall_sympy__ (cmd, A, dim - 1);
    I = double(I);
    if (~isempty(I))
      I = I + 1;
    end
  else
    print_usage ();
  end

end

%!test
%! % scalars with dim
%! a = min(sym(pi), [], 1);
%! b = sym(pi);
%! assert (isequal (a, b));
%! a = min(sym(pi), [], 2);
%! assert (isequal (a, b));
%! a = max(sym(pi), [], 1);
%! assert (isequal (a, b));
%! a = max(sym(pi), [], 2);
%! assert (isequal (a, b));

%!shared A, D
%! D = [0 1 2 3];
%! A = sym(D);

%!test
%! % row vectors
%! assert (isequal (min(A), sym(min(D))))
%! assert (isequal (min(A), sym(0)))
%! assert (isequal (max(A), sym(max(D))))
%! assert (isequal (max(A), sym(3)))

%!test
%! % row vectors with dim
%! assert (isequal (min(A, [], 1), sym(min(D, [], 1))))
%! assert (isequal (min(A, [], 2), sym(min(D, [], 2))))
%! assert (isequal (max(A, [], 1), sym(max(D, [], 1))))
%! assert (isequal (max(A, [], 2), sym(max(D, [], 2))))

%!test
%! % column vectors
%! A = A.';
%! D = D.';
%! assert (isequal (min(A), sym(min(D))))
%! assert (isequal (min(A), sym(0)))
%! assert (isequal (max(A), sym(max(D))))
%! assert (isequal (max(A), sym(3)))

%!test
%! % row vectors with dim
%! assert (isequal (min(A, [], 1), sym(min(D, [], 1))))
%! assert (isequal (min(A, [], 2), sym(min(D, [], 2))))
%! assert (isequal (max(A, [], 1), sym(max(D, [], 1))))
%! assert (isequal (max(A, [], 2), sym(max(D, [], 2))))

%!shared

%!test
%! % empty
%! a = min(sym([]));
%! assert(isempty(a))
%! a = max(sym([]));
%! assert(isempty(a))

%!test
%! % matrix
%! A = [1 4 6; 2 2 5];
%! A = sym(A);
%! assert (isequal (min(A), sym([1 2 5])))
%! assert (isequal (min(A, [], 1), sym([1 2 5])))
%! assert (isequal (min(A, [], 2), sym([1; 2])))
%! assert (isequal (max(A), sym([2 4 6])))
%! assert (isequal (max(A, [], 1), sym([2 4 6])))
%! assert (isequal (max(A, [], 2), sym([6; 5])))

%!test
%! % index output is double not sym
%! [m, I] = min(sym(2), [], 1);
%! assert (strcmp(class(I), 'double'))
%! [m, I] = max(sym(2), [], 1);
%! assert (strcmp(class(I), 'double'))

%!test
%! % empty rows/columns, I is double
%! A = sym(zeros(0, 4));
%! [m, I] =  min(A, [], 1);
%! assert (strcmp(class(I), 'double'))
%! [m, I] =  max(A, [], 1);
%! assert (strcmp(class(I), 'double'))
%! A = sym(zeros(3, 0));
%! [m, I] =  min(A, [], 2);
%! assert (strcmp(class(I), 'double'))
%! [m, I] =  max(A, [], 2);
%! assert (strcmp(class(I), 'double'))

%!test
%! % index output
%! A = [0 1 9; 10 7 4];
%! B = sym(A);
%! [m1, I1] = min(A);
%! [m2, I2] = min(B);
%! assert (isequal (I1, I2))
%! assert (isequal (m1, double(m2)))
%! [m1, I1] = max(A);
%! [m2, I2] = max(B);
%! assert (isequal (I1, I2))
%! assert (isequal (m1, double(m2)))

%!test
%! % index output, with dim
%! A = [0 1 9; 10 7 4];
%! B = sym(A);
%! [m1, I1] = min(A, [], 1);
%! [m2, I2] = min(B, [], 1);
%! assert (isequal (I1, I2))
%! assert (isequal (m1, double(m2)))
%! [m1, I1] = min(A, [], 2);
%! [m2, I2] = min(B, [], 2);
%! assert (isequal (I1, I2))
%! assert (isequal (m1, double(m2)))
%! [m1, I1] = max(A, [], 1);
%! [m2, I2] = max(B, [], 1);
%! assert (isequal (I1, I2))
%! assert (isequal (m1, double(m2)))
%! [m1, I1] = max(A, [], 2);
%! [m2, I2] = max(B, [], 2);
%! assert (isequal (I1, I2))
%! assert (isequal (m1, double(m2)))

%!test
%! % empty columns
%! A = sym(zeros(0, 4));
%! [m, I] =  min(A, [], 1);
%! assert (isequal (size(m), [0 4]))
%! assert (isequal (size(I), [0 4]))
%! [m, I] =  max(A, [], 1);
%! assert (isequal (size(m), [0 4]))
%! assert (isequal (size(I), [0 4]))

%!test
%! % empty rows
%! A = sym(zeros(3, 0));
%! [m, I] =  min(A, [], 2);
%! assert (isequal (size(m), [3 0]))
%! assert (isequal (size(I), [3 0]))
%! [m, I] =  max(A, [], 2);
%! assert (isequal (size(m), [3 0]))
%! assert (isequal (size(I), [3 0]))

%!test
%! % another empty case
%! % we differ slightly from double which gives 1x0/0x1
%! A = sym(zeros(3, 0));
%! [m, I] =  min(A, [], 1);
%! assert (isempty (m))
%! assert (isempty (I))
%! A = sym(zeros(0, 3));
%! [m, I] =  min(A, [], 2);
%! assert (isempty (m))
%! assert (isempty (I))

%!test
%! % empty without index output
%! A = sym(zeros(3, 0));
%! assert (isempty (min (A, [], 1)))
%! assert (isempty (max (A, [], 1)))
%! assert (isempty (min (A, [], 2)))
%! assert (isempty (max (A, [], 2)))
%! A = sym(zeros(0, 3));
%! assert (isempty (min (A, [], 1)))
%! assert (isempty (max (A, [], 1)))
%! assert (isempty (min (A, [], 2)))
%! assert (isempty (max (A, [], 2)))

%!test
%! % binary op form, one a scalar
%! A = sym([3 1 9]);
%! m = min(A, sym(2));
%! M = max(A, sym(2));
%! assert (isequal (m, sym([2 1 2])))
%! assert (isequal (M, sym([3 2 9])))
%! m = min(sym(2), A);
%! M = max(sym(2), A);
%! assert (isequal (m, sym([2 1 2])))
%! assert (isequal (M, sym([3 2 9])))

%!test
%! % binary op form, both scalar
%! m = min(sym(1), sym(2));
%! M = max(sym(2), sym(2));
%! assert (isequal (m, sym(1)))
%! assert (isequal (M, sym(2)))

%!test
%! syms x y
%! assert (isequal (children (min (x, y)), [x y]))

%!test
%! syms x y z
%! A = [x 1; y z];
%! assert (isequal (min (A, [], 1), [min(x, y)  min(1, z)]))
%! assert (isequal (max (A, [], 1), [max(x, y)  max(1, z)]))
%! assert (isequal (min (A, [], 2), [min(x, 1); min(y, z)]))
%! assert (isequal (max (A, [], 2), [max(x, 1); max(y, z)]))

%!test
%! syms x y positive
%! a = min([x 2 y -6]);
%! assert (isequal (a, -6))
%! a = max([x y -6]);
%! assert (isequal (a, max(x, y)))

%!test
%! syms x negative
%! a = min([x 6 10]);
%! assert (isequal (a, x))
%! a = max([x -2 6]);
%! assert (isequal (a, 6))


function varargout = fillPolygon3d(varargin)
%FILLPOLYGON3D Fill a 3D polygon specified by a list of vertex coords.
%
%   fillPolygon3d(COORD, COLOR)
%   packs coordinates in a single [N*3] array.
%   COORD can also be a cell array of polygon, in this case each polygon is
%   drawn using the same color.
%
%   fillPolygon3d(PX, PY, PZ, COLOR)
%   specifies coordinates in separate numeric vectors (either row or
%   columns)
%
%   fillPolygon3d(..., PARAM, VALUE)
%   allows to specify some drawing parameter/value pairs as for the plot
%   function.
%
%   H = fillPolygon3d(...)
%   also returns a handle to the list of created patch objects.
%
%   Example
%     t = linspace(0, 2*pi, 100)';
%     xt = 10 * cos(t);
%     yt = 5 * sin(t);
%     zt = zeros(1,100);
%     figure; fillPolygon3d(xt, yt, zt, 'c');
%
%   See Also:
%   polygons3d, drawPolygon3d, drawPolyline3d
%

% ------
% Author: David Legland
% e-mail: david.legland@inra.fr
% Created: 2007-01-05
% Copyright 2007 INRA - BIA PV Nantes - MIAJ Jouy-en-Josas.

% check case we want to draw several curves, stored in a cell array
var1 = varargin{1};
if iscell(var1)
    hold on;
    h = [];
    for i = 1:length(var1(:))
        h = [h; fillPolygon3d(var1{i}, varargin{2:end})]; %#ok<AGROW>
    end
    if nargout>0
        varargout{1}=h;
    end
    return;
end

% extract vertex coordinates
if min(size(var1)) == 1
    % if first argument is a vector (either row or column), then assumes
    % first argument contains x coords, second argument contains y coords
    % and third one the z coords
    px = var1;
    if length(varargin) < 3
        error('geom3d:fillPolygon3d:Wrong number of arguments in fillPolygon3d');
    end
    py = varargin{2};
    pz = varargin{3};
    varargin = varargin(4:end);
else
    % first argument contains all three coordinates
    px = var1(:, 1);
    py = var1(:, 2);
    pz = var1(:, 3);
    varargin = varargin(2:end);
end

% extract color information
if isempty(varargin)
    color = 'c';
else
    color = varargin{1};
    varargin = varargin(2:end);
end

% fill the polygon
h = fill3(px, py, pz, color, varargin{:});

if nargout>0
    varargout{1}=h;
end


function infsup(c)
%INFSUP       Display of interval hessians in infsup notation
%
%   infsup(c)
%

% written  04/04/04     S.M. Rump
% modified 04/06/05     S.M. Rump  rounding unchanged
% modified 02/11/06     S.M. Rump  SparseInfNanFlag removed
% modified 06/04/09     S.M. Rump  Comment
% modified 08/26/12     S.M. Rump  global variables removed
%

  if nargin<2
    name = inputname(1);
    if isempty(name)                    % happens for display(hessianinit(random))
      name = 'ans';
    end
  end

  if isa(c.x,'intval')
    display_gen(c,name,'infsup')
  else
    display_gen(c,name,'display_')
  end


function [pos] = moveinward(pos, move)
%This functions moves 'pos' inward according to their normals by 'move'
%units
propos = elproj(pos); % projection to 2D
tri = delaunay(propos); %creates delaunay triangulation of 2D plane, which will be used for the the 3D case
nor = normals(pos,tri); %compute normals of surface
ori = surfaceorientation(pos, tri, nor);
if ori==1
  % the normals are outward oriented
elseif ori==-1
  % the normals are inward oriented
  nor = -nor;
else
  ft_warning('cannot determine the orientation of the vertex normals');
end
pos = pos-move*nor; % moves pos inwards according to their normals
end


function [probas, Isubj,nf]=taldir(dirname, th_pval, DirTable)
%
% Computes the probability of the Talairach transform matrices
%    of all the subjects found in the directory "dirname".
%  Uses the mean vector and covariance matrix obtained with talairachin_table.m from
%     the data set (default data set: /space/neo/2/recon/buckner)
%  Uses th_pval as a threshold for the p-values to detect unlikely transform  matrices
%

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

if (nargin<2 | nargin>3)
    msg=sprintf('USAGE: [probas, Isubj , nf]=taldir(SubjectDir, th_pval, <DirTable>)');
    disp(msg)
end

files=dir(dirname);
nf=files;
probas=[];
Isubj=[];
Pval=[];
count=0;
probas_flag=1;

if(nargin==3)
    fsafdDir=DirTable;
else
    %%% Get the default tables'directory %%%
    if(getenv('FREESURFER_HOME'))
        fsh=getenv('FREESURFER_HOME');
        fsafdDir=strcat(fsh, '/fsafd');
    else
        error(sprintf('Impossible to find FREESURFER_HOME\n'));
    end
end

%%% 1x9 mean vector obtained from the training set %%%
%load('/space/okapi/3/data/laurence/ADF/talairaching/transfo_param_mean.mat');
%file_mu='/space/okapi/3/data/laurence/ADF/talairaching/TalairachingMean.adf'; %Loads mu
file_mu=strcat(fsafdDir, '/TalairachingMean.adf');
fi=fopen(file_mu);
pos=0;
if(fi==-1)
    mess=sprintf('Could not find %s', file_mu);
    error(mess)
else
    while(strfind(fgetl(fi), '#'))  % skip the header
        pos=ftell(fi);
    end
    fseek(fi, pos, 'bof');
    mu=(fscanf(fi, '%g'))';
    fclose(fi);
end

%%% 9x9 covariance matrix obtained from the training set %%%
%load('/space/okapi/3/data/laurence/ADF/talairaching/transfo_param_regularizedCov2.mat'); %loads sigma
%sigma_file='/space/okapi/3/data/laurence/ADF/talairaching/TalairachingCovariance.adf';
sigma_file=strcat(fsafdDir, '/TalairachingCovariance.adf');
fis=fopen(sigma_file);
pos=0;
if(fis==-1)
    mess=sprintf('Could not find %s', sigma_file);
    error(mess)
else
    while(strfind(fgetl(fis), '#'))  % skip the header
        pos=ftell(fis);
    end
    fseek(fis, pos, 'bof');
    sig=fscanf(fis, '%g');
    sigma=reshape(sig, [9,9]);
    fclose(fis);
end

%%% Probabilities of the transform matrices  %%%
%stat_file='/space/okapi/3/data/laurence/ADF/talairaching/TalairachingProbas.adf';
stat_file=strcat(fsafdDir, '/TalairachingProbas.adf');
fid=fopen(stat_file);
pos=0;
if(fid==-1)
    mess=sprintf('Could not find %s... compute probas for the first time', stat_file);
    disp(mess)
    probas_flag=0;
else
    while(strfind(fgetl(fid), '#'))  % skip the header
        pos=ftell(fid);
    end
    fseek(fid, pos, 'bof');
    yy=fscanf(fid, '%g');
    fclose(fid);
end

for i=1:(length(files))
    s=strcat(dirname,'/',files(i).name);
    ttfile=strcat(s,'/mri/transforms/talairach.xfm');
    fid=fopen(ttfile, 'r');
    if ( (fid ~= -1) && ( length(strfind(files(i).name,'0'))>=1 | (length(strfind(files(i).name,'1'))>=1 )))
        while feof(fid) == 0
            linef=fgetl(fid);
            nb=findstr(linef, 'Linear_Transform');
            if nb == 1
                pos=ftell(fid);
                break
            end
        end
        A=(fscanf(fid, '%g',12))';
        A=[A(1) A(2) A(3) A(5) A(6) A(7) A(9) A(10) A(11)]; % if trans=1, the translation parameters are not taken into account
        status=fclose(fid);
        p=mvnpdf(A,mu,sigma);
        probas=[probas p];
        Isubj=[Isubj i];
        nf(length(probas)).name=files(i).name;
        if(probas_flag)
            [pinf]=compute_pval(p, yy);
            Pval=[Pval pinf];
            if (pinf < th_pval)
                %mess=sprintf('Talairach Transform: %s failed (%g)', files(i).name, p);
                mess=sprintf('Talairach Transform: %s failed, (p=%g pval=%g)', files(i).name, p, pinf);
                disp(mess)
                count=count+1;
            else
                mess2=sprintf('Talairach Transform: %s OK, (p=%g pval=%g)', files(i).name, p, pinf);
                disp(mess2)
            end
        end
    else
        i=i+1;
        if (fid ~= -1)
            status=fclose(fid);
        end
    end
end

if (length(probas) == 0)
    messdir=sprintf('No subject found in this directory');
    disp(messdir)
end
messcount=sprintf('Number of unlikely Talairach transforms : %d', count);
disp(messcount)
% if(~probas_flag)
%     outprobas=strcat(DirTable, '/TalairachingProbas.adf');
%     save(outprobas, 'probas', '-ASCII');
% end
%y=probas;
%save('/space/okapi/3/data/laurence/talairaching/transfo_param_probas.mat', 'y');

% subfunction compute_pval() %
function [p_inf]=compute_pval(val,y)
%load('/space/okapi/3/data/laurence/ADF/talairaching/transfo_param_probas.mat'); %loads y
pas=0.05;
x=0:pas:1;
[h] = hist(y,x);
p = h/sum(h);
dinf=find(x<=val);
xinf=x(dinf);
pinf=p(1:length(xinf));
if (val>=0 & length(xinf) >1 )
    p_inf=trapz(xinf,pinf)/pas;
elseif (val>=0 & (length(xinf)<2))
    pas2=pas/10;
    x2=0:pas2:1;
    [h2] = hist(y,x2);
    p2 = h2/sum(h2);
    dinf2=find(x2<=val);
    xinf2=x2(dinf2);
    pinf2=p2(1:length(xinf2));
    if(length(xinf2)>1)
        p_inf=trapz(xinf2,pinf2)/pas2;
    else
        p_inf=0;
    end
else
    p_inf=0;

end


function tree = prtUtilRecursiveCapTreeFast(Obj,tree,x,y,index)
%tree = recursiveCapTree(Obj,tree,x,y,index)

nFeatures = size(x,2);

uniqueY = find(sum(y,1)>0);

if index > tree.maxReservedLen
    tree.W = memorySaverAppendNulls(tree.W,Obj.Memory.nAppend,Obj.nFeatures);
    tree.threshold = memorySaverAppendNulls(tree.threshold,Obj.Memory.nAppend,1);
    tree.featureIndices = memorySaverAppendNulls(tree.featureIndices,Obj.Memory.nAppend,Obj.nFeatures);
    tree.treeIndices = memorySaverAppendNulls(tree.treeIndices,Obj.Memory.nAppend,1);
    tree.terminalVote = memorySaverAppendNulls(tree.terminalVote,Obj.Memory.nAppend,1);
    tree.maxReservedLen = tree.maxReservedLen + Obj.Memory.nAppend;
end

%Base cases; if there is only one class left, we must return

if length(uniqueY) == 1
    tree.W(:,index) = inf;  %place holder for completed processing
    tree.treeIndices(index) = tree.father;
    tree.terminalVote(index) = uniqueY;
    return;
end

%Choose random subspace projection:
if Obj.featureSelectWithReplacement  %allow redundant features
    tree.featureIndices(:,index) = ceil(rand([1,Obj.nFeatures])*nFeatures)';
    tree.treeIndices(index) = tree.father;
else
    locInd = randperm(nFeatures)'; %do NOT allow redundant features
    tree.featureIndices(:,index) = locInd(1:Obj.nFeatures);
    tree.treeIndices(index) = tree.father;
end

xTrain = x(:,tree.featureIndices(:,index));

% Generate a CAP classifier (internal code, don't use prtClassCap for
% speed issues)
[w,thresholdValue,yOut] = recursiveCapTreeGenerateCap(xTrain,y);

if any(~isfinite(w)) || ~isfinite(thresholdValue)
    exitNow = true;
else

    yOut = yOut >= thresholdValue;

    % True if only one class in the output
    exitNow = ~any(yOut) || all(yOut);
end

if exitNow
    % If we get here we have the same mean under both class labels
    % or have infs in the data
    % So we exit

    % Tree params on an exit
    tree.W(:,index) = inf;  %place holder for completed processing
    tree.threshold(:,index) = nan;
    tree.treeIndices(index) = tree.father;

    % Figure out the dominant class
    classCounts = sum(y,1);
    [maxClassCounts, maxClassInd] = max(classCounts);
    isGoodClass = classCounts == maxClassCounts;

    nGoodInds = sum(isGoodClass);

    % If nGoodInds > 1 We have ties and need to decide randomly
    if nGoodInds > 1
        goodInds = find(isGoodClass);
        maxClassInd = goodInds(ceil(rand*nGoodInds));
    end

    %tree.terminalVote(index) = uniqueY(maxClassInd);
    tree.terminalVote(index) = maxClassInd;
    return
end

% Continue on...
% Store node info into tree

tree.W(:,index) = w(:);
tree.threshold(:,index) = thresholdValue;
tree.father = index;

% Split the data

% Left
xLeft = x(~yOut,:);
yLeft = y(~yOut,:);
tree = prtUtilRecursiveCapTreeFast(Obj,tree,xLeft,yLeft,index + 1);
tree.father = index;

% Right
xRight = x(yOut,:);

yRight = y(yOut,:);
maxLen = length(find(~isnan(tree.W(1,:))));
tree = prtUtilRecursiveCapTreeFast(Obj,tree,xRight,yRight,maxLen + 1);

    function M = memorySaverAppendNulls(M,nAppend,nFeats)
        M = cat(2,M,nan(nFeats,nAppend));
    end
end

function [w,thresholdValue,yOut] = recursiveCapTreeGenerateCap(x,y)
%[w,thresholdValue,yOut] = recursiveCapGenerateCap(x,y,uniqueY,nRocEvals)
% Internal function to quicly generate a CAP classifier without prt
% overhead

if size(y,2) > 2
    classCounts = sum(y,1);
    [sortedClassCounts, sortedClassInds] = sort(classCounts,'descend'); %#ok<ASGLU>
else
    sortedClassInds = [1 2];
end
% Ties go to the lower classInds

mean0 = mean(x(y(:,sortedClassInds(1)),:),1);
mean1 = mean(x(y(:,sortedClassInds(2)),:),1);
w = mean1 - mean0;

w = w./norm(w);

if isnan(w)
    w = nan(size(w));
    thresholdValue = nan;
    yOut = nan;
    return
end

selectedClasses = y(:,sortedClassInds(1)) | y(:,sortedClassInds(2));

yOut = (w*x')';
% yOut = yOut(selectedClasses,:);
yTest = y(selectedClasses,sortedClassInds(2));
tempY = yOut(selectedClasses,:);
threshold = median(tempY);

pE = 1-sum(tempY >= threshold == yTest)/length(tempY);
if pE >= .5
    %     threshold = -threshold;
    %     w = -w;
    %     yOut = -yOut;
    %
    %     pE = 1-sum(tempY >= threshold == yTest)/length(tempY);
    %     %     if pE > .5
    %         %We tried the median, then -w, and the -median, and prob(error) was
    %         %still too high. That says that the median just won't work.  So use
    %         %the ROC curve:
    %
    %         w = -w; %un-negate (!)
    %         yOut = (w*x')';
    %         yTest = y(selectedClasses,sortedClassInds(2));
    %
    %         % figure out the threshold: (1)
    %         [pf,pd,thresh] = prtScoreRoc(yOut(selectedClasses,:),yTest,'uniqueLabels',[0 1]);
    %
    %         % figure out the threshold: (2)
    %         % uY = unique(yTest);
    %         % binLabels = yTest ~= uY(1);
    %         % [~,~,pf,pd,thresh] = prtUtilMinPeThreshold(yOut(selectedClasses,:),binLabels);
    %
    %         pE = prtUtilPfPd2Pe(pf,pd);
    %         [minPe,I] = min(pE);
    %         if numel(I) > 1
    %             I = unique(I);
    %         end
    %
    %         if I < length(thresh)
    %             %for categorical variables, the threshold should live between the
    %             %samples we've seen; this is true for continuous variables too.  Makes
    %             %a big difference when multiple values take the same value
    %             thresholdValue = mean([thresh(I),thresh(I+1)]);
    %         else
    %             thresholdValue = thresh(I);
    %         end
    %
    %         if minPe >= 0.5
    %             w = -w;
    %             yOut = -yOut;
    %             % % figure out the threshold:
    %             [pf,pd,thresh] = prtScoreRoc(yOut(selectedClasses,:),yTest,'uniqueLabels',[0 1]);
    %             pE = prtUtilPfPd2Pe(pf,pd);
    %             [minPe,I] = min(pE);
    %             if numel(I) > 1
    %                 I = unique(I);
    %             end
    %             if I < length(thresh)
    %                 %for categorical variables, the threshold should live between the
    %                 %samples we've seen; this is true for continuous variables too.  Makes
    %                 %a big difference when multiple values take the same value
    %                 thresholdValue = mean([thresh(I),thresh(I+1)]);
    %             else
    %                 thresholdValue = thresh(I);
    %             end
    %
    %         end
    %         threshold = thresholdValue;
    %         pE = minPe;
    %     end
end
if pE > .5
    threshold = -inf;
end
thresholdValue = threshold;
end


function net = init_LapSRN_model(opts)
% -------------------------------------------------------------------------
%   Description:
%       initialize LapSRN model
%
%   Input:
%       - opts  : options generated from init_LapSRN_opts()
%
%   Output:
%       - net   : dagnn model
%
%   Citation:
%       Deep Laplacian Pyramid Networks for Fast and Accurate Super-Resolution
%       Wei-Sheng Lai, Jia-Bin Huang, Narendra Ahuja, and Ming-Hsuan Yang
%       IEEE Conference on Computer Vision and Pattern Recognition (CVPR), 2017
%
%   Contact:
%       Wei-Sheng Lai
%       wlai24@ucmerced.edu
%       University of California, Merced
% -------------------------------------------------------------------------

    %% parameters
    rng('default');
    rng(0) ;

    f       = opts.conv_f;
    n       = opts.conv_n;
    pad     = floor(f/2);
    depth   = opts.depth;
    scale   = opts.scale;
    level   = ceil(log(scale) / log(2));
    if( f == 3 )
        crop = [0, 1, 0, 1];
    elseif( f == 5 )
        crop = [1, 2, 1, 2];
    else
        error('Need to specify crop in deconvolution for f = %d\n', f);
    end

    %% initialize model
    net = dagnn.DagNN;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %% Feature extraction branch
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    sigma   = opts.init_sigma;
    filters = sigma * randn(f, f, 1, n, 'single');
    biases  = zeros(1, n, 'single');

    % conv
    inputs  = { 'LR' };
    outputs = { 'input_conv' };
    params  = { 'input_conv_f', 'input_conv_b' };

    net.addLayer(outputs{1}, ...
                 dagnn.Conv('size', size(filters), ...
                            'pad', pad, ...
                            'stride', 1), ...
                 inputs, outputs, params);

    idx = net.getParamIndex(params{1});
    net.params(idx).value         = filters;
    net.params(idx).learningRate  = 1;
    net.params(idx).weightDecay   = 1;

    idx = net.getParamIndex(params{2});
    net.params(idx).value         = biases;
    net.params(idx).learningRate  = 0.1;
    net.params(idx).weightDecay   = 1;

    % ReLU
    inputs  = { 'input_conv' };
    outputs = { 'input_relu' };

    net.addLayer(outputs{1}, ...
                 dagnn.ReLU('leak', 0.2), ...
                 inputs, outputs);

    next_input = outputs{1};

    %% deep conv layers (f x f x n x n)
    sigma   = sqrt( 2 / (f * f * n) );

    for s = level : -1 : 1

        % conv layers (f x f x n x n)
        for d = 1:depth

            filters = sigma * randn(f, f, n, n, 'single');
            biases  = zeros(1, n, 'single');

            % conv
            inputs  = { next_input };
            outputs = { sprintf('level%d_conv%d', s, d) };
            params  = { sprintf('level%d_conv%d_f', s, d), ...
                        sprintf('level%d_conv%d_b', s, d)};

            net.addLayer(outputs{1}, ...
                         dagnn.Conv('size', size(filters), ...
                                    'pad', pad, ...
                                    'stride', 1), ...
                         inputs, outputs, params);

            idx = net.getParamIndex(params{1});
            net.params(idx).value         = filters;
            net.params(idx).learningRate  = 1;
            net.params(idx).weightDecay   = 1;

            idx = net.getParamIndex(params{2});
            net.params(idx).value         = biases;
            net.params(idx).learningRate  = 0.1;
            net.params(idx).weightDecay   = 1;

            % ReLU
            inputs  = { sprintf('level%d_conv%d', s, d) };
            outputs = { sprintf('level%d_relu%d', s, d) };

            net.addLayer(outputs{1}, ...
                         dagnn.ReLU('leak', 0.2), ...
                     inputs, outputs);

            next_input = outputs{1};

        end

        %% features upsample layers
        filters = sigma * randn(f, f, n, n, 'single');
        biases  = zeros(1, n, 'single');

        inputs  = { next_input };
        outputs = { sprintf('level%d_upconv', s) };
        params  = { sprintf('level%d_upconv_f', s), ...
                    sprintf('level%d_upconv_b', s) };

        net.addLayer(outputs{1}, ...
                     dagnn.ConvTranspose(...
                         'size', size(filters), ...
                         'upsample', 2, ...
                         'crop', crop, ...
                         'numGroups', 1, ...
                         'hasBias', true), ...
                     inputs, outputs, params) ;

        idx = net.getParamIndex(params{1});
        net.params(idx).value         = filters;
        net.params(idx).learningRate  = 1;
        net.params(idx).weightDecay   = 1;

        idx = net.getParamIndex(params{2});
        net.params(idx).value         = biases;
        net.params(idx).learningRate  = 0.1;
        net.params(idx).weightDecay   = 1;

        %% ReLU
        inputs  = { sprintf('level%d_upconv', s) };
        outputs = { sprintf('level%d_uprelu', s) };

        net.addLayer(outputs{1}, ...
                     dagnn.ReLU('leak', 0.2), ...
                     inputs, outputs);

        next_input = outputs{1};

        %% residual prediction layer (f x f x n x 1)
        sigma   = sqrt(2 / (f * f * n));
        filters = sigma * randn(f, f, n, 1, 'single');
        biases  = zeros(1, 1, 'single');

        inputs  = { next_input };
        outputs = { sprintf('level%d_residual', s) };
        params  = { sprintf('level%d_residual_conv_f', s), ...
                    sprintf('level%d_residual_conv_b', s) };

        net.addLayer(outputs{1}, ...
            dagnn.Conv('size', size(filters), ...
                       'pad', pad, ...
                       'stride', 1), ...
            inputs, outputs, params);

        idx = net.getParamIndex(params{1});
        net.params(idx).value         = filters;
        net.params(idx).learningRate  = 1;
        net.params(idx).weightDecay   = 1;

        idx = net.getParamIndex(params{2});
        net.params(idx).value         = biases;
        net.params(idx).learningRate  = 0.1;
        net.params(idx).weightDecay   = 1;

    end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %% Image reconstruction branch
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    next_input = 'LR';

    for s = level : -1 : 1

        %% image upsample layer
        filters = single(bilinear_kernel(4, 1, 1));

        inputs  = { next_input };
        outputs = { sprintf('level%d_img_up', s) };
        params  = { sprintf('level%d_img_up_f', s) };

        net.addLayer(outputs{1}, ...
            dagnn.ConvTranspose(...
                'size', size(filters), ...
                'upsample', 2, ...
                'crop', 1, ...
                'numGroups', 1, ...
                'hasBias', false), ...
            inputs, outputs, params) ;

        idx = net.getParamIndex(params{1});
        net.params(idx).value         = filters;
        net.params(idx).learningRate  = 1;
        net.params(idx).weightDecay   = 1;

        %% residual addition layer
        inputs  = { sprintf('level%d_img_up', s), ...
                    sprintf('level%d_residual', s) };
        outputs = { sprintf('level%d_output', s) };
        net.addLayer(outputs{1}, ...
            dagnn.Sum(), ...
            inputs, outputs);

        next_input = outputs{1};

        %% Loss layer
        inputs  = { next_input, ...
                    sprintf('level%d_HR', s) };
        outputs = { sprintf('level%d_%s_loss', s, opts.loss) };

        net.addLayer(outputs{1}, ...
                 dagnn.vllab_dag_loss(...
                    'loss_type', opts.loss), ...
                 inputs, outputs);

    end

end


function [ a, b ] = p38_lim ( )

%*****************************************************************************80
%
%% P38_LIM returns the integration limits for problem 51.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    04 November 2009
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, real A, B, the limits of integration.
%
  a = 0.0;
  b = pi;

  return
end


classdef SVOREX < Algorithm
    %SVOREX Support Vector for Ordinal Regression (Explicit constraints)
    %   This class derives from the Algorithm Class and implements the
    %   SVOREX method. This class uses SVOREX implementation by
    %   W. Chu et al (http://www.gatsby.ucl.ac.uk/~chuwei/svor.htm)
    %
    %   SVOREX methods:
    %      fitpredict               - runs the corresponding algorithm,
    %                                   fitting the model and testing it in a dataset.
    %      fit                        - Fits a model from training data
    %      predict                    - Performs label prediction
    %
    %   References:
    %     [1] P.A. Gutiérrez, M. Pérez-Ortiz, J. Sánchez-Monedero,
    %         F. Fernández-Navarro and C. Hervás-Martínez
    %         Ordinal regression methods: survey and experimental study
    %         IEEE Transactions on Knowledge and Data Engineering, Vol. 28. Issue 1
    %         2016
    %         http://dx.doi.org/10.1109/TKDE.2015.2457911
    %     [2] W. Chu and S. S. Keerthi, Support Vector Ordinal Regression,
    %         Neural Computation, vol. 19, no. 3, pp. 792–815, 2007.
    %         http://10.1162/neco.2007.19.3.792
    %
    %   This file is part of ORCA: https://github.com/ayrna/orca
    %   Original authors: Pedro Antonio Gutiérrez, María Pérez Ortiz, Javier Sánchez Monedero
    %   Citation: If you use this code, please cite the associated paper http://www.uco.es/grupos/ayrna/orreview
    %   Copyright:
    %       This software is released under the The GNU General Public License v3.0 licence
    %       available at http://www.gnu.org/licenses/gpl-3.0.html

    properties
        description = 'Support Vector for Ordinal Regression (Explicit constraints)';
        parameters = struct('C', 0.1, 'k', 0.1);
    end
    properties (Access = private)
        algorithmMexPath = fullfile(fileparts(which('Algorithm.m')),'SVOREX');
    end

    methods
        function obj = SVOREX(varargin)
            %SVOREX constructs an object of the class SVOREX and sets its default
            %   characteristics
            %   OBJ = SVOREX(KERNEL) builds SVOREX with RBF as kernel function
            obj.parseArgs(varargin);
        end

        function [projectedTrain, predictedTrain] = privfit(obj,train,parameters)
            %PRIVFIT trains the model for the SVOREX method with TRAIN data and
            %vector of parameters PARAMETERS.
            if isempty(strfind(path,obj.algorithmMexPath))
                addpath(obj.algorithmMexPath);
            end
            [alpha, thresholds, projectedTrain] = svorex([train.patterns train.targets],parameters.k,parameters.C,0,0,0);
            predictedTrain = obj.assignLabels(projectedTrain, thresholds);
            model.projection = alpha;
            model.thresholds = thresholds;
            model.parameters = parameters;
            model.train = train.patterns;
            obj.model = model;
            projectedTrain = projectedTrain';
            if ~isempty(strfind(path,obj.algorithmMexPath))
                rmpath(obj.algorithmMexPath);
            end
        end

        function [projected, predicted] = privpredict(obj, test)
            %PREDICT predicts labels of TEST patterns labels. The object needs to be fitted to the data first.
            kernelMatrix = computeKernelMatrix(obj.model.train',test','rbf',obj.model.parameters.k);
            projected = obj.model.projection*kernelMatrix;

            predicted = SVOREX.assignLabels(projected, obj.model.thresholds);
            projected = projected';
        end
    end

    methods (Static = true)
        function predicted = assignLabels(projected, thresholds)
            numClasses = size(thresholds,2)+1;
            %TEST assign the labels from projections and thresholds
            project2 = repmat(projected, numClasses-1,1);
            project2 = project2 - thresholds'*ones(1,size(project2,2));

            % Asignation of the class
            % f(x) = max {Wx-bk<0} or Wx - b_(K-1) > 0
            wx=project2;

            % The procedure for that is the following:
            % We assign the values > 0 to NaN
            wx(wx(:,:)>0)=NaN;

            % Then, we choose the biggest one.
            [maximum,predicted]=max(wx,[],1);

            % If a max is equal to NaN is because Wx-bk for all k is >0, so this
            % pattern belongs to the last class.
            predicted(isnan(maximum(:,:)))=numClasses;

            predicted = predicted';
        end
    end
end