136 lines
4.7 KiB
Python
Executable file
136 lines
4.7 KiB
Python
Executable file
# -*- coding: Latin-1 -*-
|
|
from heapq import heappush, heappop, heapify
|
|
from logger import *
|
|
|
|
class SchedulerH(object):
|
|
"""
|
|
Scheduler class itself
|
|
"""
|
|
def __init__(self, models, epsilon, totalModels):
|
|
"""
|
|
Constructor
|
|
|
|
:param models: all models in the simulation
|
|
"""
|
|
self.heap = []
|
|
self.id_fetch = [None] * totalModels
|
|
for model in models:
|
|
self.id_fetch[model.model_id] = [model.timeNext, model.model_id, True, model]
|
|
heappush(self.heap, self.id_fetch[model.model_id])
|
|
|
|
self.invalids = 0
|
|
self.maxInvalids = len(models)*2
|
|
self.epsilon = epsilon
|
|
|
|
def schedule(self, model):
|
|
"""
|
|
Schedule a model
|
|
|
|
:param model: the model to schedule
|
|
"""
|
|
#assert debug("Scheduling " + str(model))
|
|
# Create the entry, as we have accepted the model
|
|
elem = [model.timeNext, model.model_id, False, model]
|
|
try:
|
|
self.id_fetch[model.model_id] = elem
|
|
except IndexError:
|
|
# A completely new model
|
|
self.id_fetch.append(elem)
|
|
self.maxInvalids += 2
|
|
# Check if it requires to be scheduled
|
|
self.id_fetch[model.model_id][2] = True
|
|
heappush(self.heap, self.id_fetch[model.model_id])
|
|
|
|
def unschedule(self, model):
|
|
"""
|
|
Unschedule a model
|
|
|
|
:param model: model to unschedule
|
|
"""
|
|
# Update the referece still in the heap
|
|
self.id_fetch[model.model_id][2] = False
|
|
# Remove the reference in our id_fetch
|
|
self.id_fetch[model.model_id] = None
|
|
|
|
def massReschedule(self, reschedule_set):
|
|
"""
|
|
Reschedule all models provided.
|
|
Equivalent to calling unschedule(model); schedule(model) on every element in the iterable.
|
|
|
|
:param reschedule_set: iterable containing all models to reschedule
|
|
"""
|
|
#NOTE rather dirty, though a lot faster for huge models
|
|
#assert debug("Mass rescheduling")
|
|
inf = float('inf')
|
|
for model in reschedule_set:
|
|
event = self.id_fetch[model.model_id]
|
|
if event[2]:
|
|
if model.timeNext == event[0]:
|
|
continue
|
|
self.invalids += 1
|
|
event[2] = False
|
|
self.id_fetch[model.model_id] = [model.timeNext, model.model_id, True, model]
|
|
heappush(self.heap, self.id_fetch[model.model_id])
|
|
#assert debug("Optimizing heap")
|
|
if self.invalids >= self.maxInvalids:
|
|
#assert info("Heap compaction in progress")
|
|
self.heap = [i for i in self.heap if i[2]]
|
|
heapify(self.heap)
|
|
self.invalids = 0
|
|
#assert info("Heap compaction complete")
|
|
|
|
def readFirst(self):
|
|
"""
|
|
Returns the time of the first model that has to transition
|
|
|
|
:returns: timestamp of the first model
|
|
"""
|
|
#assert debug("Reading first element from heap")
|
|
self.cleanFirst()
|
|
return self.heap[0][0]
|
|
|
|
def cleanFirst(self):
|
|
"""
|
|
Clean up the invalid elements in front of the list
|
|
"""
|
|
#assert debug("Cleaning list")
|
|
try:
|
|
while not self.heap[0][2]:
|
|
heappop(self.heap)
|
|
self.invalids -= 1
|
|
except IndexError:
|
|
# Nothing left, so it as clean as can be
|
|
#assert debug("None in list")
|
|
pass
|
|
|
|
def getImminent(self, time):
|
|
"""
|
|
Returns a list of all models that transition at the provided time, with a specified epsilon deviation allowed.
|
|
|
|
:param time: timestamp to check for models
|
|
|
|
.. warning:: For efficiency, this method only checks the **first** elements, so trying to invoke this function with a timestamp higher than the value provided with the *readFirst* method, will **always** return an empty set.
|
|
"""
|
|
#assert debug("Asking all imminent models")
|
|
immChildren = []
|
|
t, age = time
|
|
try:
|
|
# Age must be exactly the same
|
|
first = self.heap[0]
|
|
while (abs(first[0][0] - t) < self.epsilon) and (first[0][1] == age):
|
|
# Check if the found event is actually still active
|
|
if(first[2]):
|
|
# Active, so event is imminent
|
|
immChildren.append(first[3])
|
|
first[2] = False
|
|
else:
|
|
# Wasn't active, but we will have to pop this to get the next
|
|
# So we can lower the number of invalids
|
|
self.invalids -= 1
|
|
|
|
# Advance the while loop
|
|
heappop(self.heap)
|
|
first = self.heap[0]
|
|
except IndexError:
|
|
pass
|
|
return immChildren
|