function soln = particleSwarmOptimization(problem)
% soln = particleSwarmOptimization(problem)
%
% This function computes the solution to the optimization problem using
% particle swarm optimization
%
% INPUTS:
%   problem = struct that describes the optimization problem
%       .options.maxIter = number of iterations for the search
%       .options.populationCount = number of particles to use in search
%       .options.w = search parameter - damping
%       .options.pl = search paramter - local search
%       .options.pg = search parameter - global search
%       .xLow = [nDim, 1] = column vector for lower bound on initial search space
%       .xUpp = [nDim, 1] = column vector for upper bound on initial search space
%       .objFun = function handle:
%           f = objFun(x)
%               x = [nDim, nPop] = vectorized objective function
%               f = [1,nPop] = cost for each column in x
%
% OUTPUTS:
%   soln = output struct with solution and history log
%       .x = best point found
%       .f = objective function at best point found
%       .log = history of the search, used for plotting and analysis
%       .problem = copy of the problem struct
%
% NOTES:
%   This is just a quick test function that I wrote to study how the
%   optimization parameters effect the behavior of the optimization, as
%   well as to figure out how it works with a noisy objective function. For
%   more rigerous optimization the code should be improved, most notably by
%   adding a convergence criteria and exit flag.
%
%

maxIter = problem.options.maxIter;
nPop = problem.options.populationCount;
nDim = length(problem.xLow);

% Memory allocation
Gx = zeros(nDim,1,maxIter);  %Global best solution point
Gf = zeros(1,1,maxIter);  %Global best solution value
Lx = zeros(nDim,nPop,maxIter);  %Local best solution
Lf = zeros(1,nPop,maxIter);  %Local best value
X = zeros(nDim,nPop,maxIter);  %Particle location
F = zeros(1,nPop,maxIter);  %objFun(X);
V = zeros(nDim,nPop,maxIter);  %Particle velocity

% Linear transform for vectorized random numbers
a = problem.xLow*ones(1,nPop);
b = (problem.xUpp-problem.xLow)*ones(1,nPop);

% Initialization:
X(:,:,1) = a + b.*rand(nDim,nPop);
V(:,:,1) = -abs(b) + 2*abs(b).*rand(nDim,nPop);
F(1,:,1) = problem.objFun(X(:,:,1));
Lx(:,:,1) = X(:,:,1);
Lf(1,:,1) = F(1,:,1);
[Gf(1,1,1),idx] = min(F(1,:,1));
Gx(:,1,1) = Lx(:,idx,1);

% Run the optimization here:
pl = problem.options.pl;
pg = problem.options.pg;
w = problem.options.w;
for i=2:maxIter
    rl = rand(nDim,nPop);  %Local random search dist
    rg = rand(nDim,nPop);  %global random search dist

    %%% Update all points
    V(:,:,i) = w*V(:,:,i-1) + ...    % Inertial terms
        pl.*rl.*(Lx(:,:,i-1)-X(:,:,i-1)) + ...  % Local search
        pg.*rg.*(Gx(:,1,i-1)*ones(1,nPop)-X(:,:,i-1));   %Global search
    X(:,:,i) = X(:,:,i-1) + V(:,:,i);  %Position update
    F(1,:,i) = problem.objFun(X(:,:,i));  %Objective function evaluation

    %%% Update local best:
    update = F(1,:,i) < Lf(1,:,i-1);  %Points that have new best values
    Lf(1,update,i) = F(1,update,i);
    Lf(1,~update,i) = Lf(1,~update,i-1);
    Lx(:,update,i) = X(:,update,i);
    Lx(:,~update,i) = Lx(:,~update,i);

    %%% Update global best:
    [Gf(1,1,i),idx] = min(Lf(1,:,i));
    Gx(:,1,i) = Lx(:,idx,i);

end

% Store the final solution
soln.x = reshape(Gx(:,1,end),nDim,1);
soln.f = Gf(end);

% Store all of the search history for analysis
soln.log.Gx = Gx;
soln.log.Gf = Gf;
soln.log.Lx = Lx;
soln.log.Lf = Lf;
soln.log.X = X;
soln.log.F = F;
soln.log.V = V;
soln.problem = problem;

end


function [class, Simil] = classifier(data, ideals, y)
%   INPUT:
%
%   data    =    datamatrix
%   ideals  =    idealvectors
%   y(1)    =    p-value in similarity measure
%   y(2)    =    alpha value for OWA weights
%   y(3)    =    used owa aggregator
%
%
%   OUTPUT:
%
%   class   =    column vector of the classes in which the samples are classified
%   Simil   =    similarity values for each class

[nc, v_dim] = size(ideals);
d_dim = size(data,1);
Simil = zeros(d_dim, nc);

if nargin==2
    y = [1, 1, 1];
end

for j = 1 : nc

    Ideal = repmat(ideals(j,:),d_dim,1);

    if y(3) == 1 %Using OWA with Linguistic quantifier 1
        w=owaw1(v_dim,y(2));
        tmpmatrix=(1-abs(data.^y(1)-Ideal.^y(1))).^(1/y(1));
        Simil(:,j)=owamatrix(tmpmatrix,w);
    elseif    y(3) == 2 %Using OWA with Linguistic quantifier 2
        w=owaw2(v_dim,y(2));
        tmpmatrix=(1-abs(data.^y(1)-Ideal.^y(1))).^(1/y(1));
        Simil(:,j)=owamatrix(tmpmatrix,w);
    elseif    y(3) == 3 %Using OWA with Linguistic quantifier 3
        w=owaw3(v_dim,y(2));
        tmpmatrix=(1-abs(data.^y(1)-Ideal.^y(1))).^(1/y(1));
        Simil(:,j)=owamatrix(tmpmatrix,w);
    elseif    y(3) == 4 %Using OWA with Linguistic quantifier 4
        w=owaw4(v_dim,y(2));
        tmpmatrix=(1-abs(data.^y(1)-Ideal.^y(1))).^(1/y(1));
        Simil(:,j)=owamatrix(tmpmatrix,w);
    elseif  y(3) == 5   %O'Hagan's method
        tmpmatrix=(1-abs(data.^y(1)-Ideal.^y(1))).^(1/y(1));
        weights=Ohaganw(v_dim,y(2));
        index= 1;
        w=weights(index,:);
        Simil(:,j)=owamatrix(tmpmatrix,w);
    end

end

