1.4. The Traveling Salesman#

“Given a list of cities and the distances between each pair of the cities, find the shortest possible path that goes through all the cities, and returns to the starting city.”

1.4.1. Resources#

1.4.2. Activity Building the Traveling Salesman Problem#

1.4.2.1. Problem#

Note

  1. Create a class named TravelingSalesmanProblem that will have the following methods:

    • def __init__(self, name): Creates Instances

    • def __len__(self): Returns the length of the number of cities.

    • def __createData(self): Creates the data from the file.

    • def getTotalDistance(self, indices): Returns the total distance of the path.

    • def plotData(self, indices): Plots the data.

Test it with the following:

tsp = TravelingSalesmanProblem("bayg29")

# generate a random solution and evaluate it:
#randomSolution = random.sample(range(len(tsp)), len(tsp))

# see http://elib.zib.de/pub/mp-testdata/tsp/tsplib/tsp/bayg29.opt.tour
optimalSolution = [0, 27, 5, 11, 8, 25, 2, 28, 4, 20, 1, 19, 9, 3, 14, 17, 13, 16, 21, 10, 18, 24, 6, 22, 7, 26, 15, 12, 23]

print("Problem name: " + tsp.name)
print("Optimal solution = ", optimalSolution)
print("Optimal distance = ", tsp.getTotalDistance(optimalSolution))

# plot the solution:
plot = tsp.plotData(optimalSolution)
plot.show()

It should print the following:

Problem name: bayg29
Optimal solution =  [0, 27, 5, 11, 8, 25, 2, 28, 4, 20, 1, 19, 9, 3, 14, 17, 13, 16, 21, 10, 18, 24, 6, 22, 7, 26, 15, 12, 23]
Optimal distance =  9074.147

1.4.2.2. Solution#

import csv
import pickle
import os
import codecs

import numpy as np

from urllib.request import urlopen

import matplotlib.pyplot as plt
class TravelingSalesmanProblem:
    """This class encapsulates the Traveling Salesman Problem.
    City coordinates are read from an online file and distance matrix is calculated.
    The data is serialized to disk.
    The total distance can be calculated for a path represented by a list of city indices.
    A plot can be created for a path represented by a list of city indices.

    :param name: The name of the corresponding TSPLIB problem, e.g. 'burma14' or 'bayg29'.
    """

    def __init__(self, name):
        """
        Creates an instance of a TSP

        :param name: name of the TSP problem
        """

        # initialize instance variables:
        self.name = name
        self.locations = []
        self.distances = []
        self.tspSize = 0

        # initialize the data:
        self.__initData()

    def __len__(self):
        """
        returns the length of the underlying TSP
        :return: the length of the underlying TSP (number of cities)
        """
        return self.tspSize

    def __initData(self):
        """Reads the serialized data, and if not available - calls __create_data() to prepare it
        """

        # attempt to read serialized data:
        try:
            self.locations = pickle.load(open(os.path.join("tsp-data", self.name + "-loc.pickle"), "rb"))
            self.distances = pickle.load(open(os.path.join("tsp-data", self.name + "-dist.pickle"), "rb"))
        except (OSError, IOError):
            pass

        # serailized data not found - create the data from scratch:
        if not self.locations or not self.distances:
            self.__createData()

        # set the problem 'size':
        self.tspSize = len(self.locations)

    def __createData(self):
        """Reads the desired TSP file from the Internet, extracts the city coordinates, calculates the distances
        between every two cities and uses them to populate a distance matrix (two-dimensional array).
        It then serializes the city locations and the calculated distances to disk using the pickle utility.
        """
        self.locations = []

        # print("http://elib.zib.de/pub/mp-testdata/tsp/tsplib/tsp/" + self.name + ".tsp")
        
        # Use the following instead: https://raw.githubusercontent.com/mastqe/tsplib/master/a280.tsp
        URL = "https://raw.githubusercontent.com/mastqe/tsplib/master/"
        print(URL + self.name + ".tsp")
        # open whitespace-delimited file from url and read lines from it:
        with urlopen(URL + self.name + ".tsp") as f:
            reader = csv.reader(codecs.iterdecode(f, 'utf-8'), delimiter=" ", skipinitialspace=True)

            # skip lines until one of these lines is found:
            for row in reader:
                if row[0] in ('DISPLAY_DATA_SECTION', 'NODE_COORD_SECTION'):
                    break

            # read data lines until 'EOF' found:
            for row in reader:
                if row[0] != 'EOF':
                    # remove index at beginning of line:
                    del row[0]

                    # convert x,y coordinates to ndarray:
                    self.locations.append(np.asarray(row, dtype=np.float32))
                else:
                    break

            # set the problem 'size':
            self.tspSize = len(self.locations)

            # print data:
            print("length = {}, locations = {}".format(self.tspSize, self.locations))

            # initialize distance matrix by filling it with 0's:
            self.distances = [[0] * self.tspSize for _ in range(self.tspSize)]

            # populate the distance matrix with calculated distances:
            for i in range(self.tspSize):
                for j in range(i + 1, self.tspSize):
                    # calculate euclidean distance between two ndarrays:
                    distance = np.linalg.norm(self.locations[j] - self.locations[i])
                    self.distances[i][j] = distance
                    self.distances[j][i] = distance
                    print("{}, {}: location1 = {}, location2 = {} => distance = {}".format(i, j, self.locations[i], self.locations[j], distance))

            # serialize locations and distances:
            if not os.path.exists("tsp-data"):
                os.makedirs("tsp-data")
            pickle.dump(self.locations, open(os.path.join("tsp-data", self.name + "-loc.pickle"), "wb"))
            pickle.dump(self.distances, open(os.path.join("tsp-data", self.name + "-dist.pickle"), "wb"))

    def getTotalDistance(self, indices):
        """Calculates the total distance of the path described by the given indices of the cities

        :param indices: A list of ordered city indices describing the given path.
        :return: total distance of the path described by the given indices
        """
        # distance between th elast and first city:
        distance = self.distances[indices[-1]][indices[0]]

        # add the distance between each pair of consequtive cities:
        for i in range(len(indices) - 1):
            distance += self.distances[indices[i]][indices[i + 1]]

        return distance

    def plotData(self, indices):
        """plots the path described by the given indices of the cities

        :param indices: A list of ordered city indices describing the given path.
        :return: the resulting plot
        """

        # plot the dots representing the cities:
        plt.scatter(*zip(*self.locations), marker='.', color='red')

        # create a list of the corresponding city locations:
        locs = [self.locations[i] for i in indices]
        locs.append(locs[0])

        # plot a line between each pair of consequtive cities:
        plt.plot(*zip(*locs), linestyle='-', color='blue')

        return plt
