function h = sysViewer(oPar, cPar, fcn, typ, varargin)
%sysViewer Dynamical system graphical interface.
%   h = sysViewer(oPar, cPar, fcn, typ) builds a GUI for viewing the
%   effects of parameter changes on a one- or two-dimensional dynamical
%   system.
%
%   oPar and cPar are two-column cell arrays that define the order
%   parameter and control parameter(s), respectively. The first column
%   contains parameter names (strings to be typeset in latex). The second
%   column contains 1x2 vectors of parameter's range. This vector defines
%   plot axes limits for the order parameter and slider limits for the
%   control parameters.
%
%   The system is defined by the function handle fcn. For one-dimensional
%   systems, this should be a function with two inputs and one output. The
%   first input is system state, which will be a scalar in a one-
%   dimensional system. The second input is a vector of control parameter
%   values. The output of fcn can be either the rate of change of the order
%   parameter (in which case fcn is the flow equation), or the system
%   potential (in which case fcn is the potential function). Which function
%   is supplied can be indicated by the last input typ, one of the strings
%   'flow' or 'potential'. If typ is empty or omitted, 'flow' is the
%   default.
%
%   For two-dimensional systems defined with a flow, fcn should be a cell
%   array containing two function handles, each outputting the rate of
%   change along one dimension. Each function should take three inputs; the
%   first two are scalar values of the order parameters, the third is a
%   vector of control parameters. For two-dimensional systems defined with
%   a potential, fcn should take inputs as above and output a scalar.
%
%   The output h is a struct containing handles to the graphics objects in
%   the GUI. Intended only for advanced tweaking or troubleshooting.
%
%   sysViewer(..., defs) initializes the parameter sliders with the default
%   values in vector defs.
%
%   sysViewer(..., 'vectorize') speeds up computation for functions that
%   cannot be evaluated with a vector. In fact, any number of trailing
%   arguments will be passed to chebfun. See CHEBFUN for more options
%   (CHEBFUN2 and CHEBFUN2V for two-dimensional options).
%
% --------
% Examples:
%   ------
%   One-dimensional
%   ---
%   sysViewer({'\phi' [-pi pi]}, ...
%             {'b/a' [0 1]; '\Delta\omega' [-2 2]}, ...
%             @(x,c) c(2)*x-cos(x)-c(1)*cos(2*x), ...
%             'potential');
%
%   sysViewer({'\phi' [-pi pi]}, ...
%             {'b/a' [0 1]; '\Delta\omega' [-2 2]}, ...
%             @(x,c) c(2)-sin(x)-2*c(1)*sin(2*x), ...
%             'flow');
%
%   sysViewer({'\phi' [-pi pi]}, ...
%             {'b/a' [0 1]; '\Delta\omega' [-2 2]; 'c' [0 .5]; 'd' [0 .5]}, ...
%             @(x,c) c(2)*x-cos(x)-c(1)*cos(2*x)+c(3)*sin(x)+c(4)*sin(2*x), ...
%             'potential');
%
%   sysViewer({'\phi' [-pi pi]}, ...
%             {'b/a' [0 1]; '\Delta\omega' [-2 2]; 'c' [0 .5]; 'd' [0 .5]}, ...
%             @(x,c) c(2)-sin(x)-2*c(1)*sin(2*x)+c(3)*cos(x)+2*c(4)*cos(2*x), ...
%             'flow');
%   ------
%   Two-dimensional
%   ---
%   sysViewer('x' [-5 5]; '\dot{x}' [-5 5]}, ...
%             [{'\alpha'; '\beta'; '\delta'} repmat({[-5 5]}, 3, 1)], ...
%             {@(x,dx,r) dx, @(x,dx,r) -r(1).*x.^3 - r(2).*x - r(3).*dx}, ...
%             'flow')
%
%--------
% Dependencies (if missing, user will be prompted to download and install):
%   GUI Layout Toolbox
%   sliderPanel
%   uibutton
%   Chebfun:
%   -  Stable version (one-dimensional systems only)
%   -  Alpha release (required for viewing two-dimensional systems)
%   (as of March 14 2013)

%--------
% Henry S. Harrison
%
% Center for the Ecological Study of Perception and Action
% University of Connecticut
% henry.harrison@uconn.edu
% henry.schafer.harrison@gmail.com
%
% TO DO
%  - annottate 2D plots
%  - make into an app; wizard to set inputs?
%  - re-docking broken
%  - remove lAx
%  - prevent blinking
%  - make plots expand upon undocking sliders
%  - make tspan customizable/adaptive
%  - replace 2d annotations
%  - label 2d fixed pts?
%  - 3D vector fields
%  - some 2D systems get caught up in singularities
%  - some trajectories won't generate
%
% v1.1.1   3/14/2013
% - cleaned up dependency messages for chebfun
% - added dialog to inform user of plotting solution trajectories
% - added legend for 2D flow
%
% v1.1     3/8/2013
% - fixed stems overlapping label boxes
% - two dimensions!
%
% v1       6/7/2012
%  - added current state line to bifurcation diagram
%
% v0.9.6   5/26/2012
%  - improved bifurcation diagram generation
%  - added option to use parrallel computing toolbox
%
% v0.9.5   5/25/2012
%  - bifurcation diagrams!
%
% v0.9.1   5/22/2012
%  - fixed error that occurred when figure was updated too fast, by making
%    the sliders not interruptible
%  - no longer relabel axes with every update
%
% v0.9     5/21/2012
%  - revamped computations to take advantage of chebfun package
%  - revamped GUI to display flow and potential together
%  - made control panel undockable
%  - included requireFEXpackage to install dependencies
%
% v0.6.2   5/18/2012
%  - fixed overlapping label stems
%
% v0.6.1   2/20/2012
%  - improved method of determining fixed points in flow diagram
%
% v0.6     2/19/2012
%  - added text edit boxes for control parameters using sliderPanel
%
% v0.5.1   2/18/2012
%  - improved fixed point and lambda estimation using Adaptive Robust
%    Numerical Differentation (at some expense of speed)
%
% v0.5.0   2/15/2012
%  - initial version

%Globals
tbarBuffer     = 39;  % px
sldrHeight     = 20;  % px
sldrPad        = 50;  % px
sPanelPad      = 20;  % px
xAxisNudge     = 10;  % px
yAxisNudge     = 12;  % px
lblMargin      = 3;   % px
txtPad         = 10;  % px
axPadding      = 100; % px
axSpacing      = 0;   % px
lAxHeight      = 200; % px
titleBarHeight = 35;  % px
fSize                = 14;  % pt
fSizeLabel           = 12;  % pt
fSizeFixPt           = 12;  % pt
pLineWidth           = 2;   % pt
zLineWidth           = 1;   % pt
lblLineWidth         = 1;   % pt
fixedPtSize          = 10;  % pt
fixedPtWidth         = 2;   % pt
biDiagramWidth       = 2;   % pt
biDiagramCurValWidth = 1;   % pt
nullclineWidth       = 1;   % pt
quiverLineWidth      = .5;  % pt
quiverMarkerSize     = 1.5; % pt
solLineWidth         = .5;  % pt
solMarkerSize        = 1.5; % pt
sldrWidth    = .25;       % proportion of screensize
maxArrowSize = .05;       % proportion of range
minArrowSize = .01;       % proportion of range
sliderStep   = [.005 .1]; % proportion of range
biRes        = 500;
tspan = [0 20 2];
tspanSliderStep = [.1/20 1/20];
latexFlag = true;
warnSim   = true;
anyDefs   = false;
font                 = 'Times New Roman';
fixedPtColor         = 'r';
fixedPtBgColor       = 'w';
bgColor              = 'w';
halfStableLineSpec   = '*';
arrowColor           = 'k';
biDiagramRepStyle    = ':';
biDiagramColor       = 'r';
biDiagramCurValStyle = 'k:';
xNullclineStyle      = 'k:';
yNullclineStyle      = 'k--';
quiverLineStyle      = 'bo-';
quiverColor          = 'b';
solColor             = 'k';
saddleStyle          = 'r*';
stableStyle          = 'ro';
stableFill           = 'r';
unstableStyle        = 'ro';
unstableFill         = 'w';
centerStyle          = 'r.';
solLineStyle         = 'k';
solStartStyle        = 'ko';
defType              = 'flow';
waitPtr              = 'watch';
normPtr              = 'arrow';
tspanStr             = 'Solution Length:';
scrsz     = get(0, 'ScreenSize');
sldrWidth = sldrWidth*scrsz(3);
dependencies = {'uiextras.HBox', 27758, 'class'; ...
                'sliderPanel'  , 13845, 'file'; ...
                'chebfun'      , 23972, 'file'; ...
                'uibutton'     , 10743, 'file'};

% Check inputs
assert((isempty(cPar) || (iscell(cPar) && size(cPar,2) == 2)) && ...
    iscell(oPar) && size(oPar,2) == 2, ...
    'sysViewer:badParams', ['OPAR and CPAR must be cell arrays with' ...
    ' 2 columns.']);
cellfun(@(x) assert(ischar(x), 'sysViewer:badParamName', ...
    ['The first column of OPAR and CPAR must contain strings ' ...
    '(parameter names).']), oPar(:,1));
cellfun (@(x) assert(isnumeric(x) && numel(x) == 2, ...
    'sysViewer:badParamRange', ['The second column of OPAR and ' ...
    'CPAR must contain vectors of length 2 (parameter ranges).']), ...
    oPar(:,2));
if ~isempty(cPar)
    cellfun(@(x) assert(ischar(x), 'sysViewer:badParamName', ...
        ['The first column of OPAR and CPAR must contain strings ' ...
        '(parameter names).']), cPar(:,1));
    cellfun (@(x) assert(isnumeric(x) && numel(x) == 2, ...
        'sysViewer:badParamRange', ['The second column of OPAR and ' ...
        'CPAR must contain vectors of length 2 (parameter ranges).']), ...
        cPar(:,2));
end

O = size(oPar,1);
C = size(cPar,1);
if ~exist('typ', 'var') || isempty(typ), typ = defType; end
assert(any(strncmpi(typ, {'flow' 'potential'}, length(typ))), ...
        'sysViewer:badType', 'TYP must be ''Flow'' or ''Potential''.');
if iscell(fcn)
    assert(all(cellfun(@(f) isa(f, 'function_handle'), fcn)), ...
        'sysviewer:badfunction', ['Each element of fcn must be a ' ...
        'function handle']);
    if numel(fcn) == 1
        fcn = fcn{1};
    elseif numel(fcn) == 2
        assert(O == 2, 'sysviewer:badfunction', ['Too many elements ' ...
            'in cell array fcn.']);
        assert(~strncmpi(typ, 'potential', length(typ)), ...
            'sysviewer:badfunction', ...
            'A fcn with multiple outputs cannot describe a potential');
    end
else
    assert(isa(fcn, 'function_handle'), 'sysviewer:badfunction', ...
        ['fcn must be a function handle or cell array of function ' ...
        'handles.']);
    assert(strncmpi(typ, 'potential', length(typ)) || O == 1, ...
        'sysviewer:badfunction', ['The flow in dimensions > 1 must be ' ...
        'defined with a cell array.']);
end
if O == 1
else
    assert(O<3, 'sysViewer:tooManyDims', ['Only systems with two or ' ...
        'fewer order parameters are currently supported.']);
    if strncmpi(typ, 'flow', length(typ))
        typ = 'flow2';
    else
        typ = 'pot2';
    end
end
if exist('varargin', 'var') && ~isempty(varargin) && isnumeric(varargin{1})
    defs = varargin{1};
    assert(numel(defs) == C, 'sysViewer:badNumDefaults', ['Parameter ' ...
        'defaults (input defs) must have the same length as the ' ...
        'number of control parameters.']);
    arrayfun(@(i) assert(cPar{i,2}(1) <= defs(i) ...
        && defs(i) <= cPar{i,2}(2), 'sysViewer:defaultOutOfRange', ...
        sprintf('Element #%u of defs is out of range given in cPar{%u,2}.', ...
        i, i)), 1:C);
    anyDefs = true;
    varargin(1) = [];
end

% Check dependencies
n = size(dependencies, 1);
for i = 1:n %#ok<*FORPF>
   % read function name and FEX package ID
   dep_fun  = dependencies{i,1};
   dep_pack = dependencies{i,2};
   dep_kind = dependencies{i,3};
   % if the function does not exist in your Matlab path,
   % downloaded and install the FEX package containing that function.
   if ~exist(dep_fun, dep_kind)
       if strcmp(dep_fun, 'chebfun')
           helpdlg({['Chebfun package not found. Also, chebfun2 is required ' ...
               'for viewing 2-D systems, and is only available as an ' ...
               'alpha release (as of 3/14/2013). With the stable ' ...
               'version, only 1-D systems can be viewed.'] '' ...
               'The alpha release can be found at ' ...
               'http://www2.maths.ox.ac.uk/chebfun/chebfun2/'
               'The stable  release can be found at ' ...
               'http://www.mathworks.com/matlabcentral/fileexchange/23972' ...
               '' ['The automatic installer will install the stable ' ...
               'release. Press NO on the next dialog if you would ' ...
               'prefer the alpha with chebfun2.']}, 'Chebfun help');
       else
           P = requireFEXpackage(dep_pack);
           if isempty(P)
               error('sysViewer:missingDependency',  ...
                   ['Dependency missing; install failed or was aborted ' ...
                   '(Mathworks.com File Exchange ID# %u).'], dep_pack);
           end
       end
   end
end