[simil_val, class] = max(Simil');
class=class';


function [f] = spm_mountaincar_fun(P,G)
% [Cross-entropy] objective function for mountain car problem
% FORMAT [f] = spm_mountaincar_fun(P,G)
%
% P = spm_vec(P)
% P.a - 0th order coefficients of force
% P.b - 1st order coefficients of force
% P.c - 2nd order coefficients of force
% P.d - action efficacy
%
% G   - world model; including
%    G.fq : function fq(x) returning desired equilibrium density at x
%    G.X  : matrix of locations in x
%
% f   - KL divergence between actual and desired equilibrium densities
% x   - cell of grid point support
%
% see:
% Gaussian Processes in Reinforcement Learning
% Carl Edward Rasmussen and Malte Kuss
% Max Planck Institute for Biological Cybernetics
% Spemannstraße 38, 72076 T¨ubingen, Germany
% {carl,malte.kuss}@tuebingen.mpg.de
%__________________________________________________________________________
% Copyright (C) 2005 Wellcome Trust Centre for Neuroimaging

% Karl Friston
% $Id: spm_mountaincar_fun.m 7679 2019-10-24 15:54:07Z spm $

% place paramters in model
%--------------------------------------------------------------------------
G(1).pE = P;

% get equilibrium density
%--------------------------------------------------------------------------
[M0,q0] = spm_fp(G);

% desired equilibrium density
%--------------------------------------------------------------------------
q   = feval(G(1).fq,G(1).X);

% KL divergence or cross entropy
%--------------------------------------------------------------------------
q   = q/sum(q(:));
D   = q(:)./q0(:);
i   = find(D > exp(-16));
f   = q(i)'*log(D(i));


function [S_sorted,s]=sort_ordinal(S)
% SORT_ORDINAL reorders nodes to emphasize persistent structure in an ordered multilayer partition
%
% Version: 2.2.0
% Date: Thu 11 Jul 2019 12:25:42 CEST
%
% Nodes are reordered using the optimal leave order for the
% average linkage hierarchical clustering tree based on Hamming distance
% between community assignments
%
% Call as:
%
%     [S_sorted, s] = sort_ordinal(S)
%
% Input:
%
%     S: multilayer partition (matrix of size NxT, where N is the number
%        of nodes and T is the number of layers)
%
% Output:
%
%     S_sorted: reordered multilayer partition
%
%     s: mapping of nodes to reordered nodes
%
% Note that S_sorted=S(s, :)

d1=pdist(S,'hamming');
Z1=linkage(d1,'average');
s=optimalleaforder(Z1,d1);
S_sorted=S(s,:);


function [exo_irf_record,exo_irf_estimates]=irfexo(beta_gibbs,It,Bu,IRFperiods,IRFband,n,m,p,k,prior)

% create the cell aray that will store the values from the simulations
exo_irf_record=cell(n,m);

% deal with shocks in turn
for ii=1:m

   % step 1: repeat the simulation process a number of times equal to the number of Gibbs iterations
   for kk=1:It-Bu

   % step 3: draw beta from its posterior distribution
   beta=beta_gibbs(:,kk);
   % reshape to obtain B
   B=reshape(beta,k,n);
   % recover C, the matrix of coefficients on exogenous
   C=B(end-m+1:end,:);
   % create a matrix of zeros of dimension p*n
   Y=zeros(p,n);
   %  step 2: set the value of the last row, column i, equal to 1
   Y(p,:)=C(ii,:);

      % step 4: for each iteration kk, repeat the algorithm for periods T+1 to T+h
      for jj=1:IRFperiods-1
% % %           if prior==61
% % %          %use the function lagx to obtain the matrix X; retain only the last row
% % %    X=bear.lagx(Y,p-1);
% % %    X=X(end,:);
% % %
% % %
% % %     else

      % use the function lagx to obtain a matrix temp, containing the endogenous regressors
      temp=bear.lagx(Y,p-1);

      % define the vector X
      X=[temp(end,:) zeros(1,m)];
% % %           end
      % obtain the predicted value for T+jj
      yp=X*B;

      % concatenate yp at the top of Y
      Y=[Y;yp];

      % repeat until values are obtained for T+h
      end

   % step 5: record the results from current iteration in cell irf_record
      % loop over variables
      for jj=1:n
      % consider column jj of matrix 'Y' and trim the (p-1) initial periods: what remains is the series of IRFs for period T to period T+h-1, for variable jj
      temp=Y(p:end,jj);
      % record these values in the corresponding matrix of irf_record
      exo_irf_record{jj,ii}(kk,:)=temp';
      end

   % then go for next iteration
   end

% conduct the same process with shocks in other variables
end

% create first the cell that will contain the IRF estimates
exo_irf_estimates=cell(n,m);

% for the response of each variable to each shock, and each IRF period, compute the median, lower and upper bound from the Gibbs sampler records
% consider variables in turn
for ii=1:n
   % consider shocks in turn
   for jj=1:m
      % consider IRF periods in turn
      for kk=1:IRFperiods
      % compute first the lower bound
      exo_irf_estimates{ii,jj}(1,kk)=quantile(exo_irf_record{ii,jj}(:,kk),(1-IRFband)/2);
      % then compute the median
      exo_irf_estimates{ii,jj}(2,kk)=quantile(exo_irf_record{ii,jj}(:,kk),0.5);
      % finally compute the upper bound
      exo_irf_estimates{ii,jj}(3,kk)=quantile(exo_irf_record{ii,jj}(:,kk),1-(1-IRFband)/2);
      end
   end
end


function pdepetrans
% 1D transport - modelling with extensions for decay and fast sorption
%    using MATLAB pdepe
%
%   $Ekkehard Holzbecher  $Date: 2006/03/16 $
%--------------------------------------------------------------------------
T = 1;                     % maximum time [s]
L = 1;                     % length [m]
D = 1;                     % diffusivity [m*m/s]
v = 1;                     % velocity [m/s]
lambda = 0.0;              % decay constant [1/s]
sorption = 2;              % sorption-model: no sorption (0), linear (1),
                           %                 Freundlich (2), Langmuir (3)
k1 = 0.0004;               % sorption parameter 1 (R=0 for linear isotherm with Kd, else k1=R)
k2 = 0.5;                  % sorption parameter 2 (Kd for linear isotherm with Kd)
rhob = 1300;               % porous medium bulk density [kg/m*m*m]
theta = 0.2;               % porosity [-]
c0 = 0.0;                  % initial concentration [kg/m*m*m]
cin = 1;                   % boundary concentration [kg/m*m*m]

M = 40;                    % number of timesteps
N = 40;                    % number of nodes
%-------------------------- output parameters
gplot = 0;                 % =1: breakthrough curves; =2: profiles
gsurf = 0;                 % surface
gcont = 0;                 % =1: contours; =2: filled contours
ganim = 2;                 % animation of profiles; =1: single line; =2: all lines

t = linspace (T/M,T,M);    % time discretization
x = linspace (0,L,N);      % space discretization

%----------------------execution-------------------------------------------
if sorption == 1 & k1 <=0
    k1 = 1+k2*rhob/theta;
else
    if sorption > 1 k1 = rhob*k1/theta; end
end
options = odeset; if (c0 == 0) c0 = 1.e-20; end
c = pdepe(0,@transfun,@ictransfun,@bctransfun,x,[0 t],options,D,v,lambda,sorption,k1,k2,c0,cin);

%---------------------- graphical output ----------------------------------
switch gplot
    case 1
        plot ([0 t],c)        % breakthrough curves
        xlabel ('time'); ylabel ('concentration');
    case 2
        plot (x,c','--')      % profiles
        xlabel ('space'); ylabel ('concentration');
end
if gsurf                      % surface plot
    figure; surf (x,[0 t],c);
    xlabel ('space'); ylabel ('time'); zlabel('concentration');
end
if gcont figure; end
switch gcont
    case 1
        contour (x,[0 t],c)   % contours
        grid on; xlabel ('space'); ylabel ('time');
    case 2
        contourf(x,[0 t],c)   % filled contours
        colorbar; xlabel ('space'); ylabel ('time');
end
if (ganim)
    [FileName,PathName] = uiputfile('*.mpg');
    figure; if (ganim > 1) hold on; end
    for j = 1:size(c,1)
        axis manual;  plot (x,c(j,:),'r','LineWidth',2);
        YLim = [min(c0,cin) max(c0,cin)];
        legend (['t=' num2str(T*(j-1)/M)]);
        Anim(j) = getframe;
        plot (x,c(j,:),'b','LineWidth',2);
    end
    mpgwrite (Anim,colormap,[PathName '/' FileName]);     % mgwrite not standard MATLAB
    movie (Anim,0);   % play animation
end

%----------------------functions------------------------------
function [c,f,s] = transfun(x,t,u,DuDx,D,v,lambda,sorption,k1,k2,c0,cin)
switch sorption
    case 0
        R = 1;
    case 1
        R = k1;
    case 2
        R = 1+k1*k2*u^(k2-1);
    case 3
        R = 1+k1*k2*u/(k2+u)/(k2+u);
end
c = R;
f = D*DuDx;
s = -v*DuDx -lambda*R*u;
% --------------------------------------------------------------
function u0 = ictransfun(x,D,v,lambda,sorption,k1,k2,c0,cin)
u0 = c0;
% --------------------------------------------------------------
function [pl,ql,pr,qr] = bctransfun(xl,ul,xr,ur,t,D,v,lambda,sorption,k1,k2,c0,cin)
pl = ul-cin;
ql = 0;
pr = 0;
qr = 1;


function main
%
% This is a demo program of the paper J. Tian, L. Ma, and W. Yu, "Ant
% colony optimization for wavelet-based image interpolation using a
% three-component exponential mixture model," Expert Systems with
% Applications, Vol. 38, No. 10, Sept. 2011, pp. 12514-12520.
%
% Contact: eejtian@gmail.com
%
% Note that the PSNR values could be slightly different with that reported
% in paper due to the random number generator.
%
% The input image should have a square size.
%
% Acknowledgement: This program needs Wavelet transform toolbox, which is
% downloaded from http://www-stat.stanford.edu/~wavelab/.

clear all; close all; clc;

img_truth = im2double(imread('lena_truth.bmp'));

% Generate low-resolution image
psf_filter =  fspecial('average', 3);
img_in = imfilter(img_truth, psf_filter, 'symmetric');
wfilter_type = 'bior2.2';
[Lo_D,Hi_D,Lo_R,Hi_R] = wfilters(wfilter_type);
Lo_D = Lo_D ./ sqrt(2);
Hi_D = Hi_D ./ sqrt(2);
Lo_R = Lo_R .* sqrt(2);
Hi_R = Hi_R .* sqrt(2);
[ca1,ch1,cv1,cd1] = dwt2(img_in, Lo_D, Hi_D, 'mode', 'per');
img_low = ca1;

%--------------------------------------------------------------------------
%-------------- PASS 1: Generate mask using ACO for interpolation ---------
%--------------------------------------------------------------------------
[ca1,ch1,cv1,cd1] = dwt2(img_low, Lo_D, Hi_D, 'mode', 'per');
[ca2,ch2,cv2,cd2] = dwt2(ca1, Lo_D, Hi_D, 'mode', 'per');

ch1_mask = func_aco_thresholding_estimate_mask(ch1);
cv1_mask = func_aco_thresholding_estimate_mask(cv1);
cd1_mask = func_aco_thresholding_estimate_mask(cd1);
ch2_mask = func_aco_thresholding_estimate_mask(ch2);
cv2_mask = func_aco_thresholding_estimate_mask(cv2);
cd2_mask = func_aco_thresholding_estimate_mask(cd2);

%--------------------------------------------------------------------------
%-------------- PASS 2: Image interpolation in wavelet domain -------------
%--------------------------------------------------------------------------
% Parameter setting
img_in = img_low;
nEnlargeFactor = 2;
win_size = 7;
nTotalIteration = 10;

[ca1,ch1,cv1,cd1] = dwt2(img_in, Lo_D, Hi_D, 'mode', 'per');
[ca2,ch2,cv2,cd2] = dwt2(ca1, Lo_D, Hi_D, 'mode', 'per');

[ch1_par1, ch1_par2, ch1_par3] = func_proposed_three_state_estimation_aco_seg(ch1, ch1_mask, win_size);
[ch2_par1, ch2_par2, ch2_par3] = func_proposed_three_state_estimation_aco_seg(ch2, ch2_mask, win_size);
[cd1_par1, cd1_par2, cd1_par3] = func_proposed_three_state_estimation_aco_seg(cd1, cd1_mask, win_size);
[cd2_par1, cd2_par2, cd2_par3] = func_proposed_three_state_estimation_aco_seg(cd2, cd2_mask, win_size);
[cv1_par1, cv1_par2, cv1_par3] = func_proposed_three_state_estimation_aco_seg(cv1, cv1_mask, win_size);
[cv2_par1, cv2_par2, cv2_par3] = func_proposed_three_state_estimation_aco_seg(cv2, cv2_mask, win_size);

% Variance estimation
ch0_par1 = func_proposed_par_propogation(ch1_par1,ch2_par1,nEnlargeFactor);
cv0_par1 = func_proposed_par_propogation(cv1_par1,cv2_par1,nEnlargeFactor);
cd0_par1 = func_proposed_par_propogation(cd1_par1,cd2_par1,nEnlargeFactor);

ch0_par2 = func_proposed_par_propogation(ch1_par2,ch2_par2,nEnlargeFactor);
cv0_par2 = func_proposed_par_propogation(cv1_par2,cv2_par2,nEnlargeFactor);
cd0_par2 = func_proposed_par_propogation(cd1_par2,cd2_par2,nEnlargeFactor);

ch0_par3 = func_proposed_par_propogation(ch1_par3,ch2_par3,nEnlargeFactor);
cv0_par3 = func_proposed_par_propogation(cv1_par3,cv2_par3,nEnlargeFactor);
cd0_par3 = func_proposed_par_propogation(cd1_par3,cd2_par3,nEnlargeFactor);

% Coefficient index extrapolation
ch0_mask = imresize(ch1_mask, size(ch1_mask)*nEnlargeFactor, 'nearest');
cv0_mask = imresize(cv1_mask, size(cv1_mask)*nEnlargeFactor, 'nearest');
cd0_mask = imresize(cd1_mask, size(cd1_mask)*nEnlargeFactor, 'nearest');

rand('state',sum(100*clock));
ch0_mask_change = rand(size(ch0_mask));
ch0_mask_change = (ch0_mask_change>=0.5);
ch0_mask = (ch0_mask==1).*(ch0_mask_change==1).*0 + (ch0_mask==1).*(ch0_mask_change==0).*1 ...
            + (ch0_mask==-1).*(ch0_mask_change==1).*0 + (ch0_mask==-1).*(ch0_mask_change==0).*-1 ...
            + (ch0_mask==0).*ch0_mask;

cv0_mask_change = rand(size(cv0_mask));
cv0_mask_change = (cv0_mask_change>=0.5);
cv0_mask = (cv0_mask==1).*(cv0_mask_change==1).*0 + (cv0_mask==1).*(cv0_mask_change==0).*1 ...
            + (cv0_mask==-1).*(cv0_mask_change==1).*0 + (cv0_mask==-1).*(cv0_mask_change==0).*-1 ...
            + (cv0_mask==0).*cv0_mask;

cd0_mask_change = rand(size(ch0_mask));
cd0_mask_change = (ch0_mask_change>=0.5);
cd0_mask = (cd0_mask==1).*(cd0_mask_change==1).*0 + (cd0_mask==1).*(cd0_mask_change==0).*1 ...
            + (cd0_mask==-1).*(cd0_mask_change==1).*0 + (cd0_mask==-1).*(cd0_mask_change==0).*-1 ...
            + (cd0_mask==0).*cd0_mask;

% Generate the highest subbands
result = zeros(size(img_in,1).*nEnlargeFactor, size(img_in,2).*nEnlargeFactor);

for ii=1:nTotalIteration
    ch0 = func_proposed_gen_subband(ch0_par1, ch0_par2, ch0_par3, ch0_mask);
    cv0 = func_proposed_gen_subband(cv0_par1, cv0_par2, cv0_par3, cv0_mask);
    cd0 = func_proposed_gen_subband(cd0_par1, cd0_par2, cd0_par3, cd0_mask);
    temp = idwt2(img_in,ch0,cv0,cd0, Lo_R, Hi_R, 'mode', 'per');
    temp(temp<0) = 0;
    temp(temp>1) = 1;
    result = result + temp./nTotalIteration;
end

% Write the output image and perform PSNR evaluation
fprintf('The psnr is %.2f dB \n', func_psnr_gray(img_truth.*255, result.*255));
imwrite(uint8(result.*255), ['lena_rec.bmp'], 'bmp');

% *************************************************************************
% **************************Inner Function ********************************
% *************************************************************************
function result = func_aco_thresholding_estimate_mask(wxin)

ant_search_range_row_min = ones(size(wxin));
ant_search_range_row_max = ones(size(wxin)).*size(wxin,1);
ant_search_range_col_min = ones(size(wxin));
ant_search_range_col_max = ones(size(wxin)).*size(wxin,2);

% System setup
ant_move_step_within_iteration = 15;
total_iteration_num = 10;
search_clique_mode = 8;

wx = abs(wxin);
[nrow, ncol] = size(wx);
wx_1D = func_2D_LexicoOrder(wx);

% initialization
h = zeros(size(wx));
h_1D = func_2D_LexicoOrder(h);
p = 1./(wx.*(wx~=0)+1.*(wx==0)).*(wx~=0)+(wx==0);
p_1D = func_2D_LexicoOrder(p);

alpha = 1;
beta = 2;
rho = 0.1;
w = 0.6;
A = 5000;
B = 10;

%use one ant for each pixel position
ant_total_num = nrow*ncol;
ant_current_row = zeros(ant_total_num, 1);
ant_current_col = zeros(ant_total_num, 1);
ant_current_val = zeros(ant_total_num, 1);
rr = (meshgrid(1:nrow))'; cc = meshgrid(1:ncol);
ant_current_row = rr(:);
ant_current_col = cc(:);
ant_current_val = wx_1D((ant_current_row-1).*ncol+ant_current_col);

ant_search_range_row_min = ant_search_range_row_min(:);
ant_search_range_row_min = padarray(ant_search_range_row_min, [0 search_clique_mode-1],'replicate','post');
ant_search_range_row_max = ant_search_range_row_max(:);
ant_search_range_row_max = padarray(ant_search_range_row_max, [0 search_clique_mode-1],'replicate','post');
ant_search_range_col_min = ant_search_range_col_min(:);
ant_search_range_col_min = padarray(ant_search_range_col_min, [0 search_clique_mode-1],'replicate','post');
ant_search_range_col_max = ant_search_range_col_max(:);
ant_search_range_col_max = padarray(ant_search_range_col_max, [0 search_clique_mode-1],'replicate','post');

for nIteration = 1: total_iteration_num

    ant_current_path_val_mean = zeros(ant_total_num,1);
    ant_current_path_val_mean = ant_current_val;

    for nMoveStep = 1: ant_move_step_within_iteration-1

        if search_clique_mode == 4
            ant_search_range_row = [ant_current_row-1, ant_current_row, ant_current_row+1, ant_current_row];
            ant_search_range_col = [ant_current_col, ant_current_col+1, ant_current_col, ant_current_col-1];
        elseif search_clique_mode == 8
            ant_search_range_row = [ant_current_row-1, ant_current_row-1, ant_current_row-1, ant_current_row, ant_current_row,ant_current_row+1, ant_current_row+1, ant_current_row+1];
            ant_search_range_col = [ant_current_col-1, ant_current_col, ant_current_col+1, ant_current_col-1, ant_current_col+1, ant_current_col-1, ant_current_col, ant_current_col+1];
        end

        ant_current_row_extend = padarray(ant_current_row, [0 search_clique_mode-1],'replicate','post');
        ant_current_col_extend = padarray(ant_current_col, [0 search_clique_mode-1],'replicate','post');
        ant_search_range_val = zeros(ant_total_num,search_clique_mode);

        %replace the positions our of the image's range

        temp = (ant_search_range_row>=ant_search_range_row_min) & (ant_search_range_row<=ant_search_range_row_max) & (ant_search_range_col>=ant_search_range_col_min) & (ant_search_range_col<=ant_search_range_col_max);
        ant_search_range_row = temp.*ant_search_range_row + (~temp).*ant_current_row_extend;
        ant_search_range_col = temp.*ant_search_range_col + (~temp).*ant_current_col_extend;

        ant_search_range_transit_prob_h = zeros(size(ant_search_range_val));
        ant_search_range_transit_prob_p = zeros(size(ant_search_range_val));

        for ii=1:search_clique_mode
            ant_search_range_val(:,ii) = wx_1D((ant_search_range_row(:,ii)-1).*ncol+ant_search_range_col(:,ii));

            temp = ant_search_range_val(:,ii);
            temp = abs(temp - ant_current_path_val_mean);
            temp = 1./(temp.*(temp~=0)+1.*(temp==0)) .* (temp~=0)+(temp==0);

            ant_search_range_transit_prob_h(:,ii) = temp;
            ant_search_range_transit_prob_p(:,ii) = p_1D((ant_search_range_row(:,ii)-1).*ncol+ant_search_range_col(:,ii));

        end
        temp = (ant_search_range_transit_prob_h.^alpha) .* (ant_search_range_transit_prob_p.^beta);

        temp_sum = sum(temp,2);
        temp_sum = padarray(temp_sum, [0 search_clique_mode-1],'replicate','post');

        ant_search_range_transit_prob = temp ./ temp_sum;

        % generate a random number to determine the next position.
        rand('state', sum(100*clock));
        temp = rand(ant_total_num,1);
        temp = padarray(temp, [0 search_clique_mode-1],'replicate','post');
        temp = cumsum(ant_search_range_transit_prob,2)>=temp;
        temp = padarray(temp, [0 1],'pre');
        temp = (diff(temp,1,2)==1);

        temp_row = (ant_search_range_row .* temp)';
        [ii, jj, vv] = find(temp_row);
        ant_next_row = vv;
        temp_col = (ant_search_range_col .* temp)';
        [ii, jj, vv] = find(temp_col);
        ant_next_col = vv;

        ant_current_row = ant_next_row;
        ant_current_col = ant_next_col;
        ant_current_val = wx_1D((ant_current_row-1).*ncol+ant_current_col);
        ant_current_path_val_mean = (ant_current_path_val_mean.*nMoveStep + ant_current_val)/(nMoveStep+1);

        rr = ant_current_row;
        cc = ant_current_col;
        p_1D((rr-1).*ncol+cc,1) = w*p_1D((rr-1).*ncol+cc,1) + 1./(A+B.*ant_current_path_val_mean);
        p = func_LexicoOrder_2D(p_1D, nrow, ncol);

    end % end of nMoveStep

    p = (1-rho).*p;
    p_1D = func_2D_LexicoOrder(p);

end % end of nIteration

clear h h_1D temp
clear ant_current_row ant_current_col ant_current_val
clear ant_current_path_val_mean
clear ant_search_range_row search_range_path_col ant_search_range_val
clear ant_search_range_transit_prob_h ant_search_range_transit_prob_v ant_search_range_transit_prob
clear ant_search_range_row_min ant_search_range_row_max ant_search_range_col_min ant_search_range_col_max

result = func_determine_class_fcm(wxin, p);

% ******************************************************************************
% **************************Inner Function *************************************
% ******************************************************************************

function idx = func_determine_class_fcm(wxin, p)
wx = abs(wxin);
p_1D = func_2D_LexicoOrder(p);
wx_1D = func_2D_LexicoOrder(wx);
[nrow, ncol] = size(wx);

nFeature(:,1) = p_1D(:)./(max2(p_1D));
nFeature(:,2) = wx_1D(:)./(max2(wx_1D));
[center,U,obj_fcn] = fcm(nFeature, 2,[2.0 100 1e-5 0]);

idx = zeros(nrow:ncol,1);
if sum(sum(U(1,:) >= U(2,:))) >= sum(sum(U(1,:) < U(2,:)))
    idx = (U(1,:) < U(2,:));
else
    idx = (U(1,:) >= U(2,:));
end
idx = func_LexicoOrder_2D(idx, nrow, ncol);
idx = double(idx);
idx((idx==1)&(wxin<0)) = -1;
idx((idx==1)&(wxin>=0)) = 1;
idx(idx==0) = 0;

% *************************************************************************
% **************************Inner Function ********************************
% *************************************************************************
function result = func_LexicoOrder_2D(x, nRow, nColumn)
result = reshape(x, nColumn, nRow)';

% *************************************************************************
% **************************Inner Function ********************************
% *************************************************************************
function result = func_2D_LexicoOrder(x)
[nRow, nColumn] = size(x);
temp = x';
result = temp(:);

% *************************************************************************
% **************************Inner Function ********************************
% *************************************************************************
function result = func_psnr_gray(f, g)
f = double(f);
g = double(g);
Q=255;MSE=0;
[M,N]=size(f);
h = f - g;
MSE = sum(sum(h.*h));
MSE=MSE/M/N;
result=10*log10(Q*Q/MSE);

% *************************************************************************
% **************************Inner Function ********************************
% *************************************************************************
function [result1, result2, result3] = func_proposed_three_state_estimation_aco_seg(I, I_mask, win_size)

thre = graythresh(abs(I));
[nrow, ncol] = size(I);
padnum = (win_size-1)/2;
A = padarray(I, [padnum padnum], 'replicate', 'bot');
B = padarray(I_mask, [padnum padnum], 'replicate', 'bot');
A = im2col(A, [win_size win_size],'sliding');
B = im2col(B, [win_size win_size],'sliding');

result1 = (sum(A.*(B==1),1).*(sum((B==1),1)~=0) + 0.*(sum((B==1),1)==0)) ./ (sum((B==1),1) + (sum((B==1),1)==0).*1);
result1 = reshape(result1, size(I));
result2 = (sum(A.*(B==-1),1).*(sum((B==-1),1)~=0) + 0.*(sum((B==-1),1)==0)) ./ (sum((B==-1),1) + (sum((B==-1),1)==0).*1);
result2 = reshape(result2, size(I));
result3 = (sum(A.*A.*(B==0),1).*(sum((B==0),1)~=0) + 0.*(sum((B==0),1)==0)) ./ (sum((B==0),1) + (sum((B==0),1)==0).*1);
result3 = reshape(result3, size(I));

% *************************************************************************
% **************************Inner Function ********************************
% *************************************************************************
function ch0_var = func_proposed_par_propogation(ch1_var,ch2_var,nEnlargeFactor)

temp1 = imresize(ch1_var, size(ch1_var)*nEnlargeFactor, 'nearest').^2;
temp2 = imresize(ch2_var, size(ch2_var)*2*nEnlargeFactor, 'nearest');
ch0_var = ((temp2~=0).*temp1+(temp2==0).*0)./ ((temp2~=0).*temp2 + (temp2==0).*1);

% *************************************************************************
% **************************Inner Function ********************************
% *************************************************************************
function result = func_proposed_gen_subband(I_par1, I_par2, I_par3, I_mask)

rand('state',sum(100*clock));
result1 = exprnd(I_par1);
result2 = exprnd(I_par2);
result3 = randn(size(I_par3)).*sqrt(I_par3);
result1(isnan(result1))=0;
result2(isnan(result2))=0;
result3(isnan(result3))=0;
result = (I_mask==1).*result1 + (I_mask==-1).*result2 + (I_mask==0).*result3;


function [aVal,aJacob,aHess,papt]=aWeave(x,t,A,alpha,theta0,uTurn)
%%AWEAVE The drift function for a somewhat sinusoidal weaving motion model
%        under a 3D flat-Earth approximation. The third example below shows
%        how this flat-Earth model can be used on a curved Earth.
%
%INPUTS: x The 6X1 target state at time t consisting of 3 position and 3
%          velocity components.
%        t The time at which the drift function is to be evaluated.
%        A A scalar term determining the magnitude of the deflection during
%          turns. It should be less than alpha*pi/2 to keep the target from
%          doubling back on its previous path.
%    alpha The positive scalar weave period in radians per second.
%   theta0 The scalar phase at time 0 of the weave. A cosine function is
%          used for the weave. The default if this parameter is omitted or
%          an empty matrix is passed is 0. To start a track going in the
%          overall direction of progression of the target, set theta=0 and
%          the initial velocity direction to the overall direction that you
%          want the target to go (weaves are orthogonal to that direction).
%    uTurn A 3X1 unit vector pointing in the direction of the turn axis
%          used for the weaves. It is orthogonal to the turn plane. For
%          example, if a target is going to weave in the x-y plane, then
%          this should be [0;0;1]. The default if this parameter is omitted
%          or an empty matrix is passed is [0;0;1].
%
%OUTPUTS: aVal The 6X1 flat-Earth time-derivative of the state.
%       aJacob The 6X6 matrix of partial derivatives of aVals such that
%              aJacob(:,k) is the partial derivative of aVals(:,k) with
%              respect to x(k).
%        aHess The 6X6X6 matrix of second partial derivatives of aVals such
%              that aHess(:,k1,k2) is the second partial derivative of
%              aVals with respect to x(k1) and x(k2).
%         papt The 6X1 partial derivative with resect to time of aVals.
%
%This model is derived in [1]. It is parameterized in a manner that allows
%one to create a target trajectory that performed weaves of a desired
%amplitude in a particular direction, progressing at a desired speed
%overall.
%
%Equation 78 and 79 in [1] are for a general turning model. Equation 88
%and 89 specifically show how the velocity is modulated, which in turn can
%lead to using a time-varying angular momentum vector modified from 79 to
%Omega=A*cos(alpha*t+theta0)*uTurn. Unlike Equation 79, this is generalized
%to allow uTurn to be any rotation axis, not just the z-axis. This is the
%model as implemented here.
%
%EXAMPLE 1:
%Here, we implement code that draws Figure 11 from [1]. We want the overall
%motion direction of the target to be along the x-axis. We also want the
%target to fly travel at a specified speed and go a specified distance
%along the x axis over the observation period. The one parameter that is
%left free is the magnitude of the weaving. Here, we plot two trajectories
%that have the same starting and ending points and make the same number of
%weaves, but have different weaving magnitudes. Since both targets are
%going the same speed, we need to determine the time duration of the
%trajectories so that we can show them advancing the same amount along the
%x-axis.
% Nw=6;%The number of weave cycles.
% speed=10;%Meters per second
% s=100;%The desired distance we want to cover along the x-axis (meters).
% uTurn=[0;0;1];%Turns are in the x-y plane.
% %The initial velocity of the target is along the x axis. By setting
% %theta0-0 and the velocity of xInit to point in the desired direction of
% %progression, we can easily set the direction of progression.
% theta0=0;
% xInit=[0;0;0;speed*[1;0;0]];
%
% %Parameters for the first target
% %beta determines the weave magnitude, as in Equation 101 of [1]. This value
% %can be from 0 to 1.
% betaVal1=1;
% %Solve Equation 102 in [1] to determine how long one must travel to go a
% %distance of s meters. Also determine the weave period in meters per second
% %as well as the amplitude parameter A of the weaves.
% [tEnd1,alphaVal1,A1]=determineWeaveTime(s,speed,Nw,betaVal1);
%
% %Parameters for the second target. This target does not weave as strongly.
% betaVal2=1/2;
% [tEnd2,alphaVal2,A2]=determineWeaveTime(s,speed,Nw,betaVal2);
%
% %Now, create the trajectories. We use a Runge-Kutta algorithm with a fixed
% %step to get the values. The step has been chosen to be sufficiently small.
% %However, if we only wanted a few samples we could use RungeKAtTimes for a
% %fixed-step size algorithm, or we could use RKAdaptiveAtTimes.
% numSteps=3000;
% deltaT1=tEnd1/numSteps;
% deltaT2=tEnd2/numSteps;
% aDyn1=@(x,t)aWeave(x,t,A1,alphaVal1,theta0,uTurn);
% xList1=RungeKSteps(xInit,0,aDyn1,deltaT1,numSteps);
% aDyn2=@(x,t)aWeave(x,t,A2,alphaVal2,theta0,uTurn);
% xList2=RungeKSteps(xInit,0,aDyn2,deltaT2,numSteps);
%
% figure(1)
% clf
% hold on
% plot(xList1(1,:),xList1(2,:),'-r','linewidth',6)
% plot(xList2(1,:),xList2(2,:),'--g','linewidth',6)
% axis([0 100 0 14])
% h1=xlabel('x');
% h2=ylabel('y');
%
% set(gca,'FontSize',18,'FontWeight','bold','FontName','Times')
% set(h1,'FontSize',20,'FontWeight','bold','FontName','Times')
% set(h2,'FontSize',20,'FontWeight','bold','FontName','Times')
%
%EXAMPLE 2:
%In this example, we want a target to travel a distance of s meters in tMax
%seconds while weaving Nw times. As in the previous example, the target is
%moving along the x axis. We ned to use the function determineWeaveSpeed to
%determine the speed of the target that is required to make this happen.
% Nw=4;
% betaVal=0.5;
% tEnd=180;%The time over which the distance was traveled.
% theta0=0;
% uTurn=[0;0;1];%Turns are in the x-y plane.
% s=1.085e6;%The distance traveled.
%
% [speed,alphaVal,A]=determineWeaveSpeed(s,tEnd,Nw,betaVal);
% xInit=[0;0;0;speed*[1;0;0]];
% aDyn=@(x,t)aWeave(x,t,A,alphaVal,theta0,uTurn);
%
% numSteps=1000;
% deltaT=tEnd/numSteps;
% xList=RungeKSteps(xInit,0,aDyn,deltaT,numSteps);
% figure(2)
% clf
% hold on
% plot(xList(1,:),xList(2,:),'-r','linewidth',6)
% axis([0 s 0 8e4])
% h1=xlabel('x');
% h2=ylabel('y');
%
% set(gca,'FontSize',18,'FontWeight','bold','FontName','Times')
% set(h1,'FontSize',20,'FontWeight','bold','FontName','Times')
% set(h2,'FontSize',20,'FontWeight','bold','FontName','Times')
%
%EXAMPLE 3:
%Here, we demonstrate how to use this flat-Earth model on a curved Earth.
%Some place in the ocean off of Hawaii.
% latLonStart=[20.3924;-155.4976]*(pi/180);
% %The location of the Ahihi-Kinau Natural Area Reserve
% latLonEnd=[20.6050;-156.4353]*(pi/180);
% %The altitude of the target-- it will remain constant.
% altitudeInit=20e3;
%
% tMax=180;
% times=0:tMax;
%
% %Get an initial heading and distance. We are ignoring the altitude of the
% %target, though it would be taken into account using the (slower) function
% %indirectGeodeticProbGen
% [azi1,s]=indirectGeodeticProb(latLonStart,latLonEnd);
%
% pStart=[phi0;lambda0;altitudeInit];
% uInit=getENUAxes(pStart);
%
% xyzStart=ellips2Cart(pStart);
% %The initial heading in the local tangent plane coordinates.
% uh=[sin(azi1);cos(azi1);0];
%
% %These two parameters make the sinusoidal deviations approximately
% %centered about the nominal trajectory
% theta0=0;
% Nw=4;%The number of weave cycles.
% beta=0.5;
% %We want the plane to travel a distance of about s in tMax seconds
% %while weaving Nw times. This means that the speed along the
% %trajectory is
% [speed,alphaVal,A]=determineWeaveSpeed(s,tMax,Nw,beta);
% xInit=[xyzStart;speed*uh];
%
% %To determine the realism of this being a manned maneuver, since
% %this is level flight, the maximum G-force felt can be easily found
% %to be
% %MaxGForce=sqrt((A)^2*norm(xInit(4:6,end))^2+9.81^2)/9.81
% %which is 7.4G and is within a reasonable tolerance for a pilot
% %wearing an "anti-G" suit.
%
% uTurn=[0;0;1];%The local vertical is the turn axis.
% aDyn=@(x,t)aWeave(x,t,A,alphaVal,theta0,uTurn);
%
% deltaTMax=0.05;
% [xList,uList]=RungeKCurvedAtTimes(xInit,uInit,times,aDyn,[],deltaTMax);
% xList=xList(1:6,:);
% %If one wanted to get the velocity information the global coordinates,
% %then the following line is necessary:
% xList(4:6,:)=getGlobalVectors(xList(4:6,:),uList);
%
% %Bounds for the axes on the map in case this trajectory is plotted.
% axisMapBounds=[-156-0.6,-156+0.6,20.5-0.6,20.5+0.6];
% axisHeightBounds=[0 times(end) 0 25e3];
%
% %Convert the Cartesian trajectory into latitude, longitude and
% %altitude.
% points=Cart2Ellipse(xList(1:3,:));
%
% figure(1)
% clf
% hold on
% axis(axisMapBounds)
% axis square
%
% %Plot the trajectory of the aircraft with the curved-Earth model.
% plot(points(2,:)*180/pi,points(1,:)*180/pi,'-r','linewidth',6);
%
% h1=xlabel('Longitude');
% h2=ylabel('Latitude');
% set(gca,'FontSize',18,'FontWeight','bold','FontName','Times')
% set(h1,'FontSize',20,'FontWeight','bold','FontName','Times')
% set(h2,'FontSize',20,'FontWeight','bold','FontName','Times')
%
% %Plot the altitude as a function of time.
% figure(2)
% clf
% plot(times,points(3,:),'-r','linewidth',6);
% axis(axisHeightBounds)
%
% h1=xlabel('Time (Seconds)');
% h2=ylabel('Altitude (Meters)');
% set(gca,'FontSize',18,'FontWeight','bold','FontName','Times')
% set(h1,'FontSize',20,'FontWeight','bold','FontName','Times')
% set(h2,'FontSize',20,'FontWeight','bold','FontName','Times')
%
%REFERENCES:
%[1] D. F. Crouse, "Simulating aerial targets in 3D accounting for the
%    Earth's curvature," Journal of Advances in Information Fusion, vol.
%    10, no. 1, Jun. 2015.
%
%March 2017 David F. Crouse, Naval Research Laboratory, Washington D.C.
%(UNCLASSIFIED) DISTRIBUTION STATEMENT A. Approved for public release.

    if(nargin<6||isempty(uTurn))
        uTurn=[0;0;1];
    end

    if(nargin<5||isempty(theta0))
       theta0=0;
    end

    Omega=A*cos(alpha*t+theta0)*uTurn;
    aVal=[x(4:6);cross(Omega,x(4:6))];

    if(nargout>1)
        OmegaX=Omega(1);
        OmegaY=Omega(2);
        OmegaZ=Omega(3);

        aJacob=[0,0,0,1,        0,          0;
                0,0,0,0,        1,          0;
                0,0,0,0,        0,          1;
                0,0,0,0,        -OmegaZ,    OmegaY;
                0,0,0,OmegaZ,   0,          -OmegaX;
                0,0,0,-OmegaY,  OmegaX,     0];

        if(nargout>2)
            aHess=zeros(6,6,6);
            if(nargout>3)
                sinTerm=sin(alpha*t+theta0);

                uTurnX=uTurn(1);
                uTurnY=uTurn(2);
                uTurnZ=uTurn(3);

                vx=x(4);
                vy=x(5);
                vz=x(6);

                papt=[0;
                      0;
                      0;
                      A*alpha*(uTurnZ*vy-uTurnY*vz)*sinTerm;
                      A*alpha*(-uTurnZ*vx+uTurnX*vz)*sinTerm;
                      A*alpha*(uTurnY*vx-uTurnX*vy)*sinTerm];
            end
        end
    end
end

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


function [elem2face,face,elem2faceSign] = dof3face(elem)
%% DOF3FACE dof sturctrue for faces in 3-D.
%
% [elem2face,face,elem2faceSign] = DOF3FACE(elem) constructs data structure
% associated to faces in 3-D. elem is the connectivity matrix for a 3-D
% triangulation. elem2face is the elementwise pointer from elem to face
% indices. face is the face matrix using the ascend ordering. elem2faceSign
% records the consistency of the local faces with induced orientation and
% the global face with ascend orientation.
%
% DOF3FACE is used for elements using dof associated to faces like CR and
% WG elements in 3-D. For elements with orientation such as RT and BDM
% elements, when we use ascend ordering system, no elem2facSign is needed;
% see sc3doc for details.
%
%  See also dofedge, dof3edge
%
% Copyright (C) Long Chen. See COPYRIGHT.txt for details.

NT = size(elem,1);
totalFace = int32([elem(:,[2 3 4]); elem(:,[1 4 3]); ...
                   elem(:,[1 2 4]); elem(:,[1 3 2])]); % induced ordering
matlabversion = version;
if str2double(matlabversion(end-5:end-2)) > 2012
   [face, tempvar, j] = unique(sort(totalFace,2),'rows','legacy');
else
   [face, tempvar, j] = unique(sort(totalFace,2),'rows');
end
elem2face = uint32(reshape(j,NT,4));
elem2faceSign = int8(reshape(sum(sign(diff(totalFace(:,[1:3,1]),1,2)),2),NT,4));


%% Stream programming in Matlab
%  The stream programming is a computer programming methodology that is
% born in the field of mathematical languages using lambda calculus toole
% and exploiting the lazy evaluation methodology. Here a unefficient
% library, really useful to explain lazy evaluation and stream programming,
% is given. The set of tools is really wide to give examples of pure lazy
% evaluation, simple stream generation, the composition pattern, the
% accumulation pattern, the filtering pattern and a wide set of examples
% that allow the user to learn what stream programming is. This library
% isn't useful to create systems that must work with large ammounts of
% data, but can used where the number of data elements is small.. for
% example to generate streams of images (i.e. a stream of the
% approximations of a given image using a set of fourier armonics, this is
% a classical accumulation example).

%% What lazy evaluation is
%  The lazy evaluation is the technique of managing entities that aren't
% computed yet. For example we can think to the gradient of an image that
% can be taken as a variable and passed in functions and in workspaces, but
% that isn't computed yet, when we acces, for example, to a tail of the
% gradient that isn't computed automatically the lazy evaluation system
% computes that part of the matrix. This is usefull to optimize the code
% for execution time (parts of the gradient aren't computed) and for memory
% usage (because the parts of the gradient that aren't used arent allocated
% in the gradient matrix).
%
%  For example we can delay the evaluation of a function with a set of
% parameters:

% Function evaluation delayed:
dsin = delayEval(@sin,{2}),

%% Forcing the evaluation
%  After the delayed evaluation composition, the entity "dsin" can be thing
% to the promise of evaluation of the function "sin" with parameter "2".
% This isn't done yet, we can force the evaluation when we wish to get it.
% If we have tools to guess if an entity must be evaluated or not we can
% automatize the evaluation so that it is done only when an entity is
% accessed the first time, like the example of the gradient.
%
%  Here we force the evaluation exlpicitly:

% Forcing the evaluation:
res = forceEval(dsin),

%% The Stream Programming (SP)
%  The stream programming is a technique, based on lazy evaluation, to
% manage infinitely long sequence of elements, for examples the sequences
% of numbers, or the sequences of functions, series or other things. To
% manage an infinitely long sequence, that cannot be stored in a finite
% computer memory, we think to the sequence as a first element  followed
% with the promise to compute the other part of the sequence: this is a
% stream:
%
%     % A sample stream generating function generating the integers sequence:
%     function s = integersFrom(n)
%     s = {n, delayEval(@integersFrom,{n+1})};

% Generating an integers sequence:
integers = integersFrom(0),

% Getting another integer:
otherIntegers = forceEval(integers{2}),

% Computing the first ten integers:
firstTenInts = streamHead(integers,10),

%% Fibonacci numbers
%  The Fibonacci numbers can be constructed as a sequence where each number
% can be constructed as the sum of the previous two numbers. The first two
% numbers ar 0 and 1. With the following stream constructor the Fibonacci
% sequence can be constructed:
%
%     % The constructor of the Fibonacci sequence:
%     function s = fiboFrom(a1,a2)
%     s = {a1,delayEval(@fiboFrom,{a2,a1+a2})};
%
%  using this constructor we can obtain:

% Creating the sequence:
fib = fiboFrom(0,1);

% Getting the first ten values:
firstTenInts = streamHead(fib,10),

%% Functional list operators (from Schema language)
%  In the lisp and Schema languages the car and cdr operators are the bases
% for the management of lists. Here we have used "streamHead" to get the
% first elements of a stream, that is an infinite list; functions "head"
% and "tail" are defined as aliases of "streamCar" and "streamCdr", this
% two functions can be easily defined as follows:
%
%     % Head of a stream:
%     function v = streamCar(s)
%     v = s{1};
%
%     % Tail of a stream:
%     function so = streamCdr(si)
%     so = forceEval(si{2});
%
%  the streamHead function simply iterates with this two functions:
%
%     % Iteratively obtain a sequence of values:
%     function vals = streamHead(s,n)
%     s1 = s;
%     vals = cell(1,n);
%     for i=1:n
%         vals{i} = streamCar(s1);
%         s1 = streamCdr(s1);
%     end
%
%  other helper functions can be written with the same philosophy, like
% "streamRange" or "streamCons" to concatenate a value to a stream:
%
%     % Cut a range of a stream:
%     function vals = streamRange(s,start,nElem)
%     s1 = s;
%     for i=1:start-1
%         s1 = streamCdr(s1);
%     end
%     vals = cell(1,nElem);
%     for i=1:nElem
%         vals{i} = streamCar(s1);
%         s1 = streamCdr(s1);
%     end
%
%     % Concatenate a value with a stream:
%     function so = streamCons(v,si)
%     so = {v, delayEval(@fIdentity,{si})};

%% SP patterns: accumulate
%  In the software engeneering the design patterns are fundamental bricks
% for a correct and robust design of a complex system; generally desogn
% patterns are defined for OOP, but the same can be done for functional
% programming, procedural programming... and SP.
%  The accumulate pattern allows to define elements that operates over
% streams and that can be used as accumulators of data. Accumulators can be
% used to do a wide number of works like integration, sum of series...
% and for example the generation of streams containing successive
% approximations of series of what we wish to manage, for example the
% approximations of an image using its Fourier coefficients. Here the
% accumulator tool is defined as follows:
%
%     % Given a stream, a starting value and an accumulator function an
%     % accumulated stream is generated with the starting value as first
%     % element and the accumulator function that computes the next element.
%     function so = streamAccumulate(si,start,accumulator)
%     so = {start,delayEval(@streamAccumulate, ...
%             {streamCdr(si),
%              feval(accumulator,start,streamCar(si)),accumulator})};
%
%  Using this simple function (but take a deep look to it) we can define
% easily the integration:
%
%     % Integration of a sequence of numbers:
%     function so = integrateStream(si,dt,c)
%     so = scaleStream(streamAccumulate(si,c/dt,@plus),dt);
%
%  Let's try it:

% A discretization step:
dt = 0.1;

% A sequence of values from 0:
X = scaleStream(integers,dt);

% A sine function:
Y = filterStream(X,@sin);

% Getting sample values:
Xs = streamHead(X,10),
Ys = streamHead(Y,10),

% Computing the integral stream:
Yint = integrateStream(Y,dt,-1);
Yints = streamHead(Yint,10),
figure; hold on;
plotStream(X,Y,100,0),
plotStream(X,Yint,100,0),

%% SP patterns: accumulate
%  The composition of streams can be used to do different computations in
% different streams and then mixing them int a single stream. A simple
% example is the stream sum of other streams, we can try to sum the sin
% stream and it's integral.
%  A composition can be done given a sequence of streams and a composing
% function as follows:
%
%     % Composing n streams:
%     function so = streamCompose(streams,func)
%     argsv = {func};
%     argsf = {};
%     for i=1:size(streams,2);
%         argsv{i+1} = streamCar(streams{i});
%         argsf{i} = streamCdr(streams{i});
%     end
%     val = builtin('feval',argsv{:});
%     so = {val,delayEval(@streamCompose,{argsf,func})};
%
%  This tool allows to generate easily new composition operators:
%
%     % Adding the streams values:
%     function so = addStreams(varargin)
%     so = streamCompose(varargin,@sumVals);
%     function ris = sumVals(varargin)
%     ris = sum(cell2mat(varargin));
%
%     % Subtracting the stream values:
%     function so = subStreams(s1,s2)
%     so = streamCompose({s1,s2},@subVals);
%     function ris = subVals(v1,v2)
%     ris = v1-v2;
%
%     % Multiply streams:
%     function so = mulStreams(varargin)
%     so = streamCompose(varargin,@mulVals);
%     function ris = mulVals(varargin)
%     ris = prod(cell2mat(varargin));
%
%     % Divide streams:
%     function so = divStreams(s1,s2)
%     so = streamCompose({s1,s2},@divVals);
%     function ris = divVals(v1,v2)
%     ris = v1/v2;
%
%  Whit this tool all the composition of streams that we wish to do can be
% easily added to our operators set.

% Generating the sum of the two streams:
Ysum = addStreams(Y,Yint);

% Plotting:
figure; plotStream(X,Ysum,100,0),

%% SP patterns: filter
%  A stream can be filtered in a sense different from the previous one
% (that is the mapping of functional programming), a stream can be filtered
% with a filter that decides if an element must be discarded or not. For
% example immagine that you wish to get a sequence of prime numbers, you
% can get them filtering the stream of integers from 2 removing the
% integers that can be divided by the previous primes. We can design a
% stream filter function that recives another boolean function that can
% decide if an element can be mantained or must be rejected:
%
%     % A filtering element for streams:
%     function so = streamFilter(si,filter,varargin)
%     while ~builtin('feval',filter,head(si),varargin{:})
%         si = tail(si);
%     end
%     so = {head(si),delayEval(@streamFilter,{tail(si),filter,varargin{:}})};
%
%  This can filter element by element a stream (and can generate infinite
% loops). This can be usefull to generate streams from other discarding
% elements; the prime numbers stream is an extreme case because the filters
% chain grows of one for each element (prime) generated:
%
%     % Generation of all the primes:
%     function so = primes
%     so = PrimesFrom(integersFrom(2));
%
%     % The filtering function add a new filter to the stream:
%     function so = PrimesFrom(si)
%     % The first number is ok:
%     val=head(si); so=tail(si);
%     % The others are filtered:
%     so = streamFilter(so,@(v,p)(mod(v,p)~=0),val);
%     % Composing:
%     so = {val,delayEval(@PrimesFrom,{so})};
%
%  This is really inefficient, also because the use of the recursion is
% heavy, but it's an approach that generates the required results:

% Creating the primes stream:
pr = primes;

% Extracting values:
streamHead(pr,20),

%% Conclusions
%  The stream programming is a powerful technique to manage infinite
% sequences of elements, the lazy evaluation allows to manage this
% particular entities easily, this implementation of streams in Matlab does
% not look at computational complexity but an efficient version can be
% implemented. Tools like Simulink, Labview, HP-VEE gives the stream
% programming as a base programming tool and a graphical environment to
% generate programs connecting stream generators, operators and consumers.
% The stream programming can be an useful tool also in programs written in
% other procedural languages like Python or Java, the power is big.. but
% the diffusion of this technique is not :(


function a = clement1_inverse ( n )

%*****************************************************************************80
%
%% CLEMENT1_INVERSE returns the inverse of the CLEMENT1 matrix.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    03 October 2007
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer N, the order of A.  N must not be odd%
%
%    Output, real A(N,N), the matrix.
%
  if ( mod ( n, 2 ) == 1 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'CLEMENT1_INVERSE - Fatal error!\n' );
    fprintf ( 1, '  The matrix is singular for odd N.\n' );
    error ( 'CLEMENT1_INVERSE - Fatal error!' );
  end

  a = zeros ( n, n );

  for i = 1 : n

    if ( mod ( i, 2 ) == 1 )

      for j = i : 2 : n-1

        if ( j == i )
          prod = 1.0 / sqrt ( ( j * ( n - j ) ) );
        else
          prod = - prod ...
            * sqrt ( ( j - 1 ) * ( n + 1 - j ) ) ...
            / sqrt ( j * ( n - j ) );
        end

        a(i,j+1) = prod;
        a(j+1,i) = prod;

      end

    end

  end

  return
end


function PL=PL_Hata(fc,d,htx,hrx,Etype)
% Hata Model
% Input
%       fc    : carrier frequency[Hz]
%       d     : between base station and mobile station[m]
%       htx   : height of transmitter[m]
%       hrx   : height of receiver[m]
%       Etype : Environment Type('urban','suburban','open')
% output
%       PL    : path loss[dB]
if nargin<5, Etype = 'URBAN'; end
fc=fc/(1e6);
if fc>=150&&fc<=200, C_Rx = 8.29*(log10(1.54*hrx))^2 - 1.1;
 elseif fc>200, C_Rx = 3.2*(log10(11.75*hrx))^2 - 4.97;
 else   C_Rx = 0.8+(1.1*log10(fc)-0.7)*hrx-1.56*log10(fc);
end
PL = 69.55 +26.16*log10(fc) -13.82*log10(htx) -C_Rx ...
     +(44.9-6.55*log10(htx))*log10(d/1000);
EType = upper(Etype);
if EType(1)=='S',  PL = PL -2*(log10(fc/28))^2 -5.4;
  elseif EType(1)=='O'
    PL=PL+(18.33-4.78*log10(fc))*log10(fc)-40.97;
end


function [PSNR, y_est] = BM3D(y, z, sigma, profile, print_to_screen)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  BM3D is an algorithm for attenuation of additive white Gaussian noise from
%  grayscale images. This algorithm reproduces the results from the article:
%
%  [1] K. Dabov, A. Foi, V. Katkovnik, and K. Egiazarian, "Image Denoising
%      by Sparse 3D Transform-Domain Collaborative Filtering,"
%      IEEE Transactions on Image Processing, vol. 16, no. 8, August, 2007.
%      preprint at http://www.cs.tut.fi/~foi/GCF-BM3D.
%
%
%  FUNCTION INTERFACE:
%
%  [PSNR, y_est] = BM3D(y, z, sigma, profile, print_to_screen)
%
%  ! The function can work without any of the input arguments,
%   in which case, the internal default ones are used !
%
%  BASIC USAGE EXAMPLES:
%
%     Case 1) Using the default parameters (i.e., image name, sigma, etc.)
%
%      [PSNR, y_est] = BM3D;
%
%     Case 2) Using an external noisy image:
%
%      % Read a grayscale image and scale its intensities in range [0,1]
%      y = im2double(imread('Cameraman256.png'));
%      % Generate the same seed used in the experimental results of [1]
%      randn('seed', 0);
%      % Standard deviation of the noise --- corresponding to intensity
%      %  range [0,255], despite that the input was scaled in [0,1]
%      sigma = 25;
%      % Add the AWGN with zero mean and standard deviation 'sigma'
%      z = y + (sigma/255)*randn(size(y));
%      % Denoise 'z'. The denoised image is 'y_est', and 'NA = 1' because
%      %  the true image was not provided
%      [NA, y_est] = BM3D(1, z, sigma);
%      % Compute the putput PSNR
%      PSNR = 10*log10(1/mean((y(:)-y_est(:)).^2))
%      % show the noisy image 'z' and the denoised 'y_est'
%      figure; imshow(z);
%      figure; imshow(y_est);
%
%     Case 3) If the original image y is provided as the first input
%      argument, then some additional information is printed (PSNRs,
%      figures, etc.). That is, "[NA, y_est] = BM3D(1, z, sigma);" in the
%      above code should be replaced with:
%
%      [PSNR, y_est] = BM3D(y, z, sigma);
%
%
%  INPUT ARGUMENTS (OPTIONAL):
%
%     1) y (matrix M x N): Noise-free image (needed for computing PSNR),
%                           replace with the scalar 1 if not available.
%     2) z (matrix M x N): Noisy image (intensities in range [0,1] or [0,255])
%     3) sigma (double)  : Std. dev. of the noise (corresponding to intensities
%                          in range [0,255] even if the range of z is [0,1])
%     4) profile (char)  : 'np' --> Normal Profile
%                          'lc' --> Fast Profile
%     5) print_to_screen : 0 --> do not print output information (and do
%                                not plot figures)
%                          1 --> print information and plot figures
%
%  OUTPUTS:
%     1) PSNR (double)          : Output PSNR (dB), only if the original
%                                 image is available, otherwise PSNR = 0
%     2) y_est (matrix M x N): Final estimate (in the range [0,1])
%
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Copyright (c) 2006-2011 Tampere University of Technology.
% All rights reserved.
% This work should only be used for nonprofit purposes.
%
% AUTHORS:
%     Kostadin Dabov, email: dabov _at_ cs.tut.fi
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% In case, a noisy image z is not provided, then use the filename
%%%%  below to read an original image (might contain path also). Later,
%%%%  artificial AWGN noise is added and this noisy image is processed
%%%%  by the BM3D.
%%%%
image_name = [
%     'montage.png'
     'Cameraman256.png'
%     'boat.png'
%     'Lena512.png'
%     'house.png'
%     'barbara.png'
%     'peppers256.png'
%     'fingerprint.png'
%     'couple.png'
%     'hill.png'
%     'man.png'
    ];

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%  Quality/complexity trade-off profile selection
%%%%
%%%%  'np' --> Normal Profile (balanced quality)
%%%%  'lc' --> Low Complexity Profile (fast, lower quality)
%%%%
%%%%  'high' --> High Profile (high quality, not documented in [1])
%%%%
%%%%  'vn' --> This profile is automatically enabled for high noise
%%%%           when sigma > 40
%%%%
%%%%  'vn_old' --> This is the old 'vn' profile that was used in [1].
%%%%           It gives inferior results than 'vn' in most cases.
%%%%
if (exist('profile') ~= 1)
    profile         = 'np'; %% default profile
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%  Specify the std. dev. of the corrupting noise
%%%%
if (exist('sigma') ~= 1),
    sigma               = 25; %% default standard deviation of the AWGN
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% Following are the parameters for the Normal Profile.
%%%%