tsp = TravelingSalesmanProblem("bayg29")

# generate a random solution and evaluate it:
#randomSolution = random.sample(range(len(tsp)), len(tsp))

# see http://elib.zib.de/pub/mp-testdata/tsp/tsplib/tsp/bayg29.opt.tour
optimalSolution = [0, 27, 5, 11, 8, 25, 2, 28, 4, 20, 1, 19, 9, 3, 14, 17, 13, 16, 21, 10, 18, 24, 6, 22, 7, 26, 15, 12, 23]

print("Problem name: " + tsp.name)
print("Optimal solution = ", optimalSolution)
print("Optimal distance = ", tsp.getTotalDistance(optimalSolution))

# plot the solution:
plot = tsp.plotData(optimalSolution)
plot.show()
Problem name: bayg29
Optimal solution =  [0, 27, 5, 11, 8, 25, 2, 28, 4, 20, 1, 19, 9, 3, 14, 17, 13, 16, 21, 10, 18, 24, 6, 22, 7, 26, 15, 12, 23]
Optimal distance =  9074.147
../_images/7dfa7aaa0b60685fe947c4e1c2ebeafad655934cb29b285cc874294081fe4bf8.png

1.4.3. Solving TSP Using DEAP Framework#

1.4.3.1. Problem#

Now you will use the Deap framework to evaluate and find the best solutions. Use the following parameters:

  • POPULATION SIZE = 300

  • NUMBER OF GENERATIONS = 100

  • HALL_OF_FAME_SIZE = 1

  • Probability of crossover = 0.9

  • Probability of mutation = 0.1

  • Which is the idea fitness strategy?

  • Create a class of individual, whichuses the min fitness class as a fitness calculation.

  • Register an operator named randomOrder that generates a random permutation of the cities.

  • Register an operator named individualCreator which responsability is to use individual and randomOrder tool.

  • Create a populationCreator that generates the list of individuals

  • Make the evaluation as the total distance of the path.

  • Use tournament selection with a tournament size of 3.

  • Use cxOrdered crossover and mutationShuffleIndexes mutation.

Note

deap.tools.mutShuffleIndexes(individual, indpb)[source]

Shuffle the attributes of the input individual and return the mutant. The individual is expected to be a sequence. The indpb argument is the probability of each attribute to be moved. Usually this mutation is applied on vector of indices.

deap.tools.cxOrdered(ind1, ind2)[source]

Executes an ordered crossover (OX) on the input individuals. The two individuals are modified in place. This crossover expects sequence individuals of indices, the result for any other type of individuals is unpredictable.

More Operators:

1.4.3.2. Solution#

from deap import base
from deap import creator
from deap import tools
from deap import algorithms

import random
import array

import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
# set the random seed for repeatable results
RANDOM_SEED = 42
random.seed(RANDOM_SEED)

# create the desired traveling salesman problem instace:
TSP_NAME = "bayg29"  # name of problem
tsp = TravelingSalesmanProblem(TSP_NAME)

# Genetic Algorithm constants:
POPULATION_SIZE = 300
MAX_GENERATIONS = 200
HALL_OF_FAME_SIZE = 1
P_CROSSOVER = 0.9  # probability for crossover
P_MUTATION = 0.1   # probability for mutating an individual

toolbox = base.Toolbox()
# define a single objective, minimizing fitness strategy:
creator.create("FitnessMin", base.Fitness, weights=(-1.0,))

# create the Individual class based on list of integers:
creator.create("Individual", array.array, typecode='i', fitness=creator.FitnessMin)

# create an operator that generates randomly shuffled indices:
toolbox.register("randomOrder", random.sample, range(len(tsp)), len(tsp))

# create the individual creation operator to fill up an Individual instance with shuffled indices:
toolbox.register("individualCreator", tools.initIterate, creator.Individual, toolbox.randomOrder)

# create the population creation operator to generate a list of individuals:
toolbox.register("populationCreator", tools.initRepeat, list, toolbox.individualCreator)
# Calculating The Distance as the TSP Distance.


# fitness calculation - compute the total distance of the list of cities represented by indices:
def tpsDistance(individual):
    return tsp.getTotalDistance(individual),  # return a tuple



toolbox.register("evaluate", tpsDistance)

# Genetic operators:
toolbox.register("select", tools.selTournament, tournsize=3)
toolbox.register("mate", tools.cxOrdered)
toolbox.register("mutate", tools.mutShuffleIndexes, indpb=1.0/len(tsp))
# create initial population (generation 0):
population = toolbox.populationCreator(n=POPULATION_SIZE)

# prepare the statistics object:
stats = tools.Statistics(lambda ind: ind.fitness.values)
stats.register("min", np.min)
stats.register("avg", np.mean)
# define the hall-of-fame object:
hof = tools.HallOfFame(HALL_OF_FAME_SIZE)
# perform the Genetic Algorithm flow with hof feature added:
population, logbook = algorithms.eaSimple(population, toolbox, cxpb=P_CROSSOVER, mutpb=P_MUTATION,
                                            ngen=MAX_GENERATIONS, stats=stats, halloffame=hof, verbose=True)