% Check chebfun2
if O>1
    assert(exist('chebfun','file')>0,'sysViewer:missingChebfun2', ...
        ['Missing chebfun2 package, ' ...
        '2-D functions will not be available. ' ...
        'You may download chebfun2 at ' ...
        'http://www2.maths.ox.ac.uk/chebfun/chebfun2/ \n\n' ...
        'Note that you may have to delete your existing chebfun installation. ' ...
        'As of March 14 2013, chebfun2 is only available as an ' ...
        'alpha release. With the stable version, ' ...
        'sysviewer can only display one-dimensional systems.'])
end

% Create figure using GUI Layout Toolbox
h.f = figure( ...
    'Name'           , 'System Viewer', ...
    'OuterPosition'  , scrsz + [0 tbarBuffer 0 -tbarBuffer], ...
    'MenuBar'        , 'figure', ...
    'ToolBar'        , 'figure', ...
    'Color'          , bgColor, ...
    'CloseRequestFcn', @closeFcn, ...
    'Visible'        , 'off');
h.split = uiextras.HBox( ...
    'Parent'         , h.f, ...
    'Units'          , 'normalized', ...
    'Position'       , [0 0 1 1], ...
    'BackgroundColor', bgColor);
h.leftSplit = uiextras.VBox( ...
    'Parent'         , h.split, ...
    'Units'          , 'normalized', ...
    'Position'       , [0 0 1 1], ...
    'BackgroundColor', bgColor);
h.sBox = uiextras.BoxPanel( ...
    'Parent'         , h.leftSplit, ...
    'Title'          , 'Control parameters', ...
    'FontName'       , font, ...
    'FontSize'       , fSize, ...
    'Units'          , 'normalized', ...
    'Position'       , [0 0 1 1], ...
    'BackgroundColor', bgColor, ...
    'DockFcn'        , @dockPanel);
h.sPanel = uiextras.VBox( ...
    'Parent'         , h.sBox, ...
    'Units'          , 'normalized', ...
    'Position'       , [0 0 1 1], ...
    'Padding'        , sPanelPad/2, ...
    'Spacing'        , sPanelPad, ...
    'BackgroundColor', bgColor);
h.axPanel = uipanel( ...
    'Parent'         , h.split, ...
    'Units'          , 'normalized', ...
    'Position'       , [0 0 1 1], ...
    'BackgroundColor', bgColor);
h.axSplit = uiextras.VBox( ...
    'Parent'         , h.axPanel, ...
    'Units'          , 'normalized', ...
    'Position'       , [0 0 1 1], ...
    'BackgroundColor', bgColor, ...
    'Padding'        , axPadding, ...
    'Spacing'        , axSpacing);
h.fAx = axes( ...
    'Parent'         , double(h.axSplit), ...
    'FontName'       , font, ...
    'FontSize'       , fSize, ...
    'Units'          , 'normalized', ...
    'Position'       , [0 0 1 1], ...
    'NextPlot'       , 'replacechildren', ...
    'XLim'           , oPar{1,2}, ...
    'xAxisLocation'  , 'top');
if O == 1
    h.lAx = axes( ...
        'Parent'          , double(h.axSplit), ...
        'Units'           , 'normalized', ...
        'Position'        , [0 0 1 1], ...
        'NextPlot'        , 'replacechildren', ...
        'Visible'         , 'off', ...
        'XLim'            , oPar{1,2}, ...
        'YLim'            , [-1 1]);
    h.pAx = axes( ...
        'Parent'         , double(h.axSplit), ...
        'FontName'       , font, ...
        'FontSize'       , fSize, ...
        'Units'          , 'normalized', ...
        'Position'       , [0 0 1 1], ...
        'NextPlot'       , 'replacechildren', ...
        'XLim'           , oPar{1,2});
    h.sAx = axes( ...
        'Parent'         , h.axPanel, ...
        'Units'          , 'Normalized', ...
        'Position'       , [0 0 1 1], ...
        'XLim'           , [0 1], ...
        'YLim'           , [0 1], ...
        'Visible'        , 'off', ...
        'NextPlot'       , 'replacechildren');
    h.axSplit.Sizes = [-1 lAxHeight -1];
    linkaxes([h.fAx h.lAx h.pAx], 'x');
    h.axLink = linkprop([h.fAx h.lAx h.pAx h.sAx], {'NextPlot'});
elseif strcmpi(typ, 'pot2')
        h.pAx = axes( ...
        'Parent'         , double(h.axSplit), ...
        'FontName'       , font, ...
        'FontSize'       , fSize, ...
        'Units'          , 'normalized', ...
        'Position'       , [0 0 1 1], ...
        'NextPlot'       , 'replacechildren', ...
        'XLim'           , oPar{1,2});
    h.axSplit.Sizes = [-1 -1];
end
if O == 2
    set(h.fAx, ...
        'YLim'           , oPar{2,2}, ...
        'ButtonDownFcn'  , @flowClickFcn);
end
h.split.Sizes = [sldrWidth + 2*sldrPad -1];