%%%% Select transforms ('dct', 'dst', 'hadamard', or anything that is listed by 'help wfilters'):
transform_2D_HT_name     = 'bior1.5'; %% transform used for the HT filt. of size N1 x N1
transform_2D_Wiener_name = 'dct';     %% transform used for the Wiener filt. of size N1_wiener x N1_wiener
transform_3rd_dim_name   = 'haar';    %% transform used in the 3-rd dim, the same for HT and Wiener filt.

%%%% Hard-thresholding (HT) parameters:
N1                  = 8;   %% N1 x N1 is the block size used for the hard-thresholding (HT) filtering
Nstep               = 3;   %% sliding step to process every next reference block
N2                  = 16;  %% maximum number of similar blocks (maximum size of the 3rd dimension of a 3D array)
Ns                  = 39;  %% length of the side of the search neighborhood for full-search block-matching (BM), must be odd
tau_match           = 3000;%% threshold for the block-distance (d-distance)
lambda_thr2D        = 0;   %% threshold parameter for the coarse initial denoising used in the d-distance measure
lambda_thr3D        = 2.7; %% threshold parameter for the hard-thresholding in 3D transform domain
beta                = 2.0; %% parameter of the 2D Kaiser window used in the reconstruction

%%%% Wiener filtering parameters:
N1_wiener           = 8;
Nstep_wiener        = 3;
N2_wiener           = 32;
Ns_wiener           = 39;
tau_match_wiener    = 400;
beta_wiener         = 2.0;

