in Source/Extensions/TSP Resources/GeneticTspAlgorithm.cs [61:337]
public override async Task<TspResult> Solve(DistanceMatrix matrix, TspOptimizationType tspOptimization)
{
return await Task<TspResult>.Run<TspResult>(() =>
{
int population = matrix.Origins.Count;
double[] weight = new double[population];
var minTour = new int[population];
int[,] chromosome = new int[population, population];
double minWeight = double.MaxValue;
for (int p = 0; p < population; p++)
{
bool[] used = new bool[population];
int[] currentOrder = new int[population];
for (int n = 0; n < population; n++)
{
used[n] = false;
}
for (int n = 0; n < population; n++)
{
int i;
do
{
i = random.Next(population);
}
while (used[i]);
used[i] = true;
currentOrder[n] = i;
}
for (int n = 0; n < population; n++)
{
chromosome[p, n] = currentOrder[n];
}
if (tspOptimization == TspOptimizationType.TravelTime)
{
weight[p] = matrix.GetEdgeTime(currentOrder, true);
}
else
{
weight[p] = matrix.GetEdgeDistance(currentOrder, true);
}
if (weight[p] < minWeight)
{
minWeight = weight[p];
for (int n = 0; n < population; n++)
{
minTour[n] = chromosome[p, n];
}
}
}
for (int g = 0; g < Generations; g++)
{
if (random.NextDouble() < MutationRate)
{
int i, j, parent1, parent2;
int[] p1 = new int[population];
int[] p2 = new int[population];
int[] o1 = new int[population];
int[] o2 = new int[population];
i = random.Next(population);
j = random.Next(population);
if (weight[i] < weight[j])
{
parent1 = i;
}
else
{
parent1 = j;
}
i = random.Next(population);
j = random.Next(population);
if (weight[i] < weight[j])
{
parent2 = i;
}
else
{
parent2 = j;
}
for (i = 0; i < population; i++)
{
p1[i] = chromosome[parent1, i];
p2[i] = chromosome[parent2, i];
}
int cp1 = -1, cp2 = -1;
do
{
cp1 = random.Next(population);
cp2 = random.Next(population);
} while (cp1 == cp2 || cp1 > cp2);
Crossover(cp1, cp2, p1, p2, o1, o2, population, random);
double o1Fitness;
if (tspOptimization == TspOptimizationType.TravelTime)
{
o1Fitness = matrix.GetEdgeTime(o1, true);
}
else
{
o1Fitness = matrix.GetEdgeDistance(o1, true);
}
if (o1Fitness < weight[parent1])
{
for (i = 0; i < population; i++)
{
chromosome[parent1, i] = o1[i];
}
}
double o2Fitness;
if (tspOptimization == TspOptimizationType.TravelTime)
{
o2Fitness = matrix.GetEdgeTime(o2, true);
}
else
{
o2Fitness = matrix.GetEdgeDistance(o2, true);
}
if (o2Fitness < weight[parent2])
{
for (i = 0; i < population; i++)
{
chromosome[parent2, i] = o2[i];
}
}
for (int p = 0; p < population; p++)
{
if (weight[p] < minWeight)
{
minWeight = weight[p];
for (int n = 0; n < population; n++)
{
minTour[n] = chromosome[p, n];
}
}
}
}
else
{
int i, j, p;
int[] child = new int[population];
i = random.Next(population);
j = random.Next(population);
if (weight[i] < weight[j])
{
p = i;
}
else
{
p = j;
}
double childWeight;
for (int n = 0; n < population; n++)
{
child[n] = chromosome[p, n];
}
do
{
i = random.Next(population);
j = random.Next(population);
}
while (i == j);
int t = child[i];
child[i] = child[j];
child[j] = t;
if (tspOptimization == TspOptimizationType.TravelTime)
{
childWeight = matrix.GetEdgeTime(child, true);
}
else
{
childWeight = matrix.GetEdgeDistance(child, true);
}
int maxIndex = int.MaxValue;
double maxD = double.MinValue;
for (int q = 0; q < population; q++)
{
if (weight[q] >= maxD)
{
maxIndex = q;
maxD = weight[q];
}
}
int[] index = new int[population];
int count = 0;
for (int q = 0; q < population; q++)
{
if (weight[q] == maxD)
{
index[count++] = q;
}
}
maxIndex = index[random.Next(count)];
if (childWeight < weight[maxIndex])
{
weight[maxIndex] = childWeight;
for (int n = 0; n < population; n++)
{
chromosome[maxIndex, n] = child[n];
}
if (childWeight < minWeight)
{
minWeight = childWeight;
for (int n = 0; n < population; n++)
{
minTour[n] = child[n];
}
}
}
}
}
//Ensure first point is the starting point. Indicies form a cycle, so just need to shift.
if (minTour[0] != 0)
{
var minTourList = minTour.ToList();
var startIdx = minTourList.IndexOf(0);
var order = new List<int>();
order.AddRange(minTourList.GetRange(startIdx, minTourList.Count - startIdx));
order.AddRange(minTourList.GetRange(0, startIdx));
minTour = order.ToArray();
}
return new TspResult()
{
DistanceMatrix = matrix,
OptimizedWeight = minWeight,
OptimizedWaypoints = GetOptimizedWaypoints(matrix.Origins, minTour)
};
}).ConfigureAwait(false);
}