function [rs, rs2, rs3] = dimensions(s, bins)

%tstoolbox/@signal/dimensions
%   Syntax:
%     * [bc,in,co] = dimensions(s, bins)
%
%   Input arguments:
%     * s - data points (row vectors)
%     * bins - maximal number of partition per axis, default is 100
%
%   Output arguments:
%     * bc - scaling of boxes with partititon sizes (log[2]-log[2])
%     * in - scaling of information with partititon sizes (log[2]-log[2])
%     * co - scaling of correlation with partititon sizes (log[2]-log[2])
%
%   Compute boxcounting, information and correlation dimension of a
%   time-delay reconstructed timeseries s for dimensions from 1 to D,
%   where D is the dimension of the input vectors using boxcounting
%   approach.
%
%   Scale data to be within 0 and 1. Give a sortiment of (integer)
%   partitionsizes with almost exponential behaviour.
%
% Copyright 1997-2001 DPI Goettingen, License http://www.physik3.gwdg.de/tstool/gpl.txt

narginchk(1,2);

if ndim(s) ~= 2
    error('Signal must contain vector data');
end

if nargin<2
    bins = 100;
end

points = data(s);
[N,dim] = size(points);

% scale data to be within 0 and 1
points = points - min(min(points));
points = points / max(max(points));

% give a sortiment of (integer) partitionsizes with almost exponential behaviour
par = [2 3 4 5 6 7 8 10 12 14 16 20 23 27 32 39 46 54 64 77 91 108 128 153 182 216 256 ...
      305 363 431 512 609 725 862 1024 1218 1449 1723 2048 2436 2897 3445 4096 4871 ...
	  5793 6889 8192 9742 11586 13778 16384 19484 23171 27555 32768 38968 46341 55109 65536];

partitions = par(find(par<=bins));	% use no sizes greater than bins

[c,d,e] = boxcount(points, partitions);

c = [zeros(1,dim) ; c];             % add zeros for partition size 1
d = [zeros(1,dim) ; d];             % add zeros for partition size 1
e = [zeros(1,dim) ; e];             % add zeros for partition size 1
partitions = [1 ; partitions(:)];

a1 = achse(-log2(partitions));     		% create axis with arbitrary spacing
a1 = setname(a1, 'ld r');

a2 = setname(achse(unit, 1, 1), 'Embedding dimension');

rs = signal(core(c), s);
rs = setaxis(rs, 1, a1);
rs = setaxis(rs, 2, a2);
rs = setplothint(rs, 'multigraph');
rs = addhistory(rs,  ['Computed boxcounting dimension']);
rs = addcommandlines(rs, 's = boxdim(s', bins);
rs = setyname(rs, 'ld N(r)');
rs = setlabel(rs, 'Scaling of D0');

rs2 = signal(core(d), s);
rs2 = setaxis(rs2, 1, a1);
rs2 = setaxis(rs2, 2, a2);
rs2 = setplothint(rs2, 'multigraph');
rs2 = addhistory(rs2,  ['Computed information dimension']);
rs2 = addcommandlines(rs2, 's = infodim(s', bins);
rs2 = setyname(rs2, 'I(r)');
rs2 = setlabel(rs2, 'Scaling of D1');

rs3 = signal(core(e), s);
rs3 = setaxis(rs3, 1, a1);
rs3 = setaxis(rs3, 2, a2);
rs3 = setplothint(rs3, 'multigraph');
rs3 = addhistory(rs3,  ['Computed correlation dimension']);
rs3 = addcommandlines(rs3, 's = corrdim(s', bins);
rs3 = setyname(rs3, 'ld C(r)');
rs3 = setlabel(rs3, 'Scaling of D2');


function imgOut = KuangNormalizedGamma(img, gamma_value)
%
%
%       img = KuangNormalizedGamma(img, gamma_value)
%
%
%       Image is clamped if its values are over [a,b]
%
%       Input:
%           -img: the input img to be clamped.
%           -gamma_value: a gamma value to be applied to img.
%
%       Output:
%           -imgOut: an image with normalized gamma encoding.
%
%     Copyright (C) 2015  Francesco Banterle
%
%     This program is free software: you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation, either version 3 of the License, or
%     (at your option) any later version.
%
%     This program is distributed in the hope that it will be useful,
%     but WITHOUT ANY WARRANTY; without even the implied warranty of
%     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%     GNU General Public License for more details.
%
%     You should have received a copy of the GNU General Public License
%     along with this program.  If not, see <http://www.gnu.org/licenses/>.
%

if(~exist('gamma_value', 'var'))
    gamma_value = 1.0;
end

max_img = max(img(:));

imgOut = ((img / max_img).^gamma_value) * max_img;

end


function [feat boxes] = lbp_feature(im)

if(size(im,3) < 3)
    %black and white image
    im = cat(3, im, im, im); %make it a trivial color image
end
boxes = [1;1;size(im,1);size(im,2)];

[lbp_L0 lbp_L1 lbp_L2] = lbp_original_4x4(im);

feat.hists.L0 = lbp_L0;
feat.hists.L1 = lbp_L1;
feat.hists.L2 = lbp_L2;


function logplot(x_orig, logscale)
% Normal plot with layered logscale plot
%   logplot(x_orig, logscale)
%     x_orig    Plotted data
%     logscale  Optional 2-element vector representing plot range
%               for cropping logarithmic plot area

% Copyright (C) 2004, 2005 DSS MATLAB package team (dss@cis.hut.fi).
% Distributed by Laboratory of Computer and Information Science,
% Helsinki University of Technology. http://www.cis.hut.fi/projects/dss/.
% $Id$

if size(x_orig,1)==1
  x=x_orig';
else
  x=x_orig;
end

if size(x,1)==0; return; end
i=[1:size(x,1)];

x(x==0)=NaN;
y=log(x);
y(isinf(y))=NaN;

if nargin<2
  offset = min(x)-min(y);
  scale = (max(x)-min(x))/(max(y)-min(y));
else
  offset = logscale(1)-min(y);
  scale = (logscale(2)-logscale(1))/(max(y)-min(y));
end
plot(i, x, '-', i, (y-min(y))*scale+min(x), ':');


% plot_UWB_channel.m
clear, clf
no_output_files = 0;  % non-zero: avoids writing output files of continuous-time responses
Ts = 0.167;        % sampling time (nsec)
num_ch=100; % number of channel impulse responses to generate
randn('state',12);  % initialize state of function for repeatability
rand('state',12);   % initialize state of function for repeatability
cm = 1;  % channel model number from 1 to 4
% get channel model params based on this channel model number
[Lam,lam,Gam,gam,nlos,sdi,sdc,sdr] = UWB_parameters(cm);
fprintf(1,['Model Parameters\n' ' Lam= %.4f, lam= %.4f, Gam= %.4f, gam= %.4f\n NLOS flag= %d, std_shdw= %.4f, std_ln_1= %.4f, std_ln_2= %.4f\n'],...
 Lam,lam,Gam,gam,nlos,sdi,sdc,sdr);
% get a bunch of realizations (impulse responses)
[h_ct,t_ct,t0,np] = UWB_model_ct(Lam,lam,Gam,gam,num_ch,nlos,sdi,sdc,sdr);
% now reduce continuous-time result to a discrete-time result
[hN,N] = convert_UWB_ct(h_ct,t_ct,np,num_ch,Ts);
% if we wanted complex baseband model or to impose some filtering function,
% this would be a good place to do it
h = resample(hN,1,N);  % decimate the columns of hN by factor N
h = h*N;  % correct for 1/N scaling imposed by decimation
channel_energy = sum(abs(h).^2);  % channel energy
h_len = size(h,1);
t = [0:(h_len-1)]*Ts;  % for use in computing excess & RMS delays

for k=1:num_ch
  % determine excess delay and RMS delay
  sq_h = abs(h(:,k)).^2/channel_energy(k);
  t_norm = t - t0(k);  % remove the randomized arrival time of first cluster
  excess_delay(k) = t_norm*sq_h;
  rms_delay(k) = sqrt((t_norm-excess_delay(k)).^2*sq_h);
  % determine # of significant paths (paths within 10 dB from peak)
  threshold_dB = -10;   % dB
  temp_h = abs(h(:,k));
  temp_thresh = 10^(threshold_dB/20)*max(temp_h);
  num_sig_paths(k) = sum(temp_h>temp_thresh);
  % determine number of sig. paths (captures x % of energy in channel)
  x = 0.85;
  temp_sort = sort(temp_h.^2);  % sorted in ascending order of energy
  cum_energy = cumsum(temp_sort(end:-1:1));  % cumulative energy
  index_e = min(find(cum_energy >= x*cum_energy(end)));
  num_sig_e_paths(k) = index_e;
end
energy_mean = mean(10*log10(channel_energy));
energy_stddev = std(10*log10(channel_energy));
mean_excess_delay = mean(excess_delay);
mean_rms_delay = mean(rms_delay);
mean_sig_paths = mean(num_sig_paths);
mean_sig_e_paths = mean(num_sig_e_paths);

fprintf(1,'Model Characteristics\n');
fprintf(1,'  Mean delays: excess (tau_m) = %.1f ns, RMS (tau_rms) = %1.f\n', ...
    mean_excess_delay, mean_rms_delay);
fprintf(1,'  # paths: NP_10dB =  %.1f, NP_85%% = %.1f\n', ...
    mean_sig_paths, mean_sig_e_paths);
fprintf(1,'  Channel energy: mean = %.1f dB, std deviation = %.1f dB\n', ...
  energy_mean, energy_stddev);

subplot(421), plot(t,h), grid on
title('Impulse response realizations'), xlabel('Time (nS)')

subplot(422), plot([1:num_ch], excess_delay, 'b-', ...
  [1 num_ch], mean_excess_delay*[1 1], 'r--' );
grid on, title('Excess delay (nS)'), xlabel('Channel number')

subplot(423), plot([1:num_ch], rms_delay, 'b-', ...
  [1 num_ch], mean_rms_delay*[1 1], 'r--' );
grid on, title('RMS delay (nS)'), xlabel('Channel number')

subplot(424), plot([1:num_ch], num_sig_paths, 'b-', ...
  [1 num_ch], mean_sig_paths*[1 1], 'r--');
grid on, title('Number of significant paths within 10 dB of peak')
xlabel('Channel number')

subplot(427), plot([1:num_ch], num_sig_e_paths, 'b-', ...
  [1 num_ch], mean_sig_e_paths*[1 1], 'r--');
grid on, title('Number of significant paths capturing > 85% energy')
xlabel('Channel number')

temp_average_power = sum(h'.*(h)')/num_ch;
temp_average_power = temp_average_power/max(temp_average_power);
average_decay_profile_dB = 10*log10(temp_average_power);
subplot(425), plot(t,average_decay_profile_dB); grid on
axis([0 t(end) -60 0]), title('Average Power Decay Profile')
xlabel('Delay (nsec)'), ylabel('Average power (dB)')

subplot(426)
figh = plot([1:num_ch],10*log10(channel_energy),'b-', ...
  [1 num_ch], energy_mean*[1 1], 'g--', ...
  [1 num_ch], energy_mean+energy_stddev*[1 1], 'r:', ...
  [1 num_ch], energy_mean-energy_stddev*[1 1], 'r:');
xlabel('Channel number'), ylabel('dB'), title('Channel Energy');
legend(figh, 'Per-channel energy', 'Mean', '\pm Std. deviation', 0)

if no_output_files, return;  end
%%% save continuous-time (time,value) pairs to files
save_fn = sprintf('cm%d_imr', cm);
% A complete self-contained file for Matlab users
save([save_fn '.mat'], 't_ct', 'h_ct', 't0', 'np', 'num_ch', 'cm');
% Two comma-delimited text files for non-Matlab users:
% File #1: cmX_imr_np.csv lisTs the number of paths in each realization
dlmwrite([save_fn '_np.csv'], np, ',');  % number of paths
% File #2: cmX_imr.csv can open with Excel
%     n'th pair of columns contains the (time,value) pairs for the n'th realization
th_ct = zeros(size(t_ct,1),2*size(t_ct,2));
th_ct(:,1:2:end) = t_ct;  % odd columns are time
th_ct(:,2:2:end) = h_ct; % even columns are values
fid = fopen([save_fn '.csv'], 'w');
if fid < 0,
  error('unable to write .csv file for impulse response, file may be open in another application');
end
for k = 1:size(th_ct,1)
  fprintf(fid,'%.4f,%.6f,', th_ct(k,1:end));
  fprintf(fid,'\r\n'); % \r\n for Windoze end-of-line
end
fclose(fid);


% evaluate MPJPE up to aligning the reference body joint (pelvis)
function error = MPJPE_h36(joint,j_p)
        % joint: ground truth 3D pose
        % j_p: prediction 3D pose

        %%
        %h36m

        jroot=[(joint(9,1)+joint(12,1))/2, (joint(9,2)+joint(12,2))/2,(joint(9,3)+joint(12,3))/2];

        %jroot=mean(joint);

        lsum = joint-repmat(jroot,14,1);
        %Lsum = mean(sqrt(lsum(:,1).^2+lsum(:,2).^2+lsum(:,3).^2));

        jroot_p = [(j_p(9,1)+j_p(12,1))/2, (j_p(9,2)+j_p(12,2))/2,(j_p(9,3)+j_p(12,3))/2];
        %jroot_p = mean(j_p);
        lsu = j_p - repmat(jroot_p,14,1);
        %Lsu = mean(sqrt(lsu(:,1).^2+lsu(:,2).^2+lsu(:,3).^2));

        %scale = Lsum/Lsu;
        temp = lsum - lsu;%*scale;

        error = mean(sqrt(temp(:,1).^2+temp(:,2).^2+temp(:,3).^2));

end


%IBBOX Find bounding box
%
% BOX = IBBOX(P) is the minimal bounding box that contains the points
% described by the columns of P (2xN).
%
% BOX = IBBOX(IM) as above but the box minimally contains the non-zero
% pixels in the image IM.
%
% Notes::
% - The bounding box is a 2x2 matrix [XMIN XMAX; YMIN YMAX].

