function V = ReferenceVectorAdaptation(PopObj,V)
% Reference vector adaption strategy

%------------------------------- Copyright --------------------------------
% Copyright (c) 2023 BIMK Group. You are free to use the PlatEMO for
% research purposes. All publications which use this platform or any code
% in the platform should acknowledge the use of "PlatEMO" and reference "Ye
% Tian, Ran Cheng, Xingyi Zhang, and Yaochu Jin, PlatEMO: A MATLAB platform
% for evolutionary multi-objective optimization [educational forum], IEEE
% Computational Intelligence Magazine, 2017, 12(4): 73-87".
%--------------------------------------------------------------------------

    V = V.*repmat(max(PopObj,[],1)-min(PopObj,[],1),size(V,1),1);
end


% Test file for unbndfun/createMap.m.

function pass = test_createMap(pref)

tol = 1e1*eps;

% Doubly-unbounded domain:
dom = [-Inf Inf];
map = unbndfun.createMap(dom);

pass(1) = ( all(map.For([-1 1]) == [-Inf Inf]) ) && ...
    ( all(map.Inv([-1e100 1e100]) - [-1 1] < tol) );

% Singly-unbounded domain (left):
dom = [-Inf 3];
map = unbndfun.createMap(dom);
pass(2) = ( all(map.For([-1 1]) == [-Inf 3]) ) && ...
    ( all(map.Inv([-1e100 3]) == [-1 1]) );

% Singly-unbounded domain (right):
dom = [-100 Inf];
map = unbndfun.createMap(dom);
pass(3) = ( all(map.For([-1 1]) == [-100 Inf]) ) && ...
    ( all(map.Inv([-100 1e100]) == [-1 1]) );

end


function [mCatDecluster, mCatAfter, vCluster, vCl, vMainCluster] = calc_decluster_depth(mCatalog,nMethod)
% function [mCatDecluster, mCatAfter, vCluster, vCl, vMainCluster] = calc_decluster_depth(mCatalog,nMethod)
% ---------------------------------------------------------------------------------------------------------
% Function to decluster earthquake catalog using a windowing technique in space and time by
% Knopoff & Gardner, GJR astr. Soc, 28, 311-313, 1972 and Gardner & Knopoff, BSSA, 64,5, 1363-1367, 1974
% using different windows. Spatially, the algortihm uses a sphere to determine events.
%
% Incoming variables
% mCatalog : Incoming earthquake catalog (ZMAP format)
% nMethod  : Window length for declustering (see calc_windows.m)
%            1: Gardener & Knopoff, 1974
%            2: Gruenthal pers. communication
%            3: Urhammer, 1986
%
% Outgoing variables:
% mCatDecluster : Declustered earthquake catalog
% mCatAfter     : Catalog of aftershocks (and foreshocks)
% vCluster      : Vector indicating only aftershocks/foreshocls in cluster using a cluster number
% vCl           : Vector indicating all events in clusters using a cluster number
% vMainCluster  : Vector indicating mainshocks of clusters using a cluster number
%
% J. Woessner, woessner@seismo.ifg.ethz.ch
% last update: 29.08.02

%% Added:
% 31.07.02 Correction for problem of mainshocks with a cluster number as aftershocks belong to two sequences
% 31.07.02 Corrected fMaxClusterMag(nMagCount) to fMaxClusterMag, since counting variable not needed
% 31.07.02 Improved resizing time window by adding time difference from initial event to bigger aftershock
% 13.08.02 Added waitbars
% 28.08.02 Changed distance determination using now distance and repmat
% 29.08.02 Cluster determination strategy change: Now selecting all aftershocks using the window of the first shock,
%          adding the events from the bigger aftershocks (later labelled mainshocks); calc_decluster_ver3.m keeps
%          resizing technique

%%% Remember: Improve zero length cluster problem which might appear

%% Initialize Vectors and Matrices
mCatDecluster = [];
mCatAfter = [];
vCluster = zeros(length(mCatalog),1); % Initialize all events as mainshock
vCl = zeros(length(mCatalog),1); % Initialize all events as mainshock
vSel = zeros(length(mCatalog),1); % Initialize all events as mainshock
vMainCluster = zeros(length(mCatalog),1); % Initialize

[nXSize, nYsize] = size(mCatalog);
if nXSize == 0
    disp('Load new catalog');
    return
end

