//R o u t i n g A l g o r i t h m s

//
Part 2 - Heuristics

//
E. McCreight
//
last edited April 25, 1978 9:24 PM by emm

external
[
MoveBlock
Zero
CallSwat
bestTotalNetLength
heuristicWork

GetOrderedRandomSet
ArcLength

forceFirstNodeToEnd
n
Perm

HeuristicNet

Allocate
Free
SilZone
]


static
[
arcLens
totalCircuitLength
longestArcLen
longestArc
heuristicImprovements
improvementBreak = -1
heuristicWork = 20
]


//
2. A heuristic algorithm which does not guarantee an
//
optimum but is much more economical than the
//
combinatorial one for large nets.

let HeuristicNet() be

[ GenerateGoodPerm()
HeuristicImprove()
]


and GenerateGoodPerm() be

[ let BUSpanDest = Allocate(SilZone, n+2)
MakeMinSpanTree(BUSpanDest)

let Root = ReRoot(BUSpanDest)

let TDSpanSons = Allocate(SilZone, n+2)
let TDSpanBros = Allocate(SilZone, n+2)

ReRepresent(BUSpanDest, TDSpanSons, TDSpanBros)

Free(SilZone, BUSpanDest)

TreeWalk(Root, TDSpanSons, TDSpanBros, Perm)

Free(SilZone, TDSpanSons)
Free(SilZone, TDSpanBros)

CycleToRemoveLongest(Perm)
]


and MakeMinSpanTree(BUSpanDest) be

[ let InCluster = Allocate(SilZone, n+2)
let NearestEltInCluster = Allocate(SilZone, n+2)
let DistToCluster = Allocate(SilZone, n+2)

let NearestOutsideElt = 0
let ShortestDistToCluster = nil

for i=1 to n do
[ InCluster!i = (i eq 1)
if InCluster!i then
[ BUSpanDest!i = 0
loop
]

NearestEltInCluster!i = 1
DistToCluster!i = ArcLength(1, i)
if (NearestOutsideElt eq 0) %
(DistToCluster!i ls ShortestDistToCluster)
then
[ NearestOutsideElt = i
ShortestDistToCluster = DistToCluster!i
]
]


while NearestOutsideElt ne 0 do

[ BUSpanDest!NearestOutsideElt = NearestEltInCluster!NearestOutsideElt
InCluster!NearestOutsideElt = true

let NewClusterElt = NearestOutsideElt
NearestOutsideElt = 0

for i=1 to n do
[ if InCluster!i then loop
let DistToNewClusterElt = ArcLength(i, NewClusterElt)
if DistToNewClusterElt ls DistToCluster!i then
[ DistToCluster!i = DistToNewClusterElt
NearestEltInCluster!i = NewClusterElt
]

if (NearestOutsideElt eq 0) %
(DistToCluster!i ls ShortestDistToCluster)
then
[ NearestOutsideElt = i
ShortestDistToCluster = DistToCluster!i
]
]
]
Free(SilZone, InCluster)
Free(SilZone, NearestEltInCluster)
Free(SilZone, DistToCluster)
]



and ReRoot(BUDest) = valof

[ let Root = 1// re-root the spanning tree at a unary node
let Into = Allocate(SilZone, n+2)
unless forceFirstNodeToEnd do
[ Zero(Into+1, n)
for i=1 to n do
Into!(BUDest!i)=Into!(BUDest!i)+1
for i=1 to n do
if Into!i eq 0 then
[ Root = i
break
]
]

let Father = Into
let CurNode = Root
let CurAlt = 0
while BUDest!CurNode ne 0 do
[ Father!CurAlt = CurNode
CurAlt = CurAlt+1
CurNode = BUDest!CurNode
]

while CurAlt gr 0 do
[ CurAlt = CurAlt-1
BUDest!CurNode = Father!CurAlt
CurNode = Father!CurAlt
]

Free(SilZone, Father)

BUDest!Root = 0
resultis Root
]


and ReRepresent(BUDest, TDSons, TDBros) be

[ Zero(TDSons+1, n)
Zero(TDBros+1, n)

for i=1 to n do
[ let Father = BUDest!i
if Father eq 0 then loop// this is the root

TDBros!i = TDSons!Father
TDSons!Father = i
]
]


