ID:46219
Title:A10.8
Author:Andreas
Date:2008-05-02 11:51:44
Score:18424.1819
Result:183328.00 (cyc: 25, node: 3046)
CPU Time:54.0285
Status:Passed
Comments:
Based on:none
Code:
function retwires = solver1(pB)

    global settingsBestngroups;

    global B;
    global Bsize;
    global Borigin1;
    global Borigin2;

    global nPins;

    global wires;
    global nwires;

    global pValues;
    global pCounts;
    global pDistances;
    global pTriDistances;
    global pDistancesX;
    global pDistancesY;
    global pConnected;
    global pXvs;
    global pYvs;

    global pGroups;
    global pLargestgroupsizes;

    settingsBestngroups = 8; % 2,3,...

 
    Borigin1 = [];
    Borigin2 = [];
 
    pGroups = [];
    pLargestgroupsizes = [];


    B = pB;

    Bsize = size(B);
    wires = zeros( ((Bsize(1)-1) * Bsize(2)) + (Bsize(1) * (Bsize(2)-1)), 4);
    nwires = 0;

    pValues = unique(B(B>0))';
    nPins = size(pValues, 2);
    pCounts = zeros(size(pValues));

    for j = 1:nPins
        pCounts(j) = nnz(B == pValues(j));
    end

    % skip single pins
    skip = pCounts == 1;
    if any(skip)
        nPins = nPins - sum(skip);
        pValues = pValues(~skip);
        pCounts = pCounts(~skip);
    end


    pDistances    = cell(1, nPins);
    pTriDistances = pDistances;
    pDistancesX   = pDistances;
    pDistancesY   = pDistances;
    pConnected    = pDistances;
    pXvs          = pDistances;
    pYvs          = pDistances;
    
    WiresL1andInit();

    WiresL2();

    LinkIslands();

    retwires = wires(1:nwires, :);
end


%% WiresL1andInit

