function [sicdmeta] = pfa_sicd_meta(meta, nbdata, ifp_params)
%PFA_SICD_META Creates a SICD metadata structure for an image created by pfa_file.m
%
% Inputs:
%     meta:          Collection narrowband data.  This is the same
%                    structure returned by the get_meta function for a
%                    object returned by open_ph_reader.
%     nbdata:        CPHD-style per-pulse narrowband data.  This is the
%                    same structure returned as the second return parameter
%                    of the read_cphd function.
%     ifp_params:    Structure of some additional parameters computed
%                    during image formation.
%
% Outputs:
%     sicdmeta:      Image formation and collection information in a
%                    structure compatible with the SICD writer.
%
% Authors: Wade Schwartzkopf and Tom Krauss, NGA/IDT
%
% //////////////////////////////////////////
% /// CLASSIFICATION: UNCLASSIFIED       ///
% //////////////////////////////////////////

% Create SICD meatdata structure
sicdmeta = meta2sicd_cphdx(meta,nbdata,ifp_params.channel);

% Image Creation
sicdmeta.ImageCreation.DateTime = now();
sicdmeta.ImageCreation.Profile  = 'pfa_sicd_meta.m';

% ImageData
sicdmeta.ImageData.PixelType               = 'RE32F_IM32F';
sicdmeta.ImageData.NumRows                 = ifp_params.image_size_pixels(1);
sicdmeta.ImageData.NumCols                 = ifp_params.image_size_pixels(2);
sicdmeta.ImageData.FirstRow                = 0;
sicdmeta.ImageData.FirstCol                = 0;
sicdmeta.ImageData.FullImage.NumRows       = sicdmeta.ImageData.NumRows;
sicdmeta.ImageData.FullImage.NumCols       = sicdmeta.ImageData.NumCols;
sicdmeta.ImageData.SCPPixel.Row            = floor(sicdmeta.ImageData.NumRows/2);
sicdmeta.ImageData.SCPPixel.Col            = floor(sicdmeta.ImageData.NumCols/2);

% GeoData
sicdmeta.GeoData.EarthModel='WGS_84';
center=mean(nbdata.SRPPos); % Current PFA code only forms to this point
sicdmeta.GeoData.SCP.ECF.X=mean(center(1));
sicdmeta.GeoData.SCP.ECF.Y=mean(center(2));
sicdmeta.GeoData.SCP.ECF.Z=mean(center(3));
scp_lla = ecf_to_geodetic([sicdmeta.GeoData.SCP.ECF.X sicdmeta.GeoData.SCP.ECF.Y sicdmeta.GeoData.SCP.ECF.Z]);
sicdmeta.GeoData.SCP.LLH.Lat=scp_lla(1);
sicdmeta.GeoData.SCP.LLH.Lon=scp_lla(2);
sicdmeta.GeoData.SCP.LLH.HAE=scp_lla(3);
% Corner coordinates will be popupated later in derived_sicd_fields call

% Grid
sicdmeta.Grid.ImagePlane     = 'SLANT';
sicdmeta.Grid.Type           = 'RGAZIM';
sicdmeta.Grid.Row.Sgn=-1; % We have done an IFFT in PFA
sicdmeta.Grid.Row.ImpRespBW  = diff(ifp_params.k_v_bounds);
sicdmeta.Grid.Row.ImpRespWid = 0.886/sicdmeta.Grid.Row.ImpRespBW;
sicdmeta.Grid.Row.SS         = 1/(ifp_params.sample_rate*sicdmeta.Grid.Row.ImpRespBW);
sicdmeta.Grid.Row.KCtr       = mean(ifp_params.k_v_bounds);
sicdmeta.Grid.Row.DeltaKCOAPoly = 0;
sicdmeta.Grid.Row.WgtType.WindowName = 'UNIFORM';
sicdmeta.Grid.Col.Sgn=-1; % We have done an IFFT in PFA
sicdmeta.Grid.Col.ImpRespBW  = diff(ifp_params.k_u_bounds);
sicdmeta.Grid.Col.ImpRespWid = 0.886/sicdmeta.Grid.Col.ImpRespBW;
sicdmeta.Grid.Col.SS         = 1/(ifp_params.sample_rate*sicdmeta.Grid.Col.ImpRespBW);
sicdmeta.Grid.Col.KCtr       = 0;
sicdmeta.Grid.Col.WgtType.WindowName = 'UNIFORM';
sicdmeta.Grid.Col.DeltaKCOAPoly = 0;

% ImageFormation
sicdmeta.ImageFormation.RcvChanProc.NumChanProc = 1; % This function only handles single-channel data
sicdmeta.ImageFormation.RcvChanProc.ChanIndex = ifp_params.channel;
sicdmeta.ImageFormation.ImageFormAlgo = 'PFA';
sicdmeta.ImageFormation.TStartProc = nbdata.TxTime(1);
sicdmeta.ImageFormation.TEndProc = nbdata.TxTime(end);
if isfield(meta.Channel,'Parameters') && ...
        isfield(meta.Channel.Parameters(ifp_params.channel),'Polarization') && ...
        all(isfield(meta.Channel.Parameters(ifp_params.channel).Polarization,{'TxPol','RcvPol'}))
    sicdmeta.ImageFormation.TxRcvPolarizationProc = ...
        [meta.Channel.Parameters(ifp_params.channel).Polarization.TxPol ':' ...
            meta.Channel.Parameters(ifp_params.channel).Polarization.RcvPol];
end
sicdmeta.ImageFormation.TxFrequencyProc.MinProc = ...
    min(nbdata.SC0 + (nbdata.SCSS * double(min(ifp_params.sample_range)-1)));
sicdmeta.ImageFormation.TxFrequencyProc.MaxProc = ...
    max(nbdata.SC0 + (nbdata.SCSS * double(max(ifp_params.sample_range)-1)));
sicdmeta.ImageFormation.ImageFormAlgo = 'PFA';
sicdmeta.ImageFormation.STBeamComp = 'NO';
sicdmeta.ImageFormation.ImageBeamComp = 'NO';
sicdmeta.ImageFormation.AzAutofocus = 'NO';
sicdmeta.ImageFormation.RgAutofocus = 'NO';

% SCPCOA
sicdmeta.SCPCOA.SCPTime = nbdata.TxTime(ifp_params.ref_pulse_index);

% Timeline
if isfield(meta,'Global') && isfield(meta.Global, 'Timeline') && ...
        all(isfield(meta.Global.Timeline, {'TxTime1', 'TxTime2'}))
    sicdmeta.Timeline.CollectDuration = meta.Global.Timeline.TxTime2 - ...
        meta.Global.Timeline.TxTime1;
else
    sicdmeta.Timeline.CollectDuration = nbdata.TxTime(end) - nbdata.TxTime(1);
end

% PFA
sicdmeta.PFA.FPN = struct('X',ifp_params.fpn(1),'Y',ifp_params.fpn(2),'Z',ifp_params.fpn(3));
sicdmeta.PFA.IPN = struct('X',ifp_params.ipn(1),'Y',ifp_params.ipn(2),'Z',ifp_params.ipn(3));
sicdmeta.PFA.PolarAngRefTime = nbdata.TxTime(ifp_params.ref_pulse_index);
% This often givens a "badly conditioned" polynomial warning with fitting a
% polynomial in ECF space.  Ignore.
old_state = warning('off','MATLAB:polyfit:RepeatedPointsOrRescale');
sicdmeta.PFA.PolarAngPoly = fliplr( polyfit(nbdata.TxTime, ifp_params.k_a, 5) ).';
sicdmeta.PFA.SpatialFreqSFPoly = fliplr( polyfit(ifp_params.k_a, ifp_params.k_sf, 5) ).';
warning(old_state);
sicdmeta.PFA.Krg1 = ifp_params.k_v_bounds(1);
sicdmeta.PFA.Krg2 = ifp_params.k_v_bounds(2);
sicdmeta.PFA.Kaz1 = ifp_params.k_u_bounds(1);
sicdmeta.PFA.Kaz2 = ifp_params.k_u_bounds(2);

sicdmeta = derived_sicd_fields(sicdmeta); % Computes many derived fields

end

% //////////////////////////////////////////
% /// CLASSIFICATION: UNCLASSIFIED       ///
% //////////////////////////////////////////


function y = mrdivide(X,Y)

if (isa(Y,'sdpvar'))
    if Y.dim(1)*Y.dim(2) == 1
        y = X*Y^-1;
        return
    else
        error('Division of matrix variables not possible (maybe you meant ./).')
    end
end

try

    % Quick exit on scalar division
    if length(Y)==1
        if isinf(Y)
            y = zeros(X.dim);
        else
            y = X;
            y.basis = y.basis/Y;
        end
        y.conicinfo = [0 0];
        return
    end

    lmi_variables = getvariables(X);
    nv = length(lmi_variables);
    y  = X;
    n = X.dim(1);
    m = X.dim(2);
    if (n==1) & (m==1) % SPECIAL CODE FOR FREAKY MATLAB BUG
        y.basis = sparse(reshape(reshape(full(X.basis(:,1)),n,m)/Y,n*m,1));
        for i = 1:nv
            temp = reshape(full(X.basis(:,i+1)),n,m)/Y;
            y.basis(:,i+1) = sparse(temp(:));
        end;
    else
        y.basis = reshape(reshape(X.basis(:,1),n,m)/Y,n*m,1);
        for i = 1:nv
            temp = reshape(X.basis(:,i+1),n,m)/Y;
            y.basis(:,i+1) = temp(:);
        end;
    end

    y.dim(1) = size(temp,1);
    y.dim(2) = size(temp,2);
catch
    error(lasterr);
end


function prtPlotUtilDataSetExploreGuiSimple(theObject,parent)
% Internal function,
% xxx Need Help xxx - see prtDataSetClass.explore

if nargin == 1
    windowSize = [754 600];
    pos = prtPlotUtilCenterFigure(windowSize);

    % Create the figure an UIControls
    figH = figure('Name','PRT Data Set Explorer','Menu','none','toolbar','figure','units','pixels','position',pos,'DockControls','off');
    try
        set(figH,'Number','Off');
    catch
        try
            set(figH,'NumberTitle','off');
        end
    end

    % Trim the toolbar down to just the zooming controls
    Toolbar.handle = findall(figH,'Type','uitoolbar');
    Toolbar.Children = findall(figH,'Parent',Toolbar.handle,'HandleVisibility','off');

    % Delete a bunch of things we dont need
    delete(findobj(Toolbar.Children,'TooltipString','New Figure',...
        '-or','TooltipString','Open File','-or','TooltipString','Save Figure',...
        '-or','TooltipString','Print Figure','-or','TooltipString','Edit Plot',...
        '-or','TooltipString','Data Cursor','-or','TooltipString','Brush/Select Data',...
        '-or','TooltipString','Link Plot','-or','TooltipString','Insert Colorbar',...
        '-or','TooltipString','Insert Legend','-or','TooltipString','Show Plot Tools and Dock Figure',...
        '-or','TooltipString','Hide Plot Tools'))
    bgc = get(figH,'Color');
else
    bgc = get(gcf,'Color');
    figH = parent;
end

popUpStrs = theObject.getFeatureNames;
popUpStrs = popUpStrs(:);

popX = uicontrol(figH,'Style','popup','units','normalized','FontUnits','Normalized','FontSize',0.6,'position',[0.15 0.01 0.19 0.04],'string',popUpStrs,'callback',{@plotSelectPopupCallback 1});
popXHead = uicontrol(figH,'Style','text','units','normalized','FontUnits','Normalized','FontSize',0.75,'position',[0.05 0.01 0.09 0.04],'string','X-Axis:','BackgroundColor',bgc,'HorizontalAlignment','Right'); %#ok

popY = uicontrol(figH,'Style','popup','units','normalized','FontUnits','Normalized','FontSize',0.6,'position',[0.45 0.01 0.19 0.04],'string',popUpStrs,'callback',{@plotSelectPopupCallback 2});
popYHead = uicontrol(figH,'Style','text','units','normalized','FontUnits','Normalized','FontSize',0.75,'position',[0.35 0.01 0.09 0.04],'string','Y-Axis:','BackgroundColor',bgc,'HorizontalAlignment','Right'); %#ok

popZ = uicontrol(figH,'Style','popup','units','normalized','FontUnits','Normalized','FontSize',0.6,'position',[0.75 0.01 0.19 0.04],'string',[{'None'}; popUpStrs],'callback',{@plotSelectPopupCallback 3});
popZHead = uicontrol(figH,'Style','text','units','normalized','FontUnits','Normalized','FontSize',0.75,'position',[0.65 0.01 0.09 0.04],'string','Z-Axis:','BackgroundColor',bgc,'HorizontalAlignment','Right'); %#ok

axisH = axes('Units','Normalized','outerPosition',[0.05 0.07 0.9 0.9]);

% Setup the PopOut Option
hcmenu = uicontextmenu;
hcmenuPopoutItem = uimenu(hcmenu, 'Label', 'Popout', 'Callback', @explorerPopOut); %#ok
set(axisH,'UIContextMenu',hcmenu);

