function varargout = ihashsum(varargin)
% VL_IHASHSUM  Accumulate integer labels into a hash table
%   [H,ID,NEXT] = VL_IHASHSUM(H,ID,NEXT,K,X) counts the number of
%   occurences of the columns of X, accumulating these to the hash
%   table represented by the tripled H,ID,NEXT.
%
%   X is a D x N array of class UINT8 each row of which defines an D
%   dimensional label. Labels cannot be all zeros.
%
%   H and NEXT are 1 x C arrays of class UINT32 and ID is a D x C
%   array of class UINT8. H is a vector of counts, ID stores, for each
%   element of H, the corresponding label, and NEXT is a vector of
%   indexes.
%
%   Once constructed, the hash table can be searched by means of the
%   VL_IHASHFIND() function.
%
%   The hash table uses double hashing [1] with an initial size equal
%   to K (so that C >= K). Given a label X, this is first hashed by
%   using the FNV algorithm [2] to one of K bucket. If this bucket is
%   free, it is assigned to label X and the count is incremented.  If
%   the bucket is already assigned to the same label X, the count is
%   incremented. If the bucket is already assigned to a different
%   label, a second hash is used to scan (probe) the table for a free
%   bucket.
%
%   If no free/matching bucket is found (because the hash table is
%   full) an overflow area containing extra buckets is used. This is
%   visited by reading off indexe from the NEXT vector, until a
%   matching bucket is found or the overflow area is enlarged.
%
%   Example::
%     The following example counts integer bi-dimensional label
%     occurences:
%
%       K = 5 ;
%       h = zeros(1,K,'uint32') ;
%       id = zeros(2,K,'uint8');
%       next = zeros(1,K,'uint32') ;
%       X = uint8([1 1 ; 1 2 ; 2 1 ; 1 1]') ;
%       [h,id,next] = vl_ihashsum(h,id,next,K,X) ;
%
%     resulting in
%
%       h = [1 0 1 2 0]
%       id = [1    0    2    1    0
%             2    0    1    1    0]
%       next = [0 0 0 0 0]
%
%     For example, [1;2] has a count of 1 and [1;1] has a count of
%     2. NEXT is zero because there have been no collisions.
%
%   REFERENCES::
%   [1] http://en.wikipedia.org/wiki/Double_hashing
%   [2] http://www.isthe.com/chongo/tech/comp/fnv
%
%   See also: VL_IHASHFIND().
[varargout{1:nargout}] = vl_ihashsum(varargin{:});


function sphere_llt_grid_display_test ( )

%*****************************************************************************80
%
%% SPHERE_LLT_GRID_DISPLAY_TEST tests SPHERE_LLT_GRID_DISPLAY.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    29 April 2015
%
%  Author:
%
%    John Burkardt
%
  lat_num = 10;
  long_num = 12;
  pc(1,1:3) = [ 0.0, 0.0, 0.0 ];
  r = 10.0;

  fprintf ( 1, '\n' );
  fprintf ( 1, 'SPHERE_LLT_GRID_DISPLAY_TEST\n' );
  fprintf ( 1, '  SPHERE_LLT_GRID_DISPLAY displays an LLT grid on a sphere.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Number of latitudes is  %d\n', lat_num );
  fprintf ( 1, '  Number of longitudes is %d\n', long_num );
%
%  Get points.
%
  node_num = sphere_llt_grid_point_count ( lat_num, long_num );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  The number of grid points is %d\n', node_num );

  node_xyz = sphere_llt_grid_points ( r, pc, lat_num, long_num, node_num );
%
%  Get lines.
%
  line_num = sphere_llt_grid_line_count ( lat_num, long_num );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  Number of line segments is %d\n', line_num );

  line_data = sphere_llt_grid_lines ( lat_num, long_num, line_num );

  filename = 'sphere_llt_grid.png';

  sphere_llt_grid_display ( r, pc, lat_num, long_num, node_num, node_xyz, line_num, ...
    line_data, filename );

  return
end


function [w,winit_pix]=init_w(method,peval,image)
% [w,winit_pix]=init_w(method,peval,image)
% method:   'rand' %random initialization
%           'image' %specified initialization for example image=double(array2im(dpixc_ind))
%           'image_repmat' %for example image = mean(image,3);
%           'res' %image is res.w -> initialisation from the nmf results
% addbackgroundcomponent:   1 adds one component flat component as a background (peval.ncomp th)
%                           0 no background component
if ~isfield(peval, 'bgcomp')
    peval.bgcomp = 1;
end

switch method
    case 'rand'
        winit_pix = normalize(rand(peval.nx,peval.ny,peval.ncomp));
        msg='W initialzied as uniform random.';
    case 'image'
        winit_pix = normalize(image);
        msg='W initialized with specified 3D image.';
    case 'image_repmat'
        winit_pix(:,:,1:peval.ncomp) = normalize(repmat(image,[1,1,peval.ncomp]));
        msg='W initialized as repmat(image,[1,1,peval.ncomp].)';
    case 'res'
        s2=size(image,2); %it is only 2D (#pixX#comp)
        winit_pix(:,:,1:s2) = reshape(image, peval.nx, peval.ny, s2);
        msg='W initialized from the results res.w.';
end
winit_pix=max(winit_pix, eps); % To avoid zeros...
sw=size(winit_pix);
w=reshape(winit_pix,sw(1)*sw(2), size(winit_pix,3)); % it must be specifically set to size(winit_pix,3) for the case tehre is only one compoenent (ncomp=1)

if isfield (peval,'fid')
    mfprintf(peval.fid, [msg '\n'])
else
    fprintf([msg '\n']);
end

if peval.bgcomp
    w(:,peval.ncomp)=normalize(ones(sw(1)*sw(2),1));
    mfprintf(peval.fid, 'Last component [%g] of w initialised as a flat background. (background=%g)\n',peval.ncomp,peval.bg);
end


function z = power( x, y, op )

%POWER   Internal cvx version.

persistent BP
if isempty( BP ),
    BP.map = cvx_remap( ...
        ... % Invalid combinations: zero ^ negative, posynomial ^ negative
        { { 'zero', 'g_posynomial', 'gg_monomial' }, { 'negative' } }, ...
        ... % Constant
        { { 'constant' } }, ...
        ... % constant ^ convex/concave
        { { 'positive' }, { 'convex', 'concave' } }, ...
        ... % geometric ^ real
        { { 'l_valid_' }, { 'real' } }, ...
        ... % other non-constant ^ real
        { { 'valid' }, { 'real' } }, [0,1,2,3,4] );
    BP.funcs = { @power_c, @power_e, @power_g, @power_p };
    BP.constant = 1;
end
if isnumeric( y ) && numel( y ) == 1,
    switch y,
        case   1, z = x;           return
        case   2, z = square( x ); return
        case 0.5, z = sqrt( x );   return
        case  -1, z = recip( x );  return
    end
end
if nargin < 3, op = '.^'; end
BP.name = op;
z = cvx_binary_op( BP, x, y );

function z = power_c( x, y )
z = builtin( 'power', x, y );

function z = power_e( x, y )
z = exp( log( cvx_constant( x ) ) .* y );

function z = power_g( x, y )
z = exp( log( x ) .* y );

function z = power_p( x, y )
nx = numel( x );
ny = numel( y );
y  = cvx_constant( y );
vx = cvx_classify( x );
nz = max( nx, ny );
if ny == 1
    pu = y;
    multp = false;
else
    pu = sort( y' ); %#ok'
    pu = pu( [ true, diff(pu) ~= 0 ] );
    multp = length( pu ) ~= 1;
end
if multp,
    zp = cvx( nz, [] );
    vp = vx;
    xp = x;
    yp = y;
end
errs = {};
for pk = pu,
    if multp,
        tp = yp == pk;
        if nx > 1,
            x = cvx_fastref( xp, tp );
            x = cvx( [size(x,2),1], x );
            vx = vp( tp );
        end
        if ny > 1,
            y = yp( tp );
        end
    end
    y1 = y(1);
    if y == 2,
        z = square( x );
    elseif y1 > 1,
        z = power_cvx( x, vx, y1 );
    elseif y1 == 1,
        z = x;
    elseif y1 > 0,
        z = power_ccv( x, vx, y1 );
    elseif y1 == 0,
        z = cvx( ones(size(x)) );
    else
        z = power_neg( x, vx, y1 );
    end
    if islogical( z ),
        errs(end+1,:) = { cvx_subsref( x, z ), y }; %#ok
        continue
    end
    if nx ~= nz,
        z = repmat( z, [nz,1] );
    end
    if multp,
        zp = cvx_fastasgn( zp, tp, z );
    end
end
if multp
    z = zp;
end
if ~isempty( errs ),
    cvx_dcp_error( errs, op );
elseif multp
    z = zm;
end

%
% P > 1, integer: X affine, p-convex, n-concave
% P > 1, non-integer: X affine, p-convex
%

function y = power_cvx_fast( x, p ) %#ok
ne = 0;
nx = numel( x );
while rem(p,2) == 0,
    ne = ne + 1;
    p = p * 0.5;
end
cvx_begin
    epigraph variable y(nx) nonnegative_
    if ne > 0,
        variables z2(nx,ne-1)
        if p == 1,
            w = y;
        else
            variable w(nx)
        end
        { [x,z2], 0.5, [z2,w] } == rotated_lorentz( [ nx, ne ], 3 ); %#ok
    else
        w = x;
    end
    if p > 1,
        { [y,ones(nx,1)], w } == geo_mean_cone( [ nx, 2 ], 2, [1/p,1-1/p], 'func' );  %#ok
    end
cvx_end

function y = power_cvx( x, v, p )
persistent remap remap_i remap_e
if isempty( remap_e ),
    remap   = cvx_remap( 'affine', 'p_convex' );
    remap_i = cvx_remap( 'p_convex' ) - cvx_remap( 'n_concave' );
    remap_e = remap_i | remap;
end
if ~isempty( v ),
    isint = rem( p, 1 ) == 0;
    if isint,
        isevn = rem( p, 2 ) == 0;
        if isevn,
            v = remap_e( v );
        else
            v = remap_i( v );
        end
    else
        v = remap( v );
    end
    if ~all( v ),
        y = v == 0;
        return
    end
    v = 1 - 2 * ( v(:) == 3 );
    x = linearize( v .* x );
else
    isint = false;
end
y = power_cvx_fast( x, p );
if isint,
    y = v .* y;
end

%
% 0 < P < 1: X concave
%

function y = power_ccv( x, v, p )
persistent remap
if isempty( remap ),
    remap = ~cvx_remap( 'concave' );
end
v = remap( v );
if any( v ),
    y = v;
    return
end
cvx_begin
    hypograph variable y(numel(x)) nonnegative_
    power_cvx_fast( y, 1.0 / p ) <= x; %#ok
cvx_end

%
% P < 0, integer: p-concave, n-convex
% P < 0, non-integer: p-concave
%

function y = power_neg( x, v, p )
persistent remap remap_i
if isempty( remap_i ),
    remap   = cvx_remap( 'p_concave' );
    remap_i = remap - cvx_remap( 'n_convex' );
end
if rem( p, 1 ) == 0,
    % Integer: positive and negative lobes
    v = remap_i( v );
else
    % Non-integer: positive lobe only
    v = remap( v );
end
if ~all( v ),
    y = v == 0;
    return
end
nx = numel(x);
z  = linearize( v .* x );
cvx_begin
    epigraph variable y(nx)
    if p == 1,
        { 2, z, y } == rotated_lorentz( [nx,1], 2, 0 ); %#ok
    else
        { [z,y], 1 } == geo_mean_cone( [nx,2], 2, [-p,1], 'func' ); %#ok
    end
    cvx_setnneg(y);
cvx_end
y = v .* y;

% Copyright 2005-2014 CVX Research, Inc.
% See the file LICENSE.txt for full copyright information.
% The command 'cvx_where' will show where this file is located.


function sucra()
    % This script evaluates the percentage of space time coevered by
    %alarms
    %
    % turned into function by Celso G Reyes 2017

    ZG=ZmapGlobal.Data; % used by get_zmap_globals
    global iala
    re = [];
    % Stefan Wiemer    4/95

    report_this_filefun();

    abo = abo2;

    for tre2 = min(abo(:,4)):0.1:max(abo(:,4)-0.1)
        abo = abo2;
        abo(:,5) = abo(:,5)* days(ZG.bin_dur) + ZG.primeCatalog.Date(1);
        l = abo(:,4) >= tre2;
        abo = abo(l,:);
        l = abo(:,3) < ZG.tresh_km;
        abo = abo(l,:);
        set(gca,'NextPlot','add')

        % space time volume covered by alarms
        if isempty(abo)
            Va = 0;
        else
            Va = sum(pi*abo(:,3).^2)*iala;
        end

        % All space time
        [len, ncu] = size(cumuall);

        r = loc(3,:);
        %r = reshape(cumuall(len,:),length(gy),length(gx));
        %r=reshape(normlap2,length(yvect),length(xvect));
        l = r < ZG.tresh_km;
        V = sum(pi*r(l).^2*(teb-t0b));
        disp([' Zalarm = ' num2str(tre2)])
        disp([' =============================================='])
        disp([' Total space-time volume (R<Rmin):  ' num2str(V)])
        disp([' Space-time volume covered with alarms (R<Rmin):  ' num2str(Va)])
        disp([' Percent of total covered with alarms (R<Rmin):  ' num2str(Va/V*100) ' Percent' ])

        re = [re ; tre2 Va/V*100 ];
    end   % for tre2

    figure

    axis off

    uicontrol('Units','normal',...
        'Position',[.0 .65 .08 .06],'String','Save ',...
        'Callback',{@calSave9, re(:,1), re(:,2)})

    rect = [0.20,  0.10, 0.70, 0.60];
    axes('position',rect)
    set(gca,'NextPlot','add')
    pl = semilogy(re(:,1),re(:,2),'r');
    set(pl,'LineWidth',1.5)
    pl = semilogy(re(:,1),re(:,2),'ob');
    set(pl,'LineWidth',1.5,'MarkerSize',10)
    set(gca,'YScale','log')

    set(gca,'visible','on','FontSize',ZmapGlobal.Data.fontsz.m,'FontWeight','bold',...
        'FontWeight','bold','LineWidth',1.5,...
        'Box','on')
    grid

    ylabel('Va/Vtotal in %')
    xlabel('Zalarm ')
    watchoff

end


function r = mpower(p,q)
% MEAS/MPOWER  Implement p^q for meas.

% make a meas called r
r = meas();

% give it the right entries
r.value = p.value^q;
r.error = r.value * q * (p.error / p.value);


function [U] = hyperAmee(M, q, Smin, Smax, Imax)
% HYPERAMEE Performs the AMEE algorithm to find q endmembers
%   Performs the Automated Morphological Endmember Extraction (AMEE)
%  algorithm to find q endmembers. If only M is
%  given as input, this function calls hyperHfcVd to estimate the number
%  of endmembers (q) and then hyperPct to reduce dimensionality to (q-1).
%
% Usage
%   [U] = hyperAmee(M, q, Smin)
%   [U] = hyperAmee(M, q, Smin, Smax)
%   [U] = hyperAmee(M, q, Smin, Smax, Imax)
% Inputs
%   M    - 3d matrix of HSI data (m x n x p)
%   q    - Number of endmembers to find
%   Smin - minimum kernel size (Smin x Smin)
%   Smax - maximum kernel size (Smax x Smax)
%   Imax - maximum iterations
% Outputs
%   U - Recovered endmembers (p x q)
%
% References
%   Plaza, Antonio, et al. "Spatial/spectral endmember extraction
% by multidimensional morphological operations." Geoscience and
% Remote Sensing, IEEE Transactions on 40.9 (2002): 2025-2041.

% Error trapping
if nargin < 3 || nargin > 5
    help hyperAmee
    error('Not enough input arguments. See function description.')
elseif nargin == 3
    % i.e. Smax and Imax not given
    Smax = Smin;
    Imax = 1;
elseif nargin == 4
    % i.e. if Imax not given
    if Smin <= Smax
        Imax = round((Smax-Smin)/2)+1;
    else
        help hyperAmee
        error('Smax cannot be less than Smin. See function description.')
    end
elseif nargin == 5
    if Smin == Smax && Imax < 2
        help hyperAmee
        error('Cannot iterate more than once with these S limits.')
    elseif Imax > (Smax-Smin+1)
        Imax = round((Smax-Smin)/2)+1;
    end
end

if ndims(M) ~= 3
    error('Input image must be (m x n x p)');
else
    [h, w, p] = size(M);
end

% Build pixel vectors from M
pixVec = cell(h, w);
for hIter = 1:h
    for wIter = 1:w
        pixVec{hIter,wIter} = squeeze(M(hIter,wIter,:));
    end
end

% Morphological Eccentricity Index Score (MEI)
MEI = zeros(h, w);

% Kernel (structuring element)
for B = round(linspace(Smin, Smax, Imax));
    % Create non-overlapping arrays (to reduce computational load)
    hArray = 1:B:h; hArray(end) = h-B+1;
    wArray = 1:B:w; wArray(end) = w-B+1;

    % Move B though all pixels in M
    for wPixel = wArray;
        for hPixel = hArray;
            % (hPixel,wPixel) defines the top-left pixel of the current kernel
            ker = pixVec(hPixel:hPixel+B-1, wPixel:wPixel+B-1);
            [x, y, mei] = spatialSearch( ker );
            % global (x,y) from local (x,y)
            x = x+hPixel-1;
            y = y+wPixel-1;
            % set MEI value at max pixel location
            MEI(x, y) = mei;
        end
    end
end

% Find q largest MEI values
[tmp,idx] = sort(MEI(:), 'descend');
top       = idx(1:q)';

% Return endmembers
U = cell2mat(pixVec(top));

end % hyperAmee function

function [xMax, yMax, mei] = spatialSearch( ker )
%function [xMax, yMax, mei] = spatialSearch( ker )
% spatialSearch finds the max and min cumulative distances
% between each pixel vector and its neighbors inside a kernel
% of size (B x B) and computes the local MEI.

if ~iscell(ker)
    error('ker is not a cell! See line 57 of hyperAmee.m')
end

B = size(ker,1);

dist = zeros(B);
for i = 1:B;
    for j = 1:B;
        dist(i,j) = Dist(ker{i,j}, ker);
    end
end

% Morphological erosion to find minimum pixel vector in region B
[tmp,rowIdx] = min(dist);
[val,colIdx] = min(tmp);
xMin = rowIdx(colIdx);
yMin = colIdx;

% Morphological dilation to find maximum pixel vector in region B
[tmp,rowIdx] = max(dist);
[val,colIdx] = max(tmp);
xMax = rowIdx(colIdx);
yMax = colIdx;

% MEI computation
mei = Dist(ker{xMin, yMin}, ker{xMax, yMax});

end % spatialSearch function

function dist = Dist(a, C)
%function dist = Dist(a, C)
% Cumulative distance measure between a pixel vector and its neighbor(s).
% Plaza et al. used the Spectral Angle Mapper (SAM) measure.
%
% Inputs
%   a - pixel vector of interest (p x 1)
%   C - all pixels in neighborhood (or a single pixel vector)
% Outpus
%   dist - (cumulative) SAM distance

if ~iscell(C)
    dist = acos(dot(a,C)/(norm(a)*norm(C)));
else
    dist = 0;
    for k = 1:numel(C);
        dist = dist + acos(dot(a,C{k})/(norm(a)*norm(C{k})));
    end
end

end % Dist function


function s = char(ker)

% CHAR
%
% Return a textual representation of a polynomial kernel object.
%
%    str = char(ker);

%
% File        : @polynomial/char.m
%
% Date        : Tuesday 12th Spetember 2000
%
% Author      : Dr Gavin C. Cawley
%
% Description : Cast a polynomial kernel object to a character string.
%               Part of an object-oriented implementation of Vapnik's Support
%               Vector Machine, as described in [1].
%
% References  : [1] V.N. Vapnik,
%                   "The Nature of Statistical Learning Theory",
%                   Springer-Verlag, New York, ISBN 0-387-94559-8,
%                   1995.
%
% History     : 07/07/2000 - v1.00
%               12/09/2000 - v1.01 minor improvements to comments and help
%                                  messages
%
% Copyright   : (c) Dr Gavin C. Cawley, September 2000.
%
%    This program is free software; you can redistribute it and/or modify
%    it under the terms of the GNU General Public License as published by
%    the Free Software Foundation; either version 2 of the License, or
%    (at your option) any later version.
%
%    This program is distributed in the hope that it will be useful,
%    but WITHOUT ANY WARRANTY; without even the implied warranty of
%    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%    GNU General Public License for more details.
%
%    You should have received a copy of the GNU General Public License
%    along with this program; if not, write to the Free Software
%    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
%

s = ['polynomial (d = ' num2str(ker.d) ')'];

% bye bye...


function hb_io_test11 ( )

%*****************************************************************************80
%
%% HB_IO_TEST11 tests HB_MATVEC_A_MEM;
%
%  Modified:
%
%    04 February 2005
%
  ncol = 32;
  neltvl = 0;
  nnzero = 126;
  nrhs = 2;
  nrhsix = 0;
  nrow = 32;

  colptr = [ ...
      1,   7,  12,  18,  22,  26,  29,  34,  39,  46, ...
     53,  58,  61,  63,  65,  68,  71,  74,  79,  82, ...
     85,  88,  90,  94,  97, 102, 106, 110, 112, 117, ...
    121, 124, 127 ]';
  exact = [ ...
    0.0,   0.0,   0.0,   0.0,   0.0,   0.0,   0.0,   0.0,   0.0,   1.0, ...
    0.0,   0.0,   0.0,   0.0,   0.0,   0.0,   0.0,   0.0,   0.0,   0.0, ...
    0.0,   0.0,   0.0,   0.0,   0.0,   0.0,   0.0,   0.0,   0.0,   0.0, ...
    0.0,   0.0;
    1.0,   1.0,   1.0,   1.0,   1.0,   1.0,   1.0,   1.0,   1.0,   1.0, ...
    1.0,   1.0,   1.0,   1.0,   1.0,   1.0,   1.0,   1.0,   1.0,   1.0, ...
    1.0,   1.0,   1.0,   1.0,   1.0,   1.0,   1.0,   1.0,   1.0,   1.0, ...
    1.0,   1.0 ]';
  guess = [ ...
    1.0,   1.0,   1.0,   1.0,   1.0,   1.0,   1.0,   1.0,   1.0,   1.0, ...
    1.0,   1.0,   1.0,   1.0,   1.0,   1.0,   1.0,   1.0,   1.0,   1.0, ...
    1.0,   1.0,   1.0,   1.0,   1.0,   1.0,   1.0,   1.0,   1.0,   1.0, ...
    1.0,   1.0;
    1.0,   1.0,   1.0,   1.0,   1.0,   1.0,   1.0,   1.0,   1.0,   1.0, ...
    1.0,   1.0,   1.0,   1.0,   1.0,   1.0,   1.0,   1.0,   1.0,   1.0, ...
    1.0,   1.0,   1.0,   1.0,   1.0,   1.0,   1.0,   1.0,   1.0,   1.0, ...
    1.0,   1.0 ]';
  indcrd = 8;
  indfmt = '(16I5)';
  key = 'RUA_32';
  mxtype = 'RUA';
  output_file = 'rua_32_ax.txt';
  ptrcrd = 3;
  ptrfmt = '(16I5)';
  rhscrd = 12;
  rhsfmt = '(10F7.1)';
  rhsind = 0;
  rhsptr = 0;
  rhstyp = 'FGX';
  rhsvec = 0;
  rowind = [ ...
    1,    2,    3,    4,    7,   26,    1,    2,    9,   21, ...
   28,    2,    3,    6,    8,    9,   29,    3,    4,    5, ...
   12,    3,    5,   23,   27,    1,    6,   16,    3,    7, ...
   14,   21,   31,    1,    8,   12,   17,   27,    7,    9, ...
   10,   13,   19,   23,   27,    1,   10,   11,   21,   23, ...
   25,   27,    2,   11,   15,   18,   29,    6,   12,   24, ...
   11,   13,    3,   14,    2,   15,   20,    4,   16,   22, ...
    4,   16,   17,    6,   10,   18,   20,   30,    1,   19, ...
   26,    8,   16,   20,    3,   21,   32,   11,   22,    2, ...
   17,   21,   23,   12,   24,   26,    6,   15,   18,   24, ...
   25,   13,   18,   22,   26,    5,   24,   26,   27,    9, ...
   28,    3,    5,   27,   29,   32,   12,   17,   23,   30, ...
   13,   14,   31,   24,   28,   32 ]';
  title = '1Real unsymmetric assembled matrix based on IBM32';
  totcrd = 36;
  valcrd = 13;
  valfmt = '(10F7.1)';
  values = [ ...
  101.0,  102.0,  103.0,  104.0,  107.0, ...
  126.0,  201.0,  202.0,  209.0,  221.0, ...
  228.0,  302.0,  303.0,  306.0,  308.0, ...
  309.0,  329.0,  403.0,  404.0,  405.0, ...
  412.0,  503.0,  505.0,  523.0,  527.0, ...
  601.0,  606.0,  616.0,  703.0,  707.0, ...
  714.0,  721.0,  731.0,  801.0,  808.0, ...
  812.0,  817.0,  827.0,  907.0,  909.0, ...
  910.0,  913.0,  919.0,  923.0,  927.0, ...
 1001.0, 1010.0, 1011.0, 1021.0, 1023.0, ...
 1025.0, 1027.0, 1102.0, 1111.0, 1115.0, ...
 1118.0, 1129.0, 1206.0, 1212.0, 1224.0, ...
 1311.0, 1313.0, 1403.0, 1414.0, 1502.0, ...
 1515.0, 1520.0, 1604.0, 1616.0, 1622.0, ...
 1704.0, 1716.0, 1717.0, 1806.0, 1810.0, ...
 1818.0, 1820.0, 1830.0, 1901.0, 1919.0, ...
 1926.0, 2008.0, 2016.0, 2020.0, 2103.0, ...
 2121.0, 2132.0, 2211.0, 2222.0, 2302.0, ...
 2317.0, 2321.0, 2323.0, 2412.0, 2424.0, ...
 2426.0, 2506.0, 2515.0, 2518.0, 2524.0, ...
 2525.0, 2613.0, 2618.0, 2622.0, 2626.0, ...
 2705.0, 2724.0, 2726.0, 2727.0, 2809.0, ...
 2828.0, 2903.0, 2905.0, 2927.0, 2929.0, ...
 2932.0, 3012.0, 3017.0, 3023.0, 3030.0, ...
 3113.0, 3114.0, 3131.0, 3224.0, 3228.0, ...
 3232.0 ]';

  fprintf ( 1, '\n' );
  fprintf ( 1, 'HB_IO_TEST11\n' );
  fprintf ( 1, '  HB_MATVEC_A_MEM multiplies a matrix times a vector.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  This particular version assumes:\n' );
  fprintf ( 1, '  * the matrix is in "A" format (assembled),\n' );
  fprintf ( 1, '  * the matrix and vectors can fit in memory,\n' );
  fprintf ( 1, '  * the matrix and multiplicand have been read into\n' );
  fprintf ( 1, '    memory before the routine is called.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  For this example, the first vector X is zero except\n' );
  fprintf ( 1, '  for a 1 in row 10.  This means A*X should return\n' );
  fprintf ( 1, '  column 10 of A.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  The second vector X is all 1''s.  A*X should be\n' );
  fprintf ( 1, '  the sum of the entries of each row.\n' );

  rhsval = hb_matvec_a_mem ( nrow, ncol, nnzero, nrhs, colptr, rowind, ...
    values, exact );

  r8mat_print ( nrow, nrhs, rhsval,  '  The product vectors A*X' );

  output_unit = fopen ( output_file, 'wt' );

  if ( output_unit < 0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'TEST11 - Fatal error!\n' );
    fprintf ( 1, '  Error opening the file.\n' );
    return;
  end

  hb_file_write ( output_unit, title, key, totcrd, ptrcrd, indcrd, ...
    valcrd, rhscrd, mxtype, nrow, ncol, nnzero, neltvl, ptrfmt, indfmt, ...
    valfmt, rhsfmt, rhstyp, nrhs, nrhsix, colptr, rowind, values, ...
    rhsval, rhsptr, rhsind, rhsvec, guess, exact );

  fclose ( output_unit );

  return
end


function varargout = imChainPixels(img, varargin)
%IMCHAINPIXELS Chain neighbor pixels in an image to form a contour
%
%   POINTS = imChainPixels(IMG)
%   [PX, PY] = imChainPixels(IMG)
%   returns a list of points, chaining points visible in the image.
%   IMG shoud be a binary image, containing a single 8-connected loop.
%
%   Example
%     img = imread('circles.png');
%     img = imFillHoles(img);
%     bnd = imSkeleton(imBoundary(img));
%     figure; subplot(1, 3, 1); imshow(img);
%     subplot(1, 3, 2); imshow(imOverlay(img, bnd));
%     pts = imChainPixels(bnd);
%     subplot(1, 3, 3); imshow(img); hold on;
%     drawPolygon(pts, 'g', 'linewidth', 2);
%
%   See Also
%     imFillHoles, imSkeleton, bwboundaries
%
%   -----
%   author: David Legland
%   INRA - TPV URPOI - BIA IMASTE
%   created the 01/11/2003.
%

%   HISTORY
%   2004-04-06 add to graph lib, correct x-y ordering, and add doc.
%   2012-05-16 rename from findContour to imChainPixels

% set to logical
img = img ~= 0;

% find points in the image
[pty, ptx] = find(img);

% Initialize iteration: first set the initial point
points = zeros(length(ptx), 2);
x0 = ptx(1);
y0 = pty(1);
points(1, 1) = x0;
points(1, 2) = y0;

% Then set the second point, in the neighbourhood of the first point
vois = findNeighbors(img, [x0 y0]);
x = vois(1, 1);
y = vois(1, 2);
points(2, 1) = x;
points(2, 2) = y;

% For each point, find all neighbours (should be only 2)
% Compare with point previously processed, and choose the other one.
% then shift points references, and loop until all points are processed.
for p=3:length(points)
    vois = findNeighbors(img, [x y]);
    if vois(1,1)==x0 && vois(1,2)==y0
        x0 = x;
        y0 = y;
        x = vois(2, 1);
        y = vois(2, 2);
    else
        x0 = x;
        y0 = y;
        x = vois(1, 1);
        y = vois(1, 2);
    end
    points(p, 1) = x;
    points(p, 2) = y;
end

% format results to match output
if nargout==1
    varargout{1} = points;
elseif nargout==2
    varargout{1} = points(:, 1);
    varargout{2} = points(:, 2);
end

return

function neighList = findNeighbors(img, coord)

xp = coord(1);
yp = coord(2);
neighList = [];
nv = 0;

for x = xp-1:xp+1
    if img(yp-1, x)
        nv = nv+1;
        neighList(nv, 1) = x; %#ok<AGROW>
        neighList(nv, 2) = yp-1; %#ok<AGROW>
    end
    if img(yp+1, x)
        nv = nv+1;
        neighList(nv, 1) = x; %#ok<AGROW>
        neighList(nv, 2) = yp+1; %#ok<AGROW>
    end
end

if img(yp, xp-1)
    nv = nv+1;
    neighList(nv, 1) = xp-1;
    neighList(nv, 2) = yp;
end
if img(yp, xp+1)
    nv = nv+1;
    neighList(nv, 1) = xp+1;
    neighList(nv, 2) = yp;
end


function [matrix xmin xmax ymin ymax]=grd_read_v2(namefile)
% Function to read a GRD file
%                  (from Golden Software Surfer, ASCII format)
%
% [matrix xmin xmax ymin ymax]=grd_read_v2(name of file)
%
% Input:
%      nomarch = name of the file to be read, including ".grd" extension
% Output:
%      matrix =  matrix of the read data
%      xmin xmax ymin ymax = grid limits
%
% Coded by Alberto Avila Armella.
%          UPDATED & IMPROVED BY Jose Maria Garcia-Valdecasas

grdfile=fopen(namefile,'r');    % Open file
code=fgetl(grdfile);            % Reads surfer code 'DSAA'
% Grid dimensions (number of nodes)
aux=str2num(fgetl(grdfile)); nx=aux(1); ny=aux(2);
% X limits
aux=str2num(fgetl(grdfile)); xmin=aux(1); xmax=aux(2);
% Y limits
aux=str2num(fgetl(grdfile)); ymin=aux(1); ymax=aux(2);
% Z limits
aux=str2num(fgetl(grdfile)); zmin=aux(1); aux(2);
% Read matrix
[matrix,count] = fscanf(grdfile, '%f', [nx,ny]);
matrix=matrix';   % Trasposes matrix

fclose(grdfile);


function laith()
% LAITH Graphical Simulation of an elevator system
% laith() creates a GUI with the number of floors as input. Granting this number
% creates a building with this number of floors and an elevator that moves up
% and down in it according to the will of animated people (modeled as balls).
%
% To run, type laith in the command window or press F5 from this editor window.
%
% Laith Alkurdi is the name of a friend who worked with me on the code.
%
% Husam Aldahiyat
% Feb. 2009
% numandina@gmail.com
%
%
%% Creating Figure and Uicontrols
% create figure
figure('units','normalized','position',[.1 .1 .8 .8],'color',[1 1 1],...
	'menubar','none','numbertitle','off','name','Elevator')

% create axes
axes('position',[.35 .1 .65 .9])

% create pushbutton (Start)
pb=uicontrol('style','pushbutton','units','normalized','position',...
	[.1 .5 .04 .025],'backgroundcolor',[1 1 1],'string','Start',....
	'fontweight','bold','callback',@dogo);

% create edit box
ed2=uicontrol('style','edit','units','normalized','position',[.1 .525 .04 .025],...
	'backgroundcolor',[1 1 1],'fontweight','bold');

% create text (Floors)
uicontrol('style','text','units','normalized','position',[.1 .55 .04 .025],...
	'backgroundcolor',[1 1 1],'string','Floors','fontweight','bold')

% creates debug text
tee=uicontrol('style','text','foregroundcolor',[1 0 0],'units','normalized',...
	'position',[.025 .6 .25 .35],'backgroundcolor',[0 0 0],'max',2,'fonts',15,...
	'fontname','courier');

% this is so the the floor numbers on the z-axis will have dotted lines
% showing their connection to the elevator
grid on

% initially, we can't see the axes
axis off

% this is just so we can move the camera around during play
rotate3d

%% Drawing the Elevator
% when we press the pushbutton we go here
	function dogo(varargin)

		% if we press the 'Start' button, change its string to 'Stop'
		if strcmp(get(pb,'string'),'Start')
			set(pb,'string','Stop')
		else

			% if we press the 'Stop' button, change its string to 'Start' and
			set(pb,'string','Start')

			% clear the axes
			cla

			% and halt operation
			return
		end

		% make axes appear
		axis on

		% clear debugging text
		set(tee,'string','')

		% get number of floors and turn it from string to number
		flrz=str2double(get(ed2,'string'));

		% check input
		if flrz < 2
			errordlg('Number of floors needs to be at least 2','Stupid!')
			set(pb,'string','Start')
			return
		end

		% this is compensated later by adding 1 to flrz
		% it's stupid but I like to do things like this
		flrz=flrz-1;

		% the following (a) and (b) matrices are very important. they create our
		% 'cube' shape.
		% the first column of (a) determines the min and max values for the (x),
		% the second for (y) and third for (z). So initially we have a unit cube
		% because the min and max for (x),(y) and (z) are (0) and (1).
		a= [0 0 0;
			1 0 0;
			1 1 0;
			0 1 0;
			0 0 1;
			1 0 1;
			1 1 1;
			0 1 1];

		% this (b) matrix specifies the faces of said cube. The cube has six faces
		% and eight vertices (points). the first row of (b) specifies which points
		% of (a) lie on the [b] face.
		% For example, the first face is (1,2,6,5), which are the rows of (a).
		% This mean the points [0,0,0],[1,0,0],[1,0,1] and [0,0,1] lie on the
		% first face, and so on.
		b= [1 2 6 5;
			2 3 7 6;
			3 4 8 7;
			4 1 5 8;
			1 2 3 4;
			5 6 7 8];

		% we want to make the elevator shaft first.
		ac=a;

		% take the max for (z) and multiply it by the number of floors. I have
		% decided that each floor is (0.2) high.
		ac(5:8,3)=.2*(flrz+1);

		% make the 3D patch that has height of the number of floors. this will act
		% as the elevator shaft, or building which our elevator will move
		% through in.
		% the facealpha makes the shaft kind of transparent so you would see the
		% people inside
		patch('vertices',ac,'faces',b,'edgecolor','k','facecolor',[.3 .3 .3],...
			'facevertexalphadata',0.5,'facealpha','flat');

		% next we make the elevator itself
		c=a;

		% for this, just make the (z) column of (a) from (0) to (0.2),
		% this means our elevator is placed initially between (0) and (0.2)
		% in the (z) axis
		c(:,3)=c(:,3).*.2;

		% create our elevator!
		elv=patch('vertices',c,'faces',b,'edgecolor','w','facecolor',[0 0 1],...
			'facevertexalphadata',0.3,'facealpha','flat');

		% next we will make the two elevator doors
		c1=a;

		% the (x) of these doors is zero (flat!)
		c1(:,1)=c1(:,1).*0;

		% the (z) is the same as the elevator
		c1(:,3)=[0;0;0;0;.2;.2;.2;.2];

		% for the first door, the (y) goes from (0) to (0.5)
		c1(:,2)=c1(:,2).*.5;

		% create door number one!
		door1 = patch('vertices',c1,'faces',b,'edgecolor','k','facecolor',...
			[0 0 .8],'facevertexalphadata',1,'facealpha','flat','linewidth',2);

		% same thing for our second door
		c2=a;

		% flat (x)
		c2(:,1)=c2(:,1).*0;

		% (z) from (0) to (0.2)
		c2(:,3)=[0;0;0;0;.2;.2;.2;.2];

		% (y) from (0.5) to (1)
		c2(:,2)=c2(:,2).*.5+.5;

		% create second door!
		door2 = patch('vertices',c2,'faces',b,'edgecolor','k','facecolor',[0 0 1],'facevertexalphadata',1,'facealpha','flat',...
			'linewidth',2);

		% next we want to make flat surfaces for each ground as a reference

		% for each floor go through the loop
		for jk=1:flrz+1

			pk=a;

			% make the (z) equal a number multiple of (0.2)
			% since the min and max of (z) are the same, the resulting surface
			% is flat
			pk(:,3)=repmat(.2*(jk-1),8,1);

			% create this floor
			patch('vertices',pk,'faces',b,'edgecolor','k','facecolor','k','facevertexalphadata',0.9,'facealpha','flat');

		end

		% by now we'll have a transparent elevator shaft with floors and an
		% elevator inside. we'll next want to cover one of the shaft sides with
		% a kind of curtain patch right above and below the elevator.
		% to do this, we will create two patches, one right above the elevator
		% and extends to the roof, while the other will have a min of the ground
		% and a max of the lower limits of our elevators.
		% these two patches will have the cyan face colour

		% flat (x)
		ar=[0 0 0;
			0 0 0;
			0 1 0;
			0 1 0;
			0 0 1;
			0 0 1;
			0 1 1;
			0 1 1];

		% max (z) depends on number of floors
		ar(5:8,3)=.2*(flrz+1);

		% for our first patch, min (z) stays at (0), while max (z) changes with
		% the min height of the elevator, so initially, max (z) is (0)

		af1=ar;
		af1(5:8,3)=repmat(0,4,1);
		fp1=patch('vertices',af1,'faces',b,'edgecolor','k','facecolor','c',...
			'facevertexalphadata',1,'facealpha','flat');

		% for our second patch, max (z) stays at the roof, while min (z) changes
		% with elevator max height. initially, min (z) is (0.2)
		af2=ar;
		af2(1:4,3)=repmat(0.2,4,1);
		fp2=patch('vertices',af2,'faces',b,'edgecolor','k','facecolor','c',...
			'facevertexalphadata',1,'facealpha','flat');

		%  next we'll mark the (z) axis with labels indicating the floor names
		FN=cell(flrz+1,1);
		for kkp=1:flrz+1
			FN{kkp}=['Floor ',num2str(kkp)];
		end

		% by now we have a cell (FN) containing strings for the floors numbers,
		% so we then set the (z) tick label as this string, and the (z) ticks
		% as multiples of (0.2)
		set(gca,'zticklabel',FN,'ztick',.1:.2:(flrz+1)*.2)

		% hide (x) and (y) ticks
		set(gca,'xtick',[]);
		set(gca,'ytick',[]);

		% the following are saved points that will be used later (kind of like
		% lookup table)

		% first are the co-ordinates for the points -inside- the elevator
		in={[.25 .1];[.35 .1];[.5 .1];[.65 .1];[.8 .1];[.925 .1]};

		% these are the co-ordinates for the points outside the elevator after
		% getting out from it
		out={[-.2 .925];[-.2 .75];[-.2 .575];[-.2 .425];[-.2 .275];[-.2 .125]};

		% points outside the elevator waiting to get inside it
		toin={[-.2 .1];[-.2 .25];[-.2 .4];[-.2 .55];[-.2 .7];[-.2 .85]};

		% run function (do1)
		do1

		function do1()

			% create the ground (lobby)

			% the groud axis limits
			v(1)=-.25;
			v(2)=1;
			v(3)=0;
			v(4)=1;

			% (z) is (0) and flat, (y) is same as elevator shaft, while (x) min
			% is slightly lower (so the ground would appear sticking out)
			aaa=[v(1) v(3) 0;
				v(2) v(3) 0;
				v(2) v(4) 0;
				v(1) v(4) 0;
				v(1) v(3) 0;
				v(2) v(3) 0;
				v(2) v(4) 0;
				v(1) v(4) 0];
			b=[1 2 6 5;2 3 7 6;3 4 8 7;4 1 5 8;1 2 3 4;5 6 7 8];

			% create the ground!
			patch('vertices',aaa,'faces',b,'edgecolor',[1 1 1],'facecolor',...
				[.3 .3 .3],'facevertexalphadata',0.5,'facealpha','flat');

			% set proper view (3D)
			view(3)

			% current floor is (0)
			cf=0;

			% dummy variable, means nothing
			dumnop=4;

			% choose number of balls randomly from (1) to (6)
			num=floor(6*rand)+1;

			% create these balls (people)
			createballs(num)

			% counter to be used later
			countz=0;

			% choose heading floor randomly between (2) and max number of floors
			tofloor=floor(rand*(flrz))+1;
%
% [pa1,pa2,aa,aa1,aa2,aa3,ha]=pigeon(.05);
% 			function movp(varargin)
%
% 				for kkl=1:length(ha)
% 					set(ha(kkl),'zdata',get(ha(kkl),'zdata')+.5)
% 					set(ha(kkl),'ydata',get(ha(kkl),'ydata')+.5)
% 					set(ha(kkl),'xdata',get(ha(kkl),'xdata')-.5)
% 				end
% 				ppI=get(pa1,'vertices');
% 				ppII=get(pa2,'vertices');
% 				ppI(:,3)=ppI(:,3)+.5;
% 				ppI(:,2)=ppI(:,2)+.5;
% 				ppI(:,1)=ppI(:,1)-.5;
% 				ppII(:,3)=ppII(:,3)+.5;
% 				ppII(:,2)=ppII(:,2)+.5;
% 				ppII(:,1)=ppII(:,1)-.5;
%
% 				aa2(:,1)=aa2(:,1)-.5;
% 				aa2(:,2)=aa2(:,2)+.5;
% 				aa2(:,3)=aa2(:,3)+.5;
% 				aa1(:,1)=aa1(:,1)-.5;
% 				aa1(:,2)=aa1(:,2)+.5;
% 				aa1(:,3)=aa1(:,3)+.5;
% 				aa3(:,1)=aa3(:,1)-.5;
% 				aa3(:,2)=aa3(:,2)+.5;
% 				aa3(:,3)=aa3(:,3)+.5;
% 				aa(:,1)=aa(:,1)-.5;
% 				aa(:,2)=aa(:,2)+.5;
% 				aa(:,3)=aa(:,3)+.5;
%
% 				aa
% 				aa1
% 				aa2
% 				aa3
%
% 				get(pa1,'faces')
% 				for kk=1:2
% 					set(pa1,'vertices',aa2)
% 					set(pa2,'vertices',aa3)
% 					pause(.1)
% 					set(pa1,'vertices',aa)
% 					set(pa2,'vertices',aa1)
% 					pause(.1)
% 				end
%
%
% 			end
%% Main Loop
			% while 'Stop' pushbutton has not yet been pressed
			while strcmp(get(pb,'string'),'Stop')

				% increment counter
				countz=countz+1;

				% choose speed for opening the door
				dspeed=.1;

				% open door
				opend(dspeed)

				% move balls inside
				for j=1:num

					% move each ball from its location (toin) to its heading
					% point (in)
					hs(j)=movb(rz(j),toin{j},in{j},rand*10+15,j,hs(j)); %#ok
				end

				% choose speed for closing the door
				dspeed=.1;

				% close door
				closed(dspeed)

				% choose speed of going up
				upspeed=.035;

				% update debugging text
				set(tee,'string',{['Number of Stops: ',num2str(countz)];...
					sprintf('Current Stop: Floor %d',tofloor+1);...
					['Number of Dudes: ',num2str(num)]})
% 				movp
				% have elevator go up from (cf) to (tofloor) with speed
				% (upspeed) and ball handles (hs)
				cf=goup(upspeed,tofloor,cf,hs);

				% choose speed of door opening again
				dspeed=.075;

				% open door
				opend(dspeed)

				% next we'll want to move each ball outside the elevator
				% also, we want to get their handles

				% preallocation
				todel=zeros(1,num*2);

				% for each ball go once around the loop
				for kmpf=1:num

					% move ball outside its location to (out) and draw virtual
					% ground (patch) and get the patche's handle
					[hs2,pn]=movb(rz(num),dumnop,out{kmpf},20,kmpf,hs(kmpf));

					% store handles for each ball and ground here
					todel(kmpf*2-1:kmpf*2)=[hs2,pn];
				end

				% now it's time to make the balls and patches gradually
				% disappear

				% initial transperancy is (0.5)
				for k=.5:-.075:0

					% gradually lower the transperancy of everything (every
					% handle) in (todel)
					set(todel,'facealpha',k,'edgealpha',k)
					pause(.05)

				end

				% finally after everything is completely transparent, delete it
				delete(todel)

				% choose speed for closing the door
				speedc=.075;

				% close doors
				closed(speedc)

				% choose a new number of dudes from (1) to (6)
				num=floor(6*rand)+1;

				% choose a new floor number from (2) to number of floors
				tofloor=floor(rand*(flrz))+1;

				% update debugger text
				set(tee,'string',{['Number of Stops: ',num2str(countz)];...
					sprintf('Current Stop: Floor %d',tofloor+1);...
					['Number of Dudes: ',num2str(num)]})

				% create the balls (people)
				createballs(num)

				% choose speed to returning the elevator to the ground
				speedret=.035;

				% return elevator to the ground
				cf=retn(speedret,cf);

			end

%% Create Balls
			function createballs(num)

				% choose random radii for each ball (fat, tall, young, etc...)
				% from (0.02) to (0.05)
				rz=rand(num,1).*.03+.02;

				% next we create the balls by moving them from (toin) to (toin)
				hs=zeros(num,1);
				for n2=1:num
					hs(n2)=movb(rz(n2),toin{n2},toin{n2},10,n2);
				end
			end

		end

%% Raising the Elevator
		function cf=goup(inc_speed,floor,cf,hs)

			% counter for use later
			cc=1;
			while true

				% condition for stopping the elevator: next elevtor position
				% (indicated by current position + speed) is higher than
				% required floor, in which case, set the position of the
				% elevator as the next floor minimum coordinate
				if min(c(:,3))+inc_speed>floor*.2

					% min (z) of elevator is same as floor height
					c(1:4,3)=repmat(floor*.2,4,1);

					% max (z) of elevator is same as floor ceiling (next floor)
					c(5:8,3)=repmat(floor*.2+.2,4,1);

					% move elevator to this position
					set(elv,'vertices',c)

					% do the same thing for the elevator doors
					c1(1:4,3)=repmat(floor*.2,4,1);
					c1(5:8,3)=repmat(floor*.2+.2,4,1);
					c2(1:4,3)=repmat(floor*.2,4,1);
					c2(5:8,3)=repmat(floor*.2+.2,4,1);
					set(door1,'vertices',c1)
					set(door2,'vertices',c2)

					% also move the curtains in the same way
					af1=get(fp1,'vertices');
					af1(5:8,3)=repmat(floor*.2,4,1);
					af2=get(fp2,'vertices');
					af2(1:4,3)=repmat(.2+floor*.2,4,1);
					set(fp1,'vertices',af1)
					set(fp2,'vertices',af2)

					% and move the balls as well
					for k=1:length(hs)
						ppv=get(hs(k),'zdata');
						set(hs(k),'zdata',ppv+floor*.2-min(min(ppv)))
					end

					% update plot
					drawnow()

					% leave loop
					break
				end

				% increment counter
				cc=cc+1;

				% increase height of elevator (z) by its speed
				c(:,3)=c(:,3) + inc_speed;
				set(elv,'vertices',c)

				% same with doorsw
				c1(:,3)=c1(:,3) + inc_speed;
				c2(:,3)=c2(:,3) + inc_speed;
				set(door1,'vertices',c1)
				set(door2,'vertices',c2)

				% change the height of curtains in the same way
				af1=get(fp1,'vertices');
				af1(5:8,3)=repmat(0+cc*inc_speed+cf*.2,4,1);
				af2=get(fp2,'vertices');
				af2(1:4,3)=repmat(0.2+cc*inc_speed+cf*.2,4,1);
				set(fp1,'vertices',af1)
				set(fp2,'vertices',af2)

				% increase the height of the balls as well
				for k=1:length(hs)
					set(hs(k),'zdata',get(hs(k),'zdata')+inc_speed)
				end

				% update plot
				drawnow()

			end

			% update floor number (output)
			cf=floor;
		end

%% Returning the Elevator
		function cf=retn(inc_speed,cf)

			% counter
			cc=1;

			% destination floor
			floor=0;

			% the following is the same as raising the elevator, with the
			% replacement of a few addition with subtractions
			while true

				if min(c(:,3))-inc_speed<floor*.2

					c(1:4,3)=repmat(floor*.2,4,1);
					c(5:8,3)=repmat(floor*.2+.2,4,1);
					set(elv,'vertices',c)

					c1(1:4,3)=repmat(floor*.2,4,1);
					c1(5:8,3)=repmat(floor*.2+.2,4,1);
					c2(1:4,3)=repmat(floor*.2,4,1);
					c2(5:8,3)=repmat(floor*.2+.2,4,1);
					set(door1,'vertices',c1)
					set(door2,'vertices',c2)

					af1=get(fp1,'vertices');
					af1(5:8,3)=repmat(floor*.2,4,1);
					af2=get(fp2,'vertices');
					af2(1:4,3)=repmat(.2+floor*.2,4,1);
					set(fp1,'vertices',af1)
					set(fp2,'vertices',af2)
					drawnow()
					break
				end
				cc=cc+1;
				c(:,3)=c(:,3) - inc_speed;
				set(elv,'vertices',c)

				c1(:,3)=c1(:,3) - inc_speed;
				c2(:,3)=c2(:,3) - inc_speed;
				set(door1,'vertices',c1)
				set(door2,'vertices',c2)

				af1=get(fp1,'vertices');
				af1(5:8,3)=repmat(0-cc*inc_speed+cf*.2,4,1);
				af2=get(fp2,'vertices');
				af2(1:4,3)=repmat(0.2-cc*inc_speed+cf*.2,4,1);
				set(fp1,'vertices',af1)
				set(fp2,'vertices',af2)
				drawnow()

			end
			cf=floor;
		end

%% Opening Elevator Doors
		function opend(dspeed)

			% get location information for both doors
			var1=get(door1,'vertices');

			% for use in the while loop that lies ahead
			y1=var1(:,2);
			var2=get(door2,'vertices');

			% loop until next location of first door is lower than its fully
			% opened location (y) = (0), in which case get out of the loop and
			% manually set both door locations
			while max(y1)-dspeed>0;

				% move both doors relative to the speed, in opposite directions
				var1([3,4,7,8],2)=var1([3,4,7,8],2)-dspeed;
				var2([1,2,5,6],2)=var2([1,2,5,6],2)+dspeed;
				set(door1,'vertices',var1)
				set(door2,'vertices',var2)

				% for the loop condition
				y1=var1(:,2);

				% update plot
				drawnow()
			end

			% set both doors to fully open status
			var1(:,2)=zeros(8,1);
			var2(:,2)=ones(8,1);
			set(door1,'vertices',var1)
			set(door2,'vertices',var2)

			% update plot
			drawnow()

		end

%% Closing Elevator Doors
		function closed(dspeed)

			% very similar to opening the elevator doors, with subtraction
			% operation replacing the addition, as well as having the fully
			% closed conditions being one door having a maximum (y) of (0.5)
			% while the other has a minimum (y) of (0.5).
			var1=get(door1,'vertices');
			y1=var1(:,2);
			var2=get(door2,'vertices');
			while max(y1)+dspeed<0.5;
				var1([3,4,7,8],2)=var1([3,4,7,8],2)+dspeed;
				var2([1,2,5,6],2)=var2([1,2,5,6],2)-dspeed;
				y1=var1(:,2);
				set(door1,'vertices',var1)
				set(door2,'vertices',var2)
				drawnow()
			end
			var1([3,4,7,8],2)=repmat(.5,4,1);
			var2([1,2,5,6],2)=repmat(.5,4,1);
			set(door1,'vertices',var1)
			set(door2,'vertices',var2)
			drawnow()

		end

%% Moving the Balls
		function [h,pn]=movb(r,A,B,V,nm,varargin)

			% r: Radius of ball
			%
			% A: Starting position of centre of ball
			%
			% B: Ending position of centre of ball
			%
			% V: Speed of rotation
			%
			% nm: Number denoting the colour
			%
			% varargin: Could contain handle of previously created ball

			% so previous plots would not disappear
			hold on

			% if no previous ball is created (i.e. we want to create instead
			% of move)
			if ~numel(varargin)
				% create unit ball
				[a,b,cC2]=sphere(25);

				% adjust size of ball by multiplying by the radius
				% also, move ball to starting position by adding
				% and put ball on the ground (0z) by adding r to z
				h=surf(a.*r+A(1),b.*r+A(2),cC2.*r+r);

				% make colors cooler
				set(h,'facecolor','interp','edgecolor','interp')

				% get ball colour data
				s2=get(h,'cdata');

				% take the ball top and change its colour to something
				% now each ball has a cute little colourful hat!
				s2(end-3:end,:)=repmat(.15*nm,4,size(s2,2));
				set(h,'cdata',s2)

				% adjust axis for better viewing
 				axis equal

			end

			% for future reference
			v=axis;

			% for while loop initial status
			ctr=[1e9 1e9];

			% move ball
			if numel(varargin)

				% get handle of ball
				h=varargin{1};

				% create a patch that spans the axis edges (acts as ground)
				% (z) is flat, and depends on the ball's min (z)
				pft=min(min(get(h,'zdata')));
				aaa=[v(1) v(3) pft;
					v(2) v(3) pft;
					v(2) v(4) pft;
					v(1) v(4) pft;
					v(1) v(3) pft;
					v(2) v(3) pft;
					v(2) v(4) pft;
					v(1) v(4) pft];
				b=[1 2 6 5;2 3 7 6;3 4 8 7;4 1 5 8;1 2 3 4;5 6 7 8];

				% plot ground!
				pn=patch('vertices',aaa,'faces',b,'edgecolor',[1 1 1],'facecolor',[.3 .3 .3],...
					'facevertexalphadata',0.5,'facealpha','flat');
			end

			% get min (z) of ball (i.e. get the current floor)
			llpp=get(h,'zdata');
			cf=min(min(llpp));

			% while centre of the ball is at least .1 away from
			% the destination points, keep moving it. notice here that the
			% condition for stopping the ball movement doesn't depend on the
			% next location, but rather on the current location. this leads to
			% the balls to end up in slightly different locations that their
			% destinations, due to the randomization of the ball radius coupled
			% with their relatively high speeds
			while mean(abs(ctr-B))>1e-1

				% get centre of ball
				ctr=[(max(max(get(h,'xdata')))+min(min(get(h,'xdata'))))/2,...
					(max(max(get(h,'ydata')))+min(min(get(h,'ydata'))))/2];

				% vector from current point to destination
				rot=B-ctr;

				% get orthogonal vector (which the ball will spin around)
				yu=rot(2);
				rot(2)=rot(1);
				rot(1)=-yu;

				% rotate around ball about said vector
				% origin is centre of ball
				rotate(h,[rot,0],V,[ctr,r+cf])

				% move ball according to its speed
				% the sign commands are for the direction of movement
				% the sphere moves in X and Y the same distance as the one it has rolled
				% in other words it moves V/360
				% but it doesn't move the entirety of this roll since it is divided between
				% X and Y rolling, we find out how much is shared between X and Y using atan
				set(h,'xdata',get(h,'xdata')...
					-(sign(rot(1))-~sign(rot(1)))...
					*V/360*...
					atan(rot(2)/-rot(1)))
				set(h,'ydata',get(h,'ydata')+(sign(rot(2))+sign(rot(2)))*V/360*atan(rot(1)/-rot(2)))

				% so that axis wouldn't change while animating
				axis(v)

				% update plot
				drawnow()
			end
		end
	end
% EOF
end


function [U,output] = cpd_rnd(size_tens,R,options)
%CPD_RND Pseudorandom initialization for CPD.
%   U = cpd_rnd(size_tens,R) generates pseudorandom factor matrices U{1},
%   ..., U{N} of dimensions size_tens(n)-by-R that can be used to
%   initialize algorithms that compute the CPD of an N-th order tensor.
%
%   cpd_rnd(T,R) is shorthand for cpd_rnd(size(T),R) if T is real. If T is
%   complex, then U{n} will be generated as complex matrices by default
%   (cf. options).
%
%   cpd_rnd(size_tens,R,options) and cpd_rnd(T,R,options) may be used to
%   set the following options:
%
%      options.Real =        - The type of random number generator used to
%      [{@randn}|@rand|0]      generate the real part of each factor
%                              matrix. If 0, there is no real part.
%      options.Imag =        - The type of random number generator used to
%      [@randn|@rand|0|...     generate the imaginary part of each factor
%       {'auto'}]              matrix. If 0, there is no imaginary part.
%                              On 'auto', options.Imag is 0 unless the
%                              first argument is a complex tensor T, in
%                              which case it is equal to options.Real.
%      options.Orth =        - If true, the generated factor matrices are
%      [true|false|{'auto'}]   orthogonalized using a QR factorization.
%                              On 'auto', options.Orth is false if the
%                              first argument is a vector size_tens, and
%                              true if the first argument is a tensor T.
%
%   See also btd_rnd, lmlra_rnd, cpdgen.

%   Authors: Laurent Sorber (Laurent.Sorber@cs.kuleuven.be)
%            Marc Van Barel (Marc.VanBarel@cs.kuleuven.be)
%            Lieven De Lathauwer (Lieven.DeLathauwer@kuleuven-kulak.be)

% Process input.
isSizeVector = isnumeric(size_tens) && isvector(size_tens);
if ~isSizeVector
    T = size_tens;
    if isstruct(T), size_tens = T.size;
    else size_tens = size(T); end
end
N = length(size_tens);

% Check the options structure.
isfunc = @(f)isa(f,'function_handle');
if nargin < 3, options = struct; end
if ~isfield(options,'Real'), options.Real = @randn; end
if ~isfunc(options.Real), options.Real = @zeros; end
if ~isfield(options,'Imag'), options.Imag = 'auto'; end
if ischar(options.Imag) && strcmpi(options.Imag,'auto')
    if ~isSizeVector && ((isstruct(T) && ~isreal(T.val)) || ...
            (isnumeric(T) && ~isreal(T)))
        options.Imag = options.Real;
    else
        options.Imag = 0;
    end
end
if ~isfield(options,'Orth'), options.Orth = 'auto'; end
if ischar(options.Orth) && strcmpi(options.Orth,'auto')
	options.Orth = ~isSizeVector;
end

% Generate factor matrices.
U = arrayfun(@(n)options.Real(size_tens(n),R),1:N,'UniformOutput',0);
if isfunc(options.Imag)
    Ui = arrayfun(@(n)options.Imag(size_tens(n),R),1:N,'UniformOutput',0);
    U = cellfun(@(ur,ui)ur+ui*1i,U,Ui,'UniformOutput',0);
end
for n = 1:N*options.Orth
    if size(U{n},1) >= size(U{n},2), [U{n},~] = qr(U{n},0);
    else [Q,~] = qr(U{n}.',0); U{n} = Q.'; end
end
output = struct;


%WARPPERSPECTIVE  Applies a perspective transformation to an image
%
%     dst = cv.warpPerspective(src, M)
%     dst = cv.warpPerspective(src, M, 'OptionName',optionValue, ...)
%
% ## Input
% * __src__ Input image.
% * __M__ 3x3 transformation matrix, floating-point.
%
% ## Output
% * __dst__ Output image that has the size `DSize` (with
%   `size(dst,3) == size(src,3)`) and the same type as `src`.
%
% ## Options
% * __DSize__ Size of the output image `[w,h]`. Default `[0,0]` means using
%   the same size as the input `[size(src,2) size(src,1)]`.
% * __Interpolation__ interpolation method, default 'Linear'. One of:
%   * __Nearest__ nearest neighbor interpolation
%   * __Linear__ bilinear interpolation
%   * __Cubic__ bicubic interpolation
%   * __Lanczos4__ Lanczos interpolation over 8x8 neighborhood
% * __WarpInverse__ Logical flag to apply inverse perspective transform,
%   meaning that `M` is the inverse transformation (`dst -> src`).
%   default false
% * __BorderType__ Pixel extrapolation method. When 'Transparent', it means
%   that the pixels in the destination image corresponding to the "outliers"
%   in the source image are not modified by the function. default 'Constant'
%   * __Constant__ `iiiiii|abcdefgh|iiiiiii` with some specified `i`
%   * __Replicate__ `aaaaaa|abcdefgh|hhhhhhh`
%   * __Reflect__ `fedcba|abcdefgh|hgfedcb`
%   * __Reflect101__ `gfedcb|abcdefgh|gfedcba`
%   * __Wrap__ `cdefgh|abcdefgh|abcdefg`
%   * __Transparent__ `uvwxyz|abcdefgh|ijklmno`
%   * __Default__ same as 'Reflect101'
% * __BorderValue__ Value used in case of a constant border. default 0
% * __Dst__ Optional initial image for the output. If not set, it is
%   automatically created by the function. Note that it must match the
%   expected size `DSize` and the type of `src`, otherwise it is ignored and
%   recreated by the function. This option is only useful when
%   `BorderType=Transparent`, in which case the transformed image is drawn
%   onto the existing `Dst` without extrapolating pixels. Not set by default.
%
% The function cv.warpPerspective transforms the source image using the
% specified matrix:
%
%     dst(x,y) = src((M_11*x + M_12*y + M_13) / (M_31*x + M_32*y + M_33),
%                    (M_21*x + M_22*y + M_23) / (M_31*x + M_32*y + M_33))
%
% when the `WarpInverse` option is true. Otherwise, the transformation is first
% inverted with cv.invert and then put in the formula above instead of `M`.
%
% See also: cv.warpAffine, cv.remap, cv.resize, cv.getRectSubPix,
%  cv.perspectiveTransform, imtransform, imwarp
%


%MDL_OFFSET3 A minimalistic 3DOF robot arm with shoulder offset
%
% MDL_OFFSET3 is a script that creates the workspace variable off3 which
% describes the kinematic characteristics of a simple arm manipulator with
% a shoulder offset, using standard DH conventions.
%
% Somewhat like a Puma arm without the wrist.
%
% Also define the workspace vectors:
%   qz         zero joint angle configuration
%
% Notes::
% - Unlike most other mdl_xxx scripts this one is actually a function that
%   behaves like a script and writes to the global workspace.
%
% See also SerialLink, mdl_offset6, mdl_simple6, mdl_puma560.

% MODEL: generic, 3DOF, standard_DH

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

function r = mdl_offset3()

    % robot length values (metres)
    L1 = 1;
    L2 = 1;
    O1 = 0;
    O2 = 0.2;
    O3 = 0;

    % and build a serial link manipulator

    robot = SerialLink([
        Revolute('alpha', -pi/2, 'a', O1, 'd', 0)
        Revolute('alpha', 0,     'a', L1, 'd', O2)
        Revolute('alpha', pi/2,  'a', L2, 'd', O3)
        ], ...
        'name', 'Offset3');

    % place the variables into the global workspace
    if nargout == 1
        r = robot;
    elseif nargout == 0
        assignin('base', 'off3', robot);
        assignin('base', 'qz', [0 0 0 ]); % zero angles, arm up
    end
end


%This Matlab script can be used to reproduce Figure 7.2 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.
%
%Note: This script require additional software packages to be used, which
%need to be downloaded and installed separately. These packages are
%developed independently and are delivered with separate licenses.
%
%The downlink power allocation is optimized using CVX from CVX Research,
%Inc. (http://cvxr.com/cvx/). This script has been tested with CVX 2.1,
%using the solver Mosek, version 7.1.0.12. We discourage the use of the
%solvers SDPT3 and SeDuMi since these crashed during the test.

%Empty workspace and close figures
close all;
clear;

%Number of BSs
L = 16;

%Number of UEs per BS
K = 10;

%Number of BS antennas
M = 100;

%Define the pilot reuse factor
f = 2;

%Select the number of setups with random UE locations
nbrOfSetups = 50;

%Select the number of channel realizations per setup
nbrOfRealizations = 500;

%% Propagation parameters

%Communication bandwidth
B = 20e6;

%Total uplink transmit power per UE (mW)
p = 100;

%Total downlink transmit power per UE (mW)
rho = 100;

%Maximum downlink transmit power per BS (mW)
Pmax = K*rho;

%Compute downlink power per UE in case of equal power allocation
rhoEqual = (Pmax/K)*ones(K,L);

%Define noise figure at BS (in dB)
noiseFigure = 7;

%Compute noise power
noiseVariancedBm = -174 + 10*log10(B) + noiseFigure;

%Select length of coherence block
tau_c = 200;

%Use the approximation of the Gaussian local scattering model
accuracy = 2;

%Angular standard deviation in the local scattering model (in degrees)
ASDdeg = 10;

%Prepare to save simulation results
SE_MR_equal = zeros(K,L,nbrOfSetups);
SE_RZF_equal = zeros(K,L,nbrOfSetups);
SE_MMMSE_equal = zeros(K,L,nbrOfSetups);

SE_MR_maxmin = zeros(K,L,nbrOfSetups);
SE_RZF_maxmin = zeros(K,L,nbrOfSetups);
SE_MMMSE_maxmin = zeros(K,L,nbrOfSetups);

SE_MR_maxprod = zeros(K,L,nbrOfSetups);
SE_RZF_maxprod = zeros(K,L,nbrOfSetups);
SE_MMMSE_maxprod = zeros(K,L,nbrOfSetups);

%% Go through all setups
for n = 1:nbrOfSetups

    %Output simulation progress
    disp([num2str(n) ' setups out of ' num2str(nbrOfSetups)]);

    %Compute channel statistics for one setup
    [R,channelGaindB] = functionExampleSetup(L,K,M,accuracy,ASDdeg);

    %Compute the normalized average channel gain, where the normalization
    %is based on the noise power
    channelGainOverNoise = channelGaindB - noiseVariancedBm;

    %Generate channel realizations with estimates and estimation
    %error correlation matrices
    [Hhat,C,tau_p,~,H] = functionChannelEstimates(R,channelGainOverNoise,nbrOfRealizations,M,K,L,p,f);

    %Compute the signal and interference terms of the DL SEs using the
    %hardening bound in Theorem 4.6
    [signal_MR,interf_MR,signal_RZF,interf_RZF,signal_MMMSE,interf_MMMSE,prelogFactor] = functionComputeSINR_DL(H,Hhat,C,tau_c,tau_p,nbrOfRealizations,M,K,L,p);

    %Delete large matrices
    clear Hhat C H R;

    %Compute the SEs with equal power allocation
    SE_MR_equal(:,:,n) = functionComputeSE_DL_poweralloc(rhoEqual,signal_MR,interf_MR,prelogFactor);
    SE_RZF_equal(:,:,n) = functionComputeSE_DL_poweralloc(rhoEqual,signal_RZF,interf_RZF,prelogFactor);
    SE_MMMSE_equal(:,:,n) = functionComputeSE_DL_poweralloc(rhoEqual,signal_MMMSE,interf_MMMSE,prelogFactor);

    %Compute the SEs with max-min fairness power allocation
    disp('Solve max-min fairness problem'); %Output simulation progress
    SE_MR_maxmin(:,:,n) = functionPowerOptimization_maxmin(signal_MR,interf_MR,Pmax,prelogFactor);
    SE_RZF_maxmin(:,:,n) = functionPowerOptimization_maxmin(signal_RZF,interf_RZF,Pmax,prelogFactor);
    SE_MMMSE_maxmin(:,:,n) = functionPowerOptimization_maxmin(signal_MMMSE,interf_MMMSE,Pmax,prelogFactor);

    %Compute the SEs with max-min fairness power allocation
    disp('Solve max product SINR problem'); %Output simulation progress
    SE_MR_maxprod(:,:,n) = functionPowerOptimization_prodSINR(signal_MR,interf_MR,Pmax,prelogFactor);
    SE_RZF_maxprod(:,:,n) = functionPowerOptimization_prodSINR(signal_RZF,interf_RZF,Pmax,prelogFactor);
    SE_MMMSE_maxprod(:,:,n) = functionPowerOptimization_prodSINR(signal_MMMSE,interf_MMMSE,Pmax,prelogFactor);

end

%% Plot the simulation results

figure;
hold on; box on;

plot(sort(SE_MR_maxmin(:)),linspace(0,1,K*L*nbrOfSetups),'k--','LineWidth',1);
plot(sort(SE_MR_equal(:)),linspace(0,1,K*L*nbrOfSetups),'k-','LineWidth',1);
plot(sort(SE_MR_maxprod(:)),linspace(0,1,K*L*nbrOfSetups),'k-.','LineWidth',1);

plot(sort(SE_RZF_equal(:)),linspace(0,1,K*L*nbrOfSetups),'b-','LineWidth',1);
plot(sort(SE_MMMSE_equal(:)),linspace(0,1,K*L*nbrOfSetups),'r','LineWidth',1);

plot(sort(SE_RZF_maxprod(:)),linspace(0,1,K*L*nbrOfSetups),'b-.','LineWidth',1);
plot(sort(SE_MMMSE_maxprod(:)),linspace(0,1,K*L*nbrOfSetups),'r-.','LineWidth',1);

plot(sort(SE_RZF_maxmin(:)),linspace(0,1,K*L*nbrOfSetups),'b--','LineWidth',1);
plot(sort(SE_MMMSE_maxmin(:)),linspace(0,1,K*L*nbrOfSetups),'r--','LineWidth',1);

legend('Max-min fairness','Equal power','Max product SINR','Location','SouthEast');

xlabel('SE per UE [bit/s/Hz]');
ylabel('CDF');


% ========================================================================
% Fast Multi-Scale Structural Patch Decomposition for Multi-Exposure Image Fusion, TIP,2020
% algorithm Version 1.0
% Copyright(c) 2020, Hui Li, Kede Ma, Yongwei Yong and Lei Zhang
% All Rights Reserved.
% ----------------------------------------------------------------------
% Permission to use, copy, or modify this software and its documentation
% for educational and research purposes only and without fee is hereby
% granted, provided that this copyright notice and the original authors'
% names appear on all copies and supporting documentation. This program
% shall not be used, rewritten, or adapted as the basis of a commercial
% software or hardware product without first obtaining permission of the
% authors. The authors make no representations about the suitability of
% this software for any purpose. It is provided "as is" without express
% or implied warranty.
%----------------------------------------------------------------------
% This is a dynamic scene implementation of "Fast Multi-Scale Structural Patch Decomposition for Multi-Exposure Image Fusion"
% Please refer to the following paper:
% H. Li et al., "Fast Multi-Scale Structural Patch Decomposition for Multi-Exposure Image Fusion, 2020" In press
% IEEE Transactions on Image Processing
% Please kindly report any suggestions or corrections to xiaohui102788@126.com
%----------------------------------------------------------------------

clear ;
close all;
addpath(genpath(pwd));

    imgSeqColor= loadImg('ArchSequence'); % [0,1]
    imgSeqColor = downSample(imgSeqColor, 1024);

tic
%% motion detection
r=10;
    imgSeqColor = detection_color(imgSeqColor,r);

%% fusion as static
r1=4;
[ D1,i_mean1,aa1,N1] = scale_fine(imgSeqColor,r1);

%% the intermediate  scale
[w,h,~,~]=size(imgSeqColor);
nlev = floor(log(min(w,h)) / log(2))-5;

D2 = cell(nlev,1);
aa2= cell(nlev,1);
N2= cell(nlev,1);

r2=4;
for ii=1:nlev
    [ D2{ii},i_mean2,aa2{ii},N2{ii}] = scale_interm(i_mean1,r2);
    i_mean1=i_mean2;
end

%% the coarsest  scale
r3=4;
[fI3,i_mean3,aa3,N3] = scale_coarse(i_mean2,r3);

%% reconstruct
%% Intermediate layers
for ii=nlev:-1:1
    temp=aa2{ii};
    fI=zeros(size(temp));
    fI(1:2:size(temp,1),1:2:size(temp,2))=fI3;
    B2=boxfilter(fI, r2)./ N2{ii}+D2{ii};

    fI3=B2;
end
%% finest layers
fI=zeros(size(aa1));
fI(1:2:size(aa1,1),1:2:size(aa1,2))=B2;
B1=boxfilter(fI, r1)./ N1;
C_out=repmat(B1,[1 1 3])+D1;
toc

figure,imshow(C_out)


function coeffS = setGaussOrder(coeffS,derivativeOrder)
% function coeffS = setOrder(coeffS,derivativeOrder)
%
% APA, 6/13/2018

A1(1) = 1.3530;
B1(1) = 1.8151;
coeffS.W1    = 0.6681;
coeffS.L1    = -1.3932;
A2(1) = -0.3531;
B2(1) = 0.0902;
coeffS.W2    = 2.0787;
coeffS.L2    = -1.3732;

A1(2) = -0.6724;
B1(2) = -3.4327;
A2(2) = 0.6724;
B2(2) = 0.6100;

A1(3) = -1.3563;
B1(3) = 5.2318;
A2(3) = 0.3446;
B2(3) = -2.2355;

switch derivativeOrder

    case 'zero'
        % Zero'th order (Gaussian)
        coeffS.across_scale_normalization = 1.0;

        coeffS = computeDcoeffs(coeffS);

        coeffS.A1 = A1(1);
        coeffS.B1 = B1(1);
        coeffS.A2 = A2(1);
        coeffS.B2 = B2(1);
        coeffS = computeNcoeffs(coeffS);
        coeffS.alpha0 = 2 * coeffS.SN / coeffS.SD - coeffS.N0;
        coeffS.N0 = coeffS.N0 * coeffS.across_scale_normalization / coeffS.alpha0;
        coeffS.N1 = coeffS.N1 * coeffS.across_scale_normalization / coeffS.alpha0;
        coeffS.N2 = coeffS.N2 * coeffS.across_scale_normalization / coeffS.alpha0;
        coeffS.N3 = coeffS.N3 * coeffS.across_scale_normalization / coeffS.alpha0;
        symmetric = true;
        coeffS = computeMcoeffs(coeffS,symmetric);

    case 'second'

        % Second order (Laplacian Of Gaussian)
        %coeffS.across_scale_normalization = coeffS.sigma^2;
        coeffS.across_scale_normalization = 1.0;

        coeffS = computeDcoeffs(coeffS);

        coeffS.A1 = A1(1);
        coeffS.B1 = B1(1);
        coeffS.A2 = A2(1);
        coeffS.B2 = B2(1);
        coeffS.N0 = 0;
        coeffS.N1 = 0;
        coeffS.N2 = 0;
        coeffS.N3 = 0;
        coeffS.SN = 0;
        coeffS.DN = 0;
        coeffS.EN = 0;
        coeffS = computeNcoeffs(coeffS);
        coeffS.N0_0 = coeffS.N0;
        coeffS.N1_0 = coeffS.N1;
        coeffS.N2_0 = coeffS.N2;
        coeffS.N3_0 = coeffS.N3;
        coeffS.SN0 = coeffS.SN;
        coeffS.DN0 = coeffS.DN;
        coeffS.EN0 = coeffS.EN;

        coeffS.A1 = A1(3);
        coeffS.B1 = B1(3);
        coeffS.A2 = A2(3);
        coeffS.B2 = B2(3);
        coeffS.N0 = 0;
        coeffS.N1 = 0;
        coeffS.N2 = 0;
        coeffS.N3 = 0;
        coeffS.SN = 0;
        coeffS.DN = 0;
        coeffS.EN = 0;
        coeffS = computeNcoeffs(coeffS);
        coeffS.N0_2 = coeffS.N0;
        coeffS.N1_2 = coeffS.N1;
        coeffS.N2_2 = coeffS.N2;
        coeffS.N3_2 = coeffS.N3;
        coeffS.SN2 = coeffS.SN;
        coeffS.DN2 = coeffS.DN;
        coeffS.EN2 = coeffS.EN;

        coeffS.beta = -( 2 * coeffS.SN2 - coeffS.SD * coeffS.N0_2 ) / ( 2 * coeffS.SN0 - coeffS.SD * coeffS.N0_0 );
        coeffS.N0 = coeffS.N0_2 + coeffS.beta * coeffS.N0_0;
        coeffS.N1 = coeffS.N1_2 + coeffS.beta * coeffS.N1_0;
        coeffS.N2 = coeffS.N2_2 + coeffS.beta * coeffS.N2_0;
        coeffS.N3 = coeffS.N3_2 + coeffS.beta * coeffS.N3_0;
        coeffS.SN = coeffS.SN2 + coeffS.beta * coeffS.SN0;
        coeffS.DN = coeffS.DN2 + coeffS.beta * coeffS.DN0;
        coeffS.EN = coeffS.EN2 + coeffS.beta * coeffS.EN0;

        coeffS.alpha2  = coeffS.EN * coeffS.SD * coeffS.SD - ...
            coeffS.ED * coeffS.SN * coeffS.SD - ...
            2 * coeffS.DN * coeffS.DD * coeffS.SD + ...
            2 * coeffS.DD * coeffS.DD * coeffS.SN;

        coeffS.alpha2 = coeffS.alpha2 / (coeffS.SD * coeffS.SD * coeffS.SD);

        coeffS.N0 = coeffS.N0 * coeffS.across_scale_normalization / coeffS.alpha2;
        coeffS.N1 = coeffS.N1 * coeffS.across_scale_normalization / coeffS.alpha2;
        coeffS.N2 = coeffS.N2 * coeffS.across_scale_normalization / coeffS.alpha2;
        coeffS.N3 = coeffS.N3 * coeffS.across_scale_normalization / coeffS.alpha2;

        symmetric = true;
        coeffS = computeMcoeffs(coeffS,symmetric);

end


%%*******************************************************************
%% detect_ublk: search for implied free variables in linear
%%              block.
%% [blk2,At2,C2,ublkinfo] = detect_ublk(blk,At,C);
%%
%% i1,i2: indices corresponding to splitting of unrestricted varaibles
%% i3   : remaining indices in the linear block
%%
%% SDPT3: version 3.1
%% Copyright (c) 1997 by
%% K.C. Toh, M.J. Todd, R.H. Tutuncu
%% Last Modified: 16 Sep 2004
%%*******************************************************************

function [blk2,At2,C2,ublkinfo,parbarrier2,X2,Z2] = ...
    detect_ublk(blk,At,C,parbarrier,X,Z,printlevel)

if (nargin < 7); printlevel = 1; end

blk2 = blk; At2 = At; C2 = C;
if (nargin >= 6)
    parbarrier2 = parbarrier;
    X2 = X; Z2 = Z;
else
    X2 = []; Z2 = [];
end
numblk = size(blk,1);
ublkinfo = cell(size(blk,1),3);
tol = 1e-14;
%%
numblknew = numblk;
%%
for p = 1:numblk
    pblk = blk(p,:);
    m = size(At{p},2);
    if strcmp(pblk{1},'l')
        r = randmat(1,m,0,'n');
        % stime = cputime;
        Ap = At{p}'; Cp = C{p};
        ApTr = (r*Ap)';
        [sApTr,perm] = sort(abs(ApTr));
        idx0 = find(abs(diff(sApTr)) < tol);
        if ~isempty(idx0)
            n = pblk{2};
            i1 = perm(idx0); i2 = perm(idx0+1);
            Api1 = Ap(:,i1);
            Api2 = Ap(:,i2);
            Cpi1 = Cp(i1)';
            Cpi2 = Cp(i2)';
            idxzr = abs(Cpi1+Cpi2) < tol & sum(abs(Api1+Api2),1) < tol;
            if any(idxzr)
                i1 = i1(idxzr');
                i2 = i2(idxzr');
                blk2{p,1} = 'u';
                blk2{p,2} = length(i1);
                At2{p} = Ap(:,i1)';
                C2{p}  = Cp(i1);
                if (printlevel)
                    fprintf('\n %1.0d linear variables from unrestricted variable.\n',...
                        2*length(i1));
                end
                if (nargin >= 6)
                    parbarrier2{p} = parbarrier{p}(i1);
                    X2{p} = X{p}(i1)-X{p}(i2);
                    Z2{p} = zeros(length(i1),1);
                end
                i3 = setdiff(1:n,union(i1,i2));
                if ~isempty(i3)
                    numblknew = numblknew + 1;
                    blk2{numblknew,1} = 'l';
                    blk2{numblknew,2} = length(i3);
                    At2{numblknew,1}  = Ap(:,i3)';
                    C2{numblknew,1}   = Cp(i3);
                    if (nargin >= 6)
                        parbarrier2{numblknew,1} = parbarrier{p}(i3);
                        X2{numblknew,1} = X{p}(i3); Z2{numblknew,1} = Z{p}(i3);
                    end
                end
                ublkinfo{p,1} = i1; ublkinfo{p,2} = i2; ublkinfo{p,3} = i3;
            end
        end
    end
end
%%*******************************************************************


function x = cs_dmsol (A,b)
%CS_DMSOL x=A\b using the coarse Dulmage-Mendelsohn decomposition.
%   x = cs_dmsol(A,b) computes x=A\b where A may be rectangular and/or
%   structurally rank deficient, and b is a full vector.
%
%   Example:
%       Prob = UFget ('HB/arc130') ; A = Prob.A ; b = rand (size (A,1),1) ;
%       x = cs_dmsol (A,b) ; norm (A*x-b)
%
%   See also CS_QRSOL, CS_LUSOL, CS_DMPERM, SPRANK, RANK.

%   Copyright 2006-2007, Timothy A. Davis.
%   http://www.cise.ufl.edu/research/sparse

[m n] = size (A) ;
[p q r s cc rr] = cs_dmperm (A) ;
C = A (p,q) ;
b = b (p) ;
x = zeros (n,1) ;
if (rr(3) <= m & cc(4) <= n)                                                %#ok
    x (cc(4):n) = cs_qrsol (C (rr(3):m, cc(4):n), b (rr(3):m)) ;
    b (1:rr(3)-1) = b (1:rr(3)-1) - C (1:rr(3)-1, cc(4):n) * x (cc(4):n) ;
end
if (rr(2) < rr (3) & cc(3) < cc(4))                                         %#ok
    x (cc(3):cc(4)-1) = ...
        cs_lusol (C (rr(2):rr(3)-1, cc(3):cc(4)-1), b (rr(2):rr(3)-1)) ;
    b (1:rr(2)-1) = ...
        b (1:rr(2)-1) - C (1:rr(2)-1, cc(3):cc(4)-1) * x (cc(3):cc(4)-1) ;
end
if (rr(2) > 1 & cc(3) > 1)                                                  %#ok
    x (1:cc(3)-1) = cs_qrsol (C (1:rr(2)-1, 1:cc(3)-1), b (1:rr(2)-1)) ;
end
x (q) = x ;


function calpak_test24 ( )

%*****************************************************************************80
%
%% CALPAK_TEST24 tests JED_TO_YMDF_PERSIAN and YMDF_TO_JED_PERSIAN.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 March 2013
%
%  Author:
%
%    John Burkardt
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'CALPAK_TEST24\n' );
  fprintf ( 1, '  For the Persian calendar:\n' );
  fprintf ( 1, '  JED_TO_YMDF_PERSIAN: JED -> YMDF.\n' );
  fprintf ( 1, '  YMDF_TO_JED_PERSIAN: YMDF -> JED.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  JED (in)    YMDF                JED (out)\n' );
  fprintf ( 1, '\n' );

  jed_epoch = epoch_to_jed_persian ( );

  i = 0;

  while ( 1 )

    i = i + 1;
    jed1 = jed_test ( i );

    if ( jed1 < 0.0 )
      break
    end

    if ( jed_epoch <= jed1 )

      [ y2, m2, d2, f2 ] = jed_to_ymdf_persian ( jed1 );

      s2 = ymdf_to_s_numeric ( y2, m2, d2, f2 );

      jed3 = ymdf_to_jed_persian ( y2, m2, d2, f2 );

      fprintf ( 1, '  %11.2f  %20s  %11.2f\n', jed1, s2, jed3 );

    end

  end

  return
end


function [edges,idx,edgemap]=uniqedges(elem)
%
% [edges,idx,edgemap]=uniqedges(elem)
%
% return the unique edge list from a surface or tetrahedral mesh
%
% author: Qianqian Fang, <q.fang at neu.edu>
%
% input:
%     elem: a list of elements, each row is a list of nodes for an element.
%           elem can have 2, 3 or 4 columns
%
% output:
%     edge: unique edges in the mesh, denoted by a pair of node indices
%     idx:  index of the output in the raw edge list (returned by meshedge)
%     edgemap: index of the raw edges in the output list (for triangular mesh)
%
% -- this function is part of iso2mesh toolbox (http://iso2mesh.sf.net)
%

if(size(elem)==2)
   edges=elem;
elseif(size(elem)>=3)
   edges=meshedge(elem);
else
   error('invalid input');
end

[uedges,idx,jdx]=unique(sort(edges,2),'rows');
edges=edges(idx,:);
if(nargout>2)
    edgemap=reshape(jdx,[size(elem,1) nchoosek(size(elem,2),2)]);
end


function S = statistics(V,F,varargin)
  % STATISTICS  Determine a number of statistics about a mesh
  %
  % Inputs:
  %   V  #V by 3 list of mesh vertices
  %   F  #F by 3 list of triangle indices
  %   Optional:
  %     'Fast'  followed by bool. Whether to skip certain expensive statistics
  %     'MinArea'  Followed by factor of bounding_box_diagonal^2 area value for
  %       determining small triangles {1e-7}*bounding_box_diagonal^2
  %     'MinDist'  Followed by factor of bounding box diagonal dist value for
  %       determining close vertices {1e-7}*bounding_box_diagonal
  %     'MinAngle'  Followed by dist value for determining small angles
  %       {0.01 radians}
  % Outputs:
  %   S  Struct containing:
  %     num_faces  Number of triangles in F
  %     num_vertices  Number of vertices in V
  %     num_edges  Number of unique undirected edges
  %     num_small_triangles  Number of triangles with area < min_area
  %     num_small_angles  Number of corners with internal angles < min_angle
  %     num_close_vertices  Number of vertices minus number of unique vertices
  %       upto rounding coordinates by min_dist (~L1 distance)
  %     num_connected_components Number of connected compenents of mesh as
  %       graph (includes each unreferenced vertex as a singlton component)
  %     num_handles  Genus of surface, (2-X)/2, where X is Euler characteristic
  %     euler_characteristic  Euler characteristic
  %     num_boundary_loops  Number of connected components in undirected graph
  %       of boundary edges
  %     num_boundary_edges  Number of boundary edges
  %     num_ears  Number of topological ears (triangles with single internal
  %       edge)
  %     num_nonmanifold_edges Number of non-manifold edges (edges with valence
  %       >2)
  %     num_conflictingly_oriented_edges Number of edges with and even number
  %       of incident faces having conflicting orientation
  %     num_duplicate_vertices  Number vertices minus number of geometrically
  %       unique vertices
  %     num_nonmanifold_vertices Number of non-manifold vertices (vertices
  %       whose incident faces do not form exaclty one connected component)
  %     num_unreferenced_vertices Number of vertices not appearing in F
  %     num_combinatorially_duplicate_faces  Number of faces minus number of
  %       combinatorially unique faces
  %     num_geometrically_degenerate_faces  Number of faces with area == 0.
  %       Note that combinatorially degenerate faces will be included.
  %     num_combinatorially_degenerate_faces  Number of faces with 2 or more of
  %       the same vertices as corners
  %     Not 'Fast'
  %       num_selfintersecting_pairs  Number of self intersecting pairs of
  %         triangles
  %       num_intracomponent_selfintersecting_pairs Number of self intersecting
  %          pairs of triangles _in the same connected component_
  %
  % Examples:
  %   S = statistics(V,F,'Fast',true)
  %   subplot(3,1,1);
  %   hist(doublearea(V,F)/2,100);
  %   title('areas');
  %   subplot(3,1,2);
  %   hist(reshape(internalangles(V,F),[],1),100);
  %   title('internal angles');
  %   subplot(3,1,3);
  %   bar( ...
  %    sort(sparse( ...
  %      connected_components(F),1,diag(massmatrix(V,F,'barycentric'))), ...
  %      'descend'));
  %   title('CC areas');

  fast = false;
  min_area = 1e-7;
  min_dist = 1e-7;
  min_angle = 0.01;

  ii = 1;
  while ii<=numel(varargin)
    switch varargin{ii}
    case 'MinArea'
      assert(ii+1<=numel(varargin));
      ii = ii+1;
      min_area = varargin{ii};
    case 'MinDist'
      assert(ii+1<=numel(varargin));
      ii = ii+1;
      min_dist= varargin{ii};
    case 'MinAngle'
      assert(ii+1<=numel(varargin));
      ii = ii+1;
      min_angle = varargin{ii};
    case 'Fast'
      assert(ii+1<=numel(varargin));
      ii = ii+1;
      fast = varargin{ii};
    otherwise
      error(['Unsupported parameter `' varargin{ii} '`']);
    end
    ii = ii + 1;
  end

  bbd = sqrt(sum((max(V)-min(V)).^2,2));

  % To achieve this ordering (or almost this order?):
  % Basic counts
  S.num_faces = 0;
  S.num_vertices = 0;
  S.num_edges = 0;
  % Small things
  S.num_small_triangles = 0;
  S.num_small_angles = 0;
  S.num_kahan_length_violations = 0;
  S.num_close_vertices = 0;
  % Topology related
  S.num_connected_components = 0;
  S.num_handles = 0;
  S.euler_characteristic = 0;
  S.num_boundary_loops = 0;
  S.num_boundary_edges = 0;
  S.num_ears = 0;
  S.num_nonmanifold_edges = 0;
  S.num_conflictingly_oriented_edges = 0;
  S.num_duplicate_vertices = 0;
  S.num_nonmanifold_vertices = 0;
  S.num_unreferenced_vertices = 0;
  % Degeneracy related
  S.num_combinatorially_duplicate_faces = 0;
  S.num_geometrically_degenerate_faces = 0;
  S.num_combinatorially_degenerate_faces = 0;
  if ~fast
    S.num_intracomponent_selfintersecting_pairs = 0;
    S.num_selfintersecting_pairs = 0;
  end

  % easy
  S.num_faces = size(F,1);
  S.num_vertices = size(V,1);
  S.num_edges = size(edges(F),1);
  S.num_combinatorially_duplicate_faces = ...
    S.num_faces - size(unique(sort(F,2),'rows'),1);
  S.num_duplicate_vertices = ...
    S.num_vertices - size(remove_duplicate_vertices(V,0),1);

  C = zeros(size(V,1),1);
  C(1:max(F(:)),:) = connected_components(F);
  C(C==0) = max(C)+(1:sum(C==0));
  is_unreferenced = sparse(F,1,1,size(V,1),1)==0;
  %S.num_unreferenced_vertices = sum(sparse(C,1,1)==1)
  S.num_unreferenced_vertices = sum(is_unreferenced);
  S.num_connected_components = max(C);

  E = [F(:,[2 3]); F(:,[3 1]); F(:,[1 2])];
  % Direct all edges so sortE(:,1) < sortE(:,2)
  sortE = sort(E,2);
  % Adjacency matrix for these "redirected" edges
  DA = sparse(sortE(:,1),sortE(:,2),1,size(V,1),size(V,1));
  % If edge occurs more than once it's non-manifold
  S.num_nonmanifold_edges = nnz(DA>2);
  % If edge only occurs once then it's a boundary
  S.num_boundary_edges = nnz(DA==1);
  if S.num_nonmanifold_edges == 0
    S.num_ears = size(find_ears(F),1);
  else
    rmfield(S,'num_ears');
  end
  % Same adjacency matrix but count -1 if E(:,1)<E(:,2) for and +1 otherwise
  OA = sparse(sortE(:,1),sortE(:,2),1-2*(E(:,1)<E(:,2)),size(V,1),size(V,1));
  % Don't count boundary edges (where "redirected" edge only occured once).
  OA(DA==1) = 0;
  % non-zero count means conflictingly oriented. Note, can get +2-1=0, but this
  % could feasibly be oriented (a meshed self-intersection).
  S.num_conflictingly_oriented_edges = nnz(OA);

  isnmv = is_vertex_nonmanifold(F);
  if numel(isnmv)<size(V,1);
    isnmv(numel(isnmv)+1:size(V,1)) = 0;
  end
  S.num_nonmanifold_vertices = sum(isnmv & ~is_unreferenced);

  [~,BC] = conncomp( (DA==1)+(DA==1)' );
  S.num_boundary_loops = sum(sparse(BC,1,1)>1);

  S.euler_characteristic = S.num_vertices - S.num_edges + S.num_faces;
  b = S.num_boundary_loops;
  % http://en.wikipedia.org/wiki/Genus_(mathematics)#Orientable_surface
  % X = 2 - 2g - b
  % X + b - 2 = - 2g
  % 2-b-X  = 2g
  % g = (2-b-X)/2
  % http://sketchesoftopology.wordpress.com/2008/02/04/genus-euler-characteristic-boundary-components/
  S.num_handles = ...
    (2* ...
      (S.num_connected_components-S.num_unreferenced_vertices) - ...
    S.num_boundary_loops - ...
    (S.euler_characteristic-S.num_unreferenced_vertices))/2 ;

  dblA = doublearea(V,F);
  S.num_geometrically_degenerate_faces = sum(dblA==0);
  S.num_combinatorially_degenerate_faces = ...
    sum((F(:,1)==F(:,2)) | (F(:,2)==F(:,3)) | (F(:,3)==F(:,1)));

  S.num_small_triangles = sum(dblA<2*min_area*bbd*bbd);
  S.num_small_angles = sum(sum(internalangles(V,F)<min_angle));
  sl = sort(edge_lengths(V,F),2,'descend');
  S.num_kahan_length_violations = sum((sl(:,3)-(sl(:,1)-sl(:,2)))<0);

  S.num_close_vertices = ...
    S.num_vertices - size(remove_duplicate_vertices(V,min_dist*bbd),1);

  if ~fast
    V3 = V;
    V3(:,end+1:3) = 0;
    nd = dblA>0;
    Fnd = F(nd,:);
    [~,~,IF] = selfintersect(V3,Fnd,'DetectOnly',true);
    S.num_selfintersecting_pairs = size(IF,1);
    CF = C(F(:,1));
    CFnd = CF(nd)';
    S.num_intracomponent_selfintersecting_pairs =  ...
      sum(CFnd(IF(:,1))== CFnd(IF(:,2)));
  end

end


function check = chi_square_noncentral_check ( a, b )

%*****************************************************************************80
%
%% CHI_SQUARE_NONCENTRAL_CHECK checks the parameters of the noncentral Chi Squared PDF.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    06 September 2004
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer A, the parameter of the PDF.
%    1.0 <= A.
%
%    Input, real B, the noncentrality parameter of the PDF.
%    0.0 <= B.
%
  if ( a < 1.0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'CHI_SQUARE_NONCENTRAL_CHECK - Fatal error!\n' );
    fprintf ( 1, '  A < 1.\n' );
    check = 0;
    error ( 'CHI_SQUARE_NONCENTRAL_CHECK - Fatal error!' );
  end

  if ( b < 0.0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'CHI_SQUARE_NONCENTRAL_CHECK - Fatal error!\n' );
    fprintf ( 1, '  B < 0.\n' );
    check = 0;
    error ( 'CHI_SQUARE_NONCENTRAL_CHECK - Fatal error!' );
  end

  check = 1;

  return
end


function varargout = grDilate(varargin)
%GRDILATE Morphological dilation on graph.
%
%   LBL2 = grDilate(EDGES, LBL1)
%   Each label of the graph is assigned the highest label of its
%   neighbours, or it keeps the same label this one is bigger.
%
%   Example
%   grDilate
%
%   See also
%   grErode, grOpen, grClose
%

% ------
% Author: David Legland
% E-mail: david.legland@grignon.inra.fr
% Created: 2006-01-20
% Copyright 2006-2022 INRA - CEPIA Nantes - MIAJ (Jouy-en-Josas)

if length(varargin) == 2
    edges   = varargin{1};
    lbl     = varargin{2};
elseif length(varargin) == 3
    edges   = varargin{2};
    lbl     = varargin{3};
else
    error('Wrong number of arguments in "grDilate"');
end

lbl2 = zeros(size(lbl));

uni = unique(edges(:));
for n = 1:length(uni)
    neigh = grAdjacentNodes(edges, uni(n));
    lbl2(uni(n)) = max(lbl([uni(n); neigh]));
end

varargout{1} = lbl2;


function [img,nrg] = rayImage(ray,mic,rad,rMax)
%+========================================================================+
%|                                                                        |
%|           OPENRAY - LIBRARY FOR TRI-DIMENSIONAL RAY TRACING            |
%|           openRay is part of the GYPSILAB toolbox for Matlab           |
%|                                                                        |
%| COPYRIGHT : Matthieu Aussal (c) 2017-2018.                             |
%| PROPERTY  : Centre de Mathematiques Appliquees, Ecole polytechnique,   |
%| route de Saclay, 91128 Palaiseau, France. All rights reserved.         |
%| LICENCE   : This program is free software, distributed in the hope that|
%| it will be useful, but WITHOUT ANY WARRANTY. Natively, you can use,    |
%| redistribute and/or modify it under the terms of the GNU General Public|
%| License, as published by the Free Software Foundation (version 3 or    |
%| later,  http://www.gnu.org/licenses). For private use, dual licencing  |
%| is available, please contact us to activate a "pay for remove" option. |
%| CONTACT   : matthieu.aussal@polytechnique.edu                          |
%| WEBSITE   : www.cmap.polytechnique.fr/~aussal/gypsilab                 |
%|                                                                        |
%| Please acknowledge the gypsilab toolbox in programs or publications in |
%| which you use it.                                                      |
%|________________________________________________________________________|
%|   '&`   |                                                              |
%|    #    |   FILE       : rayImage.m                                    |
%|    #    |   VERSION    : 0.41                                          |
%|   _#_   |   AUTHOR(S)  : Matthieu Aussal                               |
%|  ( # )  |   CREATION   : 14.03.2017                                    |
%|  / 0 \  |   LAST MODIF : 01.04.2018                                    |
%| ( === ) |   SYNOPSIS   : Image-sources from ray-tracing                |
%|  `---'  |                                                              |
%+========================================================================+

% Material properties (http://www.odeon.dk/material-manufactures)
load('odeon.mat')
mat  = odeon.mat(ray.msh.col,:);
Nfrq = size(mat,2);

% Air absorbing formulae for T = 20°C (bouquin Jouhaneau p 68-69)
rhm = 30;
air = 5.5 * (50/rhm) .* (odeon.frq/1000).^1.7 * 1e-4;

% Measures
[Isrc,src] = ray.measure(mic,rad,rMax);

% Initialization
img = cell(size(src));
nrg = cell(size(src));
rfl = ones(length(ray),Nfrq);

% Loop on images sources
for i = 1:length(src)
    % Unicity for images
    [~,Ia,Ic] = unique(round(src{i}*1e12),'rows','stable');

    % Image coordinates
    img{i} = src{i}(Ia,:) - ones(length(Ia),1)*mic;

    % Image Energy
    nrg{i} = zeros(length(Ia),Nfrq);
    for j = 1:Nfrq
        nrg{i}(:,j) = accumarray(Ic,rfl(Isrc{i},j),[length(Ia),1]);
    end

    % Update reflecting coeff
    ind         = (ray.iel(:,i+1) > 0);
    rfl(ind,:)  = rfl(ind,:) .* (1 - mat(ray.iel(ind,i+1),:));
    rfl(~ind,:) = 0;
end

% Vectoriel format
img = cell2mat(img);
nrg = cell2mat(nrg);

% Atmosphere dissipation
dst = sqrt(sum(img.^2,2));
nrg = nrg .* exp(-dst*air);

% Sort in phase
[~,ind] = sort(dst);
img     = img(ind,:);
nrg     = nrg(ind,:);

% Normalisation
nrg = nrg ./ max(max(nrg));
end


function [ M, N ] = getPsiMat( data, image )
%GETPSIMAT gets \Psi matrix (LBP features) for all components
%   Detailed explanation goes here
%
% Synopsis:
%  [ M ] = getPsiMat(data, image)
%
% INPUT:
%   data    ...     struct, containes filed lbp (cell array - holds
%                   neccessary parameters for lbppyr_features_sparse
%                   function), imSize (size of image), Images (matrix
%                   [imSize(1)*imSize(2) x nImages]), nImages (count of
%                   images), structure options (with field M - count of
%                   components)
%   image   ...     idx of image on which LBP features are computed
%
% OUTPUT:
%   M       ...     cell array [1 x data.options.M] - \Psi matrices with
%                   LBP features
%   N       ...     cell array [1 x data.options.M] - \Psi matrices with
%                   indices of nonzero elements of LBP features
%
% 05-08-10 Michal Uricar
% 11-07-11 Michal Uricar, corners dataset (checked-only)

    M = cell(1, data.options.M);
    N = cell(1, data.options.M);

    for j = 1 : data.options.M;
        [M{j} N{j}] = lbp2sparse(data.Images(:, image), data.imSize, data.lbp{j}.wins, data.lbp{j}.winSize, data.lbp{j}.hop, 0);
    end;

end


function kernel = calibSPIRiT(kCalib, kSize, nCoils, CalibTyk)

% kernel = calibSPIRiT(kCalib, kSize, nCoils, CalibTyk)
%
% Function calibrates a SPIRiT kernel from a calibration area in k-space
%
%
% (c) Michael Lustig 2013
%

[AtA] = dat2AtA(kCalib,kSize);
for n=1:nCoils
	kernel(:,:,:,n) = calibrate(AtA,kSize,nCoils,n,CalibTyk);
end


function simOutput = mpcSim(nx, ny, nu, Nsim, e0, umin, umax, H, G, Lineq, Mineq, Leq, Meq, phi, gamma, lambda, chkInputBoundFlag, sivdMode, Xref)
% mpcSim Simulate the system with MPC Controller
%
% Author : Ajinkya Khade, askhade@ncsu.edu

[J, sivd,exitflag] = deal(zeros(1, Nsim));

% Initializing matrices to log simulation data
empc = zeros(nx, Nsim);         % stores error vectors at all time steps
ympc = zeros(ny, Nsim);         % stores output vectors at all time steps
umpc = zeros(nu, Nsim);         % stores calculated input vectors
uact = umpc;                    % stores applied input vectors

% Assigning values at the beginning of simulation
empc(:,1) = e0;
umpc(:,1) = 0;
sivd(1)   = Xref(2);

% Options structure for the QP Solver
options = optimoptions('quadprog','Algorithm','active-set','Display','off','TolFun',0.001);

% Simulating over N time steps
for k = 1:Nsim

    F = (2*G(empc(:,k)))';

    % Solving the QP at current time step
    [U, J(k),exitflag(k)] = quadprog(H, F, Lineq, Mineq(empc(:,k),sivd(k),Xref(2,k)), ...
                                           Leq,   Meq(empc(:,k)), ...
                                           [], [], [], options);

	% Extracting and storing calculated input at current time step
    umpc(:,k)   = U(1:nu);
    % Checking for saturation and storing applied input at current time step
    uact(:,k)   = getActualU(umpc(:,k), umin, umax, chkInputBoundFlag);
	% Calculating and storing error vector at current time step
    empc(:,k+1) = phi*empc(:,k) + gamma*uact(:,k);
	% Calculating and storing ouput at current time step
    ympc(:,k)   = lambda*empc(:,k);

    % Calculating SIVD
    if sivdMode == 0
        % SIVD varies linearly with reference trajectory
        sivd(k+1) = Xref(2,k);
    elseif sivdMode == 1
        % SIVD varies dynamically with range rate
        sivd(k+1) = getsivd(empc(2,k), umin);
    end

    % Update range and range rate to make it relative to SIVD
    empc(1,k+1) = empc(1,k+1) + (sivd(k+1) - sivd(k));
    empc(2,k+1) = empc(2,k+1) - (Xref(2,k+1) - Xref(2,k));
end

empc = empc(:,1:end-1);
sivd = sivd(:,1:end-1);

% Storing all simulation information in a structure for returning
simOutput.empc = empc;
simOutput.ympc = ympc;
simOutput.umpc = umpc;
simOutput.uact = uact;
simOutput.sivd = sivd;
simOutput.exitflag = exitflag;
simOutput.J = J;

end

function uact = getActualU(umpc, umin, umax, uConstraintFlag)
%getActualU  Calculate actual input applied.
%   This function checks if input violates bounds and calculates the actual
%   input to be applied.

uact = umpc;

if uConstraintFlag
    if umpc > umax
        uact = umax;
    elseif umpc < umin
        uact = umin;
    end
end

end


function F = OCP_F(u,x,p,discretizationMethod,isMEnabled,parIdx) %#codegen

    if isMEnabled
        fdt = OCP_GEN_fdt(u,x,p,parIdx);
        % forced to 'Euler'
        M = OCP_GEN_M(u,x,p);
        invM = inv(M);
        invMf = invM*fdt;
        % F
        F = invMf - x;
    else % M disabled
        switch discretizationMethod
            case 'RK2'
                fdt   = OCP_GEN_fdt(u,x,p,parIdx);
                f12dt = OCP_GEN_fdt(u,x-fdt/2,p,parIdx);

                F  =  f12dt  - x;
            case 'RK4'
                fdt   = OCP_GEN_fdt(u,x,p,parIdx);   % k1
                f12dt = OCP_GEN_fdt(u,x-fdt/2,p,parIdx); % k2
                f22dt = OCP_GEN_fdt(u,x-f12dt/2,p,parIdx); % k3
                f3dt  = OCP_GEN_fdt(u,x-f22dt,p,parIdx); % k4

                F = (fdt+2*f12dt+2*f22dt+f3dt)/6 - x;

            otherwise % 'Euler'
                fdt = OCP_GEN_fdt(u,x,p,parIdx);
                F  = fdt - x;
        end
    end
end


function varargout = imregrotate(varargin)
%ROIROTATE Rotate & crop region of interest avoiding 'black corners'.
% 	B = ROIROTATE(A,ROI,ANGLE,METHOD) rotates the region of intererest ROI
% 	found in the image A by ANGLE degrees in a counter-clockwise direction,
% 	using the specified interpolation method and gives the rotated
% 	region as output in B cropped out of the original image.
%
% 	Usefulness
% 	----------
% 	ROIROTATE was designed to avoid the 'black corners' typical of
%   MATLAB's imrotate function, which are apearing from its behaviour
%   of padding by zeros the space outside the image borders prior to
%   the rotation. This is possible if the image to be rotated is
%   part of a bigger image - which is the definition of a 'region
%   of interest' -, because there is enough information to fill
%   the corners.
%
% 	Description
% 	-----------
% 	Apart of the first entry which is based on the IMCROP syntax,
% 	all other are identical to the IMROTATE function.
%
%   ROI is a four-element vector with the form [xmin ymin width height];
%   these values are specified in spatial coordinates.
%
% 	xmin - starting pixel to be cut, x-th of the original image
% 	ymin - same on y-axis
% 	width - number of pixels to be cut minus one (width)
% 	height - same on height
%
% 	If you want to point the 5 pixel wide & 7 pixel heigh NW corner
% 	of an image, replace R with [1,1,4,6].
%
%   Because ROI is specified in terms of spatial coordinates,
%   the WIDTH and HEIGHT of ROI do not always correspond exactly
%   with the size of the output image. For example, suppose ROI
%   is [20 20 40 30], using the default spatial coordinate
%   system. The upper left corner of the specified rectangle is
%   the center of the pixel (20,20) and the lower right corner is
%   the center of the pixel (50,60). The resulting output image
%   is 31-by-41, not 30-by-40, because the output image includes
%   all pixels in the input that are completely or partially
%   enclosed by the rectangle.
%
%         Note for IMCROP:
%         To cut the NW pixel only:
%             NWcornerPixel = imcrop(I, [1,1,0,0]);
%
%         To cut the first top stripe of pixels:
%             topStripe = imcrop(I, [1,1,size(I,2)-1,0]);
%
% 	METHOD is a string that can have one of these values:
%
%        'nearest'  (default) nearest neighbor interpolation
%        'bilinear' bilinear interpolation
%        'bicubic'  bicubic interpolation
%
% 	If you omit the METHOD argument, ROIROTATE uses the default
% 	method of 'nearest'.
%
%   To rotate the image clockwise, specify a negative angle.
%
% 	Class Support
% 	-------------
% 	The input image can be of class uint8, uint16, or double.
%   The output image is of the same class as the input image.
%
% 	Example
% 	-------
%        I = imread('circuit.tif');
%        J = imrotate(imcrop(I,[60 80 100 90]),-21,'bilinear','crop');
%        [K x y w h] = roirotate(I,[60 80 100 90],-21,'bilinear');
%        figure, subplot(1,3,1), imshow(I), title('roi')
%        rectangle('Position',[60 80 100 90],'EdgeColor','red');
%        rectangle('Position',[x y w h],'EdgeColor','green');
%        subplot(1,3,2), imshow(J), title('imrotate')
%        subplot(1,3,3), imshow(K), title('roirotate')
%
% 	See also IMROTATE, IMCROP, IMRESIZE, IMTRANSFORM, TFORMARRAY.

%   Vlad Atanasiu - 06/05/2002
%   Revisions: 3  > 01/11/2008

% check image input data
[A,dim,x,y,width,height,ang,method] = parseInputs(varargin{:});

% calculate padding borders
padX = abs(ceil(height*sin(ang*pi/180)/2));
padY = abs(ceil(width*sin(ang*pi/180)/2));

% padding zeros if extended region of interest coordinates outside image
if x-padX < 1   % left
    A = [zeros(size(A,1),padX-x+1,dim) A];
end
if y-padY < 1   % top
    A = [zeros(padY-y+1,size(A,2),dim);...
            A];
end
if x+width+padX > size(A,2)   % right
    A = [A zeros(size(A,1),x+width+padX-size(A,2),dim)];
end
if y+height+padY > size(A,1)   % bottom
    A = [A;...
            zeros(y+height+padY-size(A,1),size(A,2),dim)];
end

% cut extended region
ROI = imcrop(A,[x-padX y-padY width+padX*2 height+padY*2]);

% rotate extended region
ROI = imrotate(ROI,ang,method,'crop');

% cut region
varargout{1} = imcrop(ROI,[padX padY width height]);

% gives extended region coordinates
if nargout == 5
    varargout{2} = x-padX;
    varargout{3} = y-padY;
    varargout{4} = width+padX*2;
    varargout{5} = height+padY*2;
end

% ------------------------------------------------

function [A,dim,x,y,width,height,ang,method] = parseInputs(varargin)
% Input checkings

% Defaults
method = 'n';

% Check number of input parameters
error(nargchk(3,4,nargin));
switch nargin
case 3,             % regrotate(A,reg,ang,)
    A = varargin{1};
	x = varargin{2}(1);
	y = varargin{2}(2);
	width = varargin{2}(3);
	height = varargin{2}(4);
    ang = varargin{3};
case 4,             % regrotate(A,reg,ang,method)
    A = varargin{1};
	x = varargin{2}(1);
	y = varargin{2}(2);
	width = varargin{2}(3);
	height = varargin{2}(4);
    ang = varargin{3};
    method = varargin{4};
otherwise,
    error('Invalid number of input arguments.');
end

% Check validity of the input parameters
if ischar(method),
    strings = {'nearest','bilinear','bicubic'};
    idx = strmatch(lower(method),strings);
    if isempty(idx),
        error(sprintf('Unknown interpolation method: %s',method));
    elseif length(idx)>1,
        error(sprintf('Ambiguous interpolation method: %s',method));
    else
        method = strings{idx};
    end
else
    error('Interpolation method have to be a string.');
end

if size(varargin{2},2) ~= 4
    error('Region of interest should be defined by 4 arguments.');
end

% transforms the format of A into an image if it is a filename
if (isstr(A))
    A = imread(A);
end

% gets the dimensions of A
dim = ndims(A);
if dim == 2, dim=1; end

% modifies if needed the region of interest coordinates if outside image
if x < 1, x = 1; end
if y < 1, y = 1; end
if x > size(A,2)-1, x = size(A,2)-1; end
if y > size(A,1)-1, y = size(A,1)-1; end
if x+width > size(A,2)-1, width = size(A,2)-x-1; end
if y+height > size(A,1)-1, height = size(A,1)-y-1; end