// 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 editedJune 15, 1977 12:14 PM by emm external [ MoveBlock // Defined by OS Zero CallSwat HeuristicNet // Defined by other modules bestTotalNetLength Route // Locally defined InitRandom Random GetOrderedRandomSet ArcLength ManhattanDistFn EuclideanDistFn n exhaustThresh Perm forceFirstNodeToEnd ] manifest [ memoTableEntries = 229 // prime ] static [ n Perm X Y 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; numargs na) be [ if na ls 5 then forceFirstNodeToEnd = false test (na ls 6) % (distanceMetricFn eq 0) ifso DistFn = ManhattanDistFn ifnot DistFn = distanceMetricFn unless randomInitialized do InitRandom() n = nNodes X = localX Y = localY Perm = ResultPerm forceFirstNodeToEnd = fFNTE let mt = vec memoTableEntries*(size MEMO/16) memoTable = mt Zero(memoTable, memoTableEntries*(size MEMO/16)) test nNodes le exhaustThresh ifso [ bestTotalNetLength = #77776 // infinity let tP = vec 200 TrialPerm = tP for i=1 to nNodes do TrialPerm!i = (i rem n)+1 TryAllPermsRecursively(nNodes-1, 0) unless forceFirstNodeToEnd do for i=1 to nNodes-1 do [ TrialPerm!i = 1 TrialPerm!nNodes = i+1 TryAllPermsRecursively(nNodes-1, 0) TrialPerm!i = i+1 ] ] ifnot HeuristicNet() if fFNTE then unless ResultPerm!nNodes eq 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 ] and ManhattanDistFn(X1, Y1, X2, Y2) = valof [ let deltaX = X1-X2 let deltaY = Y1-Y2 resultis ((deltaX ls 0)? -deltaX, deltaX)+ ((deltaY ls 0)? -deltaY, deltaY) ] and EuclideanDistFn(X1, Y1, X2, Y2) = valof [ let deltaX = X1-X2 let deltaY = Y1-Y2 deltaX = (deltaX ls 0)? -deltaX, deltaX deltaY = (deltaY ls 0)? -deltaY, deltaY let bigDelta = nil let smallDelta = nil test deltaX ge deltaY ifso [ bigDelta = deltaX smallDelta = deltaY ] ifnot [ bigDelta = deltaY smallDelta = deltaX ] let ftIndex = (smallDelta ge #3777)? smallDelta/(bigDelta rshift 4), (smallDelta lshift 4)/bigDelta let fractionTable = table [ // entryK = 32*(sec(atan(K/16))-1) 0; 0; 0; 1; 1; 1; 2; 3; 4; 5; 6; 7; 8; 9; 11; 12; 13 ] let fraction = fractionTable!ftIndex resultis bigDelta+(fraction*((bigDelta+16) rshift 4)) ] // 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. // The outer program sets bestTotalNetLength to infinity // and then calls TryAllPerms(n-1, 0) with each node in // last place in TrialPerm. and TryAllPermsRecursively(nNodesRemaining, netLengthSoFar) be [ if netLengthSoFar ge bestTotalNetLength then return if nNodesRemaining eq 0 then RecordBetterNet(netLengthSoFar) for i=nNodesRemaining to 1 by -1 do [ let t = TrialPerm!nNodesRemaining TrialPerm!nNodesRemaining = TrialPerm!i TrialPerm!i = t TryAllPermsRecursively(nNodesRemaining-1, netLengthSoFar+ ArcLength(TrialPerm!(nNodesRemaining+1), TrialPerm!nNodesRemaining)) t = TrialPerm!nNodesRemaining TrialPerm!nNodesRemaining = TrialPerm!i TrialPerm!i = t ] ] 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 ifso randomTrailer = 0 ifnot randomTrailer = 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 ] ]