def move(self, currentTime, speed, showDetails=False):
        self.checkLocation(currentTime)

        # move
        if len(self.driver['ongoingRide']) == 0:
            remainingDis = speed
            while remainingDis > 0:
                # move random direction
                (x, y) = self.driver['location']
                possibleMoves = [
                    (x + min(self.gridWorldW - x, remainingDis), y),
                    (x - min(x - 0, remainingDis), y),
                    (x, y + min(self.gridWorldH - y, remainingDis)),
                    (x, y - min(y - 0, remainingDis))
                ]
                possibleMoves = [
                    move for move in possibleMoves
                    if move[0] >= 0 and move[0] < self.gridWorldW
                    and move[1] >= 0 and move[1] < self.gridWorldH
                    and gridWorldDistance(move, (x, y)) > 0
                ]
                newLoc = possibleMoves[randint(0, len(possibleMoves) - 1)]
                self.driver['location'] = newLoc
                remainingDis -= gridWorldDistance((x, y), newLoc)
        else:
            remainingDis = speed

            if len(self.route) == 0:
                self.updateRoute()

            # move to next point in route
            while remainingDis > 0 and len(self.route) > 0:
                (x_, y_) = self.route[0]
                (x, y) = self.driver['location']
                # always try to align x axis first
                if randint(0, 1) == 0:
                    if x < x_:
                        shif = min(remainingDis, x_ - x)
                        self.driver['location'] = (x + shif, y)
                    else:
                        shif = min(remainingDis, x - x_)
                        self.driver['location'] = (x - shif, y)
                else:
                    if y < y_:
                        shif = min(remainingDis, y_ - y)
                        self.driver['location'] = (x, y + shif)
                    else:
                        shif = min(remainingDis, y - y_)
                        self.driver['location'] = (x, y - shif)
                movedDis = gridWorldDistance(self.driver['location'], (x, y))
                remainingDis -= movedDis
                self.checkLocation(currentTime)
def generateRequetSeq(gridWorldW, gridWorldH, numOfSeq,
                      maxNumOfRequestsPerSeq):
    requestSeq = []
    reqId = 0

    for i in range(numOfSeq):
        requests = []
        startPoints = set()
        endPoints = set()
        # numOfRequests = randint(0, maxNumOfRequestsPerSeq)
        numOfRequests = maxNumOfRequestsPerSeq

        for _ in range(numOfRequests):
            while True:
                startX = randint(0, gridWorldW - 1)
                startY = randint(0, gridWorldH - 1)
                endX = randint(0, gridWorldW - 1)
                endY = randint(0, gridWorldH - 1)
                if (startX, startY) != (endX, endY) and \
                    (startX, startY) not in startPoints and \
                    (endX, endY) not in endPoints:
                    startPoints.add((startX, startY))
                    endPoints.add((endX, endY))
                    break
        startPoints = list(startPoints)
        endPoints = list(endPoints)
        startEndPoints = zip(startPoints, endPoints)
        avgDistance = 0
        for (startPoint, endPoint) in startEndPoints:
            requests.append({
                "id": str(reqId),
                "userId": str(reqId),
                "startLocation": startPoint,
                "endLocation": endPoint,
                "requestedDate": i,
                "isOnCar": False,
            })
            reqId += 1
            avgDistance += gridWorldDistance(startPoint, endPoint)
        requestSeq.append(requests)

    return requestSeq
 def _getStrictLineDistance(self, origin, destination):
     if self.useGridWorld:
         return gridWorldDistance(origin, destination)
     else:
         return haversineDistance(origin, destination)
