function [maxVal,location] = logerr(p,q)
%
% modes = logerr(p,q) -- Find location of max. log-error between p&q
%
%
%
% Copyright (C) 2003 Alexander Ihler; distributable under GPL -- see README.txt
start = [getPoints(p),getPoints(q)];
tol=1e-4; % set tolerance values etc.
max_it=1000;
minDistance = 1e-2;
ppts = getPoints(p); pwts = getWeights(p); NptsP = size(ppts,2); pBW = getBW(p,1:NptsP);
qpts = getPoints(q); qwts = getWeights(q); NptsQ = size(qpts,2); qBW = getBW(q,1:NptsQ); bwMin = min([pBW,qBW],[],2);
Ndim = size(ppts,1); Nloc = size(start,2);
modeList = []; vals = []; bwmin = min([min(min(pBW)),min(min(qBW))]);
for m=1:Nloc % From each location given:
x = start(:,m); % rename for convenience
xTmp = x+inf;
iter = 1; alpha = .1; dxprev = 0*x;
% GRADIENT ASCENT TO FIND A MODE:
while (tol < dist(x,xTmp,bwMin) && iter < max_it) % Iterate until convergence:
pdiff = ppts - repmat(x,[1,NptsP]); % get distance from kernel centers
qdiff = qpts - repmat(x,[1,NptsQ]);
xTmp = x; % and compute the update:
if (strcmp('GaussianGaussian',[getType(p),getType(q)]))
Kp = prod(exp(-.5*(pdiff./pBW).^2)./pBW,1);
Kq = prod(exp(-.5*(qdiff./qBW).^2)./qBW,1);
px = pwts * Kp'; qx = qwts * Kq'; px = px + eps; qx = qx + eps;
dx = (pdiff./ pBW.^2)*(pwts .* Kp)'./px - (qdiff./ qBW.^2)*(qwts .* Kq)'./qx;
x = sign(log(px/qx)) * alpha * dx + x;
else error('Sorry; KDE type(s) not implemented');
end;
if (min(dx .* dxprev)>0) alpha = alpha ./ .9; else alpha = .5*alpha; end;
if (alpha < 1e-3) iter = inf; end;
dxprev = dx;
iter = iter + 1; % increment and continue
end
% if (iter < max_it)
modeList = [modeList,x]; % save all extremum
vals = [vals,abs(log(px/qx))]; % and how extreme
% end;
end
[vals,order] = sort(-vals);
modeList = modeList(:,order);
m = 1; % Remove any redundant modes:
while (m < size(modeList,2)) % start with "best" modes and
ind = [m+1:size(modeList,2)]; % work downwards:
d = dist( modeList(:,ind), modeList(:,m+0*ind), bwMin(:,1+0*ind));
ok = find(d > minDistance); % remove any within minDistance
modeList = modeList(:,[1:m,m+ok]); % of a better mode
vals = vals(:,[1:m,m+ok]);
m = m+1;
end;
maxVal = -vals(1); location = modeList(:,1);
function d=dist(x,y,bw)
d = sqrt( sum( ((x-y)./bw).^2 ,1));