if theObject.nFeatures > 1
    plotDims = [1 2 0];

    set(popX,'value',1); % Becase we have dont have a none;
    set(popY,'value',2); % Becase we have dont have a none;
    set(popZ,'value',1); % Becase we have a none;
else
    plotDims = [1 1 0];

    set(popX,'value',1); % Becase we have dont hvae a none;
    set(popY,'value',1); % Becase we have a none;
    set(popZ,'value',1); % Becase we have a none;
end
updatePlot;

    function plotSelectPopupCallback(myHandle, eventData, varargin) %#ok
        cVal = get(myHandle,'value');
        axisInd = varargin{1};
        if axisInd == 3
            % Z-axis we have a None option
            cVal = cVal - 1;
        end
        plotDims(axisInd) = cVal;
        updatePlot;
    end

    function updatePlot
        actualPlotDims = plotDims(plotDims>=1);
        axes(axisH); %#ok
        h = plot(theObject,actualPlotDims);
        set(h,'HitTest','off');
        set(axisH,'ButtonDownFcn',@axisOnClick);
    end
    function explorerPopOut(myHandle,eventData) %#ok
        figure;
        actualPlotDims = plotDims(plotDims>=1);
        plot(theObject,actualPlotDims);
    end
    function axisOnClick(myHandle,eventData)
        actualPlotDims = plotDims(plotDims>=1);
        data = theObject.getFeatures(actualPlotDims);

        [rP,rD] = rotateDataAndClick(data);

        dist = prtDistanceEuclidean(rP,rD);
        [~,i] = min(dist);
        obsName = theObject.getObservationNames(i);
        title(sprintf('Observation Closest To Last Click: %s',obsName{1}));

        debug = false;
        if debug
            hold on;
            d = theObject.getObservations(i);
            switch length(actualPlotDims)
                case 2
                    plot(d(1),d(2),'kx');
                case 3
                    plot3(d(1),d(2),d(3),'kx');
            end
            hold off;
        end
    end

    function [rotatedData,rotatedClick] = rotateDataAndClick(data)
        %[rotatedData,rotatedClick] = rotateDataAndClick(data)
        % Used internally; from Click3dPoint from matlab central; Copyright
        % follows

        %         Copyright (c) 2009, Babak Taati
        % All rights reserved.
        %
        % Redistribution and use in source and binary forms, with or without
        % modification, are permitted provided that the following conditions are
        % met:
        %
        %     * Redistributions of source code must retain the above copyright
        %       notice, this list of conditions and the following disclaimer.
        %     * Redistributions in binary form must reproduce the above copyright
        %       notice, this list of conditions and the following disclaimer in
        %       the documentation and/or other materials provided with the distribution
        %
        % THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
        % AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        % IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        % ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
        % LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
        % CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
        % SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
        % INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
        % CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
        % ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        % POSSIBILITY OF SUCH DAMAGE.
        point = get(gca, 'CurrentPoint'); % mouse click position
        camPos = get(gca, 'CameraPosition'); % camera position
        camTgt = get(gca, 'CameraTarget'); % where the camera is pointing to

        camDir = camPos - camTgt; % camera direction
        camUpVect = get(gca, 'CameraUpVector'); % camera 'up' vector

        % build an orthonormal frame based on the viewing direction and the
        % up vector (the "view frame")
        zAxis = camDir/norm(camDir);
        upAxis = camUpVect/norm(camUpVect);
        xAxis = cross(upAxis, zAxis);
        yAxis = cross(zAxis, xAxis);

        rot = [xAxis; yAxis; zAxis]; % view rotation

        if size(data,2) < 3
            data = cat(2,data,zeros(size(data,1),1));
        end

        % the point cloud represented in the view frame
        rotatedData = (rot * data')';
        rotatedData = rotatedData(:,1:2);
        % the clicked point represented in the view frame
        rotatedClick = rot * point' ;
        rotatedClick = rotatedClick(1:2,1)';
    end
end


function [ mask ] = sicd_mask( sicd_meta, dim1_range, dim2_range )
%SICD_MASK Create a mask of valid data from SICD metadata
%
% SICD allows a ValidData construct that defines which pixels are valid
% values with a list of vertices of an enclosing polygon.  This functions
% converts that structure into a mask over any portion of the SICD image
% space.
%
% INPUTS:
%   sicd_meta  - required: SICD metadata structure.
%   dim1_range - optional: 1x2 array [first element, last element].  If
%        producing a mask for a subimage, this is the range of image area
%        in the first dimension (what is called "columns" in SICD-- but
%        not necessarily stored in that orientation in the MATLAB reader).
%        Default is entire image range. Can also use an empty array ([]) to
%        specify entire range.
%   dim2_range - optional: 1x2 array [first element, last element].  If
%        producing a mask for a subimage, this is the range of image area
%        in the second (range, called "rows" in SICD) dimension.  Default
%        is entire image range. Can also use an empty array ([]) to specify
%        entire range.
%
% OUTPUTS:
%   mask - Logical array over the area requested
%
% Author: Wade Schwartzkopf, NGA/IDT
%
% //////////////////////////////////////////
% /// CLASSIFICATION: UNCLASSIFIED       ///
% //////////////////////////////////////////

% Default input parameters
if ~exist('row_range','var') || isempty(dim2_range)
    dim2_range = [1 sicd_meta.ImageData.FullImage.NumRows];
end
if ~exist('col_range','var') || isempty(dim1_range)
    dim1_range = [1 sicd_meta.ImageData.FullImage.NumCols];
end

if isfield(sicd_meta.ImageData,'ValidData') && ...
        isfield(sicd_meta.ImageData.ValidData,'Vertex')
    % Poly2mask has some peculiarities with including vertices (which are
    % document in the MATLAB help), so its possible that not all verticies
    % will be included in the resulting mask, but the boundary of the mask
    % will never be more than one pixel off of where it should be.
    mask = poly2mask(...
        [sicd_meta.ImageData.ValidData.Vertex.Row] + 1 ... % ValidData vertices are zero-based
           - dim2_range(1) + 1, ... % Relative to area of interest
        [sicd_meta.ImageData.ValidData.Vertex.Col] + 1 ... % ValidData vertices are zero-based
           - dim1_range(1) + 1, ... % Relative to area of interest
        diff(dim1_range)+1, diff(dim2_range)+1);
else % If valid data is not defined, assume all data is valid.
    mask = true(diff(dim1_range)+1, diff(dim2_range)+1);
end

end

% //////////////////////////////////////////
% /// CLASSIFICATION: UNCLASSIFIED       ///
% //////////////////////////////////////////


% ==============================================================================
%
%    Software License Agreement (BSD License)
%    Copyright (c) 2019
%    (www.aimlab.wpi.edu)
%
%    All rights reserved.
%
%    Redistribution and use in source and binary forms, with or without
%    modification, are permitted provided that the following conditions
%    are met:
%
%    * Redistributions of source code must retain the above copyright
%    notice, this list of conditions and the following disclaimer.
%
%    * Redistributions in binary form must reproduce the above
%    copyright notice, this list of conditions and the following
%    disclaimer in the documentation and/or other materials provided
%    with the distribution.
%
%    * Neither the name of authors nor the names of its contributors may
%    be used to endorse or promote products derived from this software
%    without specific prior written permission.
%
%    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
%    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
%    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
%    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
%    COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
%    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
%    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
%    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
%    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
%    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
%    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
%    POSSIBILITY OF SUCH DAMAGE.
%
%    \author:    <http://www.aimlab.wpi.edu>
%    \author:    <amunawar@wpi.edu>
%    \author:    Adnan Munawar
%    \version:   0.1$
% ==============================================================================

function [its,sizePath,run_time] =  RRTextend3D(dim,segmentLength,random_world,show_output)
% dim = 2;
% radius =0;
% segmentLength = 5;
% random_world = 0;
% n_its = 1000;
% standard length of path segments
if dim ==2
    start_cord = [5,5];
    goal_cord = [95,95];

else

    start_cord = [5,5,5];
    goal_cord = [95,95,95];
end

% create random world
Size = 100;
NumObstacles = 100;

if random_world ==1
    world = createWorld(NumObstacles,ones(1,dim)*Size,zeros(1,dim),dim);
else
    [world NumObstacles] = createKnownWorld(ones(1,dim)*Size,[0;0;0],dim);
end
% randomly select start and end nodes
%start_node = generateRandomNode(world,dim)
%end_node   = generateRandomNode(world,dim)
start_node = [start_cord,0,0,0];
end_node = [goal_cord,0,0,0];
% establish tree starting with the start node
tree = start_node;

a = clock;

% check to see if start_node connects directly to end_node
if ( (norm(start_node(1:dim)-end_node(1:dim))<segmentLength )...
        &&(collision(start_node,end_node,world,dim)==0) )
    path = [start_node; end_node];
else

    its = 0;
    numPaths = 0;
    flag = 0;
    while numPaths < 1,
        [tree,flag] = extendTree(tree,end_node,segmentLength,world,flag,dim);
        numPaths = numPaths + flag;
        its = its+1;
    end

end

% find path with minimum cost to end_node
path = findMinimumPath(tree,end_node,dim);
sizePath = size(path,1);

b = clock;
run_time = 3600*(b(4)-a(4)) + 60 * (b(5)-a(5)) + (b(6) - a(6));

if show_output == 1
    figure;
    plotExpandedTree(world,tree,dim);
    plotWorld(world,path,dim);
    % figure(2);
    % plotWorld(world,path,dim);
    %plotExpandedTree(world,tree,dim);
end
end

function world = createWorld(NumObstacles, endcorner, origincorner,dim)

if dim == 2

    % check to make sure that the region is nonempty
    if (endcorner(1) <= origincorner(1)) | (endcorner(2) <= origincorner(2))
        disp('Not valid corner specifications!')
        world=[];

        % create world data structure
    else
        world.NumObstacles = NumObstacles;
        world.endcorner = endcorner;
        world.origincorner = origincorner;

        % create NumObstacles
        maxRadius = min(endcorner(1)- origincorner(1), endcorner(2)-origincorner(2));
        maxRadius = 5*maxRadius/NumObstacles/2;
        for i=1:NumObstacles,
            % randomly pick radius
            world.radius(i) = maxRadius*rand;
            % randomly pick center of obstacles
            cx = origincorner(1) + world.radius(i)...
                + (endcorner(1)-origincorner(1)-2*world.radius(i))*rand;
            cy = origincorner(2) + world.radius(i)...
                + (endcorner(2)-origincorner(2)-2*world.radius(i))*rand;
            world.cx(i) = cx;
            world.cy(i) = cy;
        end
    end

elseif dim ==3;
    % check to make sure that the region is nonempty
    if (endcorner(1) <= origincorner(1)) || (endcorner(2) <= origincorner(2)) || (endcorner(3) <= origincorner(3))
        disp('Not valid corner specifications!')
        world=[];

        % create world data structure
    else
        world.NumObstacles = NumObstacles;
        world.endcorner = endcorner;
        world.origincorner = origincorner;

        % create NumObstacles
        bounds = [endcorner(1)- origincorner(1), endcorner(2)-origincorner(2), endcorner(3)-origincorner(3)];
        maxRadius = min(bounds);
        maxRadius = 5*maxRadius/NumObstacles;
        for i=1:NumObstacles,
            % randomly pick radius
            world.radius(i) = maxRadius*rand;
            % randomly pick center of obstacles
            cx = origincorner(1) + world.radius(i)...
                + (endcorner(1)-origincorner(1)-2*world.radius(i))*rand;
            cy = origincorner(2) + world.radius(i)...
                + (endcorner(2)-origincorner(2)-2*world.radius(i))*rand;
            cz = origincorner(2) + world.radius(i)...
                + (endcorner(2)-origincorner(2)-2*world.radius(i))*rand;
            world.cx(i) = cx;
            world.cy(i) = cy;
            world.cz(i) = cz;
        end
    end
end
end

function [world NumObstacles] = createKnownWorld(endcorner, origincorner,dim)
NumObstacles = 5;
if dim == 2
    % check to make sure that the region is nonempty
    if (endcorner(1) <= origincorner(1)) | (endcorner(2) <= origincorner(2)),
        disp('Not valid corner specifications!')
        world=[];
        % create world data structure
    else
        world.NumObstacles = NumObstacles;
        world.endcorner = endcorner;
        world.origincorner = origincorner;

        % create NumObstacles
        maxRadius = 10;

        world.radius(1) = maxRadius;
        cx = 50;
        cy = 50;
        world.cx(1) = cx;
        world.cy(1) = cy;

        world.radius(2) = maxRadius;
        cx = 75;
        cy = 25;
        world.cx(2) = cx;
        world.cy(2) = cy;

        world.radius(3) = maxRadius;
        cx = 25;
        cy = 75;
        world.cx(3) = cx;
        world.cy(3) = cy;

        world.radius(4) = maxRadius;
        cx = 25;
        cy = 25;
        world.cx(4) = cx;
        world.cy(4) = cy;

        world.radius(5) = maxRadius;
        cx = 75;
        cy = 75;
        world.cx(5) = cx;
        world.cy(5) = cy;
    end

elseif dim == 3

    NumObstacles = 9;
    % check to make sure that the region is nonempty
    if (endcorner(1) <= origincorner(1)) | (endcorner(2) <= origincorner(2)) | (endcorner(3) <= origincorner(3)),
        disp('Not valid corner specifications!')
        world=[];

        % create world data structure
    else
        world.NumObstacles = NumObstacles;
        world.endcorner = endcorner;
        world.origincorner = origincorner;

        % create NumObstacles
        maxRadius = 10;

        world.radius(1) = maxRadius;
        cx = 50;
        cy = 50;
        cz = 50;
        world.cx(1) = cx;
        world.cy(1) = cy;
        world.cz(1) = cz;

        world.radius(2) = maxRadius;
        cx = 25;
        cy = 25;
        cz = 25;
        world.cx(2) = cx;
        world.cy(2) = cy;
        world.cz(2) = cz;

        world.radius(3) = maxRadius;
        cx = 75;
        cy = 75;
        cz = 75;
        world.cx(3) = cx;
        world.cy(3) = cy;
        world.cz(3) = cz;

        world.radius(4) = maxRadius;
        cx = 25;
        cy = 25;
        cz = 75;
        world.cx(4) = cx;
        world.cy(4) = cy;
        world.cz(4) = cz;

        world.radius(5) = maxRadius;
        cx = 75;
        cy = 75;
        cz = 25;
        world.cx(5) = cx;
        world.cy(5) = cy;
        world.cz(5) = cz;

        world.radius(6) = maxRadius;
        cx = 25;
        cy = 75;
        cz = 25;
        world.cx(6) = cx;
        world.cy(6) = cy;
        world.cz(6) = cz;

        world.radius(7) = maxRadius;
        cx = 75;
        cy = 25;
        cz = 25;
        world.cx(7) = cx;
        world.cy(7) = cy;
        world.cz(7) = cz;

        world.radius(8) = maxRadius;
        cx = 75;
        cy = 25;
        cz = 75;
        world.cx(8) = cx;
        world.cy(8) = cy;
        world.cz(8) = cz;

        world.radius(9) = maxRadius;
        cx = 25;
        cy = 75;
        cz = 75;
        world.cx(9) = cx;
        world.cy(9) = cy;
        world.cz(9) = cz;
    end
end
end

function node=generateRandomNode(world,dim)

if dim ==2;
    % randomly pick configuration
    px       = (world.endcorner(1)-world.origincorner(1))*rand;
    py       = (world.endcorner(2)-world.origincorner(2))*rand;

    chi      = 0;
    cost     = 0;
    node     = [px, py, chi, cost, 0];

    % check collision with obstacle
    while collision(node, node, world,dim),
        px       = (world.endcorner(1)-world.origincorner(1))*rand;
        py       = (world.endcorner(2)-world.origincorner(2))*rand;

        chi      = 0;
        cost     = 0;
        node     = [px, py, chi, cost, 0];
    end

elseif dim ==3;
    % randomly pick configuration
    px       = (world.endcorner(1)-world.origincorner(1))*rand;
    py       = (world.endcorner(2)-world.origincorner(2))*rand;
    pz       = (world.endcorner(3)-world.origincorner(3))*rand;

    chi      = 0;
    cost     = 0;
    node     = [px, py, pz, chi, cost, 0];

    % check collision with obstacle
    while collision(node, node, world,dim),
        px       = (world.endcorner(1)-world.origincorner(1))*rand;
        py       = (world.endcorner(2)-world.origincorner(2))*rand;
        pz       = (world.endcorner(3)-world.origincorner(3))*rand;

        chi      = 0;
        cost     = 0;
        node     = [px, py, pz, chi, cost, 0];
    end

end

end

function collision_flag = collision(node, parent, world,dim)

collision_flag = 0;

for i=1:dim
    if (node(i)>world.endcorner(i))|(node(i)<world.origincorner(i))
        collision_flag = 1;
    end
end

if collision_flag == 0 && dim ==2
    for sigma = 0:.2:1,
        p = sigma*node(1:dim) + (1-sigma)*parent(1:dim);
        % check each obstacle
        for i=1:world.NumObstacles,
            if (norm([p(1);p(2)]-[world.cx(i); world.cy(i)])<=1*world.radius(i)),
                collision_flag = 1;
                break;
            end
        end
    end

elseif collision_flag == 0 && dim ==3
    for sigma = 0:.2:1,
        p = sigma*node(1:dim) + (1-sigma)*parent(1:dim);
        % check each obstacle
        for i=1:world.NumObstacles,
            if (norm([p(1);p(2);p(3)]-[world.cx(i); world.cy(i); world.cz(i)])<=1*world.radius(i)),
                collision_flag = 1;
                break;
            end
        end
    end
end
end

function flag = canEndConnectToTree(tree,end_node,minDist,world,dim)
flag = 0;
% check only last node added to tree since others have been checked
if ( (norm(tree(end,1:dim)-end_node(1:dim))<minDist)...
        & (collision(tree(end,1:dim), end_node(1:dim), world,dim)==0) ),
    flag = 1;
end

end

function [new_tree,flag] = extendTree(tree,end_node,segmentLength,world,flag_chk,dim)
r = 0;
flag1 = 0;
while flag1==0,
    % select a random point
    randomPoint = ones(1,dim);
    for i=1:dim
        randomPoint(1,i) = (world.endcorner(i)-world.origincorner(i))*rand;
    end

    % find leaf on node that is closest to randomPoint
    tmp = tree(:,1:dim)-ones(size(tree,1),1)*randomPoint;
    sqrd_dist = sqr_eucl_dist(tmp,dim);
    [min_dist,idx] = min(sqrd_dist);
    min_parent_idx = idx;

    new_point = (randomPoint-tree(idx,1:dim));
    new_point = tree(idx,1:dim)+(new_point/norm(new_point))*segmentLength;

    min_cost  = cost_np(tree(idx,:),new_point,dim);
    new_node  = [new_point, 0, min_cost, idx];

    if collision(new_node, tree(idx,:), world,dim)==0

        tmp_dist = tree(:,1:dim)-(ones(size(tree,1),1)*new_point);
        dist = sqr_eucl_dist(tmp_dist,dim);
        near_idx = find(dist <= r^2);

        if size(near_idx,1)>1
            size_near = size(near_idx,1);

            for i = 1:size_near
                if collision(new_node, tree(near_idx(i),:), world,dim)==0

                    cost_near = tree(near_idx(i),dim+2)+line_cost(tree(near_idx(i),:),new_point,dim);

                    if  cost_near < min_cost
                        min_cost = cost_near;
                        min_parent_idx = near_idx(i);
                    end

                end
            end
        end

        new_node = [new_point, 0 , min_cost, min_parent_idx];
        new_tree = [tree; new_node];
        new_node_idx = size(new_tree,1);

        if size(near_idx,1)>1
            reduced_idx = near_idx;
            for j = 1:size(reduced_idx,1)
                near_cost = new_tree(reduced_idx(j),dim+2);
                lcost = line_cost(new_tree(reduced_idx(j),:),new_point,dim);
                if near_cost > min_cost + lcost ...
                        && collision(new_tree(reduced_idx(j),:),new_node,world,dim)
                    before = new_tree(reduced_idx(j),dim+3)
                    new_tree(reduced_idx(j),dim+3) = new_node_idx;
                    after = new_tree(reduced_idx(j),dim+3)
                end

            end
        end
        flag1=1;
    end
end

if flag_chk == 0
    % check to see if new node connects directly to end_node
    if ( (norm(new_node(1:dim)-end_node(1:dim))<segmentLength )...
            && (collision(new_node,end_node,world,dim)==0) )
        flag = 1;
        new_tree(end,dim+1)=1;  % mark node as connecting to end.
    else
        flag = 0;
    end

else flag = 1;
end
end

function e_dist = sqr_eucl_dist(array,dim)

sqr_e_dist = zeros(size(array,1),dim);
for i=1:dim

    sqr_e_dist(:,i) = array(:,i).*array(:,i);

end
e_dist = zeros(size(array,1),1);
for i=1:dim

    e_dist = e_dist+sqr_e_dist(:,i);

end

end

%calculate the cost from a node to a point
function [cost] = cost_np(from_node,to_point,dim)

diff = from_node(:,1:dim) - to_point;
eucl_dist = norm(diff);
cost = from_node(:,dim+2) + eucl_dist;

end

%calculate the cost from a node to a node
function [cost] = cost_nn(from_node,to_node,dim)

diff = from_node(:,1:dim) - to_node(:,1:dim);
eucl_dist = norm(diff);
cost = from_node(:,dim+2) + eucl_dist;

end

function [cost] = line_cost(from_node,to_point,dim)
diff = from_node(:,1:dim) - to_point;
cost = norm(diff);
end

function path = findMinimumPath(tree,end_node,dim)

% find nodes that connect to end_node
connectingNodes = [];
for i=1:size(tree,1),
    if tree(i,dim+1)==1,
        connectingNodes = [connectingNodes ; tree(i,:)];
    end
end

% find minimum cost last node
[tmp,idx] = min(connectingNodes(:,dim+2));

% construct lowest cost path
path = [connectingNodes(idx,:); end_node];
parent_node = connectingNodes(idx,dim+3);
while parent_node>1,
    parent_node = tree(parent_node,dim+3);
    path = [tree(parent_node,:); path];
end

end

function plotExpandedTree(world,tree,dim)
ind = size(tree,1);
while ind>0
    branch = [];
    node = tree(ind,:);
    branch = [ branch ; node ];
    parent_node = node(dim+3);
    while parent_node > 1
        cur_parent = parent_node;
        branch = [branch; tree(parent_node,:)];
        parent_node = tree(parent_node,dim+3);
    end
    ind = ind - 1;

    if dim == 2
        X = branch(:,1);
        Y = branch(:,2);

        p = plot(X,Y);
        set(p,'Color','r','LineWidth',0.5,'Marker','.','MarkerEdgeColor','g');
        hold on;

    elseif dim == 3
        X = branch(:,1);
        Y = branch(:,2);
        Z = branch(:,3);

        p = plot3(X,Y,Z);
        set(p,'Color','r','LineWidth',0.5,'Marker','.','MarkerEdgeColor','g');
        hold on;
    end
end
end

function plotWorld(world,path,dim)
% the first element is the north coordinate
% the second element is the south coordinate
if dim ==2

    N = 10;
    th = 0:2*pi/N:2*pi;
    axis([world.origincorner(1),world.endcorner(1),...
        world.origincorner(2), world.endcorner(2)]);
    hold on

    for i=1:world.NumObstacles,
        X = world.radius(i)*sin(th) + world.cx(i);
        Y = world.radius(i)*cos(th) + world.cy(i);
        fill(X,Y,'blue');
    end

    X = path(:,1);
    Y = path(:,2);
    p = plot(X,Y);

elseif dim ==3
    axis([world.origincorner(1),world.endcorner(1),...
        world.origincorner(2), world.endcorner(2),...
        world.origincorner(3), world.endcorner(3)]);
    hold on

    for i=1:world.NumObstacles,
        [X Y Z] = sphere(10);
        X = (X*world.radius(i));
        Y = (Y*world.radius(i));
        Z = (Z*world.radius(i));
        surf(X+world.cx(i),Y+world.cy(i),Z+world.cz(i));
        colormap([0.5 0.2 0.3]);
    end

    X = path(:,1);
    Y = path(:,2);
    Z = path(:,3);
    p = plot3(X,Y,Z);
end
set(p,'Color','black','LineWidth',3)
xlabel('X axis');
ylabel('Y axis');
zlabel('Z axis');
title('RRT Extend Algorithm');
end


function g = diagKernGradient(kern, x, varargin)

% DIAGKERNGRADIENT Gradient of DIAG kernel's parameters.
% FORMAT
% DESC computes the gradient of functions with respect to the
% diagonal noise covariance function
% kernel's parameters. As well as the kernel structure and the
% input positions, the user provides a matrix PARTIAL which gives
% the partial derivatives of the function with respect to the
% relevant elements of the kernel matrix.
% ARG kern : the kernel structure for which the gradients are being
% computed.
% ARG x : the input locations for which the gradients are being
% computed.
% ARG partial : matrix of partial derivatives of the function of
% interest with respect to the kernel matrix. The argument takes
% the form of a square matrix of dimension  numData, where numData is
% the number of rows in X.
% RETURN g : gradients of the function of interest with respect to
% the kernel parameters. The ordering of the vector should match
% that provided by the function kernExtractParam.
%
% FORMAT
% DESC computes the derivatives as above, but input locations are
% now provided in two matrices associated with rows and columns of
% the kernel matrix.
% ARG kern : the kernel structure for which the gradients are being
% computed.
% ARG x1 : the input locations associated with the rows of the
% kernel matrix.
% ARG x2 : the input locations associated with the columns of the
% kernel matrix.
% ARG partial : matrix of partial derivatives of the function of
% interest with respect to the kernel matrix. The matrix should
% have the same number of rows as X1 and the same number of columns
% as X2 has rows.
% RETURN g : gradients of the function of interest with respect to
% the kernel parameters.
%
% SEEALSO diagKernParamInit, kernGradient, diagKernDiagGradient, kernGradX
%
% COPYRIGHT : Neil D. Lawrence, 2011

% KERN

  if nargin < 4
    trans = str2func([kern.trans, 'Transform']);
    g(1, 1) = sum(diag(varargin{end}).*trans(x, 'atox'));
  else
    g = 0;
  end
end


function v = cnn_vecms_sketch(im, net, emodel, scales, mirror, aggregate)
% CNN_VECMS_SKETCH computes a multi-scale D-dimensional CNN sketch vector for an image.
%
%   V = cnn_vecms_sketch(IM, NET, EMODEL, SCALES, MIRROR, AGGREGATE)
%
%   IM        : Input image, or input image path as a string
%   NET       : CNN network to evaluate on image IM
%   EMODEL    : Edge detector model, 0 means do not extract edges because input is already sketch
%   SCALES    : Vector of scales to resize image prior to the descriptor computation (DEFAULT: [1])
%   MIRROR    : Mirror (horizontal flip) of image for the descriptor computation (DEFAULT: 0)
%   AGGREGATE : Aggregate over scales and mirror if 1, otherwise return one vector per image scale and mirror (DEFAULT: 1)
%
%   V         : Multi-scale output, D x 1 if AGGREGATE=1, D x numel(SCALES) x (MIRROR+1) if AGGREGATE=0
%
% Authors: F. Radenovic, G. Tolias, O. Chum. 2018.

    if ~exist('scales'), scales = 1; end
    if ~exist('mirror'), mirror = 0; end
    if ~exist('aggregate'), aggregate = 1; end

    padsize = 30;

    v = [];
    for i = 1:(mirror+1)*numel(scales)
        if i == numel(scales)+1, im = fliplr(im); end;
        imr = imresize(im, scales(mod(i-1,numel(scales))+1));

        if ~isstruct(emodel)
            %% Treated as SKETCH
            if size(imr, 3) > 1; imr = rgb2gray(imr);  end
            % making sure its a binary sketch image
            imr = single(imr); imr = 255 * ((imr - min(imr(:))) ./ (max(imr(:)) - min(imr(:))));
            imr = single(imr < 0.8 * max(imr(:)));
            imr = padarray(imr, [padsize padsize], 0, 'both');
            % unifying sketches:
            % morphological thinning followed by dilation
            imr = single(bwmorph(imr, 'thin', inf));
            imr = single(imdilate(imr,strel('disk',1,0)));
            imr = single(bwmorph(imr, 'thin', inf));
            imr = single(imdilate(imr,strel('disk',2,0)));
            % final sketch2edgemap
            e = imr;
        else
            %% Treated as IMAGE
            if size(imr, 3) == 1; imr = repmat(imr, 1, 1, 3); end
            [edg, ori] = edgesDetect(imr, emodel);
            e = padarray(edg, [padsize padsize], 0, 'both');
        end

        v = [v, cnn_vec_edge(e, net)];
    end

    if aggregate
        v = sum(v, 2);
        v = vecpostproc(v);
    end

function v = cnn_vec_edge(im, net)
% CNN_VEC_EDGE computes a D-dimensional CNN edge vector for a given edge-map.
%
%   V = cnn_vec_edge(IM, NET)
%
%   IM  : Input edge-map
%   NET : CNN network to evaluate on image IM
%
%   V   : D-dimensional vector
%
% Authors: F. Radenovic, G. Tolias, O. Chum. 2018.

    minsize = 67;
    net.mode = 'test';
    descvarname = 'l2descriptor';

    use_gpu = strcmp(net.device, 'gpu');
    if use_gpu
        gpuarrayfun = @(x) gpuArray(x);
        gatherfun = @(x) gather(x);
    else
        gpuarrayfun = @(x) x; % do not convert to gpuArray
        gatherfun = @(x) x; % do not gather
    end

    if isstr(im)
        im = imread(im);
    end

    im = single(im) - mean(net.meta.normalization.averageImage(:));
    if min(size(im, 1), size(im, 2)) < minsize
        im = pad2minsize(im, minsize, 0);
    end

    net.eval({'input', gpuarrayfun(reshape(im, [size(im), 1]))});

    v = gatherfun(squeeze(net.getVar(descvarname).value));


function obj = updateBar3(obj, surfaceIndex)

%-AXIS INDEX-%
axIndex = obj.getAxisIndex(obj.State.Plot(surfaceIndex).AssociatedAxis);

%-CHECK FOR MULTIPLE AXES-%
[xsource, ysource] = findSourceAxis(obj,axIndex);

%-SURFACE DATA STRUCTURE- %
bar_data = get(obj.State.Plot(surfaceIndex).Handle);
figure_data = get(obj.State.Figure.Handle);

%-AXIS STRUCTURE-%
axis_data = get(ancestor(bar_data.Parent,'axes'));

%-GET SCENE-%
eval(['scene = obj.layout.scene' num2str(xsource) ';']);

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

%-associate scene-%
obj.data{surfaceIndex}.scene = sprintf('scene%d', xsource);

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

%-surface type-%
obj.data{surfaceIndex}.type = 'mesh3d';

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

%-FORMAT DATA-%
xdata = bar_data.XData;
ydata = bar_data.YData;
zdata = bar_data.ZData;
cdata = bar_data.CData;

%-parse xedges-%
xedges = xdata(2, 1:2:end);

%-parse yedges-%
yedges = ydata(2:6:end, 2);
yedges = [yedges', mean(diff(yedges(1:2)))];

%-parse values-%
values = [];
for n = 1:6:size(zdata, 1)
    values = [values, diff(zdata(n:n+1, 2))];
end

%-parse offsets-%
offsets = zdata(1:6:end, 2)';

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

%-get the values to use plotly's mesh3D-%
bargap = diff(yedges(1:2)) - diff(ydata(2:3));
[X, Y, Z, I, J, K] = get_plotly_mesh3d(xedges, yedges, values, bargap);

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

%-reformat Z according to offsets-%
m = 1;
lz2 = 0.5*length(Z);

for n = 1:4:lz2
    Z(n:n+3) = Z(n:n+3)+offsets(m);
    Z(n+lz2:n+lz2+3) = Z(n+lz2:n+lz2+3)+offsets(m);
    m = m + 1;
end

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

%-set mesh3d data-%
obj.data{surfaceIndex}.x = X;
obj.data{surfaceIndex}.y = Y;
obj.data{surfaceIndex}.z = Z;
obj.data{surfaceIndex}.i = int16(I-1);
obj.data{surfaceIndex}.j = int16(J-1);
obj.data{surfaceIndex}.k = int16(K-1);

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

%-coloring-%
cmap = figure_data.Colormap;

if isnumeric(bar_data.FaceColor)

    %-paper_bgcolor-%
    col = 255*bar_data.FaceColor;
    col = sprintf('rgb(%f,%f,%f)', col);

else
    switch bar_data.FaceColor

        case 'none'
            col = 'rgba(0,0,0,0)';

        case {'flat','interp'}

            switch bar_data.CDataMapping

                case 'scaled'
                    capCD = max(min(cdata(1,1),axis_data.CLim(2)),axis_data.CLim(1));
                    scalefactor = (capCD - axis_data.CLim(1))/diff(axis_data.CLim);
                    col =  255*(cmap(1+ floor(scalefactor*(length(cmap)-1)),:));
                case 'direct'
                    col =  255*(cmap(cdata(1,1),:));

            end

            col = sprintf('rgb(%f,%f,%f)', col);

        case 'auto'
            col = 'rgb(0,113.985,188.955)';
    end
end

obj.data{surfaceIndex}.color = col;

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

%-some settings-%
obj.data{surfaceIndex}.contour.show = true;
obj.data{surfaceIndex}.contour.width = 6;
obj.data{surfaceIndex}.contour.color='rgb(0,0,0)';
obj.data{surfaceIndex}.flatshading = false;

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

%-lighting settings-%
obj.data{surfaceIndex}.lighting.diffuse = 0.8;
obj.data{surfaceIndex}.lighting.ambient = 0.65;
obj.data{surfaceIndex}.lighting.specular = 1.42;
obj.data{surfaceIndex}.lighting.roughness = 0.52;
obj.data{surfaceIndex}.lighting.fresnel = 0.2;
obj.data{surfaceIndex}.lighting.vertexnormalsepsilon = 1e-12;
obj.data{surfaceIndex}.lighting.facenormalsepsilon = 1e-6;

obj.data{surfaceIndex}.lightposition.x = 0;
obj.data{surfaceIndex}.lightposition.y = 0;
obj.data{surfaceIndex}.lightposition.z = 0;

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

%-surface name-%
obj.data{surfaceIndex}.name = bar_data.DisplayName;

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

%-surface visible-%
obj.data{surfaceIndex}.visible = strcmp(bar_data.Visible,'on');

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

leg = get(bar_data.Annotation);
legInfo = get(leg.LegendInformation);

switch legInfo.IconDisplayStyle
    case 'on'
        showleg = true;
    case 'off'
        showleg = false;
end

obj.data{surfaceIndex}.showlegend = showleg;

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

%-SETTING SCENE-%

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

%-aspect ratio-%
ar = obj.PlotOptions.AspectRatio;

if ~isempty(ar)
    if ischar(ar)
        scene.aspectmode = ar;
    elseif isvector(ar) && length(ar) == 3
        xar = ar(1);
        yar = ar(2);
        zar = ar(3);
    end
else

    %-define as default-%
    xar = max(xedges(:));
    yar = max(yedges(:));
    zar = 0.7*max([xar, yar]);
end

scene.aspectratio.x = xar;
scene.aspectratio.y = yar;
scene.aspectratio.z = zar;

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

%-camera eye-%
ey = obj.PlotOptions.CameraEye;

if ~isempty(ey)
    if isvector(ey) && length(ey) == 3
        scene.camera.eye.x = ey(1);
        scene.camera.eye.y = ey(2);
        scene.camera.eye.z = ey(3);
    end
else

    %-define as default-%
    scene.camera.eye.x = xar + 7;
    scene.camera.eye.y = yar - 2;
    scene.camera.eye.z = zar + 0.5;
end

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

%-axis configuration-%
scene.xaxis.range = axis_data.XLim(end:-1:1);
scene.yaxis.range = axis_data.YLim;
scene.zaxis.range = axis_data.ZLim;

scene.xaxis.tickvals = axis_data.XTick;
scene.xaxis.ticktext = axis_data.XTickLabel;

scene.yaxis.tickvals = axis_data.YTick;
scene.yaxis.ticktext = axis_data.YTickLabel;

scene.zaxis.tickvals = axis_data.ZTick;
scene.zaxis.ticktext = axis_data.ZTickLabel;

scene.xaxis.zeroline = false;
scene.yaxis.zeroline = false;
scene.zaxis.zeroline = false;

scene.xaxis.showline = true;
scene.yaxis.showline = true;
scene.zaxis.showline = true;

scene.xaxis.tickcolor = 'rgba(0,0,0,1)';
scene.yaxis.tickcolor = 'rgba(0,0,0,1)';
scene.zaxis.tickcolor = 'rgba(0,0,0,1)';

scene.xaxis.ticklabelposition = 'outside';
scene.yaxis.ticklabelposition = 'outside';
scene.zaxis.ticklabelposition = 'outside';

scene.xaxis.title = axis_data.XLabel.String;
scene.yaxis.title = axis_data.YLabel.String;
scene.zaxis.title = axis_data.ZLabel.String;

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

%-SET SCENE TO LAYOUT-%
obj.layout = setfield(obj.layout, sprintf('scene%d', xsource), scene);

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

end

function bar_ = bar_data(position3d, size_)
    % position3d - 3-list or array of shape (3,) that represents the point of coords (x, y, 0), where a bar is placed
    % size = a 3-tuple whose elements are used to scale a unit cube to get a paralelipipedic bar
    % returns - an array of shape(8,3) representing the 8 vertices of  a bar at position3d

    if nargin < 2
        size_ = [1, 1, 1];
    end

    bar_ = [...
            0, 0, 0; ...
            1, 0, 0; ...
            1, 1, 0; ...
            0, 1, 0; ...
            0, 0, 1; ...
            1, 0, 1; ...
            1, 1, 1; ...
            0, 1, 1 ...
            ]; % the vertices of the unit cube

    for n =1:size(bar_, 1)
        bar_(n,:) = bar_(n,:) .* size_; % scale the cube to get the vertices of a parallelipipedic bar_
    end

    bar_ = bar_ + position3d; %translate each  bar_ on the directio OP, with P=position3d
end

function [vertices, I, J, K] = triangulate_bar_faces(positions, sizes)
    % positions - array of shape (N, 3) that contains all positions in the plane z=0, where a histogram bar is placed
    % sizes -  array of shape (N,3); each row represents the sizes to scale a unit cube to get a bar
    % returns the array of unique vertices, and the lists i, j, k to be used in instantiating the go.Mesh3d class

    if nargin < 2
        sizes = ones(size(positions,1), 3); %[(1,1,1)]*len(positions)
    else
        sizes;
        % if isinstance(sizes, (list, np.ndarray)) and len(sizes) != len(positions):
        %     raise ValueError('Your positions and sizes lists/arrays do not have the same length')
    end

    c = 1;
    for n = 1:size(positions, 1)
        if sizes(n, 3) ~= 0
            all_bars(:,:,c) = bar_data(positions(n,:), sizes(n,:))';
            c = c+1;
        end
    end

    % all_bars = [bar_data(pos, size)  for pos, size in zip(positions, sizes) if size[2]!=0]
    [r, q, p] = size(all_bars);

    % extract unique vertices from the list of all bar vertices
    all_bars = reshape(all_bars, [r, p*q])';
    [vertices, ~, ixr] = unique(all_bars, 'rows');

    %for each bar, derive the sublists of indices i, j, k assocated to its chosen  triangulation
    I = [];
    J = [];
    K = [];

    for k = 0:p-1
        aux = ixr([1+8*k, 1+8*k+2,1+8*k, 1+8*k+5,1+8*k, 1+8*k+7, 1+8*k+5, 1+8*k+2, 1+8*k+3, 1+8*k+6, 1+8*k+7, 1+8*k+5]);
        I = [ I;  aux(:)];
        aux = ixr([1+8*k+1, 1+8*k+3, 1+8*k+4, 1+8*k+1, 1+8*k+3, 1+8*k+4, 1+8*k+1, 1+8*k+6, 1+8*k+7, 1+8*k+2, 1+8*k+4, 1+8*k+6]);
        J = [ J;  aux(:)];
        aux = ixr([1+8*k+2, 1+8*k, 1+8*k+5, 1+8*k, 1+8*k+7, 1+8*k, 1+8*k+2, 1+8*k+5, 1+8*k+6, 1+8*k+3, 1+8*k+5, 1+8*k+7]);
        K = [ K;  aux(:)];
    end

end

function [X, Y, Z, I, J, K] = get_plotly_mesh3d(xedges, yedges, values, bargap)
    % x, y- array-like of shape (n,), defining the x, and y-ccordinates of data set for which we plot a 3d hist

    xsize = xedges(2)-xedges(1)-bargap;
    ysize = yedges(2)-yedges(1)-bargap;
    [xe, ye]= meshgrid(xedges(1:end-1), yedges(1:end-1));
    ze = zeros(size(xe));

    positions = zeros([size(xe), 3]);
    positions(:,:,1) = xe;
    positions(:,:,2) = ye;
    positions(:,:,3) = ze;

    [m, n, p] = size(positions);
    positions = reshape(positions, [m*n, p]);

    h = values'; h = h(:);
    sizes = [];
    for n = 1:length(h)
        sizes = [sizes; ysize, ysize, h(n)];
    end

    [vertices, I, J, K]  = triangulate_bar_faces(positions, sizes);
    X = vertices(:,1);
    Y = vertices(:,2);
    Z = vertices(:,3);

end


function F = in_fread_eeg(sFile, sfid, iEpoch, SamplesBounds)
% IN_FREAD_EEG:  Read an epoch from a Neuroscan .eeg file (list of epochs).
%
% USAGE:  F = in_fread_eeg(sFile, sfid, iEpoch, SamplesBounds)
%         F = in_fread_eeg(sFile, sfid, iEpoch)

% @=============================================================================
% This function is part of the Brainstorm software:
% https://neuroimage.usc.edu/brainstorm
%
% Copyright (c) University of Southern California & McGill University
% This software is distributed under the terms of the GNU General Public License
% as published by the Free Software Foundation. Further details on the GPLv3
% license can be found at http://www.gnu.org/copyleft/gpl.html.
%
% FOR RESEARCH PURPOSES ONLY. THE SOFTWARE IS PROVIDED "AS IS," AND THE
% UNIVERSITY OF SOUTHERN CALIFORNIA AND ITS COLLABORATORS DO NOT MAKE ANY
% WARRANTY, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, NOR DO THEY ASSUME ANY
% LIABILITY OR RESPONSIBILITY FOR THE USE OF THIS SOFTWARE.
%
% For more information type "brainstorm license" at command prompt.
% =============================================================================@
%
% Author: Francois Tadel, 2009-2011

fileSamples = round(sFile.prop.times .* sFile.prop.sfreq);
% Parse inputs
if (nargin < 4) || isempty(SamplesBounds)
    SamplesBounds = fileSamples;
% Check start and stop samples
elseif (SamplesBounds(1) < fileSamples(1)) || (SamplesBounds(1) > SamplesBounds(2)) || (SamplesBounds(2) > fileSamples(2))
    error('Invalid samples range.');
end

% Get some information on the file
nChannels = sFile.header.epochs(iEpoch).datasize(1);
% Position cursor in file to read this data block
startSample = SamplesBounds(1) - fileSamples(1);
pos = double(sFile.header.epochs(iEpoch).datapos) + startSample * nChannels * double(sFile.header.data.bytes_per_samp);
fseek(sfid, double(pos), 'bof');
% Read [nChannels, nSamples]
F = fread(sfid, [nChannels, SamplesBounds(2) - SamplesBounds(1) + 1], sFile.header.data.dataformat);
% Calibrate data
F = neuroscan_apply_calibration(F, sFile.header);


function U = uCheck(U,TolMesh,optimState,proj)
%UCHECK Remove duplicates, vectors outside bounds or previously evaluated

if nargin < 4 || isempty(proj); proj = 0; end

if proj
    % Project vectors outside bounds on search mesh points closest to bounds
    U = bsxfun(@max, bsxfun(@min, U, optimState.UBsearch), optimState.LBsearch);
else
    idx = any(bsxfun(@gt,U,optimState.UB) | bsxfun(@lt,U,optimState.LB),2);
    U(idx,:) = [];
end

% Remove duplicate vectors
U = unique(U,'rows');

% Remove previously evaluted vectors (within TolMesh)
if ~isempty(U)
    TolMesh = TolMesh/2;
    % TolMesh = exp(0.5*(log(TolMesh) + log(optimState.meshsize)))/2;
    % Convert everything to normalized grid coordinates for comparison
    u1 = round(U./TolMesh);
    U2 = optimState.U(1:optimState.Xmax,:);
    u2 = round(U2./TolMesh);
    [~,idx] = setdiff(u1,u2,'rows');
    U = U(idx,:);
end

% Evaluate non-bound constraints
if ~isempty(optimState.nonbcon)
    X = origunits(U,optimState);    % Convert back to original space
    C = optimState.nonbcon(X);      % Evaluate constraints
    idx = (C <= 0);                 % Keep points that satisfy constraints
    U = U(idx,:);
end

end


function [ objects, nElems ] = buildGroundTruth( objects, threshold_detection, rebuild )
%BUILDGROUNDTRUTH Analyzes the GT and applies a matching on each of the
% object candidate windows.

    nSamples = length(objects);
    nElems = 0;

    for j = 1:nSamples
        nGT = length(objects(j).ground_truth);

        if(rebuild)

            %% Initialize object candidates
            nObjs = length(objects(j).objects);
            for k = 1:nObjs
                objects(j).objects(k).OS = zeros(1, nGT);
                objects(j).objects(k).trueLabel = 'No Object';
                objects(j).objects(k).trueLabelId = [];
            end

            %% For each object
            for k = 1:nGT
                %% Check if any object in objects(j).objects matches
                %  with the ground_truth for assign them the true label!
                GT = objects(j).ground_truth(k);
                GT.height = (GT.BRy - GT.ULy + 1);
                GT.width = (GT.BRx - GT.ULx + 1);
                GT.area = GT.height * GT.width;

                %% Check for each object candidate, if it fits the current true object
                count_candidate = 1;
                for w = objects(j).objects
                    if(~isempty(w.ULx)) % if the list of candidates is not empty
                        % Check area and intersection on current window "w"
                        w.height = (w.BRy - w.ULy + 1);
                        w.width = (w.BRx - w.ULx + 1);
                        w.area = w.height * w.width;

                        % Check intersection
    %                     count_intersect_old = rectint([GT.ULy, GT.ULx, GT.height, GT.width], [w.ULy, w.ULx, w.height, w.width]);
                        x_overlap = max(0, min(GT.BRx,w.BRx) - max(GT.ULx,w.ULx));
                        y_overlap = max(0, min(GT.BRy,w.BRy) - max(GT.ULy,w.ULy));
                        count_intersect = x_overlap * y_overlap;

                        % Calculate overlap score
                        OS = count_intersect / (GT.area + w.area - count_intersect);

                        if(OS >= threshold_detection) % object detected!
                            label = objects(j).ground_truth(k).name;
                            % If OS bigger than previous, then assign this
                            if(max(w.OS) < OS)
                                w.trueLabel = label;
                                w.trueLabelId = k;
                            end
                        end
                        w.OS(k) = OS;

                        % Store w object
                        objects(j).objects(count_candidate).OS = w.OS;
                        objects(j).objects(count_candidate).trueLabel = w.trueLabel;
                        objects(j).objects(count_candidate).trueLabelId = w.trueLabelId;

                        count_candidate = count_candidate + 1;
                    end
                end
                nElems = nElems+count_candidate-1;
            end
        else % Only pick the maximum OS (already calculated) if it is over the given threshold
            count_candidate = 1;
            for w = objects(j).objects
                if(w.OS(w.trueLabelId) < threshold_detection)
                    objects(j).objects(count_candidate).trueLabel = 'No Object';
                    objects(j).objects(count_candidate).trueLabelId = [];
                end
                count_candidate = count_candidate + 1;
            end
            nElems = nElems+count_candidate-1;
        end
    end

end


function [net, state] = DnCNN_train(sigma_min,sigma_max, net, varargin)

%    The function automatically restarts after each training epoch by
%    checkpointing.
%
%    The function supports training on CPU or on one or more GPUs
%    (specify the list of GPU IDs in the `gpus` option).

% Copyright (C) 2014-16 Andrea Vedaldi.
% All rights reserved.
%
% This file is part of the VLFeat library and is made available under
% the terms of the BSD license (see the COPYING file).

%%%-------------------------------------------------------------------------
%%% solvers: SGD(default) and Adam with(default)/without gradientClipping
%%%-------------------------------------------------------------------------

%%% solver: Adam
%%% opts.solver = 'Adam';
opts.beta1   = 0.9;
opts.beta2   = 0.999;
opts.alpha   = 0.01;
opts.epsilon = 1e-8;

%%% solver: SGD
opts.solver = 'SGD';
opts.learningRate = 0.01;
opts.weightDecay  = 0.001;
opts.momentum     = 0.9 ;

%%% GradientClipping
opts.gradientClipping = false;
opts.theta            = 0.005;

%%% specific parameter for Bnorm
opts.bnormLearningRate = 0;

%%%-------------------------------------------------------------------------
%%%  setting for simplenn
%%%-------------------------------------------------------------------------

opts.conserveMemory = true;
opts.mode = 'normal';
opts.cudnn = true ;
opts.backPropDepth = +inf ;
opts.skipForward = false;
opts.numSubBatches = 1;
%%%-------------------------------------------------------------------------
%%%  setting for model
%%%-------------------------------------------------------------------------

opts.batchSize = 128 ;
opts.gpus = [];
opts.numEpochs = 300 ;
opts.modelName   = 'model';
opts.expDir = fullfile('data',opts.modelName) ;
opts.numberData   = 1;
opts.DataDir      = '../../../LDAMP_TensorFlow/TrainingData/traindata_50_128.mat';
opts.ValDataDir          = '../../../LDAMP_TensorFlow/TrainingData/valdata_50_128.mat';

%%%-------------------------------------------------------------------------
%%%  update settings
%%%-------------------------------------------------------------------------

opts = vl_argparse(opts, varargin);
opts.numEpochs = numel(opts.learningRate);

if ~exist(opts.expDir, 'dir'), mkdir(opts.expDir) ; end

%%%-------------------------------------------------------------------------
%%%  Initialization
%%%-------------------------------------------------------------------------

net = vl_simplenn_tidy(net);    %%% fill in some eventually missing values
net.layers{end-1}.precious = 1;
vl_simplenn_display(net, 'batchSize', opts.batchSize) ;

state.getBatch = getBatch ;

%%%-------------------------------------------------------------------------
%%%  Train and Test
%%%-------------------------------------------------------------------------

modelPath = @(ep) fullfile(opts.expDir, sprintf([opts.modelName,'-epoch-%d.mat'], ep));

start = findLastCheckpoint(opts.expDir,opts.modelName) ;
if start >= 1
    fprintf('%s: resuming by loading epoch %d', mfilename, start) ;
    load(modelPath(start), 'net') ;
    net = vl_simplenn_tidy(net) ;
end

%%% load training and validation data

opts.DataPath    = fullfile(opts.DataDir);
TrainData = load(opts.DataPath) ;
opts.train = find(TrainData.set==1);

opts.ValDataPath    = fullfile(opts.ValDataDir);
ValData = load(opts.ValDataPath) ;
opts.test = find(ValData.set==0);

bad_epochs=0;
max_bad_epochs=2;
for epoch = start+1 : opts.numEpochs
    %%% Train for one epoch.

    %Stop training if three epochs produced no improvement in validation
    %error
    if bad_epochs>=max_bad_epochs
        if opts.learningRate(epoch-max_bad_epochs)==.001
            load(modelPath(epoch-max_bad_epochs-1), 'net')%load the last best epoch
            save(modelPath(epoch-1), 'net')%save the just-loaded model as the best, in case it needs to be loaded because errors don't improve
            save(fullfile(opts.expDir, sprintf([opts.modelName,'-best_epoch',num2str(epoch-1)])),'net');
            opts.learningRate(epoch:end)=.0001;
            bad_epochs=0;
        elseif opts.learningRate(epoch-max_bad_epochs)==.0001
            load(fullfile(opts.expDir, sprintf([opts.modelName,'-best_epoch',num2str(epoch-max_bad_epochs-1)])),'net');
            opts.learningRate(epoch:end)=.00001;
            bad_epochs=0;
        else
            break;
        end
    end

    state.epoch = epoch ;
    state.learningRate = opts.learningRate(min(epoch, numel(opts.learningRate)));
    opts.thetaCurrent = opts.theta(min(epoch, numel(opts.theta)));
    if numel(opts.gpus) == 1
        net = vl_simplenn_move(net, 'gpu') ;
    end

    if epoch==start+1
        %Determine Initial Validation Error
        tic
        state.test = opts.test(randperm(numel(opts.test))) ; %%% shuffle
        [net, state, min_val_loss] = process_epoch(sigma_min,sigma_max,net, state, ValData, opts, 'test');
        net.layers{end}.class =[];
        toc
    end

    %Perform Training
    t0=cputime;
    state.train = opts.train(randperm(numel(opts.train))) ; %%% shuffle
    [net, state, ~] = process_epoch(sigma_min,sigma_max,net, state, TrainData, opts, 'train');
    net.layers{end}.class =[];
    time_taken=cputime-t0;

    %Determine Validation Error
    state.test = opts.test(randperm(numel(opts.test))) ; %%% shuffle
    [net, state, loss] = process_epoch(sigma_min,sigma_max,net, state, ValData, opts, 'test');
    net.layers{end}.class =[];

    net = vl_simplenn_move(net, 'cpu');

    %Save model
    save(modelPath(epoch), 'net')

    %Save as best model if validation error is low
    if loss<min_val_loss
        save(fullfile(opts.expDir, sprintf([opts.modelName,'-best_epoch',num2str(epoch)])),'net');
        min_val_loss=loss;
        bad_epochs=0;
    else
        bad_epochs=bad_epochs+1;
    end
end

%%%-------------------------------------------------------------------------
function  [net, state, total_l2_loss] = process_epoch(sigma_min,sigma_max,net, state, Data, opts, mode)
%%%-------------------------------------------------------------------------

if strcmp(mode,'train')

    switch opts.solver

        case 'SGD' %%% solver: SGD
            for i = 1:numel(net.layers)
                if isfield(net.layers{i}, 'weights')
                    for j = 1:numel(net.layers{i}.weights)
                        state.layers{i}.momentum{j} = 0;
                    end
                end
            end

        case 'Adam' %%% solver: Adam
            for i = 1:numel(net.layers)
                if isfield(net.layers{i}, 'weights')
                    for j = 1:numel(net.layers{i}.weights)
                        state.layers{i}.t{j} = 0;
                        state.layers{i}.m{j} = 0;
                        state.layers{i}.v{j} = 0;
                    end
                end
            end

    end

end

subset = state.(mode) ;
num = 0 ;
res = [];
total_l2_loss=0;
for t=1:opts.batchSize:numel(subset)

    for s=1:opts.numSubBatches
        % get this image batch
        batchStart = t + (s-1);
        batchEnd = min(t+opts.batchSize-1, numel(subset)) ;
        batch = subset(batchStart : opts.numSubBatches : batchEnd) ;
        num = num + numel(batch) ;
        if numel(batch) == 0, continue ; end

        [inputs,labels] = state.getBatch(sigma_min,sigma_max,Data, batch) ;
%         truth=inputs-labels;
%         imshow(truth(:,:,1,1),[]);

        if numel(opts.gpus) == 1
            inputs = gpuArray(inputs);
            labels = gpuArray(labels);
        end

        if strcmp(mode, 'train')
            dzdy = single(1);
            evalMode = 'normal';%%% forward and backward (Gradients)
        else
            dzdy = [] ;
            evalMode = 'test';  %%% forward only
%             evalMode = 'normal';  %%% forward and backward (Gradients)%Forces the network not to remove batch normalization.
        end

        net.layers{end}.class = labels ;
        res = vl_simplenn(net, inputs, dzdy, res, ...
            'accumulate', s ~= 1, ...
            'mode', evalMode, ...
            'conserveMemory', opts.conserveMemory, ...
            'backPropDepth', opts.backPropDepth, ...
            'cudnn', opts.cudnn) ;

    end

    if strcmp(mode, 'train')
        [state, net] = params_updates(state, net, res, opts, opts.batchSize) ;
    end

    lossL2 = gather(res(end).x) ;
    %%%--------add your code here------------------------
    if mod(floor(t/opts.batchSize),60)==1%show figure every 20 batches
        k=2;
        label_hat=res(end-1).x;
        label_hat_k=squeeze(label_hat(:,:,1,k));
        label_k=squeeze(labels(:,:,1,k));
        sig_hat_k=squeeze(inputs(:,:,1,k))-label_hat_k;
        sig_k=squeeze(inputs(:,:,1,k))-label_k;
        figure(1);
        subplot(3,2,1);imshow(inputs(:,:,1,k),[]);title('Noisy Input');
        subplot(3,2,3);imshow(label_hat_k,[]);title('Noise Estimate');
        subplot(3,2,4);imshow(label_k,[]);title('Noise Truth');
        subplot(3,2,5);imshow(sig_hat_k,[]);title('Signal Estimate');
        subplot(3,2,6);imshow(sig_k,[]);title('Signal Truth');
        Signals=inputs-labels;
        Signal_Estimates=inputs-res(end-1).x;
        MyLossL2=vl_nnloss(Signals,Signal_Estimates);%confirm this value is the same as lossL2
    end

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

    fprintf('%s: epoch %02d dataset %02d: %3d/%3d:', mode, state.epoch, mod(state.epoch,opts.numberData), ...
        fix((t-1)/opts.batchSize)+1, ceil(numel(subset)/opts.batchSize)) ;
    fprintf('error: %f \n', lossL2) ;
    total_l2_loss=total_l2_loss+lossL2;
end

%%%-------------------------------------------------------------------------
function [state, net] = params_updates(state, net, res, opts, batchSize)
%%%-------------------------------------------------------------------------

switch opts.solver

    case 'SGD' %%% solver: SGD

        for l=numel(net.layers):-1:1
            for j=1:numel(res(l).dzdw)
                if j == 3 && strcmp(net.layers{l}.type, 'bnorm')
                    %%% special case for learning bnorm moments
                    thisLR = net.layers{l}.learningRate(j) - opts.bnormLearningRate;
                    net.layers{l}.weights{j} = vl_taccum(...
                        1 - thisLR, ...
                        net.layers{l}.weights{j}, ...
                        thisLR / batchSize, ...
                        res(l).dzdw{j}) ;

                else
                    thisDecay = opts.weightDecay * net.layers{l}.weightDecay(j);
                    thisLR = state.learningRate * net.layers{l}.learningRate(j);

                    if opts.gradientClipping
                        theta = opts.thetaCurrent/thisLR;
                        state.layers{l}.momentum{j} = opts.momentum * state.layers{l}.momentum{j} ...
                            - thisDecay * net.layers{l}.weights{j} ...
                            - (1 / batchSize) * gradientClipping(res(l).dzdw{j},theta) ;
                        net.layers{l}.weights{j} = net.layers{l}.weights{j} + ...
                            thisLR * state.layers{l}.momentum{j} ;
                    else
                        state.layers{l}.momentum{j} = opts.momentum * state.layers{l}.momentum{j} ...
                            - thisDecay * net.layers{l}.weights{j} ...
                            - (1 / batchSize) * res(l).dzdw{j} ;
                        net.layers{l}.weights{j} = net.layers{l}.weights{j} + ...
                            thisLR * state.layers{l}.momentum{j} ;
                    end
                end
            end
        end

    case 'Adam'  %%% solver: Adam

        for l=numel(net.layers):-1:1
            for j=1:numel(res(l).dzdw)

                if j == 3 && strcmp(net.layers{l}.type, 'bnorm')

                    %%% special case for learning bnorm moments
                    thisLR = net.layers{l}.learningRate(j) - opts.bnormLearningRate;
                    net.layers{l}.weights{j} = vl_taccum(...
                        1 - thisLR, ...
                        net.layers{l}.weights{j}, ...
                        thisLR / batchSize, ...
                        res(l).dzdw{j}) ;
                else
                    thisLR = state.learningRate * net.layers{l}.learningRate(j);
                    state.layers{l}.t{j} = state.layers{l}.t{j} + 1;
                    t = state.layers{l}.t{j};
                    alpha = thisLR;
                    lr = alpha * sqrt(1 - opts.beta2^t) / (1 - opts.beta1^t);

                    state.layers{l}.m{j} = state.layers{l}.m{j} + (1 - opts.beta1) .* (res(l).dzdw{j} - state.layers{l}.m{j});
                    state.layers{l}.v{j} = state.layers{l}.v{j} + (1 - opts.beta2) .* (res(l).dzdw{j} .* res(l).dzdw{j} - state.layers{l}.v{j});

                    if opts.gradientClipping
                        theta = opts.thetaCurrent/lr;
                        net.layers{l}.weights{j} = net.layers{l}.weights{j} - lr * gradientClipping(state.layers{l}.m{j} ./ (sqrt(state.layers{l}.v{j}) + opts.epsilon),theta);
                    else
                        net.layers{l}.weights{j} = net.layers{l}.weights{j} - lr * state.layers{l}.m{j} ./ (sqrt(state.layers{l}.v{j}) + opts.epsilon);
                    end

                    % net.layers{l}.weights{j} = weightClipping(net.layers{l}.weights{j},2); % gradually clip the weights

                end
            end
        end
end

%%%-------------------------------------------------------------------------
function epoch = findLastCheckpoint(modelDir,modelName)
%%%-------------------------------------------------------------------------
list = dir(fullfile(modelDir, [modelName,'-epoch-*.mat'])) ;
tokens = regexp({list.name}, [modelName,'-epoch-([\d]+).mat'], 'tokens') ;
epoch = cellfun(@(x) sscanf(x{1}{1}, '%d'), tokens) ;
epoch = max([epoch 0]) ;

%%%-------------------------------------------------------------------------
function A = gradientClipping(A, theta)
%%%-------------------------------------------------------------------------
A(A>theta)  = theta;
A(A<-theta) = -theta;

%%%-------------------------------------------------------------------------
function A = weightClipping(A, theta)
%%%-------------------------------------------------------------------------
A(A>theta)  = A(A>theta) -0.0005;
A(A<-theta) = A(A<-theta)+0.0005;

%%%-------------------------------------------------------------------------
function fn = getBatch
%%%-------------------------------------------------------------------------
fn = @(sigma_min,sigma_max,x,y) getSimpleNNBatch(sigma_min,sigma_max,x,y);

%%%-------------------------------------------------------------------------
function [inputs,labels] = getSimpleNNBatch(sigma_min,sigma_max,Data, batch)
%%%-------------------------------------------------------------------------
inputs = Data.inputs(:,:,:,batch);
rng('shuffle');
mode = randperm(8);
inputs = data_augmentation(inputs, mode(1));
sigma_vec=sigma_min+rand(numel(batch),1)*(sigma_max-sigma_min);%amount of random noise to apply to each image
sigma_array=ones(size(inputs));
for i=1:numel(batch)
    sigma_array(:,:,1,i)=sigma_vec(i);
end
labels  = sigma_array/255.*randn(size(inputs),'single');
inputs = inputs + labels;

function image = data_augmentation(image, mode)

if mode == 1
    return;
end

if mode == 2 % flipped
    image = flipud(image);
    return;
end

if mode == 3 % rotation 90
    image = rot90(image,1);
    return;
end

if mode == 4 % rotation 90 & flipped
    image = rot90(image,1);
    image = flipud(image);
    return;
end

if mode == 5 % rotation 180
    image = rot90(image,2);
    return;
end

if mode == 6 % rotation 180 & flipped
    image = rot90(image,2);
    image = flipud(image);
    return;
end

if mode == 7 % rotation 270
    image = rot90(image,3);
    return;
end

if mode == 8 % rotation 270 & flipped
    image = rot90(image,3);
    image = flipud(image);
    return;
end


function [EEG]= selectmodel(EEG, model, type)
startpoints = [];
endpoints = [];
% if type ~= 1
%     newEEG = EEG;
% end

for i = 1:EEG.nbchan
    EEG.icaweights(i,:) = EEG.etc.amica.W(i,:,model);
    EEG.icasphere(i,:)  = EEG.etc.amica.S(i,:);
    EEG.icawinv(i,:)    = EEG.etc.amica.A(i,:,model);
end

disp('Calculating...')

if type == 1  % reject the data where the model is not active
    if EEG.trials > 1
        trials2keep = [];
        for i = 1:EEG.trials
            [dummy in] = max(sum(EEG.etc.amica.v_smooth(:,:,i),2));
            if model == in
                trials2keep = [trials2keep i];
            end
        end

        EEG = pop_select(EEG,'trial',trials2keep);

    else
        nepochs = 0; %number of epochs that will be excluded
        rejecting = 0;
        startpoints = [];
        endpoints = [];
        for i = 1:size(EEG.data,2)

            [y in] = max(EEG.etc.amica.v_smooth(:,i));
            if in ~= model
                if ~rejecting
                    nepochs = nepochs + 1;
                    startpoints(nepochs) = i;
                    rejecting = 1;
                end
            else
                if rejecting == 1
                    endpoints(nepochs) = i-1;
                    rejecting = 0;
                end

            end

        end
        if rejecting == 1
            endpoints(end + 1) = size(EEG.data,2);
        end

        if nepochs == 1 && endpoints == i && startpoints == 1
            error('Selected model is never active. Original data will be preserved.');
            startpoints = [];
            endpoints = [];

            return;
        end
        if nepochs == 0
            disp('Model is always active. Original data will be preserved, ICA weights for the model is loaded.');

            return;
        end

        %-------Rejecting the data where model is not active------------------
        temp_start = startpoints;
        temp_end = endpoints;
        EEG = pop_select(EEG,'nopoint',[startpoints' endpoints']);
%         for i = 1:nepochs
%             newEEG = pop_ozselect(newEEG,'nopoint',[temp_start(i) temp_end(i)]);
%             shift = temp_end(i)-temp_start(i)+1;
%             temp_start = temp_start - shift;
%             temp_end = temp_end - shift;
%         end
        %---------------------------------------------------------------------
    end
    EEG.setname = [EEG.setname ' - Model ' num2str(model)];

else
    if type == 2
        %weight the data w.r.t to the probability of the model chosen
        if isequal(EEG.etc.amica.v_smooth(model,:,:),zeros(size(EEG.etc.amica.v_smooth(model,:,:))))
           disp('Selected model has probability of 0 through the data, old dataset is preserved') ;
        else
            if EEG.trials > 1
                for i = 1:EEG.trials
                    for j = 1:size(EEG.data,2)
                        EEG.data(:,j,i) = EEG.data(:,j,i)*EEG.etc.amica.v_smooth(model,j,i);

                    end
                end

            else
                for i = 1:size(EEG.data,2)
                    EEG.data(:,i) = EEG.data(:,i)*EEG.etc.amica.v_smooth(model,i);
                end

            end
            EEG.etc.amica.weighted = 1;
        end
        EEG.setname = [EEG.setname ' - Model ' num2str(model) ' Weighted'];
    else
        if type == 3

        end

    end

end


function diagnostic = callstrul(F,h,options)

F_new = [];

for i = 1:length(F)
    if ~is(F(i),'lmi')
        F_new = F_new + F(i);
    else
        X = sdpvar(F(i));
        [l,m,r]=factors(X);
        if isempty(m)
            F_new = F_new + F(i);
        else
            [L1,R1,A1,M1,negated_cont1,negated_disc1,epsilon1,delta1,numpos1,xindicies,Pindicies] = preprocess_constraint(X);
            F_new = F_new + assignschur(F(i),'HKM_schur_LR_structure',L1,R1,A1,M1,negated_cont1,negated_disc1,epsilon1,delta1,numpos1,xindicies,Pindicies);
        end
    end
end

if nargin < 2
    % Equalities are converted internally in SDPT3 to double-sided
    % inequalities. This messes up our Schur compiler, hence we do it
    % already outside SDPT3
    options = sdpsettings('solver','sdpt3','removeequalities',-1);
else
    options.solver = 'sdpt3';
    options.removeequalities = -1;
end
diagnostic = solvesdp(F_new,h,options);


classdef matRad_ConstantRBEProjection < matRad_BackProjection
% matRad_BackProjection for optimization based on RBExDose
%
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Copyright 2019 the matRad development team.
%
% This file is part of the matRad project. It is subject to the license
% terms in the LICENSE file found in the top-level directory of this
% distribution and at https://github.com/e0404/matRad/LICENSES.txt. No part
% of the matRad project, including this file, may be copied, modified,
% propagated, or distributed except according to the terms contained in the
% LICENSE file.
%
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    methods
        function obj = matRad_ConstantRBEProjection()
        end
    end

    methods
        function RBExD = computeSingleScenario(~,dij,scen,w)
            if ~isempty(dij.physicalDose{scen})
                RBExD = dij.physicalDose{scen} * (dij.RBE * w);
            else
                RBExD = [];
                matRad_cfg = MatRad_Config.instance();
                matRad_cfg.dispWarning('Empty scenario in optimization detected! This should not happen...\n');
            end
        end

        function wGrad = projectSingleScenarioGradient(~,dij,doseGrad,scen,~)
            if ~isempty(dij.physicalDose{scen})
                wGrad = ((dij.RBE * doseGrad{scen})' * dij.physicalDose{scen})';
            else
                wGrad = [];
                matRad_cfg = MatRad_Config.instance();
                matRad_cfg.dispWarning('Empty scenario in optimization detected! This should not happen...\n');
            end
        end
    end

end


%%%%%%%%%%%%%%%%%%%%%%%
% Compute features for a set of video files from datasets
%
close all;
clear;
warning('off','all');
addpath(genpath('./lib/iqm/BRISQUE_release'));

%==================================================
% parameters
algo_name = 'BRISQUE_feat_sel';
data_name = 'KONVID_1K';

%% *You need to customize here*
if strcmp(data_name, 'TEST_VIDEOS')
    data_path = 'videos'; % dataset video path
elseif strcmp(data_name, 'KONVID_1K')
    data_path = '/media/ztu/Seagate-ztu-ugc/KONVID_1K/KoNViD_1k_videos';
elseif strcmp(data_name, 'LIVE_VQC')
    data_path = '/media/ztu/Seagate-ztu-ugc/LIVE_VQC/VideoDatabase';
elseif strcmp(data_name, 'YOUTUBE_UGC')
    data_path = '/media/ztu/Seagate-ztu-ugc/YT_UGC/original_videos';
elseif strcmp(data_name, 'LIVE_VQA')
    data_path = '/media/ztu/Seagate-ztu/LIVE_VQA/videos';
end

video_tmp = 'video_tmp';
if ~exist(video_tmp, 'dir'), mkdir(video_tmp); end
feat_path = '../features';
filelist_csv = fullfile(feat_path, [data_name,'_metadata.csv']);
filelist = readtable(filelist_csv);
num_videos = size(filelist,1);
out_path = './feat_sel_mats';
if ~exist(out_path, 'dir'), mkdir(out_path); end
out_feat_name = fullfile(out_path, [data_name,'_',algo_name,'_feats.mat']);
out_feat_frames_name = fullfile(out_path, [data_name,'_',algo_name,'_frames_feats.mat']);
feats_mat = [];
feats_mat_frames = cell( num_videos, 1 );

%===================================================

tic
% parallel
for i = 1:num_videos
    % get video full path and decoded video name
	if strcmp(data_name, 'TEST_VIDEOS')
	    video_name = fullfile(data_path,  filelist.video_name{i});
	    yuv_name = fullfile(video_tmp, [filelist.video_name{i}, '.yuv']);
	elseif strcmp(data_name, 'KONVID_1K')
	    video_name = fullfile(data_path,  [num2str(filelist.flickr_id(i)),'.mp4']);
	    yuv_name = fullfile(video_tmp, [num2str(filelist.flickr_id(i)), '.yuv']);
	elseif strcmp(data_name, 'LIVE_VQC')
	    video_name = fullfile(data_path, filelist.File{i});
	    yuv_name = fullfile(video_tmp, [filelist.File{i}, '.yuv']);
	elseif strcmp(data_name, 'YOUTUBE_UGC')
	    video_name = fullfile(data_path, filelist.category{i},...
		[num2str(filelist.resolution(i)),'P'],[filelist.vid{i},'.mkv']);
	    yuv_name = fullfile(video_tmp, [filelist.vid{i}, '.yuv']);
	elseif strcmp(data_name, 'LIVE_VQA')
	    strs = strsplit(filelist.filename{i}, '_');
	    video_name = fullfile(data_path, [strs{1}(1:2), '_Folder'], filelist.filename{i});
	    yuv_name = video_name;
	end
	fprintf('\n---\nComputing features for %d-th sequence: %s\n', i, video_name);
    % decode video and store in video_tmp dir
    if ~strcmp(video_name, yuv_name)
    cmd = ['ffmpeg -loglevel error -y -i ', video_name, ' -pix_fmt yuv420p -vsync 0 ', yuv_name];
    system(cmd);
    end

    % get video meta data
    width = filelist.width(i);
    height = filelist.height(i);
    framerate = round(filelist.framerate(i));
    nb_frames = filelist.nb_frames(i);

    % read YUV frame (credit: Dae Yeol Lee)
    fp_input = fopen(yuv_name, 'r');
    uv_width = width/2;
    uv_height = height/2;
    feats_frames = [];

    tic
    % calculate every frame
    for fr = 1:2:nb_frames-5

        try
            %% Start a file pointer
            fseek(fp_input,(fr-1)*1.5*width*height, 'bof'); % Frame read for 8 bit
            %% Y component
            %1) read y stream
            y_stream = fread(fp_input, width * height, 'uchar'); % for 8 bit
            % 2) reshape into a plane
            y_plane= reshape(y_stream, width, height).';
%             imshow(y_plane,[]);
            feats_frames(end+1,:) = brisque_feature(y_plane);
        catch
            continue
        end
    end
    fclose(fp_input);
    delete(yuv_name)
    feats_mat_frames{i} = feats_frames;

    % compute brisque mean and consistency within each 1-sec chunk!!
    cons_feats = [];
    mean_feats = [];
    n_temp_vecs = length(feats_frames(:,1));
    half_blk_len = floor(framerate/2);

    fprintf('Pooling mean and consistency features\n');

    for j = 1:half_blk_len:n_temp_vecs - half_blk_len

        j_start = j;
        j_end = j + half_blk_len;

        % compute consistency features
        cons_feats = [cons_feats; std(feats_frames(j_start:j_end, :))];
        mean_feats = [mean_feats; mean(feats_frames(j_start:j_end, :))];
    end

    feats = [mean(mean_feats) ...
             mean(cons_feats) ];

    feats_mat(i,:) = feats;
    toc
end
toc
save(out_feat_name, 'feats_mat');
save(out_feat_frames_name, 'feats_mat_frames');


function y=rmDecimate(x,r)
% rmDecimate - decimate the signal by factor (r) along first dimension.
%
%  y=rmDecimate(x,r);
%
% 2007/01 SOD: wrapper for matlab's decimate

% input check
if ~exist('x','var') || isempty(x),
    disp('Need x');
    return;
end

% no decimation if: r is not given, empty or smaller than 2.
if ~exist('r','var') || isempty(r) || r<2,
    y=x;
    return;
end

% get size of x
[s1, s2] = size(x);

% sometimes we input single precision
convert_back_to_single = false;
if isa(x,'single')
    convert_back_to_single = true;
    x=double(x);
end

% filter along first dimension, i should really vectorize this....
y = zeros(ceil(s1./r),s2);
for ii=1:s2
    % The function decimate appears to be gone from later versions of
    % Matlab.  Check what's going on here ...
    y(:,ii) = decimate(x(:,ii),r);
end

if convert_back_to_single,
    y = single(y);
end

return


function [CL] = visutil_getCommonRange(erp,ivals,varargin)
%VISUTIL_GETMAXRANGE - get maximum CLim range for several scalp plots of
%data in erp defined by ivals
%
%Synopsis:
% CLIM= visutil_getMaxRange(erp, ivals)
%
%Input:
% erp: eeg data
% ERP: struct of epoched EEG data.
% IVAL: time intervals for which scalp topography are to be plotted.

% irene, 10/2015
props= {
        'Class',     [],   '';
        'CLim',                 'sym',             'CHAR|DOUBLE[2]'};

if nargin==0,
  H= opt_catProps(props, props_scalpOutline); return
end

opt= opt_proplistToStruct(varargin{:});
[opt, isdefault]= opt_setDefaults(opt, props);
nIvals=size(ivals,1);

for ii= 1:nIvals,
    if any(isnan(ivals(ii,:))),
      continue;
    end
    eee= erp;
    if nargin>=2 && ~isempty(ivals(ii,:)) && ~sum(any(isnan(ivals))),
         eee= proc_selectIval(eee, ivals(ii,:), 'IvalPolicy','minimal');
    end
    if ~isempty(opt.Class),
         eee= proc_selectClasses(eee, opt.Class);
    end
    if max(sum(eee.y,2))>1,
        eee= proc_average(eee);
    end
    eee.x= mean(eee.x,1);
    min_max(ii,1)=min(min(eee.x));
    min_max(ii,2)=max(max(eee.x));
end

if isequal(opt.CLim, 'sym'),
  zgMax= max(abs(min_max(:,2)));
  CL= [-zgMax zgMax];
elseif isequal(opt.CLim, 'range'),
  CL= [min(min_max(:,1)) max(min_max(:,2))];
elseif isequal(opt.CLim, '0tomax'),
  CL= [0.0001*diff([min(min_max(:,1)) max(min_max(:,2))]) max(min_max(:,2))];
elseif isequal(opt.CLim, 'minto0'),
  CL= [min(min_max(:,1)) 0.0001*diff([min(min_max(:,1)) max(min_max(:,2))])];
elseif isequal(opt.CLim, 'zerotomax'),
  CL= [0 max(min_max(:,2))];
elseif isequal(opt.CLim, 'mintozero'),
  CL= [min(min_max(:,1)) 0];
end
if diff(CL)==0, CL(2)= CL(2)+eps; end
end


classdef Reshape < dagnn.ElementWise
  properties
    shape = {} ;
  end

  properties (Transient)
    inputSizes = {}
  end

  methods
    function outputs = forward(obj, inputs, params)
      outputs{1} = vl_nnreshape(inputs{1}, obj.shape) ;
      obj.inputSizes = cellfun(@size, inputs, 'UniformOutput', false) ;
    end

    function [derInputs, derParams] = backward(obj, inputs, params, derOutputs)
      derInputs{1} = vl_nnreshape(inputs{1}, obj.shape, derOutputs{1}) ;
      derParams = {} ;
    end

    function outputSizes = getOutputSizes(obj, inputSizes)
      outputSizes{1} = [0,0,0,0] ;
    end

    function rfs = getReceptiveFields(obj)
    end

    function load(obj, varargin)
      s = dagnn.Layer.argsToStruct(varargin{:}) ;
      load@dagnn.Layer(obj, s) ;
    end

    function obj = Reshape(varargin)
      obj.load(varargin{:}) ;
    end
  end
end


function [ y, next ] = p38_equil ( neqn, next )

%*****************************************************************************80
%
%% P38_EQUIL returns equilibrium solutions of problem p38.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    17 February 2013
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer NEQN, the number of equations.
%
%    Input, integer NEXT, the index of the previous
%    equilibrium, which should be 0 on first call.
%
%    Output, real Y(NEQN), the "next" equilibrium solution, if any.
%
%    Output, integer NEXT, the index of the current equilibrium,
%    or 0 if there are no more.
%
  if ( next == 0 )
    next = 1;
    y(1) = 0.0;
  elseif ( next == 1 )
    next = 2;
    y(1) = 1.0;
  else
    next = 0;
    y = [];
  end

  return
end


function view=createParamMapFromAnatomy(view)
% anatomyParamMap=createParamMapFromAnatomy(view)
%
% Creates a gray parameter map from the gray matter values in each gray node
% Only works in gray mode
% Author ARW 050805: Wrote it.
% Example : VOLUME{1}=createParamMapFromAnatomy(VOLUME{1})
%
%
mrGlobals;

if ~strcmp(view.viewType,'Gray')
    error('This function requires a Gray view');
end

%
% if (ieNotDefined('view.anat'))
%     error('Anat must be loaded');
% end

% Find out the size of the 'anat' field in the view.
anatSize=size(view.anat);

% Check here in case anat is not loaded...

% Now turn the coords into indices
grayMatterIndices=sub2ind(anatSize,view.coords(1,:),view.coords(2,:),view.coords(3,:));

map=view.anat(grayMatterIndices);
nScans=length(dataTYPES(view.curDataType).scanParams);
for t=1:nScans
    view.map{t}=[];
end

view.map{getCurScan(view)}=map;


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

%Empty workspace and close figures
close all;
clear;

%% Define parameters
M_max = 15;          % number of antenna columns/rows
d_H = 1/2;          % horizontal antenna spacing
h_BS = 25;          % height of the antenna array
h_UE = 1.5;         % height of the UE
CellRadius = 500;   % cell radius
K = 500;            % number of UEs
fc = 2.6e9;         % center frequency
bw = 20e6;          % bandwidth
N = 1024;           % number of subcarriers

% Compute derived parameters
h = h_BS - h_UE;    % effective height
d_V = 1/2;          % vertical antenna spacing
d = d_V;

%Simulate new channel reponses or load existing results (the latter is the
%preset)
simulate = false;

%% Simulate channels
if (simulate)
    % Draw random positions
    A = rand(1,K)*CellRadius^2;
    B = rand(1,K)*pi*2/3 - pi/3;
    POS = repmat(sqrt(A)',[1,2]).* [cos(B); sin(B)]'; %UE positions uniformly distributed on a disc of radius R

    % Create a new layout
    s = simulation_parameters; % Create object with general parameters
    s.center_frequency = fc;
    s.sample_density = 1;
    s.use_absolute_delays = 1;

    l = layout(s);  % Create new layout from general parameters
    l.no_rx = K;  % Generate KUEs
    l.rx_array.generate('omni'); % use omnidirectional antennas at the UEs

    l.randomize_rx_positions(CellRadius, h_UE, h_UE, 1); % randomly distribute UEs within a disc of radius R and height 1.5m
    for k=1:K
        l.rx_position(:,k) = [POS(k,1); POS(k,2);  h_UE]; % use the same positions as for the other simulations
    end

    for i=1:l.no_rx % for each receiver
        l.track(i).generate('linear',0,0) % define a linear track consiting of only one position
        l.track(i).scenario = '3GPP_3D_UMa_LOS'; % select the Urban Macrocell NLOS scenario for the link
    end

    % Simulate channel for planar array
    l.tx_array.generate('3gpp-3d', 1, M_max, M_max, fc, 1, 0, d);
    [h_channel, h_parset, h_cb] = l.get_channels();
    h_freq = h_channel.fr(bw,N);
    H_plan = zeros(K,M_max^2, N);
    for k=1:K
        H_plan(k,:,:) = squeeze(h_freq{k});
    end

    % Simulate channel for horizontal array
    l.tx_array.generate('3gpp-3d', 1, 1, M_max^2, fc, 1, 0, d);
    [h_channel, h_parset, h_cb] = l.get_channels();
    h_freq = h_channel.fr(bw,N);
    H_hori = zeros(K,M_max^2, N);
    for k=1:K
        H_hori(k,:,:) = squeeze(h_freq{k});
    end

    % Simulate channel for vertical array
    l.tx_array.generate('3gpp-3d', 1, M_max^2, 1, fc, 1, 0, d);
    [h_channel, h_parset, h_cb] = l.get_channels();
    h_freq = h_channel.fr(bw,N);
    H_vert = zeros(K,M_max^2, N);
    for k=1:K
        H_vert(k,:,:) = squeeze(h_freq{k});
    end
end

%% Compute channel orthogonality
if (~simulate)
    load('section7_orthogonality_3GPP.mat')
else

    IT = 100000;
    COR_3GPP_PLAN = zeros(1,M_max);
    COR_3GPP_HORI = zeros(1,M_max);
    COR_3GPP_VERT = zeros(1,M_max);

    for it=1:IT

        %Output simulation progress
        disp([num2str(it) ' iterations out of ' num2str(IT)]);

        % Draw random position indices
        posInd = randperm(K,2);

        % For all antenna size
        for m = 1:M_max
            M_H = m;
            M_V = m;
            M = M_H*M_V;
            indices = repmat((0:M_H-1)*M_max + 1, [M_V,1]) + repmat((0:M_V-1)', [1,M_H]);
            indices = indices(:);
            for n=1:N
                % Planar array
                h1 = H_plan(posInd(1),indices,n);
                h2 = H_plan(posInd(2),indices,n);
                COR_3GPP_PLAN(m) = abs(h1*h2')^2 / (norm(h1)^2*norm(h2)^2)/IT/N + COR_3GPP_PLAN(m);

                % Horizontal array
                h1 = H_hori(posInd(1),1:m^2,n);
                h2 = H_hori(posInd(2),1:m^2,n);
                COR_3GPP_HORI(m) = abs(h1*h2')^2 / (norm(h1)^2*norm(h2)^2)/IT/N + COR_3GPP_HORI(m);

                % Vertical array
                h1 = H_vert(posInd(1),1:m^2,n);
                h2 = H_vert(posInd(2),1:m^2,n);
                COR_3GPP_VERT(m) = abs(h1*h2')^2 / (norm(h1)^2*norm(h2)^2)/IT/N + COR_3GPP_VERT(m);
            end
        end
    end
end

%% Load channel measurements
hor_out=load('section7_measurement_horizontal.mat');
vert_out=load('section7_measurement_vertical.mat');
planar_square = load('section7_measurement_planar.mat');

x_measured=(1:8).^2;

%Compute average UE correlation
COR_MEAS_HORI = mean(hor_out.crossco).^2;
COR_MEAS_PLAN = mean(planar_square.crossco).^2;
COR_MEAS_VERT = mean(vert_out.crossco).^2;

%% Plot the simulation results
figure;
hold on; box on;

xvals = (1:M_max).^2;

plot(xvals, COR_3GPP_VERT, 'LineWidth', 1, 'Color', 'k', 'LineStyle', '-', 'Marker', 'x');
plot(x_measured, COR_MEAS_VERT(x_measured), 'LineWidth', 1, 'Color', 'k', 'LineStyle', '--', 'Marker', 'x');

plot(xvals, COR_3GPP_PLAN, 'LineWidth', 1, 'Color', 'b', 'LineStyle', '-', 'Marker', 'o');
plot(x_measured, COR_MEAS_PLAN, 'LineWidth', 1, 'Color', 'b', 'LineStyle', '--', 'Marker', 'o');

plot(x_measured, COR_MEAS_HORI(x_measured), 'LineWidth', 1, 'Color', 'r', 'LineStyle', '--','Marker', 'square');
plot(xvals, COR_3GPP_HORI, 'LineWidth', 1, 'Color', 'r', 'LineStyle', '-','Marker', 'square');

COR_IID = 1./xvals;
plot(xvals, COR_IID, 'LineWidth', 1, 'Color', 'k', 'LineStyle', '-.');

legend({'3GPP Vertical', 'Meas. Vertical', '3GPP Planar', 'Meas. Planar', 'Meas. Horizontal', '3GPP Horizontal', 'i.i.d.'}, 'location', 'southwest');
set(gca, 'XScale', 'log', 'YScale', 'log');
xlabel('Number of antennas (M)');
ylabel('Average UE correlation');
set(gca,'xtick',[1,4,9,16,25,36,49,64,121,225]);
xlim([1,M_max^2]);
ylim([COR_IID(end), 1]);


function chosenROI = chooseROIwithMouseMontage(view)
%
% chosenROI = chooseROIwithMouseMontage(view)
%
% Use mouse click to pick an ROI.  The mouse click must be within
% a small fraction of a pixel of one of the ROIs.
%
% djh, 1/10/98
% ras, updated for montage view, 09/04

% First put up some instructions
disp('Click on desired ROI to choose it.');

[y,x,b] = ginput(1);
newCoords = montage2Coords(view, [y x]');
x = newCoords(1);
y = newCoords(2);
z = newCoords(3);

chosenROI=0;
for r=1:length(view.ROIs)
    % Check if clicked on one of the coords.
    coords = view.ROIs(r).coords;
    % Get min distance between selected pixel and ROI
    if ~isempty(coords)
        xdiff = coords(1,:)-x;
        ydiff = coords(2,:)-y;
        zdiff = coords(3,:)-z;
        diff = xdiff.^2 + ydiff.^2 + zdiff.^2;
        if find (diff < 1e-2)
            chosenROI=r;
        end
    end
end

if chosenROI
    disp(['You have chosen: ',view.ROIs(chosenROI).name]);
else
    myErrorDlg('You must click ON an ROI to choose it.');
end

return


function outputImage = cumsum(this, applicationDimension)
% Computes cumulative sum along specified dimension, uses Matlab cumsum function
%
%
%   Y = MrImage()
%   Y.cumsum(applicationDimension)
%
% This is a method of class MrImage.
%
% IN
%   applicationDimension    image dimension along which operation is
%                           performed (e.g. 4 = time, 3 = slices)
%                           default: The last dimension with more than one
%                           value is chosen
%                           (i.e. 3 for 3D image, 4 for 4D image)
%
% OUT
%   outputImage             cumsum of all images along application dimension
%
% EXAMPLE
%   cumsum
%
%   See also MrImage MrImage.perform_unary_operation

% Author:   Saskia Klein & Lars Kasper
% Created:  2014-11-02
% Copyright (C) 2014 Institute for Biomedical Engineering
%                    University of Zurich and ETH Zurich
%
% This file is part of the TAPAS UniQC Toolbox, which is released
% under the terms of the GNU General Public Licence (GPL), version 3.
% You can redistribute it and/or modify it under the terms of the GPL
% (either version 3 or, at your option, any later version).
% For further details, see the file COPYING or
%  <http://www.gnu.org/licenses/>.

if nargin < 2
    applicationDimension = this.dimInfo.nDims;
else
    applicationDimension = this.dimInfo.convert_application_dimensions(...
        applicationDimension);
end

outputImage = this.perform_unary_operation(@(x) cumsum(x, applicationDimension));