%%%% Block-matching parameters:
stepFS              = 1;  %% step that forces to switch to full-search BM, "1" implies always full-search
smallLN             = 'not used in np'; %% if stepFS > 1, then this specifies the size of the small local search neighb.
stepFSW             = 1;
smallLNW            = 'not used in np';
thrToIncStep        = 8;  % if the number of non-zero coefficients after HT is less than thrToIncStep,
                          % than the sliding step to the next reference block is incresed to (nm1-1)

if strcmp(profile, 'lc') == 1,

    Nstep               = 6;
    Ns                  = 25;
    Nstep_wiener        = 5;
    N2_wiener           = 16;
    Ns_wiener           = 25;

    thrToIncStep        = 3;
    smallLN             = 3;
    stepFS              = 6*Nstep;
    smallLNW            = 2;
    stepFSW             = 5*Nstep_wiener;

end

% Profile 'vn' was proposed in
%  Y. Hou, C. Zhao, D. Yang, and Y. Cheng, 'Comment on "Image Denoising by Sparse 3D Transform-Domain
%  Collaborative Filtering"', accepted for publication, IEEE Trans. on Image Processing, July, 2010.
% as a better alternative to that initially proposed in [1] (which is currently in profile 'vn_old')
if (strcmp(profile, 'vn') == 1) | (sigma > 40),

    N2                  = 32;
    Nstep               = 4;

    N1_wiener           = 11;
    Nstep_wiener        = 6;

    lambda_thr3D        = 2.8;
    thrToIncStep        = 3;
    tau_match_wiener    = 3500;
    tau_match           = 25000;

    Ns_wiener           = 39;