and TreeWalk(Root, TDSons, TDBros, Perm) be

[ let BroStack = Allocate(SilZone, n+2)
let Depth = 0
let NodesInPerm = 0

while Depth ge 0 do
[ NodesInPerm = NodesInPerm+1
Perm!NodesInPerm = Root

let Son = TDSons!Root
if Son ne 0 then
[ BroStack!Depth = TDBros!Root
if BroStack!Depth ne 0 then Depth = Depth+1
Root = Son
loop
]

Root = TDBros!Root
if Root ne 0 then loop

Depth = Depth-1
Root = BroStack!Depth
]

Free(SilZone, BroStack)
]


and CycleToRemoveLongest(Perm) be

[ let NewPerm = Allocate(SilZone, n+2)
let LongestArcPos = nil
let LongestArcLen = -1

test forceFirstNodeToEnd

ifnot[ for i=1 to n do
[ let ThisArcLen = ArcLength(Perm!i,
Perm!((i rem n)+1))
if ThisArcLen gr LongestArcLen then
[ LongestArcLen = ThisArcLen
LongestArcPos = i
]
]

MoveBlock(lv (NewPerm!1), lv (Perm!(LongestArcPos+1)),
n-LongestArcPos)
MoveBlock(lv (NewPerm!((n-LongestArcPos)+1)), lv (Perm!1),
LongestArcPos)
MoveBlock(lv (Perm!1), lv (NewPerm!1), n)
]

ifso if ArcLength(Perm!1, Perm!2) gr
ArcLength(Perm!n, Perm!1) then // reverse Perm!2..Perm!n
for i=1 to (n-1)/2 do
[ let T = Perm!(i+1)
Perm!(i+1) = Perm!(n+1-i)
Perm!(n+1-i) = T
]
Free(SilZone, NewPerm)
]


and HeuristicImprove() be

[ let OrigFirstNode = Perm!1

let aL = Allocate(SilZone, n+2)
arcLens = aL

let tempArcLen = nil
totalCircuitLength = 0

let triesSinceImprovement = 0
let criterion = heuristicWork*n
longestArcLen = -1

for i=1 to n do
[ tempArcLen = ArcLength(Perm!i, Perm!((i rem n)+1))
totalCircuitLength = totalCircuitLength+tempArcLen
arcLens!i = tempArcLen
if tempArcLen gr longestArcLen then
[ longestArc = Perm!i
longestArcLen = tempArcLen
]
]

if forceFirstNodeToEnd then
test arcLens!n gr arcLens!1
ifso[ longestArc = Perm!n
longestArcLen = arcLens!n
]
ifnot[ longestArc = Perm!1
longestArcLen = arcLens!1
]

bestTotalNetLength = totalCircuitLength-longestArcLen
heuristicImprovements = 0

while triesSinceImprovement ls criterion do
[ triesSinceImprovement = triesSinceImprovement+1

if forceFirstNodeToEnd & (longestArc ne Perm!1) &
(longestArc ne Perm!n) then
[ CallSwat("Heuristic bug 1")
]

let segmentLasts = vec 4
GetOrderedRandomSet(3, segmentLasts, 1, n)

let segmentFirsts = vec 4
segmentFirsts!1 = (segmentLasts!3 ge n)? 1,
segmentLasts!3+1
for i=2 to 3 do
segmentFirsts!i = (segmentLasts!(i-1))+1

if ThisArrangementBetter(segmentFirsts, segmentLasts,
1, 3, 2) %
ThisArrangementBetter(segmentFirsts, segmentLasts,
1, -3, -2) %
ThisArrangementBetter(segmentFirsts, segmentLasts,
1, -3, 2) %
ThisArrangementBetter(segmentFirsts, segmentLasts,
1, 3, -2)
then
[ heuristicImprovements =
heuristicImprovements+1
if heuristicImprovements eq improvementBreak
then
CallSwat("Improvement break")

triesSinceImprovement = 0
]
]

MoveLongestArcToEnd:

CycleToRemoveLongest(Perm)

if forceFirstNodeToEnd then
for i=1 to n/2 do
[ let T = Perm!(n+1-i)// reverse it to get first
Perm!(n+1-i) = Perm!i// node at end
Perm!i = T
]

if forceFirstNodeToEnd & (Perm!n ne OrigFirstNode) then
CallSwat("Heuristic bug 2")

Free(SilZone, aL)
]



