use the shortcut-path as the ITA for the optimization, but use the full path as the ITA itself

This commit is contained in:
Sven Czarnian
2021-12-16 10:22:43 +01:00
parent 6fd4f4da1b
commit cd5c21d099
5 changed files with 67 additions and 136 deletions

View File

@@ -24,55 +24,35 @@ class Ant:
self.SequenceDelay = timedelta(seconds = 0)
self.Sequence = None
def qualifyDelay(delay, node, 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() / node.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
# - 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.Nodes[current], True, self.Configuration.EarliestArrivalTime)
inboundDelay = eta - self.Nodes[current].ArrivalCandidates[rwy.Name].InitialArrivalTime
if 0.0 > inboundDelay.total_seconds():
inboundDelay = timedelta(seconds = 0)
# Implements function (5)
def heuristicInformation(self, current : int):
_, eta, _ = self.RunwayManager.selectArrivalRunway(self.Nodes[current], self.Configuration.EarliestArrivalTime)
inboundDelay = eta - self.Nodes[current].Inbound.InitialArrivalTime
# calculate the fraction with a mix of the unused runway time and the delay of single aircrafts
fraction = self.Configuration.RunwayOccupasionRatio * unusedRunwayTime.total_seconds()
fraction += (1.0 - self.Configuration.RunwayOccupasionRatio) * inboundDelay.total_seconds()
fraction += self.SequenceDelay.total_seconds()
fraction /= 60.0
# calculate the heuristic scaling to punish increased delays for single inbounds
weight = Ant.qualifyDelay(inboundDelay, self.Nodes[current], rwy)
return weight * self.PheromoneMatrix[preceeding, current] * ((1.0 / (fraction or 1)) ** self.Configuration.Beta)
heuristic = inboundDelay.total_seconds() / 60.0
heuristic = (1.0 / (heuristic or 1)) ** self.Configuration.Beta
return heuristic
# Implements functions (3), (6)
def selectNextLandingIndex(self, preceedingIndex : int):
def selectNextLandingIndex(self):
q = float(random.randint(0, 100)) / 100
weights = []
if q <= self.Configuration.PseudoRandomSelectionRate:
for i in range(0, len(self.InboundSelected)):
if False == self.InboundSelected[i]:
weights.append(self.heuristicInformation(preceedingIndex, i))
weights.append(self.heuristicInformation(i))
else:
# roulette selection strategy
pheromoneScale = 0.0
for i in range(0, len(self.InboundSelected)):
if False == self.InboundSelected[i]:
pheromoneScale += self.heuristicInformation(preceedingIndex, i)
pheromoneScale += self.heuristicInformation(i)
for i in range(0, len(self.InboundSelected)):
if False == self.InboundSelected[i]:
weights.append(self.heuristicInformation(preceedingIndex, i) / (pheromoneScale or 1))
weights.append(self.heuristicInformation(i) / (pheromoneScale or 1))
total = sum(weights)
cumdist = list(itertools.accumulate(weights)) + [total]
@@ -89,7 +69,7 @@ class Ant:
def associateInbound(self, node : Node, earliestArrivalTime : datetime):
# prepare the statistics
rwy, eta, _ = self.RunwayManager.selectArrivalRunway(node, True, self.Configuration.EarliestArrivalTime)
rwy, eta, _ = self.RunwayManager.selectArrivalRunway(node, self.Configuration.EarliestArrivalTime)
eta = max(earliestArrivalTime, eta)
node.Inbound.PlannedRunway = rwy
@@ -110,20 +90,18 @@ class Ant:
# select the first inbound
self.InboundSelected[first] = True
delay, rwy = self.associateInbound(self.Nodes[first], self.Configuration.EarliestArrivalTime)
self.InboundScore[0] = Ant.qualifyDelay(delay, self.Nodes[first], rwy)
delay, _ = self.associateInbound(self.Nodes[first], self.Configuration.EarliestArrivalTime)
self.Sequence.append(first)
self.SequenceDelay += delay
while 1:
index = self.selectNextLandingIndex(self.Sequence[-1])
index = self.selectNextLandingIndex()
if None == index:
break
self.InboundSelected[index] = True
delay, rwy = self.associateInbound(self.Nodes[index], self.Configuration.EarliestArrivalTime)
delay, _ = self.associateInbound(self.Nodes[index], self.Configuration.EarliestArrivalTime)
self.SequenceDelay += delay
self.InboundScore[len(self.Sequence)] = Ant.qualifyDelay(delay, self.Nodes[index], rwy)
self.Sequence.append(index)
# update the local pheromone
@@ -134,7 +112,4 @@ class Ant:
# validate that nothing went wrong
if len(self.Sequence) != len(self.Nodes):
self.SequenceDelay = None
self.SequenceScore = None
self.Sequence = None
else:
self.SequenceScore = np.median(self.InboundScore)