class Driver: timestamp = -1 def __init__(self, id, pCurr): # logger in Dispatcher self.__logger = Logger('Driver') #self.__logger.setLevel(logging.DEBUG) self.__logger.info(Driver.timestamp, "__INIT__", None, None, "Create A Driver Object") self.__id = id self.__pos = pCurr self.__status = IDLE self.__riders = {} self.__trip_route = [] self.__trip_effort = 0 self.__trip_profit = 0 self.__idle_time = 0 self.__finish_trip_time = -1 def __str__(self): ret = "{" + str(self.__id) + ", " + str(self.__pos) + ", " + str( self.__status) + ", " + str(self.__trip_effort) + ", " ret = ret + str(self.__trip_profit) + ", " ret = ret + "Riders: " + self.showRidersOnBoard() + ", " ret = ret + "Route: " + self.showTripRoute() + "}" return ret def showRidersOnBoard(self): ret = "[" if len(self.__riders): for rider_id in OrderedDict( sorted(self.__riders.items(), key=lambda t: t[0])).keys(): ret = ret + rider_id + ", " ret = ret[0:len(ret) - 2] + "]" else: ret = ret + "]" return ret def showTripRoute(self): ret = "[" if len(self.__trip_route): for elem in self.__trip_route: ret = ret + str(elem.getZoneID()) + ", " ret = ret[0:len(ret) - 2] + "]" else: ret = ret + "]" return ret def getID(self): return self.__id def setRiders(self, riders): for rider_id, rider in riders.items(): self.__riders[rider_id] = rider def getRider(self, id): if id in self.__riders.keys(): return self.__riders[id] else: self.__logger.error(Driver.timestamp, "getRider", self.getID(), id, "Rider not in vehicle.") raise Exception("Rider not in vehicle.") def removeRider(self, id): if id in self.__riders.keys(): del self.__riders[id] else: self.__logger.error(Driver.timestamp, "removeRider", self.getID(), id, "Rider not in vehicle.") raise Exception("Rider not in vehicle.") def calcTripRoute(self): if len(self.__trip_route) == 0: route_strategy = RoutingInDistance(self.__riders, self.__trip_route) route_strategy.planRoute() else: self.__logger.error(Driver.timestamp, "calcTripRoute", self.getID(), None, "Trip route is empty.") raise Exception("Trip route is empty.") def popTripRoute(self): if len(self.__trip_route) > 0: return self.__trip_route.pop(0) else: self.__logger.error(Driver.timestamp, "popTripRoute", self.getID(), None, "Nothing to be poped.") raise Exception("Nothing to be poped.") def getTripRoute(self): return self.__trip_route #must calc route first def calcTripEffort(self): trip_time = 0 trip_effort = 0 pos = self.getPos() for elem in self.__trip_route: if Graph.queryTravelCost(pos, elem.getZoneID()) != 0: trip_effort = trip_effort + Graph.queryTravelCost( pos, elem.getZoneID()) else: trip_effort += 0.5 trip_time = trip_time + Graph.queryTravelCost( pos, elem.getZoneID()) elem.setEventTime(Driver.timestamp + trip_time) if elem.getEvent() == DROPOFF: rider = self.__riders[elem.getRiderID()] rider.setArrivalTimestamp(Driver.timestamp + trip_time) rider.calcDetourTime( trip_time ) #detour time is b/w the rerquest accepted and arrive at destination. pos = elem.getZoneID() if trip_effort < 0: self.__logger.warning(Driver.timestamp, "calcTripEffort", self.getID(), None, "Trip effort value is unresonable ") raise Exception("Trip effort value is unresonable ") else: self.__trip_effort += trip_effort def tickTripEffort(self): self.__trip_effort += 1 def getTripEffort(self): return self.__trip_effort def notifyRiderPrice(self): shared_number = len(self.__riders) for rider in self.__riders.values(): rider.calcPrice(shared_number) #must calc route effort and rider price first def calcTripProfit(self): trip_revenue = 0 if len(self.__riders) > 0: for rider in self.__riders.values(): if rider.getPrice() is not math.inf: trip_revenue += rider.getPrice() else: self.__logger.error(Driver.timestamp, "calcTripEffort", self.getID(), None, "Price value is unresonable ") raise Exception("Price value is unresonable ") self.__trip_profit += trip_revenue else: self.__logger.error(Driver.timestamp, "calcTripEffort", self.getID(), None, "No riders in vehicle.") raise Exception("No riders in vehicle.") def getTripProfit(self): return self.__trip_profit def setPos(self, zid): self.__pos = zid def getPos(self): return self.__pos def setStatus(self, status): self.__status = status def getStatus(self): return self.__status def tickIdleTime(self): self.__idle_time += 1 def getIdleTime(self): return self.__idle_time def setFinishTripTime(self, time): self.__finish_trip_time = time def getFinishTripTime(self): return self.__finish_trip_time
class Rider: timestamp = -1 def __init__(self, uID, sT, sZ, dZ, dP, pat, srcX, srcY, destX, destY): # logger in Dispatcher self.__logger = Logger('Rider') #self.__logger.setLevel(logging.DEBUG) self.__logger.info(Rider.timestamp, "__INIT__", None, None, "Create A Rider Object") self.__id = uID self.__request_timestamp = sT self.__srcZone = sZ self.__destZone = dZ self.__default_price = dP self.__price = math.inf self.__patience = pat self.__dirID = self.__assignDirID(srcX, srcY, destX, destY) self.__shortest_time = Graph.queryTravelCost(sZ, dZ) self.__arrival_timestamp = None self.__groupID = None self.__status = WAITING self.__wait_time = 0 self.__detour_time = -1 self.__sat = 0 if self.__default_price > 100: self.__logger.warning(Rider.timestamp, "__INIT__", None, self.getID(), str(self)) def __str__(self): ret = "{" + str(self.__id) + ', ' + str(self.__request_timestamp) + ", " + str(self.__srcZone) + ", " + str(self.__destZone) + ", " + \ str(self.__default_price) + ", " + str(self.__price) + ", " + str(self.__patience) + ", " + str(self.__dirID) +", " + \ str(self.__shortest_time) + ", " + str(self.__arrival_timestamp) + ", " + str(self.__groupID) + ", " +\ str(self.__status) + ", " + str(self.__wait_time) + ", " + str(self.__detour_time) + ", " + str(self.__sat) + "}" return ret #https://stackoverflow.com/questions/13226038/calculating-angle-between-two-vectors-in-python #The range is [-180, 180) def __calcDirection(self, srcX, srcY, destX, destY): p1 = [srcX, srcY] p0 = [destX, destY] p2 = p1 + np.array([1, 0]) v0 = np.array(p0) - np.array(p1) v1 = np.array(p2) - np.array(p1) angle = np.math.atan2(np.linalg.det([v0, v1]), np.dot(v0, v1)) return np.degrees(angle)*(-1) #Tansfer from [-180,180) to [0,360). #calculate DirID by dividing the DIR_THRESHOLD def __assignDirID(self, srcX, srcY, destX, destY): dir = self.__calcDirection(srcX, srcY, destX, destY) return int((dir+180)/DIR_THRESHOLD) def setDirID(self, dir): self.__dirID = dir def getDirID(self): return self.__dirID def setGroupID(self, grpID): self.__groupID = grpID def getGroupID(self): return self.__groupID def tickWaitTime(self): self.__wait_time += 1 def getWaitTime(self): return self.__wait_time def getShortestTime(self): return self.__shortest_time def calcDetourTime(self, time): self.__detour_time = time - self.__shortest_time def getDetourTime(self): return self.__detour_time def setArrivalTimestamp(self, time): self.__arrival_timestamp = time def getArrivalTimestamp(self): return self.__arrival_timestamp #prerequest: calc detour time first def calcPrice(self, n_shared): if self.__detour_time < 0: self.__logger.error(Rider.timestamp, "calcPrice", None, self.getID(), "Detour time is unreasonable.") raise Exception("Detour time is unreasonable.") self.__price = self.__default_price * math.exp(DETOUR_WEIGH * -self.__detour_time) if n_shared == 1: self.__price = self.__price * DISCOUNT_1 elif n_shared == 2: self.__price = self.__price * DISCOUNT_2 elif n_shared == 3: self.__price = self.__price * DISCOUNT_3 elif n_shared == 4: self.__price = self.__price * DISCOUNT_4 else: self.__logger.error(Rider.timestamp, "calcPrice", None, self.getID(), "Shared number is incorret.") raise Exception("Shared number is incorret.") def getPrice(self): return self.__price def getDefaultPrice(self): return self.__default_price def calcSat(self): if self.__detour_time < 0: self.__logger.error(Rider.timestamp, "calcSat", None, self.getID(), "Detour time is unreasonable.") raise Exception("Detour time is unreasonable.") elif self.__price > self.__default_price: self.__logger.error(Rider.timestamp, "calcSat", None, self.getID(), "Price is unreasonable.") raise Exception("Price is unreasonable.") else: self.__sat = (self.__default_price-self.__price)*SAT_PRICE - math.expm1(self.__detour_time) if self.__sat > 10000000: self.__logger.warning(Rider.timestamp, "calcPrice", None, self.getID(), "SAT is too large", str(self)) def getSat(self): return self.__sat def getID(self): return self.__id def getRequestTimeStamp(self): return self.__request_timestamp def getSrcZone(self): return self.__srcZone def getDestZone(self): return self.__destZone def getPatience(self): return self.__patience def setStatus(self, status): self.__status = status def getStatus(self): return self.__status
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())