vDecDate = mCatalog(:,3);
nCount = 0;    % Variable of cluster number

fMagThreshold = min(mCatalog(:,6)); % Set Threshold to minimum magnitude of catalog
hWaitbar1 = waitbar(0,'Identifying clusters...');
set(hWaitbar1,'Numbertitle','off','Name','Decluster percentage');
for nEvent=1:length(mCatalog(:,6))
    %nEvent
    %nCount
    if vCluster(nEvent) == 0
        fMagnitude(nEvent) = mCatalog(nEvent, 6);
        if fMagnitude(nEvent) >= fMagThreshold
            %% Define first aftershock zone and determine magnitude of strongest aftershock
            fMag = fMagnitude(nEvent);
            [fSpace, fTime] = calc_windows(fMagnitude(nEvent), nMethod);
            fSpaceDeg = km2deg(fSpace);
            %% This first if is for events with no location given
            if isnan(mCatalog(nEvent,1))
                %vSel = (vDecDate(:,1)-vDecDate(nEvent,1) >= 0) & (vDecDate(:,1)-vDecDate(nEvent,1) <= fTime  & vCluster(nEvent) == 0);
                vSel = (mCatalog(:,3) == mCatalog(nEvent,3));
            else
                mPos = [mCatalog(nEvent, 1) mCatalog(nEvent,2)];
                mPos = repmat(mPos,length(mCatalog(:,1)), 1);
                mDist = abs(distance(mCatalog(:,1), mCatalog(:,2), mPos(:,1), mPos(:,2)));
                vDepthDist = abs(mCatalog(nEvent,7)-mCatalog(:,7));
                vSel = ((mDist <= fSpaceDeg) & vDepthDist <= fSpace & (vDecDate(:,1)-vDecDate(nEvent,1) >= 0) &...
                    (vDecDate(:,1)-vDecDate(nEvent,1) <= fTime) & vCluster(nEvent) == 0);
            end% End of isnan(mCatalog)
            mTmp = mCatalog(vSel,:);
            if length(mTmp(:,1)) == 1  % Only one event thus no cluster; IF to determine cluster or not
                fMaxClusterMag = fMag;
            else
                fMaxClusterMag = max(mTmp(:,6));
                [nIndiceMaxMag] = find(mTmp(:,6) == fMaxClusterMag);
                fTimeMaxClusterMag = mTmp(max(nIndiceMaxMag),3);
                % Search for event with bigger magnitude in cluster and add to cluster
                while fMaxClusterMag-fMag > 0
                    [fSpace, fTime] = calc_windows(fMaxClusterMag, nMethod);
                    fSpaceDeg = km2deg(fSpace);
                    %% Adding aftershocks from bigger aftershock
                    mPos = [mTmp(min(nIndiceMaxMag),1) mTmp(min(nIndiceMaxMag),2)];
                    mPos = repmat(mPos,length(mCatalog(:,1)), 1);
                    mDist = abs(distance(mCatalog(:,1), mCatalog(:,2), mPos(:,1), mPos(:,2)));
                    vDepthDist = abs(mTmp(min(nIndiceMaxMag),7)-mCatalog(:,7));
                    vSel2 = ((mDist <= fSpaceDeg) & vDepthDist <= fSpace & (vDecDate(:,1)-mTmp(min(nIndiceMaxMag),3) >= 0) &...
                        (vDecDate(:,1)-mTmp(min(nIndiceMaxMag),3) <= fTime) & vCluster == 0);
                    mTmp = mCatalog(vSel2,:);
                    vSel = (vSel > 0 | vSel2 > 0); % Actual addition
                    if isempty(mTmp) % no events in aftershock zone
                        break;
                    end
                    fMag = fMaxClusterMag;
                    fMaxClusterMag = max(mTmp(:,6));
                    [nIndiceMaxMag] = find(mTmp(:,6) == fMaxClusterMag);
                    fTimeMaxClusterMag = mTmp(max(nIndiceMaxMag),3);
                    if fMaxClusterMag - fMag == 0 % no bigger event in aftershock zone
                        break;
                    end
                end  % End of while
                nCount = nCount + 1; % Set cluster number
            end % End of if length(mTmp)

            [vIndice]=find(vSel); % Vector of indices with Clusters
            vTmpCluster(vIndice,:) = nCount;
            %length(vTmpCluster(vIndice,:));
            nI=1; % Variable counting the length of the cluster
            % Select the right numbers for the cluster using the indice vector vIndice
            % First: Insert cluster number after check for length
            % Second: Check if it's a mainshock
            % Third: Keep the former cluster indice;
            while nI <= length(vIndice)
                if (~isempty(vTmpCluster(vIndice(nI))) & length(vTmpCluster(vIndice,:)) > 1 & vCluster(vIndice(nI)) == 0)
                    vCluster(vIndice(nI)) = vTmpCluster(vIndice(nI));
                    %vEventnr(vIndice,:) = nEvent;
                elseif  (~isempty(vTmpCluster(vIndice(nI)))  &&  length(vTmpCluster(vIndice,:)) == 1  &&  vCluster(vIndice(nI)) == 0)
                    vCluster(vIndice(nI)) = 0;
                else
                    vCluster(vIndice(nI)) = vCluster(vIndice(nI));
                end
                nI=nI+1;
            end %End of while nI
            %                 nCount = nCount + 1; % Set cluster number %% Watch
            %             end % End of if to determine cluster or not %% Watch
            %%% Check if the Cluster is not just one event which can happen in case of keeping the former
            %%% cluster number in preceeding while-Loop
            vSelSingle = (vCluster == nCount);
            [vIndiceSingle] = find(vSelSingle);
            %vTmpSingle(vIndiceSingle,:);
            if length(vIndiceSingle) == 1
                %nCount
                %vIndiceSingle
                vCluster(vIndiceSingle)=0; % Set the event as mainsock
                nCount = nCount-1; % Correct the cluster number down by one
            end
        end % End of if checking magnitude threshold fMagThreshold
    end % End of if checking if vCluster == 0
    if rem(nEvent,100) == 0
        waitbar(nEvent/length(mCatalog(:,6)))
    end % End updating waitbar
