classdef UniversalElementSetVariable < AbstractOrbitModelVariable
    %UniversalElementSetVariable Summary of this class goes here
    %   Detailed explanation goes here

    properties
        varObj(1,1) UniversalElementSet = UniversalElementSet.getDefaultElements();

        lb(1,6) double = 0;
        ub(1,6) double = 0;

        varC3(1,1) logical = false;
        varRp(1,1) logical = false;
        varInc(1,1) logical = false;
        varRaan(1,1) logical = false;
        varArg(1,1) logical = false;
        varTau(1,1) logical = false;
    end

    methods
        function obj = UniversalElementSetVariable(varObj)
            obj.varObj = varObj;
            obj.varObj.optVar = obj;

            obj.id = rand();
        end

        function x = getXsForVariable(obj)
            x = [];

            if(obj.varC3)
                x(end+1) = obj.varObj.c3;
            end

            if(obj.varRp)
                x(end+1) = obj.varObj.rP;
            end

            if(obj.varInc)
                x(end+1) = obj.varObj.inc;
            end

            if(obj.varRaan)
                x(end+1) = obj.varObj.raan;
            end

            if(obj.varArg)
                x(end+1) = obj.varObj.arg;
            end

            if(obj.varTau)
                x(end+1) = obj.varObj.tau;
            end
        end

        function [lb, ub] = getBndsForVariable(obj)
            useTf = obj.getUseTfForVariable();

            lb = obj.lb(useTf);
            ub = obj.ub(useTf);
        end

        function [lb, ub] = getAllBndsForVariable(obj)
            lb = obj.lb;
            ub = obj.lb;
        end

        function setBndsForVariable(obj, lb, ub)
            if(length(lb) == 6 && length(ub) == 6)
                obj.lb = lb;
                obj.ub = ub;
            else
                useTf = obj.getUseTfForVariable();

                obj.lb(useTf) = lb;
                obj.ub(useTf) = ub;
            end
        end

        function useTf = getUseTfForVariable(obj)
            useTf = [obj.varC3        obj.varRp        obj.varInc        obj.varRaan        obj.varArg        obj.varTau];
        end

        function setUseTfForVariable(obj, useTf)
            obj.varC3  = useTf(1);
            obj.varRp = useTf(2);
            obj.varInc  = useTf(3);
            obj.varRaan = useTf(4);
            obj.varArg  = useTf(5);
            obj.varTau = useTf(6);
        end

        function updateObjWithVarValue(obj, x)
            xInd = 1;

            if(obj.varC3)
                obj.varObj.c3 = x(xInd);
                xInd = xInd + 1;
            end

            if(obj.varRp)
                obj.varObj.rP = x(xInd);
                xInd = xInd + 1;
            end

            if(obj.varInc)
                obj.varObj.inc = x(xInd);
                xInd = xInd + 1;
            end

            if(obj.varRaan)
                obj.varObj.raan = x(xInd);
                xInd = xInd + 1;
            end

            if(obj.varArg)
                obj.varObj.arg = x(xInd);
                xInd = xInd + 1;
            end

            if(obj.varTau)
                obj.varObj.tau = x(xInd);
                xInd = xInd + 1; %#ok<NASGU>
            end
        end

        function nameStrs = getStrNamesOfVars(obj, evtNum, varLocType)
            if(evtNum > 0)
                subStr = sprintf('Event %i',evtNum);
            else
                subStr = varLocType;
            end

            nameStrs = {sprintf('%s C3 Energy', subStr), ...
                        sprintf('%s Radius of Periapsis', subStr), ...
                        sprintf('%s Inclination', subStr), ...
                        sprintf('%s RAAN', subStr), ...
                        sprintf('%s Argument of Periapsis', subStr), ...
                        sprintf('%s Time Past Periapsis', subStr)};

            nameStrs = nameStrs(obj.getUseTfForVariable());
        end

        function varsStoredInRad = getVarsStoredInRad(obj)
            varsStoredInRad = [false false true true true false];
        end
    end
end


function options = symbset(varargin)
%SYMBSET  Create or alter the options for Optimization with SymBuilder
%
% options = symbset('param1',value1,'param2',value2,...) creates an
% options structure with the parameters 'param' set to their corresponding
% values in 'value'. Parameters not specified will be set to the SymBuilder
% default.
%
% options = symbset(oldopts,'param1',value1,...) creates a copy of the old
% options 'oldopts' and then fills in (or writes over) the parameters
% specified by 'param' and 'value'.
%
% options = symbset() creates an options structure with all fields set to
% symbset defaults.
%
% symbset() prints a list of all possible fields and their function.

%   Copyright (C) 2013 Jonathan Currie (I2C2)

% Print out possible values of properties.
numberargs = nargin;
if (nargin == 0) && (nargout == 0)
    printfields();
    return
end
%Names and Defaults
Names = {'solver','display','solverOpts','use1stDerivs','use2ndDerivs','preallocate'}';
Defaults = {'auto','iter',[],'yes','yes','yes'}';

%Collect Sizes and lowercase matches
m = size(Names,1);
%Create structure with all names and default values
st = [Names,Defaults]'; options = struct(st{:});

% Check we have char or structure input. If structure, insert arguments
i = 1;
while i <= numberargs
    arg = varargin{i};
    if ischar(arg)
        break;
    end
    if ~isempty(arg)
        if ~isa(arg,'struct')
            error('An argument was supplied that wasn''t a string or struct!');
        end
        for j = 1:m
            if any(strcmp(fieldnames(arg),Names{j,:}))
                val = arg.(Names{j,:});
            else
                val = [];
            end
            if ~isempty(val)
                checkfield(Names{j,:},val);
                options.(Names{j,:}) = val;
            end
        end
    end
    i = i + 1;
end

%Check we have even number of args left
if rem(numberargs-i+1,2) ~= 0
    error('You do not have a value specified for each field!');
end

%Go through each argument pair and assign to correct field
expectval = 0; %first arg is a name
while i <= numberargs
    arg = varargin{i};

    switch(expectval)
        case 0 %field
            if ~ischar(arg)
                error('Expected field name to be a string! - Argument %d',i);
            end
            j = find(strcmp(arg,Names) == 1);
            if isempty(j)  % if no matches
                error('Unrecognised parameter %s',arg);
            elseif(length(j) > 1)
                error('Ambiguous parameter %s',arg);
            end
            expectval = 1; %next arg is a value
        case 1
            checkfield(Names{j,:},lower(arg));
            options.(Names{j,:}) = lower(arg);
            expectval = 0;
    end
    i = i + 1;
end

if expectval %fallen off end somehow
    error('Missing value for %s',arg);
end

%If not using 1st derivatives, turn off 2nd too
if(strcmpi(options.use1stDerivs,'no')), options.use2ndDerivs = 'no'; end

function checkfield(field,value)
%Check a field contains correct data type

if isempty(value)
    return % empty matrix is always valid
end

switch lower(field)
    %String
    case {'use1stderivs','use2ndderivs','preallocate'}
        if(ischar(value) && (strcmpi(value,'yes') || strcmpi(value,'no')))
            valid = true;
        else
            valid = false; errmsg = sprintf('Parameter %s should be a string with ''yes'' or ''no''',field);
        end

    case 'solver'
        if(ischar(value) && checkSolver(value))
            valid = true;
        else
            valid = false; errmsg = sprintf('Parameter %s should be a valid solver',field);
        end
    case 'display'
        if(ischar(value) && any(strcmpi(value,{'off','iter','final'})))
            valid = true;
        else
            valid = false; errmsg = sprintf('Parameter %s should be ''off'', ''iter'' or ''final''',field);
        end
    case 'solveropts'
        if(isstruct(value))
            valid = true;
        else
            valid = false; errmsg = sprintf('Parameter %s should be a structure',field);
        end

    otherwise
        valid = false;
        errmsg = sprintf('Unrecognized parameter name ''%s''.', field);
end

if valid
    return;
else %error
    ME = MException('symbset:FieldError',errmsg);
    throwAsCaller(ME);
end

function printfields()
%Print out fields with defaults
fprintf('        solver: [ Optimization Solver {''auto''} ] \n');
fprintf('       display: [ Solver Display Level ''off'', {''iter''}, ''final'' ]\n');
fprintf('    solverOpts: [ Solver specific options {[]} ] \n');
fprintf('  use1stDerivs: [ Use first derivatives {''yes''} (Turns off use2ndDerivs too if no) ] \n');
fprintf('  use2ndDerivs: [ Use second derivatives {''yes''} ] \n');
fprintf('   preallocate: [ Preallocate return matrices/vectors {''yes''} ] \n');
fprintf('\n');


function makecomment(filename)
% makecomment(filename)
% Forces user to make commetn and stores it into the FILENAME
% If the file already exist, it will append the comment to the end of the
% file...
comment = input('Make some comments (line string):\n','s');
fid = fopen(filename,'a');
fprintf(fid, '\nComments (%s):\n%s',datestr(now),comment);
fclose(fid);


% getchanlist() - Obtain indices of specified channel types.
%
% Usage:
%       >> chanlist = getchanlist(chanlocs, type)
%
% Inputs:
%     chanlocs - EEGLAB channel location structure
%     type     - [string] select channel of specified type
%                can enter a cell array to select several channel types
%
% Output:
%     chanlist - list of channel indices for the selected type(s)
%                sorted in increasing order
%
% Note: this function is not case sensitive
%
% Author: Arnaud Delorme, SCCN, INC, UCSD, 2004
%
% See also: pop_chanedit()

% Copyright (C) Arnaud Delorme, SCCN, INC, UCSD, 2004
%
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 2 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program; if not, write to the Free Software
% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

