classdef ParadigmSpecCSP < ParadigmDataflowSimplified
    % Advanced paradigm for oscillatory processes via the Spectrally weighted CSP algorithm.
    %
    % The Spec-CSP paradigm [1] is a more advanced variant of CSP, developed for the Berlin
    % Brain-Computer Interface (BBCI); the primary focus was motor imagery BCI, but the algorithm was
    % designed from the outset to be applicable for a wider range of applications. The implementation
    % closely follows the TR [2].
    %
    % The paradigm is applicable to the majority of oscillatory processes, and is the most advanced
    % spatio-spectrally adaptive method that is currently provided in the toolbox. Whenever the exact
    % frequency and location of some (conjectured) oscillatory process is not known exactly, Spec-CSP
    % can be used, and typically gives better results than CSP with an appropriately unrestricted (e.g.,
    % broad-band) spectral filter. Several other methods exist to adapt the spectrum to a process of
    % interest, among others Common Spatio-Spectral Patterns [3], Common Sparse Spectral Spatial Pattern
    % [4], r^2-based heuristics [5], automated parameter search, and manual selection based on visual
    % inspection. Several of these methods have been shown to give approx. comparable results [2]. An
    % alternative and competitive method, especially when there complex interactions between frequency
    % bands and time periods are to be modeled is the Dual-Augmented Lagrange paradigm
    % (para_dal/para_dal_hf).
    %
    % The method iteratively optimizes spatial and spectral filters in alternation and extracts
    % log-variance features from the resulting (filtered) signal. These features are subsequently
    % processed by a (typically simple) machine learning component, by default LDA. Learning is
    % therefore significantly slower than CSP. An option is to impose custom prior knowledge on the
    % relevant data spectrum, for example by placing a focus on the alpha rhythm, without ruling out
    % other frequencies. Note that there are parameters which constrain the spectrum: one is the
    % frequency prior and the other is the spectral filter that is applied before running the alorithm;
    % both need to be adapted when the considered spectrum shall be extended (e.g. to high-gamma
    % oscillations). Other parameters which are frequently adapted are the time window of interest and
    % the learner component (e.g., logistic regression is a good alternative choice).
    %
    % Some application areas include detection of major brain rhythm modulations (e.g. theta, alpha,
    % beta, gamma), for example related to relaxation/stress, aspects of workload, emotion,
    % sensori-motor imagery, and in general cortical idle oscillations in various modalities.
    %
    % Example: Consider the goal of predicting the emotion felt by a person at a given time. A possible
    % calibration data set for this task would contain a sequence of blocks in each of which the subject
    % is one out of several possible emotions, indicated by events 'e1','e2','e3','e4' covering these
    % blocks at regular rate. The data might for example be induced via guided imagery [6].
    %
    %   calib = io_loadset('data sets/bruce/emotions.eeg')
    %   myapproach = {'SpecCSP' 'SignalProcessing',{'EpochExtraction',[-2.5 2.5]}};
    %   [loss,model,stats] = bci_train('Data',calib,'Approach',myapproach, 'TargetMarkers',{'e1','e2','e3','e4'});
    %
    %
    % References:
    %  [1] Tomioka, R., Dornhege, G., Aihara, K., and Mueller, K.-R. "An iterative algorithm for spatio-temporal filter optimization."
    %      In Proceedings of the 3rd International Brain-Computer Interface Workshop and Training Course 2006.
    %  [2] Ryota Tomioka, Guido Dornhege, Guido Nolte, Benjamin Blankertz, Kazuyuki Aihara, and Klaus-Robert Mueller
    %      "Spectrally Weighted Common Spatial Pattern Algorithm for Single Trial EEG Classification",
    %      Mathematical Engineering Technical Reports (METR-2006-40), July 2006.
    %  [3] Steven Lemm, Benjamin Blankertz, Gabriel Curio, and Klaus-Robert M�ller.
    %      "Spatio-spectral filters for improving classification of single trial EEG."
    %      IEEE Trans Biomed Eng, 52(9):1541-1548, 2005.
    %  [4] G. Dornhege, B. Blankertz, M. Krauledat, F. Losch, G. Curio, and K.-R. M�ller,
    %      "Combined optimization of spatial and temporal filters for improving brain-computer interfacing,"
    %      IEEE Transactions on Biomedical Engineering, vol. 53, no. 11, pp. 2274?2281, 2006.
    %  [5] Benjamin Blankertz, Ryota Tomioka, Steven Lemm, Motoaki Kawanabe, and Klaus-Robert Mueller.
    %      "Optimizing spatial filters for robust EEG single-trial analysis."
    %      IEEE Signal Process Mag, 25(1):41-56, January 2008
    %  [6] Onton J & Makeig S. "Broadband high-frequency EEG dynamics during emotion imagination."
    %      Frontiers in Human Neuroscience, 2009.
    %
    % Name:
    %   Spectrally Weighted CSP
    %
    %                           Christian Kothe, Swartz Center for Computational Neuroscience, UCSD
    %                           2010-04-29

    methods

        function defaults = preprocessing_defaults(self)
            defaults = {'FIRFilter',{'Frequencies',[6 7 33 34],'Type','minimum-phase'}, 'EpochExtraction',[0.5 3.5], 'Resampling',100};
        end

        function model = feature_adapt(self,varargin)
            args = arg_define(varargin, ...
                arg_norep('signal'), ...
                arg({'patterns','PatternPairs'},3,uint32([1 1 64 1000]),'Number of CSP patterns (times two).','cat','Feature Extraction'), ...
                arg({'pp','ParameterP'},0,[-1 1],'Regularization parameter p''. Can be searched over -1:0.5:1.','cat','Feature Extraction','guru',true), ...
                arg({'qp','ParameterQ'},1,[0 4],'Regularization parameter q''. Can be searched over 0:0.5:4.','cat','Feature Extraction','guru',true), ...
                arg({'prior','SpectralPrior'},'@(f) f>=7 & f<=30',[],'Prior frequency weighting function.','cat','Feature Extraction', 'type','expression'), ...
                arg({'steps','MaxIterations'},3,uint32([1 3 10 50]),'Number of iterations. A step is spatial optimization, followed by spectral optimization.','cat','Feature Extraction'));

            [signal,n_of,pp,qp,prior,steps] = deal(args.signal,args.patterns,args.pp,args.qp,args.prior,args.steps);
            if signal.nbchan == 1
                error('Spec-CSP does intrinsically not support single-channel data (it is a spatial filter).'); end
            if signal.nbchan < args.patterns
                error('Spec-CSP prefers to work on at least as many channels as you request output patterns. Please reduce the number of pattern pairs.'); end

            % read a few parameters from the options (and re-parameterize the hyper-parameters p' and q' into p and q)
            p = pp+qp;
            q = qp;
            if isnumeric(prior) && length(prior) == 2
                prior = @(f) f >= prior(1) & f <= prior(2); end
            % number of C=Channels, S=Samples and T=Trials #ok<NASGU>
            [C,S,dum] = size(signal.data); %#ok<NASGU>
            % build a frequency table (one per DFT bin)
            freqs = (0:S-1)*signal.srate/S;
            % evaluate the prior I
            I = prior(freqs);
            % and find table indices that are supported by the prior
            bands = find(I);

            % preprocessing
            for c=1:2
                % compute the per-class epoched data X and its Fourier transform (along time), Xfft
                X{c} = exp_eval_optimized(set_picktrials(signal,'rank',c));
                [C,S,T] = size(X{c}.data);
                Xfft{c} = fft(X{c}.data,[],2);
                % the full spectrum F of covariance matrices per every DFT bin and trial of the data
                F{c} = single(zeros(C,C,max(bands),T));
                for k=bands
                    for t=1:T
                        F{c}(:,:,k,t) = 2*real(Xfft{c}(:,k,t)*Xfft{c}(:,k,t)'); end
                end
                % compute the cross-spectrum V as an average over trials
                V{c} = mean(F{c},4);
            end

            % 1. initialize the filter set alpha and the number of filters J
            J = 1; alpha{J}(bands) = 1;
            % 2. for each step
            for step=1:steps
                % 3. for each set of spectral coefficients alpha{j} (j=1,...,J)
                for j=1:J
                    % 4. calculate sensor covariance matrices for each class from alpha{j}
                    for c = 1:2
                        Sigma{c} = zeros(C);
                        for b=bands
                            Sigma{c} = Sigma{c} + alpha{j}(b)*V{c}(:,:,b); end
                    end
                    % 5. solve the generalized eigenvalue problem Eq. (2)
                    [VV,DD] = eig(Sigma{1},Sigma{1}+Sigma{2});
                    % and retain n_of top eigenvectors at both ends of the eigenvalue spectrum...
                    W{j} = {VV(:,1:n_of), VV(:,end-n_of+1:end)};
                    iVV = inv(VV)'; P{j} = {iVV(:,1:n_of), iVV(:,end-n_of+1:end)};
                    % as well as the top eigenvalue for each class
                    lambda(j,:) = [DD(1), DD(end)];
                end
                % 7. set W{c} from all W{j}{c} such that lambda(j,c) is minimal/maximal over j
                W = {W{argmin(lambda(:,1))}{1}, W{argmax(lambda(:,2))}{2}};
                P = {P{argmin(lambda(:,1))}{1}, P{argmax(lambda(:,2))}{2}};
                % 8. for each projection w in the concatenated [W{1},W{2}]...
                Wcat = [W{1} W{2}]; J = 2*n_of;
                Pcat = [P{1} P{2}];
                for j=1:J
                    w = Wcat(:,j);
                    % 9. calcualate (across trials within each class) mean and variance of the w-projected cross-spectrum components
                    for c=1:2
                        % part of Eq. (3)
                        s{c} = zeros(size(F{c},4),max(bands));
                        for k=bands
                            for t = 1:size(s{c},1)
                                s{c}(t,k) = w'*F{c}(:,:,k,t)*w; end
                        end
                        mu_s{c} = mean(s{c},1);
                        var_s{c} = var(s{c},0,1);
                    end
                    % 10. update alpha{j} according to Eqs. (4) and (5)
                    for c=1:2
                        for k=bands
                            % Eq. (4)
                            alpha_opt{c}(k) = max(0, (mu_s{c}(k)-mu_s{3-c}(k)) / (var_s{1}(k) + var_s{2}(k)) );
                            % Eq. (5), with prior from Eq. (6)
                            alpha_tmp{c}(k) = alpha_opt{c}(k).^q * (I(k) * (mu_s{1}(k) + mu_s{2}(k))/2).^p;
                        end
                    end
                    % ... as the maximum for both classes
                    alpha{j} = max(alpha_tmp{1},alpha_tmp{2});
                    % and normalize alpha{j} so that it sums to unity
                    alpha{j} = alpha{j} / sum(alpha{j});
                end
            end
            alpha = [vertcat(alpha{:})'; zeros(S-length(alpha{1}),length(alpha))];
            model = struct('W',{Wcat},'P',{Pcat},'alpha',{alpha},'freqs',{freqs},'bands',{bands},'chanlocs',{signal.chanlocs});
        end

        function features = feature_extract(self,signal,featuremodel)
            features = zeros(size(signal.data,3),size(featuremodel.W,2));
            for t=1:size(signal.data,3)
                features(t,:) = log(var(2*real(ifft(featuremodel.alpha.*fft(signal.data(:,:,t)'*featuremodel.W))))); end
        end

        function visualize_model(self,varargin) %#ok<*INUSD>
            args = arg_define([0 3],varargin, ...
                arg_norep({'myparent','Parent'},[],[],'Parent figure.'), ...
                arg_norep({'featuremodel','FeatureModel'},[],[],'Feature model. This is the part of the model that describes the feature extraction.'), ...
                arg_norep({'predictivemodel','PredictiveModel'},[],[],'Predictive model. This is the part of the model that describes the predictive mapping.'), ...
                arg({'patterns','PlotPatterns'},true,[],'Plot patterns instead of filters. Whether to plot spatial patterns (forward projections) rather than spatial filters.'), ...
                arg({'paper','PaperFigure'},false,[],'Use paper-style font sizes. Whether to generate a plot with font sizes etc. adjusted for paper.'), ...
                arg_nogui({'nosedir_override','NoseDirectionOverride'},'',{'','+X','+Y','-X','-Y'},'Override nose direction.'));
            arg_toworkspace(args);

            % no parent: create new figure
            if isempty(myparent)
                myparent = figure('Name','Common Spatial Patterns'); end
            % determine nose direction for EEGLAB graphics
            try
                nosedir = args.fmodel.signal.info.chaninfo.nosedir;
            catch
                disp_once('Nose direction for plotting not store in model; assuming +X');
                nosedir = '+X';
            end
            if ~isempty(nosedir_override)
                nosedir = nosedir_override; end
            % number of pairs, and index of pattern per subplot
            np = size(featuremodel.W,2)/2; idxp = [1:np np+(2*np:-1:np+1)]; idxf = [np+(1:np) 2*np+(2*np:-1:np+1)];
            % for each CSP pattern...
            for p=1:np*2
                subplot(4,np,idxp(p),'Parent',myparent);
                if args.patterns
                    plotdata = featuremodel.P(:,p);
                else
                    plotdata = featuremodel.W(:,p);
                end
                topoplot(plotdata,featuremodel.chanlocs,'nosedir',nosedir);
                subplot(4,np,idxf(p),'Parent',myparent);
                alpha = featuremodel.alpha(:,p);
                range = 1:max(find(alpha)); %#ok<MXFND>
                pl=plot(featuremodel.freqs(range),featuremodel.alpha(range,p));
                xlim([min(featuremodel.freqs(range)) max(featuremodel.freqs(range))]);
                l1 = xlabel('Frequency in Hz');
                l2 = ylabel('Weight');
                t=title(['Spec-CSP Pattern ' num2str(p)]);
                if args.paper
                    set([gca,t,l1,l2],'FontUnits','normalized');
                    set([gca,t,l1,l2],'FontSize',0.2);
                    set(pl,'LineWidth',2);
                end
            end
            try set(gcf,'Color',[1 1 1]); end
        end

        function layout = dialog_layout_defaults(self)
            layout = {'SignalProcessing.Resampling.SamplingRate', 'SignalProcessing.FIRFilter.Frequencies', ...
                'SignalProcessing.FIRFilter.Type', 'SignalProcessing.EpochExtraction', '', ...
                'Prediction.FeatureExtraction', '', ...
                'Prediction.MachineLearning.Learner'};
        end

        function tf = needs_voting(self)
            tf = true;
        end

    end
end


%script to reverse the entire network
s = size(original_img);
im_size = [s(1), s(2)];
contrib_cls_person_score = 1;

cls_ind = 3; %16 is person, 1 is background, 3 bike
[val, roi_ind] = max(squeeze(cls_prob(:,cls_ind)));
roi_ind = 73; % 1,9,13,14,19,26,60,102 for 0002.jpg % 83 person, 73 bike for out_0_7

fc7_roi = squeeze(fc7(roi_ind,:));
fc6_roi = squeeze(fc6(roi_ind,:));
pool_5_roi = squeeze(pool_5(roi_ind,:,:,:));
roi = rois(roi_ind,:);

disp('---start reversing the entire network')
contrib_fc7 = reverse_fc(fc7_roi,contrib_cls_person_score,cls_score_weights(:,cls_ind));
contrib_fc6 = reverse_fc(fc6_roi,contrib_fc7,fc7_weights);
contrib_roipool = reverse_fc(flat_reshape(pool_5_roi),contrib_fc6,fc6_weights);
contrib_roipool = reverse_flat_reshape(contrib_roipool, size(pool_5_roi));
disp('---completed contrib_roipool')

contrib_conv5_3 = reverse_roipool(conv5_3, pool_5_roi, contrib_roipool);
disp('---completed reverse roi_pool')

contrib_conv5_2 = reverse_conv(conv5_2, contrib_conv5_3, conv5_3_weights);
contrib_conv5_1 = reverse_conv(conv5_1, contrib_conv5_2, conv5_2_weights);
contrib_pool4 = reverse_conv(pool4, contrib_conv5_1, conv5_1_weights);
disp('---completed reverse conv5')

contrib_conv4_3 = reverse_max_vl(conv4_3, contrib_pool4);
contrib_conv4_2 = reverse_conv(conv4_2, contrib_conv4_3, conv4_3_weights);
contrib_conv4_1 = reverse_conv(conv4_1, contrib_conv4_2, conv4_2_weights);
contrib_pool3 = reverse_conv(pool3, contrib_conv4_1, conv4_1_weights);
disp('---completed reverse conv4')

contrib_conv3_3 = reverse_max_vl(conv3_3, contrib_pool3);
contrib_conv3_2 = reverse_conv(conv3_2, contrib_conv3_3, conv3_3_weights);
contrib_conv3_1 = reverse_conv(conv3_1, contrib_conv3_2, conv3_2_weights);
contrib_pool2 = reverse_conv(pool2, contrib_conv3_1, conv3_1_weights);
disp('---completed reverse conv3')

contrib_conv2_2 = reverse_max_vl(conv2_2, contrib_pool2);
contrib_conv2_1 = reverse_conv(conv2_1, contrib_conv2_2, conv2_2_weights);
contrib_pool1 = reverse_conv(pool1, contrib_conv2_1, conv2_1_weights);
disp('---completed reverse conv2')

contrib_conv1_2 = reverse_max_vl(conv1_2, contrib_pool1);
contrib_conv1_1 = reverse_conv(conv1_1, contrib_conv1_2, conv1_2_weights);
%contrib_img = reverse_conv_original_img(original_img, contrib_conv1_1, conv1_1_weights);
%disp('completed reverse conv1')

%disp('completed contrib of img')
disp('---all completed')


%SETCOST Reset classification cost matrix of dataset
%
%   A = SETCOST(A,COST,LABLIST)
%
% The classification cost matrix of the dataset A is reset to COST.
% COST should have size [C,C+n], n >= 0, if C is the number of classes.
% COST(I,J) are the costs of classifying an object of class I
% as class J. Columns C+j generate an alternative reject classes and
% may be omitted, yielding a size of [C,C].
% An empty cost matrix, COST = [] (default) is interpreted as
% COST = ONES(C) - EYE(C) (identical costs of misclassification).
%
% In LABLIST the corresponding class labels may be supplied.
% LABLIST may have only class names of the existing classes in A.
% Reset class names first by SETLABLIST if necessary.
%
% Alternatively, for classification matrices, LABLIST may refer to
% the class names stored in the feature labels. This should be used
% with care as it may disturb the existing lableling of A.
%
% If LABLIST is not given, the order defined by the existing LABLIST
% for A (determined by [NLAB,LABLIST] = renumlab(LABELS)) is used.


% prettyMap 2.0
%--------------------------------------------------------------------------
%
% plot with projection an area of the world
%
% POSSIBLE SINTAXES:
%   prettyPolar(map);
%
%   prettyPolar(map, shape);
%   prettyPolar(map, projection);
%   prettyPolar(map, lineCol);
%
%   prettyPolar(map, phiGrid, lambdaGrid);
%   prettyPolar(map, shape, projection);
%   prettyPolar(map, shape, lineCol);
%   prettyPolar(map, projection, shape);
%   prettyPolar(map, projection, lineCol);
%
%   prettyPolar(map, phiGrid, lambdaGrid, shape);
%   prettyPolar(map, phiGrid, lambdaGrid, projection);
%   prettyPolar(map, phiGrid, lambdaGrid, lineCol);
%
%   prettyPolar(map, phiMin, phiMax, lambdaMin, lambdaMax)
%   prettyPolar(map, phiMin, phiMax, shape, projection);
%   prettyPolar(map, phiMin, phiMax, shape, lineCol);
%   prettyPolar(map, phiMin, phiMax, projection, shape);
%   prettyPolar(map, phiMin, phiMax, projection, lineCol);
%
%   prettyPolar(map, phiMin, phiMax, lambdaMin, lambdaMax, shepe);
%   prettyPolar(map, phiMin, phiMax, lambdaMin, lambdaMax, projection);
%   prettyPolar(map, phiMin, phiMax, lambdaMin, lambdaMax, lineCol);
%
%   prettyPolar(map, phiGrid, lambdaGrid, phiMin, phiMax, lambdaMin, lambdaMax)
%   prettyPolar(map, phiMin, phiMax, lambdaMin, lambdaMax, shape, projection);
%   prettyPolar(map, phiMin, phiMax, lambdaMin, lambdaMax, shape, lineCol);
%   prettyPolar(map, phiMin, phiMax, lambdaMin, lambdaMax, projection, shape);
%   prettyPolar(map, phiMin, phiMax, lambdaMin, lambdaMax, projection, lineCol);
%
%   prettyPolar(map, phiGrid, lambdaGrid, phiMin, phiMax, lambdaMin, lambdaMax, shepe);
%   prettyPolar(map, phiGrid, lambdaGrid, phiMin, phiMax, lambdaMin, lambdaMax, projection);
%   prettyPolar(map, phiGrid, lambdaGrid, phiMin, phiMax, lambdaMin, lambdaMax, lineCol);
%
%   prettyPolar(map, phiGrid, lambdaGrid, phiMin, phiMax, lambdaMin, lambdaMax, shape, projection);
%   prettyPolar(map, phiGrid, lambdaGrid, phiMin, phiMax, lambdaMin, lambdaMax, shape, lineCol);
%   prettyPolar(map, phiGrid, lambdaGrid, phiMin, phiMax, lambdaMin, lambdaMax, projection, shape);
%   prettyPolar(map, phiGrid, lambdaGrid, phiMin, phiMax, lambdaMin, lambdaMax, projection, lineCol);
%
%   prettyPolar(map, phiGrid, lambdaGrid, phiMin, phiMax, lambdaMin, lambdaMax, projection, shape, lineCol);
%   prettyPolar(map, phiGrid, lambdaGrid, phiMin, phiMax, lambdaMin, lambdaMax, shape, projection, lineCol);
%
% EXAMPLE:
%   prettyPolar(map, phiMin, phiMax, lambdaMin, lambdaMax, 'Miller Cylindrical');
%
% INPUT:
%   map             matrix containing data of the whole world to be shown
%   phiGrid         array [degree]
%   lambdaGrid      array [degree]
%   phiMin          minimum latitude    [degree]
%   phiMax          maximum latitude    [degree]
%   lambdaMin       minimum longitude   [degree]
%   lambdaMax       maximum longitude   [degree]
%   projection      type of projection to be used "standard" is the default
%   shape           shapefile to load as coast (or country) contour
%                       - fill          fill coasts coarse
%                       - coast         only coasts coarse
%                       - 50m           1:50000000 scale country contours
%                       - 30m           1:30000000 scale country contours
%                       - 10m           1:10000000 scale country contours
%   lineCol         [1 1 1] array of RGB component to draw the contour lines
%
% DEFAULT VALUES:
%    projection = 'Lambert'
%
% AVAILABLE PROJECTION:
%    * Lambert
%      Stereographic
%      Orthographic
%      Azimuthal Equal-area
%      Azimuthal Equidistant
%      Gnomonic
%      Satellite
%      Albers Equal-Area Conic
%      Lambert Conformal Conic
%      Mercator
%    * Miller Cylindrical
%    * Equidistant Cylindrical (world map)
%      Oblique Mercator
%      Transverse Mercator
%      Sinusoidal
%      Gall-Peters
%      Hammer-Aitoff
%      Mollweide
%      Robinson
%    * UTM
%
% SEE ALSO:
%   mapPlot, mapPlot3D, quiver
%
% REQUIREMENTS:
%   M_Map: http://www.eos.ubc.ca/~rich/map.html
%   shape files with contours
%
% VERSION: 2.1
%
% CREDITS:
%   http://www.eos.ubc.ca/~rich/map.html
%
%   Andrea Gatti
%   DIIAR - Politecnico di Milano
%   2013-12-19
%
function prettyPolar(map, phiGrid, lambdaGrid, phiMin, phiMax, lambdaMin, lambdaMax, projection, shape, lineCol)

%shape = 'coast';
%shape = 'fill';
%shape = '10m';
%shape = '30m';
%shape = '50m';

% lineCol = [0 0 0];
limitsOk = false;

% Manage opening a new figure;
tohold = false;
if length(findall(0,'Type','figure'))>=1
    if ishold
        clf;
        tohold = true;
    else
        figure;
    end
end

switch (nargin)
    case 1                                                                % prettyMap(map);
        shape = 'coast';
        lineCol = [0 0 0];
        projection = 'Miller Cylindrical';
        phiMin = 90;
        phiMax = -90;
        lambdaMin = -180;
        lambdaMax = 180;

        deltaPhi = (phiMax-phiMin)/size(map,1);
        deltaLambda = (lambdaMax-lambdaMin)/size(map,2);

        phiGrid    = (phiMin + deltaPhi/2 : deltaPhi : phiMax - deltaPhi/2)';
        lambdaGrid = (lambdaMin + deltaLambda/2 :  deltaLambda :  lambdaMax  - deltaLambda/2)';
    case 2
        shape = 'coast';
        lineCol = [0 0 0];
        projection = 'Miller Cylindrical';
        if (ischar(phiGrid))
            if (sum(strcmp(phiGrid,[{'none'},{'coast'},{'fill'},{'10m'},{'30m'},{'50m'}]))) % prettyMap(map, shape);
                shape = phiGrid;
            else                                                          % prettyMap(map, projection);
                projection = phiGrid;
            end
        elseif (length(phiGrid) == 3)                                     % prettyMap(map, lineCol);
            lineCol = phiGrid;
        end

        phiMin = 90;
        phiMax = -90;
        lambdaMin = -180;
        lambdaMax = 180;

        deltaPhi = (phiMax-phiMin)/size(map,1);
        deltaLambda = (lambdaMax-lambdaMin)/size(map,2);

        phiGrid    = (phiMin + deltaPhi/2 : deltaPhi : phiMax - deltaPhi/2)';
        lambdaGrid = (lambdaMin + deltaLambda/2 :  deltaLambda :  lambdaMax  - deltaLambda/2)';
    case 3
        shape = 'coast';
        lineCol = [0 0 0];
        if (ischar(phiGrid))
            projection = 'Miller Cylindrical';
            if (sum(strcmp(phiGrid,[{'none'},{'coast'},{'fill'},{'10m'},{'30m'},{'50m'}])))
                shape = phiGrid;
                if (ischar(lambdaGrid))
                    projection = lambdaGrid;                              % prettyMap(map, shape, projection);
                else
                    lineCol = lambdaGrid;                                 % prettyMap(map, shape, lineCol);
                end
            else
                projection = phiGrid;
                if (ischar(lambdaGrid))
                    shape = lambdaGrid;                                   % prettyMap(map, projection, shape);
                else
                    lineCol = lambdaGrid;                                 % prettyMap(map, projection, lineCol);
                end
            end
            phiMin = 90;
            phiMax = -90;
            lambdaMin = -180;
            lambdaMax = 180;

            deltaPhi = (phiMax-phiMin)/size(map,1);
            deltaLambda = (lambdaMax-lambdaMin)/size(map,2);

            phiGrid    = (phiMin + deltaPhi/2 : deltaPhi : phiMax - deltaPhi/2)';
            lambdaGrid = (lambdaMin + deltaLambda/2 :  deltaLambda :  lambdaMax  - deltaLambda/2)';
        else                                                              % prettyMap(map, phiGrid, lambdaGrid);
            projection = 'Miller Cylindrical';
            phiMin = max(phiGrid);
            phiMax = min(phiGrid);
            lambdaMin = min(lambdaGrid);
            lambdaMax = max(lambdaGrid);
        end
    case 4
        shape = 'coast';
        lineCol = [0 0 0];
        projection = 'Miller Cylindrical';
        if (ischar(phiMin))
            if (sum(strcmp(phiMin,[{'none'},{'coast'},{'fill'},{'10m'},{'30m'},{'50m'}])))  % prettyMap(map, phiGrid, lambdaGrid, shape);
                shape = phiMin;
            else                                                          % prettyMap(map, phiGrid, lambdaGrid, projection);
                projection = phiMin;
            end
        elseif (length(phiMin) == 3)                                      % prettyMap(map, phiGrid, lambdaGrid, lineCol);
            lineCol = phiMin;
        end

        phiMin = max(phiGrid);
        phiMax = min(phiGrid);
        lambdaMin = min(lambdaGrid);
        lambdaMax = max(lambdaGrid);
    case 5
        shape = 'coast';
        lineCol = [0 0 0];
        projection = 'Miller Cylindrical';
        if (ischar(phiMin))
            if (sum(strcmp(phiMin,[{'none'},{'coast'},{'fill'},{'10m'},{'30m'},{'50m'}])))
                shape = phiMin;
                if (ischar(phiMax))
                    projection = phiMax;                                  % prettyMap(map, phiMin, phiMax, shape, projection);
                else
                    lineCol = phiMax;                                     % prettyMap(map, phiMin, phiMax, shape, lineCol);
                end
            else
                projection = phiMin;
                if (ischar(phiMax))
                    shape = phiMax;                                       % prettyMap(map, phiMin, phiMax, projection, shape);
                else
                    lineCol = phiMax;                                     % prettyMap(map, phiMin, phiMax, projection, lineCol);
                end
            end
            phiMin = max(phiGrid);
            phiMax = min(phiGrid);
            lambdaMin = min(lambdaGrid);
            lambdaMax = max(lambdaGrid);
        else                                                             %  prettyMap(map, phiMin, phiMax, lambdaMin, lambdaMax);
            limitsOk = true;
            lambdaMin = phiMin;
            lambdaMax = phiMax;
            phiMin = phiGrid;
            phiMax = lambdaGrid;

            if (phiMin < phiMax)
                tmp = phiMin;
                phiMin = phiMax;
                phiMax = tmp;
            end

            deltaPhi = (phiMax-phiMin)/size(map,1);
            deltaLambda = (lambdaMax-lambdaMin)/size(map,2);

            phiGrid    = (phiMin + deltaPhi/2 : deltaPhi : phiMax - deltaPhi/2)';
            lambdaGrid = (lambdaMin + deltaLambda/2 :  deltaLambda :  lambdaMax  - deltaLambda/2)';
         end
    case 6
        shape = 'coast';
        lineCol = [0 0 0];
        limitsOk = true;
        projection = 'Lambert';
        if (ischar(lambdaMin))
            if (sum(strcmp(lambdaMin,[{'none'},{'coast'},{'fill'},{'10m'},{'30m'},{'50m'}])))
                shape = lambdaMin;                                        % prettyMap(map, phiMin, phiMax, lambdaMin, lambdaMax, shape);
            else
                projection = lambdaMin;                                   % prettyMap(map, phiMin, phiMax, lambdaMin, lambdaMax, projection);
            end
        elseif (length(lambdaMin) == 3)
            lineCol = lambdaMin;                                          % prettyMap(map, phiMin, phiMax, lambdaMin, lambdaMax, lineCol);
        end

        lambdaMax = phiMax;
        lambdaMin = phiMin;
        phiMin = phiGrid;
        phiMax = lambdaGrid;

        if (phiMin < phiMax)
            tmp = phiMin;
            phiMin = phiMax;
            phiMax = tmp;
        end

        deltaPhi = (phiMax-phiMin)/size(map,1);
        deltaLambda = (lambdaMax-lambdaMin)/size(map,2);

        phiGrid    = (phiMin + deltaPhi/2 : deltaPhi : phiMax - deltaPhi/2)';
        lambdaGrid = (lambdaMin + deltaLambda/2 :  deltaLambda :  lambdaMax  - deltaLambda/2)';
    case 7
        shape = 'coast';
        lineCol = [0 0 0];
        limitsOk = true;
        projection = 'Lambert';
        if (ischar(lambdaMin))
            if (sum(strcmp(lambdaMin,[{'none'},{'coast'},{'fill'},{'10m'},{'30m'},{'50m'}])))
                shape = lambdaMin;
                if (ischar(lambdaMax))
                    projection = lambdaMax;                               % prettyMap(map, phiMin, phiMax, lambdaMin, lambdaMax, shape, projection);
                else
                    lineCol = lambdaMax;                                  % prettyMap(map, phiMin, phiMax, lambdaMin, lambdaMax, shape, lineCol);
                end
            else
                projection = lambdaMin;
                if (ischar(lambdaMax))
                    shape = lambdaMax;                                    % prettyMap(map, phiMin, phiMax, lambdaMin, lambdaMax, projection, shape);
                else
                    lineCol = lambdaMax;                                  % prettyMap(map, phiMin, phiMax, lambdaMin, lambdaMax, projection, lineCol);
                end
            end

            lambdaMin = phiMin;
            lambdaMax = phiMax;
            phiMin = phiGrid;
            phiMax = lambdaGrid;

            if (phiMin < phiMax)
                tmp = phiMin;
                phiMin = phiMax;
                phiMax = tmp;
            end

            deltaPhi = (phiMax-phiMin)/size(map,1);
            deltaLambda = (lambdaMax-lambdaMin)/size(map,2);

            phiGrid    = (phiMin + deltaPhi/2 : deltaPhi : phiMax - deltaPhi/2)';
            lambdaGrid = (lambdaMin + deltaLambda/2 :  deltaLambda :  lambdaMax  - deltaLambda/2)';
        else
            projection = 'lambert';                                       % prettyMap(map, phiGrid, lambdaGrid, phiMin, phiMax, lambdaMin, lambdaMax);
        end
    case 8
        shape = 'coast';
        lineCol = [0 0 0];
        limitsOk = true;
        if (ischar(projection))
            if (sum(strcmp(projection,[{'none'},{'coast'},{'fill'},{'10m'},{'30m'},{'50m'}])))
                shape = projection;                                       % prettyMap(map, phiGrid, lambdaGrid, phiMin, phiMax, lambdaMin, lambdaMax, shape);
                projection = 'Lambert';
            else
                                                                          % prettyMap(map, phiGrid, lambdaGrid, phiMin, phiMax, lambdaMin, lambdaMax, projection);
            end
        elseif (length(projection) == 3)
            lineCol = projection;                                         % prettyMap(map, phiGrid, lambdaGrid, phiMin, phiMax, lambdaMin, lambdaMax, lineCol);
            projection = 'Lambert';
        end
    case 9
        lineCol = [0 0 0];
        limitsOk = true;
        if (ischar(projection))
            if (sum(strcmp(projection,[{'none'},{'coast'},{'fill'},{'10m'},{'30m'},{'50m'}])))
                tmp = shape;
                shape = projection;
                if (ischar(tmp))
                    projection = tmp;                                     % prettyMap(map, phiGrid, lambdaGrid, phiMin, phiMax, lambdaMin, lambdaMax, shape, projection);
                else
                    lineCol = tmp;                                        % prettyMap(map, phiGrid, lambdaGrid, phiMin, phiMax, lambdaMin, lambdaMax, shape, lineCol);
                    projection = 'UTM';
                end
            else
                if (ischar(shape))
                                                                          % prettyMap(map, phiGrid, lambdaGrid, phiMin, phiMax, lambdaMin, lambdaMax, projection, shape);
                else
                    lineCol = shape;                                      % prettyMap(map, phiGrid, lambdaGrid, phiMin, phiMax, lambdaMin, lambdaMax, projection, lineCol);
                    shape = 'coast';
                end
            end
        end
    case 10                                                               % prettyMap(map, phiGrid, lambdaGrid, phiMin, phiMax, lambdaMin, lambdaMax, projection, shape, lineCol)
        limitsOk = true;
       if (sum(strcmp(projection,[{'none'},{'coast'},{'fill'},{'10m'},{'30m'},{'50m'}])))   % prettyMap(map, phiGrid, lambdaGrid, phiMin, phiMax, lambdaMin, lambdaMax, shape, projection, lineCol)
            tmp = shape;
            shape = projection;
            projection = tmp;
       end
end

if (phiMin < phiMax)
    tmp = phiMin;
    phiMin = phiMax;
    phiMax = tmp;
end

lambdaGrid = sort(lambdaGrid);

[val idMax] = max(diff(lambdaGrid));
if sum(diff(lambdaGrid) == val) == 1
    lambdaGrid(1:idMax) = lambdaGrid(1:idMax)+360;
    if ~limitsOk
        lambdaMax = lambdaGrid(idMax);
        lambdaMin = lambdaGrid(idMax+1);
    end
end
lambdaGrid = sort(lambdaGrid);

if(lambdaMax<lambdaMin)
    lambdaMax = lambdaMax+360;
end

projection = 'Transverse Mercator';

% setup the projection
if (strcmpi(projection,[{'lambert'}]) && abs(phiMax==-phiMin))
    projection='Miller Cylindrical';
end

if (sum(strcmpi(projection,[{'lambert'},{'UTM'},{'Sinusoidal'},{'Transverse Mercator'},{'Oblique Mercator'},{'Miller Cylindrical'}])))
    m_proj(projection,'long',[lambdaMin lambdaMax],'lat',[phiMax phiMin]);
else
    m_proj(projection);
end

% Printing projection
fprintf('Using projection: %s\n', projection);

if sum(diff(lambdaGrid)<-200)
    lambdaGrid(lambdaGrid<0)=lambdaGrid(lambdaGrid<0)+360;
end
% plot the map
m_pcolor(lambdaGrid,phiGrid, map);

% set the light
shading flat;

% read shapefile
if (~strcmp(shape,'none'))
	if (~strcmp(shape,'coast')) && (~strcmp(shape,'fill'))
    	if (strcmp(shape,'10m'))
        	M=m_shaperead('countries_10m');
	    elseif (strcmp(shape,'30m'))
    	    M=m_shaperead('countries_30m');
	    else
    	    M=m_shaperead('countries_50m');
	    end
    	[xMin,yMin] = m_ll2xy(lambdaMin,phiMin);
	    [xMax,yMax] = m_ll2xy(lambdaMax,phiMax);
    	for k=1:length(M.ncst)
        	lamC = M.ncst{k}(:,1);
	        ids = lamC < lambdaMin;
   	    	lamC(ids) = lamC(ids) + 360;
        	phiC = M.ncst{k}(:,2);
        	[x,y] = m_ll2xy(lamC,phiC);
        	if sum(~isnan(x))>1
            	x(find(abs(diff(x))>=abs(xMax-xMin)*0.90)+1) = nan; % Romove lines that occupy more than th 90% of the plot
	            line(x,y,'color', lineCol);
    	    end
	    end;
    else
        if (strcmp(shape,'coast'))
        	m_coast('line','color', lineCol);
        else
            m_coast('patch',lineCol);
        end
	end
end

m_grid('box','fancy','tickdir','in');
drawnow;
if (phiMax >= 0)
    h=get(gca,'Children'); hf = findobj(h(1:end),'Tag','m_grid_fancybox1');
    delete(h(18));
    delete(hf([1:5 8]));
else
    h=get(gca,'Children');
    hf = findobj(h(1:end),'Tag','m_grid_fancybox1');
    %delete(h(18));
    delete(hf([1:4 6 7]));
end
colorbar;

if tohold
    hold on;
end


% This is material illustrating the methods from the book
% Financial Modelling  - Theory, Implementation and Practice with Matlab
% source
% Wiley Finance Series
% ISBN 978-0-470-74489-5
%
% Date: 02.05.2012
%
% Authors:  Joerg Kienitz
%           Daniel Wetterau
%
% Please send comments, suggestions, bugs, code etc. to
% kienitzwetterau_FinModelling@gmx.de
%
% (C) Joerg Kienitz, Daniel Wetterau
%
% Since this piece of code is distributed via the mathworks file-exchange
% it is covered by the BSD license
%
% This code is being provided solely for information and general
% illustrative purposes. The authors will not be responsible for the
% consequences of reliance upon using the code or for numbers produced
% from using the code.

function optval = PW_Delta_CallPut(S,K,C,r,T)
% S = NSim x 1 matrix of simulated prices
% K = Strike price
% C = 1 -> Call; C = 0 -> Put

    if(C==1)
        Indicator = (S(:,end)>K);
    else
        Indicator = (S(:,end)<=K);
    end
    optval = mean(S(:,end)./S(1,1).*Indicator)*exp(-r*T);
end


function [ alpha1, alpha2, beta, beta1, beta2, czero, difeta, etazero, fzero, ...
  gamma1, gamma2, kappa, lambda1, lambda2, m, nu1, nu2, vzero, xl, xr ] = ...
  bio_constants ( )

%*****************************************************************************80
%
%% BIO_CONSTANTS sets biological constants.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    09 November 2005
%
%  Parameters:
%
%    Output, real XL, XR, the left and right endpoints of the region.
%

%
%  The extent of the domain.
%
  xl = 0.0;
  xr = 1.0;
%
%  The initial conditions.
%
  vzero = 15.0;
  kappa = 0.00554245;
  m = 10;
  czero = 0.0;
  fzero = 1.0;
  etazero = 1.0;
%
%  Parameters occurring in equations.
%
  lambda1 = 73.0;
  lambda2 = 19.0;
  nu1 = 0.007;
  nu2 = 1.28;
  difeta = 0.0144;
  beta = 0.222;
%
%  Parameters for calculation of TAU.
%
  alpha1 = 0.001;
  alpha2 = 1.0;
  beta1 = 1.0;
  beta2 = 0.001;
  gamma1 = 1.2;
  gamma2 = 1.2;

  return
end


%MDL_COBRA600 Create model of Adept Cobra 600 manipulator
%
% MDL_COBRA600 is a script that creates the workspace variable c600 which
% describes the kinematic characteristics of the 4-axis Adept Cobra 600
% SCARA manipulator using standard DH conventions.
%
% Also define the workspace vectors:
%   qz         zero joint angle configuration
%
% Notes::
% - SI units are used.
%
% See also SerialRevolute, mdl_puma560akb, mdl_stanford.

% Copyright (C) 1993-2017, by Peter I. Corke
%
% This file is part of The Robotics Toolbox for MATLAB (RTB).
%
% RTB is free software: you can redistribute it and/or modify
% it under the terms of the GNU Lesser General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% RTB is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU Lesser General Public License for more details.
%
% You should have received a copy of the GNU Leser General Public License
% along with RTB.  If not, see <http://www.gnu.org/licenses/>.
%
% http://www.petercorke.com

% MODEL: Adept, Cobra600, 4DOF, standard_DH

% hardstop limits included
links = [
    Revolute('d', 0.387, 'a', 0.325, 'qlim', [-50 50]*pi/180);
    Revolute('a', 0.275, 'alpha', pi, 'qlim', [-88 88]*pi/180);
    Prismatic('qlim', [0 0.210]);
    Revolute()
    ];

c600 = SerialLink(links, 'name', 'Cobra600', 'manufacturer', 'Adept', ...
    'plotopt', {'workspace', [0 0.8 -0.6 0.6 0 0.4]} );

qz = [0 0 0 0];


function [y] = crossprod(x,p,flag)

if nargin<3
  % always augment with constant term
  flag = 1;
end
if nargin<2
  % length of smoothing boxcar
  p = 1;
end
flag = double(flag);

% FIXME only works in case of dim=2
n    = size(x);
indx = tril(ones(n(1)))==1;
N    = 0.5*n(1)*(n(1)+1);
y    = zeros(N+flag, n(2));
for k = 1:n(2)
  tmp    = x(:,k)*x(:,k)';
  y(flag+(1:N),k) = tmp(indx);
end

if flag
  y(1,:) = 1;
end

if p>1
  krn = ones(1,p)./p;
  y   = convn(y, krn, 'valid');
end

% function [y] = crossprod(x, ix)
%
% %FIXME works only in case of dim=2
% n = size(x);
% y = zeros(0.5*n(1)*(n(1)+1), n(2));
% for k = 1:size(ix,1)
%   y(k,:) = x(ix(k,1),:).*x(ix(k,2),:);
% end


function accuracies = hkl_test(model,outputs,Xtest,varargin);
%%%%%%%%%%%%%%%%%%%%%%%
% HKL
%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% required parameters
%
% Xtest					test data (input)
%
% optional parameters
%
% Ytest					test data (output), to compute predictive performance

Ytest = [];                         % test data (response)

% READ OPTIONAL PARAMETERS
args = varargin;
nargs = length(args);
for i=1:2:nargs
	switch args{i},
		case 'Ytest',           Ytest = args{i+1};
	end
end

data = model.data;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% NORMALIZE DATA (in input space)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if ~strcmp(model.kernel,'base kernels') || ~strcmp(model.kernel,'base kernels-mkl') || ~strcmp(model.kernel,'base kernels-bimkl')
    switch model.data_normalization
        case  'scale'
            [ntest , p ] = size(Xtest);
            Xtest = Xtest - repmat(model.mean,ntest,1);
            Xtest = Xtest ./ repmat(model.std,ntest,1);
        case  'center'
            [ntest , p ] = size(Xtest);
            Xtest = Xtest - repmat(model.mean,ntest,1);
    end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% PREPROCESS DATA
% the structure data store all data necessary to compute the kernel for a given node
%
% for directed grids where each kernel in the graph is the product of base kernels
% each base kernels is represented through a Cholesky decomposition
%
% data.n				number of observations
% data.p				dimension of the grid
% data.q				maximal depth of the grid
% data.qs				number of kernels in each direction of the grid
% data.Xs				storing all dimensions in the same vector
% data.ind_Xs			indices corresponding to each base kernel
% data.d_Xs				rank of each base kernel
%
% for directed grids, the (unique root) is always the constant kernel (and thus zeroed out by centering)
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
switch model.kernel

	case {'polynomial','polynomial-mkl','polynomial-bimkl'}

		datatest = get_kernel_data(Xtest,model.kernel,model.kernel_params);
		datatest.dag_type =  'grid + input_space';

	case {'hermite', 'hermite-mkl', 'hermite-bimkl'}

		datatest = get_kernel_data(Xtest,model.kernel,model.kernel_params);
		datatest.dag_type =  'grid + input_space';

	case {'anova','anova-mkl','anova-bimkl'}

		datatest = get_kernel_data(Xtest,model.kernel,model.kernel_params,model.X,model.data);
		datatest.dag_type =  'grid + input_space';

	case {'spline','spline-mkl','spline-bimkl'}

		datatest = get_kernel_data(Xtest,model.kernel,model.kernel_params,model.X,model.data);
		datatest.dag_type =  'grid + input_space';

    case {'base kernels','base kernels-mkl','base kernels-bimkl'}

		datatest = get_kernel_data(Xtest,model.kernel,model.kernel_params,model.X,model.data);
		datatest.dag_type =  'grid + input_space';

	case {'gauss-hermite','gauss-hermite-mkl','gauss-hermite-bimkl'}

		datatest = get_kernel_data(Xtest,model.kernel,model.kernel_params);
		datatest.dag_type =  'grid + input_space';

	case {'gauss-hermite-full','gauss-hermite-full-mkl','gauss-hermite-full-bimkl'}

		datatest = get_kernel_data(Xtest,model.kernel,model.kernel_params,model.X,model.data);
		datatest.dag_type =  'grid + input_space';

end

switch model.kernel

	case {'hermite-mkl', 'gauss-hermite-mkl', 'gauss-hermite-full-mkl', 'polynomial-mkl', 'anova-mkl',  'spline-mkl' }
		dag_type = 'mkl + input_space';
		data.dag_type = dag_type;
		datatest.dag_type = dag_type;
	case {'hermite-bimkl', 'gauss-hermite-bimkl', 'gauss-hermite-full-bimkl', 'polynomial-bimkl', 'anova-bimkl',  'spline-bimkl' }
		dag_type = 'bimkl + input_space';
		data.dag_type = dag_type;
		datatest.dag_type = dag_type;
end

% NORMALIZATION OF BASE KERNELS
switch model.kernel_normalization
	case 'center'  % center before taking product of base kernels
		switch datatest.dag_type
			case { 'grid + input_space', 'mkl + input_space', 'bimkl + input_space'}
				for i=1:p
					for j=2:data.q+1
						datatest.Xs(:,data.ind_Xs{i}{j}) = datatest.Xs(:,data.ind_Xs{i}{j}) - repmat( model.meanXs{i}{j},n,1);
					end
				end

		end

	case 'scale'  % scale (and center) before taking product of base kernels
		switch datatest.dag_type
			case { 'grid + input_space', 'mkl + input_space', 'bimkl + input_space'}
				for i=1:p
					for j=2:data.q+1
						datatest.Xs(:,data.ind_Xs{i}{j}) = datatest.Xs(:,data.ind_Xs{i}{j}) - repmat( model.meanXs{i}{j},ntest,1);
						datatest.Xs(:,data.ind_Xs{i}{j}) = datatest.Xs(:,data.ind_Xs{i}{j}) / model.stdXs{i}{j};
					end
				end

		end

end

accuracies.predtest = NaN*ones(length(Ytest),length(outputs));
accuracies.predtest_unreg = NaN*ones(length(Ytest),length(outputs));

if ~isempty(Ytest)
	accuracies.testing_error = NaN*ones(1,length(outputs));
	accuracies.testing_error_unreg = NaN*ones(1,length(outputs));
	switch model.loss
		case 'logistic'
			accuracies.testing_error_class = NaN*ones(1,length(outputs));
			accuracies.testing_error_class_unreg = NaN*ones(1,length(outputs));
	end
end

for ilambda = 1:length(outputs)

	[predtrain,predtest] = predict_train_test(datatest,model.data,outputs{ilambda}.hull,outputs{ilambda}.alpha,outputs{ilambda}.b,outputs{ilambda}.zeta);
	[predtrain_unreg,predtest_unreg] = predict_train_test_unreg(datatest,model.data,model.Y,Ytest,outputs{ilambda}.hull);
	accuracies.predtest(:,ilambda) = predtest;
	accuracies.predtrain(:,ilambda) = predtrain;
	accuracies.predtest_unreg(:,ilambda) = predtest_unreg;
	accuracies.predtrain_unreg(:,ilambda) = predtrain_unreg;
	if ~isempty(Ytest)
		switch model.loss
			case 'square'
				accuracies.training_error(ilambda) =  sum( ( model.Y - predtrain ).^2 ) /length(model.Y);
				accuracies.testing_error(ilambda) =  sum( ( Ytest - predtest ).^2 ) /length(Ytest);
				accuracies.training_error_unreg(ilambda) =  sum( ( model.Y - predtrain_unreg ).^2 ) /length(model.Y);
				accuracies.testing_error_unreg(ilambda) =  sum( ( Ytest - predtest_unreg ).^2 ) /length(Ytest);

			case 'logistic'
				accuracies.training_error_class(ilambda) =  sum( abs( model.Y - (sign(predtrain-.5)+1)/2 ) ) /length(model.Y);
				accuracies.testing_error_class(ilambda) =  sum( abs( Ytest - (sign(predtest-.5)+1)/2 ) ) /length(Ytest);
				accuracies.training_error_class_unreg(ilambda) =  sum( abs( model.Y - (sign(predtrain_unreg-.5)+1)/2 ) ) /length(model.Y);
				accuracies.testing_error_class_unreg(ilambda) =  sum( abs( Ytest - (sign(predtest_unreg-.5)+1)/2 ) ) /length(Ytest);
				accuracies.training_error(ilambda) =  sum(  model.Y .* log( 1 + exp( -predtrain) ) + ( 1 - model.Y ) .* log( 1 + exp(predtrain) )  ) /length(model.Y);
				accuracies.testing_error(ilambda) =  sum(  Ytest .* log( 1 + exp( -predtest) ) + ( 1 - Ytest ) .* log( 1 + exp(predtest) )  ) /length(Ytest);
				accuracies.training_error_unreg(ilambda) =  sum(  model.Y .* log( 1 + exp( -predtrain_unreg) ) + ( 1 - model.Y ) .* log( 1 + exp(predtrain_unreg) )  ) /length(model.Y);
				accuracies.testing_error_unreg(ilambda) =  sum(  Ytest .* log( 1 + exp( -predtest_unreg) ) + ( 1 - Ytest ) .* log( 1 + exp(predtest_unreg) )  ) /length(Ytest);
		end

	end

end


function timer_tictoc_test01 ( )

%*****************************************************************************80
%
%% TEST01 times the RAND routine.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    16 June 2006
%
%  Author:
%
%    John Burkardt
%
  n_log_min = 10;
  n_log_max = 20;
  n_min = 2^n_log_min;
  n_max = 2^n_log_max;
  n_rep = 5;

  fprintf ( 1, '\n' );
  fprintf ( 1, 'TEST01\n' );
  fprintf ( 1, '  Time the MATLAB RAND routine:\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '    x = rand(n,1);\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Data vectors will be of minimum size %d\n', n_min );
  fprintf ( 1, '  Data vectors will be of maximum size %d\n', n_max );
  fprintf ( 1, '  Number of repetitions of the operation: %d\n', n_rep );

  for i_rep = 1 : n_rep

    for n_log = n_log_min : n_log_max

      n = 2^n_log;

      tic;

      x = rand(n,1);

      delta(n_log,i_rep) = toc;

    end

  end

  fprintf ( 1, '\n' );
  fprintf ( 1, 'TEST01 Results:\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, 'Vector Size  Rep #1        Rep #2        Rep #3        ' );
  fprintf ( 1, 'Rep #4        Rep #5\n' );
  fprintf ( 1, '\n' );

  for n_log = n_log_min : n_log_max
    n = 2^n_log;
    fprintf ( 1, '%10d', n );
    for j = 1 : n_rep
      fprintf ( '%14f', delta(n_log,j) );
    end
    fprintf ( 1, '\n' );
  end

  return
end


%% DEMO_febio_0011_cube_multi_generation
% Below is a demonstration for:
%
% * Building geometry for a cube with hexahedral elements
% * Defining the boundary conditions
% * Coding the febio structure
% * Running the model
% * Importing and visualizing the displacement and stress results

%% Keywords
%
% * febio_spec version 3.0
% * febio, FEBio
% * compression, tension, compressive, tensile
% * displacement control, displacement boundary condition
% * hexahedral elements, hex8
% * cube, box, rectangular
% * static, solid
% * multigeneration, multi-generation
% * multi-step analysis
% * hyperelastic, Ogden
% * displacement logfile
% * stress logfile

%%

clear; close all; clc;

%% Plot settings
fontSize=20;
faceAlpha1=0.8;
markerSize=40;
lineWidth=3;

%% Control parameters

% Path names
defaultFolder = fileparts(fileparts(mfilename('fullpath')));
savePath=fullfile(defaultFolder,'data','temp');

% Defining file names
febioFebFileNamePart='tempModel';
febioFebFileName=fullfile(savePath,[febioFebFileNamePart,'.feb']); %FEB file name
febioLogFileName=[febioFebFileNamePart,'.txt']; %FEBio log file name
febioLogFileName_disp=[febioFebFileNamePart,'_disp_out.txt']; %Log file name for exporting displacement
febioLogFileName_strainEnergy=[febioFebFileNamePart,'_energy_out.txt']; %Log file name for exporting strain energy density

%Specifying dimensions and number of elements
cubeSize=10;
sampleWidth=cubeSize; %Width
sampleThickness=cubeSize; %Thickness
sampleHeight=cubeSize; %Height
pointSpacings=1*ones(1,3); %Desired point spacing between nodes
numElementsWidth=round(sampleWidth/pointSpacings(1)); %Number of elemens in dir 1
numElementsThickness=round(sampleThickness/pointSpacings(2)); %Number of elemens in dir 2
numElementsHeight=round(sampleHeight/pointSpacings(3)); %Number of elemens in dir 3

%Define applied displacement
appliedStrain=0.3; %Linear strain (Only used to compute applied stretch)
loadingOption='tension'; % or 'tension'
switch loadingOption
    case 'compression'
        stretchLoad=1-appliedStrain; %The applied stretch for uniaxial loading
    case 'tension'
        stretchLoad=1+appliedStrain; %The applied stretch for uniaxial loading
end
displacementMagnitude=(stretchLoad*sampleHeight)-sampleHeight; %The displacement magnitude

%Material parameters
k_factor=50;
c1=2;
m1=2;
k=c1*k_factor;
c1_g=[c1/1000 c1*2];
k_g=c1_g*k_factor;

% FEA control settings
numTimeSteps=10; %Number of time steps desired
max_refs=25; %Max reforms
max_ups=0; %Set to zero to use full-Newton iterations
opt_iter=6; %Optimum number of iterations
max_retries=5; %Maximum number of retires
dtmin=(1/numTimeSteps)/100; %Minimum time step size
dtmax=1/numTimeSteps; %Maximum time step size

%% Creating model geometry and mesh
% A box is created with tri-linear hexahedral (hex8) elements using the
% |hexMeshBox| function. The function offers the boundary faces with
% seperate labels for the top, bottom, left, right, front, and back sides.
% As such these can be used to define boundary conditions on the exterior.

% Create a box with hexahedral elements
cubeDimensions=[sampleWidth sampleThickness sampleHeight]; %Dimensions
cubeElementNumbers=[numElementsWidth numElementsThickness numElementsHeight]; %Number of elements
outputStructType=2; %A structure compatible with mesh view
[meshStruct]=hexMeshBox(cubeDimensions,cubeElementNumbers,outputStructType);

%Access elements, nodes, and faces from the structure
E=meshStruct.elements; %The elements
V=meshStruct.nodes; %The nodes (vertices)
Fb=meshStruct.facesBoundary; %The boundary faces
Cb=meshStruct.boundaryMarker; %The "colors" or labels for the boundary faces

%% Splitting mesh into 2 material groups

X=V(:,1); Y=V(:,2); Z=V(:,3);
VE=[mean(X(E),2) mean(Y(E),2) mean(Z(E),2)];

logicMaterial_1=VE(:,1)<0;

elementMaterialID=logicMaterial_1+1;

%Reoder E to cope with FEBio bug in relation to element ordering and
%multiple material sets
E=[E(elementMaterialID==1,:); E(elementMaterialID==2,:);];
elementMaterialID=[elementMaterialID(elementMaterialID==1,:); elementMaterialID(elementMaterialID==2,:);];

%Fix meshStruct to allow for meshView based visualization
meshStruct.elementMaterialID=elementMaterialID;
meshStruct.elements=E;

%%
% Plotting model boundary surfaces and a cut view

hFig=cFigure;

hs=subplot(1,2,1); hold on;
title('Model boundary surfaces and labels','FontSize',fontSize);
gpatch(Fb,V,Cb,'k',faceAlpha1); view(3)
colormap(gjet(12)); icolorbar;
axisGeom(gca,fontSize);

hs=subplot(1,2,2); hold on;
title('Cut view of solid mesh','FontSize',fontSize);
optionStruct.hFig=[hFig hs];
meshView(meshStruct,optionStruct);
axisGeom(gca,fontSize);

drawnow;

%% Defining the boundary conditions
% The visualization of the model boundary shows colors for each side of the
% cube. These labels can be used to define boundary conditions.

%Define supported node sets
logicFace=Cb==5; %Logic for current face set
Fr=Fb(logicFace,:); %The current face set
bcSupportList=unique(Fr(:)); %Node set part of selected face

%Prescribed displacement nodes
logicPrescribe=Cb==6; %Logic for current face set
Fr=Fb(logicPrescribe,:); %The current face set
bcPrescribeList=unique(Fr(:)); %Node set part of selected face

%%
% Visualizing boundary conditions. Markers plotted on the semi-transparent
% model denote the nodes in the various boundary condition lists.

hf=cFigure;
title('Boundary conditions','FontSize',fontSize);
xlabel('X','FontSize',fontSize); ylabel('Y','FontSize',fontSize); zlabel('Z','FontSize',fontSize);
hold on;

gpatch(Fb,V,'kw','k',0.5);

hl(1)=plotV(V(bcSupportList,:),'k.','MarkerSize',markerSize);
hl(2)=plotV(V(bcPrescribeList,:),'r.','MarkerSize',markerSize);

legend(hl,{'BC support','BC prescribe'});

axisGeom(gca,fontSize);
camlight headlight;
drawnow;

%% Defining the FEBio input structure
% See also |febioStructTemplate| and |febioStruct2xml| and the FEBio user
% manual.

%Get a template with default settings
[febio_spec]=febioStructTemplate;

%febio_spec version
febio_spec.ATTR.version='3.0';

%Module section
febio_spec.Module.ATTR.type='solid';

%Create control structure for use by all steps
stepStruct.Control.analysis='STATIC';
stepStruct.Control.time_steps=numTimeSteps;
stepStruct.Control.step_size=1/numTimeSteps;
stepStruct.Control.solver.max_refs=max_refs;
stepStruct.Control.solver.max_ups=max_ups;
stepStruct.Control.time_stepper.dtmin=dtmin;
stepStruct.Control.time_stepper.dtmax=dtmax;
stepStruct.Control.time_stepper.max_retries=max_retries;
stepStruct.Control.time_stepper.opt_iter=opt_iter;

%Add template based default settings to proposed control section
[stepStruct.Control]=structComplete(stepStruct.Control,febio_spec.Control,1); %Complement provided with default if missing

%Remove control field (part of template) since step specific control sections are used
febio_spec=rmfield(febio_spec,'Control');

febio_spec.Step.step{1}.Control=stepStruct.Control;
febio_spec.Step.step{1}.ATTR.id=1;
febio_spec.Step.step{2}.Control=stepStruct.Control;
febio_spec.Step.step{2}.ATTR.id=2;

%Material section
materialName1='Normal_material';
febio_spec.Material.material{1}.ATTR.name=materialName1;
febio_spec.Material.material{1}.ATTR.id=1;
febio_spec.Material.material{1}.ATTR.type='Ogden unconstrained';
febio_spec.Material.material{1}.c1=c1;
febio_spec.Material.material{1}.m1=m1;
febio_spec.Material.material{1}.c2=c1;
febio_spec.Material.material{1}.m2=-m1;
febio_spec.Material.material{1}.cp=k;

materialName2='Multigen_material';
febio_spec.Material.material{2}.ATTR.name=materialName2;
febio_spec.Material.material{2}.ATTR.id=2;
febio_spec.Material.material{2}.ATTR.type='multigeneration';

febio_spec.Material.material{2}.generation{1}.ATTR.id=1;
febio_spec.Material.material{2}.generation{1}.start_time=0;
febio_spec.Material.material{2}.generation{1}.solid{1}.ATTR.type='Ogden unconstrained';
febio_spec.Material.material{2}.generation{1}.solid{1}.c1=c1_g(1);
febio_spec.Material.material{2}.generation{1}.solid{1}.m1=m1;
febio_spec.Material.material{2}.generation{1}.solid{1}.c2=c1_g(1);
febio_spec.Material.material{2}.generation{1}.solid{1}.m2=-m1;
febio_spec.Material.material{2}.generation{1}.solid{1}.cp=k_g(1);

febio_spec.Material.material{2}.generation{2}.ATTR.id=2;
febio_spec.Material.material{2}.generation{2}.start_time=1;
febio_spec.Material.material{2}.generation{2}.solid{1}.ATTR.type='Ogden unconstrained';
febio_spec.Material.material{2}.generation{2}.solid{1}.c1=c1_g(2);
febio_spec.Material.material{2}.generation{2}.solid{1}.m1=m1;
febio_spec.Material.material{2}.generation{2}.solid{1}.c2=c1_g(2);
febio_spec.Material.material{2}.generation{2}.solid{1}.m2=-m1;
febio_spec.Material.material{2}.generation{2}.solid{1}.cp=k_g(2);

%Mesh section
% -> Nodes
febio_spec.Mesh.Nodes{1}.ATTR.name='nodeSet_all'; %The node set name
febio_spec.Mesh.Nodes{1}.node.ATTR.id=(1:size(V,1))'; %The node id's
febio_spec.Mesh.Nodes{1}.node.VAL=V; %The nodel coordinates

% -> Elements
partName1='Part1';
febio_spec.Mesh.Elements{1}.ATTR.name=partName1; %Name of this part
febio_spec.Mesh.Elements{1}.ATTR.type='hex8'; %Element type
febio_spec.Mesh.Elements{1}.elem.ATTR.id=(1:1:nnz(elementMaterialID==1))'; %Element id's
febio_spec.Mesh.Elements{1}.elem.VAL=E(elementMaterialID==1,:);

partName2='Part2';
febio_spec.Mesh.Elements{2}.ATTR.name=partName2; %Name of this part
febio_spec.Mesh.Elements{2}.ATTR.type='hex8'; %Element type
febio_spec.Mesh.Elements{2}.elem.ATTR.id=(1+nnz(elementMaterialID==1):1:nnz(elementMaterialID==1)+nnz(elementMaterialID==2))'; %Element id's
febio_spec.Mesh.Elements{2}.elem.VAL=E(elementMaterialID==2,:);

% -> NodeSets
nodeSetName1='bcSupportList';
febio_spec.Mesh.NodeSet{1}.ATTR.name=nodeSetName1;
febio_spec.Mesh.NodeSet{1}.node.ATTR.id=bcSupportList(:);

nodeSetName2='bcPrescribeList';
febio_spec.Mesh.NodeSet{2}.ATTR.name=nodeSetName2;
febio_spec.Mesh.NodeSet{2}.node.ATTR.id=bcPrescribeList(:);

%MeshDomains section
febio_spec.MeshDomains.SolidDomain{1}.ATTR.name=partName1;
febio_spec.MeshDomains.SolidDomain{1}.ATTR.mat=materialName1;

febio_spec.MeshDomains.SolidDomain{2}.ATTR.name=partName2;
febio_spec.MeshDomains.SolidDomain{2}.ATTR.mat=materialName2;

%Boundary condition section
% -> Fix boundary conditions
febio_spec.Boundary.bc{1}.ATTR.type='fix';
febio_spec.Boundary.bc{1}.ATTR.node_set=nodeSetName1;
febio_spec.Boundary.bc{1}.dofs='x,y,z';

%STEP 1 Tension
febio_spec.Step.step{1}.Boundary.bc{1}.ATTR.type='prescribe';
febio_spec.Step.step{1}.Boundary.bc{1}.ATTR.node_set=nodeSetName2;
febio_spec.Step.step{1}.Boundary.bc{1}.dof='z';
febio_spec.Step.step{1}.Boundary.bc{1}.scale.ATTR.lc=1;
febio_spec.Step.step{1}.Boundary.bc{1}.scale.VAL=displacementMagnitude;
febio_spec.Step.step{1}.Boundary.bc{1}.relative=1;

febio_spec.Step.step{1}.Boundary.bc{2}.ATTR.type='fix';
febio_spec.Step.step{1}.Boundary.bc{2}.ATTR.node_set=nodeSetName2;
febio_spec.Step.step{1}.Boundary.bc{2}.dofs='x,y';

%STEP 2 Return form tension
febio_spec.Step.step{2}.Boundary.bc{1}.ATTR.type='prescribe';
febio_spec.Step.step{2}.Boundary.bc{1}.ATTR.node_set=nodeSetName2;
febio_spec.Step.step{2}.Boundary.bc{1}.dof='z';
febio_spec.Step.step{2}.Boundary.bc{1}.scale.ATTR.lc=2;
febio_spec.Step.step{2}.Boundary.bc{1}.scale.VAL=-displacementMagnitude;
febio_spec.Step.step{2}.Boundary.bc{1}.relative=1;

febio_spec.Step.step{2}.Boundary.bc{2}.ATTR.type='fix';
febio_spec.Step.step{2}.Boundary.bc{2}.ATTR.node_set=nodeSetName2;
febio_spec.Step.step{2}.Boundary.bc{2}.dofs='x,y';

%LoadData section
% -> load_controller
febio_spec.LoadData.load_controller{1}.ATTR.id=1;
febio_spec.LoadData.load_controller{1}.ATTR.type='loadcurve';
febio_spec.LoadData.load_controller{1}.interpolate='LINEAR';
febio_spec.LoadData.load_controller{1}.points.point.VAL=[0 0; 1 1];

febio_spec.LoadData.load_controller{2}.ATTR.id=2;
febio_spec.LoadData.load_controller{2}.ATTR.type='loadcurve';
febio_spec.LoadData.load_controller{2}.interpolate='LINEAR';
febio_spec.LoadData.load_controller{2}.points.point.VAL=[1 0; 2 1];

%Output section
% -> log file
febio_spec.Output.logfile.ATTR.file=febioLogFileName;
febio_spec.Output.logfile.node_data{1}.ATTR.file=febioLogFileName_disp;
febio_spec.Output.logfile.node_data{1}.ATTR.data='ux;uy;uz';
febio_spec.Output.logfile.node_data{1}.ATTR.delim=',';
febio_spec.Output.logfile.node_data{1}.VAL=1:size(V,1);

febio_spec.Output.logfile.element_data{1}.ATTR.file=febioLogFileName_strainEnergy;
febio_spec.Output.logfile.element_data{1}.ATTR.data='sed';
febio_spec.Output.logfile.element_data{1}.ATTR.delim=',';
febio_spec.Output.logfile.element_data{1}.VAL=1:size(E,1);

%% Quick viewing of the FEBio input file structure
% The |febView| function can be used to view the xml structure in a MATLAB
% figure window.

%%
% |febView(febio_spec); %Viewing the febio file|

%% Exporting the FEBio input file
% Exporting the febio_spec structure to an FEBio input file is done using
% the |febioStruct2xml| function.

febioStruct2xml(febio_spec,febioFebFileName); %Exporting to file and domNode

%% Running the FEBio analysis
% To run the analysis defined by the created FEBio input file the
% |runMonitorFEBio| function is used. The input for this function is a
% structure defining job settings e.g. the FEBio input file name. The
% optional output runFlag informs the user if the analysis was run
% succesfully.

febioAnalysis.run_filename=febioFebFileName; %The input file name
febioAnalysis.run_logname=febioLogFileName; %The name for the log file
febioAnalysis.disp_on=1; %Display information on the command window
febioAnalysis.runMode='external';%'internal';

[runFlag]=runMonitorFEBio(febioAnalysis);%START FEBio NOW!!!!!!!!

%% Import FEBio results

if runFlag==1 %i.e. a succesful run

    %%
    % Importing nodal displacements from a log file
    dataStruct=importFEBio_logfile(fullfile(savePath,febioLogFileName_disp),1,1);

    %Access data
    N_disp_mat=dataStruct.data; %Displacement
    timeVec=dataStruct.time; %Time

    %Create deformed coordinate set
    V_DEF=N_disp_mat+repmat(V,[1 1 size(N_disp_mat,3)]);

    %%
    % Importing element stress from a log file
    dataStruct=importFEBio_logfile(fullfile(savePath,febioLogFileName_strainEnergy),1,1);

    %Access data
    E_energy=dataStruct.data;

    [F,CF]=element2patch(E,E_energy(:,:,1));

    %%
    % Plotting the simulated results using |anim8| to visualize and animate
    % deformations

    c1_plot=c1*ones(size(timeVec));
    cg_plot=c1_g(1)*ones(size(timeVec));
    cg_plot(timeVec>=1)=c1_g(2);

    % Create basic view and store graphics handle to initiate animation
    hf=cFigure; %Open figure
    gtitle([febioFebFileNamePart,': Press play to animate']);

    subplot(1,2,1); hold on;
    title('Ogden parameter c_1');
    xlabel('Time'); ylabel('c_1');
    plot(timeVec,c1_plot,'b-','lineWidth',2);
    plot(timeVec,cg_plot,'r-','lineWidth',2);
    hp1=plot(timeVec(1),c1_plot(1),'b.','MarkerSize',50);
    hp2=plot(timeVec(1),cg_plot(1),'r.','MarkerSize',50);
    legend([hp1 hp2],'Material 1','Material 2');
    axis tight; axis square; set(gca,'fontsize',fontSize);
    grid on;

    subplot(1,2,2); hold on;
    hp3=gpatch(F,V_DEF(:,:,end),CF,'k',1); %Add graphics object to animate
    gpatch(Fb,V,0.5*ones(1,3),'k',0.25); %A static graphics object

    colormap(gjet(250)); hc=colorbar;
    caxis([0 max(E_energy(:))]);
    axisGeom(gca,fontSize);
    axis(axisLim(V_DEF)); %Set axis limits statically
    axis manual;
    camlight headlight;
    drawnow;

    % Set up animation features
    animStruct.Time=timeVec; %The time vector
    for qt=1:1:size(N_disp_mat,3) %Loop over time increments
        DN=N_disp_mat(:,:,qt); %Current displacement
        DN_magnitude=sqrt(sum(DN.^2,2)); %Current displacement magnitude

        [~,CF]=element2patch(E,E_energy(:,:,qt));

        %Set entries in animation structure
        animStruct.Handles{qt}=[hp3 hp3 hp1 hp1 hp2 hp2]; %Handles of objects to animate
        animStruct.Props{qt}={'Vertices','CData','XData','YData','XData','YData'}; %Properties of objects to animate
        animStruct.Set{qt}={V_DEF(:,:,qt),CF,timeVec(qt),c1_plot(qt),timeVec(qt),cg_plot(qt)}; %Property values for to set in order to animate
    end
    anim8(hf,animStruct); %Initiate animation feature
    drawnow;

end

%%
%
% <<gibbVerySmall.gif>>
%
% _*GIBBON*_
% <www.gibboncode.org>
%
% _Kevin Mattheus Moerman_, <gibbon.toolbox@gmail.com>

%%
% _*GIBBON footer text*_
%
% License: <https://github.com/gibbonCode/GIBBON/blob/master/LICENSE>
%
% GIBBON: The Geometry and Image-based Bioengineering add-On. A toolbox for
% image segmentation, image-based modeling, meshing, and finite element
% analysis.
%
% Copyright (C) 2006-2022 Kevin Mattheus Moerman and the GIBBON contributors
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program.  If not, see <http://www.gnu.org/licenses/>.


% /*----------------------------------------------------------------------
%     This file contains a simulation of the cart and pole dynamic system and
%  a procedure for learning to balance the pole.

%
clear all;
SEED=1;
rng(SEED);
SHOW_ANIMATION=1;%%if you want to visualize, set this to 1.

%%%%initialize the network
net=net_init_pole();

addpath(genpath('../CoreModules'));

SHOW_ANIMATION_EVERY_N=100; %every n trials
GAMMA   = 0.9;       % Discount factor for critic.
ACTIONS = 2;

MAX_FAILURES  =  5000;      % Termination criterion.
MAX_STEPS   =     100000;

MaxSteps=[];
Vs=[];
failures=0;
success=0;

opts.use_gpu=0;%don't use gpu for this application, since it will be slow
opts.parameters.mom =0.9;
opts.parameters.lr =1e-1;
opts.parameters.weightDecay=1e-3;
opts.parameters.clip=1e-1;

% Turning on the double buffering to plot the cart and pole
if SHOW_ANIMATION
    h = figure;
    set(h,'doublebuffer','on')
end

% Iterate through the action-learn loop.
while (failures < MAX_FAILURES)

    %%%%%%%%%%%%%%%%%%%%%%%%%%%
    %%%%%  RESET STARTS %%%%%%%
    %%%%%%%%%%%%%%%%%%%%%%%%%%%
    % Starting state is (0 0 0 0)
    x         = 0;       % cart position, meters
    x_dot     = 0;       % cart velocity
    theta     = 0;       % pole angle, radians
    theta_dot = 0.0;     % pole angular velocity

    state=[x;x_dot;theta;theta_dot];
    valid=is_valid_state(x,x_dot,theta,theta_dot);

    Inputs=zeros(4,MAX_STEPS);
    opts.dzdy =zeros(ACTIONS,MAX_STEPS);
    acts=zeros(1,MAX_STEPS);

    res(1).x=state;
    [ net,res,opts] = net_ff(net,res,opts);
    P=softmax(res(end).x,[]);
    %Choose action randomly according to the current policy.
    act=1+(rand(1)>P(1));
    samples=1;
    P(act)=P(act)-1;%der of softmaxlogloss
    opts.dzdy(:,samples)=P;
    Inputs(:,samples)=state;
    acts(samples)=act;

    %%%%%%%%%%%%%%%%%%%%%%%%%%
    %%%%%  RESET  END %%%%%%%%
    %%%%%%%%%%%%%%%%%%%%%%%%%%

    failed=0;
    while samples < MAX_STEPS && failed==0

        if SHOW_ANIMATION&&(mod(failures,SHOW_ANIMATION_EVERY_N)==0||success)
            plot_Cart_Pole(x,theta)
            if success && samples>1000
                break;
            end
        end

        %Apply action to the simulated cart-pole
        [x,x_dot,theta,theta_dot]=Cart_Pole(act-1,x,x_dot,theta,theta_dot);

        state=[x;x_dot;theta;theta_dot];
        valid=is_valid_state(x,x_dot,theta,theta_dot);

        if valid<0
            %Failure occurred
            failed = 1;
            failures=failures+1;
            MaxSteps=[MaxSteps;samples];
            disp(['Trial was ' int2str(failures) ' steps '  num2str(samples)]);
            %Reinforcement upon failure is -1.
            discounted_r=-exp(2*log(GAMMA).*[samples:-1:1]);

            V=mean(-exp(log(GAMMA).*[samples:-1:1]));%E[V(s)]
            Vs=[Vs;V];
        else
            %Not a failure.r=0.
            failed = 0;
            res(1).x=state;
            [net,res,opts] = net_ff(net,res,opts);
            P=softmax(res(end).x,[]);
            %Choose action randomly according to the current policy.

            act=1+(rand(1)>P(1));
            samples=samples+1;
            acts(samples)=act;
            %P;
            %acts(1:samples)
            P(act)=P(act)-1;%der of softmaxlogloss
            opts.dzdy(:,samples)=P;
            Inputs(:,samples)=state;

        end

        if failed

            %%%%%%%%%%%%%%%%%%%%%
            opts.dzdy=discounted_r.*opts.dzdy(:,1:samples);

            %%This is redundant, just to recalculate some intermediate values
            %%and put them into the right place.
            res(1).x=Inputs(:,1:samples);
            [net,res,opts] = net_ff(net,res,opts);

            %%
            [ net,res,opts ] = net_bp( net,res,opts );
            [ net,res,opts ] = adam( net,res,opts );

        end

    end

    if success && samples>1000
        break;
    end
    if samples>=MAX_STEPS
        success=1;
        if SHOW_ANIMATION==0
            break;
        else
            continue;
        end
    end

  end

if (failures == MAX_FAILURES)
    disp(['Pole not balanced. Stopping after ' int2str(failures) ' failures ' ]);
else
    disp(['Pole balanced successfully for at least ' int2str(MAX_STEPS) ' steps ' ]);
end
close all;
figure;subplot(1,2,1);plot(Vs);title('Values');
subplot(1,2,2);plot(MaxSteps);title('Steps');


function [ know, x ] = p03_sol ( n )

%*****************************************************************************80
%
%% P03_SOL returns the solution for problem 3.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    16 October 2011
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, integer KNOW.
%    If KNOW is 0, then the solution is not known.
%    If KNOW is positive, then the solution is known, and is returned in X.
%
%    Input, integer N, the order of the problem.  This value
%    is only needed for those problems with variable N.
%
%    Output, real X(N), the solution, if known.
%
  know = 0;

  x = zeros ( n, 1 );

  return
end


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

test_suite = functiontests(localfunctions);

function testHorizontal(testCase) %#ok<*DEFNU>
point = [0 0];
line = [1 0 0 1];
testCase.assertEqual(projPointOnLine(point, line), [1 0], 'AbsTol', .01);

function testDiagonal(testCase)
point = [0 0];
line = [2 0 1 1];
testCase.assertEqual(projPointOnLine(point, line), [1 -1], 'AbsTol', .01);

function testBigDerivative(testCase)
point = [0 0];
line = [2 0 1000 1000];
testCase.assertEqual(projPointOnLine(point, line), [1 -1], 'AbsTol', .01);

function testDiagonal2(testCase)
point = [2 3];
line = [-2 -4 6 4];
testCase.assertEqual(projPointOnLine(point, line), [4 0], 'AbsTol', .01);

function test_SingleMulti(testCase)

point = [4 2];
line1 = [0 0 1 0];
line2 = [0 0 0 1];
line3 = [0 2 2 2];

res = projPointOnLine(point, [line1;line2;line3]);
exp = [4 0;0 2;2 4];
testCase.assertEqual(exp, res, 'AbsTol', .01);

function test_MultiSingle(testCase)

line = [0 2 4 2];
p1 = [3 1];
p2 = [5 2];
p3 = [3 6];

res = projPointOnLine([p1;p2;p3], line);
exp = [2 3;4 4;4 4];
testCase.assertEqual(exp, res, 'AbsTol', .01);

function test_MultiMulti(testCase)

line1 = [0 0 1 0];
line2 = [0 0 0 1];
line3 = [0 2 2 2];
p1 = [3 1];
p2 = [2 3];
p3 = [1 5];
res = projPointOnLine([p1;p2;p3], [line1;line2;line3]);
exp = [3 0;0 3;2 4];
testCase.assertEqual(exp, res, 'AbsTol', .01);


function Mh = hmxChol(Mh)
%+========================================================================+
%|                                                                        |
%|         OPENHMX - LIBRARY FOR H-MATRIX COMPRESSION AND ALGEBRA         |
%|           openHmx is part of the GYPSILAB toolbox for Matlab           |
%|                                                                        |
%| COPYRIGHT : Matthieu Aussal (c) 2017-2018.                             |
%| PROPERTY  : Centre de Mathematiques Appliquees, Ecole polytechnique,   |
%| route de Saclay, 91128 Palaiseau, France. All rights reserved.         |
%| LICENCE   : This program is free software, distributed in the hope that|
%| it will be useful, but WITHOUT ANY WARRANTY. Natively, you can use,    |
%| redistribute and/or modify it under the terms of the GNU General Public|
%| License, as published by the Free Software Foundation (version 3 or    |
%| later,  http://www.gnu.org/licenses). For private use, dual licencing  |
%| is available, please contact us to activate a "pay for remove" option. |
%| CONTACT   : matthieu.aussal@polytechnique.edu                          |
%| WEBSITE   : www.cmap.polytechnique.fr/~aussal/gypsilab                 |
%|                                                                        |
%| Please acknowledge the gypsilab toolbox in programs or publications in |
%| which you use it.                                                      |
%|________________________________________________________________________|
%|   '&`   |                                                              |
%|    #    |   FILE       : hmxChol.m                                     |
%|    #    |   VERSION    : 0.40                                          |
%|   _#_   |   AUTHOR(S)  : Matthieu Aussal                               |
%|  ( # )  |   CREATION   : 14.03.2017                                    |
%|  / 0 \  |   LAST MODIF : 14.03.2018                                    |
%| ( === ) |   SYNOPSIS   : Cholesky factorization of H-Matrix            |
%|  `---'  |                                                              |
%+========================================================================+

% Check invertibility
if (size(Mh,1) ~= size(Mh,2)) || ~isequal(Mh.pos{1},Mh.pos{2})
    error('hmxChol.m : matrix must be invertible.')
end

%%% H-Matrix (recursion)
if (Mh.typ == 0)
    % U11 -> M11
    Mh.chd{1} = hmxChol(Mh.chd{1});

    % U12 -> U11' \ M12
    Mh.chd{2} = Mh.chd{1}'\Mh.chd{2};

    % U21 -> 0
    Mh.chd{3} = zeros(Mh.chd{3});

    % M22 -> M22 - U12'*U12
    Mh.chd{4} = Mh.chd{4} - Mh.chd{2}' * Mh.chd{2};
%     Mh.chd{4} = plusmtimes(Mh.chd{4},-1,Mh.chd{2}',Mh.chd{2});

    % U22 -> M22
    Mh.chd{4} = hmxChol(Mh.chd{4});

    % Fusion
    Mh = hmxFusion(Mh);

%%% Compressed leaf
elseif (Mh.typ == 1)
    error('hmxChol : unavailable case')

%%% Full leaf
elseif (Mh.typ == 2)
    Mh.dat = chol(Mh.dat);

%%% Unknown type
else
    error('hmxChol.m : unavailable case')
end
end


function f = or(f, g)
%|   CLASSICFUN logical OR.
%   F | G performs a logical OR of the CLASSICFUN objects F and G and returns a CLASSICFUN
%   containing elements set to either logical 1 (TRUE) or logical 0 (FALSE).
%   An element of the output CLASSICFUN is set to 1 if either input CLASSICFUN contains a
%   non-zero element at that point, otherwise it is set to 0.  F and G must
%   either be identically zero or have roots in their domains.  If this is not
%   the case, garbage is returned with no warning.

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

f.onefun = f.onefun | g.onefun;

end


% VL_AIBHIST  Compute histogram over VL_AIB tree
%  H = VL_AIBHIST(PARENTS, DATA) computes the histogram of the data
%  points DATA on the VL_AIB tree defined by PARENTS. Each element of
%  DATA indexes one of the leaves of the VL_AIB tree.
%
%  H = VL_AIBHIST(PARENTS, DATA, 'HIST') treats DATA as an histograms.
%  In this case each compoment of DATA is the number of occurences of
%  the VL_AIB leaves corresponding to that component.
%
%  H has the same dimension of parents and counts how many data points
%  are descendent of the corresponding node of the VL_AIB tree.
%
%  See also: VL_HELP(), VL_AIB(), VL_AIBCUTPUSH().

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


function maximise( varargin )

%MAXIMISE Specifiies a concave (or affine) objective to be maximized.

cvx_problem = evalin( 'caller', 'cvx_problem', '[]' );
if isempty( cvx_problem ) || ~isa( cvx_problem, 'cvxprob' ),
    error( 'A cvx problem does not exist in this scope.' );
end
if ~isempty( cvx_problem.direction ),
    if isequal( cvx_problem.direction, 'find' ),
        error( 'Objective functions cannot be added to sets.' );
    else
        error( 'An objective function has already been supplied.' );
    end
end

if nargin < 1,
    error( 'Objective expression missing.' );
elseif iscellstr( varargin ),
    arg = evalin( 'caller', sprintf( '%s ', varargin{:} ) );
elseif nargin > 1,
    error( 'Too many input arguments.' );
else
    arg = varargin{1};
end

if ~isa( arg, 'cvx' ) && ~isa( arg, 'double' ) && ~isa( arg, 'sparse' ),
    error( 'Cannot accept an objective of type ''%s''.', class( arg ) );
end
persistent remap
if isempty( remap ),
    remap = cvx_remap( 'concave', 'log-concave' );
end
vx = remap( cvx_classify( arg ) );
if ~all( vx ),
    error( 'Disciplined convex programming error:\n   Cannot maximise a(n) %s expression.', cvx_class(arg(vx==0),false,true) );
end

newobj( cvx_problem, 'maximize', arg );

% Copyright 2010 Michael C. Grant and Stephen P. Boyd.
% See the file COPYING.txt for full copyright information.
% The command 'cvx_where' will show where this file is located.


function [MPa] = Pa2MPa(Pa)
% Convert pressure from pascals to megapascals.
% Chad Greene 2012
MPa = Pa*0.000001;


function [S,K,s,w,t,dfdx] = spm_dcm_mtf(P,M,U)
% computes transfer functions using the system's eigenspectrum
% FORMAT [S,K,s,w,t,dfdx] = spm_dcm_mtf(P,M,[U])
%
% P - model parameters
% M - model (with flow M.f and expansion point M.x and M.u)
% U - induces expansion around steady state (from spm_dcm_neural_x(P,M))
%
% S    - modulation transfer functions (complex)
% K    - Volterra kernels (real)
% s    - eigenspectrum (complex)
% w    - frequencies (Hz) = M.Hz
% t    - time (seconds)   = M.pst
% dfdx - Jacobian
%
% This routine uses the eigensolution of a dynamical systems Jacobian to
% complete the first-order Volterra terminals and transfer functions  in
% peristimulus and frequency space respectively.  The advantage of using
% the-solution is that unstable modes (eigenvectors of the Jacobian) can be
% conditioned (suppressed). Furthermore, this provides for a
% computationally efficient and transparent evaluation of the transfer
% functions that draws on linear signal processing theory in frequency
% space.
%__________________________________________________________________________
% Copyright (C) 2012 Wellcome Trust Centre for Neuroimaging

% Karl Friston
% $Id: spm_dcm_mtf.m 6856 2016-08-10 17:55:05Z karl $

% get local linear approximation
%==========================================================================

% solve for steady-state - if required
%--------------------------------------------------------------------------
if nargin > 2
    M.x   = spm_dcm_neural_x(P,M);
end

% check expansion points
%--------------------------------------------------------------------------
try, M.x; catch, M.x = spm_dcm_x_neural(P,M.dipfit.model); end
try, M.u; catch, M.u = sparse(M.m,1);                      end

% frequencies and peristimulus time of interest
%--------------------------------------------------------------------------
w      = (1:64)';
t      = (0:64 - 1)'/64;
try, w = M.Hz(:);       end
try, t = M.pst(:);      end
try, t = M.dt*(1:M.N)'; end

% delay operator - if not specified already
%--------------------------------------------------------------------------
if isfield(M,'D')

    dfdx = spm_diff(M.f,M.x,M.u,P,M,1);
    dfdu = spm_diff(M.f,M.x,M.u,P,M,2);
    D    = M.D;

else

    if nargout(M.f) == 4
        [f,dfdx,D,dfdu] = feval(M.f,M.x,M.u,P,M);

    elseif nargout(M.f) == 3
        [f,dfdx,D]      = feval(M.f,M.x,M.u,P,M);
        dfdu            = spm_diff(M.f,M.x,M.u,P,M,2);

    elseif nargout(M.f) == 2
        [f,dfdx]        = feval(M.f,M.x,M.u,P,M);
        dfdu            = spm_diff(M.f,M.x,M.u,P,M,2);
        D               = 1;
    else
        dfdx            = spm_diff(M.f,M.x,M.u,P,M,1);
        dfdu            = spm_diff(M.f,M.x,M.u,P,M,2);
        D               = 1;
    end
end

% Jacobian and eigenspectrum
%==========================================================================
if nargout(M.g) == 2
    [g,dgdx] = feval(M.g,M.x,M.u,P,M);
else
    dgdx     = spm_diff(M.g,M.x,M.u,P,M,1);
end
dfdx  = D*dfdx;
dfdu  = D*dfdu;
try
   [v,s] = eig(full(dfdx),'nobalance');
catch
   v  = eye(size(dfdx));
   s  = NaN(size(dfdx));
end
s     = diag(s);

% condition unstable eigenmodes
%--------------------------------------------------------------------------
if max(w) > 1
    s = 1j*imag(s) + real(s) - exp(real(s));
else
    s = 1j*imag(s) + min(real(s),-1/32);
end

% Transfer functions
%==========================================================================

% transfer functions (FFT of kernel)
%--------------------------------------------------------------------------
nw    = size(w,1);            % number of frequencies
nt    = size(t,1);            % number of time bins
ng    = size(dgdx,1);         % number of outputs
nu    = size(dfdu,2);         % number of inputs
nk    = size(v,2);            % number of modes
S     = zeros(nw,ng,nu);
K     = zeros(nt,ng,nu);

% derivatives over modes
%--------------------------------------------------------------------------
dgdv  = dgdx*v;
dvdu  = pinv(v)*dfdu;
for j = 1:nu
    for i = 1:ng
        for k = 1:nk

            % transfer functions (FFT of kernel)
            %--------------------------------------------------------------
            Sk       = 1./(1j*2*pi*w - s(k));
            S(:,i,j) = S(:,i,j) + dgdv(i,k)*dvdu(k,j)*Sk;

            % kernels
            %--------------------------------------------------------------
            if nargout > 1
                Kk       = exp(s(k)*t);
                K(:,i,j) = K(:,i,j) + real(dgdv(i,k)*dvdu(k,j)*Kk);
            end

        end
    end
end

return

% NOTES: internal consistency with explicit Fourier transform of kernels
%==========================================================================

% augment and bi-linearise (with intrinsic delays)
%--------------------------------------------------------------------------
M.D       = D;
[M0,M1,L] = spm_bireduce(M,P);

% project onto spatial modes
%--------------------------------------------------------------------------
try,    L = M.U'*L; end

% kernels
%--------------------------------------------------------------------------
N         = length(t);
dt        = (t(2) - t(1));
[K0,K1]   = spm_kernels(M0,M1,L,N,dt);

% Transfer functions (FFT of kernel)
%--------------------------------------------------------------------------
S1        = fft(K1)*dt;
w1        = ((1:N) - 1)/(N*dt);
j         = w1 < max(w);
S1        = S1(j,1,1);
w1        = w1(j);

subplot(2,2,1), plot(t,K(:,1,1),t,K1(:,1,1));
title('kernels','fontsize',16)
xlabel('peristimulus time')

subplot(2,2,2), plot(w,real(S(:,1,1)),    w1,real(S1(:,1,1))); hold on
subplot(2,2,2), plot(w,imag(S(:,1,1)),':',w1,imag(S1(:,1,1)),':'); hold off
title('transfer functions','fontsize',16)
xlabel('frequency');


filename='Bridge_hexahedra_fine';
 ptype = 'MACRO';
method = 'SIMPALL';
materialType = 'ISOTROPIC';
initial_case = 'full';
cost = {'compliance';'perimeter'};
weights = [1, 0.1];
constraint = {'volumeConstraint'};
optimizer = 'SLERP'; incrementFactor = 1;
filterType = 'P1';

nsteps = 5;
Vfrac_final = 0.05;
Perimeter_target = 1;
optimality_final = 1e-3;
constr_final =1e-3;

Vfrac_initial = 1;
optimality_initial = 1e-2;
constr_initial = 1e-3;
TOL.rho_plus = 1;
TOL.rho_minus = 0;
TOL.E_plus = 1;
TOL.E_minus = 1e-3;
TOL.nu_plus = 1/3;
TOL.nu_minus = 1/3;


function y = gprnd(X, logtheta, covfunc)

if ~iscell(covfunc)
  covfunc = {covfunc};
end

K = regularize(feval(covfunc{:}, logtheta, X, X));% + 1e-5*diag(sparse(ones(cols(X),1)));

y = mymvnrnd(0, K);


function feat = spp_poolX_to_fcX(feat, layer, spp_model, use_gpu)
% feat = spp_poolX_to_fcX(feat, layer, spp_model, use_gpu)
%   On-the-fly conversion of last pool features to fcX
%   using the weights and biases stored in spp_model.cnn.layers.
%   feat is transformed in columns for continuous memory access and fast
%   speed
%
% Adapted from spp code written by Ross Girshick
% AUTORIGHTS
% ---------------------------------------------------------
% Copyright (c) 2014, Shaoqing Ren
%
% This file is part of the SPP code and is available
% under the terms of the Simplified BSD License provided in
% LICENSE. Please retain this notice and LICENSE if you use
% this file (or any portion of it) in your project.
% ---------------------------------------------------------
% Copyright (c) 2014, Ross Girshick
%
% This file is part of the R-CNN code and is available
% under the terms of the Simplified BSD License provided in
% LICENSE. Please retain this notice and LICENSE if you use
% this file (or any portion of it) in your project.
% ---------------------------------------------------------

fc_layer_ind = layer - (spp_model.cnn.first_fc_idx - 1);

if fc_layer_ind <= 0
    return;
end

if use_gpu
    maxNumel = 1024*1024*256; % around 4G memory
    if numel(feat) < maxNumel
        feat_gpu = gpuArray(feat);
        for i = 1:fc_layer_ind
            % weights{1} = matrix of CNN weights [input_dim x output_dim]
            % weights{2} = column vector of biases
            feat_gpu = max(0, bsxfun(@plus, spp_model.cnn.layers(i).weights_gpu{1} * feat_gpu, ...
                              spp_model.cnn.layers(i).weights_gpu{2}));
        end
        feat = gather(feat_gpu);
    else
        nSampleEach = floor(maxNumel / size(feat, 1));
        nSplits = ceil(size(feat, 2) / nSampleEach);
        splits = ones(nSplits, 1) * nSampleEach;
        splits(end) = size(feat, 2) - sum(splits(1:end-1));
        assert(sum(splits) == size(feat, 2));
        feats = mat2cell(feat, size(feat, 1), splits);
        for is = 1:length(feats)
            feat_gpu = gpuArray(feats{is});
            for i = 1:fc_layer_ind
                % weights{1} = matrix of CNN weights [input_dim x output_dim]
                % weights{2} = column vector of biases
                feat_gpu = max(0, bsxfun(@plus, spp_model.cnn.layers(i).weights_gpu{1} * feat_gpu, ...
                                  spp_model.cnn.layers(i).weights_gpu{2}));
            end
            feats{is} = gather(feat_gpu);
        end
        feat = cell2mat(feats);
    end

else
    for i = 1:fc_layer_ind
        % weights{1} = matrix of CNN weights [input_dim x output_dim]
        % weights{2} = column vector of biases
        feat = max(0, bsxfun(@plus, spp_model.cnn.layers(i).weights{1} * feat, ...
                              spp_model.cnn.layers(i).weights{2}));
    end
end


function [top, top_confidences] = nms(boxes, confidences, overlap)

% top = nms(boxes, overlap)
% Non-maximum suppression.
% Greedily select high-scoring detections and skip detections
% that are significantly covered by a previously selected detection.

if isempty(boxes)
  top = [];
else
  x1 = boxes(:,1);
  y1 = boxes(:,2);
  x2 = boxes(:,3);
  y2 = boxes(:,4);
  s = confidences';
  area = (x2-x1+1) .* (y2-y1+1);

  [vals, I] = sort(s);
  pick = [];
  while ~isempty(I)
    last = length(I);
    i = I(last);
    pick = [pick; i];
    suppress = [last];
    for pos = 1:last-1
      j = I(pos);
      xx1 = max(x1(i), x1(j));
      yy1 = max(y1(i), y1(j));
      xx2 = min(x2(i), x2(j));
      yy2 = min(y2(i), y2(j));
      w = xx2-xx1+1;
      h = yy2-yy1+1;
      if w > 0 && h > 0
        % compute overlap
        o = w * h / area(j);
        if o > overlap
          suppress = [suppress; pos];
        end
      end
    end
    I(suppress) = [];
  end
  top = boxes(pick,:);
  top_confidences = confidences(pick);
end


fid = fopen('list.txt');
C = textscan(fid, '%s %d');
all_class = 10575;
image_num_in_class = zeros(all_class,1);
image_in_class = cell(all_class,1);
for i = 1:all_class
    image_in_class{i} = find(C{2} == i -1);
    image_num_in_class(i) = length(image_in_class{i});
end;
fclose(fid);
% clear all;
% load('temp1.mat');

test_class = 2000-1;
test_num = sum(C{2}>all_class-test_class);
total = length(C{2});
train_num = total - test_num;
same_r = 0.5;

same_pair_l = floor(test_num / 2 * same_r);
same_in_class = randi(test_class,floor(same_pair_l * 2),1) + all_class-test_class;
same_in_class_unique = unique(same_in_class);
got_in_same = ones(total,1);
got_in_same(train_num+1:end) = 0;
pair1_same = zeros(same_pair_l * 10,1);
pair2_same = zeros(same_pair_l * 10,1);
p=1;
for i = 1: length(same_in_class_unique)
    if mod(p,same_pair_l/100) == 0
        disp([p same_pair_l]);
    end;
    c = same_in_class_unique(i);
    n = sum(same_in_class == same_in_class_unique(i)) * 2;
    s = image_num_in_class(c);
    if n > s
        n = floor(s / 2) * 2;
    end;
    idx_same = randperm(s);
    for j = 1 : n / 2
        pair1_same(p) = image_in_class{c}(idx_same(j*2-1));
        pair2_same(p) = image_in_class{c}(idx_same(j*2));
%         got_in_same(image_in_class{c}(idx_same(j*2-1))) = 1;
%         got_in_same(image_in_class{c}(idx_same(j*2))) = 1;
%         if p==same_pair_l
%             break;
%         end;
        p = p + 1;
    end;
end;
assert(p>same_pair_l);
idx = randperm(p-1);
pair1_same = pair1_same(idx(1:same_pair_l));
pair2_same = pair2_same(idx(1:same_pair_l));
assert(sum(C{2}(pair1_same) == C{2}(pair2_same)) == same_pair_l);
got_in_same(pair1_same) = 1;
got_in_same(pair2_same) = 1;
diff_num = test_num - length(pair1_same) * 2;
diff_sample = find(got_in_same==0);
idx = randperm(diff_num);
diff_sample = diff_sample(idx);
pair1_diff = diff_sample(1:(diff_num/2));
pair2_diff = diff_sample(diff_num/2 + 1:end);
err = find(C{2}(pair1_diff) == C{2}(pair2_diff));
% for i = 1 : length(err)
    ridx = randperm(length(err));
    pair1_diff(err) = pair1_diff(err(ridx));
% end;
assert(sum(C{2}(pair1_diff) == C{2}(pair2_diff)) == 0);
pair1 = [pair1_same;pair1_diff];
pair2 = [pair2_same;pair2_diff];
label_sim = [ones(length(pair1_same),1);zeros(length(pair1_diff),1)];
idx = randperm(length(pair1));
pair1 = pair1(idx);
pair2 = pair2(idx);
label_sim = label_sim(idx);
assert(sum((C{2}(pair1) == C{2}(pair2)) ~= label_sim) == 0);
fid1 = fopen('pair_data1_test.txt','w');
fid2 = fopen('pair_data2_test.txt','w');
fid3 = fopen('sim_label_test.txt','w');
for i = 1 : length(pair1)
    fprintf(fid1,'%s %d\r\n',C{1}{pair1(i)},C{2}(pair1(i)));
    fprintf(fid2,'%s %d\r\n',C{1}{pair2(i)},C{2}(pair2(i)));
    fprintf(fid3,'%d\r\n',label_sim(i));
end;
fclose(fid1);
fclose(fid2);
fclose(fid3);


function []  = imwriteBW(x,filename)
	m = min(x(:));
	M = max(x(:));

	xn =  (x-m)/(M-m);
	imwrite(xn,filename);
end


function [init_point, n_alg, initial_terminal_voltage] = initialise_model(param)
% initialise_model performs analytical initialisation of all variables of interest

%   This file is part of the LIONSIMBA Toolbox
%
%	Official web-site: 	http://sisdin.unipv.it/labsisdin/lionsimba.php
% 	Official GitHUB: 	https://github.com/lionsimbatoolbox/LIONSIMBA
%
%   LIONSIMBA: A Matlab framework based on a finite volume model suitable for Li-ion battery design, simulation, and control
%   Copyright (C) 2016-2018 :Marcello Torchio, Lalo Magni, Davide Raimondo,
%                            University of Pavia, 27100, Pavia, Italy
%                            Bhushan Gopaluni, Univ. of British Columbia,
%                            Vancouver, BC V6T 1Z3, Canada
%                            Richard D. Braatz,
%                            Massachusetts Institute of Technology,
%                            Cambridge, Massachusetts 02142, USA
%
%   Main code contributors to LIONSIMBA 2.0:
%                           Ian Campbell, Krishnakumar Gopalakrishnan,
%                           Imperial college London, London, UK
%
%   LIONSIMBA is a free Matlab-based software distributed with an MIT
%   license.

sign_input_density = evaluate_sign_input_density(param); % evaluates sign of input current/power density as per operating mode

T = param.T_init * ones(param.Nsum+param.Nal+param.Ncu,1);

cs_star_p   = param.cs_p_init*ones(param.Np, 1);
cs_star_n   = param.cs_n_init*ones(param.Nn, 1);
cs_star     = [cs_star_p; cs_star_n];

[Phis_p_init,~,Phis_n_init,~] = param.OpenCircuitPotentialFunction(cs_star,T,param,sign_input_density);

Phis_init = [Phis_p_init; Phis_n_init];

if param.OperatingMode==1 || param.OperatingMode==4
    I_density           = param.I_density;
elseif param.OperatingMode==2 || param.OperatingMode==5
    I_density           = param.P_density/(Phis_init(1)-Phis_init(end)); % No need for linear interpolation since starting from equilibrium
else
    I_density = 0; % dummy value for CV mode
end

ce_init = param.ce_init*[ones(param.Np,1);ones(param.Ns,1);ones(param.Nn,1)];
Phie_init = zeros(param.Np + param.Ns + param.Nn, 1); % designated as the ground potential for this system

solverFlux  = zeros(param.Np+param.Nn, 1);
film = zeros(param.Nn, 1);

jflux_init = ionicFlux(ce_init, cs_star, Phis_init, Phie_init, T, solverFlux, film, param,sign_input_density,I_density);

if param.EnableAgeing == 1
    js_init = 0.483e-5*ones(param.Nn, 1); % totally arbitrary/random value for side-reaction flux
else
    js_init = zeros(param.Nn, 1);
end

init_point = [
    jflux_init;...
    Phis_init;...
    Phie_init;...
    js_init;...
    I_density
    ];

n_alg = length(init_point);
initial_terminal_voltage = diff([Phis_n_init(end);Phis_p_init(1)]); % No need for linear interpolation since starting from equilibrium
end


function [sliceNum, planC] = getNoseSlice(outerStrMask3M,planC,outerStrName)
% Automatically identify nose slice in H&N CT scans based on
% first non-zero row of mask.
%
% AI 10/1/19
%
%------------------------------------------------------------------------
% INPUT
% outerStrMask3M   : Mask of pt outline. Set to [] to use structure name
%                    instead.
% planC
% outerStrName     : Structure name corresponding to pt outline
%------------------------------------------------------------------------

if ~isempty(outerStrMask3M)
    mask3M = outerStrMask3M;
else
    %Get mask of outer structure
    indexS = planC{end};
    strC = {planC{indexS.structures}.structureName};
    strIdx = getMatchingIndex(outerStrName,strC,'exact');
    [mask3M, planC] = getStrMask(strIdx, planC);
end

startSliceIdx = 11;
endSliceIdx = min(size(mask3M,3),100);
supMask3M = double(mask3M(:,:,startSliceIdx:endSliceIdx));

%Identify first non-zero row
[sel,rowIdxM] = max(supMask3M, [], 1);
rowIdxM = squeeze(sel.*(rowIdxM)).';
rowIdxM(rowIdxM==0) = nan;
minRowV = nanmin(rowIdxM,[],2);

%Smooth
minRowV = movmean(minRowV,5,'omitnan');

%Compute difference & identify min
%[~,mins] = min(diff([NaN;minRowV]));
[~,mins] = findpeaks(-minRowV,'MinPeakWidth',2, 'MaxPeakWidth',40);
if ~isempty(mins)
    sliceNum = mins(1) + startSliceIdx -1;
else
    sliceNum=1; %default
end

end