|
@@ -18,15 +18,24 @@ class Ant:
|
|
|
self.Configuration = configuration
|
|
|
self.RunwayManager = RunwayManager(self.Configuration)
|
|
|
self.InboundSelected = [ False ] * len(self.Configuration.Inbounds)
|
|
|
+ self.InboundScore = np.zeros([ len(self.Configuration.Inbounds), 1 ])
|
|
|
self.PheromoneMatrix = pheromoneTable
|
|
|
self.SequenceDelay = timedelta(seconds = 0)
|
|
|
self.Sequence = None
|
|
|
|
|
|
+ def qualifyDelay(delay, inbound, runway):
|
|
|
+ if 0.0 > delay.total_seconds():
|
|
|
+ delay = timedelta(seconds = 0)
|
|
|
+
|
|
|
+ # calculate the heuristic scaling to punish increased delays for single inbounds
|
|
|
+ scaledDelay = delay.total_seconds() / inbound.ArrivalCandidates[runway.Name].MaximumTimeToLose.total_seconds()
|
|
|
+ return max(1.0 / (99.0 * (scaledDelay ** 2) + 1), 0.01)
|
|
|
+
|
|
|
# Implements function (5), but adapted to the following logic:
|
|
|
# An adaption of the heuristic function is used:
|
|
|
# - Calculates the unused runway time (time between two consecutive landings)
|
|
|
# - Calculates a ratio between the inbound delay and the unused runway time
|
|
|
- # - Adds the current overal sequence delay to the heuristic function
|
|
|
+ # - Weight the overall ratio based on maximum time to lose to punish high time to lose rates while other flights are gaining time
|
|
|
def heuristicInformation(self, preceeding : int, current : int):
|
|
|
rwy, eta, unusedRunwayTime = self.RunwayManager.selectArrivalRunway(self.Configuration.Inbounds[current], True, self.Configuration.EarliestArrivalTime)
|
|
|
inboundDelay = eta - self.Configuration.Inbounds[current].ArrivalCandidates[rwy.Name].InitialArrivalTime
|
|
@@ -39,7 +48,10 @@ class Ant:
|
|
|
fraction += self.SequenceDelay.total_seconds()
|
|
|
fraction /= 60.0
|
|
|
|
|
|
- return self.PheromoneMatrix[preceeding, current] * ((1.0 / (fraction or 1)) ** self.Configuration.Beta)
|
|
|
+ # calculate the heuristic scaling to punish increased delays for single inbounds
|
|
|
+ weight = Ant.qualifyDelay(inboundDelay, self.Configuration.Inbounds[current], rwy)
|
|
|
+
|
|
|
+ return weight * self.PheromoneMatrix[preceeding, current] * ((1.0 / (fraction or 1)) ** self.Configuration.Beta)
|
|
|
|
|
|
# Implements functions (3), (6)
|
|
|
def selectNextLandingIndex(self, preceedingIndex : int):
|
|
@@ -57,13 +69,9 @@ class Ant:
|
|
|
if False == self.InboundSelected[i]:
|
|
|
pheromoneScale += self.heuristicInformation(preceedingIndex, i)
|
|
|
|
|
|
- # fallback
|
|
|
- if 0.0 >= pheromoneScale:
|
|
|
- pheromoneScale = 1.0
|
|
|
-
|
|
|
for i in range(0, len(self.InboundSelected)):
|
|
|
if False == self.InboundSelected[i]:
|
|
|
- weights.append(self.heuristicInformation(preceedingIndex, i) / pheromoneScale)
|
|
|
+ weights.append(self.heuristicInformation(preceedingIndex, i) / (pheromoneScale or 1))
|
|
|
|
|
|
total = sum(weights)
|
|
|
cumdist = list(itertools.accumulate(weights)) + [total]
|
|
@@ -91,17 +99,19 @@ class Ant:
|
|
|
|
|
|
delay = inbound.PlannedArrivalTime - inbound.InitialArrivalTime
|
|
|
if 0.0 < delay.total_seconds():
|
|
|
- return delay
|
|
|
+ return delay, rwy
|
|
|
else:
|
|
|
- return timedelta(seconds = 0)
|
|
|
+ return timedelta(seconds = 0), rwy
|
|
|
|
|
|
def findSolution(self, first : int):
|
|
|
self.Sequence = []
|
|
|
|
|
|
# select the first inbound
|
|
|
self.InboundSelected[first] = True
|
|
|
+ delay, rwy = self.associateInbound(self.Configuration.Inbounds[first], self.Configuration.EarliestArrivalTime)
|
|
|
+ self.InboundScore[0] = Ant.qualifyDelay(delay, self.Configuration.Inbounds[first], rwy)
|
|
|
self.Sequence.append(first)
|
|
|
- self.SequenceDelay += self.associateInbound(self.Configuration.Inbounds[first], self.Configuration.EarliestArrivalTime)
|
|
|
+ self.SequenceDelay += delay
|
|
|
|
|
|
while 1:
|
|
|
index = self.selectNextLandingIndex(self.Sequence[-1])
|
|
@@ -109,7 +119,9 @@ class Ant:
|
|
|
break
|
|
|
|
|
|
self.InboundSelected[index] = True
|
|
|
- self.SequenceDelay += self.associateInbound(self.Configuration.Inbounds[index], self.Configuration.EarliestArrivalTime)
|
|
|
+ delay, rwy = self.associateInbound(self.Configuration.Inbounds[index], self.Configuration.EarliestArrivalTime)
|
|
|
+ self.SequenceDelay += delay
|
|
|
+ self.InboundScore[len(self.Sequence)] = Ant.qualifyDelay(delay, self.Configuration.Inbounds[index], rwy)
|
|
|
self.Sequence.append(index)
|
|
|
|
|
|
# update the local pheromone
|
|
@@ -120,4 +132,7 @@ class Ant:
|
|
|
# validate that nothing went wrong
|
|
|
if len(self.Sequence) != len(self.Configuration.Inbounds):
|
|
|
self.SequenceDelay = None
|
|
|
+ self.SequenceScore = None
|
|
|
self.Sequence = None
|
|
|
+ else:
|
|
|
+ self.SequenceScore = np.median(self.InboundScore)
|