function g = dexpKernGradient(kern, x1, varargin)

% DEXPKERNGRADIENT Gradient of the double exponential kernel's parameters.
%
% FORMAT
% DESC computes the gradient of functions with respect to the double
% exponential 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 x1 : the input locations for which the gradients are being
% computed in the form of a design matrix.
% 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 x1.
% 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 in the form of a design matrix.
% ARG x2 : the input locations associated with the columns of the
% kernel matrix in the form of a design 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 dexpKernParamInit, kernGradient, dexpKernDiagGradient, kernGradX
%
% COPYRIGHT : David Luengo, 2009

% KERN

if nargin < 4
    x2 = x1;
else
    x2 = varargin{1};
end

[K, sK, n1] = dexpKernCompute(kern, x1, x2);

g(1) = kern.variance * sum(sum(varargin{end} .* sK ...
    .* (1 - n1*kern.decay)));
g(2) = kern.decay * sum(sum(varargin{end} .* sK));

%/~
if any(isnan(g))
  warning('g is NaN')
end
%~/


%%vis3d(img, mycmap): a GUI-enabled visualization of the 3D volume img,
%%with an optional colormap argument.

%{
Joshua Stough
JHU, iacl
June 2012
April 2013

BSD Licence:
Copyright (c) 2013, Joshua Stough
All rights reserved.

Please comment on MATLAB fileexchange if you find this useful. Thank you.

This program offers a visualization of 3D volumes.

Obviously, this is not a new idea. This program might offer over other
programs:
    -change slice via click drag or scroll
    -orthogonal planes are visualized on each projection in a color-coded
    manner, allowing a better sense of where you are in the 3D space.
    -windowing capability
    -changing the colormap
    -neurological coordinate frame

However, after seeing the slice function, I think I must be missing a lot
of built-in functionality, making this program pointless. But I share in any
event as I obviously cannot see all ends (nerd).

References to really good and thoughtful 3D viewer implementations in
matlab (including buttons and all axis flipping that I can't do):
http://www.mathworks.com/matlabcentral/fileexchange/2256-orthoview
http://www.mathworks.com/matlabcentral/fileexchange/764-sliceomatic

For some 3d matrix of double or uint8, call
>> vis3d(img);
or, if you have some multilabel segmentation image, try:
>> vis3d(seg, 'multi');
or, if you want define your own colormap, you can send that instead:
>> mymap = colormap('lines');
>> vis3d(seg, mymap);
lastly, you can customize the figure title:
>> vis3d(seg, '', 'My Figure Title');

Updates/Modifications:
4/13:
-fixed slice number issue: the out-of-plane slice number was incorrect
in the initial window.
-changed interaction: now, scrolling changes slice number
-fixed the 3d volume visualization errors arising from the treatment of
images versus matrices in matlab.
-fixed tick mark misrepresentation.
-added windowing on the colormap
-added choice of colormap in addition to typical maps.
%}

function [] = vis3d(seg, mycmap, figName)

    %We check for the colormap after we have a figure open.
    if nargin < 3
        figName = 'vis3d: click and scroll/drag vertically (up=closer to eye).';
        userSpecFigName = false; %did the user specify the figure name.
    else
        userSpecFigName = true;
    end
    %arg 2 taken care of below.

    if ~(isa(seg, 'double') || isa(seg, 'uint8'))
        fprintf('The image is not double or uint8.  You may receive many warnings.\n');
        fprintf('Cast your image to either before sending here.');
    end
   %seg = seg/max(seg(:)); %Make 0-1.
    segRange = [min(seg(:)) max(seg(:))];
    origSegRange = segRange;
    %segRange is required to ensure that if you view a slice with more or
    %less range, you get colors consistent with other slices.

    sizeSeg = size(seg);
    sn = round(sizeSeg/2);
    %slice numbers for the three projections.

    titleLines = {'YX view: ', 'YZ view: ', 'XZ view: '};
    %titleColors = {'b', 'r', 'g'};
    titleColors = {[.3 .3 .8], [.8 .3 .3], [.3 .8 .3]};

    %The figure handle, with its callbacks.
    mainHandle = figure('Position', [50 50 800 800], ...
        'WindowButtonDownFcn', @buttonDownCallback, ...
        'WindowButtonUpFcn', @buttonUpCallback, ...
        'Name', figName); hold on;

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %Adding colormap popupmenu
    colormapText = uicontrol('Style', 'text', 'Position', [300 0 100, 20], ...
        'FontSize', 12, 'FontWeight', 'bold');
    set(colormapText, 'String', 'Colormap:', 'ForegroundColor', [1 1 1]);

    colormapPopup = uicontrol('Style', 'popupmenu', ...
        'Position', [400 0 200 20], ...
        'Callback', @specifyColormap);
    set(colormapPopup, 'String', {'gray'; 'multi-label'; 'jet'}, ...
        'Value', 1, 'FontSize', 12, 'FontWeight', 'bold');

    %define the colormaps.
    %A colormap I find useful for multi-label segmentation images, which is
    %why I made this thing to begin with (and why the image is called seg).
    multi = [0 0 0;
            1 0 1;
            0 .7 1;
            1 0 0;
            .3 1 0;
            0 0 1;
            1 1 1;
            1 .7 0];
    graymap = colormap('gray');
    jetmap = colormap('jet');
    the_cmaps = {graymap; multi; jetmap};

    %Is there a user-defined map?
    %Now that we're sure to have a figure open, get a colormap.
    if nargin < 2 || strcmp(mycmap, '')
        mycmap = gray;
    elseif strcmp(mycmap, 'multi')
        mycmap = multi;
        set(colormapPopup, 'Value', 2);
    else
        %User defined a colormap to use.  Set it as current.
        the_cmaps{end+1} =  mycmap;
        set(colormapPopup, 'String', {'gray'; 'multi-label'; 'jet'; 'user-spec'}, ...
        'Value', 4);
    end
    %End of colormap popup menu.
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    %flip the matrix to better organize views. This is memory-stupid!!!
    %Please help!
    xyview = seg;
    xzview = seg;
    yzview = seg;

    xyview = flipdim(xyview, 1);

    xzview = flipdim(xzview, 1);
    xzview = permute(xzview, [3 2 1]);
    %xzview = flipdim(xzview, 2);

    yzview = permute(yzview, [1 3 2]);
    yzview = flipdim(yzview, 1);

    %Now, we plot the three orthogonal slices and try to get the two lines
    %on each slice, which represent the other planes.
    %Notice we are using axis xy, so that the tick marks are correct, that
    %also means we don't need to flip z in yz and xz views...
    handles{1} = subplot(2,2,3);
    imHandles{1} = imagesc(squeeze(xyview(:,:,sn(3))), segRange); colormap(mycmap); axis image; axis xy;
    %set(handles{1}, 'LooseInset', get(gca,'TightInset')) %made smaller...
    titleHandles{1} = title(handles{1}, 'XY view', 'Color', titleColors{1}, 'FontSize', 14, 'FontWeight', 'bold');

    handles{2} = subplot(2,2,1);
    imHandles{2} = imagesc(squeeze(yzview(sn(1),:,:)), segRange); colormap(mycmap); axis image; axis xy;
    titleHandles{2} = title(handles{2}, 'YZ view', 'Color', titleColors{2}, 'FontSize', 14, 'FontWeight', 'bold');
    %set(handles{2}, 'XDir', 'rev');
    %I used reverse here to have appropriate neurological coord, but then I
    %thought, people like to see 'through the eyes of the patient' in
    %coronal (i.e., patient l-r equals l-r in the image).

    handles{3} = subplot(2,2,2);
    imHandles{3} = imagesc(squeeze(xzview(:,sn(2),:)), segRange); colormap(mycmap); axis image; axis xy;
    titleHandles{3} = title(handles{3}, 'XZ view', 'Color', titleColors{3}, 'FontSize', 14, 'FontWeight', 'demi');

    %Making sure the titles all have the initial slice number as well.
    offsliceCoord = [3 1 2];
    for i = 1:3
        set(titleHandles{i}, 'String', sprintf('%s%03d', titleLines{i}, sn(offsliceCoord(i))));
    end

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %lower and upper bound on the intensity window and text box.

    %Adding uicontrol elements would remove the toolbar from the figure
    %without this statement.
    set(mainHandle, 'Toolbar', 'figure');

    IntWinSliderHandle{1} = uicontrol('Style', 'slider', ...
        'Position', [0 0 200 20], ...
        'Callback', @IntWinBound);
    set(IntWinSliderHandle{1}, 'Value', segRange(1));

    IntWinSliderHandle{2} = uicontrol('Style', 'slider', ...
        'Position', [0 25 200 20], ...
        'Callback', @IntWinBound);
    set(IntWinSliderHandle{2}, 'Value', segRange(2));

    for i = 1:2
        set(IntWinSliderHandle{i}, 'Min', segRange(1));
        set(IntWinSliderHandle{i}, 'Max', segRange(2));
    end

    IntWinTextBound{1} = uicontrol('Style', 'edit', ...
        'Position', [210 0 60 20], ...
        'Callback', @defineBound);
    set(IntWinTextBound{1}, 'String', segRange(1));

    IntWinTextBound{2} = uicontrol('Style', 'edit', ...
        'Position', [210 25 60 20], ...
        'Callback', @defineBound);
    set(IntWinTextBound{2}, 'String', segRange(2));

    IntWinText = uicontrol('Style', 'text', 'Position', [0 50 210 15], ...
        'FontSize', 12, 'FontWeight', 'bold');

    set(IntWinText, 'String', 'Windowing', ...
            'ForegroundColor', [1 1 1]);
    %End of intensity windowing elements.
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %And the 3D view.
    handles{4} = subplot(2,2,4);

    %We're using the slice visualization function here, but it's screwy
    %because the x and y are transposed and axes must be flipped for the
    %appropriate perspective,

    %I wanted the callback to avoid duplicating code, but the camera position
    %is hard to get before slice is called...buttonUpCallback([]); so here
    %is init.
    %due to confusing coordinates for the slice function, we need to
    %permute and flip dimensions...
    visSeg = seg;
    visSeg = permute(visSeg, [2 1 3]);
    %visSeg = flipdim(visSeg, 1);
    %visSeg = flipdim(visSeg, 2);
    flippedx = inline(sprintf('%d - x + 1', size(visSeg, 2)));
    %The 2nd dimension of the matrix ends up being 'called' x by matlab.
    %wtf?

    hslc=slice(visSeg, flippedx(sn(1)) ,sn(2),sn(3));
    axis equal; axis vis3d; set(hslc(1:3),'LineStyle','none');
    xlabel 'p-a' ;ylabel 'l-r' ;zlabel 'i-s';
    %set(gca, 'XDir', 'reverse');
    %The above XDir didn't work, without screwing up the data.  So, I'll
    %just change the labels...WAIT!: that's wrong because the slice numbers
    %become wrong then.  Have to flip...
    myx = get(gca, 'XTickLabel');
    set(gca, 'XTickLabel', flippedx(str2num(myx)));

    title 'Manually enable/disable Rotate3D.'
    %To maintain the 3D perspective throughout.
    camPos3D = get(handles{4}, 'CameraPosition');

    %Too many problems trying to regain control from the rotate3d.
    %rotHandle = rotate3d(handles{4}); so it's up to the user.
    rotHandle = rotate3d;
    setAllowAxesRotate(rotHandle, handles{1}, false);
    setAllowAxesRotate(rotHandle, handles{2}, false);
    setAllowAxesRotate(rotHandle, handles{3}, false);
    %End of the 3D view elements
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %Generate the lines representing the orthogonal planes.  This part is
    %so confusing, in part because line will use the bottom
    %left, whereas we're thinking of the top left (image) as being 0,0.
    %But it's mostly my fault, because coordinate systems are so HARD...

    lines{1}.x = [1 sizeSeg(2); sn(2) sn(2)]';
    lines{1}.y = [sn(1) sn(1); 1 sizeSeg(1)]';
    %the x coords of the horiz and vertical line respectively.
    %the y coords of the horiz and vertical line respectively.

    lines{2}.x = [1 sizeSeg(2); sn(2) sn(2)]';
    lines{2}.y = [sn(3) sn(3); 1 sizeSeg(3)]';

    lines{3}.x = [1 sizeSeg(1); sn(1) sn(1)]';
    lines{3}.y = [sn(3) sn(3); 1 sizeSeg(3)]';

    %We now instantiate the lines.  We also want the line colors to reflect
    %the plane they represent, which is given by the titleColors. The trick
    %is weird though: when we're visualizing the XY plane, the two lines on
    %it are the XZ plane (vertical), and the YZ plane, horizontal.  whew.
    %for each, first is horizontal, next is vertical.
    lineHandles = {};
    subplot(handles{1});
    lineHandles{1}(1) = line(lines{1}.x(:,1), lines{1}.y(:,1), 'Color', titleColors{2}, 'LineWidth', 1);
    lineHandles{1}(2) = line(lines{1}.x(:,2), lines{1}.y(:,2), 'Color', titleColors{3}, 'LineWidth', 1);

    subplot(handles{2});
    lineHandles{2}(1) = line(lines{2}.x(:,1), lines{2}.y(:,1), 'Color', titleColors{1}, 'LineWidth', 1);
    lineHandles{2}(2) = line(lines{2}.x(:,2), lines{2}.y(:,2), 'Color', titleColors{3}, 'LineWidth', 1);

    subplot(handles{3});
    lineHandles{3}(1) = line(lines{3}.x(:,1), lines{3}.y(:,1), 'Color', titleColors{1}, 'LineWidth', 1);
    lineHandles{3}(2) = line(lines{3}.x(:,2), lines{3}.y(:,2), 'Color', titleColors{2}, 'LineWidth', 1);
    %End of the line crap.  This is really confusing.
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    %Variables to keep track of mouse motion and which slice is being
    %maniupulated.
    lastPoint = [];
    whichView = 1;

    %At this point, time to define our callbacks.

    %This is the callback when the user clicks.  We want to determine which
    %if any projection they clicked on so that further vertical motion can
    %be associated with changing the slice for that projection.
    function buttonDownCallback(varargin)

        p = get(gca, 'CurrentPoint');
        lastPoint = [p(1); p(3)];

        %We know where they clicked with respect to the last active axes,
        %determine which axes that was.
        whichView = find(cell2mat(handles) == gca);

        if whichView == 4
            %Can't do anthing with the 3D view, unless it's rotate
            %selection.  The user has to do it themselves.
            %set(rotHandle, 'Enable', 'on', 'ActionPostCallback', @buttonUpOnRotateCallback);
            return
        end

        %By getting the camera position on a click, we can maintain the 3d
        %perspective in the case of changing slices.
        camPos3D = get(handles{4}, 'CameraPosition');

        %Now determine if they clicked on a valid spot, within the coords
        %of the chosen image/axes.
        xlim = get(gca, 'XLim');
        ylim = get(gca, 'YLim');
        if lastPoint(1) >= xlim(1) && lastPoint(1) <= xlim(2) && ...
                lastPoint(2) >= ylim(1) && lastPoint(2) <= ylim(2)
            %They clicked on a valid point, time to activate the motion
            %callback. Also let's tell them the intensity at the point they
            %click. But we also don't want to remove what they decided to
            %call the main figure.
            t_img = get(imHandles{whichView}, 'CData');
            p = round(p);
            if userSpecFigName
                set(mainHandle, 'Name', sprintf('%s: Pos: %d %d, Int: %f', ...
                    figName, p(3), p(1), t_img(p(3), p(1))));
            else
                set(mainHandle, 'Name', sprintf('Pos: %d %d, Int: %f', ...
                    p(3), p(1), t_img(p(3), p(1))));
            end
            set(mainHandle, 'WindowButtonMotionFcn', @dragCallback);
            set(mainHandle, 'WindowScrollWheelFcn', @scrollCallback);
            %fprintf('You clicked on %f, %f on gca %f (%d).\n', p(1), p(3), gca, whichView);
        %else
            %fprintf('Oops, you did''t click flippedx(sn(1))a valid point.\n');
        end
    end

    %At this point, it's established that the user clicked on one of the
    %images and is currently dragging.  We will change the image on the
    %relevant slice and update slice info (in the title).
    %And then, if this works, I'll try the red lines on the other two
    %projections.
    function dragCallback(varargin)
        p = get(gca, 'CurrentPoint');
        motionV = round([p(1); p(3)] - lastPoint);
        if abs(motionV(2)) < 2
            return
        end %Wait until the motion is noticeable.

        lastPoint = [p(1); p(3)];

        newslice = sn(offsliceCoord(whichView)) + round(motionV(2)/2);

        updateSliceViz(newslice);

    end

    function buttonUpCallback(varargin)
        %Nullify the motion and correct the 3D view.
        %Slice is too easy though, thanks Matlab.  I should be ashamed
        %http://www.mathworks.com/matlabcentral/fileexchange/2256-orthoview
        set(mainHandle, 'WindowButtonMotionFcn', '');

        axes(handles{4}); hslc=slice(visSeg, flippedx(sn(1)), sn(2), sn(3));%rotate3d on;
        axis equal; axis vis3d; set(hslc(1:3),'LineStyle','none');
        xlabel 'p-a' ;ylabel 'l-r' ;zlabel 'i-s';

        %Same stupid and incorrect label issue.
        myx = get(gca, 'XTickLabel');
        set(gca, 'XTickLabel', flippedx(str2num(myx)));

        title 'Manually enable/disable Rotate3D.'
        set(handles{4}, 'CameraPosition', camPos3D);
    end

    %I had problems with 'ActionPostCallback' and so I'm leaving rotation
    %of the 3d plot up to the user clicking on and off the button.
    %function buttonUpOnRotateCallback(varargin)
    %    set(rotHandle, 'ActionPostCallback', '');
    %    set(rotHandle, 'Enable', 'off');
    %end

    function scrollCallback(src,evnt)
        %Change whichView's slice by the vertical motion.
        offsliceCoord = [3 1 2];
        %if they're moving xy slice, that's a change in z, etc.

        if whichView == 4
            return
        end

        if evnt.VerticalScrollCount > 0
            newslice = sn(offsliceCoord(whichView)) - 1;
        else
            newslice = sn(offsliceCoord(whichView)) + 1;
        end

        updateSliceViz(newslice);

    end

    function updateSliceViz(newslice)
        %Change whichView's slice by the vertical motion.

        offsliceCoord = [3 1 2];
        %if they're moving xy slice, that's a change in z, etc.

        if newslice > 0 && newslice <= sizeSeg(offsliceCoord(whichView))
            sn(offsliceCoord(whichView)) = newslice;
        end
        subplot(handles{whichView});

        %This is a tough to comprehend part.  I want to move the lines
        %representing the current plane in the other orthogonal views.
        %I'll be changing line properties accordingly.
        if whichView == 1
            %XY view (axial)
            %imagesc(squeeze(seg(:,:,sn(3))), segRange); axis image; hold on
            %While you don't have to respecify the colormap, you do need to
            %remind imagesc of the appropriate range and ensure the axes
            %are good. In fact, I forgot that with matlab, everything is an
            %object.  Just change the data in the object.
            set(imHandles{1}, 'CData', squeeze(xyview(:,:,sn(3))));

            %Moving in z, so change the horizontal lines in the YZ and XZ
            %plots.
            set(lineHandles{2}(1), 'YData', [sn(3) sn(3)]');
            set(lineHandles{3}(1), 'YData', [sn(3) sn(3)]');

        elseif whichView == 2
            %YZ view (coronal)
            set(imHandles{2}, 'CData', squeeze(yzview(sn(1),:,:)));
            %imagesc(squeeze(seg(sn(1),:,:)), segRange); axis image

            %Moving in x, so change the horizontal line in the XY
            %(representing front-back) and the vertical in and XZ.
            %plots
            set(lineHandles{1}(1), 'YData', [sn(1) sn(1)]');
            set(lineHandles{3}(2), 'XData', [sn(1) sn(1)]');
        else
            %XZ view (sagittal)
            set(imHandles{3}, 'CData', squeeze(xzview(:,sn(2),:)));
            %imagesc(squeeze(seg(:,sn(2),:)), segRange); axis image

            %Moving in y, so change the vertical line in plot 1 and
            %horizontal line in plot 2.
            set(lineHandles{1}(2), 'XData', [sn(2) sn(2)]');
            set(lineHandles{2}(2), 'XData', [sn(2) sn(2)]');
        end
        %title(handles{whichView}, strcat(titleLines{whichView}, num2str(sn(offsliceCoord(whichView)))),...
        %    'Color', titleColors{whichView});
        %Why recreate the title if all we really want to do is change the
        %string.
        set(titleHandles{whichView}, 'String', ...
            sprintf('%s%03d', titleLines{whichView}, sn(offsliceCoord(whichView))));
    end

    function IntWinBound(varargin)
        %Here we perform the linear intensity windowing on the images.
        %First, determine the window selected by the user and update the
        %text appropriately.

        for whichSlider = 1:2
            slider_value = get(IntWinSliderHandle{whichSlider}, 'Value');
            segRange(whichSlider) = slider_value;
            set(IntWinTextBound{whichSlider}, 'String', segRange(whichSlider));
        end

        %Now, change the CLim of the four axes.  I couldn't find how to get
        %at just the axes (which have CLim defined), because subplot
        %apparently never returned a handle for my handles cell array.
        %Anyway, looping through the main figure's children did the trick.
        %(For now anyway, until I start using uipanels and such).
        for c = get(mainHandle, 'Children')'
            try
                set(c, 'CLim', segRange);
            catch exception
                continue
            end
        end

    end

    function defineBound(varargin)
        for whichBound = 1:2
            bound_str = get(IntWinTextBound{whichBound},'String');
            if strcmp(bound_str, 'max')
                bound_value = max(origSegRange);
            elseif strcmp(bound_str, 'min')
                bound_value = min(origSegRange);
            else
                bound_value = str2double(bound_str);
            end
            set(IntWinTextBound{whichBound},'String', num2str(bound_value));
            segRange(whichBound) = bound_value;
        end

        for c = get(mainHandle, 'Children')'
            try
                set(c, 'CLim', segRange);
            catch exception
                continue
            end
        end
    end

    function specifyColormap(hObject, ~)
        choice = get(hObject, 'Value');

        colormap(the_cmaps{choice});

    end

end


function plotExcitationIRF(varargin)
% Plots the excitation IRF for each hydro structure's bodies in
% the heave, surge and pitch degrees of freedom.
%
% Usage:
% ``plotExcitationIRF(hydro, hydro2, hydro3, ...)``
%
% Parameters
% ----------
%     varargin : struct(s)
%         The hydroData structure(s) created by the other BEMIO functions.
%         One or more may be input.
%

if isempty(varargin)
    error(['plotExcitationIRF: No arguments passed. Include one or more hydro ' ...
        'structures when calling: plotExcitationIRF(hydro1, hydro2, ...)']);
end

B=1;  % Wave heading index
figHandle = figure('Position',[950,100,975,521]);
titleString = ['Normalized Excitation Impulse Response Functions:   ',...
    '$$\bar{K}_i(t) = {\frac{1}{2\pi}}\int_{-\infty}^{\infty}{\frac{X_i(\omega,\theta)e^{i{\omega}t}}{{\rho}g}}d\omega$$'];
subtitleStrings = {'Surge','Heave','Pitch'};
xString = {'$$t (s)$$','$$t (s)$$','$$t (s)$$'};
yString = {['$$\bar{K}_1(t,\theta$$',' = ',num2str(varargin{1}.theta(B)),'$$^{\circ}$$)'],...
    ['$$\bar{K}_3(t,\theta$$',' = ',num2str(varargin{1}.theta(B)),'$$^{\circ}$$)'],...
    ['$$\bar{K}_5(t,\theta$$',' = ',num2str(varargin{1}.theta(B)),'$$^{\circ}$$)']};

notes = {'Notes:',...
    ['$$\bullet$$ The IRF should tend towards zero within the specified timeframe. ',...
    'If it does not, attempt to correct this by adjusting the $$\omega$$ and ',...
    '$$t$$ range and/or step size used in the IRF calculation.'],...
    ['$$\bullet$$ Only the IRFs for the first wave heading, surge, heave, and ',...
    'pitch DOFs are plotted here. If another wave heading or DOF is significant ',...
    'to the system, that IRF should also be plotted and verified before proceeding.']};

numHydro = length(varargin);
for ii = 1:numHydro
    numBod = varargin{ii}.Nb;
    tmp1 = strcat('X',num2str(ii));
    X.(tmp1) = varargin{ii}.ex_t;
    tmp2 = strcat('Y',num2str(ii));
    a = 0;
    for i = 1:numBod
        m = varargin{ii}.dof(i);
        Y.(tmp2)(1,i,:) = squeeze(varargin{ii}.ex_K(a+1,B,:));
        Y.(tmp2)(2,i,:) = squeeze(varargin{ii}.ex_K(a+3,B,:));
        Y.(tmp2)(3,i,:) = squeeze(varargin{ii}.ex_K(a+5,B,:));
        legendStrings{i,ii} = [varargin{ii}.body{i}];
        a = a + m;
    end
end

formatPlot(figHandle,titleString,subtitleStrings,xString,yString,X,Y,legendStrings,notes)
saveas(figHandle,'Excitation_IRFs.png');

end


function a = subsref(t,s)
%SUBSREF Subscripted reference for a sparse tensor.
%
%   We can extract elements or subtensors from a sparse tensor in the
%   following ways.
%
%   Case 1a: y = X(i1,i2,...,iN), where each in is an index, returns a
%   scalar.
%
%   Case 1b: Y = X(R1,R2,...,RN), where one or more Rn is a range and
%   the rest are indices, returns a sparse tensor. The elements are
%   renumbered here as appropriate.
%
%   Case 2a: V = X(S) or V = X(S,'extract'), where S is a p x n array
%   of subscripts, returns a vector of p values.
%
%   Case 2b: V = X(I) or V = X(I,'extract'), where I is a set of p
%   linear indices, returns a vector of p values.
%
%   Any ambiguity results in executing the first valid case. This
%   is particularily an issue if ndims(X)==1.
%
%   S = X.subs returns the subscripts of the nonzero entries in X.
%
%   V = X.vals returns the values of the nonzero entries in X.
%
%   Examples
%   X = sptensor([4,4,4;2,2,1;2,3,2],[3;5;1],[4 4 4]);
%   X(1,2,1) %<-- returns zero
%   X(4,4,4) %<-- returns 3
%   X(3:4,:,:) %<-- returns 2 x 4 x 4 sptensor
%   X(2,:,:) %<-- returns a 2 x 2 tensor
%   X([1,1,1;2,2,1]) %<-- returns a vector of 2 elements
%   X = sptensor([6;16;26],[1;1;1],30);
%   X([1:6]') %<-- extracts a subtensor
%   X([1:6]','extract') %<-- extracts a vector of 6 elements
%
%   See also SPTENSOR, SPTENSOR/FIND, TENSOR/SUBSREF.
%
%MATLAB Tensor Toolbox.
%Copyright 2012, Sandia Corporation.

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

switch s(1).type

    case '{}'
        error('Subscript cell reference cannot be used with sptensor.')

    case '.'
        switch s(1).subs
            case {'subs','indices'}
                a = tt_subsubsref(t.subs, s);
            case {'vals','values'}
                a = tt_subsubsref(t.vals, s);
            case 'size'
                a = tt_subsubsref(t.size, s);
            otherwise
                error(['No such field: ', s(1).subs]);
        end
        return;

    case '()'

        % *** CASE 1: Rectangular Subtensor ***
        if (numel(s(1).subs) == ndims(t)) && ...
                ~isequal(s(1).subs{end},'extract')

            % Extract the subdimensions to be extracted from t
            region = s(1).subs;

            % Pare down the list of subscripts (and values) to only
            % those within the subdimensions specified by region.
            loc = subdims(region, t);
            subs = t.subs(loc,:);
            vals = t.vals(loc);

            % Find the size of the subtensor and renumber the
            % subscripts
            [subs, sz] = renumber(subs, size(t), region);

            % Determine the subscripts
            newsiz = [];                % (future) new size
            kpdims = [];                % dimensions to keep
            rmdims = [];                % dimensions to remove

            % Determine the new size and what dimensions to keep
            for i = 1:length(region)
                if ischar(region{i}) && (region{i} == ':')
                    newsiz = [newsiz size(t,i)];
                    kpdims = [kpdims i];
                elseif numel(region{i}) > 1
                    newsiz = [newsiz numel(region{i})];
                    kpdims = [kpdims i];
                else
                    rmdims = [rmdims i];
                end
            end

            % Return a single double value for a zero-order sub-tensor
            if isempty(newsiz)
                if isempty(vals)
                    a = 0;
                else
                    a = vals;
                end
                return;
            end

            % Assemble the resulting sparse tensor
            if isempty(subs)
                a = sptensor([],[],sz(kpdims));
            else
                a = sptensor(subs(:,kpdims), vals, sz(kpdims));
            end
            return;
        end

        % Case 2: EXTRACT

        % *** CASE 2a: Subscript indexing ***
        if size(s(1).subs{1},2) == ndims(t)

            % extract array of subscripts
            srchsubs = s(1).subs{1};

       % *** CASE 2b: Linear indexing ***
        else

            % Error checking
            if numel(s(1).subs) ~= 1
                error('Invalid indexing');
            end

            idx = s(1).subs{1};
            if ndims(idx) ~=2 || size(idx,2) ~= 1
                error('Expecting a column index');
            end

            % extract linear indices and convert to subscripts
            srchsubs = tt_ind2sub(size(t),idx);

        end

        a = extract(t,srchsubs);
        a = tt_subsubsref(a,s);

        return;

    otherwise
        error('Incorrect indexing into sptensor.')
end


classdef MparameterThresholder < handle

    properties (Access = public)

    end

    properties (Access = private)
        mV
    end

    properties (Access = private)
       minLengthInUnitCell
       m0V
       m1V
    end

    methods (Access = public)

        function obj = MparameterThresholder(cParams)
            obj.init(cParams);
            obj.m0V = 0;
            obj.m1V = 1;
        end

        function m = thresh(obj,m)
            obj.mV = m;
            obj.thresholdingWhenTooSmallCell();
            obj.thresholdingLimitCases();
            m = obj.mV;
        end

    end

    methods (Access = private)

        function init(obj,cParams)
            obj.minLengthInUnitCell = cParams.minLengthInUnitCell;
        end

        function itIs = isCellTooSmall(obj)
            t = obj.minLengthInUnitCell;
            itIs = t > 1/2;
        end

        function thresholdingWhenTooSmallCell(obj)
            isSmall = obj.isCellTooSmall();
            m = obj.mV;
            m0 = obj.m0V;
            m1 = obj.m1V;
            mT = m;
            mT(isSmall) = m0 + (m1-m0)*heaviside(m(isSmall)-1/2);
            obj.mV = mT;
        end

        function thresholdingLimitCases(obj)
            obj.thresholdingLeftCellFrame();
            obj.thresholdingRightCellFrame();
        end

        function thresholdingLeftCellFrame(obj)
           m = obj.mV;
           t = obj.minLengthInUnitCell;
           mMin = obj.m0V*ones(size(t));
           mMax = mMin + t;
           obj.mV = obj.thresholdCellFrame(m,mMin,mMax);
        end

        function thresholdingRightCellFrame(obj)
           m = obj.mV;
           t = obj.minLengthInUnitCell;
           mMax = obj.m1V*ones(size(t));
           mMin = mMax - t;
           obj.mV = obj.thresholdCellFrame(m,mMin,mMax);
        end

        function m = thresholdCellFrame(obj,m,mMin,mMax)
           isMin = obj.isMin(m,mMin,mMax);
           isMax = obj.isMax(m,mMin,mMax);
           m(isMin) = mMin(isMin);
           m(isMax) = mMax(isMax);
        end

        function itIs = isMin(obj,m,mMin,mMax)
           isFrame        = obj.isInFrameAndCellNotSmall(m,mMin,mMax);
           isCloseToMmin  = obj.isMcloseToMmin(m,mMin,mMax);
           itIs           = isFrame & isCloseToMmin;
        end

        function itIs = isMax(obj,m,mMin,mMax)
           isFrame        = obj.isInFrameAndCellNotSmall(m,mMin,mMax);
           isCloseToMmax  = ~obj.isMcloseToMmin(m,mMin,mMax);
           itIs           = isFrame & isCloseToMmax;
        end

        function itIs = isInFrameAndCellNotSmall(obj,m,mMin,mMax)
           isInFrame      = mMin < m & m < mMax;
           isCellNotSmall = ~obj.isCellTooSmall();
           itIs = isInFrame & isCellNotSmall;
        end

    end

    methods (Access = private, Static)

        function itIs = isMcloseToMmin(m,mMin,mMax)
           itIs = (m - mMin) < (mMax - mMin)/2;
        end

    end

end


 % Right Stance Domain
 %
 % Contact: Right Toe
function domain = RightStance(model, load_path)
    % construct the right stance domain of RABBIT
    %
    % Parameters:
    % model: the right body model of ATLAS robot

    %% first make a copy of the robot model
    %| @note Do not directly assign with the model variable, since it is a
    %handle object.
    domain = copy(model);
    % set the name of the new copy
    domain.setName('RightStance');

    % Extract state variables
    x = domain.States.x;
    dx = domain.States.dx;

    % add contact
    right_sole = ToContactFrame(domain.ContactPoints.RightToe,...
        'PointContactWithFriction');
    fric_coef.mu = 0.6;
    % load symbolic expressions for contact (holonomic) constraints
    domain = addContact(domain,right_sole,fric_coef, [], load_path);

    % add event
    % height of non-stance foot (left toe)
    p_nsf = getCartesianPosition(domain, domain.ContactPoints.LeftToe);
    h_nsf = UnilateralConstraint(domain,p_nsf(3),'leftFootHeight','x');
    % often very simple, no need to load expression. Compute them directly
    domain = addEvent(domain, h_nsf);

    % phase variable: time
    t = SymVariable('t');
    p = SymVariable('p',[2,1]);
    tau = (t-p(2))/(p(1)-p(2));

    % relative degree two outputs:
    y_q1R = x('q1_right');
    y_q2R = x('q2_right');
    y_q1L = x('q1_left');
    y_q2L = x('q2_left');

    ya_2 = [y_q1R;
            y_q2R;
            y_q1L;
            y_q2L];

    y2_label = {'q1_right',...
                'q2_right',...
                'q1_left',...
                'q2_left'};
    % optional: load expression for virtual constraints while creating
    y2 = VirtualConstraint(domain,ya_2,'time','DesiredType','Bezier','PolyDegree',5,...
        'RelativeDegree',2,'OutputLabel',{y2_label},'PhaseType','TimeBased',...
        'PhaseVariable',tau,'PhaseParams',p,'Holonomic',true,...
        'LoadPath', load_path);

    domain = addVirtualConstraint(domain,y2);

end


function [nn,ctrs] = myhist3(varargin)
% almost the same as Matlab's hist3, except it can take weights.

i = find(strcmpi(varargin,'weights'));
if ~isempty(i),
  weights = varargin{i(end)+1};
  varargin([i,i+1]) = [];
end

[cax,args,nargs] = axescheck(varargin{:});

if nargs < 1
    error('stats:hist3:TooFewInputs', 'Requires X.')
end
x = args{1};

% See if nbins/ctrs was given as the second argument, or only name/value
% pairs.
if nargs > 1 && ~ischar(args{2})
    binSpec = args{2};
    args = args(3:end); % strip off x and nbins/ctrs
else
    binSpec = [];
    args = args(2:end); % strip off x
end

% Process input parameter name/value pairs, assume unrecognized ones are
% graphics properties.
pnames = {'nbins','ctrs','edges'};
dflts =  { [],     [],       []};
[errid,errmsg,nbins,ctrs,edges,plotArgs] = statgetargs(pnames, dflts, args{:});
if ~isempty(errmsg)
    error(['stats:hist3:' errid], errmsg);
end

% Make sure they haven't mixed 'nbins'/'ctrs'/'edges' name/value pairs with
% the CTRS or NBINS unnamed second arg syntax, or used more than one of
% those parameter name/value pairs.
if (isempty(nbins)+isempty(ctrs)+isempty(edges)+isempty(binSpec)) < 3
    error('stats:hist3:AmbiguousBinSpec', 'Ambiguous specification of bins.');
elseif ~isempty(binSpec)
    if iscell(binSpec)  % hist3(x,ctrs)
        ctrs = binSpec;
    else                % hist3(x,nbins)
        nbins = binSpec;
    end
end

if ~isempty(nbins)
    % Use the specified number of bars in each direction, centers and edges
    % to be determined.
    histBehavior = true;
    if ~(isnumeric(nbins) && numel(nbins)==2)
        error('stats:hist3:BadNbins', ...
              'The number of bins must be specified with a 2-element numeric vector.');
    end
    autobins = true;

elseif ~isempty(ctrs)
    % Use the specified bin centers.
    histBehavior = true;
    if ~(iscell(ctrs) && numel(ctrs)==2 && isnumeric(ctrs{1}) && isnumeric(ctrs{2}))
        error('stats:hist3:BadCtrs', ...
              'Bin centers must be specified with a cell array containing two numeric vectors.');
    end
    ctrs = {ctrs{1}(:)' ctrs{2}(:)'};
    autobins = false;
    nbins = [length(ctrs{1}) length(ctrs{2})];

elseif ~isempty(edges)
    % Use the specified bin edges.
    histBehavior = false;
    if ~(iscell(edges) && numel(edges)==2 && isnumeric(edges{1}) && isnumeric(edges{2}))
        error('stats:hist3:BadEdges', ...
              'Bin edges must be specified with a cell array containing two numeric vectors.');
    end
    edges = {edges{1}(:)' edges{2}(:)'};
    autobins = false;
    % Just as with histc, there will be #edges bins
    nbins = [length(edges{1}) length(edges{2})];

else
    % Assume a 10x10 grid of bars, centers and edges to be determined.
    histBehavior = true;
    autobins = true;
    nbins = [10 10];
end

[nrows,ncols] = size(x);
if ncols ~= 2
    error('stats:hist3:WrongNumCols', 'X must be a matrix with two columns.');
end

% Special case for empty data (follows what HIST does).
if isempty(x)
    if autobins
       ctrs = {1:nbins(1) 1:nbins(2)};
    end
    n = zeros(nbins); % Nothing to count, return nbins(1) by nbins(2) zeros

else
    % Bin each observation in the x-direction, and in the y-direction.
    bin = zeros(nrows,2);
    for i = 1:2
        minx = min(x(:,i));
        maxx = max(x(:,i));

        % If only the number of bins was given, compute edges and centers
        % for equal-sized bins spanning the data.
        if autobins
            if isinf(minx) || isinf(maxx)
                error('stats:hist3:InfData', ...
                      'Bin centers or edges must be specified when data contain infinite values.');
            elseif minx == maxx
                minx = minx - floor(nbins(i)/2) - 0.5;
                maxx = maxx + ceil(nbins(i)/2) - 0.5;
            end
            binwidth{i} = (maxx - minx) / nbins(i);
            edges{i} = minx + binwidth{i}*(0:nbins(i));
            ctrs{i} = edges{i}(1:nbins(i)) + binwidth{i}/2;
            % Make histc mimic hist behavior:  everything < ctrs(1) gets
            % counted in first bin, everything > ctrs(end) gets counted in
            % last bin.  ctrs, edges, and binwidth do not reflect that, but
            % histcEdges does.
            histcEdges = [-Inf edges{i}(2:end-1) Inf];

        % If the bin centers were given, compute their edges and widths.
        elseif histBehavior
            c = ctrs{i};
            dc = diff(c);
            edges{i} = [c(1) c] + [-dc(1) dc dc(end)]/2;
            binwidth{i} = diff(edges{i});
            % Make histc mimic hist behavior:  everything < ctrs(1) gets
            % counted in first bin, everything > ctrs(end) gets counted in
            % last bin.  ctrs, edges, and binwidth do not reflect that, but
            % histcEdges does.
            histcEdges = [-Inf edges{i}(2:end-1) Inf];

        % If the bin edges were given, compute their widths and centers (if
        % asked for).
        else % if ~histBehavior
            e = edges{i};
            de = diff(e);
            histcEdges = e;
            % Make the display mimic bar's histc behavior: an implied bin
            % above edges(end), the same width as the last explicit one.
            % ctrs, edges, and binwidth need that explicitly, histcEdges
            % doesn't.
            edges{i} = [e e(end)+de(end)];
            binwidth{i} = [de de(end)];
            if nargout > 1
                c = zeros(size(de));
                c(1) = e(1) + de(1)/2;
                for j = 2:length(c)
                    c(j) = 2*e(j) - c(j-1);
                end
                % When edges are specified, it may not be possible to return
                % centers for which the edges are midpoints.  Warn if that's
                % the case.
                if any(c <= e(1:end-1)) || ...
                   abs(c(end) - (e(end)-de(end)/2)) > 1000*eps(de(end));
                    warning('stats:hist3:InconsistentEdges', ...
                            'Cannot compute centers that are consistent with EDGES.');
                    c = e(1:end-1) + de/2;
                end
                ctrs{i} = [c e(end)+de(end)/2];
            end
        end

        % Get the 1D bin numbers for this column of x.  Make sure +Inf
        % goes into the nth bin, not the (n+1)th.

        % bin(j,1) holds the x bin idx for data point j
        % bin(j,2) holds the y bin idx for data point j
        [dum,bin(:,i)] = histc(x(:,i),histcEdges,1);
        bin(:,i) = min(bin(:,i),nbins(i));
    end

    % Combine the two vectors of 1D bin counts into a grid of 2D bin
    % counts
    if exist('weights','var'),
      nzidx = all(bin>0,2);
      n = accumarray(bin(nzidx,:),weights(nzidx),nbins);
    else
      n = accumarray(bin(all(bin>0,2),:),1,nbins);
    end

end

if 0 < nargout
    nn = n;
    return
end

del = .001; % space between bars, relative to bar size

% Build x-coords for the eight corners of each bar.
xx = edges{1};
xx = [xx(1:nbins(1))+del*binwidth{1}; xx(2:nbins(1)+1)-del*binwidth{1}];
xx = [reshape(repmat(xx(:)',2,1),4,nbins(1)); repmat(NaN,1,nbins(1))];
xx = [repmat(xx(:),1,4) repmat(NaN,5*nbins(1),1)];
xx = repmat(xx,1,nbins(2));

% Build y-coords for the eight corners of each bar.
yy = edges{2};
yy = [yy(1:nbins(2))+del*binwidth{2}; yy(2:nbins(2)+1)-del*binwidth{2}];
yy = [reshape(repmat(yy(:)',2,1),4,nbins(2)); repmat(NaN,1,nbins(2))];
yy = [repmat(yy(:),1,4) repmat(NaN,5*nbins(2),1)];
yy = repmat(yy',nbins(1),1);

% Build z-coords for the eight corners of each bar.
zz = zeros(5*nbins(1), 5*nbins(2));
zz(5*(1:nbins(1))-3, 5*(1:nbins(2))-3) = n;
zz(5*(1:nbins(1))-3, 5*(1:nbins(2))-2) = n;
zz(5*(1:nbins(1))-2, 5*(1:nbins(2))-3) = n;
zz(5*(1:nbins(1))-2, 5*(1:nbins(2))-2) = n;

cax = newplot(cax);
holdState = ishold(cax);

% Plot the bars in a light steel blue.
cc = repmat(cat(3,.75,.85,.95), [size(zz) 1]);

% Plot the surface, using any specified graphics properties to override
% defaults.
h = surf(cax, xx, yy, zz, cc, 'tag','hist3', plotArgs{:});

if ~holdState
    % Set ticks for each bar if fewer than 16 and the centers/edges are
    % integers.  Otherwise, leave the default ticks alone.
    if (nbins(1)<16)
        if histBehavior && all(floor(ctrs{1})==ctrs{1})
            set(cax,'xtick',ctrs{1});
        elseif ~histBehavior && all(floor(edges{1})==edges{1})
            set(cax,'xtick',edges{1});
        end
    end
    if (nbins(2)<16)
        if histBehavior && all(floor(ctrs{2})==ctrs{2})
            set(cax,'ytick',ctrs{2});
        elseif ~histBehavior && all(floor(edges{2})==edges{2})
            set(cax,'ytick',edges{2});
        end
    end

    % Set the axis limits to have some space at the edges of the bars.
    dx = range(edges{1})*.05;
    dy = range(edges{2})*.05;
    set(cax,'xlim',[edges{1}(1)-dx edges{1}(end)+dx]);
    set(cax,'ylim',[edges{2}(1)-dy edges{2}(end)+dy]);

    view(cax,3);
    grid(cax,'on');
    set(get(cax,'parent'),'renderer','zbuffer');
end

if nargout > 0
    nn = n;
end


function [verts, faces, normals] = read_off(filename)

% read_off - read data from OFF file.
%
%   [verts, faces, normals] = read_off(filename);
%
%   'verts' is a 'nb.vert x 3' array specifying the position of the vertices.
%   'faces' is a 'nb.face x 3' array specifying the connectivity of the mesh.
%   'normals' is a 'nb.normal * 3' array specifying the normal of each vertex.
%   Copyright (c) 2003 Gabriel Peyr?
%   Changed by (2009) JJCAO

fid = fopen(filename,'r');
if( fid==-1 )
    warning('Can''t open the file.');
    verts = [];faces=[];normals=[];
    return;
end

fgetl(fid);
str = fgetl(fid);
tmp = sscanf(str,'%d %d');
nverts = tmp(1);
nfaces = tmp(2);
str = fgetl(fid);
tmp = sscanf(str,'%f %f %f');

frewind(fid);
fgetl(fid); fgetl(fid);
if length(tmp) < 4 % only x y z
    [A,cnt] = fscanf(fid,'%f %f %f', 3*nverts);
    if cnt~=3*nverts
        warning('Problem in reading vertices.');
    end
    A = reshape(A, 3, cnt/3);
    verts = A';
    normals = [];
else % x y z nx ny nz
    [A,cnt] = fscanf(fid,'%f %f %f %f %f %f', 6*nverts);
    if cnt~=6*nverts
        warning('Problem in reading vertices.');
    end

    A = reshape(A, 6, cnt/6);
    A = A';
    verts = A(:,1:3);
    normals = A(:,4:6);
end

if nfaces > 0 % read Face 1  1088 480 1022
    [A,cnt] = fscanf(fid,'%d %d %d %d\n', 4*nfaces);
    if cnt~=4*nfaces
        warning('Problem in reading faces.');
    end
    A = reshape(A, 4, cnt/4);
    faces = A(2:4,:)+1;
    faces = faces';
else
    faces = [];
end

fclose(fid);
return;


%% Machine Learning Online Class
%  Exercise 7 | Principle Component Analysis and K-Means Clustering
%
%  Instructions
%  ------------
%
%  This file contains code that helps you get started on the
%  exercise. You will need to complete the following functions:
%
%     pca.m
%     projectData.m
%     recoverData.m
%     computeCentroids.m
%     findClosestCentroids.m
%     kMeansInitCentroids.m
%
%  For this exercise, you will not need to change any code in this file,
%  or any other files other than those mentioned above.
%

%% Initialization
clear ; close all; clc

%% ================= Part 1: Find Closest Centroids ====================
%  To help you implement K-Means, we have divided the learning algorithm
%  into two functions -- findClosestCentroids and computeCentroids. In this
%  part, you shoudl complete the code in the findClosestCentroids function.
%
fprintf('Finding closest centroids.\n\n');

% Load an example dataset that we will be using
load('ex7data2.mat');

% Select an initial set of centroids
K = 3; % 3 Centroids
initial_centroids = [3 3; 6 2; 8 5];

% Find the closest centroids for the examples using the
% initial_centroids
idx = findClosestCentroids(X, initial_centroids);

fprintf('Closest centroids for the first 3 examples: \n')
fprintf(' %d', idx(1:3));
fprintf('\n(the closest centroids should be 1, 3, 2 respectively)\n');

fprintf('Program paused. Press enter to continue.\n');
pause;

%% ===================== Part 2: Compute Means =========================
%  After implementing the closest centroids function, you should now
%  complete the computeCentroids function.
%
fprintf('\nComputing centroids means.\n\n');

%  Compute means based on the closest centroids found in the previous part.
centroids = computeCentroids(X, idx, K);

fprintf('Centroids computed after initial finding of closest centroids: \n')
fprintf(' %f %f \n' , centroids');
fprintf('\n(the centroids should be\n');
fprintf('   [ 2.428301 3.157924 ]\n');
fprintf('   [ 5.813503 2.633656 ]\n');
fprintf('   [ 7.119387 3.616684 ]\n\n');

fprintf('Program paused. Press enter to continue.\n');
pause;

%% =================== Part 3: K-Means Clustering ======================
%  After you have completed the two functions computeCentroids and
%  findClosestCentroids, you have all the necessary pieces to run the
%  kMeans algorithm. In this part, you will run the K-Means algorithm on
%  the example dataset we have provided.
%
fprintf('\nRunning K-Means clustering on example dataset.\n\n');

% Load an example dataset
load('ex7data2.mat');

% Settings for running K-Means
K = 3;
max_iters = 10;

% For consistency, here we set centroids to specific values
% but in practice you want to generate them automatically, such as by
% settings them to be random examples (as can be seen in
% kMeansInitCentroids).
initial_centroids = [3 3; 6 2; 8 5];

% Run K-Means algorithm. The 'true' at the end tells our function to plot
% the progress of K-Means
[centroids, idx] = runkMeans(X, initial_centroids, max_iters, true);
fprintf('\nK-Means Done.\n\n');

fprintf('Program paused. Press enter to continue.\n');
pause;

%% ============= Part 4: K-Means Clustering on Pixels ===============
%  In this exercise, you will use K-Means to compress an image. To do this,
%  you will first run K-Means on the colors of the pixels in the image and
%  then you will map each pixel on to it's closest centroid.
%
%  You should now complete the code in kMeansInitCentroids.m
%

fprintf('\nRunning K-Means clustering on pixels from an image.\n\n');

%  Load an image of a bird
A = double(imread('rainbow2.png'));

% If imread does not work for you, you can try instead
%   load ('bird_small.mat');

A = A / 255; % Divide by 255 so that all values are in the range 0 - 1

% Size of the image
img_size = size(A);

% Reshape the image into an Nx3 matrix where N = number of pixels.
% Each row will contain the Red, Green and Blue pixel values
% This gives us our dataset matrix X that we will use K-Means on.
X = reshape(A, img_size(1) * img_size(2), 3);

% Run your K-Means algorithm on this data
% You should try different values of K and max_iters here
K = 16;
max_iters = 10;

% When using K-Means, it is important the initialize the centroids
% randomly.
% You should complete the code in kMeansInitCentroids.m before proceeding
initial_centroids = kMeansInitCentroids(X, K);

% Run K-Means
[centroids, idx] = runkMeans(X, initial_centroids, max_iters);

fprintf('Program paused. Press enter to continue.\n');
pause;

%% ================= Part 5: Image Compression ======================
%  In this part of the exercise, you will use the clusters of K-Means to
%  compress an image. To do this, we first find the closest clusters for
%  each example. After that, we

fprintf('\nApplying K-Means to compress an image.\n\n');

% Find closest cluster members
idx = findClosestCentroids(X, centroids);

% Essentially, now we have represented the image X as in terms of the
% indices in idx.

% We can now recover the image from the indices (idx) by mapping each pixel
% (specified by it's index in idx) to the centroid value
X_recovered = centroids(idx,:);
round(centroids * 255)

% Reshape the recovered image into proper dimensions
X_recovered = reshape(X_recovered, img_size(1), img_size(2), 3);

% Display the original image
subplot(1, 2, 1);
imagesc(A);
title('Original');

% Display compressed image side by side
subplot(1, 2, 2);
imagesc(X_recovered)
title(sprintf('Compressed, with %d colors.', K));

fprintf('Program paused. Pres s enter to continue.\n');
pause;


function square_hex_grid_test03 ( )

%*****************************************************************************80
%
%% SQUARE_HEX_GRID_TEST03 tests HEX_GRID_01_N.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    11 January 2009
%
%  Author:
%
%    John Burkardt
%
  test_num = 17;

  nodes_per_layer_test = [ ...
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 21, 41, 81, 101, 1001, 10001 ];

  fprintf ( 1, '\n' );
  fprintf ( 1, 'SQUARE_HEX_GRID_TEST03\n' );
  fprintf ( 1, '  For a hexagonal grid of points in the unit square,\n' );
  fprintf ( 1, '  given NODES_PER_LAYER, the number of grid points\n' );
  fprintf ( 1, '  along the first layer,\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  HEX_GRID_01_N computes N, the total number of grid\n' );
  fprintf ( 1, '  points in the unit square.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '    NODES   LAYERS	     N\n' );
  fprintf ( 1, '      PER\n' );
  fprintf ( 1, '    LAYER\n' );
  fprintf ( 1, '\n' );

  for test = 1 : test_num

    nodes_per_layer = nodes_per_layer_test ( test );

    layers = hex_grid_01_layers ( nodes_per_layer );

    n = hex_grid_01_n ( nodes_per_layer );

    fprintf ( 1, '  %6d  %6d  %12d\n', nodes_per_layer, layers, n );

  end

  return
end


function h = plus(f, g)
%+   Plus for SEPARABLEAPPROX objects.
%
% F + G adds F and G. F and G can be scalars or SEPARABLEAPPROX objects.

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

if ( ~isa(f, 'separableApprox') ) % ??? + SEPARABLEAPPROX

    h = plus(g, f);

elseif ( isempty(g) ) % SEPARABLEAPPROX + []

    h = f;

elseif ( isempty(f) ) % [] + SEPARABLEAPPROX

    h = g;

elseif ( isa( g, 'double' ) )           % SEPARABLEAPPROX + DOUBLE

    g = compose( 0*f,@plus, g);   % promote double to object class.
    h = plus(f, g);

elseif ( ~isa(g, 'separableApprox') )          % SEPARABLEAPPROX + ???

    error( 'CHEBFUN:SEPARABLEAPPROX:plus:unknown', ...
        ['Undefined function ''plus'' for input arguments of type %s ' ...
        'and %s.'], class(f), class(g));

else                                     % SEPARABLEAPPROX + SEPARABLEAPPROX

    % Domain Check:
    if ( ~domainCheck(f, g) )
        error('CHEBFUN:SEPARABLEAPPROX:plus:domain', 'Inconsistent domains.');
    end

    % Type check:
    if ( ~strcmp( class(f),class(g) ) )
        error( 'CHEBFUN:SEPARABLEAPPROX:plus:unknown', ...
            ['Undefined function ''plus'' for input arguments of type %s ' ...
            'and %s. Try converting to the same type.'], class(f), class(g));
    end

    % Check for zero SEPARABLEAPPROX objects:
    if ( iszero(f) )
        h = g;
    elseif ( iszero(g) )
        h = f;
    else
        % Add together two nonzero SEPARABLEAPPROX objects:
        h = compression_plus(f, g);

    end

end

end

function h = compression_plus(f, g)
% Add SEPARABLEAPPROX objects together by a compression algorithm.

% The algorithm is as follows:
% If A = XY^T and B = WZ^T, then A + B = [X W]*[Y Z]^T,
% [Qleft, Rleft] = qr([X W])
% [Qright, Rright] = qr([Y Z])
% A + B = Qleft * (Rleft * Rright') * Qright'
% [U, S, V] = svd( Rleft * Rright' )
% A + B = (Qleft * U) * S * (V' * Qright')     -> new low rank representation

% Hack: Ensure g has the smaller pivot values.
if ( norm(f.pivotValues, -inf) < norm(g.pivotValues, -inf) )
    % [TODO]: Understand why this works!
    h = compression_plus(g, f);
    return
end

fScl = diag(1./f.pivotValues);
gScl = diag(1./g.pivotValues);
cols = [f.cols, g.cols];
rows = [f.rows, g.rows];

[Qcols, Rcols] = qr(cols);
[Qrows, Rrows] = qr(rows);

Z = zeros(length(fScl), length(gScl));
D = [ fScl, Z ; Z.', gScl ];
[U, S, V] = svd(Rcols * D * Rrows.');
% Take diagonal from SIGMA:
s = diag(S);

% Compress the format if possible.
% [TODO]: What should EPS be in the tolerance check below?
vf = vscale(f);
vg = vscale(g);

vscl = 2*max(vf, vg);
% Remove singular values that fall below eps*vscale:
idx = find( s > 10*eps * vscl, 1, 'last');

if ( isempty(idx) )
    % Return 0 separableApprox
    h = 0*f;
else
    U = U(:,1:idx);
    V = V(:,1:idx);
    s = s(1:idx);
    h = f;
    h.cols = Qcols * U;
    h.rows = Qrows * conj(V);
    % [TODO]: PivotValues have very little meaning after this compression step.
    % For now we assign the singular values as the pivot values.
    h.pivotValues = 1./s;
end

end


function jacobi_eigenvalue_test ( )

%*****************************************************************************80
%
%% JACOBI_EIGENVALUE_TEST tests the JACOBI_EIGENVALUE library.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 July 2013
%
%  Author:
%
%    John Burkardt
%
  timestamp ( );
  fprintf ( 1, '\n' );
  fprintf ( 1, 'JACOBI_EIGENVALUE_TEST\n' );
  fprintf ( 1, '  MATLAB version\n' );
  fprintf ( 1, '  Test the JACOBI_EIGENVALUE library.\n' );

  jacobi_eigenvalue_test01 ( );
  jacobi_eigenvalue_test02 ( );
  jacobi_eigenvalue_test03 ( );
%
%  Terminate.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'JACOBI_EIGENVALUE_TEST\n' );
  fprintf ( 1, '  Normal end of execution.\n' );
  fprintf ( 1, '\n' );
  timestamp ( )

  return
end


function p = minkowski_sum(a, b)

if size(a, 2) == 1 || size(b, 2) == 1
  p = bsxfun(@plus, a, b);
else
  p = zeros(2, size(a, 2) * size(b, 2));
  idx = 0;
  for j = 1:size(a, 2)
    p(:,idx+(1:size(b,2))) = bsxfun(@plus, a(:,j), b);
    idx = idx + size(b,2);
  end
  k = convhull(p(1,:), p(2,:), 'simplify', true);
  p = p(:,k(1:end-1));
end


function [xEst,PEst]=batchLSNonlinMeasLinDyn(xInit,z,h,F,R,kD,HJacob,numIter)
%%BATCHLSNONLINMEASLINDYN Perform batch least squares state estimation
%                      refinement under a nonlinear measurement model and a
%                      linear dynamic model without process noise. The
%                      iterative nonlinear least squares algorithm is used.
%
%INPUTS: xInit The initial estimate of the target state at the time of the
%              kDth measurement that is to be refined through iteration.
%            z The zDim X N matrix of measurements for the whole batch. It
%              is assumed that the measurements have the same
%              dimensionality over the batch.
%            h A NX1 cell array of function handles for the measurement
%              function that transform the state into the measurement
%              domain at each step. If the same measurement function is
%              used for all steps in the batch, then h can just be the
%              single function handle used.
%            F An xDim X xDim X (N-1) hypermatrix of matrices. The state at
%              discrete-time k+1 is modeled as F(:,:,k) times the state at
%              time k with no process noise. Alternatively, if all of the
%              state transition matrices are the same, one can just pass a
%              single xDim X xDim matrix. Note that all of the F matrices
%              must be invertible if kD is not equal to one.
%            R The zDim X zDim X N hypermatrix of measurement covariance
%              matrices. Alternatively, if all of the measurement
%              covariance matrices are the same, one can just pass a
%              single zDim X zDim matrix.
%           kD The discrete time-step at which the smoothed state estimate
%              is desired, where z(:,1) is at discrete time-step 1 (not 0).
%       HJacob A NX1 cell array of function handles for the measurement
%              Jacobian matrix that each takes the target state as a
%              parameter. If a single measurement Jacobian matrix is used
%              for all steps of the batch, then HJacob can just be the
%              single function handle used. If an empty matrix is passed or
%              HJacob is not provided, then HJacob will be found using
%              numerical differentiation via the numDiff function with
%              default parameters.
%      numIter The numer of iterations to perform in the nonlinear least
%              squares algorithm. If this parameter is omitted, the
%              default is 10.
%
%OUTPUTS: xEst The refined batch state estimate at step kD.
%         PEst A covariance matrix estimate that goes with the state
%              estimate.
%
%The algorithm is an implementation of the nonlinear iterative least
%squares algorithm of Chapter 3.4 of [1]. The covariance provided is the
%covariance associated with the algorithm. The measurement matrices for the
%propagated state as well as the transition matrices for the propagated
%state are taken as derived in Section 3.3.2 of [2].
%
%The algorithm is likely to diverge if xEst is particularly bad. A more
%robust albeit slower estimation algorithm is
%batchLSNonlinMeasLinDynProcNoise, which also supports the inclusion of
%process noise.
%
%REFERENCES:
%[1] Y. Bar-Shalom, X. R. Li, and T. Kirubarajan, Estimation with
%    Applications to Tracking and Navigation. New York: John Wiley and
%    Sons, Inc, 2001.
%[2] A. B. Poore, B. J. Slocumb, B. J. Suchomel, F. H. Obermeyer, S. M.
%    Herman, and S. M. Gadaleta, "Batch maximum likelihood (ML) and maximum
%    a posteriori (MAP) estimation with process noise for tracking
%    applications," in Proceedings of SPIE: Signal and Data Processing of
%    Small Targets, vol. 5204, San Diego, CA, 3 Aug. 2003, pp. 188-199.
%
%October 2013 David F. Crouse, Naval Research Laboratory, Washington D.C.
%(UNCLASSIFIED) DISTRIBUTION STATEMENT A. Approved for public release.

if(nargin<8)
    numIter=10;
end
if(nargin<7)
    HJacob=[];
end

xEst=xInit;

zDim=size(z,1);
xDim=size(xEst,1);
numSteps=size(z,2);

if(isa(h,'function_handle'))
    h=repmat({h},[numSteps,1]);
end

if(isa(HJacob,'function_handle'))
    HJacob=repmat({HJacob},[numSteps,1]);
end

if(isempty(HJacob))
    HJacob=cell(numSteps,1);
    for curStep=1:numSteps
        HJacob{curStep}=@(x)numDiff(x,h{curStep},zDim);
    end
end

if(size(R,3)==1)
    R=repmat(R,[1,1,numSteps]);
end

J=zeros(zDim*numSteps,xDim);
zPredStacked=zeros(zDim*numSteps,1);

RStackedInv=inv(blkDiagRep(R));

if(size(F,3)==1)
    F=repmat(F,[1,1,numSteps-1]);
end

transMats=getTransMats(F,kD);

for curIter=1:numIter
    minIdx=1;
    for curStep=1:numSteps
        maxIdx=minIdx+zDim-1;

        xCur=transMats(:,:,curStep)*xEst;
        J(minIdx:maxIdx,:)=HJacob{curStep}(xCur)*transMats(:,:,curStep);

        zPredStacked(minIdx:maxIdx)=h{curStep}(xCur);
        minIdx=maxIdx+1;
    end

    xEst=xEst+lsqminnorm(J'*RStackedInv*J,J'*RStackedInv*(z(:)-zPredStacked));
end

%If a covariance matrix estimate is desired.
if(nargout==2)
    minIdx=1;
    for curStep=1:numSteps
        maxIdx=minIdx+zDim-1;

        xCur=transMats(:,:,curStep)*xEst;
        J(minIdx:maxIdx,:)=HJacob{curStep}(xCur)*transMats(:,:,curStep);

        minIdx=maxIdx+1;
    end

    PEst=pinv(J'*RStackedInv*J);
end

end

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


%==============================================================================
% This code is part of the Matlab-based toolbox
% FAIR - Flexible Algorithms for Image Registration.
% For details see
% - https://github.com/C4IR and
% - http://www.siam.org/books/fa06/
%==============================================================================
%
% function [yc,His] = GaussNewton(fctn,yc,varargin)
%
% Gauss-Newton scheme with variable line search for minimizing J = fctn(yc)
%
% Input:
%   fctn        function handle
%   yc          starting guess
%   varargin    optional parameter, see below
%
% Output:
%   yc          numerical optimizer (current iterate)
%   his         iteration history
%
% Note: the linear systems are solved using solveLinearSystem.m
%==============================================================================

function [yc,His] = GaussNewton(fctn,yc,varargin)

if nargin==0
    help(mfilename)
    E9_Hands_NPIR
    yc = 'endOfMinimalExample';
    return;
end;

% parameter initialization -----------------------------------------------
maxIter      = 10;              % maximum number of iterations
tolJ         = 1e-3;            % for stopping, objective function
tolY         = 1e-2;            %   - " -     , current value
tolG         = 1e-2;            %   - " -     , norm of gradient
lineSearch   = @Armijo;         % linesearch scheme
LSmaxIter    = 10;              % maximum number of line search iterations
LSreduction  = 1e-4;            % minimal reduction in line search
vecNorm      = @norm;           % norm to be used for dJ and dy
solver       = [];              % linear solver
yStop        = [];              % used for stopping in multi-level framework
Jstop        = [];              %
Plots        = @(iter,para) []; % for plots;

for k=1:2:length(varargin),     % overwrites default parameter
  eval([varargin{k},'=varargin{',int2str(k+1),'};']);
end;

if ~isa(Plots,'function_handle') && (Plots == 0 || strcmp(Plots,'off')),
  Plots        = @(iter,para) []; % for plots;
end;

if isempty(yStop), yStop  = yc; end; % yStop used for stopping only
% -- end parameter setup   ----------------------------------------------

% some output
if isstring(solver) || ischar(solver)
    solverName = solver;
elseif isa(solver,'function_handle')
    solverName = func2str(solver);
else
    error(1);
end
FAIRmessage(sprintf('JM 2011/01/02 : %s / %s / %s',...
  mfilename,func2str(lineSearch),solverName))
fprintf('[ maxIter=%s / tolJ=%s / tolY=%s / tolG=%s / numel(yc)=%d]\n',...
  num2str(maxIter),num2str(tolJ),num2str(tolY),num2str(tolG),length(yc));

% -- initialize  ---------------------------------------------------------
STOP = zeros(5,1);

if isempty(Jstop),
  % evaluate objective function for stopping values and plots
  [Jstop,para] = fctn(yStop); Jstop = abs(Jstop) + (Jstop == 0);
  Plots('stop',para);
end;

% evaluate objective function for starting values and plots
[Jc,para,dJ,H] = fctn(yc);
Plots('start',para);
iter = 0; yOld = 0*yc; Jold = Jc; y0 = yc;

hisStr    = {'iter','J','Jold-J','|\nabla J|','|dy|','LS'};
his        = zeros(maxIter+2,6);
his(1,1:3) = [-1,Jstop,Jstop-Jc];
his(2,:)   = [0,Jc,Jstop-Jc,vecNorm(dJ),vecNorm(yc-yStop),0];

% some output
fprintf('%4s %-12s %-12s %-12s %-12s %4s\n%s\n',...
  hisStr{:},char(ones(1,64)*'-'));
dispHis = @(var) ...
  fprintf('%4d %-12.4e %-12.3e %-12.3e %-12.3e %4d\n',var);
dispHis(his(1,:));
dispHis(his(2,:));
% -- end initialization   ------------------------------------------------

%-- start the iteration --------------------------------------------------
while 1,
  % check stopping rules
  STOP(1) = (iter>0) && abs(Jold-Jc)   <= tolJ*(1+abs(Jstop));
  STOP(2) = (iter>0) && (norm(yc-yOld) <= tolY*(1+norm(yStop)));
  STOP(3) = norm(dJ)                   <= tolG*(1+abs(Jstop));
  STOP(4) = norm(dJ)                   <= 1e6*eps;
  STOP(5) = (iter >= maxIter);
  if all(STOP(1:3)) || any(STOP(4:5)), break;  end;

  iter = iter + 1;

  % solve the Gauss-Newton System
  [dy,solver] = solveLinearSystem(-dJ',H,solver);

  % check descent direction
  % note: descent is not granted if using an iterative solver
  descent =   dJ * dy;
  if descent > 0,
    warning('no descent direction, switch to -dy!')
    dy      = -dy;
  end;

  % perform Armijo line-search
  [t,yt,LSiter] = lineSearch(fctn,yc,dy,Jc,dJ,...
      'para',para,'LSmaxIter',LSmaxIter,'LSreduction',LSreduction);
  if (t == 0),
      break;
  end; % break if line-search fails

  % save old values and update
  yOld = yc; Jold = Jc; yc = yt;
  [Jc,para,dJ,H] = fctn(yc); % evalute objective function

  % some output
  his(iter+2,:) = [iter,Jc,Jold-Jc,vecNorm(dJ),vecNorm(yc-yOld),LSiter];
  dispHis(his(iter+2,:));
  para.normdY = vecNorm(yc - yOld);
  Plots(iter,para);
% pause
end;%while; % end of iteration loop
%-------------------------------------------------------------------------
Plots(iter,para);

% clean up
His.str = hisStr;
His.his = his(1:iter+2,:);
fprintf('STOPPING:\n');
fprintf('%d[ %-10s=%16.8e <= %-25s=%16.8e]\n',STOP(1),...
  '(Jold-Jc)',(Jold-Jc),'tolJ*(1+|Jstop|)',tolJ*(1+abs(Jstop)));
fprintf('%d[ %-10s=%16.8e <= %-25s=%16.8e]\n',STOP(2),...
  '|yc-yOld|',norm(yc-yOld),'tolY*(1+norm(yc)) ',tolY*(1+norm(yStop)));
fprintf('%d[ %-10s=%16.8e <= %-25s=%16.8e]\n',STOP(3),...
  '|dJ|',norm(dJ),'tolG*(1+abs(Jstop))',tolG*(1+abs(Jstop)));
fprintf('%d[ %-10s=%16.8e <= %-25s=%16.8e]\n',STOP(4),...
  'norm(dJ)',norm(dJ),'eps',1e3*eps);
fprintf('%d[ %-10s=  %-14d >= %-25s=  %-14d]\n',STOP(5),...
  'iter',iter,'maxIter',maxIter);

FAIRmessage([mfilename,' : done !'],'=');

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


function linplus_test589 ( )

%*****************************************************************************80
%
%% TEST589 tests R8TO_INDICATOR.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 March 2009
%
%  Author:
%
%    John Burkardt
%
  n = 10;

  fprintf ( 1, '\n' );
  fprintf ( 1, 'TEST589\n' );
  fprintf ( 1, '  R8TO_INDICATOR sets up a R8TO indicator matrix.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Matrix order N = %d\n', n );
%
%  Set the matrix.
%
  a = r8to_indicator ( n );

  r8to_print ( n, a, '  The R8TO indicator matrix:' );

  return
end


% demo script for splitting the field of view in patches and processing in
% parallel with or without memory mapping. The demo follows the file
% demo_patches.m using the CNMF class object

clear;
%% setup path to file and package
gcp;
path_to_package = '../ca_source_extraction';   % path to the folder that contains the package
addpath(genpath(path_to_package));

filename = '/Users/epnevmatikakis/Documents/Ca_datasets/Neurofinder/neurofinder.02.00/images/neurofinder0200_rig.tif';
        % path to file (assumed motion corrected)

is_memmaped = true;        % choose whether you want to load the file in memory or not

%% create object and load file

CNM = CNMF();
if is_memmaped
    CNM.readFile(filename,is_memmaped);
else
    CNM.readFile(filename,is_memmaped,1,2000); % load only a part of the file due to memory
end

%% set options and create patches

patch_size = [32,32];    % size of each patch along each dimension (optional, default: [32,32])
overlap = [6,6];         % amount of overlap in each dimension (optional, default: [4,4])
K = 10;                  % number of components to be found
gSig = 7;                % std of gaussian kernel (size of neuron)
p = 2;                   % order of autoregressive system (p = 0 no dynamics, p=1 just decay, p = 2, both rise and decay)
gnb = 3;                 % order of background
merge_thr = 0.8;         % merging threshold

options = CNMFSetParms(...
    'd1',CNM.dims(1),'d2',CNM.dims(2),...
    'search_method','dilate',...                % search locations when updating spatial components
    'deconv_method','constrained_foopsi',...    % activity deconvolution method
    'nb',1,...                                  % number of background components per patch
    'gnb',gnb,...                               % number of global background components
    'ssub',2,...
    'tsub',1,...
    'p',p,...                                   % order of AR dynamics
    'merge_thr',merge_thr,...                   % merging threshold
    'gSig',gSig,...
    'spatial_method','regularized',...
    'cnn_thr',0.2,...
    'patch_space_thresh',0.25,...
    'min_SNR',2);

CNM.optionsSet(options);
CNM.gnb = gnb;
CNM.K = K;
CNM.patch_size = patch_size;                % size of each patch along each dimension (optional, default: [32,32])
CNM.overlap = overlap;                      % amount of overlap in each dimension (optional, default: [4,4])
CNM.createPatches();                        % create patches

%% fit all patches
CNM.fitPatches();

%% component classification

CNM.evaluateComponents();   % evaluate spatial components based on their correlation with the data
CNM.CNNClassifier('')       % evaluate spatial components with the CNN classifier
CNM.eventExceptionality();  % evaluate traces
CNM.keepComponents();       % keep the components that are above certain thresholds

%% repeat processing

CNM.updateSpatial();
CNM.updateTemporal();
CNM.extractDFF();            % extract DF/F values.

%% do some plotting
figure;
CNM.correlationImage();
CNM.plotContours();
CNM.plotComponentsGUI();     % display all components


% [data, hdr] = opensvl(filename)
%
% Reads a CTF SAM (.svl) file.

function [data, hdr] = read_ctf_svl(filename)

  fid = fopen_or_error(filename, 'rb', 'ieee-be', 'ISO-8859-1');

  % ----------------------------------------------------------------------
  % Read header.
  hdr.identity = fread(fid, 8, '*char')'; % 'SAMIMAGE'
  hdr.version = fread(fid, 1, 'int32'); % SAM file version.
  hdr.setName = fread(fid, 256, '*char')'; % Dataset name.
  hdr.numChans = fread(fid, 1, 'int32');
  hdr.numWeights = fread(fid, 1, 'int32'); % 0 for static image.
  if(hdr.numWeights ~= 0)
    ft_warning('hdr.numWeights ~= 0');
  end

  fread(fid,1,'int32'); % Padding to next 8 byte boundary.

  hdr.xmin = fread(fid, 1, 'double'); % Bounding box coordinates (m).
  hdr.xmax = fread(fid, 1, 'double');
  hdr.ymin = fread(fid, 1, 'double');
  hdr.ymax = fread(fid, 1, 'double');
  hdr.zmin = fread(fid, 1, 'double');
  hdr.zmax = fread(fid, 1, 'double');
  hdr.stepSize = fread(fid, 1, 'double'); % m

  hdr.hpFreq = fread(fid, 1, 'double'); % High pass filtering frequency (Hz).
  hdr.lpFreq = fread(fid, 1, 'double'); % Low pass.
  hdr.bwFreq = fread(fid, 1, 'double'); % Bandwidth
  hdr.meanNoise = fread(fid, 1, 'double'); % Sensor noise (T).

  hdr.mriName = fread(fid, 256, '*char')';
  hdr.fiducial.mri.nas = fread(fid, 3, 'int32'); % CTF MRI voxel coordinates?
  hdr.fiducial.mri.rpa = fread(fid, 3, 'int32');
  hdr.fiducial.mri.lpa = fread(fid, 3, 'int32');

  hdr.SAMType = fread(fid, 1, 'int32'); % 0: image, 1: weights array, 2: weights list.
  hdr.SAMUnit = fread(fid, 1, 'int32');
  % Possible values: 0 coefficients Am/T, 1 moment Am, 2 power (Am)^2, 3 Z,
  % 4 F, 5 T, 6 probability, 7 MUSIC.

  fread(fid, 1, 'int32'); % Padding to next 8 byte boundary.

  if hdr.version > 1
    % Version 2 has extra fields.
    hdr.fiducial.head.nas = fread(fid, 3, 'double'); % CTF head coordinates?
    hdr.fiducial.head.rpa = fread(fid, 3, 'double');
    hdr.fiducial.head.lpa = fread(fid, 3, 'double');
    hdr.SAMUnitName = fread(fid, 32, '*char')';
  % Possible values: 'Am/T' SAM coefficients, 'Am' source strength,
  % '(Am)^2' source power, ('Z', 'F', 'T') statistics, 'P' probability.
  end

  % ----------------------------------------------------------------------
  % Read image data.
  data = fread(fid, inf, 'double');
  fclose(fid);

  % Raw image data is ordered as a C array with indices: [x][y][z], meaning
  % z changes fastest and x slowest.  These x, y, z axes point to ALS
  % (anterior, left, superior) respectively in real world coordinates,
  % which means the voxels are in SLA order.

  % ----------------------------------------------------------------------
  % Post processing.

  % Change from m to mm.
  hdr.xmin = hdr.xmin * 1000;
  hdr.ymin = hdr.ymin * 1000;
  hdr.zmin = hdr.zmin * 1000;
  hdr.xmax = hdr.xmax * 1000;
  hdr.ymax = hdr.ymax * 1000;
  hdr.zmax = hdr.zmax * 1000;
  hdr.stepSize = hdr.stepSize * 1000;

  % Number of voxels in each dimension.
  hdr.dim = [round((hdr.xmax - hdr.xmin)/hdr.stepSize) + 1, ...
    round((hdr.ymax - hdr.ymin)/hdr.stepSize) + 1, ...
    round((hdr.zmax - hdr.zmin)/hdr.stepSize) + 1];

  data = reshape(data, hdr.dim([3, 2, 1]));

  % Build transformation matrix from raw voxel coordinates (indexed from 1)
  % to head coordinates in mm.  Note that the bounding box is given in
  % these coordinates (in m, but converted above).
  % Apply scaling.
  hdr.transform = diag([hdr.stepSize * ones(1, 3), 1]);
  % Reorder directions.
  hdr.transform = hdr.transform(:, [3, 2, 1, 4]);
  % Apply translation.
  hdr.transform(1:3, 4) = [hdr.xmin; hdr.ymin; hdr.zmin] - hdr.stepSize;
  % -step is needed since voxels are indexed from 1.

end


function value = r4_aie ( x )

%*****************************************************************************80
%
%% R4_AIE evaluates the exponential scaled Airy function Ai of an R4 argument.
%
%  Discussion:
%
%    If X <= 0
%      R4_AIE ( X ) = R4_AI ( X )
%    else
%      R4_AIE ( X ) = R4_AI ( X ) * exp ( 2/3 X^(3/2) )
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    25 September 2011
%
%  Author:
%
%    Original FORTRAN77 version by Wayne Fullerton.
%    MATLAB version by John Burkardt.
%
%  Reference:
%
%    Wayne Fullerton,
%    Portable Special Function Routines,
%    in Portability of Numerical Software,
%    edited by Wayne Cowell,
%    Lecture Notes in Computer Science, Volume 57,
%    Springer 1977,
%    ISBN: 978-3-540-08446-4,
%    LC: QA297.W65.
%
%  Parameters:
%
%    Input, real X, the argument.
%
%    Output, real VALUE, the Airy function Ai of X.
%
  persistent aifcs
  persistent aigcs
  persistent aipcs
  persistent naif
  persistent naig
  persistent naip
  persistent x32sml
  persistent x3sml
  persistent xbig

  if ( isempty ( naif ) )
    aifcs = [ ...
     -0.03797135849666999750E+00, ...
      0.05919188853726363857E+00, ...
      0.00098629280577279975E+00, ...
      0.00000684884381907656E+00, ...
      0.00000002594202596219E+00, ...
      0.00000000006176612774E+00, ...
      0.00000000000010092454E+00, ...
      0.00000000000000012014E+00, ...
      0.00000000000000000010E+00 ]';
    aigcs = [ ...
      0.01815236558116127E+00, ...
      0.02157256316601076E+00, ...
      0.00025678356987483E+00, ...
      0.00000142652141197E+00, ...
      0.00000000457211492E+00, ...
      0.00000000000952517E+00, ...
      0.00000000000001392E+00, ...
      0.00000000000000001E+00 ]';
    aipcs = [ ...
     -0.0187519297793868E+00, ...
     -0.0091443848250055E+00, ...
      0.0009010457337825E+00, ...
     -0.0001394184127221E+00, ...
      0.0000273815815785E+00, ...
     -0.0000062750421119E+00, ...
      0.0000016064844184E+00, ...
     -0.0000004476392158E+00, ...
      0.0000001334635874E+00, ...
     -0.0000000420735334E+00, ...
      0.0000000139021990E+00, ...
     -0.0000000047831848E+00, ...
      0.0000000017047897E+00, ...
     -0.0000000006268389E+00, ...
      0.0000000002369824E+00, ...
     -0.0000000000918641E+00, ...
      0.0000000000364278E+00, ...
     -0.0000000000147475E+00, ...
      0.0000000000060851E+00, ...
     -0.0000000000025552E+00, ...
      0.0000000000010906E+00, ...
     -0.0000000000004725E+00, ...
      0.0000000000002076E+00, ...
     -0.0000000000000924E+00, ...
      0.0000000000000417E+00, ...
     -0.0000000000000190E+00, ...
      0.0000000000000087E+00, ...
     -0.0000000000000040E+00, ...
      0.0000000000000019E+00, ...
     -0.0000000000000009E+00, ...
      0.0000000000000004E+00, ...
     -0.0000000000000002E+00, ...
      0.0000000000000001E+00, ...
     -0.0000000000000000E+00 ]';
    eta = 0.1 * r4_mach ( 3 );
    naif = r4_inits ( aifcs, 9, eta );
    naig = r4_inits ( aigcs, 8, eta );
    naip = r4_inits ( aipcs, 34, eta );
    x3sml = eta^0.3333;
    x32sml = 1.3104 * x3sml * x3sml;
    xbig = r4_mach ( 2 )^0.6666;
  end

  if ( x < - 1.0 )
    [ xm, theta ] = r4_aimp ( x );
    value = xm * cos ( theta );
  elseif ( abs ( x ) <= x32sml )
    z = 0.0;
    value = 0.375 + ( r4_csevl ( z, aifcs, naif ) ...
      - x * ( 0.25 + r4_csevl ( z, aigcs, naig ) ) );
  elseif ( abs ( x ) <= x3sml )
    z = 0.0;
    value = 0.375 + ( r4_csevl ( z, aifcs, naif ) ...
      - x * ( 0.25 + r4_csevl ( z, aigcs, naig ) ) );
    value = value * exp ( 2.0 * x * sqrt ( x ) / 3.0 );
  elseif ( x <= 1.0 )
    z = x * x * x;
    value = 0.375 + ( r4_csevl ( z, aifcs, naif ) ...
      - x * ( 0.25 + r4_csevl ( z, aigcs, naig ) ) );
    value = value * exp ( 2.0 * x * sqrt ( x ) / 3.0 );
  elseif ( x < xbig )
    sqrtx = sqrt ( x );
    z = 2.0 / ( x * sqrtx ) - 1.0;
    value = ( 0.28125 + r4_csevl ( z, aipcs, naip ) ) / sqrt ( sqrtx );
  else
    sqrtx = sqrt ( x );
    z = - 1.0;
    value = ( 0.28125 + r4_csevl ( z, aipcs, naip ) ) / sqrt ( sqrtx );
  end

  return
end


function source = nmt_polaritytweak(cfg,source)

inside_idx = find(source.inside);

s = cell2mat(source.avg.mom(inside_idx));
ori = cell2mat(source.avg.ori(inside_idx));

if(isfield(cfg,'toilim'))
    tsel = dsearchn(source.time',cfg.toilim');
    tsel = tsel(1):tsel(2);
else
    [dum,tsel]=max(max(abs(s)));
end

% flip based on polarity of voxel with maximum power in desired time window
[dum,b]=max(nmt_rownorm(s(:,tsel)));
flipper=sign(s(b,tsel)*s(:,tsel)').*speye(size(s,1));
s = flipper*s;
ori = ori*flipper;

for ii=1:size(s,1)
    source.avg.mom{inside_idx(ii)} = s(ii,:);
    source.avg.ori{inside_idx(ii)} = ori(:,ii);
end


classdef Conv3D < dagnn.Filter
  properties
    size = [0 0 0 0]
    hasBias = true
    opts = {'cuDNN'}
  end
  methods
    function outputs = forward(obj, inputs, params)
      if ~obj.hasBias, params{2} = [] ; end

      sz = size(inputs{1}); if numel(sz) < 4, sz(4) = 1; end

      nFrames = sz(4) / obj.net.meta.curBatchSize ;

      inputs{1} = reshape(inputs{1}, sz(1), sz(2), sz(3),  nFrames, sz(4) / nFrames ) ;
      inputs{1} = permute(inputs{1}, [1 2 4 3 5]);
      sz_in = size(inputs{1});

      outputs{1} = mex_conv3d(...
        inputs{1}, params{1}, params{2}, ...
        'pad', obj.pad, ...
        'stride', obj.stride) ;

      outputs{1} = permute(outputs{1}, [1 2 4 3 5]);
      sz_out = size(outputs{1});
      if numel(sz_out) == 4, sz_out(5) = 1; end % fixes the case of single batch
      nFrames = sz_out(4); % reset nframes
      outputs{1} = reshape(outputs{1}, sz_out(1), sz_out(2), sz_out(3),  nFrames*sz_out(5) ) ;

    end

    function [derInputs, derParams] = backward(obj, inputs, params, derOutputs)
      if ~obj.hasBias, params{2} = [] ; end
      sz_in = size(inputs{1}); sz_out = size(derOutputs{1});
      if numel(sz_in) == 3, sz_in(4) = 1; end
      if numel(sz_out) == 3, sz_out(4) = 1; end
      nFramesIn = sz_in(4) / obj.net.meta.curBatchSize ;
      nFramesOut = sz_out(4) / obj.net.meta.curBatchSize ;

      inputs{1} = reshape(inputs{1}, sz_in(1), sz_in(2), sz_in(3),  nFramesIn, sz_in(4) / nFramesIn ) ;
      inputs{1} = permute(inputs{1}, [1 2 4 3 5]);
      derOutputs{1} = reshape(derOutputs{1}, sz_out(1), sz_out(2), sz_out(3),  nFramesOut, sz_out(4) / nFramesOut ) ;
      derOutputs{1} = permute(derOutputs{1}, [1 2 4 3 5]);
      [derInputs{1}, derParams{1}, derParams{2}] = mex_conv3d(...
        inputs{1}, params{1}, params{2}, derOutputs{1}, ...
        'pad', obj.pad, ...
        'stride', obj.stride) ;

      derInputs{1} = permute(derInputs{1}, [1 2 4 3 5]);
      sz_out = size(derInputs{1});
      if numel(sz_out) == 4, sz_out(5) = 1; end % fixes the case of single batch
      nFrames = sz_out(4); % reset nframes

      derInputs{1} = reshape(derInputs{1}, sz_out(1), sz_out(2), sz_out(3),  nFrames*sz_out(5) ) ;

    end

    function kernelSize = getKernelSize(obj)
      kernelSize = obj.size(1:2) ;
    end

    function outputSizes = getOutputSizes(obj, inputSizes)
      outputSizes = getOutputSizes@dagnn.Filter(obj, inputSizes) ;
      outputSizes{1}(3) = obj.size(4) ;
    end

    function params = initParams(obj)
      sc = sqrt(2 / prod(obj.size(1:3))) ;
      params{1} = randn(obj.size,'single') * sc ;
      params{2} = zeros(obj.size(4),1,'single') * sc ;
    end

    function obj = Conv(varargin)
      obj.load(varargin) ;
    end

    function rfs = getReceptiveFields(obj)
      ks = obj.getKernelSize() ;
      y1 = 1 - obj.pad(1) ;
      y2 = 1 - obj.pad(1) + ks(1) - 1 ;
      x1 = 1 - obj.pad(2) ;
      x2 = 1 - obj.pad(2) + ks(2) - 1 ;
      h = y2 - y1 + 1 ;
      w = x2 - x1 + 1 ;
      rfs.size = [h, w] ;
      rfs.stride = obj.stride(1:2) ;
      rfs.offset = [y1+y2, x1+x2]/2 ;
    end

  end
end


function [coherogram,phase,t,f] = bz_MTCoherogram(lfp1,lfp2,varargin)

%MTCoherogram - Compute LFP coherogram by multi-taper estimation.
%
%  USAGE
%
%    [coherogram,phase,t,f] = MTCoherogram(lfp1,lfp2,<options>)
%
%    lfp1,lfp2      wide-band LFPs (one channel each).
%    <options>      optional list of property-value pairs (see table below)
%
%    =========================================================================
%     Properties    Values
%    -------------------------------------------------------------------------
%     'frequency'   sampling rate (in Hz) (default = from timestamps if
%                   available, otherwise 1250Hz)
%     'range'       frequency range (in Hz) (default = all)
%     'window'      duration (in s) of the time window (default = 5)
%     'overlap'     overlap between successive windows (default = window/2)
%     'step'        step between successive windows (default = window/2)
%     'tapers'      relative resolution and order of the tapers [NW K]
%                   (default = [3 5])
%     'pad'         FFT padding (see help for cohgramc) (default = 0)
%     'show'        plot results (default = 'off')
%     'cutoffs'     cutoff values for color plot (default = [0 1])
%    =========================================================================
%
%  NOTES
%
%    The LFP can be provided either as a time stamped matrix (list of time-voltage
%    pairs), or as a voltage vector - in which case the frequency must be specified.
%
%    The time displacement between successive short time coherences can be supplied
%    either as a 'step' (explicit time difference) or as an 'overlap' (between
%    successive time windows).
%
%  OUTPUT
%
%    coherogram     coherogram magnitude
%    phase          coherogram phase
%    t              time bins
%    f              frequency bins
%
%  DEPENDENCIES
%
%    This function requires the chronux toolbox.
%
%  SEE
%
%    See also MTCoherence, MTSpectrum, MTSpectrogram, PlotColorMap.

% Copyright (C) 2010-2014 by Michaël Zugaro
%
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 3 of the License, or
% (at your option) any later version.

% Make sure chronux is installed and functional
CheckChronux('cohgramc');

% Defaults
f = 1250;
frequency = [];
window = 5;
range = [];
overlap = [];
step = [];
show = 'off';
tapers = [3 5];
pad = 0;
cutoffs = [0 1];

% Check number of parameters
if nargin < 2 | mod(length(varargin),2) ~= 0,
  error('Incorrect number of parameters (type ''help MTCoherogram'' for details).');
end

% Check parameter sizes
if size(lfp1,2) ~= 1 && size(lfp1,2) ~= 2,
	error('Parameter ''lfp1'' is not a vector or a Nx2 matrix (type ''help MTCoherogram'' for details).');
end
if size(lfp2,2) ~= 1 && size(lfp2,2) ~= 2,
	error('Parameter ''lfp2'' is not a vector or a Nx2 matrix (type ''help MTCoherogram'' for details).');
end

% Parse parameter list
for i = 1:2:length(varargin),
	if ~ischar(varargin{i}),
		error(['Parameter ' num2str(i+2) ' is not a property (type ''help MTCoherogram'' for details).']);
	end
	switch(lower(varargin{i})),
		case 'frequency',
			frequency = varargin{i+1};
			if ~isdscalar(frequency,'>0'),
				error('Incorrect value for property ''frequency'' (type ''help MTCoherogram'' for details).');
			end
		case 'range',
			range = varargin{i+1};
			if ~isdvector(range,'#2','<','>=0'),
				error('Incorrect value for property ''range'' (type ''help MTCoherogram'' for details).');
			end
		case 'window',
			window = varargin{i+1};
			if ~isdscalar(window,'>0'),
				error('Incorrect value for property ''window'' (type ''help MTCoherogram'' for details).');
			end
		case 'overlap',
			overlap = varargin{i+1};
			if ~isdscalar(overlap,'>0'),
				error('Incorrect value for property ''overlap'' (type ''help MTCoherogram'' for details).');
			end
		case 'step',
			step = varargin{i+1};
			if ~isdscalar(step,'>0'),
				error('Incorrect value for property ''step'' (type ''help MTCoherogram'' for details).');
			end
		case 'tapers',
			tapers = varargin{i+1};
			if ~isivector(tapers,'#2','>0'),
				error('Incorrect value for property ''tapers'' (type ''help MTCoherogram'' for details).');
			end
		case 'pad',
			pad = varargin{i+1};
			if ~isiscalar(pad,'>-1'),
				error('Incorrect value for property ''pad'' (type ''help MTCoherogram'' for details).');
			end
		case 'show',
			show = varargin{i+1};
			if ~isstring_FMAT(show,'on','off'),
				error('Incorrect value for property ''show'' (type ''help MTCoherogram'' for details).');
			end
		case 'cutoffs',
			cutoffs = varargin{i+1};
			if ~isdvector(cutoffs,'#2','>=0','<'),
				error('Incorrect value for property ''cutoffs'' (type ''help MTCoherogram'' for details).');
			end
		otherwise,
			error(['Unknown property ''' num2str(varargin{i}) ''' (type ''help MTCoherogram'' for details).']);
	end
end

% Determine LFP frequency
if isempty(frequency),
	if size(lfp1,2) == 2,
		frequency = 1/median(diff(lfp1(:,1)));
	else
		frequency = f;
	end
end

% Determine step/overlap
if isempty(step),
	if isempty(overlap),
		overlap = window/2;
	end
else
	if isempty(overlap),
		overlap = window-step;
	elseif overlap ~= window-step,
		error('Incompatible ''step'' and ''overlap'' parameters (type ''help MTCoherogram'' for details).');
	end
end

% Compute and plot coherogram
parameters.Fs = frequency;
if ~isempty(range), parameters.fpass = range; end
parameters.tapers = tapers;
parameters.pad = pad;
[coherogram,phase,~,~,~,t,f] = cohgramc(lfp1,lfp2,[window window-overlap],parameters);
% t = t'+lfp1(1,1);
f = f';
coherogram = coherogram';
% coherogram = permute(coherogram,[2 1 3]);  % Previous code by Gabrielle Girardeau, keep it around just in case
phase = phase';
if strcmp(lower(show),'on'),
  figure;hold on;
  subplot(2,1,1);
  PlotColorMap(coherogram,'x',t,'y',f,'cutoffs',cutoffs,'newfig','off');
  xlabel('Time (s)');
  ylabel('Frequency (Hz)');
  title('Coherogram Amplitude');
  subplot(2,1,2);
  PlotColorMap(phase,'x',t,'y',f,'cutoffs',[-pi pi],'newfig','off');
  xlabel('Time (s)');
  ylabel('Frequency (Hz)');
  title('Coherogram Phase');
end


function plot_components_3D_GUI(Y,A,C,b,f,Cn,options)

% GUI for plotting components for the case of 3D volumetric imaging

memmaped = isobject(Y);
defoptions = CNMFSetParms;
if nargin < 7 || isempty(options); options = []; end
if ~isfield(options,'d1') || isempty(options.d1); d1 = input('What is the total number of rows? \n'); else d1 = options.d1; end          % # of rows
if ~isfield(options,'d2') || isempty(options.d2); d2 = input('What is the total number of columns? \n'); else d2 = options.d2; end          % # of columns
if ~isfield(options,'d3') || isempty(options.d2); d3 = input('What is the total number of z-stacks? \n'); else d3 = options.d3; end          % # of columns
if ~isfield(options,'plot_df') || isempty(options.plot_df); options.df = defoptions.plot_df; end
plot_df = options.plot_df;
if ~isfield(options,'full_A') || isempty(options.full_A); full_A = defoptions.full_A; else full_A = options.full_A; end

T = size(C,2);
if ~ismatrix(Y)
    Y = reshape(Y,d1*d2*d3,T);
end
if nnz(A)/numel(A) > 0.3; A = full(A); end
center = com(A,d1,d2,d3);
if size(center,2) == 2
    center(:,3) = 1;
end
center = round(center);
b = double(b);
C = double(C);
f = double(f);
nA = full(sqrt(sum(A.^2))');
[K,~] = size(C);
A = A/spdiags(nA,0,K,K);    % normalize spatial components to unit energy
C = bsxfun(@times,C,nA(:));

nb = size(f,1);     % number of background components

step = 5e3;
if memmaped
    AY = zeros(K,T);
    for j = 1:step:d
        AY = AY + A(j:min(j+step-1,d),:)'*double(Y.Yr(j:min(j+step-1,d),:));
    end
else
    if issparse(A) && isa(Y,'single')
        if full_A
            AY = full(A)'*Y;
        else
            AY = A'*double(Y);
        end
    else
        AY = A'*Y;
    end
end
Y_r = (AY- (A'*A)*C - full(A'*double(b))*f) + C;

if plot_df
    [~,Df] = extract_DF_F(Y,[A,double(b)],[C;f],[],options);
else
    Df = ones(size(A,2)+1,1);
end

fig = figure('Visible','off');
set(gcf,'Position',2*[300,300,960,480]);
set(gcf,'PaperPosition',2*[300,300,960,480]);

thr = 0.95;
minC = max(squeeze(min(min(Cn,[],1),[],2)),0);
maxC = squeeze(max(max(Cn,[],1),[],2));

% Create a figure and axes
% ax = axes('Units','DF/F');
% Create slider

sld = uicontrol('Style', 'slider',...
    'Min',1,'Max',K+nb,'Value',1,'SliderStep',[1/(K+nb-1) 1],...
    'Position', [150 20 800 20],...
    'Callback', @surfzlim);

% Add a text uicontrol to label the slider.
txt = uicontrol('Style','text',...
    'Position',[400 45 120 20],...
    'String','Component');

% Make figure visble after adding all components
fig.Visible = 'on';
plot_component(1)

% This code uses dot notation to set properties.
% Dot notation runs in R2014b and later.
% For R2014a and earlier: set(f,'Visible','on');

    function surfzlim(source,callbackdata)
        i = source.Value;
        plot_component(round(i))
        % For R2014a and earlier:
        % i = get(source,'Value');
    end

    function plot_component(i)
        if i <= K
            %subplot(3,2,5);
             subplot(3,3,7);
            cla
            Atemp = reshape(full(A(:,i)),d1,d2,d3);
            data = smooth3(Atemp);
            patch(isocaps(data,0.25*max(data(:))),...
               'FaceColor','interp','EdgeColor','none');
            p1 = patch(isosurface(data,0.25*max(data(:))),...
               'FaceColor','blue','EdgeColor','none');
            isonormals(data,p1)
            view(3);
            axis vis3d tight
            camlight left;
            %colormap jet
            lighting gouraud
            title(sprintf('Component %i',i),'fontsize',16,'fontweight','bold'); drawnow;
        end
        if i <= K
            %subplot(3,2,5);
             subplot(3,3,[2,5,8]);
            %cla
            Atemp = reshape(full(A(:,i)),d1,d2,d3);
            data = smooth3(Atemp);
            patch(isocaps(data,0.25*max(data(:))),...
               'FaceColor','interp','EdgeColor','none');
            p1 = patch(isosurface(data,0.25*max(data(:))),...
               'FaceColor','blue','EdgeColor','none');
            isonormals(data,p1)
            view(3);
            axis vis3d %tight
            set(gca,'XLim',[1,d1],'YLim',[1,d2],'ZLim',[1,d3]);
            camlight left;
            %colormap jet
            lighting gouraud
            title(sprintf('Components 1 - %i',i),'fontsize',16,'fontweight','bold'); drawnow;
        end
        %subplot(3,2,[1,3]);
        subplot(3,3,[1,4]);
        if i <= K
            cla
            %,[minC(center(i,3)),maxC(center(i,3))]
            imagesc(Cn(:,:,center(i,3)),[minC(center(i,3)),maxC(center(i,3))]); axis equal; axis tight; axis off; hold on; colorbar;
            A_temp = reshape(full(A(:,i)),d1,d2,d3);
            A_temp = A_temp(:,:,center(i,3));
            A_temp = medfilt2(A_temp,[3,3]);
            A_temp = A_temp(:);
            [temp,ind] = sort(A_temp(:).^2,'ascend');
            temp =  cumsum(temp);
            ff = find(temp > (1-thr)*temp(end),1,'first');
            if ~isempty(ff)
                [~,ww] = contour(reshape(A_temp,d1,d2),[0,0]+A_temp(ind(ff)),'LineColor','k');
                ww.LineWidth = 2;
            end
            title(sprintf('Component %i, z-plane %i',i,center(i,3)),'fontsize',16,'fontweight','bold'); drawnow; %pause;
        else
            cla
            b_temp = reshape(b(:,i-K),d1,d2,d3);
            imagesc(b_temp(:,:,ceil(d3/2))); axis equal; axis tight;
            title(['Background component, z-plane',num2str(ceil(d3/2))],'fontsize',16,'fontweight','bold'); drawnow;
        end
        %subplot(3,2,[2,4,6]);
        subplot(3,3,[3,6,9]);
        if i <= K
            plot(1:T,Y_r(i,:)/Df(i),'linewidth',2); hold all; plot(1:T,C(i,:)/Df(i),'linewidth',2);
            if plot_df
                title(sprintf('Component %i (calcium DF/F value)',i),'fontsize',16,'fontweight','bold');
            else
                title(sprintf('Component %i (calcium raw value)',i),'fontsize',16,'fontweight','bold');
            end
            leg = legend('Raw trace (filtered)','Inferred');
            set(leg,'FontSize',14,'FontWeight','bold');
            title(sprintf('Component %i',i),'fontsize',16,'fontweight','bold'); drawnow; %pause;
            drawnow;
            hold off;
        else
            plot(1:T,f(i-K,:)); title('Background activity','fontsize',16,'fontweight','bold');
            drawnow;
        end
    end
end