% 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 box = ibbox(I)

    if numrows(I) == 2
        % input is a set of points
        u = I(1,:);
        v = I(2,:);
    else
        % input is an image, find the non-zero elements
        [v,u] = find(I);
    end
    umin = min(u);
    umax = max(u);
    vmin = min(v);
    vmax = max(v);

    box = [umin umax; vmin vmax];


% POLARCONT Polar contour plot
%
% Richard Rieber
% rrieber@gmail.com
% April 4, 2007
% Updated June 15, 2007
%
% function [C,h] = polarcont(r,theta,z,N,s)
%
% Purpose: This function creates polar contour plots on the current active
%          figure
%
% Inputs:  o r     - Radius vector of length m
%          o theta - Angle vector in radians of length n
%          o z     - Magnitude at the points specified in r and theta of
%                    size m x n
%          o N     - The number of contours to plot [OPTIONAL]
%          o s     - Linespec as described in PLOT [OPTIONAL]
%
% Outputs: o C     - returns contour matrix C as described in CONTOURC
%          o h     - Column vector H of handles to LINE or PATCH objects,
%                    one handle per line.
%
% OTHER NOTES:
% - Both C and h can be used as inputs to CLABEL
% - Colors are defined in colormap
% - Treat this function as a standard contour plot

function [C,h] = polarcont(r,theta,z,N,s)

[a,b] = size(z);

if a ~= length(r)
    error('r is not the same length as the first dimension of z')
end

if b ~= length(theta)
    error('theta is not the same length as the second dimension of z')
end

x = zeros(a,b);
y = zeros(a,b);

for j = 1:a
    for k = 1:b
        x(j,k) = r(j)*cos(theta(k));
        y(j,k) = r(j)*sin(theta(k));
    end
end

if nargin == 3
    [C,h] = contour(x,y,z);
elseif nargin == 4
    [C,h] = contour(x,y,z,N);
elseif nargin == 5
    [C,h] = contour(x,y,z,N,s);
else
    error('Incorrect number of inputs')
end


function X = tendiag(v,sz)
%TENDIAG Creates a tensor with v on the diagonal.
%
%   TENDIAG(V) creates a tensor with N dimensions, each of size N, where N
%   is the number of elements of V. The elements of V are placed on the
%   superdiagonal.
%
%   TENDIAG(V,SZ) is the same as above but creates a tensor of size SZ. If
%   SZ is not big enough, the tensor will be enlarged to accommodate the
%   elements of V on the superdiagonal.
%
%   Examples
%   X = tendiag([0.1 0.22 0.333]) %<-- creates a 3x3x3 tensor
%
%   See also TENSOR, SPTENDIAG.
%
%MATLAB Tensor Toolbox.
%Copyright 2012, Sandia Corporation.

% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others.
% http://www.sandia.gov/~tgkolda/TensorToolbox.
% Copyright (2012) Sandia Corporation. Under the terms of Contract
% DE-AC04-94AL85000, there is a non-exclusive license for use of this
% work by or on behalf of the U.S. Government. Export of this data may
% require a license from the United States Government.
% The full license terms can be found in the file LICENSE.txt

% Make sure v is a column vector
v = reshape(v,[numel(v) 1]);

N = numel(v);
if ~exist('sz','var')
    sz = repmat(N,1,N);
end

X = tenzeros(sz);
subs = repmat((1:N)', 1, length(sz));
X(subs) = v;


function [ fea, out ] = ex_swirl_flow1( varargin )
%EX_SWIRL_FLOW1 2D Axisymmetric laminar swirl flow.
%
%   [ FEA, OUT ] = EX_SWIRL_FLOW1( VARARGIN ) Axisymmetric swirl for in tubular region
%   where the inner cylindrical wall is rotating. Comparison with analytical solution.
%
%   Accepts the following property/value pairs.
%
%       Input       Value/{Default}        Description
%       -----------------------------------------------------------------------------------
%       rho         scalar {2}             Density
%       miu         scalar {3}             Molecular/dynamic viscosity
%       omega       scalar {5}             Angular rotational frequency (of inner wall)
%       ri          scalar {0.5}           Inner radius
%       ro          scalar {1.5}           Outer radius
%       h           scalar {3}             Height of cylinder
%       sf_u        string {sflag1}        Shape function for velocity
%       sf_p        string {sflag1}        Shape function for pressure
%       iplot       scalar 0/{1}           Plot solution (=1)
%                                                                                .
%       Output      Value/(Size)           Description
%       -----------------------------------------------------------------------------------
%       fea         struct                 Problem definition struct
%       out         struct                 Output struct

% Copyright 2013-2022 Precise Simulation, Ltd.

cOptDef = { 'rho',      2;
            'miu',      3;
            'omega',    5;
            'ri',       0.5
            'ro',       1.5;
            'h',        3;
            'sf_u',     'sflag1';
            'sf_p',     'sflag1';
            'iphys',    1;
            'iplot',    1;
            'tol',      [];
            'fid',      1 };
[got,opt] = parseopt(cOptDef,varargin{:});
fid       = opt.fid;

% Geometry and grid generation.
fea.sdim = {'r' 'z'};

ri = opt.ri;   % Inner radius.
ro = opt.ro;   % Outer radius.
h  = opt.h;    % Height of cylinder.
fea.geom.objects = { gobj_rectangle(ri,ro,-h/2,h/2) };

fea.grid = gridgen( fea, 'hmax', (ro-ri)/8, 'fid', fid );

% Equation definition.
if ( opt.iphys==1 )

  fea = addphys(fea,@swirlflow);
  fea.phys.sw.eqn.coef{1,end} = { opt.rho };
  fea.phys.sw.eqn.coef{2,end} = { opt.miu };
  fea.phys.sw.sfun            = [ repmat( {opt.sf_u}, 1, 3 ) {opt.sf_p} ];
  fea.phys.sw.bdr.sel = [5 1 5 2];
  fea.phys.sw.bdr.coef{2,end}{2,4} = opt.omega*ri;

  fea = parsephys(fea);

else

  opt.sf_u = 'sflag2';
  opt.sf_p = 'sflag1';

  fea.dvar = { 'u', 'v', 'w', 'p' };
  fea.sfun = [ repmat( {opt.sf_u}, 1, 3 ) {opt.sf_p} ];
  c_eqn    = { 'r*rho*u'' - r*miu*(2*ur_r + uz_z  +   wr_z) + r*rho*(u*ur_t + w*uz_t) + r*p_r     = r*Fr - 2*miu/r*u_t + p_t + rho*v*v_t';
               'r*rho*v'' - r*miu*(  vr_r + vz_z) + miu*v_r + r*rho*(u*vr_t + w*vz_t) + rho*u*v_t = r*Fth + miu*(v_r - 1/r*v_t)';
               'r*rho*w'' - r*miu*(  wr_r + uz_r  + 2*wz_z) + r*rho*(u*wr_t + w*wz_t) + r*p_z     = r*Fz';
               'r*ur_t + r*wz_t + u_t = 0' };
  fea.eqn = parseeqn( c_eqn, fea.dvar, fea.sdim );

  fea.coef = { 'rho', opt.rho ;
               'miu', opt.miu ;
               'Fr',  0 ;
               'Fth', 0 ;
               'Fz',  0 };

  % Boundary conditions.
  fea.bdr.d = { []  0 [] 0 ;
                []  0 [] opt.omega*ri ;
                0   0  0 0 ;
                [] [] [] [] };
  fea.bdr.n = cell(size(fea.bdr.d));

  % Fix pressure at p([r,z]=[ro,h/2]) = 0.
  [~,ix_p] = min( sqrt( (fea.grid.p(1,:)-ro).^2 + (fea.grid.p(2,:)-h/2).^2) );
  fea.pnt = struct( 'type',  'constr', ...
                    'index', ix_p, ...
                    'dvar',  'p', ...
                    'expr',  '0' );
end

% Parse and solve problem.
fea = parseprob( fea );
fea.sol.u = solvestat( fea, 'fid', fid );

% Exact (analytical) solution.
a = - opt.omega*ri^2 / (ro^2-ri^2);
b =   opt.omega*ri^2*ro^2 / (ro^2-ri^2);
v_th_ex = @(r,a,b) a.*r + b./r;

% Postprocessing.
if( opt.iplot )
  subplot(1,2,1)
  postplot( fea, 'surfexpr', 'sqrt(u^2+v^2+w^2)', 'isoexpr', 'v' )

  subplot(1,2,2)
  hold on
  grid on
  r = linspace( ri, ro, 100 );
  v_th = evalexpr( 'v', [r;zeros(1,length(r))], fea );
  plot( r, v_th, 'b--' )
  r = linspace( ri, ro, 10 );
  plot( r, v_th_ex(r,a,b), 'r.' )
  legend( 'Computed solution', 'Exact solution')
  xlabel( 'Radius, r')
  ylabel( 'Angular velocity, v')
end

% Error checking.
if( ~got.tol )
  if( opt.sf_u(end) == '2' )
    opt.tol = 0.01;
  else
    opt.tol = 0.16;
  end
end
r = linspace( ri, ro, 100 );
v_th = evalexpr( 'v', [r;zeros(1,length(r))], fea )';
out.err  = norm( v_th - v_th_ex(r,a,b) );
out.pass = out.err < opt.tol;

if( nargout==0 )
  clear fea out
end


function [L,S,obj,err,iter] = rmsc(X,lambda,opts)

% Solve the Robust Multi-view Spectral Clustering (RMSC) problem by M-ADMM
%
% min_{L,S_i} ||L||_*+lambda*\sum_i ||S_i||_1,
% s.t. X_i=L+S_i, i=1,...,m, L>=0, L1=1.
% ---------------------------------------------
% Input:
%       X       -    d*n*m tensor
%       lambda  -    >0, parameter
%       opts    -    Structure value in Matlab. The fields are
%           opts.tol        -   termination tolerance
%           opts.max_iter   -   maximum number of iterations
%           opts.mu         -   stepsize for dual variable updating in ADMM
%           opts.max_mu     -   maximum stepsize
%           opts.rho        -   rho>=1, ratio used to increase mu
%           opts.DEBUG      -   0 or 1
%
% Output:
%       L       -    d*n matrix
%       S       -    d*n*m tensor
%       obj     -    objective function value
%       err     -    residual
%       iter    -    number of iterations
%
% version 1.0 - 19/06/2016
%
% Written by Canyi Lu (canyilu@gmail.com)
%

tol = 1e-8;
max_iter = 500;
rho = 1.1;
mu = 1e-4;
max_mu = 1e10;
DEBUG = 0;

if ~exist('opts', 'var')
    opts = [];
end
if isfield(opts, 'tol');         tol = opts.tol;              end
if isfield(opts, 'max_iter');    max_iter = opts.max_iter;    end
if isfield(opts, 'rho');         rho = opts.rho;              end
if isfield(opts, 'mu');          mu = opts.mu;                end
if isfield(opts, 'max_mu');      max_mu = opts.max_mu;        end
if isfield(opts, 'DEBUG');       DEBUG = opts.DEBUG;          end

[d,n,m] = size(X);
L = zeros(d,n);
S = zeros(d,n,m);
Z = L;
Y = S;
dY = S;
Y2 = L;
iter = 0;
for iter = 1 : max_iter
    Lk = L;
    Sk = S;
    Zk = Z;
    % first super block {Z,S_i}
    [Z,nuclearnormZ] = prox_nuclear(L+Y2/mu,1/mu);
    for i = 1 : m
        S(:,:,i) = prox_l1(-L+X(:,:,i)-Y(:,:,i)/mu,lambda/mu);
    end
    % second super block {L}
    temp = (sum(X-S-Y/mu,3)+Z-Y2/mu)/(m+1);
    L = project_simplex(temp);

    for i = 1 : m
        dY(:,:,i) = L+S(:,:,i)-X(:,:,i);
    end
    dY2 = L-Z;
    chgL = max(abs(Lk(:)-L(:)));
    chgZ = max(abs(Zk(:)-Z(:)));
    chgS = max(abs(Sk(:)-S(:)));
    chg = max([chgL chgS chgZ max(abs(dY(:))) max(abs(dY2(:)))]);
    if DEBUG
        if iter == 1 || mod(iter, 10) == 0
            obj = nuclearnormZ+lambda*norm(S(:),1);
            err = sqrt(norm(dY(:))^2+norm(dY2,'fro')^2);
            disp(['iter ' num2str(iter) ', mu=' num2str(mu) ...
                    ', obj=' num2str(obj) ', err=' num2str(err)]);
        end
    end

    if chg < tol
        break;
    end
    Y = Y + mu*dY;
    Y2 = Y2 + mu*dY2;
    mu = min(rho*mu,max_mu);
end
obj = nuclearnormZ+lambda*norm(S(:),1);
err = sqrt(norm(dY(:))^2+norm(dY2,'fro')^2);


function [ prob, ier ] = mdbeta ( x, p, q )

%*****************************************************************************80
%
%% MDBETA evaluates the incomplete beta function.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    30 January 2008
%
%  Author:
%
%    Original FORTRAN77 version by Oliver Ludwig;
%    MATLAB version by John Burkardt
%
%  Reference:
%
%    Oliver Ludwig,
%    Algorithm 179:
%    Incomplete Beta Ratio,
%    Communications of the ACM,
%    Volume 6, Number 6, June 1963, page 314.
%
%  Parameters:
%
%    Input, real X, the value to which function is to be
%    integrated.  X must be in the range [0,1] inclusive.
%
%    Input, real P, the first parameter.  P must be greater
%    than 0.0.
%
%    Input, real Q, the second parameter.  Q must be greater
%    than 0.0.
%
%    Output, real PROB.  The probability that a random variable
%    from a Beta distribution having parameters P and Q will be less than
%    or equal to X.
%
%    Output, integer IER, error parameter.
%    0, normal exit.
%    1, X is not in the range [0,1] inclusive.
%    2, P or Q is less than or equal to 0.
%
%  Local parameters:
%
%    Local, real ALEPS, the logarithm of EPS1.
%
%    Local, real EPS, the machine precision.
%
%    Local, real EPS1, the smallest representable number.
%
  aleps = - 179.6016;
  eps = 2.2E-16;
  eps1 = 1.0E-78;
%
%  Check ranges of the arguments.
%
  prob = 0.0;
  y = x;

  if ( x < 0.0 || 1.0 < x )
    ier = 1;
    return
  end

  if ( p <= 0.0 || q <= 0.0 )
    ier = 2;
    return
  end

  ier = 0;

  if ( x <= 0.5 )
    interval = 0;
  else
    interval = 1;
    temp = p;
    p = q;
    q = temp;
    y = 1.0 - y;
  end

  if ( x == 0.0 || x == 1.0 )

    prob = 0.0;

    if ( interval ~= 0 )
      prob = 1.0 - prob;
      temp = p;
      p = q;
      q = temp;
    end

    return
  end

  ib = q;
  temp = ib;
  ps = q - ib;

  if ( q == temp )
    ps = 1.0;
  end

  dp = p;
  dq = q;
  px = dp * log ( y );
  pq = alogam ( dp + dq );
  p1 = alogam ( dp );
  c = alogam ( dq );
  d4 = log ( dp );
  xb = px + alogam ( ps + dp ) - alogam ( ps ) - d4 - p1;
%
%  Scaling
%
  ib = floor ( xb / aleps );
  infsum = 0.0;
%
%  First term of a decreasing series will underflow.
%
  if ( ib == 0 )

    infsum = exp ( xb );
    cnt = infsum * dp;
%
%  CNT will equal dexp ( temp ) * ( 1.d0 - ps ) * i * p * y**i / factorial ( i ).
%
    wh = 0.0;

    while ( 1 )

      wh = wh + 1.0;
      cnt = cnt * ( wh - ps ) * y / wh;
      xb = cnt / ( dp + wh );
      infsum = infsum + xb;

      if ( xb / eps < infsum )
        break
      end

    end

  end

  finsum = 0.0;

  if ( dq <= 1.0 )

    prob = finsum + infsum;

    if ( interval ~= 0 )
      prob = 1.0 - prob;
      temp = p;
      p = q;
      q = temp;
    end

    return
  end

  xb = px + dq * log ( 1.0 - y ) + pq - p1 - log ( dq ) - c;
%
%  Scaling.
%
  ib = floor ( xb / aleps );

  if ( ib < 0 )
    ib = 0;
  end

  c = 1.0 / ( 1.0 - y );
  cnt = exp ( xb - ib * aleps );
  ps = dq;
  wh = dq;

  while ( 1 )

    wh = wh - 1.0;

    if ( wh <= 0.0 )

      prob = finsum + infsum;

      if ( interval ~= 0 )
        prob = 1.0 - prob;
        temp = p;
        p = q;
        q = temp;
      end

      break

    end

    px = ( ps * c ) / ( dp + wh );

    if ( px <= 1.0 )

      if ( cnt / eps <= finsum || cnt <= eps1 / px )

        prob = finsum + infsum;

        if ( interval ~= 0 )
          prob = 1.0 - prob;
          temp = p;
          p = q;
          q = temp;
        end

        break

      end

    end

    cnt = cnt * px;
%
%  Rescale.
%
    if ( 1.0 < cnt )
      ib = ib - 1;
      cnt = cnt * eps1;
    end

    ps = wh;

    if ( ib == 0 )
      finsum = finsum + cnt;
    end

  end

  return
end


function [co, amp, ph] = computeCorAnalTSeries(vw, scan, tSeries)

% Variable check
%
if notDefined('vw'),        vw = getCurView;                    end
if notDefined('scan'),      scan = viewGet(vw, 'curscan');      end

% Compute Fourier transform
%
ft = fft(tSeries);
ft = ft(1:1+fix(size(ft, 1)/2), :);

% This quantity is proportional to the amplitude
%
scaledAmp = abs(ft);

% This is in fact, the correct amplitude
%
nCycles = viewGet(vw, 'nCycles', scan);
amp = 2*(scaledAmp(nCycles+1,:))/size(tSeries,1);

% We use the scaled amp here which is OK for computing the
% correlation. Note that the noiseBand defines the portion
% of the spectrum to use for the noise metric. As such, this
% calculation now corresponds to the correlation of the fundamental
% stimulus sinusoid with a FILTERED version of the data, where
% noiseBand determines the passband of a square-edged bandpass
% filter.
%
noiseBand    = GetNoiseBand(vw, scan);
noiseIndices = CreateNoiseIndices(scaledAmp, nCycles, noiseBand);
sqrtsummagsq = sqrt(sum(scaledAmp(noiseIndices, :).^2));

% (ras 06/07: sometimes sqrtsummagsq can be zero for some voxels;
% don't throw a warning for this line only.)
warning off MATLAB:divideByZero
co = scaledAmp(nCycles+1,:)./sqrtsummagsq;
warning on MATLAB:divideByZero
clear scaledAmp

% Calculate phase:
% 1) add pi/2 so that it is in sine phase.
% 2) minus sign because sin(x-phi) is shifted to the right by phi.
% 3) Add 2pi to any negative values so phases increase from 0 to 2pi.
%
ph = -(pi/2) - angle(ft(nCycles+1,:));
ph(ph<0) = ph(ph<0)+pi*2;