and ThisArrangementBetter(origF, origL, seg1, seg2, seg3) = valof

[ // This whole piece of code will fall apart on
// the floor unless seg1 eq 1. OK?

let seg = (lv seg1)-1
let f = vec 4
let l = vec 4
for i=1 to 3 do
[ f!i = (seg!i ls 0)? origL!(-(seg!i)), origF!(seg!i)
l!i = (seg!i ls 0)? origF!(-(seg!i)), origL!(seg!i)
]

let newArcLens = vec 4

for i=1 to 2 do
newArcLens!i = ArcLength(Perm!(l!i), Perm!(f!(i+1)))
newArcLens!3 = ArcLength(Perm!(l!3), Perm!(f!1))

let tempLongestArc = longestArc
let tempLongestArcLen = longestArcLen

if valof
[ for j=1 to 3 do
if Perm!(origL!j) eq longestArc then
resultis true
resultis false
]
then

[ tempLongestArcLen = 0
for i=1 to n do
if (arcLens!i gr tempLongestArcLen) &
valof
[ for j=1 to 3 do
if origL!j eq i then
resultis false
resultis true
]
then
[ tempLongestArc = Perm!i
tempLongestArcLen = arcLens!i
]
]

for j=1 to 3 do
if newArcLens!j gr tempLongestArcLen then
[ tempLongestArc = -(Perm!(l!j))
tempLongestArcLen = newArcLens!j
]

if forceFirstNodeToEnd then
[ let firstArc = Perm!1
let firstArcLen = arcLens!1
if origL!1 eq 1 then
firstArcLen = newArcLens!1

let lastArc = Perm!n
let lastArcLen = arcLens!n

if origL!3 eq n
then[ lastArc = Perm!(l!3)
lastArcLen = newArcLens!3
]

test firstArcLen ge lastArcLen

ifso[ tempLongestArc = -firstArc
tempLongestArcLen = firstArcLen
]

ifnot[ tempLongestArc = -lastArc
tempLongestArcLen = lastArcLen
]
]

let newNetLen = totalCircuitLength+valof
[ let sum=0
for j=1 to 3 do
sum = sum+newArcLens!j-
arcLens!(origL!j)
resultis sum
]-
tempLongestArcLen

unless newNetLen ls bestTotalNetLength do resultis false

HBetterNet:
bestTotalNetLength = newNetLen

totalCircuitLength = newNetLen+tempLongestArcLen

let tempVec = Allocate(SilZone, n+2)
let tempLens = Allocate(SilZone, n+2)

let nextWord = 1
for j=2 to 3 do
[ test seg!j ge 0
ifso[ MoveBlock(tempVec+nextWord,
lv (Perm!(f!j)),
(l!j-f!j+1))
MoveBlock(tempLens+nextWord,
lv (arcLens!(f!j)),
(l!j-f!j+1))
nextWord = nextWord+(l!j-f!j+1)
]

ifnot[ let cur = f!j
while cur ge l!j do
[ tempVec!nextWord = Perm!cur
tempLens!nextWord = arcLens!(cur-1)
if cur gr l!j &
tempLongestArc eq
Perm!(cur-1)
then
tempLongestArc = Perm!cur
cur = cur-1
nextWord = nextWord+1
]
]
tempLens!(nextWord-1) = newArcLens!j
]

arcLens!(origL!1) = newArcLens!1

longestArc = (tempLongestArc ge 0)? tempLongestArc,
-tempLongestArc
longestArcLen = tempLongestArcLen

MoveBlock(lv (Perm!(origF!2)), lv (tempVec!1), nextWord-1)
MoveBlock(lv (arcLens!(origF!2)), lv (tempLens!1),
nextWord-1)
Free(SilZone, tempVec)
Free(SilZone, tempLens)
resultis true
]