//R o u t i n g A l g o r i t h m s
//Part 1 - Combinatorics and auxiliary functions
//E. McCreight
//last edited November 16, 1978 10:40 PM by emm
external
[
MoveBlock// Defined by OS
Zero
CallSwat
DefaultArgs
HeuristicNet// Defined by other modules
bestTotalNetLength
Route// Locally defined
InitRandom
Random
GetOrderedRandomSet
ArcLength
ManhattanDistFn
EuclideanDistFn
n
exhaustThresh
Perm
forceFirstNodeToEnd
]
manifest
[
memoTableEntries = 229// prime
empty = 0
infinity = #77777
]
static
[ n
Perm
X
Y
clusterBaseVec
forceFirstNodeToEnd
randomTable
randomIndex
randomTrailer
exhaustThresh = 7
TrialPerm
bestTotalNetLength
randomInitialized = false
DistFn
memoTable
]
structure MEMO:
[ key word
value word
]
let Route(nNodes, localX, localY, ResultPerm, fFNTE, distanceMetricFn, cbv;
numargs na) be
[ DefaultArgs(lv na, -4, false, ManhattanDistFn, empty)
unless randomInitialized do InitRandom()
n = nNodes
X = localX
Y = localY
clusterBaseVec = cbv
DistFn = distanceMetricFn
Perm = ResultPerm
forceFirstNodeToEnd = fFNTE
let mt = vec memoTableEntries*(size MEMO/16)
memoTable = mt
Zero(memoTable, memoTableEntries*(size MEMO/16))
test nNodes le exhaustThresh % clusterBaseVec ne empty
ifso
[
bestTotalNetLength = infinity
let tP = vec 200
TrialPerm = tP
for i=1 to nNodes do TrialPerm!i = i
let clusterBase, clusterTop, clusterNumber = 1,nNodes,1
if clusterBaseVec ne empty then
[
clusterNumber = clusterBaseVec!0
clusterBase = clusterBaseVec!clusterNumber
]
for i=clusterBase to clusterTop do
[
TrialPerm!i = clusterTop
TrialPerm!clusterTop = i
TryAllPermsRecursively(0, clusterNumber, clusterBase, clusterTop-1)
if fFNTE & (clusterBaseVec eq empty) then break // first node in last place
TrialPerm!i = i
]
]
ifnot HeuristicNet()
if fFNTE & cbv eq empty & ResultPerm!nNodes ne 1 do
CallSwat("Wrong node at end")
]
//Inter-node distance calculating functions.
and ArcLength(i, j) = valof
[ if i eq j then resultis 0
if i gr j then
[ let t = i; i = j; j = t ]// exchange i and j
let memoKey = (i lshift 8)+j
let memo = memoTable+
((memoKey rem memoTableEntries) lshift 1)
if memo>>MEMO.key eq memoKey then
resultis memo>>MEMO.value
memo>>MEMO.key = memoKey
let value = DistFn(X!i, Y!i, X!j, Y!j)
memo>>MEMO.value = value
resultis value
]
//1. The 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.
//The outer program sets bestTotalNetLength to infinity
//and then calls TryAllPerms(0, ...) with each node in the final
//cluster in last place in TrialPerm.
and TryAllPermsRecursively(netLengthSoFar, clusterNumber,
clusterBase, clusterTop) be
[ if netLengthSoFar ge bestTotalNetLength then return
while clusterTop ls clusterBase do
[
clusterNumber = clusterNumber-1
if clusterNumber eq 0 then [ RecordBetterNet(netLengthSoFar); return ]
clusterTop = clusterBase-1
clusterBase = clusterBaseVec!clusterNumber
]
TryAllPermsRecursively(netLengthSoFar+
ArcLength(TrialPerm!(clusterTop+1), TrialPerm!clusterTop),
clusterNumber, clusterBase, clusterTop-1)
let ct = TrialPerm!clusterTop
for i=clusterTop-1 to clusterBase by -1 do
[
TrialPerm!clusterTop = TrialPerm!i
TrialPerm!i = ct
TryAllPermsRecursively(netLengthSoFar+
ArcLength(TrialPerm!(clusterTop+1), TrialPerm!clusterTop),
clusterNumber, clusterBase, clusterTop-1)
TrialPerm!i = TrialPerm!clusterTop
]
TrialPerm!clusterTop = ct
]
and RecordBetterNet(length) be
[ bestTotalNetLength = length
MoveBlock(lv (Perm!1), lv (TrialPerm!1), n)
]
//This random number generator derives from the answer to
//exercise 3.2.2-11 in the first edition of the second volume
//of Knuth’s "Art of Computer Programming." From Appendix C
//in Peterson & Weldon’s "Error-Correcting Codes" we learn
//that x↑33+x↑13+1 is a primitive polynomial over GF(2). Thus
//the sequence X(n) = (X(n-33)+X(n-13)) mod 2↑16 has a period
//length greater than 2↑33 if the first 33 elements are not all
//even.
and InitRandom() be
[ manifest
[ degree = 33
midPower = 13
]
let foo = table [ 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; ]
randomTable = foo
randomTable!0 = #101011
randomIndex = 0
randomTrailer = degree-midPower
for i=1 to 2000 do Random(1)
randomInitialized = true
]
and Random(max) = valof
[ manifest
[ degree = 33
midPower = 13
]
let result = randomTable!randomIndex+
randomTable!randomTrailer
randomTable!randomIndex = result
test randomIndex eq degree-1
ifso[ randomIndex = 0
randomTrailer = degree-midPower
]
ifnot[ randomIndex = randomIndex+1
test randomTrailer eq degree-1
ifsorandomTrailer = 0
ifnotrandomTrailer = randomTrailer+1
]
resultis (result & #77777) rem (max+1)
// This "rem" introduces a slight non-
//randomness.
]
and GetOrderedRandomSet(n, vector, lowerLimit, upperLimit) be
[ for i=1 to n do
[ let newValue = Random(upperLimit+1-
lowerLimit-i)+lowerLimit
for j=1 to i-1 do
test vector!j le newValue
ifso newValue = newValue+1
ifnot[ let t = newValue
newValue = vector!j
vector!j = t
]
vector!i = newValue
]
]