% Create sliders
if C > 0
    h.cSlider = nan(C, 1);
    h.cEdit   = h.cSlider;
    h.cPanel  = h.cSlider;
    h.cLabel  = h.cSlider;
    panelOpt.Units = 'pixels';
    sliderOpt.Callback      = @update;
    sliderOpt.Units         = 'pixels';
    sliderOpt.Position      = [sldrPad 3*sldrPad/4 sldrWidth sldrHeight];
    sliderOpt.SliderStep    = sliderStep;
    sliderOpt.Enable        = 'off';
    sliderOpt.Interruptible = 'off';
    sliderOpt.BusyAction    = 'cancel';
    editOpt.FontSize = fSizeLabel;
    editOpt.FontName = font;
    editOpt.Enable   = 'off';
    % Each control parameter gets a sliderPanel
    for i = 1:C
        sliderOpt.min    = cPar{i,2}(1);
        sliderOpt.max    = cPar{i,2}(2);
        if anyDefs
            sliderOpt.value = defs(i);
        else
            sliderOpt.value  = (cPar{i,2}(2) + cPar{i,2}(1))/2;
        end
        [h.cSlider(i), h.cPanel(i), h.cEdit(i)] = sliderPanel( ...
            h.sPanel, panelOpt, sliderOpt, editOpt, {...
            {'FontSize'   , fSizeLabel, ...
            'FontName'   , font, ...
            'String'     , sprintf('$\\,\\,\\,\\,%s=$', cPar{i,1})} ...
            {'String'     , ''} });
        % We have to get handles for the labels manually
        h.cLabel(i) = findobj(get(h.cPanel(i), 'Children'), 'flat', ...
            'String'     , sprintf('$\\,\\,\\,\\,%s=$', cPar{i,1}) );
    end
    set(h.sBox, ...
        'TitleColor'     , get(h.cPanel(1), 'BackgroundColor'));
    % We also have to find the handle for the dock button in order to get its
    % background to match
    set(findall(allchild(double(h.sBox)), ...
        'Tag'            , 'uiextras:BoxPanel:DockButton'), ...
        'BackgroundColor', get(h.cPanel(1), 'BackgroundColor'));
    set(h.sPanel, ...
        'Sizes'          , ones(size(h.cPanel))*(sldrHeight+sldrPad));
    for i = 1:C
        h.cLabel(i) = uibutton(h.cLabel(i), ...
            'Style'      , 'text', ...
            'Interpreter', 'latex');
    end

    % try to convert paramter labels from latex to html
    biStrings = cPar(:,1);
    if latexFlag
        biStrings = cellfun(@(x) sprintf('%s', ...
            regexprep(x, '\', '&')), biStrings, ...
            'UniformOutput', false);
    end
end

% 2D flow legend and slider
if O == 2
    sliderOpt.Callback    = [];
    sliderOpt.Enable      = 'on';
    sliderOpt.min         = tspan(1);
    sliderOpt.max         = tspan(2);
    sliderOpt.value       = tspan(3);
    sliderOpt.SliderStep  = tspanSliderStep;
    [h.tSlider, h.tPanel, h.tEdit] = sliderPanel( ...
        h.sPanel, panelOpt, sliderOpt, editOpt, {...
        {'FontSize'      , fSizeLabel, ...
        'FontName'       , font, ...
        'String'         , tspanStr} ...
        {'String'        , ''} });
    h.legAx = axes('Parent', double(h.sPanel), ...
        'Visible'        , 'off', ...
        'NextPlot'       , 'add');
    set(h.sPanel, ...
        'Sizes'          , [ones(size(h.cPanel));1;3].*(sldrHeight+sldrPad));
    h.legPlots(1) = plot(h.legAx, 0, 0, stableStyle, ...
        'MarkerSize'     , fixedPtSize, ...
        'MarkerFaceColor', stableFill);
    h.legPlots(2) = plot(h.legAx, 0, 0, unstableStyle, ...
        'MarkerSize'     , fixedPtSize, ...
        'MarkerFaceColor', unstableFill);
    h.legPlots(3) = plot(h.legAx, 0, 0, saddleStyle, ...
        'MarkerSize'     , fixedPtSize);
    h.legPlots(4) = plot(h.legAx, 0, 0, centerStyle,...
        'MarkerSize'     , fixedPtSize);
    h.legPlots(5) = plot(h.legAx,  [0 0], [1 1], xNullclineStyle, ...
        'LineWidth'      , nullclineWidth);
    h.legPlots(6) = plot(h.legAx,  [0 0], [1 1], yNullclineStyle, ...
        'LineWidth'      , nullclineWidth);
    xlim(h.legAx, [2 3]);
    ylim(h.legAx, [2 3]);
    h.flowLeg = legend(h.legPlots, 'Stable', 'Unstable', 'Saddle', 'Center', ...
        sprintf('$%s=0$ nullcline', oPar{1,1}), ...
        sprintf('$%s=0$ nullcline', oPar{2,1}));
    % Replace with latex strings
    if latexFlag
        set(findobj(get(h.flowLeg, 'Children'), ...
            'Type'           , 'Text'), ...
            'Interpreter'    , 'latex', ...
            'FontSize'       , fSize);
        % Don't know why, needs to be done twice
        set(findobj(get(h.flowLeg, 'Children'), ...
            'Type'           , 'Text'), ...
            'Interpreter'    , 'latex', ...
            'FontSize'       , fSize);
    end
end

% Menu
h.menu.top = uimenu(h.f, ...
    'Enable'         , 'off', ...
    'Label'          , 'sysViewer');
h.menu.bi = uimenu(h.menu.top, ...
    'Label'          , 'Generate Bifurcation Diagram...', ...
    'Callback'       , @bifurcation, ...
    'Interruptible'  , 'off', ...
    'BusyAction'     , 'cancel');
if O > 1 || C == 0
    set(h.menu.bi, ...
        'Enable'     , 'off');
end
hasPar = ~isempty(ver('distcomp'));
if hasPar
    strEn = 'on';
    parOn = logical(matlabpool('size'));
    if parOn, strChk = 'on'; else strChk = 'off'; end
else
    strEn  = 'off';
    strChk = 'off';
    parOn = false;
end
turnedParOn = false;
h.menu.par = uimenu(h.menu.top, ...
    'Label'          , 'Use Parallel Computing', ...
    'Checked'        , strChk, ...
    'Enable'         , strEn, ...
    'Callback'       , @parMenu);

% Construct anonymous parametrize function (freeze), so that going forward
% the flow and potential cases will be unified
% Freeze builds flow and potential chebfuns from a vector of control
% parameter values. Usage:
%   [flow pot] = freeze(params);
freeze = @(c) parametrize(fcn, [oPar{:,2}], c, typ, varargin);

% Initialize and make figure visible
update(h.f, [], true);
set(h.f, ...
    'ResizeFcn'      , {@update true}, ...
    'Visible'        , 'on');

    function update(~, ~, annotate)
        % Updates plot

        % Sometimes update gets called while closing figure...
        if ~ishandle(h.f) || strcmpi(get(h.f, 'BeingDeleted'), 'on')
            return
        end

        % Block user input
        if C > 0
            set([h.cSlider; h.cEdit; h.menu.top], ...
                'Enable'         , 'off');
        end
        set(h.f, ...
            'Pointer'        , waitPtr);

        % Get slider values and construct string for the title
        if C > 0
            c = nan(1, C);
            cParStr = [];
            for j = 1:C
                c(j) = get(h.cSlider(j), 'Value');
                if j>1, cParStr = [cParStr ', ']; end %#ok<AGROW>
                cParStr = sprintf('%s$%s=%0.3g$', cParStr, cPar{j,1}, c(j));
            end
        else
            c = [];
        end

        % Freeze control parameter values
        [flow, pot] = freeze(c);

        if O == 1
            % 1D systems

            % Compute fixed points
            flowSlope = diff(flow);
            fixedPts  = roots(flow);
            lambda    = flowSlope(fixedPts);

            % Clear axes. Set axes to manual to prevent figure from jumping
            set([h.fAx h.pAx], ...
                'YLimMode'       , 'manual');
            toDelete = allchild([h.fAx h.pAx h.lAx h.sAx]);
            toDelete = vertcat(toDelete{:});
            if exist('annotate', 'var') && annotate
                notToDelete = [];
            else
                notToDelete = [h.fxLbl h.fyLbl h.pxLbl h.pyLbl h.zero];
            end
            delete(setdiff(toDelete, notToDelete));

            % Draw functions
            if exist('annotate', 'var') && annotate
                h.zero = plot(h.fAx, oPar{1,2}, [0 0], 'k:', ...
                    'LineWidth'  , zLineWidth);
            end
            set(h.fAx, ...
                'NextPlot'       , 'add');
            h.flow = plot(h.fAx, flow, 'k', ...
                'LineWidth'      , pLineWidth);
            h.pot  = plot(h.pAx, pot, 'k', ...
                'LineWidth'      , pLineWidth);

            % Mark fixed points
            h.fRepellers = plot(h.fAx, fixedPts(lambda>0), ...
                zeros(size(fixedPts(lambda>0))), 'o', ...
                'MarkerSize'     , fixedPtSize, ...
                'LineWidth'      , fixedPtWidth, ...
                'Color'          , fixedPtColor, ...
                'MarkerFaceColor', 'w');
            h.pRepellers = plot(h.pAx, fixedPts(lambda>0), ...
                pot(fixedPts(lambda>0)), 'o', ...
                'MarkerSize'     , fixedPtSize, ...
                'LineWidth'      , fixedPtWidth, ...
                'Color'          , fixedPtColor, ...
                'MarkerFaceColor', 'w');
            h.fAttractors = plot(h.fAx, fixedPts(lambda<0), ...
                zeros(size(fixedPts(lambda<0))), 'o', ...
                'MarkerSize'     , fixedPtSize, ...
                'LineWidth'      , fixedPtWidth, ...
                'Color'          , fixedPtColor, ...
                'MarkerFaceColor', fixedPtColor);
            h.pAttractors = plot(h.pAx, fixedPts(lambda<0), ...
                pot(fixedPts(lambda<0)), 'o', ...
                'MarkerSize'     , fixedPtSize, ...
                'LineWidth'      , fixedPtWidth, ...
                'Color'          , fixedPtColor, ...
                'MarkerFaceColor', fixedPtColor);
            h.fHalfStable = plot(h.fAx, fixedPts(lambda==0), ...
                zeros(size(fixedPts(lambda==0))), halfStableLineSpec, ...
                'MarkerSize'     , fixedPtSize, ...
                'LineWidth'      , fixedPtWidth, ...
                'Color'          , fixedPtColor);
            h.pHalfStable = plot(h.pAx, fixedPts(lambda==0), ...
                pot(fixedPts(lambda==0)), halfStableLineSpec, ...
                'MarkerSize'     , fixedPtSize, ...
                'LineWidth'      , fixedPtWidth, ...
                'Color'          , fixedPtColor);

            % Info we'll need to draw stems later
            set(h.fAx, ...
                'Units'   , 'normalized', ...
                'YLimMode', 'auto');
            set(h.pAx, ...
                'Units'   , 'normalized', ...
                'YLimMode', 'auto');
            set(h.lAx, ...
                'Units'   , 'normalized');
            fPos = get(h.fAx, 'Position');
            pPos = get(h.pAx, 'Position');
            lPos = get(h.lAx, 'Position');
            fYlim = ylim(h.fAx);
            pYlim = ylim(h.pAx);
            lXlim = xlim(h.lAx);

            % Labels will go in lAx
            set(gcf, ...
                'CurrentAxes'    , h.sAx);
            j = 0;
            h.lblTxt  = nan(size(fixedPts));
            h.lblStem = nan(size(fixedPts));
            while numel(fixedPts) > j
                j = j+1;

                % Draw stem
                xLblPos = lPos(1) + ...
                    lPos(3)*(fixedPts(j)-lXlim(1))/diff(lXlim);
                yLblPos = [fPos(2) - fPos(4)*fYlim(1)/diff(fYlim) ...
                    pPos(2)+pPos(4)*(pot(fixedPts(j))...
                    - pYlim(1))/diff(pYlim)];
                h.lblStem(j) = plot(h.sAx, [xLblPos xLblPos], ...
                    yLblPos, ':', ...
                    'Color'    , fixedPtColor, ...
                    'LineWidth', lblLineWidth);

                % Write text
                h.lblTxt(j) = text(xLblPos, lPos(2) + lPos(4)/2, ...
                    {sprintf('$%s^*\\approx %0.3g$', ...
                    oPar{1,1}, fixedPts(j)) ...
                    sprintf('$\\lambda\\approx %0.3g$', lambda(j))}, ...
                    'Interpreter'        , 'latex', ...
                    'FontName'           , font, ...
                    'FontSize'           , fSizeFixPt, ...
                    'HorizontalAlignment', 'center', ...
                    'VerticalAlignment'  , 'middle', ...
                    'EdgeColor'          , fixedPtColor, ...
                    'LineWidth'          , lblLineWidth, ...
                    'Units'              , 'data', ...
                    'BackgroundColor'    , fixedPtBgColor, ...
                    'Margin'             , lblMargin);

                % Move text
                set(h.lblTxt(j), ...
                    'Units'              , 'pixels');
                pos = get(h.lblTxt(j), 'Extent');
                set(h.lblTxt(j), ...
                    'HorizontalAlignment', 'left', ...
                    'Position'           , pos(1:2) + [0 fSizeLabel*4/3]);

                % Ensure labels don't overlap
                k = j-1;
                while k>0
                    set(h.lblTxt(k), ...
                        'Units'       , 'pixels');
                    lExt = get(h.lblTxt(k), 'Extent');
                    rExt = get(h.lblTxt(j), 'Extent');
                    if  lExt(1)+lExt(3)+txtPad > rExt(1) ...
                            && lExt(2)+lExt(4)+txtPad > rExt(2) ...
                            && rExt(2)+rExt(4)+txtPad > lExt(2)
                        pos = get(h.lblTxt(j), 'Position');
                        pos(2) = pos(2) + lExt(4) + txtPad;
                        set(h.lblTxt(j), ...
                            'Position', pos);
                        k = j-1;
                    else
                        k = k-1;
                    end
                end
            end

            % Draw flow arrows - in the flow axis
            set(h.f, ...
                'CurrentAxes', h.fAx);
            bounds   = [oPar{1,2}(1) fixedPts' oPar{1,2}(2)];
            midPts   = bounds(1:end-1) + diff(bounds)/2;
            vels     = flow(midPts);
            scale    = maxArrowSize * diff(oPar{1,2}) / max(abs(vels));
            minSize  = minArrowSize * diff(oPar{1,2});
            aspect   = diff(oPar{1,2})/diff(ylim(h.fAx));
            h.arrows = arrayfun(@(x,y) fill([x x x+aspect*y/2], ...
                [-y/2 y/2 0], arrowColor), midPts, ...
                sign(vels).*max(scale*abs(vels), minSize));

            % Put fixed points above arrows
            uistack(h.arrows, 'bottom');

            % Annotate
            h.title = title (h.fAx, cParStr, ...
                'Interpreter', 'latex');
            if exist('annotate', 'var') && annotate
                h.fxLbl = xlabel(h.fAx, sprintf('$%s$', oPar{1,1}), ...
                    'Interpreter', 'latex', ...
                    'Units'      , 'pixels');
                h.pxLbl = xlabel(h.pAx, sprintf('$%s$', oPar{1,1}), ...
                    'Interpreter', 'latex', ...
                    'Units'      , 'pixels');
                h.fyLbl = ylabel(h.fAx, sprintf('$\\dot{%s}$', oPar{1,1}), ...
                    'Interpreter', 'latex', ...
                    'Rotation'   , 0, ...
                    'Units'      , 'pixels');
                h.pyLbl = ylabel(h.pAx, 'Potential $V$', ...
                    'Interpreter', 'latex', ...
                    'Units'      , 'pixels');
                % Adjust
                fxPos = get(h.fxLbl, 'Position');
                pxPos = get(h.pxLbl, 'Position');
                fyPos = get(h.fyLbl, 'Position');
                pyPos = get(h.pyLbl, 'Position');
                fxPos(2) = fxPos(2) + xAxisNudge;
                pxPos(2) = pxPos(2) - xAxisNudge;
                fyPos(1) = fyPos(1) - yAxisNudge;
                pyPos(1) = pyPos(1) - yAxisNudge;
                set(h.fxLbl, ...
                    'Position'   , fxPos);
                set(h.pxLbl, ...
                    'Position'   , pxPos);
                set(h.fyLbl, ...
                    'Position'   , fyPos);
                set(h.pyLbl, ...
                    'Position'   , pyPos);
            end

            % Update biDiagram
            if isfield(h, 'biPars')
                if all(find(c~=h.biPars) == h.biIdx)
                    % parameters are same as bifurcation diagram
                    if isfield(h, 'biParValLine') ...
                    && ishandle(h.biParValLine)
                        set(h.biParValLine, ...
                            'XData', c(h.biIdx)*ones(1,2));
                    end
                else % parameters have changed
                    if isfield(h, 'biParValLine') ...
                    && ishandle(h.biParValLine)
                        delete(h.biParValLine);
                    end
                end
            end

        elseif O == 2
            % 2D systems

            % Clear axes. Set axes to manual to prevent figure from jumping
            set(h.fAx, ...
                'YLimMode'       , 'manual', ...
                'XLimMode'       , 'manual');
            toDelete = allchild(h.fAx);
            if isfield(h, 'pAx') && ishandle(h.pAx)
                toDelete = [toDelete; allchild(h.pAx)];
            end
            if exist('annotate', 'var') && annotate
                notToDelete = [];
            else
                if isfield(h, 'fxLbl')
                    notToDelete = [h.fxLbl h.fyLbl];
                else
                    notToDelete = [];
                end
            end
            delete(setdiff(toDelete, notToDelete));

            % Draw flow field
            set(h.f, ...
                'CurrentAxes'    , h.fAx);
            h.q = quiver(flow, quiverLineStyle, ...
                'LineWidth'      , quiverLineWidth, ...
                'MarkerSize'     , quiverMarkerSize, ...
                'MarkerFaceColor', quiverColor);
            set(h.fAx, ...
                'NextPlot'       , 'add');

            % Draw nullclines
            flow_x = flow.xcheb;
            flow_y = flow.ycheb;
            xNull = roots(flow_x);
            yNull = roots(flow_y);
            if ~isempty(xNull)
                h.xNull = plot(xNull, xNullclineStyle, ...
                    'LineWidth' , nullclineWidth);
            end
            if ~isempty(yNull)
                h.yNull = plot(yNull, yNullclineStyle, ...
                    'LineWidth' , nullclineWidth);
            end

            % Draw roots
            fixPts = roots(flow);
            if ~isempty(fixPts)
                determinant = jacobian(flow);
                trace = diffx(flow_x) + diffy(flow_y);
                for j = 1:size(fixPts, 1)
                    if determinant(fixPts(j,1),fixPts(j,2)) <= 0
                        plot(fixPts(j,1),fixPts(j,2), saddleStyle, ...
                            'MarkerSize'     , fixedPtSize);
                    elseif trace(fixPts(j,1),fixPts(j,2)) < 0
                        plot(fixPts(j,1),fixPts(j,2), stableStyle, ...
                            'MarkerSize'     , fixedPtSize, ...
                            'MarkerFaceColor', stableFill);
                    elseif trace(fixPts(j,1),fixPts(j,2)) > 0
                        plot(fixPts(j,1),fixPts(j,2), unstableStyle, ...
                            'MarkerSize'     , fixedPtSize, ...
                            'MarkerFaceColor', unstableFill);
                    else
                        plot(fixPts(j,1),fixPts(j,2), centerStyle, ...
                            'MarkerSize'     , fixedPtSize);
                    end
                end
            end

            % Draw potential
            if ~isempty(pot)
                set(h.f, ...
                    'CurrentAxes', h.pAx);
                set(h.pAx, ...
                    'NextPlot'   , 'add', ...
                    'Box'        , 'on');
                h.potSurf = plot(pot);

                % Roots
                if ~isempty(fixPts)
                    for j = 1:size(fixPts, 1)
                        if determinant(fixPts(j,1),fixPts(j,2)) <= 0
                            plot3(fixPts(j,1),fixPts(j,2), ...
                                pot(fixPts(j,1),fixPts(j,2)), saddleStyle, ...
                                'MarkerSize'     , fixedPtSize);
                        elseif trace(fixPts(j,1),fixPts(j,2)) < 0
                            plot3(fixPts(j,1),fixPts(j,2), ...
                                pot(fixPts(j,1),fixPts(j,2)), stableStyle, ...
                                'MarkerSize'     , fixedPtSize, ...
                                'MarkerFaceColor', stableFill);
                        elseif trace(fixPts(j,1),fixPts(j,2)) > 0
                            plot3(fixPts(j,1),fixPts(j,2), ...
                                pot(fixPts(j,1),fixPts(j,2)), unstableStyle, ...
                                'MarkerSize'     , fixedPtSize, ...
                                'MarkerFaceColor', unstableFill);
                        else
                            plot3(fixPts(j,1),fixPts(j,2), ...
                                pot(fixPts(j,1),fixPts(j,2)), centerStyle, ...
                                'MarkerSize'     , fixedPtSize);
                        end
                    end
                end
                view(3);
                rotate3d on
                set(h.pAx, ...
                    'NextPlot', 'replacechildren');
            end

            % Annotate
%             if ~exist('cParStr', 'var'), cParStr = ''; end
%             h.title = title (h.fAx, cParStr, ...
%                 'Interpreter', 'latex');
%             if exist('annotate', 'var') && annotate
%                 h.fxLbl = xlabel(h.fAx, sprintf('$%s$', oPar{1,1}), ...
%                     'Interpreter', 'latex', ...
%                     'Units'      , 'pixels');
%                 h.fyLbl = ylabel(h.fAx, sprintf('$%s$', oPar{2,1}), ...
%                     'Interpreter', 'latex', ...
%                     'Rotation'   , 0, ...
%                     'Units'      , 'pixels');
%                 % Adjust
%                 fxPos = get(h.fxLbl, 'Position');
%                 fyPos = get(h.fyLbl, 'Position');
%                 fxPos(2) = fxPos(2) + xAxisNudge;
%                 fyPos(2) = fyPos(2) - yAxisNudge;
%                 set(h.fxLbl, ...
%                     'Position'   , fxPos);
%                 set(h.fyLbl, ...
%                     'Position'   , fyPos);
%                 if isfield(h, 'pAx') && ishandle(h.pAx)
%                     h.pxLbl = xlabel(h.pAx, sprintf('$%s$', oPar{1,1}), ...
%                         'Interpreter', 'latex', ...
%                         'Units'      , 'pixels');
%                     h.pyLbl = ylabel(h.pAx, sprintf('$%s$', oPar{2,1}), ...
%                         'Interpreter', 'latex', ...
%                         'Units'      , 'pixels');
%                     h.pzLbl = zlabel(h.pAx, 'Potential $V$', ...
%                         'Interpreter', 'latex', ...
%                         'Units'      , 'pixels');
%                 end
%             end

            % Inform user about plotting solutions
            if warnSim
                choice = questdlg(['Click the flow field to plot ' ...
                    'solutions (a bit buggy).'], 'Plotting Solutions', ...
                    'OK', 'Don''t show this message', 'OK');
                warnSim = ~strcmp(choice, 'Don''t show this message');
            end

        end

        % Reset axes
        set(h.fAx, ...
            'NextPlot'   , 'replacechildren');

        % Unblock user input
        if C > 0
            set([h.cSlider; h.cEdit; h.menu.top], ...
                'Enable'        , 'on');
        end
        set(h.f, ...
            'Pointer'       , normPtr);

        % Update appdata
        setappdata(h.f, 'Handles', h);
    end

    function dockPanel(obj, ~, fromCloseRequest)
        % Executes when dock button is presed on a panel

        % Fix obj reference if this callback is called via figure close
        if exist('fromCloseRequest', 'var') && fromCloseRequest
            obj = findobj(allchild(obj), ...
                'Tag', 'uiextras:BoxPanel');
            if numel(obj) ~= 1, return; end
        else
            % If callback is called from dock button, we need its parent,
            % the panel
            obj = get(obj, 'Parent');
        end

        % Figure out what object to dock
        if isfield(h, 'sBox') && isvalid(h.sBox) && obj == double(h.sBox)
            obj = h.sBox;
        elseif isfield(h, 'bPanel') && isvalid(h.bPanel) ...
            && obj == double(h.bPanel)
            obj = h.bPanel;
        else
            return
        end

        % Set the flag
        obj.IsDocked = ~obj.IsDocked;

        if obj.IsDocked
            % Return to figure
            newFig = ancestor(obj, 'Figure');
            set(obj, ...
                'Parent'         , h.leftSplit);
            delete(newFig)
            update;
        else
            % Remove from figure
            panelPos = getpixelposition(obj);
            newFig = figure( ...
                'Name'           , get(obj, 'Title'), ...
                'Units'          , 'pixels', ...
                'CloseRequestFcn', {@dockPanel true}, ...
                'DockControls'   , 'off');
            figPos = get(newFig, 'OuterPosition');
            set(newFig, ...
                'OuterPosition'  , [max(figPos(1)-panelPos(3), 0) ...
                                    max(figPos(2)-panelPos(4), 0) ...
                                    panelPos(3:4)]);
            set(obj, ...
                'Parent'         , newFig, ...
                'Units'          , 'normalized', ...
                'Position'       , [0 0 1 1]);
            update;
            figure(newFig);
        end

        % Fix panel
        if numel(h.leftSplit.Children) == 1
            h.leftSplit.Sizes = -1;
        elseif numel(h.leftSplit.Children) == 2
            h.leftSpit.Children = [h.sBox h.bPanel];
            h.leftSplit.Sizes = [numel(h.cPanel)*...
                (sldrHeight+sldrPad+sPanelPad)+titleBarHeight -1];
        end
    end

    function flowClickFcn(~, ~)
        % Plot a trajectory

        % Get slider values and construct string for the title
        if C > 0
            c = nan(1, C);
            for j = 1:C, c(j) = get(h.cSlider(j), 'Value'); end
        else
            c = [];
        end

        % Freeze control parameter values
        flow = freeze(c);

        % Solve
        startPos = get(h.fAx, 'CurrentPoint');
        if numel(startPos) ~= 2
            startPos = startPos(1,1:2);
        end
        [~, sol] = ode45(flow, [0 get(h.tSlider, 'Value')], startPos);

        % Plot
        set(h.fAx, 'NextPlot', 'add');
        plot(startPos(1), startPos(2), solStartStyle, ...
            'MarkerSize'     , solMarkerSize, ...
            'MarkerFaceColor', solColor);
        plot(sol, solLineStyle, ...
            'LineWidth'      , solLineWidth);
        set(h.fAx, 'NextPlot', 'replacechildren');

    end

    function closeFcn(~, ~)
        % Runs when main figure is closed

        % Close undocked figures
        if isfield(h, 'sBox') && isvalid(h.sBox) ...
                              && ~strcmpi(h.sBox.BeingDeleted, 'on')
            delete(ancestor(h.sBox, 'figure'));
        end

        % Close main figure
        if ishandle(h.f), delete(h.f); end

        % Parallel may have been turned on independently
        if hasPar
            parOn = logical(matlabpool('size'));
            if parOn && turnedParOn, matlabpool('close'); end
        end
    end

    function bifurcation(~, ~)
        % Updates/generates bifurcation plot

        % Dialog box to choose parameter to vary
        if C==1
            cParIdx = 1;
        else
            [cParIdx, ok] = listdlg( ...
                'ListString'   , biStrings, ...
                'SelectionMode', 'single', ...
                'Name'         , 'Generate Bifurcation Diagram', ...
                'PromptString' , {'Select a control parameter to vary.' ...
                                 ['Other parameters will be held at ' ...
                                  'their current values.']});
            if ~ok, return; end
        end

        % Block user input
        warnstate = warning('off', 'all');
        set(h.f, ...
            'Pointer', waitPtr);
        set([h.cSlider; h.cEdit; h.menu.top], ...
            'Enable' , 'off');

        % Create panel if it doesn't exist
        if ~isfield(h, 'bPanel') || ~isvalid(h.bPanel)
            h.bPanel = uiextras.BoxPanel( ...
                'Parent'         , h.leftSplit, ...
                'Title'          , 'Bifurcation Diagram', ...
                'FontName'       , font, ...
                'FontSize'       , fSize, ...
                'Units'          , 'normalized', ...
                'Position'       , [0 0 1 1], ...
                'BackgroundColor', bgColor, ...
                'DockFcn'        , @dockPanel ,...
                'TitleColor'     , get(h.sBox, 'TitleColor'));
            set(findall(allchild(double(h.bPanel)), ...
                'Tag'            , 'uiextras:BoxPanel:DockButton'), ...
                'BackgroundColor', get(h.sBox, 'TitleColor'));
            h.leftSplit.Sizes = [numel(h.cPanel)*...
                (sldrHeight+sldrPad+sPanelPad)+titleBarHeight -1];
        end

        % Create axes if it doesn't exist
        if ~isfield(h, 'bAx') || ~ishandle(h.bAx)
            h.bAx = axes( ...
                'Parent'         , double(h.bPanel), ...
                'FontName'       , font, ...
                'FontSize'       , fSize, ...
                'Units'          , 'normalized', ...
                'OuterPosition'  , [0 0 1 1], ...
                'NextPlot'       , 'add', ...
                'XLim'           , cPar{cParIdx,2}, ...
                'YLim'           , oPar{1,2});
        else
            set(h.bAx, ...
                'XLim'           , cPar{cParIdx,2});
            toDelete = [h.bxLbl; h.byLbl; h.bTitle; allchild(h.bAx)];
            delete(toDelete(ishandle(toDelete)));
        end

        % Get slider values
        c = nan(1, C);
        cParStr = [];
        for j = 1:C
            c(j) = get(h.cSlider(j), 'Value');
            if j~=cParIdx
                if (j>1 && cParIdx>1) || j>2
                    cParStr = [cParStr ', ']; %#ok<AGROW>
                end
                cParStr = sprintf('%s$%s=%0.3g$', cParStr, ...
                    cPar{j,1}, c(j));
            end
        end

        % Annotate
        h.bxLbl = xlabel(h.bAx, ['$' cPar{cParIdx,1} '$'], ...
            'Interpreter', 'latex', ...
            'Units'      , 'pixels');
        h.byLbl = ylabel(h.bAx, ['$' oPar{1,1} '$'], ...
            'Interpreter', 'latex', ...
            'Units'      , 'pixels', ...
            'Rotation'   , 0);
        h.bTitle = title(h.bAx, cParStr, ...
            'Interpreter', 'latex');
        xLblPos = get(h.bxLbl, 'Position');
        yLblPos = get(h.byLbl, 'Position');
        set(h.bxLbl, ...
            'Position'   , xLblPos - [0 xAxisNudge 0]);
        set(h.byLbl, ...
            'Position'   , yLblPos - [yAxisNudge 0 0]);

        % Determine topology of fixed points (sign of lambda) at each value
        % of control parameter, and where it changes (breakPts)
        topo     = cell(biRes, 1);
        fixedPts = cell(biRes, 1);
        cVals = linspace(cPar{cParIdx,2}(1), cPar{cParIdx,2}(2), biRes);
        breakPts   = false(biRes, 1);
        if parOn
            h.dlg = double(...
                msgbox('Scanning system...', '', 'modal'));
            ch = get(h.dlg, 'Children');
            delete(ch(2));
            txt = get(ch(1), 'Children');
            set(txt, ...
                'FontName'           , font, ...
                'FontSize'           , fSize, ...
                'BackgroundColor'    , bgColor, ...
                'VerticalAlignment'  , 'middle');
            set([ch(1) h.dlg], ...
                'Color'          , bgColor);
            set(h.dlg, ...
                'Pointer'        , waitPtr, ...
                'Resize'         , 'off');
            drawnow;
            try
                parfor m = 1:biRes
                    d = c;
                    d(cParIdx) = cVals(m);
                    [flow, ~] = freeze(d);
                    slope = diff(flow);
                    fixedPts{m} = roots(flow);
                    topo{m} = sign(slope(fixedPts{m}));
                end
                for m = 2:biRes
                    if any(topo{m} == 0)
                        breakPts(m)   = true;
                    elseif m > 1 && (numel(topo{m}) ~= numel(topo{m-1}) ...
                            ||  any(topo{m}    ~= topo{m-1}))
                        breakPts(m) = true;
                    end
                end
            catch err
                if ishandle(h.dlg), delete(h.dlg); end
                rethrow(err);
            end
            if ishandle(h.dlg), delete(h.dlg); end
        else
            wait = waitbar(0, 'Scanning system...', ...
                'CreateCancelBtn', 'delete(gcbo)');
            for m = 1:biRes
                if ~ishandle(wait)
                    delete(h.bAx);
                    return
                end
                c(cParIdx) = cVals(m);
                [flow, ~] = freeze(c);
                slope = diff(flow);
                fixedPts{m} = roots(flow);
                topo{m} = sign(slope(fixedPts{m}));
                if m > 1 && any(topo{m} == 0)
                    breakPts(m)   = true;
                elseif m > 1 && (numel(topo{m}) ~= numel(topo{m-1}) ...
                             ||  any(topo{m}    ~= topo{m-1}))
                    breakPts(m) = true;
                end
                waitbar(m/biRes, wait);
            end
            if ishandle(wait), delete(wait); end
        end

        % Concatenate roots
        breakPts = unique([1; find(breakPts); biRes]);
        B = numel(breakPts) - 1;
        attRoots = cell(B, 1);
        repRoots = cell(B, 1);
        domains  = cell(B, 1);
        for k = 1:B
            if breakPts(k)+2 > breakPts(k+1)-1, continue; end
            domains{k} = cVals(breakPts(k)+1:breakPts(k+1)-1);
            allFixedPts = [fixedPts{breakPts(k)+1:breakPts(k+1)-1}];
            attRoots{k} = allFixedPts(topo{breakPts(k)+1}==-1,:);
            repRoots{k} = allFixedPts(topo{breakPts(k)+1}==1,:);
        end

        % Plot!
        h.biAtts = cell(B, 1);
        h.biReps = cell(B, 1);
        for k = 1:B
            if ~isempty(attRoots{k})
                h.biAtts{k} = plot(h.bAx, domains{k}, attRoots{k}, '-', ...
                    'Color'    , biDiagramColor, ...
                    'LineWidth', biDiagramWidth);
            end
            if ~isempty(repRoots{k})
                h.biReps{k} = plot(h.bAx, domains{k}, repRoots{k}, ...
                    biDiagramRepStyle, ...
                    'Color'    , biDiagramColor, ...
                    'LineWidth', biDiagramWidth);
            end
        end

        % Add line for current value of control parameter
        h.biParValLine = plot(h.bAx, ...
            get(h.cSlider(cParIdx), 'Value')*ones(1,2), oPar{1,2}, ...
            biDiagramCurValStyle, ...
            'LineWidth', biDiagramCurValWidth);
        h.biPars = c;
        h.biIdx  = cParIdx;

        % Allow user input
        set(h.f, ...
            'Pointer', normPtr);
        set([h.cSlider; h.cEdit; h.menu.top], ...
            'Enable' , 'on');

        % Update appdata
        setappdata(h.f, 'Handles', h);
        warning(warnstate);
    end

    function parMenu(~, ~)
        % Executes when "Use Parallel Procesing" is selected

        % Switch state
        switch get(h.menu.par, 'Checked')
            case 'on'
                turningOn = false;
                set(h.menu.par, ...
                    'Checked', 'off');
            case 'off'
                turningOn = true;
                set(h.menu.par, ...
                    'Checked', 'on');
        end

        % Parallel may have been turned on independently
        parOn = logical(matlabpool('size'));

        % Turn on or off
        if parOn && ~turningOn
            matlabpool('close');
            parOn = false;
        elseif ~parOn && turningOn
            matlabpool('open');
            parOn = true;
            turnedParOn = true;
        end

    end
end

function [flow_cheb, pot_cheb] = parametrize( ...
    fcn, range, params, typ, varargs)
% Converts function handle to chebfun pair, freezing control parameter
% values.

if strncmpi(typ, 'flow', numel(typ))
    flow_cheb = chebfun(@(x) fcn(x, params), range, varargs{:});
    % potential = - integral(flow)
    pot_cheb  = -cumsum(flow_cheb);
elseif strncmpi(typ, 'potential', numel(typ))
    pot_cheb  = chebfun(@(x) fcn(x, params), range, varargs{:});
    % flow = -differential(potential)
    flow_cheb = -diff(pot_cheb);
elseif strcmpi(typ, 'flow2')
    flow_cheb = chebfun2v(@(x,y) fcn{1}(x, y, params), ...
        @(x,y) fcn{2}(x, y, params), range);
    % no potential
    pot_cheb  = [];
elseif strcmpi(typ, 'pot2')
    pot_cheb  = chebfun2(@(x,y) fcn(x, y, params), range);
    % flow = -gradient (potential)
    flow_cheb = -gradient(pot_cheb);
end

end

function AddedPath = requireFEXpackage(FEXSubmissionID)
%Function requireFEXpackage -
%installs Matlab Central File Exchange (FEX) submission
%with given ID into the directory chosen by the user.
%A new FEX submissions may use previous FEX submissions as its part.
%The function 'requireFEXpackage' helps in adding those previous
%submissions to the user's MATLAB installation.
%
% SYNTAX:
%    AddedPath = requireFEXpackage(FEXSubmissionID)
%
% INPUT:
%    ID of the required submission to File Exchange
%
% OUTPUT:
%    the path to that submission added to the user's MATLAB path.
%
% HOW TO CALL:
%    The command
%           P = requireFEXpackage(8277)
%    will download and install the package with ID 8277
%    (namely, nice 'fminsearchbnd' by John D'Errico)
%
% EXAMPLES -- HOW TO USE:
%
% EXAMPLE 1 (using 'exist' command):
%
%     % first, somewhere in the very beginning of your code,
%     % check if the function 'fminsearchbnd' from the FEX package 8277
%     % is on your MATLAB path, and if it is not there,
%     % require the FEX package 8277:
%     if ~(exist('fminsearchbnd', 'file') == 2)
%         P = requireFEXpackage(8277);  % fminsearchbnd is part of 8277
%     end
%
%     % Then just use 'fminsearchbnd' where you need it:
%     syms x
%     RosenbrockBananaFunction = @(x) (1-x(1)).^2 + 100*(x(2)-x(1).^2).^2;
%     x = fminsearchbnd(RosenbrockBananaFunction,[3 3])
%
% EXAMPLE 2 (using 'try-catch' command):
%
%     syms x
%     RosenbrockBananaFunction = @(x) (1-x(1)).^2+100*(x(2)-x(1).^2).^2;
%     try
%        % if function 'fminsearchbnd' already exists in your MATLAB
%        % installation, just use it:
%        x = fminsearchbnd(RosenbrockBananaFunction,[3 3])
%     catch
%        % if function 'fminsearchbnd' is not present in your MATLAB
%        % installation, first get the package 8277 (to which it belongs)
%        % from the MATLAB Central File Exchange (FEX)
%        P = requireFEXpackage(8277);  % fminsearchbnd is part of 8277
%        % and then use that function:
%        x = fminsearchbnd(RosenbrockBananaFunction,[3 3])
%     end
%
%
% NOTE: on Mac platform, the title of the dialog box for
% choosing the directory for installing the required FEX package
% is not shown; this is not a bug, this is how UIGETDIR works on Macs --
% see the documentation for UIGETDIR
% http://www.mathworks.com/help/techdoc/ref/uigetdir.html
%
% (C) Igor Podlubny, 2011

ID = num2str(FEXSubmissionID);

% Ask user for the confirmation of the installation
% of the required FEX package
yes = ['YES, Install package ' ID];
no = 'NO, do not install';
userchoice = questdlg(['The Matlab function/toolbox, which you are running, ' ...
    'requires the presence of the package ' ID ...
    ' from Matlab Central File Exchange.' ...
    'Would you like to install the FEX package ' ID ' now?'] , ...
	['Required package ' ID], ...
	yes, no, yes);

% Handle response
switch userchoice
    case yes,
        install = 1;
    case no,
        install = 0;
    otherwise,
        install = 0;
end

if install == 1
    baseURL = 'http://www.mathworks.com/matlabcentral/fileexchange/';
    query = '?download=true';

    location = uigetdir(pwd, ['Select the directory for installing the required FEX package' ID ]);
    if location ~= 0
        % download package 'ID' from Matlab Central File Exchange
        filetosave = [location filesep ID '.zip'];
        FEXpackage = [baseURL ID query];
        [~, status] = urlwrite(FEXpackage,filetosave);
        if status==0
            warndlg(['No connection to Matlab Central File Exchange,' ' or package ' ID ' does not exist.' ...
                ' Package ' ID ' has not been installed. ' ...
                ' Check you internet settings and the ID of the required package, and try again. '] , ...
                ['No connection to Matlab Central File Exchange' ' or package ' ID ' does not exist'], ...
                'modal');
            AddedPath = '';
            return
        end
        % unzip the downloaded file to the subdirectory 'ID'
        todir = [location filesep ID];
        % if the directory 'ID' doesn't exist at given location, create it
        if ~(exist([location filesep ID], 'dir') == 7)
            mkdir(location, ID);
        end
        try
            unzip(filetosave, todir);
            % after unzipping, delete the downloaded ZIP file
            delete(filetosave);
            % prepend the paths to the downloaded package to the MATLAB path
            P = genpath([location filesep ID]);
            path(P,path);
        catch %#ok<CTCH>
            % if the FEX package is not ZIP, then it is a single m-file
            % just move the file to the ID directory
            [~, name, ~] = fileparts(filetosave);
            movefile(filetosave, [todir filesep name '.m']);
            P = genpath([location filesep ID]);
            path(P,path);
        end
    else
        P = '';
    end

    AddedPath = P;
else
    AddedPath = '';
end

if install == 1,
    % Ask user about reviewing and saving the modified MATLAB path,
    % and take him to PATHTOOL, if the user wants to save the modified path
    yes = 'YES, I want to review and save the MATLAB path';
    no = 'NO, I don''t want to save the path permanently';
    userchoice = questdlg(['After adding the package ' ID ...
        ' from Matlab Central File Exchange to your MATLAB installation,' ...
        ' the MATLAB path has been modified accordingly. ', ...
        'Would you like to review and save the modified MATLAB path?'] , ...
        'Review and save the modified MATLAB path for future use?', ...
        yes, no, yes);

    % Handle response
    switch userchoice
        case yes,
            pathtool;
        case no,
        otherwise,
    end
end
end


function test_suite = test_vectorNorm
% One-line description here, please.
%   output = testVectorNorm(input)
%
%   Example
%   testVectorNorm
%
%   See also
%
%
% ------
% Author: David Legland
% e-mail: david.legland@grignon.inra.fr
% Created: 2009-04-22,    using Matlab 7.7.0.471 (R2008b)
% Copyright 2009 INRA - Cepia Software Platform.

test_suite = functiontests(localfunctions);

function testEuclidean(testCase) %#ok<*DEFNU>

v = [3 4];
norm = vectorNorm(v);
testCase.assertEqual(5, norm, 'AbsTol', .01);

function testEuclideanArray(testCase)

v = [3 4;4 3;6 8;5 12];
norm = vectorNorm(v);
testCase.assertEqual([5;5;10;13], norm, 'AbsTol', .01);

function testExplicitEuclideanArray(testCase)

v = [3 4;4 3;6 8;5 12];
norm = vectorNorm(v, 2);
testCase.assertEqual([5;5;10;13], norm, 'AbsTol', .01);

function testNorm1Array(testCase)

v = [3 4;4 3;6 8;5 12];
norm = vectorNorm(v, 1);
testCase.assertEqual([7;7;14;17], norm, 'AbsTol', .01);

function testNormInfArray(testCase)

v = [3 4;4 3;6 8;5 12];
norm = vectorNorm(v, inf);
testCase.assertEqual([4;4;8;12], norm, 'AbsTol', .01);


% Compare various inference engines on the following network (from Jensen (1996) p84 fig 4.17)
%    1
%  / | \
% 2  3  4
% |  |  |
% 5  6  7
%  \/ \/
%  8   9
% where all arcs point downwards
seed = 0;
rand('state', seed);
randn('state', seed);

N = 9;
dag = zeros(N,N);
dag(1,2)=1; dag(1,3)=1; dag(1,4)=1;
dag(2,5)=1; dag(3,6)=1; dag(4,7)=1;
dag(5,8)=1; dag(6,8)=1; dag(6,9)=1; dag(7,9) = 1;

dnodes = 1:N;
false = 1; true = 2;
ns = 2*ones(1,N); % binary nodes

onodes = [2 4];
bnet = mk_bnet(dag, ns, 'observed', onodes);
% use random params
for i=1:N
  bnet.CPD{i} = tabular_CPD(bnet, i);
end

%USEC = exist('@jtree_C_inf_engine/collect_evidence','file');
query = [3];
engine = {};
engine{end+1} = jtree_inf_engine(bnet);
engine{end+1} = jtree_sparse_inf_engine(bnet);
%engine{end+1} = jtree_ndx_inf_engine(bnet, 'ndx_type', 'SD');
%engine{end+1} = jtree_ndx_inf_engine(bnet, 'ndx_type', 'B');
%engine{end+1} = jtree_ndx_inf_engine(bnet, 'ndx_type', 'D');
%if USEC, engine{end+1} = jtree_C_inf_engine(bnet); end
%engine{end+1} = var_elim_inf_engine(bnet);
%engine{end+1} = enumerative_inf_engine(bnet);
%engine{end+1} = jtree_onepass_inf_engine(bnet, query, onodes);

maximize = 0;  % jtree_ndx crashes on max-prop
[err, time] = cmp_inference_static(bnet, engine, 'maximize', maximize);


function runtest(opt)
% Run examples in the reference:
%   B.N. Li, C.K. Chui, S. Chang, S.H. Ong (2011) Integrating spatial fuzzy
%   clustering with level set methods for automated medical image
%   segmentation. Computers in Biology and Medicine 41(1) 1-10.
%--------------------------------------------------------------------------

if opt==1
    img=imread('ctlivertumor.bmp');
    ncluster=3;
elseif opt==2
    img=imread('mrihead.bmp');
    ncluster=4;
else
    error('Invalid opt: 1 or 2 only!')
end

MF = SFCM2D(img,ncluster);

figure
subplot(231); imshow(img,[])
for i=1:ncluster
    imgfi=reshape(MF(i,:,:),size(img,1),size(img,2));
    subplot(2,3,i+1); imshow(imgfi,[])
    title(['Index No: ' int2str(i)])
end

temp=1;
while temp
    nopt = input('Input the Index No that you are interested\n');
    if ~isempty(nopt), temp=0; end
end

close(gcf);

imgfcm=reshape(MF(nopt,:,:),size(img,1),size(img,2));

fuzzyLSM(img,imgfcm,.5);


function s = resampstr(p,m,n)
%RESAMPSTR Stratified resampling
%
%  Description
%    S = RESAMPSTR(P) returns a new set of indices according to
%      the probabilities P. P is array of probabilities, which are
%      not necessarily normalized, though they must be
%      non-negative, and not all zero. The size of S is the size of P.
%
%    S = RESAMPSTR(P,M,N) returns an M by N matrix.
%
%    Default is to use no-sort resampling. For sorted resampling use
%      [PS,PI]=SORT(P);
%      S=PI(RESAMPSTR(PS));
%    Sorted re-sampling is slower but has slightly smaller
%    variance. Stratified resampling is unbiased, almost as fast as
%    deterministic resampling (RESAMPDET), and has only a slightly
%    larger variance.
%
%    In stratified resampling indices are sampled using random
%    numbers u_j~U[(j-1)/n,j/n], where n is length of P. Compare
%    this to simple random resampling where u_j~U[0,1].
%
%  Reference
%    Kitagawa, G., Monte Carlo Filter and Smoother for Non-Gaussian
%    Nonlinear State Space Models, Journal of Computational and
%    Graphical Statistics, 5(1):1-25, 1996.
%
%  See also
%    RESAMPSIM, RESAMPRES, RESAMPDET
%
% Copyright (c) 2003-2004,2010 Aki Vehtari

% This software is distributed under the GNU General Public
% License (version 3 or later); please refer to the file
% License.txt, included with the software, for details.

if nargin<2
  [m,n]=size(p);
elseif nargin==2
  n=m;
end
mn=m.*n;
pn=p./sum(p(:)).*mn;
s=zeros(m,n);
r=rand(1,mn);
k=0;
c=0;
for i=1:numel(pn)
  c=c+pn(i);
  if c>=1
    a=floor(c);
    c=c-a;
    s(k+[1:a])=i;
    k=k+a;
  end
  if k<mn && c>=r(k+1)
    c=c-1;
    k=k+1;
    s(k)=i;
  end
end


function p = prior_corrunif(varargin)
% * PRIOR_R  Correlation prior structure
%
% * Description:
%
%  - REFERENCE: prior for correlation matrix
%    Barnard, J.; McCulloch, R. & li Meng, X.
%    Modelling covariance matrices in terms of standart deviations and correlations
%    with applications to shrinkage. Statistical Sinica, 2000
%
%  - P = PRIOR_CORRUNIF('PARAM1', VALUE1, ...)
%    creates the prior structure in which the
%    named parameters have the specified values. Any unspecified
%    parameters are set to default values.
%
%  - P = PRIOR_CORRUNIF(P, 'PARAM1', VALUE1, ...)
%    modify a prior structure with the named parameters altered
%    with the specified values.
%
%  - Parameters for correlation prior [default]
%     nu       - degree of freedom [15]
%     prior_nu - prior for nu [prior_fixed]
%
%  - some inverse-Wishart properties
%    if W ~ InvWish_d (v, A) then E[W] = A/(v-d-1)
%    nu > = d
%    d = number os species (dimension of the square matrix)
%    the construction for this prior assumes A = I.
%
%  - dimension of the correlation vector: (numberClass^2 - numberClass)/2
%
% * See also
%    PRIOR_*
%
% Copyright (c) 2000-2001,2010 Aki Vehtari
% Copyright (c) 2009,2015 Jarno Vanhatalo
% Copyright (c) 2010 Jaakko Riihimäki
% ------------ 2015 Marcelo Hartmann

% This software is distributed under the GNU General Public
% License (version 3 or later); please refer to the file
% License.txt, included with the software, for details.

  ip = inputParser;
  ip.FunctionName = 'PRIOR_CORRUNIF';
  ip.addOptional('p', [], @isstruct);
  ip.addParamValue('nu', 15, @(x) isscalar(x) && x > 0);
  ip.addParamValue('prior_nu', [], @(x) isstruct(x) || isempty(x));
  ip.addParamValue('numberClass', 2, @(x) mod(x, 1) == 0 && x > 1);
  ip.addParamValue('aValue', 1, @(x) isreal(x) &&  x > 0);
  ip.parse(varargin{:});
  p = ip.Results.p;

  if isempty(p)
    init = true;
    p.type = 'CORRUNIF';

  else
    if ~isfield(p, 'type') && ~isequal(p.type, 'CORRUNIF')
      error('First argument does not seem to be a valid prior structure')
    end

    init = false;
  end

  % transformation to the real line (aValue stretches or squeeze the real line).
  p.aValue = ip.Results.aValue;

  % Initialize parameters
  % check the condition nu > numberSpecies
  if init || ~ismember('nu', ip.UsingDefaults)
      p.nu = ip.Results.nu;
  end

  if init || ~ismember('numberClass', ip.UsingDefaults)
      p.numberClass = ip.Results.numberClass;
      p.vectSize = (p.numberClass^2 - p.numberClass)/2;
  end

  if p.nu < (p.numberClass - 1)
      error('Degrees of freedom (nu) should be greater than number of classes')
  end

  % Initialize prior structure
  if init
      p.p = [];
  end
  if init || ~ismember('nu_prior', ip.UsingDefaults)
      p.p.nu = ip.Results.prior_nu;
  end

  if init
    % set functions
    p.fh.pak = @prior_corrunif_pak;
    p.fh.unpak = @prior_corrunif_unpak;
  % p.fh.RealToRho = @prior_corrunif_RealToRho;
    p.fh.lp = @prior_corrunif_lp;
    p.fh.lpg = @prior_corrunif_lpg;
    p.fh.recappend = @prior_corrunif_recappend;
  end

end

function [w, s, h] = prior_corrunif_pak(p)
% This is a mandatory subfunction used for example
% in energy and gradient computations.

  w = [];  s = {};  h = [];

  if ~isempty(p.p.nu)
      w = [w p.nu];
      s = [s; 'R.nu'];
      h = [h 1];
  end

end

function [p, w] = prior_corrunif_unpak(p, w)
% This is a mandatory subfunction used for example
% in energy and gradient computations.

  if ~isempty(p.p.nu)
      i1 = 1;
      p.nu = w(i1);
      w = w(i1 + 1:end);
  end

end

function lp = prior_corrunif_lp(x, p)
% This is a mandatory subfunction used for example
% in energy computations.

  % Evaluating log-prior(R)
  % correlation vector
  rho = x';

  % create entries
  seq = 1:p.vectSize;
  i = ceil(0.5 + 0.5 * sqrt(1 + 8*(seq)));
  j = seq - (i - 2).*(i - 1)/2;
  ind1 = (j - 1) * p.numberClass + i;
  ind2 = (i - 1) * p.numberClass + j;

  % build correlation matrix
  R = eye(p.numberClass);

  % filling elements in lower and upper part
  R([ind1, ind2]) = [rho; rho];
  detR = det(R);

  if eps < detR && ~any(abs(rho) > 1)
      % cholesk decompostion
      L = chol(R, 'lower');

      % parameters of the distribution
      a = 0.5*(p.nu - 1)*(p.numberClass - 1) - 1;
      b = - p.nu/2;

      % building principal submatrices and evaluating log determinant
      sDetlogSub = 0;
      for k = 1:p.numberClass
          A = R;
          A(:, k) = []; A(k, :) = [];
          Lsub = chol(A, 'lower');
          sDetlogSub = sDetlogSub + sum(log(diag(Lsub)));
      end

      % evaluating unnormalized log-prior
      lp = 2 * (a*sum(log(diag(L))) + b*sDetlogSub);

  else
      lp = -Inf;

  end

% adding log-hyperprior(nu)
if ~isempty(p.p.nu)
    lp = lp + p.p.nu.fh.lp(p.nu, p.p.nu) + log(p.nu);
end

end

function lpg = prior_corrunif_lpg(x, p)
% This is a mandatory subfunction used for example
% in gradient computations.

 % taking the correlation vector
 rho = x';

 % creating entries
 seq = 1:p.vectSize;
 i = ceil(0.5 + 0.5 * sqrt(1 + 8*(seq)));
 j = seq - (i - 2).*(i - 1)/2;
 ind1 = (j - 1) * p.numberClass + i;
 ind2 = (i - 1) * p.numberClass + j;

 % building corr matrix
 R = eye(p.numberClass);

 % filling elements in lower and upper part
 R([ind1, ind2]) = [rho; rho];

 % all(eig(R) > 0)
  if ~any(abs(rho) > 1)

     % grad vector
     lpg = ones(1, p.vectSize);

     % cholesk decompostion
     % L = chol(R, 'lower');

     % parameters of the distribution
     a = 0.5*(p.nu - 1)*(p.numberClass - 1) - 1;
     b = - p.nu/2;

     % building principal submatrices and evaluating log determinant
     invR = inv(R);

     % COULD WE USE COFACTOR MATRIX ?
     % Id1 = eye(p.numberClass-1);
     aux = 0;

     for j = 2:p.numberClass
         for i = 1:(j-1)
             sumtrDer = 0;
             sumtrDer = sumtrDer + 2*a*invR(j, i);
             for k = 1:p.numberClass
                 if k == i || k == j
                     % sumtrDer = sumtrDer + 0;
                     continue
                 else
                     A = R;
                     A(:, k) = []; A(k, :) = [];
                     % L = chol(A, 'lower');
                     invAk = inv(A);
                     if k < j && (i == 1 || k > i)
                         m = j-1;
                         sumtrDer = sumtrDer + 2*b*invAk(m, i);
                     elseif k < j && k < i
                         l = i-1;
                         m = j-1;
                         sumtrDer = sumtrDer + 2*b*invAk(m, l);
                     else
                         sumtrDer = sumtrDer + 2*b*invAk(j, i);
                     end
                 end
             end
             aux = aux + 1;
             lpg(aux) = sumtrDer;
         end
     end

 else
     lpg = repmat(-Inf, 1, p.vectSize);
 end

 if ~isempty(p.p.nu)
     lpgnu = p.p.nu.fh.lpg(p.nu, p.p.nu).*p.nu + 1;
     lpg = [lpg lpgnu];
  end
end

function rec = prior_corrunif_recappend(rec, ri, p)
% This subfunction is needed when using MCMC sampling (gp_mc).
% The parameters are not sampled in any case.

rec = rec;
if ~isempty(p.p.nu)
    rec.nu(ri,:) = p.nu;
end

end


% Test for trigBary.m.
function pass = test_trigBary(pref)

if ( nargin < 1 )
    pref = chebfunpref();
end

% Generate a few random points in [-1 1] to use as test values.
seedRNG(3453);
xr = 2 * rand(1000, 1) - 1;

% Set an error tolerance.
tol = 1.0e-12;

% Check evaluation for a trigonometric polynomial.
p1 = @(x) cos(4*pi*x) - 2*sin(3*pi*x) + 3*sin(2*pi*x) - 2*cos(pi*x) + 1;

xk = trigpts(10, [-1,1]);
y = trigBary(xr, p1(xk), xk, [-1, 1]);
err = norm(p1(xr) - y, Inf);
pass(1) = err < tol;

xk = trigpts(1001, [-1,1]);
y = trigBary(xr, p1(xk), xk, [-1, 1]);
err = norm(p1(xr) - y, Inf);
pass(2) = err < tol;

% Test interpolation:
xk = trigpts(10, [-1,1]);
y = trigBary(xk, p1(xk), xk, [-1, 1]);
err = norm(p1(xk) - y, Inf);
pass(3) = err < tol;

xk = chebpts(8, [-1, 1], 1);
p2 = @(x) 2*sin(3*pi*x) + 3*sin(2*pi*x) - 2*cos(pi*x) + 1;
y = trigBary(xr, p2(xk), xk, [-1, 1]);
err = norm(p2(xr) - y, Inf);
pass(4) = err < tol;

%%
% Check evaluation for an array of two polynomials.
q = @(x) [.45 + sin(pi*x), .32 + sin(pi*x) + cos(2*pi*x)];
tol = 1e-10;
xk = -2 + 4*rand(8,1);
xr = -2 + 4*rand(100, 1);
difference = q(xr) - trigBary(xr, q(xk), xk, [-2, 2]);
err = norm(difference(:), Inf);
pass(5) = err < tol;

% Test interpolation:
difference = q(xk) - trigBary(xk, q(xk), xk, [-2, 2]);
err = norm(difference(:), Inf);
pass(6) = err < tol;

% Test trigBaryWeights():
n = 2500;
w = trigBaryWeights(sort(rand(n,1)));
pass(7) = length(w) == n;

% Check for #1743.
xk = [-1 (-1/3 - eps) (1/3 - eps) 1].';
fvals = [1 ; 1 ; 1 ; 1 + eps];
dom = [-pi pi];
y = trigBary(2, fvals, xk, dom);
pass(8) = ~isinf(y) && ~isnan(y) && (abs(y - 1) < 10*eps);

% Check for #1744.
w = trigBaryWeights(linspace(-1, 1, 4).');
w_ex = [0.38883657630910357 ; -1.0 ; 1.0 ; -0.38883657630910357];
err = norm(abs(w) - abs(w_ex), Inf);
tol = 10*eps;
pass(9) = err < tol;

end


function cvt_test04 ( )

%*****************************************************************************80
%
%% CVT_TEST04 repeats test 1 with uniform initialization and Halton sampling.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    08 November 2006
%
%  Author:
%
%    John Burkardt
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'TEST04\n' );
  fprintf ( 1, '  CVT computes a Centroidal Voronoi Tessellation.\n' );
  fprintf ( 1, '  Repeat test 1, but with Halton sampling.\n' );

  dim_num = 2;
  n = 10;
  batch = 1000;
  init = 0;
  init_string = 'uniform';
  it_max = 40;
  it_fixed = 1;
  sample = 1;
  sample_num = 10000;
  sample_string = 'halton';
  seed = 123456789;
  r = [];

  seed_init = seed;

  [ r, seed, it_num, it_diff, energy ] = cvt ( dim_num, n, batch, init, ...
    sample, sample_num, it_max, it_fixed, seed, r );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  Dimension DIM_NUM =        %12d\n', dim_num );
  fprintf ( 1, '  Number of points N =       %12d\n', n );
  fprintf ( 1, '  Initial SEED =             %12d\n', seed_init );
  fprintf ( 1, '  Current SEED =             %12d\n', seed );
  fprintf ( 1, '  INIT =                    "%s".\n', init_string );
  fprintf ( 1, '  Max iterations IT_MAX =    %12d\n', it_max );
  fprintf ( 1, '  IT_FIXED (fixed samples) = %12d\n', it_fixed );
  fprintf ( 1, '  Iterations IT_NUM =        %12d\n', it_num );
  fprintf ( 1, '  Difference IT_DIFF =       %14f\n', it_diff );
  fprintf ( 1, '  CVT ENERGY =               %14f\n', energy );
  fprintf ( 1, '  SAMPLE =                  "%s".\n', sample_string );
  fprintf ( 1, '  Samples SAMPLE_NUM    =    %12d\n', sample_num );
  fprintf ( 1, '  Sampling BATCH size =      %12d\n', batch );
  fprintf ( 1, '  EPSILON (unit roundoff) =  %12e\n', eps );

  r8mat_transpose_print ( dim_num, n, r, '  Generators (rows):' );

  return
end


function s =SNR(x,xrec)
signalPower= mean(x(:).^2);
noisePower = mean((x(:) - xrec(:)).^2);
s =  signalPower/noisePower;


%This program decomposes an image into blocks.

%Parameters
% inImg         -   Input Gray Image
% blkSize       -   Window size for block processing
% out           -   Output 4 dimensional matrix with blocks.
%
%Author : Athi Narayanan S
%Student, M.E, EST,
%K.S.R College of Engineering
%Erode, Tamil Nadu, India.
%s_athi1983@yahoo.co.in
%http://sites.google.com/site/athisnarayanan/

function out = MatDec(inImg, blkSize)

[m,n]=size(inImg);

r3=m/blkSize;
c3=n/blkSize;
q4=0;
q1=0;

for i=1:r3
    for j=1:c3
        for s=1:blkSize
            for k=1:blkSize
                p3=s+q4;
                q2=k+q1;
                out(s,k,i,j)=inImg(p3,q2);
            end
        end
        q1=q1+blkSize;
    end
    q4=q4+blkSize;q1=0;
end


function [ Q ] = UpdateSARSA( s, a, r, sp, ap, tab , alpha, gamma )
% UpdateQ update de Qtable and return it using Whatkins QLearing
% s1: previous state before taking action (a)
% s2: current state after action (a)
% r: reward received from the environment after taking action (a) in state
%                                             s1 and reaching the state s2
% a:  the last executed action
% tab: the current Qtable
% alpha: learning rate
% gamma: discount factor
% Q: the resulting Qtable

Q = tab;
Q(s,a) =  Q(s,a) + alpha * ( r + gamma*Q(sp,ap) - Q(s,a) );


function [blockedIrrRxns, sol, tol] = findBlockedIrrRxns(model, tol, varargin)
% find all blocked irreversible reactions by solving one single LP problem:
%      min sum(z_pos + z_neg)
%      s.t.   Sv = 0
%             lb <= v <= ub
%             v_j + tol*z_pos_j >= tol   for each reaction j with lb_j >= 0
%             v_j - tol*z_neg_j <= -tol  for each reaction j with ub_j <= 0
%
% USAGE:
%    [blockedIrrRxns, fluxes] = findBlockedIrrRxns(model, tol, parameters)
%
% INPUT:
%    model:           COBRA model
%
% OPTIONAL INPUTL
%    tol:             tolerance for zeros (default feasTol*10, use default if the input is smaller)
%    parameters:      COBRA and solver-specific parameters, as a input structure or parameter/value inputs
%
% OUTPUTS:
%    blockedIrrRxns:  cell array of blocked irreversible reactions
%    sol:             solution structure from solveCobraLP
%    tol:             tolerance for zeros used (might be different from the input)

if nargin < 2
    tol = 0;
end

[~, cobraParams, solverVarargin] = parseCobraVarargin(varargin, {}, {}, {}, {'LP'});
% if tol < feasTol * 10, v, z_pos, z_neg = 0 may be feasible due to tolerance
tol = max([tol, cobraParams.LP.feasTol * 10]);

LP = struct();
if 0
    rxnFwdOnly = find(model.lb >= 0);
    rxnRevOnly = find(model.ub <= 0);
else
    %avoid reactions bound at zero
    rxnFwdOnly = find(model.lb >= 0 & model.ub>0);
    rxnRevOnly = find(model.ub <= 0 & model.lb<0);
end
[nF, nR] = deal(numel(rxnFwdOnly), numel(rxnRevOnly));
[m, n] = size(model.S);
LP.A = [model.S,                        sparse(m, nF + nR); ...  % Sv = 0
    sparse(1:nF, rxnFwdOnly, 1, nF, n), sparse(1:nF, 1:nF, tol, nF, nF + nR); ...  % v + tol*z_pos >= tol
    sparse(1:nR, rxnRevOnly, 1, nR, n), sparse(1:nR, (nF + 1):(nF + nR), -tol, nR, nF + nR)];  % v - tol*z_neg <= -tol
LP.b = [model.b; tol * ones(nF, 1); -tol * ones(nR, 1)];
LP.c = [zeros(n, 1); ones(nF + nR, 1)];
LP.lb = [model.lb; zeros(nF + nR, 1)];
LP.ub = [model.ub; ones(nF + nR, 1)];
LP.csense = [repmat('E', m, 1); repmat('G', nF, 1); repmat('L', nR, 1)];
LP.osense = 1;

sol = solveCobraLP(LP, solverVarargin.LP{:});

if sol.stat ~= 1
    warning('The model is infeasible')
    blockedIrrRxns = {};
    return
end

blockedIrrRxns = model.rxns((abs(sol.full(1:n)) < tol * (1 - cobraParams.LP.optTol)) & (model.lb >= 0 | model.ub <= 0));


function net = cnn_cifar_init_nin(varargin)
opts.networkType = 'simplenn' ;
opts = vl_argparse(opts, varargin) ;

% CIFAR-10 model from
% M. Lin, Q. Chen, and S. Yan. Network in network. CoRR, abs/1312.4400, 2013.

net.layers = {} ;
b=0 ;

% Block 1
net.layers{end+1} = struct('type', 'conv', ...
                           'name', 'conv1', ...
                           'weights', {{0.01*randn(5,5,3,192,'single'), b*ones(1,192,'single')}}, ...
                           'learningRate', [.1 2], ...
                           'stride', 1, ...
                           'pad', 2) ;
net.layers{end+1} = struct('type', 'relu', 'name', 'relu1') ;
net.layers{end+1} = struct('type', 'conv', ...
                           'name', 'cccp1', ...
                           'weights', {{0.05*randn(1,1,192,160, 'single'), b*ones(1,160,'single')}}, ...
                           'learningRate', [.1 2], ...
                           'stride', 1, ...
                           'pad', 0) ;
net.layers{end+1} = struct('type', 'relu', 'name', 'relu_cccp1') ;
net.layers{end+1} = struct('type', 'conv', ...
                           'name', 'cccp2', ...
                           'weights', {{0.05*randn(1,1,160,96,'single'), b*ones(1,96,'single')}}, ...
                           'learningRate', [.1 2], ...
                           'stride', 1, ...
                           'pad', 0) ;
net.layers{end+1} = struct('type', 'relu', 'name', 'relu_cccp2') ;
net.layers{end+1} = struct('name', 'pool1', ...
                           'type', 'pool', ...
                           'method', 'max', ...
                           'pool', [3 3], ...
                           'stride', 2, ...
                           'pad', 0) ;
net.layers{end+1} = struct('type', 'dropout', 'name', 'dropout1', 'rate', 0.5) ;

% Block 2
net.layers{end+1} = struct('type', 'conv', ...
                           'name', 'conv2', ...
                           'weights', {{0.05*randn(5,5,96,192,'single'), b*ones(1,192,'single')}}, ...
                           'learningRate', [.1 2], ...
                           'stride', 1, ...
                           'pad', 2) ;
net.layers{end+1} = struct('type', 'relu', 'name', 'relu2') ;
net.layers{end+1} = struct('type', 'conv', ...
                           'name', 'cccp3', ...
                           'weights', {{0.05*randn(1,1,192,192,'single'), b*ones(1,192,'single')}}, ...
                           'learningRate', [.1 2], ...
                           'stride', 1, ...
                           'pad', 0) ;
net.layers{end+1} = struct('type', 'relu', 'name', 'relu_cccp3') ;
net.layers{end+1} = struct('type', 'conv', ...
                           'name', 'cccp4', ...
                           'weights', {{0.05*randn(1,1,192,192, 'single'), b*ones(1,192,'single')}}, ...
                           'learningRate', [.1 2], ...
                           'stride', 1, ...
                           'pad', 0) ;
net.layers{end+1} = struct('type', 'relu', 'name', 'relu_cccp4') ;
net.layers{end+1} = struct('name', 'pool2', ...
                           'type', 'pool', ...
                           'method', 'avg', ...
                           'pool', [3 3], ...
                           'stride', 2, ...
                           'pad', 0) ;
net.layers{end+1} = struct('type', 'dropout', 'name', 'dropout2', 'rate', 0.5) ;

% Block 3
net.layers{end+1} = struct('type', 'conv', ...
                           'name', 'conv3', ...
                           'weights', {{0.05*randn(3,3,192,192,'single'), b*ones(1, 192, 'single')}}, ...
                           'learningRate', [.1 2], ...
                           'stride', 1, ...
                           'pad', 1) ;
net.layers{end+1} = struct('type', 'relu', 'name', 'relu3') ;
net.layers{end+1} = struct('type', 'conv', ...
                           'name', 'cccp5', ...
                           'weights', {{0.05*randn(1,1,192,192,'single'), b*ones(1,192,'single')}}, ...
                           'learningRate', [.1 2], ...
                           'stride', 1, ...
                           'pad', 0) ;
net.layers{end+1} = struct('type', 'relu', 'name', 'relu_cccp5') ;
net.layers{end+1} = struct('type', 'conv', ...
                           'name', 'cccp6', ...
                           'weights', {{0.05*randn(1,1,192,10, 'single'), b*ones(1,10,'single')}}, ...
                           'learningRate', 0.1*[.1 2], ...
                           'stride', 1, ...
                           'pad', 0) ;
net.layers{end+1} = struct('type', 'relu', 'name', 'relu_cccp6') ;
net.layers{end+1} = struct('type', 'pool', ...
                           'name', 'pool3', ...
                           'method', 'avg', ...
                           'pool', [7 7], ...
                           'stride', 1, ...
                           'pad', 0) ;

% Loss layer
net.layers{end+1} = struct('type', 'softmaxloss') ;

% Meta parameters
net.meta.inputSize = [32 32 3] ;
net.meta.trainOpts.learningRate = [0.5*ones(1,30) 0.1*ones(1,10) 0.02*ones(1,5)]  ;
net.meta.trainOpts.weightDecay = 0.0005 ;
net.meta.trainOpts.batchSize = 100 ;
net.meta.trainOpts.numEpochs = numel(net.meta.trainOpts.learningRate) ;

% Fill in default values
net = vl_simplenn_tidy(net) ;

% Switch to DagNN if requested
switch lower(opts.networkType)
  case 'simplenn'
    % done
  case 'dagnn'
    net = dagnn.DagNN.fromSimpleNN(net, 'canonicalNames', true) ;
    net.addLayer('error', dagnn.Loss('loss', 'classerror'), ...
      {'prediction','label'}, 'error') ;
  otherwise
    assert(false) ;
end


% Author: Ricardo Baptista and Matthias Poloczek
% Date:   June 2018
%
% See LICENSE.md for copyright information
%

function KL = KL_divergence_ising(Theta_P, moments, x)
% KL_divergence_ising: Function evaluates the KL divergence objective
% for Ising Models

n_vars = size(Theta_P,1);

% Generate all binary vectors
bin_vals = dec2bin(0:2^n_vars-1)-'0';
bin_vals(bin_vals == 0) = -1;
n_vectors = size(bin_vals,1);

% Compute normalizing constant for P
P_vals = zeros(n_vectors,1);
for i=1:n_vectors
	P_vals(i) = exp(bin_vals(i,:)*Theta_P*bin_vals(i,:)');
end
Zp = sum(P_vals);

% Run computation for each x
n_xvals = size(x,1);
KL = zeros(n_xvals,1);

for j=1:n_xvals

    % Apply elementwise masking to Theta
    Theta_Q = tril(Theta_P,-1);
    nnz_Q   = find(Theta_Q);
    Theta_Q(nnz_Q) = Theta_Q(nnz_Q).*(x(j,:))';
    Theta_Q = Theta_Q + Theta_Q';

    % Compute normalizing constant for Q
    Q_vals = zeros(n_vectors,1);
    for i=1:n_vectors
        Q_vals(i) = exp(bin_vals(i,:)*Theta_Q*bin_vals(i,:)');
    end
    Zq = sum(Q_vals);

    % compute KL
    KL(j) = sum(sum((Theta_P - Theta_Q).*moments)) + log(Zq) - log(Zp);

end

end


function duhatdt = rhsHeat(t,uhat,kappa,a)
duhatdt = -a^2*(kappa.^2)'.*uhat;  % Linear and diagonal


function [state_red,inv_state_red,g0,g1,c,pi,psi] = clean_G0(g0,g1,c,pi,psi)
% Solves out static constraints of the linear model using SVD
%    Adapted from Chris Sims's gensys code
%
% Input/output/References: It will be faster to read the codes below
%
% by SeHyoun Ahn, June 2016
%
% SYNTAX:
% [state_red,inv_state_red,g0,g1,c,pi,psi] = clean_G0(g0,g1,c,pi,psi)
tmp=(max(abs([g0,psi]),[],2)==0);
redundant=find(tmp);
keep=find(1-tmp);
inv_state_red=sparse(null(full(g1(redundant,:))));

g0=inv_state_red'*g0*inv_state_red;
g1=inv_state_red'*g1*inv_state_red;
g1=g0\g1;
psi=g0\inv_state_red'*psi;
pi=g0\inv_state_red'*pi;
c=g0\inv_state_red'*c;

state_red = inv_state_red';


% maximally flat delay LC filter pp 323 A. I. Zveref
% Copyright 2004-2013 The MathWorks, Inc.
R=8;      % load resistance
fc=80e3;  % bandpass corner

w=2*pi*fc;

c1=1.5012; l2=0.978; c3=.612;l4=.211;  % Rs=inf,  Rl = 1
% scale for freq and impedance ...
C1=c1/(R*w)
L2=l2*R/w
C3=c3/(R*w)
L4=l4*R/w


function [A] = tapas_uniqc_spm_matrix(P, order)
% Return an affine transformation matrix
% copy of spm_matrix from Version 6906 (SPM12) 20-Oct-16
% FORMAT [A] = spm_matrix(P [,order])
% P(1)  - x translation
% P(2)  - y translation
% P(3)  - z translation
% P(4)  - x rotation about - {pitch} (radians)
% P(5)  - y rotation about - {roll}  (radians)
% P(6)  - z rotation about - {yaw}   (radians)
% P(7)  - x scaling
% P(8)  - y scaling
% P(9)  - z scaling
% P(10) - x affine
% P(11) - y affine
% P(12) - z affine
%
% order - application order of transformations [Default: 'T*R*Z*S']
%
% A     - affine transformation matrix
%__________________________________________________________________________
%
% spm_matrix returns a matrix defining an orthogonal linear (translation,
% rotation, scaling or affine) transformation given a vector of
% parameters (P).  By default, the transformations are applied in the
% following order (i.e., the opposite to which they are specified):
%
% 1) shear
% 2) scale (zoom)
% 3) rotation - yaw, roll & pitch
% 4) translation
%
% This order can be changed by calling spm_matrix with a string as a
% second argument. This string may contain any valid MATLAB expression
% that returns a 4x4 matrix after evaluation. The special characters 'S',
% 'Z', 'R', 'T' can be used to reference the transformations 1)-4)
% above. The default order is 'T*R*Z*S', as described above.
%
% SPM uses a PRE-multiplication format i.e. Y = A*X where X and Y are 4 x n
% matrices of n coordinates.
%__________________________________________________________________________
%
% See also: tapas_uniqc_spm_imatrix.m
%__________________________________________________________________________
% Copyright (C) 1994-2011 Wellcome Trust Centre for Neuroimaging

