function [M1,MW,MW1] = perform_wavelet_matching(M1,M,options)

% perform_wavelet_matching - match multiscale histograms
%
% M1 = perform_wavelet_matching(M1,M,options);
%
%   M1 is the image to synthesize.
%   M is the exemplar image.
%
%   This function match the histogram of the image and the histogram
%   of each sub-band of a wavelet-like pyramid.
%
%   To do texture synthesis, one should apply several time this function.
%   You can do it by setting the value of options.niter_synthesis.
%   This leads to the synthesis as described in
%
%       Pyramid-Based Texture Analysis/Synthesis
%       D. Heeger, J. Bergen,
%       Siggraph 1995
%
%   The transform used for synthesis is options.synthesis_method, which can
%   be either 'steerable' 'wavelets-ortho' 'quincunx-ti' 'wavelets-ti'
%       'wavelets-circle'.
%
%   See also perform_wavelet_transform, perform_histogram_equalization
%
%   Copyright (c) 2007 Gabriel Peyre

options.null = 0;
niter_synthesis = getoptions(options, 'niter_synthesis', 1);
verb = getoptions(options, 'verb', 0);

if not(isfield(options, 'color_mode'))
    options.color_mode = 'pca';
end
if isfield(options, 'color_mode') && strcmp(options.color_mode, 'pca') && ~isfield(options, 'ColorP') && size(M,3)==3
    [tmp,options.ColorP] = change_color_mode(M,+1,options);
end
rgb_postmatching = getoptions(options, 'rgb_postmatching', 0);

if size(M,3)==3
    options.niter_synthesis = 1;
    options.verb = 0;
    for iter=1:niter_synthesis
        if verb
            progressbar(iter, niter_synthesis);
        end
        % color images
        M  = change_color_mode(M, +1,options);
        M1 = change_color_mode(M1,+1,options);
        for i=1:size(M,3)
            M1(:,:,i) = perform_wavelet_matching(M1(:,:,i),M(:,:,i), options);
        end
        M  = change_color_mode(M, -1,options);
        M1 = change_color_mode(M1,-1,options);
        if rgb_postmatching
            for i=1:size(M,3)
                M1(:,:,i) = perform_histogram_equalization(M1(:,:,i),M(:,:,i));
            end
        end
    end
    return;
end

if size(M,3)>1
    for i=1:size(M,3)
        [M1(:,:,i),MW,MW1] = perform_wavelet_matching(M1(:,:,i),M(:,:,i),options);
    end
    return;
end

n = size(M,1);
n1 = size(M1,1);

synthesis_method = getoptions(options, 'synthesis_method', 'steerable');

m = 2^( ceil(log2(n)) );
m1 = 2^( ceil(log2(n1)) );
M = perform_image_extension(M,m);
M1 = perform_image_extension(M1,m1);

% precompute input
MW = my_transform(M, m, +1, options);

for iter=1:niter_synthesis
    if verb
        progressbar(iter, niter_synthesis);
    end
    % spatial equalization
    M1 = my_equalization(M1,M);
    % forward transforms
    MW1 = my_transform(M1, m1, +1, options);
    % wavelet domain equalization
    MW1 = my_equalization(MW1,MW);
    % backward transform
    M1 = my_transform(MW1, m1, -1, options);
    % spatial equalization
    M1 = my_equalization(M1,M);
end

M1 = M1(1:n1,1:n1);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function M = my_equalization(M,M0)

options.absval = 0;
options.rows = 0;
options.cols = 0;
options.dim3 = 1;

if iscell(M)
    for i=1:min(length(M),length(M0))
        M{i} = my_equalization(M{i},M0{i});
    end
    return;
end
if size(M,3)>1
    for i=1:min(size(M,3),size(M0,3))
        M(:,:,i) = my_equalization(M(:,:,i),M0(:,:,i));
    end
    return;
end
M = perform_histogram_equalization(M,M0);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function M = my_transform(M, n, dir, options)

synthesis_method = getoptions(options, 'synthesis_method', 'steerable');
deltaJ = 5;
if strcmp(synthesis_method, 'steerable')
    deltaJ = 3;
end
Jmax = log2(n)-1;
Jmin = max(Jmax-deltaJ+1,3);

% steerable options
if not(isfield(options, 'nb_orientations'))
    options.nb_orientations = 4;
end
% wave ortho options
options.wavelet_type = 'biorthogonal_swapped';
options.wavelet_vm = 4;

switch synthesis_method
    case 'steerable'
        M = perform_steerable_transform(M, Jmin, options);
    case 'wavelets-ortho'
        if dir==-1
            M = convert_wavelets2list(M, Jmin);
        end
        M = perform_wavelet_transform(M, Jmin, dir, options);
        if dir==1
            M = convert_wavelets2list(M, Jmin);
        end
    case 'quincunx-ti'
        M = perform_quicunx_wavelet_transform_ti(M,Jmin,options);
    case 'wavelets-ti'
        options.wavelet_type = 'biorthogonal';
        options.wavelet_vm = 3;
        M = perform_atrou_transform(M,Jmin,options);
    case 'wavelets-circle'
        if dir==-1
            M = wavecircle2list(M,Jmin);
        end
        wavelet_modulo = getoptions(options, 'wavelet_modulo', 2*pi);
        M = perform_circle_haar_transform(M, Jmin, dir, wavelet_modulo, options);
        if dir==1
            M = wavecircle2list(M,Jmin);
        end
    otherwise
        error('Unknown transform.');
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function MW = wavecircle2list(M,Jmin)

if not(iscell(M))
    n = size(M,1); Jmax = log2(n)-1;
    MW = {};
    for j=Jmax:-1:Jmin
        MW{end+1} = M(end/2+1:end,:); M(end/2+1:end,:) = [];
        MW{end+1} = M(:,end/2+1:end); M(:,end/2+1:end) = [];
    end
    MW{end+1} = M;
else
    n = size(M{1},1)*2;
    MW = M{end};
    for i=length(M)-1:-1:1
        if mod(i,2)==0
            MW = [MW, M{i}];
        else
            MW = [MW; M{i}];
        end
    end
end


function value = year_length_bahai ( y )

%*****************************************************************************80
%
%% YEAR_LENGTH_BAHAI returns the number of days in a Bahai year.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    24 September 2012
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer Y, the year to be checked.
%
%    Output, integer VALUE, the number of
%    days in the year.
%
  if ( year_is_leap_bahai ( y ) )
    value = 366;
  else
    value = 365;
  end

  return
end


function M1 = vox2ras_0to1(M0)
% M1 = vox2ras_0to1(M0)
%
% Converts a 0-based vox2ras matrix to 1-based, ie,
% Pxyz = M0*[c r s 1]' = M1*[(c+1) (r+1) (s+1) 1]'
%

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

M1 = [];

if(nargin ~= 1)
  fprintf('M1 = vox2ras_0to1(M0)\n');
  return;
end

Q = zeros(4);
Q(1:3,4) = ones(3,1);

M1 = inv(inv(M0)+Q);

return;


function rule_num = wandzura_rule_num ( )

%*****************************************************************************80
%
%% WANDZURA_RULE_NUM returns the number of Wandzura rules available.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    10 December 2006
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Stephen Wandzura, Hong Xiao,
%    Symmetric Quadrature Rules on a Triangle,
%    Computers and Mathematics with Applications,
%    Volume 45, Number 12, June 2003, pages 1829-1840.
%
%  Parameters:
%
%    Output, integer RULE_NUM, the number of rules available.
%
  rule_num = 6;

  return
end


function [Min_numerator,r]=ReGet_min_numerator(x1,x2,N,m,r,fs)
%******************************************************
% $ This function is usded to increase r value if the 'at least 5 match' is not achieved.
% $ Used for both COSEn and COFMEn.
%
% $ Variable declaration:
% x1 and x2 are the vector at dimentions of m and m+1
% N is time series length
% m is embedding dimension (usually m=1)
% r is changed threshold value
% fs sample rate
%
% $ Author: Chengyu Liu (bestlcy@sdu.edu.cn)
%           Institute of Biomedical Engineering,
%           Shandong University
% $Last updated:  2015.10.10
% Las updated: 2017.19.12 (by Giulia Da Poian) vectorized
%
%   LICENSE:
%       This software is offered freely and without warranty under
%       the GNU (v3 or later) public license. See license file for
%       more information

dim = N-m;

% Fast implementation

