function [Y, R, E] = IsomapII(D, n_fcn, n_size, options)
% ISOMAPII   Computes Isomap embedding using an advanced version of
%             the algorithm in Tenenbaum, de Silva, and Langford (2000),
%             which can take advantage of sparsity in the graph and
%             redundancy in the distances.
%
% [Y, R, E] = isomapII(D, n_fcn, n_size, options);
%
% Input:
%    D = input-space distances between pairs of N points, which can
%     take 1 of 3 forms:
%      (1) a full N x N matrix (as in isomap.m)
%      (2) a sparse N x N matrix (missing entries are treated as INF)
%      (3) the name of a function (e.g. 'd_fun') that takes
%            one argument, i, and returns a row vector containng the
%            distances from all N points to point i.
%
%    n_fcn = neighborhood function ('epsilon' or 'k')
%    n_size = neighborhood size (value for epsilon or k)
%
%    options = optional structure of options:
%      options.dims = (row) vector of embedding dimensionalities to use
%                        (1:10 = default)
%      options.comp = which connected component to embed, if more than one.
%                        (1 = largest (default), 2 = second largest, ...)
%      options.display = plot residual variance and 2-D embedding?
%                        (1 = yes (default), 0 = no)
%      options.overlay = overlay graph on 2-D embedding?
%                        (1 = yes (default), 0 = no)
%      options.verbose = display progress reports?
%                        (1 = yes (default), 0 = no)
%      options.dijkstra = use dijkstra's algorithm for shortest paths with
%                         full N x N distance matrix.
%                         (1 = yes (default), 0 = use Floyd; Floyd should
%                          be used only if you are unable to MEX dijkstra.cpp)
%      options.Kmax = maximum number of neighbors (used for sparse versions
%                        of epsilon; by default, estimated by random sample)
%      options.landmarks = (row) vector of landmark points to use in MDS.
%                 (MDS finds the configuration that best approximates
%                  the distances from all points to the landmark points.
%                  The default landmark points are 1:N (i.e. all the points),
%                  which is equivalent to classical MDS.  Good
%                  results may often be obtained using a number of
%                  landmarks that is much smaller than N, but much
%                  larger than the data's intrinsic dimensionality.
%                  Note that this extension is experimental!  For
%                  discussion, see Steyvers, de Silva, and Tenenbaum
%                  (in preparation).)
%
% Output:
%    Y = Y.coords is a cell array, with coordinates for d-dimensional embeddings
%         in Y.coords{d}.  Y.index contains the indices of the points embedded.
%    R = residual variances for embeddings in Y
%    E = edge matrix for neighborhood graph
%

%    BEGIN COPYRIGHT NOTICE
%
%    Isomap II code -- (c) 1998-2000 Josh Tenenbaum
%
%    This code is provided as is, with no guarantees except that
%    bugs are almost surely present.  Published reports of research
%    using this code (or a modified version) should cite the
%    article that describes the algorithm:
%
%      J. B. Tenenbaum, V. de Silva, J. C. Langford (2000).  A global
%      geometric framework for nonlinear dimensionality reduction.
%      Science 290 (5500): 2319-2323, 22 December 2000.
%
%    Comments and bug reports are welcome.  Email to jbt@psych.stanford.edu.
%    I would also appreciate hearing about how you used this code,
%    improvements that you have made to it, or translations into other
%    languages.
%
%    You are free to modify, extend or distribute this code, as long
%    as this copyright notice is included whole and unchanged.
%
%    END COPYRIGHT NOTICE
%
% Modified by Ramon Casero <rcasero@gmail.com>, University of Oxford.
%
% Version: 0.1.1
%
% This file is distributed as a derivative work of a third-party function
% with project Gerardus.
%
% http://code.google.com/p/gerardus/
%
% Original code downloaded from the Isomap Homepage
%
% http://isomap.stanford.edu/

%%%%% Step 0: Initialization and Parameters %%%%%

if nargin < 3
     error('Too few input arguments');
elseif nargin < 4
     options = struct('dims',1:10,'overlay',1,'comp',1,'display',1,'dijkstra',1,'verbose',1);
end

if isa(D, 'function_handle')
     mode = 3;
     d_func = D;
     N = length(d_func(1));
elseif issparse(D)
     mode = 2;
     N = size(D,1);
     if ~(N==size(D,2))
          error('D must be a square matrix');
     end;
else
     mode = 1;
     N = size(D,1);
     if ~(N==size(D,2))
         error('D must be a square matrix');
     end;
end