% Karl Friston

%-Special case: translation only
%--------------------------------------------------------------------------
if numel(P) == 3
    A = eye(4);
    A(1:3,4) = P(:);
    return;
end

%-Pad P with 'null' parameters
%--------------------------------------------------------------------------
q  = [0 0 0 0 0 0 1 1 1 0 0 0];
P  = [P q((length(P) + 1):12)];

%-Translation / Rotation / Scale / Shear
%--------------------------------------------------------------------------
T  =   [1   0   0   P(1);
        0   1   0   P(2);
        0   0   1   P(3);
        0   0   0   1];

R1  =  [1   0           0           0;
        0   cos(P(4))   sin(P(4))   0;
        0  -sin(P(4))   cos(P(4))   0;
        0   0           0           1];

R2  =  [cos(P(5))   0   sin(P(5))   0;
        0           1   0           0;
       -sin(P(5))   0   cos(P(5))   0;
        0           0   0           1];

R3  =  [cos(P(6))   sin(P(6))   0   0;
       -sin(P(6))   cos(P(6))   0   0;
        0           0           1   0;
        0           0           0   1];

R   = R1*R2*R3;

Z   =  [P(7)   0       0       0;
        0      P(8)    0       0;
        0      0       P(9)    0;
        0      0       0       1];

