123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172 |
- from pypdevs.DEVS import AtomicDEVS
- from job import Job
- import random
- import dataclasses
- # Define the state of the generator as a structured object
- @dataclasses.dataclass
- class GeneratorState:
- current_time: float
- remaining: float
- to_generate: int
- next_job: None
- random: random.Random
- def __init__(self, gen_num, seed=0):
- # Current simulation time (statistics)
- self.current_time = 0.0
- # Remaining time until generation of new event
- self.remaining = 0.0
- # Counter on how many events to generate still
- self.to_generate = gen_num
- # Next job to output
- self.next_job = None
- # State of our random number generator
- self.random = random.Random(seed)
- class Generator(AtomicDEVS):
- def __init__(self, gen_param, size_param, gen_num):
- AtomicDEVS.__init__(self, "Generator")
- # Output port for the event
- self.out_event = self.addOutPort("out_event")
- # Parameters defining the generator's behaviour
- self.gen_param = gen_param
- self.size_param = size_param
- # Init state
- self.state = GeneratorState(gen_num)
- self.__nextJob() # already schedule the first job to generate
- def __nextJob(self):
- # Determine size of the event to generate
- size = max(1, int(self.state.random.gauss(self.size_param, 5)))
- # Calculate current time (note the addition!)
- creation = self.state.current_time
- # Update state
- self.state.next_job = Job(size, creation)
- self.state.remaining = self.state.random.expovariate(self.gen_param)
- def timeAdvance(self):
- # Return remaining time; infinity when generated enough
- return self.state.remaining
- def outputFnc(self):
- # Output the new event on the output port
- return {self.out_event: self.state.next_job}
- def intTransition(self):
- # Update simulation time
- self.state.current_time += self.state.remaining
- # Update number of generated events
- self.state.to_generate -= 1
- if self.state.to_generate == 0:
- # Already generated enough events, so stop
- self.state.remaining = float('inf')
- self.state.next_job = None
- else:
- # Still have to generate events, so sample for new duration
- self.__nextJob()
- return self.state
|