function varargout = process_cohere2( varargin )
% PROCESS_COHERE2: Compute the coherence between one signal in one file, and all the signals in another file.
%
% USAGE:  OutputFiles = process_cohere2('Run', sProcess, sInputA, sInputB)

% @=============================================================================
% 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, 2012-2020; Hossein Shahabi, 2019-2020

eval(macro_method);
end

%% ===== GET DESCRIPTION =====
function sProcess = GetDescription() %#ok<DEFNU>
    % Description the process
    sProcess.Comment     = 'Coherence AxB [Deprecated]';
    sProcess.Category    = 'Custom';
    sProcess.SubGroup    = 'Connectivity';
    sProcess.Index       = 652;
    sProcess.Description = 'https://neuroimage.usc.edu/brainstorm/Tutorials/Connectivity';
    % Definition of the input accepted by this process
    sProcess.InputTypes  = {'data', 'results', 'matrix'};
    sProcess.OutputTypes = {'timefreq', 'timefreq', 'timefreq'};
    sProcess.nInputs     = 2;
    sProcess.nMinFiles   = 1;
    sProcess.isPaired    = 1;

    % === CONNECT INPUT
    sProcess = process_corr2('DefineConnectOptions', sProcess);
    % === REMOVE EVOKED REPONSE
    sProcess.options.removeevoked.Comment = 'Remove evoked response from each trial';
    sProcess.options.removeevoked.Type    = 'checkbox';
    sProcess.options.removeevoked.Value   = 0;
    sProcess.options.removeevoked.Group   = 'input';
    % === COHERENCE METHOD
    sProcess.options.cohmeasure.Comment = {...
        ['Magnitude-squared Coherence
' ...
        '|C|^2 = |Gxy|^2/(Gxx*Gyy)'], ...
        ['Imaginary Coherence (2019)
' ...
        'IC    = |imag(C)|'], ...
        ['Lagged Coherence (2019)
' ...
        'LC    = |imag(C)|/sqrt(1-real(C)^2)'], ...
        [' Imaginary Coherence (before 2019)
' ...
        ' IC    = imag(C)^2 / (1-real(C)^2) ']; ...
        'mscohere', 'icohere2019','lcohere2019', 'icohere'};
    sProcess.options.cohmeasure.Type    = 'radio_label';
    sProcess.options.cohmeasure.Value   = 'mscohere';
    % === Overlap
    sProcess.options.overlap.Comment = 'Overlap for PSD estimation:' ;
    sProcess.options.overlap.Type    = 'value';
    sProcess.options.overlap.Value   = {50, '%', []};
    % === MAX FREQUENCY RESOLUTION
    sProcess.options.maxfreqres.Comment = 'Maximum frequency resolution:';
    sProcess.options.maxfreqres.Type    = 'value';
    sProcess.options.maxfreqres.Value   = {2,'Hz',2};
    % === HIGHEST FREQUENCY OF INTEREST
    sProcess.options.maxfreq.Comment = 'Highest frequency of interest:';
    sProcess.options.maxfreq.Type    = 'value';
    sProcess.options.maxfreq.Value   = {60,'Hz',2};
    % === OUTPUT MODE
    sProcess.options.outputmode.Comment = {'Save individual results (one file per input file)', 'Concatenate input files before processing (one file)', 'Save average connectivity matrix (one file)'};
    sProcess.options.outputmode.Type    = 'radio';
    sProcess.options.outputmode.Value   = 1;
    sProcess.options.outputmode.Group   = 'output';
end

%% ===== FORMAT COMMENT =====
function Comment = FormatComment(sProcess) %#ok<DEFNU>
    Comment = sProcess.Comment;
end

%% ===== RUN =====
function OutputFiles = Run(sProcess, sInputA, sInputB) %#ok<DEFNU>
    % Input options
    OPTIONS = process_corr2('GetConnectOptions', sProcess, sInputA, sInputB);
    if isempty(OPTIONS)
        OutputFiles = {};
        return
    end

    % Metric options
    OPTIONS.Method = 'cohere';
    OPTIONS.RemoveEvoked  = sProcess.options.removeevoked.Value;
    OPTIONS.MaxFreqRes    = sProcess.options.maxfreqres.Value{1};
    OPTIONS.MaxFreq       = sProcess.options.maxfreq.Value{1};
    OPTIONS.CohOverlap    = 0.50;  % First pre-define the overlap
    OPTIONS.pThresh       = 0.05;
    OPTIONS.CohMeasure    = sProcess.options.cohmeasure.Value;

    % Change the overlap if it is specified
    if isfield(sProcess.options, 'overlap') && isfield(sProcess.options.overlap, 'Value') && ...
       iscell(sProcess.options.overlap.Value) && ~isempty(sProcess.options.overlap.Value) && ~isempty(sProcess.options.overlap.Value{1})
       OPTIONS.CohOverlap = sProcess.options.overlap.Value{1}/100 ;
    end

    % Compute metric
    OutputFiles = bst_connectivity({sInputA.FileName}, {sInputB.FileName}, OPTIONS);
end


function region = p24_region ( )

%*****************************************************************************80
%
%% P24_REGION returns the name of the integration region for problem 24.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    18 March 2007
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, string REGION, the name of the integration region.
%
  region = 'box';

  return
end


% unique_bc - unique backward compatible with Matlab versions prior to 2013a

% Copyright (C) 2013 Arnaud Delorme
%
% 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.

function [C,IA,IB] = unique_bc(A,varargin)

errorFlag = error_bc;

v = version;
indp = find(v == '.');
v = str2num(v(1:indp(2)-1));
if v > 7.19, v = floor(v) + rem(v,1)/10; end

if nargin > 2
    ind = strmatch('legacy', varargin);
    if ~isempty(ind)
        varargin(ind) = [];
    end
end

if v >= 7.14
    [C,IA,IB] = unique(A,varargin{:},'legacy');
    if errorFlag
        [C2,IA2] = unique(A,varargin{:});
        if ~isequal(C, C2) || ~isequal(IA, IA2) || ~isequal(IB, IB2)
            warning('backward compatibility issue with call to unique function');
        end
    end
else
    [C,IA,IB] = unique(A,varargin{:});
end


function data_num = p04_data_num ( )

%*****************************************************************************80
%
%% P04_DATA_NUM returns the dimension of the data vector for problem 4.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    12 August 2011
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, integer DATA_NUM, the dimension of the data vector.
%
  data_num = 13;

  return
end


% update the elements of a sparse matrix .
% sparse_update(S, v, length(v));
% Note: the following must be hold or the MATLAB crashes
%     nnz(S) == length(v).
% TODO: write dimensionality check in c.


%% The SCNLOBJECT cookbook
% This cookbook is designed to familiarize yourself with the scnlobjects used within waveform. There's not really all that much to them, so there'll not be much to this, either.

%% Properties
% Scnlobjects are comprised of only four fields:
%%
%
% * Station
% * Channel
% * Network
% * Location

%%
% STATION and CHANNEL are not optional, while NETWORK and LOCATION are.

%%
% Create a series of scnls for seismic stations on Redoubt volcano
    red = scnlobject('RED','EHZ','AV','--') % full declaration
    rso = scnlobject('RSO','EHZ','AV')      % leaving out location

%%
% 3-component station, this creates rdbw as a 1x3 scnlobject
    rdbw = scnlobject('RDBW',{'BHZ','BHE','BHN'},'AV')

%% Using SET to modify a SCNLOBJECT
% use SET to create another 3 component broadband using rdbw as a template...
    rdjh = set(rdbw,'station','RDJH');

%% Grouping SCNLOBJECTS through concatenation% and finally, create something that will parse through all stations

    redstas = [red rso rdbw rdjh]
%%
% Create a couple scnls with wildcard values
% The value '*' can be entered in place of a field, so that searches can be made.

    anyehz = scnlobject('*','EHZ','*','*') % this one prints as an example...
    anybroadband = scnlobject('*',{'BHZ','BHE','BHN'},'*','*');
    anyNorthComponent = scnlobject('*',{'EHN','SHN','BHN'},'*','*');

%%
% Let's display all the variables we've got, thus far

    whos

%% Methods
% Find out what manipulations can be done with scnlobjects

    methods(redstas)

%%
% I could have typed "methods(scnlobject)", instead

%% using ISMEMBER to see if a particular locale (SCNLOBJECT) is represented
% Ismember will not only tell you if a scnlobject exists, but is also capable of telling WHERE

    [IsInList, whereInList] = ismember(rso,redstas)

%%
% ismember is sensitive to the order in which you place the scnlobjects. The size of the returned values match the size of the first argument. The previous example asks '' where can RSO be found in REDSTAS? '', while the following example essentially asks '' which REDSTAS can be found in RSO (and where)?''

    [IsInList, whereInList] = ismember(redstas,rso)

%% using ISMEMBER with wildcards
% The ismember function looks for a scnlobject in an array of scnlobjects. Lets grab the EHZ component stations using a search, then display each one

    stationsOfInterest = redstas(ismember(redstas,anyehz)) %should get 2

    for n = 1 : numel(stationsOfInterest);
        display(stationsOfInterest(n));
    end

%%
% repeat the exercise for broadband and stations... there should be 6

    mybroadbands = redstas(ismember(redstas,anybroadband));
    size(mybroadbands)

%% Use GET to see which stations we have...
% Get can also retrieve CHANNEL, NETWORK, and LOCATION information.

    get(mybroadbands,'station')

%%
% There are 3 of each because there are three components to each.

    strcat(get(mybroadbands,'station'),'|',get(mybroadbands,'channel'))