end % End of FOR over mCatalog
close(hWaitbar1);
%nCount
%% vCL Cluster vector with mainshocks in it; vCluster is now modified to get rid of mainshocks
vCl = vCluster;

%% Matrix with cluster indice, magnitude and time
mTmpCat = [vCluster mCatalog(:,6) mCatalog(:,3)];
%% Delete largest event from cluster series and add to mainshock catalog
hWaitbar2 = waitbar(0,'Identifying mainshocks in clusters...');
set(hWaitbar2,'Numbertitle','off','Name','Mainshock identification ');
for nCevent = 1:nCount
    %nCevent
    vSel4 = (mTmpCat(:,1) == nCevent); % Select cluster
    mTmpCat2 = mCatalog(vSel4,:);
    fTmpMaxMag = max(mTmpCat2(:,6)); % Select max magnitude of cluster
    vSelMag = (mTmpCat2(:,6) == fTmpMaxMag);
    [nMag] = find(vSelMag);
    if length(nMag) == 1
        vSel5 = (mTmpCat(:,1) == nCevent & mTmpCat(:,2) == fTmpMaxMag); % Select the event
        [vIndiceMag] = find(vSel5); % Find indice
        vCluster(vIndiceMag) = 0;  % Set cluster value to zero, so it is a mainshock
        vMainCluster(vIndiceMag) = nCevent; % Set mainshock vector to cluster number
    elseif isempty(nMag)
        disp('Nothing in ')
        nCevent
    else
        vSel = (mTmpCat(:,1) == nCevent & mTmpCat(:,2) == fTmpMaxMag);
        mTmpCat3 = mCatalog(vSel,:);
        [vIndiceMag] = min(find(vSel)); % Find minimum indice of event with max magnitude in cluster
        vCluster(vIndiceMag) = 0;  % Set cluster value to zero, so it is a mainshock
        vMainCluster(vIndiceMag) = nCevent;  % Set mainshock vector to cluster number
    end
    if rem(nCevent,20) == 0
        waitbar(nCevent/nCount)
    end % End updating waitbar
end % End of For nCevent
close(hWaitbar2);
%% Create a catalog of aftershocks (mCatAfter) and of declustered catalog (mCatDecluster)
vSel = (vCluster(:,1) > 0);
mCatDecluster=mCatalog(~vSel,:);
mCatAfter = mCatalog(vSel,:);