# print best individual info:
best = hof.items[0]
print("-- Best Ever Individual = ", best)
print("-- Best Ever Fitness = ", best.fitness.values[0])
gen	nevals	min    	avg  
0  	300   	21103.3	26457
1  	279   	19562.4	25128.9
2  	275   	19456.5	24267.3
3  	279   	19760.9	23592  
4  	278   	19406.4	22963.5
5  	276   	19105.2	22480.7
6  	281   	17802.4	22129.9
7  	279   	18160.2	21581.5
8  	274   	17691.3	21253.6
9  	277   	16011.9	20877.8
10 	268   	16011.9	20597.9
11 	279   	15878.8	20413.2
12 	269   	14589.1	20188.2
13 	272   	14589.1	19987.8
14 	281   	15182.9	19910.4
15 	276   	15836.2	19437  
16 	276   	15687.4	19117.2
17 	282   	15426.5	19039.4
18 	282   	14905.2	18696.7
19 	269   	15020.4	18614.9
20 	275   	13346.3	18424  
21 	276   	14711.4	18330.1
22 	275   	13139.1	18312  
23 	274   	13139.1	18005  
24 	278   	13002.5	17725.6
25 	262   	12203.5	17543.2
26 	274   	13157.3	17285.2
27 	260   	12918.6	16946.3
28 	271   	12918.6	16646  
29 	262   	12918.6	16441  
30 	279   	12652.9	16194.2
31 	265   	12652.9	15910.6
32 	278   	12565.6	15942.4
33 	278   	12520.5	15682  
34 	283   	12436.1	15569.5
35 	272   	12214  	15441.9
36 	265   	12278.3	15353.6
37 	271   	12302.9	15371.8
38 	273   	12037.5	15182  
39 	271   	11969.4	14974.3
40 	267   	12081.2	14825  
41 	266   	11785.8	14612.3
42 	282   	11477  	14591.8
43 	269   	10869.8	14446  
44 	270   	11475  	14452.8
45 	277   	11796.8	14491.9
46 	277   	11262.8	14324.7
47 	277   	11333.1	14183.2
48 	281   	11311  	14135.4
49 	271   	10921.8	14212.2
50 	274   	11172.8	14137.9
51 	279   	11295.1	13945  
52 	280   	10870.6	14044.3
53 	278   	11225.2	14167.9
54 	270   	11336.3	13993.6
55 	268   	10472.9	13886.4
56 	285   	10637.9	13841.5
57 	285   	10885.9	13732.8
58 	273   	10885.9	13634.4
59 	277   	10885.9	13478.8
60 	265   	10835.7	13253.8
61 	264   	10526.5	13286.8
62 	268   	10445.5	12951.3
63 	276   	10501.6	12833.3
64 	267   	10484.8	12683.7
65 	280   	10501.6	12505  
66 	277   	10355.2	12469.2
67 	268   	10231.6	12586.4
68 	273   	10367.5	12436.2
69 	281   	10355.2	12450.7
70 	274   	10281.8	12607.8
71 	261   	10281.8	12339.2
72 	269   	10163.3	12328.2
73 	276   	10048.3	12238.8
74 	272   	10048.3	12162.9
75 	270   	10029.8	12178.7
76 	273   	9957.92	12117  
77 	272   	9957.92	12131.7
78 	276   	9852.51	11973.6
79 	273   	9852.51	11883.2
80 	268   	9775.74	11853.7
81 	288   	9775.74	11715.1
82 	276   	9775.74	11806.3
83 	276   	9775.74	11826.1
84 	268   	9775.74	11618.9
85 	271   	9775.74	11430.3
86 	265   	9775.74	11586.3
87 	269   	9775.74	11394.7
88 	259   	9775.74	11172.9
89 	275   	9775.74	11210.5
90 	275   	9775.74	11081.7
91 	272   	9775.74	11051.4
92 	277   	9775.74	11065  
93 	274   	9775.74	11113.7
94 	276   	9775.74	11010  
95 	272   	9775.74	10886.1
96 	272   	9771.1 	10758.8
97 	267   	9771.1 	10639.7
98 	279   	9771.1 	10681.8
99 	262   	9771.1 	10511.1
100	279   	9771.1 	10403.5
101	284   	9771.1 	10424.7
102	275   	9767.79	10432.8
103	266   	9767.79	10418  
104	272   	9767.79	10264.2
105	285   	9767.79	10185.9
106	277   	9767.79	10167.7
107	279   	9767.79	10131.7
108	269   	9763.16	10109.5
109	273   	9734.57	10126.7
110	282   	9729.93	10360.6
111	268   	9729.93	10356.4
112	272   	9729.93	10529.1
113	271   	9729.93	10511.3
114	275   	9729.93	10510.6
115	270   	9729.93	10166.8
116	280   	9729.93	10064.7
117	257   	9729.93	9985.98
118	273   	9729.93	9935.52
119	281   	9729.93	9893.57
120	268   	9729.93	9936.33
121	282   	9729.93	10072.7
122	285   	9729.93	9927.8 
123	270   	9729.93	9995.76
124	266   	9729.93	9932.75
125	274   	9729.93	9938.32
126	284   	9729.93	9972.79
127	263   	9616.16	9979.21
128	275   	9616.16	9910.33
129	277   	9616.16	9975.06
130	272   	9616.16	10001.9
131	279   	9616.16	9999.09
132	284   	9616.16	9969.31
133	271   	9616.16	9917.73
134	262   	9616.16	9953.55
135	273   	9616.16	9877.65
136	266   	9616.16	9874.04
137	256   	9616.16	9737.42
138	274   	9616.16	9825.19
139	272   	9616.16	9901.44
140	269   	9616.16	9846.18
141	266   	9558.06	9843.06
142	263   	9558.06	9804.26
143	261   	9558.06	9871.85
144	279   	9558.06	9829.84
145	273   	9558.06	9939.57
146	268   	9558.06	9771.86
147	278   	9558.06	9779.87
148	278   	9556.72	9787.78
149	281   	9549.99	9779   
150	272   	9549.99	9803.48
151	278   	9549.99	9809.74
152	270   	9549.99	9780.88
153	271   	9549.99	9686.82
154	269   	9549.99	9880.91
155	265   	9549.99	9899.8 
156	282   	9549.99	9978.31
157	277   	9549.99	9823.43
158	273   	9549.99	10009.3
159	279   	9549.99	9954.48
160	273   	9549.99	9980.84
161	273   	9549.99	9985.32
162	282   	9549.99	9923.51
163	284   	9549.99	9981.25
164	273   	9549.99	10222.2
165	263   	9549.99	10151  
166	271   	9549.99	10154.6
167	279   	9549.99	10073.1
168	267   	9549.99	9895.51
169	277   	9549.99	9781.48
170	270   	9549.99	9840.1 
171	273   	9549.99	9744.42
172	273   	9549.99	9811.11
173	277   	9549.99	9792.8 
174	284   	9549.99	9860.57
175	273   	9549.99	9668.35
176	266   	9549.99	9705.16
177	275   	9549.99	9800.14
178	270   	9549.99	9751.82
179	281   	9549.99	9816.48
180	269   	9549.99	9743.48
181	280   	9549.99	9715.93
182	278   	9549.99	9792.3 
183	280   	9549.99	9716.09
184	290   	9549.99	9811.45
185	281   	9549.99	9758.04
186	269   	9549.99	9693.11
187	281   	9549.99	9761.23
188	273   	9549.99	9712.46
189	262   	9549.99	9786.26
190	276   	9549.99	9805.2 
191	282   	9549.99	9675.81
192	269   	9549.99	9733.11
193	258   	9549.99	9981.48
194	273   	9549.99	9722.19
195	267   	9549.99	9694.95
196	281   	9549.99	9845.83
197	262   	9549.99	9903.02
198	274   	9549.99	9749.83
199	270   	9549.99	9886.32
200	277   	9549.99	9837.95
-- Best Ever Individual =  Individual('i', [0, 27, 11, 5, 20, 4, 8, 25, 2, 28, 1, 19, 9, 3, 14, 17, 13, 16, 21, 10, 18, 12, 23, 7, 26, 22, 6, 24, 15])
-- Best Ever Fitness =  9549.9853515625
# plot best solution:
plt.figure(1)
tsp.plotData(best)

