/// <summary> /// Runs the optimisation. /// </summary> /// <param name="storeAll"><see langword="true"/> to store all individuals evaluated (memory required).</param> /// <param name="reportingFrequency">The number of evaluations between reporting progress.</param> /// <param name="timeOutEvaluations">The maximum number of evaluations before terminating the optimisation.</param> /// <param name="timeOutDuration">The maximum time allowed before terminating the optimisation.</param> /// <param name="newIndividualsPerGeneration">The number of new <see cref="Individual"/>s to generate each time new individuals are generated from the <see cref="Population"/>.</param> public override void Run( bool storeAll = true, int reportingFrequency = 100, int timeOutEvaluations = 0, TimeSpan?timeOutDuration = null, int newIndividualsPerGeneration = 1) { // Initialise StartTime = DateTime.Now; var optimiser = builder.CreateOptimiser(); var model = builder.CreateModel(); cancelDemanded = false; //Setup if (newIndividualsPerGeneration <= 0) { throw new ArgumentOutOfRangeException(nameof(newIndividualsPerGeneration), "At least one new individual must be created each generation."); } var nextInds = optimiser.GetNextToEvaluate(newIndividualsPerGeneration); if (timeOutEvaluations == 0) { var numDims = nextInds[0].DecisionVector.Count; timeOutEvaluations = Math.Min(numDims * 20000, 2000000); } var timeOutDurationNotNull = TimeSpan.MaxValue; if (timeOutDuration != null) { timeOutDurationNotNull = timeOutDuration.Value; } timeOutManager = new TimeOutManager(timeOutEvaluations, timeOutDurationNotNull); AllEvaluated = new List <Individual>(); FinalPopulation = null; BestFound = null; //Go! while (nextInds.Count > 0 && nextInds[0].DecisionVector.Count > 0) { foreach (var nextInd in nextInds) { nextInd.SetProperty( OptimiserPropertyNames.CreationIndex, timeOutManager.EvaluationsRun); // Evaluate model.PrepareForEvaluation(nextInd); evaluator.Evaluate(nextInd); } // Reinsert optimiser.ReInsert(nextInds); foreach (var nextInd in nextInds) { nextInd.SetProperty( OptimiserPropertyNames.ReinsertionIndex, timeOutManager.EvaluationsRun); timeOutManager.IncrementEvaluationsRun(); } // Store if (storeAll) { AllEvaluated.AddRange(nextInds); } // Update best var bestInd = optimiser.Population.Best(); if (BestFound == null || (bestInd != null && bestInd.Fitness < BestFound.Fitness)) { BestFound = bestInd; } // Create individuals for next loop nextInds = optimiser.GetNextToEvaluate(newIndividualsPerGeneration); // Check for completion if (timeOutManager.HasPerformedTooManyEvaluations() || timeOutManager.HasRunOutOfTime() || cancelDemanded) { //Bored... break; } if (optimiser.Population.IsTargetSizeReached) { if (convergenceCheckers(optimiser.Population)) { break; } } if (timeOutManager.EvaluationsRun % reportingFrequency == 0) { reporters(optimiser.Population); } } reporters(optimiser.Population); //Finish off FinalPopulation = optimiser.Population; }
/// <summary> /// Runs the optimisation. /// </summary> /// <param name="storeAll"><see langword="true"/> to store all individuals evaluated (memory required).</param> /// <param name="reportingFrequency">The number of evaluations between reporting progress.</param> /// <param name="timeOutEvaluations">The maximum number of evaluations before terminating the optimisation.</param> /// <param name="timeOutDuration">The maximum time allowed before terminating the optimisation.</param> /// <param name="newIndividualsPerGeneration">The number of new <see cref="Individual"/>s to generate each time new individuals are generated from the <see cref="Population"/>.</param> public override void Run( bool storeAll = true, int reportingFrequency = 100, int timeOutEvaluations = 0, TimeSpan?timeOutDuration = null, int newIndividualsPerGeneration = 1) { StartTime = DateTime.Now; // Calculate time outs automatically if not provided if (timeOutEvaluations == 0) { var numDims = builder.CreateModel().GetNewDecisionVector().Count; timeOutEvaluations = Math.Min(numDims * 20000, 2000000); } var timeOutDurationNotNull = TimeSpan.MaxValue; if (timeOutDuration != null) { timeOutDurationNotNull = timeOutDuration.Value; } var timeOutManager = new TimeOutManager(timeOutEvaluations, timeOutDurationNotNull); if (newIndividualsPerGeneration <= 0) { throw new ArgumentOutOfRangeException(nameof(newIndividualsPerGeneration), "At least one new individual must be created each generation."); } setUpAgents(timeOutManager, reportingFrequency, newIndividualsPerGeneration); if (reinsertionAgent == null || evaluationAgent == null) { throw new ApplicationException("Failed to initialise TPL buffers."); } reinsertionAgent.SaveAll = storeAll; // Get started var pumpPrimingInds = reinsertionAgent.CreateNewIndividuals( Math.Max(NumberOfIndividualsToStart, newIndividualsPerGeneration)); foreach (var ind in pumpPrimingInds) { reinsertionAgent.NewIndividuals.Post(ind); } // Wait for completion try { Task.WaitAll( reinsertionAgent.IndividualsForReinsertion.Completion, reinsertionAgent.NewIndividuals.Completion, evaluationAgent.EvaluatedIndividuals.Completion, evaluationAgent.IndividualsForEvaluation.Completion); } catch (AggregateException e) when(e.InnerExceptions.All(ie => ie is TaskCanceledException)) { // There is no way to wait for cancellation, // so we have to wait for completion and then // ignore the cancellation errors } FinalPopulation = reinsertionAgent.GetCurrentPopulation(); AllEvaluated = reinsertionAgent.AllEvaluated; if (FinalPopulation.Count <= 0) { return; } // Not really the best found unless the optimiser is elitist BestFound = FinalPopulation.Best(); }