class RiderStatusTracker: timestamp = -1 def __init__(self, wait_dict, serve_dict, finish_dict, cancel_dict): self.__logger = Logger("RiderStatusTracker") self.__wait_dict = wait_dict self.__serve_dict = serve_dict self.__finish_dict = finish_dict self.__cancel_dict = cancel_dict def checkRiderStatusIfTimeOut(self, rider): if RiderStatusTracker.timestamp - rider.getRequestTimeStamp( ) >= rider.getPatience(): rider.setStatus(CANCEL) self.__cancel_dict[rider.getID()] = rider zone_id = rider.getSrcZone() dir = rider.getDirID() group_id = rider.getGroupID() del self.__wait_dict[zone_id][dir][group_id][rider.getID()] if len(self.__wait_dict[zone_id][dir][group_id]) == 0: del self.__wait_dict[zone_id][dir][group_id] #cancel_dict[RiderStatusTracker.timestamp][rider.getSrcZone()] += 1 else: self.__logger.debug( RiderStatusTracker.timestamp, "updateRiderStatusWhenTimeOut", None, rider.getID(), "Cancel Time Should be: ", str(rider.getRequestTimeStamp() + rider.getPatience())) def updateRiderStatusAfterMatching(self, rider): rider.calcSat() rider.setStatus(SERVING) self.__serve_dict[rider.getID()] = rider def notifyRiderToFinishTrip(self, rider): if rider.getStatus() == SERVING: self.__finish_dict[rider.getID()] = rider rider.setStatus(FINISHED) del self.__serve_dict[rider.getID()] else: self.__logger.error(RiderStatusTracker.timestamp, "updateRiderStatusWhenInService", None, rider.getID(), "The status and dict not match.") raise Exception("The rider status and dict not match.") def updateRiderStatusWhenWait(self, rider, wait_rider_dict): if rider.getStatus() == WAITING: rider.tickWaitTime() wait_rider_dict[RiderStatusTracker.timestamp][ rider.getSrcZone()] += 1 else: self.__logger.error(RiderStatusTracker.timestamp, "updateDriverStatusWhenIdle", None, rider.getID(), "Rider Status is Wrong.") raise Exception("The rider status and dict not match.")
class Dispatcher: # Sync timestamp for logging timestamp = -1 def __init__(self): #logger in Dispatcher self.__logger = Logger('Dispatcher') self.__logger.setLevel(logging.DEBUG) self.__logger.info(Dispatcher.timestamp, "__INIT__", None, None, "Create A Dispatcher Object") #Storage for drivers and riders self.__driver_dict = {} self.__rider_wait_dict = {} self.__rider_serve_dict = {} self.__rider_finish_dict = {} self.__rider_cancel_dict = {} #Performance of driver and rider self.wait_rider={} self.no_work_driver={} self.idle_driver_before_match={} self.grp_in_4=0 self.grp_in_3=0 self.grp_in_2=0 self.grp_in_1=0 #Cluser Strategy self.__cluster_strategy = ClusteringByDir(self.__rider_wait_dict) #Matching Strategy self.__match_strategy = MatchingInQueue(self.__driver_dict, self.__rider_wait_dict, self.__rider_serve_dict) #Driver Status Tracker self.__driver_tracker = DriverStatusTracker(self.__driver_dict) #Rider Status tracker self.__rider_tracker = RiderStatusTracker(self.__rider_wait_dict, self.__rider_serve_dict, self.__rider_finish_dict, self.__rider_cancel_dict) #Driver Dict for zone_id in range(1,78): self.__driver_dict[zone_id] = {} #Rider Dict for zone_id in range(1,78): self.__rider_wait_dict[zone_id] = {} for dir_id in range(-1, 12): self.__rider_wait_dict[zone_id][dir_id] = defaultdict(dict) # for cycle in range(SIMULATION_CYCLE_START, SIMULATION_CYCLE_END): self.wait_rider[cycle] = [] self.no_work_driver[cycle] = [] for zone_id in range(0,78): self.wait_rider[cycle].append(0) self.no_work_driver[cycle].append(0) def showDriverDict(self, zone_id): ret = str(zone_id) + ": {" for driver_id in OrderedDict(sorted(self.__driver_dict[zone_id].items(), key=lambda t: t[0])).keys(): ret = ret + driver_id + ", " ret = ret + "}" return ret def getDriverFromDriverDict(self, zone_id, driver_id): for id, driver in self.__driver_dict[zone_id].items(): if id == driver_id: return driver return None def getDriverNumberOfZone(self, zone_id): return len(self.__driver_dict[zone_id]) def showRiderWaitDict(self, zone_id): ret = str(zone_id) + ": {" for dir_id in self.__rider_wait_dict[zone_id].keys(): ret = ret + str(dir_id) + ": {" for group_id in self.__rider_wait_dict[zone_id][dir_id].keys(): ret = ret + str(group_id) + ": [" for rider_id in OrderedDict(sorted(self.__rider_wait_dict[zone_id][dir_id][group_id].items(), key=lambda t: t[0])).keys(): ret = ret + str(rider_id) + ", " ret = ret + "], " ret = ret + "}, " ret = ret + "}" return ret def getRiderFromWaitDict(self, zone_id, dir_id, group_id, rider_id): for id, rider in self.__rider_wait_dict[zone_id][dir_id][group_id].items(): if id == rider_id: return rider return None def getGroupFromWaitDict(self, zone_id, dir_id, group_id): for id, group in self.__rider_wait_dict[zone_id][dir_id].items(): if id == group_id: return group return None def getRequestNumberOfZone(self, zone_id): total_num = 0 for dir_id in self.__rider_wait_dict[zone_id].keys(): for group_id in self.__rider_wait_dict[zone_id][dir_id].keys(): total_num += len(self.__rider_wait_dict[zone_id][dir_id][group_id]) return total_num def showRiderServedDict(self): ret = "{" for rider_id in OrderedDict(sorted(self.__rider_serve_dict.items(), key=lambda t: t[0])).keys(): ret=ret+str(rider_id)+", " ret=ret+"}" return ret def getRiderFromServedDict(self, rider_id): for id, rider in self.__rider_serve_dict.items(): if id == rider_id: return rider return None def showRiderFinishedDict(self): ret = "{" for rider_id in OrderedDict(sorted(self.__rider_finish_dict.items(), key=lambda t: t[0])).keys(): ret = ret + str(rider_id) + ", " ret = ret + "}" return ret def getRiderFromFinishedDict(self, rider_id): for id, rider in self.__rider_finish_dict.items(): if id == rider_id: return rider return None def showRiderCanceledDict(self): ret = "{" for rider_id in OrderedDict(sorted(self.__rider_cancel_dict.items(), key=lambda t: t[0])).keys(): ret = ret + str(rider_id) + ", " ret = ret + "}" return ret def getRiderFromCanceledDict(self, rider_id): for id, rider in self.__rider_cancel_dict.items(): if id == rider_id: return rider return None #put driver into Driver Dict at start def handleDriverIntoDict(self, driver): if isinstance(driver, Driver): if driver.getID() not in self.__driver_dict[driver.getPos()].keys(): self.__driver_dict[driver.getPos()][driver.getID()] = driver else: self.__logger.error(Dispatcher.timestamp, "handleDriverRequest", driver.getID(), None, "Driver has been in the Pool.") raise Exception("Driver has been in the Pool.") else: self.__logger.error(Dispatcher.timestamp, "handleDriverRequest", None, None, "Driver's type is wrong.") raise Exception("Driver's type is wrong.") def handleRiderIntoDict(self, rider): if isinstance(rider, Rider): self.__cluster_strategy.cluster(rider) else: self.__logger.error(Dispatcher.timestamp, "handleRiderRequest", None, None, "Rider's type is wrong.") raise Exception("Rider's type is wrong.") def matchRidertoDriver(self): for zone_id in self.__rider_wait_dict.keys(): for dir_id in self.__rider_wait_dict[zone_id].keys(): for group_id in self.__rider_wait_dict[zone_id][dir_id].copy().keys(): driver = self.__match_strategy.match(zone_id) if driver is not None: self.__logger.info(Dispatcher.timestamp, "matchRidertoDriver", driver.getID(), None, "Driver be Chosen to Serve Riders.") self.__logger.debug(Dispatcher.timestamp, "matchRidertoDriver", None, None, "Driver Zone ===> Rider Zone: ", str(driver.getPos()) + "===>" + str(zone_id)) # update driver status driver.setRiders(self.__rider_wait_dict[zone_id][dir_id][group_id]) self.__driver_tracker.updateDriverStatusAfterMatching(driver) self.__logger.debug(Dispatcher.timestamp, "matchRidertoDriver", driver.getID(), None, str(driver)) #update rider status if len(self.__rider_wait_dict[zone_id][dir_id][group_id]) == 4: self.grp_in_4 += 1 elif len(self.__rider_wait_dict[zone_id][dir_id][group_id]) == 3: self.grp_in_3 += 1 elif len(self.__rider_wait_dict[zone_id][dir_id][group_id]) == 2: self.grp_in_2 += 1 elif len(self.__rider_wait_dict[zone_id][dir_id][group_id]) == 1: self.grp_in_1 += 1 else: self.__logger.warning(Dispatcher.timestamp, "calcPoolingPerformanceInWaitDict", None, None, "Grp len is 0.") for rider in self.__rider_wait_dict[zone_id][dir_id][group_id].values(): self.__rider_tracker.updateRiderStatusAfterMatching(rider) self.__logger.debug(Dispatcher.timestamp, "matchRidertoDriver", driver.getID(), rider.getID(), str(rider)) del self.__rider_wait_dict[zone_id][dir_id][group_id] else: self.__logger.info(Dispatcher.timestamp, "matchRidertoDriver", None, None, "No Driver is available.") break def updateDriverInDict(self): for zone_id in self.__driver_dict.keys(): for driver in self.__driver_dict[zone_id].copy().values(): if driver.getStatus() == IDLE: self.__logger.info(Dispatcher.timestamp, "updateDriverStatus", driver.getID(), None, "Update Driver when IDLE.") self.__driver_tracker.updateDriverStatusWhenIdle(driver, self.no_work_driver) elif driver.getStatus() == INSERVICE: self.__logger.info(Dispatcher.timestamp, "updateDriverStatus", driver.getID(), None, "Update Driver Who is INSERVICE.") self.__driver_tracker.updateDriverStatusWhenInService(driver, self.__rider_tracker) self.__logger.debug(Dispatcher.timestamp, "updateDriverStatus", driver.getID(), None, str(driver)) else: self.__logger.error(Dispatcher.timestamp, "updateDriverStatus", driver.getID(), None, "Driver Status is Wrong.") raise Exception("Driver Status is Wrong.") def updateRidersInWaitDict(self): for zone_id in self.__rider_wait_dict.keys(): for dir_id in self.__rider_wait_dict[zone_id].keys(): for group_id in self.__rider_wait_dict[zone_id][dir_id].copy().keys(): for rider in self.__rider_wait_dict[zone_id][dir_id][group_id].copy().values(): if rider.getStatus() == WAITING: self.__rider_tracker.updateRiderStatusWhenWait(rider, self.wait_rider) self.__rider_tracker.checkRiderStatusIfTimeOut(rider) def countTotalDriverNumber(self): total_len = 0 for zone_id in self.__driver_dict.keys(): total_len = total_len + len(self.__driver_dict[zone_id]) return total_len def countDriverNumberEachZone(self): self.idle_driver_before_match[Dispatcher.timestamp] = [0] for zone_id in self.__driver_dict.keys(): cnt=0 for driver in self.__driver_dict[zone_id].values(): if driver.getStatus() == IDLE: cnt+=1 self.idle_driver_before_match[Dispatcher.timestamp].append(cnt) def countRiderNumberInWaitDict(self): total_len = 0 for zone_id in self.__rider_wait_dict.keys(): for dir_id in self.__rider_wait_dict[zone_id].keys(): for group_id in self.__rider_wait_dict[zone_id][dir_id].keys(): total_len = total_len + len(self.__rider_wait_dict[zone_id][dir_id][group_id]) return total_len def countRiderNumberInServeDict(self): return len(self.__rider_serve_dict) def countRiderNumberInFinishDict(self): return len(self.__rider_finish_dict) def countRiderNumberInCancelDict(self): return len(self.__rider_cancel_dict) def countCurrentTotalRiderNumber(self): return self.countRiderNumberInWaitDict() + self.countRiderNumberInServeDict() + self.countRiderNumberInFinishDict() + self.countRiderNumberInCancelDict() def calcAverageProfitOfDrivers(self): totalProfit = 0 for zone_id in self.__driver_dict.keys(): for driver in self.__driver_dict[zone_id].values(): totalProfit += driver.getTripProfit() return totalProfit / self.countTotalDriverNumber() def calcAverageIdleTimeOfDrivers(self): totalIdleTime = 0 for zone_id in self.__driver_dict.keys(): for driver in self.__driver_dict[zone_id].values(): totalIdleTime += driver.getIdleTime() return totalIdleTime / self.countTotalDriverNumber() def calcAverageTripEffortOfDrivers(self): totalTripEffort = 0 for zone_id in self.__driver_dict.keys(): for driver in self.__driver_dict[zone_id].values(): totalTripEffort += driver.getTripEffort() return totalTripEffort / self.countTotalDriverNumber() def calcAverageWaitTimeOfRiders(self): totalWaitTime = 0 riders = {**self.__rider_serve_dict, **self.__rider_finish_dict, **self.__rider_cancel_dict} for rider in riders.values(): totalWaitTime +=rider.getWaitTime() return totalWaitTime/(self.countRiderNumberInFinishDict()+self.countRiderNumberInServeDict()+self.countRiderNumberInCancelDict()) def calcAverageDetourTimeOfRiders(self): totalDetourTime = 0 riders = {**self.__rider_serve_dict, **self.__rider_finish_dict} for rider in riders.values(): totalDetourTime += rider.getDetourTime() return totalDetourTime/(self.countRiderNumberInFinishDict()+self.countRiderNumberInServeDict()) def calcAverageFareOfRiders(self): totalFare = 0 riders = {**self.__rider_serve_dict, **self.__rider_finish_dict} for rider in riders.values(): totalFare += rider.getPrice() return totalFare/(self.countRiderNumberInFinishDict()+self.countRiderNumberInServeDict()) def calcAverageDefaultFareRiders(self): totalDefaultFare = 0 riders = {**self.__rider_serve_dict, **self.__rider_finish_dict} for rider in riders.values(): totalDefaultFare += rider.getDefaultPrice() return totalDefaultFare/(self.countRiderNumberInFinishDict()+self.countRiderNumberInServeDict()) def calcAverageSatOfRiders(self): totalSat = 0 riders = {**self.__rider_serve_dict, **self.__rider_finish_dict, **self.__rider_cancel_dict} for rider in riders.values(): totalSat += rider.getSat() return totalSat/(self.countRiderNumberInFinishDict()+self.countRiderNumberInServeDict()+self.countRiderNumberInCancelDict())
class Simulation: def __init__(self): self.__logger = Logger('Simulation') #self.__logger.setLevel(logging.DEBUG) self.__logger.info(-1, "__INIT__", None, None, "Create Simulation Object.") self.__driver_list = RequestList() self.__rider_list = RequestList() self.__dispatcher = Dispatcher() self.__cycle = 0 self.__sim_time = [] def importData(self, ): ImportData.importDriverData(FILENAME_D, self.__driver_list) ImportData.importRiderData(FILENAME_R, self.__rider_list) def run(self): #Run simulation cycle for self.__cycle in range(SIMULATION_CYCLE_START, SIMULATION_CYCLE_END): # Synchronization the time with Modules(Driver, Dispatcher, Rider, and so on) self.__logger.info(self.__cycle, "RUN", None, None, "1. Synchronizing Time With Each Module.") #Dispatcher Module Dispatcher.timestamp = self.__cycle ClusteringStrategy.timestamp = self.__cycle MatchingStrategy.timestamp = self.__cycle DriverStatusTracker.timestamp = self.__cycle RiderStatusTracker.timestamp = self.__cycle #Driver Module Driver.timestamp = self.__cycle RoutingStrategy.timestamp = self.__cycle #Rider Module Rider.timestamp = self.__cycle #Import Module RequestList.timestamp = self.__cycle ImportDemandEvaluation.timestamp = self.__cycle # Start simulation time of this cycle print("The Cycle Number: ", self.__cycle) #print("Time: ", ImportDemandEvaluation.time) # Put the driver requests to dispatcher (The Driver List) self.__logger.info( self.__cycle, "RUN", None, None, "2. Put Drivers' Requests To Dispatcher From RequestList.") while not self.__driver_list.is_empty(): curr_driver = self.__driver_list.remove() self.__logger.debug( self.__cycle, "RUN", None, None, "Current Driver Moved into Dict of Dispatcher: ", str(curr_driver)) self.__dispatcher.handleDriverIntoDict(curr_driver) self.__dispatcher.countDriverNumberEachZone( ) #count idle driver number before match # Put the rider requests to dispatcher (The Rider List) self.__logger.info( self.__cycle, "RUN", None, None, "3. Put Rider' Requests To Dispatcher From RequestList.") while not self.__rider_list.is_empty( ) and self.__rider_list.first_element().getRequestTimeStamp( ) == self.__cycle: curr_rider = self.__rider_list.remove() self.__logger.debug( self.__cycle, "RUN", None, None, "Current Rider Moved into Dict of Dispatcher: ", str(curr_rider)) self.__dispatcher.handleRiderIntoDict(curr_rider) #Show dispatch dicts print("waiting, serving, finished, canceled: ", self.__dispatcher.countRiderNumberInWaitDict(), self.__dispatcher.countRiderNumberInServeDict(), self.__dispatcher.countRiderNumberInFinishDict(), self.__dispatcher.countRiderNumberInCancelDict()) #match driver and rider by dispatcher self.__logger.info( self.__cycle, "RUN", None, None, "4. Match Riders' Request to AN Appropriate Driver.") self.__dispatcher.matchRidertoDriver() # Update simulator's states self.__logger.info(self.__cycle, "RUN", None, None, "5. Update State of Simulator.") self.__dispatcher.updateDriverInDict() self.__dispatcher.updateRidersInWaitDict() #Show up results self.__logger.info(self.__cycle, "RUN", None, None, "6. Show Up All Results of this Cycle.") #print(self.__dispatcher.cancel_rider) #print(self.__dispatcher.no_work_driver) #if self.__cycle % SHOWN_INTERVAL == 0 and self.__cycle != SIMULATION_CYCLE_START: # self.showPerformanceMetrics() #print("\n") self.showPerformanceMetrics() print("Simulation Terminated.\n") #self.drawMonitorDict(self.__dispatcher.wait_rider, self.__dispatcher.no_work_driver) def drawMonitorDict(self, monitor_dict1, monitor_dict2): for time1, item1 in monitor_dict1.items(): for time2, item2 in monitor_dict2.items(): if time1 == time2: #plt.figure(figsize=(30, 20)) fig, (ax1, ax2) = plt.subplots(2, figsize=(30, 20)) fig.suptitle(str(time1)) ax1.plot(item1[0:78], label='Wait Rider# after match', color='r') ax1.plot(item2[0:78], label='Idle Driver# after match', color='b') ax1.set_xticks(np.arange(0, 78, step=1)) ax1.set_yticks(np.arange(0, 300, step=20)) ax1.set_ylabel("driver#") ax1.legend() ax2.plot(self.__dispatcher.idle_driver_before_match[time1], label='Idle Driver# before match', color='b') ax2.set_xticks(np.arange(0, 78, step=1)) ax2.set_yticks(np.arange(0, 300, step=20)) ax2.set_xlabel("zones") ax2.set_ylabel("driver#") ax2.legend() plt.savefig(SAVE_PATH.format(time1)) plt.close() def showPerformanceMetrics(self): print("\n") print("The Number of Riders occured so far: ", self.__dispatcher.countCurrentTotalRiderNumber()) print("The Number of Drivers: ", self.__dispatcher.countTotalDriverNumber()) print("The Number of Cycles: ", self.__cycle) print( "***************************************************************") print("Driver Performace Metrics:") print("Average Revenue: ", round(self.__dispatcher.calcAverageProfitOfDrivers(), 2)) print("Average Trip Effort: ", round(self.__dispatcher.calcAverageTripEffortOfDrivers(), 2)) print( "Average Profit: ", round( self.__dispatcher.calcAverageProfitOfDrivers() - COST_PER_CYCLE * self.__dispatcher.calcAverageTripEffortOfDrivers(), 2)) print( "Average Utilization: ", round( (260 - self.__dispatcher.calcAverageIdleTimeOfDrivers()) / 260, 2)) print( "***************************************************************") print("Rider Performace Metrics:") print("Average Waiting Time (Cycles): ", round(self.__dispatcher.calcAverageWaitTimeOfRiders(), 2)) print("Average Detour Time (Cycles): ", round(self.__dispatcher.calcAverageDetourTimeOfRiders(), 2)) print("Average Fare: ", round(self.__dispatcher.calcAverageFareOfRiders(), 2)) print("Average Default Fare: ", round(self.__dispatcher.calcAverageDefaultFareRiders(), 2)) print( "***************************************************************") print("System Performace Metrics:") print( "Serving Rate: ", round( 1 - self.__dispatcher.countRiderNumberInCancelDict() / self.__dispatcher.countCurrentTotalRiderNumber(), 2)) total = self.__dispatcher.countRiderNumberInServeDict( ) + self.__dispatcher.countRiderNumberInFinishDict() print("Pooling Rate in 4: ", round(self.__dispatcher.grp_in_4 * 4 / total, 3)) print("Pooling Rate in 3: ", round(self.__dispatcher.grp_in_3 * 3 / total, 3)) print("Pooling Rate in 2: ", round(self.__dispatcher.grp_in_2 * 2 / total, 3)) print("Pooling Rate in 1: ", round(self.__dispatcher.grp_in_1 / total, 3)) print( "***************************************************************")