# plot statistics:
minFitnessValues, meanFitnessValues = logbook.select("min", "avg")
plt.figure(2)
sns.set_style("whitegrid")
plt.plot(minFitnessValues, color='red')
plt.plot(meanFitnessValues, color='green')
plt.xlabel('Generation')
plt.ylabel('Min / Average Fitness')
plt.title('Min and Average fitness over Generations')

# show both plots:
plt.show()
../_images/f60db7af703b6ce5839f65f39c5426bf0e50add1067535d2d5e22995cf1eae65.png ../_images/fd1decc68ad3757c2e3ce74f1aac27cf8c756d70c17df8fb3002eae79e67606b.png

1.4.4. TSP Modifying Tour Size: 3#

  • Experimenting with the Tournament Size reveals that: When the size is increasing the size of the torunament, is not able to retain the best solutions…

# Calculating The Distance as the TSP Distance.


# fitness calculation - compute the total distance of the list of cities represented by indices:
def tpsDistance(individual):
    return tsp.getTotalDistance(individual),  # return a tuple


toolbox.register("evaluate", tpsDistance)


# Genetic operators:
toolbox.register("select", tools.selTournament, tournsize=2)
toolbox.register("mate", tools.cxOrdered)
toolbox.register("mutate", tools.mutShuffleIndexes, indpb=1.0/len(tsp))

# create initial population (generation 0):
population = toolbox.populationCreator(n=POPULATION_SIZE)

# prepare the statistics object:
stats = tools.Statistics(lambda ind: ind.fitness.values)
stats.register("min", np.min)
stats.register("avg", np.mean)



# define the hall-of-fame object:
hof = tools.HallOfFame(HALL_OF_FAME_SIZE)

# perform the Genetic Algorithm flow with hof feature added:
population, logbook = algorithms.eaSimple(population, toolbox, cxpb=P_CROSSOVER, mutpb=P_MUTATION,
                                            ngen=MAX_GENERATIONS, stats=stats, halloffame=hof, verbose=True)

# print best individual info:
best = hof.items[0]
print("-- Best Ever Individual = ", best)
print("-- Best Ever Fitness = ", best.fitness.values[0])
gen	nevals	min    	avg    
0  	300   	21103.5	26399.8
1  	274   	21361.6	25481.4
2  	258   	19153.7	24928.2
3  	285   	18299.3	24318.2
4  	275   	19199.8	23753.1
5  	271   	18344.1	23313.5
6  	270   	18344.1	23081.9
7  	264   	18078.7	22838.6
8  	273   	17945.4	22705.6
9  	276   	18042.5	22653.7
10 	263   	17340.4	22467.2
11 	268   	17549.7	22291.7
12 	272   	17144.4	22138.2
13 	274   	17379.9	21704.1
14 	269   	17143.3	21659.2
15 	261   	17288.3	21517.3
16 	273   	16224.5	21419.9
17 	277   	16676.9	21367.1
18 	263   	15293  	21390.3
19 	272   	16688.3	21436.5
20 	272   	16388.9	21475.2
21 	270   	16388.9	21326.1
22 	278   	16014.6	21420.9
23 	273   	16779.1	21255.7
24 	278   	16615  	21044  
25 	254   	16738.1	20971.9
26 	274   	17463  	21139.5
27 	274   	17331.4	21043.8
28 	272   	16859.7	20956.5
29 	271   	16402  	20855  
30 	271   	16206.3	20919.5
31 	271   	16492.5	20749.2
32 	268   	16853.3	20707.1
33 	264   	16667.7	20748.3
34 	288   	16083.8	20855.3
35 	277   	16157.7	20896.1
36 	265   	16036.8	20924.3
37 	266   	16169.1	20953.2
38 	268   	16335.5	20932.7
39 	279   	16335.5	20877.3
40 	269   	16521.9	20784.1
41 	281   	17424.2	21013.6
42 	273   	17046.1	21073.9
43 	262   	16854  	20843.3
44 	276   	16357.8	20953.5
45 	276   	16357.8	21156  
46 	265   	17285.9	21187.9
47 	276   	16799.8	21134.7
48 	277   	16251  	21150.8
49 	272   	15854.7	21271.9
50 	277   	15588.8	21348.2
51 	278   	14563.7	21173.6
52 	279   	14249.4	20943.6
53 	265   	16149.7	20917.3
54 	275   	17031.8	20867.9
55 	274   	16278.2	20746.1
56 	262   	15532.3	20685.8
57 	267   	16097.3	20703.7
58 	277   	16441.2	20357.1
59 	285   	15057.9	20287  
60 	270   	15057.9	20072.7
61 	263   	15311.8	20077.8
62 	275   	16103.8	20311.4
63 	270   	16103.8	20438.1
64 	274   	15672.4	20323.6
65 	268   	16123.5	20361.7
66 	258   	15764.1	20453.8
67 	278   	15573.2	20546.5
68 	278   	15573.2	20312.7
69 	276   	15945  	20168.7
70 	262   	16211  	20045.8
71 	265   	15224.5	19886.9
72 	275   	15224.5	19888.3
73 	280   	15809  	20169.8
74 	278   	16331.9	20202  
75 	271   	16285.4	20218.7
76 	268   	13871.3	20027.3
77 	264   	13871.3	19940.9
78 	264   	15407  	19734.6
79 	267   	15645.2	19789.4
80 	276   	12955.5	19732.4
81 	272   	12955.5	19861.2
82 	273   	12955.5	19564.4
83 	268   	14070.9	19513.9
84 	271   	14445.9	19350.3
85 	281   	14502.3	19297.6
86 	278   	14827.2	19126.1
87 	268   	14461.4	18970.9
88 	255   	14230.7	18559.6
89 	270   	14109.2	18499.4
90 	265   	13381.8	18369.5
91 	272   	14131.6	18252  
92 	275   	14549.2	18079.1
93 	273   	14048.4	18096.7
94 	284   	14137.4	18202.6
95 	258   	13344.2	18079.2
96 	274   	13191  	18065.4
97 	276   	13570.1	18014.6
98 	272   	13570.1	17879.5
99 	277   	13789.3	18022  
100	280   	13691.4	17954.3
101	274   	13468.1	17759.1
102	280   	13172.8	17626.5
103	268   	13159.3	17696.3
104	259   	14291  	17820  
105	279   	14462.7	17779.8
106	265   	14476.2	17836  
107	268   	13715.8	17840.7
108	276   	14242.1	17942.9
109	284   	13628  	18132.7
110	273   	13390.5	18238.5
111	279   	13600.3	18442.6
112	266   	13461.5	18331.3
113	271   	13461.5	18271.2
114	280   	12910.8	18261.2
115	281   	13587.4	18260.8
116	269   	13639.6	18263.5
117	273   	13603.5	18210.9
118	276   	13977.8	18051.2
119	280   	13195.3	17917.1
120	273   	14310.7	17827.5
121	262   	13982.4	18028.4
122	273   	13569.9	18039.5
123	278   	14228.8	18189.9
124	276   	13208.5	18056.2
125	265   	13632.2	17937.3
126	273   	14468.8	18115.5
127	274   	14330.4	18172.6
128	268   	14212.1	18202.2
129	282   	14523.6	18310.7
130	280   	14624.1	18408.5
131	277   	14025.1	18482.2
132	279   	14359.8	18284.9
133	270   	14243.4	18428.7
134	273   	13577  	18301.5
135	282   	13878.6	18267.4
136	268   	13758.6	18087.1
137	270   	14297.1	18154.7
138	268   	14274.6	18039.8
139	285   	13162.2	18088.6
140	281   	13472.2	18132.5
141	266   	13937.4	18021.2
142	267   	13257.5	17882.7
143	266   	13376.4	17756.5
144	277   	13796.6	17633.3
145	278   	13769.7	17685.6
146	276   	14044.2	17795.6
147	267   	14044.2	17691.6
148	270   	13542.7	17753.6
149	264   	13634.8	17730.1
150	276   	13294.7	17928.2
151	276   	13693.6	17949.9
152	277   	13600.8	17875.5
153	274   	12738.6	17938.5
154	268   	12738.6	17944  
155	273   	12296.6	17932.7
156	269   	12741.2	17570.3
157	274   	13152.3	17612.7
158	273   	12946  	17662.3
159	264   	12070.9	17603.5
160	267   	12070.9	17389.9
161	264   	12070.9	17347.1
162	279   	12967.3	17124  
163	275   	12370.7	16920  
164	274   	12730.9	16864.2
165	270   	13658.8	16925.7
166	267   	13225.9	17144.9
167	267   	13610.7	17313.1
168	276   	13912.6	17418.3
169	270   	12961.4	17399.4
170	271   	13335.9	17502.1
171	273   	13357.5	17628.6
172	263   	13456.1	17795.4
173	275   	14259.9	17795.4
174	267   	13859.9	17726.7
175	269   	13752  	17703.6
176	269   	13852.9	17626.9
177	283   	13539  	17612.7
178	273   	13418.4	17636.9
179	262   	13230.4	17498.5
180	279   	13702  	17553.1
181	279   	13456.2	17665  
182	270   	13874.4	17881.2
183	280   	13818.4	17950.4
184	271   	13818.4	17969.7
185	279   	13660.9	17971.5
186	272   	13793.1	18030.4
187	265   	13793.1	18153.7
188	286   	14066.1	17980.3
189	258   	13236.8	17798.1
190	272   	13463.7	17976.3
191	277   	13233.5	17818.7
192	276   	14378.3	18048.2
193	271   	13784.3	18182.4
194	278   	14436.5	18534.6
195	277   	14171.8	18530.7
196	281   	13440.1	18614.7
197	273   	13938.8	18707.3
198	271   	14678.1	18458  
199	271   	14921.4	18568.2
200	258   	14572.3	18512.5
-- Best Ever Individual =  Individual('i', [11, 27, 0, 7, 23, 26, 15, 6, 22, 24, 3, 18, 17, 13, 16, 21, 10, 14, 19, 1, 25, 4, 5, 8, 28, 2, 9, 12, 20])
-- Best Ever Fitness =  12070.9267578125
# plot best solution:
plt.figure(1)
tsp.plotData(best)