Exemple #4
0
 def _getDistance(self, origin, destination):
     if self.useGridWorld:
         return gridWorldDistance(origin, destination)
     else:
         return getDistance(origin, destination)
    def startSimulator(self, benchmark=False):

        while True:
            # extract request from sequence
            if self.currentTime <= len(self.requestSeq):
                curIdx = self.currentTime - 1
                self.totalRequestCount += len(self.requestSeq[curIdx])
                for r in self.requestSeq[curIdx]:
                    r['isOnCar'] = False
                self.requests.extend(self.requestSeq[curIdx])

            # extract driver from sequence
            if self.currentTime <= len(self.driverLocSeq):
                curIdx = self.currentTime - 1
                self.totalDriverCount += len(self.driverLocSeq[curIdx])
                for loc in self.driverLocSeq[curIdx]:
                    self.drivers.append( Driver(finishedRequestsRef=self.finishedRequests, \
                    userId=self.nextDriverId, initialLocation=loc, \
                    capacity=self.capacity, gridWorldW=self.gridWorldW, gridWorldH=self.gridWorldH) )
                    self.nextDriverId += 1

            if (self.currentTime != 1 or benchmark) and (
                    self.currentTime % self.matchEngineTriggerInterval == 0
                    or benchmark) and len(
                        self.requests) > 0 and self.currentTime <= len(
                            self.requestSeq):
                numOfRequest = len(self.requests)
                drivers = [
                    d.getDriver() for d in self.drivers
                    if len(d.getDriver()['ongoingRide']) < 2
                ]

                # ******* start match********
                mappings, remainingRequests = self.matcher.match(
                    self.requests, drivers, self.currentTime)
                # ******* end match********

                self.requests = remainingRequests

                for (req, driver) in mappings:
                    req['matchedDate'] = self.currentTime
                    driverIdx = int(driver['userId'])
                    self.drivers[driverIdx].updateRoute()
                    self.drivers[driverIdx].matchedRide += 1

                # calc stat
                numOfOccupiedSeat = 0
                numOfCurrentTotalSeats = 0
                numOfSharedOngoingRide = 0
                numOfNonSharedOngoingRide = 0

                for driver in self.drivers:
                    ongoingRideLen = len(driver.driver['ongoingRide'])
                    if ongoingRideLen == 2:
                        numOfSharedOngoingRide += ongoingRideLen
                    if ongoingRideLen == 1:
                        numOfNonSharedOngoingRide += ongoingRideLen

                    numOfOccupiedSeat += len(driver.driver['ongoingRide'])
                    numOfCurrentTotalSeats += self.capacity

                # numOfEmptySeats = numOfCurrentTotalSeats - numOfOccupiedSeat
                if numOfCurrentTotalSeats > 0:
                    u = numOfOccupiedSeat / numOfCurrentTotalSeats
                    self.seatUtilization.append((self.currentTime, u))

                self.numOfRemainingRequests.append(
                    (self.currentTime, len(remainingRequests)))

                totalOngoingRide = numOfSharedOngoingRide + numOfNonSharedOngoingRide
                if totalOngoingRide > 0:
                    sharedRate = numOfSharedOngoingRide / totalOngoingRide
                    self.shareRates.append((self.currentTime, sharedRate))

                numOfMatchedReq = numOfRequest - len(remainingRequests)
                matchRate = numOfMatchedReq / numOfRequest
                if numOfRequest > 0:
                    self.matchingRates.append((self.currentTime, matchRate))

                if len(mappings) > 0:
                    print("[t=%d] match rate=%.3f, matched/unmatched/finished/total requests: %d/%d/%d/%d" % \
                        (self.currentTime, matchRate, len(mappings), len(remainingRequests),len(self.finishedRequests), self.totalRequestCount))

                else:
                    print("[t=%d] No match found. " % (self.currentTime))
                    print("\tmatch rate=%.3f, matched/unmatched/ongoing/finished/total requests: %d/%d/%d/%d" % \
                        (matchRate, len(mappings), len(remainingRequests), len(self.finishedRequests), self.totalRequestCount))

            # increment time
            self.currentTime += 1

            # move all drivers
            for d in self.drivers:
                d.move(self.currentTime, self.driverSpeed, self.showDetails)

            # detect if all ongoing ride ended
            if self.currentTime >= len(self.requestSeq):
                hasOngoingRideInProgress = False
                for driver in self.drivers:
                    if len(driver.driver['ongoingRide']) > 0:
                        hasOngoingRideInProgress = True
                if not hasOngoingRideInProgress:
                    break

        print('[t=%d] Finished all rides' % (self.currentTime))
        print('Num of finished/unmatched/total requests: %d/%d/%d' %
              (len(self.finishedRequests), len(
                  self.requests), self.totalRequestCount))

        totalWaitingTime = 0
        totalDelay = 0
        # calculate total delay and waiting time
        for req in self.finishedRequests:
            totalWaitingTime += req['startedRideDate'] - req['requestedDate']

            optimalTravelTime = gridWorldDistance(
                req['startLocation'], req['endLocation']) / self.driverSpeed
            actualTravelTime = req['finishedDate'] - req['requestedDate']
            totalDelay += actualTravelTime - optimalTravelTime

        for req in self.requests:
            totalWaitingTime += self.currentTime - req['requestedDate']
            totalDelay += self.currentTime - req['requestedDate']

        # print('Total waiting time   = %d'%(totalWaitingTime))
        # print('Total delay          = %d'%(totalDelay))
        # reqLen = len(self.finishedRequests)
        reqLen = len(self.finishedRequests) + len(self.requests)

        self.avgWaitingTime = totalWaitingTime / reqLen
        self.avgtotalDelay = totalDelay / reqLen
        print('Average waiting time = %.3f' % (self.avgWaitingTime))
        print('Average total delay = %.3f' % (self.avgtotalDelay))
