Exemple #1
0
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="optimiser">The optimiser.</param>
        /// <param name="model">The model.</param>
        /// <param name="timeOutManager">The timeout manager.</param>
        /// <param name="convergenceCheckers">Checks for early termination.</param>
        /// <param name="reportingFrequency">Number of reinsertions between reports on progress.</param>
        /// <param name="numberOfNewIndividualsPerGeneration">Number of new individuals to generate whenever an individual is evaluated.</param>
        public ReinsertionAgent(
            Optimiser optimiser,
            IModel model,
            TimeOutManager timeOutManager,
            Func <Population, bool> convergenceCheckers,
            int reportingFrequency,
            int numberOfNewIndividualsPerGeneration)
        {
            CancellationSource       = new CancellationTokenSource();
            this.timeOutManager      = timeOutManager;
            this.convergenceCheckers = convergenceCheckers;
            NumberGenerated          = 0;
            NumberReinserted         = 0;
            AllEvaluated             = new List <Individual>();

            ReportingFrequency = reportingFrequency;

            this.optimiser = optimiser;
            this.model     = model;

            this.numberOfNewIndividualsPerGeneration = numberOfNewIndividualsPerGeneration;

            IndividualsForReinsertion = new TransformManyBlock <Individual, Individual>(
                (Func <Individual, IEnumerable <Individual> >)Process,
                new ExecutionDataflowBlockOptions
            {
                CancellationToken      = CancellationSource.Token,
                MaxDegreeOfParallelism = 1
            });

            NewIndividuals = new BufferBlock <Individual>(
                new DataflowBlockOptions
            {
                CancellationToken = CancellationSource.Token
            });

            Reports = new BroadcastBlock <Population>(i => i);

            //Set up link so that new individuals created
            // are pushed to the output buffer
            IndividualsForReinsertion.LinkTo(
                NewIndividuals,
                new DataflowLinkOptions()
            {
                PropagateCompletion = true
            });
        }
        /// <summary>
        /// Initialises all the buffers to be ready.
        /// </summary>
        /// <param name="timeOutManager">The <see cref="TimeOutManager"/>.</param>
        /// <param name="reportingFrequency">The number of reinsertions between reports on the current population</param>
        /// <param name="numberOfNewIndividualsPerGeneration">The number of new individuals to generate whenever an individual is reinserted.</param>
        private void setUpAgents(
            TimeOutManager timeOutManager,
            int reportingFrequency,
            int numberOfNewIndividualsPerGeneration)
        {
            reinsertionAgent = new ReinsertionAgent(
                builder.CreateOptimiser(),
                builder.CreateModel(),
                timeOutManager, convergenceCheckers,
                reportingFrequency,
                numberOfNewIndividualsPerGeneration);

            evaluationAgent = new EvaluationAgent(
                evaluator, reinsertionAgent.CancellationSource.Token);

            //Create link so that newly created individuals from the ReinsertionAgent
            // are pushed to the EvaluationAgent
            reinsertionAgent.NewIndividuals.LinkTo(
                evaluationAgent.IndividualsForEvaluation,
                new DataflowLinkOptions()
            {
                PropagateCompletion = true
            });

            //Create link so that evaluated individuals from the EvaluationAgent
            // are pushed to the ReinsertionAgent
            evaluationAgent.EvaluatedIndividuals.LinkTo(
                reinsertionAgent.IndividualsForReinsertion,
                new DataflowLinkOptions()
            {
                PropagateCompletion = true
            });

            //Create link so that reports from the ReinsertionAgent
            // are pushed to the reporting delegates
            reinsertionAgent.Reports.LinkTo(reportingAgent,
                                            new DataflowLinkOptions()
            {
                PropagateCompletion = true
            });
        }
        /// <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();
        }