# plot statistics:
minFitnessValues, meanFitnessValues = logbook.select("min", "avg")
plt.figure(2)
sns.set_style("whitegrid")
plt.plot(minFitnessValues, color='red')
plt.plot(meanFitnessValues, color='green')
plt.xlabel('Generation')
plt.ylabel('Min / Average Fitness')
plt.title('Min and Average fitness over Generations')

# show both plots:
plt.show()
../_images/fbd58e43152f4fef4c121721644d594e2c93df7a6124a207505441dac8139528.png ../_images/fd74ba3cf9ed384d3716bc00d51c810d1418373cafdca5547ccaa30ef4908ff7.png
### Attempt using Elitism

import elitism

# Calculating The Distance as the TSP Distance.


# fitness calculation - compute the total distance of the list of cities represented by indices:
def tpsDistance(individual):
    return tsp.getTotalDistance(individual),  # return a tuple


toolbox.register("evaluate", tpsDistance)


# Genetic operators:
toolbox.register("select", tools.selTournament, tournsize=2)
toolbox.register("mate", tools.cxOrdered)
toolbox.register("mutate", tools.mutShuffleIndexes, indpb=1.0/len(tsp))

# create initial population (generation 0):
population = toolbox.populationCreator(n=POPULATION_SIZE)

# prepare the statistics object:
stats = tools.Statistics(lambda ind: ind.fitness.values)
stats.register("min", np.min)
stats.register("avg", np.mean)



# define the hall-of-fame object:
hof = tools.HallOfFame(HALL_OF_FAME_SIZE)

# perform the Genetic Algorithm flow with hof feature added:
# population, logbook = algorithms.eaSimple(population, toolbox, cxpb=P_CROSSOVER, mutpb=P_MUTATION,
#                                             ngen=MAX_GENERATIONS, stats=stats, halloffame=hof, verbose=True)

population, logbook = elitism.eaSimpleWithElitism(population, toolbox, cxpb=P_CROSSOVER, mutpb=P_MUTATION,
                                            ngen=MAX_GENERATIONS, stats=stats, halloffame=hof, verbose=True)


# print best individual info:
best = hof.items[0]
print("-- Best Ever Individual = ", best)
print("-- Best Ever Fitness = ", best.fitness.values[0])



# plot best solution:
plt.figure(1)
tsp.plotData(best)

# plot statistics:
minFitnessValues, meanFitnessValues = logbook.select("min", "avg")
plt.figure(2)
sns.set_style("whitegrid")
plt.plot(minFitnessValues, color='red')
plt.plot(meanFitnessValues, color='green')
plt.xlabel('Generation')
plt.ylabel('Min / Average Fitness')
plt.title('Min and Average fitness over Generations')

