function [xopt,fval,exitflag,output] = spcompsearch(z, xbox, options)
% SPCOMPSEARCH  Modified compass (coordinate) search algorithm
%    performing a local search of the sparse grid inpterpolant.
%    X = SPCOMPSEARCH(Z)  Finds a local optimizer X for the given
%    sparse grid interpolant Z using a modified compass search
%    algorithm starting from the best available sparse grid point.
%    The entire range of the sparse grid interplant is searched.
%
%    X = SPCOMPSEARCH(Z, XBOX) Uses the search box XBOX, X = [a1,
%    b1; a2, b2; ...]. The size of search box XBOX must be smaller
%    than or equal to the range of the interpolant.
%
%    X = SPCOMPSEARCH(Z, XBOX, OPTIONS)  Additionally, an OPTIONS
%    structure can be provided, see SPOPTIMSET for further details.
%
%    [X,FVAL] = SPCOMPSEARCH(...)  returns the value of the
%    sparse grid interpolant at X.
%
%    [X,FVAL,EXITFLAG] = SPCOMPSEARCH(...)  returns an EXITFLAG
%    that describes the exit condition of SPCOMPSEARCH. Possible
%    values of EXITFLAG and the corresponding exit conditions are
%
%     1  SPCOMPSEARCH converged to a solution X.
%     0  Maximum number of iterations reached.
%
%    [X,FVAL,EXITFLAG,OUTPUT] = SPCOMPSEARCH(...) returns a
%    structure OUTPUT with the number of function evaluations in
%    OUTPUT.nFevals and the computing time in .time.
%
%    Example: (minimizing the three-hump camel-back function)
%       f = inline('12*x.^2-6.3*x.^4+x.^6+6*y*(y-x)');
%       range = [-3 3; -3 3];
%       options = spset('keepFunctionValues','on');
%       z = spvals(f, 2, range, options);
%       [xopt, fval] = spcompsearch(z)
%
%    See also SPOPTIMSET.

% Author : Andreas Klimke
% Version: 2.1
% Date   : September 1, 2007

% Change log:
% V2.1 : September 1, 2007
%        Changed calling syntax to match other optimization
%        methods. Added maximum number of iterations.
% V2.0 : January 23, 2006
%        Added TolFun break criterium.
% V1.9 : June 9, 2005
%        Removed multiple start processing from V1.5; moved to
%        separate routine SPMULTISTART. Removed start point
%        computation; moved to separate routine.
% V1.8 : April 15, 2005
%        Corrected bug concerning testCorners option; Modified
%        slightly to cope with new dimension-adaptive format.
% V1.7 : January 14, 2005
%        Corrected bug that lead to wrong rescaling of parts of the
%        grid data if previous results were used.
% V1.6 : January 11, 2005
%        Added capability for handling polynomial sparse grid
%        interpolants. Added tolerance on X as options.
% V1.5 : November 13, 2004
%        Added feature for performing multiple searches at a time.
% V1.4 : September 6, 2004
%        Added capability for handling dimension-adaptive data.
% V1.3 : September 6, 2004
%      : Added check if the spvals structure contains a valid
%        range; otherwise, set it to [0,1]^d.
% V1.2 : March 9, 2004
%        Added random start point option
% V1.1 : February 18, 2004
%        Moved search for optimum of sparse grid points to separate
%        routine (spfindopt.m).
% V1.0 : January 7, 2004
%        Initial version

% ------------------------------------------------------------
% Sparse Grid Interpolation Toolbox
% Copyright (c) 2006 W. Andreas Klimke, Universitaet Stuttgart
% Copyright (c) 2007-2008 W. A. Klimke. All Rights Reserved.
% See LICENSE.txt for license.
% email: klimkeas@ians.uni-stuttgart.de
% web  : http://www.ians.uni-stuttgart.de/spinterp
% ------------------------------------------------------------

t0 = clock;

if nargin < 2, xbox = []; end
if nargin < 3, options = []; end

d = z.d;

% In case that no range has been provided to spvals -> set it to
% [0,1]^d.
if isempty(z.range)
	z.range = [zeros(d,1) ones(d,1)];
end
if isempty(xbox)
	xbox = z.range;
end

if isfield(z, 'dimAdapt')
	n = z.maxLevel';
else
	n = z.maxLevel*ones(d,1,'uint8');
end

% savepoints = [];

% Determine optimization start point(s)
[xopt, fval] = spgetstartpoint(z, xbox, options);

minimize = spoptimget(options, 'Minimize', 'on');
maximize = spoptimget(options, 'Maximize', 'off');
if strcmpi(minimize, 'on'), isminimize = 1; else isminimize = 0; end
if strcmpi(maximize, 'on'), ismaximize = 1; else ismaximize = 0; end

ymin = []; ymax = [];
if isminimize
	ymin = fval(1);
	if ismaximize
		ymax = fval(2);
	end
else
	ymax = fval(1);
end