function WiresL1andInit()
    global pXvs;
    global pYvs;
    global pConnected;
    global pDistancesX;
    global pDistancesY;
    global pDistances;
    global pTriDistances;
    global nPins;
    global pValues;
    global B;
    global Borigin1;
    global Borigin2;
    global pCounts;
    global wires;
    global nwires;

    for pix = 1:nPins
        [pXvs{pix} pYvs{pix}] = find(B == pValues(pix));

        for j = 1:length(pXvs{pix})
            Borigin1(pXvs{pix}(j), pYvs{pix}(j)) = pXvs{pix}(j);
            Borigin2(pXvs{pix}(j), pYvs{pix}(j)) = pYvs{pix}(j);
        end

        pConnected{pix}    = ~~eye(pCounts(pix));
        pDistancesX{pix}   = bsxfun(@(x1, x2) abs(x1-x2), pXvs{pix}, pXvs{pix}');
        pDistancesY{pix}   = bsxfun(@(y1, y2) abs(y1-y2), pYvs{pix}, pYvs{pix}');
        pDistances{pix}    = pDistancesX{pix} + pDistancesY{pix};
        pTriDistances{pix} = triu(pDistances{pix});

        % add wires for adjacent pins immediately
        adjacent = pTriDistances{pix} == 1;
        if any(any(adjacent))
            [aix1 aix2] = find(adjacent);
            nadjacent = length(aix1);
            for j = 1:nadjacent
                pConnected{pix}(aix1(j), aix2(j)) = true;
                pConnected{pix}(aix2(j), aix1(j)) = true;
            end
            [wires nwires] = addwires(wires, nwires, [pXvs{pix}(aix1) pYvs{pix}(aix1) pXvs{pix}(aix2) pYvs{pix}(aix2)]);
        end
    end
end


%% WiresL2

function WiresL2()
    global pTriDistances;
    global pDistancesX;
    global pYvs;
    global pXvs;
    global pConnected;
    global pValues;
    global nPins;
    global B;
    global Borigin1;
    global Borigin2;
    global wires;
    global nwires;

    [sv svix] = sort(pValues, 'descend');

    for cix = 1:nPins
        pix = svix(cix);

        d2b = pTriDistances{pix} == 2;

        if any(any(d2b))
            d2bstraight = d2b & pDistancesX{pix} ~= 1;
            d2bcorner   = d2b & ~d2bstraight;

            if any(any(d2bstraight))
                [ix1 ix2] = find(d2bstraight);
                pins = [pXvs{pix}(ix1) pYvs{pix}(ix1) pXvs{pix}(ix2) pYvs{pix}(ix2)];
                midpoints     = (pins(:, [1, 2]) + pins(:, [3, 4])) / 2;
                midpointsfree = PointsFree(B, midpoints);
                if any(midpointsfree)
                    pins      = pins(midpointsfree, :);
                    midpoints = midpoints(midpointsfree, :);
                    ix1 = ix1(midpointsfree);
                    ix2 = ix2(midpointsfree);
                    for j = 1:size(midpoints, 1)
                        %check if connected
                        if ~pConnected{pix}(ix1(j), ix2(j))
                            %if not connected, connect

                            [wires nwires] = addwires(wires, nwires, [ ...
                                pins(j, [1, 2]) midpoints(j, :); ...
                                pins(j, [3, 4]) midpoints(j, :)]);

                            B(midpoints(j, 1), midpoints(j, 2)) = -pValues(pix);
                            Borigin1(midpoints(j, 1), midpoints(j, 2)) = pins(j, 1);
                            Borigin2(midpoints(j, 1), midpoints(j, 2)) = pins(j, 2);

                            pConnected{pix}(ix1(j), ix2(j)) = true;
                            pConnected{pix}(ix2(j), ix1(j)) = true;
                            pConnected{pix} = ConvexConnections(pConnected{pix});
                        end


                    end
                    for j = 1:size(midpoints, 1)

                    end
                end
            end

            if any(any(d2bcorner))
                [ix1 ix2] = find(d2bcorner);
                pins = [pXvs{pix}(ix1) pYvs{pix}(ix1) pXvs{pix}(ix2) pYvs{pix}(ix2)];
                n = size(ix1, 1);
                midpoints = [pins(:, 1) pins(:, 4); pins(:, 3) pins(:, 2)];
                midpointsfree = PointsFree(B, midpoints);
                for j = 1:n
                    if ~pConnected{pix}(ix1(j), ix2(j))
                        pick = false;
                        if midpointsfree(j)
                            freemidpoint = midpoints(j, :);
                            pick = true;
                        elseif midpointsfree(j+n)
                            freemidpoint = midpoints(j+n, :);
                            pick = true;
                        end
                        if pick
                            [wires nwires] = addwires(wires, nwires, [ ...
                                pins(j, [1, 2]) freemidpoint; ...
                                pins(j, [3, 4]) freemidpoint]);
                            B(freemidpoint(1), freemidpoint(2)) = pValues(pix) * -1;
                            Borigin1(freemidpoint(1), freemidpoint(2)) = pins(j, 1);
                            Borigin2(freemidpoint(1), freemidpoint(2)) = pins(j, 2);
                            pConnected{pix}(ix1(j), ix2(j)) = true;
                            pConnected{pix}(ix2(j), ix1(j)) = true;
                            pConnected{pix} = ConvexConnections(pConnected{pix});
                        end
                    end
                end
            end
        end % if any(any(d2b))
    end % for cix = 1:nPins
end


%% LinkIslands

function LinkIslands()
    global pLargestgroupsizes;
    global pValues;
 
    lastpin = 0;
    foundlink = true;

    while foundlink
        %showme
                
        GenerateGroups(lastpin);
        profits = bsxfun(@times, pLargestgroupsizes, pValues);

        foundlink = false;
        while ~foundlink

            [profit pin] = max(max(profits(2:end, :)));

            if isnan(profit)
                break;
            end

            if isnan(profits(2, pin)) group = 2 + find(profits(3:end, pin)>0, 1, 'first');
            else                      group = 2;
            end

            foundlink = LinkGroups(pin, 1, group, profit);

            if foundlink
                lastpin = pin;
            else
                pLargestgroupsizes(group, pin) = NaN;
                profits(group, pin) = NaN;
            end
        end
    end
end


%% GenerateGroups

function GenerateGroups(pins)
    global pConnected;
    global pGroups;
    global pLargestgroupsizes;
    global nPins;
    global pCounts;
    global settingsBestngroups;

    if ~exist('pins', 'var') || isempty(pins) || (numel(pins) == 1 && pins < 1);
        pins = 1:nPins;
    end

    memogroupsizes = settingsBestngroups;
    if isempty(pGroups)
        pGroups = cell(1, nPins);
        pLargestgroupsizes = nan(memogroupsizes, nPins);
    else
        pGroups(pins) = cell(1);
        pLargestgroupsizes(:, pins) = nan(memogroupsizes, size(pins, 2));
    end

    for pix = pins
        % Make Convex Connections-Matrix
        pConnected{pix} = ConvexConnections(pConnected{pix});
        pGroups{pix} = zeros(1, pCounts(pix));

        c = pConnected{pix};
        sc = sum(c);
        items = 1:pCounts(pix);

        curgroup = 0;

        while ~isempty(c) %any(any(~c))
            if all(sc==1)
                pGroups{pix}(items) = curgroup + (1:length(sc));
                pLargestgroupsizes( curgroup+1 : min(curgroup+length(sc), memogroupsizes), pix) = 1;
                break;
            end
            curgroup = curgroup + 1;

            [gsize, gitem] = max(sc);
            gitems = c(gitem, :);
            remains = ~gitems;

            pGroups{pix}(items(gitems)) = curgroup;
            if curgroup <= memogroupsizes
                pLargestgroupsizes(curgroup, pix) = sum(gitems);
            end

            items = items(remains);
            sc = sc(remains);
            c = c(remains, remains);
        end
    end % for pix = 1:nPins
end


%% LinkGroups

function ret = LinkGroups(pin, group1, group2, budget)
    global pGroups;
    %     global pLargestgroupsizes;
    %     global nPins;
    %     global pCounts;
    global B;
    global Bsize;
    global pValues;
    global wires;
    global nwires;
    global pYvs;
    global pXvs;
    global Borigin1;
    global Borigin2;
    global pConnected;

    % we are sniffing from g2's items towards the center of g1 (g1 is the
    % larger group)

    ixitems1 = pGroups{pin} == group1;
    ixitems2 = pGroups{pin} == group2;

    g1 = [pXvs{pin}(ixitems1) pYvs{pin}(ixitems1)];
    g2 = [pXvs{pin}(ixitems2) pYvs{pin}(ixitems2)];

    g1center = mean(g1, 1);

    bestcost = inf;
    % bestcost = budget;
    bestwires = zeros(0, 4);

    for g2ix = 1:size(g2, 1)
        origin = g2(g2ix, :);
        % 8 17
        %[newcost newwires newconnecteditem] = Sniff(origin, pin, g1center, min(bestcost, budget), g2, false(Bsize), []);
        [newcost newwires newconnecteditem] = Sniff(origin, pin, g1center, budget, g2, false(Bsize), []);
        if newcost < bestcost;
            bestcost = newcost; 
            bestwires = newwires;
            bestconnecteditem = newconnecteditem;
        end
    end 

    if ~isempty(bestwires) 
        bestwires = ShortcutWires(bestwires);
        wiredpoints = [bestwires(:, [1 2]); bestwires(end, [3 4])];
        [wires nwires] = addwires(wires, nwires, bestwires);

        for j = 1:size(wiredpoints, 1)
            if ~B(wiredpoints(j, 1), wiredpoints(j, 2))
                B(wiredpoints(j, 1), wiredpoints(j, 2)) = pValues(pin) * -1;
                Borigin1(wiredpoints(j, 1), wiredpoints(j, 2)) = g2(1,1);
                Borigin2(wiredpoints(j, 1), wiredpoints(j, 2)) = g2(1,2);
            end
        end

        % link groups in connections-matrix
        item2 = pGroups{pin} == group2;
        item1 = all(bsxfun(@eq, [pXvs{pin} pYvs{pin}], bestconnecteditem), 2);
        pConnected{pin}(item1, item2) = true;

        ret = true;
    else
        ret = false;
    end

end


%% Sniff

function [bestcost bestwires bestconnecteditem beenthere] = Sniff(position, pix, direction, budget, sourcegroup, beenthere, camefromdir)
    global Bsize;
    global B;
    global Borigin1;
    global Borigin2;
    global pValues;

    if budget <= 0;
        bestcost = inf;
        bestwires = zeros(0, 4);
        bestconnecteditem = [];
        return;
    end

    d     = direction - position;
    dabs  = abs(d);
    dsign = sign(d);
    dsign(~dsign) = 1;

    if dabs(1) > dabs(2)     compass = [dsign(1) 0; 0 dsign(2); 0 -dsign(2); -dsign(1) 0];  % force = [true true false false];
    elseif dabs(1) < dabs(2) compass = [0 dsign(2); dsign(1) 0; -dsign(1) 0; 0 -dsign(2)];  % force = [true true false false];
    else                     compass = [dsign(1) 0; 0 dsign(2); -dsign(1) 0; 0 -dsign(2)];  % force = [true true false false];
    end


    neighbors = position([1;1;1;1], :) + compass;
    picks = all(neighbors>0 & neighbors <= Bsize([1;1;1;1], :), 2);
    if ~isempty(camefromdir)
        picks = picks & any(compass ~= -camefromdir([1;1;1;1], :), 2);
    end

    if ~all(picks)
        compass = compass(picks, :);
        % force = force(picks);
        neighbors = neighbors(picks, :);
    end
    ndirections = size(neighbors, 1);

    isnewempty = true(ndirections, 1);
    
    for j = 1:ndirections
        isnewempty(j) = ~B(neighbors(j, 1), neighbors(j, 2));
        if ~isnewempty(j) && abs(B(neighbors(j, 1), neighbors(j, 2))) == pValues(pix) 
            newpin = neighbors(j, :);
            origin = [Borigin1(newpin(1), newpin(2)), Borigin2(newpin(1), newpin(2))];
            odiff = bsxfun(@eq, origin, sourcegroup);
            isnewvalid = ~any(all(odiff, 2));
            if isnewvalid
                bestcost = 1;
                bestwires = [position newpin];
                bestconnecteditem = [Borigin1(newpin(1), newpin(2)), Borigin2(newpin(1), newpin(2))];
                return;
            end
        end
    end

    bestcost = inf;
    bestwires = zeros(0, 4);
    bestconnecteditem = [];
    
    
    
    for dix = 1:ndirections
        % if bestcost < inf && ~force(dix) break; end
        if bestcost < inf; break; end
        dir = compass(dix, :);
        newpin = neighbors(dix, :);

        if beenthere(newpin(1), newpin(2)) continue; end

        if isnewempty(dix)
            B(newpin(1), newpin(2)) = -pValues(pix);
            Borigin1(newpin(1), newpin(2)) = Borigin1(position(1), position(2));
            Borigin2(newpin(1), newpin(2)) = Borigin2(position(1), position(2));

            % RECURSE
            [newcost newwires newconnecteditem beenthere] = Sniff(newpin, pix, direction, budget-1, sourcegroup, beenthere, dir);

            beenthere(newpin(1), newpin(2)) = true;
            B(newpin(1), newpin(2)) = 0;
            Borigin1(newpin(1), newpin(2)) = 0;
            Borigin1(newpin(1), newpin(2)) = 0;

            if newcost < bestcost
                bestcost = newcost + 1;
                bestwires = [[position newpin]; newwires];
                bestconnecteditem = newconnecteditem;
            end
        end
    end
    
    % check for bridges
    if budget > 27 && isinf(bestcost)
        for dix = 1:ndirections
            dir = compass(dix, :);
            newpin  = neighbors(dix, :);
            newpin2 = newpin   + dir;

            if ~isnewempty(dix) ...                          % jump reqd
                    && all([newpin2>0 newpin2 <= Bsize]) ... % inside board
                    && ~B(newpin2(1), newpin2(2)) ...
                    && B(newpin(1), newpin(2))<0 ...         % wire here
                    && ~beenthere(newpin2(1), newpin2(2)) ...   % not been there
                    && B(newpin(1), newpin(2)) ~= -pValues(pix) ...
                    

                B(newpin2(1), newpin2(2)) = -pValues(pix);
                Borigin1(newpin2(1), newpin2(2)) = Borigin1(position(1), position(2));
                Borigin2(newpin2(1), newpin2(2)) = Borigin2(position(1), position(2));

                % RECURSE
                [newcost newwires newconnecteditem beenthere] = Sniff(newpin2, pix, direction, budget-27, sourcegroup, beenthere, dir);

                beenthere(newpin2(1), newpin2(2)) = true;

                B(newpin2(1), newpin2(2)) = 0;
                Borigin1(newpin2(1), newpin2(2)) = 0;
                Borigin1(newpin2(1), newpin2(2)) = 0;

                if newcost < bestcost
                    bestcost = newcost + 27;
                    bestwires = [[position newpin]; [newpin newpin]; [newpin newpin2]; newwires];
                    bestconnecteditem = newconnecteditem;
                end
            end
        end
    end
end

% function [cost newwires] = LinkPins(pin1, pin2)
% end


%% Misc Funcs


function wires = ShortcutWires(wires)

    %anybridges?
    ixbridges = all(wires(:, [1 2]) == wires(:, [3 4]), 2);
    havebridges = any(ixbridges);
    if havebridges
        bridges = wires( ixbridges, :);
        wires   = wires(~ixbridges, :);
    end

    wiredpoints = [wires(:, [1 2]); wires(end, [3 4])];
    dx = abs(bsxfun(@minus, wiredpoints(:, 1), wiredpoints(:, 1)'));
    dy = abs(bsxfun(@minus, wiredpoints(:, 2), wiredpoints(:, 2)'));
    d = dx + dy;

    trid = triu(d, 2);
    if any(any(trid == 1))
        [xs ys] = find(trid == 1);
        [maxv, maxix] = max(ys-xs);

        x = xs(maxix);
        y = ys(maxix);

        wires = [ ...
            wires(1:x-1, :); ...
            [wires(x, 1:2) wires(y-1, 3:4)]; ...
            wires(y:end , :)];
        wires = ShortcutWires(wires);
    end

    if havebridges
        nbridges = sum(ixbridges);
        for j = 1:nbridges
            bridgepoint = bridges(j, [1 2]);
            insert = find(all(bsxfun(@eq, wires(:, [1 2]), bridgepoint), 2));
            if ~isempty(insert)
                wires = [ wires(1:insert-1, :); [bridgepoint bridgepoint]; wires(insert:end, :)];
            end
        end
    end

end


function ret = PointsFree(B, points)
    ret = false(size(points, 1), 1);
    for j = 1:size(points, 1);
        if ~B(points(j, 1), points(j, 2))
            ret(j) = true;
        end
    end
end


function [wires nwires] = addwires(wires, nwires, newwires)
    nnewwires = size(newwires, 1);
    wires(nwires+1:nwires+nnewwires, :) = newwires;
    nwires = nwires + nnewwires;
end


function connected = ConvexConnections(connected)
    if ~any(any(connected)) return; end
    nc = nnz(connected);
    connected = connected | connected';
    while true
        connected = connected | (connected ^ 2);
        newnc = nnz(connected);
        if nc ~= newnc nc = newnc;
        else           break;
        end
    end
end


function showme()
    global B;
    global wires;
    global nwires;

    visualize(max(B, 0), wires(1:nwires, :));
end