classdef SymbolManager
    % SYMBOLMANAGER allows you to control appearance of symbols on map
    properties(Constant)
        %fields = {'LineWidth','LineStyle','Color',...
        %    'Marker','MarkerSize','MarkerEdgeColor','MarkerFaceColor'};
         fields={'DisplayName';'Color';'LineStyle';'LineWidth';'Marker';'MarkerSize';'MarkerEdgeColor';'MarkerFaceColor'}
    end
    properties
        markerNames ={'+','o','*','.','x','square','diamond','^','v','<','>','pentagram','hexagram','none'};
        markerValues={'+','o','*','.','x','s',     'd',      '^','v','<','>','p',        'h',       'none'};

        lineValues = {'-','--',':','-.','none'};

        colors = {'yellow','magenta','cyan','red','lime','blue','white','black','choose'};
        colors_rgb = {[1 1 0],[1 0 1],[0 1 1], [1 0 0], [0 1 0], [0 0 1], [1 1 1], [0 0 0]};

    end

    methods
        function obj = SymbolManager()

        end

        function C=fill_values(obj,h)

            switch h.Type
                case 'scatter'
                    [MECidx, MarkerEdgeColor] = Xcolor({'flat';'none'}, h.MarkerEdgeColor);
                    [MFCidx, MarkerFaceColor] = Xcolor({'auto','flat','none'}, h.MarkerFaceColor);
                    if size(h.CData,2) == 3
                        [Cidx, CColor] = Xcolor({}, h.CData(1,:));
                    else
                        CColor={'various','choose'};
                        Cidx=1;
                    end

                    mIndex=find(strcmp(h.Marker,obj.markerNames));

                    C = {... fieldname, fieldwidth, fieldtype,
                        'DisplayName',      120, {'Style', 'text','String',h.DisplayName};...
                        'CData',            130,  {'Style','PopupMenu','String',CColor,'Value',Cidx,...
                                              'Callback', @(s,~)setLineEdgeFaceColor(s,'CData')};...
                        'LineStyle',        60, {'Style','text','String',''};...
                        'LineWidth',        50,  {'Style','edit','String',num2str(h.LineWidth),...
                                              'Callback', @(src,~)set(h,'LineWidth',str2double(src.String))};...
                        'Marker',           90,  {'Style','PopupMenu','String',obj.markerNames,'Value',find(strcmp(h.Marker,obj.markerNames)),...
                                              'Callback', @(src,~)set(h,'Marker',obj.markerNames{src.Value})};...
                        'SizeData',         50,  {'Style','edit','String',num2str(mean(h.SizeData)),...
                                              'Callback', @(src,~)set(h,'SizeData',str2double(src.String))};...
                        'MarkerEdgeColor',  130,  {'Style','PopupMenu','String',MarkerEdgeColor,'Value',MECidx,...
                                              'Callback', @(s,~)setLineEdgeFaceColor(s,'MarkerEdgeColor')};...
                        'MarkerFaceColor',  130,  {'Style','PopupMenu','String',MarkerFaceColor,'Value',MFCidx,...
                                              'Callback', @(s,~)setLineEdgeFaceColor(s,'MarkerFaceColor')};...
                        };

                case 'line'
                    [MECidx, MarkerEdgeColor] = Xcolor({'auto';'none'}, h.MarkerEdgeColor);
                    [MFCidx, MarkerFaceColor] = Xcolor({'auto','none'}, h.MarkerFaceColor);
                    [Cidx, CColor] = Xcolor({}, h.Color(1,:));

                    mIndex=find(strcmp(h.Marker,obj.markerNames));
                    assert(~isempty(mIndex),'marker issue %s not in markerNames',h.Marker);

                    C = {... fieldname, fieldwidth, fieldtype, inLine, inScatter, getfun, setfun
                        'DisplayName',  120, {'Style','text','String',h.DisplayName};...
                        'Color',        130,  {'Style','PopupMenu','String',CColor,'Value',Cidx,...
                                              'Callback',@(s,~)setLineEdgeFaceColor(s,'Color')};...
                        'LineStyle',    60,  {'Style','PopupMenu','String',obj.lineValues,'Value',find(strcmp(h.LineStyle,obj.lineValues)),...
                                              'Callback',@(src,~)set(h,'LineStyle',obj.lineValues{src.Value})};...
                        'LineWidth',    50,  {'Style','edit','String',num2str(h.LineWidth),...
                                              'Callback',@(src,~)set(h,'LineWidth',str2double(src.String))};...
                        'Marker',       90,  {'Style','PopupMenu','String',obj.markerNames,'Value',mIndex,...
                                              'Callback',@(src,~)set(h,'Marker',obj.markerNames{src.Value})};...
                        'MarkerSize',   50,  {'Style','edit','String',num2str(h.MarkerSize),...
                                              'Callback',@(src,~)set(h,'MarkerSize',str2double(src.String))};...
                        'MarkerEdgeColor',130,  {'Style','PopupMenu','String',MarkerEdgeColor,'Value',MECidx,...
                                              'Callback',@(s,~)setLineEdgeFaceColor(s,'MarkerEdgeColor')};...
                        'MarkerFaceColor',130,  {'Style','PopupMenu','String',MarkerFaceColor,'Value',MFCidx,...
                                              'Callback', @(s,~)setLineEdgeFaceColor(s,'MarkerFaceColor')};...
                        };
                otherwise
                    C={};
            end
            for i=1:size(C,1)
                C{i,4} = @()h.(C{i,1}); % get function
                C{i,5} = @(val)set(h,C{i,1},val); % set function
            end
            %disp(C)

            function setLineEdgeFaceColor(src,fld)
                if ismember(src.String{src.Value},{'auto','none','flat'})
                    h.(fld)=src.String{src.Value};
                elseif src.Value==numel(src.String) % last option is always CHOOSE
                    try
                        newc=uisetcolor(h.(fld));
                    catch
                        newc=uisetcolor([0 0 0]);
                    end
                    h.(fld)=newc;
                    % add this "new" color to the list
                    src.String(end+1)=src.String(end);
                    nm = FancyColors.name(newc);
                    src.String(end-1)={FancyColors.colorize(nm,nm)};
                else
                    cs = src.String;
                    fancy=endsWith(cs,'');
                    cs(fancy)=extractBetween(cs(fancy),'">',"");

                    nAdded = find(strcmp(cs,obj.colors{1})) - 1; % zero if nothing addeds

                    %nAdded = find(strcmp(src.String,obj.colors{1})) - 1; % zero if nothing added

                    idx=src.Value - nAdded;
                    idx=idx(1);
                    newc = FancyColors.rgb(cs{src.Value});
                    %{
                    if idx>numel(obj.colors_rgb)
                        %newc = FancyColors.rgb(src.String{src.Value});
                    else
                        newc = obj.colors_rgb{idx};
                    end
                    %}
                    h.(fld)= newc;
                end
            end

            function [idx, displist]=Xcolor(additionalOptions, existingValue)
                % find position in list. if it doesn't exist, add it. return index.

                % add field-unique options to top of list
                %displist = [additionalOptions(:) ; obj.colors(:)];
                cl = obj.colors(:);
                for n=1:numel(cl)
                    if ~startsWith(cl(n),'')
                        cl(n)={ FancyColors.colorize(cl{n},cl{n}) };
                    end
                end
                displist = [additionalOptions(:) ; cl];
                lookuplist = [additionalOptions(:) ; obj.colors_rgb(:)];

                % find existing value's position within the lookup list
                idx = find(cellfun(@(x)isequal(x,existingValue), lookuplist));

                % if our value isn't found, then add it to the top of the list, and set index to it.
                if isempty(idx) || idx==0
                    nm = FancyColors.name(existingValue);
                    displist(end+1)=displist(end);
                    displist(end-1)={FancyColors.colorize(nm,nm)};
                    idx=numel(displist)-1;
                end
            end
        end

        function test(obj, ax)

            % show the legend. has dual purpose. it assigns DisplayName and provides feedback for user
            wasVisible=~isempty(ax.Legend) && ax.Legend.Visible == "on";
            if ~wasVisible
                legend(ax,'show');
                ax.Legend.Visible='on';
            end

            f=findobj('Tag','testfigure');

            ch=ax.Children;
            x=20; xspace=5;
            y = 20; h=20;
            fullht = y+10;

            ts = ax.Title.String;
            if isempty(ts)
                ts=ax.Tag;
            end

            if isempty(f)
                f=figure('Tag','testfigure','Name',sprintf('Adjust Symbols for %s',ts));
                f.Position(3)=760;
                f.Position(4)=numel(ch)*fullht+60;
                f.MenuBar='none';
            else
                set(f,'Name',sprintf('Adjust Symbols for %s',ts));
                clf
            end

            xoff=x;
            for itt=numel(ch): -1 : 1
                if ~isvalid(ch(itt))
                    ch(itt)=[];
                    continue;
                end
                if (~strcmp(ch(itt).Type,'line') && ~strcmp(ch(itt).Type,'scatter'))
                    continue
                end
                C=obj.fill_values(ch(itt));
                for i=1:size(C,1)
                    w=C{i,2};
                    misc_nv = C{i,3};
                    uicontrol(gcf,'Position',[xoff,y,w,20],misc_nv{:});
                    xoff = xoff + w + xspace;
                end

                y=y+30; % up to next row
                if itt==1 && f.Position(3) < xoff+5
                    f.Position(3)= xoff+5;
                end
                xoff=x;
            end

            % label the fields
            flds = {'DisplayName';'Color';'LineStyle';'LineWidth';'Marker';'MarkerSize';'MarkerEdgeColor';'MarkerFaceColor'};
            for n=1:numel(obj.fields)
                fn=obj.fields{n};
                w = C{n,2};
                uicontrol(f,'Style','text','String',fn,'HorizontalAlignment','center',...
                    'Position',[xoff, y, w, h]);
                xoff = xoff + w + xspace;
            end

            % hide it again.
            if ~wasVisible
                ax.Legend.Visible='off';
            end
        end

    end
    methods(Static)
        function cb(src,ev,ax)
            sm=SymbolManager;
            sm.test(ax);
        end
    end
end


function output = trim_signals(input, offset)
    % Trim signals according to offsets
    N = length(offset);
    output = cell(size(input));
    frame_index = floor(offset/N);
%     display(frame_index);
    trim_index = max(frame_index) - frame_index;
%     display(trim_index);
    for i=1:N
        output{i} = input{i}((trim_index(i)+1):end);
    end

    % trim end so all signals have same length
    % required by non-uniform reconstruction algorithm
    minlen = min(cellfun('length', output));
    for i = 1:N
       output{i} = output{i}(1:minlen);
    end
end


function roi = roiGrayAll(seg, mr, roi);
%
% roi = roiGrayAll(seg, [mr], [roi]);
%
% Create an ROI containing all gray matter nodes for a
% segmentation, or append these nodes to an existing ROI.
%
% seg: segmentation object. See segCreate.
%
% roi: if an ROI structure is passed as a second argument,
%      will append the gray coords to the roi, rather than
%      creating a new one.
%
% ras, 01/2007.
if notDefined('seg'), error('Need a segmentation.'); end
if notDefined('roi'), roi = roiCreate('I|P|R');      end
if notDefined('mr'),  mr = [];                       end

if isempty(seg.nodes)
    [seg.nodes seg.edges] = segGet(seg, 'gray');
end

roi.coords = combineCoords(roi.coords, seg.nodes([2 1 3],:), 'union');
roi.name = sprintf('Gray Matter %s', seg.name);

if ~isempty(mr)
    roi = roiCheckCoords(roi, mr);
end

return