t1 = repmat(x2(:,1),[1 dim]);
t2 = toeplitz([x2(1,1); flipud(x2(2:end,1))], x2(:,1));
t3 = repmat(x2(:,2),[1 dim]);
t4 = toeplitz([x2(1,2); flipud(x2(2:end,2))], x2(:,2));
d2max = max(abs(t1-t2),abs(t3-t4));
d2max = cell2mat(arrayfun(@(x) circshift(d2max(x,:),[1 dim-x+1]),(1:dim)','un',0));
Min_numerator = numel(find(d2max(dim,:)<=r));

% Old implementation (slower)
% % for i=1:N-m
% %     Min_numerator=0;
% %     for j=1:N-m
% %         d2max(i,j)=max(abs(x2(i,:)-x2(j,:)));
% %         if  d2max(i,j)<=r
% %             Min_numerator=Min_numerator+1
% %         end
% %     end
% % end

if N<20
    r=r+1;
else
    r=r+round(1000/fs);
end


function [Q, vertexBool, fileNameOut] = lrsReadRay(modelName,param)
% Read in a vertex representation (*.ext) of a polytope derived from lrs
% See http://cgm.cs.mcgill.ca/~avis/C/lrslib/USERGUIDE.html#file
%
% USAGE:
%
%    [Q, vertexBool, fileNameOut] = lrsReadRay(modelName,param)
%
% INPUT:
% modelName     string giving the prefix of the *.ext file that will contain the vertex representation
%               It is assumed the file is pwd/*.ine, otherwise provide the full path.
%
% OUTPUT:
% Q             m x n integer matrix where each row is a variable and each column is a vertex or ray
% vertexBool         n x 1 Boolean vector indicating which columns of Q are vertices
%                    By default, all columns of Q are assumed to be rays.
%
% Ronan Fleming 2021

if ~exist('param','var')
    param = struct();
end
if ~isfield(param,'positivity')
    param.positivity = 0;
end
if ~isfield(param,'inequality')
    param.positivity = 0;
end
if ~isfield(param,'sh')
    param.sh = 0;
end
if ~exist('modelName','var')
    modelName = 'test';
end

if param.inequality == 0
%     if param.positivity == 0
%         modelName = [modelName '_pos_eq'];
%     else
%         modelName = [modelName '_neg_eq'];
%     end
else
    if param.positivity == 1
        modelName = [modelName '_pos_ineq'];
    else
        modelName = [modelName '_neg_ineq'];
    end
end
fileNameOut = [modelName '.ext'];

fid = fopen(fileNameOut);
if fid<0
    disp(fileNameOut)
    error('Could not open lrs output file.');
end

% pause(eps)
while 1
    tline = fgetl(fid);
    if strcmp(tline, 'begin')
        break;
    elseif ~ischar(tline)
        error('Could not read lrs output file.');
    end
end

% find the number of columns
C = textscan(fid, '%s %f %s', 1);
nCols = C{2};

% move on pointer one line
fgetl(fid);

% count the number of rows in the file
nRows = 0;
while 1
    if ~strcmp(fgetl(fid), 'end')
        nRows = nRows + 1;
    else
        break;
    end
end

fclose(fid);

% pwd
fid = fopen(fileNameOut);
if fid<0
    disp(fileNameOut)
    error('Could not open lrs output file.');
end

while 1
    if strcmp(fgetl(fid), 'begin')
        break;
    end
end

% find the number of columns
C = textscan(fid, '%s %f %s', 1);
nCols = C{2};

% move on pointer one line
fgetl(fid);

% read rows into a matrix
P = sparse(nRows, nCols);

for r = 1:nRows
    line = fgetl(fid);
    if ~contains(line,'/')
        scannedLine = sscanf(line, '%d')';  % added transpose here for reading in LP solutions
        P(r, :) = scannedLine;
    else
        line = strrep(line, '/', '.');
        scannedLine = sscanf(line, '%f')';
        for c = 1:nCols
            M = mod(scannedLine(c), 1);
            if M ~= 0
                F = fix(scannedLine(c));
                scannedLine(c) = F / M;
            else
                scannedLine(c) = int16(scannedLine(c));
            end
        end
        % pause(eps);
    end
end
fclose(fid);

% Each vertex is given in the form
% 1   v0   v 1 ...   vn-1
V = P(P(:, 1) ~= 0, 2:end)';
%remove zero vertices
V = V(:,sum(V,1)~=0);

% Each ray is given in the form
% 0   r0   r 1 ...   rn-1
R = P(P(:, 1) == 0, 2:end)';  % not the transpose

% order the rays by the number of nnz
[mlt, nlt] = size(R);
nNonZero = zeros(nlt, 1);
for n = 1:nlt
    nNonZero(n) = nnz(R(:, n));
end
%remove zero rays
R = R(:,nNonZero~=0);
[B, IX] = sort(nNonZero);
R = R(:, IX);

%first vertices then rays
Q = [V, R];
vertexBool = false(size(Q,2),1);
vertexBool(1:size(V,2))=1;


function edge = clipLine3d(line, box)
%CLIPLINE3D Clip a line with a box and return an edge.
%
%   EDGE = clipLine3d(LINE, BOX);
%   Clips the line LINE with the bounds given in BOX, and returns the
%   corresponding edge.
%
%   If the line lies totally outside of the box, returns a 1-by-6 row array
%   containing only NaN's.
%
%   If LINE is a N-by-6 array, with one line by row, returns the clipped
%   edge coresponding to each line in a N-by-6 array.
%
%   See also:
%   lines3d, edges3d, createLine3d
%

% ---------
% author : David Legland
% e-mail: david.legland@inra.fr
% INRA - TPV URPOI - BIA IMASTE
% created the 30/10/2008 from drawLine3d

%   HISTORY
%   30/10/2008 replace intersectPlaneLine by intersectLinePlane
%   25/11/2008 improve test for bounds, and use more explicit code
%   22/06/2009 fig bug, add support for several lines
%   16/11/2010 use middle point for checking edge bounds

% get box limits
xmin = box(1); xmax = box(2);
ymin = box(3); ymax = box(4);
zmin = box(5); zmax = box(6);

% extreme corners of the box
p000 = [xmin ymin zmin];
p111 = [xmax ymax zmax];

% main vectors
ex   = [1 0 0];
ey   = [0 1 0];
ez   = [0 0 1];

% box faces parallel to Oxy
planeZ0 = [p000 ex ey];
planeZ1 = [p111 ex ey];

% box faces parallel to Oxz
planeY0 = [p000 ex ez];
planeY1 = [p111 ex ez];

% box faces parallel to Oyz
planeX0 = [p000 ey ez];
planeX1 = [p111 ey ez];

% number of lines
nLines = size(line, 1);

% allocate memory for result
edge = zeros(nLines, 6);

% iterate over lines to clip
for i = 1:nLines

    % compute intersection point with each plane
    ipZ0 = intersectLinePlane(line(i,:), planeZ0);
    ipZ1 = intersectLinePlane(line(i,:), planeZ1);
    ipY0 = intersectLinePlane(line(i,:), planeY0);
    ipY1 = intersectLinePlane(line(i,:), planeY1);
    ipX1 = intersectLinePlane(line(i,:), planeX1);
    ipX0 = intersectLinePlane(line(i,:), planeX0);

    % concatenate resulting points
    points  = [ipX0;ipX1;ipY0;ipY1;ipZ0;ipZ1];

    % compute position of each point on the line
    pos     = linePosition3d(points, line(i,:));

    % keep only defined points
    ind     = find(~isnan(pos));
    pos     = pos(ind);
    points  = points(ind,:);

    % sort points with respect to their position
    [pos, ind] = sort(pos); %#ok<ASGLU>
    points  = points(ind, :);

    % keep median points wrt to position. These points define the limit of
    % the clipped edge.
    nv      = length(ind)/2;

    % create resulting edge.
    edge(i,:)   = [points(nv, :) points(nv+1, :)];
end

% check that middle point of the edge is contained in the box
midX = mean(edge(:, [1 4]), 2);
xOk  = xmin <= midX & midX <= xmax;
midY = mean(edge(:, [2 5]), 2);
yOk  = ymin <= midY & midY <= ymax;
midZ = mean(edge(:, [3 6]), 2);
zOk  = zmin <= midZ & midZ <= zmax;

% if one of the bounding condition is not met, set edge to NaN
edge (~(xOk & yOk & zOk), :) = NaN;


function cl = cluster2subclusters(cl_in,class)
% Take a single cluster cl_in and separate into subclusters based on
% vector of integers class
%
% Class must code unique subclusters subcluster order is only preserved
% if class contains all integers from 1 to nclasses:
%
% i.e., class 3 will only be in subcluster 3 if there are no missing class
% numbers in class
%
% ..
%    tor wager, july 06
% ..

classes = unique(class);    % vector of class numbers

nclust = length(classes);

% Fill in fields
for i = 1:nclust

    % voxels in this cluster
    wh_incluster = find(class == classes(i));
    nvox = length(wh_incluster);

    cl(i).title = sprintf('Subcluster of %3.0f vox from %s',nvox, cl_in.title);

    % copy these fields
    for f = {'threshold' 'M' 'dim' 'voxSize'}
        if isfield(cl_in,f{1}), cl(i).(f{1}) = cl_in.(f{1}); end
    end

    % add new values for these fields
    cl(i).name = '';
    cl(i).numVox = nvox;

    % select in_subcl voxels for these fields
    for f = {'XYZ' 'XYZmm' 'Z'}
        cl(i).(f{1}) = cl_in.(f{1})(:,wh_incluster);
    end

    % center of mass
    cl(i).mm_center = center_of_mass(cl(i).XYZmm,cl(i).Z);

end


function r8mat_nonzeros_test ( )

%*****************************************************************************80
%
%% R8MAT_NONZEROS_TEST tests R8MAT_NONZEROS.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    05 December 2014
%
%  Author:
%
%    John Burkardt
%
  m = 5;
  n = 4;
  a = zeros ( m, n );

  fprintf ( 1, '\n' );
  fprintf ( 1, 'R8MAT_NONZEROS_TEST\n' );
  fprintf ( 1, '  R8MAT_NONZEROS counts nonzeros in an R8MAT.\n' );

  c1 = 0;
  for i = 1 : m
    for j = 1 : n
      if ( mod ( i, 2 ) == 0 && mod (  j, 2 ) == 0 )
        a(i,j) = 1.0;
        c1 = c1 + 1;
      else
        a(i,j) = 0.0;
      end
    end
  end

  r8mat_print ( m, n, a, '  Matrix A:' );

  c2 = r8mat_nonzeros ( m, n, a );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  Expected nonzeros = %d\n', c1 );
  fprintf ( 1, '  Computed nonzeros = %d\n', c2 );

  return
end


function line_cvt_lloyd_test02 ( )

%*****************************************************************************80
%
%% LINE_CVT_LLOYD_TEST02 tests the constrained computation.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    28 July 2014
%
%  Author:
%
%    John Burkardt
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'LINE_CVT_LLOYD_TEST02:\n' );
  fprintf ( 1, '  Test the constrained computation.\n' );

  n = 25;
  a = 0.0;
  b = 1.0;
  it_num = 200;
  x = a + ( b - a ) * rand ( n, 1 );
  header = 'test02';

  fprintf ( 1, '\n' );
  fprintf ( 1, '  Use %d points in the interval [%g,%g]\n', n, a, b );
  fprintf ( 1, '  Take %d iterations.\n', it_num );
  fprintf ( 1, '  Call this calculation "%s"\n', header );
  fprintf ( 1, '  Expect a uniform spacing of %g\n', ( b - a ) / n );

  x = line_ccvt_lloyd ( n, a, b, it_num, header, x );

  return
end


function M = fixedrankfactory_2factors_subspace_projection(m, n, k)
% Manifold of m-by-n matrices of rank k with two factor quotient geometry.
%
% function M = fixedrankfactory_2factors_subspace_projection(m, n, k)
%
% A point X on the manifold is represented as a structure with two
% fields: L and R. The matrix L (mxk) is orthonormal,
% while the matrix R (nxk) is a full column-rank
% matrix such that X = L*R'.
%
% Tangent vectors are represented as a structure with two fields: L, R.
%
% Note: L is orthonormal, i.e., columns are orthogonal to each other.
% Such a geometry might be of interest where the left factor has a
% subspace interpretation. A motivation is in Sections 3.3 and 6.4 of the
% paper below.
%
% Please cite the Manopt paper as well as the research paper:
%     @Article{mishra2014fixedrank,
%       Title   = {Fixed-rank matrix factorizations and {Riemannian} low-rank optimization},
%       Author  = {Mishra, B. and Meyer, G. and Bonnabel, S. and Sepulchre, R.},
%       Journal = {Computational Statistics},
%       Year    = {2014},
%       Number  = {3-4},
%       Pages   = {591--621},
%       Volume  = {29},
%       Doi     = {10.1007/s00180-013-0464-z}
%     }
%
% See also: fixedrankfactory_2factors fixedrankembeddedfactory fixedrankfactory_2factors_preconditioned

% This file is part of Manopt: www.manopt.org.
% Original author: Bamdev Mishra, Dec. 30, 2012.
% Contributors:
% Change log:

    M.name = @() sprintf('LR'' quotient manifold of %dx%d matrices of rank %d', m, n, k);

    M.dim = @() (m+n-k)*k;

    % Some precomputations at the point X to be used in the inner product (and
    % pretty much everywhere else).
    function X = prepare(X)
        if ~all(isfield(X,{'RtR'}) == 1)
            X.RtR = X.R'*X.R;
        end
    end

    % The choice of the metric is motivated by symmetry and scale
    % invariance in the total space.
    M.inner = @iproduct;
    function ip = iproduct(X, eta, zeta)
        X = prepare(X);

        ip = eta.L(:).'*zeta.L(:)  + trace(X.RtR\(eta.R'*zeta.R));
    end

    M.norm = @(X, eta) sqrt(M.inner(X, eta, eta));

    M.dist = @(x, y) error('fixedrankfactory_2factors_subspace_projection.dist not implemented yet.');

    M.typicaldist = @() 10*k;

    skew = @(X) .5*(X-X');
    symm = @(X) .5*(X+X');
    stiefel_proj = @(L, H) H - L*symm(L'*H);

    M.egrad2rgrad = @egrad2rgrad;
    function rgrad = egrad2rgrad(X, egrad)
        X = prepare(X);

        rgrad.L = stiefel_proj(X.L, egrad.L);
        rgrad.R = egrad.R*X.RtR;
    end

    M.ehess2rhess = @ehess2rhess;
    function Hess = ehess2rhess(X, egrad, ehess, eta)
        X = prepare(X);

        % Riemannian gradient.
        rgrad = egrad2rgrad(X, egrad);

        % Directional derivative of the Riemannian gradient.
        Hess.L = ehess.L - eta.L*symm(X.L'*egrad.L);
        Hess.L = stiefel_proj(X.L, Hess.L);

        Hess.R = ehess.R*X.RtR + 2*egrad.R*symm(eta.R'*X.R);

        % Correction factor for the non-constant metric on the factor R.
        Hess.R = Hess.R - rgrad.R*(X.RtR\(symm(X.R'*eta.R))) - eta.R*(X.RtR\(symm(X.R'*rgrad.R))) + X.R*(X.RtR\(symm(eta.R'*rgrad.R)));

        % Projection onto the horizontal space.
        Hess = M.proj(X, Hess);
    end

    M.proj = @projection;
    function etaproj = projection(X, eta)
        X = prepare(X);

        eta.L = stiefel_proj(X.L, eta.L); % On the tangent space.
        SS = X.RtR;
        AS1 = 2*X.RtR*skew(X.L'*eta.L)*X.RtR;
        AS2 = 2*skew(X.RtR*(X.R'*eta.R));
        AS  = skew(AS1 + AS2);

        Omega = nested_sylvester(SS,AS);
        etaproj.L = eta.L - X.L*Omega;
        etaproj.R = eta.R - X.R*Omega;
    end

    M.tangent = M.proj;
    M.tangent2ambient = @(X, eta) eta;

    M.retr = @retraction;
    function Y = retraction(X, eta, t)
        if nargin < 3
            t = 1.0;
        end
        Y.L = uf(X.L + t*eta.L);
        Y.R = X.R + t*eta.R;

        % These are reused in the computation of the gradient and Hessian.
        Y = prepare(Y);
    end

    M.exp = @exponential;
    function R = exponential(X, eta, t)
        if nargin < 3
            t = 1.0;
        end

        R = retraction(X, eta, t);
        warning('manopt:fixedrankfactory_2factors_subspace_projection:exp', ...
            ['Exponential for fixed rank ' ...
            'manifold not implemented yet. Lsed retraction instead.']);
    end

    M.hash = @(X) ['z' hashmd5([X.L(:) ; X.R(:)])];

    M.rand = @random;
    % Factors L lives on Stiefel manifold, hence we will reuse
    % its random generator.
    stiefelm = stiefelfactory(m, k);
    function X = random()
        X.L = stiefelm.rand();
        X.R = randn(n, k);
    end

    M.randvec = @randomvec;
    function eta = randomvec(X)
        eta.L = randn(m, k);
        eta.R = randn(n, k);
        eta = projection(X, eta);
        nrm = M.norm(X, eta);
        eta.L = eta.L / nrm;
        eta.R = eta.R / nrm;
    end

    M.lincomb = @lincomb;

    M.zerovec = @(X) struct('L', zeros(m, k),...
        'R', zeros(n, k));

    M.transp = @(x1, x2, d) projection(x2, d);

    % vec and mat are not isometries, because of the scaled inner metric.
    M.vec = @(X, U) [U.L(:) ; U.R(:)];
    M.mat = @(X, u) struct('L', reshape(u(1:(m*k)), m, k), ...
        'R', reshape(u((m*k+1):end), n, k));
    M.vecmatareisometries = @() false;

end

% Linear combination of tangent vectors.
function d = lincomb(x, a1, d1, a2, d2) %#ok<INLSL>

    if nargin == 3
        d.L = a1*d1.L;
        d.R = a1*d1.R;
    elseif nargin == 5
        d.L = a1*d1.L + a2*d2.L;
        d.R = a1*d1.R + a2*d2.R;
    else
        error('Bad use of fixedrankfactory_2factors_subspace_projection.lincomb.');
    end

end

function A = uf(A)
    [L, unused, R] = svd(A, 0); %#ok
    A = L*R';
end

function omega = nested_sylvester(sym_mat, asym_mat)
    % omega=nested_sylvester(sym_mat,asym_mat)
    % This function solves the system of nested Sylvester equations:
    %
    %     X*sym_mat + sym_mat*X = asym_mat
    %     Omega*sym_mat+sym_mat*Omega = X
    % Mishra, Meyer, Bonnabel and Sepulchre, 'Fixed-rank matrix factorizations and Riemannian low-rank optimization'

    % Uses built-in lyap function, but does not exploit the fact that it's
    % twice the same sym_mat matrix that comes into play.

    X = lyap(sym_mat, -asym_mat);
    omega = lyap(sym_mat, -X);

end


% qpwls_std_test
% examine FFT-based prediction of QPWLS estimate pixel variance
% particularly w.r.t. effect of "mask"

if ~isvar('G2')
	down = 1;
	ig1 = image_geom('nx', 512, 'ny', 504, 'fov', 500, 'down', down);
	ig2 = ig1;
	ig2.mask = ig2.circ(220) > 0;
	sg = sino_geom('ge1', 'down', down);

	% now a double sized version
	ig3 = image_geom('nx', ig1.nx*2, 'ny', ig1.nx*2, 'fov', ig1.fov*2);

	G1 = Gtomo_dd(sg, ig1);
	G2 = Gtomo_dd(sg, ig2);
	G3 = Gtomo_dd(sg, ig3);
	im pl 2 1
	im(1, ig1.mask, 'mask1') % square
	im(2, ig2.mask, 'mask1') % circle
prompt
end

if ~isvar('std2')
	l2bs = [5:14];

	for ii=1:length(l2bs)
		l2b = l2bs(ii);
		R1 = Robject(ig1.mask);
		R2 = Robject(ig2.mask);
		R3 = Robject(ig3.mask);

		[psf var fw1(ii)] = qpwls_psf(G1, R1, 2^l2b, ig1.mask);
		std1(ii) = sqrt(var);
		[psf var fw2(ii)] = qpwls_psf(G2, R2, 2^l2b, ig2.mask);
		std2(ii) = sqrt(var);
		[psf var fw3(ii)] = qpwls_psf(G3, R3, 2^l2b, ig3.mask);
		std3(ii) = sqrt(var);
	end
end

if im
	clf
	plot(l2bs, std2, 'o', l2bs, std1, 's', l2bs, std3, '+')
	xlabel 'log_2(\beta)'
	ylabel 'relative standard deviation'
	legend('circle mask', 'full mask', 'double size')
	ir_savefig fig_qpwls_std_fan
end


function model = Initialization_Discrete(Seqs, step, order)

switch nargin
    case 1
        Num = zeros(length(Seqs), 1);
        Tmax = zeros(length(Seqs), 1);
        for i = 1:length(Seqs)
            Num(i) = length(Seqs(i).Time);
            Tmax(i) = Seqs(i).Time(end) + eps;
        end
        model.h = mean(Tmax./Num);
        model.k = floor(min(0.7*Tmax/model.h));
    case 2
        model.h = step;
        Tmax = zeros(length(Seqs), 1);
        for i = 1:length(Seqs)
            Tmax(i) = Seqs(i).Time(end) + eps;
        end
        model.k = floor(min(0.7*Tmax/model.h));
    case 3
        model.h = step;
        model.k = order;
end

D = zeros(length(Seqs),1);
for i = 1:length(Seqs)
    D(i) = max(Seqs(i).Mark);
end
model.D = max(D);
model.Tmax = [];


%% Copyright (C) 2014-2016, 2018-2019, 2022 Colin B. Macdonald
%% Copyright (C) 2022 Chris Gorman
%%
%% This file is part of OctSymPy.
%%
%% OctSymPy is free software; you can redistribute it and/or modify
%% it under the terms of the GNU General Public License as published
%% by the Free Software Foundation; either version 3 of the License,
%% or (at your option) any later version.
%%
%% This software is distributed in the hope that it will be useful,
%% but WITHOUT ANY WARRANTY; without even the implied warranty
%% of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
%% the GNU General Public License for more details.
%%
%% You should have received a copy of the GNU General Public
%% License along with this software; see the file COPYING.
%% If not, see <http://www.gnu.org/licenses/>.

%% -*- texinfo -*-
%% @documentencoding UTF-8
%% @defmethod  @@sym heaviside (@var{x})
%% @defmethodx @@sym heaviside (@var{x}, @var{zero_value})
%% Symbolic Heaviside step function.
%%
%% Example:
%% @example
%% @group
%% syms x
%% @c doctest: +SKIP_UNLESS(pycall_sympy__ ('return Version(spver) > Version("1.4")'))
%% y = heaviside (x)
%%   @result{} y = (sym) θ(x)
%% @end group
%% @end example
%%
%% There are various conventions for 'heaviside(sym(0))'; this function
%% returns the midpoint by default.
%% @example
%% @group
%% @c doctest: +SKIP_UNLESS(pycall_sympy__ ('return Version(spver) > Version("1.8")'))
%% heaviside(sym(0))
%%   @result{} (sym) 1/2
%% @end group
%% @end example
%%
%% The optional second argument overrides the default.  For example
%% to make the function right-continuous,
%% @example
%% @group
%% heaviside(0, sym(1))
%%   @result{} (sym) 1
%% @end group
%% @end example
%% or left-continuous.
%% @example
%% @group
%% heaviside(0, sym(0))
%%   @result{} (sym) 0
%% @end group
%% @end example
%%
%% If passed a matrix, the heaviside function is computed for each
%% element.
%% @example
%% @group
%% @c doctest: +SKIP_UNLESS(pycall_sympy__ ('return Version(spver) > Version("1.8")'))
%% heaviside([sym(-1) sym(0) sym(1) sym(x)])
%%   @result{} (sym) [0  1/2  1  θ(x)]  (1×4 matrix)
%% @end group
%% @end example
%% @seealso{heaviside, @@sym/dirac}
%% @end defmethod

function y = heaviside(x, h0)
  if (nargin == 1)
    y = elementwise_op ('Heaviside', x);
  elseif (nargin == 2)
    y = elementwise_op ('Heaviside', sym(x), sym(h0));
  else
    print_usage ();
  end
end

%!error heaviside (sym(1), 2, 3)

%!assert (isequal (heaviside (sym(1)), sym(1)))
%!assert (isequal (heaviside (-sym(1)), sym(0)))

%!assert (double (heaviside (1)), heaviside (1))

%!test
%! D = [1 -1; -10 20];
%! A = sym(D);
%! assert (double (heaviside (A)), heaviside (D))

%!test
%! H0 = sym([1 -2 0; 3 0 pi]);
%! A = heaviside (sym(0), H0);
%! assert (isequal (A, H0))

%!test
%! A = heaviside ([-1 0 1], sym(1)/2);
%! assert (isequal (A, [0 sym(1)/2 1]))

%!test
%! A = heaviside ([-1 0 1], sym(1)/2);
%! assert (isequal (A, [0 sym(1)/2 1]))

%!assert (isequaln (heaviside (sym(nan)), sym(nan)))

%!test
%! assert (isequaln (heaviside (sym(nan), sym(nan)), sym(nan)))
%! assert (isequaln (heaviside (0, sym(nan)), sym(nan)))
%! assert (isequaln (heaviside (2, sym(nan)), sym(1)))
%! assert (isequaln (heaviside (-2, sym(nan)), sym(0)))

%!test
%! % round trip
%! syms x
%! A = heaviside (1);
%! f = heaviside (x);
%! h = function_handle (f);
%! B = h (1);
%! assert (A, B, -eps)

%!test
%! % round trip
%! syms x h0
%! f = heaviside (x, h0);
%! h = function_handle (f, 'vars', {x h0});
%! A = heaviside (1, 1/2);
%! B = h (1, 1/2);
%! assert (A, B, -eps)
%! A = heaviside (0, 1/2);
%! B = h (0, 1/2);
%! assert (A, B, -eps)


function out = innerProduct(f, g)
%INNERPRODUCT   Inner product of two ONEFUN objects.
%   INNERPRODUCT(F, G) returns the L2 inner product (on [-1,1]) of the two
%   ONEFUN objects F and G (conjugate linear in F).
%
% See also SUM.

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

% Deal with empty case:
if ( isempty(f) || isempty(g) )
    out = [];
    return
end

if ( ~isa(f, 'onefun') || ~isa(g, 'onefun') )
    error('CHEBFUN:SINGFUN:innerProduct:input', ...
        'innerProduct() only operates on two ONEFUN objects.');
end

m = size(f, 2);
n = size(g, 2);
cf = conj(f);

% Loop over columns of f and g:
out = zeros(m, n);
for j = 1:m
    fj = extractColumns(cf, j);    % jth column of f.
    for k = 1:n
        gk = extractColumns(g, k); % kth column of g.
        % Call SUM:
        out(j,k) = sum(fj.*gk);
    end
end

end


% ZEROAXES Redraws the axes at the zero values.
% See also: CENTAXES
% Author: Andrew Knight

% Modified February 1994 to omit the zero label if necessary.
% Modified May 12th 2008 to allow  Y axis invertion, by Javier Lopez-Calderon (JLC)
%
% 03-31-2009 : Bug1: incorrect position of x-axis when y-axis is inverted (abs(ymin) ~= abs(ymax)).
% Thanks to Marcus Heldmann.
%
% 04-01-2009 : Bug1 fixed. JLC

function zeroaxes

holdwason = ishold;
axesin    = get(gcf,'CurrentAxes');
bdownf    = get(gcf,'ButtonDownFcn'); % JLC, May 12th 2008
pos       = get(axesin,'position');
ax        = axis;
xscale    = get(axesin,'XScale');
yscale    = get(axesin,'YScale');
xxticks   = get(axesin,'XTick');       %JLC, March 10, 2011
yyticks   = get(axesin,'YTick');       %JLC, March 10, 2011
xmt       = get(axesin,'XMinorTick');  %JLC, March 10, 2011
ymt       = get(axesin,'YMinorTick');  %JLC, March 10, 2011

sentido   = get(axesin,'YDir');       % JLC, May 12th 2008
set(axesin,'visible','off');
xmin = ax(1);
xmax = ax(2);
ymin = ax(3);
ymax = ax(4);
ticklength  = get(axesin,'TickLength');
XAxisHeight = ticklength(1);
YAxisWidth  = ticklength(1);
f   = polyfit([ax(1) ax(2)],[pos(1) pos(1)+pos(3)],1);
XAxisXLimits = polyval(f,[xmin xmax]);
YAxisXLimits = polyval(f,[0 YAxisWidth*abs(xmax - xmin)]);
f   = polyfit([ax(3) ax(4)],[pos(2) pos(2)+pos(4)],1);
YAxisYLimits = polyval(f,[ymin ymax]);
XAxisYLimits = polyval(f,[0 XAxisHeight*abs(ymax - ymin)]);

%
% right position of the x-axis in case of inverted y-axis
% 04-01-2009  JLC
if strcmp(sentido, 'reverse')
      Xaxis_y = 2*pos(2)+pos(4)-XAxisYLimits(1);
else
      Xaxis_y = XAxisYLimits(1);
end

XAxisPosition = [XAxisXLimits(1)
      Xaxis_y
      XAxisXLimits(2) - XAxisXLimits(1)
      XAxisYLimits(2) - XAxisYLimits(1)];

bgcolour = get(gcf,'color');

hX = axes('position',XAxisPosition,...
      'XLim',[xmin xmax],...
      'box','off',...
      'YTick',[],...
      'TickDir','out',...
      'XScale',xscale,...
      'YColor',bgcolour,...
      'color','none');

YAxisPosition = [YAxisXLimits(1)
      YAxisYLimits(1)
      YAxisXLimits(2) - YAxisXLimits(1)
      YAxisYLimits(2) - YAxisYLimits(1)];

hY = axes('position',YAxisPosition,...
      'YLim',[ymin ymax],...
      'box','off',...
      'Xtick',[],...
      'TickDir','out',...
      'YScale',yscale,...
      'XColor',bgcolour,...
      'color','none',...
      'YDir', sentido); % JLC, May 12th 2008

%
% Ticks  JLC, March 10, 2011
%
set(hX,'XTick',xxticks)
set(hY,'YTick',yyticks)
set(hX,'XMinorTick',xmt)
set(hY,'YMinorTick',ymt)

% Get rid of the zero ticks if necessary:
if ymin<0 && ~strcmp(xscale,'log')
      xticks = get(hX,'XTick');
      xticks(xticks==0) = [];
      set(hX,'XTick',xticks)
end

if xmin<0 && ~strcmp(yscale,'log')
      yticks = get(hY,'YTick');
      yticks(yticks==0) = [];
      set(hY,'YTick',yticks)
end

set(gcf,'CurrentAxes',axesin)
set(gcf,'ButtonDownFcn',bdownf)

if ~holdwason
      set(hX,'NextPlot','Replace')
      set(hY,'NextPlot','Replace')
end


function x = p24_start ( n )

%*****************************************************************************80
%
%% P24_START returns a starting point for optimization for problem 24.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    07 January 2001
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer N, the number of variables X.
%
%    Output, real X(N), a starting point for the optimization.
%
  x = ( linspace ( -5.12, +5.12, n ) )';

  return
end


%%
%
% Return normalized probs as well as scores (numerators in log domain) & norms.
% Note that scores & norms are subtracted/scaled by a constant factor.
%
% Here, we only work on a subset linearIds of the raw scores.
%
% Thang Luong @ 2015, <lmthang@stanford.edu
%
%%
function [probs, scores, norms] = normLayerForward(rawScores, maskedIds)
  % rawScores: numPositions * batchSize
  scores = rawScores;
  scores(maskedIds) = 0;

  % subtract max elements, scores: numClasses * ...
  mx = max(scores, [], 1);
  scores = bsxfun(@minus, scores, mx);

  % probs
  probs = exp(scores);
  probs(maskedIds) = 0;

  norms = sum(probs, 1); % normalization factors
  norms(norms==0) = 1; % for zero columns, set to 1.
  probs = bsxfun(@rdivide, probs, norms); % normalize
end


function x=pcmu2lin(p,s)
%PCMU2LIN Convert Mu-law PCM to linear X=(P,S)
%	lin = pcmu2lin(pcmu) where pcmu contains a vector
%	of mu-law values in the range 0 to 255.
%	No checking is performed to see that numbers are in this range.
%
%	Output values are divided by the scale factor s:
%
%		   s		Output Range
%
%		   1		+-8031	(integer values)
%		4004.2	+-2.005649 (default)
%		8031		+-1
%		8159		+-0.9843118 (+-1 nominal full scale)
%
%	The default scaling factor 4004.189931 is equal to
%	sqrt((2207^2 + 5215^2)/2) this follows ITU standard G.711.
%	The sine wave with PCM-Mu values [158 139 139 158 30 11 11 30]
%	has a mean square value of unity corresponding to 0 dBm0.

%      Copyright (C) Mike Brookes 1998
%      Version: $Id: pcmu2lin.m,v 1.4 2007/05/04 07:01:39 dmb Exp $
%
%   VOICEBOX is a MATLAB toolbox for speech processing.
%   Home page: http://www.ee.ic.ac.uk/hp/staff/dmb/voicebox/voicebox.html
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%   This program is free software; you can redistribute it and/or modify
%   it under the terms of the GNU General Public License as published by
%   the Free Software Foundation; either version 2 of the License, or
%   (at your option) any later version.
%
%   This program is distributed in the hope that it will be useful,
%   but WITHOUT ANY WARRANTY; without even the implied warranty of
%   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%   GNU General Public License for more details.
%
%   You can obtain a copy of the GNU General Public License from
%   http://www.gnu.org/copyleft/gpl.html or by writing to
%   Free Software Foundation, Inc.,675 Mass Ave, Cambridge, MA 02139, USA.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

if nargin<2
  t=9.98953613E-4;
else
  t=4/s;
end

m=15-rem(p,16);
q=floor(p/128);
e=(127-p-m+128*q)/16;
x=(q-0.5).*(pow2(m+16.5,e)-16.5)*t;


%RT2TR Convert rotation and translation to homogeneous transform
%
% TR = RT2TR(R, t) is a homogeneous transformation matrix (MxM) formed from an
% orthonormal rotation matrix R (NxN) and a translation vector t (Nx1) where
% M=N+1.
%
% For a sequence R (NxNxK) and t (NxK) results in a transform sequence (MxMxK).
%
% Notes::
% - Works for R in SO(2) or SO(3)
%  - If R is 2x2 and t is 2x1, then TR is 3x3
%  - If R is 3x3 and t is 3x1, then TR is 4x4
% - The validity of R is not checked
%
% See also T2R, R2T, TR2RT.

% Copyright (C) 1993-2015, by Peter I. Corke
%
% This file is part of The Robotics Toolbox for MATLAB (RTB).
%
% RTB is free software: you can redistribute it and/or modify
% it under the terms of the GNU Lesser General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% RTB is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU Lesser General Public License for more details.
%
% You should have received a copy of the GNU Leser General Public License
% along with RTB.  If not, see <http://www.gnu.org/licenses/>.
%
% http://www.petercorke.com

function T = rt2tr(R, t)
    if numcols(R) ~= numrows(R)
        error('R must be square');
    end
    if numrows(R) ~= numrows(t)
        error('R and t must have the same number of rows');
    end

    if size(R,3) ~= numcols(t)
        error('For sequence size(R,3) must equal size(t,2)');
    end

    if size(R,3) > 1
        Z = zeros(numcols(R),1);
        B = [Z' 1];
        T = zeros(4,4,size(R,3));
        for i=1:size(R,3)
            T(:,:,i) = [R(:,:,i) t(:,i); B];
        end
    else
        T = [R t; zeros(1,numcols(R)) 1];
    end


function [z,output] = minf_lbfgs(f,g,z0,options)
%MINF_LBFGS Minimize a function by L-BFGS with line search.
%   [z,output] = minf_lbfgs(f,g,z0) starts at z0 and attempts to find a
%   local minimizer of the real-valued function f(z). The input variables z
%   may be a scalar, vector, matrix, tensor or even a (nested) cell array
%   of tensors and its contents may be real or complex.
%
%   If f(x) is a function of real variables x, the function g(x) should
%   compute the partial derivatives of f with respect to the real variables
%   x, i.e. g(xk) := df(xk)/dx. If f(z) is a function of complex variables
%   z, the function g(z) should compute two times the partial derivative
%   of f with respect to conj(z) (treating z as constant), i.e. g(zk) :=
%   2*df(zk)/d(conj(z)) = 2*conj(df(zk)/dz). If g is the empty matrix [],
%   the real gradient or scaled conjugate cogradient is approximated with
%   finite differences. The output of the function g(z) may have the same
%   structure as z (although this is not necessary). The structure output
%   returns additional information:
%
%      output.alpha      - The line search step length in every iteration.
%      output.fevals     - The total number of function/gradient calls.
%      output.fval       - The value of the objective function f in every
%                          iteration.
%      output.info       - The circumstances under which the procedure
%                          terminated:
%                             1: Objective function tolerance reached.
%                             2: Step size tolerance reached.
%                             3: Maximum number of iterations reached.
%      output.infols     - The circumstances under which the line search
%                          terminated in every iteration.
%      output.iterations - The number of iterations.
%      output.relfval    - The difference in objective function value
%                          between every two successive iterates, relative
%                          to its initial value.
%      output.relstep    - The step size relative to the norm of the
%                          current iterate in every iteration.
%
%   minf_lbfgs(f,g,z0,options) may be used to set the following options:
%
%      options.Display = 10      - Displays output information each
%                                  options.Display iterations. Set to 0 to
%                                  disable.
%      options.LineSearch        - The line search used to minimize the
%      = @ls_mt                    objective function in the quasi-Newton
%                                  descent direction.
%      options.LineSearchOptions - The options structure passed to the line
%                                  search routine.
%      options.M                 - The number of L-BFGS updates to store.
%      = min(30,length(z0))
%      options.MaxIter = 500     - The maximum number of iterations.
%      options.TolFun = 1e-6     - The tolerance for output.relfval.
%      options.TolX = 1e-8       - The tolerance for output.relstep.

%   Authors: Laurent Sorber (Laurent.Sorber@cs.kuleuven.be)
%            Marc Van Barel (Marc.VanBarel@cs.kuleuven.be)
%            Lieven De Lathauwer (Lieven.DeLathauwer@kuleuven-kulak.be)
%
%   References:
%   [1] L. Sorber, M. Van Barel, L. De Lathauwer, "Unconstrained
%       optimization of real functions in complex variables", SIAM J. Opt.,
%       Vol. 22, No. 3, 2012, pp. 879-898.

% Evaluate the objective function and gradient.
dim = structure(z0);
fval = f(z0);
if ~isa(g,'function_handle') && isempty(g)
    grad = serialize(deriv(f,z0,fval));
else
    grad = serialize(g(z0));
end
z = z0;

% Check the options structure.
isfunc = @(f)isa(f,'function_handle');
if nargin < 4, options = struct; end
if ~isfield(options,'Display'), options.Display = 10; end
if ~isfield(options,'LineSearch') || ~isfunc(options.LineSearch)
    options.LineSearch = @ls_mt;
end
if ~isfield(options,'LineSearchOptions')
    options.LineSearchOptions = struct;
end
if ~isfield(options.LineSearchOptions,'alpha')
    options.LineSearchOptions.alpha = 1;
end
if ~isfield(options.LineSearchOptions,'c2')
    options.LineSearchOptions.c2 = 0.9;
end
if ~isfield(options,'M'), options.M = min(30,length(grad)); end
if ~isfield(options,'MaxIter'), options.MaxIter = 500; end
if ~isfield(options,'TolFun'), options.TolFun = 1e-6; end
if ~isfield(options,'TolX'), options.TolX = 1e-8; end

% Initialize the algorithm.
S = zeros(numel(grad),options.M);
Y = zeros(numel(grad),options.M);
a = zeros(1,options.M);
r = zeros(1,options.M);
m = 0;
midx = 0;

% L-BFGS with line search.
output.alpha = [];
output.fevals = 1;
output.fval = fval;
output.info = false;
output.infols = [];
output.iterations = 0;
output.relfval = [];
output.relstep = [];
while ~output.info

    % Compute the quasi-Newton step pqn = -H*grad.
    pqn = -grad;
    for i = 1:m
        a(i) = r(midx(i))*real(S(:,midx(i))'*pqn);
        pqn = pqn-a(i)*Y(:,midx(i));
    end
    if m > 0
        y1 = Y(:,midx(1));
        y1y1 = y1'*y1;
        gamma = y1y1*r(midx(1));
        pqn = 1/gamma*pqn;
    end
    for i = m:-1:1
        b = r(midx(i))*real(Y(:,midx(i))'*pqn);
        pqn = pqn+(a(i)-b)*S(:,midx(i));
    end

    % Minimize f along z+alpha*pqn.
    state = output; state.grad = grad;
    [alpha,outputls] = options.LineSearch( ...
        f,g,z,deserialize(pqn,dim),state,options.LineSearchOptions);
    output.alpha(:,end+1) = alpha;
    if length(alpha) < 2, alpha(2) = 1; end

    % Update iterate.
    z1 = serialize(z);
    z = alpha(2)*(z1+alpha(1)*pqn);
    if alpha(2) == 1
        s = alpha(1)*pqn;
    else
        s = z-z1;
    end
    z = deserialize(z,dim);

    % Update gradient and Hessian approximation.
    grad1 = grad;
    if isfield(outputls,'grad')
        grad = outputls.grad;
    else
        if ~isa(g,'function_handle') && isempty(g)
            grad = serialize(deriv(f,z,output.fval(end)));
        else
            grad = serialize(g(z));
        end
    end
    y = grad-grad1;
    sy = real(y'*s);
    if sy > 0
        m = min(m+1,options.M);
        midx = [midx(1)+1:-1:1,m:-1:midx(1)];
        S(:,midx(1)) = s;
        Y(:,midx(1)) = y;
        r(:,midx(1)) = 1/sy;
    end

    % Update the output structure.
    if isfield(outputls,'fevals')
        output.fevals = output.fevals+outputls.fevals;
    end
    if isfield(outputls,'fval')
        output.fval(end+1) = outputls.fval;
    else
        output.fval(end+1) = f(z);
    end
    if isfield(outputls,'info')
        output.infols(end+1) = outputls.info;
    end
    output.iterations = output.iterations+1;
    output.relfval(end+1) = ...
        abs(diff(output.fval(end:-1:end-1)))/abs(output.fval(1));
    output.relstep(end+1) = norm(s)/norm(z1);
    if isnan(output.relstep(end)), output.relstep(end) = 0; end
    if output.relfval(end) <= options.TolFun, output.info = 1; end
    if output.relstep(end) <= options.TolX, output.info = 2; end
    if output.iterations >= options.MaxIter, output.info = 3; end

    % Display progress.
    if options.Display > 0 && (output.iterations == 1 || output.info || ...
       mod(output.iterations,options.Display) == 0)
        if output.iterations == 1
            bold = '%s';
            [~,~,~,~,v] = regexp(version('-release'),'([0-9]+)([ab])');
            if usejava('Desktop') && str2double(v{1}{1}) > 2011 || ...
               (str2double(v{1}{1}) == 2011 && strcmpi(v{1}{2},'b'))
                bold = '%s';
            end
        end
        if output.iterations == 1 || ...
           mod(output.iterations,15*options.Display) == 0
            fprintf('\n%7s%s','',sprintf(bold,'fval'));
            fprintf('%13s%s','',sprintf(bold,'relfval'));
            fprintf('%10s%s','',sprintf(bold,'relstep'));
            fprintf('%10s%s','',sprintf(bold,'alpha'));
            fprintf('\n%30s = %4.e %6s = %4.e\n\n', ...
                    'TolFun',options.TolFun,'TolX',options.TolX);
        end
        if output.iterations == 1
            fprintf('%4i: % 14.8e |\n',0,output.fval(1));
        end
        stralpha = [repmat('%10.4e ',1,size(output.alpha,1)) '\n'];
        fprintf(['%4i: % 14.8e | %14.8e | %14.8e | ' stralpha], ...
                output.iterations,output.fval(end), ...
                output.relfval(end),output.relstep(end), ...
                abs(output.alpha(:,end)));
    end

end

% Display termination message.
if options.Display > 0
    ahref = '\n%s\n\n';
    x = round(linspace(0,output.iterations,min(500,output.iterations)));
    if length(bold) > 2
        ahref = sprintf(['\n%%s\n\n'],mat2str(x'), ...
            mat2str([output.fval(x+1)' [nan output.relfval(x(2:end))]' ...
                    [nan output.relstep(x(2:end))]'],3));
    end
    switch output.info
        case 1, fprintf(ahref,'Objective function tolerance reached.');
        case 2, fprintf(ahref,'Step size tolerance reached.');
        case 3, fprintf(ahref,'Maximum number of iterations reached.');
    end
end

end

function [z,offset] = deserialize(z,dim,offset)
    if iscell(dim)
        v = z;
        z = cell(size(dim));
        if nargin < 3, offset = 0; end
        for i = 1:numel(z)
            if iscell(dim{i})
                [z{i},offset] = deserialize(v,dim{i},offset);
            else
                n = prod(dim{i}(:));
                z{i} = reshape(v(offset+(1:n)),dim{i});
                offset = offset+n;
            end
        end
    elseif ~isempty(dim)
        z = reshape(z,dim);
    end
end

function z = serialize(z)
    if iscell(z)
        for i = find(cellfun(@iscell,z(:).'))
            z{i} = serialize(z{i});
        end
        s = cellfun(@numel,z(:)); o = [0; cumsum(s)];
        c = z; z = zeros(o(end),1);
        for i = 1:length(s), z(o(i)+(1:s(i))) = c{i}(:); end
    else
        z = z(:);
    end
end

function dim = structure(z)
    if iscell(z)
        dim = cellfun(@size,z,'UniformOutput',false);
        for i = find(cellfun(@iscell,z(:).'))
            dim{i} = structure(z{i});
        end
    else
        dim = size(z);
        if numel(z) == dim(1), dim = []; end
    end
end


function degree = grNodeOuterDegree(node, edges)
%GRNODEOUTERDEGREE Outer degree of a node in a graph
%
%   DEG = grNodeOuterDegree(NODE, EDGES);
%   Returns the outer degree of a node in the given edge list, i.e. the
%   number of edges emanating from it.
%   NODE is the index of the node, and EDGES is a liste of couples of
%   indices (origin and destination node).
%
%   Note: Also works when node is a vector of indices
%
%   See Also:
%   grNodeDegree, grNodeInnerDegree
%
%
% ------
% Author: David Legland
% e-mail: david.legland@grignon.inra.fr
% Created: 2006-01-17
% Copyright 2006 INRA - CEPIA Nantes - MIAJ (Jouy-en-Josas).
%

%   HISTORY
%   2008-08-07 pre-allocate memory, update doc

% allocate memory
N = size(node, 1);
degree = zeros(N, 1);

% compute outer degree of each vertex
for i=1:N
    degree(i) = sum(edges(:,1)==node(i));
end


function       X = Image2Patch( im_out, par )
% record the non-local patch set and the index of each patch in
% of seed patches in image
im_out         =  single(im_out);
X          =  zeros(par.ps2, par.maxrc, 'double');
k    =  0;
for l = 1:par.ch
    for i = 1:par.ps
        for j = 1:par.ps
            k    =  k+1;
            blk  = im_out(i:end-par.ps+i,j:end-par.ps+j, l);
            X(k,:) = blk(:)';
        end
    end
end


function [ x, more ] = sgmga_vcn ( n, w, x, q_min, q_max, more )

%*****************************************************************************80
%
%% SGMGA_VCN returns the next constrained vector.
%
%  Discussion:
%
%    This function is intended to replace the "naive" version, now called
%    SGMGA_VCN_NAIVE, which is too slow for high dimensional problems.
%
%    For nonnegative vectors X of dimension N, and nonnegative
%    weights W, we define:
%
%      Q = sum ( 1 <= I <= N ) W(I) * X(I)
%
%    and seek X satisfying the constraint:
%
%      Q_MIN < Q <= Q_MAX
%
%    This routine returns, one at a time exactly those X which satisfy
%    the constraint.  No attempt is made to return the X values in
%    any particular order as far as Q goes.
%
%  Example:
%
%        W               4.0 3.0 5.0
%      MIN     16.0       0   0   0
%      ---     ----      -----------
%        1     20.0       5   0   0
%        2     19.0       4   1   0
%        3     18.0       3   2   0
%        4     17.0       2   3   0
%        5     20.0       2   4   0
%        6     19.0       1   5   0
%        7     18.0       0   6   0
%        8     17.0       3   0   1
%        9     20.0       3   1   1
%       10     19.0       2   2   1
%       11     18.0       1   3   1
%       12     17.0       0   4   1
%       13     20.0       0   5   1
%       14     18.0       2   0   2
%       15     17.0       1   1   2
%       16     20.0       1   2   2
%       17     19.0       0   3   2
%       18     19.0       1   0   3
%       19     18.0       0   1   3
%       20     20.0       0   0   4
%      ---     ----      ----------
%      MAX     20.0       6   7   5
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    21 May 2010
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Fabio Nobile, Raul Tempone, Clayton Webster,
%    A Sparse Grid Stochastic Collocation Method for Partial Differential
%    Equations with Random Input Data,
%    SIAM Journal on Numerical Analysis,
%    Volume 46, Number 5, 2008, pages 2309-2345.
%
%    Fabio Nobile, Raul Tempone, Clayton Webster,
%    An Anisotropic Sparse Grid Stochastic Collocation Method for Partial
%    Differential Equations with Random Input Data,
%    SIAM Journal on Numerical Analysis,
%    Volume 46, Number 5, 2008, pages 2411-2442.
%
%  Parameters:
%
%    Input, integer N, the dimension of the vector.
%
%    Input, real W(N), the weights, which should be nonnegative.
%    At least one weight must be positive.
%
%    Input, integer X(DIM_NUM).  On first call, with
%    MORE = FALSE, the input value of X is not important.  On subsequent calls,
%    the input value of X should be the output value from the previous call.
%
%    Input, real Q_MIN, Q_MAX, the lower and upper
%    limits on the sum.
%
%    Input, logical MORE.  On input, if the user has set MORE
%    FALSE, the user is requesting the initiation of a new sequence
%    of values.  If MORE is TRUE, then the user is requesting "more"
%    values in the current sequence.
%
%    Output, integer X(DIM_NUM).
%    On output, (with MORE = TRUE), the value of X will be the "next"
%    vector in the reverse lexicographical list of vectors that satisfy
%    the condition.  However, on output with MORE = FALSE, the vector
%    X is meaningless, because there are no more vectors in the list.
%
%    Output, logical MORE.  If MORE is TRUE on output,
%    then another value was found and returned in X, but if MORE is
%    FALSE, then there are no more values in the sequence, and X is
%    NOT the next value.
%
  persistent dir;
  persistent n2;
  persistent nstart;
  persistent xmax;
  persistent xmin;
%
%  Initialization for first call.
%
%  Allocate XMAX to remember the currently maximum possible value for each X.
%
%  Locate NSTART, the index of the first nonzero weight.
%  The algorithm is easier to program if the last index we look at
%  has a nonzero weight, so that it can always make up the remainder.
%
  if ( ~more )

    xmax = zeros ( n, 1 );
    nstart = - 1;

    for i = 1 : n
      if ( 0.0 < w(i) )
        nstart = i;
        break
      end
    end
%
%  Theoretically, we could even handle the case where all weights are zero.
%  That case is ruled out elsewhere in this software, so I will not try
%  to deal with it here for now.
%
    if ( nstart == - 1 )
      fprintf ( 1, '\n' );
      fprintf ( 1, 'SGMGA_VCN - Fatal error!\n' );
      fprintf ( 1, '  No weight is positive.\n' );
      error ( 'SGMGA_VCN - Fatal error!' );
    end
%
%  Initialize X to zero, even the indices we ignore.
%
    x = zeros ( n, 1 );
%
%  N2 points to our current index of interest.
%
    n2 = n + 1;
    dir = - 1;

    more = 1;

  end
%
%  Look for the next solution vector X.
%
  while ( 1 )
%
%  If no more, the search is terminated.
%
    if ( ~more )

      break
%
%  DIR = -1, decrement N2, and, if possible, set X(N2) to XMIN.
%  DIR =  0, hold N2 at current value, and see if we can increment X(N2).
%
    elseif ( dir == - 1 || dir == 0 )

      if ( dir == - 1 )
        n2 = n2 - 1;
      end

      if ( w(n2) == 0.0 )

        xmin = 0;
        xmax(n2) = 0;

      elseif ( nstart < n2 )

        xmin = 0;
        xmax(n2) = floor ( ( q_max -  w(n2+1:n,1)' * x(n2+1:n,1) ) / w(n2) );

      elseif ( n2 == nstart && dir == - 1 )

        xmin = ceil ( ( q_min - w(n2+1:n,1)' * x(n2+1:n,1) ) / w(n2) );
        xmin = max ( xmin, 0 );
        if ( w(1:n2-1,1)' * x(1:n2-1,1) ...
           + w(n2) * xmin ...
           + w(n2+1:n,1)' * x(n2+1:n,1)  ...
          <= q_min )
          xmin = xmin + 1;
        end

        x(n2) = xmin;

        xmax(n2) = floor ( ( q_max -  w(n2+1:n,1)' * x(n2+1:n,1) ) / w(n2) );

      end

      if ( xmax(n2) < xmin )

        dir = + 1;

      else

        if ( n2 == nstart )

          if ( dir == - 1 )
            dir = 0;
            break
          elseif ( dir == 0 )
            x(n2) = x(n2) + 1;
            if ( x(n2) <= xmax(n2) )
              break
            else
              dir = + 1;
            end

          end

        else

          x(n2) = xmin;

        end

      end
%
%  DIR = + 1:
%  Try moving backwards to find an index N2 whose X we can increment.
%
    elseif ( dir == + 1 )

      while ( 1 )

        if ( n2 == n )
          dir = 0;
          more = 0;
          xmax = [];
          break;
        end

        n2 = n2 + 1;

        if ( 0.0 < w(n2) )

          if ( x(n2) < xmax(n2) )
            x(n2) = x(n2) + 1;
            dir = - 1;
            break
          end

        end
      end
    end
  end

  return
end


% contourlet2tree.m
% written by: Duncan Po
% Date: August 24, 2002
% convert the contourlet coefficients from subband structure to tree structure
% Usage: [tree, scaling] = contourlet2tree(coef, dir)
% Inputs:   coef        - contourlet coefficients
%           dir         - the directional coefficients to be processed
% Output:   tree        - the resulting tree structure
%           scaling     - the scaling function of the coefficients

function [tree, scaling] = contourlet2tree(coef, dir)

M = length(coef{2});
nlevel = length(coef)-1;

for l = 2:nlevel+1
    levndir(l-1) = log2(length(coef{l}));
end;

scaling = coef{1};

for r = 1:(length(levndir)-1)
    if levndir(r+1)==levndir(r)
        split(r) = 0;
    elseif levndir(r+1)-levndir(r)==1
        split(r) = 1;
    else
        return;
    end;
end;

for l=2:nlevel+1
    if dir> M/2
      for i=1+2^(levndir(l-1)-levndir(1))*(dir-1):2^(levndir(l-1)-levndir(1))*dir
          coef{l}{i} = coef{l}{i}.';
      end;
    end;
end;

for l=2:nlevel+1
    if (l>2) & (levndir(l-1)~=levndir(1))
        j=1;
        if split(l-2)==1
            for i=1+2^(levndir(l-1)-levndir(1))*(dir-1):2:2^(levndir(l-1)-levndir(1))*dir
                coef{l}{j} = type3transform(coef{l}{i},coef{l}{i+1});
                j = j + 1;
            end;
        else
            for i=1+2^(levndir(l-1)-levndir(1))*(dir-1):2:2^(levndir(l-1)-levndir(1))*dir
                coef{l}{j} = type4transform(coef{l}{i},coef{l}{i+1});
                j = j + 1;
            end;
        end;

        i=length(coef{l})/length(coef{2})/2;
        while i>1
            j=1;
            for k=1:2:i
                coef{l}{j} = type4transform(coef{l}{k}, coef{l}{k+1});
                j = j+1;
            end;
            i = i/2;
        end;
        interimstructure{l-1} = coef{l}{1};
    else;
        interimstructure{l-1} = coef{l}{dir};
    end;
end;

tree{1} = interimstructure{1}(:);
for l = 2:nlevel
    tree{l} = [];
    for col = 1:2:size(interimstructure{l}, 2)
        temp = interimstructure{l}(:,col:col+1);
        temp = temp.';
        tree{l} = [tree{l}; temp(:)];
    end;
end;


%TRANSL Create or unpack an SE3 translational transform
%
% Create a translational transformation matrix::
%
% T = TRANSL(X, Y, Z) is an SE(3) homogeneous transform (4x4) representing
% a pure translation of X, Y and Z.
%
% T = TRANSL(P) is an SE(3) homogeneous transform (4x4) representing a
% translation of P=[X,Y,Z]. If P (Mx3) it represents a sequence and T
% (4x4xM) is a sequence of homogeneous transforms such that T(:,:,i)
% corresponds to the i'th row of P.
%
% Unpack the translational part of a transformation matrix::
%
% P = TRANSL(T) is the translational part of a homogeneous transform T as a
% 3-element column vector.  If T (4x4xM) is a homogeneous transform
% sequence the rows of P (Mx3) are the translational component of the
% corresponding transform in the sequence.
%
% [X,Y,Z] = TRANSL(T) is the translational part of a homogeneous transform
% T as three components.  If T (4x4xM) is a homogeneous transform sequence
% then X,Y,Z (1xM) are the translational components of the corresponding
% transform in the sequence.
%
% Notes::
% - Somewhat unusually this function performs a function and its inverse.  An
%   historical anomaly.
%
% See also CTRAJ.

% Copyright (C) 1993-2015, by Peter I. Corke
%
% This file is part of The Robotics Toolbox for MATLAB (RTB).
%
% RTB is free software: you can redistribute it and/or modify
% it under the terms of the GNU Lesser General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% RTB is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU Lesser General Public License for more details.
%
% You should have received a copy of the GNU Leser General Public License
% along with RTB.  If not, see <http://www.gnu.org/licenses/>.
%
% http://www.petercorke.com

function [t1,t2,t3] = transl(x, y, z)
    if nargin == 1
        if ishomog(x)
            if ndims(x) == 3
                % transl(T)  -> P, trajectory case
                if nargout == 1
                    t1 = squeeze(x(1:3,4,:))';
                elseif nargout == 3
                    t1 = squeeze(x(1,4,:))';
                    t2 = squeeze(x(2,4,:))';
                    t3 = squeeze(x(3,4,:))';
                end
            else
                % transl(T)  -> P
                if nargout == 1 || nargout == 0
                    t1 = x(1:3,4);
                elseif nargout == 3
                    t1 = x(1,4);
                    t2 = x(2,4);
                    t3 = x(3,4);
                end

            end
        elseif length(x) == 3
            % transl(P) -> T
            t = x(:);
            t1 =    [eye(3)          t(:);
                0   0   0   1];
        else
            % transl(P) -> T, trajectory case
            n = numrows(x);
            t1 = repmat(eye(4,4), [1 1 n]);
            t1(1:3,4,:) = x';
        end
    elseif nargin == 3
        % transl(x,y,z) -> T
        t = [x; y; z];
        t1 =    rt2tr( eye(3), t);
    end


function [x,info] = mgS(A,b,elem,option,varargin)
%% MGS multigrid-type solvers
%
%   x = MGS(A,b,elem) attempts to solve the system of linear equations A*x =
%   b for x using multigrid type solver. To acheive multigrid efficiency,
%   the mesh must be of bisection type. Inside mg, an coarsening algorithm
%   on bisection grids is applied. See doc coarsen for the coarsening algorithm.
%
%   It is a simplified version of |mg| such that it can serve as a template
%   for coding multigrid methods using iFEM.
%
% Example:
%
%   [node,elem] = squaremesh([0 1 0 1],0.5);
%   for k = 1:8
%     [node,elem] = uniformrefine(node,elem);
%   end
%   pde.f = inline('p(:,1).*p(:,2)','p');
%   pde.g_D = inline('zeros(size(p,1),1)','p');
%   option.solver = 'notsolve';
%   [u,Du,eqn] = Poisson(node,elem,pde,[],option);
%   fprintf('\n Number of unknowns: %8.0u\n',length(eqn.b))
%   tic; display('Direct solver'); u = eqn.A\eqn.b; toc;
%   tic; x = mgS(eqn.A,eqn.b,elem); toc;
%   format shorte
%   fprintf('Difference between direct and mg solvers %0.2g \n',norm(u-x));
%
% See also mg
%
% Documentation in Help browser ifem mgdoc
%
% Copyright (C) Long Chen. See COPYRIGHT.txt for details.

tic;

%% Size of systems
Ndof = length(b);                  % number of dof
N = max(elem(:));                  % number of nodes
% NT = size(elem,1);                 % number of elements
dim = size(elem,2)-1;

%% Options
% Assign default values to unspecified parameters
if ~exist('option','var')
    option = [];
end
option = mgoptions(option,Ndof);    % parameters
x0 = option.x0;
N0 = option.N0;
tol = option.tol;
maxIt = option.solvermaxit;
mu = option.smoothingstep;
solver = option.solver;
preconditioner = option.preconditioner;
coarsegridsolver = option.coarsegridsolver;
printlevel = option.printlevel;
% setupflag = option.setupflag;

%% Fixed dof
isFixDof = [];
if isfield(option,'freeDof') % freeDof is given
   isFreeDof = false(N,1);
   isFreeDof(option.freeDof) = true;
   NA = size(A,1);
   if NA > length(option.freeDof)
       isFixDof = true(NA,1);
       isFixDof(isFreeDof) = false;
   end
else % Find free dof and eliminate isolated dof
    deg = sum(spones(A));  % degree of the matrix graph
    isFreeDof = false(Ndof,1);
    isFreeDof(deg>1) = true;
    isFixDof = ~isFreeDof; % degree = 1 is isolated vertex
    isFixDof(deg == 0) = false; % degree = 0 the matrix is singular
end
if any(isFixDof) % a bigger matrix is given
    xD = zeros(Ndof,1);
    xD(isFixDof) = b(isFixDof)./diag(A(isFixDof,isFixDof));
    A = A(isFreeDof,isFreeDof);% shrink to freedof only
end
if length(b) > sum(isFreeDof)  % a bigger b is given
    b = b(isFreeDof);          % shrink to freedof only
end
if length(x0) > sum(isFreeDof) % a bigger x0 is given
    x0 = x0(isFreeDof);        % shrink to freedof only
    option.x0 = x0;
end
isFreeNode = isFreeDof(1:N); % free nodes (for P1)

%% Hierarchical Structure of Mesh
%  hierarchical structure for linear element.
if dim == 2  % 2-D
    [HB, NL, level] = HBstructure(elem,N0);
end
if dim == 3  % 3-D
    if nargin > 4
        HBmesh = varargin{end}; % need HB for bisection refinement
        [HB, NL, level] = HBstructure3(elem,N0,HBmesh);
    else % no HBmesh is given. only work for the red uniform refinement
        [HB, NL, level] = HBstructure3(elem,N0);
    end
end

%% Transfer operators between multilevel meshes for P1 element
% standard prolongation and restriction operator for P1 element
[Pro,Res] = transferoperator(HB,NL,isFreeNode);
if Ndof > N
    if ~exist('auxPro','var')
        disp('The current element is not supported by mg');
    else
        Pro{level} = auxPro;
        Res{level+1} = Pro{level}';
        level = level + 1; % add one more level from P1 to current element
    end
end
clear HB auxPro

%% Matrices in each level
Ai = cell(level,1);
Ai{level} = A;
for j = level:-1:2
    Ai{j-1} = Res{j}*Ai{j}*Pro{j-1};           % Ac = Res*Af*Pro
    switch option.smoother
        case 'GS'
            Bi{j} = tril(Ai{j});        % Forward Gauss-Seidel   B = D+L
            BBi{j} = triu(Ai{j});       % Backward Gauss-Seidel BB = D+U
        case 'JAC'
            Bi{j} = spdiags(diag(Ai{j}),0,size(Ai{j},1),size(Ai{j},1));        %
            BBi{j} = Bi{j};       % Jacobi iteration
    end
    if option.smoothingparameter~=1
        Bi{j} = Bi{j}/option.smoothingparameter;
        BBi{j} = BBi{j}/option.smoothingparameter;
    end
end

%% MG cycles
% initial set up
k = 1;
x = x0;
r = b - A*x;
nb = norm(b);
err = zeros(maxIt,2);
if nb > eps  % nb is non-zero
    err(1,:) = norm(r)/nb;
else
    err(1,:) = norm(r);
end
switch solver
    case 'VCYCLE'
        if printlevel >= 1
            fprintf('Multigrid Vcycle Iteration \n')
        end
        while (max(err(k,:)) > tol) && (k <= maxIt)
            k = k + 1;
            % Step 2: Compute Br by one Vcylce MG
            Br = vcycle(r);
            % Step 3: Correct the solution
            x = x + Br;
            % Step 1: Form residual r
            r = r - A*Br;
            err(k,1) = sqrt(abs(Br'*r/(x'*b))); % approximate relative error in energy norm
            err(k,2) = norm(r)/nb; % relative error of the residual in L2-norm
            if printlevel >= 2
                fprintf('#dof: %8.0u,  #nnz: %8.0u, MG Vcycle iter: %2.0u, err = %8.4e\n',...
                         Ndof, nnz(A), k-1, max(err(k,:)));
            end
        end
        err = err(1:k,:);
        itStep = k-1;
    case 'WCYCLE'
        if printlevel >= 1
            fprintf('Multigrid Wcycle Iteration \n')
        end
        while (max(err(k,:)) > tol) && (k <= maxIt)
            k = k + 1;
            % Step 2: Compute Br by one Vcylce MG
            Br = wcycle(r);
            % Step 3: Correct the solution
            x = x + Br;
            err(k,1) = sqrt(abs(Br'*r/(x'*b))); % approximate relative error in energy norm
            % Step 1: Form residual r
            r = r - A*Br;
            err(k,2) = norm(r)/nb; % relative error of the residual in L2-norm
            if printlevel >= 2
                fprintf('#dof: %8.0u,  #nnz: %8.0u, MG Wcycle iter: %2.0u, err = %8.4e\n',...
                         Ndof, nnz(A), k-1, max(err(k,:)));
            end
        end
        err = err(1:k,:);
        itStep = k-1;
end

%% Krylov space method
% set up preconditioner
switch preconditioner
    case 'V'
        prefunc = @vcycle;
        if printlevel >= 1
            fprintf('Multigrid V-cycle Preconditioner with ')
        end
    case 'W'
        prefunc = @wcycle;
        if printlevel >= 1
            fprintf('Multigrid W-cycle Preconditioner with ')
        end
end
switch solver
    case 'CG'
        if printlevel >= 1
            fprintf('Conjugate Gradient Method\n')
        end
        [x,flag,err,itStep] = pcg(A,b,tol,maxIt,prefunc,[],x0);
    case 'MINRES'
        if printlevel >= 1
            fprintf('Minimum Residual Method \n')
        end
        [x,flag,err,itStep] = minres(A,b,tol,maxIt,prefunc,[],x0);
    case 'GMRES'
        if printlevel >= 1
            fprintf('General Minimum Residual Method\n')
        end
        if isfield(option,'restart')
            restart = option.restart;
        else
            restart = min(N,10);
        end
        [x,flag,err,itStep] = gmres(A,b,restart,tol,maxIt,prefunc,[],x0);
        itStep = (itStep(1)-1)*restart + itStep(2);
end

%% Modify x to include fix dof
if any(isFixDof)
    xD(isFreeDof) = x;
    x = xD;
end

%% Output
if k > maxIt
    flag = 1;
else
    flag = 0;
end
time = toc;
if printlevel >= 2
    fprintf('#dof: %8.0u, level: %2.0u,   coarse grid %2.0u, #nnz: %8.0u\n',...
              Ndof, level, size(Ai{1},1), nnz(Ai{1}))
end
if printlevel >= 1
    fprintf('#dof: %8.0u,  #nnz: %8.0u, smoothing: %2.0u, iter: %2.0u,   err = %8.4e,   time = %4.2g s\n',...
                 Ndof, nnz(A), mu, itStep, max(err(end,:)), time)
end
if (flag == 1) && (printlevel>0)
   fprintf('NOTE: the iterative method does not converge! \n');
end
info = struct('solverTime',time,'itStep',itStep,'error',err,'flag',flag,'stopErr',max(err(end,:)));

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% subfunctions vcycle, wcycle, fcycle, bpx
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Vcycle MG
    function Br = vcycle(r,J)        % solve equations Ae = r in each level
    if nargin<=1
        J = level;
    end
    ri = cell(J,1);            % record residual in each level
    ei = cell(J,1);            % record err in each level
    ri{J} = r;
    for i = J:-1:2
        ei{i} = Bi{i}\ri{i};   % pre-smoothing
        for s = 1:mu-1           % extra mu-1 steps smoothing
            ei{i} = ei{i} + Bi{i}\(ri{i}-Ai{i}*ei{i});
        end
        ri{i-1} = Res{i}*(ri{i} - Ai{i}*ei{i});
    end
    if strcmp(coarsegridsolver,'direct')
        ei{1} = Ai{1}\ri{1}; % direct solver in the coarest level
    else                         % iterative solver in the coarest level
        D = spdiags(diag(Ai{1}),0,size(Ai{1},1),size(Ai{1},1));
        [ei{1},flag] = pcg(Ai{1},ri{1},1/size(Ai{1},1),1000,D);
    end
    for i = 2:J
        ei{i} = ei{i} + Pro{i-1}*ei{i-1};
        ei{i} = ei{i} + BBi{i}\(ri{i}-Ai{i}*ei{i});
        for s = 1:mu-1
            ei{i} = ei{i} + BBi{i}\(ri{i}-Ai{i}*ei{i}); % post-smoothing
        end
    end
    Br = ei{J};
    end

%% Wcycle MG
    function e = wcycle(r,J)        % solve equations Ae = r in each level
    if nargin<=1
        J = level;
    end
    if J == 1
        e = Ai{J}\r;   % exact solver in the coaresest grid
        return
    end
    % fine grid pre-smoothing
    e = Bi{J}\r;        % pre-smoothing
    for s = 1:mu-1        % extra mu-1 steps smoothing
        e = e + Bi{J}\(r-Ai{J}*e);
    end
    % coarse grid correction twice
    rc = Res{J}*(r - Ai{J}*e);
    ec = wcycle(rc,J-1);
    ec = ec + wcycle(rc - Ai{J-1}*ec,J-1);
    e = e + Pro{J-1}*ec;
    % fine grid post-smoothing
    e = e + BBi{J}\(r-Ai{J}*e);
    for s = 1:mu-1
        e = e + BBi{J}\(r-Ai{J}*e); % post-smoothing
    end
    end

end


classdef LHSintegrator_StokesD < handle

    properties (Access = private)
        pressureFun
        velocityFun
        mesh
        quadrature
    end

    methods (Access = public)

        function obj = LHSintegrator_StokesD(cParams)
            %             obj.init(cParams);
            %             obj.createQuadrature();
            %             obj.createInterpolation();
            %             obj.createGeometry();
            obj.initStokesD(cParams);
            obj.createQuadrature();
        end

        function LHS = compute(obj)
            lhs = obj.computeElementalLHS();
%             LHS = obj.assembleStokesD(lhs);
            LHS = obj.assembleMatrix(lhs);
        end

    end

    methods (Access = protected)

        function lhs = computeElementalLHS(obj)
            dNdxV = obj.velocityFun.computeCartesianDerivatives(obj.quadrature);
            dvolV = obj.mesh.computeDvolume(obj.quadrature)';
            shpeP = obj.pressureFun.computeShapeFunctions(obj.quadrature);

            nElem = obj.mesh.nelem;
            nDimfV = size(dNdxV,1);
            nNodeV = size(dNdxV,2);
            nNodeP = size(shpeP,1);

            nGaus = size(dNdxV,4);

            D = zeros(nDimfV*nNodeV,nNodeP,nElem);
            for igaus = 1:nGaus
                for inode_var = 1:nNodeP
                    for inode_test = 1:nNodeV
                        for idime = 1:nDimfV
                            dof_test = inode_test*nDimfV - nDimfV + idime;
                            v = squeeze(dNdxV(idime,inode_test,:,igaus));
                            D(dof_test,inode_var,:)= squeeze(D(dof_test,inode_var,:)) - v(:).*shpeP(inode_var,igaus)...
                                .*dvolV(:,igaus);
                        end
                    end
                end
            end
            lhs = D;
        end

    end

    methods (Access = private)

        function initStokesD(obj, cParams)
            obj.mesh     = cParams.mesh;
            obj.pressureFun = cParams.pressureFun;
            obj.velocityFun = cParams.velocityFun;
%             obj.material = cParams.material;
        end

        function createQuadrature(obj)
            q = Quadrature.set(obj.mesh.type);
            q.computeQuadrature('QUADRATIC'); % ehhh
            obj.quadrature = q;
        end

        function LHS = assembleMatrix(obj, lhs)
            s.fun    = []; % !!!
            assembler = AssemblerFun(s);
            LHS = assembler.assembleFunctions(lhs, obj.velocityFun, obj.pressureFun);
        end

    end

end


function ori = byEuler(varargin)
% define orientations by Euler angles
%
% Syntax
%   ori = orientation.byEuler(phi1,Phi,phi2,CS,SS) % Bunge convention
%   ori = orientation.byEuler(alpha,beta,gamma,'ZYZ',CS,SS) % Matthies convention
%   ori = orientation.byEuler(phi1,Phi,phi2,'Kocks',CS,SS) % Kocks convention
%
% Input
%  phi1, Phi, phi2 - Euler angles in radiant
%  CS - @crystalSymmetry
%  SS - @specimenSymmetry
%
% Output
%  ori - @orientation
%
% Flags
%  Bunge, ZXZ -
%  ABG, Matthies, ZYZ -
%  Roe -
%  Kocks -
%  Canova -
%
% See also
% orientation/orientation orientation/byMiller orientation/byAxisAngle
% orientation/map

q = euler2quat(varargin{:});

ori = orientation(q,varargin{:});


function Bnew = pollBADS2N(B,x,gpstruct,LB,UB,optimState,options)
%POLLBADS2N Poll 2N fixed basis vectors (Generalized Pattern Search).

nvars = numel(x);

if isempty(B)
    Bnew = [eye(nvars); -eye(nvars)];
    Bnew = Bnew*optimState.C';

    if 0
        if size(gpstruct.x,1) > (2*nvars + nvars*nvars/4)
            try
                % H = hessian(@(xi_) gppred(xi_,gpstruct), x);
                H = fhess(@(xi_) gppred(xi_,gpstruct), x, [], 'step', optimState.searchmeshsize);
                H = nearestSPD(H,10);
                % eig(H)
                L = chol(H);
                % Bnew = solve_chol(L,Bnew')';
                Hinv = solve_chol(L,eye(nvars));
                Hinv = nearestSPD(Hinv,10);
                [V,D] = eig(Hinv);
                lD = real(log(diag(D)));
                lD(lD < max(lD) + 0.5*log(eps)) = max(lD) + 0.5*log(eps);
                while 1
                    delta = max(lD) - min(lD);
                    if delta < log(1e6); break; end
                    lD = 0.8*lD;
                end
                D = exp(0.5*lD);
                Bnew = bsxfun(@times, [V'; -V'], [D(:);D(:)]);
                % Hinv = inv(H);
                % Bnew = (chol(Hinv)*Bnew')';
            catch
                % Use diagonal matrix
            end
        end
    end

    % Global vector normalization
    D = sqrt(sum(Bnew(1:nvars,:).*Bnew(1:nvars,:),2));
    N = exp(log(D) - mean(log(D)))./D;
    Bnew = bsxfun(@times, Bnew, [N;N]);
    Bnew = bsxfun(@rdivide, Bnew, gpstruct.pollscale);

else
    Bnew = [];
end

end


classdef SegmentationLossPixel < dagnn.Loss
    % SegmentationLossPixel
    %
    % Similar to dagnn.SegmentationLoss, but also sets pixel weights.
    %
    % Inputs: scoresMap, labels, classWeights
    % Outputs: loss
    %
    % Note: All weights can be empty, which means they are ignored.
    % Note: If you use this for weakly supervised, the loss output will be
    % wrong (divided by instances, not images)
    %
    % Copyright by Holger Caesar, 2016

    properties (Transient)
        instanceWeights
    end

    methods
        function outputs = forward(obj, inputs, params) %#ok<INUSD>

            % Get inputs
            assert(numel(inputs) == 3);
            scoresMap = inputs{1};
            labels = inputs{2};
            classWeights = inputs{3};

            % Check inputs
            assert(~isempty(scoresMap));
            assert(~isempty(labels));

            % Compute invMass
            mass = sum(sum(labels > 0, 2), 1); % Removed the +1
            invMass = zeros(size(mass));
            nonEmpty = mass ~= 0;
            invMass(nonEmpty) = 1 ./ mass(nonEmpty);

            % Compute pixelWeights
            if isempty(classWeights)
                pixelWeights = [];
            else
                classWeightsPad = [0; classWeights(:)];

                %%% Pixel weighting
                pixelWeights = classWeightsPad(labels + 1);

                % Make sure mass of the image does not change
                curMasses = sum(sum(pixelWeights, 1), 2);
                divisor = curMasses ./ mass;
                valid = mass ~= 0 && curMasses ~= 0;
                if any(valid)
                    pixelWeights(:, :, :, valid) = bsxfun(@rdivide, pixelWeights(:, :, :, valid), divisor(valid));
                end

                % Checks
                pixelWeightsSum = sum(sum(pixelWeights, 1), 2);
                assert(all(abs(pixelWeightsSum - mass) < 1e-6) | pixelWeightsSum == 0);
            end;

            % Combine mass invMass and pixelWeights in instanceWeights
            obj.instanceWeights = invMass;
            if ~isempty(pixelWeights)
                obj.instanceWeights = bsxfun(@times, obj.instanceWeights, pixelWeights);
            end

            % Checks
            if ~isempty(obj.instanceWeights)
                assert(~any(isnan(obj.instanceWeights(:))))
            end

            % Compute loss
            loss = vl_nnloss(scoresMap, labels, [], ...
                'loss', obj.loss, ...
                'instanceWeights', obj.instanceWeights);

            assert(gather(~isnan(loss) && ~isinf(loss)));
            outputs{1} = loss;
            n = obj.numAveraged;
            m = n + size(scoresMap, 4);
            obj.average = (n * obj.average + double(gather(outputs{1}))) / m;
            obj.numAveraged = m;
        end

        function [derInputs, derParams] = backward(obj, inputs, params, derOutputs) %#ok<INUSL>

            % Get inputs
            scoresMap = inputs{1};
            labels = inputs{2};

            derInputs{1} = vl_nnloss(scoresMap, labels, derOutputs{1}, ...
                'loss', obj.loss, ...
                'instanceWeights', obj.instanceWeights);
            derInputs{2} = [];
            derInputs{3} = [];
            derParams = {};
        end

        function obj = SegmentationLossPixel(varargin)
            obj.load(varargin);
        end

        function forwardAdvanced(obj, layer)
            % Modification: Overrides standard forward pass to avoid giving up when any of
            % the inputs is empty.

            in = layer.inputIndexes;
            out = layer.outputIndexes;
            par = layer.paramIndexes;
            net = obj.net;
            inputs = {net.vars(in).value};

            % clear inputs if not needed anymore
            for v = in
                net.numPendingVarRefs(v) = net.numPendingVarRefs(v) - 1;
                if net.numPendingVarRefs(v) == 0
                    if ~net.vars(v).precious && ~net.computingDerivative && net.conserveMemory
                        net.vars(v).value = [];
                    end
                end
            end

            % call the simplified interface
            outputs = obj.forward(inputs, {net.params(par).value});
            for oi = 1:numel(out)
                net.vars(out(oi)).value = outputs{oi};
            end
        end
    end
end


function [gps_week, gps_sow, gps_dow] = jd2gps(jd)

% SYNTAX:
%   [gps_week, gps_sow, gps_dow] = jd2gps(jd);
%
% INPUT:
%   jd = julian day
%
% OUTPUT:
%   gps_week = GPS week
%   gps_sow  = GPS seconds of week
%   gps_dow  = GPS day of week
%
% DESCRIPTION:
%   Conversion of julian day number to GPS week and
%	seconds of week.

%--- * --. --- --. .--. ... * ---------------------------------------------
%               ___ ___ ___
%     __ _ ___ / __| _ | __|
%    / _` / _ \ (_ |  _|__ \
%    \__, \___/\___|_| |___/
%    |___/                    v 1.0RC1
%
%--------------------------------------------------------------------------
%  Copyright (C) 2021 Geomatics Research & Development srl (GReD)
%  Written by:
%  Contributors:     ...
%  A list of all the historical goGPS contributors is in CREDITS.nfo
%--------------------------------------------------------------------------
%
%   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/>.
%
%--------------------------------------------------------------------------
% 01100111 01101111 01000111 01010000 01010011
%--------------------------------------------------------------------------

deltat = jd - 2444244.5;
gps_week = floor(deltat/7);
gps_dow  = floor(deltat - gps_week*7);
gps_sow  = (deltat - gps_week*7)*86400;


% [edges] = csaAssign(n,graph)
%
% Compute min-cost assignment with non-negative integral edge weights
% using Andrew Goldberg's CSA package (precise costs version).
%
% INPUT
%	n	Number of nodes in the bipartite graph (must be even).
%	graph	3xm matrix describing graph.
%
% OUTPUT
%	edges	3xn matrix of edges in assignment.
%
% You must ensure that an assignment involving all nodes exists, else
% the code may hang.  This is a feature of the CSA package.  If your
% problem does not necessarily provide such an assignment, then you
% should overlay a high-cost perfect match as a safety net.
%
% Both graph and edges matrices have the same structure.  Each column
% gives a graph edge e.  The two nodes are given by e(1) and e(2):
%
%	e(1) < e(2)
%	1 <= e(1) <= n/2
%	n/2 < e(2) <= n
%
% The edge weight is given by e(3).
%
% Since the output edge matrix should contain one reference to each
% node, sum(sum(edges(1:2,:))) == n*(n+1)/2.
%
% David Martin <dmartin@eecs.berkeley.edu>
% January, 2003


%tests checkStoichiometricConsistency and minCardinalityConservationRelaxationVector
if ~exist('movel','var')
    load 'Recon3DModel_301.mat'
end
printLevel=0;

model = findSExRxnInd(model,[],printLevel-1);

N = model.S(:,model.SIntRxnBool);

%Recon3DModel_301 is stoichiometrically consistent, so check should be
%positive
[isConsistent, m, model] = checkStoichiometricConsistency(model, printLevel);
assert(isConsistent==1)

[mlt,nlt]=size(N');
feasTol = getCobraSolverParams('LP', 'feasTol');
param.eta=feasTol*100;
param.checkConsistency=0;
param.epsilon=1e-4;
param.nonRelaxBool=false(mlt,1);
param.checkFeasibility = 0;
param.printLevel=printLevel;

%Recon3DModel_301 is stoichiometrically consistent, so no relaxations
%should be needed
[relaxRxnBool, solutionRelax] = minCardinalityConservationRelaxationVector(N,param);
assert(nnz(relaxRxnBool)==0);

[relaxRxnBool, solutionRelax] = minCardinalityConservationRelaxationVector(N);
assert(nnz(relaxRxnBool)==0);

if solutionRelax.stat==1
    %conserved if relaxation is below epsilon
    relaxRxnBool=abs(solutionRelax.x)>=param.eta;
    if printLevel>1
        fprintf('%g%s\n',norm(N(:,~relaxRxnBool)'*solutionRelax.z),' = ||N''*z|| (should be zero)')
    end
    if printLevel>1
        fprintf('%s\n',[int2str(nnz(relaxRxnBool)) '/' int2str(length(relaxRxnBool)) ' reactions relaxed.'])
    end
else
    disp(solutionRelax)
    error('solve for minimum cardinality of conservation relaxation vector failed')
end

assert(isConsistent & nnz(relaxRxnBool)==0);


%__________________________________________________________________________
% violin.m - Simple violin plot using matlab default kernel density estimation
% Last update: 10/2015
%__________________________________________________________________________
% This function creates violin plots based on kernel density estimation
% using ksdensity with default settings. Please be careful when comparing pdfs
% estimated with different bandwidth!
%
% Differently to other boxplot functions, you may specify the x-position.
% This is usefule when overlaying with other data / plots.
%__________________________________________________________________________
%
% Please cite this function as:
% Hoffmann H, 2015: violin.m - Simple violin plot using matlab default kernel
% density estimation. INRES (University of Bonn), Katzenburgweg 5, 53115 Germany.
% hhoffmann@uni-bonn.de
%
%__________________________________________________________________________
%
% INPUT
%
% Y:     Data to be plotted, being either
%        a) n x m matrix. A 'violin' is plotted for each column m, OR
%        b) 1 x m Cellarry with elements being numerical colums of nx1 length.
%
% varargin:
% xlabel:    xlabel. Set either [] or in the form {'txt1','txt2','txt3',...}
% facecolor: FaceColor. (default [1 0.5 0]); Specify abbrev. or m x 3 matrix (e.g. [1 0 0])
% edgecolor: LineColor. (default 'k'); Specify abbrev. (e.g. 'k' for black); set either [],'' or 'none' if the mean should not be plotted
% facealpha: Alpha value (transparency). default: 0.5
% mc:        Color of the bars indicating the mean. (default 'k'); set either [],'' or 'none' if the mean should not be plotted
% medc:      Color of the bars indicating the median. (default 'r'); set either [],'' or 'none' if the mean should not be plotted
% bw:        Kernel bandwidth. (default []); prescribe if wanted as follows:
%            a) if bw is a single number, bw will be applied to all
%            columns or cells
%            b) if bw is an array of 1xm or mx1, bw(i) will be applied to cell or column (i).
%            c) if bw is empty (default []), the optimal bandwidth for
%            gaussian kernel is used (see Matlab documentation for
%            ksdensity()
%
% OUTPUT
%
% h:     figure handle
% L:     Legend handle
% MX:    Means of groups
% MED:   Medians of groups
% bw:    bandwidth of kernel
%__________________________________________________________________________
%{
% Example1 (default):

disp('this example uses the statistical toolbox')
Y=[rand(1000,1),gamrnd(1,2,1000,1),normrnd(10,2,1000,1),gamrnd(10,0.1,1000,1)];
[h,L,MX,MED]=violin(Y);
ylabel('\Delta [yesno^{-2}]','FontSize',14)

%Example2 (specify facecolor, edgecolor, xlabel):

disp('this example uses the statistical toolbox')
Y=[rand(1000,1),gamrnd(1,2,1000,1),normrnd(10,2,1000,1),gamrnd(10,0.1,1000,1)];
violin(Y,'xlabel',{'a','b','c','d'},'facecolor',[1 1 0;0 1 0;.3 .3 .3;0 0.3 0.1],'edgecolor','b',...
'bw',0.3,...
'mc','k',...
'medc','r--')
ylabel('\Delta [yesno^{-2}]','FontSize',14)

%Example3 (specify x axis location):

disp('this example uses the statistical toolbox')
Y=[rand(1000,1),gamrnd(1,2,1000,1),normrnd(10,2,1000,1),gamrnd(10,0.1,1000,1)];
violin(Y,'x',[-1 .7 3.4 8.8],'facecolor',[1 1 0;0 1 0;.3 .3 .3;0 0.3 0.1],'edgecolor','none',...
'bw',0.3,'mc','k','medc','r-.')
axis([-2 10 -0.5 20])
ylabel('\Delta [yesno^{-2}]','FontSize',14)

%Example4 (Give data as cells with different n):

disp('this example uses the statistical toolbox')

Y{:,1}=rand(10,1);
Y{:,2}=rand(1000,1);
violin(Y,'facecolor',[1 1 0;0 1 0;.3 .3 .3;0 0.3 0.1],'edgecolor','none','bw',0.1,'mc','k','medc','r-.')
ylabel('\Delta [yesno^{-2}]','FontSize',14)
%}
%%
function[h,L,MX,MED,bw]=violin(Y,varargin)

%defaults:
%_____________________
xL=[];
fc=[1 0.5 0];
lc='k';
alp=0.5;
mc='k';
medc='r';
b=[]; %bandwidth
plotlegend=1;
plotmean=1;
plotmedian=1;
x = [];
%_____________________

%convert single columns to cells:
if iscell(Y)==0
    Y = num2cell(Y,1);
end

%get additional input parameters (varargin)
if isempty(find(strcmp(varargin,'xlabel')))==0
    xL = varargin{find(strcmp(varargin,'xlabel'))+1};
end
if isempty(find(strcmp(varargin,'facecolor')))==0
    fc = varargin{find(strcmp(varargin,'facecolor'))+1};
end
if isempty(find(strcmp(varargin,'edgecolor')))==0
    lc = varargin{find(strcmp(varargin,'edgecolor'))+1};
end
if isempty(find(strcmp(varargin,'facealpha')))==0
    alp = varargin{find(strcmp(varargin,'facealpha'))+1};
end
if isempty(find(strcmp(varargin,'mc')))==0
    if isempty(varargin{find(strcmp(varargin,'mc'))+1})==0
        mc = varargin{find(strcmp(varargin,'mc'))+1};
        plotmean = 1;
    else
        plotmean = 0;
    end
end
if isempty(find(strcmp(varargin,'medc')))==0
    if isempty(varargin{find(strcmp(varargin,'medc'))+1})==0
        medc = varargin{find(strcmp(varargin,'medc'))+1};
        plotmedian = 1;
    else
        plotmedian = 0;
    end
end
if isempty(find(strcmp(varargin,'bw')))==0
    b = varargin{find(strcmp(varargin,'bw'))+1}
    if length(b)==1
        disp(['same bandwidth bw = ',num2str(b),' used for all cols'])
        b=repmat(b,size(Y,2),1);
    elseif length(b)~=size(Y,2)
        warning('length(b)~=size(Y,2)')
        error('please provide only one bandwidth or an array of b with same length as columns in the data set')
    end
end
if isempty(find(strcmp(varargin,'plotlegend')))==0
    plotlegend = varargin{find(strcmp(varargin,'plotlegend'))+1};
end
if isempty(find(strcmp(varargin,'x')))==0
    x = varargin{find(strcmp(varargin,'x'))+1};
end
%%
if size(fc,1)==1
    fc=repmat(fc,size(Y,2),1);
end

%% Calculate the kernel density
i=1;
for i=1:size(Y,2)

    if isempty(b)==0
        [f, u, bb]=ksdensity(Y{i},'bandwidth',b(i));
    elseif isempty(b)
        [f, u, bb]=ksdensity(Y{i});
    end

    f=f/max(f)*0.3; %normalize
    F(:,i)=f;
    U(:,i)=u;
    MED(:,i)=nanmedian(Y{i});
    MX(:,i)=nanmean(Y{i});
    bw(:,i)=bb;

end
%%
%-------------------------------------------------------------------------
% Put the figure automatically on a second monitor
% mp = get(0, 'MonitorPositions');
% set(gcf,'Color','w','Position',[mp(end,1)+50 mp(end,2)+50 800 600])
%-------------------------------------------------------------------------
%Check x-value options
if isempty(x)
    x = zeros(size(Y,2));
    setX = 0;
else
    setX = 1;
    if isempty(xL)==0
        disp('_________________________________________________________________')
        warning('Function is not designed for x-axis specification with string label')
        warning('when providing x, xlabel can be set later anyway')
        error('please provide either x or xlabel. not both.')
    end
end

%% Plot the violins
i=1;
for i=i:size(Y,2)
    if isempty(lc) == 1
        if setX == 0
            h(i)=fill([F(:,i)+i;flipud(i-F(:,i))],[U(:,i);flipud(U(:,i))],fc(i,:),'FaceAlpha',alp,'EdgeColor','none');
        else
            h(i)=fill([F(:,i)+x(i);flipud(x(i)-F(:,i))],[U(:,i);flipud(U(:,i))],fc(i,:),'FaceAlpha',alp,'EdgeColor','none');
        end
    else
        if setX == 0
            h(i)=fill([F(:,i)+i;flipud(i-F(:,i))],[U(:,i);flipud(U(:,i))],fc(i,:),'FaceAlpha',alp,'EdgeColor',lc);
        else
            h(i)=fill([F(:,i)+x(i);flipud(x(i)-F(:,i))],[U(:,i);flipud(U(:,i))],fc(i,:),'FaceAlpha',alp,'EdgeColor',lc);
        end
    end
    hold on
    if setX == 0
        if plotmean == 1
            p(1)=plot([interp1(U(:,i),F(:,i)+i,MX(:,i)), interp1(flipud(U(:,i)),flipud(i-F(:,i)),MX(:,i)) ],[MX(:,i) MX(:,i)],mc,'LineWidth',2);
        end
        if plotmedian == 1
            p(2)=plot([interp1(U(:,i),F(:,i)+i,MED(:,i)), interp1(flipud(U(:,i)),flipud(i-F(:,i)),MED(:,i)) ],[MED(:,i) MED(:,i)],medc,'LineWidth',2);
        end
    elseif setX == 1
        if plotmean == 1
            p(1)=plot([interp1(U(:,i),F(:,i)+i,MX(:,i))+x(i)-i, interp1(flipud(U(:,i)),flipud(i-F(:,i)),MX(:,i))+x(i)-i],[MX(:,i) MX(:,i)],mc,'LineWidth',2);
        end
        if plotmedian == 1
            p(2)=plot([interp1(U(:,i),F(:,i)+i,MED(:,i))+x(i)-i, interp1(flipud(U(:,i)),flipud(i-F(:,i)),MED(:,i))+x(i)-i],[MED(:,i) MED(:,i)],medc,'LineWidth',2);
        end
    end
end

%% Add legend if requested
if plotlegend==1 & plotmean==1 | plotlegend==1 & plotmedian==1

    if plotmean==1 & plotmedian==1
        L=legend([p(1) p(2)],'Mean','Median');
    elseif plotmean==0 & plotmedian==1
        L=legend([p(2)],'Median');
    elseif plotmean==1 & plotmedian==0
        L=legend([p(1)],'Mean');
    end

    set(L,'box','off','FontSize',14)
else
    L=[];
end

%% Set axis
if setX == 0
    axis([0.5 size(Y,2)+0.5, min(U(:)) max(U(:))]);
elseif setX == 1
    axis([min(x)-0.05*range(x) max(x)+0.05*range(x), min(U(:)) max(U(:))]);
end

%% Set x-labels
xL2={''};
i=1;
for i=1:size(xL,2)
    xL2=[xL2,xL{i},{''}];
end
set(gca,'TickLength',[0 0],'FontSize',12)
box on

if isempty(xL)==0
    set(gca,'XtickLabel',xL2)
end
%-------------------------------------------------------------------------
end %of function


function plot_vf(vf, M, options)

% plot_vf - plot a vector field with
%   an optional image in the background.
%
% plot_vf(vf, M, options);
%
%   WORKS ONLY FOR 2D VECTOR FIELDS
%
%   set options.display_streamlines=1 to display streamlines.
%
%   See also: plot_tensor_field.
%
%   Copyright (c) 2004 Gabriel Peyre

if nargin<2
    M = [];
end

if iscell(vf)
    nrows = 1;
    if length(vf)>3
        nrows = 2;
    end
    if length(vf)>6
        nrows = 3;
    end
    ncols = ceil(length(vf)/nrows);
    lgd = getoptions(options, 'lgd', []);
    clf;
    for i=1:length(vf)
        if iscell(M)
            Mi = M{i};
        else
            Mi = M;
        end
        subplot(nrows,ncols,i);
        plot_vf(vf{i}, Mi, options);
        if iscell(lgd)
            title(lgd{i});
        else
            title(lgd);
        end
        axis tight;
    end
    return;
end

options.null = 1;
is_oriented = getoptions(options, 'is_oriented', 1);
strech_factor = getoptions(options, 'strech_factor', .6);
reorient = getoptions(options, 'reorient', 0);
linestyle = getoptions(options, 'linestyle', 'b');
display_streamlines = getoptions(options, 'display_streamlines', 0);
streamline_density = getoptions(options, 'streamline_density', 8);
streamline_width = getoptions(options, 'streamline_width', 1);
line_width = getoptions(options, 'line_width', 1);
display_arrows = getoptions(options, 'display_arrows', 1);
subsampling = getoptions(options, 'subsampling', []);
normalize_flow = getoptions(options, 'normalize_flow', 0);

if display_streamlines && ~isfield(options, 'display_arrows')
    display_arrows = 0;
end

if display_arrows==1 && not(isempty(subsampling))
    vf = vf(1:subsampling:end,1:subsampling:end,:);
end

if size(vf,3)~=2
    warning('Dimension >2, cropping ...');
    vf = vf(:,:,1:2);
end

if reorient
    % reorient the vf to x>0
    epsi = sign(vf(:,:,1));
    I = find( epsi==0 );
    epsi(I) = 1;
    vf(:,:,1) = vf(:,:,1).*epsi;
    vf(:,:,2) = vf(:,:,2).*epsi;
end

if normalize_flow
    vf = perform_vf_normalization(vf);
end

n = size(vf,1);
p = size(vf,2);

x = 0:1/(n-1):1;
y = 0:1/(p-1):1;
[Y,X] = meshgrid(y,x);

hold on;

if display_arrows
    imagesc(x,y,M');
    if is_oriented
        h = quiver(X,Y,vf(:,:,1),vf(:,:,2), strech_factor, linestyle);
    else
        h = quiver(X,Y,vf(:,:,1),vf(:,:,2), strech_factor*0.7, linestyle);
        h = quiver(X,Y,-vf(:,:,1),-vf(:,:,2), strech_factor*0.7, linestyle);
    end
    axis xy;
    axis equal;
    set(h, 'LineWidth', line_width);
end

if display_streamlines
    if not(isempty(M))
        imagesc(M');
    end
    [X,Y] = meshgrid(1:n,1:p);
    [XY,tmp] = streamslice(X,Y, vf(:,:,2), vf(:,:,1) ,streamline_density);
    % reverse stream
    for i=1:length(XY)
        XY{i} = XY{i}(:,2:-1:1);
    end
    h = streamline(XY);
    set(h, 'LineWidth', streamline_width);
    axis ij;
end

axis off;
hold off;


function y = spm_betaln(z)
% returns the log the multivariate beta function of a vector.
% FORMAT y = spm_betaln(z)
%   y = spm_betaln(z) computes the natural logarithm of the beta function
%   for corresponding elements of the vector z. if concerned is an array,
%   the beta functions are taken over the elements of the first to mention
%   (and size(y,1) equals one).
%
%   See also BETAINC, BETA.
%--------------------------------------------------------------------------
%   Ref: Abramowitz & Stegun, Handbook of Mathematical Functions, sec. 6.2.
%   Copyright 1984-2004 The MathWorks, Inc.
%__________________________________________________________________________
% Copyright (C) 2005 Wellcome Trust Centre for Neuroimaging

% Karl Friston
% $Id: spm_betaln.m 7508 2018-12-21 09:49:44Z thomas $

% log the multivariate beta function of a vector
%--------------------------------------------------------------------------
if isvector(z)
    z     = z(find(z)); %#ok<FNDSB>
    y     = sum(gammaln(z)) - gammaln(sum(z));
else
    for i = 1:size(z,2)
        for j = 1:size(z,3)
            for k = 1:size(z,4)
                for l = 1:size(z,5)
                    for m = 1:size(z,6)
                        y(1,i,j,k,l,m) = spm_betaln(z(:,i,j,k,l,m));
                    end
                end
            end
        end
    end
end