AtomicDEVSBlock ResourceHandler { name = "ResourceHandler" parameters = 1 initialState = "self.state, self.elapsed = {'resources': parameters[0], 'queue': []}, 0.0" timeAdvance = """ if self.state['queue'] and self.state['resources']: # Can grant a resource return 0.0 else: # No request queued, or no available resources to handle the request return float('inf') """ outputFnc = """ return {self.resource_out: {'id': self.state['queue'][0]}} """ intTransition = """ # Processed a request that could be processed self.state['resources'] -= 1 del self.state['queue'][0] return self.state """ extTransition = """ for inp in inputs[self.resource_in]: if inp['type'] == 'request': # Queue the request self.state['queue'].append(inp['id']) elif inp['type'] == 'release': # Increment the number of available resources self.state['resources'] += 1 return self.state """ } InputPort rh_ri { name = "resource_in" } OutputPort rh_ro { name = "resource_out" } DEVSBlockToPort (ResourceHandler, rh_ri) {} DEVSBlockToPort (ResourceHandler, rh_ro) {} AtomicDEVSBlock Activity { name = "Activity" parameters = 2 initialState = """ class ActivityState(object): def __init__(self, name, distribution): self.timer = float('inf') self.mode = 'inactive' self.counter = 0 self.name = name self.distribution = distribution def __str__(self): return str(vars(self)) def random_sample(self): return self.distribution(self.counter) self.state, self.elapsed = ActivityState(parameters[0], parameters[1]), 0.0 """ timeAdvance = """ return self.state.timer """ outputFnc = """ if self.state.mode == 'active': # Output the control token to the next model in line, and release the resources return {self.control_out: {}, self.resource_out: [{'type': 'release'}]} elif self.state.mode == 'request_resource': # Output a request for resources with a specified ID (used to find out whether this was our request) return {self.resource_out: [{'type': 'request', 'id': '%s-%s' % (self.state.name, self.state.counter)}]} else: return {} """ intTransition = """ self.state.timer -= self.timeAdvance() if self.state.mode == 'request_resource': # Go and request the required resource self.state.mode = 'wait_resource' self.state.timer = float('inf') elif self.state.mode == 'active': # Finished execution, so release resources self.state.mode = 'inactive' self.state.timer = 0.0 self.state.timer = float('inf') self.state.counter += 1 return self.state """ extTransition = """ self.state.timer -= self.elapsed if self.state.mode == 'inactive' and self.control_in in inputs: # Got control token, so ask for the required resources self.state.mode = 'request_resource' self.state.timer = 0.0 # NOTE this violates DEVS, though is easy to debug #print('Activate ' + str(self.state.name) + ' at time ' + str(self.time_last[0] + self.elapsed)) elif self.state.mode == 'wait_resource' and self.resource_in in inputs and inputs[self.resource_in]['id'] == '%s-%s' % (self.state.name, self.state.counter): # Got required resources, so start execution self.state.mode = 'active' self.state.timer = self.state.random_sample() return self.state """ } InputPort act_ri { name = "resource_in" } OutputPort act_ro { name = "resource_out" } DEVSBlockToPort (Activity, act_ri) {} DEVSBlockToPort (Activity, act_ro) {} AtomicDEVSBlock ParallelSplit { name = "ParallelSplit" parameters = 0 initialState = "self.state, self.elapsed = False, 0.0" timeAdvance = """ if self.state: return 0.0 else: return float('inf') """ outputFnc = """ return {self.control_out: {}} """ intTransition = """ return False """ extTransition = """ return True """ } InputPort split_ci { name = "control_in" } OutputPort split_co { name = "control_out" } DEVSBlockToPort (ParallelSplit, split_ci) {} DEVSBlockToPort (ParallelSplit, split_co) {} AtomicDEVSBlock Synchronization { name = "Synchronization" parameters = 1 initialState = "self.state, self.elapsed = {'current': parameters[0], 'max': parameters[0]}, 0.0" timeAdvance = """ if self.state['current'] == 0: return 0.0 else: return float('inf') """ outputFnc = """ return {self.control_out: {}} """ intTransition = """ self.state['current'] = self.state['max'] return self.state """ extTransition = """ self.state['current'] -= 1 return self.state """ } InputPort syn_ci { name = "control_in" } OutputPort syn_co { name = "control_out" } DEVSBlockToPort (Synchronization, syn_ci) {} DEVSBlockToPort (Synchronization, syn_co) {} AtomicDEVSBlock ExclusiveChoice { name = "ExclusiveChoice" parameters = 1 initialState = """ class ExclusiveChoiceState(object): def __init__(self, distribution): self.counter = 0 self.choice = None self.distribution = distribution def __str__(self): return str(vars(self)) def make_choice(self): return self.distribution(self.counter) self.state, self.elapsed = ExclusiveChoiceState(parameters[0]), 0.0 """ timeAdvance = """ if self.state.choice is not None: return 0.0 else: return float('inf') """ outputFnc = """ if self.state.choice == 0: return {self.control_out1: {}} else: return {self.control_out2: {}} """ intTransition = """ self.state.choice = None self.state.counter += 1 return self.state """ extTransition = """ # Got a control token, so have to make a choice self.state.choice = self.state.make_choice() return self.state """ } InputPort xor_ci { name = "control_in" } OutputPort xor_co1 { name = "control_out1" } OutputPort xor_co2 { name = "control_out2" } DEVSBlockToPort (ExclusiveChoice, xor_ci) {} DEVSBlockToPort (ExclusiveChoice, xor_co1) {} DEVSBlockToPort (ExclusiveChoice, xor_co2) {} AtomicDEVSBlock SimpleMerge { name = "SimpleMerge" parameters = 0 initialState = "self.state, self.elapsed = False, 0.0" timeAdvance = """ if self.state: return 0.0 else: return float('inf') """ outputFnc = """ return {self.control_out: {}} """ intTransition = """ return False """ extTransition = """ return True """ } InputPort or_ci { name = "control_in" } OutputPort or_co { name = "control_out" } DEVSBlockToPort (SimpleMerge, or_ci) {} DEVSBlockToPort (SimpleMerge, or_co) {} AtomicDEVSBlock MultiInstance { name = "MultiInstance" parameters = 2 initialState = """ class MultiInstanceState(object): def __init__(self, name, num, distribution): self.spawned = num self.collected = 0 self.counter = 0 self.mode = 'inactive' self.running_tasks = [] self.requested = [] self.name = name self.distribution = distribution def __str__(self): return str(vars(self)) def task_time(self): return self.distribution(self.counter) self.state, self.elapsed = MultiInstanceState(parameters[0], parameters[1], parameters[2]) """ timeAdvance = """ if self.state.mode == 'finish': return 0.0 elif self.state.running_tasks: return self.state.running_tasks[0][0] elif self.state.mode == 'request_resources': return 0.0 else: return float('inf') """ outputFnc = """ if self.state.mode == 'request_resources': # Request all resources in one go return {self.resource_out: [{'type': 'request', 'id': i} for i in self.state.requested]} elif self.state.mode == 'active': # Finished an instance, so release it return {self.resource_out: [{'type': 'release'}]} elif self.state.mode == 'finish': # Finished execution of all, so pass on token return {self.control_out: {}} else: return {} """ intTransition = """ ta = self.timeAdvance() for t in self.state.running_tasks: t[0] -= ta if self.state.mode == 'active': # Finished an instance, so pop it del self.state.running_tasks[0] self.state.collected += 1 if self.state.collected == self.state.spawned: self.state.mode = 'finish' elif self.state.mode == 'request_resources': # Requested resources, so be ready for a response self.state.mode = 'active' elif self.state.mode == 'finish': self.state.mode = 'inactive' self.state.collected = 0 self.state.counter += 1 self.state.running_tasks = [] return self.state """ extTransition = """ # Got input, so have to spawn #num of them for t in self.state.running_tasks: t[0] -= self.elapsed if self.state.mode == 'inactive' and self.control_in in inputs: self.state.mode = 'request_resources' self.state.requested = ['%s-%s-%s' % (self.state.name, self.state.counter, i) for i in range(self.state.spawned)] if self.state.mode in ['active', 'release_resource'] and self.resource_in in inputs: # Got a resource, so allocate it to an activity self.state.running_tasks.append([self.state.task_time(), self.state.requested.pop(0)]) # NOTE this violates DEVS, though is easy to debug #print('Spawn ' + str(self.state.running_tasks[-1][1]) + ' at time ' + str(self.time_last[0] + self.elapsed)) self.state.running_tasks.sort() return self.state """ } InputPort mi_ci { name = "control_in" } OutputPort mi_co { name = "control_out" } InputPort mi_ri { name = "resource_in" } OutputPort mi_ro { name = "resource_out" } DEVSBlockToPort (MultiInstance, mi_ci) {} DEVSBlockToPort (MultiInstance, mi_co) {} DEVSBlockToPort (MultiInstance, mi_ri) {} DEVSBlockToPort (MultiInstance, mi_ro) {}