if strcmp(n_fcn, 'k')
     K = n_size;
     if ~(K==round(K))
         error('Number of neighbors for k method must be an integer');
     end
     if ((mode==2) && ~(min(sum(D'>0))>=K))
         error('Sparse D matrix must contain at least K nonzero entries in each row');
     end
elseif strcmp(n_fcn, 'epsilon')
     epsilon = n_size;
     if isfield(options,'Kmax')
         K = options.Kmax;
     elseif (mode==3)    %% estimate maximum equivalent K %%
         tmp = zeros(10,N);
         for i=1:10
             tmp(i,:) = d_func(ceil(N*rand));
         end
         K = 2*max(sum(tmp'<epsilon));    % just to be safe
     end
else
     error('Neighborhood function must be either epsilon or k');
end

if (mode == 3)
     INF = inf;
else
     INF =  1000*max(max(D))*N;  %% effectively infinite distance
end

if ~isfield(options,'dims')
     options.dims = 1:10;
end
if ~isfield(options,'overlay')
     options.overlay = 1;
end
if ~isfield(options,'comp')
     options.comp = 1;
end
if ~isfield(options,'display')
     options.display = 1;
end
if ~isfield(options,'verbose')
     options.verbose = 1;
end
if ~isfield(options,'landmarks')
     options.landmarks = 1:N;
end
if ~isfield(options,'dijkstra')
     options.dijkstra = 1;
end
dims = options.dims;
comp = options.comp;
overlay = options.overlay;
displ = options.display;
verbose = options.verbose;
landmarks = options.landmarks;
use_dijk = options.dijkstra;

Y.coords = cell(length(dims),1);
R = zeros(1,length(dims));

%%%%% Step 1: Construct neighborhood graph %%%%%
disp('Constructing neighborhood graph...');

if ((mode == 1) && (use_dijk == 0))
     if strcmp(n_fcn, 'k')
         [tmp, ind] = sort(D);
         tic;
         for i=1:N
             D(i,ind((2+K):end,i)) = INF;
             if ((verbose == 1) && (rem(i,50) == 0))
                 disp([' Iteration: ' num2str(i) '     Estimated time to completion: ' num2str((N-i)*toc/60/50) ' minutes']); tic;
             end
         end
     elseif strcmp(n_fcn, 'epsilon')
         warning off    %% Next line causes an unnecessary warning, so turn it off
         D =  D./(D<=epsilon);
         D = min(D,INF);
         warning on
     end
     D = min(D,D');    %% Make sure distance matrix is symmetric
elseif ((mode == 1) && (use_dijk == 1))
     if n_fcn == 'k'
         [tmp, ind] = sort(D);
         tic;
         for i=1:N
             D(i,ind((2+K):end,i)) = 0;
             if ((verbose == 1) && (rem(i,50) == 0))
                 disp([' Iteration: ' num2str(i) '     Estimated time to completion: ' num2str((N-i)*toc/60/50) ' minutes']); tic;
             end
         end
     elseif strcmp(n_fcn, 'epsilon')
         D =  D.*(D<=epsilon);
     end
     D = sparse(D);
     D = max(D,D');    %% Make sure distance matrix is symmetric
elseif (mode == 2)
     if n_fcn == 'k'
         Di = zeros(N*K,1);      Dj = zeros(N*K,1);       Ds = zeros(N*K,1);
         counter = 0;
         [a,b,c] = find(D);
         tic;
         for i=1:N
             l = find(a==i);
             [g,f] = sort(c(l));
             Di(counter+(1:K)) = i;
             Dj(counter+(1:K)) = b(l(f(1:K)));
             Ds(counter+(1:K)) = g(1:K);
             counter = counter+K;
             if ((verbose == 1) && (rem(i,50) == 0))
                  disp([' Iteration: ' num2str(i) '     Estimated time to completion: ' num2str((N-i)*toc/60/50) ' minutes']); tic;
             end
         end
         D = sparse(Di(1:counter), Dj(1:counter), Ds(1:counter));
         clear Di Dj Ds counter;
     elseif strcmp(n_fcn, 'epsilon')
         D =  D.*(D<=epsilon);
     end
     D = max(D,D');    %% Make sure distance matrix is symmetric
elseif (mode == 3)
     Di = zeros(N*(K+1),1);      Dj = zeros(N*(K+1),1);       Ds = zeros(N*(K+1),1);
     counter = 0;
     tic;
     for i=1:N
         d = d_func(i);
         if n_fcn == 'k'
             [c,b] = sort(d);
             Di(counter+(1:(K+1))) = i;
             Dj(counter+(1:(K+1))) = b(1:(K+1));
             Ds(counter+(1:(K+1))) = c(1:(K+1));
             counter = counter+(K+1);
         elseif strcmp(n_fcn, 'epsilon')
             [a,b,c] = find(d.*(d<=epsilon));
             l = length(a);
             Di(counter+(1:l)) = i;
             Dj(counter+(1:l)) = b;
             Ds(counter+(1:l)) = c;
             counter = counter+l;
         end
         if ((verbose == 1) && (rem(i,50) == 0))
              disp([' Iteration: ' num2str(i) '     Estimated time to completion: ' num2str((N-i)*toc/60/50) ' minutes']); tic;
         end
     end
     D = sparse(Di(1:counter), Dj(1:counter), Ds(1:counter));
     clear Di Dj Ds counter;
     D = max(D,D');    %% Make sure distance matrix is symmetric
end

if (overlay == 1)
     if ((mode == 1) && (use_dijk == 0))
         E = int8(1-(D==INF));  %%  Edge information for subsequent graph overlay
     else
         [a,b,c] = find(D);
         E = sparse(a,b,ones(size(a)));
     end
end

%%%%% Step 2: Compute shortest paths %%%%%
disp('Computing shortest paths...');

if ((mode==1) && (use_dijk == 0))
     tic;
     for k=1:N
         D = min(D,repmat(D(:,k),[1 N])+repmat(D(k,:),[N 1]));
         if ((verbose == 1) && (rem(k,20) == 0))
              disp([' Iteration: ' num2str(k) '     Estimated time to completion: ' num2str((N-i)*toc/i/60) ' minutes']);
         end
     end
else
     D = dijkstra(D, landmarks);
end

%%%%% Step 3: Construct low-dimensional embeddings (Classical MDS) %%%%%
disp('Constructing low-dimensional embeddings (Classical MDS)...');

%%%%% Remove outliers from graph %%%%%
disp('  Checking for outliers...');

if ((mode == 1) && (use_dijk == 0))
     [tmp, firsts] = min(D==INF);     % first point each point connects to
else
     [tmp, firsts] = min(D==inf);     % first point each point connects to
end
[comps, I, J] = unique(firsts);    % first point in each connected component
n_comps = length(comps);           % number of connected components
size_comps = sum((repmat(firsts,n_comps,1)==((1:n_comps)'*ones(1,N)))');
                                   % size of each connected component
[tmp, comp_order] = sort(size_comps);  %% sort connected components by size
comps = comps(comp_order(end:-1:1));
size_comps = size_comps(comp_order(end:-1:1));
if (comp>n_comps)
     comp=1;                              %% default: use largest component
end
Y.index = find(firsts==comps(comp)); %% list of points in relevant component
Y.index = setdiff(Y.index,find(isinf(min(D)))); % prune points that don't connect
                                                % to any landmarks
N = length(Y.index);
[tmp, landmarks, land_ind] = intersect(landmarks,Y.index);
                                       % list of landmarks in component
nl = length(landmarks);
D = full(D(landmarks,Y.index))';
disp(['    Number of connected components in graph: ' num2str(n_comps)]);
disp(['    Embedding component ' num2str(comp) ' with ' num2str(length(Y.index)) ' points.']);

dims = unique(min(dims,nl-1));    % don't embed in more dimensions than landmarks-1
if (nl==N)
     opt.disp = 0;
     [vec, val] = eigs(-.5*(D.^2 - sum(D.^2)'*ones(1,N)/N - ones(N,1)*sum(D.^2)/N + sum(sum(D.^2))/(N^2)), max(dims), 'LR', opt);
else
     subB = -.5*(D.^2 - sum(D'.^2)'*ones(1,nl)/nl - ones(N,1)*sum(D.^2)/N+sum(sum(D.^2))/(N*nl));
     opt.disp = 0;
     [alpha,beta] = eigs(subB'*subB, max(dims), 'LR', opt);
     val = beta.^(1/2);
     vec = subB*alpha*inv(val);
     clear subB alpha beta;
end
h = real(diag(val));
[foo,sorth] = sort(h);  sorth = sorth(end:-1:1);
val = real(diag(val(sorth,sorth)));
vec = vec(:,sorth);

D = reshape(D,N*nl,1);
for di = 1:length(dims)
     Y.coords{di} = real(vec(:,1:dims(di)).*(ones(N,1)*sqrt(val(1:dims(di)))'))';
     r2 = 1-corrcoef(reshape(real(L2_distance(Y.coords{di}, Y.coords{di}(:,land_ind))),N*nl,1),D).^2;
     R(di) = r2(2,1);
     if (verbose == 1)
         disp(['  Isomap on ' num2str(N) ' points with dimensionality ' num2str(dims(di)) '  --> residual variance = ' num2str(R(di))]);
     end
end

clear D;

%%%%%%%%%%%%%%%%%% Graphics %%%%%%%%%%%%%%%%%%

if (displ==1)
     %%%%% Plot fall-off of residual variance with dimensionality %%%%%
     figure;
     hold on
     plot(dims, R, 'bo');
     plot(dims, R, 'b-');
     hold off
     ylabel('Residual variance');
     xlabel('Isomap dimensionality');

     %%%%% Plot two-dimensional configuration %%%%%
     twod = find(dims==2);
     if ~isempty(twod)
         figure;
         hold on;
         plot(Y.coords{twod}(1,:), Y.coords{twod}(2,:), 'ro');
         if (overlay == 1)
             gplot(E(Y.index, Y.index), [Y.coords{twod}(1,:); Y.coords{twod}(2,:)]');
             title('Two-dimensional Isomap embedding (with neighborhood graph).');
         else
             title('Two-dimensional Isomap.');
         end
         hold off;
     end
end

return;


%otyp==0->cont, otyp==1->disc
function [A N]=sys_ned_dcm(llh, vel_n, Cbn, acc, otyp, dt)
% position   (1-3)
% velocity   (4-6)
% attitude   (7-9)

%system disturbance coefs
N=zeros(9,6);
N(7:9,4:6)=-Cbn; %attitude
N(4:6,1:3)=Cbn; %velocity

%system matrix
A=zeros(9);
[Rn, Re, g, sL, cL, WIE_E]=geoparam_v000(llh);
tL=sL/cL;
Rn_h=Rn+llh(3);
Re_h=Re+llh(3);
acc_n=Cbn*acc;

A(1,3)=-vel_n(1)/(Rn_h)^2;
A(1,4)=1/(Rn_h);

A(2,1)=vel_n(2)*tL/(Re_h)/cL;
A(2,3)=-vel_n(2)/(Re_h)/(Re_h)/cL;
A(2,5)=1/(Re_h)/cL;

A(3,6)=-1;

A(4,1)=-(2*WIE_E*cL*vel_n(2)+vel_n(2)*vel_n(2)/(Re_h)/cL/cL);
A(4,3)=(-vel_n(1)*vel_n(3)/(Rn_h)/(Rn_h)+vel_n(2)*vel_n(2)*tL/(Re_h)/(Re_h));
A(4,4)=vel_n(3)/(Rn_h);
A(4,5)=-(2*WIE_E*sL+2*vel_n(2)*tL/(Re_h));
A(4,6)=vel_n(1)/(Rn_h);
A(4,8)=-acc_n(3);
A(4,9)=acc_n(2);

A(5,1)=(2*WIE_E*cL*vel_n(1)-2*WIE_E*sL*vel_n(3)+vel_n(2)*vel_n(1)/(Re_h)/cL/cL);
A(5,3)=-(vel_n(2)*vel_n(3)+vel_n(2)*vel_n(1)*tL)/(Re_h)/(Re_h);
A(5,4)=(2*WIE_E*sL+vel_n(2)*tL/(Re_h));
A(5,5)=(vel_n(3)+vel_n(1)*tL)/(Re_h);
A(5,6)=(2*WIE_E*cL+vel_n(2)/(Re_h));
A(5,7)=acc_n(3);
A(5,9)=-acc_n(1);

A(6,1)=2*WIE_E*sL*vel_n(2);
A(6,3)=(vel_n(1)*vel_n(1)/(Rn_h)/(Rn_h)+vel_n(2)*vel_n(2)/(Re_h)/(Re_h));
A(6,4)=-2*vel_n(1)/(Rn_h);
A(6,5)=-2*(WIE_E*cL+vel_n(2)/(Re_h));
A(6,7)=-acc_n(2);
A(6,8)=acc_n(1);

A(7,1)=-WIE_E*sL;
A(7,3)=-vel_n(2)/(Re_h)/(Re_h);
A(7,5)=1/(Re_h);
A(7,8)=-(WIE_E*sL+vel_n(2)*tL/(Re_h));
A(7,9)=vel_n(1)/(Rn_h);

A(8,3)=vel_n(1)/(Rn_h)/(Rn_h);
A(8,4)=-1/(Rn_h);
A(8,7)=(WIE_E*sL+vel_n(2)*tL/(Re_h));
A(8,9)=(WIE_E*cL+vel_n(2)/(Re_h));

A(9,1)=-(WIE_E*cL+vel_n(2)/(Re_h)/cL/cL);
A(9,3)=vel_n(2)*tL/(Re_h)/(Re_h);
A(9,5)=-tL/(Re_h);
A(9,7)=-vel_n(1)/(Rn_h);
A(9,8)=-(WIE_E*cL+vel_n(2)/(Re_h));

%discretize A;
if (otyp==0)
    A=A;
elseif(otyp==1)
    A=expm(A*dt);
end


function xp = spm_dirichlet_exceedance(alpha,Nsamp)
% Compute exceedance probabilities for a Dirichlet distribution
% FORMAT xp = spm_dirichlet_exceedance(alpha,Nsamp)
%
% Input:
% alpha     - Dirichlet parameters
% Nsamp     - number of samples used to compute xp [default = 1e6]
%
% Output:
% xp        - exceedance probability
%__________________________________________________________________________
%
% This function computes exceedance probabilities, i.e. for any given model
% k1, the probability that it is more likely than any other model k2.
% More formally, for k1=1..Nk and for all k2~=k1, it returns p(x_k1>x_k2)
% given that p(x)=dirichlet(alpha).
%
% Refs:
% Stephan KE, Penny WD, Daunizeau J, Moran RJ, Friston KJ
% Bayesian Model Selection for Group Studies. NeuroImage (in press)
%__________________________________________________________________________
% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging

% Will Penny & Klaas Enno Stephan
% $Id: spm_dirichlet_exceedance.m 3118 2009-05-12 17:37:32Z guillaume $

if nargin < 2
    Nsamp = 1e6;
end

Nk = length(alpha);

% Perform sampling in blocks
%--------------------------------------------------------------------------
blk = ceil(Nsamp*Nk*8 / 2^28);
blk = floor(Nsamp/blk * ones(1,blk));
blk(end) = Nsamp - sum(blk(1:end-1));

xp = zeros(1,Nk);
for i=1:length(blk)

    % Sample from univariate gamma densities then normalise
    % (see Dirichlet entry in Wikipedia or Ferguson (1973) Ann. Stat. 1,
    % 209-230)
    %----------------------------------------------------------------------
    r = zeros(blk(i),Nk);
    for k = 1:Nk
        r(:,k) = spm_gamrnd(alpha(k),1,blk(i),1);
    end
    sr = sum(r,2);
    for k = 1:Nk
        r(:,k) = r(:,k)./sr;
    end

    % Exceedance probabilities:
    % For any given model k1, compute the probability that it is more
    % likely than any other model k2~=k1
    %----------------------------------------------------------------------
    [y, j] = max(r,[],2);
    xp = xp + histc(j, 1:Nk)';

end
xp = xp / Nsamp;


function cube_exactness_test01 ( )

%*****************************************************************************80
%
%% CUBE_EXACTNESS_TEST01 tests product Gauss-Legendre rules for the Legendre 3D integral.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    16 August 2014
%
%  Author:
%
%    John Burkardt
%
  a(1:3) = -1.0;
  b(1:3) = +1.0;

  fprintf ( 1, '\n' );
  fprintf ( 1, 'CUBE_EXACTNESS_TEST01\n' );
  fprintf ( 1, '  Product Gauss-Legendre rules for the 3D Legendre integral.\n' );
  fprintf ( 1, '  Density function rho(x) = 1.\n' );
  fprintf ( 1, '  Region: -1 <= x <= +1.\n' );
  fprintf ( 1, '          -1 <= y <= +1.\n' );
  fprintf ( 1, '          -1 <= z <= +1.\n' );
  fprintf ( 1, '  Level: L\n' );
  fprintf ( 1, '  Exactness: 2*L+1\n' );
  fprintf ( 1, '  Order: N = (L+1)*(L+1)*(L+1)\n' );

  for l = 0 : 5

    nx = l + 1;
    ny = l + 1;
    nz = l + 1;
    n = nx * ny * nz;
    t = 2 * l + 1;

    [ x, y, z, w ] = legendre_3d_set ( a, b, nx, ny, nz );

    p_max = t + 1;
    legendre_3d_exactness ( a, b, n, x, y, z, w, p_max );

  end

  return
end


function varargout = revolutionSurface(varargin)
%REVOLUTIONSURFACE Create a surface of revolution from a planar curve.
%
%   usage
%   [X Y Z] = revolutionSurface(C1, C2, N);
%   create the surface of revolution of parametrized function (xt, yt),
%   with N+1 equally spaced slices, around the Oz axis.
%   It assumed that C1 corresponds to the x coordinate, and that C2
%   corresponds to the Oz coordinate.
%
%   [X Y Z] = revolutionSurface(CURVE, N);
%   is the same, but generating curve is given in a single parameter CURVE,
%   which is a [Nx2] array of 2D points.
%
%   [X Y Z] = revolutionSurface(..., THETA)
%   where THETA is a vector, uses values of THETA for computing revolution
%   angles.
%
%   [X Y Z] = revolutionSurface(..., LINE);
%   where LINE is a 1x4 array, specifes the revolution axis in the
%   coordinate system of the curve. LINE is a row vector of 4 parameters,
%   containing [x0 y0 dx dy], where (x0,y0) is the origin of the line and
%   (dx,dy) is a direction vector of the line.
%   The resulting revolution surface still has Oz axis as symmetry axis. It
%   can be transformed using transformPoint3d function.
%   Surface can be displayed using :
%   H = surf(X, Y, Z);
%   H is a handle to the created patch.
%
%   revolutionSurface(...);
%   by itself, directly shows the created patch.
%
%   Example
%   % draws a piece of torus
%   circle = circleAsPolygon([10 0 3], 50);
%   [x y z] = revolutionSurface(circle, linspace(0, 4*pi/3, 50));
%   surf(x, y, z);
%   axis equal;
%
%
%
%   See also
%       surf, transformPoint3d, drawSphere, drawTorus, drawEllipsoid
%       surfature (on Matlab File Exchange)
%
%
%   ------
%   Author: David Legland
%   e-mail: david.legland@grignon.inra.fr
%   Created: 2004-04-09
%   Copyright 2005 INRA - CEPIA Nantes - MIAJ Jouy-en-Josas.

%   based on function cylinder from matlab
%   31/06/2006 fix bug when passing 3 parameters
%   20/04/2007 rewrite processing of input parameters, add psb to specify
%       revolution axis
%   24/10/2008 fix angle vector
%   29/07/2010 doc update

%% Initialisations

% default values

% use revolution using the full unit circle, decomposed into 24 angular
% segments (thus, some vertices correspond to particular angles 30°,
% 45°...)
theta = linspace(0, 2*pi, 25);

% use planar vertical axis as default revolution axis
revol = [0 0 0 1];

% extract the generating curve
var = varargin{1};
if size(var, 2)==1
    xt = var;
    yt = varargin{2};
    varargin(1:2) = [];
else
    xt = var(:,1);
    yt = var(:,2);
    varargin(1) = [];
end

% extract optional parameters: angles, axis of revolution
% parameters are identified from their length
while ~isempty(varargin)
    var = varargin{1};

    if length(var) == 4
        % axis of rotation in the base plane
        revol = var;

    elseif length(var) == 1
        % number of points -> create row vector of angles
        theta = linspace(0, 2*pi, var);

    else
        % use all specified angle values
        theta = var(:)';

    end
    varargin(1) = [];
end

%% Create revolution surface

% ensure length is enough
m = length(xt);
if m==1
    xt = [xt xt];
end

% ensure x and y are vertical vectors
xt = xt(:);
yt = yt(:);

% transform xt and yt to replace in the reference of the revolution axis
tra = createTranslation(-revol(1:2));
rot = createRotation(pi/2 - lineAngle(revol));
[xt, yt] = transformPoint(xt, yt, tra*rot);

% compute surface vertices
x = xt * cos(theta);
y = xt * sin(theta);
z = yt * ones(size(theta));

%% Process output arguments

% format output depending on how many output parameters are required
if nargout == 0
    % draw the revolution surface
    surf(x, y, z);

elseif nargout == 1
    % draw the surface and return a handle to the shown structure
    h = surf(x, y, z);
    varargout{1} = h;

elseif nargout == 3
    % return computed mesh
    varargout = {x, y, z};
end


% Copyright (C) Daphne Koller, Stanford University, 2012

function [MEU OptimalDecisionRule] = OptimizeWithJointUtility( I )
  % Inputs: An influence diagram I with a single decision node and one or more utility nodes.
  %         I.RandomFactors = list of factors for each random variable.  These are CPDs, with
  %              the child variable = D.var(1)
  %         I.DecisionFactors = factor for the decision node.
  %         I.UtilityFactors = list of factors representing conditional utilities.
  % Return value: the maximum expected utility of I and an optimal decision rule
  % (represented again as a factor) that yields that expected utility.
  % You may assume that there is a unique optimal decision.

  % This is similar to OptimizeMEU except that we must find a way to
  % combine the multiple utility factors.  Note: This can be done with very
  % little code.

  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  % YOUR CODE HERE
  %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 Uti = I.UtilityFactors(1);
 for i = 2:length(I.UtilityFactors)
	 Uti = FactorSum(Uti,I.UtilityFactors(i));
 end
 I.UtilityFactors = Uti;
[MEU OptimalDecisionRule] = OptimizeMEU(I);

end


% BOOSTING_EXAMPLE
%
% Constructs a 2-dimensional dataset classifiable by boosting, but not any
% simple linear classifier, because of the thresholding nature of the data.

rand('seed', 0);

% m datapoints in 2-dimensions
mm = 150;
X = rand(mm, 2);

thresh_pos = .6;
y = [X(:, 1) < thresh_pos & X(:, 2) < thresh_pos];
y = 2 * y - 1;

for T = [2, 4, 5, 10]
  figure;
  hpos = plot(X(y == 1, 1), X(y == 1, 2), 'o');
  hold on;
  hneg = plot(X(y == -1, 1), X(y == -1, 2), 'x');
  set(hpos, 'linewidth', 2);
  set(hneg, 'linewidth', 2);

  [theta, feature_inds, thresholds] = stump_booster(X, y, T);

  x1_coords = linspace(0, 1, 100);
  x2_coords = linspace(0, 1, 100);
  Z = zeros(100);
  for ii = 1:100
    for jj = 1:100
      pred = (sign(x1_coords(ii) - thresholds(feature_inds == 1))' * ...
              theta(feature_inds == 1)) + ...
             (sign(x2_coords(jj) - thresholds(feature_inds == 2))' * ...
              theta(feature_inds == 2));
      Z(jj, ii) = sign(pred);
    end
  end

  C = contourc(x1_coords, x2_coords, Z, [0 0]);
  h = plot(C(1, 2:end), C(2, 2:end), 'k-');
  set(h, 'linewidth', 2);
  title(sprintf('Iterations = %d', T));
  set(gca, 'fontsize', 18);
  print('-depsc2', sprintf('boost_plot_%d.eps', T));
end

%% Now solve the logistic regression problem directly

mm = 200;
X = rand(mm, 2);
y = [X(:, 1) < thresh_pos & X(:, 2) < thresh_pos];
y = 2 * y - 1;

theta_log = zeros(3, 1);
X_logit = [ones(mm, 1), X];
for iter = 1:1000
  risk = (1/mm) * sum(log(1 + exp(-y .* (X_logit * theta_log))));
  if (mod(iter, 50) == 0)
    fprintf(1, 'Iter %d, loss %1.4f\n', iter, risk);
  end
  p = 1 ./ (1 + exp(y .* (X_logit * theta_log)));
  g = -(1/mm) * X_logit' * (p .* y);
  theta_log = theta_log - 2 * g;
end

x1_coord = linspace(0, 1, 100);
x2_coord = -(theta_log(1) + theta_log(2) * x1_coord) / theta_log(3);

figure;
hpos = plot(X(y == 1, 1), X(y == 1, 2), 'o');
hold on;
hneg = plot(X(y == -1, 1), X(y == -1, 2), 'x');
set(hpos, 'linewidth', 2);
set(hneg, 'linewidth', 2);
h = plot(x1_coord, x2_coord, 'k-', 'linewidth', 2);
axis([0 1 0 1]);
set(gca, 'fontsize', 18);
print -depsc2 'logistic_plot.eps';


function [r, v] = orb2eci(mu, oev)

% convert classical orbital elements to eci state vector

% input

%  mu     = gravitational constant (km**3/sec**2)
%  oev(1) = semimajor axis (kilometers)
%  oev(2) = orbital eccentricity (non-dimensional)
%           (0 <= eccentricity < 1)
%  oev(3) = orbital inclination (radians)
%           (0 <= inclination <= pi)
%  oev(4) = argument of perigee (radians)
%           (0 <= argument of perigee <= 2 pi)
%  oev(5) = right ascension of ascending node (radians)
%           (0 <= raan <= 2 pi)
%  oev(6) = true anomaly (radians)
%           (0 <= true anomaly <= 2 pi)

% output

%  r = eci position vector (kilometers)
%  v = eci velocity vector (kilometers/second)

% Orbital Mechanics with Matlab

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

r = zeros(3, 1);
v = zeros(3, 1);

% unload orbital elements array

sma = oev(1);
ecc = oev(2);
inc = oev(3);
argper = oev(4);
raan = oev(5);
tanom = oev(6);

slr = sma * (1 - ecc * ecc);

rm = slr / (1 + ecc * cos(tanom));

arglat = argper + tanom;

sarglat = sin(arglat);
carglat = cos(arglat);

c4 = sqrt(mu / slr);
c5 = ecc * cos(argper) + carglat;
c6 = ecc * sin(argper) + sarglat;

sinc = sin(inc);
cinc = cos(inc);

sraan = sin(raan);
craan = cos(raan);

% position vector

r(1) = rm * (craan * carglat - sraan * cinc * sarglat);
r(2) = rm * (sraan * carglat + cinc * sarglat * craan);
r(3) = rm * sinc * sarglat;

% velocity vector

v(1) = -c4 * (craan * c6 + sraan * cinc * c5);
v(2) = -c4 * (sraan * c6 - craan * cinc * c5);
v(3) = c4 * c5 * sinc;


function [xi,w]=thirdOrderTetrahedronCubPoints()
%%THIRDORDERTETRAHEDRONCUBPOINTS Obtain third-order cubature points
%   for integration over a tetrahedron in 3D. The points and weights are
%   for the tetrahedron with vertices (1,0,0), (0,1,0), (0,0,1), and
%   (0,0,0), but can be transformed to any tetrahedron using
%   transformSimplexTetrahedronPts.
%
%INPUTS: None
%
%OUTPUTS: xi This is a 3XnumCubPoints set of points for the standard
%            tetrahedron.
%          w A 1XnumCubPoints set of cubature weights. This sums to the
%            volume of the standard tetrahedron (1/6).
%
%This function implements the points given in [1] (8 points).
%
%EXAMPLE:
%Given the vertices of the simplex, we compare a third-order moment
%computed using these cubature points to one computed using
%monomialIntSimplex. The results are the same within typical finite
%precision limits.
% [xi,w]=thirdOrderTetrahedronCubPoints();
% alpha=[1;1;1];
% theMoment=findMomentFromSamp(alpha,xi,w);
% intVal=monomialIntSimplex(alpha);
% RelErr=(theMoment-intVal)/intVal
%
%REFERENCES:
%[1] F. D. Witherden and P. E. Vincent, "On the identification of symmetric
%    quadrature rules for finite element methods," Computer and Mathematics
%    with Applications, vol. 69, no. 10, pp. 1232-1241, May 2015.
%
%October 2022 David F. Crouse, Naval Research Laboratory, Washington D.C.
%(UNCLASSIFIED) DISTRIBUTION STATEMENT A. Approved for public release.

M=[-0.34367339496723662642072827083693243093,  -0.34367339496723662642072827083693243093,   -0.9689798150982901207378151874892027072,   0.18162379004944980942342872025562069427;
   -0.34367339496723662642072827083693243093,   -0.9689798150982901207378151874892027072,  -0.34367339496723662642072827083693243093,   0.18162379004944980942342872025562069427;
    -0.9689798150982901207378151874892027072,  -0.34367339496723662642072827083693243093,  -0.34367339496723662642072827083693243093,   0.18162379004944980942342872025562069427;
   -0.34367339496723662642072827083693243093,  -0.34367339496723662642072827083693243093,  -0.34367339496723662642072827083693243093,   0.18162379004944980942342872025562069427;
   -0.78390550020314279176487322158837338344,  -0.78390550020314279176487322158837338344,   0.35171650060942837529461966476512015033,   0.15170954328388352390990461307771263906;
   -0.78390550020314279176487322158837338344,   0.35171650060942837529461966476512015033,  -0.78390550020314279176487322158837338344,   0.15170954328388352390990461307771263906;
    0.35171650060942837529461966476512015033,  -0.78390550020314279176487322158837338344,  -0.78390550020314279176487322158837338344,   0.15170954328388352390990461307771263906;
   -0.78390550020314279176487322158837338344,  -0.78390550020314279176487322158837338344,  -0.78390550020314279176487322158837338344,   0.15170954328388352390990461307771263906];
w=M(:,4);
xi=M(:,1:3)';
%Transform the points to the standard tetrahedron.
v1=[-1, 1,-1,-1;
    -1,-1,-1, 1;
    -1,-1, 1, -1];
v2=[1,0,0,0;
    0,1,0,0;
    0,0,1,0];
[A,d]=affineTransBetweenTetrahedra(v1,v2);
xi=bsxfun(@plus,A*xi,d);
w=w/8;
end

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


function dx = susp_sys(x,u)

% Dynamics of the syspension system
x1 = x(1);
x2 = x(2);
x3 = x(3);
x4 = x(4);

% Coefficients
mb = 300;    % kg
mw = 60;     % kg
bs = 1000;   % N/m/s
ks = 16000 ; % N/m
kt = 190000; % N/m
kn = ks/10;  % N/m

% System Dynamics
dx1 = x2;
dx2 = -(ks*(x1-x3)+kn*(x1-x3)^3)/mb - (bs*(x2-x4)-10000*u)/mb;
dx3 = x4;
dx4 =  (ks*(x1-x3)+kn*(x1-x3)^3)/mw + (bs*(x2-x4)-kt*x3-10000*u)/mw;

% Combine the output
dx = [dx1;
	  dx2;
	  dx3;
	  dx4];
end


function g = p13_g ( n, x )

%*****************************************************************************80
%
%% P13_G evaluates the gradient for problem 13.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    18 October 2011
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer N, the number of variables.
%
%    Input, real X(N), the values of the variables.
%
%    Output, real G(N), the gradient of the objective function.
%
  g = zeros ( n, 1 );

  s1 = sum ( cos ( x(1:n) ) );

  s2 = 0.0;
  for j = 1 : n
    t =  ( n + j ) - sin ( x(j) ) - s1 - j * cos ( x(j) );
    s2 = s2 + t;
    g(j) = ( j * sin ( x(j) ) - cos ( x(j) ) ) * t;
  end

  for j = 1 : n
    g(j) = 2.0 * ( g(j) + sin ( x(j) ) * s2 );
  end

  return
end


function im = UpsampleImage(img, line_factor, elem_factor)
% Returns an FFT upsampled image.
%
% Returns an image which is upsampled by the inverse FFTing, zero padding
% by the supplied amount (line_factor and elem_factor) and FFTing back.
%
% Usage:
%     im = UpsampleImage(img, line_factor, elem_factor)
%
% Example:
%     im = UpsampleImage(some_image data, 1.5, 1.5);
%
%
% //////////////////////////////////////////
% /// CLASSIFICATION: UNCLASSIFIED       ///
% //////////////////////////////////////////

    [rows,cols] = size(img);

    % Inverse FFT
    sp = fftshift(ifft2(fftshift(img))) / (rows*cols);
    %%%sp = ifft2(img) / (rows*cols);

    padded_data = zeros( floor(rows*line_factor), floor(cols*elem_factor) );
    if (line_factor < 1  &&  elem_factor < 1)
        row_start  = floor((rows-(rows*line_factor))/2);
        row_length = size(padded_data,1);
        col_start  = floor((cols-(cols*elem_factor))/2);
        col_length = size(padded_data,2);
        padded_data = sp(row_start:(row_start+row_length), ...
                         col_start:(col_start+col_length));
    else
        % Zero pad around the edges
        off_line = floor((rows*line_factor - rows)/2.0);
        off_elem = floor((cols*elem_factor - cols)/2.0) ;
        padded_data(off_line:off_line+rows-1, off_elem:off_elem+cols-1) = sp;
    end

    % Then just FFT back to get the image.
    im = fftshift(fft2(fftshift(padded_data))) * (rows*cols);
    %%%im = fft2(padded_data) / (rows*cols);
end
%
% //////////////////////////////////////////
% /// CLASSIFICATION: UNCLASSIFIED       ///
% //////////////////////////////////////////


% Weighted random sampling.
%
% INPUTs: number of draws from a discrete distribution (n)
%         possible values to pick from, (P)
%         set of normalized weights/probabilities, (W)
% OUTPUTs: s - set of n numbers drawn from P
%              according to the weights in W
%
% GB: last updated, Oct 31 2012

function s = weightedRandomSample(n,P,W)

s = [];

if abs(sum(W)-1)>10**(-8);
    printf('The probabilities do not sum up to 1.\n');
    s = 'probabilities do not sum up to 1';
    return;
end

% divide the unit interval into |P| segments each with length W_i
unit = [0,W(1)];
for w=2:length(W)
  unit = [unit W(w)+unit(length(unit))];
end

% draw a random number in the unit interval uniformly - where does it fall?
while length(s)<n

  lb = max(find(unit<rand));    % rand is in [unit(lb), unit(lb+1)]
  s = [s P(lb)];                % pick P(lb)

end


function [eigvector, eigvalue] = LGE(W, D, options, data)
% LGE: Linear Graph Embedding
%
%       [eigvector, eigvalue] = LGE(W, D, options, data)
%
%             Input:
%               data       - data matrix. Each row vector of data is a
%                         sample vector.
%               W       - Affinity graph matrix.
%               D       - Constraint graph matrix.
%                         LGE solves the optimization problem of
%                         a* = argmax (a'data'WXa)/(a'data'DXa)
%                         Default: D = I
%
%               options - Struct value in Matlab. The fields in options
%                         that can be set:
%
%                     ReducedDim   -  The dimensionality of the reduced
%                                     subspace. If 0, all the dimensions
%                                     will be kept. Default is 30.
%
%                            Regu  -  1: regularized solution,
%                                        a* = argmax (a'X'WXa)/(a'X'DXa+ReguAlpha*I)
%                                     0: solve the sinularity problem by SVD (PCA)
%                                     Default: 0
%
%                        ReguAlpha -  The regularization parameter. Valid
%                                     when Regu==1. Default value is 0.1.
%
%                            ReguType  -  'Ridge': Tikhonov regularization
%                                         'Custom': User provided
%                                                   regularization matrix
%                                          Default: 'Ridge'
%                        regularizerR  -   (nFea x nFea) regularization
%                                          matrix which should be provided
%                                          if ReguType is 'Custom'. nFea is
%                                          the feature number of data
%                                          matrix
%
%                            PCARatio     -  The percentage of principal
%                                            component kept in the PCA
%                                            step. The percentage is
%                                            calculated based on the
%                                            eigenvalue. Default is 1
%                                            (100%, all the non-zero
%                                            eigenvalues will be kept.
%                                            If PCARatio > 1, the PCA step
%                                            will keep exactly PCARatio principle
%                                            components (does not exceed the
%                                            exact number of non-zero components).
%
%
%             Output:
%               eigvector - Each column is an embedding function, for a new
%                           sample vector (row vector) x,  y = x*eigvector
%                           will be the embedding result of x.
%               eigvalue  - The sorted eigvalue of the eigen-problem.
%               elapse    - Time spent on different steps
%
%
%
%    Examples:
%
% See also LPP, NPE, IsoProjection, LSDA.
%
%
%Reference:
%
%   1. Deng Cai, Xiaofei He, Jiawei Han, "Spectral Regression for Efficient
%   Regularized Subspace Learning", IEEE International Conference on
%   Computer Vision (ICCV), Rio de Janeiro, Brazil, Oct. 2007.
%
%   2. Deng Cai, Xiaofei He, Yuxiao Hu, Jiawei Han, and Thomas Huang,
%   "Learning a Spatially Smooth Subspace for Face Recognition", CVPR'2007
%
%   3. Deng Cai, Xiaofei He, Jiawei Han, "Spectral Regression: A Unified
%   Subspace Learning Framework for Content-Based Image Retrieval", ACM
%   Multimedia 2007, Augsburg, Germany, Sep. 2007.
%
%   4. Deng Cai, "Spectral Regression: A Regression Framework for
%   Efficient Regularized Subspace Learning", PhD Thesis, Department of
%   Computer Science, UIUC, 2009.
%
%   version 3.0 --Dec/2011
%   version 2.1 --June/2007
%   version 2.0 --May/2007
%   version 1.0 --Sep/2006
%
%   Written by Deng Cai (dengcai AT gmail.com)
%

MAX_MATRIX_SIZE = 1600; % You can change this number according your machine computational power
EIGVECTOR_RATIO = 0.1; % You can change this number according your machine computational power

if (~exist('options','var'))
   options = [];
end

ReducedDim = 30;
if isfield(options,'ReducedDim')
    ReducedDim = options.ReducedDim;
end

if ~isfield(options,'Regu') || ~options.Regu
    bPCA = 1;
    if ~isfield(options,'PCARatio')
        options.PCARatio = 1;
    end
else
    bPCA = 0;
    if ~isfield(options,'ReguType')
        options.ReguType = 'Ridge';
    end
    if ~isfield(options,'ReguAlpha')
        options.ReguAlpha = 0.1;
    end
end

bD = 1;
if ~exist('D','var') || isempty(D)
    bD = 0;
end

[nSmp,nFea] = size(data);
if size(W,1) ~= nSmp
    error('W and data mismatch!');
end
if bD && (size(D,1) ~= nSmp)
    error('D and data mismatch!');
end

bChol = 0;
if bPCA && (nSmp > nFea) && (options.PCARatio >= 1)
    if bD
        DPrime = data'*D*data;
    else
        DPrime = data'*data;
    end
    DPrime = full(DPrime);
    DPrime = max(DPrime,DPrime');
    [R,p] = chol(DPrime);
    if p == 0
        bPCA = 0;
        bChol = 1;
    end
end

%======================================
% SVD
%======================================

if bPCA
    [U, S, V] = mySVD(data);
    [U, S, V]=CutonRatio(U,S,V,options);
    eigvalue_PCA = full(diag(S));
    if bD
        data = U*S;
        eigvector_PCA = V;

        DPrime = data'*D*data;
        DPrime = max(DPrime,DPrime');
    else
        data = U;
        eigvector_PCA = V*spdiags(eigvalue_PCA.^-1,0,length(eigvalue_PCA),length(eigvalue_PCA));
    end
else
    if ~bChol
        if bD
            DPrime = data'*D*data;
        else
            DPrime = data'*data;
        end

        switch lower(options.ReguType)
            case {lower('Ridge')}
                if options.ReguAlpha > 0
                    for i=1:size(DPrime,1)
                        DPrime(i,i) = DPrime(i,i) + options.ReguAlpha;
                    end
                end
            case {lower('Tensor')}
                if options.ReguAlpha > 0
                    DPrime = DPrime + options.ReguAlpha*options.regularizerR;
                end
            case {lower('Custom')}
                if options.ReguAlpha > 0
                    DPrime = DPrime + options.ReguAlpha*options.regularizerR;
                end
            otherwise
                error('ReguType does not exist!');
        end

        DPrime = max(DPrime,DPrime');
    end
end

WPrime = data'*W*data;
WPrime = max(WPrime,WPrime');

%======================================
% Generalized Eigen
%======================================

dimMatrix = size(WPrime,2);

if ReducedDim > dimMatrix
    ReducedDim = dimMatrix;
end

if isfield(options,'bEigs')
    bEigs = options.bEigs;
else
    if (dimMatrix > MAX_MATRIX_SIZE) && (ReducedDim < dimMatrix*EIGVECTOR_RATIO)
        bEigs = 1;
    else
        bEigs = 0;
    end
end

if bEigs
    %disp('use eigs to speed up!');
    option = struct('disp',0);
    if bPCA && ~bD
        [eigvector, eigvalue] = eigs(WPrime,ReducedDim,'la',option);
    else
        if bChol
            option.cholB = 1;
            [eigvector, eigvalue] = eigs(WPrime,R,ReducedDim,'la',option);
        else
            [eigvector, eigvalue] = eigs(WPrime,DPrime,ReducedDim,'la',option);
        end
    end
    eigvalue = diag(eigvalue);
else
    if bPCA && ~bD
        [eigvector, eigvalue] = eig(WPrime);
    else
        [eigvector, eigvalue] = eig(WPrime,DPrime);
    end
    eigvalue = diag(eigvalue);

    [junk, index] = sort(-eigvalue);
    eigvalue = eigvalue(index);
    eigvector = eigvector(:,index);

    if ReducedDim < size(eigvector,2)
        eigvector = eigvector(:, 1:ReducedDim);
        eigvalue = eigvalue(1:ReducedDim);
    end
end

if bPCA
    eigvector = eigvector_PCA*eigvector;
end

for i = 1:size(eigvector,2)
    eigvector(:,i) = eigvector(:,i)./norm(eigvector(:,i));
end

function [U, S, V]=CutonRatio(U,S,V,options)
    if  ~isfield(options, 'PCARatio')
        options.PCARatio = 1;
    end

    eigvalue_PCA = full(diag(S));
    if options.PCARatio > 1
        idx = options.PCARatio;
        if idx < length(eigvalue_PCA)
            U = U(:,1:idx);
            V = V(:,1:idx);
            S = S(1:idx,1:idx);
        end
    elseif options.PCARatio < 1
        sumEig = sum(eigvalue_PCA);
        sumEig = sumEig*options.PCARatio;
        sumNow = 0;
        for idx = 1:length(eigvalue_PCA)
            sumNow = sumNow + eigvalue_PCA(idx);
            if sumNow >= sumEig
                break;
            end
        end
        U = U(:,1:idx);
        V = V(:,1:idx);
        S = S(1:idx,1:idx);
    end


%KDOG Difference of Gaussian kernel
%
% K = KDOG(SIGMA1) is a 2-dimensional difference of Gaussian kernel equal
% to KGAUSS(SIGMA1) - KGAUSS(SIGMA2), where SIGMA1 > SIGMA2.  By default
% SIGMA2 = 1.6*SIGMA1.  The kernel is centred within the matrix K whose
% half-width H = 3xSIGMA and W=2xH+1.
%
% K = KDOG(SIGMA1, SIGMA2) as above but SIGMA2 is specified directly.
%
% K = KDOG(SIGMA1, SIGMA2, H) as above but the kernel half-width is specified.
%
% Notes::
% - This kernel is similar to the Laplacian of Gaussian and is often used
%   as an efficient approximation.
%
% See also KGAUSS, KDGAUSS, KLOG, ICONV.

% Copyright (C) 1993-2011, by Peter I. Corke
%
% This file is part of The Machine Vision Toolbox for Matlab (MVTB).
%
% MVTB is free software: you can redistribute it and/or modify
% it under the terms of the GNU Lesser General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% MVTB 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 Lesser General Public License for more details.
%
% You should have received a copy of the GNU Leser General Public License
% along with MVTB.  If not, see <http://www.gnu.org/licenses/>.

function m = kdog(sigma1, sigma2, w)

    % sigma1 > sigma2
    if nargin == 1
        sigma2 = 1.6*sigma1;
        w = ceil(2*sigma2);
    elseif nargin == 2
        sigma2 = 1.6*sigma1;
        w = ceil(2*sigma2);
    elseif nargin == 3
        if sigma2 < sigma1
            t = sigma1;
            sigma1 = sigma2;
            sigma2 = t;
        end
    end
	if nargin < 3
        w = ceil(3*sigma1);
	end

    % sigma2 > sigma1
    m1 = kgauss(sigma1, w);     % thin kernel
    m2 = kgauss(sigma2, w);     % wide kernel

    m = m2 - m1;


function stat_ds=cosmo_stat(ds, stat_name, output_stat_name)
% compute t-test or F-test (ANOVA) statistic
%
% stat_ds=cosmo_stats(ds, stat_name[, output_stat_name])
%
% Inputs:
%   ds                dataset struct with
%                       .samples PxQ, for P observations on Q features
%                       .sa.targets Px1 observation conditions (classes)
%                       .sa.chunks  Px1 observation chunks (e.g. subjects).
%   stat_name         One of [*]:
%                     't' : one-sample t-test against zero (nclasses==1),
%                           or paired t-test (nclasses==2)
%                     't2': two-sample t-test with equal variance,
%                           (nclasses==2) contrasting samples with unq(1)
%                           minus unq(2) where unq=unique(ds.sa.targets)
%                     'F' : one-way ANOVA or repeated measures ANOVA
%                           (nclasses>=2)
%                     [*] nclasses is the number of unique values in
%                         ds.sa.targets
%   output_stat_name  (optional) 'left', 'right', 'both', 'z', 'p', or
%                      the empty string '' (default).
%                     - 'left', 'right', and 'both' return a p-value with
%                        the specified tail.
%                     - 'p' returns a p-value, with tail='right' if
%                        stat_name='F' and tail='both' otherwise.
%                     - 'z' returns a z-score corresponding to the p-value
%                     - '' (empty) returns the t or F statistic.
%                     Missing values can be indicated by NaNs; if these are
%                     present and a p-value or z-score is returned, then
%                     these values are computed with a possible variable
%                     number of degrees of freedom across features.
%
% Returns:
%   stat_ds          dataset struct with fields:
%     .samples       1xQ statistic value, or (if output_stat_name is
%                    non-empty) z-score or p-value. See the Notes below
%                    for interpreting p-values.
%     .sa            struct with field:
%        .stats      One of 'Ftest(df1,df2)', 'Ttest(df)', 'Zscore()', or
%                    'Pval()', where df* are the degrees of freedom
%     .[f]a          identical to the input ds.[f]a, if present.
%
% Examples:
%     % one-sample t-test
%     % make a simple dataset
%     ds=struct();
%     ds.samples=reshape(mod(1:7:(12*3*7),13)',[],3)-3;
%     ds.sa.targets=ones(12,1);
%     ds.sa.chunks=(1:12)';
%     cosmo_disp(ds.samples);
%     %||   [ -2         4        -3
%     %||      5        -2         4
%     %||     -1         5        -2
%     %||      :         :         :
%     %||      9         2         8
%     %||      3         9         2
%     %||     -3         3         9 ]@12x3
%     %
%     % run one-sample t-test
%     s=cosmo_stat(ds,'t');
%     cosmo_disp(s);
%     %|| .samples
%     %||   [ 2.49      3.36      2.55 ]
%     %|| .sa
%     %||   .stats
%     %||     { 'Ttest(11)' }
%     %
%     % compute z-score of t-test
%     s=cosmo_stat(ds,'t','z');
%     cosmo_disp(s);
%     %|| .samples
%     %||   [ 2.17      2.73      2.21 ]
%     %|| .sa
%     %||   .stats
%     %||     { 'Zscore()' }
%     %
%     % compute (two-tailed) p-value of t-test
%     s=cosmo_stat(ds,'t','p');
%     cosmo_disp(s);
%     %|| .samples
%     %||   [ 0.03   0.00633    0.0268 ]
%     %|| .sa
%     %||   .stats
%     %||     { 'Pval()' }
%     %
%     % compute left-tailed p-value of t-test
%     s=cosmo_stat(ds,'t','left');
%     cosmo_disp(s);
%     %|| .samples
%     %||   [ 0.985     0.997     0.987 ]
%     %|| .sa
%     %||   .stats
%     %||     { 'Pval()' }
%
%     % one-way ANOVA
%     % each observation is independent and thus each chunk is unique;
%     % there are three conditions with four observations per condition
%     ds=struct();
%     ds.samples=reshape(mod(1:7:(12*3*7),13)',[],3)-3;
%     ds.sa.targets=repmat(1:3,1,4)';
%     ds.sa.chunks=(1:12)';
%     s=cosmo_stat(ds,'F');
%     cosmo_disp(s);
%     %|| .samples
%     %||   [ 0.472    0.0638      0.05 ]
%     %|| .sa
%     %||   .stats
%     %||     { 'Ftest(2,9)' }
%     % compute z-score
%     s=cosmo_stat(ds,'F','z'); % convert to z-score
%     cosmo_disp(s);
%     %|| .samples
%     %||   [ -0.354     -1.54     -1.66 ]
%     %|| .sa
%     %||   .stats
%     %||     { 'Zscore()' }
%
%
%     % two-sample t-test
%     % each observation is independent and thus each chunk is unique;
%     % there are two conditions with four observations per condition
%     ds=struct();
%     ds.samples=reshape(mod(1:7:(12*3*7),13)',[],3)-3;
%     ds.sa.targets=repmat(1:2,1,6)';
%     ds.sa.chunks=(1:12)';
%     s=cosmo_stat(ds,'t2','p'); % return p-value
%     cosmo_disp(s);
%     %|| .samples
%     %||   [ 0.0307  0.000242  7.07e-05 ]
%     %|| .sa
%     %||   .stats
%     %||     { 'Pval()' }
%     %
%     % for illustration, this test gives the same p-values as a
%     % repeated measures ANOVA
%     s=cosmo_stat(ds,'F','p');
%     cosmo_disp(s);
%     %|| .samples
%     %||   [ 0.0307  0.000242  7.07e-05 ]
%     %|| .sa
%     %||   .stats
%     %||     { 'Pval()' }
%
% Notes:
%  - If output_stat_name is not provided or empty, then this function runs
%    considerably faster than the builtin matlab functions
%    (ttest, ttest2, or anova1).
%  - When output_stat_name=='p' then the p-values returned are the same as
%    the builtin matlab functions anova1, ttest, and ttest2 with the
%    default tails.
%  - To run a one-sample t-tests against x (if x~=0), one has to
%    subtract x from ds.samples before using ds as input to this function
%  - The .sa.chunks and .sa.targets determine which test is performed:
%    * statname=='t': all chunks are unique => one-sample t-test
%                   : each chunk present twice => paired-sample t-test
%    * statname=='F': all chunks are unique => one-way ANOVA
%                   : each chunk present N times => repeated measures ANOVA
%    See cosmo_montecarlo_cluster_stat for examples on how .sa.targets and
%    .sa.chunks should be set for different statistics.
%  - Missing values can be indicated by NaNs, and if the output is a
%    p-value (or a z-score based on the p-value), then the output is
%    computed for different features using varying degrees of freedom.
%    For example, if the dataset has 10 samples and a one-sample t-test is
%    used, z-scores for samples with no NaN values is based on the
%    t-statistic with df=9, but those with two missing values (NaN values)
%    are based on the t-statistic with df=7. A use case is computing fMRI
%    group statistics where overlap across brains is not perfect at the
%    voxel-by-voxel level, in as imilar approach as AFNI's 3dttest++ with
%    the '-toz' option.
%  - This function computes feature-wise statistics that are not corrected
%    for multiple comparisons. To correct for multiple comparisons, see
%    cosmo_montecarlo_cluster_stat.
%
% See also: anova1, ttest, ttest2, cosmo_montecarlo_cluster_stat
%
% #   For CoSMoMVPA's copyright information and license terms,   #
% #   see the COPYING file distributed with CoSMoMVPA.           #

    if nargin<3
        output_stat_name='';
    end

    [output_stat_name,tail]=get_stat_definition(stat_name,...
                                                output_stat_name);
    [samples,targets,chunks,type]=get_descriptors(ds);

    % run specified helper function
    if isfield(ds.sa,'contrast')
        contrast=ds.sa.contrast;
    else
        contrast=[];
    end

    % ensure stat_name matches the number of classes
    verify_class_count(stat_name,targets);

    % get ttest1, ttest2 or Ftest function handle
    stat_func=get_stat_func(stat_name);

    % apply statistic function handle
    [stat,df_struct,stat_label]=apply_stat_func(stat_func,...
                                    samples,targets,chunks,type,contrast);

    % convert to p-value or z-score, if necessary
    [stat,stat_label]=compute_output_stat(stat,df_struct,stat_label,...
                                                tail,output_stat_name);

    % store output
    stat_ds=struct();
    if isfield(ds,'a'), stat_ds.a=ds.a; end
    if isfield(ds,'fa'), stat_ds.fa=ds.fa; end
    stat_ds.samples=stat;
    stat_ds.sa.stats={stat_label};

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% helper functions
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [stat,df_struct,stat_label]=apply_stat_func(stat_func,...
                                                samples,targets,chunks,...
                                                type,contrast)
% applies the stat_func to samples, taking into account missing values
% (indicated by NaN) in samples
    samples_nan_msk=isnan(samples);
    has_missing=any(any(samples_nan_msk,1) & ~all(samples_nan_msk,1));
    if ~has_missing
        [stat,df_struct,stat_label]=apply_stat_func_no_nans(stat_func,...
                                                samples,targets,chunks,...
                                                type,contrast);
        return;
    end

    [nsamples,nfeatures]=size(samples);
    stat=zeros(1,nfeatures);

    zeroed_samples=samples;
    zeroed_samples(~samples_nan_msk)=0;

    nan_counts=sum(samples_nan_msk,1);
    unq_counts=unique(nan_counts);

    % build indicator matrix, so that a value in zeroed_samples(i,j)=v
    % - v=0 means that samples(i,j) is not NaN
    % - v=k, k>0 means that samples(i,j) is the k-th NaN value in that
    % column
    for c=1:numel(unq_counts)
        count=unq_counts(c);
        col_msk=nan_counts==count;

        msk=bsxfun(@and, samples_nan_msk, col_msk);
        zeroed_samples(msk)=repmat((1:count)',1,sum(col_msk));
    end

    % using the indicator matrix, split up the samples in blocks so that
    % in each block, the same rows in samples are NaN. Each block is
    % processed seperately in the 'for' loop below.

    [indices, zeroed_unq]=cosmo_index_unique(zeroed_samples');

    nclasses=max(targets);

    for k=1:numel(indices)
        zeroed=zeroed_unq(k,:)';
        cols=indices{k};

        nan_msk=zeroed>0;

        % keep samples where there are non-NaN values for the corresponding
        % chunk
        keep_msk=any(bsxfun(@eq,chunks(:),chunks(~nan_msk)'),2);
        keep_samples=samples(keep_msk,cols);

        % ensure chunks are numbered 1:max(chunks)
        [unused,unused,keep_chunks]=unique(chunks(keep_msk));

        % select targets
        keep_targets=targets(keep_msk);

        % compute t or F statistic
        [stat_k,df,stat_label_k]=stat_func(keep_samples,...
                                        keep_targets,...
                                        keep_chunks,...
                                        type,contrast);

        % if for some samples in a chunk the value was NaN and for others
        % it was not NaN, then the output is NaN
        has_mixed_nan_and_non_nan=any(nan_msk(keep_msk));

        % if a target value was completely non-present, then
        % the output is NaN
        keep_targets_msk=false(1,nclasses);
        keep_targets_msk(targets(keep_msk))=true;

        if has_mixed_nan_and_non_nan || any(~keep_targets_msk)
            stat_k(:)=NaN;
        end

        % store stat val
        stat(cols)=stat_k;

        if k==1
            % allocate space
            df_count=numel(df);
            df_matrix=zeros(df_count,nfeatures);
            stat_label=stat_label_k;
        else
            % stat label must always be the same
            assert(isequal(stat_label,stat_label_k));
        end

        ncols=numel(cols);

        df_matrix(:,cols)=repmat(df(:),1,ncols);
    end

    single_sample=samples(:,1);
    single_sample(:)=0;

    [unused,max_df]=stat_func(single_sample,targets,chunks,...
                                    type,contrast);

    df_struct=struct();
    df_struct.max_df=max_df(:);
    df_struct.feature_wise_df=df_matrix;

function [stat,df_struct,stat_label]=apply_stat_func_no_nans(stat_func,...
                                                samples,targets,chunks,...
                                                type,contrast)
    % much faster computation of statistics, if there are no NaNs
    [stat,max_df,stat_label]=stat_func(samples,targets,chunks,...
                                             type,contrast);

    nfeatures=size(samples,2);

    df_struct=struct();
    df_struct.max_df=max_df(:);
    df_struct.feature_wise_df=repmat(max_df(:),1,nfeatures);

function f=get_stat_func(stat_name)
    stat_name2func=struct();
    stat_name2func.t=@ttest1_wrapper;
    stat_name2func.t2=@ttest2_wrapper;
    stat_name2func.F=@ftest_wrapper;

    assert(isfield(stat_name2func,stat_name))

    f=stat_name2func.(stat_name);

function verify_class_count(stat_name,targets)
    stat_name2interval=struct();
    stat_name2interval.t=[1,2];
    stat_name2interval.t2=[2,2];
    stat_name2interval.F=[2,Inf];

    if ~isfield(stat_name2interval,stat_name)
        error('illegal statname ''%s'', supported are: %s',stat_name,...
                    cosmo_strjoin(fieldnames(stat_name2interval),', '));
    end

    valid_interval=stat_name2interval.(stat_name);

    count=max(targets);
    assert(count==numel(unique(targets)));

    min_count=valid_interval(1);
    if count<min_count
        error('statname ''%s'' requires at least %d unique targets',...
                        stat_name,min_count);
    end

    max_count=valid_interval(2);
    if count>max_count
        error('statname ''%s'' requires at most %d unique targets',...
                        stat_name,max_count);
    end

function [stat,stat_label]=compute_output_stat(stat,df_struct,stat_name,...
                                                 tail,output_stat_name)
% transform output is required

    if isempty(output_stat_name)
        % raw t or F value
        stat_fa_name=stat_name;

        % features with missing values (as indicated by df values that
        % are different from the maximum df possible) are set to NaN
        df_is_max_msk=bsxfun(@eq,df_struct.max_df,...
                                       df_struct.feature_wise_df);
        has_missing=~all(df_is_max_msk,1);
        stat(has_missing)=NaN;

        % set degrees of freedom
        df_str=arrayfun(@(x) sprintf('%d',x), df_struct.max_df,...
                                    'UniformOutput',false);
        stat_label=sprintf('%s(%s)',stat_fa_name,...
                                    cosmo_strjoin(df_str,','));
    else
        % transform to left-tailed p-value for each unique combination
        % of degrees of freedom
        stat=apply_cdf_wrapper_different_dfs(stat_name,stat,df_struct);

        switch output_stat_name
            case 'z'
                % transform to z-score
                stat=cosmo_norminv(stat);
                stat_fa_name='Zscore';
            case 'p'
                switch tail
                    case 'left'
                        % do nothing
                    case 'right'
                        % invert p-value
                        stat=1-stat;
                    case 'both'
                        % take whichever tail is more extreme
                        stat=(.5-abs(stat-.5))*2;
                    otherwise
                        assert(false,'this should not happen');
                end
                stat_fa_name='Pval';
            otherwise
                error('illegal output type %s', output_stat_name);
        end

        stat_label=sprintf('%s()',stat_fa_name);
    end

function cdf_stat=apply_cdf_wrapper_different_dfs(stat_name,stat,df_struct)
    % applies the cdf wrapper to each unique combination of degrees of
    % freedom stored in df_struct.feature_wise_df

    [idx, unique_dfs]=cosmo_index_unique(df_struct.feature_wise_df');

    % allocate space for output
    cdf_stat=zeros(size(stat))+NaN;

    % compute result
    for k=1:numel(idx)
        cols=idx{k};
        df_cell=num2cell(unique_dfs(k,:));

        col_stat=stat(cols);
        msk=~isnan(col_stat);

        cdf_stat(cols(msk))=cdf_wrapper(stat_name,col_stat(msk),df_cell{:});
    end

function y=cdf_wrapper(name, x, df1, df2)
    ensure_has_stats_functions();
    if ~(df1>0)
        y=zeros(size(x))+NaN;
        return;
    end

    switch name
        case 'Ttest'
            assert(nargin==3);
            y=tcdf(x, df1);

        case 'Ftest'
            assert(nargin==4);
            if ~(df2>0)
                y=zeros(size(x))+NaN;
            return;
            end

            y=fcdf(x, df1, df2);

        otherwise
            assert(false);
    end

function [stat,df,stat_label]=ttest1_wrapper(samples,targets,chunks,...
                                                           type,contrast)
    if ~isempty(contrast)
        error('contrast is not supported for t-stat');
    end

    nclasses=max(targets);
    if nclasses==2
        samples=pairwise_differences(samples,targets,chunks);
        nclasses=1;
    end

    if nclasses~=1
        error('t-stat: expected 1 or 2 classes, found %d',...
                    nclasses);
    end

    [stat,df]=quick_ttest(samples);
    stat_label='Ttest';

function [stat,df,stat_label]=ttest2_wrapper(samples,targets,chunks,...
                                                           type,contrast)
    if ~isempty(contrast)
        error('contrast is not supported for t-stat');
    end

    if strcmp(type,'within')
        error(['ttest2 stat: the values in chunks and targets suggest '...
                    'a within-subject design. If you want to '...
                    'run a paired-test, use ''t'' (not ''t2'') ',...
                    'as the second argument']);
    end

    m1=targets==1;
    m2=targets==2;

    [stat,df]=quick_ttest2(samples(m1,:),...
                          samples(m2,:));
    nclasses=max(targets);
    if nclasses~=2
        % missing targets, set all to NaN
        assert(nclasses<2)
        stat(:)=NaN;
    end

    stat_label='Ttest';

function [stat,df,stat_label]=ftest_wrapper(samples,targets,chunks,...
                                                            type,contrast)
    nclasses=max(targets);

    if nclasses<2
        error('F stat: expected >=2 classes, found %d',nclasses);
    end

    switch type
        case 'between'
            [stat,df]=quick_ftest_between(samples, targets, ...
                                        chunks,contrast);
        case 'within'
            [stat,df]=quick_ftest_within(samples, targets, ...
                                        chunks,contrast);

    end
    stat_label='Ftest';

function [f,df]=quick_ftest_between(samples,targets,chunks,contrast)
    % one-way ANOVA
    has_contrast=~isempty(contrast);
    contrast_sum=0;

    nclasses=max(targets);

    [ns,nf]=size(samples);
    mu=sum(samples,1)/ns; % grand mean

    b=zeros(nclasses,nf); % between-class sum of squares
    nsc=zeros(nclasses,1);
    wss=0; % within-class sum of squares

    for k=1:nclasses
        msk=k==targets;

        nsc(k)=sum(msk); % number of samples in this class
        sample=samples(msk,:);
        muc=sum(sample,1)/nsc(k); % class mean

        % between- and within-class sum of squares
        if has_contrast
            cmsk=contrast(msk);
            if ~all(cmsk(1)==cmsk)
                error('Contrast has differerent values in level %d',k);
            end
            contrast_sum=contrast_sum+cmsk(1);
            b(k,:)=sum(bsxfun(@times,contrast(msk),mu-muc),1);
        else
            b(k,:)=(mu-muc);
        end
        wss=wss+sum(bsxfun(@minus,muc,sample).^2,1);
    end

    if has_contrast
        if contrast_sum~=0
            error('contrast has sum %d, should be 0', contrast_sum);
        end
        bss=sum(b,1).^2/sum(contrast.^2);
        df1=1;
    else
        bss=sum(bsxfun(@times,nsc,b.^2),1);
        df1=nclasses-1;
    end

    df=[df1,ns-nclasses];

    mbss=bss/df(1);
    mwss=wss/df(2);

    f=zeros(1,nf)+NaN;
    msk=mbss>0;
    f(msk)=mbss(msk)./mwss(msk);

function [f,df]=quick_ftest_within(samples,targets,chunks,contrast)
    % repeated measures anova
    if ~isempty(contrast)
        error('contrast is not supported for within-subject design');
    end

    nchunks=max(chunks);
    nclasses=max(targets);

    nfeatures=size(samples,2);
    gm=mean(samples,1); % grand mean

    sst=zeros(1,nfeatures);
    ssw=zeros(1,nfeatures);
    for k=1:nclasses
        xk=samples(k==targets,:);
        n=size(xk,1);

        if n==0
            ssw(:)=NaN;
            break;
        end

        mu=sum(xk,1)/n;
        sst=sst+n*(gm-mu).^2;
        ssw=ssw+sum(bsxfun(@minus,mu,xk).^2);
    end

    sss=zeros(1,nfeatures);
    for k=1:nchunks
        xk=samples(k==chunks,:);
        n=size(xk,1);
        mu=mean(xk,1);
        sss=sss+n*(gm-mu).^2;
    end

    df1=(nclasses-1);
    mst=sst/df1;

    df2=df1*(nchunks-1);
    sse=ssw-sss;
    mse=sse/df2;

    msk=mse>0;
    f=zeros(1,nfeatures)+NaN;
    f(msk)=mst(msk)./mse(msk);
    df=[df1 df2];

function [t,df]=quick_ttest(x)
    % one-sample t-test against zero

    [ns,nf]=size(x);
    mu=sum(x,1)/ns; % grand mean

    df=ns-1;
    scaling=ns*df;

    % sum of squares
    ss=sum(bsxfun(@minus,x,mu).^2,1);

    t=zeros(1,nf)+NaN;
    msk=ss>0;
    t(msk)=mu(msk).*sqrt(scaling./ss(msk));

function [t,df]=quick_ttest2(x,y)
    % two-sample t-test with equal variance assumption

    [nx,nf]=size(x);
    ny=size(y,1);

    df=nx+ny-2;
    if nx==0 || ny==0
        t=zeros(1,nf)+NaN;
        return;
    end

    mux=sum(x,1)/nx; % mean of class x
    muy=sum(y,1)/ny; % "           " y

    scaling=(nx*ny)*df/(nx+ny);

    % sum of squares
    ss=sum([bsxfun(@minus,x,mux);bsxfun(@minus,y,muy)].^2,1);

    t=zeros(1,nf)+NaN;
    msk=ss>0;
    t(msk)=(mux(msk)-muy(msk)) .* sqrt(scaling./ss(msk));

function ensure_has_stats_functions()
    % - Octave has the required functionality in the octave-forge
    %   statistics toolbox and will raise an error if it is not installed.
    % - Matlab will raise an error message that the statistics toolbox is
    %   required
    persistent cached_has_stat_funcs;

    if isequal(cached_has_stat_funcs,[])
        if cosmo_wtf('is_matlab') ...
                    && isempty(which('tinv')) ...
                    && isempty(which('fcdf'))
            raise_exception_if_absent=true;
            cached_has_stat_funcs=cosmo_check_external('@stats', ...
                                raise_exception_if_absent);
        else
            cached_has_stat_funcs=false;
        end
    end

function [samples,targets,chunks,type]=get_descriptors(ds)
    cosmo_isfield(ds,{'samples','sa.chunks','sa.targets'},true);

    samples=ds.samples;

    % unique targets
    [unused,unusued,targets]=unique(ds.sa.targets);

    % unique chunks
    [unq_chunks,unusued,chunks]=unique(ds.sa.chunks);
    nc=max(chunks);

    if isequal(sort(ds.sa.chunks),unq_chunks)
        type='between';
    else
        combis=(targets-1)*nc+chunks;
        if isequal(sort(combis),(1:numel(combis))')
            type='within';
        else
            error(['Either all chunks must be unique, or each chunk '...
                        'must contain the same targets']);
        end
    end

function delta=pairwise_differences(samples,targets,chunks)
    % for one-sample t-test: compute differences between first and second
    % target
    n=size(samples,1);
    assert(numel(targets)==n);
    assert(numel(chunks)==n);

    assert(mod(n,2)==0);
    n2=n/2;

    idxs=zeros(n2,2);
    for k=1:n
        assert(idxs(chunks(k),targets(k))==0);
        idxs(chunks(k),targets(k))=k;
    end
    assert(isequal(size(idxs),[n2,2]));
    assert(all(idxs(:)>0));

    delta=samples(idxs(:,1),:)-samples(idxs(:,2),:);

function [output_stat_name,tail]=get_stat_definition(stat_name,...
                                                    output_stat_name)
    if any(cosmo_match({'left','right','both'},output_stat_name))
        tail=output_stat_name;
        output_stat_name='p';
    elseif strcmp(output_stat_name,'p')
        switch stat_name
            case 'F'
                tail='right'; % show anova1  behaviour w.r.t. p-values
            otherwise
                tail='both'; % show ttest[2] "                       "
        end
    else
        tail='both';
    end


function a = moler1_inverse ( alpha, n )

%*****************************************************************************80
%
%% MOLER1_INVERSE returns the inverse of the MOLER1 matrix.
%
%  Formula:
%
%    if ( I = J )
%      A(I,J) =              min ( N-I, N-J ) * ALPHA^2 + 1
%    else
%      A(I,J) = (-1)^(I+J) * min ( N-I, N-J ) * ALPHA^2 + ALPHA
%
%  Example:
%
%    ALPHA = 2, N = 5
%
%     17 -14  10 -6  2
%    -14  13 -10  6 -2
%     10 -10   9 -6  2
%     -6   6  -6  5 -2
%      2  -2   2 -2  1
%
%  Properties:
%
%    The matrix is symmetric.
%
%    Successive elements of each diagonal decrease by ALPHA**2.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    29 October 2007
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, real ALPHA, the scalar that defines the inverse
%    Moler matrix.
%
%    Input, integer N, the order of A.
%
%    Output, real A(N,N), the matrix.
%
  a = zeros ( n, n );

  v = zeros ( n, 1 );
  v(1) = 1.0;
  v(2) = - alpha;
  for i = 3 : n
    v(i) = - ( alpha - 1.0 ) * v(i-1);
  end

  for i = 1 : n
    for j = 1 : n
      if ( i <= j )
        a(i,j) = v(1+j-i:n+1-i)' * v(1    :n+1-j);
      else
        a(i,j) = v(1    :n+1-i)' * v(1+i-j:n+1-j);
      end
    end
  end

  return
end


% Sample Code to test the Tensor Completion program :

clear;

n1 = 50;
n2 = 50;
n3 = 50;
r = 5;
tol   = [];
nitr  = [];
ninit = [];

% generate random low-rank orthogonal tensor
U01 = randn(n1,r);U02 = randn(n2,r);U03 = randn(n3,r);
[U1 temp] = qr(U01);[U2 temp] = qr(U02);[U3 temp] = qr(U03);
U1=U1(:,1:r);U2=U2(:,1:r);U3=U3(:,1:r);
T = zeros(n1,n2,n3);
for i=1:n3
    T(:,:,i) = U1*diag(U3(i,:))*U2';
end

% sample entries
p = 2*(r^0.5*log(n1*n2*n3))/sqrt(n1*n2*n3);
E = ceil(rand(n1,n2,n3)-1+p);
TE = T.*E;

% exact tensor completion
fprintf(1,'exact tensor completion using alternating minimization\n');
[V1 V2 V3 S dist] = TenALS(TE, E, r, ninit, nitr, tol);
rmse=0;
for i3=1:n3
   A1 = U1;
   A2 = U2*diag(U3(i3,:));
   B1 = V1;
   B2 = V2*diag(V3(i3,:).*S(:)');
   rmse = rmse + trace(A1'*A1*A2'*A2) + trace(B1'*B1*B2'*B2) -2*trace(B1'*A1*A2'*B2) ;
end
fprintf(1,'root mean squared error = %e\n',sqrt(rmse/r));

% noisy tensor completion
fprintf(1,'\nnoisy tensor completion using alternating minimization\n');
[V1 V2 V3 S dist] = TenALS(TE+(0.0001/sqrt(n1*n2*n3)*randn(n1,n2,n3).*E), E, r, ninit, nitr, tol);
rmse=0;
for i3=1:n3
   A1 = U1;
   A2 = U2*diag(U3(i3,:));
   B1 = V1;
   B2 = V2*diag(V3(i3,:).*S(:)');
   rmse = rmse + trace(A1'*A1*A2'*A2) + trace(B1'*B1*B2'*B2) -2*trace(B1'*A1*A2'*B2) ;
end
fprintf(1,'root mean squared error = %e\n',sqrt(rmse/r));


function M0 = matching_ind_und(CIJ)
%MATCHING_IND_UND       matching index
%
%   M0 = MATCHING_IND_UND(CIJ) computes matching index for undirected
%   graph specified by adjacency matrix CIJ. Matching index is a measure of
%   similarity between two nodes' connectivity profiles (excluding their
%   mutual connection, should it exist).
%
%   Inputs:     CIJ,    undirected adjacency matrix
%
%   Outputs:    M0,     matching index matrix.
%
%   Richard Betzel, Indiana University, 2013
%
CIJ0 = CIJ;
K = sum(CIJ0);
R = K ~= 0;
N = sum(R);
CIJ = CIJ0(R,R);
I = ~eye(N);
M = zeros(N,N);
for i = 1:N

    c1 = CIJ(i,:);
    use = bsxfun(@or,c1,CIJ);
    use(:,i) = 0;
    use = use.*I;

    ncon1 = bsxfun(@times,use,c1);
    ncon2 = bsxfun(@times,use,CIJ);
    ncon = sum(ncon1 + ncon2,2);

    M(:,i) = 2*sum(ncon1 & ncon2,2)./ncon;

end
M = M.*I;
M(isnan(M)) = 0;
M0 = zeros(size(CIJ0));
M0(R,R) = M;


function x = r8pbu_sl ( n, mu, a_lu, b )

%*****************************************************************************80
%
%% R8PBU_SL solves a R8PBU system factored by R8PBU_FA.
%
%  Discussion:
%
%    The R8PBU storage format is for a symmetric positive definite band matrix.
%
%    To save storage, only the diagonal and upper triangle of A is stored,
%    in a compact diagonal format that preserves columns.
%
%    The diagonal is stored in row MU+1 of the array.
%    The first superdiagonal in row MU, columns 2 through N.
%    The second superdiagonal in row MU-1, columns 3 through N.
%    The MU-th superdiagonal in row 1, columns MU+1 through N.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    28 March 2004
%
%  Author:
%
%    MATLAB version by John Burkardt.
%
%  Reference:
%
%    Dongarra, Bunch, Moler, Stewart,
%    LINPACK User's Guide,
%    SIAM, Philadelphia, 1979.
%
%  Parameters:
%
%    Input, integer N, the order of the matrix.
%    N must be positive.
%
%    Input, integer MU, the number of superdiagonals of the matrix.
%    MU must be at least 0 and no more than N-1.
%
%    Input, real A_LU(MU+1,N), the matrix, as factored by R8PBU_FA.
%
%    Input, real B(N), the right hand side of the linear system.
%
%    Output, real X(N), the solution vector.
%
  x(1:n) = b(1:n);
%
%  Solve L * Y = B.
%
  for k = 1 : n
    ilo = max ( 1, k - mu );
    x(k) = ( x(k) - x(ilo:k-1) * a_lu(mu+1+ilo-k:mu,k)  ) ...
      / a_lu(mu+1,k);
  end
%
%  Solve U * X = Y.
%
  for k = n : -1 : 1

    x(k) = x(k) / a_lu(mu+1,k);

    ilo = max ( 1, k - mu );
    for i = ilo : k-1
      x(i) = x(i) - x(k) * a_lu(mu+1+i-k,k);
    end

  end

  return
end


function [ o, x, w ] = cn_jac_02_xiu ( n, alpha, beta )

%*****************************************************************************80
%
%% CN_JAC_02_XIU implements the Xiu rule for region CN_JAC.
%
%  Discussion:
%
%    The rule has order
%
%      O = N + 1.
%
%    The rule has precision P = 2.
%
%    CN is the cube [-1,+1]^N with the Jacobi (beta) weight function
%
%      w(alpha,beta;x) = product ( 1 <= i <= n ) (1-x(i))^beta (1+x(i))^alpha.
%
%    with -1 < alpha, -1 < beta.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    07 March 2010
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Dongbin Xiu,
%    Numerical integration formulas of degree two,
%    Applied Numerical Mathematics,
%    Volume 58, 2008, pages 1515-1520.
%
%  Parameters:
%
%    Input, integer N, the spatial dimension.
%
%    Input, real ALPHA, BETA, the parameters.
%    -1.0 < ALPHA, -1.0 < BETA.
%
%    Output, integer O, the order.
%
%    Output, real X(N,O), the abscissas.
%
%    Output, real W(O), the weights.
%
  if ( alpha <= -1.0 )
    fprint ( 1, '\n' );
    fprint ( 1, 'CN_JAC_02_XIU - Fatal error!\n' );
    fprint ( 1, '  ALPHA <= -1.0\n' );
    error ( 'CN_JAC_02_XIU - Fatal error!' );
  end

  if ( beta <= -1.0 )
    fprint ( 1, '\n' );
    fprint ( 1, 'CN_JAC_02_XIU - Fatal error!\n' );
    fprint ( 1, '  BETA <= -1.0\n' );
    error ( 'CN_JAC_02_XIU - Fatal error!' );
  end

  o = n + 1;

  x = zeros ( n, o );
  w = zeros ( o, 1 );

  for j = 1 : o

    i = 0;
    for r = 1 : floor ( n / 2 )
      arg = 2 * r * ( j - 1 ) * pi / ( n + 1 );
      i = i + 1;
      x(i,j) = sqrt ( 2.0 ) * cos ( arg );
      i = i + 1;
      x(i,j) = sqrt ( 2.0 ) * sin ( arg );
    end

    if ( i < n )
      i = i + 1;
      x(i,j) = r8_mop ( j - 1 );
    end

  end

  gamma0 = ( alpha + beta + 2.0 ) / 2.0;
  delta0 = ( alpha - beta ) / 2.0;
  c1 = 2.0 * ( alpha + 1.0 ) * ( beta + 1.0 ) / ( alpha + beta + 3.0 ) ...
    / ( alpha + beta + 2.0 );

  x(1:n,1:o) = ( sqrt ( gamma0 * c1 ) * x(1:n,1:o) - delta0 ) / gamma0;

  expon = 0;
  volume_1d = c1_jac_monomial_integral ( alpha, beta, expon );
  volume = volume_1d ^ n;

  w(1:o) = volume / o;

  return
end


function exact = p37_exact ( )

%*****************************************************************************80
%
%% P37_EXACT returns the exact integral for problem 37.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    04 November 2009
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, real EXACT, the value of the integral.
%
  alpha = p37_param_get ( );

  exact = atan ( ( 4.0 - pi ) * 4.0^( alpha - 1.0 ) ) ...
        + atan (         pi   * 4.0^( alpha - 1.0 ) );

  return
end


function inds = graphPeripheralVertices(v, e, l)
%GRAPHPERIPHERALVERTICES Peripheral vertices of a graph
%
%   INDS = graphPeripheralVertices(V, E)
%   Return indices of peripheral vertices, that is, vertices whose
%   eccentricity is maximal and equal to the diameter of the graph.
%
%   INDS = graphPeripheralVertices(V, E, L)
%   Specify length of each edge. Default is 1 for each edge.
%
%
%   Example
%     nodes = [20 20;20 50;20 80;50 50;80 20;80 50;80 80];
%     edges = [1 2;2 3;2 4;4 6;5 6;6 7];
%     figure; drawGraph(nodes, edges);
%     axis([0 100 0 100]); axis equal; hold on
%     INDP = graphPeripheralVertices(nodes, edges);
%     INDP =
%         1
%         3
%         5
%         7
%
%
%   See Also
%   grPropagateDistance, grVertexEccentricity
%   graphCenter, graphDiameter, graphRadius
%
% ------
% Author: David Legland
% e-mail: david.legland@grignon.inra.fr
% Created: 2010-09-07,    using Matlab 7.9.0.529 (R2009b)
% Copyright 2010 INRA - Cepia Software Platform.

% ensure there is a valid length array
if nargin<3
    l = ones(size(e,1), 1);
end

g = grVertexEccentricity(v, e, l);

inds = find(g==max(g));


% Copyright (C) 1993-2017, by Peter I. Corke
%
% This file is part of The Robotics Toolbox for MATLAB (RTB).
%
% RTB is free software: you can redistribute it and/or modify
% it under the terms of the GNU Lesser General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% RTB 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 Lesser General Public License for more details.
%
% You should have received a copy of the GNU Leser General Public License
% along with RTB.  If not, see <http://www.gnu.org/licenses/>.
%
% http://www.petercorke.com

%%begin

% In the field of robotics there are many possible ways of representing
% orientations of which the most common are:
% - orthonormal rotation matrices (3x3),
% - three angles (1x3), and
% - quaternions.

% A rotation of pi/2 about the x-axis can be represented as an orthonormal rotation
% matrix

R = rotx(pi/2)
% which we can see is a 3x3 matrix.

% Such a matrix has the property that it's columns (and rows) are sets of orthogonal
% unit vectors.  The determinant of such a matrix is always 1

det(R)

% Let's create a more complex rotation

R = rotx(30, 'deg') * roty(50, 'deg') * rotz(10, 'deg')
% where this time we have specified the rotation angle in degrees.

% Any rotation can be expressed in terms of a single rotation about some axis
% in space

[theta,vec] = tr2angvec(R)
% where theta is the angle (in radians) and vec is unit vector representing the
% direction of the rotation axis.

% Commonly rotations are represented by Euler angles

eul = tr2eul(R)
% which are three angles such that R = rotz(a)*roty(b)*rotz(c), ie. the rotations
% required about the Z, then then the Y, then the Z axis.

% Rotations are also commonly represented by roll-pitch-yaw  angles

rpy = tr2rpy(R)
% which are three angles such that R = rotx(r)*roty(p)*rotz(y), ie. the rotations
% required about the X, then then the Y, then the Z axis.

% We can investigate the effects of rotations about different axes
% using this GUI based demonstration.  The menu buttons allow the rotation
% axes to be varied
%  *** close the window when you are done.
tripleangle('rpy', 'wait')

% The final useful form is the quaternion which comprises 4 numbers.  We can create
% a quaternion from an orthonormal matrix

q = Quaternion(R)
% where we can see that it comprises a scalar part and a vector part.  To convert back

q.R
% which is the same of the value of R we determined above.

% Quaternions are a class and the orientations they represent can be compounded, just
% as we do with rotation matrices by multiplication.

% First we create two quaternions

q1 = Quaternion( rotx(pi/2) )
q2 = Quaternion( roty(pi/2) )

% then the rotation of q1 followed by q2 is simply

q1 * q2

% We can also take the inverse of a Quaternion

q1 * inv(q1)
% which results in a null rotation (zero vector part)


function c = he_polynomial_coefficients ( n )

%*****************************************************************************80
%
%% HE_POLYNOMIAL_COEFFICIENTS: coefficients of He(i,x).
%
%  Discussion:
%
%    He(i,x) represents the probabilist's Hermite polynomial.
%
%  First terms:
%
%    N/K     0     1      2      3       4     5      6    7      8    9   10
%
%     0      1
%     1      0     1
%     2     -1     0      1
%     3      0    -3      0      1
%     4      3     0     -6      0       1
%     5      0    15      0    -10       0     1
%     6    -15     0     45      0     -15     0      1
%     7      0  -105      0    105       0   -21      0     1
%     8    105     0   -420      0     210     0    -28     0      1
%     9      0   945      0  -1260       0   378      0   -36      0   1
%    10   -945     0   4725      0   -3150     0    630     0    -45   0    1
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    07 March 2012
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Milton Abramowitz and Irene Stegun,
%    Handbook of Mathematical Functions,
%    US Department of Commerce, 1964.
%
%  Parameters:
%
%    Input, integer N, the highest order polynomial to compute.
%    Note that polynomials 0 through N will be computed.
%
%    Output, real C(1:N+1,1:N+1), the coefficients of the Hermite polynomials.
%
  if ( n < 0 )
    c = [];
    return
  end

  c(1:n+1,1:n+1) = 0.0;

  c(1,1) = 1.0;

  if ( n == 0 )
    return
  end

  c(2,2) = 1.0;

  for i = 2 : n
    c(i+1,1)     =                             - ( i - 1 ) * c(i-1,1);
    c(i+1,2:i-1) =                c(i  ,1:i-2) - ( i - 1 ) * c(i-1,2:i-1);
    c(i+1,  i  ) =                c(i  ,  i-1);
    c(i+1,  i+1) =                c(i  ,  i  );
  end

  return
end


% Vm = vsh_modified_in_fast(theta,phi,l,m,p0)
%
% Vector spherical harmonic funtion modified from Hill's function
% V_lm for quantum numbers l and m. Angles theta and phi should be
% given in radians. p0 contains the values of the Legendre polynomial.
%
function Vm = vsh_modified_in_fast(theta,phi,l,m,p0)

% Copyright (c) 2016, Elekta Oy
% ---------------------------------------
%
% Redistribution and use of the Software in source and binary forms, with or without
% modification, are permitted for non-commercial use.
%
% The Software is provided "as is" without warranties of any kind, either express or
% implied including, without limitation, warranties that the Software is free of defects,
% merchantable, fit for a particular purpose. Developer/user agrees to bear the entire risk
% in connection with its use and distribution of any and all parts of the Software under this license.
%

scale = 1;

%scale_sph = (-1)^m*sqrt((2*l+1)*prod(1:(l-m))/(4*pi*prod(1:(l+m))));
%scale_minus = 1/((-1)^(m-1)*sqrt((2*l+1)*prod(1:(l-(m-1)))/(4*pi*prod(1:(l+(m-1))))));
%scale_plus = 1/((-1)^(m+1)*sqrt((2*l+1)*prod(1:(l-(m+1)))/(4*pi*prod(1:(l+(m+1))))));

Y = spharm_fast(theta,phi,l,m,p0);
if m > -l
  Yminus = spharm_fast(theta,phi,l,m-1,p0);
else
  Yminus = 0;
end
if m < l
  Yplus = spharm_fast(theta,phi,l,m+1,p0);
else
  Yplus = 0;
end

cosp = cos(phi); sinp = sin(phi);
%dY = 0.5*scale_sph*((l+m)*(l-m+1)*scale_minus*Yminus*complex(cos(phi),sin(phi))-scale_plus*Yplus*complex(cos(-phi),sin(-phi)));  % dY/dtheta
%dY = 0.5*(-sqrt((l+m)*(l-m+1))*Yminus*complex(cos(phi),sin(phi))+sqrt((l-m)*(l+m+1))*Yplus*complex(cos(-phi),sin(-phi)));
dY = 0.5*(-sqrt((l+m)*(l-m+1))*Yminus*complex(cosp,sinp)+sqrt((l-m)*(l+m+1))*Yplus*complex(cosp,-sinp));
if theta == 0 % To prevent division by zero
  theta = eps;
end
Vm(1) = scale*(-(l+1))*Y;
Vm(2) = scale*dY;
Vm(3) = scale*(i*m/sin(theta))*Y;


function  [a,resnorm]=Optimize_my_LM2(Loss_fun,a0,data,TolX,TolFun,MaxIter)

% author  Zhang Xin

tao=1e-10;
xk=a0;

v=2;

Jacobi=Get_Jacobi(Loss_fun,xk,data);
Ek=Loss_fun(xk,data);

g=Jacobi'*Ek;

found=logical(norm(g)<=TolFun);
mou=tao*max(diag(Jacobi'*Jacobi));

k=0;
while (~found && k<MaxIter+1)

    %delta_x=-(Jacobi'*Jacobi+mou*eye(size(a0,2)))\Jacobi'*Ek;

    delta_x=-[Jacobi;sqrt(mou)*eye(size(a0,2))]\[Ek;zeros(size(a0,2),1)];

    if (norm(delta_x)<=TolX*(norm(xk)+TolX))
        found=true;

    else
        xk_new=xk+delta_x';
        Ek=Loss_fun(xk,data);
        Ek_new=Loss_fun(xk_new,data);
        L0=delta_x'*Jacobi'*Ek;
        L_delta=delta_x'*Jacobi'*Jacobi*delta_x;
        rho=(Ek'*Ek-Ek_new'*Ek_new)/(-L0-L_delta);

        if rho>0

            fprintf('Iterations: %d, Residual: %d, Step: %d \n',k,Ek'*Ek,norm(delta_x));
            k=k+1;

            xk=xk_new;
            Jacobi=Get_Jacobi(Loss_fun,xk,data);
            Ek=Loss_fun(xk,data);
            g=Jacobi'*Ek;
            found=(norm(g)<=TolFun);
            mou=mou*max([1/3,1-(2*rho-1)^3]);
            v=2;
        else
            mou=mou*v;
            v=2*v;

        end

    end

end

xk=xk+delta_x';
Ek=Loss_fun(xk,data);
fprintf('Iterations: %d, Residual: %d, Step: %d \n',k,Ek'*Ek,norm(delta_x));

a=xk;

resnorm=Ek'*Ek;

end

function Jacobi=Get_Jacobi(Loss_fun,xk,data)

scale=1e-4;

%Ek=Loss_fun(xk,data);

for i=1:length(xk)
    x_temp1=xk;
    x_temp2=xk;
    if abs(x_temp1(i))>scale

        delta=x_temp1(i)*scale;
    else
        delta=scale;
    end
    x_temp1(i)=x_temp1(i)+delta;
    x_temp2(i)=x_temp2(i)-delta;

    E_temp1=Loss_fun(x_temp1,data);

    E_temp2=Loss_fun(x_temp2,data);

    Jacobi(:,i)=(E_temp1-E_temp2)/delta/2;

end

end


function p = predict(theta, X)
%PREDICT Predict whether the label is 0 or 1 using learned logistic
%regression parameters theta
%   p = PREDICT(theta, X) computes the predictions for X using a
%   threshold at 0.5 (i.e., if sigmoid(theta'*x) >= 0.5, predict 1)

m = size(X, 1); % Number of training examples

% You need to return the following variables correctly
p = zeros(m, 1);

% ====================== YOUR CODE HERE ======================
% Instructions: Complete the following code to make predictions using
%               your learned logistic regression parameters.
%               You should set p to a vector of 0's and 1's
%
temp= sigmoid( X*theta);
for i=1:m
    if temp(i) >=0.5
    p(i)=1;
    else
    p(i)=0;
    end

end

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

end


function point_num = sphere_llt_point_num ( lat_num, long_num )

%*****************************************************************************80
%
%% SPHERE_LLT_POINT_NUM counts points for an LLT grid on a sphere in 3D.
%
%  Discussion:
%
%    An LLT grid is a grid of triangles defined by latitude and longitude
%    lines over the surface of a sphere in 3D.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    29 April 2015
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer LAT_NUM, LONG_NUM, the number of latitude
%    and longitude lines to draw.  The latitudes do not include the North and
%    South poles, which will be included automatically, so LAT_NUM = 5, for
%    instance, will result in points along 7 lines of latitude.
%
%    Output, integer POINT_NUM, the number of grid points.
%
  point_num = 2 + lat_num * long_num;

  return
end


function [d] = spm_kl_normal (m_q,c_q,m_p,c_p)
% KL divergence between two multivariate normal densities
% FORMAT [d] = spm_kl_normal (m_q,c_q,m_p,c_p)
%
% KL (Q||P) = <log Q/P> where avg is wrt Q
%
% between two Normal densities Q and P
%
% m_q, c_q    Mean and covariance of first Normal density
% m_p, c_p    Mean and covariance of second Normal density
%___________________________________________________________________________
% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging

% Will Penny
% $Id: spm_kl_normal.m 2696 2009-02-05 20:29:48Z guillaume $

d=length(m_q);
m_q=m_q(:);
m_p=m_p(:);

Term1=0.5*spm_logdet(c_p)-0.5*spm_logdet(c_q);

inv_c_p=inv(c_p);
Term2=0.5*trace(inv_c_p*c_q)+0.5*(m_q-m_p)'*inv_c_p*(m_q-m_p);

d=Term1+Term2-0.5*d;


function x = r8mat_utsol ( n, r, b )

%*****************************************************************************80
%
%% R8MAT_UTSOL solves R' * X = B for an upper triangular matrix R.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    25 June 2013
%
%  Author:
%
%    MATLAB version by John Burkardt.
%
%  Reference:
%
%    Jack Dongarra, Jim Bunch, Cleve Moler, Pete Stewart,
%    LINPACK User's Guide,
%    SIAM, 1979,
%    ISBN13: 978-0-898711-72-1,
%    LC: QA214.L56.
%
%  Parameters:
%
%    Input, integer N, the order of the matrix.
%
%    Input, real R(N,N), the upper triangular matrix.
%
%    Input, real B(N), the right hand side.
%
%    Output, real X(N), the solution.
%
  x(1:n,1) = b(1:n);

  x(1,1) = x(1,1) / r(1,1);

  for j = 2 : n
    x(j,1) = ( x(j,1) - r(1:j-1,j)' * x(1:j-1,1) ) / r(j,j);
  end

  return
end


function [rs, eigvals, eigvecs] = pca(s, mode, maxpercent)

%tstoolbox/@signal/pca
%   Syntax:
%     * [rs, eigvals, eigvecs] = pca(s) => mode='normalized' , maxpercent
%       = 95
%     * [rs, eigvals, eigvecs] = pca(s, mode) => maxpercent = 95
%     * [rs, eigvals, eigvecs] = pca(s, mode, maxpercent)
%
%   Input arguments:
%     * each row of data is one 'observation', e.g. the sample values of
%       all channels in a multichannel measurement at one point in time
%     * mode can be one of the following : 'normalized' (default), 'mean',
%       'raw'
%          + in mode 'normalized' each column of data is centered by
%            removing its mean and then normalized by dividing through its
%            standard deviation before the covariance matrix is calculated
%          + in mode 'mean' only the mean of every column of data is
%            removed
%          + in mode 'raw' no preprocessing is applied to data
%     * maxpercent gives the limit of the accumulated percentage of the
%       resulting eigenvalues, default is 95 %
%
%   Principal component analysis of column orientated data set.
%
% Copyright 1997-2001 DPI Goettingen, License http://www.physik3.gwdg.de/tstool/gpl.txt

%
%   principal component analysis of column orientated data set <data>
%
%   input arguments :
%
%   - each row of data is one 'observation', e.g. the sample values of
%     all channels in a multichannel measurement at one point in time
%
%   - mode can be one of the following : 'normalized' (default), 'mean', 'raw'
%     - in mode 'normalized' each column of data is centered by removing its mean
%       and then normalized by dividing through its standard deviation before
%       the covariance matrix is calculated
%     - in mode 'mean' only the mean of every column of data is removed
%     - in mode 'raw' no preprocessing is applied to data
%
%   - maxpercent gives the limit of the accumulated percentage of the resulting
%     eigenvalues, default is 95 %
%
% [rs, eigvals, eigvecs] = pca(s)       => mode='normalized' , maxpercent = 95
% [rs, eigvals, eigvecs] = pca(s, mode)                     => maxpercent = 95
% [rs, eigvals, eigvecs] = pca(s, mode, maxpercent)
%
% C.Merkwirth,U.Parlitz,W.Lauterborn  DPI Goettingen 1998

narginchk(1,3);

if nargin < 2
	mode = 'normalized';
end
if nargin < 3
	maxpercent = 95;
end

if ndim(s)~=2
	error('pca needs a signal with two dimensions as input')
end

dat = data(s);
n = dlens(s,1);
m = dlens(s,2);

htext = {''};
htext{end+1} = 'Applied Karhunen-Loeve Transform (pca)';
htext{end+1} = ['Tried to capture ' num2str(maxpercent) ' percent of total variance'];

mpercent = maxpercent/100;
mode = lower(mode); 		% no problems with uppercase letters

if strncmp(mode, 'r',1)
	mode = 'raw';
	htext{end+1} = 'No data preprocessing';
elseif strncmp(mode, 'm',1)
	mode = 'mean';
	htext{end+1} = 'Removed mean from data set';
	mn = mean(dat);
	dat = dat - repmat(mn, n, 1);
else
	mode = 'normalized';
	htext{end+1} = 'Removed mean and normalized data';
	mn = mean(dat);
	dv = std(dat);
	dat = dat - repmat(mn, n, 1);
	dat = dat ./ repmat(dv, n, 1);
end

if n>m
	htext{end+1} = 'Used direct method to compute covariance matrix';
	K =   dat' * dat;       % oder K = corrcoef(dat)
	[Q,D] = eig(K);
 else
    htext{end+1} = 'using indirect method to compute covariance matrix';
 	C = dat * dat';
 	[Q,D] = eig(C);
end

[evalues,index] = sort(diag(D));
evalues = flipud(evalues);
index = flipud(index);

total = sum(evalues);
rlvm = min(find(cumsum(evalues) >= (total*mpercent)));

if isempty(rlvm)			% in case percentage was choosen over 100 %,
	rlvm = length(evalues); % return all eigenvalues
end

frvals = evalues(1:rlvm);

if n>m
	frvecs = Q(:, index(1:rlvm));
	trnsfrmd=dat*frvecs;
else
 	scalefac = 1./ sqrt(evalues(1:rlvm));
 	for i = 1:rlvm
 		P(:,i) = Q(:,index(i)) * scalefac(i);
 	end
 	frvecs = dat' * P; % '
	trnsfrmd=C*P;
end

a = achse(unit, 1,1);
a = setname(a, 'Mode');

rs = signal(core(trnsfrmd), s);
rs = addhistory(rs, htext);
rs = addcommandlines(rs, 's = pca(s', mode, maxpercent);
rs = setaxis(rs, 2, a);
%rs = settype(rs, 'Transformed data set');
rs = setplothint(rs, 'multigraph');

eigvals = signal(core(frvals),s);
eigvals = addhistory(eigvals, htext);
eigvals = addcommandlines(eigvals, '[dummy, s] = pca(s', mode, maxpercent);
eigvals = setaxis(eigvals, 1, a);
%eigvals = settype(eigvals, 'Eigenvalues');
eigvals = setplothint(eigvals, 'bar');

eigvecs = signal(core(frvecs),s);
eigvecs = addhistory(eigvecs, htext);
eigvecs = addcommandlines(eigvecs, '[dummy, dummy2, s] = pca(s', mode, maxpercent);
eigvecs = setaxis(eigvecs, 2, a);
eigvecs = setaxis(eigvecs, 1, getaxis(s,2));
%eigvecs = settype(eigvecs, 'Eigenvectors');


function [G]=erdosRenyi(nv,p,Kreg)
%Funciton [G]=edosRenyi(nv,p,Kreg) generates a random graph based on
%the Erdos and Renyi algoritm where all possible pairs of 'nv' nodes are
%connected with probability 'p'.
%
% Inputs:
%   nv - number of nodes
%   p  - rewiring probability
%   Kreg - initial node degree of for regular graph (use 1 or even numbers)
%
% Output:
%   G is a structure inplemented as data structure in this as well as other
%   graph theory algorithms.
%   G.Adj   - is the adjacency matrix (1 for connected nodes, 0 otherwise).
%   G.x and G.y -   are row vectors of size nv wiht the (x,y) coordinates of
%                   each node of G.
%   G.nv    - number of vertices in G
%   G.ne    - number of edges in G
%
%Created by Pablo Blinder. blinderp@bgu.ac.il
%
%Last update 25/01/2005

%build regular lattice
A=sparse(nv,nv);
Kreg=fix(abs(Kreg)/2);Kreg=(Kreg<1)+Kreg;

for k=1:Kreg
    A=sparse(A+diag(ones(1,length(diag(A,k))),k)+diag(ones(1,length(diag(A,nv-k))),nv-k));
end
ne0=nnz(A);
%find connected pairs
[v1,v2]=find(A);
% P=permPairs(nv);%my version is faster
Dis=(rand(length(v1),1)<=p);%pairs to disconnect
A(v1(Dis),v2(Dis))=0;
vDis=unique([v1(Dis),v2(Dis)]);%disconnected vertices
nDis=ne0-nnz(A);sum(Dis);

%cycle trough disconnected pairs
disconPairs=[v1(Dis),v2(Dis)];
for n=1:nDis
    %choose one of the vertices from the disconnected pair
    i=ceil(rand*size(disconPairs,1));
    j=logical(1+rand>0.5);
    vDisToRec=disconPairs(i,j);
    %find non adjacent vertices and reconnect
    adj=[find(A(:,vDisToRec)) ; find(A(vDisToRec,:))'];
    nonAdj=setdiff(1:nv,adj);
    vToRec=nonAdj(ceil(rand*length(nonAdj)));
    S=sort([vDisToRec vToRec]);
    A(S(1),S(2))=1;
end
[x,y]=getNodeCoordinates(nv);
%make adjacency matrix symetric
A=A+fliplr((flipud(triu(A))));
G=struct('Adj',A,'x',x','y',y','nv',nv,'ne',nnz(A));


% Filename: ora_foc.m
% Oustaloup-Recursive-Approximation for fractional order differentiator
% Reference
% [1] Oustaloup, A.; Levron, F.; Mathieu, B.; Nanot, F.M.; "Frequency-band
%     complex noninteger differentiator: characterization and synthesis".
%     EEE Transactions on Circuits and Systems I: Fundamental Theory and
%     Applications, I , Volume: 47 Issue: 1, Jan. 2000, Page(s): 25 -39
% [2] D. Xue, Y.Q. Chen and D. Atherton. "Linear feedback control -
%     analysis and design with Matlab 6.5". Textbook draft. Chapter 9
%     "Fractional order control - An introduction". PDF available upon
%     request. Send request email to "yqchen@ieee.org".
% by YangQuan Chen. Nov. 2001.
% Utah State University. http://www.csois.usu.edu/people/yqchen/
% FOC web http://mechatronics.ece.usu.edu/foc/
%
% Input variables:
%       r: the fractional order as in s^r, r is a real number
%       N: order of the finite TF approximation for both (num/den)
%           (Note: 2N+1 recursive z-p pairs)
%       w_L: low frequency limit of the range of the frequency of interest
%       w_H: upper freq. limit of the range of the frequency of interest
% Output:
%       sys_foc: continuous time transfer function system object (TF)
% Sample values: w_L=0.1;w_H=1000;  r=0.5;  N=4;
% Existing problem: Be careful when doing "c2d", I met some problems.
function [sys_foc]=ora_foc(r,N,w_L,w_H)
w_L=w_L*0.1;w_H=w_H*10; % enlarge the freq. range of interest for goodness
mu=w_H/w_L;                %
w_u=sqrt(w_H*w_L);
alpha=(mu)^(r/(2*N+1));
eta=(mu)^((1-r)/(2*N+1));
k=-N:N;
w_kp=(mu).^( (k+N+0.5-0.5*r)/(2*N+1) )*w_L;
w_k=(mu).^( (k+N+0.5+0.5*r)/(2*N+1) )*w_L;
D_N_K=(w_u/w_H)^r * prod(w_k) / prod(w_kp);
D_N_P=-w_k;D_N_Z=-w_kp;
[num,den]=zp2tf(D_N_Z',D_N_P',D_N_K);
sys_foc=tf(num,den);