diff --git a/Banchmarking/Benchmarking.csproj b/Banchmarking/Benchmarking.csproj
index f36995f..b8c69e8 100644
--- a/Banchmarking/Benchmarking.csproj
+++ b/Banchmarking/Benchmarking.csproj
@@ -8,9 +8,9 @@
-
-
-
+
+
+
diff --git a/GeneticAlgorithm.UnitTests/ChildrenGeneratorTests.cs b/GeneticAlgorithm.UnitTests/ChildrenGeneratorTests.cs
index 27a899e..478db01 100644
--- a/GeneticAlgorithm.UnitTests/ChildrenGeneratorTests.cs
+++ b/GeneticAlgorithm.UnitTests/ChildrenGeneratorTests.cs
@@ -27,7 +27,7 @@ public void TestMutationsHappen(double mutationProbability)
var crossoverManager = A.Fake();
A.CallTo(() => crossoverManager.Crossover(A._, A._))
.ReturnsLazily((IChromosome c1, IChromosome c2) => c1);
- var childrenGenerator = new ChildrenGenerator(crossoverManager, new BassicMutationProbabilityManager(mutationProbability), new RouletteWheelSelection());
+ var childrenGenerator = new ChildrenGenerator(crossoverManager, new BasicMutationProbabilityManager(mutationProbability), new RouletteWheelSelection());
childrenGenerator.GenerateChildren(population, populationSize, 0, null);
const double errorMargin = 0.05;
@@ -44,7 +44,7 @@ public void RetusnRightNumberOfChromosomes(int childrenCount)
{
const int count = 1500;
var crossoverManager = A.Fake();
- var childrenGenerator = new ChildrenGenerator(crossoverManager, new BassicMutationProbabilityManager(0), new RouletteWheelSelection());
+ var childrenGenerator = new ChildrenGenerator(crossoverManager, new BasicMutationProbabilityManager(0), new RouletteWheelSelection());
var children = childrenGenerator.GenerateChildren(GetPopulation(count), childrenCount, 0, null);
Assert.AreEqual(childrenCount, children.Length, "Didn't get enough children");
foreach (var chromosome in children)
@@ -71,7 +71,7 @@ public void BadMutationProbability_ThrowException(double probability)
[DataRow(-1)]
public void RequestBadNumberOfChildren_ThrowsException(int childrenCount)
{
- var childrenGenerator = new ChildrenGenerator(A.Fake(), new BassicMutationProbabilityManager(0),
+ var childrenGenerator = new ChildrenGenerator(A.Fake(), new BasicMutationProbabilityManager(0),
new RouletteWheelSelection());
childrenGenerator.GenerateChildren(GetPopulation(1), childrenCount, 0, null);
}
@@ -83,7 +83,7 @@ public void SelectionStrategyReturnsNull_ThrowsException()
{
var selectionStrategy = A.Fake();
A.CallTo(() => selectionStrategy.SelectChromosome()).Returns(null);
- var childrenGenerator = new ChildrenGenerator(A.Fake(), new BassicMutationProbabilityManager(0),
+ var childrenGenerator = new ChildrenGenerator(A.Fake(), new BasicMutationProbabilityManager(0),
selectionStrategy);
childrenGenerator.GenerateChildren(GetPopulation(1), 1, 0, null);
}, typeof(GeneticAlgorithmException));
diff --git a/GeneticAlgorithm.UnitTests/Components/CrossoverManagers/Utilities/NonReapetingAdjacencyMatrixTests.cs b/GeneticAlgorithm.UnitTests/Components/CrossoverManagers/Utilities/NonReapetingAdjacencyMatrixTests.cs
index 097ca90..5dbfc64 100644
--- a/GeneticAlgorithm.UnitTests/Components/CrossoverManagers/Utilities/NonReapetingAdjacencyMatrixTests.cs
+++ b/GeneticAlgorithm.UnitTests/Components/CrossoverManagers/Utilities/NonReapetingAdjacencyMatrixTests.cs
@@ -103,10 +103,10 @@ public void GetNeigbor_GetRandomNeigbor(bool selectNeighborWithLeastNeighbors)
}
var excpectedToGetAtLeast = selectNeighborWithLeastNeighbors ? 35 : 25;
- Assert.IsTrue(excpectedToGetAtLeast < got2);
- Assert.IsTrue(excpectedToGetAtLeast < got5);
+ Assert.IsTrue(excpectedToGetAtLeast < got2, $"Got 2 only {got2} times");
+ Assert.IsTrue(excpectedToGetAtLeast < got5, $"Got 5 only {got5} times");
if (!selectNeighborWithLeastNeighbors)
- Assert.IsTrue(excpectedToGetAtLeast < got4);
+ Assert.IsTrue(excpectedToGetAtLeast < got4, $"Got 4 only {got4} times");
}
[TestMethod]
diff --git a/GeneticAlgorithm.UnitTests/ExceptionTests.cs b/GeneticAlgorithm.UnitTests/ExceptionTests.cs
index 7f904bb..25ec6d7 100644
--- a/GeneticAlgorithm.UnitTests/ExceptionTests.cs
+++ b/GeneticAlgorithm.UnitTests/ExceptionTests.cs
@@ -4,6 +4,8 @@
using FakeItEasy;
using GeneticAlgorithm.Exceptions;
using GeneticAlgorithm.Interfaces;
+using GeneticAlgorithm.PopulationRenwalManagers;
+using GeneticAlgorithm.StopManagers;
using GeneticAlgorithm.UnitTests.TestUtils;
using Microsoft.VisualStudio.TestTools.UnitTesting;
@@ -21,7 +23,7 @@ public void SetNegativePopulationSize_ThrowsException(int size) =>
.Build();
[TestMethod]
- [ExpectedException(typeof(GeneticAlgorithmException))]
+ [ExpectedException(typeof(GeneticAlgorithmArgumentException))]
[DataRow(1)]
[DataRow(-2)]
public void BadNumberOfGenerations_ThrowsException(int size) =>
@@ -107,30 +109,95 @@ public void GetCurrentPopulation_EngineRunning_ThrowException()
[ExpectedException(typeof(EngineAlreadyRunningException))]
public void SetCurrentPopulation_EngineRunning_ThrowException()
{
- var engine =
- new TestGeneticSearchEngineBuilder(2, int.MaxValue, new TestPopulationManager(new double[] { 2, 2 })).Build();
+ Utils.RunTimedTest(() =>
+ {
+ var engine =
+ new TestGeneticSearchEngineBuilder(2, int.MaxValue, new TestPopulationManager(new double[] { 2, 2 })).Build();
- Task.Run(() => engine.Run());
- while (!engine.IsRunning) ;
+ Task.Run(() => engine.Run());
+ while (!engine.IsRunning) ;
- engine.SetCurrentPopulation(new double[] { 3 ,3 }.ToChromosomes("Converted"));
+ engine.SetCurrentPopulation(new double[] { 3, 3 }.ToChromosomes("Converted"));
- Assert.Fail("Should have thrown an exception by now");
+ Assert.Fail("Should have thrown an exception by now");
+ });
}
[TestMethod]
[ExpectedException(typeof(GeneticAlgorithmException))]
public void SetCurrentPopulation_WrongNumberOfChromosomes_ThrowException()
{
- var engine =
+ Utils.RunTimedTest(() =>
+ {
+ var engine =
new TestGeneticSearchEngineBuilder(2, int.MaxValue, new TestPopulationManager(new double[] { 2, 2 })).Build();
- Task.Run(() => engine.Run());
- while (!engine.IsRunning) ;
+ Task.Run(() => engine.Run());
+ while (!engine.IsRunning) ;
- engine.SetCurrentPopulation(new double[] { 3, 3 ,3 }.ToChromosomes("Converted"));
+ engine.SetCurrentPopulation(new double[] { 3, 3, 3 }.ToChromosomes("Converted"));
- Assert.Fail("Should have thrown an exception by now");
+ Assert.Fail("Should have thrown an exception by now");
+ });
}
+
+ [TestMethod]
+ [ExpectedException(typeof(GeneticAlgorithmArgumentException))]
+ public void StopAtConvergence_DiffNegative_ThrowException() =>
+ new StopAtConvergence(-0.1);
+
+ [TestMethod]
+ [ExpectedException(typeof(GeneticAlgorithmArgumentException))]
+ public void StopAtEvaluation_EvaluationNegative_ThrowException() =>
+ new StopAtEvaluation(-0.1);
+
+ [TestMethod]
+ [ExpectedException(typeof(GeneticAlgorithmArgumentException))]
+ public void StopAtGeneration_BadGeneration_ThrowException() =>
+ new StopAtGeneration(1);
+
+ [TestMethod]
+ [ExpectedException(typeof(GeneticAlgorithmArgumentException))]
+ public void StopIfNoImprovment_BadGenerationsToConsider_ThrowException() =>
+ new StopIfNoImprovment(0, 0.5);
+
+ [TestMethod]
+ [ExpectedException(typeof(GeneticAlgorithmArgumentException))]
+ public void RenewIfNoImprovment_BadGenerationsToConsider_ThrowException() =>
+ new RenewIfNoImprovment(0, 1, 0.5);
+
+ [TestMethod]
+ [DataRow(-0.1)]
+ [DataRow(0)]
+ [DataRow(1.1)]
+ [ExpectedException(typeof(GeneticAlgorithmArgumentException))]
+ public void RenewIfNoImprovment_BadPrecentageToRenew_ThrowException(double precentageToRenew) =>
+ new RenewIfNoImprovment(1, 0.5, precentageToRenew);
+
+ [TestMethod]
+ [ExpectedException(typeof(GeneticAlgorithmArgumentException))]
+ public void RenewAtConvergence_BadGenerationsToConsider_ThrowException() =>
+ new RenewAtConvergence(-0.1, 0.5);
+
+ [TestMethod]
+ [DataRow(-0.1)]
+ [DataRow(0)]
+ [DataRow(1.1)]
+ [ExpectedException(typeof(GeneticAlgorithmArgumentException))]
+ public void RenewAtConvergence_BadPrecentageToRenew_ThrowException(double precentageToRenew) =>
+ new RenewAtConvergence(1, precentageToRenew);
+
+ [TestMethod]
+ [ExpectedException(typeof(GeneticAlgorithmArgumentException))]
+ public void RenewAtDifferenceBetweenAverageAndMaximumFitness_NegativeDiff_ThrowException() =>
+ new RenewAtDifferenceBetweenAverageAndMaximumFitness(-0.1, 0.5);
+
+ [TestMethod]
+ [DataRow(-0.1)]
+ [DataRow(0)]
+ [DataRow(1.1)]
+ [ExpectedException(typeof(GeneticAlgorithmArgumentException))]
+ public void RenewAtDifferenceBetweenAverageAndMaximumFitness_BadPrecentageToRenew_ThrowException(double precentageToRenew) =>
+ new RenewAtDifferenceBetweenAverageAndMaximumFitness(1, precentageToRenew);
}
}
diff --git a/GeneticAlgorithm.UnitTests/GeneticAlgorithm.UnitTests.csproj b/GeneticAlgorithm.UnitTests/GeneticAlgorithm.UnitTests.csproj
index db3da38..7594503 100644
--- a/GeneticAlgorithm.UnitTests/GeneticAlgorithm.UnitTests.csproj
+++ b/GeneticAlgorithm.UnitTests/GeneticAlgorithm.UnitTests.csproj
@@ -8,9 +8,9 @@
-
-
-
+
+
+
diff --git a/GeneticAlgorithm.UnitTests/NumberVectorTests.cs b/GeneticAlgorithm.UnitTests/NumberVectorTests.cs
index 57f998c..6320cb0 100644
--- a/GeneticAlgorithm.UnitTests/NumberVectorTests.cs
+++ b/GeneticAlgorithm.UnitTests/NumberVectorTests.cs
@@ -29,7 +29,7 @@ public NumberVectorTests()
[TestMethod]
[DataRow(RunType.Run)]
[DataRow(RunType.Next)]
- public void BassicTest(RunType runType)
+ public void BasicTest(RunType runType)
{
var searchEngine =
new GeneticSearchEngineBuilder(POPULATION_SIZE, 50, crossoverManager, populationGenerator)
diff --git a/GeneticAlgorithm.UnitTests/PopulationRenwalManagerTests.cs b/GeneticAlgorithm.UnitTests/PopulationRenwalManagerTests.cs
index 3092325..206c58d 100644
--- a/GeneticAlgorithm.UnitTests/PopulationRenwalManagerTests.cs
+++ b/GeneticAlgorithm.UnitTests/PopulationRenwalManagerTests.cs
@@ -18,14 +18,14 @@ public void RenewAtConvergenceTest(RunType runType)
{
var populationManager = new TestPopulationManager(new double[] {1, 1, 1});
populationManager.SetPopulationGenerated(new[]
- {new double[] {2, 2, 2}, new double[] {3, 3, 3}, new double[] {4, 4, 4}});
+ {new double[] {2, 3, 2}, new double[] {4, 4, 4}, new double[] {5, 5, 5}});
var engine = new TestGeneticSearchEngineBuilder(POPULATION_SIZE, 4, populationManager)
.AddPopulationRenwalManager(new RenewAtConvergence(0.9, 1))
.IncludeAllHistory().Build();
var result = engine.Run(runType);
- Assert.AreEqual(4, result.BestChromosome.Evaluate());
+ Assert.AreEqual(3, result.BestChromosome.Evaluate());
}
[TestMethod]
@@ -76,6 +76,23 @@ public void RenewIfNoImprovmentTest2(RunType runType)
Assert.AreEqual(2, result.BestChromosome.Evaluate());
}
+ [TestMethod]
+ [DataRow(RunType.Run)]
+ [DataRow(RunType.Next)]
+ public void RenewAtDifferenceBetweenAverageAndMaximumFitnessTest(RunType runType)
+ {
+ var populationManager = new TestPopulationManager(new double[] { 1, 2, 1 });
+ populationManager.SetPopulationGenerated(new[]
+ {new double[] {2, 5, 2}, new double[] {6, 6, 6}, new double[] {7, 7, 7}});
+ var engine = new TestGeneticSearchEngineBuilder(POPULATION_SIZE, 4, populationManager)
+ .AddPopulationRenwalManager(new RenewAtDifferenceBetweenAverageAndMaximumFitness(1, 1))
+ .IncludeAllHistory().Build();
+
+ var result = engine.Run(runType);
+
+ Assert.AreEqual(5, result.BestChromosome.Evaluate());
+ }
+
[TestMethod]
[DataRow(RunType.Run)]
[DataRow(RunType.Next)]
diff --git a/GeneticAlgorithm.UnitTests/ProbabilityUtilsTests.cs b/GeneticAlgorithm.UnitTests/ProbabilityUtilsTests.cs
index 1f0c049..21de6c8 100644
--- a/GeneticAlgorithm.UnitTests/ProbabilityUtilsTests.cs
+++ b/GeneticAlgorithm.UnitTests/ProbabilityUtilsTests.cs
@@ -20,7 +20,7 @@ public void P_Test(double probability)
var trueCount = 0;
var falseCount = 0;
var attempts = 1000;
- var margernOnError = attempts * 0.1;
+ var marginOfError = attempts * 0.1;
for (int i = 0; i < attempts; i++)
{
if (ProbabilityUtils.P(probability))
@@ -29,8 +29,8 @@ public void P_Test(double probability)
falseCount++;
}
- trueCount.AssertIsWithinRange(attempts * probability, margernOnError);
- falseCount.AssertIsWithinRange(attempts * (1 - probability), margernOnError);
+ trueCount.AssertIsWithinRange(attempts * probability, marginOfError);
+ falseCount.AssertIsWithinRange(attempts * (1 - probability), marginOfError);
}
[TestMethod]
@@ -103,7 +103,10 @@ public void SelectKRandomElements_ElementsAreRandom()
// No element is generated more than 20% of the time
foreach (var element in slelectedElements)
- Assert.IsTrue(slelectedElements.Count(e => e.Equals(element)) < length * 5 * 2 * 0.2, $"{nameof(element)} {element} selected too many times");
+ {
+ var timesSelected = slelectedElements.Count(e => e.Equals(element));
+ Assert.IsTrue(timesSelected < length * 5 * 2 * 0.2, $"{nameof(element)} {element} selected too many times ({timesSelected}).");
+ }
}
[TestMethod]
diff --git a/GeneticAlgorithm.UnitTests/SearchTests.cs b/GeneticAlgorithm.UnitTests/SearchTests.cs
index 92c7b31..0a30b54 100644
--- a/GeneticAlgorithm.UnitTests/SearchTests.cs
+++ b/GeneticAlgorithm.UnitTests/SearchTests.cs
@@ -86,24 +86,35 @@ public void BestChromosome()
[TestMethod]
public void SearchTimeWithNextTest()
{
- var sleepTime = 10;
var generations = 50;
- var populationManager = new TestPopulationManager(new double[] { 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 });
+ var populationManager = new TestPopulationManager(new double[] { 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 }, millisecondsPerGeneration: 10);
var engine = new TestGeneticSearchEngineBuilder(10, generations, populationManager).Build();
var stopwatch = new Stopwatch();
stopwatch.Start();
GeneticSearchResult result = null;
while (result == null || !result.IsCompleted)
- {
result = engine.Next();
- Thread.Sleep(sleepTime);
- }
+
+ stopwatch.Stop();
+
+ Assert.IsTrue(stopwatch.Elapsed.TotalMilliseconds * 0.90 < stopwatch.Elapsed.TotalMilliseconds, $"time is too short. {nameof(stopwatch.Elapsed)} = {stopwatch.Elapsed}; {nameof(result.SearchTime)} = {result.SearchTime.TotalMilliseconds}");
+ Assert.IsTrue(stopwatch.Elapsed.TotalMilliseconds * 1.1 > stopwatch.Elapsed.TotalMilliseconds, $"time is too long. {nameof(stopwatch.Elapsed)} = {stopwatch.Elapsed}; {nameof(result.SearchTime)} = {result.SearchTime.TotalMilliseconds}");
+ }
+
+ [TestMethod]
+ public void SearchTimeRunTest()
+ {
+ var populationManager = new TestPopulationManager(new double[] { 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 });
+ var engine = new TestGeneticSearchEngineBuilder(10, 50, populationManager).Build();
+
+ var stopwatch = new Stopwatch();
+ stopwatch.Start();
+ var result = engine.Run();
stopwatch.Stop();
- var time = stopwatch.Elapsed.TotalMilliseconds - sleepTime * generations -
- result.SearchTime.TotalMilliseconds;
- Assert.IsTrue(time < 0.2 * stopwatch.Elapsed.TotalMilliseconds);
+ Assert.IsTrue(stopwatch.Elapsed.TotalMilliseconds * 0.90 < stopwatch.Elapsed.TotalMilliseconds, $"time is too short. {nameof(stopwatch.Elapsed)} = {stopwatch.Elapsed}; {nameof(result.SearchTime)} = {result.SearchTime.TotalMilliseconds}");
+ Assert.IsTrue(stopwatch.Elapsed.TotalMilliseconds * 1.1> stopwatch.Elapsed.TotalMilliseconds, $"time is too long. {nameof(stopwatch.Elapsed)} = {stopwatch.Elapsed}; {nameof(result.SearchTime)} = {result.SearchTime.TotalMilliseconds}");
}
[DataRow(false, RunType.Run)]
diff --git a/GeneticAlgorithm.UnitTests/SearchUtilsTests.cs b/GeneticAlgorithm.UnitTests/SearchUtilsTests.cs
index 2e719aa..5f6ad92 100644
--- a/GeneticAlgorithm.UnitTests/SearchUtilsTests.cs
+++ b/GeneticAlgorithm.UnitTests/SearchUtilsTests.cs
@@ -47,7 +47,7 @@ public void CombineTest_BothArraysContainElements()
}
[TestMethod]
- public void CombineTest_FirstArrayEmty()
+ public void CombineTest_FirstArrayEmpty()
{
var population1 = new IChromosome[] {};
var population2 = new[] { chromosome1, chromosome2 , chromosome3 };
diff --git a/GeneticAlgorithm.UnitTests/SetAndGetPopulationTests.cs b/GeneticAlgorithm.UnitTests/SetAndGetPopulationTests.cs
index c542251..e9e9ef4 100644
--- a/GeneticAlgorithm.UnitTests/SetAndGetPopulationTests.cs
+++ b/GeneticAlgorithm.UnitTests/SetAndGetPopulationTests.cs
@@ -1,4 +1,5 @@
-using System.Threading.Tasks;
+using System;
+using System.Threading.Tasks;
using GeneticAlgorithm.Exceptions;
using GeneticAlgorithm.UnitTests.TestUtils;
using Microsoft.VisualStudio.TestTools.UnitTesting;
@@ -26,30 +27,39 @@ public void GetCurrentPopulation_EngineRunning_ThrowException()
[ExpectedException(typeof(EngineAlreadyRunningException))]
public void SetCurrentPopulation_EngineRunning_ThrowException()
{
- var engine =
- new TestGeneticSearchEngineBuilder(2, int.MaxValue, new TestPopulationManager(new double[] { 2, 2 })).Build();
-
- Task.Run(() => engine.Run());
- while (!engine.IsRunning) ;
-
- engine.SetCurrentPopulation(new double[] { 3, 3 }.ToChromosomes("Converted"));
-
- Assert.Fail("Should have thrown an exception by now");
+ Utils.RunTimedTest(() =>
+ {
+ var engine =
+ new TestGeneticSearchEngineBuilder(2, int.MaxValue, new TestPopulationManager(new double[] { 2, 2 })).Build();
+
+ Task.Run(() => engine.Run());
+ while (!engine.IsRunning) ;
+
+ engine.SetCurrentPopulation(new double[] { 3, 3 }.ToChromosomes("Converted"));
+
+ if (engine.IsRunning)
+ Assert.Fail("Should have thrown an exception.");
+ else
+ Assert.Fail("For some reason, the engine is no longer running.");
+ });
}
[TestMethod]
[ExpectedException(typeof(GeneticAlgorithmException))]
public void SetCurrentPopulation_WrongNumberOfChromosomes_ThrowException()
{
- var engine =
+ Utils.RunTimedTest(() =>
+ {
+ var engine =
new TestGeneticSearchEngineBuilder(2, int.MaxValue, new TestPopulationManager(new double[] { 2, 2 })).Build();
- Task.Run(() => engine.Run());
- while (!engine.IsRunning) ;
+ Task.Run(() => engine.Run());
+ while (!engine.IsRunning) ;
- engine.SetCurrentPopulation(new double[] { 3, 3, 3 }.ToChromosomes("Converted"));
+ engine.SetCurrentPopulation(new double[] { 3, 3, 3 }.ToChromosomes("Converted"));
- Assert.Fail("Should have thrown an exception by now");
+ Assert.Fail("Should have thrown an exception by now");
+ });
}
[TestMethod]
diff --git a/GeneticAlgorithm.UnitTests/StartAndPauseTests.cs b/GeneticAlgorithm.UnitTests/StartAndPauseTests.cs
index 654dae5..17b694d 100644
--- a/GeneticAlgorithm.UnitTests/StartAndPauseTests.cs
+++ b/GeneticAlgorithm.UnitTests/StartAndPauseTests.cs
@@ -38,7 +38,7 @@ public void IsRunningTest(bool engineRunning)
if (engineRunning)
Task.Run(() => engine.Run());
- Thread.Sleep(10);
+ Thread.Sleep(100);
Assert.AreEqual(engineRunning, engine.IsRunning);
}
diff --git a/GeneticAlgorithm.UnitTests/StopManagerTests.cs b/GeneticAlgorithm.UnitTests/StopManagerTests.cs
index 1864669..9ffe346 100644
--- a/GeneticAlgorithm.UnitTests/StopManagerTests.cs
+++ b/GeneticAlgorithm.UnitTests/StopManagerTests.cs
@@ -47,14 +47,17 @@ public void StopAtConvergenceTest(RunType runType)
[DataRow(RunType.Next)]
public void StopIfNoImprovmentTest1(RunType runType)
{
- var populationManager = new TestPopulationManager(new[]
- {new double[] {1, 1, 1}, new double[] {2, 2, 2}, new double[] {3, 3, 3}, new double[] {4, 4, 4}});
- var engine = new TestGeneticSearchEngineBuilder(POPULATION_SIZE, MAX_GENERATIONS, populationManager)
- .AddStopManager(new StopIfNoImprovment(3, 3)).IncludeAllHistory().Build();
+ Utils.RunTimedTest(() =>
+ {
+ var populationManager = new TestPopulationManager(new[]
+ {new double[] {1, 1, 1}, new double[] {2, 2, 2}, new double[] {3, 3, 3}, new double[] {4, 4, 4}});
+ var engine = new TestGeneticSearchEngineBuilder(POPULATION_SIZE, MAX_GENERATIONS, populationManager)
+ .AddStopManager(new StopIfNoImprovment(3, 3)).IncludeAllHistory().Build();
- var result = engine.Run(runType);
+ var result = engine.Run(runType);
- Assert.AreEqual(4, result.Generations);
+ Assert.AreEqual(4, result.Generations);
+ });
}
[TestMethod]
@@ -62,14 +65,17 @@ public void StopIfNoImprovmentTest1(RunType runType)
[DataRow(RunType.Next)]
public void StopIfNoImprovmentTest2(RunType runType)
{
- var populationManager = new TestPopulationManager(new[]
- {new double[] {1, 1, 1}, new double[] {2, 2.5, 2}, new double[] {3, 3, 3}});
- var engine = new TestGeneticSearchEngineBuilder(POPULATION_SIZE, MAX_GENERATIONS, populationManager)
- .AddStopManager(new StopIfNoImprovment(1, 0.9)).IncludeAllHistory().Build();
+ Utils.RunTimedTest(() =>
+ {
+ var populationManager = new TestPopulationManager(new[]
+ {new double[] {1, 1, 1}, new double[] {2, 2.5, 2}, new double[] {3, 3, 3}});
+ var engine = new TestGeneticSearchEngineBuilder(POPULATION_SIZE, MAX_GENERATIONS, populationManager)
+ .AddStopManager(new StopIfNoImprovment(1, 0.9)).IncludeAllHistory().Build();
- var result = engine.Run(runType);
+ var result = engine.Run(runType);
- Assert.AreEqual(3, result.Generations);
+ Assert.AreEqual(3, result.Generations);
+ });
}
[TestMethod]
@@ -77,17 +83,20 @@ public void StopIfNoImprovmentTest2(RunType runType)
[DataRow(RunType.Next)]
public void StopIfNoImprovmentTest3(RunType runType)
{
- var populationManager = new TestPopulationManager(new[]
- {
+ Utils.RunTimedTest(() =>
+ {
+ var populationManager = new TestPopulationManager(new[]
+ {
new double[] {1, 1, 1}, new double[] {2, 2, 2}, new double[] {3, 3, 3}, new double[] {4, 4, 4},
new double[] {4, 4, 4}, new double[] {4, 4, 4}
- });
- var engine = new TestGeneticSearchEngineBuilder(POPULATION_SIZE, MAX_GENERATIONS, populationManager)
- .AddStopManager(new StopIfNoImprovment(2, 0.9)).IncludeAllHistory().Build();
+ });
+ var engine = new TestGeneticSearchEngineBuilder(POPULATION_SIZE, MAX_GENERATIONS, populationManager)
+ .AddStopManager(new StopIfNoImprovment(2, 0.9)).IncludeAllHistory().Build();
- var result = engine.Run(runType);
+ var result = engine.Run(runType);
- Assert.AreEqual(6, result.Generations);
+ Assert.AreEqual(6, result.Generations);
+ });
}
[TestMethod]
@@ -95,46 +104,52 @@ public void StopIfNoImprovmentTest3(RunType runType)
[DataRow(RunType.Next)]
public void StopManagerGetsRightInfoTest(RunType runType)
{
- var generation = 0;
- var stopManager = A.Fake();
- A.CallTo(() => stopManager.ShouldStop(A._, A._, A._)).Invokes(
- (Population p, IEnvironment e, int g) =>
- {
- Assert.AreEqual(generation, g, "Wrong generation");
- foreach (var chromosome in p.GetChromosomes())
- Assert.AreEqual(generation + 1, chromosome.Evaluate(), "Wrong chromosome");
- foreach (var evaluation in p.GetEvaluations())
- Assert.AreEqual(generation + 1, evaluation, "Wrong evaluation");
- generation++;
-
- });
- var populationManager = new TestPopulationManager(new[]
- {new double[] {1, 1, 1}, new double[] {2, 2, 2}, new double[] {3, 3, 3}});
- var engine = new TestGeneticSearchEngineBuilder(POPULATION_SIZE, 3, populationManager)
- .AddStopManager(stopManager).IncludeAllHistory().Build();
-
- engine.Run(runType);
+ Utils.RunTimedTest(() =>
+ {
+ var generation = 0;
+ var stopManager = A.Fake();
+ A.CallTo(() => stopManager.ShouldStop(A._, A._, A._)).Invokes(
+ (Population p, IEnvironment e, int g) =>
+ {
+ Assert.AreEqual(generation, g, "Wrong generation");
+ foreach (var chromosome in p.GetChromosomes())
+ Assert.AreEqual(generation + 1, chromosome.Evaluate(), "Wrong chromosome");
+ foreach (var evaluation in p.GetEvaluations())
+ Assert.AreEqual(generation + 1, evaluation, "Wrong evaluation");
+ generation++;
+
+ });
+ var populationManager = new TestPopulationManager(new[]
+ {new double[] {1, 1, 1}, new double[] {2, 2, 2}, new double[] {3, 3, 3}});
+ var engine = new TestGeneticSearchEngineBuilder(POPULATION_SIZE, 3, populationManager)
+ .AddStopManager(stopManager).IncludeAllHistory().Build();
+
+ engine.Run(runType);
+ });
}
[TestMethod]
public void AddMultipleStopManagers_AllManagersAreCalled()
{
- bool manager1Called = false, manager2Called = false;
- var testPopulationManager = new TestPopulationManager(new double[] { 1, 1, 1, 1, 1 });
- var managers = new[] { A.Fake(), A.Fake() };
- A.CallTo(() => managers[0].ShouldStop(A._, A._, A._))
- .Invokes((Population p, IEnvironment e, int g) => manager1Called = true);
- A.CallTo(() => managers[1].ShouldStop(A._, A._, A._))
- .Invokes((Population p, IEnvironment e, int g) => manager2Called = true);
-
- var engine = new TestGeneticSearchEngineBuilder(5, 10, testPopulationManager)
- .AddStopManagers(managers)
- .Build();
-
- engine.Next();
-
- Assert.IsTrue(manager1Called);
- Assert.IsTrue(manager2Called);
+ Utils.RunTimedTest(() =>
+ {
+ bool manager1Called = false, manager2Called = false;
+ var testPopulationManager = new TestPopulationManager(new double[] { 1, 1, 1, 1, 1 });
+ var managers = new[] { A.Fake(), A.Fake() };
+ A.CallTo(() => managers[0].ShouldStop(A._, A._, A._))
+ .Invokes((Population p, IEnvironment e, int g) => manager1Called = true);
+ A.CallTo(() => managers[1].ShouldStop(A._, A._, A._))
+ .Invokes((Population p, IEnvironment e, int g) => manager2Called = true);
+
+ var engine = new TestGeneticSearchEngineBuilder(5, 10, testPopulationManager)
+ .AddStopManagers(managers)
+ .Build();
+
+ engine.Next();
+
+ Assert.IsTrue(manager1Called);
+ Assert.IsTrue(manager2Called);
+ });
}
}
}
diff --git a/GeneticAlgorithm.UnitTests/TestUtils/Assertions.cs b/GeneticAlgorithm.UnitTests/TestUtils/Assertions.cs
index 8568e64..7e9afaf 100644
--- a/GeneticAlgorithm.UnitTests/TestUtils/Assertions.cs
+++ b/GeneticAlgorithm.UnitTests/TestUtils/Assertions.cs
@@ -92,10 +92,10 @@ public static void AssertThrowAggretateExceptionOfType(Action action, Type excep
}
}
- public static void AssertIsWithinRange(this int value, double expactedValue, double margenOfError)
+ public static void AssertIsWithinRange(this int value, double expactedValue, double marginOfError)
{
- Assert.IsTrue(value >= expactedValue - margenOfError, $"Value ({value}) is too small (expacted value = {expactedValue})");
- Assert.IsTrue(value <= expactedValue + margenOfError, $"Value ({value}) is too big (expacted value = {expactedValue})");
+ Assert.IsTrue(value >= expactedValue - marginOfError, $"Value ({value}) is too small (expacted value = {expactedValue})");
+ Assert.IsTrue(value <= expactedValue + marginOfError, $"Value ({value}) is too big (expacted value = {expactedValue})");
}
}
}
diff --git a/GeneticAlgorithm.UnitTests/TestUtils/TestPopulationManager.cs b/GeneticAlgorithm.UnitTests/TestUtils/TestPopulationManager.cs
index 678240b..05bfe43 100644
--- a/GeneticAlgorithm.UnitTests/TestUtils/TestPopulationManager.cs
+++ b/GeneticAlgorithm.UnitTests/TestUtils/TestPopulationManager.cs
@@ -1,4 +1,5 @@
using System;
+using System.Threading;
using FakeItEasy;
using GeneticAlgorithm.Interfaces;
@@ -23,7 +24,7 @@ public TestPopulationManager(double[][] populationEvaluation)
});
}
- public TestPopulationManager(double[] populationEvaluation, Func nextGenerationEvaluationFunc = null)
+ public TestPopulationManager(double[] populationEvaluation, Func nextGenerationEvaluationFunc = null, int millisecondsPerGeneration = 0)
{
GenerateInitailPopulation(populationEvaluation);
@@ -33,6 +34,7 @@ public TestPopulationManager(double[] populationEvaluation, Func childrenGenerator.GenerateChildren(A._, A._, A._, A._)).ReturnsLazily(
(Population p, int n, int g, IEnvironment e) =>
{
+ Thread.Sleep(millisecondsPerGeneration);
index++;
var newEvaluation = new double[populationEvaluation.Length];
diff --git a/GeneticAlgorithm.UnitTests/TestUtils/Utils.cs b/GeneticAlgorithm.UnitTests/TestUtils/Utils.cs
index e663eb5..60d3713 100644
--- a/GeneticAlgorithm.UnitTests/TestUtils/Utils.cs
+++ b/GeneticAlgorithm.UnitTests/TestUtils/Utils.cs
@@ -1,5 +1,7 @@
using GeneticAlgorithm.Components.Chromosomes;
using GeneticAlgorithm.Interfaces;
+using System;
+using System.Threading.Tasks;
namespace GeneticAlgorithm.UnitTests.TestUtils
{
@@ -47,5 +49,26 @@ public static int ToInt(this T value)
///
public static T[] ToArray(this IChromosome chromosome) =>
((VectorChromosome)chromosome).GetVector();
+
+ ///
+ /// If the action dosn't finish in time, the test is terminated and failes.
+ ///
+ public static void RunTimedTest(Action action, TimeSpan? time = null)
+ {
+ if (time == null)
+ time = TimeSpan.FromSeconds(1);
+
+ var task = Task.Run(action);
+ try
+ {
+ task.Wait(time.Value);
+ }
+ catch (AggregateException e)
+ {
+ throw e.InnerException;
+ }
+ if (!task.IsCompleted)
+ throw new Exception($"{nameof(action)} didn't finish in time.");
+ }
}
}
diff --git a/GeneticAlgorithm.UnitTests/UpdatePopulationTests.cs b/GeneticAlgorithm.UnitTests/UpdatePopulationTests.cs
index 6113af2..bbefece 100644
--- a/GeneticAlgorithm.UnitTests/UpdatePopulationTests.cs
+++ b/GeneticAlgorithm.UnitTests/UpdatePopulationTests.cs
@@ -110,18 +110,21 @@ public void RenewPopulationViaManager_RenewedPopulationUpdated()
[TestMethod]
public void ConvertPopulation_NewPopulationUpdated()
{
- var initialPopulation = new double[] { 2, 2 };
- var newPopulation = new double[] { 3, 3 };
- var populationManager = new TestPopulationManager(initialPopulation);
+ Utils.RunTimedTest(() =>
+ {
+ var initialPopulation = new double[] { 2, 2 };
+ var newPopulation = new double[] { 3, 3 };
+ var populationManager = new TestPopulationManager(initialPopulation);
- var engine = CreateEngineBuilder(populationManager).Build();
- engine.OnNewGeneration += populationUpdatedOnEvent.Save;
+ var engine = CreateEngineBuilder(populationManager).Build();
+ engine.OnNewGeneration += populationUpdatedOnEvent.Save;
- engine.Next();
+ engine.Next();
- engine.SetCurrentPopulation(newPopulation.ToChromosomes("Converted"));
+ engine.SetCurrentPopulation(newPopulation.ToChromosomes("Converted"));
- AssertManagersUpdated(new[] { initialPopulation, newPopulation });
+ AssertManagersUpdated(new[] { initialPopulation, newPopulation });
+ });
}
[TestMethod]
diff --git a/GeneticAlgorithm/ChildrenGenerator.cs b/GeneticAlgorithm/ChildrenGenerator.cs
index 36b2d84..6314fd8 100644
--- a/GeneticAlgorithm/ChildrenGenerator.cs
+++ b/GeneticAlgorithm/ChildrenGenerator.cs
@@ -60,7 +60,7 @@ private void CheckMuationProbability(double probability)
{
if (probability >= 0 && probability <= 1) return;
- if (mutationManager.GetType() == typeof(BassicMutationProbabilityManager))
+ if (mutationManager.GetType() == typeof(BasicMutationProbabilityManager))
throw new InternalSearchException(
$"Code 1004 (Bad mutation value for manager {mutationManager.GetType()})");
throw new BadMutationProbabilityException(probability);
diff --git a/GeneticAlgorithm/Components/ComponetsUtils.cs b/GeneticAlgorithm/Components/ComponetsUtils.cs
index cfcd27c..464cc73 100644
--- a/GeneticAlgorithm/Components/ComponetsUtils.cs
+++ b/GeneticAlgorithm/Components/ComponetsUtils.cs
@@ -4,10 +4,10 @@ namespace GeneticAlgorithm.Components
{
static class ComponetsUtils
{
- public static (int, int) GetTwoRandomNumbers(this Random random, int max)
+ public static (int, int) GetTwoRandomNumbers(int max)
{
- var num1 = random.Next(max);
- var num2 = random.Next(max);
+ var num1 = ProbabilityUtils.GetRandomInt(0, max);
+ var num2 = ProbabilityUtils.GetRandomInt(0, max);
return (Math.Min(num1, num2), Math.Max(num1, num2));
}
diff --git a/GeneticAlgorithm/Components/CrossoverManagers/EdgeRecombinationCrossover.cs b/GeneticAlgorithm/Components/CrossoverManagers/EdgeRecombinationCrossover.cs
index 79d67e0..997a1df 100644
--- a/GeneticAlgorithm/Components/CrossoverManagers/EdgeRecombinationCrossover.cs
+++ b/GeneticAlgorithm/Components/CrossoverManagers/EdgeRecombinationCrossover.cs
@@ -23,7 +23,6 @@ public class EdgeRecombinationCrossover : ICrossoverManager
{
private readonly IMutationManager mutationManager;
private readonly IEvaluator evaluator;
- private readonly Random random = new Random();
///
/// EdgeRecombinationCrossover Works on chromosomes of type VectorChromosome<T>.
@@ -44,7 +43,7 @@ public IChromosome Crossover(IChromosome chromosome1, IChromosome chromosome2)
var vector1 = ((VectorChromosome)chromosome1).GetVector();
var vector2 = ((VectorChromosome)chromosome2).GetVector();
var length = vector1.Length;
- var firstElement = vector1[random.Next(0, vector1.Length)];
+ var firstElement = vector1[ProbabilityUtils.GetRandomInt(0, vector1.Length)];
var childArray = new NonReapetingAdjacencyMatrix(vector1, vector2, true).Crossover(firstElement, length);
return new VectorChromosome(childArray, mutationManager, evaluator);
diff --git a/GeneticAlgorithm/Components/CrossoverManagers/GeneralEdgeRecombinationCrossover.cs b/GeneticAlgorithm/Components/CrossoverManagers/GeneralEdgeRecombinationCrossover.cs
index 660950c..8df38da 100644
--- a/GeneticAlgorithm/Components/CrossoverManagers/GeneralEdgeRecombinationCrossover.cs
+++ b/GeneticAlgorithm/Components/CrossoverManagers/GeneralEdgeRecombinationCrossover.cs
@@ -16,7 +16,6 @@ public class GeneralEdgeRecombinationCrossover : ICrossoverManager
{
private readonly IMutationManager mutationManager;
private readonly IEvaluator evaluator;
- private readonly Random random = new Random();
public GeneralEdgeRecombinationCrossover(IMutationManager mutationManager, IEvaluator evaluator)
{
@@ -29,7 +28,7 @@ public IChromosome Crossover(IChromosome chromosome1, IChromosome chromosome2)
var vector1 = ((VectorChromosome)chromosome1).GetVector();
var vector2 = ((VectorChromosome)chromosome2).GetVector();
var length = vector1.Length;
- var firstElement = vector1[random.Next(0, vector1.Length)];
+ var firstElement = vector1[ProbabilityUtils.GetRandomInt(0, vector1.Length)];
var childArray = new ReapetingAdjacencyMatrix(vector1, vector2).Crossover(firstElement, length);
return new VectorChromosome(childArray, mutationManager, evaluator);
diff --git a/GeneticAlgorithm/Components/CrossoverManagers/HeuristicCrossover.cs b/GeneticAlgorithm/Components/CrossoverManagers/HeuristicCrossover.cs
index 8786dc2..bb4718f 100644
--- a/GeneticAlgorithm/Components/CrossoverManagers/HeuristicCrossover.cs
+++ b/GeneticAlgorithm/Components/CrossoverManagers/HeuristicCrossover.cs
@@ -23,7 +23,6 @@ public class HeuristicCrossover : ICrossoverManager
{
private readonly IMutationManager mutationManager;
private readonly IEvaluator evaluator;
- private readonly Random random = new Random();
///
/// HeuristicCrossover Works on chromosomes of type VectorChromosome<T>.
@@ -44,7 +43,7 @@ public IChromosome Crossover(IChromosome chromosome1, IChromosome chromosome2)
var vector1 = ((VectorChromosome)chromosome1).GetVector();
var vector2 = ((VectorChromosome)chromosome2).GetVector();
var length = vector1.Length;
- var firstElement = vector1[random.Next(0, vector1.Length)];
+ var firstElement = vector1[ProbabilityUtils.GetRandomInt(0, vector1.Length)];
var childArray = new NonReapetingAdjacencyMatrix(vector1, vector2, false).Crossover(firstElement, length);
return new VectorChromosome(childArray, mutationManager, evaluator);
diff --git a/GeneticAlgorithm/Components/CrossoverManagers/OrderBasedCrossover.cs b/GeneticAlgorithm/Components/CrossoverManagers/OrderBasedCrossover.cs
index 85dd20e..5a6b4c1 100644
--- a/GeneticAlgorithm/Components/CrossoverManagers/OrderBasedCrossover.cs
+++ b/GeneticAlgorithm/Components/CrossoverManagers/OrderBasedCrossover.cs
@@ -22,7 +22,6 @@ namespace GeneticAlgorithm.Components.CrossoverManagers
///
public class OrderBasedCrossover : ICrossoverManager
{
- private readonly Random random = new Random();
private readonly IMutationManager mutationManager;
private readonly IEvaluator evaluator;
@@ -45,7 +44,7 @@ public IChromosome Crossover(IChromosome chromosome1, IChromosome chromosome2)
var vector1 = ((VectorChromosome)chromosome1).GetVector();
var vector2 = ((VectorChromosome)chromosome2).GetVector();
var length = vector1.Length;
- var indexes = ProbabilityUtils.SelectKRandomNumbersNonRepeating(length, random.Next(length));
+ var indexes = ProbabilityUtils.SelectKRandomNumbersNonRepeating(length, ProbabilityUtils.GetRandomInt(0, length));
var elementsFromParent2 = new HashSet();
var elementsFromParent2OrderedByIndex = new List();
diff --git a/GeneticAlgorithm/Components/CrossoverManagers/OrderCrossover.cs b/GeneticAlgorithm/Components/CrossoverManagers/OrderCrossover.cs
index 26a57a9..d72e2c2 100644
--- a/GeneticAlgorithm/Components/CrossoverManagers/OrderCrossover.cs
+++ b/GeneticAlgorithm/Components/CrossoverManagers/OrderCrossover.cs
@@ -45,7 +45,7 @@ public IChromosome Crossover(IChromosome chromosome1, IChromosome chromosome2)
var vector2 = ((VectorChromosome) chromosome2).GetVector();
var length = vector1.Length;
- (var start, var end) = random.GetTwoRandomNumbers(length + 1);
+ (var start, var end) = ComponetsUtils.GetTwoRandomNumbers(length + 1);
var genomesFromChromosome1 = new HashSet();
for (int i = start; i < end; i++)
genomesFromChromosome1.Add(vector1[i]);
diff --git a/GeneticAlgorithm/Components/CrossoverManagers/PartiallyMappedCrossover.cs b/GeneticAlgorithm/Components/CrossoverManagers/PartiallyMappedCrossover.cs
index 1d71540..3a612b4 100644
--- a/GeneticAlgorithm/Components/CrossoverManagers/PartiallyMappedCrossover.cs
+++ b/GeneticAlgorithm/Components/CrossoverManagers/PartiallyMappedCrossover.cs
@@ -20,7 +20,6 @@ namespace GeneticAlgorithm.Components.CrossoverManagers
///
public class PartiallyMappedCrossover : ICrossoverManager
{
- private readonly Random random = new Random();
private readonly IMutationManager mutationManager;
private readonly IEvaluator evaluator;
@@ -45,7 +44,7 @@ public IChromosome Crossover(IChromosome chromosome1, IChromosome chromosome2)
var indexManager = new IndexManager(vector2);
var length = vector1.Length;
- (var start, var end) = random.GetTwoRandomNumbers(length + 1);
+ (var start, var end) = ComponetsUtils.GetTwoRandomNumbers(length + 1);
var addedIndexes = new List();
var genomesFromChromosome1 = new List();
for (int i = start; i < end; i++)
diff --git a/GeneticAlgorithm/Components/CrossoverManagers/PositionBasedCrossoverManager.cs b/GeneticAlgorithm/Components/CrossoverManagers/PositionBasedCrossoverManager.cs
index 5195910..17a1522 100644
--- a/GeneticAlgorithm/Components/CrossoverManagers/PositionBasedCrossoverManager.cs
+++ b/GeneticAlgorithm/Components/CrossoverManagers/PositionBasedCrossoverManager.cs
@@ -21,7 +21,6 @@ namespace GeneticAlgorithm.Components.CrossoverManagers
///
public class PositionBasedCrossoverManager : ICrossoverManager
{
- private readonly Random random = new Random();
private readonly IMutationManager mutationManager;
private readonly IEvaluator evaluator;
@@ -44,7 +43,7 @@ public IChromosome Crossover(IChromosome chromosome1, IChromosome chromosome2)
var vector1 = ((VectorChromosome)chromosome1).GetVector();
var vector2 = ((VectorChromosome)chromosome2).GetVector();
var length = vector1.Length;
- var indexesToTakeFromParent1 = ProbabilityUtils.SelectKRandomNumbersNonRepeating(length, random.Next(length));
+ var indexesToTakeFromParent1 = ProbabilityUtils.SelectKRandomNumbersNonRepeating(length, ProbabilityUtils.GetRandomInt(0, length));
var genomesFromChromosome1 = new HashSet();
var newVector = new T[length];
diff --git a/GeneticAlgorithm/Components/CrossoverManagers/Utilities/NonReapetingAdjacencyMatrix.cs b/GeneticAlgorithm/Components/CrossoverManagers/Utilities/NonReapetingAdjacencyMatrix.cs
index 527d5d3..75211b0 100644
--- a/GeneticAlgorithm/Components/CrossoverManagers/Utilities/NonReapetingAdjacencyMatrix.cs
+++ b/GeneticAlgorithm/Components/CrossoverManagers/Utilities/NonReapetingAdjacencyMatrix.cs
@@ -10,7 +10,6 @@ namespace GeneticAlgorithm.Components.CrossoverManagers.Utilities
///
public class NonReapetingAdjacencyMatrix : IAdjacencyMatrix
{
- private readonly Random random = new Random();
private readonly Dictionary> adjacencyMatrix = new Dictionary>();
///
@@ -34,13 +33,13 @@ public T GetNeighbor(T element)
var neighbors = adjacencyMatrix[element];
Remove(element, neighbors);
if (neighbors.Count == 0)
- return adjacencyMatrix.Keys.ElementAt(random.Next(adjacencyMatrix.Count));
+ return adjacencyMatrix.Keys.ElementAt(ProbabilityUtils.GetRandomInt(adjacencyMatrix.Count));
if (!selectNeighborWithLeastNeighbors)
- return neighbors.ElementAt(random.Next(neighbors.Count));
+ return neighbors.ElementAt(ProbabilityUtils.GetRandomInt(neighbors.Count));
var elemenetsWithMinNeighbors = FindNeighborsWithLeaseNeighbors(neighbors);
- return elemenetsWithMinNeighbors[random.Next(elemenetsWithMinNeighbors.Count)];
+ return elemenetsWithMinNeighbors[ProbabilityUtils.GetRandomInt(elemenetsWithMinNeighbors.Count)];
}
private List FindNeighborsWithLeaseNeighbors(LinkedList neighbors)
diff --git a/GeneticAlgorithm/Components/CrossoverManagers/Utilities/ReapetingAdjacencyMatrix.cs b/GeneticAlgorithm/Components/CrossoverManagers/Utilities/ReapetingAdjacencyMatrix.cs
index d163b7f..74c4e38 100644
--- a/GeneticAlgorithm/Components/CrossoverManagers/Utilities/ReapetingAdjacencyMatrix.cs
+++ b/GeneticAlgorithm/Components/CrossoverManagers/Utilities/ReapetingAdjacencyMatrix.cs
@@ -10,17 +10,15 @@ namespace GeneticAlgorithm.Components.CrossoverManagers.Utilities
///
public class ReapetingAdjacencyMatrix : IAdjacencyMatrix
{
- private readonly Random random = new Random();
private readonly Dictionary> adjacencyMatrix = new Dictionary>();
-
public T GetNeighbor(T element)
{
var neighbors = adjacencyMatrix[element];
if (neighbors.Count == 0)
- return adjacencyMatrix.Keys.ElementAt(random.Next(adjacencyMatrix.Count));
+ return adjacencyMatrix.Keys.ElementAt(ProbabilityUtils.GetRandomInt(adjacencyMatrix.Count));
- return neighbors.ElementAt(random.Next(neighbors.Count));
+ return neighbors.ElementAt(ProbabilityUtils.GetRandomInt(neighbors.Count));
}
public ReapetingAdjacencyMatrix(T[] vector1, T[] vector2)
diff --git a/GeneticAlgorithm/Components/MutationManagers/DisplacementMutationBase.cs b/GeneticAlgorithm/Components/MutationManagers/DisplacementMutationBase.cs
index e6ce34f..16c6c11 100644
--- a/GeneticAlgorithm/Components/MutationManagers/DisplacementMutationBase.cs
+++ b/GeneticAlgorithm/Components/MutationManagers/DisplacementMutationBase.cs
@@ -14,7 +14,6 @@ namespace GeneticAlgorithm.Components.MutationManagers
///
class DisplacementMutationBase : IMutationManager
{
- private readonly Random random = new Random();
private readonly bool inversionSttretch;
public DisplacementMutationBase(bool inversionSttretch)
@@ -24,8 +23,8 @@ public DisplacementMutationBase(bool inversionSttretch)
public T[] Mutate(T[] vector)
{
- (var start, var end) = random.GetTwoRandomNumbers(vector.Length + 1);
- var insertionIndex = random.Next(vector.Length - (end - start));
+ (var start, var end) = ComponetsUtils.GetTwoRandomNumbers(vector.Length + 1);
+ var insertionIndex = ProbabilityUtils.GetRandomInt(vector.Length - (end - start));
var vectorWithoutStretch = new T[vector.Length - (end - start)];
for (int i = 0; i < start; i++)
vectorWithoutStretch[i] = vector[i];
diff --git a/GeneticAlgorithm/Components/MutationManagers/DoubleUniformMutationManager.cs b/GeneticAlgorithm/Components/MutationManagers/DoubleUniformMutationManager.cs
index 946d207..82e6fe5 100644
--- a/GeneticAlgorithm/Components/MutationManagers/DoubleUniformMutationManager.cs
+++ b/GeneticAlgorithm/Components/MutationManagers/DoubleUniformMutationManager.cs
@@ -11,7 +11,6 @@ public class DoubleUniformMutationManager : IMutationManager
{
private readonly double minValue;
private readonly double range;
- private readonly Random random = new Random();
public DoubleUniformMutationManager(double minValue, double maxValue)
{
@@ -23,7 +22,7 @@ public double[] Mutate(double[] vector)
{
for (int i = 0; i < vector.Length; i++)
if (ProbabilityUtils.P(1.0 / vector.Length))
- vector[i] = minValue + random.NextDouble() * range;
+ vector[i] = minValue + ProbabilityUtils.GetRandomDouble() * range;
return vector;
}
diff --git a/GeneticAlgorithm/Components/MutationManagers/ExchangeMutationManager.cs b/GeneticAlgorithm/Components/MutationManagers/ExchangeMutationManager.cs
index 618c0f9..f3d66c9 100644
--- a/GeneticAlgorithm/Components/MutationManagers/ExchangeMutationManager.cs
+++ b/GeneticAlgorithm/Components/MutationManagers/ExchangeMutationManager.cs
@@ -9,12 +9,10 @@ namespace GeneticAlgorithm.Components.MutationManagers
///
public class ExchangeMutationManager : IMutationManager
{
- private readonly Random random = new Random();
-
public T[] Mutate(T[] vector)
{
- int from = random.Next(vector.Length);
- int to = random.Next(vector.Length);
+ int from = ProbabilityUtils.GetRandomInt(vector.Length);
+ int to = ProbabilityUtils.GetRandomInt(vector.Length);
var temp = vector[to];
vector[to] = vector[from];
diff --git a/GeneticAlgorithm/Components/MutationManagers/InsertionMutationManager.cs b/GeneticAlgorithm/Components/MutationManagers/InsertionMutationManager.cs
index 488b475..cbf0f58 100644
--- a/GeneticAlgorithm/Components/MutationManagers/InsertionMutationManager.cs
+++ b/GeneticAlgorithm/Components/MutationManagers/InsertionMutationManager.cs
@@ -9,12 +9,10 @@ namespace GeneticAlgorithm.Components.MutationManagers
///
public class InsertionMutationManager : IMutationManager
{
- private readonly Random random = new Random();
-
public T[] Mutate(T[] vector)
{
- var toRemove = random.Next(vector.Length);
- var insertAt = random.Next(vector.Length);
+ var toRemove = ProbabilityUtils.GetRandomInt(vector.Length);
+ var insertAt = ProbabilityUtils.GetRandomInt(vector.Length);
var newVector = new T[vector.Length];
if (toRemove < insertAt)
diff --git a/GeneticAlgorithm/Components/MutationManagers/IntUniformMutationManager.cs b/GeneticAlgorithm/Components/MutationManagers/IntUniformMutationManager.cs
index f0bbc9b..3165eaf 100644
--- a/GeneticAlgorithm/Components/MutationManagers/IntUniformMutationManager.cs
+++ b/GeneticAlgorithm/Components/MutationManagers/IntUniformMutationManager.cs
@@ -11,7 +11,6 @@ public class IntUniformMutationManager : IMutationManager
{
private readonly int minValue;
private readonly int maxValue;
- private readonly Random random = new Random();
public IntUniformMutationManager(int minValue, int maxValue)
{
@@ -23,7 +22,7 @@ public int[] Mutate(int[] vector)
{
for (int i = 0; i < vector.Length; i++)
if (ProbabilityUtils.P(1.0 / vector.Length))
- vector[i] = random.Next(minValue, maxValue + 1);
+ vector[i] = ProbabilityUtils.GetRandomInt(minValue, maxValue + 1);
return vector;
}
diff --git a/GeneticAlgorithm/Components/MutationManagers/ScrambleMutationManager.cs b/GeneticAlgorithm/Components/MutationManagers/ScrambleMutationManager.cs
index 8bd4c1f..81b7dea 100644
--- a/GeneticAlgorithm/Components/MutationManagers/ScrambleMutationManager.cs
+++ b/GeneticAlgorithm/Components/MutationManagers/ScrambleMutationManager.cs
@@ -10,12 +10,10 @@ namespace GeneticAlgorithm.Components.MutationManagers
///
public class ScrambleMutationManager : IMutationManager
{
- private readonly Random random = new Random();
-
public T[] Mutate(T[] vector)
{
- (var start, var end) = random.GetTwoRandomNumbers(vector.Length + 1);
- var scrambledGenomes = vector.Skip(start).Take(end - start).ToArray().Shuffle(random);
+ (var start, var end) = ComponetsUtils.GetTwoRandomNumbers(vector.Length + 1);
+ var scrambledGenomes = vector.Skip(start).Take(end - start).ToArray().Shuffle();
var newVector = new T[vector.Length];
for (int i = 0; i < start; i++)
diff --git a/GeneticAlgorithm/Components/MutationManagers/SimpleInversionMutationManager.cs b/GeneticAlgorithm/Components/MutationManagers/SimpleInversionMutationManager.cs
index c73005f..95691a0 100644
--- a/GeneticAlgorithm/Components/MutationManagers/SimpleInversionMutationManager.cs
+++ b/GeneticAlgorithm/Components/MutationManagers/SimpleInversionMutationManager.cs
@@ -9,11 +9,9 @@ namespace GeneticAlgorithm.Components.MutationManagers
///
public class SimpleInversionMutationManager : IMutationManager
{
- private readonly Random random = new Random();
-
public T[] Mutate(T[] vector)
{
- (var start, var end) = random.GetTwoRandomNumbers(vector.Length + 1);
+ (var start, var end) = ComponetsUtils.GetTwoRandomNumbers(vector.Length + 1);
var newVector = new T[vector.Length];
for (int i = 0; i < start; i++)
diff --git a/GeneticAlgorithm/Exceptions/GeneticAlgorithmArgumentException.cs b/GeneticAlgorithm/Exceptions/GeneticAlgorithmArgumentException.cs
new file mode 100644
index 0000000..0f4683f
--- /dev/null
+++ b/GeneticAlgorithm/Exceptions/GeneticAlgorithmArgumentException.cs
@@ -0,0 +1,16 @@
+namespace GeneticAlgorithm.Exceptions
+{
+ public class GeneticAlgorithmArgumentException : GeneticAlgorithmException
+ {
+ public GeneticAlgorithmArgumentException(string message) :
+ base(message)
+ {
+ }
+
+ ///
+ /// Returns an exception stating that argument name was smaller than zero.
+ ///
+ public static GeneticAlgorithmArgumentException SmallerThanZeroException(string argumentName, double value) =>
+ new GeneticAlgorithmArgumentException($"{argumentName} was {value}. {argumentName} must be at least zero!");
+ }
+}
diff --git a/GeneticAlgorithm/GeneticSearchEngineBuilder.cs b/GeneticAlgorithm/GeneticSearchEngineBuilder.cs
index f2d8403..39cf404 100644
--- a/GeneticAlgorithm/GeneticSearchEngineBuilder.cs
+++ b/GeneticAlgorithm/GeneticSearchEngineBuilder.cs
@@ -175,7 +175,7 @@ protected void PreBuildActions()
environment = new DefaultEnvironment();
if (mutationManager == null)
- mutationManager = new BassicMutationProbabilityManager(mutationProbability);
+ mutationManager = new BasicMutationProbabilityManager(mutationProbability);
}
public virtual GeneticSearchEngine Build()
diff --git a/GeneticAlgorithm/MutationProbabilityManagers/BassicMutationProbabilityManager.cs b/GeneticAlgorithm/MutationProbabilityManagers/BasicMutationProbabilityManager.cs
similarity index 81%
rename from GeneticAlgorithm/MutationProbabilityManagers/BassicMutationProbabilityManager.cs
rename to GeneticAlgorithm/MutationProbabilityManagers/BasicMutationProbabilityManager.cs
index 3adbdd7..a7c2fcc 100644
--- a/GeneticAlgorithm/MutationProbabilityManagers/BassicMutationProbabilityManager.cs
+++ b/GeneticAlgorithm/MutationProbabilityManagers/BasicMutationProbabilityManager.cs
@@ -3,11 +3,11 @@
namespace GeneticAlgorithm.MutationManagers
{
- public class BassicMutationProbabilityManager : IMutationProbabilityManager
+ public class BasicMutationProbabilityManager : IMutationProbabilityManager
{
private readonly double mutation;
- public BassicMutationProbabilityManager(double mutation)
+ public BasicMutationProbabilityManager(double mutation)
{
if (mutation > 1 || mutation < 0)
throw new GeneticAlgorithmException(nameof(mutation) + " must be between 0.0 to 1.0 (including)");
diff --git a/GeneticAlgorithm/PopulationRenwalManagers/PopulationRenwalUtils.cs b/GeneticAlgorithm/PopulationRenwalManagers/PopulationRenwalUtils.cs
new file mode 100644
index 0000000..2d421ea
--- /dev/null
+++ b/GeneticAlgorithm/PopulationRenwalManagers/PopulationRenwalUtils.cs
@@ -0,0 +1,16 @@
+using GeneticAlgorithm.Exceptions;
+
+namespace GeneticAlgorithm.PopulationRenwalManagers
+{
+ static class PopulationRenwalUtils
+ {
+ public static void VerifyPrecentageToRenew(this double precentageToRenew)
+ {
+ if (precentageToRenew <= 0)
+ throw new GeneticAlgorithmArgumentException($"{nameof(precentageToRenew)} can't be smaller or equale to zero (was {precentageToRenew})");
+ if (precentageToRenew > 1)
+ throw new GeneticAlgorithmArgumentException($"{nameof(precentageToRenew)} can't be greater than one (was {precentageToRenew})");
+
+ }
+ }
+}
diff --git a/GeneticAlgorithm/PopulationRenwalManagers/RenewAtConvergence.cs b/GeneticAlgorithm/PopulationRenwalManagers/RenewAtConvergence.cs
index 1b0ed2d..200db00 100644
--- a/GeneticAlgorithm/PopulationRenwalManagers/RenewAtConvergence.cs
+++ b/GeneticAlgorithm/PopulationRenwalManagers/RenewAtConvergence.cs
@@ -1,4 +1,5 @@
-using GeneticAlgorithm.Interfaces;
+using GeneticAlgorithm.Exceptions;
+using GeneticAlgorithm.Interfaces;
namespace GeneticAlgorithm.PopulationRenwalManagers
{
@@ -15,6 +16,8 @@ public class RenewAtConvergence : IPopulationRenwalManager
///
public RenewAtConvergence(double diff, double precentageToRenew)
{
+ precentageToRenew.VerifyPrecentageToRenew();
+
this.precentageToRenew = precentageToRenew;
stopManager = new StopManagers.StopAtConvergence(diff);
}
diff --git a/GeneticAlgorithm/PopulationRenwalManagers/RenewAtDifferenceBetweenAverageAndMaximumFitness.cs b/GeneticAlgorithm/PopulationRenwalManagers/RenewAtDifferenceBetweenAverageAndMaximumFitness.cs
new file mode 100644
index 0000000..ce56b00
--- /dev/null
+++ b/GeneticAlgorithm/PopulationRenwalManagers/RenewAtDifferenceBetweenAverageAndMaximumFitness.cs
@@ -0,0 +1,38 @@
+using GeneticAlgorithm.Exceptions;
+using GeneticAlgorithm.Interfaces;
+using System.Linq;
+
+namespace GeneticAlgorithm.PopulationRenwalManagers
+{
+ ///
+ /// Will renew "precentageToRenew" of the population when the difference between the average and max evaluation is equal to or less than "diff".
+ ///
+ public class RenewAtDifferenceBetweenAverageAndMaximumFitness : IPopulationRenwalManager
+ {
+ private readonly double precentageToRenew;
+ private readonly double diff;
+
+ ///
+ /// Will renew "precentageToRenew" of the population when the difference between the min evaluation and max evaluation is equal to or less than "diff".
+ ///
+ public RenewAtDifferenceBetweenAverageAndMaximumFitness(double diff, double precentageToRenew)
+ {
+ precentageToRenew.VerifyPrecentageToRenew();
+ this.precentageToRenew = precentageToRenew;
+ this.diff = diff >= 0 ? diff : throw GeneticAlgorithmArgumentException.SmallerThanZeroException(nameof(diff), diff); ;
+ }
+
+ public void AddGeneration(Population population)
+ {
+ // nothing to do here
+ }
+
+ public double ShouldRenew(Population population, IEnvironment environment, int generation)
+ {
+ var max = population.Select(c => c.Evaluation).Max();
+ var average = population.Select(c => c.Evaluation).Average();
+
+ return max - average < diff ? precentageToRenew : 0;
+ }
+ }
+}
diff --git a/GeneticAlgorithm/PopulationRenwalManagers/RenewIfNoImprovment.cs b/GeneticAlgorithm/PopulationRenwalManagers/RenewIfNoImprovment.cs
index 28d05f9..5e3fa88 100644
--- a/GeneticAlgorithm/PopulationRenwalManagers/RenewIfNoImprovment.cs
+++ b/GeneticAlgorithm/PopulationRenwalManagers/RenewIfNoImprovment.cs
@@ -1,4 +1,5 @@
-using GeneticAlgorithm.Interfaces;
+using GeneticAlgorithm.Exceptions;
+using GeneticAlgorithm.Interfaces;
using GeneticAlgorithm.StopManagers;
namespace GeneticAlgorithm.PopulationRenwalManagers
@@ -16,6 +17,8 @@ public class RenewIfNoImprovment : IPopulationRenwalManager
///
public RenewIfNoImprovment(int generationsToConsider, double minImprvment, double precentageToRenew)
{
+ precentageToRenew.VerifyPrecentageToRenew();
+
this.precentageToRenew = precentageToRenew;
stopManager = new StopIfNoImprovment(generationsToConsider, minImprvment);
}
diff --git a/GeneticAlgorithm/ProbabilityUtils.cs b/GeneticAlgorithm/ProbabilityUtils.cs
index db34b93..fbca18a 100644
--- a/GeneticAlgorithm/ProbabilityUtils.cs
+++ b/GeneticAlgorithm/ProbabilityUtils.cs
@@ -6,7 +6,38 @@ namespace GeneticAlgorithm
{
public static class ProbabilityUtils
{
- private static readonly Random random = new Random();
+ private static Random random = new Random();
+ private static object randomLockObject = new object();
+
+ ///
+ /// Returens a random double between 0 and 1.
+ ///
+ public static double GetRandomDouble()
+ {
+ // We need this lock, since random isn't thread-safe
+ lock (randomLockObject)
+ return random.NextDouble();
+ }
+
+ ///
+ /// Returens a random double between min (inclusive) and max (exclusive).
+ ///
+ public static int GetRandomInt(int min, int max)
+ {
+ // We need this lock, since random isn't thread-safe
+ lock (randomLockObject)
+ return random.Next(min, max);
+ }
+
+ ///
+ /// Returens a random double between 0 (inclusive) and max (exclusive).
+ ///
+ public static int GetRandomInt(int max)
+ {
+ // We need this lock, since random isn't thread-safe
+ lock (randomLockObject)
+ return random.Next(max);
+ }
///
/// Returns true with a probability of probability - where probability is between 0 to 1 (including)
@@ -16,7 +47,7 @@ public static bool P(double probability)
if (probability > 1 || probability < 0)
throw new InternalSearchException($"Code 1008 (probability is {probability})");
- return random.NextDouble() < probability;
+ return GetRandomDouble() < probability;
}
///
@@ -68,8 +99,8 @@ public static double GaussianDistribution(double sd, double mean)
///
private static double GetStandardDistribution()
{
- var u1 = 1.0 - random.NextDouble();
- var u2 = 1.0 - random.NextDouble();
+ var u1 = 1.0 - GetRandomDouble();
+ var u2 = 1.0 - GetRandomDouble();
return Math.Sqrt(-2.0 * Math.Log(u1)) * Math.Sin(2.0 * Math.PI * u2);
}
}
diff --git a/GeneticAlgorithm/SearchUtils.cs b/GeneticAlgorithm/SearchUtils.cs
index c02cb59..9f59977 100644
--- a/GeneticAlgorithm/SearchUtils.cs
+++ b/GeneticAlgorithm/SearchUtils.cs
@@ -56,14 +56,17 @@ public static double Clip(this double value, double min, double max)
return value;
}
- public static T[] Shuffle(this ICollection collection, Random random)
+ ///
+ /// Only send the random if the compoment calling shuffle doesn't need to be thread safe.
+ ///
+ public static T[] Shuffle(this ICollection collection, Random random = null)
{
var array = collection.ToArray();
int n = array.Length;
while (n > 1)
{
n--;
- int k = random.Next(n + 1);
+ int k = random != null ? random.Next(n + 1) : ProbabilityUtils.GetRandomInt(n + 1);
T value = array[k];
array[k] = array[n];
array[n] = value;
diff --git a/GeneticAlgorithm/StopManagers/StopAtConvergence.cs b/GeneticAlgorithm/StopManagers/StopAtConvergence.cs
index f44599c..fe2b2f9 100644
--- a/GeneticAlgorithm/StopManagers/StopAtConvergence.cs
+++ b/GeneticAlgorithm/StopManagers/StopAtConvergence.cs
@@ -1,4 +1,5 @@
-using GeneticAlgorithm.Interfaces;
+using GeneticAlgorithm.Exceptions;
+using GeneticAlgorithm.Interfaces;
namespace GeneticAlgorithm.StopManagers
{
@@ -11,6 +12,9 @@ public class StopAtConvergence : IStopManager
///
public StopAtConvergence(double diff)
{
+ if (diff < 0)
+ throw GeneticAlgorithmArgumentException.SmallerThanZeroException(nameof(diff), diff);
+
this.diff = diff;
}
diff --git a/GeneticAlgorithm/StopManagers/StopAtEvaluation.cs b/GeneticAlgorithm/StopManagers/StopAtEvaluation.cs
index 1a0b2e1..30e6dbe 100644
--- a/GeneticAlgorithm/StopManagers/StopAtEvaluation.cs
+++ b/GeneticAlgorithm/StopManagers/StopAtEvaluation.cs
@@ -1,4 +1,5 @@
using System.Linq;
+using GeneticAlgorithm.Exceptions;
using GeneticAlgorithm.Interfaces;
namespace GeneticAlgorithm.StopManagers
@@ -12,6 +13,10 @@ public class StopAtEvaluation : IStopManager
///
public StopAtEvaluation(double evaluationToStopAt)
{
+ if (evaluationToStopAt < 0)
+ throw GeneticAlgorithmArgumentException.SmallerThanZeroException(nameof(evaluationToStopAt), evaluationToStopAt);
+
+
this.evaluationToStopAt = evaluationToStopAt;
}
diff --git a/GeneticAlgorithm/StopManagers/StopAtGeneration.cs b/GeneticAlgorithm/StopManagers/StopAtGeneration.cs
index 19c23da..1838736 100644
--- a/GeneticAlgorithm/StopManagers/StopAtGeneration.cs
+++ b/GeneticAlgorithm/StopManagers/StopAtGeneration.cs
@@ -3,7 +3,7 @@
namespace GeneticAlgorithm.StopManagers
{
- class StopAtGeneration : IStopManager
+ public class StopAtGeneration : IStopManager
{
private readonly int generationToStopAt;
@@ -11,7 +11,7 @@ public StopAtGeneration(int generationToStopAt)
{
this.generationToStopAt = generationToStopAt > 1
? generationToStopAt
- : throw new GeneticAlgorithmException(nameof(generationToStopAt) + " must be greater then one");
+ : throw new GeneticAlgorithmArgumentException(nameof(generationToStopAt) + " must be greater then one");
}
public bool ShouldStop(Population population, IEnvironment environment, int generation) =>
diff --git a/GeneticAlgorithm/StopManagers/StopIfNoImprovment.cs b/GeneticAlgorithm/StopManagers/StopIfNoImprovment.cs
index 412fe9a..f258d10 100644
--- a/GeneticAlgorithm/StopManagers/StopIfNoImprovment.cs
+++ b/GeneticAlgorithm/StopManagers/StopIfNoImprovment.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using GeneticAlgorithm.Exceptions;
using GeneticAlgorithm.Interfaces;
namespace GeneticAlgorithm.StopManagers
@@ -16,7 +17,9 @@ public class StopIfNoImprovment : IStopManager
///
public StopIfNoImprovment(int generationsToConsider, double minImprovment)
{
- this.generationsToConsider = generationsToConsider;
+ this.generationsToConsider = generationsToConsider > 0
+ ? generationsToConsider
+ : throw new GeneticAlgorithmArgumentException(nameof(generationsToConsider) + " must be greater then zero");
this.minImprovment = minImprovment;
}
diff --git a/README.md b/README.md
index 22a7dde..ad68b8d 100644
--- a/README.md
+++ b/README.md
@@ -50,7 +50,7 @@ Your chromosomes will need to implement the [IChromosome](/GeneticAlgorithm/Inte
public interface IChromosome
{
///
- /// Must return a value that is greater then zero
+ /// Must return a value that is greater then zero.
///
double Evaluate();
@@ -60,9 +60,12 @@ Your chromosomes will need to implement the [IChromosome](/GeneticAlgorithm/Inte
You can find a sample Chromosome [here](/GeneticAlgorithm/Components/Chromosomes/VectorChromosome.cs).
+Please note that the Evaluate and Mutate methods will be called on deferent chromosomes in parallel, so they must be thread safe in that aspect.
+
### ICrossoverManager
You'll need to implement the [ICrossoverManager](/GeneticAlgorithm/Interfaces/ICrossoverManager.cs) interface. This tells the engine how to perform crossovers for your chromosomes.
+Please note that your crossoverManager will be called on deferent chromosomes in parallel, so it must be thread safe in that aspect.
You can read more about crossovers [here](https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm)).
```CSharp
@@ -78,6 +81,7 @@ You can find some sample CrossoverManagers [here](/GeneticAlgorithm/Components/C
You'll also need to implement the [IPopulationGenerator](/GeneticAlgorithm/Interfaces/IPopulationGenerator.cs) interface. The engine uses this class to create its initial population.
The PopulationGenerator will also renew the population when needed (see [IPopulationRenwalManagers](#ipopulationrenwalmanagers)).
+PopulationGenerator doesn't need to be thread safe.
```CSharp
public interface IPopulationGenerator
@@ -190,6 +194,7 @@ In addition, [here](/GeneticAlgorithm/PopulationRenwalManagers) are some example
Existing PopulationRenwalManagers:
- [RenewAtConvergence](/GeneticAlgorithm/PopulationRenwalManagers/RenewAtConvergence.cs): The search will renew some of the population if the difference between chromosomes in the population is too small.
- [RenewIfNoImprovment](/GeneticAlgorithm/PopulationRenwalManagers/RenewIfNoImprovment.cs): Will renew some of the population if the improvement over 'X' generations isn't good enough.
+- [RenewAtDifferenceBetweenAverageAndMaximumFitness](/GeneticAlgorithm/PopulationRenwalManagers/RenewAtDifferenceBetweenAverageAndMaximumFitness.cs): Will renew some of the population when the difference between the average and max evaluation is equal too small (available since 1.3.4).
Example:
```CSharp