function chanlist = getchanlist(chanlocs, type)

    if nargin < 1
        help getchanlist;
        return;
    end;

    if nargin < 2 || ~isfield(chanlocs, 'type')
        chanlist = [1:length(chanlocs)];
        return;
    end;

    % search channel types
    % --------------------
    if isstr(type), type = { type }; end;
    type = lower(type);
    chanlist = [];
    alltypes = lower({ chanlocs.type });
    for index = 1:length(type)
        tmplist = strmatch(type{index}, alltypes, 'exact');
        if isempty(tmplist)
            fprintf('Warning: no channel of type ''%s'' found\n', type{index});
        end;
        chanlist = [ chanlist tmplist' ];
    end;
    chanlist = sort(chanlist);


function printPlot(fileName, directory, directoryHtml)

% PRINTPLOT Print a plot to eps and png files.
% FORMAT
% DESC prints a plot to the specified file name and directory.
% ARG fileName : the base name of the file to use.
% ARG directory : the directory to place the eps files in.
% ARG directoryPng : the directory to place png the file in.
%
% SEEALSO : preparePlot
%
% COPYRIGHT : Neil D. Lawrence, 2008

% NDLUTIL

  global printDiagram

  if isempty(printDiagram)
    printTrue = true; % User hasn't been explicit, assume print.
  else
    printTrue = printDiagram; % Use user preference.
  end
  if printTrue
    if nargin < 2
      directory = '.';
    end
    if nargin < 3
      png = false;
    else
      png = true;
    end
    fprintf('Printing eps plot ...\n');
    print('-depsc', [directory filesep fileName '.eps']) % OCTAVE doesn't
                                                       % include .eps automatically
    if isoctave
      % make a plot with text separated.
      fprintf('Printing epslatex plot ...\n');
      print('-depslatex', [directory filesep fileName '_latex.tex'])
    end
    cmap = colormap;
    if png
      fprintf('Printing png plot ...\n');
      % make smaller for PNG plot.
      pos = get(gcf, 'paperposition');
      origpos = pos;
      pos(3) = pos(3)/2;
      pos(4) = pos(4)/2;
      set(gcf, 'paperposition', pos);
      fontsize = get(gca, 'fontsize');
      set(gca, 'fontsize', fontsize/2);
      lineWidth = get(gca, 'lineWidth');
      set(gca, 'lineWidth', lineWidth*2);
      print('-dpng', [directoryHtml filesep fileName '.png']);
      set(gcf, 'paperposition', origpos);
      set(gca, 'fontsize', fontsize);
      set(gca, 'lineWidth', lineWidth);
    end

    fprintf('Printing black and white eps plot ...\n');
    colormap gray
    print('-deps', [directory filesep fileName 'NoColour.eps']) % Octave
                                                                % doesn't
                                                                % include
                                                                % .eps automatically
    colormap(cmap);
  end
end


function readBinary(obj,filename)
%READBINARY Load sequence from binary file.
%   READBINARY(seqObj, filename) Read the given filename and load sequence
%   data stored in the binary version of the Pulseq open file format. The
%   binary format is described in the specficiation available at
%   http://pulseq.github.io
%
%   Examples:
%   Load the sequence defined in gre.bin in sequences directory
%
%       readBinary(seqObj,'sequences/gre.bin')
%
% See also  writeBinary

binaryCodes = obj.getBinaryCodes();
fid=fopen(filename);
magicNum = fread(fid,8,'uchar');
assert(all(magicNum==binaryCodes.fileHeader(:)),'Not a binary file');
version_major = fread(fid,1,'int64');
version_minor = fread(fid,1,'int64');
version_revision = fread(fid,1,'int64');
assert(version_major==binaryCodes.version_major,'Unsupported version_major %d', version_major)
assert(version_minor==binaryCodes.version_minor,'Unsupported version_minor %d', version_minor)
assert(version_revision==binaryCodes.version_revision,'Unsupported version_revision %d', version_revision)

% set version
obj.version_major = version_major;
obj.version_minor = version_minor;
obj.version_revision = version_revision;

% Clear sequence data
obj.blockEvents={};
obj.definitions=containers.Map();
obj.gradLibrary=mr.EventLibrary();
obj.shapeLibrary=mr.EventLibrary();
obj.rfLibrary=mr.EventLibrary();
obj.adcLibrary=mr.EventLibrary();
obj.delayLibrary=mr.EventLibrary();

% Load data from file
while true
    section = int64(fread(fid,1,'int64'));
    if isempty(section)
        break
    end

    switch section
        case binaryCodes.section.definitions
            obj.definitions = readDefinitions(fid);
        case binaryCodes.section.blocks
            obj.blockEvents = readBlocks(fid);
        case binaryCodes.section.rf
            format = {'float64','int32','int32','int32','float64','float64'};
            obj.rfLibrary = readEvents(fid,format,[1 1 1 1e-6 1 1]);
        case binaryCodes.section.gradients
            format = {'float64','int32','int32'};
            obj.gradLibrary = readEvents(fid,format,[1 1 1e-6],'g',obj.gradLibrary);
        case binaryCodes.section.trapezoids
            format = {'float64','int64','int64','int64','int64'};
            obj.gradLibrary = readEvents(fid,format,[1 1e-6 1e-6 1e-6 1e-6],'t',obj.gradLibrary);
        case binaryCodes.section.adc
            format = {'int64','int64','int64','float64','float64'};
            obj.adcLibrary = readEvents(fid,format,[1 1e-9 1e-6 1 1]);
        case binaryCodes.section.delays
            format = {'int64'};
            obj.delayLibrary = readEvents(fid,format,1e-6);
        case binaryCodes.section.shapes
            obj.shapeLibrary = readShapes(fid);
        otherwise
            error('Unknown section code: %s',dec2hex(section));
    end
end
fclose(fid);

warning('readBinary() is not fully functional yet... as it needs to apply similar post-processing as read()');

return

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%% Helper functions  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    function def = readDefinitions(fid)
        %readDefinitions Read the [DEFINITIONS] section of a sequence file.
        %   defs=readDefinitions(fid) Read user definitions from file
        %   identifier of an open MR sequence file and return a map of
        %   key/value entries.

        def = containers.Map();
        numDefs = fread(fid,1,'int64');
        for i=1:numDefs
            c = fread(fid,1,'char');
            key=[];
            while c~=0 && length(key)<255
                key=[key c];
                c = fread(fid,1,'char');
            end
            key = char(key);
            count = fread(fid,1,'int8');
            type = fread(fid,1,'char');
            switch type
                case 'f'
                    values = double(fread(fid,count,'float64'));
                case 'i'
                    values = int(fread(fid,count,'int32'));
                case 'c'
                    values = char(fread(fid,count,'char')');
                    if values(end)==0
                        values=values(1:(end-1));
                    end
                otherwise
                    error('Unknown definition type');
            end
            def(key) = values;
        end
    end

    function eventTable = readBlocks(fid)
        %readBlocks Read the [BLOCKS] section of a sequence file.
        %   library=readBlocks(fid) Read blocks from file identifier of an
        %   open MR sequence file and return the event table.

        numBlocks = double(fread(fid,1,'int64'));
        eventIds = double(fread(fid,7*numBlocks,'int32'));
        eventTable_tmp = reshape(eventIds,7,numBlocks)';
        eventTable = cell(1, numBlocks);
        for ii = 1:numBlocks
            eventTable{ii} = eventTable_tmp(ii,:);
        end
    end

    function eventLibrary = readEvents(fid,format,scale,type,eventLibrary)
        %readEvents Read an event section of a sequence file.
        %   library=readEvents(fid,fmt,scale) Read event data of given
        %   format and scale elements according to column vector scale.
        %
        %   library=readEvents(fid,fmt,scale,type) Attach the type string
        %   to elements of the library.
        %
        %   library=readEvents(...,library) Append new events to the given
        %   library.

        if nargin<3
            scale=1;
        end
        if nargin<5
            eventLibrary=mr.EventLibrary();
        end
        numEvents = fread(fid,1,'int64');
        for i=1:numEvents
            id = double(fread(fid,1,'int32'));
            data = zeros(1,length(format));
            for j=1:length(format)
                data(j) = double(fread(fid,1,format{j}));
            end
            data=scale.*data;
            if nargin<4
                eventLibrary.insert(id,data);
            else
                eventLibrary.insert(id,data,type);
            end
        end
    end

    function shapeLibrary = readShapes(fid)
        %readShapes Read the [SHAPES] section of a sequence file.
        %   library=readShapes(fid) Read shapes from file identifier of an
        %   open MR sequence file and return a library of shapes.

        shapeLibrary=mr.EventLibrary();
        numShapes = fread(fid,1,'int64');
        for i=1:numShapes
            id = double(fread(fid,1,'int32'));
            numUncompressed = double(fread(fid,1,'int64'));
            numCompressed = double(fread(fid,1,'int64'));
            data = double(fread(fid,numCompressed,'float64'))';
            shapeData = [numUncompressed data];
            shapeLibrary.insert(id,shapeData);
        end
    end

end


function vl_demo_print(varargin)
% VL_DEMO_PRINT
%   VL_DEMO_PRINT(NAME) prints the current figure to the documentation
%   directory with the specified filename, assuming that the global
%   variable VL_DEMO_PRINT is defined and non-empty when MATLAB is
%   started (our using SETENV() from MATLAB). Otherwise the function
%   flushes the displays and returns.
%
%   VL_DEMO_PRINT(NAME, R) specifies a magnification factor R, setting
%   the figure width relatively to the page width. If not specified, R
%   is assumed to be 1/2.
%
%   Remarks:: The figure paper type is set to letter, that has size 8.5 x
%     11 inches. When converted for web viewing, images are rasterized
%     at either 75 or 95 DPI, The documentation system converts images
%     to bitmap with a resolution of 75 DPI, which makes a letter size
%     page 637 or 808 pixels large, repsectively.
%
%     In MATLAB font sizes are usually expressed in points, where a
%     point is a 1/72 inch. Thus a 12pt font sampled at 75 DPI is
%     about 12.5 pixels high.

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

if isempty(getenv('VL_DEMO_PRINT'))
  drawnow ;
  return ;
end

if isa(varargin{1}, 'double')
  fig = varargin{1} ;
  varargin(1) = [] ;
else
  fig = gcf ;
end

name = varargin{1} ;

if length(varargin) < 2
  figurePaperSize = 0.5 ;
else
  figurePaperSize = varargin{2} ;
end

vl_printsize(fig, figurePaperSize) ;

figDir = fullfile(vl_root,'doc','demo') ;
if ~ exist(figDir, 'dir')
  mkdir(figDir) ;
end

if 0
  filePath = fullfile(figDir, [name '.eps']) ;
  print(fig, '-depsc2', filePath) ;
else
  filePath = fullfile(figDir, [name '.jpg']) ;
  print(fig, '-djpeg95', filePath, '-r95') ;
end
fprintf('%s: wrote file ''%s''\n', mfilename,  filePath) ;


function [hFig, iDS, iFig] = view_channels_3d(FileNames, Modality, SurfaceType, is3DElectrodes, isDetails)
% VIEW_CHANNELS_3D: Display channel files on top of subject anatomy.

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

global GlobalData;
% Parse inputs
if (nargin < 5) || isempty(isDetails)
    isDetails = 0;
end
if (nargin < 4) || isempty(is3DElectrodes)
    is3DElectrodes = 0;
end
if (nargin < 3) || isempty(SurfaceType)
    SurfaceType = 'scalp';
end
if ischar(FileNames)
    FileNames = {FileNames};
end
hFig = [];
iDS = [];
iFig = [];
% Coils or channel markers?
isShowCoils = ismember(Modality, {'Vectorview306', 'CTF', '4D', 'KIT', 'KRISS', 'BabyMEG', 'NIRS-BRS', 'RICOH'});

% === DISPLAY SURFACE ===
% Get study
[sStudy, iStudy] = bst_get('ChannelFile', FileNames{1});
if isempty(sStudy)
    return
end
% Get subject
sSubject = bst_get('Subject', sStudy.BrainStormSubject);
% View surface if available
if ~isempty(sSubject)
    % If displaying MEG coils: remove completely the transparency for nicer display with Matlab >= 2014b
    if isShowCoils
        opaqueAlpha = 0;
    else
        opaqueAlpha = .1;
    end
    % If passing a filename
    if ~isempty(strfind(SurfaceType, '.mat'))
        SurfaceFile = SurfaceType;
        SurfaceType = file_gettype(SurfaceFile);
    else
        SurfaceFile = [];
    end
    % Display surface
    switch lower(SurfaceType)
        case 'cortex'
            if ~isempty(sSubject.iCortex) && (sSubject.iCortex <= length(sSubject.Surface))
                if isempty(SurfaceFile)
                    SurfaceFile = sSubject.Surface(sSubject.iCortex).FileName;
                end
                switch (Modality)
                    case 'SEEG',  SurfAlpha = .8;
                    case 'ECOG',  SurfAlpha = .2;
                    otherwise,    SurfAlpha = opaqueAlpha;
                end
                hFig = view_surface(SurfaceFile, SurfAlpha, [], 'NewFigure');
            end
        case 'innerskull'
            if ~isempty(sSubject.iInnerSkull) && (sSubject.iInnerSkull <= length(sSubject.Surface))
                if isempty(SurfaceFile)
                    SurfaceFile = sSubject.Surface(sSubject.iInnerSkull).FileName;
                end
                switch (Modality)
                    case 'SEEG',  SurfAlpha = .5;
                    case 'ECOG',  SurfAlpha = .2;
                    otherwise,    SurfAlpha = opaqueAlpha;
                end
                hFig = view_surface(SurfaceFile, SurfAlpha, [], 'NewFigure');
            end
        case 'scalp'
            if ~isempty(sSubject.iScalp) && (sSubject.iScalp <= length(sSubject.Surface))
                if isempty(SurfaceFile)
                    SurfaceFile = sSubject.Surface(sSubject.iScalp).FileName;
                end
                switch (Modality)
                    case 'SEEG',  SurfAlpha = .8;
                    case 'ECOG',  SurfAlpha = .8;
                    case 'NIRS-BRS'
                        if isDetails
                            SurfAlpha = .8;
                        else
                            SurfAlpha = opaqueAlpha;
                        end
                    otherwise
                        SurfAlpha = opaqueAlpha;
                end
                hFig = view_surface(SurfaceFile, SurfAlpha, [], 'NewFigure');
            end
        case {'anatomy', 'subjectimage'}
            if ~isempty(sSubject.iAnatomy) && (sSubject.iAnatomy <= length(sSubject.Anatomy))
                if isempty(SurfaceFile)
                    SurfaceFile = sSubject.Anatomy(sSubject.iAnatomy).FileName;
                end
                SurfAlpha = .1;
                hFig = view_mri_3d(SurfaceFile, [], SurfAlpha, 'NewFigure');
            end
    end
end
% Warning if no surface was found
if isempty(hFig)
    disp('BST> Warning: The anatomy of this subject was not imported properly.');
end

% === DISPLAY CHANNEL FILES ===
% Only one: Markers and labels
if (length(FileNames) == 1)
    if is3DElectrodes
        isLabels = 0;
    else
        isLabels = 1;
    end
    isMarkers = ~isShowCoils || isDetails;
    [hFig, iDS, iFig] = view_channels(FileNames{1}, Modality, isMarkers, isLabels, hFig, is3DElectrodes);
    % SEEG and ECOG: Open tab "iEEG"
    if ismember(Modality, {'SEEG', 'ECOG', 'ECOG+SEEG'})
        gui_brainstorm('ShowToolTab', 'iEEG');
    end
% Multiple: Markers only
else
    ColorTable = [1,0,0; 0,1,0; 0,0,1];
    for i = 1:length(FileNames)
        color = ColorTable(mod(i-1,size(ColorTable,1))+1,:);
        % View channel file
        [hFig, iDS, iFig] = view_channels(FileNames{i}, Modality, 1, 0, hFig);
        % Rename objects so that they are not deleted by the following call
        hPatch = findobj(hFig, 'tag', 'SensorsPatch');
        set(hPatch, 'FaceColor', color, 'FaceAlpha', .3, 'SpecularStrength', 0, ...
                    'EdgeColor', color, 'EdgeAlpha', .2, 'LineWidth', 1, ...
                    'Marker', 'none', 'Tag', 'MultipleSensorsPatches');
        if (i ~= length(FileNames))
            hPatch = copyobj(hPatch, get(hPatch,'Parent'));
            % Delete loaded channel information to force it to be reloaded by the view_channels function
            GlobalData.DataSet(iDS).Channel = [];
        end
    end
end


% Synchronoise the streams such that they will work with the network.
% Things did in this function:
%   1. upsample streams to match other streams of higher frame rate. This
%   is only done when streams are specified by DataSyncSet to have the same
%   frame rate. Also discarded last frames longer streams to make the
%   streams have the same number of frames.
%   2. apply VAD to some streams. Here VAD is stored in one stream
%   (normally the last stream). We first upsample/downsample VAD framerate
%   to match the stream to be VADed. Then remove nonspeech segments. VAD
%   should be stored as 1-D feature stream.
%
% Author: Xiong Xiao, Temasek labs, NTU, Singapore.
% Date Created: 10 Oct 2015
% Last Modified: 21 Apr 2016
%
function [data_sync, nFr_actual, isTensor, isVAD, isFramewise] = SynchronizeDataStreams2(alldata, para)
[nStream, nUtt] = size(alldata);

isTensor = para.IO.isTensor;
isVAD = zeros(nStream,1);
isFramewise = zeros(nStream,1);
data_sync = alldata;
nFr_actual = zeros(nUtt, nStream);

ApplyVADSet = para.IO.ApplyVADSet;
DataSyncSet = para.IO.DataSyncSet;
if isempty(DataSyncSet) && isempty(ApplyVADSet)
    for utt_i = 1:nUtt
        for i=1:nStream
            [~,n2,n3] = size(data_sync{i, utt_i});
            if isTensor(i)
                if n2==0
                    nFr_actual(utt_i,i) = 0;
                else
                    nFr_actual(utt_i,i) = n3;
                end
            else
                nFr_actual(utt_i,i) = n2;
            end
            if n2>1
                isFramewise(i) = 1;     % if any sentence has more than one frame, it is framewise feature or label
            end
        end
    end
    return;
end

for utt_i = 1:nUtt
    % Apply VAD and segmentation first, if required
    for vi=1:length(ApplyVADSet)
        isVAD(ApplyVADSet{vi}(end))=1;
        curr_vad_set = ApplyVADSet{vi};
        if isempty(curr_vad_set); continue; end
        data_sync{curr_vad_set(1), utt_i} = SynchronizeStreamsVAD( data_sync(curr_vad_set, utt_i), para.IO.vadAction{vi} );
    end

    % Apply Frame rate synchronization to all Sync Sets
    for di=1:length(DataSyncSet)
        curr_sync_set = DataSyncSet{di};
        if isempty(curr_sync_set); continue; end
        data_sync(curr_sync_set, utt_i) = SynchronizeStreamsFrameRate(  data_sync(curr_sync_set, utt_i) , para.IO.frame_rate(curr_sync_set) , isTensor(curr_sync_set)  );
    end

%     for i=1:nStream
%         [~,~,n3] = size(data_sync{i, utt_i});
%         if n3>1; isTensor(i) = 1;   end
%     end
end
for utt_i = 1:nUtt
    for i=1:nStream
        [~,n2,n3] = size(data_sync{i, utt_i});
        if isTensor(i)
            if n2==0
                nFr_actual(utt_i,i) = 0;
            else
                nFr_actual(utt_i,i) = n3;
            end
        else
            nFr_actual(utt_i,i) = n2;
        end
        if n2>1
            isFramewise(i) = 1;     % if any sentence has more than one frame, it is framewise feature or label
        end
    end
end
end


classdef ConstraintValues < matlab.mixin.SetGet
    %ConstraintValues Summary of this class goes here
    %   Detailed explanation goes here

    properties
        c = [];
        ceq = [];
        value = [];
        lb = [];
        ub = [];
        type = {};
        eventNum = [];
        cEventInds = [];
        ceqEventInds = [];
        consts AbstractConstraint = AbstractConstraint.empty(1,0);
        cCInds = [];
        cCeqInds = [];
        valueStateComps = [];
    end

    methods
        function obj = ConstraintValues()

        end

        function updateValues(obj, c, ceq, value, lb, ub, type, eventNum, cEventInds, ceqEventInds, consts, cCInds, cCeqInds, valueStateComps)
            obj.c = c;
            obj.ceq = ceq;
            obj.value = value;
            obj.lb = lb;
            obj.ub = ub;
            obj.type = type;
            obj.eventNum = eventNum;
            obj.cEventInds = cEventInds;
            obj.ceqEventInds = ceqEventInds;
            obj.consts = consts;
            obj.cCInds = cCInds;
            obj.cCeqInds = cCeqInds;
            obj.valueStateComps = valueStateComps;
        end

        function [c, ceq, value, lb, ub, type, eventNum, cEventInds, ceqEventInds, consts, cCInds, cCeqInds, valueStateComps] = getValues(obj)
            c = obj.c;
            ceq = obj.ceq;
            value = obj.value;
            lb = obj.lb;
            ub = obj.ub;
            type = obj.type;
            eventNum = obj.eventNum;
            cEventInds = obj.cEventInds;
            ceqEventInds = obj.ceqEventInds;
            consts = obj.consts;
            cCInds = obj.cCInds;
            cCeqInds = obj.cCeqInds;
            valueStateComps = obj.valueStateComps;
        end
    end
end


function c = sigma_delta_control

c = hdlnewcontrol(mfilename);

c.forEach('design_multi_stage3/Stage1_40_Tap_FIR_using_LUT/Sum',...
 'built-in/Sum', {},...
 'hdldefaults.ProductTreeHDLEmission',{});

%for tree implementation use hdldefaults.ProductTreeHDLEmission
%for cascade implementaiton use hdldefaults.ProductCascadeHDLEmission


function outTable = convertToTableCore(featureLexicon,inParams)

% deal with optional arguments
if nargin<2 || isempty(inParams)
  inParams=struct();
end

%featureLexicon = ReadXMLParams(featureconfigfile);
allpf = fieldnames(featureLexicon.perframe);
pftypeList = {};
for pfndx = 1:numel(allpf)
  curpf = allpf{pfndx};
  curtypes  = featureLexicon.perframe.(curpf).type;
  if ischar(curtypes)
    curT = curtypes;
    if ~any(strcmp(pftypeList,curT))
      pftypeList{end+1} = curT;
    end
  else
    for tndx = 1:numel(curtypes)
      curT = curtypes{tndx};
      if ~any(strcmp(pftypeList,curT))
        pftypeList{end+1} = curT;
      end
    end
  end
end

types = fieldnames(inParams);
outTable = cell(numel(pftypeList),3);
for ndx = 1:numel(pftypeList)
  matches = strcmp(types,pftypeList{ndx});
  if any(matches)
    mndx = find(matches,1);
    outTable{ndx,1} = types{mndx};
    outTable{ndx,2} = inParams.(types{mndx}).mode{1};
    outTable{ndx,3} = inParams.(types{mndx}).selection{1};
  else
    outTable{ndx,1} = pftypeList{ndx};
    outTable{ndx,2} = 'None';
    outTable{ndx,3} = 'normal';
  end
end


report_this_filefun(mfilename('fullpath'));

str = [];
out = reshape(bv2,33759,1,1);
out = out*100;

[newmatfile, newpath] = uiputfile([ hodo '*.dat'], 'Save As'); %Syntax change Matlab Version 7, no window positioning on macs

s = [33  ;33 ; 31  ;out(:,1)   ];
s = s'
fid = fopen([newpath newmatfile],'w') ;;
fwrite(fid,s,'integer*8');
fclose(fid);
clear s
return


function [nodes, edges2] = grRemoveEdge(nodes, edges, edge)
%GRREMOVEEDGE Remove an edge in a graph.
%
%   [NODES2 EDGES2] = grRemoveEdge(NODES, EDGES, EDGE2REMOVE)
%   Remove an edge in the edges list, and return the modified graph.
%   The NODES array is not modified.

% ------
% Author: David Legland
% E-mail: david.legland@inrae.fr
% Created: 2003-08-13
% Copyright 2003-2022 INRA - TPV URPOI - BIA IMASTE

dim = size(edges);
edges2 = zeros(dim(1)-1, 2);
edges2(1:edge-1, :) = edges(1:edge-1, :);
edges2(edge:dim(1)-1, :) = edges(edge+1:dim(1), :);


function w = load_seisan(request)
   %LOAD_SEISAN loads a waveform from SEISAN files
   % combineWaves isn't currently used!

   % Glenn Thompson 2016/05/25 based on load_miniseed
   % request.combineWaves is ignored
   w=[];
   if isstruct(request)
      [thisSource, chanInfo, startTimes, endTimes, ~] = unpackDataRequest(request);
      for i=1:numel(chanInfo)
         for j=1:numel(startTimes)
            thisfilename = getfilename(thisSource,chanInfo(i),startTimes(j))
            thisw = load_seisan_file(thisfilename{1}); %, startTimes(j), endTimes(j));
            w = [w thisw];
         end
      end
      w = w(:);

   else
      %request should be a filename
      thisFilename = request;
      if exist(thisFilename, 'file')
        w = load_seisan_file(thisFilename);
      else
          w = waveform();
          warning(sprintf('File %s does not exist',thisFilename));
      end
   end
end

function w = load_seisan_file(fn)%dataRequest)
   % Read a v7.0 or later SEISAN file
   w  = waveform; %initialize, in case nothing works
   MACHINEFORMAT = 'l';
   %disp('Little Endian');
   fid = fopen(fn,'r',MACHINEFORMAT);
   bytesToRead = fread(fid,1,'uint32');
   if bytesToRead ~= 80
      fclose(fid);
      MACHINEFORMAT = 'b';
      %disp('Switching to Big Endian');
      fid = fopen(fn,'r',MACHINEFORMAT);
      bytesToRead = fread(fid,1,'uint32');
      if bytesToRead ~= 80

         warning('Waveform:load_seisan:invalidFileFormat',['File does not appear to be a SEISAN file,]'...
            '[ or is an old PC version.\n This program is currently]',...
            '[ incapable of opening PC SEISAN files older than V7.0']);
         fclose(fid);
         return
      end
   end

   fseek(fid,0,-1);

   nsta = 0;
   for i=1:333;
      bytesToRead = fread(fid,1,'uint32');
      if bytesToRead == 80
         st(1:80) = fread(fid,80,'char');
         if i== 1
            h = parseSeisanHeader(st);
            nsta = h.stationCount;
         end

         if i >= 3
            for j=1:3
               thisbit = st(((j-1) * 26 + 1):(j*26));
               ch = parseSeisamChannelHeader(thisbit);
            end
         end
         bytesRead = fread(fid,1,'uint32');

      else
         break
      end
   end

   for j = 1: nsta
      dt = fread(fid,1040,'char');
      mydata = parseSeisamData(dt);
      w(j) = waveform;
      w(j) = set(w(j),'station',mydata.station,'channel',mydata.channel,...
         'start',getStartTime(mydata),'freq',mydata.sampleRate);

      nbytesread = fread(fid,1,'uint32'); %bytecount
      bytestoread = fread(fid,1,'uint32'); %bytecount

      rawdata = fread(fid,bytestoread / 4,'int32');
      w(j) = set(w(j),'data',rawdata);

      nbytesread = fread(fid,1,'uint32'); %bytecount
      nbytesToread2 = fread(fid,1,'uint32'); %bytecount
   end
   fclose(fid);
