Finish 2012-11-07 16:00:00 UTC

Sleer Fiddled

by Nicholas Howe

Status: Passed
Results: 1427 (cyc: 6, node: 2980)
CPU Time: 77.709
Score: 2696.16
Submitted at: 2012-11-02 20:57:49 UTC
Scored at: 2012-11-02 21:13:27 UTC

Current Rank: 1514th (Highest: 67th )
Basis for: octarine is not a colour (diff)
Basis for: Just passing by (diff)
Basis for: The art of mergers (diff)
...and 1 other.

Comments
Please login or create a profile.
Code
function xy = sleerfid(a, xy, wts)
    xy1 = try09(a, xy, wts);
    n1 = numKnots(xy1,a);
    xy2 = hannes(a, xy, wts);
    n2 = numKnots(xy2,a);
    xy3 = blackwidow(a, xy, wts);
    n3 = numKnots(xy3,a);
    if ((n1<n2)&(n1<n3))
        xy = xy1;
    elseif (n2<n3)
        xy = xy2;
    else
        xy = xy3;
    end;
end

function xyOut = try09(a, xyIn, wts)

N=size(xyIn,1);

D=min(N,mindist(a).^0.25);
mD=mean(D,1);
E=D-repmat(mD,[size(D,1),1])-repmat(mD',[1,size(D,2)])+mean(mD);
[x,nill]=svd(E);
xyOut0=x(:,1:2); 

beta1=10;
beta2=120;
lambda=.1;
thr=.01;
xyOut=N*xyOut0+randn(size(xyOut0))/1e3;
for ncut=1:2
    M=a; M(1:size(M,1)+1:end)=1;
    M=bsxfun(@rdivide,M,sum(M,2));
    Mbeta=(((1-lambda)*eye(N)+lambda*M)^beta1);
    for n1=1:beta2
        xyOut=Mbeta*xyOut;
        mxyOut=mean(xyOut,1);
        cxyOut=cov(xyOut,1);
        [c1,d1,c2]=svd(cxyOut);
        xyOut=(xyOut-mxyOut(ones(N,1),:))*c1*diag(1./sqrt(.1+diag(d1)))*c2'; %sqrtm(pinv(.1*eye(2)+cxyOut));
    end
    [i,j]=find(a>thr); 
    dd=sum((xyOut(i,:)-xyOut(j,:)).^2,2);
    k=find(dd>4*mean(dd));
    if isempty(k), break; end
    a(i(k)+N*(j(k)-1))=thr;
end
xyOut0=xyOut;


xyOut0=sqrt(N)*detrend(xyOut0,'constant')*diag(1./max(eps,std(xyOut0,1,1)));
K=10;
k=1;
[sxyOut0,idxequal]=sortrows(round(K*xyOut0)/K);
idxequal=idxequal(all(~diff(sxyOut0,1,1),2));
xyOut=round(xyOut0*k);
while size(unique(xyOut,'rows'),1)~=N
    k=k*2;
    xyOut=xyOut0*k;
    xyOut(idxequal,:)=(xyOut0(idxequal,:)+randn(numel(idxequal),2)/K)*k;
    xyOut=round(xyOut);
end
dxy = round(wts*(xyOut-xyIn)./sum(wts)); % Howe's
xyOut = bsxfun(@minus,xyOut,dxy);

end

function D=mindist(C)

N=size(C,1);
X=logical(speye(N));
D=inf(N,N);

D(X)=0;
for n=1:N,
    X=(C*X)>0;
    X=X&(D>n);
    if ~any(X(:)),break;end
    D(X)=n;
end

end

function xyOut = hannes(a, xyIn, wts)
sz=size(a,1);
deg=diag(sum(a));
L=diag(sum(a))-a;
[V,D]=eig(L,deg);
xyOut=0;
outdiam=sqrt(sum((max(V(:,2:3))-min(V(:,2:3))).^2));
indiam=sqrt(sum((max(xyIn)-min(xyIn)).^2));
mult=indiam/outdiam;
while size(unique(xyOut,'rows'),1)<sz
xyOut=round(V(:,2:3)*mult);
[u,i]=unique(xyOut,'rows');
m=setdiff(1:sz,i);
xyOut(m,:)=xyOut(m,:)+round(rand(length(m),2))*2-1;
mult=mult*1.5;
end;
end

function xy = blackwidow(a, xy, wts)

nn = length(a);
mid = mean(xy);
dev = std(xy);
[u,s,v] = svd(xy);
if (s(2,2)<0.1)
    xy = xy+bsxfun(@times,2*sqrt(s(1))*randn(nn,1),v(:,2)');
end;

%logical a for outer boundary finding
la = logical(a);
deg = sum(la);
while any(deg==1)
    la(deg==1,:) = 0;
    la(:,deg==1) = 0;
    deg = sum(la);
end;

ia = logical(a*a*a*a+eye(nn));
if ~all(ia(:))
    xy = relax2(la, ia, xy, 10, false);
end;
ia = logical(a*a*a+eye(nn));
if ~all(ia(:))
    xy = relax2(la, ia, xy, 20, false);
end;
ia = logical(a*a+eye(nn));
if ~all(ia(:))
    xy = relax2(la, ia, xy, 20, false);
end;
ia = logical(a+eye(nn));
xy = relax2(la, ia, xy, 10, nn>50);
%wa = edgeWeights(a,xy);
xy = relax2(la, ia, xy, 30, nn>50);

%         gplot(ia,xy,'o-');
%         axis equal;
%         waitforbuttonpress;
% % synthetic spherical deprojection
%         d = sqrt(sum(xy.^2,2));
%         radius = max(d)*1.1;
%         th = acos(d./radius);
%         d2 = (pi/2-th)*radius;
%         xy = xy.*repmat(d2./d,1,2);
%         gplot(ia,xy,'o-');
%         axis equal;
%         waitforbuttonpress;
        
end

function xy = relax2(a, wa, xy, nrep, dohoop)
% Iterative method based on https://akpublic.research.att.com/areas/visualization/papers_videos/pdf/DBLP-journals-camwa-Koren05.pdf

% gplot(a,xy,'o-');
% axis equal;
% waitforbuttonpress;

nn = length(wa);
dev = std(xy);

% xymin = min(xy);
% xymax = max(xy);


% gplot(a,xy,'o-');
% axis equal;
% waitforbuttonpress;

for i = 1:nrep*nn
    j = randi(nn);
    nz = find(wa(j,:));
    w = wa(nz,j);
    wsum = sum(w);
    xy(j,1) = sum(xy(nz,1).*w)./wsum;
    xy(j,2) = sum(xy(nz,2).*w)./wsum;
    
    if (mod(i,nn)==0)
        xy = xy-repmat(mean(xy),nn,1);
        xy = xy.*repmat(dev./std(xy),nn,1);
        
        if dohoop
%             gplot(ia,xy,'o-');
%             axis equal;
%             waitforbuttonpress;
            xy = hoop(xy,a);
%             gplot(ia,xy,'o-');
%             axis equal;
%             waitforbuttonpress;
        end;
        
        [u,s,v] = svd(xy);
        xy  = u(:,1:2)*diag(sqrt([prod(diag(s)) prod(diag(s))]))*v';

%         gplot(ia,xy,'o-');
%         axis equal;
%         waitforbuttonpress;
    end;
end;

% gplot(a,xy,'o-');
% axis equal;
% waitforbuttonpress;

% force to grid
for i = 1:nn
    xy(i,:) = vicinityPoint(xy(i,:),xy(1:i-1,:));
end;
end

function xy = relax(a, ia, xy, nrep, dohoop)
% Iterative method based on https://akpublic.research.att.com/areas/visualization/papers_videos/pdf/DBLP-journals-camwa-Koren05.pdf

nn = length(ia);
dev = std(xy);

for i = 1:nrep*nn
    j = randi(nn);
    xy(j,:) = mean(xy(ia(:,j),:));
    
    if (mod(i,nn)==0)
        xy = xy-repmat(mean(xy),nn,1);
        xy = xy.*repmat(dev./std(xy),nn,1);
        
        if dohoop
            xy = hoop(xy,a);
        end;
        
        [u,s,v] = svd(xy);
        xy  = u(:,1:2)*diag(sqrt([prod(diag(s)) prod(diag(s))]))*v';
    end;
end;

% force to grid
for i = 1:nn
    xy(i,:) = vicinityPoint(xy(i,:),xy(1:i-1,:));
end;
end

function xy = hoop(xy,a)
k = outer(xy,a);
d = sqrt(sum(xy.^2,2));
maxd = max(d);
xy(k,:) = xy(k,:).*repmat(maxd./d(k),1,2);
end

function k = outer(xy,a)
%figure(1);
% clf
% gplot(a,xy,'o-');
% axis equal;
% hold on

nn = size(xy,1);
deg = sum(a);
ink = false(1,nn);
vc = (deg'>0)&(xy(:,1)==min(xy(deg>0,1)));
v = find(vc&(xy(:,2)==min(xy(vc,2))),1);
th = pi/2;
hp = atan2(xy(:,2),xy(:,1));
hp1 = hp(v);
chp = 0;
% plot(xy(v,1),xy(v,2),'r*');
i = 0;
while (chp < 2*pi)&(i<nn)
    i = i+1;
    ink(v) = true;
    hp0 = hp1;
    nbr = find(a(v,:));
    dir0 = atan2(xy(nbr,2)-xy(v,2),xy(nbr,1)-xy(v,1));
    dir = mod(dir0-hp(v),2*pi);
    dir(ink(nbr)) = dir(ink(nbr))-10;
    [~,iv] = max(dir);
    %figure(2);
    %clf; hold on; for i = 1:numel(nbr), plot(xy([v nbr(i)],1),xy([v nbr(i)],2),'o-'); end; axis equal; hold off
    v0 = v;
    v = nbr(iv);
    %figure(1);
%     plot(xy(v,1),xy(v,2),'r*');
%     title(v);
%     xlabel(chp);
    hp1 = hp(v);
    chp = chp+mod(hp0-hp1+pi,2*pi)-pi;
    th = atan2(xy(v0,2)-xy(v,2),xy(v0,1)-xy(v,1));
end;
k = find(ink);
end


function xy = vicinityPoint(xy0,pxy)
r = 0;
xy = [];
rxy0 = round(xy0);
if isempty(pxy)
    xy = rxy0;
end;
while isempty(xy)
    hits = find((pxy(:,1)>=rxy0(1)-r)&(pxy(:,1)<=rxy0(1)+r)&(pxy(:,2)>=rxy0(2)-r)&(pxy(:,2)<=rxy0(2)+r));
    filled = sparse(pxy(hits,2)-rxy0(2)+1+r,pxy(hits,1)-rxy0(1)+1+r,true,2*r+1,2*r+1);
    if ~all(filled(:))
        [xg,yg] = meshgrid(rxy0(1)+(-r:r)-xy0(1),rxy0(2)+(-r:r)-xy0(2));
        d = xg.^2+yg.^2;
        d(filled) = inf;
        [bdy,bdx] = find(d==min(d(:)),1);
        xy = rxy0+[bdx bdy]-r-1;
    else
        r = r+1;
    end
end;
end
function N = numKnots(XY,A)

% This function finds the number of knots in a network of points XY whose
% connectivity is given by A.

% Consider only unique lines (A is symmetric with ones on diagonal)
A = triu(A,1);
nLines = nnz(A);

% Find xy coordinates for first and second point on each line
[p1i,p2i] = find(A);
x1 = repmat(XY(p1i,1),1,nLines);
y1 = repmat(XY(p1i,2),1,nLines);
x2 = repmat(XY(p2i,1),1,nLines);
y2 = repmat(XY(p2i,2),1,nLines);
x3 = repmat(XY(p1i,1)',nLines,1);
y3 = repmat(XY(p1i,2)',nLines,1);
x4 = repmat(XY(p2i,1)',nLines,1);
y4 = repmat(XY(p2i,2)',nLines,1);

pick = tril(true(nLines),-1);
x1 = x1(pick);
y1 = y1(pick);
x2 = x2(pick);
y2 = y2(pick);
x3 = x3(pick);
y3 = y3(pick);
x4 = x4(pick);
y4 = y4(pick);

N = sum(areIntersecting(x1,y1,x2,y2,x3,y3,x4,y4));
end

function bool = areIntersecting(x1,y1,x2,y2,x3,y3,x4,y4)
% Determine if two line segments intersect.
%
% line1 = [x1, y1, x2, y2]
% line2 = [x3, y3, x4, y4]
%
% This function is robust to floating point precision issues assuming all
% input coordinates are integer-valued. If all coordinates have absolute
% values that do not exceed x, then the arithmetic operations used in this
% function could, as an intermediate step, produce a value with magnitude
% as large as 8*x^4. For double-precision floating point, this implies
% that the following must be satisfied:
%
% 8*x^4 < 2^53
%
% or equivalently, x < 5792.
%
% http://en.wikipedia.org/wiki/Line-line_intersection

bool = false(1,numel(x1));
gen = true(numel(x1),1);

% Test to see if the lines share exactly one endpoint. If so, the lines
% intersect if either of the free points lies on the line segment formed by
% the other two points.

s13 = find((x1==x3)&(y1==y3));
%s13 = find((x1==x3)&(y1==y3)&((x2~=x4)|(y2~=y4)));
bool(s13) = (isPointOnSegment(x2(s13), y2(s13), x1(s13), y1(s13), x4(s13), y4(s13))|isPointOnSegment(x4(s13), y4(s13), x1(s13), y1(s13), x2(s13), y2(s13)));
gen(s13) = false;
s14 = find((x1==x4)&(y1==y4));
%s14 = find((x1==x4)&(y1==y4)&((x2~=x3)|(y2~=y3)));
bool(s14) = (isPointOnSegment(x2(s14), y2(s14), x1(s14), y1(s14), x3(s14), y3(s14))|isPointOnSegment(x3(s14), y3(s14), x1(s14), y1(s14), x2(s14), y2(s14)));
gen(s14) = false;
s23 = find((x2==x3)&(y2==y3));
%s23 = find((x2==x3)&(y2==y3)&((x1~=x4)|(y1~=y4)));
bool(s23) = (isPointOnSegment(x1(s23), y1(s23), x2(s23), y2(s23), x4(s23), y4(s23))|isPointOnSegment(x4(s23), y4(s23), x1(s23), y1(s23), x2(s23), y2(s23)));
gen(s23) = false;
s24 = find((x2==x4)&(y2==y4));
%s24 = find((x2==x4)&(y2==y4)&((x1~=x3)|(y1~=y3)));
bool(s24) = (isPointOnSegment(x1(s24), y1(s24), x2(s24), y2(s24), x3(s24), y3(s24))|isPointOnSegment(x3(s24), y3(s24), x1(s24), y1(s24), x2(s24), y2(s24)));
gen(s24) = false;

% Next we check for parallel and coincident lines. Parallel lines
% obviously don't intersect. Coincident lines intersect if an endpoint from
% one of the lines lies on the other segment.

ss = find(gen&haveSameSlope(x1, y1, x2, y2, x3, y3, x4, y4));
gen(ss) = false;
si = ss(haveSameIntercept(x1(ss), y1(ss), x2(ss), y2(ss), x3(ss), y3(ss), x4(ss), y4(ss)));
bool(si) = ((isPointBetween(x3(si), x4(si), x1(si), 1) & isPointBetween(y3(si), y4(si), y1(si), 1)) | ...
               (isPointBetween(x3(si), x4(si), x2(si), 1) & isPointBetween(y3(si), y4(si), y2(si), 1)) | ...
               (isPointBetween(x1(si), x2(si), x3(si), 1) & isPointBetween(y1(si), y2(si), y3(si), 1)) | ...
               (isPointBetween(x1(si), x2(si), x4(si), 1) & isPointBetween(y1(si), y2(si), y4(si), 1)));

% If we get this far, we're in the general case of two well-defined
% non-parallel lines. The lines formed by the two segments must intersect
% somewhere. Find this intersection point and determine if it lies on the
% segments.

gen = find(gen);

Px_n = (x1(gen).*y2(gen) - y1(gen).*x2(gen)).*(x3(gen) - x4(gen)) - (x1(gen) - x2(gen)).*(x3(gen).*y4(gen) - y3(gen).*x4(gen));
Px_d = (x1(gen) - x2(gen)).*(y3(gen) - y4(gen)) - (y1(gen) - y2(gen)).*(x3(gen) - x4(gen));

Py_n = (x1(gen).*y2(gen) - y1(gen).*x2(gen)).*(y3(gen) - y4(gen)) - (y1(gen) - y2(gen)).*(x3(gen).*y4(gen) - y3(gen).*x4(gen));
Py_d = (x1(gen) - x2(gen)).*(y3(gen) - y4(gen)) - (y1(gen) - y2(gen)).*(x3(gen) - x4(gen));

bool(gen) = (isPointBetween(x1(gen), x2(gen), Px_n, Px_d) & ...
    isPointBetween(y1(gen), y2(gen), Py_n, Py_d) & ...
    isPointBetween(x3(gen), x4(gen), Px_n, Px_d) & ...
    isPointBetween(y3(gen), y4(gen), Py_n, Py_d));

end

function bool = haveSameIntercept(x1, y1, x2, y2, x3, y3, x4, y4)
bool = (x4 - x3).*(y1.*(x2 - x1) - x1.*(y2 - y1)) == ...
       (x2 - x1).*(y3.*(x4 - x3) - x3.*(y4 - y3));
end

function bool = haveSameSlope(x1, y1, x2, y2, x3, y3, x4, y4)
bool = (y2 - y1).*(x4 - x3) == (x2 - x1).*(y4 - y3);
end

function bool = isPointOnSegment(x1, y1, x2, y2, x3, y3)
% Determine if point (x1, y1) is on the segment formed by (x2, y2) and (x3, y3).
bool = haveSameSlope(x2, y2, x1, y1, x1, y1, x3, y3) & ...
       isPointBetween(x2, x3, x1, 1) & ...
       isPointBetween(y2, y3, y1, 1);
end

function bool = isPointBetween(pt1, pt2, num, den)
% Determine if either of the following is satisfied:
% pt1 <= num/den <= pt2
% pt1 >= num/den >= pt2

bool = ((pt1.*den <= num) & (num <= pt2.*den)) | ...
       ((pt1.*den >= num) & (num >= pt2.*den));
end