function [hPatch,outP,FV, cl, myLight] = mask2surface(P,varargin)
% ::
%
%    [hPatch,outP,FV, cl, myLight] = mask2surface(P)
%
% :Input:
%
%   **P:**
%        a file name for a mask file, OR a clusters structure
%
% :Inputs:
%
%   **hPatch:**
%        handle to surface patch
%
%   **outP:**
%        file name, with path, of mat file containing faces and vertices
%
%   **FV:**
%        isosurface
%
%   **cl:**
%        clusters structure with coords and meshgrid info
%
%   **varargin:**
%        suppress lighting (0) or do lighting (1)
%
%   **varargin{2}:**
%        color for patch objects
%
% ..
%    tor wager 9/23/02
% ..
%
% uses get_cluster_volume, adapted from Sergey Pakhomov
%
% use with cluster_surf.m to map activations onto surfaces:
% cluster_surf(clusters1,clusters2,outP,10,{[0 1 0] [1 0 0]})
%
% or use getvertexcolors.m to map colors onto surface using hPatch.

hPatch = []; outP = [];  cl = []; myLight = [];
mycolor = [.5 .5 .5];
myalpha = 1;

P = which(P);
if isempty(P), error('Cannot find image.');, end

if isstr(P), cl = mask2clusters(P);, else, cl = P;, P=cl(1).P;, end

height_threshold = .9;
dolight = 1;

if length(varargin) > 0, dolight = varargin{1};, end
if length(varargin) > 1, mycolor = varargin{2};, end

set(0,'CurrentFigure', gcf)

omit = cat(1,cl.numVox);
cl(find(omit==1)) = [];

for i = 1:length(cl)

    % added for SPM2 compatibility
    cl(i).voxSize = abs(cl(i).voxSize);

    cl2(i) = get_cluster_volume(cl(i));
    V = smooth3(cl2(i).vTal,'gaussian',[5 5 5]);

	FV(i) = isosurface(cl2(i).xTal, cl2(i).yTal, cl2(i).zTal, V, height_threshold);
	hPatch(i) = patch(FV);
	isonormals(cl2(i).xTal, cl2(i).yTal, cl2(i).zTal, cl2(i).vTal, hPatch(i));

    try
		set(hPatch, 'Tag', P, 'FaceColor', mycolor, 'EdgeColor', 'none', 'FaceAlpha', myalpha);
	catch
		set(hPatch, 'Tag', P, 'FaceColor', mycolor, 'EdgeColor', 'none');
	end

end

cl = cl2;  clear cl2

if dolight
    view(135,30);
    myLight = standardMRIlighting('full',[hPatch hPatch]);
    material dull
end

[d f e] = fileparts(P);
outP = fullfile(d, filesep,['surf_' f '.mat']);
%if outP(1) == filesep, outP = outP(2:end);end
save(outP, 'FV');

return


function [gly_crop, gly_inrange] = crop_candidates(img_frame, curr_samples, template_size)
%create gly_crop, gly_inrange

nsamples = size(curr_samples,1);
c = prod([template_size 3]);
gly_inrange = zeros(nsamples,1);
gly_crop = zeros(c,nsamples);

for n = 1:nsamples
    curr_afnv = curr_samples(n, :);

    %    [img_cut, gly_inrange(n)] = IMGaffine_r(img_frame, curr_afnv, template_size);
    [img_cut, gly_inrange(n)] = IMGaffine_c(img_frame, curr_afnv, template_size);

    gly_crop(:,n) = reshape(img_cut, c , 1);
end


% distance to closest region of interest
function [data,units,mind] = compute_closestroi2(trx,n,dosave_d)

if nargin < 3,
  dosave_d = true;
end

flies = trx.exp2flies{n};
nflies = numel(flies);
closestfly = cell(1,nflies);
mind = cell(1,nflies);
for i = 1:nflies,
  fly = flies(i);
  ROIdata=trx.roi2{n}.data{fly};
  mind{i} = inf(1,trx(fly).nframes);
  closestfly{i} = nan(1,trx(fly).nframes);
  for j = 1:size(ROIdata,1),
    fn = sprintf('dist2roi2_%d',j);
    dcurr = trx(fly).(fn);
    idx = dcurr < mind{i};
    mind{i}(idx) = dcurr(idx);
    closestfly{i}(idx) = j;
  end
end

% so that we don't compute dcenter twice
if dosave_d,
  data = mind; %#ok<NASGU>
  units = parseunits('mm'); %#ok<NASGU>
  filename = trx.GetPerFrameFile('mindist2roi2',n);
  save(filename,'data','units');
