Skip to content

Creating a Custom StopManager

Zvi Rosenfeld edited this page Oct 6, 2019 · 5 revisions

StopManagers give you the power to terminate the search once it's no longer interesting (for instance, if the chromosomes are no longer improving, or if the chromosomes are very similar).

In this tutorial, we'll create a stop-manager that will stop the search when the improvement is over X generations is smaller than Y. (For example, if the improvement over 3 generations is less then one).

Creating a Skeleton Class

Let's start be creating a skeleton class that implements the IStopManager interface. We'll call our class StopIfNoImprovment.

    class StopIfNoImprovment : IStopManager
    {
        public bool ShouldStop(Population population, IEnvironment environment, int generation)
        {
            throw new System.NotImplementedException();
        }

        public void AddGeneration(Population population)
        {
            throw new System.NotImplementedException();
        }
    }

MinImprovment and Generations Values

Let's give the user the ability to determine the minImprovment and generations values (that is, the values that if the improvement over "generationsToConsider" generations is less then "minImprovment", we'll terminate the search). We'll let the user provide these parameters in the constructor.

        private readonly int generationsToConsider;
        private readonly double minImprovment;

        public StopIfNoImprovment(int generationsToConsider, double minImprovment)
        {
            this.generationsToConsider = generationsToConsider;
            this.minImprovment = minImprovment;
        }

Implementing the AddGeneration Method

We'll need to remember the best evaluation from previous generations. We'll do this by implementing the AddGenertion method. AddGenertion is called once per generation (after the ShouldStop method for that generation), and it's purpose it to let the stop-manager collect information about previous generations.

In this implementation, I'm going to remember all historical data (even though - technically - it's enough to only remember "generationsToConsider" generations back).

        private readonly List<double> oldEvaluations = new List<double>();

        public void AddGeneration(Population population)
        {
            oldEvaluations.Add(population.GetEvaluations().Max());
        }

Implementing the ShouldStop Method

Finally, let's implement the ShouldStop method.

        public bool ShouldStop(Population population, IEnvironment environment, int generation)
        {
            var currentEvaluation = population.GetEvaluations().Max();
            if (oldEvaluations.Count < generationsToConsider)
                return false;
            
            var min = oldEvaluations.Skip(generation - generationsToConsider- 1).Take(generationsToConsider).Min();

            return Math.Abs(currentEvaluation - min) <= minImprovment;
        }

The Full Code

You can find the full code here