ID:45689
Title:pickle, complex and arbitrary
Author:nathan q
Date:2008-04-30 21:19:01
Score:22688.4437
Result:226757.00 (cyc: 19, node: 966)
CPU Time:4.9272
Status:Passed
Comments:
Based on:none
Code:
function W = solver(B)

% gettingBetter3: start with most valuable nets, not highest voltages
% gettingBetter2: multiple nets
% 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

% evaluate total value of each net
for i=1:nIDs
    totalV(i) = sum(Bv(Bv==pinIDs(i)));
end

[totalV,isort] = sort(totalV,'descend');
pinIDs=pinIDs(isort);

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
    % next 2 lines are indeed MUCH faster than ind2sub
    pinLocs2D(:,2) = floor((pinLocs1D-1)/sizeB(1))+1;
    pinLocs2D(:,1) = pinLocs1D -  (pinLocs2D(:,2)-1)*sizeB(1); 

    % Get the net started
    % Find the pin nearest the centroid, and find something to connect it to

    % find centroid of the prospective net:
    ic=sum(pinLocs2D(:,1))/nPins; 
    jc=sum(pinLocs2D(:,2))/nPins; 

    % distance from each pin to centroid:
    cdist = abs(ic-pinLocs2D(:,1)) + abs(jc-pinLocs2D(:,2));
    
    for k=1:3
        % These 3 attempts to start a net are costly - 50% time increase
        % for a 3% score descrease wrt to a single shot.
        if k==1 % first attempt: pick the pin nearest the centroid of the net
            [cdistMin,iPin] = min(cdist);
        elseif k==2  % 2nd attempt: mid-range
            [cdistMin,iPin] = min(cdist-mean(cdist));
        elseif k==3   % 3rd attempt: outlier
            [cdistMin,iPin] = max(cdist);
        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;
            break
        end
    end
    
    % now loop over all pins, and for ones that aren't live, try to connect them. 
    
    % compute distance matrix
%     D = abs (repmat(pinLocs2D(:,1),[1 nPins]) - repmat(pinLocs2D(:,1)',[nPins 1])) + ...
%         abs (repmat(pinLocs2D(:,2),[1 nPins]) - repmat(pinLocs2D(:,2)',[nPins 1])) ; 
%     D = abs ( pinLocs2D(:,ones(1,nPins)) - pinLocs2D(:,ones(1,nPins))' ) + ...
%         abs ( pinLocs2D(:,2*ones(1,nPins)) - pinLocs2D(:,2*ones(1,nPins))' ) ; 
    
%     D(~livePins,:) = Inf;
%     D(:,~livePins) = Inf;
    D(logical(eye(nPins)))=Inf;
    
    % THIS IS SLOW
    if any(livePins)    % For now, only do this if we've already succeeded on the first connection (but that's STUPID).
        for k=1:4  % multiple passes may help
            for iPin=1:nPins
                if livePins(iPin)
                    continue
                end
                % staircase distance to all other pins
                dist = sum(abs(pinLocs2D(iPin*ones(nPins,1),:) - pinLocs2D),2);
                dist(iPin) = Inf;
                dist(~livePins)=Inf;
                [distMin,iTarget] = min(dist);
%                 [wLink,V] = pathfinder1(pinLocs2D(iPin,:), pinLocs2D(iTarget,:), V);
        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;  % this shouldn't be necessary
                end
            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
        t=j1; j1=j2; j2=t;          t=i1; i1=i2; i2=t;  
        %[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
        t=j1; j1=j2; j2=t;          t=i1; i1=i2; i2=t;  
        %         [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,V1] = pathfinder1([i1 j1],[i1 j2],V);
    if any(W1)
        [W2,V2] = pathfinder1([i1 j2],[i2 j2],V1);
        if any(W2)
            W=[W1; W2];
            V = V2;
            return
        end
    end
elseif ~V0(i2,j1)
    [W1,V1] = pathfinder1([i1 j1],[i2 j1],V);
    if any(W1)
        [W2,V2] = pathfinder1([i2 j1],[i2 j2],V1);
        if any(W2)
            W=[W1; W2];
            V =V2; %= 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