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