//routeCombin.bcpl

//
Combinatorial wire router

//
last edited by Dave Rumph, November 27, 1984 4:43 PM
//
fixed net length computation bug that resulted in lengths one segment too short
//
last edited by McCreight, July 27, 1981 4:59 PM

get "route.defs"

static
[ n
Perm
X
Y
clusterBaseVec
forceFirstNodeToEnd

exhaustThresh = 7

TrialPerm
bestTotalNetLength

randomInitialized = false
]


let CombinRoute() be

[
bestTotalNetLength = infinity
let tP = Allocate(swapZone, n+1)
TrialPerm = tP
let cbv = vec 3

cbv!0 = 1 // number of clusters
cbv!1 = 1 // base of first cluster

if clusterBaseVec ne empty then cbv = clusterBaseVec

let clusterNumber = cbv!0

for i=1 to n do TrialPerm!i = i

//
This combinatorial algorithm results in a true
//
optimum but is prohibitively expensive for large nets.
//
The idea is that there are two vectors X and Y holding the
//
X and Y co-ordinates of a set of nodes (1...n), and a vector
//
TrialPerm (1...n) containing a permutation of the integers 1...n.
//
These integers are arranged in "clusters", which intra-permute but
//
cannot inter-permute.

// Unfortunately, recursive calling to essentially unlimited depth
// can overflow our rather small stack, and it seems difficult
// to talk Bcpl into doing its stack in a free storage zone. Therefore we
// simulate the recursion with vectors. clusterTop contains the depth
// of the recursion, and the goal in the outer loop is to diminish jStk!clusterTop,
// which is the difference between clusterTop and the element to be exchanged with it
// in the trial permutation TrialPerm.

let netLengthSoFarStk = Allocate(swapZone, n+1)
let clusterNumberStk = Allocate(swapZone, n+1)
let jStk = Allocate(swapZone, n+1)
let netLengthSoFar = 0

jStk!n = (forceFirstNodeToEnd & (clusterBaseVec eq empty))? 0, // special case
n-cbv!clusterNumber // normal case

let ct,j = nil,nil

let clusterTop = n
while clusterTop le n do
[
if jStk!clusterTop ls 0 then
[ // this level finished. We must guarantee that TrialPerm!clusterTop..
// TrialPerm!1 have the values they had when clusterTop was last
// decremented to its present value.

ct = TrialPerm!clusterTop
for k=clusterTop to cbv!clusterNumber+1 by -1 do
TrialPerm!k = TrialPerm!(k-1)
TrialPerm!(cbv!clusterNumber) = ct

netLengthSoFar = netLengthSoFarStk!clusterTop
clusterNumber = clusterNumberStk!clusterTop
clusterTop = clusterTop+1
loop
]

// exchange a pair at this level

ct = TrialPerm!clusterTop
j = cbv!clusterNumber+jStk!clusterTop
TrialPerm!clusterTop = TrialPerm!j
TrialPerm!j = ct

jStk!clusterTop = jStk!clusterTop-1

let newNetLengthSoFar = (clusterTop ge n)? 0,
netLengthSoFar+
ArcLength(TrialPerm!clusterTop, TrialPerm!(clusterTop+1))

if newNetLengthSoFar ge bestTotalNetLength then loop

// finish this path or go deeper to next level

test clusterTop eq 2
ifso
[
let tnl = newNetLengthSoFar+ArcLength(TrialPerm!1,TrialPerm!2)
if tnl ls bestTotalNetLength then RecordBetterNet(tnl)
loop
]
ifnot
[
clusterTop = clusterTop-1
clusterNumberStk!clusterTop = clusterNumber
netLengthSoFarStk!clusterTop = netLengthSoFar

while clusterTop ls cbv!clusterNumber do clusterNumber = clusterNumber-1

jStk!clusterTop = clusterTop-cbv!clusterNumber
netLengthSoFar = newNetLengthSoFar
]
]

if forceFirstNodeToEnd & clusterBaseVec eq empty & Perm!n ne 1 do
CallSwat("Wrong node at end")

Free(swapZone, jStk)
Free(swapZone, netLengthSoFarStk)
Free(swapZone, clusterNumberStk)
Free(swapZone, tP)
]




and RecordBetterNet(length) be

[ bestTotalNetLength = length
MoveBlock(lv (Perm!1), lv (TrialPerm!1), n)
]



// Function to decide whether a net has any external connections

and HasExternalConnections(net) = valof
[
let pin = net>>net.pinList
while @pin ne mark do
[
let icinst,pinNo = nil,pin
FindIcinst(lv icinst, lv pinNo)
if Icclass(icinst)>>icclass.isConnector then resultis true
pin = @pin
]
resultis false
]