123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 |
- # -*- 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
|