end

function h = parseSeisanHeader(headerBlock)

   hFieldName = {'network','stationCount','centuryCode','year','doy','month','day','hr','min','sec','totalTime'};
   hFieldpos = {2:30,31:33,34,35:36,38:40,42:43,45:46,48:49,51:52,54:59,61:69};
   hFieldType = ['sddddddddff']; %s=string, d=integer, f=float

   for n=1:numel(hFieldName)
      switch hFieldType(n)
         case 's'
            h.(hFieldName{n}) = deblank(char(headerBlock([hFieldpos{n}])));
         case 'd'
            h.(hFieldName{n}) = str2double(char(headerBlock([hFieldpos{n}]')));
         case 'f'
            h.(hFieldName{n}) = str2double(char(headerBlock([hFieldpos{n}]')));
      end
   end
end
function ch = parseSeisamChannelHeader(channelBlock)

   chFieldName= {'station','comp','lastStaLetter','startRelToEvent','staDataInterval'};
   chFieldpos = {2:5,6:9,10,11:17,19:26};
   chFieldType = ['sssff']; %s=string, d=integer, f=float

   for n=1:numel(chFieldName)
      switch chFieldType(n)
         case 's'
            ch.(chFieldName{n}) = deblank(char(channelBlock([chFieldpos{n}])));
         case 'd'
            ch.(chFieldName{n}) = str2double(char(channelBlock([chFieldpos{n}]')));
         case 'f'
            ch.(chFieldName{n}) = str2double(char(channelBlock([chFieldpos{n}]')));
      end
   end
end
function d = parseSeisamData(dataBlock)

   dFieldName= {'station','channel','centuryCode','year','doy',...
      'month','day','hr','min','timingIndicator','second','sampleRate',...
      'nsamp','lat','lon','elev','gainFactor','howManyBits'};
   dFieldpos = {1:5,6:9,10,11:12,14:16,...
      18:19,21:22,24:25,27:28,29,30:35,37:43,...
      45:50,52:59,61:69,71:75,76,77};
   dFieldType = ['ssdddddddsffdffdsd']; %s=string, d=integer, f=float

   for n=1:numel(dFieldName)
      switch dFieldType(n)
         case 's'
            temp = char(dataBlock([dFieldpos{n}]));
            d.(dFieldName{n}) = deblank(temp(:)');
         case 'd'
            d.(dFieldName{n}) = str2double(char(dataBlock([dFieldpos{n}]')));
         case 'f'
            d.(dFieldName{n}) = str2double(char(dataBlock([dFieldpos{n}]')));
      end
   end
end

function st = getStartTime(myData)

   switch myData.centuryCode
      case 0
         baseyear = 1900;
      case 1
         baseyear = 2000;
      otherwise
         baseyear = 0;
   end
   st = datenum(myData.year + baseyear,...
      myData.month,...
      myData.day,...
      myData.hr,...
      myData.min,...
      myData.second);

   return
end


function popt = partition_options(pdefault, varargin)
%PARTITION_OPTIONS Options for EQ partition
%
%Syntax
% popt = partition_options(pdefault,options);
%
%Description
% POPT = PARTITION_OPTIONS(PDEFAULT,options) collects partition options,
% specified as name, value pairs, and places these into the structure POPT.
% The structure PDEFAULT is used to define default option values.
%
% The structures pdefault and popt may contain the following fields:
% extra_offset:  boolean
%
% The following partition options are available.
%
% 'offset':      Control extra rotation offsets for S^2 and S^3 regions.
%     'extra':   Use extra rotation offsets for S^2 and S^3 regions, to try
%                to minimize energy.
%                Sets opt.extra_offset to true.
%     'normal':  Do not use extra offsets
%                Sets opt.extra_offset to false.
%
% Some shortcuts are also provided.
% POPT = PARTITION_OPTIONS(pdefault) just sets POPT to PDEFAULT.
%
% The following are equivalent to PARTITION_OPTIONS(PDEFAULT,'offset','extra'):
% PARTITION_OPTIONS(PDEFAULT,true)
% PARTITION_OPTIONS(PDEFAULT,'extra')
%
% The following are equivalent to PARTITION_OPTIONS(PDEFAULT,'offset','normal'):
% PARTITION_OPTIONS(PDEFAULT,false)
% PARTITION_OPTIONS(PDEFAULT,'normal')
%
%Examples
% > pdefault.extra_offset=false;
% > popt=partition_options(pdefault,'offset','extra')
% popt =
%     extra_offset: 1
%
% > popt=partition_options(pdefault,false)
% popt =
%     extra_offset: 0

% Copyright 2004-2005 Paul Leopardi for the University of New South Wales.
% $Revision 1.10 $ $Date 2005-06-01 $
% Documentation files renamed
% $Revision 1.00 $ $Date 2005-02-12 $
%
% For licensing, see COPYING.
% For references, see AUTHORS.
% For revision history, see CHANGELOG.

popt = pdefault;
nargs = length(varargin);

if nargs == 1
    %
    % Short circuit: single argument is value of extra_offset
    %
    value = varargin{1};
    switch value
    case true
        popt.extra_offset = true;
    case false
        popt.extra_offset = false;
    case 'extra'
        popt.extra_offset = true;
    case 'normal'
        popt.extra_offset = false;
    otherwise
        value_error(value,varargin{:});
    end
    return;
end

nopts = floor(nargs/2);
opt_args = {varargin{1:2:2*nopts-1}};
for k=1:nopts
    if ~ischar([opt_args{k}])
        fprintf('Option names must be character strings\n');
        option_error(varargin{:});
    end
end
opt_vals = {varargin{2:2:2*nopts}};

option_name = 'offset';
pos = strmatch(option_name,opt_args,'exact');
if ~isempty(pos)
    if (length(pos) == 1)
        value = opt_vals{pos};
    else
        duplicate_error(option_name,varargin{:});
    end
    switch value
    case 'extra'
        popt.extra_offset = true;
    case 'normal'
        popt.extra_offset = false;
    otherwise
        value_error(value,varargin{:});
    end
end

function duplicate_error(option_name,varargin)
fprintf('Duplicate option %s\n',option_name);
option_error(varargin{:});
%
% end function

function value_error(value,varargin)
fprintf('Invalid option value ');
disp(value);
option_error(varargin{:});
%
% end function

function option_error(varargin)
fprintf('Error in options:\n');
disp(varargin);
error('Please check "help partition_options" for options');
%
% end function


function obj = updateHeatmapAnnotation(obj,anIndex)

%-------X/YLABEL FIELDS--------%
% title...[DONE]
% titlefont.size...[DONE]
% titlefont.family...[DONE]
% titlefont.color...[DONE]

%------ANNOTATION FIELDS-------%

% x: ...[DONE]
% y: ...[DONE]
% xref: ...[DONE]
% yref: ...[DONE]
% text: ...[DONE]
% showarrow: ...[HANDLED BY CALL TO ANNOTATION];
% font: ...[DONE]
% xanchor: ...[DONE]
% yanchor: ...[DONE]
% align: ...[DONE]
% arrowhead: ...[HANDLED BY CALL FROM ANNOTATION];
% arrowsize: ...[HANDLED BY CALL FROM ANNOTATION];
% arrowwidth: ...[HANDLED BY CALL FROM ANNOTATION];
% arrowcolor: ...[HANDLED BY CALL FROM ANNOTATION];
% ax: ...[HANDLED BY CALL FROM ANNOTATION];
% ay: ...[HANDLED BY CALL FROM ANNOTATION];
% textangle: ...[DONE]
% bordercolor: ...[DONE]
% borderwidth: ...[DONE]
% borderpad: ...[DONE]
% bgcolor: ...[DONE]
% opacity: ...[NOT SUPPORTED IN MATLAB]

%-AXIS INDEX-%
nanns = length(obj.layout.annotations);
axIndex = nanns + obj.getAxisIndex(obj.State.Text(anIndex).AssociatedAxis);

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

%-get heatmap title name-%
title_name = obj.State.Text(anIndex).Handle;

%-show arrow-%
obj.layout.annotations{axIndex}.showarrow = false;

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

%-anchor title to paper-%
if obj.State.Text(anIndex).Title
    %-xref-%
    obj.layout.annotations{axIndex}.xref = 'paper';
    %-yref-%
    obj.layout.annotations{axIndex}.yref = 'paper';
else
    %-xref-%
    obj.layout.annotations{axIndex}.xref = ['x' num2str(xsource)];
    %-yref-%
    obj.layout.annotations{axIndex}.yref = ['y' num2str(ysource)];
end

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

%-xanchor-%
obj.layout.annotations{axIndex}.xanchor = 'middle';

%-align-%
obj.layout.annotations{axIndex}.align = 'middle';

%-xanchor-%
obj.layout.annotations{axIndex}.yanchor = 'top';

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

%-text-%
obj.layout.annotations{axIndex}.text = sprintf('<b>%s</b>', title_name);
obj.layout.annotations{axIndex}.font.size = 14;

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

if obj.State.Text(anIndex).Title

    %-AXIS DATA-%
    eval(['xaxis = obj.layout.xaxis' num2str(xsource) ';']);
    eval(['yaxis = obj.layout.yaxis' num2str(ysource) ';']);

    %-x position-%
    obj.layout.annotations{axIndex}.x = mean(xaxis.domain);
    %-y position-%
    obj.layout.annotations{axIndex}.y = (yaxis.domain(2) + 0.04);
else
    %-x position-%
    obj.layout.annotations{axIndex}.x = text_data.Position(1);
    %-y position-%
    obj.layout.annotations{axIndex}.y = text_data.Position(2);
end

%-------------------------------------------------------------------------%
end


function [all_opts,use_libigl_static_library] = gptoolbox_mexopts(varargin)

  use_libigl_static_library = [];
  debug = false;
  % Map of parameter names to variable names
  params_to_variables = containers.Map( ...
    {'Static','Debug'}, ...
    {'use_libigl_static_library','debug'});
  v = 1;
  while v <= numel(varargin)
    param_name = varargin{v};
    if isKey(params_to_variables,param_name)
      assert(v+1<=numel(varargin));
      v = v+1;
      % Trick: use feval on anonymous function to use assignin to this workspace
      feval(@()assignin('caller',params_to_variables(param_name),varargin{v}));
    else
      error('Unsupported parameter: %s',varargin{v});
    end
    v=v+1;
  end

  verbose = false;
  MEXOPTS={'-largeArrayDims','-DMEX'};
  if verbose
    MEXOPTS={'-v',MEXOPTS{:}};
  end
  MSSE42='CXXFLAGS=$CXXFLAGS -msse4.2';
  STDCPP11='CXXFLAGS=$CXXFLAGS -std=c++11';
  try
    ELTOPO_INC= sprintf('-I%s/',path_to_eltopo);
    ELTOPO_LIB= strsplit(sprintf('-L%s/eltopo3d -leltopo_release',path_to_eltopo));
  catch e
    ELTOPO_INC='-DELTOPO_NOT_FOUND';
    ELTOPO_LIB={'-DELTOPO_NOT_FOUND'};
  end
  CLANG={'CXX=/usr/bin/clang++','LD=/usr/bin/clang++'};
  FRAMEWORK_LDFLAGS='LDFLAGS=\$LDFLAGS -framework Foundation -framework AppKit -framework Accelerate';
  NOOPT_LDOPTIMFLAGS='LDOPTIMFLAGS="-O "';
  if debug
    MEXOPTS={'-g',MEXOPTS{:}};
  end

  % See libigl documentation. In short, Libigl is a header-only library by
  % default: no compilation needed (like Eigen). There's an advanced **option**
  % to precompile libigl as a static library. This cuts down on compilation time.
  % It is optional and more difficult to set up. Set this to true only if you
  % know what you're doing.
  %use_libigl_static_library  = false;
  if isempty(use_libigl_static_library)
    use_libigl_static_library = exist([path_to_libigl '/lib/libigl.a'],'file')~=0;
  end
  if use_libigl_static_library
    r = -1;
    if strcmp(char(java.lang.System.getProperty('user.name')),'ajx')
      cmd = sprintf('cd "%s"/lib && /usr/local/bin/cmake ../optional/ -DLIBIGL_USE_STATIC_LIBRARY=ON -DLIBIGL_WITH_ANTTWEAKBAR=ON -DLIBIGL_WITH_BBW=ON -DLIBIGL_WITH_CORK=ON -DLIBIGL_WITH_CGAL=ON -DLIBIGL_WITH_COMISO=ON -DLIBIGL_WITH_EMBREE=ON -DLIBIGL_WITH_LIM=ON -DLIBIGL_WITH_MATLAB=ON -DLIBIGL_WITH_MOSEK=ON -DLIBIGL_WITH_NANOGUI=OFF -DLIBIGL_WITH_OPENGL=ON -DLIBIGL_WITH_PNG=ON -DLIBIGL_WITH_TETGEN=ON -DLIBIGL_WITH_TRIANGLE=ON -DLIBIGL_WITH_VIEWER=ON -DLIBIGL_WITH_XML=ON -DCMAKE_BUILD_TYPE=Release && ../scripts/make.sh -j3',path_to_libigl);
    else
      cmd = sprintf('cd "%s"/lib && /usr/local/bin/cmake ../optional/ -DLIBIGL_USE_STATIC_LIBRARY=ON -DLIBIGL_WITH_ANTTWEAKBAR=ON -DLIBIGL_WITH_BBW=ON -DLIBIGL_WITH_CORK=ON -DLIBIGL_WITH_CGAL=ON -DLIBIGL_WITH_COMISO=ON -DLIBIGL_WITH_EMBREE=ON -DLIBIGL_WITH_LIM=ON -DLIBIGL_WITH_MATLAB=ON -DLIBIGL_WITH_MOSEK=ON -DLIBIGL_WITH_NANOGUI=OFF -DLIBIGL_WITH_OPENGL=ON -DLIBIGL_WITH_PNG=ON -DLIBIGL_WITH_TETGEN=ON -DLIBIGL_WITH_TRIANGLE=ON -DLIBIGL_WITH_VIEWER=ON -DLIBIGL_WITH_XML=ON -DCMAKE_BUILD_TYPE=Release && make -j3',path_to_libigl);
    end
    if verbose
      fprintf('%s\n',cmd);
    end
    [r,c] = system(cmd);
    if r ~= 0
      warning('libigl Make error:\n%s',c);
      use_libigl_static_library = false;
    end
  end

  %use_libigl_static_library= false;
  LIBIGL_INC=sprintf('-I%s/include',path_to_libigl);
  if use_libigl_static_library
    LIBIGL_FLAGS='-DIGL_STATIC_LIBRARY';
    LIBIGL_LIB=strsplit(sprintf('-L%s/lib -ligl',path_to_libigl));
    LIBIGL_LIBEMBREE='-ligl_embree';
    LIBIGL_LIBMATLAB='-ligl_matlab';
    LIBIGL_LIBCGAL='-ligl_cgal';
    LIBIGL_LIBCORK='-ligl_cork';
  else
    % `mex` has a silly requirement that arguments be non-empty, hence the NOOP
    % defines
    LIBIGL_FLAGS='-DIGL_SKIP';
    LIBIGL_LIB={'-DIGL_SKIP'};
    LIBIGL_LIBMATLAB='-DIGL_SKIP';
    LIBIGL_LIBEMBREE='-DIGL_SKIP';
    LIBIGL_LIBCGAL='-DIGL_SKIP';
    LIBIGL_LIBCORK='-DIGL_SKIP';
  end
  LIBIGL_BASE={LIBIGL_INC,LIBIGL_FLAGS,LIBIGL_LIB{:},LIBIGL_LIBMATLAB};

  if exist(sprintf('%s/external/nanogui/ext/eigen/',path_to_libigl))
    EIGEN_INC=sprintf('-I%s/external/nanogui/ext/eigen/',path_to_libigl);
  elseif exist('/usr/local/include/eigen3')
    EIGEN_INC='-I/usr/local/include/eigen3';
  elseif exist('/opt/local/include/eigen3')
    EIGEN_INC='-I/opt/local/include/eigen3';
  end

  EMBREE=[path_to_libigl '/external/embree'];
  EMBREE_INC=strsplit(sprintf('-DWITH_EMBREE -I%s -I%s/include/',EMBREE,EMBREE));
  %EMBREE_LIB=strsplit(sprintf('-ltbb -L%s -lembree_avx -lembree_avx2 -lembree_sse42 -limage -llexers -llights -llights_ispc -lnoise -lnoise_ispc -lscenegraph -lsimd -lsys -ltasking -ltexture -ltexture_ispc -ltutorial -ltutorial_device -ltutorial_device_ispc ',[path_to_libigl '/external/embree/build/']));
  EMBREE_LIB=strsplit(sprintf('-L%s -lembree',[path_to_libigl '/external/embree/build/']));

  CORK_INC=sprintf('-I%s/src',[path_to_libigl '/external/cork']);
  CORK_LIB=strsplit(sprintf('-L%s -lcork',[path_to_libigl '/lib']));

  TINYXML2=[path_to_libigl '/external/tinyxml2'];
  TINYXML2_INC=sprintf('-I%s/',TINYXML2);
  TINYXML2_LIB=strsplit(sprintf('-L%s/ -ltinyxml2',TINYXML2));

  if exist('/usr/local/include/CGAL')
    CGAL='/usr/local/';
  elseif exist('/opt/local/include/CGAL')
    CGAL='/opt/local/';
  end
  CGAL_INC=sprintf('-I%s/include',CGAL);
  CGAL_LIB=strsplit(sprintf('-L%s/lib -lCGAL -lCGAL_Core -lgmp -lmpfr',CGAL));
  CGAL_FLAGS='CXXFLAGS=\$CXXFLAGS -frounding-math';

  BOOST='/usr/local/';
  BOOST_INC=sprintf('-I%s/include',BOOST);
  BOOST_LIB=strsplit(sprintf('-L%s/lib -lboost_thread-mt -lboost_system-mt',BOOST));

  all_opts = { ...
         MEXOPTS{:},...
         MSSE42, ...
         STDCPP11, ...
         EIGEN_INC, ...
         ELTOPO_INC, ...
         ELTOPO_LIB{:}, ...
         FRAMEWORK_LDFLAGS, ...
         LIBIGL_BASE{:}, ...
         LIBIGL_LIBEMBREE, ...
         LIBIGL_LIBCGAL, ...
         LIBIGL_LIBCORK, ...
         EMBREE_INC{:}, EMBREE_LIB{:}, ...
         CORK_INC,CORK_LIB{:}, ...
         TINYXML2_INC,TINYXML2_LIB{:}, ...
         CGAL_INC,CGAL_LIB{:},CGAL_FLAGS, ...
         BOOST_INC,BOOST_LIB{:}, ...
         };
end


function [estimate] = ft_inverse_pcc(sourcemodel, sens, headmodel, dat, C, varargin)

% FT_INVERSE_PCC implements a linearly-constrained miminum variance beamformer that
% allows for post-hoc computation of canonical or partial coherence or correlation.
% Moreover, if cortico-cortical interactions are computed, the spatial filters are
% computed with a paired dipole as sourcemodel, thus suppressing the distortive
% effect of correlated activity from the seed region.
%
% Use as
%   [estimate] = ft_inverse_pcc(sourcemodel, sens, headmodel, dat, cov, ...)
% where
%   sourcemodel is the input source model, see FT_PREPARE_SOURCEMODEL
%   sens        is the gradiometer or electrode definition, see FT_DATATYPE_SENS
%   headmodel   is the volume conductor definition, see FT_PREPARE_HEADMODEL
%   dat         is the data matrix with the ERP or ERF
%   cov         is the data covariance or cross-spectral density matrix
% and
%   estimate    contains the estimated source parameters
%
% Additional input arguments should be specified as key-value pairs and can include
%   'refchan'
%   'refdip'
%   'supchan'
%   'supdip'
%   'feedback'
%   'keepcsd'
%   'keepfilter'
%   'keepleadfield'
%   'keepmom'
%   'lambda'
%   'projectnoise'
%   'realfilter'
%   'fixedori'
%
% These options influence the forward computation of the leadfield
%   'reducerank'      = 'no' or number  (default = 3 for EEG, 2 for MEG)
%   'backproject'     = 'yes' or 'no', in the case of a rank reduction this parameter determines whether the result will be backprojected onto the original subspace (default = 'yes')
%   'normalize'       = 'no', 'yes' or 'column' (default = 'no')
%   'normalizeparam'  = parameter for depth normalization (default = 0.5)
%   'weight'          = number or Nx1 vector, weight for each dipole position to compensate for the size of the corresponding patch (default = 1)
%
% See also FT_SOURCEANALYSIS, FT_PREPARE_HEADMODEL, FT_PREPARE_SOURCEMODEL

% Copyright (C) 2005-2020, Robert Oostenveld & Jan-Mathijs Schoffelen
%
% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org
% for the documentation and details.
%
%    FieldTrip is free software: you can redistribute it and/or modify
%    it under the terms of the GNU General Public License as published by
%    the Free Software Foundation, either version 3 of the License, or
%    (at your option) any later version.
%
%    FieldTrip is distributed in the hope that it will be useful,
%    but WITHOUT ANY WARRANTY; without even the implied warranty of
%    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%    GNU General Public License for more details.
%
%    You should have received a copy of the GNU General Public License
%    along with FieldTrip. If not, see <http://www.gnu.org/licenses/>.
%
% $Id$

if mod(nargin-5,2)
  % the first 5 arguments are fixed, the other arguments should come in pairs
  ft_error('invalid number of optional arguments');
end

% get the optional input arguments, or use defaults
refchan        = ft_getopt(varargin, 'refchan');
refdip         = ft_getopt(varargin, 'refdip');
supchan        = ft_getopt(varargin, 'supchan');
supdip         = ft_getopt(varargin, 'supdip');
feedback       = ft_getopt(varargin, 'feedback',      'text');
keepcsd        = ft_getopt(varargin, 'keepcsd',       'yes');
keepfilter     = ft_getopt(varargin, 'keepfilter',    'no');
keepleadfield  = ft_getopt(varargin, 'keepleadfield', 'no');
keepmom        = ft_getopt(varargin, 'keepmom',       'yes');
projectnoise   = ft_getopt(varargin, 'projectnoise',  'yes');
realfilter     = ft_getopt(varargin, 'realfilter',    'yes');
fixedori       = ft_getopt(varargin, 'fixedori',      'no');
weightnorm     = ft_getopt(varargin, 'weightnorm',    'no');

% construct the low-level options for the covariance matrix inversion as key-value pairs, these are passed to FT_INV
invopt = {};
invopt = ft_setopt(invopt, 'lambda',    ft_getopt(varargin, 'lambda', 0));
invopt = ft_setopt(invopt, 'kappa',     ft_getopt(varargin, 'kappa'));
invopt = ft_setopt(invopt, 'tolerance', ft_getopt(varargin, 'tol'));
invopt = ft_setopt(invopt, 'method',    ft_getopt(varargin, 'invmethod'));

% construct the low-level options for the leadfield computation as key-value pairs, these are passed to FT_COMPUTE_LEADFIELD
leadfieldopt = {};
leadfieldopt = ft_setopt(leadfieldopt, 'reducerank',     ft_getopt(varargin, 'reducerank'));
leadfieldopt = ft_setopt(leadfieldopt, 'backproject',    ft_getopt(varargin, 'backproject'));
leadfieldopt = ft_setopt(leadfieldopt, 'normalize',      ft_getopt(varargin, 'normalize'));
leadfieldopt = ft_setopt(leadfieldopt, 'normalizeparam', ft_getopt(varargin, 'normalizeparam'));
leadfieldopt = ft_setopt(leadfieldopt, 'weight',         ft_getopt(varargin, 'weight'));

% convert the yes/no arguments to the corresponding logical values
fixedori       = istrue(fixedori);
keepcsd        = istrue(keepcsd);  % see below
keepfilter     = istrue(keepfilter);
keepleadfield  = istrue(keepleadfield);
keepmom        = istrue(keepmom);
projectnoise   = istrue(projectnoise);
realfilter     = istrue(realfilter);

if ~isequal(weightnorm, 'no')
  ft_error('weight normalization is not supported');
end

if ~keepcsd
  ft_warning('setting keepcsd to ''yes'', overruling specified option');
  keepcsd = true; % this needs to be true by definition
end

% flags to avoid calling isfield repeatedly in the loop over grid positions (saves a lot of time)
hasmom        = isfield(sourcemodel, 'mom');
hasleadfield  = isfield(sourcemodel, 'leadfield');
hasfilter     = isfield(sourcemodel, 'filter');

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% find the dipole positions that are inside/outside the brain
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if ~isfield(sourcemodel, 'inside')
  if hasfilter
    sourcemodel.inside = ~cellfun(@isempty, sourcemodel.filter);
  elseif hasleadfield
    sourcemodel.inside = ~cellfun(@isempty, sourcemodel.leadfield);
  else
    sourcemodel.inside = ft_inside_headmodel(sourcemodel.pos, headmodel);
  end
end

% convert to logical representation
sourcemodel = fixinside(sourcemodel);

% keep the original details on inside and outside positions
originside = sourcemodel.inside;
origpos    = sourcemodel.pos;

% select only the dipole positions inside the brain for scanning
sourcemodel.pos    = sourcemodel.pos(originside,:);
sourcemodel.inside = true(size(sourcemodel.pos,1),1);

if hasmom
  sourcemodel.mom = sourcemodel.mom(:, originside);
end

if hasfilter
  ft_info('using precomputed filters\n');
  sourcemodel.filter = sourcemodel.filter(originside);
elseif hasleadfield
  ft_info('using precomputed leadfields\n');
  sourcemodel.leadfield = sourcemodel.leadfield(originside);
else
  ft_info('computing forward model on the fly\n');
end

if ~isempty(refdip)
  rf = ft_compute_leadfield(refdip, sens, headmodel, leadfieldopt{:});
else
  rf = [];
end

if ~isempty(supdip)
  sf = ft_compute_leadfield(supdip, sens, headmodel, leadfieldopt{:});
else
  sf = [];
end

% sanity check
if (~isempty(rf) || ~isempty(sf)) && hasfilter
  ft_error('precomputed filters cannot be used in combination with a refdip or supdip')
end

megchan  = setdiff(1:size(C,1), [refchan supchan]);
Nrefchan = length(refchan);
Nsupchan = length(supchan);
Nmegchan = length(megchan);
Cmeg     = C(megchan,megchan);   %  the filter uses the csd between all MEG channels

% it is difficult to give a quantitative estimate of lambda, therefore also
% support relative (percentage) measure that can be specified as string (e.g. '10%')
% the converted value needs to be passed on to ft_inv
lambda = ft_getopt(invopt, 'lambda');
if ~isempty(lambda) && ischar(lambda) && lambda(end)=='%'
  ratio  = sscanf(lambda, '%f%%');
  ratio  = ratio/100;
  lambda = ratio * trace(C)/size(C,1);
  invopt = ft_setopt(invopt, 'lambda', lambda);
end

if projectnoise
  % estimate the noise level in the covariance matrix by the smallest singular (non-zero) value
  noise = svd(Cmeg);
  noise = noise(rank(Cmeg));
  % estimated noise floor is equal to or higher than a numeric lambda
  noise = max(noise, lambda);
end

if realfilter
  % construct the filter only on the real part of the CSD matrix, i.e. filter is real
  invCmeg = ft_inv(real(Cmeg), invopt{:});
else
  % construct the filter on the complex CSD matrix, i.e. filter contains imaginary component as well
  % this results in a phase rotation of the channel data if the filter is applied to the data
  invCmeg = ft_inv(Cmeg, invopt{:});
end

ft_progress('init', feedback, 'scanning grid');
for i=1:size(sourcemodel.pos,1)
  ft_progress(i/size(sourcemodel.pos,1), 'scanning grid %d/%d\n', i, size(sourcemodel.pos,1));

  if hasfilter
    % precomputed filter is provided, the leadfield is not needed
  elseif hasleadfield && hasmom && size(sourcemodel.mom, 1)==size(sourcemodel.leadfield{i}, 2)
    % reuse the leadfield that was previously computed and project
    lf = sourcemodel.leadfield{i} * sourcemodel.mom(:,i);
  elseif  hasleadfield &&  hasmom
    % reuse the leadfield that was previously computed but don't project
    lf = sourcemodel.leadfield{i};
  elseif  hasleadfield && ~hasmom
    % reuse the leadfield that was previously computed
    lf = sourcemodel.leadfield{i};
  elseif ~hasleadfield &&  hasmom
    % compute the leadfield for a fixed dipole orientation
    lf = ft_compute_leadfield(sourcemodel.pos(i,:), sens, headmodel, leadfieldopt{:}) * sourcemodel.mom(:,i);
  else
    % compute the leadfield
    lf = ft_compute_leadfield(sourcemodel.pos(i,:), sens, headmodel, leadfieldopt{:});
  end

  % determine the dimensionality of the source (usually 3, or 6 for a dipole pair)
  if hasfilter
    sourcedim = size(sourcemodel.filter{i},1);
  else
    % concatenate scandip, refdip and supdip
    lfa = [lf rf sf];
    sourcedim = size(lfa,2);
  end

  if fixedori
    if isempty(refdip) && isempty(supdip) && isempty(refchan) && isempty(supchan)
      % compute the leadfield for the optimal dipole orientation
      % subsequently the leadfield for only that dipole orientation will
      % be used for the final filter computation
      if hasfilter && size(sourcemodel.filter{i},1)==1
        % nothing to do
        ft_warning('Ignoring ''fixedori''. The fixedori option is supported only if there is ONE dipole for location.')
      else
        if hasfilter && size(sourcemodel.filter{i},1)~=1
          filt = sourcemodel.filter{i};
        else
          filt = pinv(lfa' * invCmeg * lfa) * lfa' * invCmeg;
        end
        [u, s, v] = svd(real(filt * Cmeg * ctranspose(filt)));
        maxpowori = u(:,1);
        if numel(s)>1
          eta = s(1,1)./s(2,2);
        else
          eta = nan;
        end
        lfa  = lfa * maxpowori;
        estimate.ori{i} = maxpowori;
        estimate.eta(i) = eta;
        % update the number of dipole components
        sourcedim = size(lfa,2);
      end
    else
      ft_warning('Ignoring ''fixedori''. The fixedori option is supported only if there is ONE dipole for location.')
    end
  end

  if hasfilter
    % use the provided filter
    filt = sourcemodel.filter{i};
  else
    % construct the spatial filter
    filt = pinv(lfa' * invCmeg * lfa) * lfa' * invCmeg;                % use PINV/SVD to cover rank deficient leadfield
  end

  % concatenate the source filters with the channel filters
  filtn = zeros(sourcedim+Nrefchan+Nsupchan, Nmegchan+Nrefchan+Nsupchan);
  % this part of the filter relates to the sources
  filtn(1:sourcedim,megchan) = filt;
  % this part of the filter relates to the channels
  filtn((sourcedim+1):end,setdiff(1:(Nmegchan+Nrefchan+Nsupchan), megchan)) = eye(Nrefchan+Nsupchan);
  filt = filtn;
  clear filtn

  if keepcsd
    estimate.csd{i,1} = filt * C * ctranspose(filt);
  end
  if projectnoise
    estimate.noisecsd{i,1} = noise * (filt * ctranspose(filt));
  end
  if keepmom && ~isempty(dat)
    estimate.mom{i,1} = filt * dat;
  end
  if keepfilter
    estimate.filter{i,1} = filt;
  end
  if keepleadfield && needleadfield
    estimate.leadfield{i,1} = lf;
  end

  % remember how all components in the output csd should be interpreted
  %scandiplabel = repmat({'scandip'}, 1, size(lf, 2));    % based on last leadfield
  scandiplabel = repmat({'scandip'}, 1, size(filt, 1)-size(rf, 2)-size(sf, 2)-Nrefchan-Nsupchan); % robust if lf does not exist
  refdiplabel  = repmat({'refdip'},  1, size(rf, 2));
  supdiplabel  = repmat({'supdip'},  1, size(sf, 2));
  refchanlabel = repmat({'refchan'}, 1, Nrefchan);
  supchanlabel = repmat({'supchan'}, 1, Nsupchan);
  % concatenate all the labels
  estimate.csdlabel{i,1} = [scandiplabel refdiplabel supdiplabel refchanlabel supchanlabel];

end % for each dipole position
ft_progress('close');

% wrap it all up, prepare the complete output
estimate.inside  = originside;
estimate.pos     = origpos;

fnames_cell   = {'leadfield' 'filter' 'ori' 'csd' 'noisecsd' 'subspace' 'mom' 'csdlabel'};
for k = 1:numel(fnames_cell)
  if isfield(estimate, fnames_cell{k})
    estimate.(fnames_cell{k})( originside) = estimate.(fnames_cell{k});
    estimate.(fnames_cell{k})(~originside) = {[]};
  end
end

fnames_scalar = {'pow' 'noise' 'eta' 'coh'};
for k = 1:numel(fnames_scalar)
  if isfield(estimate, fnames_scalar{k})
    estimate.(fnames_scalar{k})( originside) = estimate.(fnames_scalar{k});
    estimate.(fnames_scalar{k})(~originside) = nan;
  end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% helper function to compute the pseudo inverse. This is the same as the
% standard MATLAB function, except that the default tolerance is twice as
% high.
%   Copyright 1984-2004 The MathWorks, Inc.
%   $Revision$  $Date: 2009/01/07 13:12:03 $
%   default tolerance increased by factor 2 (Robert Oostenveld, 7 Feb 2004)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function X = pinv(A,varargin)
[m,n] = size(A);
if n > m
  X = pinv(A',varargin{:})';
else
  [U,S,V] = svd(A,0);
  if m > 1, s = diag(S);
  elseif m == 1, s = S(1);
  else s = 0;
  end
  if nargin == 2
    tol = varargin{1};
  else
    tol = 10 * max(m,n) * max(s) * eps;
  end
  r = sum(s > tol);
  if (r == 0)
    X = zeros(size(A'),class(A));
  else
    s = diag(ones(r,1)./s(1:r));
    X = V(:,1:r)*s*U(:,1:r)';
  end
end


function fig_handle = montage(image_obj, varargin)
% Create a montage of an image_vector (or statistic_image or fmri_data)
% object, on top of a standard anatomical underlay.
% - Takes optional inputs to fmridisplay.addblobs (see help for options)
% - Max 4 images in object. Use get_wh_image to select images from object if needed.
%
% *Usage:
% ::
%
%    [fig_handle or o2 fmridisp object] = montage(image_obj, [optional arguments])
%
% :Optional inputs:
%   **fmridisplay:**
%        for fmridisplay object style montage [default]
%
%   **scnmontage:**
%        for circa 2008-style SCN lab montage for each image vector
%
% :Examples:
% ::
%
%    o2 = montage(mask);
%
%    o2 = montage(dat, 'trans');
%    o2 = montage(dat, 'trans', 'color', [1 0 0]);
%    o2 = montage(dat, 'trans', 'color', [1 0 0], 'transvalue', .4);
%    o2 = montage(dat, 'trans', 'maxcolor', [1 .3 0], 'mincolor', [.5 0 1]);
%    o2 = montage(dat, 'trans', 'mincolor', [.5 0 1], 'transvalue', .5);
%
%    Options for canlab_results_fmridisplay are also passed forward, so that
%    different named montage types can be used.  E.g.,:
%
%    o2 = montage(t, 'trans', 'full');
%
% Set all color maps to the same range:
% o2 = montage(dat, 'trans', 'mincolor', [.5 0 1], 'transvalue', .7, 'cmaprange', [0 3]);

meth = 'fmridisplay';
% montagetype = 'compact2';  % default. This is passed into canlab_results_fmridisplay

for i = 1:length(varargin)
    if ischar(varargin{i})
        switch varargin{i}
            case 'scnmontage', meth = 'scnmontage';

            case {'trans', 'color' 'maxcolor', 'mincolor', 'transvalue', 'cmaprange', 'full', 'compact2' 'noverbose', 'indexmap'}
                % ignore these - passed through

            otherwise, warning(['Unknown input string option:' varargin{i}]);
        end
    end
end

% number of images (cols)
n = size(image_obj.dat, 2);

switch meth
    case 'fmridisplay'

        if n > 4
            disp('Warning: Showing first 4 images in data object only.');
            n = 4;
        end

        % r = region(image_obj);

        if n > 1
            do_multirow = true;
            o2 = canlab_results_fmridisplay([], 'noblobs', 'nooutline', 'multirow', n, varargin{:});

            % scale so all maps are on same color scale
            [~, cmaprange] = get_data_range(image_obj);

        else
            do_multirow = false;
            o2 = canlab_results_fmridisplay([], 'noblobs', 'nooutline', varargin{:}); % pass forward args.
        end

        montage_indx = 1:2:2*n;

        for i = 1:n

            obj = get_wh_image(image_obj, i);

            if do_multirow % plot only on montages for this image

                % add title - new in 2021, so use try...catch for now
                if isa(image_obj, 'statistic_image') && ~isempty(image_obj.image_labels)
                    try
                        o2 = title_montage(o2, montage_indx(i)+1, image_obj.image_labels{i});
                    catch
                        disp('Problem displaying title montage for statistic_image object');
                    end
                end

                o2 = addblobs(o2, region(obj, 'noverbose'), 'cmaprange', cmaprange, 'nooutline', varargin{:}, 'wh_montages', [montage_indx(i) montage_indx(i)+1]);

            else % just one image, plot on all montages

                % add title - new in 2021, so use try...catch for now
                if isa(image_obj, 'statistic_image') && ~isempty(image_obj.image_labels)
                    try
                        o2 = title_montage(o2, 5, image_obj.image_labels{1});
                    catch
                        disp('Problem displaying title montage for statistic_image object');
                    end
                end

                o2 = addblobs(o2, region(obj, 'noverbose'), 'nooutline', varargin{:});

            end

            drawnow

        end

        if ~do_multirow

            % Plot legend only for single-row, otherwise obscures some images

            o2 = legend(o2, varargin{:});  % pass through "noverbose" option

        end

        fig_handle = o2;
        clear o2

    case 'scnmontage'

        overlay = which('SPM8_colin27T1_seg.img');

        cl = cell(1, n);
        fig_handle = zeros(1, n);

        for i = 1:n

            % data from this image
            dat = image_obj.dat(:, i);

            % top and bottom 10%
            %dat(dat > prctile(dat, 10) & dat < prctile(dat, 90)) = 0;

            cl{i} = iimg_indx2clusters(dat, image_obj.volInfo);

            fig_handle(i) = montage_clusters(overlay, cl{i}, [2 2]);

            set(fig_handle, 'Name', sprintf('Montage %3.0f', i), 'Tag', sprintf('Montage %3.0f', i))

        end

    otherwise, warning(['Unknown input string option:' varargin{i}]);

end % switch

end % function

function [datvec, clim] = get_data_range(obj)
% see same function in render_on_surface, similar in render_blobs

clim = [];

if isa(obj, 'statistic_image')

    sig = logical(obj.sig);
    dat = obj.dat(sig);

else

    wh = obj.dat ~= 0 & ~isnan(obj.dat);
    dat = obj.dat(wh);

end

datvec = dat(:);

if any(isinf(datvec))
    warning('Some image values are Inf. Expect erratic behavior/errors.');
    whinf = isinf(datvec);
    datvec(whinf) = sign(datvec(whinf)) .* max(abs(datvec(~whinf)));
end

if isempty(clim)

    %clim = [min(datvec) max(datvec)];  % clim: data values for min and max, should become min/max colors

    if any(datvec < 0) && any(datvec > 0) % split colormap

        clim = double([prctile(datvec(datvec < 0), 10) prctile(datvec(datvec > 0), 90)]); % Match defaults for montage in render_blobs

    else
        % may need adjustment
        clim = [min(datvec) max(datvec)];

    end

    % if no variance, we have constant data values - special case.
    % reducing lower clim(1) will effectively map all data to max color value
    if abs(diff(clim)) < 100 * eps
        clim(1) = clim(2) - 1;
    end

end

end % function


function model = add_head_parts(model, X, num_parts, hi_res_size, low_res_size, a)
% Add subparts to the head part
%   model = add_head_parts(model, X, num_parts, hi_res_size, low_res_size, a)
%
% Return value
%   model           Updated person grammar model
%
% Arguments
%   model           Person grammar model
%   X               X is the person grammar's "head" symbol
%   num_parts       Number of subparts to add
%   hi_res_size     Size of high resolution subparts
%   low_res_size    Size of low resolution subparts
%   a               Subpart filter weight scale (used to reduce the influence
%                   of newly initialized parts that are added to the model)

% AUTORIGHTS
% -------------------------------------------------------
% Copyright (C) 2011-2012 Ross Girshick
%
% This file is part of the voc-releaseX code
% (http://people.cs.uchicago.edu/~rbg/latent/)
% and is available under the terms of an MIT-like license
% provided in COPYING. Please retain this notice and
% COPYING if you use this file (or a portion of it) in
% your project.
% -------------------------------------------------------

% Terminal symbols for the two head filter subtypes
X_lf  = model.rules{X}(1).rhs(1);
X_rf  = model.rules{X}(2).rhs(1);
fid   = model.symbols(X_lf).filter;
% Add high resolution subparts
model = model_add_parts(model, X, 1, 2, fid, num_parts, hi_res_size, 1, a);

% Add two new rules: X -> X_lf | X_rf
% so that we can add low resolution parts to these
[model, rule] = model_add_struct_rule(model, X, X_lf, {[0 0 0]});
[model, rule] = model_add_struct_rule(model, X, X_rf, {[0 0 0]}, 'mirror_rule', rule);
model.blocks(rule.offset.blocklabel).learn = 0;
% Add low resolution subparts
model = model_add_parts(model, X, 3, 4, fid, num_parts, low_res_size, 0, a);
% Set the scale score parameters so that the low resolution parts have
% very low scores above the bottom octave of the pyramid
% (i.e., revent these rules from firing above the bottom octave)
model.blocks(model.rules{X}(3).loc.blocklabel).w = [0; -1000; -1000];
model.blocks(model.rules{X}(4).loc.blocklabel).w = [0; -1000; -1000];


classdef ImageRegr < Algorithms.CDAlg
    methods
        function obj = ImageRegr()
            obj@Algorithms.CDAlg('Image Regression', '')
        end
        [DI, coeffs] = detectChange(obj, ~, ~);
    end
end


classdef prtUiDataSetClassExploreWidgetTabPlotOptions < prtUiDataSetClassExploreWidgetTab

    properties

        titleStr = 'Plot Options';

        possibleMarkers = {'o','s','^','d','v','x','.','<','>','p','h'};

        dataCell
        handles
    end

    methods
        function self = prtUiDataSetClassExploreWidgetTabPlotOptions(varargin)
            self = self@prtUiDataSetClassExploreWidgetTab(varargin{:});

            init(self);
        end

        function init(self)

            self.handles.table = uitable('parent',self.managedHandle,...
                'units','normalized','position',[0 0 1 1]); % Dummy position

            %self.handles.jScrollPane = findjobj(self.handles.table);
            %self.handles.jTable = self.handles.jScrollPane.getViewport.getView;

            % uY, visible, legend string, shape, color, edgeColor, markerSize, edgeSize

            initData(self);

            columnFormat = {'char', 'logical', self.possibleMarkers,'char','char','numeric','numeric'};
            columnHeadings = {'String','Visible','Shape','Color','Edge Color',' Size','Edge Size'};

            self.handles.uicontextmenu = uicontextmenu;
            self.handles.uicontextmenuReset = uimenu(self.handles.uicontextmenu, 'Label', 'reset', 'Callback', @(h,e)self.reset);

            % Set the actual data in the cell
            set(self.handles.table,...
                'columnName',columnHeadings,...
                'columnFormat',columnFormat,...
                'RearrangeableColumns','on',...
                'RowName',{},...cat(1,num2cell(self.widget.plotManager.dataSet.uniqueClasses(:)),{nan}),...
                'TooltipString','Plotting Options',...
                'ColumnEditable',true(1,size(self.dataCell,2)),...
                'CellEditCallback',@(h,e)self.tableCellEditCallback(h,e),...
                'UIContextMenu',self.handles.uicontextmenu);

            %javaaddpath(fullfile(prtRoot,'+prtExternal','+ColorCell'));

            %self.handles.jTable.setModel(javax.swing.table.DefaultTableModel(self.dataCell,columnHeadings))
            %self.handles.jTable.getColumnModel.getColumn(3).setCellRenderer(ColorCellRenderer);
            %self.handles.jTable.getColumnModel.getColumn(3).setCellEditor(ColorCellEditor);

            %self.handles.jTable.getColumnModel.getColumn(4).setCellRenderer(ColorCellRenderer);
            %self.handles.jTable.getColumnModel.getColumn(4).setCellEditor(ColorCellEditor);

            % Set the column widths to take up the whole area
            %self.handles.jTable.setAutoResizeMode(self.handles.jTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS);
        end

        function reset(self)
            self.widget.plotManager.setDataSetDependentProperties();
            initData(self);
        end

        function initData(self)

            uYs = self.widget.plotManager.dataSet.uniqueClasses;

            data = cell(length(uYs)+1, 7);
            data(:,1) = cat(1,self.widget.plotManager.legendStrings,{self.widget.plotManager.legendStringUnlabeled});
            data(:,2) = num2cell(logical(cat(1, self.widget.plotManager.isVisible(:), self.widget.plotManager.isVisibleUnlabeled)));
            data(:,3) = cat(1,num2cell(self.widget.plotManager.markers(:)),{self.widget.plotManager.markerUnlabeled});

            for iClass = 1:length(uYs)

                cColor = max(min(round(self.widget.plotManager.colors(iClass,:)*255),255),0);
                cEdgeColor = max(min(round(self.widget.plotManager.edgeColors(iClass,:)*255),255),0);

                data{iClass,4} = sprintf('%d,%d,%d',cColor(1), cColor(2), cColor(3));
                data{iClass,5} = sprintf('%d,%d,%d',cEdgeColor(1), cEdgeColor(2), cEdgeColor(3));
            end
            cColor = max(min(round(self.widget.plotManager.colorUnlabeled*255),255),0);
            cEdgeColor = max(min(round(self.widget.plotManager.edgeColorUnlabeled*255),255),0);

            data{end,4} = sprintf('%d,%d,%d',cColor(1), cColor(2), cColor(3));
            data{end,5} = sprintf('%d,%d,%d',cEdgeColor(1), cEdgeColor(2), cEdgeColor(3));

            data(:,6) = num2cell(cat(1,self.widget.plotManager.markerSizes(:), self.widget.plotManager.markerSizeUnlabeled));
            data(:,7) = num2cell(cat(1,self.widget.plotManager.markerLineWidths(:), self.widget.plotManager.markerLineWidthUnlabeled));

            self.dataCell = data;

            set(self.handles.table,'data',self.dataCell);
        end
        function tableCellEditCallback(self, h, e)

            inds = e.Indices;

            switch inds(2)
                case 1
                    changeLegend(self, h, e);
                case 2
                    changeVisible(self, h, e);
                case 3
                    changeMarkers(self, h, e);
                case 4
                    changeColors(self, h, e);
                case 5
                    changeEdgeColors(self, h, e);
                case 6
                    changeMarkerSize(self, h, e);
                case 7
                    changeMarkerEdgeSize(self, h, e)
            end
        end

        function changeVisible(self, h, e)
            newValue = logical(e.NewData);

            cData = self.dataCell;
            if e.Indices(1) < size(cData,1)
                self.widget.plotManager.isVisible(e.Indices(1)) = newValue;
            else
                self.widget.plotManager.isVisibleUnlabeled = newValue;
            end

            self.widget.plotManager.legendRefresh()

            self.dataCell{e.Indices(1), e.Indices(2)} = newValue;
        end
        function changeLegend(self, h, e)
            if e.Indices(1) < size(self.dataCell,1)
                self.widget.plotManager.legendStrings{e.Indices(1)} = e.NewData;
            else
                self.widget.plotManager.legendStringUnlabeled = e.NewData;
            end

            self.dataCell{e.Indices(1), e.Indices(2)} = e.NewData;
        end
        function changeMarkers(self, h, e)
            if e.Indices(1) < size(self.dataCell,1)
                self.widget.plotManager.markers(e.Indices(1)) = e.NewData;
            else
                self.widget.plotManager.markerUnlabeled = e.NewData;
            end

            self.dataCell{e.Indices(1), e.Indices(2)} = e.NewData;
        end
        function changeColors(self, h, e)
            [err, color] = testColorValueString(self, e.NewData);
            if err
                set(self.handles.table,'data',self.dataCell); % Keep what we had
                return
            end

            if e.Indices(1) < size(self.dataCell,1)
                self.widget.plotManager.colors(e.Indices(1),:) = color;
            else
                self.widget.plotManager.colorUnlabeled = color;
            end

            self.dataCell{e.Indices(1), e.Indices(2)} = e.NewData;
        end
        function changeEdgeColors(self, h, e)
            [err, color] = testColorValueString(self, e.NewData);
            if err
                set(self.handles.table,'data',self.dataCell); % Keep what we had
                return
            end

            if e.Indices(1) < size(self.dataCell,1)
                self.widget.plotManager.edgeColors(e.Indices(1),:) = color;
            else
                self.widget.plotManager.edgeColorUnlabeled = color;
            end

            self.dataCell{e.Indices(1), e.Indices(2)} = e.NewData;
        end
        function [err, color] = testColorValueString(self, val)

            err = true;
            color = [];
            try
                commaLocs = find(val==',');
                if length(commaLocs) ~= 2
                    return
                end

                color = zeros(1,3);
                color(1) = str2double(val(1:commaLocs(1)-1));
                color(2) = str2double(val((commaLocs(1)+1):(commaLocs(2)-1)));
                color(3) = str2double(val((commaLocs(2)+1):end));

                color = color/255;

                if any(color < 0) || any(color > 1) || any(isnan(color))
                    color = [];
                    return
                end
                err = false;
            catch
                err = true;
                color = [];
            end
        end

        function changeMarkerSize(self, h, e)
            try
                assert(e.NewData > 0);
                if e.Indices(1) < size(self.dataCell,1)
                    self.widget.plotManager.markerSizes(e.Indices(1)) = e.NewData;
                else
                    self.widget.plotManager.markerSizeUnlabeled = e.NewData;
                end

                self.dataCell{e.Indices(1), e.Indices(2)} = e.NewData;

            catch %#ok<CTCH>
                set(self.handles.table,'data',self.dataCell);
            end
        end
        function changeMarkerEdgeSize(self, h, e)
            try
                assert(e.NewData > 0);
                if e.Indices(1) < size(self.dataCell,1)
                    self.widget.plotManager.markerLineWidths(e.Indices(1)) = e.NewData;
                else
                    self.widget.plotManager.markerLineWidthUnlabeled = e.NewData;
                end

                self.dataCell{e.Indices(1), e.Indices(2)} = e.NewData;

            catch %#ok<CTCH>
                set(self.handles.table,'data',self.dataCell);
            end
        end
    end
end


function this = subsasgn(this, selector, value)
%SUBSASGN   Modify parameters of BA optical flow algorithm
%   THIS = SUBSASGN(THIS, SEL, VAL) sets parameter of a HS optical
%   flow algorithm THIS using given selector SEL to value VAL.  The
%   modified object is returned.
%   Available selectors:
%     - ".optical_flow":   Flow base object
%     - ".pyramid_levels": Levels of the image pyramid
%     - ".warping_mode":   'forward' for forward warping and 'backward'
%                          for backward warping
%     - ".solver":         Selector for the linear equation solver
%                          ('backslash' for the builtin solver and 'sor'
%                          for a MEX-based SOR solver)
%     - ".max_iters":      Maximum number of iterations at each pyramid
%                          level
%     - ".limit_update":   Flag whether to restrict the incremental flow
%                          at each level to [-1, 1]
%
%   This is a member function of the class 'ba_optical_flow'.

%   Author: Deqing Sun, Department of Computer Science, Brown University
%   Contact: dqsun@cs.brown.edu
%   $Date: 2007-11-30 $
%   $Revision: $
%
% Copyright 2007-2010, Brown University, Providence, RI. USA
%
%                          All Rights Reserved
%
% All commercial use of this software, whether direct or indirect, is
% strictly prohibited including, without limitation, incorporation into in
% a commercial product, use in a commercial service, or production of other
% artifacts for commercial purposes.
%
% Permission to use, copy, modify, and distribute this software and its
% documentation for research purposes is hereby granted without fee,
% provided that the above copyright notice appears in all copies and that
% both that copyright notice and this permission notice appear in
% supporting documentation, and that the name of the author and Brown
% University not be used in advertising or publicity pertaining to
% distribution of the software without specific, written prior permission.
%
% For commercial uses contact the Technology Venture Office of Brown University
%
% THE AUTHOR AND BROWN UNIVERSITY DISCLAIM ALL WARRANTIES WITH REGARD TO
% THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
% FITNESS FOR ANY PARTICULAR PURPOSE.  IN NO EVENT SHALL THE AUTHOR OR
% BROWN UNIVERSITY BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
% DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
% PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
% ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
% THIS SOFTWARE.

  % Allow full access to all fields of the structure
  this = builtin('subsasgn', this, selector, value);


function svm = svmRemove(svm, indices)
% svm = svmRemove(svm, indices)
% SUPPORT VECTOR MACHINE - REMOVE
% ---------------------------------------------------------
% Removes the specified condition from the SVM structure, patching up any
% holes it leaves in the order of the condition numbers.
%
% INPUTS
%   svm - Structure generated by svmInit.
%   indices - Vector of indices to remove from SVM structure.
%
% OUTPUTS
%   svm - Structure with specified indices removed.
%
% USAGE
%   After generating an SVM structure, removing conditions 2 and 3.
%       svm = svmInit(...);
%       svm = svmRemove(svm, [2 3]);
%
% See also SVMINIT, SVMRUN, SVMEXPORTMAP, SVMBOOTSTRAP, SVMRELABEL,
% SVMRUNOPTIONS, SLINIT.
%
% renobowen@gmail.com [2010]
%
    keepIndices = ~ismember(svm.group, indices);
    svm.run = svm.run(keepIndices, :);
    svm.group = svm.group(keepIndices, :);
    svm.trial = svm.trial(keepIndices, :);
    svm.data = svm.data(keepIndices, :);

    combineInto = min(svm.group);
    svm = svmRelabel(svm, [combineInto indices], svm.grouplabel{combineInto});
end