end

% The 'vn_old' profile corresponds to the original parameters for strong noise proposed in [1].
if (strcmp(profile, 'vn_old') == 1) & (sigma > 40),

    transform_2D_HT_name = 'dct';

    N1                  = 12;
    Nstep               = 4;

    N1_wiener           = 11;
    Nstep_wiener        = 6;

    lambda_thr3D        = 2.8;
    lambda_thr2D        = 2.0;
    thrToIncStep        = 3;
    tau_match_wiener    = 3500;
    tau_match           = 5000;

    Ns_wiener           = 39;

end

decLevel = 0;        %% dec. levels of the dyadic wavelet 2D transform for blocks (0 means full decomposition, higher values decrease the dec. number)
thr_mask = ones(N1); %% N1xN1 mask of threshold scaling coeff. --- by default there is no scaling, however the use of different thresholds for different wavelet decompoistion subbands can be done with this matrix

if strcmp(profile, 'high') == 1, %% this profile is not documented in [1]

    decLevel     = 1;
    Nstep        = 2;
    Nstep_wiener = 2;
    lambda_thr3D = 2.5;
    vMask = ones(N1,1); vMask((end/4+1):end/2)= 1.01; vMask((end/2+1):end) = 1.07; %% this allows to have different threhsolds for the finest and next-to-the-finest subbands
    thr_mask = vMask * vMask';
    beta         = 2.5;
    beta_wiener  = 1.5;