def peakTrafficTime(unitOfTimeToGenerate, maxNumOfReqGeneratePerUnitTime,
                    totalDriver):
    '''
    Waiting time= T_pickup - T_request
    total travel delay = T_drop - T*_arrive
        where T*_arrive the earliest possible time at which the destination could be reached
    
    1 time unit ~ 6 seconds
    1 space unit ~ 1 meter
    '''
    gridWorldH = 1000  # 1km
    gridWorldW = 5000  # 5km
    totalRequests = unitOfTimeToGenerate * maxNumOfReqGeneratePerUnitTime
    numOfDriversChoices = [
        totalDriver,
        # totalRequests//20,
        # totalRequests//30,
    ]

    for numOfDrivers in numOfDriversChoices:

        # generate requests for all rounds
        requestSeq = generateRequetSeq(gridWorldW, gridWorldH,
                                       unitOfTimeToGenerate,
                                       maxNumOfReqGeneratePerUnitTime)

        # generate driver locations
        driverLocSeq = []
        for i in range(unitOfTimeToGenerate):
            if i == 0:
                dn = numOfDrivers
                driversLoc = []
                for _ in range(dn):
                    x = randint(0, gridWorldW - 1)
                    y = randint(0, gridWorldH - 1)
                    driversLoc.append((x, y))
                driverLocSeq.append(driversLoc)
            else:
                driverLocSeq.append([])

        # print stats

        totalRequest = totalRequests

        print()
        print('num of requsts =', totalRequest)
        print('num of drivers =', numOfDrivers)

        print()
        # calculate avg travel distance of requests
        startLocations = [
            req['startLocation'] for seq in requestSeq for req in seq
        ]
        endLocations = [
            req['endLocation'] for seq in requestSeq for req in seq
        ]
        avgTravelDis = 0
        for (s1, s2) in zip(startLocations, endLocations):
            avgTravelDis += gridWorldDistance(s1, s2)
        avgTravelDis /= len(driverLocSeq)
        print('Average travel distance of request:', avgTravelDis)

        # calculate avg distance of pairwise drivers' initial locations
        driversLocations = [loc for seq in driverLocSeq for loc in seq]
        driverInitLocationPairs = list(combinations(driversLocations, 2))
        locationAvgDistance = 0
        for (s1, s2) in driverInitLocationPairs:
            locationAvgDistance += gridWorldDistance(s1, s2)
        locationAvgDistance /= len(driverInitLocationPairs)
        print('Average distance of pairwise drivers\' locations:',
              locationAvgDistance)

        print()
        print('Start Greedy simulation')
        gridWorld_greedy = GridWorldSimulator(
            gridWorldW=gridWorldW,
            gridWorldH=gridWorldH,
            constraints_param={
                'maxMatchDistance': maxMatchDistance_,
            },
            requestSeq=requestSeq,
            driverLocSeq=driverLocSeq,
            driverSpeed=82,  # ~25 km/h
            capacity=2,
            matchEngineTriggerInterval=10,
            algo='greedy',
            showDetails=False)
        gridWorld_greedy.startSimulator()

        print()
        print('Start Dynamic simulation')
        gridWorld_dynamic = GridWorldSimulator(
            gridWorldW=gridWorldW,
            gridWorldH=gridWorldH,
            constraints_param={
                'maxMatchDistance': maxMatchDistance_,
                'maxCost': maxCost_
            },
            requestSeq=requestSeq,
            driverLocSeq=driverLocSeq,
            driverSpeed=82,  # ~50 km/h
            capacity=2,
            matchEngineTriggerInterval=10,
            algo='dynamic',
            showDetails=False)
        gridWorld_dynamic.startSimulator()

        # plot figure
        gs = gridspec.GridSpec(2, 2)

        ax = plt.subplot(gs[0, 0])
        ax.set_title('Matching Rate', fontsize=20)
        ax.set_xlabel('time', fontsize=18)
        ax.set_ylabel('# of matched requests / # of total requests',
                      fontsize=12)
        x = [x for (x, _) in gridWorld_greedy.matchingRates]
        y = [y for (_, y) in gridWorld_greedy.matchingRates]
        ax.plot(x, y, linestyle='-', label='greedy')
        x = [x for (x, _) in gridWorld_dynamic.matchingRates]
        y = [y for (_, y) in gridWorld_dynamic.matchingRates]
        ax.plot(x, y, linestyle='--', label='dynamic')
        ax.legend()

        ax = plt.subplot(gs[0, 1])
        ax.set_title('Ride Share Rate', fontsize=20)
        ax.set_xlabel('time', fontsize=18)
        ax.set_ylabel(
            '# of rides that share car with others / # of total rides',
            fontsize=12)
        x = [x for (x, _) in gridWorld_greedy.shareRates]
        y = [y for (_, y) in gridWorld_greedy.shareRates]
        ax.plot(x, y, linestyle='-', label='greedy')
        x = [x for (x, _) in gridWorld_dynamic.shareRates]
        y = [y for (_, y) in gridWorld_dynamic.shareRates]
        ax.plot(x, y, linestyle='--', label='dynamic')
        ax.legend()

        ax = plt.subplot(gs[1, 0])
        ax.set_title('Unhandled Requests', fontsize=20)
        ax.set_xlabel('time', fontsize=18)
        ax.set_ylabel('# of unhandled requests', fontsize=18)
        x = [x for (x, _) in gridWorld_greedy.numOfRemainingRequests]
        y = [y for (_, y) in gridWorld_greedy.numOfRemainingRequests]
        ax.plot(x, y, linestyle='-', label='greedy')
        x = [x for (x, _) in gridWorld_dynamic.numOfRemainingRequests]
        y = [y for (_, y) in gridWorld_dynamic.numOfRemainingRequests]
        ax.plot(x, y, linestyle='--', label='dynamic')
        ax.legend()

        ax = plt.subplot(gs[1, 1])
        numOfBarGroup = 2
        idex = np.arange(numOfBarGroup)
        bar_width = 0.35
        opacity = 0.8
        greedy_data = (gridWorld_greedy.avgWaitingTime,
                       gridWorld_greedy.avgtotalDelay)
        dynamic_data = (gridWorld_dynamic.avgWaitingTime,
                        gridWorld_dynamic.avgtotalDelay)
        rects1 = ax.bar(idex,
                        greedy_data,
                        bar_width,
                        alpha=opacity,
                        color='r',
                        label='Greedy')
        rects2 = ax.bar(idex + bar_width,
                        dynamic_data,
                        bar_width,
                        alpha=opacity,
                        color='b',
                        label='Dynamic')
        ax.set_ylabel('time unit', fontsize=18)
        ax.set_title('Delay', fontsize=20)
        ax.set_xticks(idex + bar_width / 2)
        ax.set_xticklabels(('avg waiting time', 'avg total delay'),
                           fontsize=14)
        ax.legend()

        fig = plt.gcf()
        fig.set_size_inches(15, 12)
        fig.suptitle('%d fix drivers / %d total ride requests' %
                     (numOfDrivers, totalRequest),
                     fontsize=26)
        timestr = time.strftime("%Y%m%d-%H%M%S")
        fig.savefig('simulationResult/%s_peak_%d_%d.png' %
                    (timestr, numOfDrivers, totalRequest))