# show both plots:
plt.show()
gen	nevals	min    	avg    
0  	300   	21219.9	26467.8
1  	276   	20638  	25521.8
2  	282   	20272.5	24884.4
3  	260   	18344.9	24197.1
4  	278   	18344.9	23918.4
5  	278   	17194.8	23487.6
6  	280   	17194.8	23202.3
7  	282   	17194.8	23106  
8  	275   	17194.8	22890.5
9  	278   	16695.1	22527.2
10 	273   	16695.1	22323.1
11 	279   	16695.1	22103  
12 	275   	16695.1	21905.8
13 	262   	16695.1	21578.5
14 	270   	16695.1	21511.8
15 	271   	16695.1	21421.8
16 	267   	16695.1	21416.1
17 	269   	16448.3	21469.7
18 	271   	16443.9	21180.3
19 	278   	16443.9	21154.2
20 	282   	16443.9	21224.8
21 	273   	16147.2	21298.1
22 	275   	16147.2	21319.3
23 	270   	16147.2	21238.5
24 	277   	14959.4	21254.6
25 	269   	14959.4	21262.3
26 	272   	14959.4	21114.6
27 	260   	14959.4	21199.2
28 	280   	14959.4	21174  
29 	270   	14959.4	21024.7
30 	271   	14959.4	20909.9
31 	267   	14959.4	20744  
32 	270   	14505.1	20586.8
33 	276   	14505.1	20572.7
34 	268   	14505.1	20585.1
35 	277   	14505.1	20593.3
36 	273   	14505.1	20373.2
37 	269   	14432.1	20338.1
38 	265   	14432.1	20251.1
39 	270   	14432.1	20027  
40 	268   	14432.1	19904.4
41 	270   	14432.1	19865.6
42 	281   	14432.1	19723.6
43 	272   	14432.1	19403.4
44 	263   	14432.1	19393.1
45 	279   	14432.1	19404.7
46 	278   	14432.1	19095  
47 	265   	14353.2	18961  
48 	279   	14353.2	18960.3
49 	272   	14336.5	18909.9
50 	279   	14336.5	19068.2
51 	266   	14291  	19109.2
52 	260   	14291  	19077.7
53 	267   	14291  	19043.8
54 	278   	14291  	19074.8
55 	270   	14291  	19183  
56 	263   	14291  	19122.6
57 	276   	14291  	19053.9
58 	280   	14291  	19265  
59 	268   	13912.2	19110.3
60 	280   	13912.2	19154.2
61 	274   	13912.2	19151.5
62 	279   	13912.2	19186.3
63 	274   	13912.2	19076.5
64 	270   	13912.2	18957  
65 	271   	13680  	19043.5
66 	268   	13680  	18885.5
67 	275   	13680  	18870.7
68 	282   	13680  	18860.3
69 	281   	13680  	18984.5
70 	275   	13680  	18966  
71 	275   	13680  	18713.1
72 	270   	13680  	18877.2
73 	267   	13680  	18771.1
74 	276   	13680  	18721.6
75 	272   	13680  	18730.5
76 	274   	13680  	18719.6
77 	280   	13680  	18629.1
78 	271   	13680  	19013.3
79 	276   	13680  	18954.8
80 	263   	13680  	18965.8
81 	268   	13539.2	19078.7
82 	269   	13539.2	18964.2
83 	269   	13539.2	19171.5
84 	263   	13539.2	19073.9
85 	273   	13539.2	19108.6
86 	270   	13539.2	19345.2
87 	266   	13539.2	19330.6
88 	260   	13539.2	19278.1
89 	272   	13539.2	19367.2
90 	276   	13539.2	19219  
91 	271   	13539.2	19422  
92 	269   	13539.2	19438.4
93 	271   	13539.2	19301.6
94 	281   	13539.2	19521.6
95 	267   	13539.2	19447  
96 	267   	13539.2	19416.6
97 	276   	13539.2	19510.2
98 	281   	13539.2	19566.9
99 	265   	13539.2	19519.1
100	267   	13539.2	19356.7
101	264   	13539.2	19210.5
102	273   	13539.2	19203.6
103	277   	13539.2	19181.4
104	267   	13539.2	18950.4
105	270   	13539.2	18946.4
106	277   	13539.2	19101.3
107	278   	13539.2	19126.7
108	277   	13539.2	19076.7
109	270   	13539.2	19198.5
110	260   	13539.2	19010.5
111	265   	13531.3	19203.9
112	276   	13155.3	19083.3
113	283   	13155.3	18903.2
114	271   	13155.3	18779.2
115	280   	13155.3	18662  
116	279   	13155.3	18638.1
117	266   	13155.3	18731.5
118	267   	13155.3	18649.7
119	272   	13155.3	18777.7
120	276   	13155.3	18563.6
121	271   	13155.3	18477.8
122	266   	13155.3	18401.6
123	284   	13155.3	18180.6
124	279   	13155.3	18271  
125	267   	13155.3	18375.8
126	283   	13155.3	18192  
127	264   	13155.3	18437.5
128	276   	13155.3	18491.9
129	250   	13155.3	18249.9
130	267   	13155.3	18140  
131	267   	13155.3	18326  
132	271   	13155.3	18352.6
133	273   	13155.3	18533  
134	273   	13155.3	18456.4
135	271   	13155.3	18440.1
136	275   	13155.3	18353.6
137	273   	13155.3	18340.5
138	274   	13155.3	18287.8
139	276   	13155.3	18304.6
140	272   	13155.3	18203.1
141	278   	13155.3	18367.2
142	273   	13155.3	18628.6
143	264   	13155.3	18564.2
144	278   	13155.3	18668  
145	260   	13155.3	18585.9
146	276   	13155.3	18586.5
147	263   	13155.3	18583.1
148	270   	13155.3	18165.6
149	270   	13155.3	18193.8
150	262   	13155.3	18288.4
151	272   	13155.3	18125.1
152	274   	13155.3	18429.8
153	259   	13155.3	18464  
154	265   	13155.3	18499.6
155	269   	13155.3	18317.6
156	286   	13155.3	18350.5
157	255   	13155.3	18277.5
158	274   	13071  	18338.9
159	269   	13071  	18233.7
160	267   	13071  	18378  
161	273   	13071  	18350.4
162	282   	13071  	18146.3
163	274   	13071  	18005.8
164	279   	13071  	18303.3
165	273   	13071  	18319.4
166	285   	13071  	18674.4
167	276   	13071  	18771.8
168	266   	13071  	18825.1
169	255   	13071  	18610.6
170	275   	13071  	18712.8
171	271   	13071  	18762.3
172	267   	13071  	18941.9
173	284   	13071  	19018.1
174	274   	13071  	19268.8
175	274   	13071  	19311.6
176	266   	13071  	19214.6
177	281   	13071  	19308.3
178	289   	13071  	19196.7
179	277   	13071  	19067.4
180	256   	13071  	19091.8
181	286   	13071  	19183.3
182	270   	13071  	19080.7
183	269   	13071  	18880.7
184	262   	13071  	18716.6
185	265   	13071  	18638.1
186	277   	13071  	18493.9
187	275   	13071  	18739.1
188	267   	13071  	18706.8
189	266   	13071  	18900.2
190	271   	13071  	18870  
191	282   	13071  	19022.7
192	268   	13071  	19037.4
193	274   	13071  	18949  
194	263   	13071  	18789  
195	275   	13071  	18757.7
196	272   	13071  	18854.2
197	259   	13071  	18893.6
198	273   	13071  	18928.7
199	265   	13071  	19257.7
200	280   	13071  	19339.1
-- Best Ever Individual =  Individual('i', [13, 17, 16, 21, 10, 24, 6, 15, 20, 8, 11, 5, 4, 2, 28, 25, 7, 23, 27, 0, 12, 1, 3, 14, 9, 19, 26, 22, 18])
-- Best Ever Fitness =  13071.04296875
../_images/0566caa3577b51ae3c259dc028491f4252179f82337ac1f75f4bc7a5a12a2d4d.png ../_images/14dc040109be9db95c79ec8c59dec556ea37bdb1cef33c2ed20362a61090518a.png
from deap import base
from deap import creator
from deap import tools