function gpcf = gpcf_cat(varargin)
%GPCF_CAT  Create a categorical covariance function
%
%  Description
%    GPCF = GPCF_CAT('PARAM1',VALUE1,'PARAM2,VALUE2,...)
%    creates a categorical covariance function structure in
%    which the named parameters have the specified values. Any
%    unspecified parameters are set to default values.
%
%    GPCF = GPCF_CAT(GPCF,'PARAM1',VALUE1,'PARAM2,VALUE2,...)
%    modify a covariance function structure with the named
%    parameters altered with the specified values.
%
%    Categorical covariance function returns correlation 1 if input
%    values X_i and X_j are equal and 0 otherwise.
%
%    Parameters for categorical covariance function
%      selectedVariables - a vector defining which inputs are used
%
%  See also
%    GP_SET, GPCF_*, PRIOR_*, MEAN_*
%
% Copyright (c) 2007-2010 Jarno Vanhatalo
% Copyright (c) 2008-2010 Jaakko Riihimäki
% Copyright (c) 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.

  ip=inputParser;
  ip.FunctionName = 'GPCF_CAT';
  ip.addOptional('gpcf', [], @isstruct);
  ip.addParamValue('selectedVariables',[], ...
                   @(x) isempty(x) || (isvector(x) && all(x>0)));
  ip.parse(varargin{:});
  gpcf=ip.Results.gpcf;

  if isempty(gpcf)
    % Initialize a covariance function structure
    init=true;
    gpcf.type = 'gpcf_cat';
  else
    % Modify a covariance function structure
    if ~isfield(gpcf,'type') && ~isequal(gpcf.type,'gpcf_cat')
      error('First argument does not seem to be a valid covariance function structure')
    end
    init=false;
  end

  if ~ismember('selectedVariables',ip.UsingDefaults)
    if ~isempty(ip.Results.selectedVariables)
      gpcf.selectedVariables = ip.Results.selectedVariables;
    elseif isfield(gpcf,'selectedVariables')
      gpcf=rmfield(gpcf,'selectedVariables');
    end
  end
  if init
    gpcf.fh.pak = @gpcf_cat_pak;
    gpcf.fh.unpak = @gpcf_cat_unpak;
    gpcf.fh.lp = @gpcf_cat_lp;
    gpcf.fh.lpg = @gpcf_cat_lpg;
    gpcf.fh.cfg = @gpcf_cat_cfg;
    gpcf.fh.ginput = @gpcf_cat_ginput;
    gpcf.fh.cov = @gpcf_cat_cov;
    gpcf.fh.trcov  = @gpcf_cat_trcov;
    gpcf.fh.trvar  = @gpcf_cat_trvar;
    gpcf.fh.recappend = @gpcf_cat_recappend;
  end

end

function [w,s,h] = gpcf_cat_pak(gpcf, w)
%GPCF_CAT_PAK  Combine GP covariance function parameters into
%              one vector.
%
%  Description
%    W = GPCF_CAT_PAK(GPCF) takes a covariance function
%    structure GPCF and combines the covariance function
%    parameters and their hyperparameters into a single row
%    vector W. This is a mandatory subfunction used for
%    example in energy and gradient computations.
%
%       w = []
%
%  See also
%    GPCF_CAT_UNPAK

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

function [gpcf, w] = gpcf_cat_unpak(gpcf, w)
%GPCF_CAT_UNPAK  Sets the covariance function parameters into
%                the structure
%
%  Description
%    [GPCF, W] = GPCF_CAT_UNPAK(GPCF, W) takes a covariance
%    function structure GPCF and a parameter vector W, and
%    returns a covariance function structure identical to the
%    input, except that the covariance parameters have been set
%    to the values in W. Deletes the values set to GPCF from W
%    and returns the modified W. This is a mandatory subfunction
%    used for example in energy and gradient computations.
%
%    Assignment is inverse of
%       w = []
%
%  See also
%   GPCF_CAT_PAK

end

function lp = gpcf_cat_lp(gpcf)
%GPCF_CAT_LP  Evaluate the energy of prior of covariance function parameters
%
%  Description
%    LP = GPCF_CAT_LP(GPCF) takes a covariance function
%    structure GPCF and returns log(p(th)), where th collects the
%    parameters.  This is a mandatory subfunction used for example
%    in energy computations.
%
%  See also
%    GPCF_CAT_PAK, GPCF_CAT_UNPAK, GPCF_CAT_LPG, GP_E

  lp = 0;

end

function lpg = gpcf_cat_lpg(gpcf)
%GPCF_CAT_LPG  Evaluate gradient of the log prior with respect
%               to the parameters.
%
%  Description
%    LPG = GPCF_CAT_LPG(GPCF) takes a covariance function
%    structure GPCF and returns LPG = d log (p(th))/dth, where th
%    is the vector of parameters.  This is a mandatory subfunction
%    used for example in gradient computations.
%
%  See also
%    GPCF_CAT_PAK, GPCF_CAT_UNPAK, GPCF_CAT_LP, GP_G

  lpg = [];

end

function DKff = gpcf_cat_cfg(gpcf, x, x2, mask, i1)
%GPCF_CAT_CFG  Evaluate gradient of covariance function
%              with respect to the parameters.
%
%  Description
%    DKff = GPCF_CAT_CFG(GPCF, X) takes a covariance function
%    structure GPCF, a matrix X of input vectors and returns
%    DKff, the gradients of covariance matrix Kff = k(X,X) with
%    respect to th (cell array with matrix elements). This is a
%    mandatory subfunction used in gradient computations.
%
%    DKff = GPCF_CAT_CFG(GPCF, X, X2) takes a covariance function
%    structure GPCF, a matrix X of input vectors and returns
%    DKff, the gradients of covariance matrix Kff = k(X,X2) with
%    respect to th (cell array with matrix elements). This subfunction
%    is needed when using sparse approximations (e.g. FIC).
%
%    DKff = GPCF_CAT_CFG(GPCF, X, [], MASK) takes a covariance
%    function structure GPCF, a matrix X of input vectors and
%    returns DKff, the diagonal of gradients of covariance matrix
%    Kff = k(X,X2) with respect to th (cell array with matrix
%    elements). This subfunction is needed when using sparse
%    approximations (e.g. FIC).
%
%    DKff = GPCF_CAT_CFG(GPCF, X, X2, MASK, i) takes a covariance
%    function structure GPCF, a matrix X of input vectors and
%    returns DKff, the gradients of covariance matrix Kff =
%    k(X,X2), or k(X,X) if X2 is empty, with respect to ith
%    hyperparameter. This subfunction is needed when using
%    memory save option in gp_set.
%
%  See also
%    GPCF_CAT_PAK, GPCF_CAT_UNPAK, GPCF_CAT_LP, GP_G

  if nargin==5
    % Use memory save option
    if i1==0
      % Return number of hyperparameters
      DKff=0;
      return
    end
  end
  DKff = {};

end

function [DKff, lpg]  = gpcf_cat_ginput(gpcf, x, x2, i1)
%GPCF_CAT_GINPUT  Evaluate gradient of covariance function with
%                 respect to x.
%
%  Description
%    DKff = GPCF_CAT_GINPUT(GPCF, X) takes a covariance function
%    structure GPCF, a matrix X of input vectors and returns
%    DKff, the gradients of covariance matrix Kff = k(X,X) with
%    respect to X (cell array with matrix elements). This subfunction
%    is needed when computing gradients with respect to inducing
%    inputs in sparse approximations.
%
%    DKff = GPCF_CAT_GINPUT(GPCF, X, X2) takes a covariance
%    function structure GPCF, a matrix X of input vectors
%    and returns DKff, the gradients of covariance matrix Kff =
%    k(X,X2) with respect to X (cell array with matrix elements).
%    This subfunction is needed when computing gradients with
%    respect to inducing inputs in sparse approximations.
%
%    DKff = GPCF_CAT_GINPUT(GPCF, X, X2, i) takes a covariance
%    function structure GPCF, a matrix X of input vectors
%    and returns DKff, the gradients of covariance matrix Kff =
%    k(X,X2), or k(X,X) if X2 is empty, with respect to ith
%    covariate in X. This subfunction is needed when using
%    memory save option in gp_set.
%
%  See also
%   GPCF_CAT_PAK, GPCF_CAT_UNPAK, GPCF_CAT_LP, GP_G

  [n, m] =size(x);

  if nargin==4
    % Use memory save option
    if i1==0
      % Return number of covariates
      if isfield(gpcf,'selectedVariables')
        DKff=length(gpcf.selectedVariables);
      else
        DKff=m;
      end
      return
    end
  end

  if nargin == 2 || isempty(x2)
    ii1 = 0;
    for j = 1:n
      for i=1:m
        ii1 = ii1 + 1;
        DKff{ii1} = zeros(n);
        lpg(ii1) = 0;
      end
    end
  elseif nargin == 3 || nargin == 4
    ii1 = 0;
    for j = 1:n
      for i=1:m
        ii1 = ii1 + 1;
        DKff{ii1} = zeros(n, size(x2,1));
        lpg(ii1) = 0;
      end
    end
  end
end

function C = gpcf_cat_cov(gpcf, x1, x2, varargin)
%GP_CAT_COV  Evaluate covariance matrix between two input vectors
%
%  Description
%    C = GP_CAT_COV(GP, TX, X) takes in covariance function of a
%    Gaussian process GP and two matrixes TX and X that contain
%    input vectors to GP. Returns covariance matrix C. Every
%    element ij of C contains covariance between inputs i in TX
%    and j in X. This is a mandatory subfunction used for example
%    in prediction and energy computations.
%
%  See also
%    GPCF_CAT_TRCOV, GPCF_CAT_TRVAR, GP_COV, GP_TRCOV

  if isempty(x2)
    x2=x1;
  end
  [n1,m1]=size(x1);
  [n2,m2]=size(x2);

  if m1~=m2
    error('the number of columns of X1 and X2 has to be same')
  end

  C=repmat(true,n1,n2);
  if isfield(gpcf, 'selectedVariables')
    for j = 1:length(gpcf.selectedVariables)
      jj=gpcf.selectedVariables(j);
      C = C & bsxfun(@eq,x1(:,jj),x2(:,jj)');
    end
  else
    for j = 1:m1
      C = C & bsxfun(@eq,x1(:,j),x2(:,j)');
    end
  end
  C=double(C);
  C = sparse(C);
end

function C = gpcf_cat_trcov(gpcf, x)
%GP_CAT_TRCOV  Evaluate training covariance matrix of inputs
%
%  Description
%    C = GP_CAT_TRCOV(GP, TX) takes in covariance function of a
%    Gaussian process GP and matrix TX that contains training
%    input vectors. Returns covariance matrix C. Every element ij
%    of C contains covariance between inputs i and j in TX. This
%    is a mandatory subfunction used for example in prediction and
%    energy computations.
%
%  See also
%    GPCF_CAT_COV, GPCF_CAT_TRVAR, GP_COV, GP_TRCOV

  [n,m]=size(x);

  C=repmat(true,n,n);
  if isfield(gpcf, 'selectedVariables')
    for j = 1:length(gpcf.selectedVariables)
      jj=gpcf.selectedVariables(j);
      C = C & bsxfun(@eq,x(:,jj),x(:,jj)');
    end
  else
    for j = 1:m
      C = C & bsxfun(@eq,x(:,j),x(:,j)');
    end
  end
  C=double(C);
  C = sparse(C);
end

function C = gpcf_cat_trvar(gpcf, x)
%GP_CAT_TRVAR  Evaluate training variance vector
%
%  Description
%    C = GP_CAT_TRVAR(GPCF, TX) takes in covariance function of a
%    Gaussian process GPCF and matrix TX that contains training
%    inputs. Returns variance vector C. Every element i of C
%    contains variance of input i in TX. This is a mandatory
%    subfunction used for example in prediction and energy
%    computations.
%
%  See also
%    GPCF_CAT_COV, GP_COV, GP_TRCOV

  [n,m]=size(x);
  C=ones(n,1);

end

function reccf = gpcf_cat_recappend(reccf, ri, gpcf)
%RECAPPEND  Record append
%
%  Description
%    RECCF = GPCF_CAT_RECAPPEND(RECCF, RI, GPCF) takes a
%    covariance function record structure RECCF, record index RI
%    and covariance function structure GPCF with the current MCMC
%    samples of the parameters. Returns RECCF which contains
%    all the old samples and the current samples from GPCF.
%    This subfunction is needed when using MCMC sampling (gp_mc).
%
%  See also
%    GP_MC and GP_MC -> RECAPPEND

  if nargin == 2
    % Initialize the record
    reccf.type = 'gpcf_cat';

    % Set the function handles
    reccf.fh.pak = @gpcf_cat_pak;
    reccf.fh.unpak = @gpcf_cat_unpak;
    reccf.fh.lp = @gpcf_cat_lp;
    reccf.fh.lpg = @gpcf_cat_lpg;
    reccf.fh.cfg = @gpcf_cat_cfg;
    reccf.fh.cov = @gpcf_cat_cov;
    reccf.fh.trcov  = @gpcf_cat_trcov;
    reccf.fh.trvar  = @gpcf_cat_trvar;
    reccf.fh.recappend = @gpcf_cat_recappend;
  else
    % Append to the record
    if isfield(gpcf, 'selectedVariables')
      reccf.selectedVariables = gpcf.selectedVariables;
    end
  end
end


classdef Constant_LineSearchInitiator < LineSearchInitiator

    properties (Access = private)
        value
    end

    methods (Access = public)

        function obj = Constant_LineSearchInitiator(cParams)
            obj.init(cParams);
            obj.value = cParams.value;
        end

        function initStep = compute(obj,lastStep)
            initStep = obj.value;
        end

    end

end


function f = tan( f )
%TAN   Tangent of a SEPARABLEAPPROX.

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

% Empty check:
if ( isempty( f ) )
    return
end

f = compose( f, @tan );

end


function arrivals_per_event(cobj)
    N = numel(cobj.arrivals);
    na = [];
    if N>1
        for c=1:N
            na = [na numel(cobj.arrivals{c}.time)];
        end
        m = max(na);
        for v=1:m
            disp(sprintf('arrivals = %d, count = %d', v, sum(na==v) ));
        end
    end

end


function f = minus(f, g)
%-   CHEBFUN minus.
%   F - G subtracts CHEBFUNs F and G, or a scalar from a CHEBFUN if either F or
%   G is a scalar.
%
%   H = MINUS(F, G) is called for the syntax 'F - G'.

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

f = plus(f, uminus(g));

end


function epoch = spm_cfg_eeg_epochs
% Configuration file for M/EEG epoching
%__________________________________________________________________________
% Copyright (C) 2008-2016 Wellcome Trust Centre for Neuroimaging

% Stefan Kiebel
% $Id: spm_cfg_eeg_epochs.m 7095 2017-06-07 10:15:59Z vladimir $

D        = cfg_files;
D.tag    = 'D';
D.name   = 'File Name';
D.filter = 'mat';
D.num    = [1 1];
D.help   = {'Select the M/EEG mat file.'};

bc        = cfg_menu;
bc.tag    = 'bc';
bc.name   = 'Baseline correction';
bc.help   = {'Perform baseline correction when epoching, or not.'};
bc.labels = {'Yes','No'};
bc.values = {1 0};
bc.val    = {1};

% input via trl file
trlfile        = cfg_files;
trlfile.tag    = 'trlfile';
trlfile.name   = 'Trial definition file';
trlfile.filter = 'mat';
trlfile.num    = [1 1];
trlfile.help   = {'Select the trialfile mat file.'};

eventpadding         = cfg_entry;
eventpadding.tag     = 'eventpadding';
eventpadding.name    = 'Event padding';
eventpadding.strtype = 'r';
eventpadding.val     = {0};
eventpadding.num     = [1 1];
eventpadding.help    = {['In seconds: the additional time period around each trial',...
    'for which the events are saved with the trial (to let the ',...
    'user keep and use for analysis events which are outside ',...
    'trial borders). Default is 0 s.']};

% input via trialdef
timewin         = cfg_entry;
timewin.tag     = 'timewin';
timewin.name    = 'Time window';
timewin.strtype = 'r';
timewin.num     = [1 2];
timewin.help    = {'Start and end of epoch [ms].'};

conditionlabel         = cfg_entry;
conditionlabel.tag     = 'conditionlabel';
conditionlabel.name    = 'Condition label';
conditionlabel.strtype = 's';
conditionlabel.help    = {''};

eventtype         = cfg_entry;
eventtype.tag     = 'eventtype';
eventtype.name    = 'Event type';
eventtype.strtype = 's';
eventtype.help    = {''};

eventvalue         = cfg_entry;
eventvalue.tag     = 'eventvalue';
eventvalue.name    = 'Event value';
eventvalue.strtype = 'e';
eventvalue.help    = {''};

trlshift         = cfg_entry;
trlshift.tag     = 'trlshift';
trlshift.name    = 'Shift';
trlshift.strtype = 'r';
trlshift.num     = [1 1];
trlshift.val     = {0};
trlshift.help    = {'shift the triggers by a fixed amount (ms)',...
                   '(e.g. projector delay).'};

trialdef      = cfg_branch;
trialdef.tag  = 'trialdef';
trialdef.name = 'Trial';
trialdef.val  = {conditionlabel eventtype eventvalue, trlshift};
trialdef.help = {''};

define1        = cfg_repeat;
define1.tag    = 'unused';
define1.name   = 'Trial definitions';
define1.values = {trialdef};
define1.help   = {''};

define      = cfg_branch;
define.tag  = 'define';
define.name = 'Define trial';
define.val  = {timewin define1};
define.help = {''};

% input via trialdef
trialength         = cfg_entry;
trialength.tag     = 'trialength';
trialength.name    = 'Trial length';
trialength.strtype = 'r';
trialength.num     = [1 1];
trialength.help    = {'Arbitary trial length [ms].'};

arbitrary      = cfg_branch;
arbitrary.tag  = 'arbitrary';
arbitrary.name = 'Arbitrary trials';
arbitrary.val  = {trialength, conditionlabel};
arbitrary.help = {'Epoch the data in arbitray fixed length trials (e.g. for spectral analysis).'};

trlchoice        = cfg_choice;
trlchoice.tag    = 'trialchoice';
trlchoice.name   = 'How to define trials';
trlchoice.help   = {'Choose one of the two options how to define trials.'}';
trlchoice.values = {trlfile define arbitrary};

prefix         = cfg_entry;
prefix.tag     = 'prefix';
prefix.name    = 'Filename Prefix';
prefix.help    = {'Specify the string to be prepended to the filenames of the epoched dataset. Default prefix is ''e''.'};
prefix.strtype = 's';
prefix.num     = [1 Inf];
prefix.val     = {'e'};

epoch          = cfg_exbranch;
epoch.tag      = 'epoch';
epoch.name     = 'Epoching';
epoch.val      = {D, trlchoice, bc, eventpadding, prefix};
epoch.help     = {'Epoch continuous EEG/MEG data.'};
epoch.prog     = @eeg_epochs;
epoch.vout     = @vout_eeg_epochs;
epoch.modality = {'EEG'};

%==========================================================================
function out = eeg_epochs(job)
% construct the S struct
S.D = job.D{1};

if isfield(job.trialchoice, 'define')
    S.timewin  = job.trialchoice.define.timewin;
    S.trialdef = job.trialchoice.define.trialdef;
elseif isfield(job.trialchoice, 'arbitrary')
    S.trialength = job.trialchoice.arbitrary.trialength;
    S.conditionlabels = job.trialchoice.arbitrary.conditionlabel;
else
    trlfile = load(char(job.trialchoice.trlfile));
    usetrl  = 0;

    % In the new code trl file contains both trl matrix and trial definition
    % struct. trl is usually only applicable to the file on which it was
    % defined and there it must have priority because it can be manually
    % adjusted in the GUI. Otherwise trialdef has priority if present.
    if isfield(trlfile, 'trl')
        if ~all(isfield(trlfile, {'trialdef', 'timewin'}))
             usetrl = 1;
        elseif isfield(trlfile, 'source')
                D = spm_eeg_load(S.D);
                if isequal(D.fname, trlfile.source)
                    usetrl = 1;
                end
        end
    elseif ~all(isfield(trlfile, {'trialdef', 'timewin'}))
        error('The trial definition file could not be inetrpreted');
    end

    if usetrl
        S.trl = trlfile.trl;
        if isfield(trlfile, 'conditionlabels')
            S.conditionlabels = trlfile.conditionlabels;
        end
    else
        S.trialdef = trlfile.trialdef;
        S.timewin = trlfile.timewin;
    end
end

S.bc = job.bc;
S.prefix = job.prefix;
S.eventpadding = job.eventpadding;

out.D      = spm_eeg_epochs(S);
out.Dfname = {fullfile(out.D.path, out.D.fname)};

%==========================================================================
function dep = vout_eeg_epochs(job)
% Output is always in field "D", no matter how job is structured
dep = cfg_dep;
dep.sname = 'Epoched Data';
% reference field "D" from output
dep.src_output = substruct('.','D');
% this can be entered into any evaluated input
dep.tgt_spec   = cfg_findspec({{'strtype','e'}});

dep(2) = cfg_dep;
dep(2).sname = 'Epoched Datafile';
% reference field "Dfname" from output
dep(2).src_output = substruct('.','Dfname');
% this can be entered into any file selector
dep(2).tgt_spec   = cfg_findspec({{'filter','mat'}});


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Released under the MIT License.
% If you use this code, please cite the following paper:
% Mahmoud Afifi, Abdelrahman Abdelhamed, Abdullah Abuolaim, Abhijith
% Punnappurath, and Michael S Brown. CIE XYZ Net: Unprocessing Images for
% Low-Level Computer Vision Tasks. arXiv preprint, 2020.
%
% Author: Mahmoud Afifi | Email: mafifi@eecs.yorku.ca, m.3afifi@gmail.com
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function options = get_training_options(epochs,miniBatch,lR,...
    checkpoint_dir,validation_data, validation_frequency, ...
    GPUDevice, L2Reg, checkpoint_period)

if nargin == 6
    L2Reg = 1.000e-7;
    checkpoint_period = 5;
elseif nargin == 7
    checkpoint_period = 5;
end
gpuDevice(GPUDevice);

if exist(checkpoint_dir,'dir') == 0
    mkdir(checkpoint_dir);
end

options = trainingOptions('adam', ...
    'InitialLearnRate',lR, ...
    'L2Regularization',L2Reg, ...
    'MaxEpochs',epochs, ...
    'MiniBatchSize',miniBatch, ...
    'CheckpointPath',checkpoint_dir, ...
    'Shuffle','once',...%'every-epoch', ...
    'VerboseFrequency',1,...
    'LearnRateSchedule','piecewise',...
    'LearnRateDropPeriod',75,... %drop learning rate every 250 epochs
    'LearnRateDropFactor',0.5,... %drop by 0.5
    'Plots','none',...%'training-progress',...
    'ExecutionEnvironment','gpu',...
    'GradientDecayFactor',0.9,...
    'SquaredGradientDecayFactor' ,0.999,...
    'ValidationData',validation_data,...
    'ValidationFrequency',validation_frequency, ...
    'OutputFcn',@(info)plotTrainingAccuracy(info,checkpoint_dir,...
    checkpoint_period));


classdef prtDecisionBinary < prtDecision
    % prtDecisionBinary Base class for all prtDecisionBinary objects
    %
    % A prtDecisionBinary object is an abstract class and cannot be
    % instantiated.
    %
    % prtBinaryDecsion objects find a threshold value that is used to make
    % decisions based on certain criteria.
    %
    % prtDecisionBinary objects all have the following function:
    %
    % getThreshold - return the prtDecisionBinary objects decision
    %                threshold
    %
    % See also: prtDecisionBinaryMinPe, prtDecisionBinarySpecifiedPd,
    % prtDecisionBinarySpecifiedPf, prtDecisionMap

    methods (Abstract)
        threshold = getThreshold(Obj)
        % THRESH = getThreshold returns the objects threshold
    end
    methods
        function obj = prtDecisionBinary()
            obj.classTrain = 'prtDataSetClass';
            obj.classRun = 'prtDataSetStandard';
            obj.classRunRetained = true;

            obj.isSupervised = true;
        end
    end

    methods (Access=protected,Hidden=true)
        function DS = runAction(Obj,DS)
            theClasses = Obj.classList;
            DS = DS.setObservations(theClasses((DS.getObservations >= Obj.getThreshold) + 1));
        end
         function xOut = runActionFast(Obj,xIn,ds) %#ok<INUSD>
            theClasses = Obj.classList;
            xOut = theClasses((xIn >= Obj.getThreshold) + 1);
        end
    end

    methods (Access = protected, Hidden = true)
        function ClassObj = preTrainProcessing(ClassObj, DataSet)
            % Overload preTrainProcessing() so that we can determine mary
            % output status
            assert(DataSet.isLabeled & DataSet.nClasses > 1,'The prtDataSetClass input to the train() method of a prtDecisionBinary must have non-empty targets and have more than one class.');

            ClassObj = preTrainProcessing@prtAction(ClassObj,DataSet);
        end
    end

    methods (Hidden)
        function str = exportSimpleText(self) %#ok<MANU>
            titleText = sprintf('%% prtDecisionBinaryMinPe\n');
            decisionThresholdText = prtUtilMatrixToText(self.threshold,'varName','minPeDecisionThreshold');
            str = sprintf('%s%s%s',titleText,decisionThresholdText);
        end
    end
end


run vlfeat/toolbox/vl_setup ;
run matconvnet/matlab/vl_setupnn ;
addpath('core');
addpath('helpers');


function h = sldrawgraph(G, X, Xt, ppedges, ppsn, pptn)
%SLDRAWGRAPH Draws a graph
%
% $ Syntax $
%   - sldrawgraph(G, X)
%   - sldrawgraph(G, X, Xt)
%   - sldrawgraph(G, X, [], ppedges)
%   - sldrawgraph(G, X, [], ppedges, ppsn)
%   - sldrawgraph(G, X, Xt, ppedges)
%   - sldrawgraph(G, X, Xt, ppedges, pptn)
%   - h = sldrawgraph(...)
%
% $ Arguments $
%   - G:        The graph in any acceptable form
%   - X:        The sample matrix of (source) nodes (2xn or 3xn)
%   - Xt:       The sample matrix of (target) nodes (2xn or 3xn)
%   - ppedges:  The cell array of parameters for plotting graph edges
%   - ppsn:     The cell array of parameters for plotting source nodes
%   - pptn:     The cell array of parameters for plotting target nodes
%   - h:        The vector of handles to all plotted objects
%
% $ Description $
%   - sldrawgraph(G, X) draws a graph with the coordinates of the
%     graph nodes given in X (a 2 x n matrix for 2D points or 3 x n
%     matrix for 3D points), using default plotting parameters.
%
%   - sldrawgraph(G, X, Xt) draws a bigraph using default plotting
%     parameters.
%
%   - sldrawgraph(G, X, [], ppedges) draws a graph using the specified
%     parameters to draw edges.
%
%   - sldrawgraph(G, X, [], ppedges, ppsn) draws a graph using the
%     specified parameters to draw edges and nodes.
%
%   - sldrawgraph(G, X, Xt, ppedges) draws a bigraph using the specified
%     parameters to draw edges.
%
%   - sldrawgraph(G, X, Xt, ppedges, ppsn, pptn) draws a bigraph using the
%     specified parameters to draw edges and nodes.
%
%   - h = sldrawgraph(...) returns the handles to the plotted objects.
%
% $ History $
%   - Created by Dahua Lin, on Sep 11st, 2006
%

%% parse and verify input arguments

if nargin < 2
    raise_lackinput('sldrawgraph', 2);
end

EG = sledgeset(G, 'off');
gi = slgraphinfo(EG);
n = gi.n;
nt = gi.nt;

d = size(X, 1);
if ~isnumeric(X) || ndims(X) ~= 2 || (d ~= 2 && d ~= 3)
    error('sltoolbox:invalidarg', ...
        'The X should be a 2D numeric matrix, and should have 2 or 3 rows.');
end

if nargin < 3 || isempty(Xt)
    Xt = X;
    bi = false;
else
    if ~isnumeric(Xt) || ndims(Xt) ~= 2
        error('sltoolbox:invalidarg', ...
            'The X should be a 2D numeric matrix, and should have 2 or 3 rows.');
    end
    if size(Xt, 1) ~= d
        error('sltoolbox:sizmismatch', ...
            'The sample dimensions in Xt is not the same as X');
    end
    bi = true;
end

if size(X, 2) ~= n || size(Xt, 2) ~= nt
    error('sltoolbox:sizmismatch', ...
        'The size of graph is not consistent with the sample numbers');
end

if nargin < 4 || isempty(ppedges)
    ppedges = {};
end

if nargin < 5 || isempty(ppsn)
    ppsn = {};
end

if nargin < 6 || isempty(pptn)
    pptn = ppsn;
end

if nargout >= 1
    output_h = true;
else
    output_h = false;
end

%% Prepare Data for plotting

% produce pruned NaN-separated coordinate list

edges = EG.edges;
edges = slpruneedgeset(n, nt, edges);

I = edges(:,1);
J = edges(:,2);
nedges = length(I);

xc = [X(1, I); Xt(1, J); NaN(1, nedges)];
xc = xc(:);
yc = [X(2, I); Xt(2, J); NaN(1, nedges)];
yc = yc(:);
if d == 3
    zc = [X(3, I); Xt(3, J); NaN(1, nedges)];
    zc = zc(:);
end

%% plot edges

% plot the edges
if d == 2
    ch = plot(xc, yc, ppedges{:});
else
    ch = plot3(xc, yc, zc, ppedges{:});
end
if output_h
    h = ch;
end
clear xc yc zc;

%% plot source nodes

if ~isempty(ppsn)
    ppsn = [ppsn, {'LineStyle', 'none'}];
    hold on;
    if d == 2
        ch = plot(X(1,:), X(2,:), ppsn{:});
    else
        ch = plot3(X(1,:), X(2,:), X(3,:), ppsn{:});
    end
    if output_h
        h = [h; ch];
    end
end

%% plot target nodes

if bi && ~isempty(pptn)
    pptn = [pptn, {'LineStyle', 'none'}];
    hold on;
    if d == 2
        ch = plot(Xt(1,:), Xt(2,:), pptn{:});
    else
        ch = plot3(Xt(1,:), Xt(2,:), Xt(3,:), pptn{:});
    end
    if output_h
        h = [h; ch];
    end
end


function[dzdxout] = roiPooling_freeform_backward(dzdx, combineFgBox)
% [dzdxout] = roiPooling_freeform_backward(dzdx, combineFgBox)
%
% Freeform pooling backward pass.
%
% If specified, this function sums the gradients for the foreground
% mask and the entire box. Otherwise it just passed through the gradients.
%
% Copyright by Holger Caesar, 2015

if combineFgBox,
    % Sum the gradients from fg and entire box
    half = size(dzdx, 3) / 2;
    dzdxFg  = dzdx(:, :, 1:half, :);
    dzdxBox = dzdx(:, :, half+1:end, :);
    dzdxout = dzdxFg + dzdxBox;
else
    % Just pass through the gradients
    dzdxout = dzdx;
end;


function cellInfo = Plant_States_Bus(varargin)
% PLANT_STATES_BUS returns a cell array containing bus object information
%
% Optional Input: 'false' will suppress a call to Simulink.Bus.cellToObject
%                 when the MATLAB file is executed.
% The order of bus element attributes is as follows:
%   ElementName, Dimensions, DataType, SampleTime, Complexity, SamplingMode, DimensionsMode, Min, Max, DocUnits, Description

suppressObject = false;
if nargin == 1 && islogical(varargin{1}) && varargin{1} == false
    suppressObject = true;
elseif nargin > 1
    error('Invalid input argument(s) encountered');
end

cellInfo = { ...
  { ...
    'Plant_States_Bus', ...
    '', ...
    '', ...
    'Auto', ...
    '-1', {...
{'timestamp', 1, 'uint32', -1, 'real', 'Sample', 'Fixed', [], [], sprintf('ms'), ''}; ...
{'phi', 1, 'single', -1, 'real', 'Sample', 'Fixed', [], [], sprintf('rad'), ''}; ...
{'theta', 1, 'single', -1, 'real', 'Sample', 'Fixed', [], [], sprintf('rad'), ''}; ...
{'psi', 1, 'single', -1, 'real', 'Sample', 'Fixed', [], [], sprintf('rad'), ''}; ...
{'rot_x_B', 1, 'single', -1, 'real', 'Sample', 'Fixed', [], [], sprintf('rad/s'), ''}; ...
{'rot_y_B', 1, 'single', -1, 'real', 'Sample', 'Fixed', [], [], sprintf('rad/s'), ''}; ...
{'rot_z_B', 1, 'single', -1, 'real', 'Sample', 'Fixed', [], [], sprintf('rad/s'), ''}; ...
{'acc_x_O', 1, 'single', -1, 'real', 'Sample', 'Fixed', [], [], sprintf('m/s2'), ''}; ...
{'acc_y_O', 1, 'single', -1, 'real', 'Sample', 'Fixed', [], [], sprintf('m/s2'), ''}; ...
{'acc_z_O', 1, 'single', -1, 'real', 'Sample', 'Fixed', [], [], sprintf('m/s2'), ''}; ...
{'vel_x_O', 1, 'single', -1, 'real', 'Sample', 'Fixed', [], [], sprintf('m/s'), ''}; ...
{'vel_y_O', 1, 'single', -1, 'real', 'Sample', 'Fixed', [], [], sprintf('m/s'), ''}; ...
{'vel_z_O', 1, 'single', -1, 'real', 'Sample', 'Fixed', [], [], sprintf('m/s'), ''}; ...
{'x_R', 1, 'single', -1, 'real', 'Sample', 'Fixed', [], [], sprintf('m'), ''}; ...
{'y_R', 1, 'single', -1, 'real', 'Sample', 'Fixed', [], [], sprintf('m'), ''}; ...
{'h_R', 1, 'single', -1, 'real', 'Sample', 'Fixed', [], [], sprintf('m'), ''}; ...
{'lat', 1, 'double', -1, 'real', 'Sample', 'Fixed', [], [], sprintf('rad'), ''}; ...
{'lon', 1, 'double', -1, 'real', 'Sample', 'Fixed', [], [], sprintf('rad'), ''}; ...
{'alt', 1, 'double', -1, 'real', 'Sample', 'Fixed', [], [], sprintf('m'), ''}; ...
{'lat_0', 1, 'double', -1, 'real', 'Sample', 'Fixed', [], [], sprintf('rad'), ''}; ...
{'lon_0', 1, 'double', -1, 'real', 'Sample', 'Fixed', [], [], sprintf('rad'), ''}; ...
{'alt_0', 1, 'double', -1, 'real', 'Sample', 'Fixed', [], [], sprintf('m'), ''}; ...
    } ...
  } ...
}';

if ~suppressObject
    % Create bus objects in the MATLAB base workspace
    Simulink.Bus.cellToObject(cellInfo)
end


function w = sign(w)
   %SIGN Signum function for waveforms.
   % WAVEFORM = SIGN(WAVEFORM)
   % see sign

   % AUTHOR: Celso Reyes, Geophysical Institute, Univ. of Alaska Fairbanks
   % $Date$
   % $Revision$

   for n=1:numel(w)
      % w(n) = set(w(n),'data',sign(double(get(w(n),'data'))));
      w(n).data = sign(w(n).data);
   end
end


function T = full(T)
%FULL Convert formatted data set to an array.
%   T = fmt(T) converts the formatted data set T into a MATLAB array. If T
%   is incomplete, unknown entries are represented by the value NaN.

%   Authors: Laurent Sorber (Laurent.Sorber@cs.kuleuven.be)
%            Marc Van Barel (Marc.VanBarel@cs.kuleuven.be)
%            Lieven De Lathauwer (Lieven.DeLathauwer@kuleuven-kulak.be)
%
%   References:
%   [1] L. Sorber, M. Van Barel, L. De Lathauwer, "Structured data fusion,"
%       ESAT-SISTA Internal Report 13-177, KU Leuven, 2013.

if isnumeric(T), return; end
if ~isstruct(T)
    error('full:T','T must be a data set formatted by fmt.');
end

val = T.val;
size_tens = T.size;
if 8*prod(size_tens) > 8e9
    error('full:size','T is too large to be stored as an array.');
end
if ~isfield(T,'ind')
    ind = sub2ind(size_tens,T.sub{:});
else
    ind = T.ind;
end

if isfield(T,'sparse') && T.sparse
    T = zeros(size_tens);
elseif isfield(T,'incomplete') && T.incomplete
    T = nan(size_tens);
else
    error('full')
end
T(ind) = val;


% EEG_EPOCHFORMAT - Convert the epoch information of a dataset from struct
%                     to array or vice versa.
%
% Usage: >> [epochsout fields] = eeg_epochformat( epochs, 'format', fields, events );
%
% Input:
%   epochs - epoch numerical or cell array or epoch structure
%   format - ['struct'|'array'] convert epoch array to structure and epoch
%            structure to array.
%   fields - [optional] cell array of strings containing the names of
%            the epoch struct fields. If this field is empty, it uses the
%            following list for the names of the fields { 'var1' 'var2' ... }.
%            For structure conversion, this field helps export a given
%            event type. If this field is left empty, the time locking
%            event for each epoch is exported.
%   events - numerical array of event indices associated with each epoch.
%            For array conversion, this field is ignored.
%
% Outputs:
%   epochsout - output epoch array or structure
%   fields    - output cell array with the name of the fields
%
% Epoch format:
%   struct - Epoch information is organised as an array of structs
%   array  - Epoch information is organised as an 2-d array of numbers,
%            each column representing a user-defined variable (the
%            order of the variable is a function of its order in the
%            struct format).
%
% Note: 1) The epoch structure is defined only for epoched data.
%       2) The epoch 'struct' format is more comprehensible.
%          For instance, to see all the properties of epoch i,
%          type >> EEG.epoch(i)
%          Unfortunately, structures are awkward for expert users to deal
%          with from the command line (Ex: To get an array of 'var1' values,
%           >> celltomat({EEG.epoch(:).var1})')
%          In array format, assuming 'var1' is the first variable
%          declared, the same information is obtained by
%           >> EEG.epoch(:,1)
%       3) This function automatically updates the 'epochfields'
%          cell array depending on the format.
%
% Author: Arnaud Delorme, CNL / Salk Institute, 12 Feb 2002
%
% See also: EEGLAB

%123456789012345678901234567890123456789012345678901234567890123456789012

% Copyright (C) Arnaud Delorme, CNL / Salk Institute, 12 Feb 2002, arno@salk.edu
%
% This file is part of EEGLAB, see http://www.eeglab.org
% for the documentation and details.
%
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are met:
%
% 1. Redistributions of source code must retain the above copyright notice,
% this list of conditions and the following disclaimer.
%
% 2. Redistributions in binary form must reproduce the above copyright notice,
% this list of conditions and the following disclaimer in the documentation
% and/or other materials provided with the distribution.
%
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
% THE POSSIBILITY OF SUCH DAMAGE.

% $Log: eeg_epochformat.m,v $
% Revision 1.4  2005/05/24 16:57:09  arno
% cell2mat
%
% Revision 1.3  2003/07/20 19:32:20  scott
% typos
%
% Revision 1.2  2002/04/21 01:10:35  scott
% *** empty log message ***
%
% Revision 1.1  2002/04/05 17:32:13  jorn
% Initial revision
%

% 03/13/02 added field arrays options -ad

function [ epoch, fields, epocheventout] = eeg_epochformat( epoch, format, fields, epochevent);

if nargin < 2
   help eeg_epochformat;
   return;
end;

if nargin < 3
    fields = {};
end
epocheventout = [];

switch format
case 'struct'
   if ~isempty(epoch) && ~isstruct(epoch)

      fields = getnewfields( fields, size(epoch,2) - length(fields));

      % generate the structure
      % ----------------------
      command = 'epoch = struct(';
      for index = 1:length(fields)
          if iscell(epoch)
              command = [ command '''' fields{index} ''', epoch(:,' num2str(index) ')'',' ];
          else
              command = [ command '''' fields{index} ''', mattocell( epoch(:,' num2str(index) ')'',' ...
                            '[1], ones(1,size(epoch,1))),' ];
          end;
      end
      eval( [command(1:end-1) ');' ] );

      if exist('epochevent') == 1
         for index = 1:size(epoch,2)
             if iscell(epochevent)
                 epoch(index).event = epochevent{index};
             else
                 epoch(index).event = epochevent(index);
             end
         end
      end
   end

case 'array'
    if isstruct(epoch)

        % note that the STUDY std_maketrialinfo also gets the epoch info for the
        % time locking event

        selectedType = fields;
        if iscell(fields) && ~isempty(fields), selectedType = fields{1}; end
  	    fields = fieldnames( epoch );

        eval( [ 'values = { epoch.' fields{1} ' };' ]);

        if any(cellfun(@length, values) > 1)
            if ~isfield(epoch, 'eventlatency')
                error('eventlatency field not present in data epochs');
            end

            if isempty(selectedType)
                % find indices of time locking events
                for index = 1:length(epoch)
                    epochlat = [ epoch(index).eventlatency{:} ];
                    tmpevent = find( abs(epochlat) < 0.02 );
                    if isempty(tmpevent)
                        error('time locking event missing, cannot convert to array');
                    end
                    epochSubIndex(index) = tmpevent;
                end
            else
                % find indices of specific event type (if several take the
                % first one
                for index = 1:length(epoch)
                    epochtype = epoch(index).eventtype;
                    tmpeventind = strmatch( selectedType, epochtype );
                    if length(tmpeventind) > 1
                        fprintf('Warning: epoch %d has several events of "type" %s, taking the fist one\n', index, selectedType);
                    end
                    if isempty(tmpeventind)
                         epochSubIndex(index) = NaN;
                    else epochSubIndex(index) = tmpeventind(1);
                    end
                end
            end
        else
            epochSubIndex = ones(1, length(epoch));
        end

        % copy values to array
        tmp = cell( length(epoch), length( fields ));
        for index = 1:length( fields )
            for trial = 1:length(epoch)
                tmpval = getfield(epoch, {trial}, fields{index});
                if isnan(epochSubIndex(trial))
                     tmp(trial, index) = { NaN };
                elseif iscell(tmpval)
                     tmp(trial, index) = tmpval(epochSubIndex(trial));
                elseif ~ischar(tmpval)
                     tmp(trial, index) = { tmpval(epochSubIndex(trial)) };
                else tmp(trial, index) = { tmpval };
                end
            end
        end
        epoch = tmp;
    end
    otherwise, error('unrecognised format');
end

return;

% create new field names
% ----------------------
function epochfield = getnewfields( epochfield, nbfields )
   count = 1;
   if nbfields > 0
        while nbfields > 0
            if isempty( strmatch([ 'var' int2str(count) ], epochfield ) )
               epochfield =  { epochfield{:} [ 'var' int2str(count) ] };
               nbfields = nbfields-1;
            else    count = count+1;
            end
        end;
   else
        epochfield = epochfield(1:end+nbfields);
   end;
return;


function [] = assertVectorsAlmostEqual(a, b, comparetype, tolerance)
  if (max(abs(reshape(a-b,[],1))) > tolerance)
    testFailed(a,b);
  elseif (min(size(a) == size(b)) < 1)
    testFailed(a,b);
  end

function [] = testFailed(a, b)
  [ST, I] = dbstack(2);
  disp(strcat("FAILED: ",  ST(1).name));
  disp(a)
  disp("--")
  disp(b)


function [x0, lb, ub] = ma_formOptim_X0_LB_UB(variables)
%ma_formOptim_X0_LB_UB Summary of this function goes here
%   Detailed explanation goes here

    lb = [];
    ub = [];
    x0 = [];
    for(varC = variables) %#ok<*NO4LP>
        var = varC{1};
        lb = [lb,var.lb]; %#ok<*AGROW>
        ub = [ub,var.ub];
        x0 = [x0,var.x0];
    end
end


%IMPEXP_GMSH Import/export grid in GMSH format.
%
%   [ GRID ] = IMPEXP_GMSH( FILE_NAME, MODE, DATA, IIND, FID_LOG, BIX )
%   Import and export of Gmsh (.msh) Ascii mesh and grid file format.
%
%   FILE_NAME is a string specifying the (root) file name to process.
%
%   MODE can either be a string indicating IMPORT (where boundary
%   numbering are reconstructed from Gmsh physical or elemental tags if
%   available), IMPORT_BDR (boundary reconstruction with gridbdr), or
%   EXPORT.
%
%   With the IMPORT mode option the function returns a GRID struct. While
%   for exporting, the input DATA can be given as either a valid fea
%   finite element data struct, or a FEATool grid struct.
%
%   IIND is an optional array for physical domains (subdomains in 2D and
%   boundaries in 3D) to extract and import (default all).
%
%   FID_LOG is an optional log file handle for message output
%   (negative for Gui output or empty for no output).
%
%   BIX is an optional index vector to correct boundary numbering.

% Copyright 2013-2022 Precise Simulation, Ltd.


%kkminimum 'Returns Lower Value between Input 1 and (Input 2 or Constant)'
% This MatLab function was automatically generated by a converter (KhorosToMatLab) from the Khoros kminimum.pane file
%
% Parameters:
% InputFile: i1 'Input 1', required: 'First input data object'
% OutputFile: o 'Output', required: 'Resulting output data object'
% InputFile: i2 'Input 2', optional: 'Second input data object'
%
% Example: o = kkminimum({i1, i2}, {'i1','';'o','';'i2',''})
%
% Khoros helpfile follows below:
%
%  PROGRAM
% kminimum - Returns Lower Value between Input 1 and (Input 2 or Constant)
%
%  DESCRIPTION
% This operator compares each data point in \fBInput 1" with either the value of
% the corresponding point in \fBInput 2" or the \fBConstant\fP value (which
% ever is specified by the user), and returns the minimum of the two values.
%
% Executing "Clip Minimum" runs the program \fIkarith2\fP with the -min flag.
%
%  "Data Type - Single Input" 5
% .cI $DATAMANIP/repos/shared/man/sections/value_type_1input
%
%  "Data Type - Two Input Objects" 5
% .cI $DATAMANIP/repos/shared/man/sections/value_type_2input
%
%  "Map Data - Single Input" 5
% .cI $DATAMANIP/repos/shared/man/sections/map_1input
%
%  "Map Data - Two Input Objects" 5
% .cI $DATAMANIP/repos/shared/man/sections/map_2input
%
%  "Validity Mask" 5
% .cI $DATAMANIP/repos/shared/man/sections/mask_2input
%
%  "Input Objects of Different Sizes" 5
% .cI $DATAMANIP/repos/shared/man/sections/resize_2input
% The values used to pad the data when input files are not the same size are
% (0.0, 0.0).
%
%  "Explicit Location and Time Data - Single Input" 5
% .cI $DATAMANIP/repos/shared/man/sections/loc_and_time_1input
%
%  "Explicit Location and Time Data - Two Input Objects" 5
% .cI $DATAMANIP/repos/shared/man/sections/loc_and_time_2input
%
%  "Failure Modes - Single Input"
% .cI $DATAMANIP/repos/shared/man/sections/fail_1input
%
%  "Failure Modes - Two Input Objects"
% .cI $DATAMANIP/repos/shared/man/sections/fail_2input
%
%
%
%  EXAMPLES
%
%  "SEE ALSO"
% DATAMANIP::karith2
%
%  RESTRICTIONS
% Operations on complex data are not supported at this time.  If the
% input object is complex, only the real component of the data is
% processed, and the output object is real.
%
%  REFERENCES
%
%  COPYRIGHT
% Copyright (C) 1993 - 1997, Khoral Research, Inc. ("KRI")  All rights reserved.
%

function varargout = kkminimum(varargin)
if nargin ==0
  Inputs={};arglist={'',''};
elseif nargin ==1
  Inputs=varargin{1};arglist={'',''};
elseif nargin ==2
  Inputs=varargin{1}; arglist=varargin{2};
else error('Usage: [out1,..] = kkminimum(Inputs,arglist).');
end
if size(arglist,2)~=2
  error('arglist must be of form {''ParameterTag1'',value1;''ParameterTag2'',value2}')
 end
narglist={'i1', '__input';'o', '__output';'i2', '__input'};
maxval={0,0,1};
minval={0,0,1};
istoggle=[0,0,1];
was_set=istoggle * 0;
paramtype={'InputFile','OutputFile','InputFile'};
% identify the input arrays and assign them to the arguments as stated by the user
if ~iscell(Inputs)
Inputs = {Inputs};
end
NumReqOutputs=1; nextinput=1; nextoutput=1;
  for ii=1:size(arglist,1)
  wasmatched=0;
  for jj=1:size(narglist,1)
   if strcmp(arglist{ii,1},narglist{jj,1})  % a given argument was matched to the possible arguments
     wasmatched = 1;
     was_set(jj) = 1;
     if strcmp(narglist{jj,2}, '__input')
      if (nextinput > length(Inputs))
        error(['Input ' narglist{jj,1} ' has no corresponding input!']);
      end
      narglist{jj,2} = 'OK_in';
      nextinput = nextinput + 1;
     elseif strcmp(narglist{jj,2}, '__output')
      if (nextoutput > nargout)
        error(['Output nr. ' narglist{jj,1} ' is not present in the assignment list of outputs !']);
      end
      if (isempty(arglist{ii,2}))
        narglist{jj,2} = 'OK_out';
      else
        narglist{jj,2} = arglist{ii,2};
      end

      nextoutput = nextoutput + 1;
      if (minval{jj} == 0)
         NumReqOutputs = NumReqOutputs - 1;
      end
     elseif isstr(arglist{ii,2})
      narglist{jj,2} = arglist{ii,2};
     else
        if strcmp(paramtype{jj}, 'Integer') & (round(arglist{ii,2}) ~= arglist{ii,2})
            error(['Argument ' arglist{ii,1} ' is of integer type but non-integer number ' arglist{ii,2} ' was supplied']);
        end
        if (minval{jj} ~= 0 | maxval{jj} ~= 0)
          if (minval{jj} == 1 & maxval{jj} == 1 & arglist{ii,2} < 0)
            error(['Argument ' arglist{ii,1} ' must be bigger or equal to zero!']);
          elseif (minval{jj} == -1 & maxval{jj} == -1 & arglist{ii,2} > 0)
            error(['Argument ' arglist{ii,1} ' must be smaller or equal to zero!']);
          elseif (minval{jj} == 2 & maxval{jj} == 2 & arglist{ii,2} <= 0)
            error(['Argument ' arglist{ii,1} ' must be bigger than zero!']);
          elseif (minval{jj} == -2 & maxval{jj} == -2 & arglist{ii,2} >= 0)
            error(['Argument ' arglist{ii,1} ' must be smaller than zero!']);
          elseif (minval{jj} ~= maxval{jj} & arglist{ii,2} < minval{jj})
            error(['Argument ' arglist{ii,1} ' must be bigger than ' num2str(minval{jj})]);
          elseif (minval{jj} ~= maxval{jj} & arglist{ii,2} > maxval{jj})
            error(['Argument ' arglist{ii,1} ' must be smaller than ' num2str(maxval{jj})]);
          end
        end
     end
     if ~strcmp(narglist{jj,2},'OK_out') &  ~strcmp(narglist{jj,2},'OK_in')
       narglist{jj,2} = arglist{ii,2};
     end
   end
   end
   if (wasmatched == 0 & ~strcmp(arglist{ii,1},''))
        error(['Argument ' arglist{ii,1} ' is not a valid argument for this function']);
   end
end
% match the remaining inputs/outputs to the unused arguments and test for missing required inputs
 for jj=1:size(narglist,1)
     if  strcmp(paramtype{jj}, 'Toggle')
        if (narglist{jj,2} ==0)
          narglist{jj,1} = '';
        end;
        narglist{jj,2} = '';
     end;
     if  ~strcmp(narglist{jj,2},'__input') && ~strcmp(narglist{jj,2},'__output') && istoggle(jj) && ~ was_set(jj)
          narglist{jj,1} = '';
          narglist{jj,2} = '';
     end;
     if strcmp(narglist{jj,2}, '__input')
      if (minval{jj} == 0)  % meaning this input is required
        if (nextinput > size(Inputs))
           error(['Required input ' narglist{jj,1} ' has no corresponding input in the list!']);
        else
          narglist{jj,2} = 'OK_in';
          nextinput = nextinput + 1;
        end
      else  % this is an optional input
        if (nextinput <= length(Inputs))
          narglist{jj,2} = 'OK_in';
          nextinput = nextinput + 1;
        else
          narglist{jj,1} = '';
          narglist{jj,2} = '';
        end;
      end;
     else
     if strcmp(narglist{jj,2}, '__output')
      if (minval{jj} == 0) % this is a required output
        if (nextoutput > nargout & nargout > 1)
           error(['Required output ' narglist{jj,1} ' is not stated in the assignment list!']);
        else
          narglist{jj,2} = 'OK_out';
          nextoutput = nextoutput + 1;
          NumReqOutputs = NumReqOutputs-1;
        end
      else % this is an optional output
        if (nargout - nextoutput >= NumReqOutputs)
          narglist{jj,2} = 'OK_out';
          nextoutput = nextoutput + 1;
        else
          narglist{jj,1} = '';
          narglist{jj,2} = '';
        end;
      end
     end
  end
end
if nargout
   varargout = cell(1,nargout);
else
  varargout = cell(1,1);
end
global KhorosRoot
if exist('KhorosRoot') && ~isempty(KhorosRoot)
w=['"' KhorosRoot];
else
if ispc
  w='"C:\Program Files\dip\khorosBin\';
else
[s,w] = system('which cantata');
w=['"' w(1:end-8)];
end
end
[varargout{:}]=callKhoros([w 'karith2"  -min'],Inputs,narglist);


%ETS2 Elementary transform sequence in 2D
%
% This class and package allows experimentation with sequences of spatial
% transformations in 2D.
%
%          import ETS2.*
%          a1 = 1; a2 = 1;
%          E = Rz('q1') * Tx(a1) * Rz('q2') * Tx(a2)
%
% Operation methods::
%   fkine      forward kinematics
%
% Information methods::
%   isjoint    test if transform is a joint
%   njoints    the number of joint variables
%   structure  a string listing the joint types
%
% Display methods::
%   display    display value as a string
%   plot       graphically display the sequence as a robot
%   teach      graphically display as robot and allow user control
%
% Conversion methods::
%   char       convert to string
%   string     convert to string with symbolic variables
%
% Operators::
%   *          compound two elementary transforms
%   +          compound two elementary transforms
%
% Notes::
% - The sequence is an array of objects of superclass ETS2, but with
%   distinct subclasses: Rz, Tx, Ty.
% - Use the command 'clear imports' after using ETS3.
%
%
% See also ETS3.

% Copyright (C) 1993-2017, by Peter I. Corke
%
% This file is part of The Robotics Toolbox for MATLAB (RTB).
%
% RTB is free software: you can redistribute it and/or modify
% it under the terms of the GNU Lesser General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% RTB is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU Lesser General Public License for more details.
%
% You should have received a copy of the GNU Leser General Public License
% along with RTB.  If not, see <http://www.gnu.org/licenses/>.
%
% http://www.petercorke.com
classdef ETS2
    properties
        what     % type of transform (string): Rx, Ry, etc
        param    % the constant numerical parameter (if not joint)
        qvar     % the integer joint index 1..N (if joint)
        qlim     % for prismatic joint, a 2 vector [min,max]
    end

    methods
        function obj = ETS2(what, x, varargin)
            %ETS2.ETS2  Create an ETS2 object
            %
            % E = ETS2(W, V) is a new ETS2 object that defines an elementary transform where
            % W is 'Rz', 'Tx' or 'Ty' and V is the paramter for the transform.  If V is a string
            % of the form 'qN' where N is an integer then the transform is considered
            % to be a joint.  Otherwise the transform is a constant.
            %
            % E = ETS2(E1) is a new ETS2 object that is a clone of the ETS2 object E1.
            %
            % See also ETS2.Rz, ETS2.Tx, ETS2.Ty.

            assert(nargin > 0, 'RTB:ETS2:ETS2:badarg', 'no arguments given');

            opt.qlim = [];
            opt = tb_optparse(opt, varargin);

            obj.qvar = NaN;
            obj.param = 0;

            if ~isempty(opt.qlim)
                assert(length(opt.qlim) == 2, 'ETS2: qlim must be a 2-vector');
            end
            obj.qlim = opt.qlim;

            if nargin > 1
                if isa(x, 'ETS2')
                    % clone it
                    obj.what = x.what;
                    obj.qvar = x.qvar;
                    obj.param = x.param;
                else
                    % create a new one
                    assert(ismember(what, {'Tx','Ty','R','Rz'}), 'ETS2: invalid transform type given');
                    if strcmp(what, 'R')
                        what = 'Rz';
                    end
                    if ischar(x)
                        obj.qvar = str2num(x(2:end));
                    else
                        obj.param = x;
                    end
                    obj.what = what;
                end
            end
        end

        function r = fkine(ets, q, varargin)
            %ETS2.fkine Forward kinematics
            %
            % ETS.fkine(Q, OPTIONS) is the forward kinematics, the pose of the end of the
            % sequence as an SE2 object.  Q (1xN) is a vector of joint variables.
            %
            % ETS.fkine(Q, N, OPTIONS) as above but process only the first N elements
            % of the transform sequence.
            %
            % Options::
            %  'deg'     Angles are given in degrees.
            r = SE2;

            opt.deg = false;
            [opt,args] = tb_optparse(opt, varargin);

            if opt.deg
                opt.deg = pi/180;
            else
                opt.deg = 1;
            end

            n = length(ets);
            if ~isempty(args) && isreal(args{1})
                n = args{1};
            end
            assert(n>0 && n <= length(ets), 'RTB:ETS2:badarg', 'bad value of n given');

            for i=1:n
                e = ets(i);
                if e.isjoint
                    v = q(e.qvar);
                else
                    v = e.param;
                end
                switch e.what
                    case 'Tx'
                        r = r * SE2(v, 0, 0);
                    case 'Ty'
                        r = r * SE2(0, v, 0);
                    case 'Rz'
                        r = r * SE2(0, 0, v*opt.deg);
                end
            end
            r = r.simplify();  % simplify it if symbolic
        end

        function b = isjoint(ets)
            %ETS2.isjoint  Test if transform is a joint
            %
            % E.isjoint is true if the transform element is a joint, that is, its
            % parameter is of the form 'qN'.
            b = ~isnan(ets.qvar);
        end

        function v = isprismatic(ets)
            %ETS2.isprismatic  Test if transform is prismatic joint
            %
            % E.isprismatic is true if the transform element is a joint, that is, its
            % parameter is of the form 'qN' and it controls a translation.
            v = isjoint(ets) && (ets.what(1) == 'T');
        end

        function k = find(ets, j)
            %ETS2.find  Find joints in transform sequence
            %
            % E.find(J) is the index in the transform sequence ETS (1xN) corresponding
            % to the J'th joint.
            [~,k] = find([ets.qvar] == j);
        end

        function n = njoints(ets)
            %ETS2.njoints  Number of joints in transform sequence
            %
            % E.njoints is the number of joints in the transform sequence.
            %
            % See also ETS2.n.
            n = max([ets.qvar]);
        end

        function v = n(ets)
            %ETS2.n  Number of joints in transform sequence
            %
            % E.njoints is the number of joints in the transform sequence.
            %
            % Notes::
            % - Is a wrapper on njoints, for compatibility with SerialLink object.
            % See also ETS2.n.
            v = ets.njoints;
        end

        function s = string(ets)
            %ETS2.string  Convert to string with symbolic variables
            %
            % E.string is a string representation of the transform sequence where
            % non-joint parameters have symbolic names L1, L2, L3 etc.
            %
            % See also trchain.
            for i = 1:length(ets)
                e = ets(i);
                if e.isjoint
                    term = sprintf('%s(q%d)', e.what, e.qvar);
                else
                    term = sprintf('%s(L%d)', e.what, constant);
                    constant = constant + 1;
                end
                if i == 1
                    s = term;
                else
                    s = [s ' ' term];
                end
            end
        end

        function out = mtimes(ets1, ets2)
            %ETS2.mtimes Compound transforms
            %
            % E1 * E2 is a sequence of two elementary transform.
            %
            % See also ETS2.plus.
            assert( strcmp(superclasses(ets1), superclasses(ets2)), 'ETS2: both operands must have superclass ETS2, perhaps run ''clear import'', and start over');
            out = [ets1 ets2];
        end

        function out = plus(ets1, ets2)
            %ETS2.plus Compound transforms
            %
            % E1 + E2 is a sequence of two elementary transform.
            %
            % See also ETS2.mtimes.
            assert( strcmp(superclasses(ets1), superclasses(ets2)), 'ETS2: both operands must have superclass ETS2, perhaps run ''clear import'', and start over');

            out = [ets1 ets2];
        end

        function s = structure(ets)
            %ETS2.structure  Show joint type structure
            %
            % E.structure is a character array comprising the letters 'R' or 'P' that
            % indicates the types of joints in the elementary transform sequence E.
            %
            % Notes::
            % - The string will be E.njoints long.
            %
            % See also SerialLink.config.
            s = '';
            for e = ets
                if e.qvar > 0
                    switch e.what
                        case {'Tx', 'Ty'}
                            s = [s 'P'];
                        case 'Rz'
                            s = [s 'R'];
                    end
                end
            end
        end

        function display(ets)
            %ETS2.display Display parameters
            %
            % E.display() displays the transform or transform sequence parameters in
            % compact single line format.
            %
            % Notes::
            % - This method is invoked implicitly at the command line when the result
            %   of an expression is an ETS2 object and the command has no trailing
            %   semicolon.
            %
            % See also ETS2.char.
            loose = strcmp( get(0, 'FormatSpacing'), 'loose');

            if loose
                disp(' ');
            end
            disp([inputname(1), ' = '])
            disp( char(ets) );
        end % display()

        function s = char(ets)
            %ETS2.char Convert to string
            %
            % E.char() is a string showing transform parameters in a compact format.  If E is a transform sequence (1xN) then
            % the string describes each element in sequence in a single line format.
            %
            % See also ETS2.display.
            s = '';

            function s = render(z)
                if isa(z, 'sym')
                    s = char(z);
                else
                    s = sprintf('%g', z);
                end
            end

            for e = ets
                if e.isjoint
                    s = [s sprintf('%s(q%d)', e.what, e.qvar) ];
                else
                    s = [s sprintf('%s(%s)', e.what, render(e.param))];

                end
            end
        end

        function teach(robot, varargin)
            %ETS2.teach Graphical teach pendant
            %
            % Allow the user to "drive" a graphical robot using a graphical slider
            % panel.
            %
            % ETS.teach(OPTIONS) adds a slider panel to a current ETS plot. If no
            % graphical robot exists one is created in a new window.
            %
            % ETS.teach(Q, OPTIONS) as above but the robot joint angles are set to Q (1xN).
            %
            % Options::
            % 'eul'           Display tool orientation in Euler angles (default)
            % 'rpy'           Display tool orientation in roll/pitch/yaw angles
            % 'approach'      Display tool orientation as approach vector (z-axis)
            % '[no]deg'       Display angles in degrees (default true)
            %
            % GUI::
            % - The Quit (red X) button removes the teach panel from the robot plot.
            %
            % Notes::
            % - The currently displayed robots move as the sliders are adjusted.
            % - The slider limits are derived from the joint limit properties.  If not
            %   set then for
            %   - a revolute joint they are assumed to be [-pi, +pi]
            %   - a prismatic joint they are assumed unknown and an error occurs.
            %
            % See also ETS2.plot.

            %-------------------------------
            % parameters for teach panel
            bgcol = [135 206 250]/255;  % background color
            height = 0.06;  % height of slider rows
            %-------------------------------

            %---- handle options
            opt.deg = true;
            opt.orientation = {'rpy', 'eul', 'approach'};
            opt.d_2d = true;
            opt.callback = [];
            [opt,args] = tb_optparse(opt, varargin);

            if nargin == 1
                q = zeros(1,robot.n);
            else
                q = varargin{1};
                varargin = varargin{2:end};
            end
            robot.plot(q, varargin{:})

            RTBPlot.install_teach_panel('ETS2', robot, q, opt);
        end

        function plot(ets, qq, varargin)
            %ETS2.plot Graphical display and animation
            %
            % ETS.plot(Q, options) displays a graphical animation of a robot based on
            % the transform sequence.  Constant translations are represented as pipe segments, rotational joints as cylinder, and
            % prismatic joints as boxes. The robot is displayed at the joint angle Q (1xN), or
            % if a matrix (MxN) it is animated as the robot moves along the M-point trajectory.
            %
            % Options::
            % 'workspace', W    Size of robot 3D workspace, W = [xmn, xmx ymn ymx zmn zmx]
            % 'floorlevel',L    Z-coordinate of floor (default -1)
            %-
            % 'delay',D         Delay betwen frames for animation (s)
            % 'fps',fps         Number of frames per second for display, inverse of 'delay' option
            % '[no]loop'        Loop over the trajectory forever
            % '[no]raise'       Autoraise the figure
            % 'movie',M         Save an animation to the movie M
            % 'trail',L         Draw a line recording the tip path, with line style L
            %-
            % 'scale',S         Annotation scale factor
            % 'zoom',Z          Reduce size of auto-computed workspace by Z, makes
            %                   robot look bigger
            % 'ortho'           Orthographic view
            % 'perspective'     Perspective view (default)
            % 'view',V          Specify view V='x', 'y', 'top' or [az el] for side elevations,
            %                   plan view, or general view by azimuth and elevation
            %                   angle.
            % 'top'             View from the top.
            %-
            % '[no]shading'     Enable Gouraud shading (default true)
            % 'lightpos',L      Position of the light source (default [0 0 20])
            % '[no]name'        Display the robot's name
            %-
            % '[no]wrist'       Enable display of wrist coordinate frame
            % 'xyz'             Wrist axis label is XYZ
            % 'noa'             Wrist axis label is NOA
            % '[no]arrow'       Display wrist frame with 3D arrows
            %-
            % '[no]tiles'       Enable tiled floor (default true)
            % 'tilesize',S      Side length of square tiles on the floor (default 0.2)
            % 'tile1color',C   Color of even tiles [r g b] (default [0.5 1 0.5]  light green)
            % 'tile2color',C   Color of odd tiles [r g b] (default [1 1 1] white)
            %-
            % '[no]shadow'      Enable display of shadow (default true)
            % 'shadowcolor',C   Colorspec of shadow, [r g b]
            % 'shadowwidth',W   Width of shadow line (default 6)
            %-
            % '[no]jaxes'       Enable display of joint axes (default false)
            % '[no]jvec'        Enable display of joint axis vectors (default false)
            % '[no]joints'      Enable display of joints
            % 'jointcolor',C    Colorspec for joint cylinders (default [0.7 0 0])
            % 'jointcolor',C    Colorspec for joint cylinders (default [0.7 0 0])
            % 'jointdiam',D     Diameter of joint cylinder in scale units (default 5)
            %-
            % 'linkcolor',C     Colorspec of links (default 'b')
            %-
            % '[no]base'        Enable display of base 'pedestal'
            % 'basecolor',C     Color of base (default 'k')
            % 'basewidth',W     Width of base (default 3)
            %
            % The options come from 3 sources and are processed in order:
            % - Cell array of options returned by the function PLOTBOTOPT (if it exists)
            % - Cell array of options given by the 'plotopt' option when creating the
            %   SerialLink object.
            % - List of arguments in the command line.
            %
            % Many boolean options can be enabled or disabled with the 'no' prefix.  The
            % various option sources can toggle an option, the last value encountered is used.
            %
            % Graphical annotations and options::
            %
            % The robot is displayed as a basic stick figure robot with annotations
            % such as:
            % - shadow on the floor
            % - XYZ wrist axes and labels
            % - joint cylinders and axes
            % which are controlled by options.
            %
            % The size of the annotations is determined using a simple heuristic from
            % the workspace dimensions.  This dimension can be changed by setting the
            % multiplicative scale factor using the 'mag' option.
            %
            % Figure behaviour::
            %
            % - If no figure exists one will be created and the robot drawn in it.
            % - If no robot of this name is currently displayed then a robot will
            %   be drawn in the current figure.  If hold is enabled (hold on) then the
            %   robot will be added to the current figure.
            % - If the robot already exists then that graphical model will be found
            %   and moved.
            %
            %
            % Notes::
            % - The options are processed when the figure is first drawn, to make different options come
            %   into effect it is neccessary to clear the figure.
            % - Delay betwen frames can be eliminated by setting option 'delay', 0 or
            %   'fps', Inf.
            % - The size of the plot volume is determined by a heuristic for an all-revolute
            %   robot.  If a prismatic joint is present the 'workspace' option is
            %   required.  The 'zoom' option can reduce the size of this workspace.
            %
            % See also ETS2.teach, SerialLink.plot3d.

            % heuristic to figure robot size
            reach = 0;
            for e=ets
                switch e.what
                    case {'Tx', 'Ty', 'Tz'}
                        if isjoint(e)
                            reach = reach + e.qlim(2);
                        else
                            reach = reach + e.param;
                        end
                end
            end

            opt = RTBPlot.plot_options([], [varargin 'reach', 3, 'top']);
            h = draw_ets(ets, qq, opt);

            set(gca, 'Tag', 'RTB.plot');
            set(gcf, 'Units', 'Normalized');
            pf = get(gcf, 'Position');

            if opt.raise
                % note this is a very time consuming operation
                figure(gcf);
            end

            if strcmp(opt.projection, 'perspective')
                set(gca, 'Projection', 'perspective');
            end

            if isstr(opt.view)
                switch opt.view
                    case 'top'
                        view(0, 90);
                    case 'x'
                        view(0, 0);
                    case 'y'
                        view(90, 0)
                    otherwise
                        error('rtb:plot:badarg', 'view must be: x, y, top')
                end
            elseif isnumeric(opt.view) && length(opt.view) == 2
                view(opt.view)
            end

            % enable mouse-based 3D rotation
            rotate3d on

            ets.animate(qq);
        end

        function animate(ets, qq)
            handles = findobj('Tag', 'ETS2');
            h = handles.UserData;
            opt = h.opt;

            ets = h.ets;
            for q = qq'
                for i=1:length(ets)

                    % create the transform for displaying this element (joint cylinder + link)
                    e = ets(i);
                    if i == 1
                        T = SE2;
                    else
                        T = ets.fkine(q, i-1, 'setopt', opt);
                    end

                    % update the pose of the corresponding graphical element (joint cylinder + link)
                    set(h.element(i), 'Matrix', T.SE3.T);

                    if isprismatic(e)
                        % for prismatic joints, scale the box
                        switch e.what
                            case 'Tx'
                                set(h.pjoint(e.qvar), 'Matrix', diag([q(e.qvar) 1 1 1]));
                            case 'Ty'
                                set(h.pjoint(e.qvar), 'Matrix', diag([1 q(e.qvar) 1 1]));
                        end
                    end
                end

                % update the wrist frame
                T = ets.fkine(q, 'setopt', opt);
                if ~isempty(h.wrist)
                    trplot2(T, 'handle', h.wrist);
                end

                % render and pause
                if opt.delay > 0
                    pause(opt.delay);
                    drawnow
                end
            end
        end

   end

   methods (Access=private)

            function h_ = draw_ets(ets, q, opt)

                clf
                disp('creating new ETS plot');

                axis(opt.workspace);

                s = opt.scale;
                % create an axis
                ish = ishold();
                if ~ishold
                    % if hold is off, set the axis dimensions
                    axis(opt.workspace);
                    hold on
                end

                group = hggroup('Tag', 'ETS2');
                h.group = group;

                % create the graphical joint and link elements
                for i=1:length(ets)
                    e = ets(i);

                    if opt.debug
                        fprintf('create graphics for %s\n', e.char );
                    end

                    % create a graphical depiction of the transform element
                    % This is drawn to resemble orthogonal plumbing.

                    if i == 1
                        T = SE2;
                    else
                        T = ets.fkine(q, i-1, 'setopt', opt);
                    end

                    % create the transform for displaying this element (joint cylinder + link)
                    h.element(i) = hgtransform('Tag', sprintf('element%d', i), 'Matrix', T.SE3.T, 'Parent', h.group);

                    if isjoint(e)
                        % it's a joint element: revolute or prismatic
                        switch e.what
                            case 'Tx'
                                h.pjoint(e.qvar) = hgtransform('Tag', 'prismatic', 'Parent', h.element(i), 'Matrix', diag([q(e.qvar) 1 1 1]));
                                RTBPlot.box('x', opt.jointdiam*s, [0 1], opt.pjointcolor, [], 'Parent', h.pjoint(i));
                            case 'Ty'
                                h.pjoint(e.qvar) = hgtransform('Tag', 'prismatic', 'Parent', h.element(i), 'Matrix', diag([1 q(e.qvar) 1 1]));
                                RTBPlot.box('y', opt.jointdiam*s, [0 1], opt.pjointcolor, [], 'Parent', h.pjoint(i));
                            case 'Rz'
                                RTBPlot.cyl('z', opt.jointdiam*s, opt.jointlen*s*[-1 1], opt.jointcolor, [], 'Parent', h.element(i));
                        end
                    else
                        % it's a constant transform
                        switch e.what
                            case 'Tx'
                                RTBPlot.cyl('x', s, [0 e.param], opt.linkcolor, [], 'Parent', h.element(i));
                            case 'Ty'
                                RTBPlot.cyl('y', s, [0 e.param], opt.linkcolor, [], 'Parent', h.element(i));
                            case 'Rz'
                                RTBPlot.cyl('z', opt.jointdiam*s, opt.jointlen*s*[-1 1], opt.linkcolor, [], 'Parent', h.element(i));
                        end
                    end

                    assert( ~(opt.jaxes && opt.jvec), 'RTB:ETS2:plot:badopt', 'Can''t specify ''jaxes'' and ''jvec''')

                    % create the joint axis line
                    if opt.jaxes
                        if e.isjoint
                            line('XData', [0 0], ...
                                'YData', [0 0], ...
                                'ZData', 14*s*[-1 1], ...
                                'LineStyle', ':', 'Parent', h.element(i));

                            % create the joint axis label
                            text(0, 0, 14*s, sprintf('q%d', e.qvar), 'Parent', h.element(i))
                        end
                    end

                    % create the joint axis vector
                    if opt.jvec
                        if e.isjoint
                            daspect([1 1 1]);
                            ha = arrow3([0 0 -12*s], [0 0 15*s], 'c');
                            set(ha, 'Parent', h.element(i));

                            % create the joint axis label
                            text(0, 0, 20*s, sprintf('q%d', e.qvar), 'Parent', h.element(i))
                        end
                    end

                end

                % display the wrist coordinate frame
                if opt.wrist
                    if opt.arrow
                        % compute arrow3 scale factor...
                        d = axis(gca);
                        if length(d) == 4
                            d = norm( d(3:4)-d(1:2) ) / 72;
                        else
                            d = norm( d(4:6)-d(1:3) ) / 72;
                        end
                        extra = {'arrow', 'width', 1.5*s/d};
                    else
                        extra = {};
                    end
                    h.wrist = trplot2(eye(3,3), 'labels', upper(opt.wristlabel), ...
                        'color', 'k', 'length', opt.wristlen*s, extra{:});
                else
                    h.wrist = [];
                end

                xlabel('X')
                ylabel('Y')
                zlabel('Z')
                grid on

                % restore hold setting
                if ~ish
                    hold off
                end

                h.opt = opt;
                h.ets = ets;

                if nargout > 0
                    h_ = h;
                end

                % attach the handle structure to the top graphical element

                h.q = q;
                handles.opt = opt;

                set(group, 'UserData', h);
            end

         end

end


function r = plus(p,q)
% this function adds the x, y, and z values of the structures that I use in
% the FVtool.
%
% SYNOPSIS:
%
%
% PARAMETERS:
%
%
% RETURNS:
%
%
% EXAMPLE:
%
% SEE ALSO:
%

% Copyright (c) 2012-2016 Ali Akbar Eftekhari
% See the license file

if (isa(p, 'CellVector')&&isa(q, 'CellVector'))
    r=p;
    r.xvalue = p.xvalue+q.xvalue;
    r.yvalue = p.yvalue+q.yvalue;
    r.zvalue = p.zvalue+q.zvalue;
elseif isa(p, 'CellVector')
    r=p;
    r.xvalue = p.xvalue+q;
    r.yvalue = p.yvalue+q;
    r.zvalue = p.zvalue+q;
else
    r=q;
    r.xvalue = p+q.xvalue;
    r.yvalue = p+q.yvalue;
    r.zvalue = p+q.zvalue;
end


% Animation Object member functions
% See also
%
% Animation             Animation class (wth 3D data, projection, camera info ...)
% addNoise              Add noise to the animation
% centerW               Generate camera position from R and t in an Animation
% computeError          Compute several SFM errors
% display               Display the different elements contained in the object
% generateCamFromRt     Generate camera position from R and t in an Animation
% generateP             Compute the projection matrices using K, R and t
% generateS             Generate S tranformed by R and t
% generateSFromLSBasis  Generate 3D data from the basis of an Animation
% generateW             Generate projected data
% sampleFrame           Sample an Animation by reducing the number of frames
% setFirstPRtToId       Sets the first P or (R,t) of an Animation to eye(3,4)
% subsasgn              Set an element in the Animation object
% subsref               Reference an element in the Animation object


function [img, seg, names, counts] = LM2segments(D, imagesize, HOMEIMAGES, HOMELMSEGMENTS)
%
% Transforms all the labelme labels into segmentation masks.
% It takes into account the occlusions, removing labeled pixels that are
% occluded by other objects. Depth ordering is achieved using the function
% LMsortlayers.m
%
% For unlabeled pixels, seg(...) = 0
%
%  [img, seg, names, counts] = LM2segments(D, imagesize, HOMEIMAGES, HOMELMSEGMENTS)
% 'img' and 'seg' are matrices
%
% To precompute the segmentations:
%
%   LM2segments(D(1), [], HOMEIMAGES, HOMELMSEGMENTS) % removing the second
%     argument, makes the segmentation mask to have the same size than the
%     images.
%
% To read the precomputed segmentations:
%   [img, seg, names] = LM2segments(D(1), [], HOMEIMAGES, HOMELMSEGMENTS);
%
%
% HOMEANNOTATIONS = 'http://labelme.csail.mit.edu/Annotations'
% HOMEIMAGES = 'http://labelme.csail.mit.edu/Images'

if nargin == 2 && nargout<3
    % SPECIAL BEHAVIOR
    %
    % seg = LM2segments(annotation, imagesize);
    imgtmp = zeros(imagesize);
    annotationtmp = LMsortlayers(D.annotation, imgtmp);

    % Get segmentation
    [S_instances, classes] = LMobjectmask(annotationtmp, size(imgtmp));
    %classesndx = [annotationtmp.object.namendx];
    %area = squeeze(sum(sum(S_instances,1),2));

    %j = find(area>2); % remove small objects
    %S_instances = S_instances(:,:,j);
    %classesndx = classesndx(j);

    % Assign labels taking into account occlusions!
    Mclasses = zeros([imagesize(1) imagesize(2)]);
    for k = size(S_instances,3):-1:1;
        S_instances(:,:,k) = k*S_instances(:,:,k);
        Mclasses = Mclasses+(Mclasses==0).*S_instances(:,:,k);
    end
    img  = uint16(Mclasses);
    seg = classes;

    return
end

if nargin==4
    precomputed = 1;

    if length(D) == 1
        fileseg = fullfile(HOMELMSEGMENTS, D(1).annotation.folder, [D(1).annotation.filename(1:end-4) '.mat']);
        % read the image and return
        if exist(fileseg, 'file')
            load(fileseg)
            seg = S;
            img = [];
            return
        end
    end
else
    precomputed = 0;
    HOMELMSEGMENTS = '';
end

Nimages = length(D);

% Create list of objects:
n=0;
while 1
    n=n+1;
    if n >length(D)
        [D, names, counts] = LMcreateObjectIndexField(D);
        break
    end

    if isfield(D(n).annotation, 'object')
        if ~isfield(D(n).annotation.object, 'namendx')
            [D, names, counts] = LMcreateObjectIndexField(D);
        else
            [names, counts, imagendx, objectndx, objclass_ndx] = LMobjectnames(D, 'name');
        end
        break
    end
end

% [names, counts, imagendx, objectndx, objclass_ndx] = LMobjectnames(D, 'name');
% for k = 1:length(objclass_ndx)
%     D(imagendx(k)).annotation.object(objectndx(k)).namendx = objclass_ndx(k);
% end
Nobjectclasses = length(names);

if nargout>0
    if Nimages > 1
        % Initalize output variables
        seg = zeros([imagesize(1) imagesize(2) Nimages], 'uint16');
        img = zeros([imagesize(1) imagesize(2) 3 Nimages], 'uint8');
    end
end

if Nimages > 1
    figure
end

for ndx = 1:Nimages
    % Load image
    imgtmp = LMimread(D, ndx, HOMEIMAGES);
    annotation = D(ndx).annotation;
    if size(imgtmp,3)==1; imgtmp = repmat(imgtmp, [1 1 3]); end
    [nrows ncols cc] = size(imgtmp);

    % Scale image so that image box fits tight in image
    if ~isempty(imagesize)
        scaling = max(imagesize(1)/nrows, imagesize(2)/ncols);
        [annotationtmp, imgtmp] = LMimscale(annotation, imgtmp, scaling, 'bicubic');

        % Crop image to final size
        [nr nc cc] = size(imgtmp);
        sr = floor((nr-imagesize(1))/2);
        sc = floor((nc-imagesize(2))/2);
        [annotationtmp, imgtmp] = LMimcrop(annotationtmp, imgtmp, [sc+1 sc+imagesize(2) sr+1 sr+imagesize(1)]);

        Mclasses = zeros([imagesize(1) imagesize(2)]);
    else
        annotationtmp = annotation;

        Mclasses = zeros([size(imgtmp,1) size(imgtmp,2)]);
    end

    if isfield(annotationtmp, 'object')
        % Sort layers
        annotationtmp = LMsortlayers(annotationtmp, imgtmp);

        % Get segmentation
        [S_instances, classes] = LMobjectmask(annotationtmp, size(imgtmp));
        classesndx = [annotationtmp.object.namendx];
        area = squeeze(sum(sum(S_instances,1),2));

        j = find(area>2); % remove small objects
        S_instances = S_instances(:,:,j);
        classesndx = classesndx(j);

        % Assign labels taking into account occlusions!
        for k = size(S_instances,3):-1:1;
            S_instances(:,:,k) = classesndx(k)*S_instances(:,:,k);
            Mclasses = Mclasses+(Mclasses==0).*S_instances(:,:,k);
        end
    end

    if nargout>0
        % Store values
        seg(:,:,ndx)   = uint16(Mclasses);
        img(:,:,:,ndx) = imgtmp;
    end

    % Save gist if a HOMELMSEGMENTS file is provided
    if precomputed
        I = imgtmp;
        S = uint16(Mclasses);
        S_instances = uint16(S_instances);
        mkdir(fullfile(HOMELMSEGMENTS, D(ndx).annotation.folder))
        fileseg = fullfile(HOMELMSEGMENTS, D(ndx).annotation.folder, [D(ndx).annotation.filename(1:end-4) '.mat']);
        if ~isempty(imagesize)
            save (fileseg, 'I', 'S', 'names', 'S_instances')
        else
            save (fileseg, 'S', 'names', 'S_instances')
        end
    end

    % Visualization
    if Nimages > 1
        subplot(121)
        image(imgtmp); axis('equal'); axis('tight');
        title(sprintf('%d (out of %d)', ndx, Nimages))
        subplot(122)
        image(mod(Mclasses+1,256)); axis('equal'); axis('tight');
        colormap([0 0 0; hsv(min(Nobjectclasses+1,256))])
        drawnow
    end
end
%
% if Nimages > 1
%     if nargout > 0
%         % plot stats
%         figure
%         subplot(121)
%         loglog(sort(counts, 'descend'))
%         xlabel('count rank')
%         ylabel('Number of instances')
%         axis('tight')
%         pixelcounts = hist(single(seg(:)), 0:single(max(seg(:))));
%         unlabeled = pixelcounts(1);
%         pixelcounts = pixelcounts(2:end); % remove unlabeled pixels;
%         subplot(122)
%         loglog(sort(pixelcounts, 'descend'))
%         xlabel('area rank')
%         ylabel('Number of pixels')
%         axis('tight')
%         title(sprintf('%d categories', length(names)))
%
%         Ns = min(20, size(seg,3));
%         figure
%         montage(reshape(uint8(mod(seg(:,:,1:Ns),256)), [imagesize(1) imagesize(2) 1 Ns]))
%         colormap(gray(min(Nobjectclasses ,256)))
%     else
%         figure
%         loglog(sort(counts, 'descend'))
%         xlabel('count rank')
%         ylabel('Number of instances')
%         axis('tight')
%     end
% end


function [TorF, vstr, rdate] = have_feature_knitro()
%HAVE_FEATURE_KNITRO  Detect availability/version info for Artelys Knitro
%
%   Feature detection function implementing 'knitro' tag for HAVE_FEATURE
%   to detect availability/version of Artelys Knitro, a nonlinear
%   programming solver (https://www.artelys.com/solvers/knitro/).
%
%   See also HAVE_FEATURE, NLPS_MASTER, KNITROMATLAB.

%   MP-Opt-Model
%   Copyright (c) 2004-2020, Power Systems Engineering Research Center (PSERC)
%   by Ray Zimmerman, PSERC Cornell
%
%   This file is part of MP-Opt-Model.
%   Covered by the 3-clause BSD License (see LICENSE file for details).
%   See https://github.com/MATPOWER/mp-opt-model for more info.

tmp = have_feature('knitromatlab', 'all');
if tmp.av
    TorF = tmp.av;
    vstr = tmp.vstr;
    rdate = tmp.date;
else
    tmp = have_feature('ktrlink', 'all');
    if tmp.av
        TorF = tmp.av;
        vstr = tmp.vstr;
        rdate = tmp.date;
    else
        TorF = 0;
        vstr = '';
        rdate = '';
    end
end