Example #1
0
def evaluateNewIndividualFormat(individual):
    """ Evaluate an individual's fitness as a candidate timetable for the bus network.

    An individual's fitness is evaluated based on the waiting time for passengers requesting buses for the lines
    represented in the individual. Shorter waiting times on average mean better solutions. The algorithm works by by
    first sorting the individual by starting times, grouped by the bus  lines.

    Args:
        individual: an individual represented as [[lineID, Capacity, frequency, startTime]...]

    Return:
        a fitness score calculated as a cost to the bus company.
    """
    totalWaitingMinutes = []
    totalNumberRequests = []
    leftOver = []
    db = DB()
    # Order individual by starting slice time
    individual = sorted(individual, key=itemgetter(3))
    # Order individual by bus line
    individual = sorted(individual, key=itemgetter(0))
    # ------------------------------------------------------------
    # Evaluate average time based on requests & bus capacity
    # ------------------------------------------------------------
    # Get the starting time for the 1st slice
    firstSliceHr = datetime.datetime.combine(Fitness.yesterday, datetime.time(db.timeSliceArray[0][0], 0, 0))
    # Initialize initial trip time
    initialTripTime = firstSliceHr
    print individual
    for i in range(len(individual)):
        # phenotype = db.generatePhenotype(individual[i][0], individual[i][3])
        phenotype = db.generatePhenotype2(individual[i])
        initialCrew = 0
        leftOvers = 0
        # ------------------------------------------------------
        # Evaluate average time and capacity for each gene now
        # ------------------------------------------------------
        for j in range(len(phenotype)):
            for k in range(len(phenotype[j])):
                # Define parameters for the first search
                initialTrip = initialTripTime
                lastTrip = phenotype[j][k][1]
                # This is a restriction, so the search is not incoherent
                if initialTrip > lastTrip:
                    initialTrip = lastTrip - timedelta(minutes=individual[i][2])
                # Search on requests from people going in and out of the bus
                request = fitnessClass.searchRequest(initialTrip, lastTrip, phenotype[j][k][0], individual[i][0])
                requestOut = fitnessClass.searchRequestOut(initialTrip, lastTrip, phenotype[j][k][0], individual[i][0])
                # TODO: Replace the length by the sum of the number of requests
                # Calculate the number of people that is left on the bus
                initialCrew = initialCrew + (len(request) - len(requestOut))
                # Compare the crew against the capacity, if it is higher then the waiting time based on capacity is calculated
                if(initialCrew > individual[i][1]):
                    # People that did not make it !!
                    leftOvers = initialCrew - individual[i][1]
                    # Total waiting time is number of people left times waiting time in minutes
                    if i < len(phenotype[j])-1:
                        # Send next gene and bus stop
                        leftOversWaitTime = leftOvers * individual[i][2]
                    else:
                        # Heuristic, computation of this would result really expensive
                        leftOversWaitTime = leftOvers * db.minutesHour
                    leftOver.append([leftOvers,leftOversWaitTime])
                # Assign the last trip value to the initial trip
                initialTripTime = phenotype[j][k][1]
                if len(request) > 0:
                    waitingMinutes = 0
                    numberRequests = 0
                    for l in range(len(request)):
                        waitingTime = phenotype[j][k][1] - request[l]["_id"]["RequestTime"]
                        waitingMinutes = waitingMinutes + round(((waitingTime.total_seconds() % 3600) / databaseClass.minutesHour), 2)
                        numberRequests = numberRequests + int(request[l]["total"])
                    totalWaitingMinutes.append(waitingMinutes)
                    totalNumberRequests.append(numberRequests)
    # Summarize the results 
    # Initialize total variable
    totalLeftOverTime = 0
    #noOfLeftOvers = 0
    # Loop trough leftovers array
    for z in range(len(leftOver)):
        # Summarize the waiting time for all the leftovers in every bus stop
        totalLeftOverTime += leftOver[z][1]
        #noOfLeftOvers += leftOver[z][0]
    # Summarize the waiting times based on requests and based on capacity
    totalWaitingTime = sum(totalWaitingMinutes) + totalLeftOverTime
    #averageWaitingTime = totalWaitingTime / (sum(totalNumberRequests) + noOfLeftOvers)
    return fitnessClass.calculateCost(individual, totalWaitingTime, 0),