KarrLab/wc_rules

View on GitHub
wc_rules/simulator/scheduler.py

Summary

Maintainability
B
6 hrs
Test Coverage
A
93%
from pqdict import pqdict
from collections import defaultdict, deque
from numpy import log, seterr
#from numpy.random import rand
import random
from abc import ABC, abstractmethod
from sortedcontainers import SortedSet
from ..utils.collections import subdict
import copy

seterr(divide="ignore",invalid='ignore')


class Scheduler:

    def __init__(self):        
        self.events = pqdict()

    def peek(self):
        if len(self.events) > 0:
            event,time = self.events.topitem()
            return event,time
        return None, float('inf')
    
    def update(self,time,variables={}):
        # updates local state of the scheduler
        return self

    def insert(self,time,event):
        self.events[event] = time
        return self

    def pop(self):
        if len(self.events) > 0:
            event,time = self.events.popitem()
            return event,time
        return None, float('inf')


class RepeatedEventScheduler(Scheduler):

    def __init__(self, event, period, start=0.0):
        super().__init__()
        self.event = event
        self.period = period
        self.insert(start,self.event)

    def pop(self):
        event,time = Scheduler.pop(self)
        if event is not None:
            self.insert(time+self.period,self.event)
        return event,time

class CoordinatedScheduler(Scheduler):

    def __init__(self,schedulers):
        self.schedulers = schedulers

    def get_first_scheduler(self):
        ind = pqdict({i:x.peek()[1] for i,x in enumerate(self.schedulers)}).top()
        return self.schedulers[ind]

    def pop(self):
        return self.get_first_scheduler().pop()

    def peek(self):
        return self.get_first_scheduler().peek()
        
    def update(self,time,variables={}):
        for sch in self.schedulers:
            sch.update(time,variables)
        return self

    def close(self):
        for sch in self.schedulers:
            sch.close()
        return self

class NextReactionMethod(Scheduler):
    ''' Gibson & Bruck 2000 '''

    def __init__(self):        
        super().__init__()
        self.propensities = defaultdict(float)

    def update(self,time,variables={}):
        for var, value in variables.items():
            if var.endswith('.propensity'):
                event = '.'.join(var.split('.')[:-1])
                self.propensities[event] = value
                self.schedule(time,event)
        return self

    def schedule(self,time,event):
        assert event in self.propensities
        propensity = self.propensities[event]
        tau = - log(random.random()) / propensity
        self.insert(time + tau,event)
        return self

    def pop(self):
        event,time = Scheduler.pop(self)
        self.schedule(time,event)
        return event,time

    def peek(self):
        event,time =  Scheduler.peek(self)
        self.schedule(time,event)
        return event,time

class PeriodicWriteObservables(RepeatedEventScheduler):

    def __init__(self,start=0.0,period=1.0,write_location='output',observables=[]):
        super().__init__('write_observables',period,start)
        self.write_location = write_location
        self.observables = observables
        self.data = deque()