S   =  [1      P(10)   P(11)   0;
        0      1       P(12)   0;
        0      0       1       0;
        0      0       0       1];

%-Affine transformation matrix
%--------------------------------------------------------------------------
if nargin < 2
    A = T*R*Z*S;
else
    A = eval(sprintf('%s;', order));
    if ~isnumeric(A) || ~isequal(size(A),[4 4])
        error('tapas:uniqc:SpmMatrix:InvalidOrderExpression', ...
            'Invalid order expression ''%s''.', order);
    end
end


function fitness = trace_fit_gaussian(C,fr,t_int,fac)

if nargin < 4 || isempty(fac); fac = 3; end
if nargin < 3 || isempty(t_int); t_int = 0.25; end
if nargin < 2 || isempty(fr); fr = 30; end

Np = round(t_int*fr);
[K,T] = size(C);
bas = zeros(K,1);
sn = zeros(K,1);
for i = 1:K
    [~,density,xmesh] = kde(C(i,:));
    [~,ind] = max(density);
    bas(i) = xmesh(ind);
    sn(i) = std(C(i,C(i,:)<bas(i)))/sqrt(1-2/pi);
end

z = bsxfun(@times, 1./(fac*sn(:)), bsxfun(@minus, C, bas));  % normalized z scores
z_pr = 1 - normcdf(z);