def benchmark(numOfReqToGenAtFirst):
    '''
    Waiting time= T_pickup - T_request
    total travel delay = T_drop - T*_arrive
        where T*_arrive the earliest possible time at which the destination could be reached
    
    1 time unit ~ 6 seconds
    1 space unit ~ 1 meter
    '''
    gridWorldH = 1000  # 1km
    gridWorldW = 5000  # 5km
    totalRequests = numOfReqToGenAtFirst
    numOfDriversChoices = [
        (numOfReqToGenAtFirst) // 2,
        (numOfReqToGenAtFirst) // 4,
        (numOfReqToGenAtFirst) // 6,
    ]

    greedySimulators = []
    dynamicSimulators = []

    for numOfDrivers in numOfDriversChoices:

        # generate requests for all rounds
        requestSeq = generateRequetSeq(gridWorldW, gridWorldH, 1,
                                       numOfReqToGenAtFirst)

        # generate driver locations
        driverLocSeq = []
        for i in range(1):
            dn = numOfDrivers
            driversLoc = []
            for _ in range(dn):
                x = randint(0, gridWorldW - 1)
                y = randint(0, gridWorldH - 1)
                driversLoc.append((x, y))
            driverLocSeq.append(driversLoc)

        # print stats

        totalRequest = 0
        for seq in requestSeq:
            totalRequest += len(seq)

        print()
        print('num of requsts =', totalRequest)
        print('num of drivers =', numOfDrivers)

        print()
        print('Start Greedy simulation')
        gridWorld_greedy = GridWorldSimulator(
            gridWorldW=gridWorldW,
            gridWorldH=gridWorldH,
            constraints_param={
                'maxMatchDistance': maxMatchDistance_,
            },
            requestSeq=requestSeq,
            driverLocSeq=driverLocSeq,
            driverSpeed=82,  # ~25 km/h
            capacity=2,
            matchEngineTriggerInterval=10,
            algo='greedy',
            showDetails=False)
        gridWorld_greedy.startSimulator(benchmark=True)

        print()
        print('Start Dynamic simulation')
        gridWorld_dynamic = GridWorldSimulator(
            gridWorldW=gridWorldW,
            gridWorldH=gridWorldH,
            constraints_param={
                'maxMatchDistance': maxMatchDistance_,
                'maxCost': maxCost_
            },
            requestSeq=requestSeq,
            driverLocSeq=driverLocSeq,
            driverSpeed=82,  # ~50 km/h
            capacity=2,
            matchEngineTriggerInterval=10,
            algo='dynamic',
            showDetails=False)
        gridWorld_dynamic.startSimulator(benchmark=True)

        print()
        # calculate avg travel distance of requests
        startLocations = [
            req['startLocation'] for seq in requestSeq for req in seq
        ]
        endLocations = [
            req['endLocation'] for seq in requestSeq for req in seq
        ]
        avgTravelDis = 0
        for (s1, s2) in zip(startLocations, endLocations):
            avgTravelDis += gridWorldDistance(s1, s2)
        avgTravelDis /= len(driverLocSeq)
        print('Average travel distance of request:', avgTravelDis)

        # calculate avg distance of pairwise drivers' initial locations
        driversLocations = [loc for seq in driverLocSeq for loc in seq]
        driverInitLocationPairs = list(combinations(driversLocations, 2))
        locationAvgDistance = 0
        for (s1, s2) in driverInitLocationPairs:
            locationAvgDistance += gridWorldDistance(s1, s2)
        locationAvgDistance /= len(driverInitLocationPairs)
        print('Average distance of pairwise drivers\' locations:',
              locationAvgDistance)

        greedySimulators.append(gridWorld_greedy)
        dynamicSimulators.append(gridWorld_dynamic)

    labels = (
        '1:2\n(%d:%d)' % (totalRequests // 2, totalRequests),
        '1:4\n(%d:%d)' % (totalRequests // 4, totalRequests),
        '1:6\n(%d:%d)' % (totalRequests // 6, totalRequests),
    )

    # plot figure
    gs = gridspec.GridSpec(1, 2)

    ax = plt.subplot(gs[0, 0])
    numOfBarGroup = 3
    idex = np.arange(numOfBarGroup)
    bar_width = 0.35
    opacity = 0.8
    data_1 = tuple([len(sim.requests) for sim in greedySimulators])
    data_2 = tuple([len(sim.requests) for sim in dynamicSimulators])
    rects1 = ax.bar(idex,
                    data_1,
                    bar_width,
                    alpha=opacity,
                    color='c',
                    label='Greedy')
    rects2 = ax.bar(idex + bar_width,
                    data_2,
                    bar_width,
                    alpha=opacity,
                    color='y',
                    label='Dynamic')
    ax.set_ylabel('# of requests', fontsize=18)
    ax.set_title('Unhandled Requests', fontsize=20)
    ax.set_xticks(idex + bar_width / 2)
    ax.set_xticklabels(labels, fontsize=18)
    ax.legend()

    ax = plt.subplot(gs[0, 1])
    numOfBarGroup = 3
    idex = np.arange(numOfBarGroup)
    bar_width = 0.35
    opacity = 0.8
    data_1 = tuple([sim.avgtotalDelay for sim in greedySimulators])
    data_2 = tuple([sim.avgtotalDelay for sim in dynamicSimulators])
    rects1 = ax.bar(idex,
                    data_1,
                    bar_width,
                    alpha=opacity,
                    color='r',
                    label='Greedy')
    rects2 = ax.bar(idex + bar_width,
                    data_2,
                    bar_width,
                    alpha=opacity,
                    color='b',
                    label='Dynamic')
    ax.set_ylabel('time unit', fontsize=16)
    ax.set_title('Total Delay', fontsize=20)
    ax.set_xticks(idex + bar_width / 2)
    ax.set_xticklabels(labels, fontsize=18)
    ax.legend()

    fig = plt.gcf()
    fig.set_size_inches(24, 12)
    fig.suptitle('Performance of different driver-request ratio', fontsize=26)
    timestr = time.strftime("%Y%m%d-%H%M%S")
    fig.savefig('simulationResult/%s_benchmark_%drequest_.png' %
                (timestr, totalRequests))
    fig.clear()