#region License Information /* HeuristicLab * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using System; using System.Collections.Generic; using System.Linq; using HeuristicLab.Analysis; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Data; using HeuristicLab.Operators; using HeuristicLab.Optimization; using HeuristicLab.Optimization.Operators; using HeuristicLab.Parameters; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; using HeuristicLab.Random; namespace HeuristicLab.Algorithms.RandomSearch { [Item("Random Search Algorithm (RS)", "A random search algorithm.")] [Creatable(CreatableAttribute.Categories.Algorithms, Priority = 150)] [StorableClass] public sealed class RandomSearchAlgorithm : HeuristicOptimizationEngineAlgorithm, IStorableContent { public string Filename { get; set; } #region Problem Properties public override Type ProblemType { get { return typeof(IHeuristicOptimizationProblem); } } private ISingleObjectiveHeuristicOptimizationProblem SingleObjectiveProblem { get { return Problem as ISingleObjectiveHeuristicOptimizationProblem; } } private IMultiObjectiveHeuristicOptimizationProblem MultiObjectiveProblem { get { return Problem as IMultiObjectiveHeuristicOptimizationProblem; } } #endregion #region Parameter Properties private IFixedValueParameter SeedParameter { get { return (IFixedValueParameter)Parameters["Seed"]; } } private IFixedValueParameter SetSeedRandomlyParameter { get { return (IFixedValueParameter)Parameters["SetSeedRandomly"]; } } private IFixedValueParameter AnalyzerParameter { get { return (IFixedValueParameter)Parameters["Analyzer"]; } } private IFixedValueParameter MaximumEvaluatedSolutionsParameter { get { return (IFixedValueParameter)Parameters["MaximumEvaluatedSolutions"]; } } private IFixedValueParameter BatchSizeParameter { get { return (IFixedValueParameter)Parameters["BatchSize"]; } } private IFixedValueParameter MaximumIterationsParameter { get { return (IFixedValueParameter)Parameters["MaximumIterations"]; } } private IFixedValueParameter TerminatorParameter { get { return (IFixedValueParameter)Parameters["Terminator"]; } } #endregion #region Properties public int Seed { get { return SeedParameter.Value.Value; } set { SeedParameter.Value.Value = value; } } public bool SetSeedRandomly { get { return SetSeedRandomlyParameter.Value.Value; } set { SetSeedRandomlyParameter.Value.Value = value; } } public MultiAnalyzer Analyzer { get { return AnalyzerParameter.Value; } } public int MaximumEvaluatedSolutions { get { return MaximumEvaluatedSolutionsParameter.Value.Value; } set { MaximumEvaluatedSolutionsParameter.Value.Value = value; } } public int BatchSize { get { return BatchSizeParameter.Value.Value; } set { BatchSizeParameter.Value.Value = value; } } public int MaximumIterations { get { return MaximumIterationsParameter.Value.Value; } set { MaximumIterationsParameter.Value.Value = value; } } public MultiTerminator Terminators { get { return TerminatorParameter.Value; } } #endregion #region Helper Properties private SolutionsCreator SolutionsCreator { get { return OperatorGraph.Iterate().OfType().First(); } } #endregion #region Preconfigured Analyzers [Storable] private BestAverageWorstQualityAnalyzer singleObjectiveQualityAnalyzer; #endregion #region Preconfigured Terminators [Storable] private ComparisonTerminator evaluationsTerminator; [Storable] private ExecutionTimeTerminator executionTimeTerminator; [Storable] private SingleObjectiveQualityTerminator qualityTerminator; #endregion #region Constructors [StorableConstructor] private RandomSearchAlgorithm(bool deserializing) : base(deserializing) { } [StorableHook(HookType.AfterDeserialization)] private void AfterDeserialization() { Initialize(); } private RandomSearchAlgorithm(RandomSearchAlgorithm original, Cloner cloner) : base(original, cloner) { singleObjectiveQualityAnalyzer = cloner.Clone(original.singleObjectiveQualityAnalyzer); evaluationsTerminator = cloner.Clone(original.evaluationsTerminator); qualityTerminator = cloner.Clone(original.qualityTerminator); executionTimeTerminator = cloner.Clone(original.executionTimeTerminator); Initialize(); } public override IDeepCloneable Clone(Cloner cloner) { return new RandomSearchAlgorithm(this, cloner); } public RandomSearchAlgorithm() : base() { #region Add parameters Parameters.Add(new FixedValueParameter("Seed", "The random seed used to initialize the new pseudo random number generator.", new IntValue(0))); Parameters.Add(new FixedValueParameter("SetSeedRandomly", "True if the random seed should be set to a random value, otherwise false.", new BoolValue(true))); Parameters.Add(new FixedValueParameter("Analyzer", "The operator used to analyze the solutions each iteration.", new MultiAnalyzer())); Parameters.Add(new FixedValueParameter("MaximumEvaluatedSolutions", "The number of random solutions the algorithm should evaluate.", new IntValue(1000))); Parameters.Add(new FixedValueParameter("BatchSize", "The number of random solutions that are evaluated (in parallel) per iteration.", new IntValue(100))); Parameters.Add(new FixedValueParameter("MaximumIterations", "The number of iterations that the algorithm will run.", new IntValue(10)) { Hidden = true }); Parameters.Add(new FixedValueParameter("Terminator", "The termination criteria that defines if the algorithm should continue or stop.", new MultiTerminator()) { Hidden = true }); #endregion #region Create operators var randomCreator = new RandomCreator(); var variableCreator = new VariableCreator() { Name = "Initialize Variables" }; var resultsCollector = new ResultsCollector(); var solutionCreator = new SolutionsCreator() { Name = "Create Solutions" }; var analyzerPlaceholder = new Placeholder() { Name = "Analyzer (Placeholder)" }; var evaluationsCounter = new IntCounter() { Name = "Increment EvaluatedSolutions" }; var subScopesRemover = new SubScopesRemover(); var iterationsCounter = new IntCounter() { Name = "Increment Iterations" }; var terminationOperator = new TerminationOperator(); #endregion #region Create and parameterize operator graph OperatorGraph.InitialOperator = randomCreator; randomCreator.SeedParameter.Value = null; randomCreator.SeedParameter.ActualName = SeedParameter.Name; randomCreator.SetSeedRandomlyParameter.Value = null; randomCreator.SetSeedRandomlyParameter.ActualName = SetSeedRandomlyParameter.Name; randomCreator.Successor = variableCreator; variableCreator.CollectedValues.Add(new ValueParameter("Iterations", new IntValue(0))); variableCreator.CollectedValues.Add(new ValueParameter("EvaluatedSolutions", new IntValue(0))); variableCreator.Successor = resultsCollector; resultsCollector.CollectedValues.Add(new LookupParameter("Iterations", "The current iteration number.")); resultsCollector.CollectedValues.Add(new LookupParameter("EvaluatedSolutions", "The current number of evaluated solutions.")); resultsCollector.Successor = solutionCreator; solutionCreator.NumberOfSolutionsParameter.ActualName = BatchSizeParameter.Name; solutionCreator.ParallelParameter.Value.Value = true; solutionCreator.Successor = evaluationsCounter; evaluationsCounter.ValueParameter.ActualName = "EvaluatedSolutions"; evaluationsCounter.Increment = null; evaluationsCounter.IncrementParameter.ActualName = BatchSizeParameter.Name; evaluationsCounter.Successor = analyzerPlaceholder; analyzerPlaceholder.OperatorParameter.ActualName = AnalyzerParameter.Name; analyzerPlaceholder.Successor = subScopesRemover; subScopesRemover.RemoveAllSubScopes = true; subScopesRemover.Successor = iterationsCounter; iterationsCounter.ValueParameter.ActualName = "Iterations"; iterationsCounter.Increment = new IntValue(1); iterationsCounter.Successor = terminationOperator; terminationOperator.TerminatorParameter.ActualName = TerminatorParameter.Name; terminationOperator.ContinueBranch = solutionCreator; #endregion #region Create analyzers singleObjectiveQualityAnalyzer = new BestAverageWorstQualityAnalyzer(); #endregion #region Create terminators evaluationsTerminator = new ComparisonTerminator("EvaluatedSolutions", ComparisonType.Less, MaximumEvaluatedSolutionsParameter) { Name = "Evaluated solutions." }; qualityTerminator = new SingleObjectiveQualityTerminator() { Name = "Quality" }; executionTimeTerminator = new ExecutionTimeTerminator(this, new TimeSpanValue(TimeSpan.FromMinutes(5))); #endregion #region Parameterize UpdateAnalyzers(); ParameterizeAnalyzers(); UpdateTerminators(); #endregion Initialize(); } #endregion #region Events public override void Prepare() { if (Problem != null) base.Prepare(); } protected override void OnProblemChanged() { base.OnProblemChanged(); ParameterizeStochasticOperator(Problem.SolutionCreator); foreach (var @operator in Problem.Operators.OfType()) ParameterizeStochasticOperator(@operator); ParameterizeIterationBasedOperators(); ParameterizeSolutionsCreator(); ParameterizeAnalyzers(); ParameterizeTerminators(); if (SingleObjectiveProblem != null) SingleObjectiveProblem.Evaluator.QualityParameter.ActualNameChanged += Evaluator_QualityParameter_ActualNameChanged; UpdateAnalyzers(); UpdateTerminators(); } protected override void RegisterProblemEvents() { base.RegisterProblemEvents(); if (SingleObjectiveProblem != null) { var maximizationParameter = (IValueParameter)SingleObjectiveProblem.MaximizationParameter; if (maximizationParameter != null) maximizationParameter.ValueChanged += new EventHandler(MaximizationParameter_ValueChanged); } } protected override void DeregisterProblemEvents() { if (SingleObjectiveProblem != null) { var maximizationParameter = (IValueParameter)SingleObjectiveProblem.MaximizationParameter; if (maximizationParameter != null) maximizationParameter.ValueChanged -= new EventHandler(MaximizationParameter_ValueChanged); } base.DeregisterProblemEvents(); } protected override void Problem_SolutionCreatorChanged(object sender, EventArgs e) { base.Problem_SolutionCreatorChanged(sender, e); ParameterizeStochasticOperator(Problem.SolutionCreator); if (SingleObjectiveProblem != null) SingleObjectiveProblem.Evaluator.QualityParameter.ActualNameChanged += Evaluator_QualityParameter_ActualNameChanged; ParameterizeSolutionsCreator(); ParameterizeAnalyzers(); } protected override void Problem_EvaluatorChanged(object sender, EventArgs e) { base.Problem_EvaluatorChanged(sender, e); foreach (var @operator in Problem.Operators.OfType()) ParameterizeStochasticOperator(@operator); UpdateAnalyzers(); ParameterizeSolutionsCreator(); } protected override void Problem_OperatorsChanged(object sender, EventArgs e) { base.Problem_OperatorsChanged(sender, e); ParameterizeIterationBasedOperators(); UpdateTerminators(); } private void Evaluator_QualityParameter_ActualNameChanged(object sender, EventArgs e) { ParameterizeAnalyzers(); } private void MaximizationParameter_ValueChanged(object sender, EventArgs e) { ParameterizeTerminators(); } private void QualityAnalyzer_CurrentBestQualityParameter_NameChanged(object sender, EventArgs e) { ParameterizeTerminators(); } #endregion #region Parameterization private void Initialize() { if (SingleObjectiveProblem != null) SingleObjectiveProblem.Evaluator.QualityParameter.ActualNameChanged += Evaluator_QualityParameter_ActualNameChanged; singleObjectiveQualityAnalyzer.CurrentBestQualityParameter.NameChanged += QualityAnalyzer_CurrentBestQualityParameter_NameChanged; MaximumEvaluatedSolutionsParameter.Value.ValueChanged += MaximumEvaluatedSolutions_ValueChanged; BatchSizeParameter.Value.ValueChanged += BatchSize_ValueChanged; } private void ParameterizeSolutionsCreator() { SolutionsCreator.EvaluatorParameter.ActualName = Problem.EvaluatorParameter.Name; SolutionsCreator.SolutionCreatorParameter.ActualName = Problem.SolutionCreatorParameter.Name; } private void ParameterizeAnalyzers() { singleObjectiveQualityAnalyzer.ResultsParameter.ActualName = "Results"; singleObjectiveQualityAnalyzer.ResultsParameter.Hidden = true; singleObjectiveQualityAnalyzer.QualityParameter.Depth = 1; if (SingleObjectiveProblem != null) { singleObjectiveQualityAnalyzer.MaximizationParameter.ActualName = SingleObjectiveProblem.MaximizationParameter.Name; singleObjectiveQualityAnalyzer.MaximizationParameter.Hidden = true; singleObjectiveQualityAnalyzer.QualityParameter.ActualName = SingleObjectiveProblem.Evaluator.QualityParameter.ActualName; singleObjectiveQualityAnalyzer.QualityParameter.Hidden = true; singleObjectiveQualityAnalyzer.BestKnownQualityParameter.ActualName = SingleObjectiveProblem.BestKnownQualityParameter.Name; singleObjectiveQualityAnalyzer.BestKnownQualityParameter.Hidden = true; } } private void ParameterizeIterationBasedOperators() { if (Problem != null) { foreach (IIterationBasedOperator op in Problem.Operators.OfType()) { op.IterationsParameter.ActualName = "Iterations"; op.IterationsParameter.Hidden = true; op.MaximumIterationsParameter.ActualName = MaximumIterationsParameter.Name; } } } private void ParameterizeTerminators() { if (SingleObjectiveProblem != null) qualityTerminator.Parameterize(singleObjectiveQualityAnalyzer.CurrentBestQualityParameter, SingleObjectiveProblem); } private void ParameterizeStochasticOperator(IOperator @operator) { var stochasticOperator = @operator as IStochasticOperator; if (stochasticOperator != null) { stochasticOperator.RandomParameter.ActualName = "Random"; stochasticOperator.RandomParameter.Hidden = true; } } private void MaximumEvaluatedSolutions_ValueChanged(object sender, EventArgs e) { MaximumIterations = MaximumEvaluatedSolutions / BatchSize; } private void BatchSize_ValueChanged(object sender, EventArgs e) { MaximumIterations = MaximumEvaluatedSolutions / BatchSize; } #endregion #region Updates private void UpdateAnalyzers() { Analyzer.Operators.Clear(); if (Problem != null) { if (SingleObjectiveProblem != null) Analyzer.Operators.Add(singleObjectiveQualityAnalyzer, singleObjectiveQualityAnalyzer.EnabledByDefault); foreach (var analyzer in Problem.Operators.OfType()) Analyzer.Operators.Add(analyzer, analyzer.EnabledByDefault); } } private void UpdateTerminators() { var newTerminators = new Dictionary { {evaluationsTerminator, !Terminators.Operators.Contains(evaluationsTerminator) || Terminators.Operators.ItemChecked(evaluationsTerminator)}, {executionTimeTerminator, Terminators.Operators.Contains(executionTimeTerminator) && Terminators.Operators.ItemChecked(executionTimeTerminator)} }; if (Problem != null) { if (SingleObjectiveProblem != null) newTerminators.Add(qualityTerminator, Terminators.Operators.Contains(qualityTerminator) && Terminators.Operators.ItemChecked(qualityTerminator)); foreach (var terminator in Problem.Operators.OfType()) newTerminators.Add(terminator, !Terminators.Operators.Contains(terminator) || Terminators.Operators.ItemChecked(terminator)); } Terminators.Operators.Clear(); foreach (var newTerminator in newTerminators) Terminators.Operators.Add(newTerminator.Key, newTerminator.Value); } #endregion } }