Contact
CoCalc Logo Icon
StoreFeaturesDocsShareSupport News AboutSign UpSign In
| Download
Views: 74
Kernel: Python 2 (SageMath)
import numpy as np import pandas as pd import copy import seaborn as sns import matplotlib.pyplot as plt
class Elevator(object): """An Elevator is a generic class that can move one floor up and down and let the passengers off and on simultaneously with the help of a convenience function called "open_door". """ def __init__(self, building, capacity = 10): """ Initializes an instance of a class with a certain capacity identified by the user. Each object is characterized by the number of passengers, its current floor, the building where it is situated, and a list of passengers inside the elevator. """ self.capacity = capacity # number of people elevator can hold self.current_floor = 1 # elevator starts at ground floor: 1 self.building = building self.num_passengers = 0 # self.passengers is a dictionary from a destination floor number # to a list of Passenger objects (the Passengers that need to get off at floor i) self.passengers = { i : [] for i in range(1, building.num_floors + 1) } def move(self, direction): """Moves the elevator one floor up or down. """ self.current_floor += direction # direction is integer +1 or -1 def let_off(self, passenger, timestep = None): """Removes `passenger` from the elevator and adds them to the building. If `passenger` has arrived on their destination floor, add them to `arrived_passengers`. Raises an error if `passenger` is not on the elevator. """ try: self.passengers[passenger.end_floor].remove(passenger) except: raise("Passenger not found on elevator!") self.num_passengers -= 1 if passenger.end_floor == self.current_floor: self.building.arrived_passengers.append(passenger) else: self.building.waiting_passengers[self.current_floor].append(passenger) self.building.num_passengers += 1 if timestep is not None: passenger.travel_time += timestep - passenger.last_boarding passenger.last_deboarding = timestep return def let_on(self, passenger, timestep = None): """Adds `passenger` to the elevator from the current floor Raises an error if `passenger` is not on the elevator's current_floor """ try: self.building.waiting_passengers[self.current_floor].remove(passenger) except: raise("Passenger not found on current floor!") self.building.num_passengers -= 1 self.passengers[passenger.end_floor].append(passenger) self.num_passengers += 1 if timestep is not None: passenger.wait_time += timestep - passenger.last_deboarding passenger.last_boarding = timestep return def open_doors(self, timestep = None): """A convenience function for letting people on and off floors simultaneously""" # passengers get off for passenger in self.passengers[self.current_floor]: self.let_off(passenger, timestep) # passengers get on floor_lst = self.building.waiting_passengers[self.current_floor] while self.capacity > self.num_passengers and floor_lst: passenger = floor_lst[-1] self.let_on(passenger, timestep) return def not_empty(self): """Returns True if elevator is not empty.""" return self.num_passengers > 0 class Building(object): """The building generates and stores the passengers waiting for the elevator.""" def __init__(self, num_floors, num_passengers): """By default requires user specified number of floors and passengers.""" self.num_floors = num_floors self.arrived_passengers = [] self.waiting_passengers = { i : [] for i in range(1, num_floors + 1) } self.num_passengers = 0 self.add_passengers_randomly(num_passengers) def add_passengers_randomly(self, number): """Generates random passengers added to each floor.""" for i in range(number): start = np.random.randint(1, self.num_floors + 1) end = start while end == start: end = np.random.randint(1, self.num_floors + 1) passenger = Passenger(start,end) self.waiting_passengers[passenger.start_floor].append(passenger) self.num_passengers += number def not_empty(self): """Returns True if building is not empty.""" return self.num_passengers > 0 class Passenger(object): """Initiates passengers with start and end floor, called in building class.""" def __init__(self, start_floor, end_floor): """Initializes variables for keeping track of wait_ and travel_time Allows for multiple boardings/deboardings from the elevator """ self.start_floor = start_floor self.end_floor = end_floor self.last_boarding = 0 self.last_deboarding = 0 self.wait_time = 0 self.travel_time = 0
# Main Program def display_state_and_collect_analytics(elevator, building, analytics): """Displays the current elevator and building state. Collects relevant data about the performance of the elevator. """ print building.num_passengers def run_simulation(elevator,building,strategy,log_progress=True): """Runs the simulation for a given strategy. Continues to call the given strategy until all passengers are processed. """ is_moving_up = True timestep = 0 analytics = {'waiting_times':[]} while building.not_empty() or elevator.not_empty(): timestep,is_moving_up = strategy(elevator,building,timestep,is_moving_up) if log_progress: display_state_and_collect_analytics(elevator, building, analytics) analytics['tot_time'] = timestep analytics['arrived_passengers'] = building.arrived_passengers return analytics def basic_controller(elevator, building,timestep,is_moving_up): """Implements basic elevator strategy. Elevator goes up and down the building, stopping at every floor along the way. """ elevator.open_doors(timestep = timestep) timestep += 1 # switch directions if the elevator reaches the top or bottom of the building if elevator.current_floor == building.num_floors: is_moving_up = False elif elevator.current_floor == 1: is_moving_up = True # elevator moves up or down elevator.move(1 if is_moving_up else -1) timestep += 1 return(timestep,is_moving_up) def secondary_controller(elevator, building, timestep,is_moving_up): """Implements an elevator strategy where the elevator goes up and down the building, stopping at every floor where someone needs to get off or on. """ if elevator.current_floor == building.num_floors: is_moving_up = False elif elevator.current_floor == 1: is_moving_up = True on_floor = building.waiting_passengers[elevator.current_floor] off_floor = elevator.passengers[elevator.current_floor] space = True if elevator.num_passengers < elevator.capacity else False if (off_floor) or (on_floor and space): elevator.open_doors(timestep = timestep) else: # switch directions if the elevator reaches the top or bottom of the building elevator.move(1 if is_moving_up else -1) # elevator moves up or down timestep += 1 return(timestep,is_moving_up) if __name__ == "__main__": # create building object with random passenger set up building1 = Building(num_floors=20, num_passengers=100) # an identical copy of the building building2 = copy.deepcopy(building1) # two elevators, each with its own associated building elevator1 = Elevator(building1, capacity=10) elevator2 = Elevator(building2, capacity=10) # run simulations with each of the two strategies results1 = run_simulation(elevator1,building1,basic_controller) results2 = run_simulation(elevator2,building2,secondary_controller)
94 90 89 88 87 87 86 86 86 85 84 83 81 80 79 79 79 78 77 76 76 75 75 75 75 75 74 73 72 72 71 71 71 70 70 68 66 65 65 64 63 63 63 63 62 62 62 62 62 62 61 61 60 59 59 58 57 55 55 55 55 55 55 55 54 54 53 53 53 52 52 52 52 51 51 49 49 48 48 48 48 46 45 45 45 45 44 43 43 42 41 41 41 41 40 40 38 38 38 38 38 38 38 37 36 36 35 35 34 33 33 33 33 33 33 33 33 33 33 33 31 29 28 27 27 26 26 25 25 25 24 24 24 24 24 23 21 21 21 20 20 19 19 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 16 14 11 11 11 11 10 9 8 7 7 7 7 7 7 7 4 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 94 94 90 90 89 89 88 88 87 87 87 86 86 86 86 85 85 84 84 83 83 81 80 80 79 79 78 78 78 78 77 77 76 76 75 74 74 74 73 73 73 73 73 73 73 72 72 71 70 70 70 69 69 68 68 68 67 67 67 67 65 65 63 62 62 62 59 58 58 58 58 58 58 58 58 57 56 56 56 56 56 55 55 54 54 53 52 52 52 51 50 50 49 49 49 48 48 47 47 46 46 46 46 43 43 43 43 43 43 43 43 43 42 42 42 41 41 40 39 39 39 38 37 37 36 35 35 35 34 34 34 34 34 34 33 33 33 33 33 33 33 33 33 32 32 31 31 28 28 27 27 26 25 25 25 25 23 22 22 22 22 20 19 19 19 18 18 16 15 15 15 15 15 15 15 15 15 14 14 13 13 12 12 12 11 11 11 11 11 11 11 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 8 8 7 7 7 7 7 7 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