end

data = closestfly;
units = parseunits('unit');


function [signalMovie] = createSignalBasedMovie(inputSignals,inputImages,varargin)
	% uses images and signals for sources from an original movie to create a cleaner, more binary movie
	% biafra ahanonu
	% started: 2014.07.20 [14:09:34]
	% inputs
		% inputSignals - [n t], n = number of signals, t = time
		% inputImages - [n x y], n = number of images, x/y are the dimensions of the images, use permute(inputImages,[3 1 2]) if you store z dimension last
	% outputs
		% signalMovie - [x y t] movie, reconstructed from cell traces
	% options
		% filterInputs: should the input images be automatically filtered to remove large or low SNR signals? 0 = no, 1 = yes
		% signalType 'raw' or 'peak', peaks uses a smoothed version of the detected peaks
		% inputPeaks : [n t] matrix (n = number of signals, t = time) of pre-computed peaks, should contain 1 = peak, 0 = no peak

	% changelog
		% 2017.01.14 [20:06:04] - support switched from [nSignals x y] to [x y nSignals]
        % 2019.08.26 [10:45:29] - Additional threshold, peak support
		% 2021.08.08 [19:30:20] - Updated to handle CIAtah v4.0 switch to all functions inside ciapkg package.
	% TODO
		%

	import ciapkg.api.* % import CIAtah functions in ciapkg package API.

	%========================
	% should the input images be automatically filtered to remove large or low SNR signals?
	options.filterInputs = 0;
	% 'raw' or 'peak', peaks uses a smoothed version of the detected peaks
	options.signalType = 'peak';
	% [n t] matrix (n = number of signals, t = time) of pre-computed peaks, should contain 1 = peak, 0 = no peak
	options.inputPeaks = [];
	% options for peak
	options.dt = 1/5;
	options.tau = 0.5;
	options.pgam = 1-options.dt/options.tau;
	% 'yes', no'
	options.normalizeOutputMovie = 'yes';
	options.waitbarOn = 1;
    options.imageThreshold = 0.4;
	% get options
	options = getOptions(options,varargin);
	% display(options)
	% unpack options into current workspace
	% fn=fieldnames(options);
	% for i=1:length(fn)
	% 	eval([fn{i} '=options.' fn{i} ';']);
	% end
	%========================

	try
		if options.filterInputs==1
			[inputImages, inputSignals, valid, imageSizes] = filterImages(inputImages, inputSignals);
		end
		inputSignalsCopy = inputSignals;
		nSignals = size(inputSignalsCopy,1);
		nPts = size(inputSignalsCopy,2);
		mSize = size(inputImages);
		movieDims = [mSize(1) mSize(2) nPts];
		signalMovie = double(NaN(movieDims));
		inputImagesBinary = thresholdImages(inputImages,'binary',1,'threshold',options.imageThreshold);
		if isempty(options.inputPeaks)
			[signalPeaks, signalPeakIdx] = computeSignalPeaks(inputSignals,'makePlots',0,'makeSummaryPlots',0,'numStdsForThresh',2.3,'detectMethod','raw');
		else
			signalPeaks = options.inputPeaks;
		end
		switch options.signalType
			case 'peak'
				inputSignalsCopy = signalPeaks;
				inputSignalsCopy = inputSignalsCopy + 0.5;
				for signalNo = 1:nSignals
					V.dt    = options.dt;  % time step size
					tau     = options.tau;    % decay time constant
			        P.gam   = 1-options.dt/options.tau; % C(t) = gam*C(t-1)
					inputSignalsCopy(signalNo,:) = filter(1,[1 -P.gam],inputSignalsCopy(signalNo,:));         % calcium concentration
				end
			case 'raw'

			otherwise
				% body
		end

		reverseStr = '';
		for signalNo = 1:nSignals
			try
				%thisSignal = zeros([1 1 nPts]);
				%thisSignal(1,1,:) = inputSignalsCopy(signalNo,:);
				thisSignal = inputSignalsCopy(signalNo,:);
				thisImage = squeeze(inputImagesBinary(:,:,signalNo));
				% get location of all cell pixels and setup linear indexing variables
				[x y] = find(thisImage==1);
				xrepmat = repmat(x,[1 nPts])';
				yrepmat = repmat(y,[1 nPts])';
				framerepmat = repmat(1:nPts,[1 length(x)]);
				% get the linear index in the movie of all points to replace, faster than looping over each frame
				linearInd = sub2ind(movieDims, xrepmat(:),yrepmat(:), framerepmat(:));
				% repeat the signal so it will fill the entire binary part of the image
				thisSignalRepmat = repmat(thisSignal,[1 length(x)]);
				%
				% [size(thisSignalRepmat(:)) size(linearInd) 10]
				%isempty(thisSignalRepmat(:))
				% [size(signalMovie)]
				signalMovie(linearInd) = thisSignalRepmat(:);
				reverseStr = cmdWaitbar(signalNo,nSignals,reverseStr,'inputStr','making trace movie','waitbarOn',options.waitbarOn,'displayEvery',1);
				% =======
				% OLD
				%for i=1:nPts
				%    signalMovie(x,y,i) = thisSignal(i);
				%end
				%playMovie(signalMovie);
				%tmpMovie = repmat(thisImage,[1 1 nPts]);
				%tmpMovie = bsxfun(@times,thisSignal,tmpMovie);
				%playMovie(tmpMovie);
				%signalMovie = signalMovie + tmpMovie;
				% =======
			catch err
				display(repmat('@',1,7))
				disp(getReport(err,'extended','hyperlinks','on'));
				display(repmat('@',1,7))
			end
		end

		switch options.normalizeOutputMovie
			case 'yes'
				% normalize movie to keep consistent
				[signalMovie] = normalizeVector(signalMovie,'normRange','zeroToOne');
			case 'no'
				%
			otherwise
				% body
		end

	catch err
		display(repmat('@',1,7))
		disp(getReport(err,'extended','hyperlinks','on'));
		display(repmat('@',1,7))
	end
