% collapseDim() - collapse a range of values across a chosen dimension
%                 using the chosen method (e.g., average, peak, integral).
%
% Inputs:
%   C           -   [Nchs x Nchs x DIM3 x Dim4 x ... ] connectivity matrix.
%
% Optional:
%   'dim'         -   the dimension to collapse {def: 3}
%   'range'       -   [min-idx max-idx] index range to collapse.
%                     If range is a single value, than the layer for that
%                     index only is returned. {def: collapse entire dim}
%   'method'      -   ['mean' | 'net' | 'peak']. 'net' applies the trapz()
%                     integral ('dx' option must be set) {def: 'mean'}
%                 -   if method=@fcn, then function fcn() will be applied.
%                     This function must take a matrix as first argument
%                     and a dimension across which to evaluate as the
%                     second arg.
%   'dx'          -   [real] Required if 'method'='net'. This is the
%                     spacing increment (in same units as dataset)for trapz
%                     e.g., if integrating across frequency with freq.
%                     spacing of 0.5Hz, then dx=0.5;
%   'peakWidth'   -   [real] The width (in points) over which to identify
%                     a local peak. e.g., if peakWidth is 10, C(n,n,f) is
%                     only a peak if C(n,n,f:f-5)<C(n,n,f)>C(n,n,f:f+5)
%   'numPeaks'    -   [real] maximum number of peaks to return [if
%                     method='peaks' or 'peaks2d']
% Output:
%   C       -   collapsed [Nchs x Nchs x ... x 1 x ...] matrix with
%               dimension 'dim' reduced to a singleton
%   peaks   -   [Nchs x Nchs x ... x (numdims(C)-1) x Npeaks]
%               matrix containing indicies of peaks along the collapsed
%               dimension.
%
% Example:  collapse C(:,:,10:50) using integral with unit spacing
%           C2 = collapseDim(C,'dim',3,'range',[10 50],'method','net','dx',1)
%
% SEE ALSO
% localmax(), CAT
%
% Copyright (c) 2008 by Tim Mullen
function [C peaks] = collapseDim(C,varargin)

if nargin<2
    help collapseFreqs;
    return;
end

peaks = [];

range = [];
method = 'mean';
peakWidth = 20;
dim = 3;
dx = 0;
mph = -Inf;
numPeaks = 1;
keepedges = 1;
extent = 0;

for i=1:2:length(varargin)-1
    switch varargin{i}
        case 'range',       range = varargin{i+1};
        case 'method',      method = varargin{i+1};
        case 'dx',          dx = varargin{i+1};
        case 'dim',         dim = varargin{i+1};
        case 'peakWidth',   peakWidth = varargin{i+1};
        case 'numPeaks',    numPeaks = varargin{i+1};
        case 'minpeakheight', mph = varargin{i+1};
        case 'keepedges',   keepedges = varargin{i+1};
        case 'extent',      extent = varargin{i+1};
    end
end

if size(C,dim)==1
    return;
end

maxrange = size(C,dim);

if dim>length(size(C))
    error('The matrix does not have this many dimensions!');
end

% collapse over full range?
if isempty(range)
    range = [1 maxrange];
end

if length(range)>2
    error('range must be singleton or a 2-element [min max] vector');
end

% handle when single freq. input
if length(range)==1,
    C = getRange(C,dim,[range range]);
    return;
end

% range checking
if range(1)<1 || range(2)>maxrange
    error(sprintf(['range out of bounds\n' ...
                   'range must be between %d and %d'],...
                   1,maxrange));
   return;
end