import random
import array

import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

import tsp
import elitism

# set the random seed for repeatable results
RANDOM_SEED = 42
random.seed(RANDOM_SEED)

# create the desired traveling salesman problem instace:
TSP_NAME = "bayg29"  # name of problem
tsp = tsp.TravelingSalesmanProblem(TSP_NAME)

# Genetic Algorithm constants:
POPULATION_SIZE = 300
MAX_GENERATIONS = 200
HALL_OF_FAME_SIZE = 30
P_CROSSOVER = 0.9  # probability for crossover
P_MUTATION = 0.1   # probability for mutating an individual

toolbox = base.Toolbox()

# define a single objective, minimizing fitness strategy:
creator.create("FitnessMin", base.Fitness, weights=(-1.0,))

# create the Individual class based on list of integers:
creator.create("Individual", array.array, typecode='i', fitness=creator.FitnessMin)

# create an operator that generates randomly shuffled indices:
toolbox.register("randomOrder", random.sample, range(len(tsp)), len(tsp))

# create the individual creation operator to fill up an Individual instance with shuffled indices:
toolbox.register("individualCreator", tools.initIterate, creator.Individual, toolbox.randomOrder)

# create the population creation operator to generate a list of individuals:
toolbox.register("populationCreator", tools.initRepeat, list, toolbox.individualCreator)


# fitness calculation - compute the total distance of the list of cities represented by indices:
def tpsDistance(individual):
    return tsp.getTotalDistance(individual),  # return a tuple


toolbox.register("evaluate", tpsDistance)


# Genetic operators:
toolbox.register("select", tools.selTournament, tournsize=2)
toolbox.register("mate", tools.cxOrdered)
toolbox.register("mutate", tools.mutShuffleIndexes, indpb=1.0/len(tsp))



# create initial population (generation 0):
population = toolbox.populationCreator(n=POPULATION_SIZE)

# prepare the statistics object:
stats = tools.Statistics(lambda ind: ind.fitness.values)
stats.register("min", np.min)
stats.register("avg", np.mean)

# define the hall-of-fame object:
hof = tools.HallOfFame(HALL_OF_FAME_SIZE)

# perform the Genetic Algorithm flow with hof feature added:
population, logbook = elitism.eaSimpleWithElitism(population, toolbox, cxpb=P_CROSSOVER, mutpb=P_MUTATION,
                                            ngen=MAX_GENERATIONS, stats=stats, halloffame=hof, verbose=True)

# print best individual info:
best = hof.items[0]
print("-- Best Ever Individual = ", best)
print("-- Best Ever Fitness = ", best.fitness.values[0])

# plot best solution:
plt.figure(1)
tsp.plotData(best, label='Best Solution')

# plot statistics:
minFitnessValues, meanFitnessValues = logbook.select("min", "avg")
plt.figure(2)
sns.set_style("whitegrid")
plt.plot(minFitnessValues, color='red')
plt.plot(meanFitnessValues, color='green')
plt.xlabel('Generation')
plt.ylabel('Min / Average Fitness')
plt.title('Min and Average fitness over Generations')

