Ejemplo n.º 1
0
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(
            "***************************************************************")