#region License Information
/* HeuristicLab
* Copyright (C) 2002-2021 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.Linq;
using HEAL.Attic;
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.Random;
using HeuristicLab.Selection;
namespace HeuristicLab.Algorithms.MultiObjectiveLocalSearch {
[Item("Simple Evolutionary Multiobjective Algorithm (G-SEMO)", "Global Simple Evolutionary MultiObjective Algorithm is implemented as described in the literature (e.g. Laumanns, M., Thiele, L. and Zitzler, E., 2004. Running time analysis of evolutionary algorithms on a simplified multiobjective knapsack problem. Natural Computing, 3(1), pp. 37-51), but adds the option to evaluate additional children in each generation.")]
[StorableType("D9025144-B783-4484-B35B-7543C5A6D031")]
[Creatable(CreatableAttribute.Categories.SingleSolutionAlgorithms)]
public class GSEMO : HeuristicOptimizationEngineAlgorithm, IStorableContent {
public string Filename { get; set; }
public override Type ProblemType => typeof(IMultiObjectiveHeuristicOptimizationProblem);
public new IMultiObjectiveHeuristicOptimizationProblem Problem {
get { return (IMultiObjectiveHeuristicOptimizationProblem)base.Problem; }
set { base.Problem = value; }
}
private IFixedValueParameter SeedParameter {
get { return (IFixedValueParameter)Parameters["Seed"]; }
}
private IFixedValueParameter SetSeedRandomlyParameter {
get { return (IFixedValueParameter)Parameters["SetSeedRandomly"]; }
}
public IFixedValueParameter MaximumGenerationsParameter {
get { return (IFixedValueParameter)Parameters["MaximumGenerations"]; }
}
public IFixedValueParameter PopulationSizeParameter {
get { return (IFixedValueParameter)Parameters["PopulationSize"]; }
}
public IFixedValueParameter OffspringParameter {
get { return (IFixedValueParameter)Parameters["Offspring"]; }
}
public IConstrainedValueParameter MutatorParameter {
get { return (IConstrainedValueParameter)Parameters["Mutator"]; }
}
public IValueParameter AnalyzerParameter {
get { return (IValueParameter)Parameters["Analyzer"]; }
}
public IFixedValueParameter DominateOnEqualQualitiesParameter {
get { return (IFixedValueParameter)Parameters["DominateOnEqualQualities"]; }
}
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 int MaximumGenerations {
get { return MaximumGenerationsParameter.Value.Value; }
set { MaximumGenerationsParameter.Value.Value = value; }
}
public int PopulationSize {
get { return PopulationSizeParameter.Value.Value; }
set { PopulationSizeParameter.Value.Value = value; }
}
public int Offspring {
get { return OffspringParameter.Value.Value; }
set { OffspringParameter.Value.Value = value; }
}
public IManipulator Mutator {
get { return MutatorParameter.Value; }
set {
if (!MutatorParameter.ValidValues.Contains(value))
MutatorParameter.ValidValues.Add(value);
MutatorParameter.Value = value;
}
}
public MultiAnalyzer Analyzer {
get { return AnalyzerParameter.Value; }
set { AnalyzerParameter.Value = value; }
}
public bool DominateOnEqualQualities {
get { return DominateOnEqualQualitiesParameter.Value.Value; }
set { DominateOnEqualQualitiesParameter.Value.Value = value; }
}
[Storable]
private RankBasedParetoFrontAnalyzer paretoFrontAnalyzer;
[Storable]
private RandomCreator randomCreator;
[Storable]
private SolutionsCreator solutionsCreator;
[Storable]
private CrowdingDistanceAssignment popSizeCrowding;
[StorableConstructor]
protected GSEMO(StorableConstructorFlag _) : base(_) { }
protected GSEMO(GSEMO original, Cloner cloner)
: base(original, cloner) {
paretoFrontAnalyzer = cloner.Clone(original.paretoFrontAnalyzer);
randomCreator = cloner.Clone(original.randomCreator);
solutionsCreator = cloner.Clone(original.solutionsCreator);
popSizeCrowding = cloner.Clone(original.popSizeCrowding);
RegisterEventhandlers();
}
public GSEMO() {
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("MaximumGenerations", "Stopping criterion, terminates after this number of generations.", new IntValue(1000)));
Parameters.Add(new FixedValueParameter("PopulationSize", "The size of the pareto archive, the NSGA-II's rank and crowding sorter will be used to determine which solutions remain in the population.", new IntValue(int.MaxValue)));
Parameters.Add(new FixedValueParameter("Offspring", "The number of offspring to generate in each generation.", new IntValue(1)));
Parameters.Add(new ConstrainedValueParameter("Mutator", "The operator that mutates a solutions slightly."));
Parameters.Add(new ValueParameter("Analyzer", "The operator used to analyze each generation.", new MultiAnalyzer()));
Parameters.Add(new FixedValueParameter("DominateOnEqualQualities", "Flag which determines wether solutions with equal quality values should be treated as dominated.", new BoolValue(false)) { Hidden = true });
randomCreator = new RandomCreator();
solutionsCreator = new SolutionsCreator();
var countInitialEvaluatedSolutions = new SubScopesCounter();
var resultsCollectorLoop = new ResultsCollector();
var variableCreator = new VariableCreator();
var analyzerLoop = new Placeholder();
var selector = new RandomSelector();
var generationProcessor = new SubScopesProcessor();
var usspManipulation = new UniformSubScopesProcessor();
var manipulatorPlaceholder = new Placeholder();
var usspEvaluation = new UniformSubScopesProcessor();
var evaluatorPlaceholder = new Placeholder();
var countEvaluatedSolutions = new SubScopesCounter();
var merge = new MergingReducer();
var nonDominatedSort = new FastNonDominatedSort();
var frontSelector = new LeftReducer();
var popSizeCounter = new SubScopesCounter();
var popSizeComparator = new Comparator();
var popSizeBranch = new ConditionalBranch();
popSizeCrowding = new CrowdingDistanceAssignment();
var popSizeSorter = new CrowdedComparisonSorter();
var popSizeSelector = new LeftSelector();
var popSizeTrimmer = new RightReducer();
var incrementGenerations = new IntCounter();
var comparator = new Comparator();
var conditionalBranch = new ConditionalBranch();
var resultsCollectorFinish = new ResultsCollector();
var analyzerFinish = new Placeholder();
OperatorGraph.InitialOperator = randomCreator;
randomCreator.RandomParameter.ActualName = "Random";
randomCreator.SeedParameter.ActualName = SeedParameter.Name;
randomCreator.SeedParameter.Value = null;
randomCreator.SetSeedRandomlyParameter.ActualName = SetSeedRandomlyParameter.Name;
randomCreator.SetSeedRandomlyParameter.Value = null;
randomCreator.Successor = variableCreator;
variableCreator.Name = "Generations := 0";
variableCreator.CollectedValues.Add(new ValueParameter("Generations", new IntValue(0)));
variableCreator.Successor = solutionsCreator;
solutionsCreator.Name = "Create initial solution";
solutionsCreator.NumberOfSolutionsParameter.Value = new IntValue(1);
solutionsCreator.Successor = countInitialEvaluatedSolutions;
countInitialEvaluatedSolutions.Name = "Initialize EvaluatedSolutions";
countInitialEvaluatedSolutions.ValueParameter.ActualName = "EvaluatedSolutions";
countInitialEvaluatedSolutions.Successor = resultsCollectorLoop;
resultsCollectorLoop.CollectedValues.Add(new LookupParameter("Evaluated Solutions", null, "EvaluatedSolutions"));
resultsCollectorLoop.CollectedValues.Add(new LookupParameter("Generations"));
resultsCollectorLoop.ResultsParameter.ActualName = "Results";
resultsCollectorLoop.Successor = analyzerLoop;
analyzerLoop.Name = "(Analyzer)";
analyzerLoop.OperatorParameter.ActualName = AnalyzerParameter.Name;
analyzerLoop.Successor = selector;
selector.NumberOfSelectedSubScopesParameter.Value = null;
selector.NumberOfSelectedSubScopesParameter.ActualName = OffspringParameter.Name;
selector.RandomParameter.ActualName = "Random";
selector.CopySelected = new BoolValue(true);
selector.Successor = generationProcessor;
generationProcessor.Name = "Process Generations";
generationProcessor.Operators.Add(new EmptyOperator() { Name = "Leave Parent Population" });
generationProcessor.Operators.Add(usspManipulation);
generationProcessor.Successor = merge;
usspManipulation.Name = "Mutate Child Population";
usspManipulation.Parallel = new BoolValue(false);
usspManipulation.Operator = manipulatorPlaceholder;
usspManipulation.Successor = usspEvaluation;
manipulatorPlaceholder.Name = "(Manipulator)";
manipulatorPlaceholder.OperatorParameter.ActualName = MutatorParameter.Name;
usspEvaluation.Parallel = new BoolValue(true);
usspEvaluation.Operator = evaluatorPlaceholder;
usspEvaluation.Successor = countEvaluatedSolutions;
evaluatorPlaceholder.Name = "(Evaluate)";
evaluatorPlaceholder.OperatorParameter.ActualName = "Evaluator";
countEvaluatedSolutions.Name = "Increment EvaluatedSolutions";
countEvaluatedSolutions.ValueParameter.ActualName = "EvaluatedSolutions";
merge.Successor = nonDominatedSort;
nonDominatedSort.Name = "Calculate Fronts";
nonDominatedSort.DominateOnEqualQualitiesParameter.ActualName = DominateOnEqualQualitiesParameter.Name;
nonDominatedSort.Successor = frontSelector;
frontSelector.Name = "Keep Best Front";
frontSelector.Successor = popSizeCounter;
popSizeCounter.Name = "Count Population";
popSizeCounter.AccumulateParameter.Value = new BoolValue(false);
popSizeCounter.ValueParameter.ActualName = "CurrentPopulationSize";
popSizeCounter.Successor = popSizeComparator;
popSizeComparator.Name = "CurrentPopulationSize > PopulationSize ?";
popSizeComparator.LeftSideParameter.ActualName = "CurrentPopulationSize";
popSizeComparator.RightSideParameter.Value = null;
popSizeComparator.RightSideParameter.ActualName = PopulationSizeParameter.Name;
popSizeComparator.Comparison.Value = ComparisonType.Greater;
popSizeComparator.ResultParameter.ActualName = "TrimPopulation";
popSizeComparator.Successor = popSizeBranch;
popSizeBranch.Name = "Trim Population ?";
popSizeBranch.ConditionParameter.ActualName = "TrimPopulation";
popSizeBranch.TrueBranch = popSizeCrowding;
popSizeBranch.Successor = incrementGenerations;
popSizeCrowding.CrowdingDistanceParameter.Depth = 1;
popSizeCrowding.Successor = popSizeSorter;
popSizeSorter.CrowdingDistanceParameter.ActualName = popSizeCrowding.CrowdingDistanceParameter.ActualName;
popSizeSorter.RankParameter.ActualName = nonDominatedSort.RankParameter.ActualName;
popSizeSorter.RankParameter.Depth = 1;
popSizeSorter.Successor = popSizeSelector;
popSizeSelector.CopySelected = new BoolValue(false);
popSizeSelector.NumberOfSelectedSubScopesParameter.Value = null;
popSizeSelector.NumberOfSelectedSubScopesParameter.ActualName = PopulationSizeParameter.Name;
popSizeSelector.Successor = popSizeTrimmer;
popSizeTrimmer.Name = "Trim PopulationSize";
popSizeTrimmer.Successor = null;
incrementGenerations.Name = "Generations++";
incrementGenerations.Increment = new IntValue(1);
incrementGenerations.ValueParameter.ActualName = "Generations";
incrementGenerations.Successor = comparator;
comparator.Name = "Generations >= MaximumGenerations ?";
comparator.Comparison = new Comparison(ComparisonType.GreaterOrEqual);
comparator.LeftSideParameter.ActualName = "Generations";
comparator.ResultParameter.ActualName = "Terminate";
comparator.RightSideParameter.ActualName = "MaximumGenerations";
comparator.Successor = conditionalBranch;
conditionalBranch.Name = "Terminate?";
conditionalBranch.ConditionParameter.ActualName = "Terminate";
conditionalBranch.FalseBranch = resultsCollectorLoop;
conditionalBranch.TrueBranch = resultsCollectorFinish;
resultsCollectorFinish.CollectedValues.Add(new LookupParameter("Evaluated Solutions", null, "EvaluatedSolutions"));
resultsCollectorFinish.CollectedValues.Add(new LookupParameter("Generations"));
resultsCollectorFinish.ResultsParameter.ActualName = "Results";
resultsCollectorFinish.Successor = analyzerFinish;
analyzerFinish.Name = "(Analyzer)";
analyzerFinish.OperatorParameter.ActualName = AnalyzerParameter.Name;
paretoFrontAnalyzer = new RankBasedParetoFrontAnalyzer();
paretoFrontAnalyzer.RankParameter.ActualName = "Rank";
paretoFrontAnalyzer.RankParameter.Depth = 1;
paretoFrontAnalyzer.ResultsParameter.ActualName = "Results";
ParameterizeAnalyzers();
UpdateAnalyzers();
RegisterEventhandlers();
}
public override IDeepCloneable Clone(Cloner cloner) {
return new GSEMO(this, cloner);
}
[StorableHook(HookType.AfterDeserialization)]
private void AfterDeserialization() {
RegisterEventhandlers();
}
private void RegisterEventhandlers() {
if (Problem != null) {
Problem.Evaluator.QualitiesParameter.ActualNameChanged += new EventHandler(Evaluator_QualitiesParameter_ActualNameChanged);
}
}
public override void Prepare() {
if (Problem != null) base.Prepare();
}
#region Events
protected override void OnProblemChanged() {
ParameterizeStochasticOperator(Problem.SolutionCreator);
ParameterizeStochasticOperator(Problem.Evaluator);
foreach (var op in Problem.Operators.OfType()) ParameterizeStochasticOperator(op);
ParameterizeSolutionsCreator();
ParameterizeAnalyzers();
ParameterizeQualitiesOperators();
ParameterizeIterationBasedOperators();
UpdateMutators();
UpdateAnalyzers();
Problem.Evaluator.QualitiesParameter.ActualNameChanged += new EventHandler(Evaluator_QualitiesParameter_ActualNameChanged);
base.OnProblemChanged();
}
protected override void Problem_SolutionCreatorChanged(object sender, EventArgs e) {
ParameterizeStochasticOperator(Problem.SolutionCreator);
ParameterizeSolutionsCreator();
base.Problem_SolutionCreatorChanged(sender, e);
}
protected override void Problem_EvaluatorChanged(object sender, EventArgs e) {
ParameterizeStochasticOperator(Problem.Evaluator);
ParameterizeSolutionsCreator();
ParameterizeAnalyzers();
ParameterizeQualitiesOperators();
Problem.Evaluator.QualitiesParameter.ActualNameChanged += new EventHandler(Evaluator_QualitiesParameter_ActualNameChanged);
base.Problem_EvaluatorChanged(sender, e);
}
protected override void Problem_OperatorsChanged(object sender, EventArgs e) {
foreach (var op in Problem.Operators.OfType()) ParameterizeStochasticOperator(op);
ParameterizeIterationBasedOperators();
UpdateMutators();
UpdateAnalyzers();
base.Problem_OperatorsChanged(sender, e);
}
private void Evaluator_QualitiesParameter_ActualNameChanged(object sender, EventArgs e) {
ParameterizeAnalyzers();
ParameterizeQualitiesOperators();
}
#endregion
private void ParameterizeSolutionsCreator() {
solutionsCreator.EvaluatorParameter.ActualName = Problem.EvaluatorParameter.Name;
solutionsCreator.SolutionCreatorParameter.ActualName = Problem.SolutionCreatorParameter.Name;
}
private void ParameterizeStochasticOperator(IOperator op) {
var stochasticOp = op as IStochasticOperator;
if (stochasticOp != null) {
stochasticOp.RandomParameter.ActualName = randomCreator.RandomParameter.ActualName;
stochasticOp.RandomParameter.Hidden = true;
}
}
private void ParameterizeAnalyzers() {
paretoFrontAnalyzer.ResultsParameter.ActualName = "Results";
paretoFrontAnalyzer.ResultsParameter.Hidden = true;
if (Problem != null) {
paretoFrontAnalyzer.QualitiesParameter.ActualName = Problem.Evaluator.QualitiesParameter.ActualName;
paretoFrontAnalyzer.QualitiesParameter.Depth = 1;
paretoFrontAnalyzer.QualitiesParameter.Hidden = true;
}
}
private void ParameterizeIterationBasedOperators() {
if (Problem != null) {
foreach (var op in Problem.Operators.OfType()) {
op.IterationsParameter.ActualName = "Generations";
op.IterationsParameter.Hidden = true;
op.MaximumIterationsParameter.ActualName = "MaximumGenerations";
op.MaximumIterationsParameter.Hidden = true;
}
}
}
private void ParameterizeQualitiesOperators() {
if (Problem != null) {
popSizeCrowding.QualitiesParameter.ActualName = Problem.Evaluator.QualitiesParameter.Name;
}
}
private void UpdateMutators() {
var oldMutator = MutatorParameter.Value;
MutatorParameter.ValidValues.Clear();
var defaultMutator = Problem.Operators.Where(x => !(x is ISingleObjectiveOperator)).OfType().FirstOrDefault();
foreach (var mutator in Problem.Operators.Where(x => !(x is ISingleObjectiveOperator)).OfType().OrderBy(x => x.Name))
MutatorParameter.ValidValues.Add(mutator);
if (oldMutator != null) {
var mutator = MutatorParameter.ValidValues.FirstOrDefault(x => x.GetType() == oldMutator.GetType());
if (mutator != null) MutatorParameter.Value = mutator;
else oldMutator = null;
}
if (oldMutator == null && defaultMutator != null)
MutatorParameter.Value = defaultMutator;
}
private void UpdateAnalyzers() {
Analyzer.Operators.Clear();
if (Problem != null) {
foreach (var analyzer in Problem.Operators.Where(x => !(x is ISingleObjectiveOperator)).OfType()) {
foreach (var param in analyzer.Parameters.OfType())
param.Depth = 1;
Analyzer.Operators.Add(analyzer, analyzer.EnabledByDefault);
}
}
Analyzer.Operators.Add(paretoFrontAnalyzer, paretoFrontAnalyzer.EnabledByDefault);
}
}
}