end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% Note: touch below this point only if you know what you are doing!
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%% Check whether to dump information to the screen or remain silent
dump_output_information = 1;
if (exist('print_to_screen') == 1) & (print_to_screen == 0),
    dump_output_information = 0;
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% Create transform matrices, etc.
%%%%
[Tfor, Tinv]   = getTransfMatrix(N1, transform_2D_HT_name, decLevel);     %% get (normalized) forward and inverse transform matrices
[TforW, TinvW] = getTransfMatrix(N1_wiener, transform_2D_Wiener_name, 0); %% get (normalized) forward and inverse transform matrices

if (strcmp(transform_3rd_dim_name, 'haar') == 1) | (strcmp(transform_3rd_dim_name(end-2:end), '1.1') == 1),
    %%% If Haar is used in the 3-rd dimension, then a fast internal transform is used, thus no need to generate transform
    %%% matrices.
    hadper_trans_single_den         = {};
    inverse_hadper_trans_single_den = {};
else
    %%% Create transform matrices. The transforms are later applied by
    %%% matrix-vector multiplication for the 1D case.
    for hpow = 0:ceil(log2(max(N2,N2_wiener))),
        h = 2^hpow;
        [Tfor3rd, Tinv3rd]   = getTransfMatrix(h, transform_3rd_dim_name, 0);
        hadper_trans_single_den{h}         = single(Tfor3rd);
        inverse_hadper_trans_single_den{h} = single(Tinv3rd');
    end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% 2D Kaiser windows used in the aggregation of block-wise estimates
%%%%
if beta_wiener==2 & beta==2 & N1_wiener==8 & N1==8 % hardcode the window function so that the signal processing toolbox is not needed by default
    Wwin2D = [ 0.1924    0.2989    0.3846    0.4325    0.4325    0.3846    0.2989    0.1924;
        0.2989    0.4642    0.5974    0.6717    0.6717    0.5974    0.4642    0.2989;
        0.3846    0.5974    0.7688    0.8644    0.8644    0.7688    0.5974    0.3846;
        0.4325    0.6717    0.8644    0.9718    0.9718    0.8644    0.6717    0.4325;
        0.4325    0.6717    0.8644    0.9718    0.9718    0.8644    0.6717    0.4325;
        0.3846    0.5974    0.7688    0.8644    0.8644    0.7688    0.5974    0.3846;
        0.2989    0.4642    0.5974    0.6717    0.6717    0.5974    0.4642    0.2989;
        0.1924    0.2989    0.3846    0.4325    0.4325    0.3846    0.2989    0.1924];
    Wwin2D_wiener = Wwin2D;
else
    Wwin2D           = kaiser(N1, beta) * kaiser(N1, beta)'; % Kaiser window used in the aggregation of the HT part
    Wwin2D_wiener    = kaiser(N1_wiener, beta_wiener) * kaiser(N1_wiener, beta_wiener)'; % Kaiser window used in the aggregation of the Wiener filt. part
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% If needed, read images, generate noise, or scale the images to the
%%%% [0,1] interval
%%%%
if (exist('y') ~= 1) | (exist('z') ~= 1)
    y        = im2double(imread(image_name));  %% read a noise-free image and put in intensity range [0,1]
    randn('seed', 0);                          %% generate seed
    z        = y + (sigma/255)*randn(size(y)); %% create a noisy image
else  % external images

    image_name = 'External image';

    % convert z to double precision if needed
    z = double(z);

    % convert y to double precision if needed
    y = double(y);

    % if z's range is [0, 255], then convert to [0, 1]
    if (max(z(:)) > 10), % a naive check for intensity range
        z = z / 255;
    end

    % if y's range is [0, 255], then convert to [0, 1]
    if (max(y(:)) > 10), % a naive check for intensity range
        y = y / 255;
    end
end

if (size(z,3) ~= 1) | (size(y,3) ~= 1),
    error('BM3D accepts only grayscale 2D images.');
end

% Check if the true image y is a valid one; if not, then we cannot compute PSNR, etc.
y_is_invalid_image = (length(size(z)) ~= length(size(y))) | (size(z,1) ~= size(y,1)) | (size(z,2) ~= size(y,2));
if (y_is_invalid_image),
    dump_output_information = 0;
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Print image information to the screen
%%%%
if dump_output_information == 1,
    fprintf('Image: %s (%dx%d), sigma: %.1f\n', image_name, size(z,1), size(z,2), sigma);
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% Step 1. Produce the basic estimate by HT filtering
%%%%
tic;
y_hat = bm3d_thr(z, hadper_trans_single_den, Nstep, N1, N2, lambda_thr2D,...
	lambda_thr3D, tau_match*N1*N1/(255*255), (Ns-1)/2, (sigma/255), thrToIncStep, single(Tfor), single(Tinv)', inverse_hadper_trans_single_den, single(thr_mask), Wwin2D, smallLN, stepFS );
estimate_elapsed_time = toc;

if dump_output_information == 1,
    PSNR_INITIAL_ESTIMATE = 10*log10(1/mean((y(:)-double(y_hat(:))).^2));
    fprintf('BASIC ESTIMATE, PSNR: %.2f dB\n', PSNR_INITIAL_ESTIMATE);
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% Step 2. Produce the final estimate by Wiener filtering (using the
%%%%  hard-thresholding initial estimate)
%%%%
tic;
y_est = bm3d_wiener(z, y_hat, hadper_trans_single_den, Nstep_wiener, N1_wiener, N2_wiener, ...
    'unused arg', tau_match_wiener*N1_wiener*N1_wiener/(255*255), (Ns_wiener-1)/2, (sigma/255), 'unused arg', single(TforW), single(TinvW)', inverse_hadper_trans_single_den, Wwin2D_wiener, smallLNW, stepFSW, single(ones(N1_wiener)) );
wiener_elapsed_time = toc;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% Calculate the final estimate's PSNR, print it, and show the
%%%% denoised image next to the noisy one
%%%%
y_est = double(y_est);

PSNR = 0; %% Remains 0 if the true image y is not available
if (~y_is_invalid_image), % checks if y is a valid image
    PSNR = 10*log10(1/mean((y(:)-y_est(:)).^2)); % y is valid
end

if dump_output_information == 1,
    fprintf('FINAL ESTIMATE (total time: %.1f sec), PSNR: %.2f dB\n', ...
        wiener_elapsed_time + estimate_elapsed_time, PSNR);

    figure, imshow(z); title(sprintf('Noisy %s, PSNR: %.3f dB (sigma: %d)', ...
        image_name(1:end-4), 10*log10(1/mean((y(:)-z(:)).^2)), sigma));

    figure, imshow(y_est); title(sprintf('Denoised %s, PSNR: %.3f dB', ...
        image_name(1:end-4), PSNR));

end

return;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Some auxiliary functions
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function [Tforward, Tinverse] = getTransfMatrix (N, transform_type, dec_levels)
%
% Create forward and inverse transform matrices, which allow for perfect
% reconstruction. The forward transform matrix is normalized so that the
% l2-norm of each basis element is 1.
%
% [Tforward, Tinverse] = getTransfMatrix (N, transform_type, dec_levels)
%
%  INPUTS:
%
%   N               --> Size of the transform (for wavelets, must be 2^K)
%
%   transform_type  --> 'dct', 'dst', 'hadamard', or anything that is
%                       listed by 'help wfilters' (bi-orthogonal wavelets)
%                       'DCrand' -- an orthonormal transform with a DC and all
%                       the other basis elements of random nature
%
%   dec_levels      --> If a wavelet transform is generated, this is the
%                       desired decomposition level. Must be in the
%                       range [0, log2(N)-1], where "0" implies
%                       full decomposition.
%
%  OUTPUTS:
%
%   Tforward        --> (N x N) Forward transform matrix
%
%   Tinverse        --> (N x N) Inverse transform matrix
%

if exist('dec_levels') ~= 1,
    dec_levels = 0;
end

if N == 1,
    Tforward = 1;
elseif strcmp(transform_type, 'hadamard') == 1,
    Tforward    = hadamard(N);
elseif (N == 8) & strcmp(transform_type, 'bior1.5')==1 % hardcoded transform so that the wavelet toolbox is not needed to generate it
    Tforward =  [ 0.353553390593274   0.353553390593274   0.353553390593274   0.353553390593274   0.353553390593274   0.353553390593274   0.353553390593274   0.353553390593274;
       0.219417649252501   0.449283757993216   0.449283757993216   0.219417649252501  -0.219417649252501  -0.449283757993216  -0.449283757993216  -0.219417649252501;
       0.569359398342846   0.402347308162278  -0.402347308162278  -0.569359398342846  -0.083506045090284   0.083506045090284  -0.083506045090284   0.083506045090284;
      -0.083506045090284   0.083506045090284  -0.083506045090284   0.083506045090284   0.569359398342846   0.402347308162278  -0.402347308162278  -0.569359398342846;
       0.707106781186547  -0.707106781186547                   0                   0                   0                   0                   0                   0;
                       0                   0   0.707106781186547  -0.707106781186547                   0                   0                   0                   0;
                       0                   0                   0                   0   0.707106781186547  -0.707106781186547                   0                   0;
                       0                   0                   0                   0                   0                   0   0.707106781186547  -0.707106781186547];
elseif (N == 8) & strcmp(transform_type, 'dct')==1 % hardcoded transform so that the signal processing toolbox is not needed to generate it
    Tforward = [ 0.353553390593274   0.353553390593274   0.353553390593274   0.353553390593274   0.353553390593274   0.353553390593274   0.353553390593274   0.353553390593274;
       0.490392640201615   0.415734806151273   0.277785116509801   0.097545161008064  -0.097545161008064  -0.277785116509801  -0.415734806151273  -0.490392640201615;
       0.461939766255643   0.191341716182545  -0.191341716182545  -0.461939766255643  -0.461939766255643  -0.191341716182545   0.191341716182545   0.461939766255643;
       0.415734806151273  -0.097545161008064  -0.490392640201615  -0.277785116509801   0.277785116509801   0.490392640201615   0.097545161008064  -0.415734806151273;
       0.353553390593274  -0.353553390593274  -0.353553390593274   0.353553390593274   0.353553390593274  -0.353553390593274  -0.353553390593274   0.353553390593274;
       0.277785116509801  -0.490392640201615   0.097545161008064   0.415734806151273  -0.415734806151273  -0.097545161008064   0.490392640201615  -0.277785116509801;
       0.191341716182545  -0.461939766255643   0.461939766255643  -0.191341716182545  -0.191341716182545   0.461939766255643  -0.461939766255643   0.191341716182545;
       0.097545161008064  -0.277785116509801   0.415734806151273  -0.490392640201615   0.490392640201615  -0.415734806151273   0.277785116509801  -0.097545161008064];
elseif (N == 8) & strcmp(transform_type, 'dst')==1 % hardcoded transform so that the PDE toolbox is not needed to generate it
    Tforward = [ 0.161229841765317   0.303012985114696   0.408248290463863   0.464242826880013   0.464242826880013   0.408248290463863   0.303012985114696   0.161229841765317;
       0.303012985114696   0.464242826880013   0.408248290463863   0.161229841765317  -0.161229841765317  -0.408248290463863  -0.464242826880013  -0.303012985114696;
       0.408248290463863   0.408248290463863                   0  -0.408248290463863  -0.408248290463863                   0   0.408248290463863   0.408248290463863;
       0.464242826880013   0.161229841765317  -0.408248290463863  -0.303012985114696   0.303012985114696   0.408248290463863  -0.161229841765317  -0.464242826880013;
       0.464242826880013  -0.161229841765317  -0.408248290463863   0.303012985114696   0.303012985114696  -0.408248290463863  -0.161229841765317   0.464242826880013;
       0.408248290463863  -0.408248290463863                   0   0.408248290463863  -0.408248290463863                   0   0.408248290463863  -0.408248290463863;
       0.303012985114696  -0.464242826880013   0.408248290463863  -0.161229841765317  -0.161229841765317   0.408248290463863  -0.464242826880013   0.303012985114696;
       0.161229841765317  -0.303012985114696   0.408248290463863  -0.464242826880013   0.464242826880013  -0.408248290463863   0.303012985114696  -0.161229841765317];
elseif strcmp(transform_type, 'dct') == 1,
    Tforward    = dct(eye(N));
elseif strcmp(transform_type, 'dst') == 1,
    Tforward    = dst(eye(N));
elseif strcmp(transform_type, 'DCrand') == 1,
    x = randn(N); x(1:end,1) = 1; [Q,R] = qr(x);
    if (Q(1) < 0),
        Q = -Q;
    end;
    Tforward = Q';
else %% a wavelet decomposition supported by 'wavedec'
    %%% Set periodic boundary conditions, to preserve bi-orthogonality
    dwtmode('per','nodisp');

    Tforward = zeros(N,N);
    for i = 1:N
        Tforward(:,i)=wavedec(circshift([1 zeros(1,N-1)],[dec_levels i-1]), log2(N), transform_type);  %% construct transform matrix
    end
end

%%% Normalize the basis elements
Tforward = (Tforward' * diag(sqrt(1./sum(Tforward.^2,2))))';

%%% Compute the inverse transform matrix
Tinverse = inv(Tforward);

return;


function [fDeltaProbability, fProbabilityN, fProbabilityH, mPredictionFMD, vObservedFMD, vMagnitudeBins, vProbH, vProbN] ...
        = pt_poissonian(mLearningCatalog, fLearningTime, mObservedCatalog, fObservedTime, nMinimumNumber, fBValueH, fBValueN, ...
        fMcH, fMcN, fMinMag, fMaxMag)
    % Calculation of likelihoods for two models based on a- and b-values
    %
    % [fDeltaProbability, fProbabilityN, fProbabilityH, mPredictionFMD, vObservedFMD, vMagnitudeBins, vProbH, vProbN]
    %   = pt_poissonian(mLearningCatalog, fLearningTime, mObservedCatalog, fObservedTime, nMinimumNumber, fBValueH, fBValueN,
    %                   fMcH, fMcN, fMinMag, fMaxMag);
    %
    %
    % Input parameters:
    %   mLearningCatalog    Earthquake catalog of the learning period
    %   fLearningTime       Length of learning period (can be different than the exact length of mLearningCatalog)
    %   mObservedCatalog    Earthquake catalog of the observed period
    %   fObservedTime       Length of observed period (can be different than the exact length of mObservedCatalog)
    %   nMinimumNumber      Minimum number of earthquakes in the catalog for calculating the output values
    %   fBValueH            b-value for test hypothesis
    %   fBValueN            b-value for null hypothesis
    %   fMcH                Magnitude of completeness for the test hypothesis
    %   fMcN                Magnitude of completeness for the null hypothesis
    %   fMinMag             Minimum magnitude for testing
    %   fMaxMag             Maximum magnitude for testing
    %
    % Output parameters:
    %   fDeltaProbability   Difference of the log-likelihood between both of the models
    %   fProbabilityN       Log-likelihood of the null hypothesis
    %   fProbabilityH       Log-likelihood of the test hypothesis
    %   mPredictionFMD      Forecasted FMD of both models (mPredictionFMD(:,1) test hypothesis, (:,2) null hypothesis)
    %   vObservedFMD        Vector with observations corresponding to mPredictionFMD
    %   vMAgnitudeBins      Vector containing the tested magnitude bins
    %   vProbH              log-likelihoods per magnitude bin of the test hypothesis
    %   vProbN              log-likelihoods per magnitude bin of the null hypothesis
    %
    % Danijel Schorlemmer
    % April 30, 2003

    report_this_filefun();

    % Index description
    % xxxxN : Variable with a value for the null hypothesis model
    % xxxxH : Variable with a value for the hypothesis model

    if ((length(mLearningCatalog(:,1)) < nMinimumNumber) | (isnan(fBValueH)) | (isnan(fBValueN)))
        fDeltaProbability = nan;
        fProbabilityH = nan;
        fProbabilityN = nan;
        mPredictionFMD = [];
        vObservedFMD = [];
        vMagnitudeBins = [];
        vProbH = [];
        vProbN =[];
    else
        % Select the higher magnitude of completeness
        fMc = max([fMcH fMcN]);
        % Cut the first catalog at magnitude of completeness
        vSel = mLearningCatalog(:,6) >= fMc;
        mCalcACatalog = mLearningCatalog(vSel,:);
        if length(mCalcACatalog(:,1)) >= nMinimumNumber
            % Compute the maximum likelihood a-values for both models
            fAValueH = calc_MaxLikelihoodA(mCalcACatalog, fBValueH);
            fAValueN = calc_MaxLikelihoodA(mCalcACatalog, fBValueN);
            % Create the predicted FMD
            vCnt = (fMinMag:0.1:fMaxMag+0.1)'; % Add one more magnitude bin for later use of diff()
            vNumberH = 10.^(fAValueH - (fBValueH * vCnt))/fLearningTime * fObservedTime;
            vNumberN = 10.^(fAValueN - (fBValueN * vCnt))/fLearningTime * fObservedTime;
            mNumbers = [vNumberH vNumberN];
            % Determine the number of events in each magnitude bin
            mPredictionFMD = -diff(mNumbers);
            % Cut the second catalog at the minimum magnitude for testing
            vSel = mObservedCatalog(:,6) >= fMinMag;
            mCalcCatalog = mObservedCatalog(vSel,:);
            % Create the FMD for the period of observation
            vObservedFMD = histogram(mCalcCatalog(:,6), fMinMag:0.1:fMaxMag);
            % Calculate the likelihoods for both of the models
            vProbH = calc_logpoisspdf(vObservedFMD', mPredictionFMD(:,1));
            vProbN = calc_logpoisspdf(vObservedFMD', mPredictionFMD(:,2));
            % Return the values
            fProbabilityH = sum(vProbH);
            fProbabilityN = sum(vProbN);
            fDeltaProbability = fProbabilityN - fProbabilityH;
            vObservedFMD = vObservedFMD';   % Simply for returning the vector in the same way as vPredictionFMD
            vMagnitudeBins = (fMinMag:0.1:fMaxMag)';
        else
            fDeltaProbability = nan;
            fProbabilityH = nan;
            fProbabilityN = nan;
            mPredictionFMD = [];
            vObservedFMD = [];
            vMagnitudeBins = [];
            vProbH = [];
            vProbN =[];
        end
    end
end


% Frequency response Magnet Driver circuit network using DS method
%  and G array.
% File:  c:\M_files\short_updates\UsingGarray1.m
% 02/10/07
% See Word file UsingGarray1.doc for background explanations.
clear;clc;
% unit suffixes
u=1e-6;K=1e3;m=1e-3;u=1e-6;p=1e-12;
% component values
R1=5*K;R2=1*K;R3=10*K;
C1=0.1*u;C2=400*p;
Ein=1; % Unity input for (normalized) transfer function
N=2; % Number of capacitors = order of circuit
%
% Form W, Q, S, and P arrays:
%
W=[1+R3/R1 1+R3/R1;R2 0];Q=[0 -1/R1;-1 1];S=[Ein/R1;0];P=diag([C1 C2]);
%
% Get A, B, D, & E arrays:
%
C=inv(W*P);A=C*Q;B=C*S;
% D & E from the first output equation:
D1=[0 R1/(R1+R3)];E1=R3/(R1+R3);
% D & E from the second (easier) output equation:
D2=[0 1];E2=0;
%
% Now we can form the G array = F*P as follows.
%
F=[R3 R3]; % R3 is the coefficient of both iC1 and iC2 in Vo2
% which are derivative terms (iC=dVc/dt, etc.)
G=F*P;
%
% * * * * * * * * * * * * Frequency response * * * * * * * * * * * *
%
I=eye(N); % identity matrix
%
% Log frequency sweep from BF to BF+ND
%
BF=0;ND=4;PD=25;NP=ND*PD+1;Fr=logspace(BF,BF+ND,NP);
for i=1:NP
   s=2*pi*Fr(i)*j; % j = sqrt(-1)
   stm=(s*I-A)\B;v1=abs(D1*stm+E1);Vo1(i)=20*log10(v1);
   v2=abs((D2+G*A)*stm+E2+G*B);Vo2(i)=20*log10(v2);
end
%
% Plot frequency (Vo1 & Vo2 separated by 0.2 dBV to ovoid overlay)
%
h=plot(log10(Fr),Vo1-0.2,'b',log10(Fr),Vo2,'r');
set(h,'LineWidth',2);
grid on;
axis auto
ylabel('dBV');title('Magnet Driver Output');
xlabel('Log Freq(Hz)');
legend('Vo1 - 0.2','Vo2 using G array');
figure(1);
%


classdef SOP_F16 < PROBLEM
% <single> <real> <expensive/none>
% Six-hump camel-back function

%------------------------------- Reference --------------------------------
% X. Yao, Y. Liu, and G. Lin, Evolutionary programming made faster, IEEE
% Transactions on Evolutionary Computation, 1999, 3(2): 82-102.
%------------------------------- 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".
%--------------------------------------------------------------------------

    methods
        %% Default settings of the problem
        function Setting(obj)
            obj.M = 1;
            obj.D = 2;
            obj.lower    = zeros(1,obj.D) - 5;
            obj.upper    = zeros(1,obj.D) + 5;
            obj.encoding = ones(1,obj.D);
        end
        %% Calculate objective values
        function PopObj = CalObj(obj,PopDec)
            PopObj = 4*PopDec(:,1).^2-2.1*PopDec(:,1).^4+PopDec(:,1).^6/3+PopDec(:,1).*PopDec(:,2)-4*PopDec(:,2).^2+4*PopDec(:,2).^4;
        end
        %% Generate the minimum objective value
        function R = GetOptimum(obj,N)
            R = -1.0316;
        end
    end
end


function Y = invariantMultiply_new( A, X)
%
%           Y = invariantMultiply( A, X );
%
%  This function computes the multiplication of a spatially invariant
%  point spread function (PSF) times an image
%                y = A*x
%
%  Here we use a Kronecker product approach to better handle reflexive
%  boundary conditions
%
%  Input:
%            A  -  psfMatrix object
%            X  -  array containing the image to which the psfMatrix
%                  is to be multiplied.
%
%  Output:
%            Y  -  contains the result after PSF multiplication.
%

%  J. Nagy  7/5/2016

imsize = size( X );
psfMatData = A.matdata;

switch A.boundary
    case 'periodic'
        if A.transpose
            Y = real(ifft2(conj(psfMatData).*fft2(X)));
        else
            Y = real(ifft2(psfMatData.*fft2(X)));
        end
    case 'zero'
        p = A.p;
        padSize = [size(psfMatData,1),size(psfMatData,2)] - size(X);
        Xpad = padarray(X, padSize, 'post');
        Xtilde = fft2(Xpad);
        Xtilde = Xtilde(:,p(:,1));
        if A.transpose
            Y = conj(psfMatData(:,:,1)).*Xtilde;
        else
            Y = psfMatData(:,:,1).*Xtilde;
        end
        Y = real(ifft2(Y));
        Y = Y(:, p(:,1));
        Y = Y(1:imsize(1), 1:imsize(2));
    case 'reflexive'
        p = A.p;
        padSize = [size(psfMatData,1),size(psfMatData,2)] - size(X);
        Xpad = padarray(X, padSize, 'post');
        Xtilde = fft2(Xpad);
        Xtilde = Xtilde(:,p(:,1));
        if A.transpose
            term1 = conj(psfMatData(:,:,1)).*Xtilde;
            term2 = conj(psfMatData(:,:,2)).*Xtilde(:,p(:,1));
            term3 = conj(psfMatData(:,:,3)).*Xtilde(p(:,2),:);
            term4 = conj(psfMatData(:,:,4)).*Xtilde(p(:,2),p(:,1));
        else
            term1 = psfMatData(:,:,1).*Xtilde;
            term2 = psfMatData(:,:,2).*Xtilde;
            term2 = term2(:,p(:,1));
            term3 = psfMatData(:,:,3).*Xtilde;
            term3 = term3(p(:,2),:);
            term4 = psfMatData(:,:,4).*Xtilde;
            term4 = term4(p(:,2),p(:,1));
        end
        Y = real(ifft2(term1 + term2 + term3 + term4));
        Y = Y(:,p(:,1));
        Y = Y(1:imsize(1), 1:imsize(2));
    otherwise
        error('still working on this')
end


function varargout = imGradient(img, varargin)
% Compute gradient magnitude of a grayscale image.
%
%   [GX, GY] = imGradient(IMG);
%   [GX, GY, GZ] = imGradient(IMG);
%   Compute the components of the gradient vector of a 2D or a 3D image.
%   The gradient is computed in each orthogonal direction by using
%   normalised Sobel filters.
%   For a 2D image, gradient magnitude and angle can be computed from:
%   GMAG = hypot(GX, GY);
%   GANGLE = atan2(GY, GX);
%
%   GRAD = imGradient(IMG);
%   Compute an image of gradient magnitude. Magnitude is computed as:
%   - hypot(dx, dy) for 2D images
%   - hypot(hypot(dx, dy), dz) for 3D images
%
%   GRAD = imGradient(IMG, SIGMA);
%   Specifies the width of the kernel (2D only). The size of the kernel is
%   determined automatically from the SIGMA.
%
%   GRAD = imGradient(IMG, 'filter', FILTER);
%   Specifies the filter used for computing gradient in the X direction.
%   Note that fspecial('sobel') or fspecial('prewitt') return unnormalized
%   filters for the Y direction (horizontal gradient).
%
%   ... = imGradient(..., OPTION1, OPTION2...);
%   Will use the given set of options when computing the gradient filter.
%   See the documentation of imfilter for details.
%   Default options are 'conv' and 'replicate'.
%
%   Example
%   % display edge strength computed on cameraman picture
%     img = imread('cameraman.tif');
%     grad = imGradient(img);
%     imshow(grad, [0 max(grad(:))]);  colormap parula;
%     % use larger parameter for sigma
%     grad5 = imGradient(img, 5);
%     figure; imshow(grad5, [0 max(grad5(:))]); colormap parula;
%
%   % compute edge direction on rice picture
%     img = imread('rice.png');
%     [dx, dy] = imGradient(img);
%     grad = hypot(dx, dy);
%     theta = atan2(dy, dx);
%     rgb = angle2rgb(theta);     % convert to floating-point rgb
%     bin = grad>20;              % select only salient edges
%     rgb(~bin(:,:, [1 1 1])) = 0;% display salient edges orientation
%     imshow(rgb);
%
%   % Uses a different filter (the same as for the "gradient" function)
%     img = imread('cameraman.tif');
%     grad = imGradient(img, 'filter', [1 0 -1]);
%     imshow(grad, [0 max(grad(:))]);
%
%   See also
%     imLaplacian, imMorphoGradient, imHessian
%     imfilter, fspecial, angle2rgb, gradient

% ------
% Author: David Legland
% e-mail: david.legland@inrae.fr
% Created: 2009-08-19,    using Matlab 7.7.0.471 (R2008b)
% Copyright 2009 INRA - Cepia Software Platform.

% HISTORY
% 2010-01-13 add support for gradient direction and filter options
% 2010-02-16 change output format for 2 output parameters, add support
%   for 3D images, and add psb to change filter.
% 2010-03-03 use convolution by default
% 2010-03-05 return result as double, normalize default filter
% 2010-12-06 use 3D kernel by default for 3D images
% 2013-05-20 add support for variable kernel width (2D only)

%% Parse input arguments

% image dimension
dim = size(img);

% number of dimension of image (do not manage color images)
nd = length(dim);

% check if the width of the kernel is specified
sigma = 0;
if ~isempty(varargin)
    var1 = varargin{1};
    if isnumeric(var1) && isscalar(var1)
        sigma = var1;
        varargin(1) = [];
    end
end

% default filter for gradient: normalised sobel
if nd <= 2
    sx = gradientKernels(sigma);
elseif nd == 3
    sx = gradientKernels3d(sigma);
else
    error('Input image must have 2 or 3 dimensions');
end

% check if another gradient filter is proposed
for i = 1:length(varargin)-1
    if strcmp(varargin{i}, 'filter')
        sx = varargin{i+1};
        varargin(i:i+1) = [];
        break;
    end
end

% default options for computations
varargin = [{'replicate'}, {'conv'}, varargin];

%% Gradient computation

% compute gradients in each main direction
if nd == 2
    % Process 2D Image
    dx = imfilter(double(img), sx, varargin{:});
    dy = imfilter(double(img), sx', varargin{:});

elseif nd == 3
    % Process 3D Image
    sy = permute(sx, [2 3 1]);
    sz = permute(sx, [3 1 2]);
    dx = imfilter(double(img), sx, varargin{:});
    dy = imfilter(double(img), sy, varargin{:});
    dz = imfilter(double(img), sz, varargin{:});
end

%% Format output

% Depending on number of output arguments, returns either the gradient
% module, or each component of the gradient vector.
if nargout == 1
    % compute gradient module
    if nd == 2
        varargout{1} = hypot(dx, dy);
    else
        varargout{1} = hypot(hypot(dx, dy), dz);
    end

else
    % return each component of the vector array
    varargout{1} = dx;
    varargout{2} = dy;
    if nd > 2
        varargout{3} = dz;
    end
end


function Y = ttm(X,V,varargin)
%TTM Sparse tensor times matrix.
%
%   Y = TTM(X,A,N) computes the n-mode product of the sptensor X with
%   a dense matrix A; i.e., X x_N A.  The integer N specifies the
%   dimension (or mode) of X along which A should be multiplied.  If
%   size(A) = [J,I], then X must have size(X,N) = I.  The result will
%   will be a (dense) tensor or sptensor of the same order and size as X
%   except that size(Y,N) = J.
%
%   Y = TTM(X,{A,B,C,...}) computes the n-mode product of the sptensor
%   X with a sequence of matrices in the cell array.  The n-mode
%   products are computed sequentially along all dimensions (or modes)
%   of X. The cell array contains ndims(X) matrices.
%
%   Y = TTM(X,{A,B,C,...},DIMS) computes the sequence tensor-matrix
%   products along the dimensions specified by DIMS.
%
%   Y = TTM(...,'t') performs the same computations as above except
%   the matrices are transposed.
%
%   Examples
%   X = sptenrand([5 3 4 2], 10);
%   A = rand(4,5); B = rand(4,3); C = rand(3,4); D = rand(3,2);
%   Y = ttm(X, A, 1)         %<-- computes X times A in mode-1
%   Y = ttm(X, {A,B,C,D}, 1) %<-- same as above
%   Y = ttm(X, A', 1, 't')   %<-- same as above
%   Y = ttm(X, {A,B,C,D}, [1 2 3 4]) %<-- 4-way multiply
%   Y = ttm(X, {D,C,B,A}, [4 3 2 1]) %<-- same as above
%   Y = ttm(X, {A,B,C,D})            %<-- same as above
%   Y = ttm(X, {A',B',C',D'}, 't')   %<-- same as above
%   Y = ttm(X, {C,D}, [3 4])     %<-- X times C in mode-3 & D in mode-4
%   Y = ttm(X, {A,B,C,D}, [3 4]) %<-- same as above
%   Y = ttm(X, {A,B,D}, [1 2 4])   %<-- 3-way multiply
%   Y = ttm(X, {A,B,C,D}, [1 2 4]) %<-- same as above
%   Y = ttm(X, {A,B,D}, -3)        %<-- same as above
%   Y = ttm(X, {A,B,C,D}, -3)      %<-- same as above
%
%   See also SPTENSOR, TENSOR/TTM.
%
%MATLAB Tensor Toolbox.
%Copyright 2012, Sandia Corporation.

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

%% Check the number of arguments
if (nargin < 2)
    error('TTM requires at least two arguments.');
end

%% Create 'n' and 'tflag' arguments from varargin
n = 1:ndims(X);
tflag = '';
if numel(varargin) == 1
    if ischar(varargin{1})
        tflag = varargin{1};
    else
        n = varargin{1};
    end
elseif numel(varargin) == 2
    n = varargin{1};
    tflag = varargin{2};
end

%% Handle cell array
if iscell(V)
    % Copy n into dims
    dims = n;
    % Check that the dimensions are valid
    [dims,vidx] = tt_dimscheck(dims,ndims(X),numel(V));
    % Calculate individual products
    Y = ttm(X, V{vidx(1)}, dims(1), tflag);
    for i = 2 : numel(dims)
        Y = ttm(Y, V{vidx(i)}, dims(i), tflag);
    end
    % All done
    return;
end

%% Check the second argument
if ndims(V) ~= 2
    error('tensor/ttm: 2nd argument must be a matrix.');
end

%% Flip V is transposed
if tflag == 't'
    V = V';
end

%% Check n
if numel(n) ~= 1 || (n < 0) || (n > ndims(X))
    error('Dimension N must be between 1 and NDIMS(X).');
end

%% Compute the product

% Check that sizes match!
if size(X,n) ~= size(V,2)
    error('Size mismatch on V');
end

% Compute the new size
siz = size(X);
siz(n) = size(V,1);

% Compute Xn'
Xnt = sptenmat(X,n,'t');

% Extract the dimensions
rdims = Xnt.rdims;
cdims = Xnt.cdims;

% Convert to sparse matrix and do the multiplication; result is generally a
% dense matrix
Z = double(Xnt) * V';

if nnz(Z) <= 0.5 * prod(siz)
    % Final result is a *sparse* tensor
    Ynt = sptenmat(Z, rdims, cdims, siz);
    Y = sptensor(Ynt);
else
    % Final result is a *dense* tensor
    Ynt = tenmat(Z, rdims, cdims, siz);
    Y = tensor(Ynt);
end

end