end


function day_list_common ( y1, m1, d1, y2, m2, d2 )

%*****************************************************************************80
%
%% DAY_LIST_COMMON prints a list of days between two dates.
%
%  Discussion:
%
%    Given the dates of September 25, 2005 and October 2, 2005,
%    the routine should print out:
%
%    Sun, Sep 25 2005 -
%    Mon, Sep 26 2005 -
%    Tue, Sep 27 2005 -
%    Wed, Sep 28 2005 -
%    Thu, Sep 29 2005 -
%    Fri, Sep 30 2005 -
%    Sat, Oct 01 2005 -
%    Sun, Oct 02 2005 -
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    15 June 2012
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer Y1, M1, D1, the first date.
%
%    Input, integer Y2, M2, D2, the second date.
%
  y = y1;
  m = m1;
  d = d1;
  f = 0.0;

  cmp = '<';

  while ( cmp ~= '>' )

    w = ymdf_to_weekday_common ( y, m, d, f );

    w_name = weekday_to_name_common3 ( w );

    m_name = month_to_month_name_common3 ( m );

    fprintf ( 1, '%3s, %3s %02d %4d -\n', w_name, m_name, d, y );

    [ y, m, d, f ] = ymdf_next_common ( y, m, d, f );

    cmp = ymdf_compare ( y, m, d, f, y2, m2, d2, f );

  end

  return
end


 close all;clear all;clc
tic;
%% inputs

options=odeset('RelTol',1e-9,'AbsTol',1e-9);

solinit = bvpinit(linspace(0,6,3),5*ones(3,1));

[T,Y]=bvpMSM('bvpme',solinit,@bcsme,@dbcsme,options);
figure(2);plot(T,Y);axis tight
toc


function E = stToEdges( S, nms, suppress )
% Convert sketch tokens to edges.
%
% USAGE
%  E = stToEdges( S, [nms], [suppress] )
%
% INPUTS
%  S          - [h x w x (nTokens+1)] sketch token probability maps
%  nms        - [1] if true apply non-maximum suppression to edges
%  suppress   - [1] if true suppress boundary confidence in order to
%                   compensate padding effect
%
% OUTPUTS
%  E          - [h x w] edge probability map
%
% EXAMPLE
%
% See also stDetect
%
% Sketch Token Toolbox     V0.95
% Copyright 2013 Joseph Lim [lim@csail.mit.edu]
% Please email me if you find bugs, or have suggestions or questions!
% Licensed under the Simplified BSD License [see bsd.txt]

    % get default arguments
    if(nargin<2 || isempty(nms)),
        nms=1;
    end
    if(nargin<3 || isempty(suppress)),
        suppress=1;
    end

    % extract edge probabilities
    E = 1-S(:,:,end);

    % apply nms
    if nms
        O=edgeOrient(E,4);
        E=edgeNms(E,O,1);
    end

    % apply boundary suppression
    if suppress
        S=5;
        for s=1:S,
            E([s end-s+1],:,:)=E([s end-s+1],:,:)*(s-1)/S;
        end
        for s=1:S,
            E(:,[s end-s+1],:)=E(:,[s end-s+1],:)*(s-1)/S;
        end
    end

