|
@@ -11,18 +11,15 @@ public class AntColonyOptimizer
|
|
|
private double[][] distances;
|
|
|
private double[][] pheromones;
|
|
|
private readonly double evaporationRate;
|
|
|
- private readonly int numberOfAnts;
|
|
|
|
|
|
private readonly List<IAnt> xants = [];
|
|
|
- private IAnt[] ants;
|
|
|
+ private IAnt[]? ants;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-
|
|
|
|
|
|
-
|
|
|
public AntColonyOptimizer(double[][] distances, double evaporationRate = 0.1)
|
|
|
{
|
|
|
numberOfCities = distances.GetLength(0);
|
|
@@ -43,20 +40,32 @@ public class AntColonyOptimizer
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- public AntColonyOptimizer AddAnts<T>(int count) where T : IAnt
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ public AntColonyOptimizer AddAnts<T>(int count, params object[] args) where T : IAnt
|
|
|
{
|
|
|
for (int i = 0; i < count; i++)
|
|
|
{
|
|
|
- xants.Add(Activator.CreateInstance<T>()!);
|
|
|
+
|
|
|
+ xants.Add((T)Activator.CreateInstance(typeof(T), args)!);
|
|
|
}
|
|
|
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
- public AntColonyOptimizer ShuffleAnts()
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ public AntColonyOptimizer CompileAnts(bool shuffle = false)
|
|
|
{
|
|
|
ants = [.. xants];
|
|
|
- Random.Shared.Shuffle(ants);
|
|
|
+
|
|
|
+ if (shuffle) Random.Shared.Shuffle(ants);
|
|
|
|
|
|
return this;
|
|
|
}
|
|
@@ -77,60 +86,58 @@ public class AntColonyOptimizer
|
|
|
|
|
|
public (List<int> bestTour, double bestDistance) Solve(int maxIterations)
|
|
|
{
|
|
|
-
|
|
|
+
|
|
|
+ if (ants is null) throw new MissingMemberException("Колония пуста. Забыли вызвать AntColonyOptimizer.CompileAnts()?");
|
|
|
+
|
|
|
+ Console.WriteLine($"Поиск кратчайшего Гамильтонова цикла с {ants.Length} муравьев и {maxIterations} итераций");
|
|
|
+
|
|
|
for (int i = 0; i < maxIterations; i++)
|
|
|
{
|
|
|
ConcurrentBag<List<int>> antTours = [];
|
|
|
ConcurrentBag<double> antDistances = [];
|
|
|
|
|
|
- Console.Write($"{i}/{maxIterations} - {bestDistanceEver}\r");
|
|
|
-
|
|
|
|
|
|
var iterationTours = ants.AsParallel().Select(ant =>
|
|
|
{
|
|
|
var ct = ant.ConstructTour(ref distances, ref pheromones);
|
|
|
+
|
|
|
if (!ct.HasValue) return ([], double.MaxValue);
|
|
|
var (tour, distance) = ct.Value;
|
|
|
antTours.Add(tour);
|
|
|
antDistances.Add(distance);
|
|
|
-
|
|
|
|
|
|
return (tour, distance);
|
|
|
});
|
|
|
|
|
|
+
|
|
|
for (int j = 0; j < antTours.Count; j++)
|
|
|
{
|
|
|
ants[j].UpdatePheromones(ref pheromones);
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
EvaporatePheromones();
|
|
|
-
|
|
|
-
|
|
|
|
|
|
+
|
|
|
(List<int> Tour, double Distance) bestIterationTour = iterationTours.MinBy(x => x.distance);
|
|
|
- if (bestIterationTour.Distance < bestDistanceEver)
|
|
|
+ if (bestIterationTour.Distance < bestDistanceEver)
|
|
|
{
|
|
|
bestDistanceEver = bestIterationTour.Distance;
|
|
|
bestTourEver = bestIterationTour.Tour;
|
|
|
- Console.WriteLine();
|
|
|
+ Console.WriteLine($"{i} - {bestDistanceEver,20}");
|
|
|
}
|
|
|
- };
|
|
|
+
|
|
|
+ Console.Write($"{i}/{maxIterations} - {bestDistanceEver}\r");
|
|
|
+ }
|
|
|
|
|
|
return (bestTourEver, bestDistanceEver);
|
|
|
}
|
|
|
|
|
|
|
|
|
-
|
|
|
+
|
|
|
|
|
|
private void EvaporatePheromones()
|
|
|
{
|
|
|
-
|
|
|
for (int i = 0; i < numberOfCities; i++)
|
|
|
{
|
|
|
for (int j = 0; j < numberOfCities; j++)
|