Efficiency Comparison

def extract_times(results,strategy): """Extract efficiency metrics from stored passenger objects.""" waited = [] # times waiting for elevator travelled = [] # times on elevator totals = [] # total times travelled # add every passengers data to aggregate lists for passenger in results['arrived_passengers']: waited.append(passenger.wait_time) travelled.append(passenger.travel_time) totals.append(passenger.wait_time+passenger.travel_time) # update dictionary with extracted data strategy["runtimes"].append(results["tot_time"]) strategy["waits"].append(waited) strategy["travels"].append(travelled) strategy["totals"].append(totals) def compare_strategies(strategies,runs=100): """Run simulation 'runs' times for each strategy and extract efficiency metrics.""" metrics = [] # create a metric dictionary for each strategy for strategy in strategies: metrics.append({"runtimes":[],"waits":[],"travels":[],"totals":[]}) # run the simulation for each strategy, 'runs' times for sim_run in range(runs): basic_building = Building(num_floors=20, num_passengers=100) buildings = [] elevators = [] results = [] for i,strategy in enumerate(strategies): building = copy.deepcopy(basic_building) elevator = Elevator(building, capacity=10) results = run_simulation(elevator,building,strategy,log_progress=False) extract_times(results,metrics[i]) return(metrics)
# collect efficiency measures for each strategy developed strategies = [basic_controller,secondary_controller] strategy1,strategy2 = compare_strategies(strategies,1000)
# simple tabular summary of simulation runtimes under each strategy pd.DataFrame([strategy1["runtimes"],strategy2["runtimes"]], index=['Strategy 1','Strategy 2']).T.describe()
Strategy 1 Strategy 2
count 1000.000000 1000.000000
mean 451.926000 279.687000
std 41.834683 19.346869
min 324.000000 229.000000
25% 420.000000 260.000000
50% 458.000000 279.000000
75% 474.000000 296.000000
max 610.000000 341.000000
plt.figure(figsize=(8,4)) sns.distplot(strategy1["runtimes"],label='Strategy 1',kde=False) sns.distplot(strategy2["runtimes"],label='Strategy 2',kde=False) plt.title('Histograms of Simulation Runtimes') plt.ylabel('Number of Simulations') plt.xlabel('Runtime (time to process all passengers)') plt.legend() plt.show()
Image in a Jupyter notebook
def all_waiting_times(times): """Simple helper function to merge list of lists.""" return([time for simulation in times for time in simulation])
plt.figure(figsize=(8,4)) sns.distplot(all_waiting_times(strategy1['waits']),label='Strategy 1',kde=False,bins=10) sns.distplot(all_waiting_times(strategy2['waits']),label='Strategy 2',kde=False,bins=10) plt.title('Histograms of Individual Waiting Times') plt.ylabel('Number of Passengers') plt.xlabel('Waiting Time (time waiting for elevator)') plt.legend() plt.show()
Image in a Jupyter notebook
plt.figure(figsize=(8,4)) sns.distplot(all_waiting_times(strategy1['travels']),label='Strategy 1',kde=False,bins=10) sns.distplot(all_waiting_times(strategy2['travels']),label='Strategy 2',kde=False,bins=10) plt.title('Histograms of Individual Travel Times') plt.ylabel('Number of Passengers') plt.xlabel('Travel Time (time on elevator)') plt.legend() plt.show()
Image in a Jupyter notebook
plt.figure(figsize=(8,4)) sns.distplot(all_waiting_times(strategy1['totals']),label='Strategy 1',kde=False,bins=10) sns.distplot(all_waiting_times(strategy2['totals']),label='Strategy 2',kde=False,bins=10) plt.title('Histograms of Individual Time in Simulation') plt.ylabel('Number of Passengers') plt.xlabel('Total Time (time in simulation)') plt.legend() plt.show()
Image in a Jupyter notebook