filt_z = filter(ones(1,Np),1,log(z_pr),[],2);
fitness = min(filt_z,[],2);


% Fig. 7.2  Feedback Control of Dynamic Systems, 6e
%            Franklin, Powell, Emami
% script to generate Fig. 7.2

clear all;
close all;

F = [0 1; 0 -0.05];
G = [0; 0.001];
H = [0 1];
J = 0;
sys=ss(F,500*G,H,J);
step(sys);
title('Fig. 7.2: Response of car velocity to a step in u');
nicegrid;


function covMa = cal_covMa4Block(Block,blockWin)
K = size(Block,1);
num = size(Block,4);
N = size(Block,2);
K_m = K/2+1;
X = zeros(size(Block));
for i = 1:num
    X(:,:,:,i) = fft(Block(:,:,i).*blockWin);
end
covMa = zeros(N,N,K_m,num);
for i = 1:num
    for j = 1:K_m
        temp = permute(X(j,:,:,i),[2 3 1 4]);
        covMa(:,:,j,i) = temp*temp'/size(X,3);
    end
end


% MRC_scheme.m
% Receiver diversity - MRC
clear, clf
L_frame=130;
N_packet=4000;
b=2;                % Set to 1/2/3/4 for BPSK/QPSK/16QAM/64QAM
SNRdBs=[0:2:20];
sq2=sqrt(2);
%SNRdBs=[0:10:20]; sq2=sqrt(2);
for iter=1:3
   if iter==1
       NT=1;
       NR=1;
       gs='-kx'; % SISO
    elseif iter==2
        NT=1;
        NR=2;
        gs='-^';
   else
       NT=1;
       NR=4;
       gs='-ro';
   end
   sq_NT=sqrt(NT);
   for i_SNR=1:length(SNRdBs)
      SNRdB=SNRdBs(i_SNR);
      sigma=sqrt(0.5/(10^(SNRdB/10)));
      for i_packet=1:N_packet
         symbol_data=randi([0,1],L_frame*b,NT);
         [temp,sym_tab,P]=modulator(symbol_data.',b);
         X=temp.';
         Hr = (randn(L_frame,NR)+j*randn(L_frame,NR))/sq2;
         H = reshape(Hr,L_frame,NR);
         Habs = sum(abs(H).^2,2);
         Z=0;
         for i=1:NR
            R(:,i) = sum(H(:,i).*X,2)/sq_NT + sigma*(randn(L_frame,1)+j*randn(L_frame,1));
            Z = Z + R(:,i).*conj(H(:,i));
         end
         for m=1:P
            d1(:,m)=abs(sum(Z,2)-sym_tab(m)).^2+(-1+sum(Habs,2))*abs(sym_tab(m))^2;
         end
         [y1,i1] = min(d1,[],2);
         Xd=sym_tab(i1).';
         temp1 = X>0;
         temp2 = Xd>0;
         noeb_p(i_packet)=sum(sum(temp1~=temp2));
      end
      BER(iter,i_SNR) = sum(noeb_p)/(N_packet*L_frame*b);
   end
   semilogy(SNRdBs,BER(iter,:),gs);
   hold on;
   axis([SNRdBs([1 end]) 1e-6 1e0])
end
title('BER perfoemancde of MRC Scheme');
xlabel('SNR[dB]');
ylabel('BER')
grid on;
set(gca,'fontsize',9)
legend('SISO','MRC (Tx:1,Rx:2)','MRC (Tx:1,Rx:4)')


function [m2] = km22m2(km2)
% Convert area from square kilometers to square meters.
% Chad A. Greene 2012
m2 = km2*1000000;


function xfac=dasp(lat)
% DASP sets data aspect ratio to 1
% or if optional lat is supplied, crude projection
% Usage: xfac=dasp(lat);
% where: lat = latitude in degrees
% xfac : the ratio lon/lat
if(nargin==1),
   if (isnan(lat)),
      set(gca,'DataAspectRatioMode','auto');
   else
      xfac=cos(lat*pi/180);
      set (gca, 'DataAspectRatio', [1 xfac 1000] );
   end
else
   set (gca, 'DataAspectRatio', [1 1 1000] );
end


%  Figure 4.6      Feedback Control of Dynamic Systems, 6e
%                   Franklin, Powell, Emami
%
numG=2;
den=[1 1 2];
% add integrator
denG=conv(den,[1 0]);
t=0:.03:10;
y=step(numG,denG,t);
axis('square');
plot(t,t,t,y);
title('Fig. 4.6 Relationship between ramp response and Kv');
xlabel('Time (sec)');
ylabel('r, y');
axis('normal')
gtext('r')
gtext('y')
gtext('e_{ss}=1/K_v')
nicegrid;


function [Btuph] = TW2Btuph(TW)
% Convert power from terawatts to British thermal units per hour.
% Chad A. Greene 2012
Btuph = TW*3.412141633e+12;


% Gives estimate of T0-normalized LF parameters given an Rd value
%
% Description
%  The Rd shape parameter [1] of the Liljencrants-Fant (LF) glottal model [2]
%  expresses a regression of the original shape parameters {te,tp,ta}. This
%  function gives the shape parameters {te,tp,ta} which correspond to a given Rd
%  value.
%
% Input
%  Rd  : The Rd shape parameter to convert.
%
% Output
%  te  : Glottal shape parameter, see [1]p.6 (assuming T0=1 ! (T0-normalized))
%  tp  : Glottal shape parameter, see [1]p.6 (assuming T0=1 ! (T0-normalized))
%  ta  : Glottal shape parameter, see [1]p.6 (assuming T0=1 ! (T0-normalized))
%
% See Also
%  gfm_spec_lf.m
%
% References
%  [1] G. Fant, "The LF-model revisited. Transformations and frequency domain
%      analysis", STL-QPSR 36(2-3):119-156, 1995.
%  [2] G. Fant, J. Liljencrants and Q. Lin, "A four-parameter model of glottal
%      flow", STL-QPSR, vol. 4, pp. 1-13, 1985.
%
% Copyright (c) 2011 University of Crete - Computer Science Department
%
% License
%  This file is under the LGPL license,  you can
%  redistribute it and/or modify it under the terms of the GNU Lesser General
%  Public License as published by the Free Software Foundation, either version 3
%  of the License, or (at your option) any later version. This file is
%  distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
%  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
%  PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
%  details.
%
% This function is part of the Covarep project: http://covarep.github.io/covarep
%
% Author
%  Gilles Degottex <degottex@csd.uoc.gr>
%

function [te tp ta] = Rd2tetpta(Rd)

	Rap = (-1+4.8.*Rd)/100;                             % [1](2)
	Rkp = (22.4+11.8.*Rd)/100;                          % [1](3)
	Rgp = 1./(4*((0.11.*Rd./(1/2+1.2.*Rkp))-Rap)./Rkp); % [1] indirectly (4)

	tp = 1./(2.*Rgp); % [1]p.121
	te = tp.*(Rkp+1); % [1]p.121
	ta = Rap;         % [1]p.121

return


function t = logtform(rmin, rmax, nr, nw)
% LOGTFORM makes a log-polar transform structure for imtransform
%     T = LOGTFORM(RMIN, RMAX, NR, NW) returns the transform structure for
%     a system with minimum ring radius RMIN, maximum ring radius RMAX, NR
%     rings and NR wedges. The empty matrix may be given for any one (but
%     only one) of these in which case the circular-samples condition
%     RMAX=RMIN*exp(2*pi*(NR-1)/NW) will be applied (with an adjustment
%     to RMIN if necessary to make NR and NW integers.
%
% See also LOGSAMPLE, LOGSAMPBACK

% Copyright David Young 2010

[rmin, rmax, nr, nw, k] = complete_args(rmin, rmax, nr, nw);
tdata = struct('rmin', rmin, 'rmax', rmax, 'nr', nr, 'nw', nw, 'k', k);
t = maketform('custom', 2, 2, @contorth, @rthtocon, tdata);
end

function x = contorth(u, t)
% Conventional to log-polar. See maketform.
td = t.tdata;
[th, p] = cart2pol(u(:,1), u(:, 2));
p(~p) = td.rmin/2;            % Omit centre point
x = [td.k * log(p/td.rmin),  td.nw*mod(th/(2*pi), 1)];
end

function u = rthtocon(x, t)
% Log-polar to conventional. See maketform.
td = t.tdata;
p = td.rmin * exp(x(:, 1)/td.k);
th = (2*pi/td.nw) * x(:, 2);
[x, y] = pol2cart(th, p);
u = [x, y];
end

function [rmin, rmax, nr, nw, k] = complete_args(rmin, rmax, nr, nw)
% Circular pixels condition
if isempty(rmin)
    k = nw / (2*pi);
    rmin = rmax * exp((1-nr)/k);
elseif isempty(rmax)
    k = nw / (2*pi);
    rmax = rmin * exp((nr-1)/k);
elseif isempty(nw)
    k = (nr-1) / log(rmax/rmin);
    nw = round(2 * pi * k);
    k = nw / (2*pi);
    rmin = rmax * exp((1-nr)/k);
elseif isempty(nr)
    k = nw / (2*pi);
    nr = round(k * log(rmax/rmin) + 1);
    rmin = rmax * exp((1-nr)/k);
else
    k = (nr-1) / log(rmax/rmin);
end
end