switch lower(method)
    case 'mean'
        C = nan_mean(getRange(C,dim,range),dim);
    case 'net'
        if ~dx, error('''dx'' must be specified for ''net'' method'); end
        C = trapz(getRange(C,dim,range),dim);
        C = C.*dx;
    case 'peak'     % 1D peak detection
        [C peaks] = findConnPeaks(getRange(C,dim,range),dim, mph,peakWidth,numPeaks,keepedges,extent);
    case 'peak2d'   % 2D peak detection
%         C = getRange(C,dim,range);
        newC = zeros([size(C,1) size(C,2)],'single');
        peaks.freqs = zeros(size(C,1),size(C,2),numPeaks);
        peaks.times = zeros(size(C,1),size(C,2),numPeaks);
        if issymmetric(C)    % only estimate peaks for upper triangle (faster)
            for i=1:size(C,1)
                for j=i:size(C,2)
                    [pkval peaks.freqs(i,j,:) peaks.times(i,j,:)] = findpeaksND(squeeze(C(i,j,:,:)),peakWidth, true,numPeaks);   %max([size(C,3) size(C,4)])
                    newC(i,j) = pkval; %max(pkval);  % only return the maximum peak
                    newC(j,i) = newC(i,j);   % symmetric, so fill in lower triangle too
                end
            end
        else
            for i=1:size(C,1)
                for j=1:size(C,2)  % all channels

                    % new stuff
                    [pk] = imregionalmax(squeeze(C(i,j,:,:)));
                    if all(pk(:))
                        continue;  % no peak here
                    else
                        cc = squeeze(C(i,j,:,:));
                        [rows cols] = size(cc);
                        if extent
                            [ii jj] = find(pk);
                            for pp=1:length(ii)  % for each peak
                                % check if it's extent-neighborhood is
                                % greater than mph

                                if all(cc(setdiff_bc(max(1,ii-extent):min(rows,ii+extent),ii),setdiff_bc(max(1,jj-extent):min(cols,jj+extent),jj))<=mph)
                                    pk(ii,jj)=0;
                                end
                            end
                            if ~any(pk(:)), continue; end
                        end

                        cc = cc.*pk;
                        [newC(i,j) ii] = max(cc(:));
                        [peaks.freqs(i,j) peaks.times(i,j)] = ind2sub(size(cc),ii);

                    end

                end
            end
        end
        C = newC;

    case 'maxmag'
        % 1-D max magnitude (max of absval) along dimension dim
        [C peaks] = max(abs(getRange(C,dim,range)),[],dim);
    case 'max'
        % 1-D max along dimension dim
        [C peaks] = max(getRange(C,dim,range),[],dim);
    case 'min'
        % 1-D min along dimension dim
        [C peaks] = min(getRange(C,dim,range),[],dim);
    case {'getrange' 'shrinkonly'}
        C = getRange(C,dim,range);
    otherwise
        try
            C = feval(method,getRange(C,dim,range),dim);
        catch
            error('could not evaluate function');
        end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% extract a range of values from a specified dim
function C = getRange(C,dim,range)

numdims = length(size(C));

st = '';
for i=1:numdims
    st = fastif(dim==i,[st ' range(1):range(2),'],[st ':,']);
end
st(end) = [];

eval(['C = C( ' st ');']);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function [Cout pidxs] = findConnPeaks(C,dim,mph,mpd,npeaks,keepedges,extent)
    % C is [nchs nchs dim3 dim4]
    % dim is the dimension to find 1-d peaks along (this dimension will be
    % collapsed to a singleton)
    % output is same size as C with singleton dimension dim
    % mph is the minimum peak heights
    % mpd is the minimum distance between peaks
    % npeaks is the max number of peaks to return
    % keepedges determines whether or not to count a max at the series edge
    %   as a peak
    % extent determines the number of pixels adjecent to a peak that must
    % be greater than mph

    if nargin<6
        keepedges = 0;
    end

    if nargin<7
        extent = 0;
    end

    warning off

    verb = 0;

    if nargin<5
        npeaks = 10;    % number of top peaks to store in pidxs
    end

    % permute C so we are finding peaks over last (4th) dimension
    permutation = [1 2 fastif(dim==3,[4 3],[3 4])];
    C=permute(C,permutation);

    [rows cols nd3 nd4] = size(C);
    pidxs = zeros(rows,cols,nd3,npeaks);
    Cout = zeros(rows,cols,nd3);

    if nd3>10
        fprintf('warning: searching for peaks over %d series -- this may take a while...\n',nd3);
        verb=1;
    end
    if verb, h=waitbar(0,'searching for peaks...'); cur=1; end
    for kk=1:nd3
        for ch1=1:rows
            for ch2=1:cols
                series = [squeeze(C(ch1,ch2,kk,:))];
                if keepedges==0
                    [peaks locs] = findpeaks(series,length(series),extent,0,mph);
                else
                    [peaks locs] = findpeaks([0 ; series ; 0],length(series),extent,0,mph);
                end
                locs = round(locs);

                if ~isempty(locs)
                    pidxs(ch1,ch2,kk,1:min(length(locs),npeaks)) = ...          % keep indices of npeaks largest peak
                        locs(1:min(length(locs),npeaks))-keepedges;             % -1 to counteract zero-padding
                    Cout(ch1,ch2,kk)=peaks(1);                                  % store largest peak value
                else
                    pidxs(ch1,ch2,kk,:)=nan;
                    Cout(ch1,ch2,kk)=nan;
                end

                if verb, waitbar(cur/(nd3*rows*cols),h); cur=cur+1; end

            end
        end

        if ~mod(kk,10), fprintf('.'); end
    end

    if verb, close(h); end
    warning on;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function sym = issymmetric(C)
% check if C is symmetric along the first two dimensions

sym = 1;

sz = size(C);

for i=1:sz(1)
    for j=1:sz(2)
        if ~isequal(C(i,j,:,:,:,:),C(j,i,:,:,:,:))
            sym = 0;
            return;
        end
    end
end


function recon_im = sense_recon(smap, reduced_fft, reduced_dim, np, regularizer, mask, figs_on)
% function recon_im = sense_recon(smap, reduced_fft, reduced_dim, np,
%       regularizer, figs_on)
% in:
%   smap          [N M nc]                complex sensitivity maps
%   reduced_fft   [N/np M] or [N M/np]    undersampled fft
%   reduced_dim   1 or 2                  dimension of undersampling
%   np            degree of undersampling
%   regularizer   string, 'none' or 'tikhonov'
%   mask          [N M] boolean
%   figs_on       boolean that shows intermediate images for debugging
% out:
%   recon_im      [N M]                   SENSE reconstructed image
% This implementation assumes that the fft will be reduced in such a way
% that the DC term is still included (i.e. even DFT coefficients retained)
% 2012-06-07 Mai Le, University of Michigan

assert(isequal(size(mask), size(squeeze(smap(:,:,1)))), 'mask size does not match image size');

% dimensions of original image
dims = [size(smap,1) size(smap,2)];

% number of coils
nc = size(smap,3);

% create aliased intermediate images
aliased_im = zeros(size(reduced_fft,1), size(reduced_fft,2), nc);
for ii = 1:nc
     aliased_im(:,:,ii) = ifft2(reduced_fft(:,:,ii));
end

% plot aliased images
if (figs_on)
    figure;
    for ii = 1:nc
        subplot(2,2,ii); imshow(abs(aliased_im(:,:,ii)),[]); colorbar;
    end
end

% calculate regularization parameter
% I found empirically that somewhere between 0.5% and 1% of the max SVD
% value works well for beta
C = Cdiff1(np);
[U, SIG, V] = svd(C'*C);
% beta = 0.01*max(SIG(:));
beta = 0.005*max(SIG(:));

% reconstruct image by finding (regularized) LS solution for each set of pixels
recon_im = zeros(dims);
indeces = (0:np-1)*dims(reduced_dim)/np;
if (reduced_dim == 1)
    for ii = 1:dims(1)/np
        for jj = 1:dims(2)
            if any(mask(ii+indeces,jj))
%                 S = constructS(reduced_dim, smap, ii+indeces, jj, np);
                ivect = ii+indeces;
                S = squeeze([smap(ivect(mask(ii+indeces,jj)),jj,:)]).';
                if ~all(mask(ii+indeces,jj))
                    S = S.';
                end
                a = squeeze([aliased_im(ii,jj,1:nc)]);
                v = recon_pixels(S,a,regularizer, beta);
                [recon_im] = place_pixels(recon_im, v, reduced_dim, dims, ii, jj, np, mask(ii+indeces,jj));
            end
        end
    end
else
    for ii = 1:dims(1)
        for jj = 1:dims(2)/np
            if any(mask(ii,jj+indeces))
%                 S = constructS(reduced_dim, smap, ii, jj+indeces, np, mask(ii,jj+indeces));
                jvect = jj+indeces;
                S = squeeze([smap(ii,jvect(mask(ii,jj+indeces)),:)]).';
                if ~all(mask(ii,jj+indeces))
                    S = S.';
                end
                a = squeeze([aliased_im(ii,jj,1:nc)]);
                v = recon_pixels(S,a,regularizer, beta);
                [recon_im] = place_pixels(recon_im, v, reduced_dim, dims, ii, jj, np, mask(ii,jj+indeces));
            end
        end
    end
end
% figure; subplot(121); imshow(test_fill,[]); colorbar;
% subplot(122); imshow(real(recon_im),[]); colorbar;
% keyboard;

% selects values from sensitivity map relevant for specific pixels
% depending on reduced_dim, either ivect or jvect is a 1x2 vector
% function S = constructS(reduced_dim, smap, ivect, jvect, np, mask_vector)
%
%
% S = squeeze([smap(ivect,jvect(mask_vector),:)]).';

% places each of the reconstructed pixels in the reconstructed image
function [recon_im] = place_pixels(recon_im, v, reduced_dim, dims, ii, jj, np, mask)
indeces = (0:np-1)*dims(reduced_dim)/np;
if (reduced_dim == 1)
    mk = 1;
    vk = 1;
    while (mk <= np)
        if (mask(mk))
            recon_im(ii+indeces(mk),jj) = v(vk);
            vk = vk + 1;
        end
        mk = mk + 1;
    end
else
    vk = 1;
    mk = 1;
    while (mk <= np)
        if (mask(mk))
            recon_im(ii,jj+indeces(mk)) = v(vk);
            vk = vk + 1;
        end
        mk = mk + 1;
    end
end

% reconstruct pixels with or without Tikhonov regularization
function pixels = recon_pixels(S,a,regularizer, beta)
switch regularizer
    case 'none'
        pixels = S\a;
    case 'tikhonov'
        M = min(size(S));
        pixels = inv(S'*S+(beta^2)*eye(M))*S'*a;
    otherwise
        pixels = S\a;
end


function [ferns,hsPr] = fernsClfChangeNFerns( data, hs, ferns, Mnew, varargin )
% Train random fern classifier.
%
% See "Fast Keypoint Recognition in Ten Lines of Code" by Mustafa Ozuysal,
% Pascal Fua and Vincent Lepetit, CVPR07.
%
% Dimensions:
%  M - number ferns
%  S - fern depth
%  F - number features
%  N - number input vectors
%  H - number classes
%
% USAGE
%  [ferns,hsPr] = fernsClfTrain( data, hs, [varargin] )
%
% INPUTS
%  data     - [NxF] N length F feature vectors
%  hs       - [Nx1] target output labels in [1,H]
%  varargin - additional params (struct or name/value pairs)
%   .S        - [10] fern depth (ferns are exponential in S)
%   .M        - [50] number of ferns to train
%   .thrr     - [0 1] range for randomly generated thresholds
%   .bayes    - [1] if true combine probs using bayes assumption
%   .ferns    - [] if given reuse previous ferns (recompute pFern)
%
% OUTPUTS
%  ferns    - learned fern model w the following fields
%   .fids     - [MxS] feature ids for each fern for each depth
%   .thrs     - [MxS] threshold corresponding to each fid
%   .pFern    - [2^SxHxM] learned log probs at fern leaves
%   .bayes    - if true combine probs using bayes assumption
%   .inds     - [NxM] cached indices for original training data
%   .H        - number classes
%  hsPr     - [Nx1] predicted output labels
%
% EXAMPLE
%  N=5000; H=5; d=2; [xs0,hs0,xs1,hs1]=demoGenData(N,N,H,d,1,1);
%  fernPrm=struct('S',4,'M',50,'thrr',[-1 1],'bayes',1);
%  tic, [ferns,hsPr0]=fernsClfTrain(xs0,hs0,fernPrm); toc
%  tic, hsPr1 = fernsClfApply( xs1, ferns ); toc
%  e0=mean(hsPr0~=hs0); e1=mean(hsPr1~=hs1);
%  fprintf('errors trn=%f tst=%f\n',e0,e1); figure(1);
%  subplot(2,2,1); visualizeData(xs0,2,hs0);
%  subplot(2,2,2); visualizeData(xs0,2,hsPr0);
%  subplot(2,2,3); visualizeData(xs1,2,hs1);
%  subplot(2,2,4); visualizeData(xs1,2,hsPr1);
%
% See also fernsClfApply, fernsInds
%
% Piotr's Image&Video Toolbox      Version 2.50
% Copyright 2010 Piotr Dollar.  [pdollar-at-caltech.edu]
% Please email me if you find bugs, or have suggestions or questions!
% Licensed under the Lesser GPL [see external/lgpl.txt]

dfs={'thrr',[0 1],'tmp',''};
[thrr,~]=getPrmDflt(varargin,dfs,1);

[Mold,S] = size(ferns.fids);
[N,F]=size(data); assert(length(hs)==N);
H=max(hs); assert(all(hs>0)); assert(S<=20);

if Mnew == Mold,
elseif Mnew < Mold,
  Mremove = Mold - Mnew;
  % randomly choose some ferns to remove
  idx_remove = randsample(Mold,Mremove);
  ferns.fids(idx_remove,:) = [];
  ferns.thrs(idx_remove,:) = [];
  ferns.counts(:,:,idx_remove) = [];
  ferns.pFern(:,:,idx_remove) = [];
  ferns.inds(:,idx_remove) = [];
else

  Madd = Mnew - Mold;
  % create some new ferns
  thrs_add=rand(Madd,S)*(thrr(2)-thrr(1))+thrr(1);
  fids_add=uint32(floor(rand(Madd,S)*F+1));
  inds_add=fernsInds(data,fids_add,thrs_add);

  % store new ferns
  ferns.fids(Mold+1:Mnew,:) = fids_add;
  ferns.thrs(Mold+1:Mnew,:) = thrs_add;
  ferns.inds(:,Mold+1:Mnew) = inds_add;

  % get counts for each leaf for each class for each new fern
  pFern_add = nan(2^S,H,Madd);
  edges = 1:2^S;
  for m = 1:Madd,
    for h = 1:H,
      pFern_add(:,h,m) = histc(inds_add(hs==h,m),edges);
    end
  end
  pFern_add = pFern_add + ferns.bayes;
  ferns.counts(:,:,Mold+1:Mnew) = pFern_add;

  % convert fern leaf class counts into probabilities
  if( ferns.bayes<=0 )
    norm = 1./sum(pFern_add,2);
    pFern_add = bsxfun(@times,pFern_add,norm);
  else
    norm = 1./sum(pFern_add,1);
    pFern_add = bsxfun(@times,pFern_add,norm);
    pFern_add=log(pFern_add);
  end
  ferns.pFern(:,:,Mold+1:Mnew) = pFern_add;

  clear pFern;
end

if(nargout==2),
  hsPr=fernsClfApply([],ferns,ferns.inds);
end

end


classdef CustomSequence < IncrementalSequence

    properties (Access = public)
        factor
    end

    methods (Access = public)

        function obj = CustomSequence(x0,x1,nSteps,initialValue,finalValue)
            obj@IncrementalSequence(x0,x1,nSteps,initialValue,finalValue);
        end

    end

    methods (Access = protected)

        function generateAlphaSequence(obj)
            if obj.nSteps < 2
                x = x1;
            else
                iSteps = 0:obj.nSteps-1;
                x = 1-(1-iSteps/(obj.nSteps-1)).^(obj.factor);
                x = (x1-x0)*x + x0;
            end
            obj.alpha = x;
        end

    end

end


%This Matlab script can be used to reproduce Figure 5.8 in the monograph:
%
%Emil Bjornson, Jakob Hoydis and Luca Sanguinetti (2017),
%"Massive MIMO Networks: Spectral, Energy, and Hardware Efficiency",
%Foundations and Trends in Signal Processing: Vol. 11, No. 3-4,
%pp. 154-655. DOI: 10.1561/2000000093.
%
%For further information, visit: https://www.massivemimobook.com
%
%This is version 1.0 (Last edited: 2017-11-04)
%
%License: This code is licensed under the GPLv2 license. If you in any way
%use this code for research that results in publications, please cite our
%monograph as described above.

%Empty workspace and close figures
close all;
clear;

%% Propagation and hardware parameters

%Communication bandwidth
B = 0.1*10^(6); %100 kHz

%PA efficiency
mu = 0.4;

%Range of antenna-UE ratios
cRange = [1 2 4 8];

%Number of UEs
K = 10;

%Fixed circuit power per BS (in Watt)
P_FIX = 10;

%Circuit power per BS antenna (in Watt)
P_BS = 1;

%Circuit power UE (in Watt)
P_UE = 0.5;

%Range of SE values
sumSE = (0:0.00002:40)';

%Select ratio between noise power and beta_0^0
sigma2_beta = 10^(-6*0.1);

%Compute nu_0 in (5.14)
nu_0 = sigma2_beta/mu;

%Strength of inter-cell interference  = -15 dB
barbeta = 10^(-15/10);

%Prepare to save simulation results
EE = zeros(length(sumSE),length(cRange));
maxEE = zeros(length(cRange),1);
maxSE = zeros(length(cRange),1);

%% Go through range of antenna-UE ratios
for index1 = 1:length(cRange)

    %Compute number of BS antennas
    M = cRange(index1)*K;

    %Go through range of SE values
    for index2 = 1:length(sumSE)

        p = sigma2_beta*((M-1)/(2^sumSE(index2) - 1) - K*barbeta +1 - K)^-1;

        if p < 0

            break;

        end

        EE(index2,index1) = B*K*sumSE(index2)/(K*p/mu + P_FIX + M*P_BS + K*P_UE);

    end

    [max_value, index_max ] = max(EE(:,index1));

    maxEE(index1) = max_value;

    maxSE(index1) = K*sumSE(index_max);

end

%% Plot the simulation results
figure(1);
hold on; box on;

plot(K*sumSE,EE(:,1),'k','LineWidth',1);
plot(K*sumSE,EE(:,2),'k-.','LineWidth',1);
plot(K*sumSE,EE(:,3),'k--','LineWidth',1);
plot(K*sumSE,EE(:,4),'k:','LineWidth',1);

set(gca,'YScale','log');
xlabel('Sum SE [bit/s/Hz/cell]');
ylabel('EE [bit/Joule]');
legend('M/K = 1','M/K = 2','M/K = 4','M/K = 8','Location','NorthEast');

axis([0 max(sumSE) 10^2 10^6])

semilogy(maxSE,maxEE,'ro','LineWidth',1,'MarkerFaceColor','r');


%----------------------------------------------------------------
% Depth Map Super-Resolution by Deep Multi-Scale Guidance, ECCV16
%                     written by T.-W. HUI
%----------------------------------------------------------------
function Z = normalizeIm(Z, range)

if nargin < 2
    range = [0.01 1];
end

validMap = Z > 0;
Z = Z - min(Z(validMap));
Z = Z/max(Z(validMap));
Z(~validMap) = 0;
Z(validMap) = Z(validMap) + range(1);
Z = range(2)*Z/max(max(Z));

end


function c = tapas_hgf_ar1_config
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Contains the configuration for the Hierarchical Gaussian Filter (HGF) for AR(1)
% processes and continuous inputs.
%
% The HGF is the model introduced in
%
% Mathys C, Daunizeau J, Friston, KJ, and Stephan KE. (2011). A Bayesian foundation
% for individual learning under uncertainty. Frontiers in Human Neuroscience, 5:39.
%
% This file refers to CONTINUOUS inputs (Eqs 48ff in Mathys et al., (2011));
% for binary inputs, refer to tapas_hgf_ar1_binary_config.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% The HGF configuration consists of the priors of parameters and initial values. All priors are
% Gaussian in the space where the quantity they refer to is estimated. They are specified by their
% sufficient statistics: mean and variance (NOT standard deviation).
%
% Quantities are estimated in their native space if they are unbounded (e.g., the omegas). They are
% estimated in log-space if they have a natural lower bound at zero (e.g., the sigmas).
%
% The phis are estimated in 'logit space' because they are confined to the interval from 0 to 1.
% 'Logit-space' is a logistic sigmoid transformation of native space with a variable upper bound
% a>0:
%
% tapas_logit(x) = ln(x/(a-x)); x = a/(1+exp(-tapas_logit(x)))
%
% Parameters can be fixed (i.e., set to a fixed value) by setting the variance of their prior to
% zero. Aside from being useful for model comparison, the need for this arises whenever the scale
% and origin at the j-th level are arbitrary. This is the case if the observation model does not
% contain the representations mu_j and sigma_j. A choice of scale and origin is then implied by
% fixing the initial value mu_j_0 of mu_j and either kappa_j-1 or omega_j-1.
%
% Fitted trajectories can be plotted by using the command
%
% >> tapas_hgf_ar1_plotTraj(est)
%
% where est is the stucture returned by tapas_fitModel. This structure contains the estimated
% perceptual parameters in est.p_prc and the estimated trajectories of the agent's
% representations (cf. Mathys et al., 2011). Their meanings are:
%
%         est.p_prc.mu_0       row vector of initial values of mu (in ascending order of levels)
%         est.p_prc.sa_0       row vector of initial values of sigma (in ascending order of levels)
%         est.p_prc.phi        row vector of phis
%         est.p_prc.m          row vector of ms
%         est.p_prc.ka         row vector of kappas (in ascending order of levels)
%         est.p_prc.om         row vector of omegas (in ascending order of levels)
%         est.p_prc.al         alpha
%
%         est.traj.mu          mu (rows: trials, columns: levels)
%         est.traj.sa          sigma (rows: trials, columns: levels)
%         est.traj.muhat       prediction of mu (rows: trials, columns: levels)
%         est.traj.sahat       precisions of predictions (rows: trials, columns: levels)
%         est.traj.v           inferred variance of random walk (rows: trials, columns: levels)
%         est.traj.w           weighting factors (rows: trials, columns: levels)
%         est.traj.da          volatility prediction errors  (rows: trials, columns: levels)
%         est.traj.dau         input prediction error
%         est.traj.ud          updates with respect to prediction  (rows: trials, columns: levels)
%         est.traj.psi         precision weights on prediction errors  (rows: trials, columns: levels)
%         est.traj.epsi        precision-weighted prediction errors  (rows: trials, columns: levels)
%         est.traj.wt          full weights on prediction errors (at the first level,
%                                  this is the learning rate) (rows: trials, columns: levels)
%
% Tips:
% - When analyzing a new dataset, take your inputs u and use
%
%   >> est = tapas_fitModel([], u, 'tapas_hgf_ar1_config', 'tapas_bayes_optimal_config');
%
%   to determine the Bayes optimal perceptual parameters (given your current priors as defined in
%   this file here, so choose them wide and loose to let the inputs influence the result). You can
%   then use the optimal parameters as your new prior means for the perceptual parameters.
%
% - If you get an error saying that the prior means are in a region where model assumptions are
%   violated, lower the prior means of the omegas, starting with the highest level and proceeding
%   downwards.
%
% - Alternatives are lowering the prior means of the kappas, if they are not fixed, or adjusting
%   the values of the kappas or omegas, if any of them are fixed.
%
% - If the log-model evidence cannot be calculated because the Hessian poses problems, look at
%   est.optim.H and fix the parameters that lead to NaNs.
%
% - Your guide to all these adjustments is the log-model evidence (LME). Whenever the LME increases
%   by at least 3 across datasets, the adjustment was a good idea and can be justified by just this:
%   the LME increased, so you had a better model.
%
% --------------------------------------------------------------------------------------------------
% Copyright (C) 2012-2013 Christoph Mathys, TNU, UZH & ETHZ
%
% This file is part of the HGF toolbox, which is released under the terms of the GNU General Public
% Licence (GPL), version 3. You can redistribute it and/or modify it under the terms of the GPL
% (either version 3 or, at your option, any later version). For further details, see the file
% COPYING or <http://www.gnu.org/licenses/>.

% Config structure
c = struct;

% Model name
c.model = 'hgf_ar1';

% Number of levels (minimum: 2)
c.n_levels = 2;

% Input intervals
% If input intervals are irregular, the last column of the input
% matrix u has to contain the interval between inputs k-1 and k
% in the k-th row, and this flag has to be set to true
c.irregular_intervals = false;

% Sufficient statistics of Gaussian parameter priors

% PLACEHOLDER VALUES
% It is often convenient to set some priors to values
% derived from the inputs. This can be achieved by
% using placeholder values. The available placeholders
% are:
%
% 99991   Value of the first input
%         Usually a good choice for mu_0mu(1)
% 99992   Variance of the first 20 inputs
%         Usually a good choice for mu_0sa(1)
% 99993   Log-variance of the first 20 inputs
%         Usually a good choice for logsa_0mu(1)
%         and logalmu
% 99994   Log-variance of the first 20 inputs minus two
%         Usually a good choice for ommu(1)

% Initial mus and sigmas
% Format: row vectors of length n_levels
% For all but the first level, this is usually best
% kept fixed to 1 (determines origin on x_i-scale).
c.mu_0mu = [99991, 1];
c.mu_0sa = [99992, 0];

c.logsa_0mu = [99993, log(0.1)];
c.logsa_0sa = [    1,        1];

% Phis
% Format: row vector of length n_levels.
% Phi is estimated in logit-space because it is
% bounded between 0 and 1
% Fix this to zero (leading to a Gaussian random walk) by
% setting logitphimu = -Inf; logitphisa = 0;
c.logitphimu = [tapas_logit(0.1,1), -Inf];
c.logitphisa = [        10^2,    0];

% ms
% Format: row vector of length n_levels.
% This should be fixed for all levels where the omega of
% the next lowest level is not fixed because that offers
% an alternative parametrization of the same model.
c.mmu = [99991, c.mu_0mu(2)];
c.msa = [99992,           0];

% Kappas
% Format: row vector of length n_levels-1.
% This should be fixed (preferably to 1) if the observation model
% does not use mu_i+1 (kappa then determines the scaling of x_i+1).
c.logkamu = [log(1)];
c.logkasa = [     0];

% Omegas
% Format: row vector of length n_levels
c.ommu = [99994,   -6];
c.omsa = [ 10^2, 10^2];

% Alpha
% Format: scalar
% Fix this to zero (no percpeptual uncertainty) by setting
% logalmu = -Inf; logalsa = 0;
c.logalmu = 99993;
c.logalsa = 2^2;

% Gather prior settings in vectors
c.priormus = [
    c.mu_0mu,...
    c.logsa_0mu,...
    c.logitphimu,...
    c.mmu,...
    c.logkamu,...
    c.ommu,...
    c.logalmu,...
         ];

c.priorsas = [
    c.mu_0sa,...
    c.logsa_0sa,...
    c.logitphisa,...
    c.msa,...
    c.logkasa,...
    c.omsa,...
    c.logalsa,...
         ];

% Check whether we have the right number of priors
expectedLength = 4*c.n_levels+2*(c.n_levels-1)+2;
if length([c.priormus, c.priorsas]) ~= 2*expectedLength;
    error('tapas:hgf:PriorDefNotMatchingLevels', 'Prior definition does not match number of levels.')
end

% Model function handle
c.prc_fun = @tapas_hgf_ar1;

% Handle to function that transforms perceptual parameters to their native space
% from the space they are estimated in
c.transp_prc_fun = @tapas_hgf_ar1_transp;

return;


% test of Laplacian pyramid

n = 256;
name = 'lena';
M = load_image(name,n);
Jmin = 3;
MW = perform_pyramid_transform_simoncelli(M, Jmin);

save_image = 0;

for i=1:4
    subplot(2,2,i);
    imagesc(MW{i});
    axis image;
    axis off;
    if save_image
        imwrite(rescale(MW{i}), sprintf('MW%d.png', i), 'png');
    end
end
colormap gray(256);

if save_image
    imwrite(rescale(M), sprintf('M.png', i), 'png');
end


% SP_EVALUATE_ELEMENT_LIST_PARAM: compute the basis functions, in the parametric domain, in a given list of elements.
%
%     sp = sp_evaluate_element_list_param (space, msh_elems, 'option1', value1, ...)
%
% INPUTS:
%
%    space:   object defining the space of discrete functions (see sp_scalar)
%    msh_elems: msh structure containing the information of quadrature or
%               visualization points, for a given list of elements
%               (see msh_cartesian/msh_evaluate_element_list)
%   'option', value: additional optional parameters, currently available options are:
%
%              Name     |   Default value |  Meaning
%           ------------+-----------------+----------------------------------
%            value      |      true       |  compute shape_functions
%            gradient   |      false      |  compute shape_function_gradients
%            hessian    |      false      |  compute shape_function_hessians
%
% OUTPUT:
%
%    sp: struct representing the discrete function space, with the following fields:
%              (see the article for a detailed description)
%
%    FIELD_NAME      (SIZE)                                        DESCRIPTION
%    ncomp           (scalar)                                      number of components of the functions of the space (actually, 1)
%    ndof            (scalar)                                      total number of degrees of freedom
%    ndof_dir        (1 x ndim vector)                             degrees of freedom along each direction
%    nsh_max         (scalar)                                      maximum number of shape functions per element
%    nsh             (1 x msh_elems.nel vector)                    actual number of shape functions per each element
%    connectivity    (nsh_max x msh_elems.nel vector)              indices of basis functions that do not vanish in each element
%    shape_functions (msh_elems.nqn x nsh_max x msh_elems.nel)     basis functions evaluated at each quadrature node in each element
%    shape_function_gradients
%         (ndim x msh_elems.nqn x nsh_max x msh_elems.nel)         basis function gradients evaluated at each quadrature node in each element
%    shape_function_hessians
%         (ndim x ndim x msh_elems.nqn x nsh_max x msh_elems.nel)  basis function hessians evaluated at each quadrature node in each element
%
% Copyright (C) 2009, 2010, 2011 Carlo de Falco
% Copyright (C) 2011, 2015, 2019 Rafael Vazquez
%
%    This program is free software: you can redistribute it and/or modify
%    it under the terms of the GNU General Public License as published by
%    the Free Software Foundation, either version 3 of the License, or
%    (at your option) any later version.

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

function sp = sp_evaluate_element_list_param (space, msh, varargin)

value = true;
gradient = false;
hessian = false;
if (~isempty (varargin))
  if (~rem (length (varargin), 2) == 0)
    error ('sp_evaluate_element_list_param: options must be passed in the [option, value] format');
  end
  for ii=1:2:length(varargin)-1
    if (strcmpi (varargin {ii}, 'value'))
      value = varargin {ii+1};
    elseif (strcmpi (varargin {ii}, 'gradient'))
      gradient = varargin {ii+1};
    elseif (strcmpi (varargin {ii}, 'hessian'))
      hessian = varargin {ii+1};
    else
      warning ('Ignoring unknown option %s', varargin {ii});
    end
  end
end

sp_univ = space.sp_univ;

elem_list = msh.elem_list;

elem_ind = cell (msh.ndim, 1);
[elem_ind{:}] = ind2sub (msh.nel_dir, elem_list);
elem_ind = cell2mat (elem_ind);

nsh = 1;
for idim = 1:msh.ndim
  nsh = nsh .* sp_univ(idim).nsh(elem_ind(idim,:));
end

for idim = 1:msh.ndim
  csize = ones (1, msh.ndim);
  csize(idim) = sp_univ(idim).nsh_max;
  crep = [sp_univ.nsh_max];
  crep(idim) = 1;
  conn{idim} = reshape (sp_univ(idim).connectivity(:,elem_ind(idim,:)), [csize, msh.nel]);
  conn{idim} = repmat (conn{idim}, [crep, 1]);
end

connectivity = zeros (space.nsh_max, msh.nel);
indices = ones (size (conn{1}));
for idim = 1:msh.ndim
  indices = indices & conn{idim} ~= 0;
end
% for idim = 1:msh.ndim
%   conn{idim} = conn{idim}(indices);
% end
connectivity(indices) = sub2ind ([space.ndof_dir, 1], conn{:}); % The extra 1 makes things work in any dimension
connectivity = reshape (connectivity, space.nsh_max, msh.nel);

clear conn csize crep indices

sp = struct('nsh_max', space.nsh_max, 'nsh', nsh, 'ndof', space.ndof,  ...
            'ndof_dir', space.ndof_dir, 'connectivity', connectivity, ...
            'ncomp', 1, 'degree', space.degree);

if (value || gradient || hessian)
shp = cell(1,msh.ndim); shg = cell(1,msh.ndim); shh = cell(1,msh.ndim);
  for idim = 1:msh.ndim
    ssize = ones (1, 2*msh.ndim);
    ssize([idim, msh.ndim+idim]) = [msh.nqn_dir(idim), sp_univ(idim).nsh_max];
    srep = [msh.nqn_dir, sp_univ.nsh_max];
    srep([idim, msh.ndim+idim]) = 1;
    shp{idim} = reshape (sp_univ(idim).shape_functions(:,:,elem_ind(idim,:)), [ssize, msh.nel]);
    shp{idim} = repmat (shp{idim}, [srep, 1]);
    shp{idim} = reshape (shp{idim}, msh.nqn, space.nsh_max, msh.nel);
    shg{idim} = reshape (sp_univ(idim).shape_function_gradients(:,:,elem_ind(idim,:)), [ssize, msh.nel]);
    shg{idim} = repmat (shg{idim}, [srep, 1]);
    shg{idim} = reshape (shg{idim}, msh.nqn, space.nsh_max, msh.nel);
    shh{idim} = reshape (sp_univ(idim).shape_function_hessians(:,:,elem_ind(idim,:)), [ssize, msh.nel]);
    shh{idim} = repmat (shh{idim}, [srep, 1]);
    shh{idim} = reshape (shh{idim}, msh.nqn, space.nsh_max, msh.nel);
  end

  if (value)
    sp.shape_functions = 1;
    for idim = 1:msh.ndim
      sp.shape_functions = sp.shape_functions .* shp{idim};
    end
  end

  if (gradient)
    for idim = 1:msh.ndim
      shape_fun_grad = shg{idim};
      for jdim = setdiff (1:msh.ndim, idim)
        shape_fun_grad = shape_fun_grad .* shp{jdim};
      end
      sp.shape_function_gradients(idim,:,:,:) = shape_fun_grad;
    end
    sp.shape_function_gradients = reshape (sp.shape_function_gradients, ...
                                  msh.ndim, msh.nqn, sp.nsh_max, msh.nel);
  end

  if (hessian && (isfield (msh, 'geo_map_der2') || msh.nel == 0))
    for idim = 1:msh.ndim
      shape_fun_hess = shh{idim};
      for jdim = setdiff (1:msh.ndim, idim)
        shape_fun_hess = shape_fun_hess .* shp{jdim};
      end
      sp.shape_function_hessians(idim,idim,:,:,:) = shape_fun_hess;

      for jdim = setdiff (1:msh.ndim, idim)
        shape_fun_hess = shg{idim} .* shg{jdim};
        for kdim = setdiff (1:msh.ndim, [idim, jdim])
          shape_fun_hess = shape_fun_hess .* shp{kdim};
        end
        sp.shape_function_hessians(idim,jdim,:,:,:) = shape_fun_hess;
      end
    end
  end

  clear shp shg shh

  if (strcmpi (space.space_type, 'NURBS'))
    sp = bsp_2_nrb__ (sp, msh, space.weights);
  end
end

end


function p = addDisjointBilinearSDPcut(p)

if any(p.K.s) && any(p.variabletype == 1)
    top = 1+p.K.f+p.K.l+sum(p.K.q)+p.K.e+sum(p.K.p);
    newData = [];
    newKs = [];
    for i = 1:length(p.K.s)
        data = p.F_struc(top:top+p.K.s(i)^2-1,:);
        used = find(any(data(:,2:end)));
        if ~any(p.variabletype(used))
            % This is a linear SDP F(x) >= 0
            possible_t = setdiff(p.linears,used);
            weCanDoIt = 1;
            for j = 1:length(possible_t)
                t = possible_t(j);
                generateMonomials = t_times_x(t,used,p);
                if ~any(isnan(generateMonomials))
                    if ~isinf(p.lb(t))
                        % F0*(t-L) + Fi*xi*(t-L) >= 0
                        temp = data;
                        temp(:,1 + t) = temp(:,1);
                        temp(:,1) = temp(:,1)*-p.lb(t);
                        temp(:,1 + generateMonomials) = temp(:,1+used);
                        temp(:,1+used) = temp(:,1+used)*-p.lb(t);
                        newData = [newData;temp];
                        newKs = [newKs p.K.s(i)];
                    end
                    if ~isinf(p.ub(t))
                        % F0*(U-t) + Fi*xi*(U-t) >= 0
                        temp = data;
                        temp(:,1 + t) = -temp(:,1);
                        temp(:,1) = temp(:,1)*p.ub(t);
                        temp(:,1 + generateMonomials) = -temp(:,1+used);
                        temp(:,1+used) = temp(:,1+used)*p.ub(t);
                        newData = [newData;temp];
                        newKs = [newKs p.K.s(i)];
                    end
                end
            end
        end
        top = top + p.K.s(i)^2;
    end
    if ~isempty(newData);
        p.F_struc = [p.F_struc;newData];
        p.K.s = [p.K.s newKs];
    end
end

function index = t_times_x(t,x,p)
index = [];
for i = 1:length(x)
    xi = x(i);
    p_t = p.monomtable(t,:);
    p_x = p.monomtable(xi,:);
    j = findrows(p.monomtable,p_t+p_x);
    if isempty(j)
        index(i) = nan;
    else
        index(i) = j;
    end
end


function [ y, m ] = month_carry_julian ( y, m )

%*****************************************************************************80
%
%% MONTH_CARRY_JULIAN carries a year of months on the Julian calendar.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    09 December 2008
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer Y, integer M, the year and month.
%
%    Output, integer Y, integer M, the year and month.
%    On output, M is no greater than 12.
%
  while ( 1 )

    months = year_length_months_julian ( y );

    if ( m <= months )
      break
    end

    m = m - months;
    y = y + 1;

  end

  return
end


%% FUNCTION example_LSSMTC.m
%   Example of multi-task clustering.
%
%% LICENSE
%   This program is free software: you can redistribute it and/or modify
%   it under the terms of the GNU General Public License as published by
%   the Free Software Foundation, either version 3 of the License, or
%   (at your option) any later version.
%
%   This program is distributed in the hope that it will be useful,
%   but WITHOUT ANY WARRANTY; without even the implied warranty of
%   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%   GNU General Public License for more details.
%
%   You should have received a copy of the GNU General Public License
%   along with this program.  If not, see <http://www.gnu.org/licenses/>.
%
%   Copyright (C) 2011 - 2012 Quanquan Gu, Jiayu Zhou, and Jieping Ye
%
%   You are suggested to first read the Manual.
%   For any problem, please contact with Jiayu Zhou via jiayu.zhou@asu.edu
%
%   Last modified on June 17, 2012.
%
%% RELATED PAPERS
%   [1]Quanquan Gu, Jie Zhou. Learning the shared subspace
%      for multi-task clustering and transductive transfer
%      classification. In Proc. of the International Conference
%      on Data Mining (ICDM), Miami, Florida, USA, 2009.

clear
close all
clc

addpath('../MALSAR/functions/mutli-task clustering/');
addpath('../MALSAR/utils/');

%===========================================
%This is a demo on comp v.s. sci data set

path = '../data/Newsgroup/comp.vs.sci/';

m = 2;
cellX = cell(m,1);
cellgnd = cell(m,1);
for i=1:m
    task_data = load([path 'Task' num2str(i)]);
    cellX{i} = task_data.fea';
    % if the evaluation metrices are not needed
    % then cellgnd can be set to [].
    cellgnd{i} = task_data.gnd;
end

c = length(unique(cellgnd{1})); % cluster number

opts.tFlag = 2; % termination: run maximum iteration.
opts.maxIter = 20; % maximum iteration.

l = 2; % subspace dimension
lambda = 0.75; % multi-task regulariation paramter
[W cellM cellP residue cellAcc cellNMI] = LSSMTC(cellX,cellgnd,c,l,lambda,opts);

figure
for i = 1:m
    subplot(1,m,i)
    plot(cellAcc{i})
    ylabel('accuracy')
    xlabel('iteration')
    title(sprintf('Task %u', i))
end
print('-dpdf', '-r600', 'LSSMTC_acc');

figure
for i = 1:m
    subplot(1,m,i)
    plot(cellNMI{i})
    ylabel('normalized mutual information')
    xlabel('iteration')
    title(sprintf('Task %u', i))
end
print('-dpdf', '-r600', 'LSSMTC_nmi');


function [hpe] = TW2hpe(TW)
% Convert power from terawatts to electric horsepower.
% Chad A. Greene 2012
hpe = TW*1340482573.7265;


function varargout = drawEdgeLabels(p, e, value)
%DRAWEDGELABELS Draw values associated to graph edges
%
%   usage:
%   drawEdgeLabels(NODES, EDGES, VALUES);
%   NODES: array of double, containing x and y values of nodes
%   EDGES: array of int, containing indices of in and out nodes
%   VALUES is an array the same length of EDGES, containing values
%   associated to each edges of the graph.
%
%   The function computes the center of each edge, and puts the text with
%   associated value.
%
%   H = drawEdgeLabels(...) return array of handles to each text structure,
%   making possible to change font, color, size
%
%
%   -----
%   author: David Legland
%   INRA - TPV URPOI - BIA IMASTE
%   created the 10/02/2003.
%

%   HISTORY
%   10/03/2004 included into lib/graph library

if length(p) > 1 && length(e) > 1
    h = zeros(length(e), 1);
    hold on;
    for l=1:length(e)
        % indices of source and target nodes
        n1 = e(l, 1);
        n2 = e(l, 2);

        % node coordinates
        x1 = p(n1, 1);
        y1 = p(n1, 2);
        x2 = p(n2, 1);
        y2 = p(n2, 2);

        % display the edge
        line([x1 x2], [y1 y2]);

        % coordinates of edge label
        xm = (x1 + x2)/2;
        ym = (y1 + y2)/2;

        % display label
        h(l) = text(xm, ym, sprintf('%3d', floor(value(l))));
    end
end

if nargout == 1
    varargout = {h};
end


% - This function is intended for image pre-processing
% - The function has five input arguments:-
% - FileName: the name of the input image.
% - PathName: the path of the input image.
% - Threshold: is set by default, you can change it

function BW=PreProcessing_General(FileName,Threshold)
%==========================================================================
% - This is to check whether the user needs to use automatic Thresholding;
% - or he may need to change the default value.
if nargin==1
    Threshold=0.35;
end
%==========================================================================
% - This is to read the input image.
global NROWS
global NCOLS
IN_IMG=imread(FileName);
NROWS=size(IN_IMG,1);
NCOLS=size(IN_IMG,2);
%==========================================================================
% - This is to apply image enhacement , waiting for control input from
% - the user.

% - This is to define the window size.

W_Size=3;
IN_IMG=medfilt2(IN_IMG,[W_Size W_Size]);

background = imopen(IN_IMG,strel('disk',3));
IN_IMG = IN_IMG + background;

%==========================================================================
% - In case you need to show the output after applying median filter
% - uncomment this part
% figure;imshow(IN_IMG);
% set(title('Median Filter'),'color','b');
%==========================================================================
% - This is to apply Otsu's method thresholding
% - Global image threshold using Otsu's method
% Threshold = graythresh(IN_IMG);
figure; imshow(IN_IMG,[]);
BW=im2bw(IN_IMG,Threshold);
% figure; imshow(BW,[]); pause;
BW = imcomplement(BW);
% figure; imshow(BW,[]); pause;
% SE = strel('disk',3);
% BW = imclose(BW,SE);
% figure; imshow(BW,[]); pause;
BW = imfill(BW,'holes');
% figure; imshow(BW,[]); pause;
SE2 = strel('disk',3);
BW = imopen(BW,SE2);
% figure; imshow(BW,[]); pause;
% BW = imclearborder(BW);
% figure; imshow(BW,[]); pause;

%==========================================================================
% - To display the output after applying Otsu (uncomment this part) ,
% - save the image in Alg_Output folder
% figure;imshow(BW);impixelinfo;
% set(title('Image Threshold'),'color','b');
%==========================================================================
[~,name,~] = fileparts(FileName);
imwrite(BW,['./Results/Step1_PreProcess/' name '_Pre.jpg'],'jpg');
%==========================================================================
end


function [vert,conn,tria,tnum] = refine2_om(varargin)
%REFINE2_OM (Frontal)-Delaunay-refinement for two-dimensional,
% polygonal geometries.
% Has been slightly edited for OceanMesh2D to make sure boundary edges are
% absolutely preserved and to get rid of non-unique points
%   [VERT,EDGE,TRIA,TNUM] = REFINE2(NODE,EDGE) returns a co-
%   nstrained Delaunay triangulation of the polygonal region
%   {NODE,EDGE}. NODE is an N-by-2 array of polygonal verti-
%   ces and EDGE is an E-by-2 array of edge indexing. Each
%   row in EDGE represents an edge of the polygon, such that
%   NODE(EDGE(JJ,1),:) and NODE(EDGE(JJ,2),:) are the coord-
%   inates of the endpoints of the JJ-TH edge. If the argum-
%   ent EDGE is omitted it assumed that the vertices in NODE
%   are connected in ascending order.
%
%   [...] = REFINE2(NODE,EDGE,PART) computes a triangulation
%   for a multiply-connected geometry. PART is a cell-array
%   of polygonal "parts", where each element PART{KK} is an
%   array of edge indices defining a given polygonal region.
%   EDGE(PART{KK}, :) is the set of edges in the KK-TH part.
%
%   VERT is a V-by-2 array of XY coordinates in the triangu-
%   lation, EDGE is an array of constrained edges, TRIA is a
%   T-by-3 array of triangles, and TNUM is a T-by-1 array of
%   part indices. Each row of TRIA and EDGE define an eleme-
%   nt. VERT(TRIA(II,1),:), VERT(TRIA(II,2),:) and VERT(TRIA
%   (II,3),:) are the coordinates of the II-TH triangle. The
%   edges in EDGE are defined in a similar manner. NUM is an
%   array of part indexing, such that TNUM(II) is the index
%   of the part in which the II-TH triangle resides.
%
%   [...] = REFINE2(..., OPTS) passes an additional options
%   structure OPTS, containing various user-defined paramet-
%   ers, including:
%
% - OPTS.KIND = {'DELFRONT'}, 'DELAUNAY' -- the type of ref-
%   inement employed. The 'DELFRONT' algorithm is typically
%   slower, but produces higher quality output.
%
% - OPTS.RHO2 = {1.025} -- the maximum allowable radius-edge
%   ratio. Refinement proceeds until all interior triangles
%   satisfy the radius-edge threshold. Smaller radius-edge
%   ratios lead to improved triangle shape, with RHO2=1 req-
%   uiring that all angles exceed 30 degrees. Setting RHO2<1
%   may lead to non-convergence.
%
% - OPTS.REF1 = {'REFINE'}, 'PRESERVE' -- refinement 'flag'
%   for 1-dimensional faces (i.e. edges). The 'PRESERVE' op-
%   tion results in minimal refinement, attempting to retain
%   the initial edges without further subdivision. Edges are
%   split only to satisfy basic geomertical conformance.
%
% - OPTS.REF2 = {'REFINE'}, 'PRESERVE' -- refinement 'flag'
%   for 2-dimensional faces (i.e. trias). The 'PRESERVE' op-
%   tion results in minimal refinement, attempting to retain
%   the initial trias without further subdivision. Trias are
%   split only to satisfy basic geomertical conformance.
%
% - OPTS.SIZ1 = {1.333} -- the normalised rel.-length th-
%   reshold for edge-elements. Each exterior edge is refined
%   until LL/HH<SIZ1, where LL is the edge-length, HH is the
%   edge-centred mesh-size value.
%
% - OPTS.SIZ2 = {1.300} -- the normalised rel.-length th-
%   reshold for tria-elements. Each interior tria is refined
%   until RE/HH<SIZ2, where RE is an effective tria length,
%   based on the circumradius, HH is the tria-centred mesh-
%   size value.
%
% - OPTS.DISP = { +10 } -- refinement verbosity. Set to INF
%   for quiet execution.
%
%   [...] = REFINE2(..., HFUN,ARGS) also passes an optional
%   mesh-size function argument. Setting HFUN = HMAX, where
%   HMAX is a scalar value, imposes a constant size constra-
%   int over the full domain. HFUN can also be defined as a
%   general function handle [HH] = HFUN(PP), where PP is an
%   N-by-2 array of XY coordinates and HH is the associated
%   vector of mesh-size values. User-defined HFUN must be
%   fully vectorised. Additional arguments {A1,A2,...AN} for
%   HFUN can be passed as trailing parameters to REFINE2. In
%   such cases, HFUN must adopt a signature [HH] = HFUN(PP,
%   A1,A2,...,AN). HFUN must return positive values.
%
%   See also SMOOTH2, TRIDIV2, TRICOST, TRIDEMO

%   This routine implements a "multi-refinement" variant of
%   Delaunay-refinement type mesh-generation. Both standard
%   Delaunay-refinement and Frontal-Delaunay type algorithms
%   are available. The Frontal-Delaunay approach is a simpl-
%   ified version of the JIGSAW algorithm, described in:
%
% * D. Engwirda, (2014): "Locally-optimal Delaunay-refineme-
%   nt and optimisation-based mesh generation", Ph.D. Thesis
%   School of Mathematics and Statistics, Univ. of Sydney.
%   http://hdl.handle.net/2123/13148
%
% * D. Engwirda & D. Ivers, (2016): "Off-centre Steiner poi-
%   nts for Delaunay-refinement on curved surfaces", Comput-
%   er-Aided Design, (72), 157--171.
%   http://dx.doi.org/10.1016/j.cad.2015.10.007

%   This work is an extension of the "off-centre" type tech-
%   niques introduced in:
%
% * H. Erten & A. Ungor, (2009): "Quality triangulation with
%   locally optimal Steiner points", SIAM Journal on Scient-
%   ific Comp. 31(3), 2103--2130.
%   http://doi.org/10.1137/080716748
%
% * S. Rebay, (1993): "Efficient Unstructured Mesh Generati-
%   on by Means of Delaunay Triangulation and Bowyer-Watson
%   Algorithm, J. Comp. Physics 106(1), 125--138.
%   http://dx.doi.org/10.1006/jcph.1993.1097

%   Generally speaking, the Delaunay-refinement method impl-
%   emented here is a variantion of the "classical" algorit-
%   hm introduced in:
%
% * J. Ruppert, (1995): "A Delaunay refinement algorithm for
%   quality 2-dimensional mesh generation." Journal of Algo-
%   rithms 18(3), 548--585.
%   http://dx.doi.org/10.1006/jagm.1995.1021
%
%   See also: S. Cheng, T. Dey & J. Shewchuk, (2012): "Dela-
%   unay mesh generation", CRC Press, for comprehensive cov-
%   erage of Delaunay-based meshing techniques.

%   A much more advanced, and fully three-dimensional imple-
%   mentation is available in the JIGSAW library. For addit-
%   ional information, see:
%   https://github.com/dengwirda/jigsaw-matlab

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

    node = []; PSLG = []; part = {}; opts = [] ;
    hfun = []; harg = {};

%---------------------------------------------- extract args
    if (nargin>=+1), node = varargin{1}; end
    if (nargin>=+2), PSLG = varargin{2}; end
    if (nargin>=+3), part = varargin{3}; end
    if (nargin>=+4), opts = varargin{4}; end
    if (nargin>=+5), hfun = varargin{5}; end
    if (nargin>=+6), harg = varargin(6:end); end

   [opts] = makeopt(opts) ;

%---------------------------------------------- default EDGE
    nnod = size(node,1) ;

    if (isempty(PSLG))
        PSLG = [(1:nnod-1)',(2:nnod)'; nnod,1] ;
    end

%---------------------------------------------- default PART
    ncon = size(PSLG,1) ;

    if (isempty(part)), part{1} = (1:ncon)'; end

%---------------------------------------------- basic checks
    if (~isnumeric(node) || ~isnumeric(PSLG) || ...
        ~iscell   (part) || ~isstruct (opts) )
        error('refine2:incorrectInputClass' , ...
            'Incorrect input class.') ;
    end

%---------------------------------------------- basic checks
    if (ndims(node) ~= +2 || ndims(PSLG) ~= +2)
        error('refine2:incorrectDimensions' , ...
            'Incorrect input dimensions.');
    end
    if (size(node,2) < +2 || size(PSLG,2) < +2)
        error('refine2:incorrectDimensions' , ...
            'Incorrect input dimensions.');
    end

%---------------------------------------------- basic checks
    if (min([PSLG(:)])<+1 || max([PSLG(:)])>nnod)
        error('refine2:invalidInputs', ...
            'Invalid EDGE input array.') ;
    end

    pmin = cellfun(@min,part);
    pmax = cellfun(@max,part);

    if (min([pmin(:)])<+1 || max([pmax(:)])>ncon)
        error('refine2:invalidInputs', ...
            'Invalid PART input array.') ;
    end

%-------------------------------- prune any non-unique topo.
   [~,ivec,jvec] = ...
        unique(sort(PSLG,+2),'rows') ;

    PSLG = PSLG(ivec,:) ;

    for ppos = +1:length(part)

        if ( ~isnumeric(part{ppos}) )
            error (  ...
            'refine2:incorrectInputClass', ...
                'Incorrect input class. ') ;
        end

        part{ppos} = ...
            unique(jvec(part{ppos})) ;

    end

%-------------------------------- check part "manifold-ness"
    for ppos = +1:length(part)

        eloc = PSLG(part{ppos},:) ;
        nadj = ...
            accumarray(eloc(:),1) ;

        if (any(mod(nadj,2) ~= 0) )
        error('refine2:nonmanifoldInputs', ...
            'Non-manifold PART detected.') ;
        end

    end

%---------------------------------------------- output title
    if (~isinf(opts.disp))
        fprintf(1,'\n') ;
        fprintf(1,' Refine triangulation...\n') ;
        fprintf(1,'\n') ;
        fprintf(1,[...
' -------------------------------------------------------\n', ...
'      |ITER.|          |CDT1(X)|          |CDT2(X)|     \n', ...
' -------------------------------------------------------\n', ...
             ] ) ;
    end

%-------------------------------- PASS 0: inflate box bounds
    vert = node; tria = []; tnum = []; iter = 0 ;
    conn = PSLG;

    vmin = min(vert,[],1);      % inflate bbox for stability
    vmax = max(vert,[],1);

    vdel = vmax - 1.*vmin;
    vmin = vmin - .5*vdel;
    vmax = vmax + .5*vdel;

    vbox = [
        vmin(1), vmin(2)
        vmax(1), vmin(2)
        vmax(1), vmax(2)
        vmin(1), vmax(2)
           ] ;
    vert = [vert ; vbox] ;

%-------------------------------- PASS 0: shield sharp feat.
   [vert,conn,tria,tnum,iter] = ...
        cdtbal0(vert,conn,tria,tnum, ...
            node,PSLG,part,opts,hfun,harg,iter);

%-------------------------------- PASS 1: refine 1-simplexes
   [vert,conn,tria,tnum,iter] = ...
        cdtref1(vert,conn,tria,tnum, ...
            node,PSLG,part,opts,hfun,harg,iter);

%-------------------------------- PASS 2: refine 2-simplexes
   [vert,conn,tria,tnum,iter] = ...
        cdtref2(vert,conn,tria,tnum, ...
            node,PSLG,part,opts,hfun,harg,iter);

    if (~isinf(opts.disp)), fprintf(1,'\n'); end

%-------------------------------- trim extra adjacency info.
    tria = tria( :,1:3) ;

%-------------------------------- trim vert. - deflate bbox.
    keep = false(size(vert,1),1);
    keep(tria(:)) = true;
    keep(conn(:)) = true;

    redo = zeros(size(vert,1),1);
    redo(keep) = ...
        (+1:length(find(keep)))';

    conn = redo(conn);
    tria = redo(tria);

    vert = vert(keep,:) ;

end

function [vert,conn,tria,tnum,iter] = ...
            cdtbal0(vert,conn,tria,tnum, ...
                node,PSLG,part,opts,hfun,harg,iter)
%CDTBAL0 constrained Delaunay-refinement for "sharp" 0-dim.
%features at PSLG vertices.
%   [...] = CDTBAL0(...) refines the set of 1-simplex eleme-
%   nts incident to "sharp" features in the PSLG. Specifica-
%   lly, edges that subtend "small" angles are split about a
%   set of new "collar" vertices, equi-distributed about the
%   centre of "sharp" features. Collar size is computed as a
%   min. of the incident edge-len. and local mesh-size cons-
%   traints.

    if (iter <= opts.iter)

    %------------------------------------- build current CDT
       [vert,conn, ...
        tria,tnum] = deltri2(vert,conn, ...
                             node,PSLG, ...
                             part, ...
                             opts.dtri) ;

    %------------------------------------- build current adj
       [edge,tria] = tricon2(tria,conn) ;

       [feat,ftri] = isfeat2(vert, ...
                             edge,tria) ;

        apex = false(size(vert,1), 1) ;
        apex(tria(ftri)) =  true ;

        if strcmpi(opts.ref1,'preserve')
            return;
        end

    %------------------------------------- eval. length-fun.
        if (~isempty(hfun))
            if (isnumeric(hfun))
            vlen = hfun * ...
              ones(size(vert,1),1) ;
            else
            vlen = feval( ...
                hfun,vert,harg{:}) ;
            vlen = vlen(:) ;
            end
        else
            vlen = +inf * ...
              ones(size(vert,1),1) ;
        end

    %------------------------------------- form edge vectors
        evec = vert(conn(:,2),:) ...
             - vert(conn(:,1),:) ;
        elen = sqrt(sum(evec.^2,2));
        evec = evec./[elen,elen] ;

    %------------------------------------- min. adj. lengths
        for epos = +1 : size(conn,1)

            ivrt = conn(epos,1) ;
            jvrt = conn(epos,2) ;

            vlen(ivrt) = min( ...
            vlen(ivrt), .67*elen(epos)) ;
            vlen(jvrt) = min( ...
            vlen(jvrt), .67*elen(epos)) ;

        end

    %------------------------------------- mark feature edge
        iref = apex(conn(:,1)) ...      %- refine at vert. 1
            & ~apex(conn(:,2)) ;
        jref = apex(conn(:,2)) ...      %- refine at vert. 2
            & ~apex(conn(:,1)) ;
        dref = apex(conn(:,1)) ...      %- refine at both!
            &  apex(conn(:,2)) ;

        keep =~apex(conn(:,1)) ...      %- refine at neither
            & ~apex(conn(:,2)) ;

    %------------------------------------- protecting collar
        ilen = vlen(conn(iref,1)) ;
        inew = vert(conn(iref,1),:) ...
        + [ilen,ilen].*evec(iref,:) ;

        jlen = vlen(conn(jref,2)) ;
        jnew = vert(conn(jref,2),:) ...
        - [jlen,jlen].*evec(jref,:) ;

        Ilen = vlen(conn(dref,1)) ;
        Inew = vert(conn(dref,1),:) ...
        + [Ilen,Ilen].*evec(dref,:) ;

        Jlen = vlen(conn(dref,2)) ;
        Jnew = vert(conn(dref,2),:) ...
        - [Jlen,Jlen].*evec(dref,:) ;

        vnew = [inew; jnew; Inew; Jnew] ;

    %------------------------------------- add new vert/edge
        iset = (1:size(inew,1))' ...
                + size(vert,1) ;

        jset = (1:size(jnew,1))' ...
                + size(inew,1) + ...
                + size(vert,1) ;

        Iset = (1:size(Inew,1))' ...
                + size(inew,1) + ...
                + size(jnew,1) + ...
                + size(vert,1) ;

        Jset = (1:size(Jnew,1))' ...
                + size(inew,1) + ...
                + size(jnew,1) + ...
                + size(Inew,1) + ...
                + size(vert,1) ;

        vert = [vert ; vnew] ;

        cnew = [conn(iref,1), iset ;
                conn(iref,2), iset ;
                conn(jref,2), jset ;
                conn(jref,1), jset ;
                conn(dref,1), Iset ;
                conn(dref,2), Jset ;
                Iset, Jset] ;
        conn = [conn(keep,:); cnew ] ;

    end

end

function [vert,conn,tria,tnum,iter] = ...
            cdtref1(vert,conn,tria,tnum, ...
                node,PSLG,part,opts,hfun,harg,iter)
%CDTREF1 constrained Delaunay-refinement for 1-simplex elem-
%nts embedded in R^2.
%   [...] = CDTREF1(...) refines the set of 1-simplex eleme-
%   nts embedded in the triangulation until all constraints
%   are satisfied. Specifically, edges are refined until all
%   local mesh-spacing and encroachment conditions are met.
%   Refinement proceeds according to either a Delaunay-refi-
%   nement or Frontal-Delaunay type approach, depending on
%   user-settings. In either case, new steiner vertices are
%   introduced to split "bad" edges - those that violate the
%   set of prescribed constraints. In the "-DR" type process
%   edges are split about their circumballs (midpoints). In
%   the "-FD" approach, new vertices are positioned such th-
%   at mesh-spacing constraints are satisfied in a "locally-
%   optimal" fashion.

    tcpu.full = +0. ;
    tcpu.ball = +0. ;
    tcpu.hfun = +0. ;
    tcpu.encr = +0. ;
    tcpu.offc = +0. ;

    vidx = (1:size(vert,1))';     %- "new" vert list to test

    tnow =  tic ;

    ntol = +1.55;

    while (strcmpi(opts.ref1,'refine'))

        iter = iter + 1 ;

        if (iter>=opts.iter),break; end

    %------------------------------------- calc. circumballs
        ttic = tic ;

        bal1 = cdtbal1(vert,conn) ;

        tcpu.ball = ...
            tcpu.ball + toc(ttic) ;

    %------------------------------------- eval. length-fun.
        ttic = tic ;

        if (~isempty(hfun))
            if (isnumeric(hfun))
            fun0 = hfun * ...
              ones(size(vert,1),1);
            fun1 = hfun ;
            else
            fun0(vidx) = ...
                feval(hfun, ...
            vert(vidx,:), harg{:});
            fun0 = fun0(:) ;
            fun1 = fun0(conn(:,1))...
                 + fun0(conn(:,2));
            fun1 = fun1 / +2. ;
            end
        else
            fun0 = +inf * ...
              ones(size(vert,1),1);
            fun1 = +inf ;
        end

        siz1 = ...
         +4. * bal1(:,3)./(fun1.*fun1) ;

        tcpu.hfun = ...
            tcpu.hfun + toc(ttic) ;

    %------------------------------------- test encroachment
        ttic = tic ;

        bal1(:,3) = ...
            (1.-eps^.75) * bal1(:,3) ;

       [vp,vi] = ...
           findball(bal1,vert(:,1:2));

    %------------------------------------- near=>[vert,edge]
        next = +0;
        ebad = false(size(conn,1),1) ;
        near = zeros(size(conn,1),1) ;
        for ii = +1 : size(vp,1)
            for ip = vp(ii,1):vp(ii,2)
                jj = vi(ip);
                if (ii ~= conn(jj,1) ...
                &&  ii ~= conn(jj,2) )
                next = next + 1;
                near(next,1) = ii;
                near(next,2) = jj;
                end
            end
        end

        near = near(1:next-0,:);

        if (~isempty(near))
    %-- mark edge "encroached" if there is a vert within its
    %-- dia.-ball that is not joined to either of its vert's
    %-- via an existing edge...
            ivrt = conn(near(:,2),1);
            jvrt = conn(near(:,2),2);

            pair = [near(:,1), ivrt];
            ivec = setset2(pair,conn) ;

            pair = [near(:,1), jvrt];
            jvec = setset2(pair,conn) ;

            okay = ~ivec & ~jvec ;

            ebad(near(okay,2))=true ;

        end

        tcpu.encr = ...
            tcpu.encr + toc(ttic);

    %------------------------------------- refinement queues
        ref1 = false(size(conn,1),1);
        ref1(ebad)           = true ;   %- edge encroachment
        ref1(siz1>opts.siz1* ...        %- bad equiv. length
                  opts.siz1) = true ;

        num1 = find(ref1)  ;

    %------------------------------------- dump-out progess!
        if (mod(iter,opts.disp)==0)
            numc = size(conn,1) ;
            numt = size(tria,1) ;
            fprintf(+1, ...
            '%11i %18i %18i\n', ...
            [iter,numc,numt]) ;
        end

    %------------------------------------- nothing to refine
        if (isempty(num1)), break; end

    %------------------------------------- refine "bad" tria
        switch (lower(opts.kind))
        case 'delaunay'
    %------------------------------------- do circ-ball pt's
        new1 = bal1(ref1, 1:2) ;

        vidx = (1:size(new1,1))' ...
                + size(vert,1) ;

        cnew = [conn( ref1,1), vidx
                conn( ref1,2), vidx];
        conn = [conn(~ref1,:); cnew];

    %------------------------------------- update vertex set
        vert = [vert; new1(:,1:2)];

        case 'delfront'
    %-- symmetric off-centre scheme:- refine edges from both
    %-- ends simultaneously, placing new vertices to satisfy
    %-- the worst of mesh-spacing and local voronoi constra-
    %-- ints.

        ttic = tic ;

        evec = vert(conn(ref1,2),:) ...
             - vert(conn(ref1,1),:) ;
        elen = sqrt(sum(evec.^2,2)) ;
        evec = evec ./ [elen, elen] ;

    %------------------------------------- "voro"-type dist.
        vlen = sqrt(bal1(ref1,3));

    %------------------------------------- "size"-type dist.
        ihfn = fun0(conn(ref1,1));
        jhfn = fun0(conn(ref1,2));

    %------------------------------------- bind "safe" dist.
        ilen = min(vlen,ihfn) ;
        jlen = min(vlen,jhfn) ;

    %------------------------------------- locate offcentres
        inew = vert(conn(ref1,1),:) ...
             + [ilen,ilen].*evec ;
        jnew = vert(conn(ref1,2),:) ...
             - [jlen,jlen].*evec ;

    %------------------------------------- iter. "size"-type
        for ioff = +1 : +3
    %------------------------------------- eval. length-fun.
        if (~isempty(hfun))
            if (isnumeric(hfun))
            iprj = hfun * ...
              ones(size(inew,1),1);
            jprj = hfun * ...
              ones(size(jnew,1),1);
            else
            iprj = feval( ...
                hfun,inew,harg{:});
            jprj = feval( ...
                hfun,jnew,harg{:});
            iprj = iprj(:);
            jprj = jprj(:);
            end
        else
            iprj = +inf * ...
              ones(size(inew,1),1);
            jprj = +inf * ...
              ones(size(jnew,1),1);
        end

        iprj = 0.5*ihfn + 0.5*iprj;
        jprj = 0.5*jhfn + 0.5*jprj;

    %------------------------------------- bind "safe" dist.
        ilen = min(vlen,iprj) ;
        jlen = min(vlen,jprj) ;

    %------------------------------------- locate offcentres
        inew = vert(conn(ref1,1),:) ...
             + [ilen,ilen].*evec ;
        jnew = vert(conn(ref1,2),:) ...
             - [jlen,jlen].*evec ;

        end

    %------------------------------------- merge i,j if near
        near = ...
            ilen+jlen>=vlen*ntol ;

        znew = inew(near,:) * .5 ...
             + jnew(near,:) * .5 ;

        inew = inew(~near,1:2) ;
        jnew = jnew(~near,1:2) ;

    %------------------------------------- split constraints
        zset = (1:size(znew,1))' ...
                + size(vert,1) ;

        iset = (1:size(inew,1))' ...
                + size(znew,1) + ...
                + size(vert,1) ;

        jset = (1:size(jnew,1))' ...
                + size(znew,1) + ...
                + size(inew,1) + ...
                + size(vert,1) ;

        set1 = num1( near);
        set2 = num1(~near);

        cnew = [conn( set1,1), zset
                conn( set1,2), zset
                conn( set2,1), iset
                conn( set2,2), jset
                iset, jset ] ;
        conn = [conn(~ref1,:); cnew];

    %------------------------------------- update vertex set
        vert = [vert; znew(:,1:2)];
        vert = [vert; inew(:,1:2)];
        vert = [vert; jnew(:,1:2)];

        vidx = [zset; iset; jset] ;

        tcpu.offc = ...
            tcpu.offc + toc(ttic) ;

        end % switch(lower(opts.kind))

    end

    tcpu.full = ...
        tcpu.full + toc(tnow) ;

    if (~isinf(opts.disp) )
    %------------------------------------- print final stats
        numc = size(conn,1) ;
        numt = size(tria,1) ;
        fprintf(+1, ...
        '%11i %18i %18i\n', ...
        [iter,numc,numt]) ;
    end

    if (opts.dbug)
    %------------------------------------- print debug timer
        fprintf(1,'\n') ;
        fprintf(1,' 1-simplex REF. timer...\n');
        fprintf(1,'\n') ;
        fprintf(1, ...
        ' FULL: %f \n', tcpu.full);
        fprintf(1, ...
        ' BALL: %f \n', tcpu.ball);
        fprintf(1, ...
        ' HFUN: %f \n', tcpu.hfun);
        fprintf(1, ...
        ' ENCR: %f \n', tcpu.encr);
        fprintf(1, ...
        ' OFFC: %f \n', tcpu.offc);
        fprintf(1,'\n') ;
    end

end

function [vert,conn,tria,tnum,iter] = ...
            cdtref2(vert,conn,tria,tnum, ...
                node,PSLG,part,opts,hfun,harg,iter)
%CDTREF2 constrained Delaunay-refinement for 2-simplex elem-
%nts embedded in R^2.
%   [...] = CDTREF2(...) refines the set of 2-simplex eleme-
%   nts embedded in the triangulation until all constraints
%   are satisfied. Specifically, triangles are refined until
%   all local mesh-spacing and element-shape conditions are
%   met. Refinement proceeds according to either a Delaunay-
%   refinement or Frontal-Delaunay type approach, depending
%   on user-settings. In either case, new steiner points are
%   introduced to split "bad" triangles - those that violate
%   the set of prescribed constraints. In the "-DR" type pr-
%   ocess triangles are split about their circumballs. In
%   the "-FD" approach, new vertices are positioned such th-
%   at mesh-spacing and element-shape constraints are satis-
%   fied in a "locally-optimal" fashion.

    tcpu.full = +0. ;
    tcpu.dtri = +0. ;
    tcpu.tcon = +0. ;
    tcpu.ball = +0. ;
    tcpu.hfun = +0. ;
    tcpu.offc = +0. ;
    tcpu.filt = +0. ;

    vidx = (1:size(vert,1))';     %- "new" vert list to test

    tnow =  tic ;

    near = +.775;

    while (strcmpi(opts.ref2,'refine'))

        iter = iter + 1 ;

    %------------------------------------- build current CDT
        ttic = tic ;

        nold = size(vert,1) ;

       [vert,conn, ...
        tria,tnum]= deltri2(vert,conn, ...
                            node,PSLG, ...
                            part, ....
                            opts.dtri) ;

        nnew = size(vert,1) ;

        vidx = ...
       [vidx; (nold:nnew)'] ;

        % wjp: in case the new mesh has fewer nodes than old one
        vidx(vidx > nnew) = [];

        tcpu.dtri = ...
            tcpu.dtri + toc(ttic) ;

    %------------------------------------- build current adj
        ttic = tic ;

       [edge,tria]= tricon2(tria,conn) ;

        tcpu.tcon = ...
            tcpu.tcon + toc(ttic) ;

        if (iter>=opts.iter),break; end

    %------------------------------------- calc. circumballs
        ttic = tic ;

        bal1 = cdtbal1(vert,conn) ;
        bal2 = cdtbal2(vert, ...
                       edge,tria) ;
        len2 = minlen2(vert,tria) ;

        rho2 = bal2(:,+3) ./ len2 ;

    %------------------------------------- refinement scores
        scr2 = rho2 .* bal2(:,+3) ;

        tcpu.ball = ...
            tcpu.ball + toc(ttic) ;

    %------------------------------------- eval. length-fun.
        ttic = tic ;

        if (~isempty(hfun))
            if (isnumeric(hfun))
            fun0 = hfun * ...
              ones(size(vert,1),1);
            fun2 = hfun ;
            else
            fun0(vidx) = ...
                feval(hfun, ...
            vert(vidx,:), harg{:});
            fun0 = fun0(:) ;
            fun2 = fun0(tria(:,1))...
                 + fun0(tria(:,2))...
                 + fun0(tria(:,3));
            fun2 = fun2 / +3. ;
            end
        else
            fun0 = +inf * ...
              ones(size(vert,1),1);
            fun2 = +inf ;
        end

        siz2 = ...
         +3. * bal2(:,3)./(fun2.*fun2) ;

        tcpu.hfun = ...
            tcpu.hfun + toc(ttic) ;

    %------------------------------------- refinement queues
        ref1 = false(size(conn,1),1);
        ref2 = false(size(tria,1),1);

        stri = isfeat2(vert,edge,tria) ;

        ref2(rho2>opts.rho2* ...        %- bad rad-edge len.
                  opts.rho2) = true ;
        ref2(stri) = false ;
        ref2(siz2>opts.siz2* ...        %- bad equiv. length
                  opts.siz2) = true ;

        num2 = find(ref2);

    %------------------------------------- dump-out progess!
        if (mod(iter,opts.disp)==0)
            numc = size(conn,1) ;
            numt = size(tria,1) ;
            fprintf(+1, ...
            '%11i %18i %18i\n', ...
            [iter,numc,numt]) ;
        end

    %------------------------------------- nothing to refine
        if (isempty(num2)), break; end

       [scr2,idx2] = sort( ...
            scr2(num2),'descend');
        num2 = num2(idx2);

    %------------------------------------- refine "bad" tria
        switch (lower(opts.kind))
        case 'delaunay'
    %------------------------------------- do circ-ball pt's
        new2 = zeros(length(num2),3);
        new2(:,1:2) = bal2(num2,1:2);

        rmin = ...                      %- min. insert radii
            len2(num2)*(1.-eps^.75)^2 ;

        new2(:,  3) = max( ...
            bal2(num2,3)*near^2,rmin) ;

        case 'delfront'
    %-- off-centre scheme -- refine triangles by positioning
    %-- new vertices along a local segment of the voronoi
    %-- diagram, bounded by assoc. circmballs. New points
    %-- are placed to satisfy the worst of local mesh-length
    %-- and element-shape constraints.

        ttic = tic ;

    %------------------------------------- find frontal edge
       [lmin,emin] = ...
            minlen2(vert,tria(num2,:)) ;

        ftri = false(length(num2),1) ;
        epos = zeros(length(num2),1) ;
        tadj = zeros(length(num2),1) ;

        for ii = +1 : length(epos)
            epos(ii) = tria( ...
                num2(ii),emin(ii)+3) ;
        end

    %------------------------------------- find frontal tria
        for enum = +1 : +3

            eidx = tria(num2,enum+3) ;

            ftri = ...
            ftri | edge(eidx,5) > +0 ;

            ione = ...
                num2 ~= edge(eidx,3) ;
            itwo = ~ione ;

            tadj(ione) = ...
                edge(eidx(ione),3);
            tadj(itwo) = ...
                edge(eidx(itwo),4);

            okay = tadj > +0 ;
            tidx = tadj(okay);

            ftri(okay) = ...
            ftri(okay) | ~ref2(tidx) ;

        end

        if (~any(ftri))                 %- can this happen!?
        ftri = true(length(num2),+1) ;
        end

    %------------------------------------- locate offcentres
        emid = vert(edge(epos,+1),:) ...
             + vert(edge(epos,+2),:) ;
        emid = emid * +0.50 ;

        elen = sqrt(lmin(:));

    %------------------------------------- "voro"-type dist.
        vvec = bal2(num2,1:2)-emid ;
        vlen = sqrt(sum(vvec.^2,2));
        vvec = vvec ./ [vlen,vlen] ;

        hmid = fun0(edge(epos,+1),:) ...
             + fun0(edge(epos,+2),:) ;
        hmid = hmid * +0.50 ;

    %------------------------------------- "ball"-type dist.
        rtri = elen * opts.off2 ;
        rfac = elen * +0.50 ;
        dsqr = rtri.^2 - rfac.^2;
        doff = rtri + ...
            sqrt(max(+0.,dsqr)) ;

    %------------------------------------- "size"-type dist.
        dsiz = +sqrt(3.)/2. * hmid ;

    %------------------------------------- bind "safe" dist.
       [dist,ioff] = ...
          min([dsiz,doff,vlen],[],2) ;

    %------------------------------------- locate offcentres
        off2 = ...
        emid + [dist,dist] .* vvec ;

    %------------------------------------- iter. "size"-type
        for isub = +1 : +3
    %------------------------------------- eval. length-fun.
        if (~isempty(hfun))
            if (isnumeric(hfun))
            hprj = hfun * ...
              ones(size(off2,1),1) ;
            else
            hprj = feval( ...
                hfun,off2,harg{:}) ;
            hprj = hprj(:) ;
            end
        else
            hprj = +inf * ...
              ones(size(off2,1),1) ;
        end

    %------------------------------------- "size"-type dist.
        hprj = .33*hmid + .67*hprj ;

        dsiz = +sqrt(3.)/2. * hprj ;

        dsiz(dsiz<elen*.50) = +inf ;    %- edge-ball limiter
        dsiz(dsiz>vlen*.95) = +inf ;    %- circ-ball limiter

    %------------------------------------- bind "safe" dist.
       [dist,ioff] = ...
          min([dsiz,doff,vlen],[],2) ;

    %------------------------------------- locate offcentres
        off2 = ...
        emid + [dist,dist] .* vvec ;

        end

        orad = ...
        sqrt((elen*.5).^2 + dist.^2) ;

    %------------------------------------- do offcentre pt's
        new2 = ...
        zeros(length(find(ftri)),+3) ;
        new2(:,1:2) = off2(ftri,1:2) ;

        rmin = ...                      %- min. insert radii
            lmin(ftri)*(1.-eps^.75)^2 ;

        new2(:,  3) = max( ...
            (orad(ftri)*near).^2,rmin);

        tcpu.offc = ...
            tcpu.offc + toc (ttic) ;

        end % switch(lower(opts.kind))

    %------------------------------------- inter.-ball dist.
        ttic = tic ;

    %------------------------------------- proximity filters
       [vp,vi] = ...
          findball(new2,new2(:,1:2)) ;

        keep = true (size(new2,1),1) ;
        for ii = size(vp,1):-1:+1
            for ip = vp(ii,1) ...
                   : vp(ii,2)
                jj = vi(ip);
                if (keep(jj) && ...
                    keep(ii) && ...
                    jj < ii )

                keep(ii) = false ;
                break;

                end
            end
        end

        new2 = new2(keep,:);

    %------------------------------------- test encroachment
        bal1(:,3) = ...
            (1.-eps^.75) * bal1(:,3);

       [vp,vi] = ...
          findball(bal1,new2(:,1:2));

        keep = true (size(new2,1),1);
        for ii = +1:+1:size(vp,1)
            for ip = vp(ii,1) ...
                   : vp(ii,2)
                jj = vi(ip);
                ref1(jj) =  true ;
                keep(ii) = false ;
            end
        end

    %------------------------------------- leave sharp edges
        ebnd = false(size(edge,1),1);
        ebnd(tria(stri,4:6)) = true ;

        enot = ...
        setset2(conn,edge(ebnd,1:2));

        ref1(enot) = false ;

    %------------------------------------- preserve boundary
        if (strcmpi(opts.ref1,...
            'preserve'))
        ref1(:)    = false ;
        end

    %------------------------------------- refinement points
        new2 = new2(keep,:);
        new1 = bal1(ref1,:);

        tcpu.filt = ...
            tcpu.filt + toc(ttic) ;

    %------------------------------------- split constraints
        idx1 = ...
       (1:size(new1))'+size(vert,1) ;

        idx2 = ...
       (1:size(new2))'+size(new1,1) ...
                      +size(vert,1) ;

        cnew = [conn( ref1,1), idx1
                conn( ref1,2), idx1];
        conn = [conn(~ref1,:); cnew];

        vidx = [idx1; idx2];

    %------------------------------------- update vertex set
        nold = size(vert,1);
        vert = [vert; new1(:,1:2)];
        vert = [vert; new2(:,1:2)];
        % wjp: make sure vertices are unique
        vert = unique(vert,'rows','stable');
        nnew = size(vert,1);

        if (nnew == nold), break; end   %- we *must* be done

    end

    tcpu.full = ...
        tcpu.full + toc(tnow) ;

    if (~isinf(opts.disp) )
    %------------------------------------- print final stats
        numc = size(conn,1) ;
        numt = size(tria,1) ;
        fprintf(+1, ...
        '%11i %18i %18i\n', ...
        [iter,numc,numt]) ;
    end

    if (opts.dbug)
    %------------------------------------- print debug timer
        fprintf(1,'\n') ;
        fprintf(1,' 2-simplex REF. timer...\n');
        fprintf(1,'\n') ;
        fprintf(1, ...
        ' FULL: %f \n', tcpu.full);
        fprintf(1, ...
        ' DTRI: %f \n', tcpu.dtri);
        fprintf(1, ...
        ' TCON: %f \n', tcpu.tcon);
        fprintf(1, ...
        ' BALL: %f \n', tcpu.ball);
        fprintf(1, ...
        ' HFUN: %f \n', tcpu.hfun);
        fprintf(1, ...
        ' OFFC: %f \n', tcpu.offc);
        fprintf(1, ...
        ' FILT: %f \n', tcpu.filt);
        fprintf(1,'\n') ;
    end

end

function [opts] = makeopt(opts)
%MAKEOPT setup the options structure for REFINE2.

    if (~isfield(opts,'dtri'))
        opts.dtri = 'constrained';
    else
    if (~strcmpi(opts.dtri, 'conforming') && ...
        ~strcmpi(opts.dtri,'constrained') )
        error( ...
    'refine2:invalidOption','Invalid constraint DTRI.');
    end
    end

    if (~isfield(opts,'kind'))
        opts.kind = 'delfront';
    else
    if (~strcmpi(opts.kind, 'delfront') && ...
        ~strcmpi(opts.kind, 'delaunay') )
        error( ...
    'refine2:invalidOption','Invalid refinement KIND.');
    end
    end

    if (~isfield(opts,'ref1'))
        opts.ref1 = 'refine';
    else
    if (~strcmpi(opts.ref1,   'refine') && ...
        ~strcmpi(opts.ref1, 'preserve') )
        error( ...
    'refine2:invalidOption','Invalid refinement REF1.');
    end
    end

    if (~isfield(opts,'ref2'))
        opts.ref2 = 'refine';
    else
    if (~strcmpi(opts.ref2,   'refine') && ...
        ~strcmpi(opts.ref2, 'preserve') )
        error( ...
    'refine2:invalidOption','Invalid refinement REF2.');
    end
    end

    if (~isfield(opts,'iter'))
        opts.iter = +inf;
    else
    if (~isnumeric(opts.iter))
        error('refine2:incorrectInputClass', ...
            'Incorrect input class.');
    end
    if (numel(opts.iter)~= +1)
        error('refine2:incorrectDimensions', ...
            'Incorrect input dimensions.') ;
    end
    if (opts.iter <= +0)
        error('refine2:invalidOptionValues', ...
            'Invalid OPT.ITER selection.') ;
    end
    end

    if (~isfield(opts,'disp'))
        opts.disp = +10 ;
    else
    if (~isnumeric(opts.disp))
        error('refine2:incorrectInputClass', ...
            'Incorrect input class.');
    end
    if (numel(opts.disp)~= +1)
        error('refine2:incorrectDimensions', ...
            'Incorrect input dimensions.') ;
    end
    if (opts.disp <= +0)
        error('refine2:invalidOptionValues', ...
            'Invalid OPT.DISP selection.') ;
    end
    end

    if (~isfield(opts,'rho2'))
        opts.rho2 = 1.025;
    else
    if (~isnumeric(opts.rho2))
        error('refine2:incorrectInputClass', ...
            'Incorrect input class.');
    end
    if (numel(opts.rho2)~= +1)
        error('refine2:incorrectDimensions', ...
            'Incorrect input dimensions.') ;
    end
    if (opts.rho2 < +1.)
        error('refine2:invalidOptionValues', ...
            'Invalid OPT.RHO2 selection.') ;
    end
    end

    if (~isfield(opts,'off2'))
        opts.off2 = 0.933;
    else
    if (~isnumeric(opts.off2))
        error('refine2:incorrectInputClass', ...
            'Incorrect input class.');
    end
    if (numel(opts.off2)~= +1)
        error('refine2:incorrectDimensions', ...
            'Incorrect input dimensions.') ;
    end
    if (opts.off2 < +.7)
        error('refine2:invalidOptionValues', ...
            'Invalid OPT.OFF2 selection.') ;
    end
    end

    if (~isfield(opts,'siz1'))
        opts.siz1 = 1.333;
    else
    if (~isnumeric(opts.siz1))
        error('refine2:incorrectInputClass', ...
            'Incorrect input class.');
    end
    if (numel(opts.siz1)~= +1)
        error('refine2:incorrectDimensions', ...
            'Incorrect input dimensions.') ;
    end
    if (opts.siz1 <= 0.)
        error('refine2:invalidOptionValues', ...
            'Invalid OPT.SIZ1 selection.') ;
    end
    end

    if (~isfield(opts,'siz2'))
        opts.siz2 = 1.300;
    else
    if (~isnumeric(opts.siz2))
        error('refine2:incorrectInputClass', ...
            'Incorrect input class.');
    end
    if (numel(opts.siz2)~= +1)
        error('refine2:incorrectDimensions', ...
            'Incorrect input dimensions.') ;
    end
    if (opts.siz2 <= 0.)
        error('refine2:invalidOptionValues', ...
            'Invalid OPT.SIZ2 selection.') ;
    end
    end

    if (~isfield(opts,'dbug'))
        opts.dbug = false;
    else
    if (~islogical(opts.dbug))
        error('refine2:incorrectInputClass', ...
            'Incorrect input class.');
    end
    if (numel(opts.dbug)~= +1)
        error('refine2:incorrectDimensions', ...
            'Incorrect input dimensions.') ;
    end
    end

end


function fem1d_pack_test ( )

%*****************************************************************************80
%
%% FEM1D_PACK_TEST tests the FEM1D_PACK library.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    18 March 2011
%
%  Author:
%
%    John Burkardt
%
  timestamp ( );
  fprintf ( 1, '\n' );
  fprintf ( 1, 'FEM1D_PACK_TEST\n' );
  fprintf ( 1, '  MATLAB version\n' );
  fprintf ( 1, '  Test the FEM1D_PACK library.\n' );

  fem1d_pack_test01 ( );
%
%  Terminate.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'FEM1D_PACK_TEST\n' );
  fprintf ( 1, '  Normal end of execution.\n' );
  fprintf ( 1, '\n' );
  timestamp ( );

  return
end


function Hd = gen_iir_coeffs
%GEN_IIR_COEFFS Returns a discrete-time filter object.

%
% M-File generated by MATLAB(R) 7.7 and the Signal Processing Toolbox 6.10.
%
% Generated on: 16-Dec-2008 10:06:34
%

% Elliptic Lowpass filter designed using FDESIGN.LOWPASS.

% All frequency values are in Hz.
Fs = 1024;  % Sampling Frequency

Fpass = 100;     % Passband Frequency
Fstop = 125;     % Stopband Frequency
Apass = 1;       % Passband Ripple (dB)
Astop = 80;      % Stopband Attenuation (dB)
match = 'both';  % Band to match exactly

% Construct an FDESIGN object and call its ELLIP method.
h  = fdesign.lowpass(Fpass, Fstop, Apass, Astop, Fs);
Hd = design(h, 'ellip', 'MatchExactly', match);
set(Hd, 'Arithmetic', 'double');

% [EOF]


classdef OptimalExponentsComparatorWithPNorm < handle

    properties (Access = private)
        optimalComputer
    end

    properties (Access = private)
        optimalExponentParams
        pNorm
    end

    methods (Access = public)

        function obj = OptimalExponentsComparatorWithPNorm(cParams)
            obj.init(cParams);
        end

        function compute(obj)
            obj.computeOptimalExponents();
            obj.plotStressNormRelationWithQ();
            obj.plotConvergence();
        end

    end

    methods (Access = private)

        function init(obj,cParams)
            obj.optimalExponentParams.txi  = pi/4;
            obj.optimalExponentParams.rho  = 0.15;
            obj.optimalExponentParams.phi  = pi/4;
            obj.optimalExponentParams.hMesh = 0.01;
            obj.pNorm = {2,4,16,32,'max'};
        end

        function computeOptimalExponents(obj)
            s = obj.optimalExponentParams;
            for iP = 1:length(obj.pNorm)
                p = obj.pNorm{iP};
                s.pNorm = p;
                s.fileName = ['ExamplePaper',num2str(p)];
                oC = OneOptimalExponentComputerAndFunctionVariation(s);
                oC.compute();
                obj.optimalComputer{iP} = oC;
            end

        end

        function plotStressNormRelationWithQ(obj)
            f = figure();
            hold on
            for iP = 1:length(obj.pNorm)
                h{iP} = plot(obj.optimalComputer{iP}.qValues(2:end),obj.optimalComputer{iP}.fValues(2:end),'-+');
                p = obj.pNorm{iP};
                if isequal(p,'max')
                    leg{iP} = '$p = \infty$';
                else
                    leg{iP} = ['p = ',num2str(p)];
                end
            end
            outPutPath = '/home/alex/git-repos/MicroStructurePaper/';
            fTitle = 'Stress norm';
            xlabel('$q$','interpreter','latex')
            % set(gca, 'XTickLabel',[])
            ylabel(fTitle,'interpreter','latex')

            for iP = 1:length(obj.pNorm)
                x = obj.optimalComputer{iP}.qValues(2:end);
                y = obj.optimalComputer{iP}.fValues(2:end);
                [~,imin] = min(y);
                plot(x(imin),y(imin),'-s','Color',h{iP}.Color,'MarkerSize',10,'MarkerEdgeColor',h{iP}.Color,'MarkerFaceColor',h{iP}.Color)
            end

            legObj = legend(leg);
            set(legObj,'Interpreter','latex','Location','Best');
            %outputName = [outPutPath,'StressNormVsQForPmax'];
            %outputName = [outPutPath,'StressNormVsQForDifferentP'];
            printer = plotPrinter(f,h);
           % printer.print(outputName);
        end

        function plotConvergence(obj)
            f = figure();
            hold on
            for iP = 1:length(obj.pNorm)
                h{iP} = plot(obj.optimalComputer{iP}.fOptIter,'-+');
                p = obj.pNorm{iP};
                if isequal(p,'max')
                    leg{iP} = '$p = \infty$';
                else
                    leg{iP} = ['p = ',num2str(p)];
                end
            end
            outPutPath = '/home/alex/git-repos/MicroStructurePaper/';
            fTitle = 'Stress norm';
            xlabel('iterations','interpreter','latex')
            ylabel(fTitle,'interpreter','latex')

            legObj = legend(leg);
            set(legObj,'Interpreter','latex','Location','Best');
            outputName = [outPutPath,'StressNormMinimizationForPmax'];
            %outputName = [outPutPath,'StressNormMinimizationFineMax'];
            printer = plotPrinter(f,h);
           % printer.print(outputName);
        end

    end

end


function h = supportFunction(polygon, varargin)
%SUPPORTFUNCTION Compute support function of a polygon.
%
%   H = supportFunction(POLYGON, N)
%   uses N points for suport function approximation
%
%   H = supportFunction(POLYGON)
%   assume 24 points for approximation
%
%   H = supportFunction(POLYGON, V)
%   where V is a vector, uses vector V of angles to compute support
%   function.
%
%   See also
%   polygons2d, convexification

% ------
% Author: David Legland
% E-mail: david.legland@inrae.fr
% Created: 2004-12-20
% Copyright 2004-2022 INRA - TPV URPOI - BIA IMASTE

N = 24;
u = 0:2*pi/N:2*pi*(1-1/N);

if length(varargin)==1
    var = varargin{1};
    if length(var)==1
        N = var;
        u = 0:2*pi/N:2*pi*(1-1/N);
    else
        u = var;
    end
end

% ensure u vertical vector
if size(u, 1)==1
    u=u';
end

h = zeros(size(u));

for i=1:length(u)

    v = repmat([cos(u(i)) sin(u(i))], [size(polygon, 1), 1]);

    h(i) = max(dot(polygon, v, 2));
end


function exact = p03_exact ( )

%*****************************************************************************80
%
%% P03_EXACT returns the exact integral for problem 3.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    04 November 2009
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, real EXACT, the value of the integral.
%
  exact = 2.0 / 3.0;

  return
end


function c = plus(a,b)
% PLUS implements a+b, where either a or b is an adiff object.

switch [class(a),class(b)]

case 'adiffdouble'
   c = adiff(a.x+b, repmat(a.dx,[length(b),1]), a.root);

case 'doubleadiff'
   c = adiff(b.x+a, repmat(b.dx,[length(a),1]), b.root);

case 'adiffadiff'
   checkroot(a,b);
   if size(a.dx,1)~=size(b.dx,1)
      if size(a.dx,1)==1
         a.dx = repmat(a.dx,size(b.dx,1),1);
      elseif size(b.dx,1)==1
         b.dx = repmat(b.dx,size(a.dx,1),1);
      end
   end
   c = adiff( a.x+b.x,a.dx+b.dx, a.root);

otherwise
   error(['Can''t add ',class(a),' and ',class(b)]);

end


function option = mgoptions(option,N)
%% MGOPTIONS default options for multigrid solver
%
% x0 = 0;	tol = 1e-8;   solver = 'CG';    preconditioner = 'Vcycle';
% N0 = 500; coarsegridsolver = 'direct';    mu = 1;
%
% Copyright (C) Long Chen. See COPYRIGHT.txt for details.

if isfield(option,'x0') && strcmpi(option.x0,'rand')
    option.x0 = rand(N,1);
end
if ~isfield(option,'x0')
    option.x0 = zeros(N,1);
end
if ~isfield(option,'tol')
    option.tol = 1e-8;
end
if ~isfield(option,'refType')
    option.refType = 'red';
end
if isfield(option,'solvermaxIt')
    option.solvermaxit = option.solvermaxIt;
elseif isfield(option,'solvermaxit')
    option.solvermaxit = option.solvermaxit;
else
    option.solvermaxit = min(N,200);
end
if isfield(option,'solver')
    option.solver = upper(option.solver);
else
    option.solver = 'CG';
end
if isfield(option,'outsolver')
    option.outsolver = upper(option.outsolver);
else
    option.outsolver = 'CG';
end
if isfield(option,'smoother')
    option.smoother = upper(option.smoother);
else
    option.smoother = 'GS';  % defacult one is Gauss-Seidel
    % option.solver = 'JAC' % Jacobi preconditioner
end
if ~isfield(option,'smoothingstep')  % smoothing steps
    option.smoothingstep = 1;
end
if ~isfield(option,'smoothingratio')  % ratio of variable smoothing
    option.smoothingratio = 1;
end
if ~isfield(option,'smoothingparameter')  % smoothing parameter
    option.smoothingparameter = 1;
end
if isfield(option,'preconditioner')
    option.preconditioner = upper(option.preconditioner);
elseif ~strcmp(option.solver,'Vcycle') && ~strcmp(option.solver,'Wcycle') ...
        && ~strcmp(option.solver,'Fcycle')
    option.preconditioner = 'V';
else
    option.preconditioner = 'NO';
end
if ~isfield(option,'N0')
    option.N0 = 50;
end
if ~isfield(option,'coarsegridsolver')
    option.coarsegridsolver = 'direct';    % solver in the coarsest grid
end
if ~isfield(option,'printlevel')
    option.printlevel = 1;
end
if ~isfield(option,'setupflag')
    option.setupflag = true;
end


% Function to derive residual peak prominence parameter
%
% Description
% Function to derive residual peak prominence parameter
%
%
% Inputs
%  x        : [samples] [Nx1]  Speech signal
%  fs       : [Hz]      [1x1]  Sampling frequency
%  res      : [samples] [Nx1]  Linear prediction residual of speech
%  Es       : [dB]      [Mx1]  Energy contour
%
% Outputs
%  peak_inter:[samples] [Nx2]  Interpolated peak prominence contour
%
% Example
%  Please see the HOWTO_glottalsource.m example file.
%
% References
%  [1] Drugman, T., Kane, J., Gobl, C., `Automatic Analysis of Creaky
%       Excitation Patterns', Submitted to Computer Speech and
%       Language.
%  [2] Kane, J., Drugman, T., Gobl, C., (2013) `Improved automatic
%       detection of creak', Computer Speech and Language 27(4), pp.
%       1028-1047.
%  [3] Drugman, T., Kane, J., Gobl, C., (2012) `Resonator-based creaky
%       voice detection', Interspeech 2012, Portland, Oregon, USA.
%
% Copyright (c) 2013 University of Mons, FNRS & 2013 Trinity College Dublin
%
% License
%  This code is a part of the GLOAT toolbox with the following
%  licence:
%  This program is free software: you can redistribute it and/or modify
%  it under the terms of the GNU General Public License as published by
%  the Free Software Foundation, either version 3 of the License, or
%  (at your option) any later version.
%  This program is distributed in the hope that it will be useful,
%  but WITHOUT ANY WARRANTY; without even the implied warranty of
%  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%  GNU General Public License for more details.
%
% This function is part of the Covarep project: http://covarep.github.io/covarep
%
% Authors
%  Thomas Drugman <thomas.drugman@umons.ac.be> & John Kane <kanejo@tcd.ie>

function [peak_inter,peak_prom,peak_t,rep] = res_peak(x,fs,F0mean,res,Es)

% Function to generate residual peak prominence contour which makes up the
% second component of the creak detection algorithm.

% Different settings according to the speakers baseline pitch
if F0mean>100
    maxCreakF0=90;
elseif F0mean < 100 && F0mean>=85
    maxCreakF0=65;
elseif F0mean<85
    maxCreakF0=55;
else maxCreakF0=80;
end

% Set window length based on maximum possible creaky F0
winLen=round(fs/maxCreakF0)*2;

% Resonator settings
Phi=2*pi*1*F0mean/fs;
Rho=0.8;
rep=filter([1 0 0],[1 -2*Rho*cos(Phi) Rho^2],res);

% Measure residual peak prominence
[peak_prom,peak_t] = get_res_peak_prom(rep,fs,winLen,x,Es);

% Interpolate
if length(peak_prom)>1
    peak_inter=interp1(peak_t,peak_prom,1:length(x));
else peak_inter=zeros(1,length(x));
end

peak_inter=[peak_inter(:) (1:length(x))'];