switch(lower(z.gridType))
 case {'maximum', 'noboundary', 'clenshaw-curtis'}
	linear = 1;
 case {'chebyshev', 'gauss-patterson'}
	linear = 0;
 otherwise
		error('MATLAB:spinterp:badopt',['Unknown grid type ''' gridtype '''.']);
end

maxiter = spoptimget(options, 'MaxIter', 100);

tolx = spoptimget(options, 'TolX', []);
if isempty(tolx)
	if linear
		tolx = inf;
	else
		tolx = max(z.estRelError * 1e-2, 10*eps);
	end
end

tolfun = spoptimget(options, 'TolFun', 1e-6);
dispopt = spoptimget(options, 'Display', 'off');

nfevals = 0;

x = zeros(2*d,d);

exitflag = zeros(size(xopt,2));

for k = 1:size(xopt,2)

	% Compute the step length parameters
	dx = 1./2.^(floor(double(n)/double(d))).*(z.range(:,2)-z.range(:,1));
	dxunit = 1./2.^(floor(double(n)/double(d)));
	dxmin = 1./2.^double(n);
	dxminvec = 1./2.^double(n).*(z.range(:,2)-z.range(:,1));

	% correct the start values to lie on a full grid point
	if linear
		updated = 0;
		for l = 1:d
			xtemp = floor((xopt(l,k) - z.range(l,1)) / ...
										dxminvec(l))*dxminvec(l) + z.range(l,1);
			while xtemp < xbox(l,1)
				xtemp = xtemp + dxminvec(l);
			end
			if xtemp > xbox(l,2)
				% this can only be true if the search box is smaller than the
				% step width dx. In this case, take the center of the search
				% box as the starting point.
				xtemp = (xbox(l,1) + xbox(l,2))/2;
			end
			if xtemp ~= xopt(l,k)
				xopt(l,k) = xtemp;
				updated = 1;
			end
		end
		if updated
			xoptcell = num2cell(xopt(:,k));
			nfevals = nfevals + 1;
      if k == 1 && isminimize
        ymin = spinterp(z, xoptcell{:});
      else
        ymax = spinterp(z, xoptcell{:});
      end
    end
	end

  [isdispiter, iterstr] = initoptidisp(dispopt);
  if isdispiter
	  if k == 1 && isminimize
		  disp(sprintf(iterstr, 0, nfevals, 0, ymin, 'start point'));
	  else
		  disp(sprintf(iterstr, 0, nfevals, 0, ymax, 'start point'));
		end
	end
	if k == 2
		isminimize = 0;
	end

	exitflag(k) = 0;
	for kit = 1:maxiter

		% save the points for later processing, if requested by the
    % user
		%if nargout == 3
		%	if isminimize
		%		savepoints = [savepoints; [xopt(:,k)' ymin]];
		%	else
		%		savepoints = [savepoints; [xopt(:,k)' ymax]];
		%	end
		%end

		nfevals = nfevals + uint32(d)*2;

		% Generate search points
		id = uint32(1);
		for l = 1:d
			for l2 = 1:d
				if l == l2
					x(id,l) = xopt(l,k) - dx(l);
					x(id+1,l) = xopt(l,k) + dx(l);
					if x(id,l) < xbox(l,1)
            x(id,l) = xbox(l,1);
          end
          if x(id+1,l) > xbox(l,2)
            x(id+1,l) = xbox(l,2);
          end
				else
					x(id,l2) = xopt(l2,k);
					x(id+1,l2) = xopt(l2,k);
				end
			end
			id = id + 2;
		end

		% Perform sparse grid interpolation
		xcell = num2cell(x,1);
		ytemp = spinterp(z, xcell{:});

		if isminimize
			[ymintemp, id] = min(ytemp);
			if ymintemp < ymin
				xopt(:,k) = x(id,:)';
      	if isdispiter, disp(sprintf(iterstr, kit, nfevals, ...
	                          0, ymintemp, 'coordinate step')); end
        % Terminate if function value change is below tolerance
        if abs(ymin-ymintemp) < tolfun
				  ymin = ymintemp;
					exitflag(k) = 1;
          break;
        end
        ymin = ymintemp;
			else
      	if isdispiter, disp(sprintf(iterstr, kit, nfevals, ...
	                          0, ymin, 'contract step')); end
				if all(dxunit <= dxmin) && all(dxunit <= tolx)
					exitflag(k) = 1;
					break;
				end
				for l = 1:d
					if dxunit(l) > dxmin(l) || dxunit(l) > tolx
						dxunit(l) = dxunit(l) / 2;
						dx(l) = dx(l) / 2;
					end
				end
			end
		else
			[ymaxtemp, id] = max(ytemp);
			if ymaxtemp > ymax
				xopt(:,k) = x(id,:)';
      	if isdispiter, disp(sprintf(iterstr, kit, nfevals, ...
	                          0, ymaxtemp, 'coordinate step')); end
        % Terminate if function value change is below tolerance
        if abs(ymax-ymaxtemp) < tolfun
				  ymax = ymaxtemp;
					exitflag(k) = 1;
          break;
        end
				ymax = ymaxtemp;
			else
      	if isdispiter, disp(sprintf(iterstr, kit, nfevals, ...
	                          0, ymax, 'contract step')); end
				if all(dxunit <= dxmin) && all(dxunit <= tolx)
					exitflag(k) = 1;
					break;
				end
				for l = 1:d
					if dxunit(l) > dxmin(l) || dxunit(l) > tolx
						dxunit = dxunit / 2;
						dx = dx / 2;
					end
				end
			end
		end
	end
end

fval = [ymin ymax];

if nargout == 4
	output.nFEvals = nfevals;
	output.time = etime(clock, t0);
	% output.points = savepoints;
end


function [output] = F_power_spectrum(input_layer)
% assume the input is a DxTxN matrix of complex spectrum, where D is the dimension of the feature vector,
% T is the number of frames in the minibatch or utterance, and N is the
% number of sentences
ComplexSpectrum = input_layer.a;
output = abs( ComplexSpectrum .* conj(ComplexSpectrum) );

end


function [data] = simpleFill2D(data, flags, fun)
% SYNTAX:
%    [data_filled] = simpleFill1D(data, flags)
%
% DESCRIPTION:
%    fill flagged data with a simple interpolation using MATLAB
%    interp1 'pchip', 'extrap'
%
% NOTE: data can be a matrix, the operation is executed column by column
%

%--- * --. --- --. .--. ... * ---------------------------------------------
%               ___ ___ ___
%     __ _ ___ / __| _ | __|
%    / _` / _ \ (_ |  _|__ \
%    \__, \___/\___|_| |___/
%    |___/                    v 1.0RC1
%
%--------------------------------------------------------------------------
%  Copyright (C) 2021 Geomatics Research & Development srl (GReD)
%  Written by:       Andrea Gatti
%  Contributors:     Andrea Gatti
%  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
%--------------------------------------------------------------------------

if nargin < 3
        % Correlation function
        fun = @(dist) exp(-(dist).^2);
end

    x_g = 1 : size(data,2);
    y_g = 1 : size(data,1);

    [x_mesh, y_mesh] = meshgrid(x_g, y_g);

    x_p = x_mesh(:);
    x_o = x_mesh(~flags);

    y_p = y_mesh(:);
    y_o = y_mesh(~flags);

    data_o = data(~flags);

    for x = 1 : size(data,2)
        id_p = (x_p == x);
        if sum(id_p) > 0
            tmp_x_p = x_p(id_p);
            tmp_y_p = y_p(id_p);
            d = sqrt((repmat(tmp_x_p, 1, size(x_o,1)) - repmat(x_o', size(tmp_x_p, 1), 1)).^2 + ...
                (repmat(tmp_y_p, 1, size(y_o,1)) - repmat(y_o', size(tmp_y_p, 1), 1)).^2);
            %d = d / sqrt(sum(size(data).^2));
            data(id_p) = ((fun(d) * data_o) ./ sum(fun(d),2));
        end
    end
end


%DEMO_POLYGONSKELETON  One-line description here, please.
%
%   output = demo_polygonSkeleton(input)
%
%   Example
%   demo_polygonSkeleton
%
%   See also
%

% ------
% Author: David Legland
% e-mail: david.legland@inrae.fr
% INRAE - BIA Research Unit - BIBS Platform (Nantes)
% Created: 2022-02-18,    using Matlab 9.10.0.1739362 (R2021a) Update 5
% Copyright 2022 INRAE.

% Note: this example require the "matGraphs" toolbox
% (https://github.com/mattools/matGraphs)
% start from a binary shape
img = imread('circles.png');
img = imfill(img, 'holes');
% figure; imshow(img); hold on;

% compute a smooth contour
cntList = bwboundaries(img);
poly = cntList{1}(2:end,:);
poly = smoothPolygon(poly, 5);

% draw the polygon
figure; hold on; axis equal; axis([0 250 0 250]);
drawPolygon(poly, 'color', 'k', 'linewidth', 1);

% compute skeleton
[vertices, adjList] = polygonSkeleton(poly);
% convert adjacency list to an edge array
edges = adjacencyListToEdges(adjList);
% draw the skeleton graph
drawGraphEdges(vertices, edges, 'color', 'b');

print(gcf, 'demo_polygonSkeleton.png', '-dpng');


function sVF = grad(sF, varargin)
% gradient of a spherical function
%
% Syntax
%   sVF = grad(sF)  % returns the gradient as a spherical vector field
%   g = grad(sF, v) % return the gradient in point v as vector3d
%
% Input
%  sF - @S2FunHarmonic
%  v - @vector3d
%
% Output
%  sVF - @sphericalVectorFieldHarmonic
%    g - @vector3d
%

if nargin > 1

  delta = 0.1*degree;

  N = varargin{1};   % normal direction
  t1 = perp(N);      % first tangential vector
  t2 = normalize(cross(N,t1));  % second tangential vector

  % the exponential map on the sphere
  v2 = rotation.byAxisAngle(t1,-delta) .* N;
  v1 = rotation.byAxisAngle(t2,delta) .* N;

  sFN = sF.eval(N);

  sVF = ((sF.eval(v1)-sFN) .* t1 + (sF.eval(v2)-sFN) .* t2) ./ delta;

else
  sVF = S2VectorFieldHarmonic.quadrature(@(v) grad(sF,v));
end

end


function [cp,tm,b,t,wh,oocvec] = change_point(t,tt,Mode,tthresh)
% :Usage:
% ::
%
%     [cp,tm,b,t,wh,ooc_vector] = change_point(t,tt,Mode,tthresh)
%
%     [cp,baseline mean,max t value,time of max t] = change_point(Zm,sterr,tt,tthresh)
%
% :Inputs:
%
%   **tt:**
%        is number of baseline timepoints
%
%   **t:**
%        is group t-value timeseries
%
%
%   **Mode: 'thresh' or 'time':**
%        if 'thresh': tthresh = threshold for significant t-values.
%
%        change_point finds the first significant supra-threshold t-value and
%        looks back in time to estimate the change point.
%
%        if Mode = 'time'
%
%        change_point finds the estimated change-point for process determined
%        to be out of control at time tthresh
%
% :Outputs:
%
%   **wh:**
%        indices of out of control points
%
%   **ooc_vector:**
%        indicator vector for ooc points
%

    switch Mode
        case 'thresh'
            % find t-values above threshold
            % see timeseries_mc_pvalue to get threshold

            oocvec = abs(t) > abs(tthresh);
            wh = find(oocvec);
            wh(wh <= tt) = [];      % eliminate values in baseline period

            if isempty(wh),
                b = [];
            else
                b = wh(1);
            end

        case 'time'
            b = tthresh;
            wh = b;
            oocvec = [];
        otherwise
            error('Mode must be thresh or time');
    end

    % tm = tmax, b = time of max t
    %[tm, b] = max(abs(t(tt+1:end)));              % Calculate maximum absolute t-value
    % b = b+tt;                                     % max t time

    tm = t(b);                                      % put sign back in

    % zero-crossing

    if ~isempty(b)
        [a,cp] = max((sign(t(1:b)) ~= sign(tm)).*(1:b));  % change point, last zero crossing
    else
        cp = [];
    end

return


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
%
%   Copyright (c) 2007 Gabriel Peyre

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

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;
    for iter=1:niter_synthesis
        % 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, +1, options);

for iter=1:niter_synthesis
    % spatial equalization
    M1 = my_equalization(M1,M);
    % forward transforms
    MW1 = my_transform(M1, +1, options);
    % wavelet domain equalization
    MW1 = my_equalization(MW1,MW);
    % backward transform
    M1 = my_transform(MW1, -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, dir, options)

n = size(M,1);
deltaJ = 5;
Jmax = log2(n)-1;
Jmin = max(Jmax-deltaJ+1,3);

synthesis_method = getoptions(options, 'synthesis_method', 'steerable');
% 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);
    otherwise
        error('Unknown transform.');
end


function [row, col, mu] = isolated_peaks_new(S1, ops)
% takes a matrix of timepoints by channels S1
% outputs threshold crossings that are relatively isolated from other peaks
% outputs row, column and magnitude of the threshold crossing
loc_range = getOr(ops, 'loc_range', [5 4]);
long_range = getOr(ops, 'long_range', [30 6]);
Th = ops.spkTh;
nt0 = ops.nt0;

% loc_range = [3  1];
% long_range = [30  6];

% finding the local minimum in a sliding window within plus/minus loc_range extent
% across time and across channels
smin = my_min(S1, loc_range, [1 2]);
peaks = single(S1<smin+1e-3 & S1<Th); % the peaks are samples that achieve this local minimum, AND have negativities less than a preset threshold

% only take local peaks that are isolated from other local peaks
sum_peaks = my_sum(peaks, long_range, [1 2]); % if there is another local peak close by, this sum will be at least 2
peaks = peaks .* (sum_peaks<1.2) .* S1; % set to 0 peaks that are not isolated, and multiply with the voltage values

% exclude temporal buffers
peaks([1:nt0 end-nt0:end], :) = 0;

[row, col, mu] = find(peaks); % find the non-zero peaks, and take their amplitudes

mu = - mu; % invert the sign of the amplitudes


function R = compute_residuals(Y,A,b,C,f)

% compute residual traces for each component

% INPUTS
% Y     matrix of data in 2D format of pointer to file
% A     set of spatial components
% b     set of spatial background components
% C     set of temporal components
% f     set of temporal background component

AA = A'*A;
AY = mm_fun(A,Y);
nA2 = sum(A.^2,1);
R = bsxfun(@times, AY - AA*C - (A'*b)*f,1./nA2(:));


function  [im_out, Par] = TWSC_Sigma_RW(Par)
im_out     =   Par.nim;
% parameters for noisy image
[h,  w, ch] = size(im_out);
Par.h = h;
Par.w = w;
Par.ch = ch;
Par = SearchNeighborIndex( Par );
% original noisy image to patches
NY = Image2Patch( Par.nim, Par );
Par.Sigma = sqrt(mean(Par.nSig.^2));
for ite  =  1 : Par.Outerloop
    % iterative regularization
    im_out = im_out + Par.delta * (Par.nim - im_out);
    % image to patches
    Y = Image2Patch( im_out, Par );
    % estimate local noise variance, par.lambdals is put here since the MAP and Bayesian rules
    if Par.lambda1 ~= 0
        if ite == 1
            SigmaRow = zeros(size(NY));
        else
            SigmaRow = (NY-Y).^2;
        end
    end
    SigmaCol = Par.lambda2 * sqrt(abs(repmat(Par.Sigma^2, 1, size(Y,2)) - mean((NY - Y).^2))); % Estimated Local Noise Level
    % estimation of noise variance
    if mod(ite-1, Par.Innerloop)==0
        Par.nlsp = max(Par.nlspgap, Par.nlsp - Par.nlspgap);
        % searching non-local patches
        blk_arr = Block_Matching_RW( Y, Par );
    end
    % Weighted Sparse Coding
    Y_hat = zeros(Par.ps2ch, Par.maxrc, 'double');
    W_hat = zeros(Par.ps2ch, Par.maxrc, 'double');
    for i = 1:Par.lenrc
        index = blk_arr(:, i);
        nlY = Y( : , index );
        DC = mean(nlY, 2);
        nDCnlY = bsxfun(@minus, nlY, DC);
        % Compute W2
        W2 = 1 ./ (SigmaCol(index) + eps);
        % update D
        [D, S, ~] = svd( full(nDCnlY), 'econ' );
        % update S
        S = sqrt(max( diag(S).^2 - length(index) * SigmaCol(index(1))^2, 0 ));
        if Par.lambda1 == 0
            % update weight for sparse coding
            Wsc = bsxfun( @rdivide, SigmaCol(index).^2, S + eps );
            % update C by soft thresholding
            B = D' * nDCnlY;
            C = sign(B) .* max( abs(B) - Wsc, 0 );
            % update Y
            nDCnlYhat = D * C;
        else
            W1 = exp( - Par.lambda1*mean(SigmaRow(:, index), 2)); % max?
            S = diag(S);
            % min |Z|_1 + |W1(Y-DSC)W2|_F,2  s.t.  C=Z
            C = TWSC_ADMM( nDCnlY, D, S, W1, W2, Par );
            % update Y
            nDCnlYhat = D * S * C;
        end
        % add back DC components
        nlYhat = bsxfun(@plus, nDCnlYhat, DC);
        % aggregation
        Y_hat(:, index) = Y_hat(:, index) + bsxfun(@times, nlYhat, W2);
        W_hat(:, index) = W_hat(:, index) + repmat(W2, [Par.ps2ch, 1]);
    end
    % Reconstruction
    im_out = PGs2Image(Y_hat, W_hat, Par);
end
return;


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

%*****************************************************************************80
%
%% LINE_CCVT_LLOYD carries out the constrained Lloyd algorithm.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    28 July 2014
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer N, the number of generators.
%
%    Input, real A, B, the left and right endpoints.
%
%    Input, integer IT_NUM, the number of iterations to take.
%
%    Input, string HEADER, an identifying string.
%
%    Input, real X(N), the initial point locations.
%
%    Output, real X(N), the final point locations.
%
  x = x(:);
%
%  Print the initial generators.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Initial generators:\n' );
  fprintf ( 1, '\n' );
  for k = 1 : n
    fprintf ( 1, '  %4d  %f\n', k, x(k,1) );
  end
%
%  Initialize the plotting arrays.
%
  step = 1 : it_num;
  e = nan ( it_num, 1 );
  xm = nan ( it_num, 1 );

  for it = 1 : it_num

    x_plot ( 1:n, it ) = x(1:n,1);

    x_new = line_ccvt_lloyd_step ( n, a, b, x );

    e(it) = line_cvt_energy ( n, a, b, x );
    e(it) = max ( e(it), eps );
%
%  Display the energy.
%
    figure ( 1 )
    plot ( step, log ( e ), 'm-*' )
    title ( 'Log (Energy)' )
    xlabel ( 'Step' )
    ylabel ( 'Energy' )
    grid
%
%  Compute the generator motion.
%
    xm(it,1) = sum ( ( x_new(:) - x(:) ).^2 ) / n;
%
%  Display the generator motion.
%
    figure ( 2 )
    plot ( step, log ( xm ), 'm-*' )
    title ( 'Log (Average generator motion)' )
    xlabel ( 'Step' )
    ylabel ( 'Motion' )
    grid
%
%  Update the generators.
%
    x(1:n,1) = x_new(1:n,1);

  end

  x_plot(1:n,it_num+1) = x(1:n,1);
%
%  Print the current generators.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Current generators:\n' );
  fprintf ( 1, '\n' );
  for k = 1 : n
    fprintf ( 1, '  %4d  %f\n', k, x(k,1) );
  end
%
%  Plot the evolution of the locations of the generators.
%
  figure ( 3 )

  y = ( 0 : it_num );
  for k = 1 : n
    plot ( x_plot(k,1:it_num+1), y, 'LineWidth', 1 )
    hold on;
  end
  grid on
  hold off;

  title ( 'Generator evolution.' );
  xlabel ( 'Generator positions' );
  ylabel ( 'Iterations' );
%
%  Save the plots.
%
  figure ( 1 )
  filename = strcat ( header, '_energy.png' );
  print ( '-dpng', filename );
  figure ( 2 )
  filename = strcat ( header, '_motion.png' );
  print ( '-dpng', filename );
  figure ( 3 )
  filename = strcat ( header, '_evolution.png' );
  print ( '-dpng', filename );

  return
end


function [GrayCode,GrayCodeLength] = ImprovedGenerateGrayCode( Range )
% Input: Range is vector storing the maximum state in each digit.
% Output; GrayCode is the generated Graycode,GrayCodeLength is the number
% of generated Gray code.
Len = size( Range,2 );
if isempty( find( Range>1 ) ) == 1 %#ok<EFIND>
    GrayCode = zeros(1,Len);  GrayCodeLength = 1;
    return
end
[ LocalGrayCode,GrayCodeLength ] = GenerateGrayCode( Range( Range > 1 ) );

 t = 1;GrayCode  = zeros( GrayCodeLength,Len );
for p = 1:Len
   if Range( p ) == 1
      GrayCode(:,p) = zeros( GrayCodeLength,1 );
   else
      GrayCode(:,p) = LocalGrayCode(:,t);
      t = t + 1;
   end
end

end


function ind = sub2indn(varargin)

% function ind = sub2indn(siz,A,nanOutBound)
% ------------------------------------------------------------------------
% This function is similar to MATLAB's sub2ind function. However the input
% subscrip indices are provided as an nxm array, such that numel(siz)=m and
% numel(ind)=n. The output are the equivalent linear indices
%
%   See also: ind2subn ind2sub sub2ind.
%
% Change log
% 2018/05/17 Optionally output NaN values for out of bound indices
% ------------------------------------------------------------------------

%% Parse input

switch nargin
    case 2
        siz=varargin{1};
        A=varargin{2};
        nanOutBound=0;
    case 3
        siz=varargin{1};
        A=varargin{2};
        nanOutBound=varargin{3};
end

%%
siz = double(siz);
numDim = numel(siz);
k = cumprod(siz);

if numDim < 2
    error('Invalid size specified. The number of dimensions should be equal or larger than 2');
end

if any(size(A)==0)
    A=[];
end

if ~isempty(A)

    if size(A,2) ~= numDim
        error('The specified array size and number of subscript index columns do not match');
    end

    if ~nanOutBound
        if any(A(:)<1) || any(max(A,[],1)>siz)
            %Verify subscripts are within range
            error('Index out of range');
        end
    else
        A(A<1)=NaN;
        A(A>siz(ones(size(A,1),1),:))=NaN;
    end

    ind=A(:,1);
    for q=2:1:numDim
        ind = ind + (double(A(:,q))-1)*k(q-1);
    end
else
    ind=[];
end

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


function [dat, W, A, lambda]= proc_ssd(dat, freqs, varargin)
% PROC_SSD - Spatio-Spectral Decomposition for a given frequency band of
% interest
%
%Synopsis:
% [DAT, W, A, LAMBDA]= PROC_SSD(DAT, FREQS, <OPT>)
%
% INPUT:
%     DAT -   data structure of continous data
%     FREQS - 3 x 2 matrix with the cut-off frequencies for the following
%             bands:
%             - first row: pass-band for the signal of interest
%             - second row: pass-band for the noise
%             - third row: stop-band for the noise
%             See the example below.
% OPT - struct or property/value list of optional properties:
%     .filterOrder  -     filter order used for butterworth bandpass and
%                         bandstop filtering. Default: 2
%     .epochIndices -     a matrix of size N x 2, where N is the number of
%                         good (i.e. artifact free) data segments. Each row of
%                         this matrix contains the first and the last sample index of
%                         a data segment, i.e. epoch_indices(n,:) = [1000, 5000]
%                         means that the n'th segment starts at sample 1000 and
%                         ends at sample 5000.
%
% OUTPUT:
% DAT       - updated data structure
% W         - SSD projection matrix (filters are in the columns)
% A         - estimated mixing matrix (spatial patterns are in the columns)
% LAMBDA    - generalized eigenvalue score of SSD objective function
%
%
%
% Description:
% This is a function for the extraction of neuronal oscillations
% with optimized signal-to-noise ratio. The algorithm maximizes
% the power at the center frequency (signal of interest) while simultaneously suppressing it
% at the flanking frequency bins (noise band).
%
% Example for FREQS:
% Let us consider that we want to extract oscillations in the 10-12 Hz
% frequency range. Then we define:
%   freqs = [10 12; 8 14; 9 13].
% The first row defines the frequency band of interest, here 10-12 Hz. The
% second and third row define the pass-pand and stop-band for the noise, respectively.
% Here we have a passband of 8-14 Hz and a stop-band of 9-13 Hz in order
% to get the noise activity just below and just above the band of interest.
%
%
%
% References:
%
% Nikulin VV, Nolte G, Curio G. A novel method for reliable and fast extraction
% of neuronal EEG/MEG oscillations on the basis of spatio-spectral decomposition.
% NeuroImage, 2011, 55: 1528-1535.
%
% Haufe, S., Dahne, S., & Nikulin, V. V. Dimensionality reduction for the
% analysis of brain oscillations. NeuroImage, 2014 (accepted for publication)
% DOI: 10.1016/j.neuroimage.2014.06.073

props= {'filterOrder'   3           'INT'
        'epochIndices'  []          'DOUBLE[- -2]'};

if nargin==0,
  dat = props; return
end

dat = misc_history(dat);
misc_checkType(dat, 'STRUCT(x clab fs)');
opt = opt_proplistToStruct(varargin{:});
opt = opt_setDefaults(opt, props);
opt_checkProplist(opt, props);

%% check if data is segmented or continous
is_epoched = ndims(dat.x) == 3;
if is_epoched
    % if the data is segmented (i.e. epoched), then concatenate epochs
    [Te, Nc, Ne] = size(dat.x);
    dat.x = reshape(permute(dat.x, [1,3,2]), [Te*Ne, Nc]);
end

%% compute SSD
[W, A, lambda, ~, X_ssd] = ssd(dat.x, freqs, dat.fs, opt.filterOrder, opt.epochIndices);

%% store the bandpass-filtered data, projected onto the SSD filters

% make sure to put the data in the correct format
if is_epoched
    X_ssd = permute(reshape(X_ssd, [Te, Ne, size(X_ssd,2)]), [1,3,2]);
end
% store the transformed data
dat.x = X_ssd;

%% rename channel labels and save old channel labels
dat.origClab= dat.clab;
dat.clab=cell(1,size(dat.x,2));
for k=1:size(dat.x,2)
    dat.clab{k} = sprintf('ssd %d',k);
end


function gf=comp_filterbankresponse(g,a,L,do_real)

M=numel(g);

if size(a,2)>1
    % G1 is done this way just so that we can determine the data type.
    G1=comp_transferfunction(g{1},L);
    gf=abs(G1).^2*(L/a(1,1)*a(1,2));

    for m=2:M
        gf=gf+abs(comp_transferfunction(g{m},L)).^2*(L/a(m,1)*a(m,2));
    end;

else
    % G1 is done this way just so that we can determine the data type.
    G1=comp_transferfunction(g{1},L);
    gf=abs(G1).^2*(L/a(1));

    for m=2:M
        gf=gf+abs(comp_transferfunction(g{m},L)).^2*(L/a(m));
    end;

end;

if do_real
    gf=gf+involute(gf);
end;

gf=gf/L;


% Multi-Frame Analysis based on Discrete Cepstral Envelope (DCE-MFA)
%
% Input
%  af            : Array of structures with matrices containing sinusoidal
%                  parameters (as the output of sin_analysis.m).
%                  Each matrix is made of:
%                   The 1st line for the frequency of each sinusoid [Hz]
%                   The 2nd line for their amplitude (linear scale)
%                  The DC has to be included (in the first column)
%  fs            : [Hz] Signal's sampling frequency
%  order         : Cepstral order
%  [extrap_dcny] : If true (default), alleviate stability problems of the DCE
%                     by replacing the DCE value and extrapolating sinusoidal
%                     components up to Nyquist.
%                  If false, use the sinusoidal components as they are.
%  [scale]       : empty  : Frequency linear scale (default)
%                 'mel'  : see frq2mel (for MFCC computation)
%                 'bark' : see frq2bark
%                 'erb'  : see frq2erb
%  [Bw]          : [Hz] Standard-deviation of the Gaussian used as weighting
%                       function (for emphasizing the importance of the low
%                       frequencies in the solution).
%                       Bw As to be big enough to have the weights still
%                       significant up to Nyquist.
%  [lr]          : Regularization parameter (as in [2]) (def. 0)
%  [dftlen]      : DFT's length, if the 4th output argument is requested.
%
% Output
%  cc             : Cepstral coefficients
%  Dk             : [log] Log energy corrections
%  af             : As in input, plus the aligned amplitudes values in the
%                   'a' field.
%  E              : The amplitude cepstral envelope
%
% References
%  [1] Y. Shiga and S. King, "Estimation of voice source and vocal tract
%      characteristics based on multi-frame analysis," EUROSPEECH, 2003.
%  [2] M. Campedel-Oudot, O. Cappe and E. Moulines, "Estimation of the Spectral
%      Envelope of Voiced Sounds Using a Penalized Likelihood Approach"
%
% Copyright (c) Yannis Stylianou, 2011, Bilbao
%
% License
%  This file is part of libphoni. libphoni 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. libphoni 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.
%
% This function is part of the COVAREP project: http://covarep.github.io/covarep
%
% Authors
%  Yannis Stylianou <yannis@csd.uoc.gr>
%  Gilles Degottex <degottex@csd.uoc.gr> (regularization term)
%

function [cc Dk af E] = env_dce_mfa(af, fs, order, extrap_dcny, scale, Bw, lr, dftlen)

    debug = 0; % 0:Do nothing; 1:Plot iterations info; 2:Plot results

    % Input parameters
    if nargin<4; extrap_dcny=true; end
    if nargin<5; scale = []; end
    if nargin<6 || isempty(Bw); Bw = 2000*(fs/16000); end% 2kHz with 16kHz[1]
    if nargin<7 || isempty(lr); lr = 0; end
    if nargin<8; dftlen=4096; end

    if ~isempty(scale)
        Bw = 100*fs; % To make it as similar as possible to the DCE-SFA
        lr = 3.5e-2; % To make it as similar as possible to the DCE-SFA [2]
        eval(['fnscale=@frq2' scale ';']);
        for n=1:numel(af)
            af(n).f = 0.5*fs*fnscale(af(n).f)/fnscale(fs/2);
        end
    end

    % If asked, extrapolate components at DC and up to Nyquist
    if extrap_dcny; af = env_extrap_sins_dcny(af, fs); end

    for n=1:numel(af)
        af(n).f = af(n).sins(1,:);
        af(n).a = log(af(n).sins(2,:));
    end

    if debug>1; subplot(211); hold off; end

    M = length(af);

    BWB = 0;  % [1](9)
    erI = 0;  % Error of previous step (initialization error)
    iter = 0; % Iteration number
    cc = zeros(order+1,1);  % initialization for ceps
    rt = 0;

    for k=1:M
        fk = af(k).f;
        ak = af(k).a;
        Nk = length(fk);
        fk = fk(:);
        ak = ak(:);
        Bk = [ones(Nk,1) 2*cos(2*pi*fk/fs*(1:order))];

        wk = exp(-fk.^2 / (2 * Bw * Bw))'; % Bottom-right paragraph p.3
        Wk = diag(wk)/Nk; % (8)

        % keep the main matrices
        BWB = BWB+(Bk'*Wk*Bk); % order by order
        af(k).Bk = Bk;        % keep Bk
        af(k).Wk = Wk;        % keep Wk
        uk = ones(Nk,1);

        dk = uk'*Wk*(ak)/(uk'*Wk*uk); % (10) with c=0
        erI = erI + ((ak-dk*uk)'*Wk*(ak-dk*uk));% (7) with c=0
        rt =  rt + (Bk'*Wk*(ak-dk*uk)); % Right-hand term of (9)
    end

    if debug>0; disp(['iter:' num2str(iter) ' error=' num2str(erI) 'log']); end

    % first estimation of ceps
    if lr==0
        cc = BWB\rt; % Solution of (9)
    else
        cc = (BWB+lr*diag(ones(size(BWB,1),1)))\rt; % Solution of (9) + Regul term
    end
    cc(1) = 0;

    iter = 1;
    while(1)
        er = 0;
        rt = 0; % Right-hand term of (9)
        Dk = zeros(M,1); % log energy corrections

        for k=1:M
            ak = af(k).a;ak= ak(:);
            Bk = af(k).Bk;
            Wk = af(k).Wk;

            Nk = length(ak);
            uk = ones(Nk,1);

            dk = uk'*Wk*(ak-Bk*cc)/(uk'*Wk*uk);% (10)
            h = (ak-dk*uk-Bk*cc);
            er = er + (h'*Wk*h);% (7)
            rt =  rt + (Bk'*Wk*(ak-dk*uk)); % Right-hand term of (9)

            Dk(k) = dk;
        end
        if lr==0
            cc = BWB\rt; % Solution of (9)
        else
            cc = (BWB+lr*diag(ones(size(BWB,1),1)))\rt; % Solution of (9) + Regul term
        end
        cc(1) = 0;

        if debug>0; disp(['iter:' num2str(iter) ' error=' num2str(er) 'log']); end
    %      disp(['reldiff=' num2str(abs((erI-er)/er))]);

        if debug>1
            % plot
            subplot(211);
                plot(iter-1,log(erI), 'o');
                hold on
                plot(iter,log(er), 'x');
                title(num2str(iter));
            subplot(212);
                hold off;
                for k=1:M
                    plot(af(k).f,af(k).a-Dk(k),'+');
                    hold on;
                end
                dftlen = 2048;
                fv = fs*(0:dftlen/2)/dftlen;
                lF = 2*cos(2*pi*fv'/fs*(1:order))*cc(2:order+1);
                plot(fv,lF,'r', 'LineWidth', 2);
            keyboard
        end

        if( abs((erI-er)/er)<0.001 ) % Stop if error doesn't improve more than 0.1%
            break;
        else
            erI = er;
            iter = iter+1;
        end
    end

    % Align the gain corrections with respect to the central frame
    ci = floor((numel(af)-1)/2)+1;
    cc(1) = cc(1)+Dk(ci);
    Dk = Dk - Dk(ci);
    cc(2:end) = 2*cc(2:end);

    % Include the log energy corrections into the output
    for fi=1:numel(af)
        af(fi).a = af(fi).a - Dk(fi);
    end

    % If asked, compute the envelope
    if nargout>2
        if isempty(scale)
            E = exp(fft(cc, dftlen));
            E = E(1:end/2+1);
        else
            if strcmp(scale,'bark')
                E = barkcc2spec(cc, fs, dftlen);
                E = E(1:end/2+1);
            elseif strcmp(scale,'mel')
                E = exp(fft(cc, dftlen));
                E = E(1:dftlen/2+1);
                E = cc2hspec(cc, fs, dftlen);
                E = fwcep2hspec(cc, fs, dftlen);
            end
        end
    end

return


function [d,a] =  training(a,d)

% [results,algorithm] =  training(algorithm,data,loss)

  disp(['normalizing with ' get_name(a) '.... '])

  x=get_x(d); l=get_dim(d);

  if a.scale_type==4
     y=get_y(d);
     corr = zeros(size(x,2),1);
     corr = (mean(x(y==1,:))-mean(x(y==-1,:))).^2;
     st   = std(x(y==1,:)).^2+std(x(y==-1,:)).^2;
     a.corr = corr ./ st;
  end

 if a.scale_type==1 | a.scale_type==3  | a.scale_type==4
  a.mean_vec  = mean(x);
  a.scale_vec = std(x);
  if a.scale_type==3 %% try to do both scalings
    x = x - ones(l,1)*a.mean_vec; x = x * diag(1./a.scale_vec);
  end
 end
 if a.scale_type==2 | a.scale_type==3
   a.mean_vec2  = mean(x')';
   a.scale_vec2 = std(x')';
 end

 d=test(a,d);


% Test file for ADCHEBFUN norm related functions

function pass = test_norm

% List of trigonometric functions to test.
normFun1 = @(u) norm(u, 2);
normFun2 = @(u) norm(u, 2).^2;
normFun3 = @(u) 1./norm(u, 2);
normFun4 = @(u) 1./norm(u, 2).^2;
normFun5 = @(u) norm(u, 2) + norm(diff(u));
normFun5 = @(u) norm(u, 2).^2 + norm(diff(u)).^3;

funcList = {normFun1, normFun2, normFun3, normFun4, normFun5};

% Call the ADCHEBFUN testUnary() method to do the tests.
pass = adchebfun.testUnary(funcList);

end


% Test file for chebtech/alias.m

function pass = test_alias(pref)

if ( nargin < 1 )
    pref = chebtech.techPref();
end

for n = 1:2
    if ( n == 1 )
        testclass = chebtech1();
    else
        testclass = chebtech2();
    end

    F = @sin;
    f = testclass.make(@(x) F(x), [], pref);

    k = 11;
    g = f;
    g.coeffs = testclass.alias(f.coeffs, k);
    x = testclass.chebpts(k);
    values = testclass.coeffs2vals(g.coeffs);
    pass(n, 1) = norm(values - F(x), inf) < 10*vscale(g)*eps;

    g.coeffs = testclass.alias(f.coeffs, 2);
    exact_values = sin(testclass.chebpts(2));
    values = testclass.coeffs2vals(g.coeffs);
    pass(n, 2) = size(g,1) == 2 && norm(values - exact_values, inf) < ...
        1e1*vscale(g)*eps;

    F = @sin;
    f = testclass.make(@(x) [F(x), -F(x)], [], pref);
    k = 11;
    g = f;
    g.coeffs = testclass.alias(f.coeffs, k);
    x = testclass.chebpts(k);
    values = testclass.coeffs2vals(g.coeffs);
    pass(n, 3) = norm(values - [F(x), -F(x)], inf) < 10*max(vscale(g)*eps);

    g = f;
    g.coeffs = testclass.alias(f.coeffs, 2);
    y = testclass.chebpts(2);
    exact_values = [sin(y) -sin(y)];
    values = testclass.coeffs2vals(g.coeffs);
    pass(n, 4) = size(g,1) == 2 && ...
        norm(values - exact_values, inf) < 10*max(vscale(g)*eps);

    F = @(x) sin(1000*x);
    f = testclass.make(@(x) [F(x), -F(x)], [], pref);
    k = 32;
    g = f;
    g.coeffs = testclass.alias(f.coeffs, k);
    x = testclass.chebpts(k);
    values = testclass.coeffs2vals(g.coeffs);
    pass(n, 5) = norm(values - [F(x), -F(x)], inf) < 1e3*max(vscale(g)*eps);

    k = 100;
    g = f;
    g.coeffs = testclass.alias(f.coeffs, k);
    x = testclass.chebpts(k);
    values = testclass.coeffs2vals(g.coeffs);
    pass(n, 6) = norm(values - [F(x), -F(x)], inf) < 1e4*max(vscale(g)*eps);

    g = f;
    g.coeffs = testclass.alias(f.coeffs, 2);
    y = testclass.chebpts(2);
    exact_values = [sin(1000*y) -sin(1000*y)];
    values = testclass.coeffs2vals(g.coeffs);
    pass(n, 7) = size(g, 1) == 2 && ...
        norm(values - exact_values, inf) < 1e3*eps;

    F = @(x) cos(1000*x);
    f = testclass.make(@(x) [F(x), -F(x)], [], pref);

    g = f;
    g.coeffs = testclass.alias(f.coeffs, 1);
    values = testclass.coeffs2vals(g.coeffs);
    pass(n, 8) = size(g, 1) == 1 && norm(values - [1, -1], inf) < ...
        1e2*max(vscale(g)*eps);

    g = f;
    g.coeffs = testclass.alias(f.coeffs, 2);
    y = testclass.chebpts(2);
    exact_values = [cos(1000*y) -cos(1000*y)];
    values = testclass.coeffs2vals(g.coeffs);
    pass(n, 9) = length(g) == 2 && ...
        norm(values - exact_values, inf) < 1e3*max(vscale(g)*eps);

end

end


function N = find_steps_number(T,dt)
in = 10:16;
Ni = 2.^in;
[~,idx_N] = min(abs(bsxfun(@minus,Ni,round(T/dt))));
N = 2^in(idx_N);
end


%% Blob Detection
% This program demonstrates how to use BLOB to detect and filter region.
%
% Sources:
%
% * <https://github.com/opencv/opencv/blob/3.1.0/samples/cpp/detect_blob.cpp>
%

%% Image
img = cv.imread(fullfile(mexopencv.root(),'test','detect_blob.png'), 'Color',true);
img = rot90(img);

%% Detector Parameters
% this is default parameters for |cv.SimpleBlobDetector|
params = struct();
params.ThresholdStep = 10;
params.MinThreshold = 10;
params.MaxThreshold = 220;
params.MinRepeatability = 2;
params.MinDistBetweenBlobs = 10;
params.FilterByColor = false;
params.BlobColor = 0;
params.FilterByArea = false;
params.MinArea = 25;
params.MaxArea = 5000;
params.FilterByCircularity = false;
params.MinCircularity = 0.9;
params.MaxCircularity = 1e37;
params.FilterByInertia = false;
params.MinInertiaRatio = 0.1;
params.MaxInertiaRatio = 1e37;
params.FilterByConvexity = false;
params.MinConvexity = 0.95;
params.MaxConvexity = 1e37;

%%
% we are going to detect blobs with 6 different param configurations
p = repmat(params, 6, 1);

%%
% 1st: we want all
p(1).FilterByArea = true;
p(1).MinArea = 1;
p(1).MaxArea = size(img,1) * size(img,2);

%%
% 2nd: we want area between 500 and 2900 pixels
p(2).FilterByArea = true;
p(2).MinArea = 500;
p(2).MaxArea = 2900;

%%
% 3rd: we want only circular object
p(3).FilterByCircularity = true;

%%
% 4th: we want ratio inertia
p(4).FilterByInertia = true;
p(4).MinInertiaRatio = 0;
p(4).MaxInertiaRatio = 0.2;

%%
% 5th: we want convexity
p(5).FilterByConvexity = true;
p(5).MinConvexity = 0;
p(5).MaxConvexity = 0.9;

%%
% 6th: we want blob with gravity center color equal to 0 (dark blobs)
p(6).FilterByColor = true;
p(6).BlobColor = 0;

%%
% helper function to convert params struct to pairs of name/value options
getopts = @(s) reshape([fieldnames(s), struct2cell(s)]', 1, []);

%% Detect
% blob detectors loop
for i=1:numel(p)
    % create detector using specified options
    opts = getopts(p(i));
    sbd = cv.SimpleBlobDetector(opts{:});

    % detect keypoint
    kpts = sbd.detect(img);

    % draw results
    out = cv.drawKeypoints(img, kpts);
    for k=1:numel(kpts)
        out = cv.circle(out, kpts(k).pt, round(kpts(k).size), ...
            'Color',randi([0 255],[1 3]));
    end

    % show output
    figure('Name',sprintf('BLOB%d',i))
    imshow(out)

    % create a title to describe current parameters
    str = {};
    if p(i).FilterByArea
        str{end+1} = sprintf('Area range [%g to %g]', ...
            p(i).MinArea, p(i).MaxArea);
    end
    if p(i).FilterByCircularity
        str{end+1} = sprintf('Circularity range [%g to %g]', ...
            p(i).MinCircularity, p(i).MaxCircularity);
    end
    if p(i).FilterByColor
        str{end+1} = sprintf('Blob color %g', p(i).BlobColor);
    end
    if p(i).FilterByConvexity
        str{end+1} = sprintf('Convexity range [%g to %g]', ...
            p(i).MinConvexity, p(i).MaxConvexity);
    end
    if p(i).FilterByInertia
        str{end+1} = sprintf('Inertia ratio range [%g to %g]', ...
            p(i).MinInertiaRatio, p(i).MaxInertiaRatio);
    end
    title(str)
end


function plotClass(X, label)
% Plot 2d/3d samples of different classes with different colors.
% Written by Mo Chen (sth4nth@gmail.com).
[d,n] = size(X);
if nargin == 1
    label = ones(n,1);
end
assert(n == length(label));

color = 'brgmcyk';
m = length(color);
c = max(label);

figure(gcf);
clf;
hold on;
switch d
    case 2
        view(2);
        for i = 1:c
            idc = label==i;
%             plot(X(1,label==i),X(2,label==i),['.' color(i)],'MarkerSize',15);
            scatter(X(1,idc),X(2,idc),36,color(mod(i-1,m)+1));
        end
    case 3
        view(3);
        for i = 1:c
            idc = label==i;
%             plot3(X(1,idc),X(2,idci),X(3,idc),['.' idc],'MarkerSize',15);
            scatter3(X(1,idc),X(2,idc),X(3,idc),36,color(mod(i-1,m)+1));
        end
    otherwise
        error('ERROR: only support data of 2D or 3D.');
end
axis equal
grid on
hold off


function desc = calcLabHist(rgb_im, seg, numRegion)
    if ~isa(rgb_im,'uint8'),
        rgb_im = im2uint8(rgb_im);
    end

    cform = makecform('srgb2lab');
    im = applycform(rgb_im,cform);

    binNum = 50;
    binVal = 0:256/(binNum):256;
    desc = zeros([numRegion binNum*3]);

    cnt = 0;
    ind={};
    for iReg=1:numRegion
        ind{iReg} = seg(:)==iReg;
    end

    for ch=1:3
        for bin=1:binNum
            cnt = cnt + 1;
            I = im(:,:,ch);
            I = ( (I>=binVal(bin)) & (I<binVal(bin+1)) );
            for iReg=1:numRegion
                desc(iReg, cnt) = sum(I(ind{iReg}));
            end
        end
    end

    tmp = sum(desc, 2);
    desc = (desc ./ repmat(tmp(:), [1 size(desc,2)]))*3;
end


RGB = imread('saturn.png');
I = rgb2gray(RGB);
I2G = imnoise(I,'gaussian', 0.02);
I2 = imnoise(I,'salt & pepper', 0.02);
I20 = imnoise(I,'salt & pepper', 0.2);
figure, imshow(RGB);
figure, imshow(I);
figure, imshow(I2G);
figure, imshow(I2);
figure, imshow(I20);


function [success path] = traverse_world(start,pot)
%
% traverse world
%
res(size(pot,1),size(pot,2))=0;
t = 1;
nr = start.r;
nc = start.c;
res(nr,nc,t)=1;
while((t<size(pot,3))&&(pot(nr,nc,t)~=0)&&(pot(nr,nc,t)~=1))
    if(nr ~= 1)
        n = pot(nr-1,nc,t+1);
    else
        n = Inf;
    end
    if(nc ~= size(pot,2))
        e = pot(nr,nc+1,t+1);
    else
        e = Inf;
    end
    if(nr ~= size(pot,1))
        s = pot(nr+1,nc,t+1);
    else
        s = Inf;
    end
    if(nc ~= 1)
        w = pot(nr,nc-1,t+1);
    else
        w = Inf;
    end
    st = pot(nr,nc,t+1);
    minv = min([n,e,s,w,st]);
    if (minv == st)
        %do nothing
    elseif((minv == n)&&(nr ~= 1))
        nr = nr - 1;
    elseif((minv == e)&&(nc ~= 10))
        nc = nc + 1;
    elseif((minv == s)&&(nr ~= 10))
        nr = nr + 1;
    elseif((minv == w)&&(nc ~= 1))
        nc = nc - 1;
    end
    t = t + 1;
    res(nr,nc,t)=1;
end
if(pot(nr,nc,t)==0)
    success = 1; %if goal reached
else
    success = 0; %if goal no longer reachable
end
path = res;
end


function [data, XYZvoxSphere, XYZmmSphere] = iimg_sphere_timeseries(images, XYZmmCenter, radius)
% :Usage:
% ::
%
%     function [data, XYZvoxSphere, XYZmmSphere] = iimg_sphere_timeseries(images, XYZmm, radius)
%
% :Inputs:
%
%   **images:**
%        list of image files
%
%   **XYZmm:**
%        [3 x n] array of mm coords
%
%   **radiu:**
%        radius in mm of sphere to generate
%
% :Outputs:
%
%   **data:**
%        voxel data
%
%   **XYZvoxSphere:**
%        voxel

    Vimages = spm_vol(images);
    [XYZvox(1,:) XYZvox(2,:) XYZvox(3,:)] = ind2sub(Vimages(1).dim(1:3), 1:prod(Vimages(1).dim(1:3)));
    XYZmm = Vimages(1).mat(1:3, :)*[XYZvox; ones(1, size(XYZvox, 2))];

    dist = [XYZmm(1,:) - XYZmmCenter(1); XYZmm(2,:) - XYZmmCenter(2); XYZmm(3,:) - XYZmmCenter(3)];
    whVoxelsInSphere = find(sum(dist.^2) <= radius^2);

    XYZmmSphere = unique(XYZmm(:,whVoxelsInSphere)', 'rows')';
    XYZvoxSphere = unique(XYZvox(:,whVoxelsInSphere)', 'rows')';

    data = spm_get_data(Vimages, XYZvoxSphere);
end


% WAVELET_3D_PYRAMID Compute the roto-translation wavelet transfrom
%
% Usage
%   [y_Phi, y_Psi, meta_Phi, meta_Psi] = wavelet_3d_pyramid(y, filters, filters_rot, options)
%
% Input
%   y (numeric): a 3d matrix whose first two dimension corresponds to spatial
%       postion and third dimension corresponds to orientation.
%   filters (struct): a 2d pyramid filter bank (applied along spatial variable)
%   filters_rot (struct): a 1d filter bank (applied along orientation)
%   options (struct): containing the following optional fields
%       x_resolution (int): the log of spatial resolution
%       psi_mask (bool array): a mask for determining which filter to apply
%       oversampling (int): the log of spatial oversampling
%       oversampling_rot (int): the log of orientation oversampling
%
% Output
%   y_Phi (numeric): the roto-translation convolution y * Phi
%   y_Psi (cell): containing all the roto-translation convolution y * Psi
%   meta_phi (struct): meta associated to y_Phi
%   meta_psi (struct): meta associated to y_Psi
%
% Description
%   This is a pyramid implementation of the roto-translation wavelet
%   transform. Another (slower, FFT-based) implementation is available as
%   WAVELET_3D.
%	This function computes the roto-translation convolution of a three dimensional
%	signal y, with roto-translation wavelets defined as the separable product
%	low pass :
%		PHI(U,V) * PHI(THETA)
%	high pass :
%		PHI(U,V) * PHI(THETA)
%		PSI(U,V) * PHI(THETA)
%		PSI(U,V) * PSI(THETA)
%
% Reference
%	Rotation, Scaling and Deformation Invariant Scattering for Texture
%	Discrimination, Laurent Sifre, Stephane Mallat
%	Proc of CVPR 2013
%	http://www.cmapx.polytechnique.fr/~sifre/research/cvpr_13_sifre_mallat_final.pdf
%
% See also
%   WAVELET_LAYER_3D, WAVELET_FACTORY_3D

function [y_Phi, y_Psi, meta_Phi, meta_Psi] = wavelet_3d_pyramid(y,...
        filters, filters_rot, options)

    % retrieve info on input
    Q = filters.meta.Q;
    L = filters_rot.meta.size_filter / 2;
    % do not compute any convolution with high pass if y_Psi is not
    % outputed
    calculate_psi = (nargout>=2);
    [N, M, T] = size(y);

    % retrieve options
    white_list = {'J', 'angular_range', 'oversampling_rot', 'j_min', 'q_mask'};
    check_options_white_list(options, white_list);
    options = fill_struct(options, 'J', 4);
    options = fill_struct(options, 'angular_range', 'non_specified');
    options = fill_struct(options, 'oversampling_rot', -1);
    options = fill_struct(options, 'j_min', 0);
    options = fill_struct(options, 'q_mask', ones(1, Q));

    % angular resolution
    switch (options.angular_range)
        case 'zero_pi'
            angular_res = floor(log2(2*L/(2*T)));
        case 'zero_2pi'
            angular_res = floor(log2(2*L/T));
        otherwise
            error('unspecified angular range');
    end

    if (isa(filters.h.filter.coefft, 'single'))
        cast = @single;
    else
        cast = @double;
    end

    %%%%%%%%%%%%%%%%%%
    %%% low passes %%%
    %%%%%%%%%%%%%%%%%%

    %%%%%%%%%%%%%%%%%%
    %%% phi - phi %%%%
    %%%%%%%%%%%%%%%%%%

    %% low pass filter spatial : cascade with h for every slice
    % initialize structure
    hy.signal{1} = y;
    hy.meta.j(1) = 0;

    % low pass spatial using a pyramid
    h = filters.h.filter;
    for j = 1:options.J
        for theta = 1:T % filter each slice
            if (theta == 1) % allocate when size is known
                tmp_slice = pad_conv_sub_unpad(hy.signal{j}(:,:,theta), h);
                tmp = cast(zeros([size(tmp_slice), T]));
                tmp(:,:,theta) = tmp_slice;
            else
                clear tmp_slice;
                tmp(:,:,theta) = ...
                    pad_conv_sub_unpad(hy.signal{j}(:,:,theta), h);
            end
        end
        hy.signal{j+1} = tmp;
        hy.meta.j(j+1) = j;
    end
    y_phi.signal{1} = hy.signal{options.J+1};
    y_phi.meta.j(1) = hy.meta.j(options.J+1);

    %% low pass filter anguler : fft along anguler
    % initialize structure (recopy if range is zero_pi)
    ds = max(filters_rot.meta.J/filters_rot.meta.Q - options.oversampling_rot, 0);
    if (2^ds == 2*L)
        % in this case it is faster to compute the sum along the angle
        y_Phi = sum(y_phi.signal{1},3) / 2^(ds/2);
    else
        if (strcmp(options.angular_range, 'zero_pi'))
            % divide by sqrt(2) for energy preservation
            y_phi.signal{1} = repmat(y_phi.signal{1}, [1 1 2]) / sqrt(2);
        end
        y_phi_f = fft(y_phi.signal{1}, [], 3);
        phi_angle = filters_rot.phi.filter;
        y_Phi = real(...
            sub_conv_1d_along_third_dim_simple(y_phi_f, phi_angle, ds));
    end
    meta_Phi.j2 = options.J;
    meta_Phi.k2 = filters_rot.meta.J;

    %%

    %%%%%%%%%%%%%%%%%%%
    %%% high passes %%%
    %%%%%%%%%%%%%%%%%%%

    if (calculate_psi)
        p = 1;
        %%%%%%%%%%%%%%%%%%
        %%% phi - psi %%%%
        %%%%%%%%%%%%%%%%%%

        %% low pass spatial - already computed
        %% high pass angular
        % NOTE : y_phi_f
        % (the (angular) fourier transform of y * (spatial) phi)
        % might have already been computed
        if ~exist('y_phi_f', 'var')
            % fourier angle
            if (strcmp(options.angular_range, 'zero_pi'))
                % divide by sqrt(2) for energy preservation
                y_phi.signal{1} = repmat(y_phi.signal{1}, [1 1 2]) / sqrt(2);
            end
            y_phi_f = fft(y_phi.signal{1}, [], 3);
        end
        for k2 = 0:numel(filters_rot.psi.filter)-1
            psi_angle = filters_rot.psi.filter{k2+1};
            ds = max(k2/filters_rot.meta.Q - options.oversampling_rot, 0);
            y_Psi{p} = ...
                sub_conv_1d_along_third_dim_simple(y_phi_f, psi_angle, ds);
            meta_Psi.j2(p) = options.J;
            meta_Psi.q2(p) = 0;
            meta_Psi.theta2(p) = 0;
            meta_Psi.k2(p) = k2;
            p = p + 1;
        end

        %%%%%%%%%%%%%%%%%%
        %%% psi - phi %%%%
        %%%%%%%%%%%%%%%%%%
        %      AND       %
        %%%%%%%%%%%%%%%%%%
        %%% psi - phi %%%%
        %%%%%%%%%%%%%%%%%%

        %% high pass spatial - with pyramid
        if (angular_res == 0)
            g = filters.g.filter;

            for j2 = options.j_min:options.J-1
                for q = find(options.q_mask==1)-1
                    for theta2 = 1:L
                        if (strcmp(options.angular_range, 'zero_pi'))
                            for theta = 1:L
                                % convolution with psi_{j1, theta + theta2}
                                theta_sum_mod2L =  1 + mod(theta + theta2 - 2, 2*L);
                                theta_sum_modL =  1 + mod(theta + theta2 - 2, L);
                                tmp_slice = pad_conv_unpad(hy.signal{j2+1}(:,:,theta), g{theta_sum_modL + L*q});
                                if (theta == 1) % allocate
                                    tmp = cast(zeros([size(tmp_slice), 2*L]));
                                end
                                if (theta_sum_mod2L <= L)
                                    tmp(:,:,theta) = tmp_slice;
                                    tmp(:,:,theta+L) = conj(tmp_slice);
                                else
                                    tmp(:,:,theta) = conj(tmp_slice);
                                    tmp(:,:,theta+L) = tmp_slice;
                                end
                            end
                        else % options.angular_range is 'zero_2pi'
                            for theta = 1:2*L
                                % convolution with psi_{j1, theta + theta2}
                                theta_sum_mod2L =  1 + mod(theta + theta2 - 2, 2*L);
                                theta_sum_modL =  1 + mod(theta + theta2 - 2, L);
                                if (theta_sum_mod2L <= L)
                                    curr_g =  g{theta_sum_modL + L*q};
                                else
                                    curr_g =  conjugate_filter(g{theta_sum_modL + L*q});
                                end
                                tmp_slice = pad_conv_unpad(hy.signal{j2+1}(:,:,theta), curr_g);
                                if (theta == 1) % allocate
                                    tmp = cast(zeros([size(tmp_slice), 2*L]));
                                end
                                tmp(:,:,theta) = tmp_slice;

                            end
                        end

                        % tmp can now be filtered along the orientation
                        tmp_f = fft(tmp, [], 3);
                        %% low pass angle
                        ds = min(2*L, max(filters_rot.meta.J/filters_rot.meta.Q - options.oversampling_rot, 0));
                        if (2^ds == 2*L)
                            % faster to compute the sum along the angle
                            y_Psi{p} = sum(tmp, 3) / 2^(ds/2);
                        else
                            y_Psi{p} = ...
                                sub_conv_1d_along_third_dim_simple(tmp_f, phi_angle, ds);
                        end
                        meta_Psi.j2(p) = j2;
                        meta_Psi.theta2(p) = theta2;
                        meta_Psi.k2(p) = filters_rot.meta.J;
                        meta_Psi.q2(p) = q;
                        p = p + 1;

                        %% high pass angle
                        for k2 = 0:numel(filters_rot.psi.filter)-1
                            psi_angle = filters_rot.psi.filter{k2+1};
                            ds = max(k2/filters_rot.meta.Q - options.oversampling_rot, 0);
                            y_Psi{p} = ...
                                sub_conv_1d_along_third_dim_simple(tmp_f, psi_angle, ds);
                            meta_Psi.j2(p) = j2;
                            meta_Psi.theta2(p) = theta2;
                            meta_Psi.k2(p) = k2;
                            meta_Psi.q2(p) = q;
                            p = p + 1;
                        end

                    end
                end
            end
        else
            error('not yet supported');
        end

    end

    function out = pad_conv_sub_unpad(in, filter)
        Npad = size(in) + filters.meta.size_filter - 1;
        out = pad_signal(in, Npad, 'symm', 1);
        out = conv_sub_2d(out, filter, 1);
        out = unpad_signal(out, 1, size(in), filters.meta.offset);
    end

    function out = pad_conv_unpad(in, filter)
        Npad = size(in) + filters.meta.size_filter - 1;
        out = pad_signal(in, Npad, 'symm', 1);
        out = conv_sub_2d(out, filter, 0);
        out = unpad_signal(out, 0, size(in), filters.meta.offset);
    end

    function conj_filter = conjugate_filter(filter)
        conj_filter = filter;
        conj_filter.coefft = conj(filter.coefft);
    end
end


function [sbatch2 sbatch3] = select_neighbors(sbatch1, data)

l = double(data.Ltraining(sbatch1)) + 1;
nnn1 = size(data.indnlabels,1);
sbatch2 = double(data.indnlabels(ceil(rand(numel(sbatch1),1).*(data.nnlabels(l))) + (l-1)*nnn1));

nnn2 = size(data.nnTraining,1);
sbatch3 = double(data.nnTraining(ceil(rand(numel(sbatch1),1).*(data.nns(sbatch1))) + (sbatch1-1)*nnn2));


function [w, infos] = subsamp_tr(problem, in_options)

% Trust Region Method
% Authors: Jonas Kohler and Aurelien Lucchi, 2017

% Minimize a continous, unconstrained function using the Trust Region method.
%
% References
% ----------
% Conn, A. R., Gould, N. I., & Toint, P. L. (2000). Trust region methods. Society for Industrial and Applied Mathematics.
%
%
% Original Python code was created by J. M. Kohler and A. Lucchi (https://github.com/dalab/subsampled_cubic_regularization)
%
%
% This file is part of SGDLibrary.
%
% Ported to MATLAB code by K.Yoshikawa and H.Kasai on March, 2018.
% Modified by H.Kasai on Apr. 17, 2018

    % set dimensions and samples
    d = problem.dim();
    n = problem.samples();

    %% set local options
    local_options.sampling_scheme = 'exponential'; % 'linear', 'exponential'
    local_options.penalty_increase_multiplier = 2;  % multiply by..
    local_options.penalty_derease_multiplier = 2;  % divide by..
    local_options.initial_tr_radius = 1;
    local_options.successful_treshold = 0.1;
    local_options.very_successful_treshold = 0.9;
    local_options.grad_tol = 1e-9;
    local_options.max_trust_radius = 1e4;

    % sampling
    local_options.Hessian_sampling = 1;
    local_options.gradient_sampling = 0;
    local_options.initial_sample_size_Hessian = 0.025;
    local_options.initial_sample_size_gradient = 0.25;

    % subproblem
    local_options.subproblem_solver = 'GLTR';

    local_options.krylov_tol = 1e-1;
    local_options.exact_tol = 1e-2;

    % merge options
    options = mergeOptions(get_default_options(d), local_options);
    options = mergeOptions(options, in_options);

    if options.verbose > 1
        fprintf('- Subproblem_solver:%s\n', options.subproblem_solver)
        fprintf('- Hessian_sampling:%d\n', options.Hessian_sampling)
        fprintf('- Gradient_sampling:%d\n', options.gradient_sampling)
        fprintf('- Sampling_scheme:%s\n\n', options.sampling_scheme)
    end

    % decide mode
    if options.gradient_sampling == 0 && options.Hessian_sampling == 0
        mode = 'TR';
    else
        mode = 'Subsamp TR';
    end

    % initialize
    iter = 0;
    grad_calc_count = 0;
    w = options.w_init;
    lambda_k = 0;
    successful_flag = false;
    tr_radius = options.initial_tr_radius;  % intial tr radius

    grad = problem.full_grad(w);

    % compute exponential growth constant such that full sample size is reached in n_iterations
    if strcmp(options.sampling_scheme, 'exponential')
        exp_growth_constant = ((1-options.initial_sample_size_Hessian)*n)^(1/options.max_iter);
    end

    % store first infos
    clear infos;
    [infos, f_val, optgap] = store_infos(problem, w, options, [], iter, grad_calc_count, 0);

    % display infos
    if options.verbose > 0
        fprintf('%s:        : Iter = %03d, cost = %.16e, optgap = %.4e\n', mode, iter, f_val, optgap);
    end

    % set start time
    start_time = tic();

    for i = 0 : options.max_iter-1

        %% I: Subsampling
        % a) determine batchsize
        if strcmp(options.sampling_scheme, 'exponential')

            sample_size_Hessian = options.Hessian_sampling*(fix(min([n, n*options.initial_sample_size_Hessian + exp_growth_constant^(i+1)]))+1) + (1-options.Hessian_sampling)*n;
            sample_size_gradient = options.gradient_sampling*(fix(min([n, n*options.initial_sample_size_gradient + exp_growth_constant^(i+1)]))+1) + (1-options.gradient_sampling)*n;

        elseif strcmp(options.sampling_scheme, 'linear')

            sample_size_Hessian = options.Hessian_sampling*fix(min([n, max([n*options.initial_sample_size_Hessian, n/options.max_iter*(i+1)])]))+(1-options.Hessian_sampling)*n;
            sample_size_gradient = options.gradient_sampling*fix(min([n, max([n*options.initial_sample_size_gradient, n/options.max_iter*(i+1)])]))+(1-options.gradient_sampling)*n;

        elseif strcmp(options.sampling_scheme, 'fix') % Added by HK

            sample_size_Hessian = options.Hessian_sampling*fix(min(n, n*options.initial_sample_size_Hessian))+(1-options.Hessian_sampling)*n;
            sample_size_gradient = options.gradient_sampling*fix(min(n, n*options.initial_sample_size_gradient))+(1-options.gradient_sampling)*n;

        else

            sample_size_Hessian = n;
            sample_size_gradient = n;

        end

        % b) draw batches
        if sample_size_Hessian < n
            int_idx_Hessian = randi([1, n], sample_size_Hessian,1); % KY
            bool_idx_Hessian = false(n,1);
            bool_idx_Hessian(int_idx_Hessian) = true;
            sub_hess_indices = find(bool_idx_Hessian);
        else
            sub_hess_indices = 1:n;
        end

        if sample_size_gradient < n
            int_idx_gradient = randi([1, n], sample_size_gradient,1);
            bool_idx_gradient = false(n,1);
            bool_idx_gradient(int_idx_gradient) = true;
            sub_grad_indices = find(bool_idx_gradient);
        else
            sub_grad_indices = 1:n;
        end

        n_samples_per_step = sample_size_Hessian+sample_size_gradient;

        % recompute gradient either because of accepted step or because of re-sampling
        if options.gradient_sampling == 1 || successful_flag == 1
            %grad = gradient_f(w, new_X2, new_Y2, alpha);
            grad = problem.grad(w, sub_grad_indices');
            grad_norm = norm(grad);
            if grad_norm < options.grad_tol
                fprintf('Norm of gradient (%e) reached: grad_tol = %g\n', grad_norm, options.grad_tol);
                break;
            end
        end

        %% II: Step computation
        % b) call subproblem solver
        [s, lambda_k] = tr_subsolver(problem, w, grad, tr_radius, sub_hess_indices, successful_flag, lambda_k, options.subproblem_solver,...
                                           options.exact_tol, options.krylov_tol);

        %sn = norm(s);

        %% III: Regularization Update
        f_prev = problem.cost(w);
        f_curr = problem.cost(w+s);
        function_decrease = f_prev - f_curr; % f(w) - f(w+w)

        %Hs = Hv_f(w, new_X, new_Y, s, alpha);
        Hs = problem.hess_vec(w, s, sub_hess_indices);

        model_decrease = -((grad'*s) + 0.5 * (s'*Hs));

        rho = function_decrease / model_decrease;

        if model_decrease >=0
            if options.verbose > 2
                fprintf('\tNegative model decrease (%e). This should not have happened\n', model_decrease);
            end
        end

        % update w if step s is successful
        if rho >= options.successful_treshold
            w = w + s;
            loss = f_curr;
            successful_flag = true;
            accstr = 'ACC';
        else
            loss = f_prev;
            accstr = 'REJ';
        end

        % Update trust region radius
        tr_radius_ = tr_radius;
        if rho < options.successful_treshold
            tr_radius = tr_radius * (1/options.penalty_increase_multiplier);
            %fprintf('unscuccesful iteration\n');
            successful_flag = false;
            trstr = 'TR-';
        elseif rho > options.very_successful_treshold && ((norm(s) - tr_radius) < 1e-10)
            tr_radius = min([options.penalty_derease_multiplier * tr_radius, options.max_trust_radius]);
            trstr = 'TR+';
        else
            trstr = '   ';
        end

%         % recompute gradient either because of accepted step or because of re-sampling
%         if options.gradient_sampling == 1 || successful_flag == 1
%             %grad = gradient_f(w, new_X2, new_Y2, alpha);
%             grad = problem.grad(w, sub_grad_indices');
%             grad_norm = norm(grad);
%             if grad_norm < options.grad_tol
%                 break;
%             end
%         end

        % measure elapsed time
        elapsed_time = toc(start_time);

        % count gradient evaluations
        grad_calc_count = grad_calc_count + n_samples_per_step;
        iter = iter + 1;

        % store infos
        [infos, f_val, optgap] = store_infos(problem, w, options, infos, iter, grad_calc_count, elapsed_time);

        % display infos
        if options.verbose > 0
            fprintf('%s: %s %s: Iter = %03d, cost = %.16e, optgap = %.4e', mode, accstr, trstr, iter, f_val, optgap);
            if options.verbose > 1
                fprintf(', sample (H,G)= (%d, %d)\n', sample_size_Hessian, sample_size_gradient)
            else
                fprintf('\n');
            end
        end

        if optgap < options.tol_optgap
            fprintf('Optimality gap tolerance reached: tol_optgap = %g\n', options.tol_optgap);
            break;
        end
    end

    if iter == options.max_iter
        fprintf('Max epoch reached: max_iter = %g\n', options.max_iter);
    end

end


function gram_vector = find_gram_vector(samplesf, new_sample, num_training_samples, params)
% Find the inner product of the new sample with the existing samples. TO be
% used for distance calculation

% Note: Since getting the 'exact' distance between the samples is not important,
% the inner product computation is done by using only the half spectrum for
% efficiency. In practice the error incurred by this is negligible. Also
% since we wannt to merge samples that are similar, and finding the best
% match is not important, small error in the distance computation doesn't
% matter

gram_vector = inf(params.nSamples,1,'like', params.data_type);

num_feature_blocks = numel(new_sample);

if num_training_samples == params.nSamples
    % This if statement is only for speed
    ip = zeros(1,'like', params.data_type);
    for k = 1:num_feature_blocks
        ip_block = 2*reshape(samplesf{k}, num_training_samples, []) * conj(new_sample{k}(:));
        ip = ip + real(ip_block);
    end

    gram_vector = ip;
elseif num_training_samples > 0
    ip = zeros(1,'like', params.data_type);
    for k = 1:num_feature_blocks
        ip_block = 2*reshape(samplesf{k}(1:num_training_samples,:,:,:),num_training_samples, []) * conj(new_sample{k}(:));
        ip = ip + real(ip_block);
    end

    gram_vector(1:num_training_samples) = ip;
end
end


  function ob = Fatrix(dim, arg, varargin)
%|function ob = Fatrix(dim, arg, handles, options)
%|
%| WARNING: any new objects should use fatrix2 instead of this!
%|
%| Construct Fatrix object, which is a 'fake matrix' or 'function-based matrix'
%| object, designed to generalize matrices by representing any linear operator.
%| The caller can provide a variety of (overloaded) "methods" for this object,
%| particularly multiplication and transposed multiplication.
%| Using this "meta object" allows the object designer to focus on the key
%| methods, rather than reinventing matrix methods for each new object.
%| Basic methods include things like "size" and "disp" etc., whereas more
%| advanced methods included ob(:,1) or [ob1; ob2] among many others.
%| See Gblur.m for examples.
%|
%|	ob * x		multiplication
%|	ob' * x		transposed multiplication
%|
%| It is up to the caller to provide function handles for both!
%|
%| in
%|	dim [2]		Fatrix "dimensions"
%|	arg		arguments passed to handle functions
%|				(usually a cell or struct)
%|
%| handles (all optional): 'name1', handle1, 'name2', handle2, ...
%|	'forw'		forw(arg, x)	ob * x
%|	'back'		back(arg, x)	ob' * x
%|	'gram'		build_gram(ob, W, reuse), build G' * W * G
%|	'free'		free(arg)
%|	'abs'		ob = abs(ob): absolute value operation
%|	'ufun'		out = ufun(ob, varargin) : user-defined function
%|	'block_setup'	ob = block_setup(ob, varargin)
%|	'blockify_data'	cell_data = blockify_data(ob, array_data, varargin)
%|	'mtimes_block'	mtimes_block(arg, is_transpose, x, iblock, nblock)
%|	'power'		ob = power(ob, sup)	ob.^sup
%|
%| options
%|	'caller', string	name of calling routine ("meta class")
%|				default: name determined automatically.
%|	'cascade_after', thing		ob * x -> thing * forw(arg, x)
%|	'cascade_before', thing		ob * x -> forw(arg, thing * x)
%|		these "things" can also be function handles (see mtimes_block.m)
%|
%| out
%|	ob		Fatrix object
%|
%| Copyright 2004-6-29, Jeff Fessler, University of Michigan

% create default object, as required by Mathworks
ob.caller = '';
ob.arg = {};
ob.dim = [];
ob.is_transpose = false;
ob.is_subref = false;
ob.nblock = [];
ob.iblock = [];

% trick: default to some simple anonymous functions that will work if
% "arg" is anything that knows how to multiply, e.g., a matrix.
ob.handle_back = @(M,y) M' * y;
ob.handle_forw = @(M,x) M * x;
ob.handle_power = @(M,p) M .^ p;

ob.handle_ufun = [];
ob.handle_abs = [];
ob.handle_free = [];
ob.handle_gram = [];
ob.handle_mtimes_block = [];
ob.handle_block_setup = [];
ob.handle_blockify_data = [];
ob.cascade_after = [];
ob.cascade_before = [];

if nargin == 0 % required by Mathworks
	if nargout == 0, help(mfilename), end
	ob = class(ob, 'Fatrix');
return
end

if nargin < 2
	ir_usage
end

ob.arg = arg;
ob.dim = dim;

ob = vararg_pair(ob, varargin, 'subs', { ...
	'ufun', 'handle_ufun';
	'abs', 'handle_abs';
	'free', 'handle_free';
	'back', 'handle_back';
	'forw', 'handle_forw';
	'gram', 'handle_gram';
	'power', 'handle_power';
	'block_setup', 'handle_block_setup';
	'blockify_data', 'handle_blockify_data';
	'mtimes_block', 'handle_mtimes_block'});

if isempty(ob.caller)
	ob.caller = caller_name;
end

ob = class(ob, mfilename);


function res = parallelLine3d(line, point)
%PARALLELLINE3D  Create 3D line parallel to another one.
%
%   L2 = parallelLine3d(L, P)
%   Creates the 3D line L2, parallel to the line L, and containing the
%   point P.
%
%   Example
%
%   See also
%   geom3d, parallelLine, parallelPlane

% ------
% Author: David Legland
% E-mail: david.legland@grignon.inra.fr
% Created: 2012-08-23, using Matlab 7.9.0.529 (R2009b)
% Copyright 2012-2022 INRA - Cepia Software Platform

res = [point line(:, 4:6)];


function res = eq(p,q)
%EQ           Implements  p == q  for polynomials
%
%Result 1 iff p and q are mathematically identical
%

% written  08/28/00     S.M. Rump
% modified 04/04/04     S.M. Rump  set round to nearest for safety
% modified 04/06/05     S.M. Rump  rounding unchanged
%

  p = removevars(permvars(polynom(p),'lex'));
  q = removevars(permvars(polynom(q),'lex'));
  res = isequal(p.e,q.e) & isequal(p.c,q.c) & isequal(p.v,q.v);


function [K] = kv1u1(x, y, xp, yp, hyp, i)

logsigma = hyp(1);
logthetax = hyp(2);
logthetay = hyp(3);

n_x = size(x,1);
n_y = size(y,1);
n_xp = size(xp,1);
n_yp = size(yp,1);

x = repmat(x,1,n_xp);
y = repmat(y,1,n_yp);
xp = repmat(xp',n_x,1);
yp = repmat(yp',n_y,1);

switch i

case 0

K=exp(1).^(logsigma+(-1).*logthetax+(-1).*logthetay+(-1/2).*exp(1).^((-1) ...
  .*logthetax).*(x+(-1).*xp).^2+(-1/2).*exp(1).^((-1).*logthetay).*(y+(-1) ...
  .*yp).^2).*(x+(-1).*xp).*(y+(-1).*yp);

case 1 % logsigma

K=exp(1).^(logsigma+(-1).*logthetax+(-1).*logthetay+(-1/2).*exp(1).^((-1) ...
  .*logthetax).*(x+(-1).*xp).^2+(-1/2).*exp(1).^((-1).*logthetay).*(y+(-1) ...
  .*yp).^2).*(x+(-1).*xp).*(y+(-1).*yp);

case 2 % logthetax

K=exp(1).^(logsigma+(-1).*logthetax+(-1).*logthetay+(-1/2).*exp(1).^((-1) ...
  .*logthetax).*(x+(-1).*xp).^2+(-1/2).*exp(1).^((-1).*logthetay).*(y+(-1) ...
  .*yp).^2).*((-1)+(1/2).*exp(1).^((-1).*logthetax).*(x+(-1).*xp).^2).*(x+ ...
  (-1).*xp).*(y+(-1).*yp);

case 3 % logthetay

K=exp(1).^(logsigma+(-1).*logthetax+(-1).*logthetay+(-1/2).*exp(1).^((-1) ...
  .*logthetax).*(x+(-1).*xp).^2+(-1/2).*exp(1).^((-1).*logthetay).*(y+(-1) ...
  .*yp).^2).*(x+(-1).*xp).*((-1)+(1/2).*exp(1).^((-1).*logthetay).*(y+(-1) ...
  .*yp).^2).*(y+(-1).*yp);

otherwise

        K = zeros(n_x, n_xp);
end

end


function classifieroutput = fcnnclassify(fcnn,X,R)
%FCNNCLASSIFY Fully-connected neural network classifier.
%   CLASSIFIEROUTPUT = FCNNCLASSIFY(FCNN,X,R) uses a feedforward pass
%   through a fully-connected neural net, fcnn, to classify a set of
%   input pattern vectors (rows of X). If the pattern class membership
%   matrix, R, is provided, this function also outputs the percent of
%   patterns classified correctly.
%
%   Type
%
%   >> help fcninfo
%
%   at the prompt for detailed explanations of the components of the
%   fully-connected neural net.
%
%   classifieroutput is a structure with the following fields.
%
%   classifieroutput.Class
%    A vector whose number of elements is equal to the number of input
%    patterns. The kth element of this vector gives the number of the
%    class to which the kth vector was assigned (i.e., classified).
%
%   classifieroutput.ClassificationRate
%    A scalar that gives the percent of patterns classified correctly,
%    assuming that classifierinput.R was provided. If this is not the
%    case then classifieroutput.ClassificationRate = [].
%
%   Copyright 2002-2020 Gatesmark
%
%   This function, and other functions in the DIPUM Toolbox, are based
%   on the theoretical and practical foundations established in the
%   book Digital Image Processing Using MATLAB, 3rd ed., Gatesmark
%   Press, 2020.
%
%   Book website: http://www.imageprocessingplace.com
%   License: https://github.com/dipum/dipum-toolbox/blob/master/LICENSE.txt

% INPUTS
np = size(X,2);

% CLASSIFY PATTERNS
% Feedforward.
fcnn = fcnnff(fcnn,X);
% Find the maximum value of fcnn(L).A in each column. The location of a
% maximum in a column gives the class of the pattern corresponding to
% that column. Could also do with softmax to associate a probability
% number with each output, but the net calssificationresult would be the
% same because the largest values of each approach would still
% correspond to the same input patterns.
for j = 1:np
    idx = find(fcnn(end).A(:,j)== max(max((fcnn(end).A(:,j)))));
    classifieroutput.Class(j) = idx;
end

% IF A CLASS MEMBERSHIP MATRIX WAS PROVIDED, USE IT TO COMPUTE THE
% CORRECT CLASSIFICATION RATE.
if nargin == 3
   numErrors = 0;
   % Compute the correct classification rate.
   for j = 1:np
      idx = find(R(:,j) == 1); % Class of input pattern j.
      if ~isequal(classifieroutput.Class(j),idx)
          numErrors = numErrors + 1;
      end
   end
    classifieroutput.ClassificationRate = ((np - numErrors)/np)*100;
else
    classifieroutput.ClassificationRate = [];
end


function [m] = yd2m(yd)
% Convert length from yards to meters.
% Chad Greene 2012
m = yd*0.9144;


function [rVect, vVect] = getStateAtTime_alg(time, sma, ecc, inc, raan, arg, mean, epoch, gmu)
%getStateAtTime Summary of this function goes here
%   Detailed explanation goes here
    numTimes = length(time);

    oneArray = (zeros(1, numTimes)+1);

    sma = sma * oneArray;
    ecc = ecc * oneArray;
    inc = AngleZero2Pi(deg2rad(inc)) * oneArray;
    raan = AngleZero2Pi(deg2rad(raan)) * oneArray;
    arg = AngleZero2Pi(deg2rad(arg)) * oneArray;
    M0 = deg2rad(mean) * oneArray;

    n = computeMeanMotion(sma, gmu);
    deltaT = time - epoch;
    M = (M0(:) + n(:).*deltaT(:))';
    tru = computeTrueAnomFromMean(M, ecc);

    if(length(tru) > 1)
        [rVect,vVect] = vect_getStatefromKepler(sma, ecc, inc, raan, arg, tru, gmu, false);
    else
        [rVect, vVect] = getStatefromKepler_Alg(sma, ecc, inc, raan, arg, tru, gmu);
    end

    rVect(isnan(rVect)) = 0;
    vVect(isnan(vVect)) = 0;
end


% function m = evalf(trueclass,cl,x,sfct)
% DESCRIPTION
%   computes f1 measure
%   ignores x and sfct - just for compatibility
% Copyright (c) 1998-2002 by Alexander Strehl
function m = evalf(trueclass,cl,x,sfct)

remappedcl = zeros(size(cl));

A = zeros(max(cl),2+max(trueclass));
for i=1:max(cl),
 activepoints = find(cl==i);
 nu1=trueclass(activepoints);
 num=max(trueclass);
 composition = hist(nu1,1:num);
 j = find(composition==max(composition));
 j = j(1);
 A(i,:) = [j i composition];
end;
A = sortrows(A);
A = A(:,3:size(A,2));
nha = sum(A,1);
nell = sum(A,2);
nhamatrix = ones(length(nell),1) * nha;
nellmatrix = nell * ones(1,length(nha));
fmatrix = (2*A) ./ (nhamatrix+nellmatrix);
m = sum(max(fmatrix,[],1) .* nha) / length(trueclass);


% Test whether stable conditional Gaussian inference works
% Make a linear dynamical system
%   X1 -> X2
%   |     |
%   v     v
%   Y1    Y2

intra = zeros(2);
intra(1,2) = 1;
inter = zeros(2);
inter(1,1) = 1;
n = 2;

X = 2; % size of hidden state
Y = 2; % size of observable state

ns = [X Y];
bnet = mk_dbn(intra, inter, ns, 'discrete', [], 'observed', 2);

x0 = rand(X,1);
V0 = eye(X);
C0 = rand(Y,X);
R0 = eye(Y);
A0 = rand(X,X);
Q0 = eye(X);

bnet.CPD{1} = gaussian_CPD(bnet, 1, 'mean', x0, 'cov', V0);
bnet.CPD{2} = gaussian_CPD(bnet, 2, 'mean', zeros(Y,1), 'cov', R0, 'weights', C0);
bnet.CPD{3} = gaussian_CPD(bnet, 3, 'mean', zeros(X,1), 'cov', Q0, 'weights', A0);

T = 5; % fixed length sequences

engine = {};
engine{end+1} = kalman_inf_engine(bnet);
engine{end+1} = scg_unrolled_dbn_inf_engine(bnet, T);
engine{end+1} = jtree_unrolled_dbn_inf_engine(bnet, T);

inf_time = cmp_inference_dbn(bnet, engine, T, 'check_ll', 0);


% Test file for trigtech/poly.m

function pass = test_poly(pref)

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

testclass = trigtech();

%%
% Check a few simple examples.

f = testclass.make(@(x) zeros(size(x)), [], pref);
p = poly(f);
pass(1) = (norm(p, inf) <= 10*vscale(f)*eps);

f = testclass.make(@(x) 3*ones(size(x)), [], pref);
p = poly(f);
pass(2) = (norm(p - 3, inf) < 10*vscale(f)*eps);

f = testclass.make(@(x) 1+cos(pi*x), [], pref);
p = poly(f);
pass(3) = (norm(p - [0.5 1 0.5], inf) < 10*vscale(f)*eps);

f = testclass.make(@(x) 1 + exp(2*1i*pi*x) + exp(-1i*pi*x), [], pref);
p = poly(f);
pass(4) = (norm(p - [0 1 1 0 1], inf) ...
    < 10*vscale(f)*eps);

%%
% Verify operation for array-valued chebtech objects.

f = testclass.make(@(x) [3*ones(size(x)), 1+cos(pi*x), ...
    1 + exp(2*1i*pi*x) + exp(-1i*pi*x)], [], pref);
p = poly(f);
p_exact = [0 0   0;...
           0 0.5 1;...
           3 1   1;...
           0 0.5 0;...
           0 0   1].';
pass(5) = (norm(p(:) - p_exact(:), inf) < 10*max(vscale(f)*eps));

end


function power_loss(y, ons, X)

%  'true' model fit

% assume 'true' is FIR estimate
DX = tor_make_deconv_mtx3(ons, 20, 1);

% get residual variance and rss from best model
[bdx, fdx, rdx, rss, r_var, N, kdx] = fit_model(DX, y);

% if you had specified the right canonical shape at the start
Xbest = conv(ons, bdx); Xbest = Xbest(1:N);
Xbest(:, end+1) = 1;

% get residual variance and rss from best model
[bdx, fdx, rdx, rss, r_var, N, kdx] = fit_model(DX, y);

% E(t), expected t-value if you had gotten the HRF exactly right
% --------------------------------------------------------
c = eye(2);
c(:, end) = []; % remove intercept; assumes intcpt is at end!

[bbest, fbest, rbest, rss, r_var, N, kbest] = fit_model(Xbest, y);

[tbest, pbest] = get_t_values(c, bbest, Xbest, r_var);

delta = tbest;
alpha = .001;
df = N - kbest;
t_thresh = tinv(1 - alpha ./ 2, df);

power_best = 1 - nctcdf(t_thresh, df, delta);

% E(t), expected t-value with canonical HRF
% --------------------------------------------------------
hrf = spm_hrf(2);
CX = conv(ons, hrf); CX = CX(1:N);
CX(:, end+1) = 1;

% get residual variance and rss from canonical model
[bc, fc, rc, rss_c, r_var_c, N, kc] = fit_model(CX, y);

[tc, pc] = get_t_values(c, bc, CX, r_var_c);

delta = tc;
df = N - kc;
power_c = 1 - nctcdf(t_thresh, df, delta);

% Difference: Power loss
power_loss_val = 100 * (power_best - power_c) ./ power_best;

% significance for FIR model: full vs. reduced
% --------------------------------------------------------
Xred = ones(N, 1);

[F, p, dfb, dfe] = full_vs_reduced(y, DX, Xred, rss, N, kdx);

f_thresh = finv(1 - alpha, dfb, dfe);
fdelta = F;
power_fir = ncfcdf(f_thresh, dfb, dfe, fdelta);

power_loss_fir = 100 * (power_best - power_fir) ./ power_best;

% Plot
% --------------------------------------------------------
create_figure('plot'); plot(y, 'k'); hold on;
plot(fbest, 'r');
plot(fc, 'b');

fprintf(1,'With best (ideal HRF) model: t = %3.2f, p = %3.4f, power = %3.4f\n', tbest, pbest, power_best);
fprintf(1,'With canonical HRF model: t = %3.2f, p = %3.4f, power = %3.4f\n', tc, pc, power_c);
fprintf(1,'With FIR model F-test: F = %3.2f, p = %3.4f, power = %3.4f\n', F, p, power_fir);

fprintf(1, 'Power loss: Canonical vs. ideal: %3.2f%%\n', power_loss_val);
fprintf(1, 'Power loss: FIR vs. ideal: %3.2f%%\n', power_loss_fir);

end

%
% full vs. reduced
function [F, p, dfb, dfe] = full_vs_reduced(y, Xfull, Xred, rss, N, kfull)

[bred, fred, rred, rss_red] = fit_model(Xred, y);

dfb = (kfull - 1);
dfe = (N - kfull);

F = ( (rss_red - rss) ./ dfb ) ./ ( rss ./ dfe );

p = 1 - fcdf(F, dfb, dfe);

end

function [b, f, r, rss, r_var, N, k] = fit_model(X, y)
N = size(y, 1);
k = size(X, 2);

b = pinv(X) * y;
f = X * b;
r = y - f;

rss = r' * r;
r_var = rss ./ (N - k);

end

function [t, p, cb, var_cbeta] = get_t_values(c, b, X, r_var)

var_cbeta = diag( sqrt(r_var) * c' * inv(X' * X) * c );

% effect
cb = c' * b;

% t-values
t = cb ./ var_cbeta;

p = 2 * ( 1 - tcdf(abs(t), size(X,1) - size(X,2)) );

end


function [R,eff] = randmio_und_connected(R, ITER)
%RANDMIO_UND_CONNECTED     Random graph with preserved degree distribution
%
%   R = randmio_und_connected(W,ITER);
%   [R eff] = randmio_und_connected(W, ITER);
%
%   This function randomizes an undirected network, while preserving the
%   degree distribution. The function does not preserve the strength
%   distribution in weighted networks. The function also ensures that the
%   randomized network maintains connectedness, the ability for every node
%   to reach every other node in the network. The input network for this
%   function must be connected.
%
%   Input:      W,      undirected (binary/weighted) connection matrix
%               ITER,   rewiring parameter
%                       (each edge is rewired approximately ITER times)
%
%   Output:     R,      randomized network
%               eff,    number of actual rewirings carried out
%
%   References: Maslov and Sneppen (2002) Science 296:910
%
%
%   2007-2012
%   Mika Rubinov, UNSW
%   Jonathan Power, WUSTL
%   Olaf Sporns, IU

%   Modification History:
%   Jun 2007: Original (Mika Rubinov)
%   Apr 2008: Edge c-d is flipped with 50% probability, allowing to explore
%             all potential rewirings (Jonathan Power)
%   Mar 2012: Limit number of rewiring attempts, count number of successful
%             rewirings (Olaf Sporns)

n=size(R,1);
[i,j]=find(tril(R));
K=length(i);
ITER=K*ITER;

% maximal number of rewiring attempts per 'iter'
maxAttempts= round(n*K/(n*(n-1)));
% actual number of successful rewirings
eff = 0;

for iter=1:ITER
    att=0;
    while (att<=maxAttempts)                                     %while not rewired
        rewire=1;
        while 1
            e1=ceil(K*rand);
            e2=ceil(K*rand);
            while (e2==e1),
                e2=ceil(K*rand);
            end
            a=i(e1); b=j(e1);
            c=i(e2); d=j(e2);

            if all(a~=[c d]) && all(b~=[c d]);
                break           %all four vertices must be different
            end
        end

        if rand>0.5
            i(e2)=d; j(e2)=c; 	%flip edge c-d with 50% probability
            c=i(e2); d=j(e2); 	%to explore all potential rewirings
        end

        %rewiring condition
        if ~(R(a,d) || R(c,b))
            %connectedness condition
            if ~(R(a,c) || R(b,d))
                P=R([a d],:);
                P(1,b)=0; P(2,c)=0;
                PN=P;
                PN(:,d)=1; PN(:,a)=1;

                while 1
                    P(1,:)=any(R(P(1,:)~=0,:),1);
                    P(2,:)=any(R(P(2,:)~=0,:),1);
                    P=P.*(~PN);
                    if ~all(any(P,2))
                        rewire=0;
                        break
                    elseif any(any(P(:,[b c])))
                        break
                    end
                    PN=PN+P;
                end
            end %connectedness testing

            if rewire               %reassign edges
                R(a,d)=R(a,b); R(a,b)=0;
                R(d,a)=R(b,a); R(b,a)=0;
                R(c,b)=R(c,d); R(c,d)=0;
                R(b,c)=R(d,c); R(d,c)=0;

                j(e1) = d;          %reassign edge indices
                j(e2) = b;
                eff = eff+1;
                break;
            end %edge reassignment
        end %rewiring condition
        att=att+1;
    end %while not rewired
end %iterations


function [out] = idv2idv(n)
% Outputs a transformation matrix for changing from forward to reverse order.
%
% order 1 (Jennie's)
%
% 000, 001, 010, 011, 100, 101, 110, 111
%
% order 2 (mine)
%
% 000, 100, 010, 110, 001, 101, 011, 111
%
% USAGE:
%
%    [out] = idv2idv(n)
%
% INPUT:
%    n:      matrix, size of matrix `(2^n x 2^n)`
%
% OUTPUT:
%    out:    transforamtion matrix

warning('are you sure you want to call this function?');

if n <= 0
    out = 1;
    return;
end

out = sparse(2^n,2^n);
for i = 0:(2^n-1)
    t = dec2bin(i,n);
    t2 = t(end:-1:1);
    i2 = bin2dec(t2);
    out(i+1,i2+1) = 1;
end


%%***********************************************************************
%% fapproblem:
%%
%% (primal prob.) min  Tr C*X
%%                s.t. diag(X) = e
%%                    -Eij * X = 2/(k-1)  if (i,j) in  U
%%                    -Eij * X <= 2/(k-1) if (i,j) in GU
%%  where Eij = ei*ej' + ej*ei'
%%  b = e
%%  C = (1/2)*Diag(We) - (k-1)/(2k) *L(G)
%%  SignP(i,j) = 1 if (i,j) in GU, 2 if (i,j) in U; 0 otherwise
%%  M_ij = -1/(k-1) if (i,j) in  U or GU; 0 otherwise
%%-----------------------------------------------------------------------
%% (primal prob.) min  Tr C*X
%%                s.t. diag(X) = e
%%                    LL <= X <= UU  if (i,j) in  U
%%
%%  where L_ij = -1/(k-1) if (i,j) in  U or GU; -inf otherwise,
%%      U_ij = -1/(k-1) if (i,j) in  U; inf otherwise
%%
%%
%%
%% [blk,Avec,C,b,LL,UU,SignP,M,kparm] = fapread_lu(fname);
%%***********************************************************************
%% SDPNAL+
%% Copyright (c) 2014 by
%% Liuqin Yang, Defeng Sun, and Kim-Chuan Toh
%%***********************************************************************

 function [blk,Avec,C,b,LL,UU,SignP,M,kparm] = fapread_lu(fname)

%%
%% read fap data
%%
   if exist(fname)
      fid = fopen(fname,'r');
   elseif exist([fname,'.dat']);
      fid = fopen([fname,'.dat'],'r');
   else
      fprintf('** Problem not found. \n');
      blk = []; Avec = []; C = []; b = [];
      LL =[]; UU =[];SignP = []; M =[]; kparm = [];
      return;
   end
   [tmpr,count] = fscanf(fid,'%c');
   datavec = sscanf(tmpr,'%f'); clear tmpr;
   n = datavec(1);
   numedges = datavec(2);
   kparm = datavec(3);
   datavec = datavec(4:length(datavec));
   len = length(datavec);
   if (len ~= 3*numedges)
      error(' fapread: numedges and data do not match.');
   end
   I = datavec(1:3:len);
   J = datavec(2:3:len);
   w = datavec(3:3:len);

   idxU = find(w==1000);
   IU = I(idxU); JU = J(idxU); wU = w(idxU);
   U = spconvert([IU JU wU; n n 0]);
   U = U + U';

   idx2 = find(w~=1000);
   I2 = I(idx2); J2 = J(idx2); w2 = w(idx2);
   GU = spconvert([I2 J2 w2; n n 0]);
   GU = GU + GU';

   fclose(fid);
%%
%% blk, Avec, C, b
%%
    n = length(U);
    mU = nnz(triu(U,1));
    mGU = nnz(triu(GU,1));
    m = mGU + mU + n;

    %%b = [ones(n,1); (2/(kparm-1))*ones(mU+mGU,1)];
    b = ones(n,1);
    %b = [];
    LG = diag(GU*ones(n,1))-GU;
    C{1,1} = 0.5*(diag(GU*ones(n,1))) - ((kparm-1)/(2*kparm))*LG;
    %%C{2,1} = zeros(mGU,1);

    blk{1,1} = 's';  blk{1,2} = n;
    %%blk{2,1} = 'l';  blk{2,2} = mGU;
%%
%%
%%
    r2 = sqrt(2);
    I = zeros(m,1); J = zeros(m,1); w = zeros(m,1);
    cnt = 0;
    e = [1:n]';
    I(1:n) = e.*(e+1)/2;
    J(1:n) = e;
    w = ones(n,1);
    cnt = cnt+n;
    for i = 1:n
        idx = find(U(i,i+1:n));
        idx = idx+i;      %% adjust index.
        len = length(idx);
        I(cnt+[1:len]) = i + idx.*(idx-1)/2;
        J(cnt+[1:len]) = cnt+[1:len]';
        w(cnt+[1:len]) = -r2*ones(len,1);
        cnt = cnt + len;
    end
    for i = 1:n
        idx = find(GU(i,i+1:n));
        idx = idx+i;      %% adjust index.
        len = length(idx);
        I(cnt+[1:len]) = i + idx.*(idx-1)/2;
        J(cnt+[1:len]) = cnt+[1:len]';
        w(cnt+[1:len]) = -r2*ones(len,1);
        cnt = cnt + len;
    end
    Av = spconvert([I,J,w; n*(n+1)/2, m, 0]);
    Avec{1,1} = Av(:,1:n);

    sign0 = zeros(n,n);
    sign0(GU ~= 0) = 1;
    sign0(U ~= 0) = 2;
    SignP{1,1} = sign0;

    M0 = zeros(n,n);
    M0(sign0 ~= 0) = -1/(kparm-1);
    M{1,1} = M0;
    LL0 = -inf*ones(n,n);
    LL0(sign0 ~= 0) = -1/(kparm-1);
    LL{1,1} = LL0;
    UU0 = inf*ones(n,n);
    UU0(sign0 == 2) = -1/(kparm-1);
    UU{1,1} = UU0;
%%***********************************************************************