ID:45683
Title:getting better
Author:nathan q
Date:2008-04-30 19:15:59
Score:27904.8153
Result:278978.00 (cyc: 14, node: 779)
CPU Time:1.6749
Status:Passed
Comments:
Based on:none
Code:
function W = solver(B)

% gettingBetter: bring mutiple pins into the network
% wifi2: keep track of voltage to avoid crossings

V=B;    % voltage map

Bv = B(:);
sizeB = size(B);
W = zeros(0,4);

BvNZ = Bv(logical(Bv));   % non-zero elements

pinIDs = sort(unique(BvNZ),'descend');
nIDs = numel(pinIDs);    % there is always a zero in the list

if isempty (pinIDs) return; end


% loop over possible nets
for i=1:nIDs

    % start with the highest-valued group (first in the list)
    pinID = pinIDs(i);

    % number of pins in this net
    nPins = sum(BvNZ==pinID);
    if nPins<=1
        continue
    end
    livePins = false(nPins,1);    % true for pins that are connected

    %locations of pins in this net
    pinLocs2D = zeros(nPins,2);

    pinLocs1D = find(Bv==pinID);
    for j=1:nPins
        [pinLocs2D(j,1) pinLocs2D(j,2)] = ind2sub(sizeB,pinLocs1D(j));   % this could probably be faster
    end

    % for the first pin on the list, just find its nearest neighbour and connect them
    iPin = 1;   % first pin in the net
    %staircase distance from pin1 to every other pin
    dist = sum(abs(pinLocs2D(iPin*ones(nPins,1),:) - pinLocs2D),2);
    dist(iPin) = Inf;
    wLink=[];
    while isempty(wLink) && any(dist<Inf)
        [distMin,iTarget] = min(dist);
        [wLink,V] = pathfinder1(pinLocs2D(iPin,:), pinLocs2D(iTarget,:), V);
        dist(iTarget) = Inf;   % don't check last target pin again
    end
    if any(wLink)
        W=[W; wLink];
        livePins(iPin)=1;
        livePins(iTarget)=1;
    end
    
    % now loop over all pins, and for ones that aren't live, try to connect them. 
    
    % THIS IS SLOW
    if livePins(iPin)    % For now, only do this if we've already succeeded on the first connection (but that's STUPID).
        for iPin=1:nPins
            if livePins(iPin)
                continue
            end
            dist = sum(abs(pinLocs2D(iPin*ones(nPins,1),:) - pinLocs2D),2);
            dist(iPin) = Inf;
            dist(~livePins)=Inf;
            [distMin,iDistMin] = min(dist);
            [wLink,V] = pathfinder1(pinLocs2D(iPin,:), pinLocs2D(iDistMin,:), V);

            if any(wLink)
                W=[W; wLink];
                livePins(iPin)=1;
                livePins(iDistMin)=1;  % this shouldn't be necessary
            end
        end
    end
end


return


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [W,V] = pathfinder1(loc1,loc2,V);

% return a series of moves (links) from loc1 to loc2 on the board B
% this is pathfinder 1 - looks for simple horiz and vert paths only

i1=loc1(1);
j1=loc1(2);
i2=loc2(1);
j2=loc2(2);

W=[];

v = V(i1,j1);  % "voltage"
V0 = V;
V0(V==v) = 0;    % zero out locations at the same voltage we are at - we can safely run wires through them

% check for very special case - pins are adjacent
if abs(i1-i2)+abs(j1-j2)==1   
    W = [i1 j1 i2 j2]; 
    V = updateV(V,W,v);
    return
end

% less special - on the same row
if i1==i2
    if j2<j1
        [j2,j1]=copyVar(j1,j2); [i2,i1]=copyVar(i1,i2);
    end
    if sum(V0(i1,j1+1:j2-1)) == 0    % clear path between them
        L = ones(j2-j1,1);   % length of path
        W = [ i1*L (j1:j2-1)' i2*L (j1+1:j2)' ];
        V = updateV(V,W,v);
        return
    else
        return
    end
end

% less special - on the same column
if j1==j2
    if i2<i1
        [j2,j1]=copyVar(j1,j2); [i2,i1]=copyVar(i1,i2);
    end
    if sum(V0(i1+1:i2-1,j1)) == 0    % clear path between them
        L = ones(i2-i1,1);   % length of path
        W = [ (i1:i2-1)' j1*L (i1+1:i2)' j2*L ];
        V = updateV(V,W,v);
        return
    else
        return
    end
end

% if we get this far, pins are not on the same row or col. 
% Try the 2 possible routes around the sides of a rectangle, using this function
% recursively to get to the corner.

if ~V0(i1,j2)
    [W1,V] = pathfinder1([i1 j1],[i1 j2],V);
    if any(W1)
        [W2,V] = pathfinder1([i1 j2],[i2 j2],V);
        if any(W2)
            W=[W1; W2];
            V = updateV(V,W,v);
            return
        end
    end
elseif ~V0(i2,j1)
    [W1,V] = pathfinder1([i1 j1],[i2 j1],V);
    if any(W1)
        [W2,V] = pathfinder1([i2 j1],[i2 j2],V);
        if any(W2)
            W=[W1; W2];
            V = updateV(V,W,v);
            return
        end
    end
end

% if we get this far, we've failed

return % end of pathfinder1
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


function V = updateV(V,W,v)
% Update the voltage map with a new set of connectors.
n = size(W,1);
%v = V(W(1,1),W(1,2));

V(W(1,1),W(1,2))=v;
% this loop could be faster
for i=1:n;
    V(W(i,3),W(i,4)) = v;
end

return

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function[b1,b2] = copyVar(a1,a2)
b1=a1;
b2=a2;
return