%%
% to get a vertical list, I could transpose mybroadbands using (')

    strcat( get(mybroadbands', 'station') , '|' , get(mybroadbands', 'channel') )

%% Using UNIQUE to whittle down a bunch of scnlobjects
% Assume that for some reason, you have a list of scnlobjects with some members being repeated. This may happen when you retrieve scnlobjects from a group of waveforms. You'd like to know which station/channels are actually being represented within your data set. Here's how:
%
% set up the situation as listed:
    manyscnls = [redstas, red, rso, red, redstas]
%%
% Find out which ones we have:
    unique(manyscnls)


function [TorF, vstr, rdate] = have_feature_sdpt3()
%HAVE_FEATURE_SDPT3  Detect availability/version info for SDPT3
%
%   Feature detection function implementing 'sdpt3' tag for HAVE_FEATURE
%   to detect availability/version of SDPT3 SDP solver
%   (https://github.com/sqlp/sdpt3)
%
%   See also HAVE_FEATURE, SDPT3.

%   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.

TorF = exist('sdpt3','file') == 2;
vstr = '';
rdate = '';
if TorF && have_feature('evalc')
    str = evalc('help sdpt3');
    pat = 'version\s+([^\s]+).*Last Modified: ([^\n]+)\n';
    [s,e,tE,m,t] = regexp(str, pat);
    if ~isempty(t)
        vstr = t{1}{1};
        rdate = datestr(t{1}{2}, 'dd-mmm-yyyy');
    end
end


function ax_out = subplot_tight(numRows,numCols,currIdx,spacing)
% tight version of subplot, by xiuye
% FUNCTION: subplot_tight(numRow,numCol,ax_curr,spacing)
%
% INPUT:
% - numRows: number of rows
% - numCols: number of columns
% - currIdx: the index of the current selected suplot, counting
%     left to right and top to bottom, like
%     1 | 2 | 3
%     4 | 5 | 6
%     This parameter can also take a vector of several indices. The user
%     would typically specify contiguous indices, and the corresponding
%     subplots will be merged into a single axis (subplot).
% - spacing: optional vector to specify spacing parameters. Can be of length
%     1, 2, 3 or 4.
%     The order of the parameters is [frameWidth,axBorderWidth,bottomframe
%
% OUTPUT:
% - ax_out: axis handle of the current subplot axis, if output requested
%
% USAGE:
% ax_out = subplot_tight(m,n,p), as in the built-in function SUBPLOT, breaks
%     the Figure window into an m-by-n matrix of small axes, selects the
%     p-th axes for the current plot, and returns the axes handle.  The axes
%     are counted along the top row of the Figure window, then the second
%     row, etc.
%     ax_out, returns the current axis if specified [i.e. if no semicolon
%     is used, the axis info is not printed automatically].
%
% subplot_tight(m,n,P), where P is a vector, specifies an axes position
%     that covers all the subplot positions listed in P.
%
% subplot_tight(m,n,p,frameWidth), where frameWidth is a number between 0
%     and 1 (normalized to size of the full figure)that specifies all 4
%     margins of the figure.
%
% subplot_tight(m,n,p,[frameWidth,axBorderWidth]), where axBorderWidth is
%     a number between 0 and 1 (normalized to size of the full figure) that
%     specifies the margins between adjacent subplots (in all 4 directions).
%
% subplot_tight(m,n,p,[frameWidth,axBorderWidth,bottomFrameWidth]), where
%     bottomFrameWidth is a number between 0 and 1 that overwrites the
%     frameWidth value for the bottom margin of the figure.
%
% subplot_tight(m,n,p,[fWidth,aWidth,bottomFrameWidth,topFrameWidth]), where
%     topFrameWidth is a number between 0 and 1 that overwrites the
%     frameWidth value for the top margin of the figure.

%% set params
% set default (before user override)
frameWidth = 0.05;
bottomFrameWidth = frameWidth;
topFrameWidth = frameWidth;

axBorderWidth = 0.02;

% user override:
if exist('spacing','var')
    frameWidth = spacing(1);
    bottomFrameWidth = frameWidth;
    topFrameWidth = frameWidth;

    if length(spacing)>=2,
        axBorderWidth = spacing(2);
    end
    if length(spacing)>=3
        bottomFrameWidth = spacing(3);
    end
    if length(spacing)>=4
        topFrameWidth = spacing(4);
    end
end

leftFrameWidth = frameWidth;
rightFrameWidth = frameWidth;

widthCol = (1-leftFrameWidth-rightFrameWidth)/numCols;
heightRow = (1-topFrameWidth-bottomFrameWidth)/numRows;
netwidthCol = (1-leftFrameWidth-rightFrameWidth-(numCols-1)*axBorderWidth)/numCols;
netheightRow = (1-topFrameWidth-bottomFrameWidth-(numRows-1)*axBorderWidth)/numRows;

[i_col, i_row] = ind2sub([numCols,numRows],currIdx);

if length(currIdx)==1 % default
    % left, bottom, width, height
    pos1 = leftFrameWidth+(i_col-1)*widthCol;
    pos2 = 1-topFrameWidth-i_row*heightRow;
    pos3 = netwidthCol;
    pos4 = netheightRow;

else % merge "grids": assign the combined space to this axis
    left = leftFrameWidth+(i_col-1)*widthCol;
    bottom = 1-topFrameWidth-i_row*heightRow;
    right = left + netwidthCol;
    top = bottom + netheightRow;

    for i_sub = 1:length(currIdx)
        left(i_sub) = leftFrameWidth+(i_col(i_sub)-1)*widthCol;
        bottom(i_sub) = 1-topFrameWidth-i_row(i_sub)*heightRow;
        right(i_sub) = left(i_sub) + netwidthCol;
        top(i_sub) = bottom(i_sub) + netheightRow;
    end
    pos1 = min(left);
    pos2 = min(bottom);
    pos3 = max(right)-pos1;
    pos4 = max(top)-pos2;
end

%% make axis
ax = axes('Position',[pos1,pos2,pos3,pos4]);
% % subplot('Position',[pos1,pos2,pos3,pos4]);
% % small difference from using axes: subplot deletes any underlying subplots

% return identifier, if requested:
if(nargout > 0)
    ax_out = ax;
end


function writeNewtExperiment(model,metData,metSampleNames,fileName,param)
%writes out an experimental data file for an model exported to SBML and
%imported into newteditor

% version\t1.0
% name\tsample experiment data
% description\tAdenoid Cystic Carcinoma 2014 vs 2019
% color\t0\t#FFFFFF\t100\t#FF0000
% gene\t2014\t2019
% RB1\t36\t12
% TP53\t36\t72
% CDKN2A\t0\t14
% MDM2\t0\t5
% CCNE\t0\t7

[nNodes,nSamples]=size(metData);
[nMets,nRxns]=size(model.S);
if nNodes ~= nMets
    error('size(metData,1) must equal size(model.S,1)')
end

if ~exist('fileName','var')
    fileName = [pwd filesep 'newtExpData.txt'];
end

fid = fopen(fileName,'w');

if ~exist('param','var')
    param=struct;
end

if ~isfield(param,'version')
    param.version = datestr(now,30);
end

if ~isfield(param,'name')
    if isfield(model,'modelID')
        param.name = model.modelID;
    else
        param.name = 'aModel';
    end
end

if ~isfield(param,'description')
    if isfield(model,'description')
        param.description = model.description;
    else
        param.description = 'aDescription';
    end
end

% color\t0\t#FFFFFF\t100\t#FF0000
%color -100  0 #00FF00 100 #0000FF
if ~isfield(param,'color')
   param.color.minValue = -100;
   param.color.minColor = '#FF0000';
   param.color.zeroValue = 0;
   param.color.zeroColor = '#FF0000';
   param.color.maxValue =  100;
   param.color.maxColor = '#0000FF';
%    if ~isfield(param.color,'string')
%         param.color.string = [param.color.minValue '\t' param.color.minColor '\t' param.color.zeroValue '\t' param.color.zeroColor '\t' param.color.maxValue '\t' param.color.maxColor];
%    end
end

%fprintf('name\tsample experiment data\r\ndescription\tAdenoid Cystic Carcinoma 2014 vs 2019\r\nel\t2014\t2019\r\nRB1\t36\t12\r\nTP53\t36\t72\r\nCDKN2A\t0\t14\r\nMDM2\t0\t5\r\nCCNE\t0\t7\r')

%header
fprintf(fid,'%s\t%s\n','version', param.version);
fprintf(fid,'%s\t%s\n','name', param.name);
fprintf(fid,'%s\t%s\n','description', param.description);
fprintf(fid,'%s\t%i\t%s\t%i\t%s\t%i\t%s\n','color', param.color.minValue,param.color.minColor,param.color.zeroValue,param.color.zeroColor,param.color.maxValue ,param.color.maxColor);

%experiment names
fprintf(fid,'%s\t','node');
if ~exist('metSampleNames','var')
    for n=1:nSamples
        if n~=nSamples
            fprintf(fid,'%s\t',['exp' int2str(n)]);
        else
            fprintf(fid,'%s',['exp' int2str(n)]);
        end
    end
    fprintf(fid,'\n');
else
    if ischar(metSampleNames)
        metSampleNames={metSampleNames};
    end
    for n=1:nSamples
        if n~=nSamples
            fprintf(fid,'%s\t',metSampleNames{n});
        else
            fprintf(fid,'%s',metSampleNames{n});
        end
    end
    fprintf(fid,'\n');
end

%assume that the map in newt was exported via an sbml file, in which case
%the node ids are in sbml format
convertedMets = convertSBMLID(model.mets);

%experimental data
useM=0;
for i=1:nMets
    if useM
        fprintf(fid,'%s',['M_' convertedMets{i}]);
    else
        fprintf(fid,'%s\t',model.metNames{i});
    end

    for j=1:nSamples
        if j~=nSamples
            fprintf(fid,'%i\t', full(metData(i,j)));
        else
            fprintf(fid,'%i', full(metData(i,j)));
        end
    end
    fprintf(fid,'\n') ;
end

fclose(fid);


%  Inspired by a question on the dynare forum at
%  http://www.dynare.org/phpBB3/viewtopic.php?f=1&t=3206
%


function YESNO = isinterval(F)
%ISINTERVAL (overloaded)

F = flatten(F);
if isempty(F.clauses)
    YESNO = 1;
else
    YESNO = 1;
    i = 1;
    while (i<=length(F.clauses)) & YESNO
        Fi = F.clauses{i};
        YESNO =  YESNO & is(Fi.data,'interval');
        i = i+1;
    end
end


function a = transpose(a)
%TRANSPOSE    Implements  a.'  for Taylor
%
%   c = a.'
%

% written  05/21/09     S.M. Rump
%

  index = reshape(1:prod(a.size),a.size)';
  a.size = fliplr(a.size);
  a.t = a.t(:,index);


function b = hoffman_rhs ( )

%*****************************************************************************80
%
%% HOFFMAN_RHS returns the Hoffman right hand side.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    11 October 2007
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, real B(3,1), the right hand side vector.
%
  b = [ 1.0; ...
        0.0; ...
        0.0 ];

  return
end


function d = grdinfo2(file);
%GRDINFO2  Print information about a GMT grdfile (netCDF format, GMT v3 or v4)
%
% Uses NetCDF libraries to display information about a GMT grid file.
% Duplicates (some) functionality of the program grdinfo (which requires
% compilation as a mexcdf function on each architecture) using
% Matlab 2008b (and later) built-in NetCDF functionality
% instead of GMT libraries.
%
% GRDINFO2('file.grd') will display information about the GMT grid
% file 'file.grd' in a format similar to the gmt command grdinfo.
%
% D = GRDINFO('file.grd') will in addition return a vector containing
% (xmin, xmax, ymin, ymax, zmin, zmax, format, xinc, yinc). Format is
% 1 for pixel registration and 0 for grid node registration.
%
% See also GRDREAD2, GRDWRITE2

% This program is expected to work on any GMT netCDF format file,
% but it does not duplicate all the functionality of GMT's I/O
% library, so it will not work on all files supported by GMT.
% In particular, it will fail on binary format grdfiles.
% It is the responsibility of the user to determine whether this
% program is appropriate for any given task.
%
% For more information on GMT grid file formats, see:
% http://www.soest.hawaii.edu/gmt/gmt/doc/gmt/html/GMT_Docs/node70.html
% Details on Matlab's native netCDF capabilities are at:
% http://www.mathworks.com/access/helpdesk/help/techdoc/ref/netcdf.html

% GMT (Generic Mapping Tools, <http://gmt.soest.hawaii.edu>)
% was developed by Paul Wessel and Walter H. F. Smith

% Kelsey Jordahl
% Marymount Manhattan College
% http://marymount.mmm.edu/faculty/kjordahl/software.html

% Time-stamp: <Wed Jan  6 16:26:46 EST 2010>

% Version 1.1.1, 6-Jan-2010
% first released on MATLAB Central
% modification
% DB 	05/2014 	Suppress command window output

if nargin < 1,
  help(mfilename);
  return,
end

% check for appropriate Matlab version (>=7.7)
V=regexp(version,'[ \.]','split');
if (str2num(V{1})<7) | (str2num(V{1})==7 & str2num(V{2})<7),
  ver
  error('grdread2: Requires Matlab R2008b or later!');
end

ncid = netcdf.open(file, 'NC_NOWRITE');
if isempty(ncid),
  return,
end

[ndims,nvars,ngatts,unlimdimid] = netcdf.inq(ncid);

if (nvars==3),                        % new (v4) GMT netCDF grid file
%  for attnum=0:(ngatts-1),
  title=getatt_clean(ncid,'title');
  conv=getatt_clean(ncid,'Conventions');
  pixel=getatt_clean(ncid,'node_offset');
  if isempty(pixel), pixel=0; end
  desc=getatt_clean(ncid,'description');
  command=getatt_clean(ncid,'history');
  vers = getatt_clean(ncid,'GMT_version');
  xname = netcdf.getAtt(ncid,0,'long_name');
  yname = netcdf.getAtt(ncid,1,'long_name');
  zname = netcdf.getAtt(ncid,2,'long_name');
  xrange = netcdf.getAtt(ncid,0,'actual_range');
  yrange = netcdf.getAtt(ncid,1,'actual_range');
  zrange = netcdf.getAtt(ncid,2,'actual_range');
  [dimname,nx]=netcdf.inqDim(ncid,0);
  [dimname,ny]=netcdf.inqDim(ncid,1);
else
  if (nvars==6),                        % old (v3) GMT netCDF grid file
    [dimname, dimlen] = netcdf.inqDim(ncid,1);
    if (dimname=='xysize'),             % make sure it really is v3 netCDF
      title=getatt_clean(ncid,'title');
      command=getatt_clean(ncid,'source');
      conv=[];
      desc=[]; zrange=[0 0]; vers='3.x format file';
      xrange=netcdf.getVar(ncid,0)';
      xname=netcdf.getAtt(ncid,0,'units');
      yrange=netcdf.getVar(ncid,1)';
      yname=netcdf.getAtt(ncid,1,'units');
      zrange=netcdf.getVar(ncid,2)';
      zname=netcdf.getAtt(ncid,2,'units');
%      z=netcdf.getVar(ncid,5);
      dim=netcdf.getVar(ncid,4)';
      nx=dim(1); ny=dim(2);
      zname='z';
      pixel=netcdf.getAtt(ncid,5,'node_offset');
    else
      error('Apparently not a GMT netCDF grid');
    end
  else
    error('Wrong number of variables in netCDF file!');
  end
end

if pixel,                         % pixel node registered
  dx=diff(xrange)/double(nx); % convert int to double for division
  dy=diff(yrange)/double(ny);
else                              % gridline registered
  dx=diff(xrange)/double(nx-1); % convert int to double for division
  dy=diff(yrange)/double(ny-1);
end

%disp(['Title: ' title]);
%disp(['Conventions: ' conv]);
%disp(['GMT version: ' vers]);
%disp(['Command: ' command]);
%disp(['Remark: ' desc]);
%if pixel,
%  disp('Pixel node registration used');
%else
%  disp('Gridline node registration used');
%end
%disp(['x_min: ' num2str(xrange(1)) ' x_max: ' num2str(xrange(2)) ...
%                   ' name: ' xname])
%disp(['y_min: ' num2str(yrange(1)) ' y_max: ' num2str(yrange(2)) ...
%                   ' name: ' yname])
%disp(['z_min: ' num2str(zrange(1)) ' z_max: ' num2str(zrange(2)) ...
%                   ' name: ' zname])

switch nargout
  case 1,
   % need to make sure that zrange and pixel are cast into double precision
   d=[xrange(1) xrange(2) yrange(1) yrange(2) double(zrange(1)) double(zrange(2)) double(pixel) dx dy];
end

function val = getatt_clean(ncid,attname)
%
% Call netcdf.getAtt when not sure whether global attribute 'attname' exists.
% Trap error and return empty vector in that case.
%
eval(['val = netcdf.getAtt(ncid,netcdf.getConstant(''NC_GLOBAL''),''' attname ''');'],'val=[];');


function leap = hammersley_leap_get ( )

%*****************************************************************************80
%
%% HAMMERSLEY_BASE_GET gets the leap vector of the leaped Hammersley subsequence.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    29 January 2005
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, integer LEAP(1:DIM_NUM), the Hammersley leap vector.
%
  global hammersley_BASE
  global hammersley_LEAP
  global hammersley_DIM_NUM
  global hammersley_SEED
  global hammersley_STEP

  dim_num = hammersley_DIM_NUM;

  if ( ~halham_dim_num_check ( dim_num ) )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'HAMMERSLEY_LEAP_GET - Fatal error!\n' );
    error ( 'HAMMERSLEY_LEAP_GET - Fatal error!' );
  end

  if ( length ( hammersley_LEAP ) ~= dim_num )

    hammersley_LEAP = [];

    for i = 1 : dim_num
      hammersley_LEAP(i) = 1;
    end

  end

  leap(1:dim_num) = hammersley_LEAP(1:dim_num);

  return
end


function [out] = prep_addFeatures(dat1,dat2)
% prep_addFeatures (Pre-processing procedure):
%
% Description:
%     This function add the latter feature vector(dat2)
%     to the former one(dat1)
%
% Example:
% [out] = prep_addFeatures(dat1,dat2)
% [out] = prep_addFeatures({dat1,dat2,dat3,dat4,...})
%
% Input:
%     dat1 - Feature vector in a struct form
%     dat2 - Feature vector in a struct form, with same class as dat1
%
% Returns:
%     out - Updated feature vector added aditional features
%
%
% Seon Min Kim, 04-2016
% seonmin5055@gmail.com

if iscell(dat1)
    temp = dat1{1};
    for i=2:size(dat1,2)
        temp = prep_addFeatures(temp,dat1{i});
    end
    out = temp;
    return
end

if ~isfield(dat1,'x') || ~isfield(dat2,'x')
    warning('OpenBMI: Data structure must have a field named ''x''')
    return
end
if size(dat1.x,2) ~= size(dat2.x,2)
    warning('OpenBMI: Unmatched the number of trials')
    return
end
if ~isfield(dat1,'class') || ~isfield(dat1,'y_dec')
    warning('OpenBMI: Data structure should have a field named ''class'',''y_dec''')
end

r1 = rmfield(dat1,'x');
r2 = rmfield(dat2,'x');
if ~isequal(r1,r2)
    warning('OpenBMI: Two features must be extracted from the data with same class and trials')
    return
end

out = r1;
out.x = cat(1,dat1.x,dat2.x);


function matlab_random_parallel_test ( )

%*****************************************************************************80
%
%% MATLAB_RANDOM_PARALLEL_TEST looks at random number generation in parallel Matlab.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    25 April 2014
%
%  Author:
%
%    John Burkardt
%
  timestamp ( );
  fprintf ( 1, '\n' );
  fprintf ( 1, 'MATLAB_RANDOM_PARALLEL_TEST\n' );
  fprintf ( 1, '  MATLAB version.\n' );
  fprintf ( 1, '  Look at random number generation in parallel Matlab.\n' );

  matlab_random_parallel_test01 ( );
  matlab_random_parallel_test02 ( );
  matlab_random_parallel_test03 ( );
%
%  Terminate.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'MATLAB_RANDOM_PARALLEL_TEST\n' );
  fprintf ( 1, '  Normal end of execution.\n' );
  fprintf ( 1, '\n' );
  timestamp ( );

  return
end
function timestamp ( )

%*****************************************************************************80
%
%% TIMESTAMP prints the current YMDHMS date as a timestamp.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 February 2003
%
%  Author:
%
%    John Burkardt
%
  t = now;
  c = datevec ( t );
  s = datestr ( c, 0 );
  fprintf ( 1, '%s\n', s );

  return
end


function submitWeb(partId)
%SUBMITWEB Generates a base64 encoded string for web-based submissions
%   SUBMITWEB() will generate a base64 encoded string so that you can submit your
%   solutions via a web form

  fprintf('==\n== [ml-class] Submitting Solutions | Programming Exercise %s\n==\n', ...
          homework_id());
  if ~exist('partId', 'var') || isempty(partId)
    partId = promptPart();
  end

  % Check valid partId
  partNames = validParts();
  if ~isValidPartId(partId)
    fprintf('!! Invalid homework part selected.\n');
    fprintf('!! Expected an integer from 1 to %d.\n', numel(partNames));
    fprintf('!! Submission Cancelled\n');
    return
  end

  [login] = loginPrompt();
  if isempty(login)
    fprintf('!! Submission Cancelled\n');
    return
  end

  [result] = submitSolution(login, partId, output(partId), ...
                            source(partId));
  result = base64encode(result);

  fprintf('\nSave as submission file [submit_ex%s_part%d.txt]: ', ...
          homework_id(), partId);
  saveAsFile = input('', 's');
  if (isempty(saveAsFile))
    saveAsFile = sprintf('submit_ex%s_part%d.txt', homework_id(), partId);
  end

  fid = fopen(saveAsFile, 'w');
  if (fid)
    fwrite(fid, result);
    fclose(fid);
    fprintf('\nSaved your solutions to %s.\n\n', saveAsFile);
    fprintf(['You can now submit your solutions through the web \n' ...
             'form in the programming exercises. Select the corresponding \n' ...
             'programming exercise to access the form.\n']);

  else
    fprintf('Unable to save to %s\n\n', saveAsFile);
    fprintf(['You can create a submission file by saving the \n' ...
             'following text in a file: (press enter to continue)\n\n']);
    pause;
    fprintf(result);
  end

end

% ================== CONFIGURABLES FOR EACH HOMEWORK ==================

function id = homework_id()
  id = '4';
end

function [partNames] = validParts()
  partNames = { 'Feedforward and Cost Function', ...
                'Regularized Cost Function', ...
                'Sigmoid Gradient', ...
                'Neural Network Gradient (Backpropagation)' ...
                'Regularized Gradient' ...
                };
end

function srcs = sources()
  % Separated by part
  srcs = { { 'nnCostFunction.m' }, ...
           { 'nnCostFunction.m' }, ...
           { 'sigmoidGradient.m' }, ...
           { 'nnCostFunction.m' }, ...
           { 'nnCostFunction.m' } };
end

function out = output(partId)
  % Random Test Cases
  X = reshape(3 * sin(1:1:30), 3, 10);
  Xm = reshape(sin(1:32), 16, 2) / 5;
  ym = 1 + mod(1:16,4)';
  t1 = sin(reshape(1:2:24, 4, 3));
  t2 = cos(reshape(1:2:40, 4, 5));
  t  = [t1(:) ; t2(:)];
  if partId == 1
    [J] = nnCostFunction(t, 2, 4, 4, Xm, ym, 0);
    out = sprintf('%0.5f ', J);
  elseif partId == 2
    [J] = nnCostFunction(t, 2, 4, 4, Xm, ym, 1.5);
    out = sprintf('%0.5f ', J);
  elseif partId == 3
    out = sprintf('%0.5f ', sigmoidGradient(X));
  elseif partId == 4
    [J, grad] = nnCostFunction(t, 2, 4, 4, Xm, ym, 0);
    out = sprintf('%0.5f ', J);
    out = [out sprintf('%0.5f ', grad)];
  elseif partId == 5
    [J, grad] = nnCostFunction(t, 2, 4, 4, Xm, ym, 1.5);
    out = sprintf('%0.5f ', J);
    out = [out sprintf('%0.5f ', grad)];
  end
end

% ========================= SUBMIT HELPERS =========================

function src = source(partId)
  src = '';
  src_files = sources();
  if partId <= numel(src_files)
      flist = src_files{partId};
      for i = 1:numel(flist)
          fid = fopen(flist{i});
          while ~feof(fid)
            line = fgets(fid);
            src = [src line];
          end
          fclose(fid);
          src = [src '||||||||'];
      end
  end
end

function ret = isValidPartId(partId)
  partNames = validParts();
  ret = (~isempty(partId)) && (partId >= 1) && (partId <= numel(partNames));
end

function partId = promptPart()
  fprintf('== Select which part(s) to submit:\n', ...
          homework_id());
  partNames = validParts();
  srcFiles = sources();
  for i = 1:numel(partNames)
    fprintf('==   %d) %s [', i, partNames{i});
    fprintf(' %s ', srcFiles{i}{:});
    fprintf(']\n');
  end
  fprintf('\nEnter your choice [1-%d]: ', ...
          numel(partNames));
  selPart = input('', 's');
  partId = str2num(selPart);
  if ~isValidPartId(partId)
    partId = -1;
  end
end

function [result, str] = submitSolution(email, part, output, source)

  result = ['a:5:{' ...
            p_s('homework') p_s64(homework_id()) ...
            p_s('part') p_s64(part) ...
            p_s('email') p_s64(email) ...
            p_s('output') p_s64(output) ...
            p_s('source') p_s64(source) ...
            '}'];

end

function s = p_s(str)
   s = ['s:' num2str(numel(str)) ':"' str '";'];
end

function s = p_s64(str)
   str = base64encode(str, '');
   s = ['s:' num2str(numel(str)) ':"' str '";'];
end

% =========================== LOGIN HELPERS ===========================

function [login] = loginPrompt()
  % Prompt for password
  [login] = basicPrompt();
end

function [login] = basicPrompt()
  login = input('Login (Email address): ', 's');
end

% =========================== Base64 Encoder ============================
% Thanks to Peter John Acklam
%

function y = base64encode(x, eol)
%BASE64ENCODE Perform base64 encoding on a string.
%
%   BASE64ENCODE(STR, EOL) encode the given string STR.  EOL is the line ending
%   sequence to use; it is optional and defaults to '\n' (ASCII decimal 10).
%   The returned encoded string is broken into lines of no more than 76
%   characters each, and each line will end with EOL unless it is empty.  Let
%   EOL be empty if you do not want the encoded string broken into lines.
%
%   STR and EOL don't have to be strings (i.e., char arrays).  The only
%   requirement is that they are vectors containing values in the range 0-255.
%
%   This function may be used to encode strings into the Base64 encoding
%   specified in RFC 2045 - MIME (Multipurpose Internet Mail Extensions).  The
%   Base64 encoding is designed to represent arbitrary sequences of octets in a
%   form that need not be humanly readable.  A 65-character subset
%   ([A-Za-z0-9+/=]) of US-ASCII is used, enabling 6 bits to be represented per
%   printable character.
%
%   Examples
%   --------
%
%   If you want to encode a large file, you should encode it in chunks that are
%   a multiple of 57 bytes.  This ensures that the base64 lines line up and
%   that you do not end up with padding in the middle.  57 bytes of data fills
%   one complete base64 line (76 == 57*4/3):
%
%   If ifid and ofid are two file identifiers opened for reading and writing,
%   respectively, then you can base64 encode the data with
%
%      while ~feof(ifid)
%         fwrite(ofid, base64encode(fread(ifid, 60*57)));
%      end
%
%   or, if you have enough memory,
%
%      fwrite(ofid, base64encode(fread(ifid)));
%
%   See also BASE64DECODE.

%   Author:      Peter John Acklam
%   Time-stamp:  2004-02-03 21:36:56 +0100
%   E-mail:      pjacklam@online.no
%   URL:         http://home.online.no/~pjacklam

   if isnumeric(x)
      x = num2str(x);
   end

   % make sure we have the EOL value
   if nargin < 2
      eol = sprintf('\n');
   else
      if sum(size(eol) > 1) > 1
         error('EOL must be a vector.');
      end
      if any(eol(:) > 255)
         error('EOL can not contain values larger than 255.');
      end
   end

   if sum(size(x) > 1) > 1
      error('STR must be a vector.');
   end

   x   = uint8(x);
   eol = uint8(eol);

   ndbytes = length(x);                 % number of decoded bytes
   nchunks = ceil(ndbytes / 3);         % number of chunks/groups
   nebytes = 4 * nchunks;               % number of encoded bytes

   % add padding if necessary, to make the length of x a multiple of 3
   if rem(ndbytes, 3)
      x(end+1 : 3*nchunks) = 0;
   end

   x = reshape(x, [3, nchunks]);        % reshape the data
   y = repmat(uint8(0), 4, nchunks);    % for the encoded data

   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   % Split up every 3 bytes into 4 pieces
   %
   %    aaaaaabb bbbbcccc ccdddddd
   %
   % to form
   %
   %    00aaaaaa 00bbbbbb 00cccccc 00dddddd
   %
   y(1,:) = bitshift(x(1,:), -2);                  % 6 highest bits of x(1,:)

   y(2,:) = bitshift(bitand(x(1,:), 3), 4);        % 2 lowest bits of x(1,:)
   y(2,:) = bitor(y(2,:), bitshift(x(2,:), -4));   % 4 highest bits of x(2,:)

   y(3,:) = bitshift(bitand(x(2,:), 15), 2);       % 4 lowest bits of x(2,:)
   y(3,:) = bitor(y(3,:), bitshift(x(3,:), -6));   % 2 highest bits of x(3,:)

   y(4,:) = bitand(x(3,:), 63);                    % 6 lowest bits of x(3,:)

   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   % Now perform the following mapping
   %
   %   0  - 25  ->  A-Z
   %   26 - 51  ->  a-z
   %   52 - 61  ->  0-9
   %   62       ->  +
   %   63       ->  /
   %
   % We could use a mapping vector like
   %
   %   ['A':'Z', 'a':'z', '0':'9', '+/']
   %
   % but that would require an index vector of class double.
   %
   z = repmat(uint8(0), size(y));
   i =           y <= 25;  z(i) = 'A'      + double(y(i));
   i = 26 <= y & y <= 51;  z(i) = 'a' - 26 + double(y(i));
   i = 52 <= y & y <= 61;  z(i) = '0' - 52 + double(y(i));
   i =           y == 62;  z(i) = '+';
   i =           y == 63;  z(i) = '/';
   y = z;

   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   % Add padding if necessary.
   %
   npbytes = 3 * nchunks - ndbytes;     % number of padding bytes
   if npbytes
      y(end-npbytes+1 : end) = '=';     % '=' is used for padding
   end

   if isempty(eol)

      % reshape to a row vector
      y = reshape(y, [1, nebytes]);

   else

      nlines = ceil(nebytes / 76);      % number of lines
      neolbytes = length(eol);          % number of bytes in eol string

      % pad data so it becomes a multiple of 76 elements
      y = [y(:) ; zeros(76 * nlines - numel(y), 1)];
      y(nebytes + 1 : 76 * nlines) = 0;
      y = reshape(y, 76, nlines);

      % insert eol strings
      eol = eol(:);
      y(end + 1 : end + neolbytes, :) = eol(:, ones(1, nlines));

      % remove padding, but keep the last eol string
      m = nebytes + neolbytes * (nlines - 1);
      n = (76+neolbytes)*nlines - neolbytes;
      y(m+1 : n) = '';

      % extract and reshape to row vector
      y = reshape(y, 1, m+neolbytes);

   end

   % output is a character array
   y = char(y);

end


function submitWeb(partId)
%SUBMITWEB Generates a base64 encoded string for web-based submissions
%   SUBMITWEB() will generate a base64 encoded string so that you can submit your
%   solutions via a web form

  fprintf('==\n== [ml-class] Submitting Solutions | Programming Exercise %s\n==\n', ...
          homework_id());
  if ~exist('partId', 'var') || isempty(partId)
    partId = promptPart();
  end

  % Check valid partId
  partNames = validParts();
  if ~isValidPartId(partId)
    fprintf('!! Invalid homework part selected.\n');
    fprintf('!! Expected an integer from 1 to %d.\n', numel(partNames));
    fprintf('!! Submission Cancelled\n');
    return
  end

  [login] = loginPrompt();
  if isempty(login)
    fprintf('!! Submission Cancelled\n');
    return
  end

  [result] = submitSolution(login, partId, output(partId), ...
                            source(partId));
  result = base64encode(result);

  fprintf('\nSave as submission file [submit_ex%s_part%d.txt]: ', ...
          homework_id(), partId);
  saveAsFile = input('', 's');
  if (isempty(saveAsFile))
    saveAsFile = sprintf('submit_ex%s_part%d.txt', homework_id(), partId);
  end

  fid = fopen(saveAsFile, 'w');
  if (fid)
    fwrite(fid, result);
    fclose(fid);
    fprintf('\nSaved your solutions to %s.\n\n', saveAsFile);
    fprintf(['You can now submit your solutions through the web \n' ...
             'form in the programming exercises. Select the corresponding \n' ...
             'programming exercise to access the form.\n']);

  else
    fprintf('Unable to save to %s\n\n', saveAsFile);
    fprintf(['You can create a submission file by saving the \n' ...
             'following text in a file: (press enter to continue)\n\n']);
    pause;
    fprintf(result);
  end

end

% ================== CONFIGURABLES FOR EACH HOMEWORK ==================

function id = homework_id()
  id = '7';
end

function [partNames] = validParts()
  partNames = {
                'Find Closest Centroids (k-Means)', ...
                'Compute Centroid Means (k-Means)' ...
                'PCA', ...
                'Project Data (PCA)', ...
                'Recover Data (PCA)' ...
                };
end

function srcs = sources()
  % Separated by part
  srcs = { { 'findClosestCentroids.m' }, ...
           { 'computeCentroids.m' }, ...
           { 'pca.m' }, ...
           { 'projectData.m' }, ...
           { 'recoverData.m' } ...
           };
end

function out = output(partId)
  % Random Test Cases
  X = reshape(sin(1:165), 15, 11);
  Z = reshape(cos(1:121), 11, 11);
  C = Z(1:5, :);
  idx = (1 + mod(1:15, 3))';
  if partId == 1
    idx = findClosestCentroids(X, C);
    out = sprintf('%0.5f ', idx(:));
  elseif partId == 2
    centroids = computeCentroids(X, idx, 3);
    out = sprintf('%0.5f ', centroids(:));
  elseif partId == 3
    [U, S] = pca(X);
    out = sprintf('%0.5f ', abs([U(:); S(:)]));
  elseif partId == 4
    X_proj = projectData(X, Z, 5);
    out = sprintf('%0.5f ', X_proj(:));
  elseif partId == 5
    X_rec = recoverData(X(:,1:5), Z, 5);
    out = sprintf('%0.5f ', X_rec(:));
  end
end

% ========================= SUBMIT HELPERS =========================

function src = source(partId)
  src = '';
  src_files = sources();
  if partId <= numel(src_files)
      flist = src_files{partId};
      for i = 1:numel(flist)
          fid = fopen(flist{i});
          while ~feof(fid)
            line = fgets(fid);
            src = [src line];
          end
          fclose(fid);
          src = [src '||||||||'];
      end
  end
end

function ret = isValidPartId(partId)
  partNames = validParts();
  ret = (~isempty(partId)) && (partId >= 1) && (partId <= numel(partNames));
end

function partId = promptPart()
  fprintf('== Select which part(s) to submit:\n', ...
          homework_id());
  partNames = validParts();
  srcFiles = sources();
  for i = 1:numel(partNames)
    fprintf('==   %d) %s [', i, partNames{i});
    fprintf(' %s ', srcFiles{i}{:});
    fprintf(']\n');
  end
  fprintf('\nEnter your choice [1-%d]: ', ...
          numel(partNames));
  selPart = input('', 's');
  partId = str2num(selPart);
  if ~isValidPartId(partId)
    partId = -1;
  end
end

function [result, str] = submitSolution(email, part, output, source)

  result = ['a:5:{' ...
            p_s('homework') p_s64(homework_id()) ...
            p_s('part') p_s64(part) ...
            p_s('email') p_s64(email) ...
            p_s('output') p_s64(output) ...
            p_s('source') p_s64(source) ...
            '}'];

end

function s = p_s(str)
   s = ['s:' num2str(numel(str)) ':"' str '";'];
end

function s = p_s64(str)
   str = base64encode(str, '');
   s = ['s:' num2str(numel(str)) ':"' str '";'];
end

% =========================== LOGIN HELPERS ===========================

function [login] = loginPrompt()
  % Prompt for password
  [login] = basicPrompt();
end

function [login] = basicPrompt()
  login = input('Login (Email address): ', 's');
end

% =========================== Base64 Encoder ============================
% Thanks to Peter John Acklam
%

function y = base64encode(x, eol)
%BASE64ENCODE Perform base64 encoding on a string.
%
%   BASE64ENCODE(STR, EOL) encode the given string STR.  EOL is the line ending
%   sequence to use; it is optional and defaults to '\n' (ASCII decimal 10).
%   The returned encoded string is broken into lines of no more than 76
%   characters each, and each line will end with EOL unless it is empty.  Let
%   EOL be empty if you do not want the encoded string broken into lines.
%
%   STR and EOL don't have to be strings (i.e., char arrays).  The only
%   requirement is that they are vectors containing values in the range 0-255.
%
%   This function may be used to encode strings into the Base64 encoding
%   specified in RFC 2045 - MIME (Multipurpose Internet Mail Extensions).  The
%   Base64 encoding is designed to represent arbitrary sequences of octets in a
%   form that need not be humanly readable.  A 65-character subset
%   ([A-Za-z0-9+/=]) of US-ASCII is used, enabling 6 bits to be represented per
%   printable character.
%
%   Examples
%   --------
%
%   If you want to encode a large file, you should encode it in chunks that are
%   a multiple of 57 bytes.  This ensures that the base64 lines line up and
%   that you do not end up with padding in the middle.  57 bytes of data fills
%   one complete base64 line (76 == 57*4/3):
%
%   If ifid and ofid are two file identifiers opened for reading and writing,
%   respectively, then you can base64 encode the data with
%
%      while ~feof(ifid)
%         fwrite(ofid, base64encode(fread(ifid, 60*57)));
%      end
%
%   or, if you have enough memory,
%
%      fwrite(ofid, base64encode(fread(ifid)));
%
%   See also BASE64DECODE.

%   Author:      Peter John Acklam
%   Time-stamp:  2004-02-03 21:36:56 +0100
%   E-mail:      pjacklam@online.no
%   URL:         http://home.online.no/~pjacklam

   if isnumeric(x)
      x = num2str(x);
   end

   % make sure we have the EOL value
   if nargin < 2
      eol = sprintf('\n');
   else
      if sum(size(eol) > 1) > 1
         error('EOL must be a vector.');
      end
      if any(eol(:) > 255)
         error('EOL can not contain values larger than 255.');
      end
   end

   if sum(size(x) > 1) > 1
      error('STR must be a vector.');
   end

   x   = uint8(x);
   eol = uint8(eol);

   ndbytes = length(x);                 % number of decoded bytes
   nchunks = ceil(ndbytes / 3);         % number of chunks/groups
   nebytes = 4 * nchunks;               % number of encoded bytes

   % add padding if necessary, to make the length of x a multiple of 3
   if rem(ndbytes, 3)
      x(end+1 : 3*nchunks) = 0;
   end

   x = reshape(x, [3, nchunks]);        % reshape the data
   y = repmat(uint8(0), 4, nchunks);    % for the encoded data

   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   % Split up every 3 bytes into 4 pieces
   %
   %    aaaaaabb bbbbcccc ccdddddd
   %
   % to form
   %
   %    00aaaaaa 00bbbbbb 00cccccc 00dddddd
   %
   y(1,:) = bitshift(x(1,:), -2);                  % 6 highest bits of x(1,:)

   y(2,:) = bitshift(bitand(x(1,:), 3), 4);        % 2 lowest bits of x(1,:)
   y(2,:) = bitor(y(2,:), bitshift(x(2,:), -4));   % 4 highest bits of x(2,:)

   y(3,:) = bitshift(bitand(x(2,:), 15), 2);       % 4 lowest bits of x(2,:)
   y(3,:) = bitor(y(3,:), bitshift(x(3,:), -6));   % 2 highest bits of x(3,:)

   y(4,:) = bitand(x(3,:), 63);                    % 6 lowest bits of x(3,:)

   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   % Now perform the following mapping
   %
   %   0  - 25  ->  A-Z
   %   26 - 51  ->  a-z
   %   52 - 61  ->  0-9
   %   62       ->  +
   %   63       ->  /
   %
   % We could use a mapping vector like
   %
   %   ['A':'Z', 'a':'z', '0':'9', '+/']
   %
   % but that would require an index vector of class double.
   %
   z = repmat(uint8(0), size(y));
   i =           y <= 25;  z(i) = 'A'      + double(y(i));
   i = 26 <= y & y <= 51;  z(i) = 'a' - 26 + double(y(i));
   i = 52 <= y & y <= 61;  z(i) = '0' - 52 + double(y(i));
   i =           y == 62;  z(i) = '+';
   i =           y == 63;  z(i) = '/';
   y = z;

   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   % Add padding if necessary.
   %
   npbytes = 3 * nchunks - ndbytes;     % number of padding bytes
   if npbytes
      y(end-npbytes+1 : end) = '=';     % '=' is used for padding
   end

   if isempty(eol)

      % reshape to a row vector
      y = reshape(y, [1, nebytes]);

   else

      nlines = ceil(nebytes / 76);      % number of lines
      neolbytes = length(eol);          % number of bytes in eol string

      % pad data so it becomes a multiple of 76 elements
      y = [y(:) ; zeros(76 * nlines - numel(y), 1)];
      y(nebytes + 1 : 76 * nlines) = 0;
      y = reshape(y, 76, nlines);

      % insert eol strings
      eol = eol(:);
      y(end + 1 : end + neolbytes, :) = eol(:, ones(1, nlines));

      % remove padding, but keep the last eol string
      m = nebytes + neolbytes * (nlines - 1);
      n = (76+neolbytes)*nlines - neolbytes;
      y(m+1 : n) = '';

      % extract and reshape to row vector
      y = reshape(y, 1, m+neolbytes);

   end

   % output is a character array
   y = char(y);

end


function [ h, hmin, hmax ] = p18_stepsize ( option )

%*****************************************************************************80
%
%% P18_STEPSIZE returns step sizes for problem 18.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    24 September 2008
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer OPTION, the option index.
%
%    Output, real H, HMIN, HMAX, suggested values for the
%    initial step, the minimum step, and the maximum step.
%
  h =    2.500;
  hmin = 0.001;
  hmax = 5.000;

  return
end


function [legend_h,object_h,plot_h,text_strings] = columnlegend(numcolumns, str, location)
%
%   columnlegend creates a legend with a specified number of columns.
%
%   columnlegend(numcolumns, str, location)
%       numcolumns - number of columns in the legend
%       cellstr - cell array of strings for the legend
%       location - location variable for legend, default is 'NorthEast'
%                  possible values: 'NorthWest', 'NorthEast', 'SouthEast', 'SouthWest'
%
%   example:
%      legend_str = [];
%      for i=1:10,
%           x = 1:i:(10*i);
%           plot(x); hold on;
%           legend_str = [legend_str; {num2str(i)}];
%      end
%      columnlegend(3, legend_str, 'NorthWest');
%
%
%   Author: Simon Henin <shenin@gc.cuny.edu>

if nargin < 3
   location = 'NorthEast';
end

%create the legend
[legend_h,object_h,plot_h,text_strings] = legend(str);

%some variables
numlines = length(str);
numpercolumn = ceil(numlines/numcolumns);

%get old width, new width and scale factor
pos = get(legend_h, 'position');
width = numcolumns*pos(3);
rescale = pos(3)/width;

%get some old values so we can scale everything later
xdata = get(object_h(numlines+1), 'xdata');
ydata1 = get(object_h(numlines+1), 'ydata');
ydata2 = get(object_h(numlines+3), 'ydata');

%we'll use these later to align things appropriately
sheight = ydata1(1)-ydata2(1);                  % height between data lines
height = ydata1(1);                             % height of the box. Used to top margin offset
line_width = (xdata(2)-xdata(1))*rescale;   % rescaled linewidth to match original
spacer = xdata(1)*rescale;                    % rescaled spacer used for margins

%put the legend on the upper left corner to make initial adjustments easier
loci = get(gca, 'position');
set(legend_h, 'position', [loci(1) pos(2) width pos(4)]);

col = -1;
for i=1:numlines,
    if mod(i,numpercolumn)==1,
        col = col+1;
    end

    if i==1
        linenum = i+numlines;
    else
        linenum = linenum+2;
    end
    labelnum = i;

    position = mod(i,numpercolumn);
    if position == 0,
         position = numpercolumn;
    end

    %realign the labels
    set(object_h(linenum), 'ydata', [(height-(position-1)*sheight) (height-(position-1)*sheight)]);
    set(object_h(linenum), 'xdata', [col/numcolumns+spacer col/numcolumns+spacer+line_width]);

    set(object_h(linenum+1), 'ydata', [height-(position-1)*sheight height-(position-1)*sheight]);
    set(object_h(linenum+1), 'xdata', [col/numcolumns+spacer*3.5 col/numcolumns+spacer*3.5]);

    set(object_h(labelnum), 'position', [col/numcolumns+spacer*2+line_width height-(position-1)*sheight]);

end

%unfortunately, it is not possible to force the box to be smaller than the
%original height, therefore, turn it off and set background color to none
%so that it no longer appears
set(legend_h, 'Color', 'None', 'Box', 'off');

%let's put it where you want it
pos = get(legend_h, 'position');
fig_pos = get(gca, 'position');
switch lower(location),
    case {'northeast'}
        set(legend_h, 'position', [pos(1)+fig_pos(3)-pos(3) pos(2) pos(3) pos(4)]);
    case {'southeast'}
        set(legend_h, 'position', [pos(1)+fig_pos(3)-pos(3) fig_pos(2)-pos(4)/2+pos(4)/4 pos(3) pos(4)]);
    case {'southwest'}
        set(legend_h, 'position', [fig_pos(1) fig_pos(2)-pos(4)/2+pos(4)/4 pos(3) pos(4)]);
end


function patches = load_hpatches(impath)
%LOAD_PATCHES Load and cut HPatches patch file

patches = imread(impath);
npatches = size(patches, 1) ./ size(patches, 2);
assert(mod(npatches, 1) == 0, 'Invalid patch image height.');
patches = mat2cell(patches, size(patches, 2)*ones(1, npatches), size(patches, 2));
patches = permute(patches, [2, 3, 4, 1]);
patches = cell2mat(patches);
end


% VARGPLVMTOOLBOXES Load in the relevant toolboxes for variational gplvm.

importLatest('netlab');
importLatest('gpmat');


function dicom_write_volume(Volume,filename,volscale,info)
% This function DICOM_WRITE_VOLUME will write a Matlab 3D volume as
% a stack of 2D slices in separate dicom files.
%
% dicom_write_volume(Volume,Filename,Scales,Info)
%
% inputs,
%   Volume: The 3D Matlab volume
%   Filename: The name of the dicom files
%   Scales: The dimensions of every voxel/pixel
%   Info: A struct with dicom tags and values
%
% Function is written by D.Kroon University of Twente (May 2009)

% Check inputs
if(exist('filename','var')==0), filename=[]; end
if(exist('info','var')==0), info=[]; end
if(exist('volscale','var')==0), volscale=[1 1 1]; end

% Show file dialog if no file name specified
if(isempty(filename))
    [filename, pathname] = uiputfile('*.dcm', 'Save to Dicom');
    filename= [pathname filename];
end

% Add dicom tags to info structure
if(~isstruct(info))
    info=struct;
    % Make random series number
    SN=round(rand(1)*1000);
    % Get date of today
    today=[datestr(now,'yyyy') datestr(now,'mm') datestr(now,'dd')];
    info.SeriesNumber=SN;
    info.AcquisitionNumber=SN;
    info.StudyDate=today;
    info.StudyID=num2str(SN);
    info.PatientID=num2str(SN);
    info.PatientPosition='HFS';
    info.AccessionNumber=num2str(SN);
    info.StudyDescription=['StudyMAT' num2str(SN)];
    info.SeriesDescription=['StudyMAT' num2str(SN)];
    info.Manufacturer='Matlab Convert';
    info.SliceThickness=volscale(3);
    info.PixelSpacing=volscale(1:2);
    info.SliceLocation=0;
end

% Remove filename extention
pl=find(filename=='.'); if(~isempty(pl)), filename=filename(1:pl-1); end

% Read Volume data
disp('Writing Dicom Files...');
for slicenum=1:size(Volume,3)
    filenamedicom=[filename number2string(slicenum) '.dcm'];
    % Add slice specific dicom info
    info.InstanceNumber = slicenum;
    info.SliceLocation = info.SliceLocation+volscale(3);
    % Write the dicom file
    disp(['Writing : ' filenamedicom]);
    dicomwrite(Volume(:,:,slicenum), filenamedicom, info)
end

function numstr=number2string(num)
    num=num2str(num);
    numzeros='000000';
    numstr=[numzeros(length(num):end) num];


function value = SPEED_OF_LIGHT( )
%SPEED_OF_LIGHT Constant for speed of light in meters per second
%
% //////////////////////////////////////////
% /// CLASSIFICATION: UNCLASSIFIED       ///
% //////////////////////////////////////////

value = 299792458;

end

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


function test_sameobject
% Result should be 1 in both cases below.

a = rand(4);
b = a;
if sameobject(a,b) ~= 1
  error('failed');
end
if helper(a,a) ~= 1
  error('failed');
end
disp('Test passed.')

function x = helper(a,b)

x = sameobject(a,b);


function [ varargout ] = Beam_Propagation_Method_GUI ( varargin )

%% GUI for Beam Propagation Method (BPM)
%
%%
%    Author:   Ido Schwartz (IS)
%    April 2011 (ver. 1.0.0)
%
%% build GUI
fig = build_gui;
h   = guidata ( fig );

switch nargout      %----------------------- check nargout
    case 0
        % do nothing
    case 1                                  % return a handle to GUI
        varargout(1) = {fig};
    otherwise
        error ('Invalid number of output arguments');
end

e = exist ('data_bpm_tmp.mat','file');
if e==2
    delete('data_bpm_tmp.mat');
end

end

%% uifunctions
function fig = build_gui

setappdata(0,'UseNativeSystemDialogs',false);

fig = figure;

set (fig, 'Name', ' Beam Propagation Method GUI','NumberTitle', 'off', 'Visible','off');
set (fig, 'deleteFcn', @close_figure_callback ); %%%%%%%%%%%%%%%
set (fig, 'Color', get(0,'defaultUicontrolBackgroundColor') );

back_color = get (fig,'Color');
edit_box_back_color = [1 1 1];      % white

%% ------------------------------------ draw tools panel
tools_panel = uipanel('units', 'normalized', 'position' , [.005 .005 .99 .11] ,...  %% draw panel
    'parent' , fig,    'tag' , ' tools_panel'  , 'TitlePosition', 'righttop', ...
    'title' , 'tools');

uicontrol ('style', 'pushbutton', 'units', 'normalized', 'position', [0.003 0.1 0.12 0.8],...
    'HorizontalAlignment','center', 'FontWeight', 'bold','fontsize' , 12 ,...
    'string', 'simulation panel'  ,'tag', 'graphs_pushbutton', 'callback', @graphs_pushbutton_callback, 'parent' , tools_panel );

uicontrol ('style', 'pushbutton', 'units', 'normalized', 'position', [0.126 0.1 0.12 0.8],...
    'HorizontalAlignment','center', 'FontWeight', 'bold','fontsize' , 12 ,...
    'string', 'set parameters'  ,'tag', 'setparameters_pushbutton', 'callback', @setparameters_pushbutton_callback, 'parent' , tools_panel );

uicontrol ('style', 'pushbutton', 'units', 'normalized', 'position', [0.877 0.1 0.12 0.8],...
    'HorizontalAlignment','center', 'FontWeight', 'bold','fontsize' , 12 ,...
    'string', 'Exit'  ,'tag', 'exit_pushbutton', 'callback', @exit_pushbutton_callback, 'parent' , tools_panel );

%% ------------------------------------ draw graphs panel
graph_panel = uipanel('units', 'normalized', 'position' , [.005 .11 .99 .885] ,...  %% draw panel
    'parent' , fig,    'tag' , 'g_panel'  , 'TitlePosition', 'righttop', ...
    'title' , 'Graphs');

uicontrol ('style', 'pushbutton', 'units', 'normalized', 'position', [0.003 0.003 0.12 0.07],...
    'HorizontalAlignment','center', 'FontWeight', 'bold','fontsize' , 12 ,...
    'string', 'start'  ,'tag', 'start_pushbutton', 'callback', @start_pushbutton_callback, 'parent' , graph_panel );

uicontrol ('style', 'pushbutton', 'units', 'normalized', 'position', [0.126 0.003 0.12 0.07],...
    'HorizontalAlignment','center', 'FontWeight', 'bold','fontsize' , 12 ,'enable','off',...
    'string', 'stop'  ,'tag', 'stop_pushbutton', 'callback', @stop_pushbutton_callback, 'parent' , graph_panel );

uicontrol ('style', 'pushbutton', 'units', 'normalized', 'position', [0.875 0.003 0.12 0.07],...
    'HorizontalAlignment','center', 'FontWeight', 'bold','fontsize' , 12 ,'enable','on',...
    'string', 'save'  ,'tag', 'save_pushbutton', 'callback', @save_pushbutton_callback, 'parent' , graph_panel );

axes('parent',graph_panel,'tag','ax1','Position', [.04 .125 .58 .83]'); %define the axes space
axes('parent',graph_panel,'tag','ax2','Position',[.665 .4 .3 .5]); %define the axes space

%% ------------------------------------ draw Set Parameters panel
parameters_panel = uipanel('units', 'normalized', 'position' , [.005 .11 .99 .885] ,...  %% draw panel
    'parent' , fig,    'tag' , 'p_panel'  , 'TitlePosition', 'righttop', ...
    'title' , 'Set Parameters');
% --------------------------------------------------------- Field parameters
field_panel = uipanel('units', 'normalized', 'position' , [.005 .005 .3 .99] ,...  %% draw panel
    'parent' , parameters_panel,    'tag' , 'field_panel'  , 'TitlePosition', 'righttop', ...
    'title' , 'Field Initial Parameters');

uicontrol ('style', 'text', 'units', 'normalized', 'position', [0.05 0.9 0.9 0.1],...
    'HorizontalAlignment','left', 'FontWeight', 'bold','fontsize' , 12 ,...
    'string', 'F(r,z=0)=A*exp(-0.5*(r/w)^2)'  ,'tag', 'field_text', 'parent' , field_panel );

uicontrol ('style', 'text', 'units', 'normalized', 'position', [0.05 0.83 0.11 0.07],...
    'HorizontalAlignment','left', 'FontWeight', 'normal','fontsize' , 12 ,...
    'string', 'A = '  ,'tag', 'A_text', 'parent' , field_panel );

uicontrol ('style', 'edit', 'units', 'normalized', 'position', [0.165 0.83 0.15 0.07],...
    'HorizontalAlignment','center', 'FontWeight', 'normal','fontsize' , 12 ,...
    'string', '1' , 'backgroundcolor',[1 1 1],'tag', 'A_edit','enable','on', 'parent' , field_panel );

uicontrol ('style', 'text', 'units', 'normalized', 'position', [0.05 0.75 0.11 0.07],...
    'HorizontalAlignment','left', 'FontWeight', 'normal','fontsize' , 12 ,...
    'string', 'w = '  ,'tag', 'w_text', 'parent' , field_panel );

uicontrol ('style', 'edit', 'units', 'normalized', 'position', [0.165 0.75 0.15 0.07],...
    'HorizontalAlignment','center', 'FontWeight', 'normal','fontsize' , 12 ,...
    'string', '10' ,'backgroundcolor',[1 1 1],'tag', 'w_edit','enable','on', 'parent' , field_panel );

uicontrol ('style', 'text', 'units', 'normalized', 'position', [0.33 0.75 0.22 0.07],...
    'HorizontalAlignment','left', 'FontWeight', 'normal','fontsize' , 12 ,...
    'string', 'micrometer '  ,'tag', 'w_units_text', 'parent' , field_panel );

uicontrol ('style', 'text', 'units', 'normalized', 'position', [0.05 0.67 0.11 0.07],...
    'HorizontalAlignment','left', 'FontWeight', 'normal','fontsize' , 12 ,...
    'string', 'wave length'  ,'tag', 'lambda_text', 'parent' , field_panel );

uicontrol ('style', 'edit', 'units', 'normalized', 'position', [0.165 0.67 0.15 0.07],...
    'HorizontalAlignment','center', 'FontWeight', 'normal','fontsize' , 12 ,...
    'string', '0.5' ,'backgroundcolor',[1 1 1],'tag', 'lambda_edit','enable','on', 'parent' , field_panel );

uicontrol ('style', 'popupmenu', 'units', 'normalized', 'position', [0.33 0.67 0.3 0.07],...
    'HorizontalAlignment','left', 'FontWeight', 'normal','fontsize' , 12,'backgroundcolor',[1 1 1] ,...
    'string', {'micrometer','nanometer'} ,'tag', 'lambda_popup', 'callback', @lambda_popupmenu_callback, 'parent' , field_panel );

% --------------------------------------------------------- Medium Parameters ---
medium_panel = uipanel('units', 'normalized', 'position' , [.305 .005 .3 .99] ,...  %% draw panel
    'parent' , parameters_panel,    'tag' , 'medium_panel'  , 'TitlePosition', 'righttop', ...
    'title' , 'Medium Parameters');

tex=axes('parent',medium_panel,'tag','tex','Position', [.005 .98 .0001 .0001],'XTick',[],'YTick',[]); %define the axes space
text( 1,1, '\bfn=n_0+n_1exp(-\alphar^m/w^m)', 'parent' , tex ,'FontSize',12);

uicontrol ('style', 'popupmenu', 'units', 'normalized', 'position', [0.005 0.87 0.5 0.07],...
    'HorizontalAlignment','left', 'FontWeight', 'normal','fontsize' , 12 ,'backgroundcolor',[1 1 1],...
    'string', {'uniform','linear','quadratic','customize'} ,'tag', 'medium_popup', 'callback', @medium_popupmenu_callback, 'parent' , medium_panel );

tex=axes('parent',medium_panel,'tag','tex','Position', [.005 .8 .0001 .0001],'XTick',[],'YTick',[]); %define the axes space
text( 1,1, 'n_0 =', 'parent' , tex ,'FontSize',12);

uicontrol ('style', 'edit', 'units', 'normalized', 'position', [0.15 0.775 0.15 0.06],...
    'HorizontalAlignment','center', 'FontWeight', 'normal','fontsize' , 12 ,...
    'string', '1' ,'backgroundcolor',[1 1 1],'tag', 'n0_edit','enable','on', 'parent' , medium_panel );

tex=axes('parent',medium_panel,'tag','tex','Position', [.005 .73 .0001 .0001],'XTick',[],'YTick',[]); %define the axes space
text( 1,1, 'n_1 =', 'parent' , tex ,'FontSize',12);

uicontrol ('style', 'edit', 'units', 'normalized', 'position', [0.15 0.705 0.15 0.06],...
    'HorizontalAlignment','center', 'FontWeight', 'normal','fontsize' , 12 ,...
    'string', '0' ,'backgroundcolor',[1 1 1],'tag', 'n1_edit','enable','off', 'parent' , medium_panel );

tex=axes('parent',medium_panel,'tag','tex','Position', [.35 .74 .0001 .0001],'XTick',[],'YTick',[]); %define the axes space
text( 1,1, '*10^-^4', 'parent' , tex ,'FontSize',12);

tex=axes('parent',medium_panel,'tag','tex','Position', [.005 .66 .0001 .0001],'XTick',[],'YTick',[]); %define the axes space
text( 1,1, '\alpha =', 'parent' , tex ,'FontSize',12);

uicontrol ('style', 'edit', 'units', 'normalized', 'position', [0.15 0.635 0.15 0.06],...
    'HorizontalAlignment','center', 'FontWeight', 'normal','fontsize' , 12 ,...
    'string', '0.5' ,'backgroundcolor',[1 1 1],'tag', 'alpha_edit','enable','off', 'parent' , medium_panel );

tex=axes('parent',medium_panel,'tag','tex','Position', [.005 .59 .0001 .0001],'XTick',[],'YTick',[]); %define the axes space
text( 1,1, 'm =', 'parent' , tex ,'FontSize',12);

uicontrol ('style', 'edit', 'units', 'normalized', 'position', [0.15 0.565 0.15 0.06],...
    'HorizontalAlignment','center', 'FontWeight', 'normal','fontsize' , 12 ,...
    'string', '0' ,'backgroundcolor',[1 1 1],'tag', 'm_edit','enable','off', 'parent' , medium_panel );

uicontrol ('style', 'text', 'units', 'normalized', 'position', [0.001 0.47 0.8 0.07],...
    'HorizontalAlignment','left', 'FontWeight', 'bold','fontsize' , 12 ,...
    'string', 'max value of r = 1000*(wave length)'  ,'tag', 'r_max_text', 'parent' , medium_panel );

uicontrol ('style', 'text', 'units', 'normalized', 'position', [0.001 0.415 0.8 0.07],...
    'HorizontalAlignment','left', 'FontWeight', 'bold','fontsize' , 12 ,...
    'string', 'size of propagation step:'  ,'tag', 'dz_size_text', 'parent' , medium_panel );

uicontrol ('style', 'text', 'units', 'normalized', 'position', [0.05 0.365 0.15 0.07],...
    'HorizontalAlignment','left', 'FontWeight', 'bold','fontsize' , 12 ,...
    'string', 'dz ='  ,'tag', 'dz_text', 'parent' , medium_panel );

 uicontrol ('style', 'edit', 'units', 'normalized', 'position', [0.16 0.38 0.15 0.06],...
     'HorizontalAlignment','center', 'FontWeight', 'normal','fontsize' , 12 ,...
     'string', '5' ,'backgroundcolor',[1 1 1],'tag', 'dz_edit','enable','on', 'parent' , medium_panel );

 uicontrol ('style', 'text', 'units', 'normalized', 'position', [0.35 0.365 0.3 0.07],...
     'HorizontalAlignment','left', 'FontWeight', 'bold','fontsize' , 12 ,...
     'string', 'micrometer'  ,'tag', 'dz_unit_text', 'parent' , medium_panel );

 uicontrol ('style', 'text', 'units', 'normalized', 'position', [0.001 0.285 0.8 0.07],...
     'HorizontalAlignment','left', 'FontWeight', 'bold','fontsize' , 12 ,...
     'string', 'propagation distance:'  ,'tag', 'z_distance_text', 'parent' , medium_panel );

 uicontrol ('style', 'text', 'units', 'normalized', 'position', [0.05 0.235 0.15 0.07],...
     'HorizontalAlignment','left', 'FontWeight', 'bold','fontsize' , 12 ,...
     'string', 'z ='  ,'tag', 'z_text', 'parent' , medium_panel );

uicontrol ('style', 'edit', 'units', 'normalized', 'position', [0.16 0.25 0.15 0.06],...
    'HorizontalAlignment','center', 'FontWeight', 'normal','fontsize' , 12 ,...
    'string', '1000' ,'backgroundcolor',[1 1 1],'tag', 'steps_edit','enable','on', 'parent' , medium_panel );

uicontrol ('style', 'popupmenu', 'units', 'normalized', 'position', [0.35 0.237 0.28 0.07],...
    'HorizontalAlignment','left', 'FontWeight', 'normal','fontsize' , 12 ,'backgroundcolor',[1 1 1],...
    'string', {'dz steps','micrometer'} ,'tag', 'steps_popup', 'callback', @steps_popupmenu_callback, 'parent' , medium_panel );

%
%% ------------------------------------ prepare gui_handles
h = guihandles;                                                                            % get handles of uicontrols
h.fig = fig;                                                                                % figures handle
h.object = [];                                                                                % instrument object
h.back_color = back_color;                                                 % figure's background color
h.edit_box_back_color = edit_box_back_color;   % edit box background color
h.start_itr = 1;
h.Output = [];

h.dir_path = fileparts(mfilename('fullpath')); % path of the gui mfile
%
%% ------------------------------------ show figure
% update guidata
guidata ( fig, h );

% show figure
hide_object(parameters_panel);
show_object(graph_panel);
movegui(fig,'center');
set(gcf,'Visible','on');

% focus on uicontrol
focus_on(h.start_pushbutton);
end
%
%% ============================================== focus_on uicontrol ===
function focus_on ( hObject )
% focus on uicontrol only if figure is visible
h = guidata (hObject);
visible_fig = findobj(h.fig,'flat','Visible','on');
if ~isempty(visible_fig)
    uicontrol(hObject);
    drawnow expose;
end
end
%
%% ============================================== hide_object ===
function hide_object (hObject)
set ( hObject, 'Visible', 'off' );
end
%
%% ============================================== show_object ===
function show_object (hObject)
set ( hObject, 'Visible', 'on' );
drawnow expose;
end
%
%% ============================================== callbacks ===
%
%% ============================================== exit_pushbutton_callback ===
function exit_pushbutton_callback (hObject,eventdata)
e = exist ('data_bpm_tmp.mat','file');
if e==2
    delete('data_bpm_tmp.mat');
end
close;                                      % close GUI and all open ports
                                            % (see close_figure_callback)
end
%
%% ============================================== close_figure_callback ===
function close_figure_callback (hObject,eventdata)
stop_pushbutton_callback (hObject,eventdata);
end
%
%% ============================================== stop_pushbutton_callback ===
function stop_pushbutton_callback (hObject,eventdata)
h = guidata(hObject);
set(findobj('tag','stop_pushbutton'),'enable','off');
set(findobj('tag','start_pushbutton'),'enable','on','BackGroundColor',h.back_color,'string','start');
set(findobj('tag','setparameters_pushbutton'),'enable','on');
set(findobj('tag','graphs_pushbutton'),'enable','on');
end
%
%% ============================================== start_pushbutton_callback ===
function flag = start_pushbutton_callback (hObject,flag)
h = guidata(hObject);
get(findobj('tag','start_pushbutton'),'string');

set(findobj('tag','stop_pushbutton'),'enable','on');
set(findobj('tag','setparameters_pushbutton'),'enable','off');
set(findobj('tag','graphs_pushbutton'),'enable','off');
set(findobj('tag','start_pushbutton'),'enable','off','string','running','BackGroundColor',[0 1 0]);
% --------------------------------------------------------------------------

[A w Lam n0 deltaN alpha m dz z]=get_data_from_gui(h);
% Propagation of gaussian using BPM

NR          =     2^13;                % Numerical Resolution

%************Propagating Parameters ********%
steps=round(z/dz);                                          % max value of z-axis
%************Medium Parameters **********%
x_max=1000*Lam;                                        % maximum value of x-axis
%........................................................................%
dx = 2*x_max/(NR-1);
x = -x_max : dx : x_max;
dkx = pi/(x_max)*(NR-1)/NR;
kx = ( (-NR/2):(NR/2-1) )*dkx;
k0  = 2*pi/Lam;
%........................................................................%

%************Inpout Field  Parameters****************%

fz=A*exp(-0.5*(abs(x)/w).^2);        % initial field distribution

N=deltaN*exp(-alpha*(abs(x)/w).^m);

    start_itr = 1;
    Output = zeros(NR,steps);
    Output(:,1) = abs(fz).^2;

%%%%%%%%%%%%%%%%%%%%%%%%
%************PROPAGATION *****************%
%%%%%%%%%%%%%%%%%%%%%%%%
    Fz=ifftshift(ifft(ifftshift(fz)));
    Fz_d=Fz.*exp(1i*(kx.^2)./(2*k0*(n0+N))*dz/2);
    fz=fftshift(fft(fftshift(Fz_d)));

for itr=start_itr:steps-1

    fz_N=fz.*exp(-1i*N*k0*dz);
    Fz=ifftshift(ifft(ifftshift(fz_N)));
    D=exp(1i*(kx.^2)./(2*k0*(n0+N))*dz);
    Fz_D=Fz.*D;
    fz=fftshift(fft(fftshift(Fz_D)));

    plot(h.ax1,x,abs(fz).^2);
    axis(h.ax1,[-0.5*10^-4 0.5*10^-4 0 4*A]);
    set(get(h.ax1,'XLabel'),'String','\bfr [m]');
    set(get(h.ax1,'YLabel'),'String','\bfI [r]');
    set(get(h.ax1,'Title'),'String','\bfIntensity');

    Output(:,itr)=abs(fz).^2;

    imagesc((0:itr)*dz,x,Output(:,1:itr),'parent',h.ax2);
    colormap('hot');
    ylim(h.ax2,[-0.5*10^-4 0.5*10^-4]);
    set(get(h.ax2,'XLabel'),'String','\bfz [m]');
    set(get(h.ax2,'YLabel'),'String','\bfr [m]');
    set(get(h.ax2,'Title'),'String','\bfIntensity Map');
    drawnow;

    val1 = get(findobj('tag','stop_pushbutton'),'enable');
    if strcmp(val1,'off')
        break
    end

end

Fz=ifftshift(ifft(ifftshift(fz)));
Fz_d=Fz.*exp(1i*(kx.^2)./(2*k0*(n0+N))*dz/2);
fz=fftshift(fft(fftshift(Fz_d)));

Output(:,itr+1)=abs(fz).^2;
save('data_bpm_tmp.mat','Output');

plot(h.ax1,x,abs(fz).^2);
axis(h.ax1,[-0.5*10^-4 0.5*10^-4 0 4*A]);
set(get(h.ax1,'XLabel'),'String','\bfr [m]');
set(get(h.ax1,'YLabel'),'String','\bfI [r]');
set(get(h.ax1,'Title'),'String','\bfIntensity');

imagesc((0:itr)*dz,x,Output(:,1:itr+1),'parent',h.ax2);
colormap('hot');
ylim(h.ax2,[-0.5*10^-4 0.5*10^-4]);
set(get(h.ax2,'XLabel'),'String','\bfz [m]');
set(get(h.ax2,'YLabel'),'String','\bfr [m]');
set(get(h.ax2,'Title'),'String','\bfIntensity Map');

% ---------------------------------------------
    set(findobj('tag','start_pushbutton'),'enable','on','string','running','BackGroundColor',h.back_color,'string','start');
    set(findobj('tag','stop_pushbutton'),'enable','off');
    set(findobj('tag','setparameters_pushbutton'),'enable','on');
    set(findobj('tag','graphs_pushbutton'),'enable','on');
end
%
%% ============================================== save_pushbutton_callback ===
function save_pushbutton_callback (hObject,eventdata)
h = guidata(hObject);
e = exist ('data_bpm_tmp.mat','file');
if e==2
    load('data_bpm_tmp.mat');
else
    Output = [];
end
uisave('Output','BPM Simulation.mat');
end
%
%% ============================================== graphs_pushbutton_callback ===
function graphs_pushbutton_callback (hObject,eventdata)
h=guidata(hObject);
hide_object(h.p_panel);
show_object(h.g_panel);
end
%
%% ============================================== setparameters_pushbutton_callback ===
function setparameters_pushbutton_callback (hObject,eventdata)
h=guidata(hObject);
hide_object(h.g_panel);
show_object(h.p_panel);

% focus on uicontrol
focus_on(h.start_pushbutton);
end
%
%% ============================================== lambda_popupmenu_callback ===
function lambda_popupmenu_callback (hObject,eventdata)
h=guidata(hObject);
val=get(h.lambda_popup,'value');
lambda_edit=findobj('tag','lambda_edit');
lambda=get(lambda_edit,'string');

switch val
    case 1
        new_lambda=num2str(str2double(lambda)/1000);
        set(lambda_edit,'string',new_lambda);
    case 2
        new_lambda=num2str(str2double(lambda)*1000);
        set(lambda_edit,'string',new_lambda);
end
end
%
%% ============================================== medium_popupmenu_callback ===
function medium_popupmenu_callback (hObject,eventdata)
h=guidata(hObject);
val=get(h.medium_popup,'value');
n0=findobj('tag','n0_edit');
n1=findobj('tag','n1_edit');
alpha=findobj('tag','alpha_edit');
m=findobj('tag','m_edit');

switch val
    case 1
        set(n0,'enable','on');
        set(n1,'enable','off','string','0');
        set(alpha,'enable','off','string','0.5');
        set(m,'enable','off','string','0');
    case 2
        set(n0,'enable','on');
        set(n1,'enable','on','string','10');
        set(alpha,'enable','on');
        set(m,'enable','off','string','1');
    case 3
        set(n0,'enable','on');
        set(n1,'enable','on','string','10');
        set(alpha,'enable','on');
        set(m,'enable','off','string','2');
    case 4
        set(n0,'enable','on');
        set(n1,'enable','on');
        set(alpha,'enable','on');
        set(m,'enable','on');
end

end
%
%% ============================================== steps_popupmenu_callback ===
function steps_popupmenu_callback (hObject,eventdata)
h=guidata(hObject);
val=get(h.steps_popup,'value');
steps_edit=findobj('tag','steps_edit');
steps=get(steps_edit,'string');
dz=str2double(get(findobj('tag','dz_edit'),'string'));

switch val
    case 1
        new_steps=num2str(round(str2double(steps)/dz));
        set(steps_edit,'string',new_steps);
    case 2
        new_steps=num2str(round(str2double(steps)*dz));
        set(steps_edit,'string',new_steps);
end

end
%
%% ============================================== get_data_from_gui ===
function [A w lambda n0 n1 alpha m dz z]=get_data_from_gui(h)
A_text=get(h.A_edit,'string');
A=str2double(A_text);

w_text=get(h.w_edit,'string');
w=str2double(w_text);
w=w*10^(-6);

lambda_text=get(h.lambda_edit,'string');
lambda=str2double(lambda_text);
w_val=get(h.lambda_popup,'value');
switch w_val
    case 1
        lambda=lambda*10^(-6);
    case 2
        lambda=lambda*10^(-9);
end

n0_text=get(h.n0_edit,'string');
n0=str2double(n0_text);

n1_text=get(h.n1_edit,'string');
n1=str2double(n1_text);
n1=n1*10^(-4);

alpha_text=get(h.alpha_edit,'string');
alpha=str2double(alpha_text);

m_text=get(h.m_edit,'string');
m=str2double(m_text);

dz_text=get(h.dz_edit,'string');
dz=str2double(dz_text);
dz=dz*10^(-6);

z_text=get(h.steps_edit,'string');
z=str2double(z_text);
z_val=get(h.steps_popup,'value');
switch z_val
    case 1
        z=z*dz;
    case 2
        z=z*10^(-6);
end
end


function [F, isArrayValued] = quasi2cheb(F)
%QUASI2CHEB   Convert a quasimatrix to an array-valued CHEBFUN.
%   QUASI2CHEB(F) converts the quasimatrix F to an array-valued CHEBFUN by
%   taking the union of the domains of each of the columns.
%
%   [G, ISARRAYVALUED] = QUASI2CHEB(F) returns a second output with the value
%   TRUE if G is a CHEBFUN (i.e,. numel(G) == 1), and FALSE if G remains a
%   quasimatrix.
%
% See also QUASIMATRIX, CHEB2QUASI, NUM2CELL.

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

if ( numel(F) < 2 )
    % F is already a quasimatrix!
    isArrayValued = 1;
    return
end

% Unify the breakpoints:
F = restrict(F, get(F, 'domain'));

% Collect each column in a cell:
F = cheb2cell(F);

% Call CAT to collate the columns:
F = cat(2 - F{1}.isTransposed, F{:});

isArrayValued = numel(F) == 1;

end


%PLOT_POINT	Draw a feature point
%
% PLOT_POINT(P, OPTIONS) adds point markers to the current plot, where P (2xN)
% and each column is the point coordinate.
%
% Options::
%  'textcolor', colspec     Specify color of text
%  'textsize', size         Specify size of text
%  'bold'                   Text in bold font.
%  'printf', {fmt, data}    Label points according to printf format
%                           string and corresponding element of data
%  'sequence'               Label points sequentially
%
% Additional options are passed through to PLOT for creating the marker.
%
% Examples::
%   Simple point plot
%        P = rand(2,4);
%        plot_point(P);
%
%   Plot points with markers
%        plot_point(P, '*');
%
%   Plot points with square markers and labels 1 to 4
%        plot_point(P, 'sequence', 's');
%
%   Plot points with circles and annotations P1 to P4
%        data = [1 2 4 8];
%        plot_point(P, 'printf', {' P%d', data}, 'o');
%
% Notes::
% - The point(s) is added to the current plot.
% - 2D points only.
%
% See also PLOT, TEXT.

% Copyright (C) 1993-2014, 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

function plot_point(p, varargin)

    opt.textcolor = 'g';
    opt.textsize = 12;
    opt.printf = [];
    opt.sequence = false;
    opt.bold = false;

    [opt,arglist] = tb_optparse(opt, varargin);

    % default marker style
    if isempty(arglist)
        arglist = {'sb'};
    end

    % add stuff to pull .u and .v out of a vector of objects
    if ~isnumeric(p) && any(strcmp('u_', properties(p)))
        % p is an object with u_ and v_ properties
        p = [[p.u_]; [p.v_]];
    end

    holdon = ishold();
	hold on
	for i=1:numcols(p)
		plot(p(1,i), p(2,i), arglist{:});
        if opt.sequence
            show(p(:,i), '%d', i, opt);
        end

        if ~isempty(opt.printf)
            show(p(:,i), opt.printf{1}, opt.printf{2}(i), opt);
        end

	end
    if ~holdon
        hold off
    end
    figure(gcf)
end

function show(p, fmt, val, opt)
    if opt.bold
        fw = 'bold';
    else
        fw = 'normal';
    end
    text(p(1), p(2), sprintf([' ' fmt], val), ...
        'HorizontalAlignment', 'left', ...
        'VerticalAlignment', 'middle', ...
        'FontUnits', 'pixels', ...
        'FontSize', opt.textsize, ...
        'FontWeight', fw, ...
        'Color', opt.textcolor);
end


function value = p23_autonomous ( )

%*****************************************************************************80
%
%% P23_AUTONOMOUS reports whether problem P23 is autonomous.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    17 February 2013
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, integer VALUE, is 1 if the equation is autonomous.
%
  value = 1;

  return
end


function labels = loadMNISTLabels(filename)
%loadMNISTLabels returns a [number of MNIST images]x1 matrix containing
%the labels for the MNIST images

fp = fopen(filename, 'rb');
assert(fp ~= -1, ['Could not open ', filename, '']);

magic = fread(fp, 1, 'int32', 0, 'ieee-be');
assert(magic == 2049, ['Bad magic number in ', filename, '']);

numLabels = fread(fp, 1, 'int32', 0, 'ieee-be');

labels = fread(fp, inf, 'unsigned char');

assert(size(labels,1) == numLabels, 'Mismatch in label count');

fclose(fp);

end


function signal = set_selepos(varargin)
% Select a set of epochs from a data set.
% Signal = set_selepos(Signal, EpochIndices)
%
% In:
%   Signal       : epoched EEGLAB data set from which epochs shall be selected
%
%   EpochIndices : indices of the epochs that should be retained
%
% Out:
%   Signal       : Newly created data set consisting of the retained epochs in the order
%                  specified in EpochIndices.
%
% Examples:
%   % for an epoched data set, select epochs 50-100
%   eeg = set_selepos(eeg,50:100)
%
% See also:
%   set_selinterval, set_partition, set_makepos
%
%                                Christian Kothe, Swartz Center for Computational Neuroscience, UCSD
%                                2010-04-01
dp;

% set_selepos_version<2.0> -- for the cache

if ~exp_beginfun('editing') return; end

declare_properties('independent_channels',true,'independent_trials',false);

arg_define(varargin, ...
    arg_norep({'signal','Signal'}), ...
    arg({'epoch_range','EpochIndices','epos'},[],uint32([1 1000000]),'Indices of retained epochs.','shape','row'));

% input validation
utl_check_fields(signal,{'epoch','event','data','pnts'},'signal','signal'); %#ok<NODEF>
if isempty(signal.epoch) && size(signal.data,3) > 1
    error('Your signal has epoched data but has an empty .epoch field. This is not permitted. Use set_makepos instead of pop_epoch for epoching in BCILAB.'); end

if ~isempty(signal.epoch)
    if ~isfield(signal.epoch,'event')
        error('The given signal is lacking the required .epoch.event field.'); end
    if isa(epoch_range,'logical') %#ok<NODEF>
        epoch_range = find(epoch_range); end
    if ~isreal(epoch_range)
        error('The given epoch range contains data that is not real-valued.'); end
    if length(signal.epoch) < max(epoch_range)
        error('The epoch range to select exceeds the length of the signal''s .epoch field (%i): %s.',length(signal.epoch),hlp_tostring(epoch_range)); end

    % select epochs within time series fields
    for field = utl_timeseries_fields(signal)
        if ~isempty(signal.(field{1}))
            try
                signal.(field{1}) = signal.(field{1})(:,:,epoch_range,:,:,:,:,:);
            catch e
                error('The given epoch indices could not be extracted from the time-series field .%s with error: %s. Field size was: %i, epoch indices were: %s',field{1},e.message,size(signal.(field{1}),3),hlp_tostring(epoch_range));
            end
        end
    end

    % reindex .epoch field
    signal.epoch = signal.epoch(epoch_range);
    % reindex .event field
    signal.event = signal.event([signal.epoch.event]);
    if ~isempty(epoch_range)
        % get new .event.epoch indices
        epoch_numevents = cellfun('length',{signal.epoch.event});
        for j=length(epoch_numevents):-1:1
            tmp{j} = ones(1,epoch_numevents(j))*j; end;
        epoch_indices = [tmp{:}];
        if ~isempty(signal.event)
            % validate signal.event
            if ~isfield(signal.event,'latency')
                error('The given signal is lacking the required .event.latency field.'); end
            if ~isfield(signal.event,'epoch')
                error('The given signal is lacking the required .event.epoch field.'); end
            latency_numels = cellfun('prodofsize',{signal.event.latency});
            if any(latency_numels == 0)
                error('The given signal has one or more events with empty .latency field. This is not permitted.');
            elseif any(latency_numels ~= 1)
                error('The given signal has one or more events with a .latency value that is not a scalar. This is not permitted.');
            end
            % rewrite pseudo-continuous event latencies based on epoch index change
            [signal.event.latency] = arraydeal([signal.event.latency] + signal.pnts*(epoch_indices - [signal.event.epoch]));
            % relink events and epochs
            [signal.event.epoch] = arraydeal(epoch_indices);
        end
        [signal.epoch.event] = chopdeal(1:length(signal.event),epoch_numevents);
    end
    % update misc meta-data
    signal.trials = size(signal.data,3);
    if ~signal.trials
        disp_once('WARNING: After set_selepos your signal is empty.'); end
elseif ~isempty(epoch_range)
    error('The given epochs could not be selected since the signal is empty.');
end

exp_endfun;


function [lats, lons] = GetCoastalPoints(Quality,maxLevel,minArea,LatLon)
%GETCOASTALPOINTS Reads the coastal points from a GSHHS file (version 2.x)
%
% USAGE:
%   [lats, lons] = GetCoastalPoints(Quality,maxLevel,minArea,LatLon)
%
% INPUTS:
%   Quality - integer specifying the quality of the coastline to load.
%       Acceptable values are 1-5. Only the coastline corresponding to 1
%       is available by default. REQUIRED
%   maxLevel - max level of data coastline to load. Levels are:
%           1 land, 2 lake, 3 island in lake, 4 pond in island in lake.
%           Default 1
%   minArea - minimum area (km^2) within a coastline to load. Default 10
%   LatLon - 1 by 4 vector describing a window in which a coastline must be
%       included in order for it to be loaded. Values are
%       [minLat minLong maxLat maxLon]. If empty load all. Default []
%
% OUTPUTS:
%   lats - latitude coordinates.
%   lons - longitude coordinates.
%
% Note: shapes are separated by NaN
%
% GSHHS data and a description of its format can be found at:
%
% "A Global Self-consistent, Hierarchical, High-resolution Shoreline Database"
% http://www.ngdc.noaa.gov/mgg/shorelines/gshhs.html
%
% or
%
% "A Global Self-consistent, Hierarchical, High-resolution Geography Database"
% http://www.soest.hawaii.edu/pwessel/gshhs/index.html
%
% Author: Sean Hatch
% Modified by Wade Schwartzkopf to handle GSHHS version 2.x
%
% //////////////////////////////////////////
% /// CLASSIFICATION: UNCLASSIFIED       ///
% //////////////////////////////////////////

%Modified by Pat Cutler (NGA) 20130306 for load images segments LatLon
%input and documented inputs and outputs

if ~exist('maxLevel','var') || isempty(maxLevel)
    maxLevel = 1;
end

if ~exist('minArea','var') || isempty(minArea)
    minArea = 10;
end

if ~exist('LatLon','var') || isempty(LatLon)
    LatLonCheck = 0;
else
    LatLonCheck = 1;
end

% open the GSHHS data file
% the _c file contains the crudest data in the shoreline hierarchy
files = {'gshhs_c.b', 'gshhs_l.b', 'gshhs_i.b', 'gshhs_h.b', 'gshhs_f.b'};
coastline_file = files{Quality};
fid = fopen(coastline_file, 'r', 'b');
% read in all of the data blocks from the file
tot_points = 1;
lons = NaN;
lats = NaN;
while true
    % read the header of the block
    [polygon_id, count] = fread(fid, 1, 'int32'); % Unique polygon id number, starting at 0
    if (count < 1)
        break;
    end
    num_points = fread(fid, 1, 'int32');  % Number of points in this polygon
    flag = fread(fid, 1, 'int32');
    level = bitand(flag, 255); % 1 land, 2 lake, 3 island_in_lake, 4 pond_in_island_in_lake
    version = bitand(bitshift(flag,-8),255); % Should be 7 for GSHHS release 7 (i.e., version 2.0)
    greenwich = bitget(flag,17); % Greenwich is 1 if Greenwich is crossed
    source = bitget(flag,25); % 0 = CIA WDBII, 1 = WVS
    river = bitget(flag,26); % 0 = not set, 1 = river-lake and level = 2
    % Min/max extent stored in file in micro-degrees
    west  = fread(fid, 1, 'int32') ./ 1e6; % degrees
    east  = fread(fid, 1, 'int32') ./ 1e6; % degrees
    south = fread(fid, 1, 'int32') ./ 1e6; % degrees
    north = fread(fid, 1, 'int32') ./ 1e6; % degrees
    area  = fread(fid, 1, 'int32') ./10;   % Area of polygon in km^2
    area_full  = fread(fid, 1, 'int32') ./10; % Area of original full-resolution polygon in km^2
    container = fread(fid, 1, 'int32'); % Id of container polygon that encloses this polygon (-1 if none)
    % Id of ancestor polygon in the full resolution set that was the source of this polygon (-1 if none)
    ancestor = fread(fid, 1, 'int32');
    % make sure that this is a coast for land of a reasonable size
    if (level <= maxLevel) && (area(1) > minArea)
        if checkAOI(east,west,north,south)
            % read in the lons/lats of all the data points
            data = fread(fid, [2,num_points] , 'int32') ./ 1e6;

            % shift the range of the longitudes
            hi = find(data(1,:) > 180);
            data(1,hi) = data(1,hi) - 360;

            % check for wrap around
            wraps = [find(abs(diff(data(1, :))) > 180), num_points];
            num_wraps = length(wraps);
            unwrap = data(:,1:wraps(1));
            if num_wraps > 1
                check = zeros(num_wraps-1,1);
                for index = 2:num_wraps
                    check(index-1) = checkAOI(max(data(2,wraps(index-1)+1:wraps(index))),...
                        min(data(2,wraps(index-1)+1:wraps(index))),...
                        max(data(1,wraps(index-1)+1:wraps(index))),...
                        min(data(1,wraps(index-1)+1:wraps(index))));

                    unwrap = [unwrap, [NaN;NaN], data(:,wraps(index-1)+1:wraps(index))];
                end
                if ~any(check)
                    continue
                end
            end
            data = unwrap;
            num_points = num_points + num_wraps - 1;

            % concatenate them to the rest of the list
            tot_points = tot_points + num_points + 1;
            lons = [lons, data(1, :), NaN];
            lats = [lats, data(2, :), NaN];
        else
            % skip over the data points
            fseek(fid, 8.*num_points, 'cof');
        end
    else
        % skip over the data points
        fseek(fid, 8.*num_points, 'cof');
    end
end

% close the data file
fclose(fid);

    function check = checkAOI(east,west,north,south)
        if LatLonCheck
            if west > 180
                west = west-360;
            end
            if east > 180
                east = east-360;
            end
            %longitudinal exclusion
            LonExclude = (west < LatLon(2) && east < LatLon(2)) || (west > LatLon(4) && east > LatLon(4));
            %latitudinal exclusion
            LatExclude = (south < LatLon(1) && north < LatLon(1)) || (south > LatLon(3) && north > LatLon(3));
            if LonExclude || LatExclude
                check = 0;
            else
                %longitudinal crossing
                LonCross = (west < LatLon(2) && east > LatLon(2)) || (west < LatLon(4) && east > LatLon(4));
                %latitudinal crossing
                LatCross = (south < LatLon(1) && north > LatLon(1)) || (south < LatLon(3) && north > LatLon(3));
                if LonCross && ~LonExclude
                    check = 1;
                else if LatCross && ~LatExclude
                        check = 1;
                    else
                        check = 0;
                    end
                end
            end
        else
            check = 1;
        end
    end

end

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


function value = p34_autonomous ( )

%*****************************************************************************80
%
%% P34_AUTONOMOUS reports whether problem P34 is autonomous.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    17 February 2013
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, integer VALUE, is 1 if the equation is autonomous.
%
  value = 1;

  return
end


function pyObj = bst_mat2py(matArray, isForced)
% BST_MAT2PY: Converts Matlab matrices to Python arrays
%
% INPUTS:
%    - matArray: Matlab array to convert to a Python array
%    - isForced: Boolean, if 1: force a manual conversion of the array.
%                Useful for preventing Matlab from transposing the row vectors into column vectors.
%
% @=============================================================================
% 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: Martin Cousineau, 2019
%          Francois Tadel, 2020

% Parse inputs
if (nargin < 2) || isempty(isForced)
    isForced = 0;
end

% Get Matlab version
MatlabVersion = bst_get('MatlabVersion');
% Empty objects
if isempty(matArray)
    pyObj = py.None;
% Matlab >= 2020b: Can convert everything
elseif (MatlabVersion >= 909) && ~isForced
    pyObj = matArray;
% Matlab <= 2020a: Must do some manual conversions
else
    switch class(matArray)
        case {'double', 'single', 'logical', 'int8', 'int16', 'int32', 'int64', 'uint8', 'uint16', 'uint32', 'uint64'}
            % Convert numerical matrices to Numpy arrays
            shape = int64(size(matArray));
            pyObj = py.numpy.array(reshape(matArray', 1, []));
            pyObj = pyObj.reshape(shape);

        case 'cell'
            % Convert cell arrays to Python lists (which support mixed types)
            pyObj = py.list(matArray(:)');

        otherwise
            error(['Unsupported class: ' class(matArray)]);
    end
end


%PLOTSOM Plot the Self-Organizing Map in 2D
%
%    PLOTSOM(W)
%
% Plot the Self-Organizing Map W, trained by som.m. This is only
% possible if the map is 2D.
%
% SEE ALSO (PRTools Guide)
% SOM


function y = any(x)

% ANY    True if any element of a vector is a nonzero number or is
%    logical 1 (TRUE).  ANY ignores entries that are NaN (Not a Number).
%
%    For vectors, ANY(V) returns logical 1 (TRUE) if any of the
%    elements of the vector is a nonzero number or is logical 1 (TRUE).
%    Otherwise it returns logical 0 (FALSE).  For matrices, ANY(X)
%    operates on the columns of X, returning a row vector of logical 1's
%    and 0's.

if nargin>1
  error('this implementation is only supported with one input argument');
end

siz = size(x);
if numel(siz)>2
  error('this implementation is only supported with vector or matrix input');
end

if siz(1)==1 || siz(2)==1
  y = false;
  for i=1:prod(siz)
    if x(i)
      y = true;
      break
    end
  end

else
  y = false(1,siz(2));
  for j=1:siz(2)
    for i=1:siz(1)
      if x(i,j)
        y(1,j) = true;
        break
      end
    end
  end

end