function [jump_list, lid_ko, data,  running_mean] = getJumps(data, rate_scale)
% Return outliers in a relatively constant time series
%
% INPUT
%   data          data (column, eventually it can have a second column containing std)
%   rate_scale    24/rate_scale => used for scaling window size (1 => daily, 24 => hourly ...)
%
% OUTPUT
%
% SYNTAX
%   [jump_list, id_ko, data, running_mean] = getJumps(data, rate_scale)
%

%--- * --. --- --. .--. ... * ---------------------------------------------
%               ___ ___ ___
%     __ _ ___ / __| _ | __|
%    / _` / _ \ (_ |  _|__ \
%    \__, \___/\___|_| |___/
%    |___/                    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
%--------------------------------------------------------------------------
    flag_smooth = true; % Apply a spline smoothing to rate (duration 3 days)
    spline_base = 7; % in days

    if size(data,2) == 2
        data_std = data(:,2);
        data = data(:,1);
    else
        data_std = 0;
    end
    med_data = median(data, 'omitnan');
    data = data - med_data;

    % Compute thresholds - empirical but it works (outliers should be less than 75% percent)
    thr_perc = 0.75;
    tmp = diff(data);
    tmp(abs(tmp) > 3 * perc(noNaN(abs(tmp)), thr_perc)) = nan;
    thr = std(tmp, 'omitnan');
    clear tmp;

    % Outlier detection
    if any(data_std)
        [lid_ko, data] = getOutliers([data data_std], thr);
    else
        [lid_ko, data] = getOutliers(data, thr);
    end

    flag_running = true;
    % Initialization

    % Jump parameters
    run_win = 5 * rate_scale;   % window size for running mean
    cumsum_thr = 2;             % above this threshold, cumulate residuals
    cum_thr = 6;                % above this threshold the cumulate TRIGGERS A JUMP

    % Recompute a running_threshold
    % when the noise is higher the discrimination of jumps is lower
    thr = movstd(diff(data), run_win, 'omitnan');
    if not(any(thr))
        thr(:) = nan2zero(std(data, 'omitnan'));
    end

    q_win = floor(run_win / 2);
    thr((q_win + 1) : end - q_win) = min(thr((2*q_win +1):end), thr(1:end - (2*q_win)));

    mthr = median(thr, 'omitnan');

    thr(isnan(zero2nan(thr))) = mthr;
    run_win_variable = round(max(1,sqrt((thr - mthr)/mthr)) * run_win);
    run_win_variable = [run_win_variable; run_win_variable(end)];
    %thr = mthr + 0.1 * (thr - mthr);

    mu = data(1); % initial mean
    i = 1 + find(not(isnan(data(2:end))), 1, 'first');  % running index on observations
    [s_plus, s_minus] = deal(zeros(size(data,1),1)); % sensors
    [n_plus, n_minus] = deal(uint16(zeros(size(data,1),1))); % epochs since sensor cumulation started

    running_mean = data; % running mean

    j = 1;           % running index on jumps
    jump_list = 0;   % list of jumps
    while i <= length(data)
        % if jumps are not detected
        if isnan(data(i))
            s_plus(i) = s_plus(i-1);        % keep the old sensor
            s_minus(i) = s_minus(i-1);      % keep the old sensor
            n_plus(i)  = iif(s_plus(i)  > 0, n_plus(i-1)  + 1, 0);
            n_minus(i) = iif(s_minus(i) < 0, n_minus(i-1) + 1, 0);
            running_mean(i) = mu;
            i = i + 1;
        else
            % while no jumps are detected and i is running on observations
            while i <= length(data) && s_plus(i-1) <= (cum_thr * thr(i-1)) && s_minus(i-1) >= -(cum_thr * thr(i-1))
                val = iif(abs(data(i) - mu) > 0.9*(cum_thr * thr(i-1)), mu, data(i));
                s_plus(i)  = max(0, s_plus(i-1)  + (data(i) - mu) - (cumsum_thr * thr(i-1)));
                s_minus(i) = min(0, s_minus(i-1) + (data(i) - mu) + (cumsum_thr * thr(i-1)));

                n_plus(i)  = iif(s_plus(i)  > 0 , n_plus(i-1)  + 1, 0);
                n_minus(i) = iif(s_minus(i) < 0 , n_minus(i-1) + 1, 0);

                if flag_running
                    mu = nan2zero(mean(data(max(jump_list(j)+1, i + 1 - run_win_variable(i)):i), 'omitnan'));
                end
                running_mean(i) = mu;
                i = i + 1;
            end
            if i <= length(data)
                n_d = i - 1;
                j = j + 1;
                jump_list(j) = iif(s_plus(n_d) > (cum_thr * thr(i-1)), n_d - n_plus(n_d), n_d - n_minus(i-1));
                mu = nan2zero(mean(data(max(jump_list(j)+1, n_d - run_win_variable(n_d)):(n_d)), 'omitnan'));

                jmp_magnitude = running_mean(jump_list(j)) - mu;
                Core.getLogger.addMessage(sprintf('Jump detected at epoch %d, it happened in epoch %d, length: %d, old mean %f.2, new mean %f.2, for a jump of %.2f\n', n_d, jump_list(j), n_d - jump_list(j) + 1, running_mean(jump_list(j)), mu, jmp_magnitude),100);
                if (i <= length(data))
                    [s_plus(i-1), s_minus(i-1)] = deal(0);
                    [n_plus(i-1), n_minus(i-1)] = deal(0);
                end
            end
        end
        mu = nan2zero(mean(data(max(jump_list(j)+1, i - run_win_variable(i-1)):(i-1)), 'omitnan'));
        running_mean(i-1) = mu;
    end

    % compute running mean backwords
    if flag_running
        running_smooth = running_mean;
        robustness_perc = 0.90;
        n_sigma = 6;

        % flag small jumps (1-2 epochs are too small to be considered "real jumps"
        for j = fliplr(find(diff(jump_list) < 3))
            id_ko = jump_list(j)+1:jump_list(j+1);
            data(id_ko) = nan;
            lid_ko(id_ko) = true;
            jump_list(j) = jump_list(j+1);
            jump_list(j+1) = [];
        end

        last_win_id = jump_list(j)+1 : size(data,1); % last window
        % Compute a trend "robust" using the robustness_perc of data
        %step_median(last_win_id) = median(data(last_win_id), 'omitnan');
        [tmp, trend] = strongDeTrend(data(last_win_id), robustness_perc, 1-((1-robustness_perc)/2), n_sigma);
        if flag_smooth && sum(not(isnan((data(last_win_id))))) > 5
            if any(trend); running_mean(last_win_id) = movmean(tmp, run_win, 'omitnan') + trend; end
            try
                [~, ~, ~, running_smooth(last_win_id)] = splinerMat(1:numel(last_win_id), data(last_win_id), ceil(spline_base * rate_scale), 1e-5, 1:numel(last_win_id)); % medium splines
            catch
                if any(trend); running_smooth(last_win_id) = movmean(tmp, run_win, 'omitnan') + trend; end
            end
        else
            if any(trend); running_smooth(last_win_id) = movmean(tmp, run_win, 'omitnan') + trend; end
        end
        for j = 2 : numel(jump_list)
            last_win_id = jump_list(j-1)+1 : (jump_list(j));
            %step_median(last_win_id) = median(data(last_win_id), 'omitnan');
            [tmp, trend] = strongDeTrend(data(last_win_id), robustness_perc, 1-((1-robustness_perc)/2), n_sigma);
            if flag_smooth && sum(not(isnan((data(last_win_id))))) > 5
                if any(trend); running_mean(last_win_id) = movmean(tmp, run_win, 'omitnan') + trend; end
                try
                    [~, ~, ~, running_smooth(last_win_id)] = splinerMat(1:numel(last_win_id), data(last_win_id), ceil(spline_base * rate_scale), 1e-5, 1:numel(last_win_id)); % medium splines
                catch
                    if any(trend); running_smooth(last_win_id) = movmean(tmp, run_win, 'omitnan') + trend; end
                end
            else
                if any(trend); running_smooth(last_win_id) = movmean(tmp, run_win, 'omitnan') + trend; end
            end
        end

        %  remove very small jumps - recursive
        flag_rem_jmp = true;
        while flag_rem_jmp
            % Check the magnitude of the jump, with both moving mean and splines, if it is too small is a false alarm
            jmp_magnitude = min(diff(running_mean(jump_list(2:end) + repmat([0 1]', 1, numel(jump_list)-1))), ...
                                diff(running_smooth(jump_list(2:end) + repmat([0 1]', 1, numel(jump_list)-1))));
            % Jump smaller than half the noise in that window of data will be ignored
            id_small_jmp = abs(jmp_magnitude)' < max(0.4,(thr(jump_list(2:end))));
            if any(id_small_jmp)
                jump_list(find(id_small_jmp) + 1) = [];  % remove jmp

                % recompute running mean
                last_win_id = jump_list(end)+1 : size(data,1);
                %step_median(last_win_id) = median(data(last_win_id), 'omitnan');
                % remove the trend before computing the running mean (this help in case of very steep intervals of data)
                [tmp, trend] = strongDeTrend(data(last_win_id), robustness_perc, 1-((1-robustness_perc)/2), n_sigma);
                if flag_smooth && sum(not(isnan((data(last_win_id))))) > 5
                    if any(trend); running_mean(last_win_id) = movmean(tmp, run_win, 'omitnan') + trend; end
                    try
                        [~, ~, ~, running_smooth(last_win_id)] = splinerMat(1:numel(last_win_id), data(last_win_id), ceil(spline_base * rate_scale), 1e-5, 1:numel(last_win_id)); % medium splines
                    catch
                        running_smooth(last_win_id) = movmean(tmp, run_win, 'omitnan') + trend;
                    end
                else
                    if any(trend); running_smooth(last_win_id) = movmean(tmp, run_win, 'omitnan') + trend; end
                end
                for j = 2 : numel(jump_list)
                    last_win_id = jump_list(j-1)+1 : (jump_list(j));
                    [tmp, trend] = strongDeTrend(data(last_win_id), robustness_perc, 1-((1-robustness_perc)/2), n_sigma);
                    if flag_smooth && sum(not(isnan((data(last_win_id))))) > 5
                        if any(trend); running_mean(last_win_id) = movmean(tmp, run_win, 'omitnan') + trend; end
                        try
                            [~, ~, ~, running_smooth(last_win_id)] = splinerMat(1:numel(last_win_id), data(last_win_id), ceil(spline_base * rate_scale), 1e-5, 1:numel(last_win_id)); % medium splines
                        catch
                            if any(trend); running_smooth(last_win_id) = movmean(tmp, run_win, 'omitnan') + trend; end
                        end
                    else
                        if any(trend); running_smooth(last_win_id) = movmean(tmp, run_win, 'omitnan') + trend; end
                    end
                end
            else
                flag_rem_jmp = false;
            end
        end
        running_mean = running_smooth;
    else
        last_win_id = jump_list(j)+1 : size(data,1);
        running_mean(last_win_id) = mean(data(last_win_id), 'omitnan');
    end

    running_mean = running_mean + med_data;
    data = data + med_data;
    % figure; plot(-s_minus); hold on; plot(s_plus); hold on; plot(cum_thr * thr)
end


function cnn_imagenet_minimal()
% CNN_IMAGENET_MINIMAL   Minimalistic demonstration of how to run an ImageNet CNN model

% setup toolbox
run(fullfile(fileparts(mfilename('fullpath')), ...
  '..', 'matlab', 'vl_setupnn.m')) ;

% download a pre-trained CNN from the web
if ~exist('imagenet-vgg-f.mat', 'file')
  urlwrite('http://www.vlfeat.org/matconvnet/models/imagenet-vgg-f.mat', ...
    'imagenet-vgg-f.mat') ;
end
net = load('imagenet-vgg-f.mat') ;

% obtain and preprocess an image
im = imread('peppers.png') ;
im_ = single(im) ; % note: 255 range
im_ = imresize(im_, net.normalization.imageSize(1:2)) ;
im_ = im_ - net.normalization.averageImage ;

% run the CNN
res = vl_simplenn(net, im_) ;

% show the classification result
scores = squeeze(gather(res(end).x)) ;
[bestScore, best] = max(scores) ;
figure(1) ; clf ; imagesc(im) ;
title(sprintf('%s (%d), score %.3f',...
   net.classes.description{best}, best, bestScore)) ;


function [uSol, NuSol] = startMultistep(K, dt, L, Nc, Nv, ~, S, uInit, NuInit)
%STARTMULTISTEP   Get enough initial data when using a multistep scheme.
%    [USOL, NUSOL] = STARTMULTISTEP(K, dt, L, NC, NV, pref, S, uInit, NuInit)
%    uses a one-step algorithm to start a multistep scheme.

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

% Note for developers: multistep algorithms are started with the one-step LIRK4
% time-stepping scheme.

% Set-up:
q = K.steps;                      % number of steps
nVars = S.numVars;                % number of unknown functions
%N = sqrt(size(uSol{1}, 1)/nVars); % number of grid points

% Create a cell-array to store the coefficients at the Q steps:
uSol = cell(q, 1);
NuSol = cell(q, 1);

% Store the initial conidition in the last column:
uSol{q} = uInit{1};
NuSol{q} = NuInit{1};

% Set-up the scheme:
K = imex('lirk4');
schemeCoeffs = computeCoeffs(K, dt, L, [], S);

% Do (Q-1) steps of LIRK4:
uOld = uInit;
NuOld = NuInit;
for j = 1:(q-1)
    [uNew, NuNew] = oneStep(K, dt, schemeCoeffs, Nc, Nv, nVars, S, uOld, NuOld);
    uSol{q-j} = uNew{1};
    NuSol{q-j} = NuNew{1};
    uOld = uNew;
    NuOld = NuNew;
end

end


function sep = graph_separated(G, X, Y, S)

G2 = G;
G2(S,:) = 0;
G2(:,S) = 0;
conn = reachability_graph(G2);
conn2 = conn(X,Y);
sep = all(conn2(:)==0);


function [mssim, ssim_map] = ssim_index(img1, img2, K, window, L)

%========================================================================
%SSIM Index, Version 1.0
%Copyright(c) 2003 Zhou Wang
%All Rights Reserved.
%
%The author was with Howard Hughes Medical Institute, and Laboratory
%for Computational Vision at Center for Neural Science and Courant
%Institute of Mathematical Sciences, New York University, USA. He is
%currently with Department of Electrical and Computer Engineering,
%University of Waterloo, Canada.
%
%----------------------------------------------------------------------
%Permission to use, copy, or modify this software and its documentation
%for educational and research purposes only and without fee is hereby
%granted, provided that this copyright notice and the original authors'
%names appear on all copies and supporting documentation. This program
%shall not be used, rewritten, or adapted as the basis of a commercial
%software or hardware product without first obtaining permission of the
%authors. The authors make no representations about the suitability of
%this software for any purpose. It is provided "as is" without express
%or implied warranty.
%----------------------------------------------------------------------
%
%This is an implementation of the algorithm for calculating the
%Structural SIMilarity (SSIM) index between two images. Please refer
%to the following paper:
%
%Z. Wang, A. C. Bovik, H. R. Sheikh, and E. P. Simoncelli, "Image
%quality assessment: From error measurement to structural similarity"
%IEEE Transactios on Image Processing, vol. 13, no. 4, Apr. 2004.
%
%Kindly report any suggestions or corrections to zhouwang@ieee.org
%
%----------------------------------------------------------------------
%
%Input : (1) img1: the first image being compared
%        (2) img2: the second image being compared
%        (3) K: constants in the SSIM index formula (see the above
%            reference). defualt value: K = [0.01 0.03]
%        (4) window: local window for statistics (see the above
%            reference). default widnow is Gaussian given by
%            window = fspecial('gaussian', 11, 1.5);
%        (5) L: dynamic range of the images. default: L = 255
%
%Output: (1) mssim: the mean SSIM index value between 2 images.
%            If one of the images being compared is regarded as
%            perfect quality, then mssim can be considered as the
%            quality measure of the other image.
%            If img1 = img2, then mssim = 1.
%        (2) ssim_map: the SSIM index map of the test image. The map
%            has a smaller size than the input images. The actual size:
%            size(img1) - size(window) + 1.
%
%Default Usage:
%   Given 2 test images img1 and img2, whose dynamic range is 0-255
%
%   [mssim ssim_map] = ssim_index(img1, img2);
%
%Advanced Usage:
%   User defined parameters. For example
%
%   K = [0.05 0.05];
%   window = ones(8);
%   L = 100;
%   [mssim ssim_map] = ssim_index(img1, img2, K, window, L);
%
%See the results:
%
%   mssim                        %Gives the mssim value
%   imshow(max(0, ssim_map).^4)  %Shows the SSIM index map
%
%========================================================================

if (nargin < 2 | nargin > 5)
   mssim = -Inf;
   ssim_map = -Inf;
   return;
end

if (size(img1) ~= size(img2))
   mssim = -Inf;
   ssim_map = -Inf;
   return;
end

[M N] = size(img1);

if (nargin == 2)
   if ((M < 11) | (N < 11))
	   mssim = -Inf;
	   ssim_map = -Inf;
      return
   end
   window = fspecial('gaussian', 11, 1.5);	%
   K(1) = 0.01;								      % default settings
   K(2) = 0.03;								      %
   L = 255;                                  %
end

if (nargin == 3)
   if ((M < 11) | (N < 11))
	   mssim = -Inf;
	   ssim_map = -Inf;
      return
   end
   window = fspecial('gaussian', 11, 1.5);
   L = 255;
   if (length(K) == 2)
      if (K(1) < 0 | K(2) < 0)
		   mssim = -Inf;
   		ssim_map = -Inf;
	   	return;
      end
   else
	   mssim = -Inf;
   	ssim_map = -Inf;
	   return;
   end
end

if (nargin == 4)
   [H W] = size(window);
   if ((H*W) < 4 | (H > M) | (W > N))
	   mssim = -Inf;
	   ssim_map = -Inf;
      return
   end
   L = 255;
   if (length(K) == 2)
      if (K(1) < 0 | K(2) < 0)
		   mssim = -Inf;
   		ssim_map = -Inf;
	   	return;
      end
   else
	   mssim = -Inf;
   	ssim_map = -Inf;
	   return;
   end
end

if (nargin == 5)
   [H W] = size(window);
   if ((H*W) < 4 | (H > M) | (W > N))
	   mssim = -Inf;
	   ssim_map = -Inf;
      return
   end
   if (length(K) == 2)
      if (K(1) < 0 | K(2) < 0)
		   mssim = -Inf;
   		ssim_map = -Inf;
	   	return;
      end
   else
	   mssim = -Inf;
   	ssim_map = -Inf;
	   return;
   end
end

C1 = (K(1)*L)^2;
C2 = (K(2)*L)^2;
window = window/sum(sum(window));
img1 = double(img1);
img2 = double(img2);

mu1   = filter2(window, img1, 'valid');
mu2   = filter2(window, img2, 'valid');
mu1_sq = mu1.*mu1;
mu2_sq = mu2.*mu2;
mu1_mu2 = mu1.*mu2;
sigma1_sq = filter2(window, img1.*img1, 'valid') - mu1_sq;
sigma2_sq = filter2(window, img2.*img2, 'valid') - mu2_sq;
sigma12 = filter2(window, img1.*img2, 'valid') - mu1_mu2;

if (C1 > 0 & C2 > 0)
   ssim_map = ((2*mu1_mu2 + C1).*(2*sigma12 + C2))./((mu1_sq + mu2_sq + C1).*(sigma1_sq + sigma2_sq + C2));
else
   numerator1 = 2*mu1_mu2 + C1;
   numerator2 = 2*sigma12 + C2;
	denominator1 = mu1_sq + mu2_sq + C1;
   denominator2 = sigma1_sq + sigma2_sq + C2;
   ssim_map = ones(size(mu1));
   index = (denominator1.*denominator2 > 0);
   ssim_map(index) = (numerator1(index).*numerator2(index))./(denominator1(index).*denominator2(index));
   index = (denominator1 ~= 0) & (denominator2 == 0);
   ssim_map(index) = numerator1(index)./denominator1(index);
end

mssim = mean2(ssim_map);

return


function mv = mv_ampsSubplots(mv, sz, runs, subtractMeans)
%
% mv = mv_ampsSubplots([mv], [sz], [runs], [subtractMeans=0]);
%
% Plot amplitude response vectors for each condition in a
% separate subplot for comparison.
%
% If sz = [rows cols] is provided, will arrange the subplots in the
% sepcified number of subplots. Otherwise, arranges the subplots
% in an approximately square array.
%
% If runs is provided, only computes mv_amps for those runs. Otherwise
% uses all runs.
%
% subtractMeans is a flag to remove the mean response across conditions
% for each voxel (as in Haxby et al., 2001). Default is 0.
%
% ras, 01/2007.
if notDefined('mv'),    mv = get(gcf, 'UserData');      end
if notDefined('sz'),    sz = [];                        end
if notDefined('runs'),  runs = unique(mv.trials.run);   end
if notDefined('subtractMeans'),	subtractMeans = 0;		end

amps = mv_amps(mv, runs);
nVoxels = size(amps, 1);
nConds = size(amps, 2);
sel = find(tc_selectedConds(mv));

if subtractMeans==1
	amps = amps - repmat(nanmean(amps, 2), [1 nConds]);
end

if checkfields(mv, 'ui', 'fig')
	delete(findobj('Parent', mv.ui.fig, 'Type', 'axes'));
end

% compute an order of axes to plot
if ~isempty(sz)
    if length(sz)==2
        nRows = sz(1);
        nCols = sz(2);
    elseif length(sz)==nConds
        % explicit specify axes order
    end
else
    nRows = ceil(sqrt(nConds));
    nCols = ceil(nConds/nRows);
end

ysz = [min(amps(:)) max(amps(:))];

% plot
for c = 1:nConds
    hax(c) = subplot(nRows, nCols, c);

    mv_sparkline(1:nVoxels, amps(:,c), ysz);

    if c == ((nRows-1)*nCols + 1) % lower left-hand corner
        axis on
        xlabel('Voxels', 'FontName', mv.params.font);
        ylabel('% Signal', 'FontName', mv.params.font);
        axis tight
    end
    title(mv.trials.condNames{sel(c)}, 'FontName', mv.params.font, ...
          'FontSize', mv.params.fontsz);
end
normAxes;

axes( hax( (nRows-1)*nCols + 1 ) );
% tuftify;

return


function varargout = sampleinthist(varargin)
% VL_SAMPLINTHIST  Sample integral histogram
%   HISTS = VL_SAMPLINTHIST(INTHIST, BOXES) samples the integral
%   histogram INTHIST to obtain the histograms of the specified
%   BOXES.
%
%   INTHIST is a MxNxK array, where M x N are ``spatial'' dimensions,
%   and K is the number of histogram bins. INTHIST may be of class
%   UINT32 or DOUBLE.
%
%   Each box is a four dimensional vector [IMIN JMIN IMAX JMAX]' of
%   class UINT32 and correspond to the index set [IMIN, IMAX] x [JMIN,
%   JMAX]. To specify an empty box, let IMIN > IMAX.
%
%   HISTS stores one histogram per column (one for each box) and has K
%   rows, one for each histogram bin. HIST is of the same class of
%   INTHIST.
%
%   See also: VL_INTHIST(), VL_IMINTEGRAL(), VL_HELP().
[varargout{1:nargout}] = vl_sampleinthist(varargin{:});


function mpe = find_mpe(engine, evidence, varargin)
% FIND_MPE Find the most probable explanation of the data (assignment to the hidden nodes)
% function mpe = find_mpe(engine, evidence,...)
%
% evidence{i} = [] if X(i) is hidden, and otherwise contains its observed value (scalar or column vector).
%
% The following optional arguments can be specified in the form of name/value pairs:
% [default value in brackets]
%
% soft    - a cell array of soft/virtual evidence;
%           soft{i} is a prob. distrib. over i's values, or [] [ cell(1,N) ]
%

bnet = bnet_from_engine(engine);
ns = bnet.node_sizes(:);
N = length(bnet.dag);

engine.evidence = evidence;

% set default params
exclude = [];
soft_evidence = cell(1,N);

% parse optional params
args = varargin;
nargs = length(args);
for i=1:2:nargs
  switch args{i},
   case 'soft',    soft_evidence = args{i+1};
   otherwise,
    error(['invalid argument name ' args{i}]);
  end
end
engine.maximize = 1;

onodes = find(~isemptycell(evidence));
hnodes = find(isemptycell(evidence));
pot_type = determine_pot_type(bnet, onodes);
 if strcmp(pot_type, 'cg')
  check_for_cd_arcs(onodes, bnet.cnodes, bnet.dag);
end

hard_nodes = 1:N;
soft_nodes = find(~isemptycell(soft_evidence));
S = length(soft_nodes);
if S > 0
  assert(pot_type == 'd');
  assert(mysubset(soft_nodes, bnet.dnodes));
end

% Evaluate CPDs with evidence, and convert to potentials
pot = cell(1, N+S);
for n=1:N
  fam = family(bnet.dag, n);
  e = bnet.equiv_class(n);
  if isempty(bnet.CPD{e})
    error(['must define CPD ' num2str(e)])
  else
    pot{n} = convert_to_pot(bnet.CPD{e}, pot_type, fam(:), evidence);
  end
end

for i=1:S
  n = soft_nodes(i);
  pot{N+i} = dpot(n, ns(n), soft_evidence{n});
end
clqs = engine.clq_ass_to_node([hard_nodes soft_nodes]);

[clpot, seppot] = init_pot(engine, clqs, pot, pot_type, onodes);
[clpot, seppot] = collect_evidence(engine, clpot, seppot);
mpe = find_max_config(engine, clpot, seppot, evidence); % instead of distribute evidence


function percentCorrect = prtEvalPercentCorrect(classifier,dataSet,nFolds)
% prtEvalPercentCorrect    Calculate percent correct of a classification operation
%
%   percentCorrect = prtEvalPercentCorrect(prtClassifier, prtDataSet)
%   returns the percentage of correctly classified elements of prtDataSet
%   when classifier by prtClassifier. prtDataSet must be a labeled,
%   prtDataSetStandard object. prtClassifier must be a prtClass object.
%
%   percentCorrect = prtEvalPercentCorrect(prtClassifier, prtDataSet,
%   nFolds)  returns the percentage of correctly classified elements of
%   prtDataSet when classifier by prtClassifier with K-fold
%   cross-validation. prtDataSet must be a labeled, prtDataSetStandard
%   object. prtClassifier must be a prtClass object. nFolds is the number
%   of folds in the K-fold cross-validation.
%
%   percentCorrect = prtEvalPercentCorrect(prtClassifier, prtDataSet,
%   xValInds) same as above, but use crossValidation with specified indices
%   instead of random folds.
%
%   Example:
%   dataSet = prtDataGenSpiral;
%   classifier = prtClassDlrt;
%   pc =  prtEvalPercentCorrect(classifier, dataSet)
%
%   See Also: prtEvalPdAtPf, prtEvalPfAtPd, prtEvalAuc,
%   prtEvalMinCost

if nargin < 3 || isempty(nFolds)
    nFolds = 1;
end
results = prtUtilEvalParseAndRun(classifier,dataSet,nFolds);

%(note: can't check results.nFeatures here any more...)
if dataSet.nClasses == 2 %binary classifier
    [pf,pd] = prtScoreRoc(results.getObservations,dataSet.getTargets);
    pe = prtUtilPfPd2Pe(pf,pd);
    minPe = min(pe);
    percentCorrect = 1-minPe;
else
    %Note, this is a hack; we need to fix this.
    if isa(classifier,'prtAlgorithm')
        guess = results.getObservations;
    else
        if classifier.includesDecision
            guess = results.getObservations;
        else
           %Naive MAP decision:
           % [twiddle,guess] = max(results.getObservations,[],2); %#ok<ASGLU>
           %Naive MAP decision:
           prtMap = prtDecisionMap;
           prtMap = train(prtMap,results);
           results = prtMap.run(results);
           guess = results.getObservations;
        end
    end
    percentCorrect = prtScorePercentCorrect(guess,dataSet.getTargets);
    %confusionMatrix = prtScoreConfusionMatrix(guess,dataSet.getTargets);
    %percentCorrect = prtUtilConfusion2PercentCorrect(confusionMatrix);
end


function [bar] = kPa2bar(kPa)
% Convert pressure from kilopascals to bar.  It's interesting how we tend
% to say "bar" as the plural for "bar".  I've heard people say "millibars"
% but I've also heard "millibar" as its plural.  The same does not seem to
% be true for other units of pressure.  We'd say "5 atmospheres".  For some
% reason, I often hear people talk about singular form of animals as their
% plural, too.  Of course there's deer and fish, but I'm not talking about
% those.  I've actually heard people say "Look at those alpaca" or "we saw
% some bear" or "There are lots of squirrel out today".  Strange.
% Chad A. Greene 2012
bar = kPa/100;


function add1 = cfg_example_add1
% Example script that creates an cfg_exbranch to sum two numbers. The
% inputs are entered as two single numbers, the output is just a single
% number.
%
% This code is part of a batch job configuration system for MATLAB. See
%      help matlabbatch
% for a general overview.
%_______________________________________________________________________
% Copyright (C) 2007 Freiburg Brain Imaging

% Volkmar Glauche
% $Id: cfg_example_add1.m 1716 2008-05-23 08:18:45Z volkmar $

rev = '$Rev: 1716 $'; %#ok

%% Input Items
% Input a
input1         = cfg_entry; % This is the generic data entry item
input1.name    = 'Input a'; % The displayed name
input1.tag     = 'a';       % The name appearing in the harvested job structure. This name must be unique among all items in the val field of the superior node
input1.strtype = 'e';       % No restriction on what type of data is entered. This could be used to restrict input to real numbers, integers ...
input1.num     = [1 1];     % Number of inputs required (2D-array with exactly one row and one column)
input1.help    = {'This is input a.','This input will be added to the other input.'}; % help text displayed

% Input b
input2         = cfg_entry; % This is the generic data entry item
input2.name    = 'Input b'; % The displayed name
input2.tag     = 'b';       % The name appearing in the harvested job structure. This name must be unique among all items in the val field of the superior node
input2.strtype = 'e';       % No restriction on what type of data is entered. This could be used to restrict input to real numbers, integers ...
input2.num     = [1 1];     % Number of inputs required (2D-array with exactly one row and one column)
input2.help    = {'This is input b.','This input will be added to the other input.'}; % help text displayed

%% Executable Branch
add1      = cfg_exbranch;       % This is the branch that has information about how to run this module
add1.name = 'Add1';             % The display name
add1.tag  = 'cfg_example_add1'; % The name appearing in the harvested job structure. This name must be unique among all items in the val field of the superior node
add1.val  = {input1 input2};    % The items that belong to this branch. All items must be filled before this branch can run or produce virtual outputs
add1.prog = @cfg_example_run_add1;  % A function handle that will be called with the harvested job to run the computation
add1.vout = @cfg_example_vout_add1; % A function handle that will be called with the harvested job to determine virtual outputs
add1.help = {'Add two numbers.'};

%% Local Functions
% The cfg_example_vout_add1 function can go here, it is not useful outside
% the batch environment.
function vout = cfg_example_vout_add1(job)
% Determine what outputs will be present if this job is run. In this case,
% the structure of the inputs is fixed, and the output is always a single
% number. Note that input items may not be numbers, they can also be
% dependencies.

vout = cfg_dep;                        % The dependency object
vout.sname      = 'Add1: a + b';       % Displayed dependency name
vout.src_output = substruct('()',{1}); % The output subscript reference. This could be any reference into the output variable created during computation


function [iout] = center_crop(im,a,b)

[w,h,~] = size(im);
c1 = w-a-(w-a)/2;
c2 = h-b-(h-b)/2;
iout = im(c1+1:c1+a,c2+1:c2+b,:);

end


function hdr = mayo2nifti1(ohdr,mat)
% Convert from an ANALYZE to a NIFTI-1 header
% _______________________________________________________________________
% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging

%
% $Id$

if isfield(ohdr,'magic'),
    hdr = ohdr;
    return;
end;
hdr            = empty_hdr;
hdr.dim        = ohdr.dim;
hdr.datatype   = ohdr.datatype;
hdr.bitpix     = ohdr.bitpix;
hdr.pixdim     = ohdr.pixdim;
hdr.vox_offset = ohdr.vox_offset;
hdr.scl_slope  = ohdr.roi_scale;
hdr.scl_inter  = ohdr.funused1;
hdr.descrip    = ohdr.descrip;
hdr.aux_file   = ohdr.aux_file;
hdr.glmax      = ohdr.glmax;
hdr.glmin      = ohdr.glmin;
hdr.cal_max    = ohdr.cal_max;
hdr.cal_min    = ohdr.cal_min;
hdr.magic      = 'ni1';

switch hdr.datatype,
case 130, hdr.datatype = 256; %  int8
case 132, hdr.datatype = 512; % uint16
case 136, hdr.datatype = 768; % uint32
end;

if nargin<2,
    % No mat, so create the equivalent from the hdr...
    if any(ohdr.origin(1:3)), origin = double(ohdr.origin(1:3));
    else                      origin = (double(ohdr.dim(2:4))+1)/2; end;
    vox    = double(ohdr.pixdim(2:4));
    if vox(1)<0,
        % Assume FSL orientation
        flp    = 0;
    else
        % Assume SPM or proper Analyze
        flp    = spm_flip_analyze_images;
    end;
    if all(vox == 0), vox = [1 1 1]; end;
    off    = -vox.*origin;
    mat    = [vox(1) 0 0 off(1) ; 0 vox(2) 0 off(2) ; 0 0 vox(3) off(3) ; 0 0 0 1];
    if flp,
        %disp(['Assuming that image is stored left-handed']);
        mat = diag([-1 1 1 1])*mat;
    else
        %disp(['Assuming that image is stored right-handed']);
    end;
end;

hdr            = encode_qform0(mat,hdr);
mat            = mat*[eye(4,3) [1 1 1 1]'];
hdr.srow_x     = mat(1,:);
hdr.srow_y     = mat(2,:);
hdr.srow_z     = mat(3,:);
hdr.qform_code = 2;
hdr.sform_code = 2;
return;


function [map,textons] = computeTextons(fim,k)
% function [map,textons] = computeTextons(fim,k)

d = numel(fim);
n = numel(fim{1});
data = zeros(d,n);
for i = 1:d,
  data(i,:) = fim{i}(:)';
end

[map,textons] = kmeansML(k,data,'maxiter',30,'verbose',0);
[w,h] = size(fim{1});
map = reshape(map,w,h);


function [enhancedMag, enhancedWav] = RunLogMMSE(noisyFile, fs, isFile)
addpath('../../../../Enhancement/Loizou/MATLAB_code/statistical_based');

w = warning ('off','all');
if isFile
    noisyFile = ExtractWordsFromString_v2(noisyFile);
    noisyFile = noisyFile{1};
    % [enhancedWav, fs] = logmmse_vectorize(noisyFile);
    [enhancedWav, fs] = logmmse(noisyFile, [], isFile);
else
    [enhancedWav] = logmmse(noisyFile, fs, isFile);
end

if fs==16000
    fftlen = 512;
else
    fftlen = 256;
end

[~,enhancedMag] = wav2abs_multi(enhancedWav, fs, 0.01, 0.025, fftlen);
enhancedMag = 2*log(abs(enhancedMag(1:fftlen/2+1,:)));

end


clear; close all; clc; dbstop if error;

%--------------------------------------------------------------------------
% This demo process the data from the RIT Target Detection Blind Test
% contest which is located at: http://dirsapps.cis.rit.edu/blindtest/
% To use this file, you select a target detection algorithm and a target to
% find and then the script runs the algorithm and outputs the data into the
% outputDir.  Two files are outputted, a .img and a .hdr. You upload these
% files to the RIT website and they are automatically scored.
%--------------------------------------------------------------------------
% Parameters
inputFilename = 'data\blind_test\HyMap\blind_test_refl.img';
fasticaToolboxPath = '..\matlab_hyperspectral_toolbox\trunk\FastICA_25';
targetFilenames = {'data\blind_test\SPL\F5\F5_f.txt'};
outputDir = 'RIT Data Results';
% See switch statement for algorithm choices
algorithm = 'ace'
%algorithm = 'rmf-sum';
%algorithm = 'plmf'
%algorithm = 'matchedFilter';
%algorithm = 'sam'
%--------------------------------------------------------------------------

addpath('gmm');

addpath(fasticaToolboxPath);
mkdir(outputDir);

% Read in the data
w = 280;
h = 800;
p = 126;
M = multibandread(inputFilename, [w h p], 'int16', 0, 'bil', 'ieee-le')/1e4;
lData = hyperGetHymapWavelengthsNm();

% Read in target signatures
[sig1, lSig] = hyperGetEnviSignature(targetFilenames{1});

% Get signature from data for comparison
fsig1 = squeeze(M(122,495,:));
%sig1 = fsig1;

% Resample data to commone wavelength set
desiredLambdas = lData;
sig1 = squeeze(hyperResample(sig1, lSig, desiredLambdas));
figure; plot(sig1); grid on; title('Signature 1');
    xlabel('Wavelength [nm]'); ylabel('Reflectance [%]');
    hold on; plot(fsig1, '--');
    legend('Recorded', 'From Image');

goodBands = 1:p; %[3:63 69:93 98:123];

% Image sharpening
if 0
    ff = fspecial('unsharp',0.2);
    for k=1:p
        M(:,:,k) = imfilter(M(:,:,k),ff,'same');
        M(:,:,k) = imfilter(M(:,:,k),ff,'same');
        %M(:,:,k) = imfilter(M(:,:,k),ff,'same');
    end
end

figure; imagesc(M(:,:,40)); axis image; colormap(gray);

% Try to discover in-situ to lab kernel.
% TODO
% sub(:,1) = M(144,515,:);
% sub(:,2) = M(144,516,:);
% sub(:,3) = M(144,517,:);
% sub(:,4) = M(145,515,:);
% sub(:,5) = M(145,516,:);
% sub(:,6) = M(145,517,:);
% sub(:,7) = M(146,515,:);
% sub(:,8) = M(146,516,:);
% sub(:,9) = M(146,517,:);
%
% alpha = pinv(sub)*sig1; %alpha = alpha ./ sum(alpha(:));
% err = sub*alpha - sig1; err = err - mean(err); badBands = find(abs(err)>0.02);
% goodBands = setxor(1:p,badBands);
% figure; plot(err); hold on; plot(sig1,'.'); plot(fsig1,'.-'); hold off; grid on;
%     legend({'err','lab sig','in situ sig'})
% alpha = reshape(alpha,3,3);
% figure; imagesc(alpha);
%
% for k=1:p
%     %M(:,:,p) = conv2(M(:,:,p),alpha,'same');
% end

% Emperical dervied
goodBands = [3     4     5     6     7     8     9    10    11    12    14    15    16    17    18 ...
    19    20    22    23    24    26    28    29    31    32    33    34    35    36    37 ...
    38    39    40    41    42    43    44    45    46    49    51    52    53    54    55 ...
    56    57    58    59    60    61    62    66    69    70    71    72    86    87    88 ...
    89    90    91    92    93    96    97    98    99   100   101   102   103   104   105 ...
   106   107   108   109   110   111   112   113   115   116   117   119   120   121   122];
%sig1 = squeeze(hyperResample(sig1, lSig, desiredLambdas));
figure; plot(sig1(goodBands)); grid on; title('Signature 1 - good bands only');
    xlabel('Wavelength [nm]'); ylabel('Reflectance [%]');
    hold on; plot(fsig1(goodBands), '--');
    legend('Recorded', 'From Image');

% Display data
M = hyperConvert2d(M);
%[M, H, snr] = hyperMnf(M, w, h);
M_pct = hyperPct(M, 3);
M_pct = hyperNormalize(hyperConvert3d(M_pct,w,h,3));
figure; imagesc(M_pct); axis image; title('Scene');

% Data conditioning
M = M(goodBands, :);
sig1 = sig1(goodBands);
%fsig1 = fsig1(goodBands);
%sig1 = fsig1;

%q = hyperHfcVd(M);

% Do PCT
if 0
    M = [M sig1];
    %[M,V] = hyperPct(M,size(M,1));
    [M,V] = hyperPct(M,55);
    sig1 = M(:,end);
    M = M(:,1:end-1);
    p = size(M,1);
    goodBands = 1:p;
end

%q = hyperHfcVd(M);
q = 39;

algorithm = lower(algorithm);
tic
switch algorithm
    case 'ica-eea'
        [U, X] = hyperIcaEea(M, 50, sig1);
        r = X(1,:);
        r = hyperConvert3d(r, w, h, 1);
    case 'rx'
        r = hyperConvert3d(hyperRxDetector(M), w, h, 1);
    case 'matchedfilter'
        r = hyperConvert3d(hyperMatchedFilter(M, sig1), w, h, 1);
    case 'ace'
        r = hyperConvert3d(hyperAce(M, sig1), w, h, 1);
    case 'mace'
        r = hyperConvert3d(hyperMace(M, sig1), w, h, 1);
    case 'sid'
        r = hyperConvert3d(hyperSid(M, sig1), w, h, 1);
    case 'cem'
        r = hyperConvert3d(hyperCem(M, sig1), w, h, 1);
    case 'plmf'
        r = hyperPlmf(hyperConvert3d(M,w,h,p),sig1,9);
    case 'rmf-sum'
        r = hyperRmf(hyperConvert3d(M,w,h,p),sig1,11,'sum');
    case 'rmf-meanlocal'
        r = hyperRmf(hyperConvert3d(M,w,h,p),sig1,11,'meanLocal');
    case 'rmf-meangloballocal'
        r = hyperRmf(hyperConvert3d(M,w,h,p),sig1,11,'meanGlobalLocal');
    case 'glrt'
        r = hyperConvert3d(hyperGlrt(M, sig1), w, h, 1);
    case 'osp'
        U = hyperAtgp(M, q, sig1);
        r = hyperConvert3d(hyperOsp(M, U, sig1), w, h, 1);
    case 'amsd'
        r = hyperConvert3d(hyperAmsd(M, U, sig1), w, h, 1);
    case 'hud'
        U = hyperAtgp(M, q, sig1);
        r = hyperConvert3d(hyperHud(M, U, sig1), w, h, 1);
    case 'nnls'
        U = hyperAtgp(M, q, sig1);
        r = hyperConvert3d(hyperNnls(M,U),w,h,q);
        r = r(:,:,1);
    case 'fcls'
        U = hyperAtgp(M, q, sig1);
        r = hyperConvert3d(hyperFcls(M,U),w,h,q);
        r = r(:,:,1);
    case 'ucls'
        U = hyperAtgp(M, q, sig1);
        r = hyperConvert3d(hyperUcls(M,U),w,h,q);
        r = r(:,:,1);
    case 'sam'
        r = (1./(eps+hyperConvert3d(hyperSam(M, sig1), w, h, 1)));
    otherwise
        error('Incorrect algorithm name specified!\n');
end
toc

% Display results and write to file
figure; imagesc(r); axis image; colorbar;
    title(algorithm);

[a,b]=sort(r(:),'descend');
tmp = a(1:20);
figure; plot(tmp./tmp(1)); grid on;
[x, y, val] = hyperMax2d(r);

% d1 = r(122,494)
% d2 = r(127,490)
% N = prod(size(r));
% [v] = sort(r(:),'ascend');
% idx = find(v==d2);
% N-idx
% figure; hist(r(:),100);

tmp = (hyperNormalize(r)*2^10);
multibandwrite(tmp, sprintf('%s\\results.img', outputDir), 'bil', 'PRECISION', 'int16', 'MACHFMT', 'ieee-le');

[pd,fa] = hyperRoc(r);
figure; plot(fa,pd,'.'); grid on; title(sprintf('%s\n%s',algorithm, targetFilenames{1}));


fprintf('All results should be zero\n');
pochhammer(5.6,0)
pochhammer(1e4,3) - 27.63132109093154778328
pochhammer(1e4,1e3) - 9258.70469397627827724045
pochhammer(1e5,3) - 34.538806394660688260
pochhammer(1e6,3) - 41.44653467389032232
pochhammer(0.1,100) - 357.3415591371226056543663


filename='CantileverBeam_Triangle_Linear_Fine';
ptype = 'MACRO';
method = 'SIMPALL';
materialType = 'ISOTROPIC';
initial_case = 'full';
cost = {'compliance';'perimeter'};
weights = [1 0.1];
constraint = {'volumeConstraint'};
optimizer = 'PROJECTED GRADIENT';
incrementFactor = 1;
designVariable = 'Density';
filterType = 'P1';

nsteps = 5;
Vfrac_final = 0.5;
Perimeter_target=1;
optimality_final =1e-3;
constr_final =1e-3;

Vfrac_initial = 1;
optimality_initial = 1e-3;
constr_initial = 1e-3;

TOL.rho_plus = 1;
TOL.rho_minus = 0;
TOL.E_plus = 1;
TOL.E_minus = 1e-3;
TOL.nu_plus = 1/3;
TOL.nu_minus = 1/3;


function [oz] = yd32oz(yd3)
% Convert volume from cubic yards to US liquid ounces.
% Chad Greene 2012
oz = yd3*25852.675324;


function lambdas = hessianspectrum(problem, x, usepreconstr, storedb, key)
% Returns the eigenvalues of the (preconditioned) Hessian at x.
%
% function lambdas = hessianspectrum(problem, x)
% function lambdas = hessianspectrum(problem, x, useprecon)
% function lambdas = hessianspectrum(problem, x, useprecon, storedb)
% function lambdas = hessianspectrum(problem, x, useprecon, storedb, key)
%
% If useprecon is not set, or if it is set to 'noprecon' (default), this
% computes and returns the eigenvalues of the Hessian operator (which needs
% to be symmetric but not necessarily definite) on the tangent space at x.
% There are problem.M.dim() eigenvalues. Matlab's eigs is used internally.
%
% If useprecon is set to 'precon', the eigenvalues of the composition of
% the Hessian with the preconditioner at x are computed: Precon o Hessian.
% The preconditioner must have been defined in the problem structure and
% has to be symmetric, positive definite. It is supposed to approximate the
% inverse of the (Riemannian) Hessian. Ideally, the preconditioned Hessian
% is better conditioned (smaller ratio of largest to smallest eigenvalue in
% magnitude) than the non-preconditioned spectrum. The present tool can
% help assess that.
%
% The typical ways to define a preconditioner are via problem.precon or
% problem.sqrtprecon (see comment below). These should be function handles
% with the same input/output system as problem.hess for the Hessian.
%
% If the Hessian is not available from the problem structure, an
% approximate Hessian will be used. There are no guarantees of
% interpretability, but this may nevertheless be useful at times.
%
% Even though the Hessian and the preconditioner are both symmetric, their
% composition is not symmetric. This can slow down the call to 'eigs'
% substantially. If possible, you may specify the square root of the
% preconditioner in the problem structure, as sqrtprecon. This operator on
% the tangent space at x must also be symmetric, positive definite, and
% such that SqrtPrecon o SqrtPrecon = Precon. Then, the spectrum of the
% symmetric operator SqrtPrecon o Hessian o SqrtPrecon is computed: it is
% the same as the spectrum of Precon o Hessian, but is usually faster to
% compute. If both Precon and SqrtPrecon are provided, only SqrtPrecon will
% be used.
%
% The input and the output of the Hessian and of the preconditioner are
% projected on the tangent space to avoid undesired contributions of the
% ambient space.
%
% storedb is a StoreDB object, key is the StoreDB key to point x.
%
% Requires the manifold description in problem.M to have these functions:
%
%   u_vec = vec(x, u_mat) :
%       Returns a column vector representation of the normal (usually
%       matrix) representation of the tangent vector u_mat. vec must be an
%       isometry between the tangent space (with its Riemannian metric) and
%       a subspace of R^n where n = length(u_vec), with the 2-norm on R^n.
%       In other words: it is an orthogonal projector.
%
%   u_mat = mat(x, u_vec) :
%       The inverse of vec (its adjoint).
%
%   u_mat_clean = tangent(x, u_mat) :
%       Subtracts from the tangent vector u_mat any component that would
%       make it "not really tangent", by projection.
%
%   answer = vecmatareisometries() :
%       Returns true if the linear maps encoded by vec and mat are
%       isometries, false otherwise. It is better if the answer is yes.
%
% See also: hessianextreme canGetPrecon canGetSqrtPrecon

% This file is part of Manopt: www.manopt.org.
% Original author: Nicolas Boumal, July 3, 2013.
% Contributors:
% Change log:
%
%   Dec. 18, 2014 (NB):
%       The lambdas are now sorted when they are returned.
%
%   April 3, 2015 (NB):
%       Works with the new StoreDB class system.
%       Does no longer accept sqrtprecon as an input: the square root of
%       the preconditioner may now be specified directly in the problem
%       structure, following the same syntax as the preconditioner precon.
%
%   April 4, 2015 (NB):
%       By default, the spectrum is computed without the preconditioner's
%       effect, even if it is available. A new input option allows to
%       switch this behavior without the need to change the problem
%       structure.

    % Allow omission of the key, and even of storedb.
    if ~exist('key', 'var')
        if ~exist('storedb', 'var')
            storedb = StoreDB();
        end
        key = storedb.getNewKey();
    end

    % Manage the option to use or not use a preconditioner.
    % The input is a string. It is here transformed into a Boolean.
    if ~exist('usepreconstr', 'var') || isempty(usepreconstr)
        usepreconstr = 'noprecon';
    end
    switch lower(usepreconstr)
        case 'noprecon'
            useprecon = false;
        case 'precon'
            useprecon = true;
        otherwise
            % A bit of legacy code heads up.
            if isa(usepreconstr, 'function_handle')
                warning('manopt:hessianspectrum:oldsyntax', ...
                        ['This function no longer expects sqrtprecon ' ...
                         'as input. Place it in the problem structure.']);
            end
            error('Input useprecon must be either ''precon'' or ''noprecon''.');
    end

    % No warning if an approximate Hessian is available, as then the user
    % is presumably aware of what they are doing.
    if ~canGetHessian(problem) && ~canGetApproxHessian(problem)
        warning('manopt:hessianspectrum:nohessian', ...
                ['The Hessian appears to be unavailable.\n' ...
                 'Will try to use an approximate Hessian instead.\n'...
                 'Since this approximation may not be linear or '...
                 'symmetric,\nthe computation might fail and the '...
                 'results (if any)\nmight make no sense.']);
    end

    vec = @(u_mat) problem.M.vec(x, u_mat);
    mat = @(u_vec) problem.M.mat(x, u_vec);
    tgt = @(u_mat) problem.M.tangent(x, u_mat);

    % n: size of a vectorized tangent vector
    % dim: dimension of the tangent space
    % necessarily, n >= dim.
    % The vectorized operators we build below will have at least n - dim
    % zero eigenvalues.
    n = length(vec(problem.M.zerovec(x)));
    dim = problem.M.dim();

    % It is usually a good idea to force a gradient computation to make
    % sure precomputable things are precomputed.
    if canGetGradient(problem)
        [unused1, unused2] = getCostGrad(problem, x, storedb, key); %#ok
    end

    hess = @(u_mat) tgt(getHessian(problem, x, tgt(u_mat), storedb, key));
    hess_vec = @(u_vec) vec(hess(mat(u_vec)));

    % Regardless of preconditioning, we can only have a symmetric
    % eigenvalue problem if the vec/mat pair of the manifold is an
    % isometry:
    vec_mat_are_isometries = problem.M.vecmatareisometries();

    if ~useprecon

        % No preconditioner to use: simply use the Hessian as is.

        eigs_opts.issym = vec_mat_are_isometries;
        eigs_opts.isreal = true;
        lambdas = eigs(hess_vec, n, dim, 'LM', eigs_opts);

    elseif canGetSqrtPrecon(problem)

        % There is a preconditioner, and we have its square root: deal with
        % the symmetric composition SqrtPrecon o Hessian o SqrtPrecon.

        sqrtprec = @(u_mat) tgt(getSqrtPrecon(problem, x, tgt(u_mat), storedb, key));
        sqrtprec_vec = @(u_vec) vec(sqrtprec(mat(u_vec)));

        eigs_opts.issym = vec_mat_are_isometries;
        eigs_opts.isreal = true;
        lambdas = eigs(@(u_vec) ...
                      sqrtprec_vec(hess_vec(sqrtprec_vec(u_vec))), ...
                      n, dim, 'LM', eigs_opts);

    elseif canGetPrecon(problem)

        % There is a preconditioner, but we don't have its square root:
        % deal with the non-symmetric composition Precon o Hessian.

        prec = @(u_mat) tgt(getPrecon(problem, x, tgt(u_mat), storedb, key));
        prec_vec = @(u_vec) vec(prec(mat(u_vec)));
        % prec_inv_vec = @(u_vec) pcg(prec_vec, u_vec);

        eigs_opts.issym = false;
        eigs_opts.isreal = true;
        lambdas = eigs(@(u_vec) prec_vec(hess_vec(u_vec)), ...
                       n, dim, 'LM', eigs_opts);

    else

        error('No preconditioner is available in the problem structure.');

    end

    lambdas = sort(lambdas);

end


% Authors: A. Iscen, G. Tolias, Y. Avrithis, T. Furon, O. Chum. 2017.
% create image and feature ids for features of an image collection
% [image_ids, feature_ids] = imgfeatids (nof)
% nof: Nx1 vector with number of features per image
% image_ids: Mx1 image id per feature. M = sum(nof)
% feautre_ids: Mx1 unique feature ids
function [image_ids, feature_ids] = imgfeatids (nof)

% image ids for each database descriptor
cs = cumsum(double (nof));
[~, image_ids] = histc (1: cs (end), [1 cs+1]); %image ids here

% to create feature ids
feature_ids = 1:sum (nof);
rng = cs (1) + 1: length (feature_ids); %range such that values of first image are left unchanged
feature_ids (rng) = feature_ids (rng) - cs ( image_ids (rng) - 1); % subtract number of features of previous images such that fids becomes number of feature id per image


function hFig = view_mri_histogram( MriFile )
% VIEW_MRI_HISTOGRAM: Compute and view the histogram of a brainstorm MRI.
%
% USAGE:  hFig = view_mri_histogram( MriFile );
%
% INPUT:
%    - MriFile : Full path to a brainstorm MRI file
% OUTPUT:
%    - hFig    : Matlab handle to the figure where the histogram is displayed
% @=============================================================================
% This function is part of the Brainstorm software:
% https://neuroimage.usc.edu/brainstorm
%
% Copyright (c) University of Southern California & McGill University
% This software is distributed under the terms of the GNU General Public License
% as published by the Free Software Foundation. Further details on the GPLv3
% license can be found at http://www.gnu.org/copyleft/gpl.html.
%
% FOR RESEARCH PURPOSES ONLY. THE SOFTWARE IS PROVIDED "AS IS," AND THE
% UNIVERSITY OF SOUTHERN CALIFORNIA AND ITS COLLABORATORS DO NOT MAKE ANY
% WARRANTY, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, NOR DO THEY ASSUME ANY
% LIABILITY OR RESPONSIBILITY FOR THE USE OF THIS SOFTWARE.
%
% For more information type "brainstorm license" at command prompt.
% =============================================================================@
%
% Authors: Francois Tadel, 2006-2020

%% ===== COMPUTE HISTOGRAM =====
% Display progress bar
bst_progress('start', 'View MRI historgram', 'Computing histogram...');
% Load full MRI
MRI = load(MriFile);
% Compute histogram
Histogram = mri_histogram(MRI.Cube(:,:,:,1));
% Save histogram
s.Histogram = Histogram;
bst_save(MriFile, s, 'v7', 1);

%% ===== DISPLAY HISTOGRAM =====
% Create figure
hFig = figure('Name',        'MRI Histogram', ...
              'Color',        get(0,'defaultUicontrolBackgroundColor'), ...
              'Pointer',      'arrow', ...
              'NumberTitle',  'off', ...
              'DockControls', 'off', ...
              'Menubar',      'none', ...
              'Toolbar',      'figure');
% Adapt figure size
figPos = get(hFig, 'Position');
set(hFig, 'Position', figPos+[0 0 20 40]);
% Get maximum value
maxVal = max(cat(1,Histogram.max.y));
% If a maximum value was found, used this value to limit the Y axis
if (maxVal<1)
    maxVal = max(Histogram.smoothFncY);
end
bar(Histogram.fncX + 0.5, Histogram.fncY);
% White background
hWndComponents = get(hFig, 'Children');
i = 1;
while (~isequal(get(hWndComponents(i), 'Type'), 'axes') && (i <= length(hWndComponents)))
    i = i + 1;
end
if (i > length(hWndComponents))
    return;
end
hAxes = hWndComponents(i);
set(hAxes, 'Color', [1 1 1]);
hold on;
% Plot all the curves
plot(Histogram.smoothFncX +0.5, Histogram.smoothFncY, 'r');
plot(Histogram.fncX + 0.5, Histogram.cumulFncY .* maxVal.*1.2, 'g');
plot(cat(1,Histogram.max.x), cat(1,Histogram.max.y), 'r^', 'MarkerFaceColor', 'r', 'MarkerSize', 7);
plot(cat(1,Histogram.min.x), cat(1,Histogram.min.y), 'rv', 'MarkerFaceColor', 'g', 'MarkerSize', 7);
% Define axis labels and limits
xlabel('Intensity value');
ylabel('Number of voxels');
yLimits = [0 maxVal*1.3];
ylim(yLimits);
% Display background and white matter thresholds
line([Histogram.bgLevel, Histogram.bgLevel], yLimits, 'Color','b');
line([Histogram.whiteLevel, Histogram.whiteLevel], yLimits, 'Color','y');
h = legend('MRI hist.','Smoothed hist.','Cumulative hist.','Maxima','Minima',...
    'Scalp or grey thresh.','White m thresh.');
set(h, 'FontSize',  bst_get('FigFont'), ...
       'FontUnits', 'points');

% Hide progress bar
bst_progress('stop');


function ekg_filt(up)
%EKG_FILT extracts respiratory signals using various filtering techniques
% from the ECG signal as specified in PC's literature review.
%	            ekg_filt(option, up)
%
%	Inputs:
%		option          the option which has led to this function being used
%       up              universal parameters structure
%
%	Outputs:
%       ...
%

fprintf('\n--- Extracting Respiratory Signals using Filtering Techniques ');
log_int_respSig = 0;             % Has value 1 unless this is a final respiratory signal

for subj = up.paramSet.subj_list

    %% Cycle through each method
    for filt_no = 1 : length(up.al.options.ekg_filt)

        %% Skip if this processing has been done previously
        eval(['save_name = ''ekg', up.paths.filenames.filt '_' up.al.options.ekg_filt{filt_no} ''';']);
        iden_resp_sig_file_ending
        savepath = [up.paths.data_save_folder, num2str(subj), ending];
        exist_log = check_exists(savepath, save_name);
        if exist_log
            continue
        end

        %% Load relevant data
        if ~exist('data', 'var')
            load([up.paths.data_load_folder, up.paths.data_load_filename]);
        end
        % Extract EKG data
        rel_data = data(subj).ekg;
        rel_data.fs = data(subj).ekg.fs;

        %% Filter the raw signal using this method
        respWave = feval(up.al.options.ekg_filt{filt_no}, rel_data, up);

        %% Band-pass filter
        filtered_data = bpf_signal_to_remove_non_resp_freqs(respWave, respWave.fs, up);
        eval([save_name ' = filtered_data;']);

        %% Save processed data
        save_or_append_data
    end

end

end


% GRADIENT STEP function.
% Computes the cost and gradient of the neural network for unrolled theta parameters.
function [J gradients] = nn_gradient_step(nn_params_unrolled, layers, X, y, lambda)
    % Reshape nn_params back into the matrix parameters.
    nn_params = nn_params_roll(nn_params_unrolled, layers);

    % Compute the cost.
    J = nn_cost_function(nn_params, layers, X, y, lambda);

    % Do backpropagation.
    gradients = nn_backpropagation(nn_params, layers, X, y, lambda);
end


function check = half_normal_check ( a, b )

%*****************************************************************************80
%
%% HALF_NORMAL_CHECK checks the parameters of the Half Normal PDF.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    12 September 2004
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, real A, B, the parameters of the PDF.
%    0.0 < B.
%
%    Output, logical CHECK, is true if the parameters are legal.
%
  if ( b <= 0.0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'HALF_NORMAL_CHECK - Fatal error!\n' );
    fprintf ( 1, '  B <= 0.\n' );
    error ( 'HALF_NORMAL_CHECK - Fatal error!' );
  end

  check = 1;

  return
end


function f=idtwfbreal(c,par,varargin)
%IDTWFBREAL Inverse Dual-tree Filterbank for real-valued signals
%   Usage:  f=idtwfbreal(c,info);
%           f=idtwfbreal(c,dualwt,Ls);
%
%   Input parameters:
%         c           : Input coefficients.
%         info        : Transform params. struct
%         dualwt      : Dual-tree Wavelet Filterbank definition
%         Ls          : Length of the reconstructed signal.
%
%   Output parameters:
%         f     : Reconstructed data.
%
%   `f = idtwfbreal(c,info)` reconstructs real-valued signal *f* from the
%   coefficients *c* using parameters from `info` struct. both returned by
%   |dtwfbreal| function.
%
%   `f = idtwfbreal(c,dualwt,Ls)` reconstructs real-valued signal *f* from the
%   coefficients *c* using dual-tree filterbank defined by `dualwt`. Plese
%   see |dtwfbreal| for supported formats. The *Ls* parameter is mandatory
%   due to the ambiguity of reconstruction lengths introduced by the
%   subsampling operation.
%   Note that the same flag as in the |dtwfbreal| function have to be used,
%   otherwise perfect reconstruction cannot be obtained. Please see help
%   for |dtwfbreal| for description of the flags.
%
%   Examples:
%   ---------
%
%   A simple example showing perfect reconstruction using |idtwfbreal|:::
%
%      f = gspi;
%      J = 7;
%      wtdef = {'qshift3',J};
%      c = dtwfbreal(f,wtdef);
%      fhat = idtwfbreal(c,wtdef,length(f));
%      % The following should give (almost) zero
%      norm(f-fhat)
%
%   See also: dtwfbreal dtwfbinit

complainif_notenoughargs(nargin,2,'IDTWFBREAL');

if(~iscell(c))
   error('%s: Unrecognized coefficient format.',upper(mfilename));
end

if(isstruct(par)&&isfield(par,'fname'))
   complainif_toomanyargs(nargin,2,'IDTWFBREAL');

   if ~strcmpi(par.fname,'dtwfbreal')
      error(['%s: Wrong func name in info struct. ',...
             ' The info parameter was created by %s.'],...
             upper(mfilename),par.fname);
   end

   dtw = dtwfbinit({'dual',par.wt},par.fOrder);
   Ls = par.Ls;
   ext = 'per';
   L = wfbtlength(Ls,dtw,ext);
else
   complainif_notenoughargs(nargin,3,'IDTWFBREAL');

   %% PARSE INPUT
   definput.keyvals.Ls=[];
   definput.keyvals.dim=1;
   definput.import = {'wfbtcommon'};

   [flags,kv,Ls]=ltfatarghelper({'Ls'},definput,varargin);
   complainif_notposint(Ls,'Ls');

   ext = 'per';
   % Initialize the wavelet tree structure
   dtw = dtwfbinit(par,flags.forder);

   [Lc,L]=wfbtclength(Ls,dtw,ext);

   % Do a sanity check
   if ~isequal(Lc,cellfun(@(cEl) size(cEl,1),c))
      error(['%s: The coefficient subband lengths do not comply with the'...
             ' signal length *Ls*.'],upper(mfilename));
   end
end

%% ----- step 3 : Run computation
[nodesBF, rangeLoc, rangeOut] = treeBFranges(dtw,'rev');
outLengths = nodesInLen(nodesBF,L,strcmpi(ext,'per'),dtw);
outLengths(end) = L;

f = comp_idtwfb(c,dtw.nodes(nodesBF),dtw.dualnodes(nodesBF),outLengths,...
                rangeLoc,rangeOut,ext,0);
f = postpad(f,Ls);


% Homogeneous Propagation Medium Example
%
% This example provides a simple demonstration of using k-Wave for the
% simulation and detection of the pressure field generated by an initial
% pressure distribution within a two-dimensional homogeneous propagation
% medium.
%
% author: Bradley Treeby
% date: 29th June 2009
% last update: 17th October 2011
%
% This function is part of the k-Wave Toolbox (http://www.k-wave.org)
% Copyright (C) 2009-2014 Bradley Treeby and Ben Cox

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

clear all;

% =========================================================================
% SIMULATION
% =========================================================================

% create the computational grid
Nx = 128;           % number of grid points in the x (row) direction
Ny = 128;           % number of grid points in the y (column) direction
dx = 0.1e-3;        % grid point spacing in the x direction [m]
dy = 0.1e-3;        % grid point spacing in the y direction [m]
kgrid = makeGrid(Nx, dx, Ny, dy);

% define the properties of the propagation medium
medium.sound_speed = 1500;  % [m/s]
medium.alpha_coeff = 0.75;  % [dB/(MHz^y cm)]
medium.alpha_power = 1.5;

% create initial pressure distribution using makeDisc
disc_magnitude = 5; % [Pa]
disc_x_pos = 50;    % [grid points]
disc_y_pos = 50;    % [grid points]
disc_radius = 8;    % [grid points]
disc_1 = disc_magnitude*makeDisc(Nx, Ny, disc_x_pos, disc_y_pos, disc_radius);

disc_magnitude = 3; % [Pa]
disc_x_pos = 80;    % [grid points]
disc_y_pos = 60;    % [grid points]
disc_radius = 5;    % [grid points]
disc_2 = disc_magnitude*makeDisc(Nx, Ny, disc_x_pos, disc_y_pos, disc_radius);

source.p0 = disc_1 + disc_2;

% define a centered circular sensor
sensor_radius = 4e-3;   % [m]
num_sensor_points = 50;
sensor.mask = makeCartCircle(sensor_radius, num_sensor_points);

% run the simulation
sensor_data = kspaceFirstOrder2D(kgrid, medium, source, sensor);

% =========================================================================
% VISUALISATION
% =========================================================================

% plot the initial pressure and sensor distribution
figure;
imagesc(kgrid.y_vec*1e3, kgrid.x_vec*1e3, source.p0 + cart2grid(kgrid, sensor.mask), [-1 1]);
colormap(getColorMap);
ylabel('x-position [mm]');
xlabel('y-position [mm]');
axis image;

% plot the simulated sensor data
figure;
imagesc(sensor_data, [-1, 1]);
colormap(getColorMap);
ylabel('Sensor Position');
xlabel('Time Step');
colorbar;


function a = i4_to_a ( i )

%*****************************************************************************80
%
%% I4_TO_A returns the I-th alphabetic character.
%
%  Example:
%
%    I   A
%
%   -8  ' '
%    0  ' '
%    1  'A'
%    2  'B'
%   ..
%   26  'Z'
%   27  'a'
%   52  'z'
%   53  ' '
%   99  ' '
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    02 May 2004
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer I, the index of the letter to be returned.
%    0 is a space;
%    1 through 26 requests 'A' through 'Z', (ASCII 65:90);
%    27 through 52 requests 'a' through 'z', (ASCII 97:122);
%
%    Output, character A, the requested alphabetic letter.
%
  if ( i <= 0 )
    a = ' ';
  elseif ( 1 <= i & i <= 26 )
    a = 'A' + i - 1;
  elseif ( 27 <= i & i <= 52 )
    a = 'a' + i - 27;
  else
    a = ' ';
  end

  return
end


function Power = actuatorPower(States, Actuators, Phase)
% function Power = actuatorPower(States, Actuators, Phase)
%
% Computer Generated File -- DO NOT EDIT
%
% This function was created by the function Write_Power()
% 13-Dec-2013 11:41:00
%
%  ARGUMENTS:
%   States = [Nstate x Ntime] matrix of states
%   Actuator = [Nactuator x Ntime] matrix of actuator values
%   Phase = {'D','F','S1',S2'} or omit.
%       Since the ankle torques are acting against the ground, they should
%       be set to zero when a given leg is in flight. If Phase is included,
%       then this function will force these inputs to be zero. If it is
%       ommitted, then it is assumed that the user has done that error
%       checking.
%
%  RETURNS:
%   Power = a struct with fields for each actuator:
%       leg one (linear force actuator)
%       leg two (linear force actuator)
%       ankle one (torque actuator)
%       ankle two (torque actuator)
%       hip (torque from leg one on leg two
%
%
% Matthew Kelly
% Cornell University
%

%
% See also DERIVE_EOM
x0 = States(:,1); % (m) Hip horizontal position
y0 = States(:,2); % (m) Hip vertical position
x1 = States(:,3); % (m) Foot One horizontal position
y1 = States(:,4); % (m) Foot One vertical position
x2 = States(:,5); % (m) Foot Two horizontal position
y2 = States(:,6); % (m) Foot Two vertical position
dx0 = States(:,7); % (m/s) Hip horizontal velocity
dy0 = States(:,8); % (m/s) Hip vertical velocity
dx1 = States(:,9); % (m/s) Foot One horizontal velocity
dy1 = States(:,10); % (m/s) Foot One vertical velocity
dx2 = States(:,11); % (m/s) Foot Two horizontal velocity
dy2 = States(:,12); % (m/s) Foot Two vertical velocity

if nargin==2
    Phase = '';
end

F1 = Actuators(:,1); % (N) Compresive axial force in Leg One
F2 = Actuators(:,2); % (N) Compresive axial force in Leg Two
if strcmp(Phase,'F') || strcmp(Phase, 'S2')
    T1 = zeros(size(Actuators,1),1); %Foot One not in contact with ground!
else
    T1 = Actuators(:,3); % (Nm) External torque applied to Leg One
end
if strcmp(Phase,'F') || strcmp(Phase, 'S1')
    T2 = zeros(size(Actuators,1),1); %Foot Two not in contact with ground!
else
    T2 = Actuators(:,4); % (Nm) External torque applied to Leg Two
end
Thip = Actuators(:,5); % (Nm) Torque acting on Leg Two from Leg One

% Intermediate Calculations
L1 = ((x0 - x1).^2 + (y0 - y1).^2).^(1./2);
L2 = ((x0 - x2).^2 + (y0 - y2).^2).^(1./2);
dL1 = ((dx0 - dx1).*(x0 - x1) + (dy0 - dy1).*(y0 - y1))./L1;
dL2 = ((dx0 - dx2).*(x0 - x2) + (dy0 - dy2).*(y0 - y2))./L2;
% th1 = atan2(x1 - x0, y1 - y0);
% th2 = atan2(x2 - x0, y2 - y0);
dth1 = -((dy0 - dy1).*(x0 - x1) - (dx0 - dx1).*(y0 - y1))./L1.^2;
dth2 = -((dy0 - dy2).*(x0 - x2) - (dx0 - dx2).*(y0 - y2))./L2.^2;

Power.legOne = F1.*dL1;
Power.legTwo = F2.*dL2;
Power.ankleOne = T1.*dth1;
Power.ankleTwo = T2.*dth2;
Power.hip = -Thip.*(dth1 - dth2);

end


function [B,L,N,P] = gp_bwboundaries(BW,CONN)
  % GP_BWBOUNDARIES Find boundaries of regions and holes in a logical image
  %
  % B = gp_bwboundaries(BW)
  % [B,L,N] = gp_bwboundaries(BW,CONN)
  %
  % Inputs:
  %   BW  h by w logical BWage
  % Outputs:
  %   B  cell array containing where each element B{b} contains a #B{c} by 2
  %     list of row and column indices of pixels in the bth boundary
  %   L  h by w BWage of ids of regions and holes (0 for "unlabeled" false
  %     pixels touching the border)
  %   N  number of regions (first N elements of B are regions, the rest are
  %     "holes")
  %
  % See also: gp_bwlabel
  %

  if nargin<2
    CONN = 8;
  end

  A4 = fd_laplacian(size(BW))~=0;
  A8 = ((A4*1*A4)>1) + A4;
  A = {[],[]};
  switch CONN
  case 4
    A{1} = A8;
    A{2} = A4;
  case 8
    A{1} = A4;
    A{2} = A8;
  end

  LN = gp_bwlabel(BW);
  LP = gp_bwlabel(~BW);
  % Combine
  L = LN + (LN==0).*(LP+max(LN(:)));

  % BFS from outside
  O = reshape(full(sparse([2:size(BW,1)-1 1:size(BW,1):numel(BW)-size(BW,1) size(BW,1):size(BW,1):numel(BW) numel(BW)-size(BW,1)+1:numel(BW)-1],1,1)),size(BW));

  K = {O&BW,false(size(BW))};
  outside = [];
  inside = [];

  outside = union(outside,setdiff(unique(L.*O.*~BW),0));

  while true
    G = ismember(L,union(inside,outside));
    %BWshow(G);
    %pause
    K{1} = K{1} | (reshape((A{1}*1*G(:))~=0,size(BW)) & BW & ~G);
    %BWshow(matrixnormalize(K{1}-K{2}))
    %pause
    inside = union(inside,setdiff(unique(L.*(K{1}|K{2})),0));
    if isempty(setdiff(L,union(inside,outside)))
      break;
    end
    G = ismember(L,union(inside,outside));
    K{2} = K{2} | (reshape((A{2}*1*G(:))~=0,size(BW)) & ~G);
    outside = setdiff(union(outside,L.*((~BW & reshape((A{1}*1*G(:))~=0,size(BW))))),0);
    %BWshow(matrixnormalize(K{1}-K{2}))
    %pause
    if isempty(setdiff(L,union(inside,outside)))
      break;
    end
  end

  B = {{},{}};
  for c = 1:max(L(:))
    for e = 1:2
      BWc = K{e} & L==c;
      [Lc,ncc] = gp_bwlabel(BWc,8);
      for cc = 1:ncc
        BWcc = Lc == cc;
        % Super inefficient search
        Acc = A{3-e};
        Acc(~BWcc,:) = 0;
        Acc(:,~BWcc) = 0;
        Acc = Acc - diag(diag(Acc));
        [s,t] = find(Acc,1,'first');
        P = [];
        p = s;
        while sum(Acc(:))>0
          P = [P;p];
          Acc(p,:) = 0;
          [~,p] = max(Acc(:,p));
        end
        [LI,LJ] = ind2sub(size(BW),P);
        if ~isempty(LI)
          %
          B{e} = {B{e}{:} [LI([1:end 1]) LJ([1:end 1])]}';
        end
      end
    end
  end
  N = numel(B{1});
  B = {B{1}{:} B{2}{:}}';

  L = L.*~ismember(L,L.*(O&~BW));
  [~,~,L] = unique(L);
  L = reshape(L,size(BW));

end


function [MatingPool,offspringLoc] = MatingSelection(B,s)
% The mating selection of EAG-MOEA/D

%------------------------------- Copyright --------------------------------
% Copyright (c) 2023 BIMK Group. You are free to use the PlatEMO for
% research purposes. All publications which use this platform or any code
% in the platform should acknowledge the use of "PlatEMO" and reference "Ye
% Tian, Ran Cheng, Xingyi Zhang, and Yaochu Jin, PlatEMO: A MATLAB platform
% for evolutionary multi-objective optimization [educational forum], IEEE
% Computational Intelligence Magazine, 2017, 12(4): 73-87".
%--------------------------------------------------------------------------

    [N,T] = size(B);

    %% Select N subproblems by roulette-wheel selection
    S = sum(s,2) + 1e-6;
    D = S./sum(S) + 0.002;
    D = D./sum(D);
    offspringLoc = RouletteWheelSelection(N,1./D);

    %% Select two parents in each selected subproblem
    MatingPool = zeros(1,2*N);
    for i = 1 : N
        MatingPool([i,i+N]) = B(offspringLoc(i),randperm(T,2));
    end
end


function [y] = crossprodw(x, w)

% expand, compute cross-product and whiten
y = w*crossprod(x);


function calc_bootfitrms_a2(a,time,timef,bootloops,maepi)
    % function calc_bootfitrms_a2(a,time,timef,bootloops,maepi);
    % --------------------------------------------------
    % Plots Ncum observed vs. Ncum modeled for specified time windows
    %
    % Input variables:
    % a         : earthquake catalog
    % time      : learning period fo fit Omori parameters
    % timef     : forecast period
    % bootloops : Number of bootstraps
    % maepi     : mainshock

    % S.Neukomm/ S.Wiemer / J.Woessner
    % last update: 04.08.03

report_this_filefun(mfilename('fullpath'));
    % Surpress warnings from fmincon
    warning off;

    %[m_main, main] = max(a.Magnitude);
    date_matlab = datenum(a.Date.Year,a.Date.Month,a.Date.Day,a.Date.Hour,a.Date.Minute,zeros(size(a,1),1));
    date_main = datenum(floor(maepi(3)),maepi(4),maepi(5),maepi(8),maepi(9),0);
    time_aftershock = date_matlab-date_main;

    % Select biggest aftershock earliest in time, but more than 1 day after mainshock
    fDay = 1;
    ft_c=fDay/365; % Time not considered to find biggest aftershock
    vSel = (a.Date > maepi(:,3)+ft_c & a.Date<= maepi(:,3)+time/365);
    mCat = a.subset(vSel);
    vSel = mCat(:,6) == max(mCat(:,6));
    vBigAf = mCat(vSel,:)
    if length(mCat(:,1)) > 1
        vSel = vBigAf(:,3) == min(vBigAf(:,3));
        vBigAf = vBigAf(vSel,:);
    end

    date_biga = datenum(floor(vBigAf(3)),vBigAf(4),vBigAf(5),vBigAf(8),vBigAf(9),0);
    fT1 = date_biga - date_main; % Time of big aftershock

    % Aftershock times
    l = time_aftershock(:) > 0;
    tas = time_aftershock(l);
    eqcatalogue = a.subset(l);

    l = tas <= time;
    time_as=tas(l);

    % Calculate uncertainty and mean values of p,c,and k
    %[pval, pstd, cval, cstd, kval, kstd, loopout] = brutebootloglike_a2(tas(l),bootloops,fT1)
    % Calculate p,c,k for dataset
    nMod = 1;
    %nMod = 2
    if nMod == 1

        [pval1, pval2, cval1, cval2, kval1, kval2] = bruteforcerms_a2(time_as,fT1,nMod)

        pval1 = round(100*pval1)/100;
        cval1 = round(100*cval1)/100;
        kval1 = round(10*kval1)/10;
        kval2 = round(10*kval2)/10;

    else
        [pval1, pval2, cval1, cval2, kval1, kval2] = bruteforcerms_a2(time_as,fT1,nMod)
        pval1 = round(100*pval1)/100;
        pval2 = round(100*pval2)/100;
        cval1 = round(100*cval1)/100;
        cval2 = round(100*cval2)/100;
        kval1 = round(10*kval1)/10;
        kval2 = round(10*kval2)/10;
    end

    if (isnan(pval1) == 0 & isnan(pval2) == 0)

        figure_w_normalized_uicontrolunits('Numbertitle','off','Name','Forecast aftershock occurence')
        %     pval1 = 0.9;
        %     pval2 = 0.9;
        %     cval1 = 0.2;
        %     cval2 = 0.2;
        %     kval1 = 1000;
        %     kval2 = 2000;
        %loopout = [loopout , loopout(:,1)*0];

        %     % Times up to the forecast time
        %     lf = tas <= time+timef ;
        %     time_asf= [tas(lf) ];
        %     time_asf=sort(time_asf);
        %

        %
        %     % Compute the confidence limits
        %     for j = 1:length(loopout(:,1));
        %
        %         cumnr = (1:length(time_asf))'; cumnr_model = [];
        %         pvalb = loopout(j,1);
        %         cvalb = loopout(j,2);
        %         kvalb = loopout(j,3);
        %         for i=1:length(time_asf)
        %             if pval ~= 1
        %                 cm = kvalb/(pvalb-1)*(cvalb^(1-pvalb)-(time_asf(i)+cvalb)^(1-pvalb));
        %             else
        %                 cm = kvalb*log(time_asf(i)/cvalb+1);
        %             end
        %             cumnr_model = [cumnr_model; cm];
        %         end
        %         plot(time_asf,cumnr_model,'color',[0.8 0.8 0.8]);
        %         loopout(j,4) = max(cumnr_model);
        %         hold on
        %         %drawnow
        %     end
        %     % 2nd moment of bootstrap number of forecasted number of events
        %     fStdBst = calc_StdDev(loopout(:,4));
        %
        %     % now plot the forecast ...
        %     cumnrf = (1:length(time_asf))'; cumnr_modelf = [];
        %     for i=1:length(time_asf)
        %         if pval ~= 1
        %             cm = kval/(pval-1)*(cval^(1-pval)-(time_asf(i)+cval)^(1-pval));
        %         else
        %             cm = kval*log(time_asf(i)/cval+1);
        %         end
        %         cumnr_modelf = [cumnr_modelf; cm];
        %     end
        %     pf1 =  plot(time_asf,cumnr_modelf,'g-.','Linewidth',2);
        %     hold on
        %     pf2 =  plot(time_asf,cumnrf, 'b-','Linewidth',2);
        %
        % plot the best fit
        % Cumulative number of pbserved events
        cumnr = (1:length(tas))';
        cumnr_model = [];

        for i=1:length(tas)
            if tas(i) <= fT1
                if pval1 ~= 1
                    cm = kval1/(pval1-1)*(cval1^(1-pval1)-(tas(i)+cval1)^(1-pval1));
                else
                    cm = kval1*log(tas(i)/cval1+1);
                end
                cumnr_model = [cumnr_model; cm];
            else
                if (pval1 ~= 1 & pval2 ~= 1)
                    cm = kval1/(pval1-1)*(cval1^(1-pval1)-(tas(i)+cval1)^(1-pval1))+ kval2/(pval2-1)*(cval2^(1-pval2)-(tas(i)-fT1+cval2)^(1-pval2));
                else
                    cm = kval1*log(tas(i)/cval1+1) + kval2*log((tas(i)-fT1)/cval2+1);
                end
                cumnr_model = [cumnr_model; cm];
            end
        end
        tas=sort(tas);
        cumnr_model=sort(cumnr_model);
        p1 = plot(tas,cumnr_model,'r','Linewidth',2);
        hold on

        p2 = plot(tas,cumnr,'b','Linewidth',2,'Linestyle','--');
        %     string=['p = ' num2str(pval) '+-' num2str(pstd) '; c = ' num2str(cval) '+-' num2str(cstd) '; k = ' num2str(kval) '+-' num2str(kstd)];
        %     title(string)
        %
        %     % Plot observed events in forecast period from endpoint of modeled events in learning period
        %     vSel = time_asf >= max(time_as);
        %     vCumnr_forecast = cumnrf(vSel,:);
        %     vTime_forecast = time_asf(vSel,:);
        %     % Difference of modelled and observed number of events at time_as
        %     fDiff_timeas = cumnr_modelf(length(time_as))-cumnrf(length(time_as));
        %     vCumnr_forecast = vCumnr_forecast+fDiff_timeas;
        %     pf3 = plot(vTime_forecast, vCumnr_forecast,'m-.','Linewidth',2);
        %
        %
        % %     [Y, in] = sort(loopout(:,4));
        % %     %n5Conf = round(0.05*length(loopout))
        % %     %Y = find(in == n5Conf);
        % %     %Y = find(in == 5);
        % %     loops = loopout(in,:);
        % %     n5Conf = floor(min((find(round(loops(:,4))==round(prctile(loops(:,4),5))))));
        % %     %n5Conf = round(0.05*length(loops));
        % %     pvalb = loops(n5Conf,1);
        % %     cvalb = loops(n5Conf,2);
        % %     kvalb = loops(n5Conf,3);
        % %
        % %     cumnr = (1:length(time_as))'; cumnr_model = [];
        % %     for i=1:length(time_as)
        % %         if pval ~= 1
        % %             cm = kvalb/(pvalb-1)*(cvalb^(1-pvalb)-(time_as(i)+cvalb)^(1-pvalb));
        % %         else
        % %             cm = kvalb*log(time_as(i)/cvalb+1);
        % %         end
        % %         cumnr_model = [cumnr_model; cm];
        % %     end
        % %
        % %     %plot(time_as,cumnr_model,'k--','Linewidth',1);
        % %
        % %     %n95Conf = round(0.95*length(loopout));
        % %     %Y = find(in == n95Conf);
        % %     %loops = loopout(in,:);
        % %     n95Conf = ceil(max(find(round(loops(:,4))==round(prctile(loops(:,4),95)))));
        % %     %n95Conf = round(0.95*length(loops));
        % %     pvalb = loops(n95Conf,1);
        % %     cvalb = loops(n95Conf,2);
        % %     kvalb = loops(n95Conf,3);
        % %     cumnr = (1:length(time_as))'; cumnr_model = [];
        % %     for i=1:length(time_as)
        % %         if pval ~= 1
        % %             cm = kvalb/(pvalb-1)*(cvalb^(1-pvalb)-(time_as(i)+cvalb)^(1-pvalb));
        % %         else
        % %             cm = kvalb*log(time_as(i)/cvalb+1);
        % %         end
        % %         cumnr_model = [cumnr_model; cm];
        % %     end
        % %     %pc = plot(time_as,cumnr_model,'k--','Linewidth',1);
        %
        %     xlabel('Time [days]')
        %     ylabel('Cumulative number of aftershocks')
        %     xlim([0 max(time_asf)]);
        %
        %
        %     % calculate uncertainty sigma in forecasted number of aftershocks by
        %     % error propagation law
        %     time1 = time+timef;
        %     if pval == 1
        %         pv = 1-10^(-6);
        %     else
        %         pv = pval;
        %     end
        %     mpm1 = 1-pv;
        %     t1c = time1+cval;
        %     t0c = time+cval;
        %     sigma = (((-t1c^mpm1+t0c^mpm1)/(pv-1)*kstd)^2+...
        %         (kval/(pv-1)*(-t1c^mpm1*mpm1/t1c+t0c^mpm1*mpm1/t0c)*cstd)^2+...
        %         (kval/(pv-1)*(t1c^mpm1*log(t1c)+t1c^mpm1/(pv-1)-t0c^mpm1*log(t0c)-t0c^mpm1/(pv-1))*pstd)^2)^0.5;
        %     % Plot standard deviation error propagation law
        %     ps1=errorbar(max(time_asf),max(cumnr_modelf),sigma,sigma);
        %     set(ps1,'Linewidth',4,'Color',[0 1 0])
        %     % Plot standard deviation from bootstrap
        %     ps2=errorbar(max(time_asf),max(cumnr_modelf),fStdBst,fStdBst);
        %     set(ps2,'Linewidth',2,'Color',[1 0 0])
        %
        %     legend([p2 p1 pf1 pf3 min(ps1) min(ps2)],'data','model','forecast','observed','\sigma (Epl)','\sigma (Bst)',0)
        %
        %     % Title
        %     % Rate change from error propagation law
        %     % Find amount of events in forecast period for modeled data
        %     nummod = max(cumnr_modelf)-cumnr_modelf(length(time_as));
        %     % Find amount of  events in forecast period for observed data
        %     l = time_asf <=time+timef & time_asf > time;
        %     numreal = sum(l); % observed number of aftershocks
        %     fRc_Flaw = (numreal-nummod)/sigma;
        %     fRc_Bst = (numreal-nummod)/fStdBst;
        %     string=['p = ' num2str(pval) '+-' num2str(pstd) '; c = ' num2str(cval) '+-' num2str(cstd) '; k = ' num2str(kval) '+-' num2str(kstd)];
        %     title(string)
        %     string=['\sigma(Epl) = ' num2str(sigma) '; \sigma(Bst) = ' num2str(fStdBst)];
        %     text(0.25,100,string)
        %     % Set line for learning period
        %     yy = get(gca,'ylim');
        %     plot([max(time_as) max(time_as)],[0 yy(2)],'k-.')
    else
        disp('no result')
    end


function model = circulant_rand(d)
% random circulant embedding
% d dim of feature
% model.r  circulant vector from gaussian distribution
% model.bernoulli random bernoulli vector for sign flipping

    model.r = randn(d,1);
    rr = randn(1,d);
    rr(rr > 0) = 1;
    rr(rr <= 0 ) = -1;
    model.bernoulli = rr;
end


function ebsd = calcParentEBSD(job)
% reconstruct parent EBSD
%
% Syntax
%   job.calcParentEBSD
%
% Input
%  job - @parentGrainReconstructor
%
% Output
%  ebsd - reconstructed parent @EBSD
%

% copy prior EBSD
ebsd = job.ebsdPrior;

% find Ids of grains that are either parent or child phase
isRecData = ebsd.phaseId == job.childPhaseId | ...
  ebsd.phaseId == job.parentPhaseId;

% compute new grainIds
ebsd.grainId(ebsd.grainId>0) = job.mergeId(ebsd.grainId(ebsd.grainId>0));

grainIds = max(1,ebsd.grainId);
grainIds(~isRecData) = 1;

% consider only child pixels that have been reconstructed to parent
% grains
isNowParent = ebsd.phaseId == job.childPhaseId &...
  job.grains.phaseId(grainIds) == job.parentPhaseId;

% maybe there is nothing to do
if nnz(isNowParent) == 0, return; end

% compute parent orientation
[ori,fit] = calcParent(ebsd(isNowParent).orientations,...
  job.grains(ebsd.grainId(isNowParent)).meanOrientation,job.p2c);

% compute variantId
vId = calcVariantId(ori, ebsd(isNowParent).orientations,job.p2c);
ebsd.prop.variantId = NaN(size(ebsd));
ebsd.prop.variantId(isNowParent) = vId;

% adjust parent and child orientations such that the misorientation is
% closest to the given OR job.p2c
ori = ori.project2FundamentalRegion .* inv(variants(job.p2c,vId)) * job.p2c;

% setup parent ebsd
ebsd.prop.fit = nan(size(ebsd));
ebsd(isNowParent).orientations = ori;
ebsd.prop.fit(isNowParent) = fit;

end


function [y] = spm_gx_hdm_sck(x,u,P,M)
% Simulated BOLD response to input.
% FORMAT [y] = spm_gx_hdm_sck(x,u,P,M)
% y    - BOLD response (%)
% x    - state vector     (see spm_fx_fmri)
% P    - Parameter vector (see spm_fx_fmri)
%__________________________________________________________________________
%
% This function implements the BOLD signal model described in:
%
% Stephan KE, Weiskopf N, Drysdale PM, Robinson PA, Friston KJ (2007)
% Comparing hemodynamic models with DCM. NeuroImage 38: 387-401.
%__________________________________________________________________________
% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging

% Karl Friston & Klaas Enno Stephan
% $Id: spm_gx_hdm_sck.m 6263 2014-11-17 13:48:36Z karl $

% biophysical constants for 1.5 T:
%==========================================================================

% echo time (seconds)
%--------------------------------------------------------------------------
try
    TE = M(1).TE;
catch
    TE = 0.04;
end

% resting venous volume
%--------------------------------------------------------------------------
V0    = 100*0.08;

% slope r0 of intravascular relaxation rate R_iv as a function of oxygen
% saturation Y:  R_iv = r0*[(1-Y)-(1-Y0)]
%--------------------------------------------------------------------------
r0    = 25;

% frequency offset at the outer surface of magnetized vessels
%--------------------------------------------------------------------------
nu0   = 40.3;

% region-specific resting oxygen extraction fractions
%--------------------------------------------------------------------------
E0    = P(5,:);

% region-specific ratios of intra- to extravascular components of
% the gradient echo signal (prior mean = 1, log-normally distributed
% scaling factor)
%--------------------------------------------------------------------------
epsi  = exp(P(6,:));

% coefficients in BOLD signal model
%--------------------------------------------------------------------------
k1    = 4.3.*nu0.*E0.*TE;
k2    = epsi.*r0.*E0.*TE;
k3    = 1 - epsi;

% exponentiation of hemodynamic state variables
%--------------------------------------------------------------------------
x     = exp(x);

% BOLD signal
%--------------------------------------------------------------------------
v     = x(3,:);
q     = x(4,:);
y     = V0.*(k1.*(1 - q) + k2.*(1 - (q./v)) + k3.*(1 - v));


function tcm = spm_load_tcm(C)
% tcm = spm_load_tcm(C)
%
% Adapted from SPM function spm_load_priors(V)
% Load the local version of tissue correlation maps for segmentation,
% mainly getting the B-spline coefficients for subsequent sampling using
% B-spline interpolation.
%
% C: local TCM matrix (dim1 x dim2 x dim3 x K x K x 6, dim1~dim3 are same
% as the image size, K is number of tissue types, 6 means 6-neighborhood)
% tcm: a structure for TCM
%
% This function is intended to be used in conjunction with spm_sample_tcm.
% tcm = spm_load_tcm(C);
% C_slice = spm_sample_tcm(tcm,X,Y,Z);
%____________________________________________________________________________
%
% John Ashburner
% Yu (Andy) Huang, 2013-06-04

tiny = eps*eps; % 1e-3; % ANDY 2013-06-05

deg = 1;

% if ~isstruct(V), V  = spm_vol(V); end;
% spm_check_orientations(V);

% =========================NOTE!!!!!!=====================================
% TCM is saved as .mat file only (NOT as NIFTI file).
% Because if NIFTI, it'll have huge size. The header info is NOT needed as
% long as TCM is generated from the same dataset as TPM (then it's already in correct orientation)
% If the dataset that was used to generate TCM does NOT have same header
% info as the TPM NIFTI file, then this interpolation will NOT work
% properly for TCM.
% Therefore, TCM should be generated from the same dataset that was used to
% get TPM, at least header info should be same. % ANDY 2013-06-05
% =========================NOTE!!!!!!=====================================

% tpm.V = V;
% tpm.M = tpm.V(1).mat;

d = size(C);
% Kb = numel(tpm.V);
tcm.dat = cell(d(4:6));

% spm_progress_bar('Init',tpm.V(1).dim(3),'Loading priors','Planes loaded');
% for i=1:tpm.V(1).dim(3)
%     M         = spm_matrix([0 0 i]);
%     s         = zeros(tpm.V(1).dim(1:2));
%     for k1=1:Kb
%         tmp                = spm_slice_vol(tpm.V(k1),M,tpm.V(1).dim(1:2),0);
%         tpm.dat{k1}(:,:,i) = max(min(tmp,1),0);
%         s                  = s + tmp;
%     end;
%     t = s>1;
%     if any(t)
%         for k1=1:Kb
%             tmp           = tpm.dat{k1}(:,:,i);
%             tmp(t)        = tmp(t)./s(t); % normalize the loaded TPM
%             % eTPM.nii will be normalized here. Others (bTPM, cTPM, cTPMthresh) were normalized before loading.
%             tpm.dat{k1}(:,:,i) = tmp;
%         end;
%     end;
%     spm_progress_bar('Set',i);
% end;

tcm.bg1 = zeros(d(4:6));
tcm.bg2 = zeros(d(4:6));
for k=1:d(6)
    for j=1:d(5)
        for i=1:d(4)
            tcm.bg1(i,j,k) = mean(mean(C(:,:,1,i,j,k)));
            tcm.bg2(i,j,k) = mean(mean(C(:,:,end,i,j,k)));
            tcm.dat{i,j,k} = spm_bsplinc(log(C(:,:,:,i,j,k)+tiny),[deg deg deg  0 0 0]);
            % get B-spline coefficients for subsequent sampling using B-spline interpolation

%             tcm.dat{i,j,k} = spm_bsplinc(log(C(2:(end-1),2:(end-1),2:(end-1),i,j,k)+tiny),[deg deg deg  0 0 0]);
%             % here use the 2nd slice and the penultimate slice, because for TCM, it has edge effects, on the edges, some neighbors are not defined.
%             % therefore, edge slices are all discarded when computing B-spline coefficients % ANDY 2013-06-05
        end
    end
end

% tcm.tiny = tiny;
tcm.deg  = deg+1;
% spm_progress_bar('Clear');
return;


function [imgOut, L_wa] = YPWardGlobalTMO(img, Ld_max, maxLayers)
%
%       [imgOut, L_wa] = YPWardGlobalTMO(img, Ld_max, maxLayers)
%
%
%       Input:
%           -img: input HDR image
%           -Ld_max: maximum monitor LDR luminance in cd/m^2
%           -L_wa: world adpatation luminance in cd/m^2
%
%       Output
%           -imgOut: tone mapped image
%           -L_wa: luminance adaptation
%
%     Copyright (C) 2020 Francesco Banterle
%
%     This program is free software: you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation, either version 3 of the License, or
%     (at your option) any later version.
%
%     This program is distributed in the hope that it will be useful,
%     but WITHOUT ANY WARRANTY; without even the implied warranty of
%     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%     GNU General Public License for more details.
%
%     You should have received a copy of the GNU General Public License
%     along with this program.  If not, see <http://www.gnu.org/licenses/>.
%
%     This is the TumblinTMO with Yee and Pattanaik Luminance Adaptation;
%     see the file tmo/util/YeePattanaikLuminanceAdaptation.m
%

if(~exist('Ld_max', 'var'))
    Ld_max = 100;
end

if(~exist('maxLayers', 'var'))
    maxLayers = 32;
end

if(Ld_max <= 0.0)
    Ld_max = 100;
end

L_wa = YeePattanaikLuminanceAdaptation(img, maxLayers);

imgOut = WardGlobalTMO(img, Ld_max, L_wa);

end


% fastranc.m -  adaptive noise cancellation for fmrib_fastr.m
%   [out,y]=fmribanc(refs,d,N,mu)
%
%   Inputs:
%       refs: Reference data
%       d:   Input data
%       N:   filter order (length)
%       mu:  Step size
%
%   Outputs:
%       out: error signal (signal after noise cancellation)
%       y: filtered out noise
%
%   If a binary version of this program is present in same directory
%   it will be run instead.  The binary version is MUCH fastr.  However,
%   if it is not present or unavailable for your platform, you can use
%   the matlab compiler to compile the C Mex-File  fastranc.c by typing
%   >> mex fastranc.c
%   from your command line after you CD into the fmrib1.0 plugin directory.
%   This will create the appropriate binary file for your platform
%   (if you have the MATLAB compiler). You can check what binaries are
%   available by looking at the extention of the fastranc.* files:
%   fastranc.mexa64   -  Linux 64 bit (compiled on Xeon EM64T but might
%                          be the same for athalon 64)
%   fastranc.mexaxp   -  Alpha 64 processor,
%   fastranc.mexglx   -  Linux 32 bit processor.
%   fastranc.dll      -  Windows.
%
%   Check your matlab help for more info on compiling MEX files.
%
%
%   Author:  Rami K. Niazy
%
%   Copyright (c) 2004 University of Oxford

% Copyright (C) 2004 University of Oxford
% Author:   Rami K. Niazy, FMRIB Centre
%           rami@fmrib.ox.ac.uk
%
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 2 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program; if not, write to the Free Software
% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

function [out,y]=fastranc(refs,d,N,mu)

nargchk(4,4,nargin);
refs=refs(:);
d=d(:);
mANC=length(d);
if length(d)~=length(refs)
error('Reference and Input data must be of the same length','fmribanc() error!');
end

W=zeros(N+1,1);
r=flipud([0;refs(1:N)]);
out=zeros(mANC,1);
y=zeros(mANC,1);

for E=N+1:mANC

    %-----------------calc------------------------------------------

    r=[refs(E);r(1:end-1)];
    y(E)=sum(W.*r);
    out(E)=d(E)-y(E);
    W=W+2*mu*out(E)*r;

    %---------------------------------------------------------------
end
return;