# show both plots:
plt.show()
gen	nevals	min    	avg  
0  	300   	21103.3	26457
1  	252   	19726.4	25210.9
2  	249   	18977.1	24364.3
3  	257   	17868.2	23514.7
4  	237   	17585.3	22929.8
5  	247   	17585.3	22350.6
6  	247   	17585.3	21831.4
7  	249   	17012.3	21442.6
8  	238   	17012.3	20999.7
9  	249   	16856.3	20513.2
10 	249   	16766.4	20235.4
11 	249   	16165.7	19852.8
12 	244   	14934  	19588.4
13 	242   	14934  	19454.3
14 	252   	14934  	19412.6
15 	245   	14757.5	19286.6
16 	242   	14757.5	19057.2
17 	253   	14757.5	18846.9
18 	246   	14757.5	18782.7
19 	240   	14607  	18293.7
20 	249   	14607  	17740.2
21 	248   	14227.7	17786.1
22 	238   	14227.7	17546.7
23 	242   	12893.9	17310.7
24 	245   	12893.9	16959.3
25 	241   	12893.9	16699.8
26 	242   	12766.2	16481.4
27 	246   	12766.2	16321.5
28 	246   	12662.4	16263.8
29 	236   	12662.4	15799.7
30 	248   	12610.1	15691.9
31 	245   	12610.1	15636.5
32 	247   	12410.6	15465  
33 	253   	12199.6	15328.7
34 	242   	12199.6	15059.9
35 	237   	11848.8	15000.8
36 	251   	11848.8	14836.8
37 	237   	11848.8	14476.5
38 	240   	11848.8	14406.1
39 	251   	11787.9	14350.9
40 	244   	11787.9	14119.6
41 	240   	11645.8	13769.5
42 	248   	11611.2	13731.4
43 	251   	11208.4	13714.4
44 	243   	11208.4	13642.7
45 	245   	11208.4	13548.5
46 	256   	11208.4	13507.2
47 	247   	11208.4	13489.6
48 	244   	11208.4	13402.3
49 	240   	11093.4	13304.7
50 	248   	11093.4	13213.2
51 	241   	10975.6	12976.7
52 	235   	10975.6	12877.5
53 	257   	10975.6	12878.6
54 	247   	10855.3	12847  
55 	246   	10855.3	12690  
56 	245   	10855.3	12702.2
57 	246   	10855.3	12835.6
58 	251   	10673.6	12916  
59 	248   	10673.6	12836.2
60 	240   	10572.8	12905.9
61 	230   	10572.8	12600.5
62 	245   	10572.8	12687.6
63 	253   	10572.8	12515.9
64 	235   	10572.8	12429  
65 	245   	10572.8	12582.2
66 	232   	10572.8	12713.7
67 	252   	10572.8	12741.4
68 	235   	10197.1	12809.4
69 	244   	10197.1	12705.1
70 	257   	10197.1	12876.2
71 	247   	10197.1	12885.3
72 	254   	10197.1	12819.5
73 	242   	10197.1	12871.6
74 	233   	10197.1	12692.1
75 	243   	10197.1	12795.3
76 	242   	10197.1	12824.4
77 	246   	10197.1	12819.1
78 	239   	10197.1	12716.5
79 	246   	10197.1	12514.2
80 	238   	10197.1	12521.6
81 	245   	10021.4	12453.3
82 	252   	10021.4	12233.4
83 	251   	9958.81	12295.2
84 	246   	9958.81	12005.7
85 	243   	9817.91	12051.9
86 	239   	9817.91	11983.5
87 	253   	9752.08	11980.8
88 	243   	9752.08	11948.1
89 	232   	9718.78	11783.5
90 	244   	9718.78	11544.6
91 	253   	9718.78	11590.4
92 	248   	9718.78	11575.3
93 	246   	9584.21	11487.4
94 	237   	9584.21	11324.7
95 	237   	9584.21	11209.5
96 	244   	9584.21	11226.7
97 	257   	9584.21	11277.8
98 	238   	9352.51	10975  
99 	249   	9352.51	10994.3
100	236   	9352.51	10923.4
101	250   	9352.51	11018.6
102	242   	9352.51	11023.7
103	254   	9341.54	10962.8
104	241   	9341.54	10727.6
105	241   	9266.7 	10828.5
106	236   	9266.7 	10722.4
107	246   	9266.7 	10516.8
108	246   	9266.69	10608.1
109	243   	9266.69	10671  
110	243   	9266.69	10615.1
111	255   	9266.69	10645  
112	246   	9266.69	10633.7
113	252   	9266.69	10576.4
114	243   	9266.69	10533.5
115	242   	9266.69	10431.7
116	244   	9266.69	10376.1
117	240   	9266.69	10343.1
118	254   	9232.07	10219.5
119	245   	9232.07	10117.4
120	256   	9232.07	10202.2
121	242   	9232.07	10209.1
122	248   	9232.07	10382  
123	246   	9232.07	10256  
124	245   	9204.93	10105  
125	234   	9204.93	10150.4
126	236   	9204.93	10088.2
127	229   	9204.93	10045.4
128	253   	9204.93	10161.8
129	247   	9204.93	10007  
130	246   	9170.3 	9969.34
131	236   	9170.3 	9993.64
132	260   	9170.3 	10131.6
133	242   	9170.3 	9926.74
134	247   	9170.3 	9887.23
135	250   	9170.3 	9966.44
136	243   	9170.3 	9958.18
137	251   	9170.3 	10143.4
138	244   	9108.77	10185.9
139	245   	9108.77	10237.1
140	235   	9108.77	10149.8
141	254   	9108.77	10217.6
142	252   	9104.36	10189.9
143	245   	9104.36	10114.9
144	250   	9074.15	10124.3
145	251   	9074.15	10127.8
146	242   	9074.15	10201.5
147	251   	9074.15	10169.5
148	250   	9074.15	10113.9
149	229   	9074.15	10025.9
150	242   	9074.15	9933.94
151	231   	9074.15	9967.2 
152	253   	9074.15	9962.38
153	252   	9074.15	10085.3
154	243   	9074.15	9887.07
155	244   	9074.15	9916.6 
156	235   	9074.15	9798.14
157	238   	9074.15	9741.92
158	245   	9074.15	9854.62
159	252   	9074.15	9950.48
160	238   	9074.15	9933.46
161	251   	9074.15	9986.24
162	244   	9074.15	10045.3
163	241   	9074.15	9945.64
164	244   	9074.15	10113  
165	244   	9074.15	10091.2
166	252   	9074.15	9984.51
167	246   	9074.15	9963.11
168	245   	9074.15	9903   
169	257   	9074.15	9911.7 
170	247   	9074.15	9881.34
171	236   	9074.15	9973.72
172	241   	9074.15	9980.26
173	242   	9074.15	9883.92
174	249   	9074.15	9878.07
175	239   	9074.15	9900.23
176	240   	9074.15	9790.76
177	244   	9074.15	9647.22
178	248   	9074.15	9791.55
179	251   	9074.15	9679.68
180	251   	9074.15	9715.82
181	249   	9074.15	9696.82
182	249   	9074.15	9653.68
183	252   	9074.15	9655.67
184	233   	9074.15	9450.34
185	243   	9074.15	9464.17
186	236   	9074.15	9307.74
187	244   	9074.15	9380   
188	250   	9074.15	9348.07
189	238   	9074.15	9256.05
190	250   	9074.15	9340.67
191	233   	9074.15	9372.6 
192	243   	9074.15	9339.89
193	251   	9074.15	9346.98
194	239   	9074.15	9332.73
195	229   	9074.15	9388.14
196	254   	9074.15	9352.36
197	253   	9074.15	9299.68
198	256   	9074.15	9293.32
199	255   	9074.15	9356.17
200	235   	9074.15	9328.94
-- Best Ever Individual =  Individual('i', [0, 23, 12, 15, 26, 7, 22, 6, 24, 18, 10, 21, 16, 13, 17, 14, 3, 9, 19, 1, 20, 4, 28, 2, 25, 8, 11, 5, 27])
-- Best Ever Fitness =  9074.146484375
../_images/baef6bf65a0d519f38749548d63eb258bcd043861a60228162d7394e2034bba1.png ../_images/3c0df0e993bff852f59457e43c72bfb248066c15c404903c97b5006b64bcb7cf.png