clear;
%
addpath '..';
%
fs=100;
nt=1000;
t=[1:nt]./fs;t=t(:);
%
f0=1.5;f1=10/2.15;
opm=log2(f1/f0)*60/t(end);
fup=f0*2.^(opm/60*t);fup=fup(:);
%
f0=10-(10-1.5)/2;f1=10;
inc=(f1-f0)/nt;
fdn=[f1:-inc:f0+inc];fdn=fdn(:);
%
f=0.75/t(end);
am1=0.25*sin(2*pi*f*t-pi/4);am1=am1+0.75;
am2=0.25*sin(2*pi*f*t-pi/1.7);am2=am2+0.75;
am3=0.25*sin(2*pi*f*t-pi/8);am3=am3+0.75;
am4=0.25*sin(2*pi*f*t-pi/2.5);am4=am4+0.75;
am5=0.25*sin(2*pi*f*t-pi/5);am5=am5+0.75;
am6=0.25*sin(2*pi*f*t-pi/10);am6=am6+0.75;
%
x1=am1.*sin(1*2*pi*cumsum(fup/fs));x1=x1./std(x1);
x2=am2.*sin(2*2*pi*cumsum(fup/fs));x2=x2./std(x2);
x3=am3.*sin(3*2*pi*cumsum(fup/fs));x3=x3./std(x3);
x4=am4.*sin(1*2*pi*cumsum(fdn/fs));x4=x4./std(x4);
x5=am5.*sin(2*2*pi*cumsum(fdn/fs));x5=x5./std(x5);
x6=am6.*sin(3*2*pi*cumsum(fdn/fs));x6=x6./std(x6);
%
fp=[fdn,2*fup,fup];
xp=[x4,x2,x1];
[nt,nch]=size(xp);
%
nsens=1;
%A=randn(nsens,nch);
A=[1,1,1];
%
xe=(A*xp.').';
xc=A(ones(nt,1),:).*xp;
%
%xe=xe+0.05*randn(nt,nsens); % add noise
%
nfft=128;nwin=100;novlap=50;dflag='mean';
[Sxx_m,freq,time]=p_gram(xe,nfft,fs,nwin,novlap,dflag);
%
r=4000;
ford=1;
[xs1,bw,T] = vk2(xe,fp(:,1),fs,r,ford);
[xs2,bw,T] = vk2(xe,fp(:,2),fs,r,ford);
[xs3,bw,T] = vk2(xe,fp(:,3),fs,r,ford);
xs=[xs1,xs2,xs3];
%
figure(1);
h=plot(t,xc,'--',t,abs(xs),'r');
set(h(2:end),'linewidth',2);
xlabel('Time [Sec]');
ylabel('Amplitude');
title('Single Order Extraction');
%
rm=4000;
tol=0.001;maxit=1000;
[xm,bwm,Tm,fl,rr,it,rv] = vkm(xe,fp,fs,rm*ones(nch,1),ford,tol,maxit);
%
figure(2);
h=plot(t,xc,'--',t,abs(xm),'r');
set(h(2:end),'linewidth',2);
xlabel('Time [Sec]');
ylabel('Amplitude');
title('Multiple Order Extraction');
%
figure(3);
semilogy(rv);
xlabel('Iteration');
ylabel('Residual');
%
figure(4);
typ='lin';f_min=0;f_max=32.5;
spec_plot2(Sxx_m,freq,time,typ,f_min,f_max,0,0.8);
colorbar('off');
g=colormap('gray');colormap(flipud(g));
title('Spectrogram of orders');
%
%%


function z = proj_sdp(z,n)
if n==0
    return;
elseif n==1
    z = max(z,0);
    return;
end

% expand to full size matrix
b = tril(ones(n));
b(b == 1) = z;
z = b;
z = (z + z');
z = z - diag(diag(z)) / 2;

% rescale so projection works, and matrix norm preserved
% see http://www.seas.ucla.edu/~vandenbe/publications/mlbook.pdf pg 3
% scale diags by sqrt(2)
z(eye(n) == 1) = z(eye(n) == 1) .* sqrt(2);

[V,S] = eig(z);
S = diag(S);

idx = find(S>0);
V = V(:,idx);
S = S(idx);
z = V*diag(S)*V';

% scale diags by 1/sqrt(2)
z(eye(n) == 1) = z(eye(n) == 1) ./ sqrt(2);

z = z(tril(ones(n)) == 1);
end


function u=rotrack(u0,x,y,nu,T)
%
%  Solves the linear equation u_t + y u_x - x u_y = 0 by "front tracking" +
%  dimensional splitting, using a time step dictated by dt/dx=nu for each
%  substep.
%  Neumann boundary condition are implicit.
%
dx=x(2)-x(1);
dt=nu*dx;
nstep=ceil(T/dt);
dt=T/nstep;
nu=dt/dx;
u=u0;
for i=1:nstep,
	u=transp(u,nu*y,1);
	u=transp(u,-nu*x,2);
end;


%% Demo of gaimc - 'Graph Algorithms In Matlab Code'
% Matlab includes great algorithms to work with sparse matrices but does
% provide a reasonable set of algorithms to work with sparse matrices as
% graph data structures.  My other project -- MatlabBGL -- provides a
% high-performance solution to this problem by directly interfacing the
% Matlab sparse matrix data structure with the Boost Graph Library.
% That library, however, suffers from enormous complication because
% it must be compiled for each platform.  The Boost Graph Library
% heavily uses advanced C++ features that impair easy portability
% between platforms.  In contrast, the gaimc library is implemented in
% pure Matlab code, making it completely portable.
%
% The cost of the portability for this library is a 2-4x slowdown in
% the runtime of the algorithms as well as significantly fewer
% algorithms to choose from.

%% Sparse matrices as graphs
% To store the connectivity structure of the graph, gaimc uses the
% adjacency matrix of a graph.
%
% A graph is represented by a set of vertices and a set of
% edges between the vertices.  Often, we write $G = (V,E)$ to denote the
% graph, the set of vertices, and the set of edges, respectively.  In
% gaimc, like in my other package MatlabBGL, we represent graphs with their
% adjacency matrices.  This representation is handy in Matlab because
% Matlab is rather efficient at working with the large sparse matrices that
% typically arise as adjacency matrices.
%
% To convert from $G=(V,E)$ to an adjacency matrix, we identify each vertex
% with a row of the matrix via a bijective map.  The adjacency matrix is
% then a $|V| \times |V|$ matrix called A.  The entry A(i,j) = 1 for
% any edge between in $E$ and 0 otherwise.  Let's look at an example.

load_gaimc_graph('bfs_example');
graph_draw(A,xy,'labels',labels)
full(A)
labels'

%%
% This output means that vertex 'r' is row 1, vertex 's' is row 2 and
% because A(1,2) = 1, then there is an edge between them, just like in the
% picture.
%
% One funny property is that A(2,1) = 1 too!  So we actually have to store
% each edge twice in the adjacency matrix.  This might seem wasteful, but
% its hard to avoid as I've learned while working on graph algorithms.  So
% don't worry about it!  It also makes the generalization to directed
% graphs (below) easy.
%
% For more information about the adjacency matrix representation of a
% graph, see a standard book on graph algorithms.
%

%% Weighted and directed graphs
% Our previous case handled the situation for undirected graphs only.  To
% encode weighted and directed graphs, we use weighted and non-symmetric
% adjacency matrices.
%
% For a weighted matrix, A(i,j) = distance between i and j for most of the
% algorithms in gaimc.  But A(i,j) = 0 means there is no edge, and so
% sometimes things can get a little tricky to get what you want.
%
% For a directed graph, just set A(i,j) ~= A(j,i).  The adjacency matrix
% won't be symmetric, but that's what you want!
%
% To understand more, explore the examples or read up on adjacency matrices
% in graph theory books.

%% Loading helper
% To make loading our sample graphs easy, gaimc defines it's own function
% to load graphs.

load_gaimc_graph('dfs_example'); % loads one of our example graphs
whos

%%
% This helps make our examples work regardless of where the current
% directory lies.

%% Search algorithms
% The two standard graph search algorithms are depth first search and
% breadth first search.  This library implements both.

%%
% Load the example matrix from the Boost Graph Library
load_gaimc_graph('dfs_example');
figure(1); graph_draw(A,xy,'labels',labels);

%%
% Run a depth first search.  The output records the distance to the other
% vertices, except where the vertices are not reachable starting from the
% first node A.
d=dfs(A,1)

%%
% From this example, we see that vertices a-f are reachable from vertex a,
% but that verice g-i are not reachable.  Given the of the edges, this
% makes sense.

%%
% Let's look at breadth first search too, using a different example.
load_gaimc_graph('bfs_example');
figure(1); clf; graph_draw(A,xy,'labels',labels);

%%
% The breadth first search algorithm records the distance from the starting
% vertex to each vertex it visits in breadth first order.  This means it
% visits all the vertices in order of their distance from the starting
% vertex.  The d output records the distance, and the dt output records the
% step of the algorithm when the breadth first search saw the node.
[d dt] = bfs(A,2);
% draw the graph where the label is the "discovery time" of the vertex.
figure(1); clf; graph_draw(A,xy,'labels',num2str(dt));

%%
% Notice how the algorithm visits all vertices one edge away from the start
% vertex (0) before visiting those two edges away.

%% Shortest paths
% In the previous two examples, the distance between vertices was
% equivalent to the number of edges.  Some graphs, however, have specific
% weights, such as the graph of flights between airports.  We can use this
% information to build information about the _shortest path_ between two
% nodes in a network.

% Find the minimum travel time between Los Angeles (LAX) and
% Rochester Minnesota (RST).
load_gaimc_graph('airports')
A = -A; % fix funny encoding of airport data
lax=247; rst=355;

[d pred] = dijkstra(A,lax); % find all the shorest paths from Los Angeles.

fprintf('Minimum time: %g\n',d(rst));
% Print the path
fprintf('Path:\n');
path =[]; u = rst; while (u ~= lax) path=[u path]; u=pred(u); end
fprintf('%s',labels{lax});
for i=path; fprintf(' --> %s', labels{i}); end, fprintf('\n');

%% Minimum spanning trees
% A minimum spanning tree is a set of edges from a graph that ...
%
% This demo requires the mapping toolbox for maximum effect, but we'll do
% okay without it.

%%
% Our data comes from a graph Brendan Frey prepared for his affinity
% propagation clustering tool.  For 456 cities in the US, we have the mean
% travel time between airports in those cities, along with their latitude
% and longitude.
load_gaimc_graph('airports')

%%
% For some reason, the data is stored with the negative travel time between
% cities.  (I believe this is so that closer cities have larger edges
% between them.)  But for a minimum spanning tree, we want the actual
% travel time between cities.
A = -A;

%%
% Now, we just call MST and look at the result.
% T = mst_prim(A);
% This command means we can't run the demo, so it's commented out.

%%
% Oops, travel time isn't symmetric!  Let's just pick the longest possible
% time.
A = max(A,A');
T = mst_prim(A);
sum(sum(T))/2 % total travel time in tree

%%
% Well, the total weight isn't that helpful, let's _look_ at the data
% instead.
clf;
gplot(T,xy);

%%
% Hey!  That looks like the US!  You can see regional airports and get some
% sense of the overall connectivity.

%% Connected components
% The connected components of a network determine which parts of the
% network are reachable from other parts.  One of your first questions
% about any network should generally be: is it connected?
%
% There are two types of connected components: components and strongly
% connected components.  gaimc only implements an algorithm for the latter
% case, but that's okay!  It turns out it computes exactly the right thing
% for connected components as well.  The difference only occurs when the
% graph is undirected vs. directed.

load_gaimc_graph('dfs_example')
graph_draw(A,xy)

%%
% This picture shows there are 3 strongly connected components and 2
% connected components

% get the number of strongly connected components
max(scomponents(A))

%%

% get the number of connected components
max(scomponents(A|A'))  % we make the graph symmetric first by "or"ing each entry

%%
% Let's look at the vertices in the strongly connected components
cc = scomponents(A)
%%
% The output tells us that vertices 1,2,3,5,6 are in one strong component,
% vertex 4 is it's own strong component, and vertices 7,8,9 are in another
% one.  Remember that a strong component is all the vertices mutually
% reachable from a given vertex.  If you start at vertex 4, you can't get
% anywhere else!  That's why it is in a different component than vertices
% 1,2,3,5,6.

%%
% We also have a largest_component function that makes it easy to just get
% the largest connected component.
clf;
[Acc,f] = largest_component(A);
graph_draw(Acc,xy(f,:))
%%
% The filter variable f, tells us which vertices in the original graph made
% it into the largest strong component.  We can just apply that filter to
% the coordinates xy and reuse them for drawing the graph!

%% Statistics
% Graph statistics are just measures that indicate a property of the graph
% at every vertex, or at every edges.  Arguably the simplest graph
% statistic would be the average vertex degree.  Because such statistics
% are easy to compute with the adjaceny matrix in Matlab, they do not have
% special functions in gaimc.

%%
% Load a road network to use for statistical computations
load_gaimc_graph('minnesota');
gplot(A,xy);

%%
% Average vertex degree
d = sum(A,2);
mean(d)

%%
% So the average number of roads at any intersection is 2.5.  My guess is
% that many roads have artificial intersections in the graph structure that
% do not correspond to real intersections.  Try validating that hypothesis
% using the library!

%%
% Average clustering coefficients
ccfs = clustercoeffs(A);
mean(ccfs)
% The average clustering coefficient is a measure of the edge density
% throughout the graph.  A small value indicates that the network has few
% edges and they are well distributed throughout the graph.

%%
% Average core numbers
cn = corenums(A);
mean(cn)

%% Efficient repetition
% Every time a gaimc function runs, it converts the adjacency matrix into a
% set of compressed sparse row arrays.  These arrays yield efficient access
% to the edges of the graph starting at a particular vertex.  For many
% function calls on the same graph, this conversion process slows the
% algorithms.  Hence, gaimc also accepts pre-converted input, in which case
% it skips it's conversion.
%
% Let's demonstrate how this works by calling Dijkstra's algorithm to
% compute the shortest paths between all vertices in the graph.  The
% Floyd Warshall algorithm computes these same quantities more efficiently,
% but that would just be one more algorithm to implement and maintain.

%%
% Load and convert the graph.
load_gaimc_graph('all_shortest_paths_example');
A = spfun(@(x) x-min(min(A))+1,A); % remove the negative edges
As = convert_sparse(A);
%%
% Now, we'll run Dijkstra's algorithm for every vertex and save the result
% On my 2GHz laptop, this takes 0.000485 seconds.
n = size(A,1);
D = zeros(n,n);
tic
for i=1:n
    D(i,:) = dijkstra(As,i);
end
toc
%%
% Let's try it without the conversion to see if we can notice the
% difference in speed.
% On my 2GHz laptop, this takes 0.001392 seconds.
D2 = zeros(n,n);
tic
for i=1:n
    D2(i,:) = dijkstra(A,i);
end
toc
%%
% And just to check, let's make sure the output is the same.
isequal(D,D2)


function cvt_movie ( )

%*****************************************************************************80
%
%% CVT_MOVIE generates and animates a CVT dataset.
%
%  Discussion:
%
%    This program is meant to be used interactively.  It's also
%    possible to prepare a simple input file beforehand and use it
%    in batch mode.
%
%    The program requests input values from the user:
%
%    * NDIM, the spatial dimension,
%    * N, the number of points to generate,
%    * SEED, a seed to use for random number generation;
%    * INIT, initialize the points:
%      ** file, by reading data from file;
%      ** 'GRID', picking points from a grid;
%      ** 'HALTON', from a Halton sequence;
%      ** 'RAND', using MATLAB's RAND function;
%      ** 'UNIFORM', using a simple uniform RNG;
%    * IT_MAX, the maximum number of iterations;
%    * IT_FIXED, the number of iterative steps to take
%      using a fixed set of sampling points.
%    * SAMPLE, how to conduct the sampling:
%      ** 'GRID', picking points from a grid;
%      ** 'HALTON', from a Halton sequence;
%      ** 'RAND', using MATLAB's RAND function;
%      ** 'UNIFORM', using a simple uniform RNG;
%    * SAMPLE_NUM, the number of sampling points;
%    * BATCH, the number of sampling points to create at one time;
%    * MOVIE_NAME is the name of the file in which the movie is stored;\n' );
%    * OUTPUT, a file into which the data can be stored.
%
%    To indicate that no further computations are desired, it is
%    enough to input a nonsensical value, such as -1.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    08 December 2004
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Qiang Du, Vance Faber, and Max Gunzburger,
%    Centroidal Voronoi Tessellations: Applications and Algorithms,
%    SIAM Review, Volume 41, 1999, pages 637-676.
%
  DEBUG = 1;

  timestamp ( );

  fprintf ( 1, '\n' );
  fprintf ( 1, 'CVT_MOVIE\n' );
  fprintf ( 1, '  MATLAB version\n' );
  fprintf ( 1, '  Generate and animate a CVT dataset.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  This program is meant to be used interactively.\n' );
  fprintf ( 1, '  It is also possible to prepare a simple input \n' );
  fprintf ( 1, '  file beforehand and use it in batch mode.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  The program requests input values from the user:\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  * NDIM, the spatial dimension,\n' );
  fprintf ( 1, '  * N, the number of points to generate,\n' );
  fprintf ( 1, '  * SEED, a seed to use for random number generation,\n' );
  fprintf ( 1, '  * INIT, initialize the points:\n' );
  fprintf ( 1, '    ** file, read data from a file;\n' );
  fprintf ( 1, '    ** ''GRID'', by picking points from a grid;\n' );
  fprintf ( 1, '    ** ''HALTON'', from a Halton sequence;\n' );
  fprintf ( 1, '    ** ''RAND'', using MATLAB''s RAND function;\n' );
  fprintf ( 1, '    ** ''UNIFORM'', using a simple uniform RNG;\n' );
  fprintf ( 1, '  * IT_MAX, the maximum number of iterations.\n' );
  fprintf ( 1, '  * IT_FIXED, the number of iterative steps to take\n' );
  fprintf ( 1, '    using a fixed set of sampling points.\n' );
  fprintf ( 1, '  * SAMPLE, how to conduct the sampling.\n' );
  fprintf ( 1, '    ** ''GRID'', by picking points from a grid;\n' );
  fprintf ( 1, '    ** ''HALTON'', from a Halton sequence;\n' );
  fprintf ( 1, '    ** ''RAND'', using MATLAB''s RAND function;\n' );
  fprintf ( 1, '    ** ''UNIFORM'', using a simple uniform RNG;\n' );
  fprintf ( 1, '  * SAMPLE_NUM, the number of sample points;\n' );
  fprintf ( 1, '  * BATCH, the number of sampling points to create at one time;\n' );
  fprintf ( 1, '  * OUTPUT, a file into which the data is stored.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  To indicate that no further computations are \n' );
  fprintf ( 1, '  desired, it is enough to input a nonsensical value, \n' );
  fprintf ( 1, '  such as -1.\n' );

  while ( 1 )

    fprintf ( 1, '  *\n' );
    fprintf ( 1, ' *\n' );
    fprintf ( 1, '*  Ready to generate a new dataset:\n' );
    fprintf ( 1, ' *\n' );
    fprintf ( 1, '  *\n' );
    fprintf ( 1, '\n' );
    fprintf ( 1, '  NDIM is the spatial dimension.\n' );
    fprintf ( 1, '  (Try ''2'' if you have no preference.)\n' );
    fprintf ( 1, '  (Any value less than 1 terminates execution.)\n' );
    ndim = [];
    ndim = input ( '  Enter NDIM:  ' );

    fprintf ( 1, '  Default NDIM = %12d\n', ndim );

    if ( ndim < 1 )
      fprintf ( 1, '\n' );
      fprintf ( 1, 'CVT_MOVIE\n' );
      fprintf ( 1, '  The input value of NDIM = %12d\n', ndim );
      fprintf ( 1, '  is interpreted as a request for termination.\n' );
      fprintf ( 1, '  Normal end of execution.\n' );
      break
    end

    fprintf ( 1, '\n' );
    fprintf ( 1, '  N is the number of points to generate.\n' );
    fprintf ( 1, '  (Try ''25'' if you have no preference.)\n' );
    fprintf ( 1, '  (Any value less than 1 terminates execution.)\n' );
    n = [];
    n = input ( '  Enter N:  ' );

    fprintf ( 1, '  User input N = %12d\n', n );

    if ( n < 1 )
      fprintf ( 1, '\n' );
      fprintf ( 1, 'CVT_MOVIE\n' );
      fprintf ( 1, '  The input value of N = %12d\n', n );
      fprintf ( 1, '  is interpreted as a request for termination.\n' );
      fprintf ( 1, '  Normal end of execution.\n' );
      break
    end

%   fprintf ( 1, '\n' );
%   fprintf ( 1, '  SEED is a seed for the random number generation.\n' );
%   fprintf ( 1, '  (Try ''123456789'' if you have no preference.)\n' );
%   fprintf ( 1, '  (Any value less than 0 terminates execution.)\n' );
%   seed = [];
%   seed = input ( '  Enter SEED:  ' );
    seed = 123456789;
    fprintf ( 1, '  Default SEED = %d\n', seed );

    if ( seed < 0 )
      fprintf ( 1, '\n' );
      fprintf ( 1, 'CVT_MOVIE\n' );
      fprintf ( 1, '  The input value of SEED = %12d\n', seed );
      fprintf ( 1, '  is interpreted as a request for termination.\n' );
      fprintf ( 1, '  Normal end of execution.\n' );
      break
    end

    fprintf ( 1, '\n' );
    fprintf ( 1, '  INIT is the method of initializing the data:\n' );
    fprintf ( 1, '\n' );
    fprintf ( 1, '  file       read data from a file;\n' );
    fprintf ( 1, '  ''GRID''     by picking points from a grid;\n' );
    fprintf ( 1, '  ''HALTON''   from a Halton sequence;\n' );
    fprintf ( 1, '  ''RAND''     using MATLAB''s RAND function;\n' );
    fprintf ( 1, '  ''UNIFORM''  using a simple uniform RNG;\n' );
    fprintf ( 1, ' \n' );
    fprintf ( 1, '  (Try ''RAND'' if you have no preference.)\n' );
    fprintf ( 1, '  (A blank value terminates execution).\n' );
    fprintf ( 1, '  (Be sure to INCLUDE QUOTES around the string!\n' );
    fprintf ( 1, ' \n' );

    init_string = [];
    init_string = input ( '  Enter INIT:  ' );

    fprintf ( 1, '  User input INIT = "%s".\n', init_string );

    if ( s_len_trim ( init_string ) <= 0 )
      fprintf ( 1, '\n' );
      fprintf ( 1, 'CVT_MOVIE\n' );
      fprintf ( 1, '  The input value of INIT \n' );
      fprintf ( 1, '  is interpreted as a request for termination.\n' );
      fprintf ( 1, '  Normal end of execution.\n' );
      break
    end

    if ( s_eqi ( init_string, 'RAND'  ) )
      init = -1;
    elseif ( s_eqi ( init_string, 'RANDOM' ) )
      init_string = 'RAND';
      init = -1;
    elseif ( s_eqi ( init_string, 'UNIFORM' ) )
      init = 0;
    elseif ( s_eqi ( init_string, 'HALTON'  ) )
      init = 1;
    elseif ( s_eqi ( init_string, 'GRID'    ) )
      init = 2;
    elseif ( 0 < s_len_trim ( init_string ) )
      init = 3;
    else
      fprintf ( 1, '\n' );
      fprintf ( 1, 'CVT_MOVIE\n' );
      fprintf ( 1, '  The input value of INIT \n' );
      fprintf ( 1, '  is interpreted as a request for termination.\n' );
      fprintf ( 1, '  Normal end of execution.\n' );
      break
    end

    fprintf ( 1, '\n' );
    fprintf ( 1, '  IT_MAX is the maximum number of iterations.\n' );
    fprintf ( 1, '\n' );
    fprintf ( 1, '  An iteration carries out the following steps:\n' );
    fprintf ( 1, '  * the Voronoi region associated with each\n' );
    fprintf ( 1, '    generator is estimated by sampling;\n' );
    fprintf ( 1, '  * the centroid of each Voronoi region is estimated.\n' );
    fprintf ( 1, '  * the generator is replaced by the centroid.\n' );
    fprintf ( 1, '\n' );
    fprintf ( 1, '  If "enough" sampling points are used,\n' );
    fprintf ( 1, '  and "enough" iterations are taken, this process\n' );
    fprintf ( 1, '  will converge.\n' );
    fprintf ( 1, '\n' );
    fprintf ( 1, '  (Try ''50'' if you have no preference.)\n' );
    fprintf ( 1, '  (A negative value terminates execution).\n' );
    fprintf ( 1, '\n' );
    it_max = [];
    it_max = input ( '  Enter IT_MAX:  ' );

    fprintf ( 1, '  User input IT_MAX = %12d\n', it_max );

    if ( it_max < 0 )
      fprintf ( 1, ' \n' );
      fprintf ( 1, 'CVT_MOVIE\n' );
      fprintf ( 1, '  The input value of IT_MAX = %12d\n', it_max );
      fprintf ( 1, '  is interpreted as a request for termination.\n' );
      fprintf ( 1, '  Normal end of execution.\n' );
      break
    end

    fprintf ( 1, '\n' );
    fprintf ( 1, '  IT_FIXED is the number of consecutive iterations\n' );
    fprintf ( 1, '  to take with a fixed set of sample points.\n' );
    fprintf ( 1, '\n' );
    fprintf ( 1, '  Setting IT_FIXED to 1 means a new set of sample\n' );
    fprintf ( 1, '  points is generated on every iterative step;\n' );
    fprintf ( 1, '  Setting IT_FIXED equal to IT_MAX means a single set\n' );
    fprintf ( 1, '  of sample points is used for the entire iteration.\n' );
    fprintf ( 1, '\n' );
    fprintf ( 1, '  Any value between 1 and IT_MAX is reasonable.\n' );
    fprintf ( 1, '\n' );
    fprintf ( 1, '  (Try "%d" if you do not have a preference).\n', it_max );
    fprintf ( 1, '  (A 0 or negative value terminates execution).\n' );
    fprintf ( 1, '\n' );
    it_fixed = [];
    it_fixed = input ( '  Enter IT_FIXED:  ' );

    fprintf ( 1, '  User input IT_FIXED = %12d\n', it_fixed );

    if ( it_max < 0 )
      fprintf ( 1, ' \n' );
      fprintf ( 1, 'CVT_MOVIE\n' );
      fprintf ( 1, '  The input value of IT_FIXED = %12d\n', it_fixed );
      fprintf ( 1, '  is interpreted as a request for termination.\n' );
      fprintf ( 1, '  Normal end of execution.\n' );
      break
    end

    fprintf ( 1, '\n' );
    fprintf ( 1, '  SAMPLE is the method of sampling the region:\n' );
    fprintf ( 1, '\n' );
    fprintf ( 1, '  ''GRID''     by picking points from a grid;\n' );
    fprintf ( 1, '  ''HALTON''   from a Halton sequence;\n' );
    fprintf ( 1, '  ''RAND''     using MATLAB''s RAND function;\n' );
    fprintf ( 1, '  ''UNIFORM''  using a simple uniform RNG;\n' );
    fprintf ( 1, '\n' );
    fprintf ( 1, '  (Try ''RAND'' if you have no preference.)\n' );
    fprintf ( 1, '  (A blank value terminates execution).\n' );
    fprintf ( 1, '  (Be sure to INCLUDE QUOTES around the string!\n' );
    fprintf ( 1, '\n' );

    sample_string = [];
    sample_string = input ( '  Enter SAMPLE:  ' );

    fprintf ( 1, '  User input SAMPLE = "%s".\n', sample_string );

    if ( s_len_trim ( sample_string ) <= 0 )
      fprintf ( 1, '\n' );
      fprintf ( 1, 'CVT_MOVIE\n' );
      fprintf ( 1, '  The input value of SAMPLE \n' );
      fprintf ( 1, '  is interpreted as a request for termination.\n' );
      fprintf ( 1, '  Normal end of execution.\n' );
      break
    end

    if ( s_eqi ( sample_string, 'RAND'  ) )
      sample = -1;
    elseif ( s_eqi ( sample_string, 'RANDOM' ) )
      sample = -1;
      sample_string = 'RAND';
    elseif ( s_eqi ( sample_string, 'UNIFORM' ) )
      sample = 0;
    elseif ( s_eqi ( sample_string, 'HALTON'  ) )
      sample = 1;
    elseif ( s_eqi ( sample_string, 'GRID'    ) )
      sample = 2;
    else
      fprintf ( 1, '\n' );
      fprintf ( 1, 'CVT_MOVIE\n' );
      fprintf ( 1, '  The input value of SAMPLE \n' );
      fprintf ( 1, '  is interpreted as a request for termination.\n' );
      fprintf ( 1, '  Normal end of execution.\n' );
      break
    end

    fprintf ( 1, '\n' );
    fprintf ( 1, '  SAMPLE_NUM is the number of sample points.\n' );
    fprintf ( 1, '\n' );
    fprintf ( 1, '  The Voronoi regions will be explored by generating\n' );
    fprintf ( 1, '  SAMPLE_NUM points.  For each sample point, the\n' );
    fprintf ( 1, '  nearest generator is found.  Using more points\n' );
    fprintf ( 1, '  gives a better estimate of these regions.\n' );
    fprintf ( 1, '\n' );
    fprintf ( 1, '  SAMPLE_NUM should be much larger than N, the\n' );
    fprintf ( 1, '  number of generators.\n' );
    fprintf ( 1, '\n' );
    fprintf ( 1, '  (Try ''10000'' if you have no preference.)\n' );
    fprintf ( 1, '  (A zero or negative value terminates execution.)\n' );
    fprintf ( 1, '\n' );

    sample_num = [];
    sample_num = input ( '  Enter SAMPLE_NUM:  ' );

    fprintf ( 1, '  User input SAMPLE_NUM = %12d\n', sample_num );

    if ( sample_num <= 0 )
      fprintf ( 1, '\n' );
      fprintf ( 1, 'CVT_MOVIE\n' );
      fprintf ( 1, '  The input value of SAMPLE_NUM = %12d\n', sample_num );
      fprintf ( 1, '  is interpreted as a request for termination.\n' );
      fprintf ( 1, '  Normal end of execution.\n' );
      break
    end

%   fprintf ( 1, '\n' );
%   fprintf ( 1, '  BATCH is the number of sample points to create\n' );
%   fprintf ( 1, '  at one time\n' );
%   fprintf ( 1, '\n' );
%   fprintf ( 1, '  BATCH should be between 1 and SAMPLE_NUM.\n' );
%   fprintf ( 1, '\n' );
%   fprintf ( 1, '  It is FASTER to set BATCH to SAMPLE_NUM;\n' );
%   fprintf ( 1, '  setting BATCH to 1 requires the least memory.\n' );
%   fprintf ( 1, '\n' );
%   fprintf ( 1, '  (Try ''%d'' if you have no preference.)\n', ...
%     min ( 1000, sample_num ) );
%   fprintf ( 1, '  (A zero or negative value terminates execution.)\n' );
%   fprintf ( 1, '\n' );

%   batch = [];
%   batch = input ( '  Enter BATCH:  ' );
    batch = 1000;

    fprintf ( 1, '  Default BATCH = %12d\n', batch );

    if ( batch <= 0 )
      fprintf ( 1, '\n' );
      fprintf ( 1, 'CVT_MOVIE\n' );
      fprintf ( 1, '  The input value of BATCH = %12d\n', batch );
      fprintf ( 1, '  is interpreted as a request for termination.\n' );
      fprintf ( 1, '  Normal end of execution.\n' );
      break
    end

    fprintf ( 1, '\n' );
    fprintf ( 1, '  MOVIE_NAME is the name of the file in which the movie is stored;\n' );
    fprintf ( 1, '\n' );
    fprintf ( 1, '  (Try ''movie.avi'' if you have no preference.)\n' );
    fprintf ( 1, '  (A blank value terminates execution).\n' );
    fprintf ( 1, '  (Be sure to INCLUDE QUOTES around the string!\n' );
    fprintf ( 1, ' \n' );

    movie_name = [];
    movie_name = input ( '  Enter MOVIE_NAME:  ' );

    fprintf ( 1, '  User input MOVIE_NAME = %s\n', movie_name );

%   fprintf ( 1, '\n' );
%   fprintf ( 1, '  OUTPUT is a file into which the data is stored;\n' );
%   fprintf ( 1, '\n' );
%   fprintf ( 1, '  (Try ''cvt.txt'' if you have no preference.)\n' );
%   fprintf ( 1, '  (A blank value terminates execution).\n' );
%   fprintf ( 1, '  (Be sure to INCLUDE QUOTES around the string!\n' );
%   fprintf ( 1, ' \n' );

%   file_out_name = [];
%   file_out_name = input ( '  Enter OUTPUT:  ' );

    file_out_name = 'cvt.txt';

    fprintf ( 1, '  Default OUTPUT = "%s".\n', file_out_name );

    if ( s_len_trim ( file_out_name ) <= 0 )
      fprintf ( 1, '\n' );
      fprintf ( 1, 'CVT_MOVIE\n' );
      fprintf ( 1, '  The input value of OUTPUT \n' );
      fprintf ( 1, '  is interpreted as a request for termination.\n' );
      fprintf ( 1, '  Normal end of execution.\n' );
      break
    end

    if ( s_len_trim ( file_out_name ) <= 0 )
      fprintf ( 1, '\n' );
      fprintf ( 1, 'CVT_MOVIE\n' );
      fprintf ( 1, '  The input value of OUTPUT \n' );
      fprintf ( 1, '  is interpreted as a request for termination.\n' );
      fprintf ( 1, '  Normal end of execution.\n' );
      break
    end
%
%  Initialize the data.
%
    if ( init == 3 )
      r = data_read ( sample_string, ndim, n );
    else
      r = [];
    end

    seed_init = seed;
%
%  Initialize the data unless the user has already done that.
%
    if ( init ~= 3 )

      initialize = 1;

      [ r, seed ] = cvt_sample ( ndim, n, n, init, initialize, seed );

    end
%
%  If the initialization and sampling steps use the same random number
%  scheme, then the sampling scheme does not have to be initialized.
%
    if ( init == sample )
      initialize = 0;
    else
      initialize = 1;
    end

    if ( file_exist ( movie_name ) )
      file_delete ( movie_name )
    end

    if ( DEBUG )
      fprintf ( 1, '\n' );
      fprintf ( 1, '  Step    SEED          L2-Change     Energy\n' );
      fprintf ( 1, '\n' );
    end

    num_frames_per_second = 10;
    aviobj = avifile ( movie_name, 'fps', num_frames_per_second );
    box = [ 0.0, 0.0; 1.0, 0.0; 1.0, 1.0; 0.0, 1.0 ]';

    it_num = 0;
    it_diff = 0.0;
    seed_base = seed_init;
    seed = seed_init;

    while ( it_num < it_max )
%
%  Once every IT_FIXED steps, update the base value of SEED,
%  either to SEED_INIT before the first call to CVT_ITERATE, or to the
%  output value of SEED from the previous call to CVT_ITERATE.
%
%  Otherwise, reset the value of SEED to SEED_BASE.
%
      if ( mod ( it_num, it_fixed ) == 0 )
        seed_base = seed;
      else
        seed = seed_base;
      end

      it_num = it_num + 1;

      seed_init2 = seed;

      [ r, seed, it_diff, energy ] = cvt_iterate ( ndim, n, batch, sample, ...
        initialize, sample_num, seed, r );

      scatter ( r(1,1:n), r(2,1:n), [], 'r', 'filled' );
      line ( [ 0.0, 1.0, 1.0, 0.0, 0.0 ], [ 0.0, 0.0, 1.0, 1.0, 0.0 ] );
      axis ( [ -0.05, 1.05, -0.05, 1.05 ] );
      axis equal
%
%  Label the axes and the plot.
%
    xlabel ( 'X', 'FontName', 'Helvetica', 'FontWeight', 'bold', ...
      'FontSize', 16 );

    ylabel ( 'Y', 'FontName', 'Helvetica', 'FontWeight', 'bold', ...
      'FontSize', 16, 'Rotation', 0 );

    it_string = sprintf ( 'Step %4d', it_num );

    title ( it_string, 'FontName', 'Helvetica', 'FontWeight', ...
      'bold', 'FontSize', 16 );

      frame = getframe ( gca );
      aviobj = addframe ( aviobj, frame );

      initialize = 0;

      if ( DEBUG )
        fprintf ( 1, '  %4d  %12d  %14e  %14e\n', ...
          it_num, seed_init2, it_diff, energy );
      end

    end

    aviobj = close ( aviobj );
%
%  Write the final data to a file.
%
    cvt_write ( ndim, n, batch, seed_init, seed, init_string, it_max, ...
      it_fixed, it_num, it_diff, energy, sample_string, sample_num, ...
      r, file_out_name );

    fprintf ( 1, '\n' );
    fprintf ( 1, '  The data was written to the file "%s".\n', ...
      file_out_name );

    fprintf ( 1, '\n' );
    fprintf ( 1, '  Press RETURN to proceed.\n' );

    pause

  end

  fprintf ( 1, '\n' );
  fprintf ( 1, '  Final value of SEED = %d\n', seed );
  fprintf ( 1, '\n' );
  timestamp ( );

  return
end


function [X p ei ej] = chrobak_payne_straight_line_drawing(A,varargin)
% CHROBAK_PAYNE_STRAIGHT_LINE_DRAWING Draw planar graphs with straight lines
%
% X = chrobak_payne_straight_line_drawing(A) generates coordinates for each
% vertex such that a planar graph A can be drawn without any edge
% crossings.  This function reports an error if A is not planar.
%
% [X,p,ei,ej] = ... returns additional information.  p is a
% canonical planar ordering of the vertices, and [ei ej] are additional
% edges required to make A a maximal_planar graph.
%
% ... = chrobak_payne_straight_line_drawing(A,...) takes a set of
% key-value pairs or an options structure.  See set_matlab_bgl_options
% for the standard options.
%   options.is_maximal: is A already a maximal planar graph [{0} | 1]
%
% Note: Be careful with is_maximal=1 and nocheck=1.  If the graph is not
% maximal, then the call will crash Matlab.
%
% Example:
%   [A,xy] = grid_graph(6,5);
%   X = chrobak_payne_straight_line_drawing(A);
%   gplot(A,X,'.-'); hold on; gplot(A,xy*20,'r.-'); hold off
%   % it's still planar, but not obviously a grid!

% David Gleich
% Copyright, Stanford University, 2008

%% History
%  2007-10-06: Initial coding
%%

[trans check full2sparse] = get_matlab_bgl_options(varargin{:});
if full2sparse && ~issparse(A), A = sparse(A); end

options = struct('is_maximal',0);
options = merge_options(options,varargin{:});
if check
    check_matlab_bgl(A,struct('sym',1));
    if options.is_maximal,
        [i j] = make_maximal_planar(A);
        if ~isempty(i), error('matlab_bgl:checkFailed',...
            'The graph was not a maximal planar but is_maximal was set.'); end
    end
end

[ei ej p X] = planar_drawing_mex(A,options.is_maximal,0);


function f = f08_f0 ( n, x, y )

%*****************************************************************************80
%
%% F08_F0 returns the value of function 8.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    29 January 2012
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer N, the number of evaluation points.
%
%    Input, real X(N,1), Y(N,1), the evalution points.
%
%    Output, real F(N,1), the function values.
%
  t1(1:n,1) = 5.0 - 10.0 * x(1:n,1);
  t2(1:n,1) = 5.0 - 10.0 * y(1:n,1);
  t3(1:n,1) = exp ( - 0.5 * t1(1:n,1) .* t1(1:n,1) );
  t4(1:n,1) = exp ( - 0.5 * t2(1:n,1) .* t2(1:n,1) );
  f(1:n,1) = t3(1:n,1) + 0.75 * t4(1:n,1) .* ( 1.0 + t3(1:n,1) );

  return
end


  function ob = Gembed(varargin)
%|function ob = Gembed([args])
%| Construct Gembed object that embes a short vector into a longer vector.
%| with dimensions [(Nd)].
%|
%| option1:
%|	'list'	[N]		list of array entries
%|	'odim'	ndims
%|
%| option2:
%|	'samp'	logical [(Nd)]	sampling pattern of array entries
%|
%| out
%|	ob	[M N]	fatrix2 object, where M = numel(samp), N = length(list)
%|
%| The two versions are related by list = find(samp), odim = size(samp).
%|
%| Copyright 2010-12-01, Jeff Fessler, University of Michigan

if nargin < 1, ir_usage, end
if nargin == 1 && streq(varargin{1}, 'test'), Gembed_test, return, end

arg.samp = [];
arg.list = [];
arg.odim = [];
arg = vararg_pair(arg, varargin);

if ~isempty(arg.samp) && isempty(arg.list) && isempty(arg.odim)
	ob = Gembed_samp_build(arg.samp);

elseif isempty(arg.samp) && ~isempty(arg.list) && ~isempty(arg.odim)
	ob = Gembed_list_build(arg.odim, arg.list);

else
	fail('must give exactly one of samp, or list and odim')
end

% Gembed_list_build()
function ob = Gembed_list_build(odim, list)
arg.odim = odim;
arg.list = list;

ob = fatrix2( ...
	'accept1d', true, ... % trick: OK because of forw(forw()) in mtimes2
	'idim', numel(arg.list), ...
	'odim', arg.odim, ...
	'arg', arg, ...
	'forw', @Gembed_list_forw, ...
	'back', @Gembed_list_back, ...
	'caller', [mfilename '(list)']);
%	'mask', true(numel(arg.list),1), ...

% Gembed_list_forw(): y = A * x
% in
%	x	[N]
% out
%	y	[(M)]
%
function y = Gembed_list_forw(arg, x)

y = zeros([arg.odim 1], class(x)); % [(M)]
y(arg.list) = x;

% Gembed_list_back(): x = A' * y
% in
%	y	[(M)]
% out
%	x	[N]
%
function x = Gembed_list_back(arg, y)

x = y(arg.list);

% Gembed_samp_build()
function ob = Gembed_samp_build(samp)
arg.samp = samp;
arg.odim = size(samp);
if arg.odim(end) == 1
	arg.odim = arg.odim(1:end-1); % remove trailing '1'
end
if ~islogical(arg.samp), error 'samp must be logical', end

ob = fatrix2( ...
	'idim', sum(arg.samp(:)), ...
	'odim', arg.odim, ...
	'arg', arg, ...
	'forw', @Gembed_samp_forw, ...
	'back', @Gembed_samp_back, ...
	'caller', [mfilename '(list)']);

% Gembed_samp_forw()
function y = Gembed_samp_forw(arg, x)
y = zeros([arg.odim 1], class(x)); % [(M)]
y(arg.samp) = x;

% Gembed_samp_back()
function x = Gembed_samp_back(arg, y)
x = y(arg.samp);

% Gembed_test
function Gembed_test

odim = [5 2];
list = [2 1 9 7];
odim = prod(odim); % required because of fatrix2 full 1d ambiguity

for ii=1:2
	if ii==1 % type list
		A = Gembed('odim', odim, 'list', list);
	else % type samp
		samp = false([odim 1]);
		samp(list) = 1;
		A = Gembed('samp', samp);
	end

	fatrix2_tests(A)
	test_adjoint(A);
end


function [y]=gnanmean(varargin)
% function [y]=gnanmean(A,dimDir)
%------------------------------------------------------------------------
% this function is a replacement for nanmean which is part of the
% statistics and machine learning toolbox.
% The use of mean with the omitnan flag is used or if this does not work
% (for old MATLAB versions) a custom implementation is used.
%
% Change log:
% 2020/01/09 Created
%------------------------------------------------------------------------

%%
try
    %Use 'omitnan' flag
    y = mean(varargin{:},'omitnan');
catch
    %Use custom version
    A=varargin{1};
    if nargin==2
        dimDir=varargin{2};
    else
        dimDir=1;
    end
    L=isnan(A);
    Q=sum(~L,dimDir);
    B=A;
    B(L)=0;
    S=sum(B,dimDir);
    y=S./Q;
    y(all(L,dimDir))=NaN;
end

end

%%
% _*GIBBON footer text*_
%
% License: <https://github.com/gibbonCode/GIBBON/blob/master/LICENSE>
%
% GIBBON: The Geometry and Image-based Bioengineering add-On. A toolbox for
% image segmentation, image-based modeling, meshing, and finite element
% analysis.
%
% Copyright (C) 2006-2022 Kevin Mattheus Moerman and the GIBBON contributors
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program.  If not, see <http://www.gnu.org/licenses/>.


function [vert,econ,tria] = cfmtri2(vert,econ)
%CFMTRI2 compute a conforming 2-simplex Delaunay triangulat-
%ion in the two-dimensional plane.
%   [VERT,CONN,TRIA]=CFMTRI2(VERT,CONN) computes the confor-
%   ming Delaunay trianguation, given the points VERT, and
%   edge constraints CONN. New points are inserted to bisect
%   edge constraints until all are recovered. VERT is a
%   V-by-2 array of XY coordinates to be triangulated, TRIA
%   is a T-by-3 array of vertex indexing, with each row
%   defining a triangle, such that VERT(TRIA(II,1),:),
%   VERT(TRIA(II,2),:) and VERT(TRIA(II,3),:) are the coord-
%   inates of the II-TH triangle. CONN is a C-by-2 array of
%   constraining edges, where each row defines an edge, as
%   per the TRIA array.
%
%   See also DELTRI2, DELAUNAYN

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

%---------------------------------------------- basic checks
    if ( ~isnumeric(vert) || ...
         ~isnumeric(econ) )
        error('cfmtri2:incorrectInputClass' , ...
            'Incorrect input class.') ;
    end

%---------------------------------------------- basic checks
    if (ndims(vert) ~= +2 || ndims(econ) ~= +2)
        error('cfmtri2:incorrectDimensions' , ...
            'Incorrect input dimensions.');
    end

    if (size(vert,2)~= +2 || size(econ,2)~= +2)
        error('cfmtri2:incorrectDimensions' , ...
            'Incorrect input dimensions.');
    end

%-- the DELAUNAYN routine is *not* well-behaved numerically,
%-- so explicitly re-scale the problem about [-1,-1; +1,+1].
    vmax = max(vert,[],1) ;
    vmin = min(vert,[],1) ;

    vdel = vmax - vmin;
    vdel = mean(vdel) ;
    vdel = vdel * +.5 ;

    vmid = vmax + vmin;
    vmid = vmid * +.5 ;

    vert = vert - vmid;
    vert = vert / vdel;

%-- keep bisecting edge constraints until they are all reco-
%-- vered!
    while (true)

    %----------------- un-constrained delaunay triangulation
        tria = delaunay2(vert) ;

        nv = size(vert,+1);
        nt = size(tria,+1);

    %----------------------------- build non-unique edge-set
        ee = zeros(nt*3,2);
        ee((1:nt)+nt*0,:) = tria(:,[1,2]);
        ee((1:nt)+nt*1,:) = tria(:,[2,3]);
        ee((1:nt)+nt*2,:) = tria(:,[3,1]);

    %----------------- find constraints within tria-edge set
       [in] = setset2(econ,ee) ;

    %----------------------------- done when have contraints
        if (all(in)), break; end

    %----------------------------- un-recovered edge centres
        vm = vert(econ(~in,1),:) ...
           + vert(econ(~in,2),:) ;
        vm = vm * +.5 ;

    %----------------------------- un-recovered edge indexes
        ev = nv+(1:size(vm,1))';
        en = [econ(~in,+1), ev;
              econ(~in,+2), ev];

    %----------------------------- push new vert/edge arrays
        vert = [vert( :,:); vm];
        econ = [econ(in,:); en];

    end

%--------------------------------- undo geomertic re-scaling
    vert = vert * vdel ;
    vert = vert + vmid ;

end

function [tria] = delaunay2(vert)
%DELAUNAY2 thin wrapper for DELAUNAYN, so that we can have a
%   more efficient version in OCTAVE...

    isoctave = exist( ...
        'OCTAVE_VERSION','builtin')>+0;

    if (isoctave)

    %-- call QHULL and then filter zero-volume simplexes via
    %-- vectorised area comparisons.

    %-- note silliness re. EVAL, so that MATLAB doesn't com-
    %-- plain re. OCTAVE '__' names.

        tria = eval( ...
          '__delaunayn__(vert)') ;

        ab = vert(tria(:,2),:) ...
           - vert(tria(:,1),:) ;
        ac = vert(tria(:,3),:) ...
           - vert(tria(:,1),:) ;

        aa = ab(:,1).* ac(:,2) ...
           - ab(:,2).* ac(:,1) ;

        lb = sumsq(ab,2) ;
        lc = sumsq(ac,2) ;

        ll = max (lb,lc) ;

        keep = abs(aa) >= ll * eps^.8 ;

        tria = tria(keep,:);

    else

    %-- the default call in MATLAB seems to be fast enough!!

        tria = ...
        delaunay (vert(:,1),vert(:,2));

    end

end


function [p, npix] = histroi(f, c, r)
%HISTROI Computes the histogram of an ROI in an image.
%   [P, NPIX] = HISTROI(F, C, R) computes the histogram, P, of a
%   polygonal region of interest (ROI) in image F.  The polygonal
%   region is defined by the column and row coordinates of its
%   vertices, which are specified (sequentially) in vectors C and R,
%   respectively. All pixels of F must be >= 0. Parameter NPIX is the
%   number of pixels in the polygonal region.

%   Copyright 2002-2004 R. C. Gonzalez, R. E. Woods, & S. L. Eddins
%   Digital Image Processing Using MATLAB, Prentice-Hall, 2004
%   $Revision: 1.5 $  $Date: 2003/09/05 16:14:35 $

% Generate the binary mask image.
B = roipoly(f, c, r);

% Compute the histogram of the pixels in the ROI.
p = imhist(f(B));

% Obtain the number of pixels in the ROI if requested in the output.
if nargout > 1
   npix = sum(B(:));
end


function [deltaTNew,xNew,tNew,k,dxdtCur,exitCode]=performOneAdaptiveRKStep(xCur,tCur,f,deltaT,deltaTMinMag,deltaTMaxMag,dxdtCur,order,solutionChoice,AbsTol,RelTol)
%%PERFORMONEADAPTIVERKSTEP Perform a single adaptive Runge-Kutta step,
%                   returning the new adjusted stepsize. This function is a
%                   subroutine of the function RKAdaptiveOverRange. Though
%                   most folks will just directly use the function
%                   RKAdaptiveOverRange to perform adaptive Runge-Kutta
%                   integration over a particular timespan, this subroutine
%                   has been broken out separately as one might want to
%                   program Runge-Kutta integration routines that
%                   adaptively integrate until a certain criterion is
%                   satisfied. As this function is meant as an efficient
%                   subroutine, none of the inputs provide default
%                   parameters if omitted.
%
%INPUTS: xCur The NX1 state vector at time tCur.
%        tCur The scalar current time of integration.
%           f The function handle for f(x,t)=dxdt over which integration is
%             to be performed. The output is NX1-dimensional.
%      deltaT The current stepsize to be taken in t. This can be positive
%             or negative.
% deltaTMinMag The minimum allowable magnitude of the step size.
% deltaTMaxMag The maximum allowable magnitude of the step size.
%      dxdtCur The value f(xCur,tCur). This is requested so that methods
%             that are FSAL (See comments to the function RungeKStep) can
%             avoid additional computations.
% order,solutionChoice  A pair of optional parameters that specify the
%              highest order of the embedded Runge-Kutta pair to use as
%              well as the specific algorithm to use. Details are given in
%              the comments to the RungeKStep function. If omitted or empty
%              matrices are passed, the default order of 5 is used and the
%              default solutionChoice of 0 is used.
%       RelTol The maximum relative error tolerance allowed, a positive
%              scalar (its use is explained in more detail below).
%       AbsTol The absolute error tolerance allowed, a positive scalar, of
%              the same for all components of x, or a positive NX1 vector.
%
%OUTPUTS: deltaTNew The value of deltaT that can be used for the next
%               adaptive step (i.e. pass it to this function). If the
%               function fails (exitCode~=0), then this will be set to the
%               last step size used.
%          xNew The updated NX1 state vector.
%          tNew The time of the updated state vector.
%             k The values of the derivatives f evaluated at various
%               points as determined by the algorithm used for the
%               step. This can be passed to functions like RKInterpPolys to
%               perform interpolation.
%      exitCode A code indicating whether the step could be successfully
%               performed. Possible values are
%               0: Integration was successful.
%               1: Unable to get a small enough step size.
%               3: Non-finite number encountered.
%
%The algorithm used for the step is described in the comments to the
%function RKAdaptiveOverRange.
%
%June 2015 David F. Crouse, Naval Research Laboratory, Washington D.C.
%(UNCLASSIFIED) DISTRIBUTION STATEMENT A. Approved for public release.

    %Determine the orders of the main and subsidiary embedded Runge-Kutta
    %formulae that were chosen. The order of convergence for the step size
    %testing is the smallest order taken. The isFSAL flag indicates whether
    %k(:,end) is the value of f evaluated at the next step.
    [orders,isFSAL]=RungeKStep(order,solutionChoice);
    RKOrder=min(orders);

    deltaTMag=abs(deltaT);
    deltaTSign=sign(deltaT);

    %The first time the choice in step size fails, it is adjusted the
    %"optimal" way in the Runge-Kutta-Fehlberg method. Additional times,
    %the step size is just halved in the hope that it will reach an
    %accepted value more quickly.
    failedReducingStepSize=false;
    moveOnToNextStep=false;
    while(moveOnToNextStep==false)
        %The returned value dxValdt in k(:,1) is for xCur and tCur, which
        %is curStep-1.
        [xPredMain,xPredSubsid,k]=RungeKStep(xCur,tCur,f,deltaT,dxdtCur,order,solutionChoice);

        %Integration can only be over finite functions.
        if(any(~isfinite(xPredMain))||any(~isfinite(xPredSubsid)))
            xNew=[];
            tNew=[];
            exitCode=3;
            deltaTNew=deltaTMag;
            return;
        end

        %The local error estimate. This must be transformed into a
        %combination relative/ absolute error term to determine whether
        %the step should be rejected.
        normFactor=max(max(abs(xPredMain),abs(xCur)),AbsTol/RelTol);
        theError=max(abs((xPredMain-xPredSubsid)./normFactor));

        if(theError>RelTol)
            if(deltaTMag<deltaTMinMag)
                %If the step size got too small, then return.
                xNew=[];
                tNew=[];
                exitCode=1;
                deltaTNew=[];
                return;
            end

            if(failedReducingStepSize==false)
                failedReducingStepSize=true;

                %The Fehlberg step reduction (using the relative error).
                deltaTMag=max(deltaTMinMag,deltaTMag*max(0.1, 0.8*(RelTol/theError)^(1/RKOrder)));
            else
                %Just halve the step size.
                deltaTMag=deltaTMag/2;
            end
            deltaT=deltaTSign*deltaTMag;
        else
            %The step was successful; leave the loop.
            moveOnToNextStep=true;
        end
    end

    %The step is successful, save the results from the step, including
    %information so that interpolation can be perfromed, if necessary.
    xNew=xPredMain;
    tNew=tCur+deltaT;

    %Save the current value to be reused on the next step, if the method
    %is an FSAL function, so that an evaluation of f can be avoided.
    if(isFSAL)
        dxdtCur=k(:,end);
    else
        dxdtCur=f(xNew,tNew);
    end

    %If a step is successful, then increase the step size for the
    %next step in the standard manner used with Runge-Kutta-
    %Fehlberg methods, but limit the maximum size of the increase
    %to a scale factor of 4. This avoid huge step sizes when the
    %predicted error is very small.
    deltaTMag=min(deltaTMaxMag,deltaTMag*min(4,0.8*(RelTol/theError)^(1/RKOrder)));

    %Since the minimum step size changes every loop, this makes sure that
    %deltaT does not go beneath it just because the loop changed.
    deltaTMag=max(deltaTMag,deltaTMinMag);
    deltaTNew=deltaTMag*deltaTSign;

    exitCode=0;
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 [S,D,J] = sample_discrete(D,n)
  % SAMPLE_DISCRETE  Sample a discrete distribution given by D n times. This
  % employs the "Alias Table Method". Ensuring that the running time is O(n +
  % m)
  %
  % Inputs:
  %   D  m list of probabilities summing to 1
  %   n  number of samples to output
  % Outputs:
  %   S  n list of indices into D
  %   D  m list of alias table heights
  %   J  m list of "upper half" reindices
  %

  % Assume column vector
  D = D(:);
  % https://hips.seas.harvard.edu/blog/2013/03/03/the-alias-method-efficient-sampling-with-many-discrete-outcomes/
  m = numel(D);
  assert(abs(sum(D) - 1)<1e-15);
  % We want to sort based on above or below 1/n
  D = D*m;
  % now we can sort based on above or below 1
  % Below queue: http://www.alecjacobson.com/weblog/?p=3933
  % and preallocate up to 2*m (extra m to be safe, I don't think it's needed)
  B = find(D<1);
  Bl = numel(B);
  B(end+1:2*m) = 0;
  % After queue, and preallocate up to m
  A = find(D>=1);
  Al = numel(A);
  A(end+1:m) = 0;
  % Upper half list (initialize with this index because above includes "equal")
  J = (1:m)';

  % While below and above still have elements
  while Bl>0 && Al>0
    % pop below
    b = B(Bl);
    Bl = Bl - 1;
    % Look above
    a = A(Al);
    % a going to be b's upper half
    J(b) = a;
    % lob off enough to fit D(b) to 1
    %D(a) = D(a) - (1.0 - D(b));
    % Reduce rounding error (see comments above)
    D(a) = (D(a) + D(b)) - 1.0;
    if D(a) < 1
      % pop off above
      Al = Al - 1;
      % push onto below
      Bl = Bl+1;
      B(Bl) = a;
    % else still on above
    end
  end

  R1 = floor(rand(n,1)*m)+1;
  R2 = rand(n,1);
  I = (1:m)';
  % select those that are in upper half
  upper = R2>=D(R1);
  S = I(R1);
  S(upper) = J(R1(upper));

end


function pass = test_biharm( )

tol = 1e7*chebfunpref().cheb2Prefs.chebfun2eps;

%  Test some cylindrical harmonics
%k = [];
%get eigenvalues
err=[];
k=1;
for ell = [ 1 2 3]
    for m = 1:abs(ell)
        %find eigenvalues
        jzero = roots(chebfun(@(x) besselj(ell,x), [sqrt((3/4)^2*pi^2+ell^2) (m+ell/2)*pi]));
        jzero=jzero(m);
        f = diskfun.harmonic(ell, m);
        lap2 = biharm(f);
        %pass(k, 1) = numel(lap2.pivotValues) == numel(f.pivotValues);
        %%NOTE: doesn't always get rank right
        err(k) = SampleError((jzero)^4*f, lap2)/(jzero)^4;
        pass(k) = SampleError((jzero)^4*f, lap2) < 2*(jzero)^4*tol;
        k = k+1;
    end
end

pass = pass(:)';
end

function sample_error = SampleError(h, g)
m = 7;
n = m-1;
[x, y] = getPoints(m, n);
[L2, T2] = meshgrid(x, y);
F = feval(h, L2, T2, 'polar');
approx = fevalm(g, x, y);
sample_error = norm(F(:) - approx(:), inf);
end

function [x, y] = getPoints(m, n)

x = trigpts(2*n, [-pi pi]);
y = chebpts(m);
y = y(ceil(m/2):end);

end


function UNew = fluidDirichlet2D(varargin);
% fluidDirichlet2D: solve fluid registraion in 2D with Dirichlet
%        boundary conditions
%
%
% author: Nathan D. Cahill
% email: nathan.cahill@rit.edu
% affiliation: Rochester Institute of Technology
% date: January 2014
% licence: GNU GPL v3
%
% Copyright Nathan D. Cahill
% Code available from https://github.com/tomdoel/npReg
%
%

% parse input arguments
[DU,F,mu,lambda,PixSize,NumPix,HX,HY] = parse_inputs(varargin{:});

% construct filters that implement discretized Navier-Lame equations
d1 = [1;-2;1]/(PixSize(1)^2);
d2 = [1 -2 1]/(PixSize(2)^2);
d12 = [1 0 -1;0 0 0;-1 0 1]/(4*PixSize(1)*PixSize(2));

[A11,A22] = deal(zeros(3,3));
A11(:,2) = A11(:,2) + (lambda+2*mu)*d1;
A11(2,:) = A11(2,:) + mu*d2;
A22(:,2) = A22(:,2) + mu*d1;
A22(2,:) = A22(2,:) + (lambda+2*mu)*d2;

A12 = d12*(lambda+mu)/4;
A21 = A12;

% multiply force field by adjoint of Navier-Lame equations
Fnew = zeros(NumPix(1),NumPix(2),2);
Fnew(:,:,1) = imfilter(F(:,:,1),A22,'replicate') - imfilter(F(:,:,2),A12,'replicate');
Fnew(:,:,2) = imfilter(F(:,:,2),A11,'replicate') - imfilter(F(:,:,1),A21,'replicate');

% compute sine transform of new force field
FnewF1 = imag(fft(imag(fft(Fnew(:,:,1),2*NumPix(1)-2,1)),2*NumPix(2)-2,2));
FnewF2 = imag(fft(imag(fft(Fnew(:,:,2),2*NumPix(1)-2,1)),2*NumPix(2)-2,2));
FnewF1 = FnewF1(1:NumPix(1),1:NumPix(2));
FnewF2 = FnewF2(1:NumPix(1),1:NumPix(2));

% construct images of coordinates scaled by pi/(N or M)
[alpha,beta] = ndgrid(pi*(0:(NumPix(1)-1))/(NumPix(1)-1),pi*(0:(NumPix(2)-1))/(NumPix(2)-1));

% construct LHS factor
LHSfactor = mu.*(lambda+2*mu).*(2*cos(alpha) + 2*cos(beta) - 4).^2;

% set origin term to 1, as DC term does not matter
LHSfactor(1,1) = 1;

% solve for FFT of V
VF1 = FnewF1./LHSfactor;
VF2 = FnewF2./LHSfactor;

% perform inverse DST
V1 = imag(ifft(imag(ifft(VF1,2*NumPix(1)-2,1)),2*NumPix(2)-2,2));
V2 = imag(ifft(imag(ifft(VF2,2*NumPix(1)-2,1)),2*NumPix(2)-2,2));

% crop and concatenate
V = cat(3,V1(1:NumPix(1),1:NumPix(2)),V2(1:NumPix(1),1:NumPix(2)));

% construct estimate of transformation Jacobian
J = zeros(NumPix(1),NumPix(2),2,2);
J(:,:,1,1) = 1 - imfilter(V(:,:,1),HX,'replicate','same');
J(:,:,2,1) = -imfilter(V(:,:,1),HY,'replicate','same');
J(:,:,1,2) = -imfilter(V(:,:,2),HX,'replicate','same');
J(:,:,2,2) = 1 - imfilter(V(:,:,2),HY,'replicate','same');

% now perform Euler integration to construct new displacements
UNew = zeros(NumPix(1),NumPix(2),2);
UNew(:,:,1) = J(:,:,1,1).*V(:,:,1) + J(:,:,1,2).*V(:,:,2);
UNew(:,:,2) = J(:,:,2,1).*V(:,:,1) + J(:,:,2,2).*V(:,:,2);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [DU,F,mu,lambda,PixSize,NumPix,HX,HY] = parse_inputs(varargin);

% get arguments
F = varargin{2};
PixSize = varargin{4}(1:2);
NumPix = [varargin{5} varargin{6}];
mu = varargin{8};
lambda = varargin{9};
DU = varargin{11};
HX = varargin{12};
HY = varargin{13};
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


% Performs fast detrended fluctuation analysis on a nonstationary input signal to
% obtain an estimate for the scaling exponent.
%
% Useage:
% [alpha, intervals, flucts] = fastdfa(x)
% [alpha, intervals, flucts] = fastdfa(x, intervals)
% Inputs
%    x          - input signal: must be a column vector
% Optional inputs
%    intervals  - List of sample interval widths at each scale
%                 (If not specified, then a binary subdivision is constructed)
%
% Outputs:
%    alpha      - Estimated scaling exponent
%    intervals  - List of sample interval widths at each scale
%    flucts     - List of fluctuation amplitudes at each scale
%
% (c) 2006 Max Little. If you use this code, please cite:
% M. Little, P. McSharry, I. Moroz, S. Roberts (2006),
% Nonlinear, biophysically-informed speech pathology detection
% in Proceedings of ICASSP 2006, IEEE Publishers: Toulouse, France.
%

function [alpha, intervals, flucts] = ML_fastdfa(x, varargin)

[xpts, ypts] = ML_fastdfa_core(x, varargin{:});

% Sort the intervals, and produce a log-log straight line fit
datapts   = sortrows([xpts, ypts],1);
intervals = datapts(:,1);
flucts    = datapts(:,2);

coeffs    = polyfit(log10(xpts), log10(ypts), 1);
alpha     = coeffs(1);

end


%% Set up paths

path(path,'mesh_functions/');
path(path,'../data');

%% Read shape

[X,T] = readOff('../data/meshes/moomoo_s0.off');
M = getMeshData(X,T,10); % compute 10 LB eigenfunctions for fun

%% Set up Gaussian blur function

blurTime = .001; % if this gets too small, distances get noisy
blurSteps = 3;

% h = blurTime/blurSteps;

blur = @(x) blurOnMesh(x,M,blurTime,blurSteps); % faster than pre-factored?
blurTranspose = @(x) blurOnMesh(x,M,blurTime,blurSteps,1);

%% Design a few functions to average

centerVerts = [300 100 600];
nFunctions = length(centerVerts);

distributions = zeros(M.numVertices,nFunctions);

for i=1:nFunctions
    distributions(centerVerts(i),i) = 1./M.areaWeights(centerVerts(i));
end

distributions = blur(distributions);

close all
for i=1:nFunctions
    f = subplot(1,nFunctions,i);
    showDescriptor(M,distributions(:,i),[],[],[],f);
    colorbar off;
    title(sprintf('Distribution %d',i));
end

%% Take the barycenter

euclideanBarycenter = sum(distributions,2)/nFunctions;

f = subplot(1,2,1);
showDescriptor(M,euclideanBarycenter,[],[],[],f);
title('Euclidean barycenter');
colorbar off;

alpha = [1 1 1];
barycenter = convolutionalBarycenter(distributions,alpha,M.areaWeights,blur,blurTranspose);

f = subplot(1,2,2);
showDescriptor(M,barycenter,[],[],[],f);
title('Wasserstein barycenter');
colorbar off;

%% Test different entropy limits

averageEntropy = -mean(sum(bsxfun(@times,distributions.*log(distributions),M.areaWeights),1));

entropyChanges = [-1.5 -1 -.5 0 .5 1 1.5];

euclideanBarycenter = sum(distributions,2)/nFunctions;

f = subplot(1,length(entropyChanges)+1,1);
showDescriptor(M,euclideanBarycenter,[],[],[],f);
title('Euclidean barycenter');
colorbar off;

for i=1:length(entropyChanges)
    targetEntropy = averageEntropy + entropyChanges(i);

    alpha = [1 1 1];
    barycenter = convolutionalBarycenter(distributions,alpha,M.areaWeights,blur,blurTranspose,targetEntropy);

    f = subplot(1,length(entropyChanges)+1,i+1);
    showDescriptor(M,barycenter,[],[],[],f);
    title(sprintf('entropy < average+(%g)',entropyChanges(i)));
    colorbar off;

    drawnow;
end

%% Try displacement interpolation

nTimeSteps = 100;

p1 = distributions(:,1);
p2 = distributions(:,2);

interp = zeros(M.numVertices,nTimeSteps);
for i=1:nTimeSteps
    fprintf('i = %d/%d\n',i,nTimeSteps);
    t = (i-1)/(nTimeSteps-1);
    alpha = [t 1-t]; % is this right?
    interp(:,i) = convolutionalBarycenter([p1 p2],alpha,M.areaWeights,blur,blurTranspose,averageEntropy);
end

%% Animate the result

f = figure;
for i=1:nTimeSteps
    clf;
    showDescriptor(M,interp(:,i),[],[],[],f);
    colorbar off;
    drawnow;
end


function bw = bwfunc(re)
mm = 1;
m =mean2(re);
s = std2(re);
maxv = max(re(:));
switch mm
    case 1
        T = m + 0.5*(maxv - m);
    case 2
        ratio = 0.6;
        T = ratio * maxv;
    case 3
        ratio = 3;
        T = m+ ratio*s;
end
bw = re> T;
end


function subRoPS =  subRoPSFunc(projNeighbor,binSize)
%get the distribution matrix
neighbNum = length(projNeighbor);
distrMatrix = zeros(binSize,binSize);
minX = min(projNeighbor(:,1));
stepX = (max(projNeighbor(:,1))-minX)/binSize;
minY = min(projNeighbor(:,2));
stepY = (max(projNeighbor(:,2))-minY)/binSize;

if stepX==0 || stepY==0
    subRoPS = [0,0,0,0,0];
    return;
end

for k=1:neighbNum
    idxX = ceil((projNeighbor(k,1) - minX)/stepX);
    idxY = ceil((projNeighbor(k,2) - minY)/stepY);
    if idxX>binSize      idxX = binSize;  end
    if idxX<1                idxX = 1;            end
    if idxY>binSize     idxY = binSize;   end
    if idxY<1                idxY = 1;            end
    distrMatrix(idxX,idxY) = distrMatrix(idxX,idxY)+1;
end
distrMatrix = distrMatrix/neighbNum;%normalization
%calculate the moment of this distribution matrix
meanX = 0;
meanY = 0;
pde = 0;
for idxX = 1:binSize
    for idxY = 1:binSize
        meanX = meanX+idxX*distrMatrix(idxX,idxY);
        meanY = meanY+idxY*distrMatrix(idxX,idxY);
        if distrMatrix(idxX,idxY)>0
            pde = pde - distrMatrix(idxX,idxY)*log2(distrMatrix(idxX,idxY));
        end
    end
end
u11 = 0;
u21 = 0;
u12 = 0;
u22 = 0;

for idxX = 1:binSize
    for idxY = 1:binSize
        u11 = u11+(idxX-meanX)*(idxY-meanY)*distrMatrix(idxX,idxY);
        u21 = u21+(idxX-meanX)^2*(idxY-meanY)*distrMatrix(idxX,idxY);
        u12 = u12+(idxX-meanX)*(idxY-meanY)^2*distrMatrix(idxX,idxY);
        u22 = u22+(idxX-meanX)^2*(idxY-meanY)^2*distrMatrix(idxX,idxY);
    end
end
 subRoPS = [u11,u21,u12,u22,pde];


function [mu, inv_sigma] = fit_gaussian(x,class)

N = max(class);
mu = zeros(N,size(x,2));
inv_sigma = zeros(size(x,2),size(x,2),N);

for i=1:N,
    mu(i,:) = mean(x(class==i,:));
    inv_sigma(:,:,i) = inv(cov(x(class==i,:)));
end


% This library is coded for the double pendulum example
% Last Updated: 2019/07/30
% Coded By: K.Kahirman

function [Data,Sym_Struct]=SINDyLib(X,dX,iter,u,Highest_Poly_Order,Highest_Trig_Order,Highest_U_Order,Highest_dPoly_Order)
%% First get the size of the X matrix, determin the data length and the number of variables we have.
[Data_Length,Variable_Number]=size(X);
[~,Variable_Number_dX]=size(dX);
[~,Variable_Number_u]=size(u);
%Also create the symbolic variable
Symbol=sym('z',[Variable_Number,1]);
Symbol_dX=sym('dz',[Variable_Number,1]);
Symbol_u=sym('u',[Variable_Number_u,1]);

%Now according the Highest Polynomial Order entered, we will calculate the data matrix.
Data=[];
Index=1;

%% First calculate the polynomial term

% Form basis vector
Basis=[X(:,1) X(:,2) X(:,1)-X(:,2) X(:,1)-2*X(:,2) 2*X(:,1)-X(:,2) 2*X(:,1)-2*X(:,2)];
Basis_Sym=[Symbol(1) Symbol(2) Symbol(1)-Symbol(2) Symbol(1)-2*Symbol(2) 2*Symbol(1)-Symbol(2) 2*Symbol(1)-2*Symbol(2)];

% Add the trigonometric form
for i=1:size(Basis,2)
   Data(:,Index)=sin(Basis(:,i));
   Sym_Struct{1,Index}=sin(Basis_Sym(1,i));
   Index=Index+1;
end

for i=1:size(Basis,2)
   Data(:,Index)=cos(Basis(:,i));
   Sym_Struct{1,Index}=cos(Basis_Sym(1,i));
   Index=Index+1;
end

for i=3:size(Basis,2)
   Data(:,Index)=cos(Basis(:,i)).^2;
   Sym_Struct{1,Index}=cos(Basis_Sym(1,i))^2;
   Index=Index+1;
end

% Adding following terms will reduce the noise robustness
% for i=3:size(Basis,2)
%    Data(:,Index)=sin(Basis(:,1)).*cos(Basis(:,i));
%    Sym_Struct{1,Index}=sin(Basis_Sym(1,1))*cos(Basis_Sym(1,i));
%    Index=Index+1;
% end
%
% for i=3:size(Basis,2)
%    Data(:,Index)=cos(Basis(:,1)).*cos(Basis(:,i));
%    Sym_Struct{1,Index}=cos(Basis_Sym(1,1))*cos(Basis_Sym(1,i));
%    Index=Index+1;
% end
%
% for i=3:size(Basis,2)
%    Data(:,Index)=sin(Basis(:,2)).*cos(Basis(:,i));
%    Sym_Struct{1,Index}=sin(Basis_Sym(1,2))*cos(Basis_Sym(1,i));
%    Index=Index+1;
% end
%
% for i=3:size(Basis,2)
%    Data(:,Index)=cos(Basis(:,2)).*cos(Basis(:,i));
%    Sym_Struct{1,Index}=cos(Basis_Sym(1,2))*cos(Basis_Sym(1,i));
%    Index=Index+1;
% end

% Add polynomial term
Data(:,Index)=X(:,3);
Sym_Struct{1,Index}=Symbol(3);
Index=Index+1;

Data(:,Index)=X(:,4);
Sym_Struct{1,Index}=Symbol(4);
Index=Index+1;

for i=3:size(Basis,2)
   Data(:,Index)=X(:,3).*sin(Basis(:,i));
   Sym_Struct{1,Index}=Symbol(3)*sin(Basis_Sym(1,i));
   Index=Index+1;
end

for i=3:size(Basis,2)
   Data(:,Index)=X(:,4).*sin(Basis(:,i));
   Sym_Struct{1,Index}=Symbol(4)*sin(Basis_Sym(1,i));
   Index=Index+1;
end

for i=3:size(Basis,2)
   Data(:,Index)=X(:,3).^2.*sin(Basis(:,i));
   Sym_Struct{1,Index}=Symbol(3)^2*sin(Basis_Sym(1,i));
   Index=Index+1;
end

for i=3:size(Basis,2)
   Data(:,Index)=X(:,4).^2.*sin(Basis(:,i));
   Sym_Struct{1,Index}=Symbol(4)^2*sin(Basis_Sym(1,i));
   Index=Index+1;
end

% Add dx term
Data(:,Index)=dX(:,1);
Sym_Struct{1,Index}=Symbol_dX(iter);
Index=Index+1;

for i=3:size(Basis,2)
   Data(:,Index)=dX(:,1).*cos(Basis(:,i)).^2;
   Sym_Struct{1,Index}=Symbol_dX(iter)*cos(Basis_Sym(1,i)).^2;
   Index=Index+1;
end

% Add constant
%Order zero:
Data(:,Index)=ones(Data_Length,1);
Sym_Struct{1,Index}=1;


% =========================================================================
% NCSR for image denoising, Version 1.0
% Copyright(c) 2013 Weisheng Dong, Lei Zhang, Guangming Shi, and Xin Li
% All Rights Reserved.
%
% ----------------------------------------------------------------------
% Permission to use, copy, or modify this software and its documentation
% for educational and research purposes only and without fee is here
% granted, provided that this copyright notice and the original authors'
% names appear on all copies and supporting documentation. This program
% shall not be used, rewritten, or adapted as the basis of a commercial
% software or hardware product without first obtaining permission of the
% authors. The authors make no representations about the suitability of
% this software for any purpose. It is provided "as is" without express
% or implied warranty.
%----------------------------------------------------------------------
%
% This is an implementation of the algorithm for image interpolation
%
% Please cite the following paper if you use this code:
%
% Weisheng Dong, Lei Zhang, Guangming Shi, and Xin Li.,"Nonlocally
% centralized sparse representation for image restoration", IEEE Trans. on
% Image Processing, vol. 22, no. 4, pp. 1620-1630, Apr. 2013.
%
%--------------------------------------------------------------------------
function [pos_arr, wei_arr]  =  Block_matching(im, par)
S         =  30;
f         =  par.win;
f2        =  f^2;
nv        =  par.nblk;
s         =  par.step;
hp        =  max(12*par.nSig, par.hp);

N         =  size(im,1)-f+1;
M         =  size(im,2)-f+1;
r         =  [1:s:N];
r         =  [r r(end)+1:N];
c         =  [1:s:M];
c         =  [c c(end)+1:M];
L         =  N*M;
X         =  zeros(f*f, L, 'single');

k    =  0;
for i  = 1:f
    for j  = 1:f
        k    =  k+1;
        blk  =  im(i:end-f+i,j:end-f+j);
        X(k,:) =  blk(:)';
    end
end

I     =   (1:L);
I     =   reshape(I, N, M);
N1    =   length(r);
M1    =   length(c);
pos_arr   =  zeros(nv, N1*M1 );
wei_arr   =  zeros(nv, N1*M1 );
X         =  X';

for  i  =  1 : N1
    for  j  =  1 : M1

        row     =   r(i);
        col     =   c(j);
        off     =  (col-1)*N + row;
        off1    =  (j-1)*N1 + i;

        rmin    =   max( row-S, 1 );
        rmax    =   min( row+S, N );
        cmin    =   max( col-S, 1 );
        cmax    =   min( col+S, M );

        idx     =   I(rmin:rmax, cmin:cmax);
        idx     =   idx(:);
        B       =   X(idx, :);
        v       =   X(off, :);

        dis     =   (B(:,1) - v(1)).^2;
        for k = 2:f2
            dis   =  dis + (B(:,k) - v(k)).^2;
        end
        dis   =  dis./f2;
        [val,ind]   =  sort(dis);
        dis(ind(1))  =  dis(ind(2));

        wei         =  exp( -dis(ind(1:nv))./hp );
        wei         =  wei./(sum(wei)+eps);
        indc        =  idx( ind(1:nv) );
        pos_arr(:,off1)  =  indc;
        wei_arr(:,off1)  =  wei;
    end
end
pos_arr  = pos_arr';
wei_arr  = wei_arr';