class MMCC: """ Simulation object tasked with conducting the MMCC system """ def run(self, total_servers: int, total_arrival: int) -> None: """ Begin the simulation of a MMCC system. Process the information until termination criteria is meet. Params: - total_servers :: The number of servers that can handle clients at any one instance. - total_arrival :: The total number of clients that can be handled within the simulation. """ # Initialise the beginning parameters of the simulation self.servers = Servers(total_servers) # Set up server handler self.events = EventHandler() # Set up the event handler startingEvent = Event("arrival", 0) # Construct the first event object startingEvent.departure_time -= startingEvent.arrival_time # Reset times startingEvent.arrival_time = 0 # Reset times self.events.add(startingEvent) # Create the first event # Begin iteration of events, record arrivals for checking self.num_arrival = 0 while (self.num_arrival < total_arrival): # Collect next event from the event handler currentEvent = self.events.next() # Update simulation time self.sim_time = currentEvent.time() if currentEvent.type == "arrival": # Arrival event received self.num_arrival += 1 # Record number of arrivals # Create new arrival event self.events.add(Event("arrival", currentEvent.time())) # Check if any server is available if not self.servers.isFree(): self.events.block( currentEvent) # Arriving client is blocked continue # Begin serving the client. currentEvent.servedBy(self.servers.allocate()) # All event handler to manage departure self.events.add(currentEvent) else: # Departure event received self.servers.deallocate( currentEvent.servedBy()) # Free the server self.events.depart(currentEvent) # Record departure def blockingProbability(self) -> float: """ Calculate the blocking probability for the previous simulation run. Returns: - float :: Probability of blocking """ return len(self.events.blocked) / self.num_arrival def serverUtilisation(self) -> float: """ Calculate the server utilisation for the previous simulation run. Returns: - float :: Server utilisation value """ return sum([e.serviceTime() for e in self.events.departed]) / self.sim_time def report(self) -> None: """ Display the results of the simulation is a readible fashion. """ print("\tEvents Handled ::") print("\t\tArrival:", self.num_arrival) incomplete = self.num_arrival - (len(self.events.departed) + len(self.events.blocked)) print("\t\tIncomplete events:", incomplete) print("\t\tDeparture:", len(self.events.departed)) print("\t\tBlocked:", len(self.events.blocked)) print("\tBlocking rate:", self.blockingProbability()) print("\tServer Utilisation:", self.serverUtilisation())
class MMCC: """ Class to simulate M/M/C/C system """ def run(self, server_number: int, arrival_total: int): """ Run simulation with specified parameters :param server_number: Number of servers :param arrival_total: Number of events """ # Initialise Servers and EventHandler self.servers = Servers(server_number) self.events = EventHandler() # Create and add initial event starting_event = Event("arrival", 0) starting_event.departure_time -= starting_event.arrival_time starting_event.arrival_time = 0 self.events.add(starting_event) # Run simulation until number of events handled self.arrival_number = 0 while (self.arrival_number < arrival_total): # Iterate to next event and update simulation time current_event = self.events.next() self.simulation_time = current_event.time() # If arrival, update counter and add to appropriate list if current_event.event_type == "arrival": self.arrival_number += 1 self.events.add(Event("arrival", current_event.time())) # If no servers free, block event if not self.servers.is_free(): self.events.block(current_event) continue # Assign server to event current_event.served_by(self.servers.allocate()) self.events.add(current_event) # If departure, free server and depart else: self.servers.deallocate(current_event.served_by()) self.events.depart(current_event) def blocking_probability(self) -> float: """ Obtain blocking probability of previous run :return: Blocking probability """ return len(self.events.blocked) / self.arrival_number def server_utilisation(self) -> float: """ Obtain server utilisation of previous run :return: Server utilisation """ return sum([e.service_time() for e in self.events.departed]) / self.simulation_time