end

function E = edgeNms( E, O, r )
    % suppress locations where edge is stronger in orthogonal direction
    E1=imPad(E,r+1,'replicate');
    Dx=cos(O);
    Dy=sin(O);

    [ht,wd]=size(E1);
    [cs,rs]=meshgrid(r+2:wd-r-1,r+2:ht-r-1);
    for i=-r:r,
        if i==0
            continue;
        end
        cs0=i*Dx+cs;
        dcs=cs0-floor(cs0);
        cs0=floor(cs0);

        rs0=i*Dy+rs;
        drs=rs0-floor(rs0);
        rs0=floor(rs0);

        E2 = (1-dcs).*(1-drs) .* E1(rs0+0+(cs0-1)*ht);
        E2 = E2 + dcs.*(1-drs) .* E1(rs0+0+(cs0-0)*ht);
        E2 = E2 + (1-dcs).*drs .* E1(rs0+1+(cs0-1)*ht);
        E2 = E2 + dcs.*drs .* E1(rs0+1+(cs0-0)*ht);
        E(E*1.01<E2) = 0;
    end
end

function O = edgeOrient( E, r )
    % compute very approximate orientation map from edge map
    E2=convTri(E,r);
    f=[-1 2 -1];

    Dx=conv2(E2,f,'same');
    Dy=conv2(E2,f','same');
    F=conv2(E2,[1 0 -1; 0 0 0; -1 0 1],'same')>0;
    Dy(F)=-Dy(F);
    O=mod(atan2(Dy,Dx),pi);
end


function output = callqpip(interfacedata)

% Retrieve needed data
options = interfacedata.options;
model = yalmip2quadprog(interfacedata);

if options.savedebug
    model.ops = options.qpip;
    save debugfile model
end

if options.showprogress;showprogress(['Calling ' interfacedata.solver.tag],options.showprogress);end
solvertime = tic;
[x,flag,lm] = qpip(model.Q, model.c, model.A, model.b, model.Aeq, model.beq, model.lb, model.ub, options.verbose,options.qpip.mu,options.qpip.method);
solvertime = toc(solvertime);

% Internal format for duals
if ~isempty(lm)
    D_struc = [lm.equality;lm.inequality];
else
    D_struc = [];
end

% Check, currently not exhaustive...
switch flag
    case 0
        problem = 0;
    case 2
        problem = 1;
    otherwise
        problem = 1;
end

infostr = yalmiperror(problem,'QPIP');

% Save all data sent to solver?
if options.savesolverinput
    solverinput = model;
else
    solverinput = [];
end

% Save all data from the solver?
if options.savesolveroutput
    solveroutput.x = x;
    solveroutput.flag = flag;
    solveroutput.lm = lm;
else
    solveroutput = [];
end

% Standard interface
output = createOutputStructure(x(:),D_struc,[],problem,infostr,solverinput,solveroutput,solvertime);


function [S,Y,YS,lbfgs_start,lbfgs_end,Hdiag,skipped] = lbfgsAdd(y,s,S,Y,YS,lbfgs_start,lbfgs_end,Hdiag,useMex)
ys = y'*s;
skipped = 0;
corrections = size(S,2);
if ys > 1e-10
	if lbfgs_end < corrections
		lbfgs_end = lbfgs_end+1;
		if lbfgs_start ~= 1
			if lbfgs_start == corrections
				lbfgs_start = 1;
			else
				lbfgs_start = lbfgs_start+1;
			end
		end
	else
		lbfgs_start = min(2,corrections);
		lbfgs_end = 1;
	end

	if useMex
		lbfgsAddC(y,s,Y,S,ys,int64(lbfgs_end));
	else
		S(:,lbfgs_end) = s;
		Y(:,lbfgs_end) = y;
	end
	YS(lbfgs_end) = ys;

	% Update scale of initial Hessian approximation
	Hdiag = ys/(y'*y);
else
	skipped = 1;
end