#region License Information /* HeuristicLab * Copyright (C) 2002-2014 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 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.PluginInfrastructure; namespace HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm { [Item("WeightedParentsDiversityComparator", "Compares the similarity against that of its parents (assumes the parents are subscopes to the child scope). This operator works with any number of subscopes > 0.")] [StorableClass] public class WeightedParentsDiversityComparator : SingleSuccessorOperator, ISubScopesQualityComparatorOperator, ISimilarityBasedOperator { [Storable] public ISolutionSimilarityCalculator SimilarityCalculator { get; set; } public IValueLookupParameter MaximizationParameter { get { return (IValueLookupParameter)Parameters["Maximization"]; } } public ILookupParameter LeftSideParameter { get { return (ILookupParameter)Parameters["LeftSide"]; } } public ILookupParameter> RightSideParameter { get { return (ILookupParameter>)Parameters["RightSide"]; } } public ILookupParameter ResultParameter { get { return (ILookupParameter)Parameters["Result"]; } } public ValueLookupParameter ComparisonFactorParameter { get { return (ValueLookupParameter)Parameters["ComparisonFactor"]; } } public ValueLookupParameter DiversityComparisonFactorParameter { get { return (ValueLookupParameter)Parameters["DiversityComparisonFactor"]; } } private ValueLookupParameter ComparisonFactorLowerBoundParameter { get { return (ValueLookupParameter)Parameters["DiversityComparisonFactorLowerBound"]; } } private ValueLookupParameter ComparisonFactorUpperBoundParameter { get { return (ValueLookupParameter)Parameters["DiversityComparisonFactorUpperBound"]; } } public IConstrainedValueParameter ComparisonFactorModifierParameter { get { return (IConstrainedValueParameter)Parameters["ComparisonFactorModifier"]; } } public ValueLookupParameter ResultsParameter { get { return (ValueLookupParameter)Parameters["Results"]; } } public ILookupParameter GenerationsParameter { get { return (LookupParameter)Parameters["Generations"]; } } public ValueParameter EnableDivCriteriaParameter { get { return (ValueParameter)Parameters["EnableDivCriteria"]; } } private const string spDetailsParameterName = "SPDetails"; private const string divDataRowName = "DiversitySuccessCount"; private const string qualityDataRowName = "QualitySuccessCount"; private const string overallCountDataRowName = "OverallCount"; private const string successCountDataRowName = "SuccessCount"; [Storable] private int currentGeneration; [Storable] private int divCount; [Storable] private int qualityCount; [Storable] private int overallCount; [Storable] private int successCount; [StorableConstructor] protected WeightedParentsDiversityComparator(bool deserializing) : base(deserializing) { } protected WeightedParentsDiversityComparator(WeightedParentsDiversityComparator original, Cloner cloner) : base(original, cloner) { SimilarityCalculator = cloner.Clone(original.SimilarityCalculator); currentGeneration = original.currentGeneration; divCount = original.divCount; qualityCount = original.qualityCount; overallCount = original.overallCount; successCount = original.successCount; } public WeightedParentsDiversityComparator() : base() { Parameters.Add(new ValueLookupParameter("Maximization", "True if the problem is a maximization problem, false otherwise")); Parameters.Add(new LookupParameter("LeftSide", "The quality of the child.")); Parameters.Add(new ScopeTreeLookupParameter("RightSide", "The qualities of the parents.")); Parameters.Add(new LookupParameter("Result", "The result of the comparison: True means Quality is better, False means it is worse than parents.")); Parameters.Add(new ValueLookupParameter("ComparisonFactor", "Determines if the quality should be compared to the better parent (1.0), to the worse (0.0) or to any linearly interpolated value between them.")); Parameters.Add(new ValueLookupParameter("DiversityComparisonFactor", "Determines if the quality should be compared to the better parent (1.0), to the worse (0.0) or to any linearly interpolated value between them.", new DoubleValue(0.0))); Parameters.Add(new ValueLookupParameter("DiversityComparisonFactorLowerBound", "The lower bound of the comparison factor (start).", new DoubleValue(0.5))); Parameters.Add(new ValueLookupParameter("DiversityComparisonFactorUpperBound", "The upper bound of the comparison factor (end).", new DoubleValue(1.0))); Parameters.Add(new OptionalConstrainedValueParameter("ComparisonFactorModifier", "The operator used to modify the comparison factor.", new ItemSet(new IDiscreteDoubleValueModifier[] { new LinearDiscreteDoubleValueModifier() }), new LinearDiscreteDoubleValueModifier())); Parameters.Add(new ValueLookupParameter("Results", "The result collection where the population diversity analysis results should be stored.")); Parameters.Add(new LookupParameter("Generations", "The current number of generations.")); Parameters.Add(new ValueParameter("EnableDivCriteria", "Use diversity as additional offspring selection criteria.", new BoolValue(true))); foreach (IDiscreteDoubleValueModifier modifier in ApplicationManager.Manager.GetInstances().OrderBy(x => x.Name)) ComparisonFactorModifierParameter.ValidValues.Add(modifier); IDiscreteDoubleValueModifier linearModifier = ComparisonFactorModifierParameter.ValidValues.FirstOrDefault(x => x.GetType().Name.Equals("LinearDiscreteDoubleValueModifier")); if (linearModifier != null) ComparisonFactorModifierParameter.Value = linearModifier; ParameterizeComparisonFactorModifiers(); } public override IDeepCloneable Clone(Cloner cloner) { return new WeightedParentsDiversityComparator(this, cloner); } [StorableHook(HookType.AfterDeserialization)] private void AfterDeserialization() { if (!Parameters.ContainsKey("Generations")) Parameters.Add(new LookupParameter("Generations", "The current number of generations.")); if (!Parameters.ContainsKey("Results")) Parameters.Add(new ValueLookupParameter("Results", "The result collection where the population diversity analysis results should be stored.")); if (!Parameters.ContainsKey("EnableDivCriteria")) Parameters.Add(new ValueParameter("EnableDivCriteria", "Use diversity as additional offspring selection criteria.", new BoolValue(true))); } private void ParameterizeComparisonFactorModifiers() { //TODO: does not work if Generations parameter names are changed foreach (IDiscreteDoubleValueModifier modifier in ComparisonFactorModifierParameter.ValidValues) { modifier.IndexParameter.ActualName = "Generations"; modifier.EndIndexParameter.ActualName = "MaximumGenerations"; modifier.EndValueParameter.ActualName = ComparisonFactorUpperBoundParameter.Name; modifier.StartIndexParameter.Value = new IntValue(0); modifier.StartValueParameter.ActualName = ComparisonFactorLowerBoundParameter.Name; modifier.ValueParameter.ActualName = "DiversityComparisonFactor"; } } public override IOperation Apply() { ItemArray rightQualities = RightSideParameter.ActualValue; if (rightQualities.Length < 1) throw new InvalidOperationException(Name + ": No subscopes found."); double compFact = ComparisonFactorParameter.ActualValue.Value; double diversityComFact = DiversityComparisonFactorParameter.ActualValue.Value; bool maximization = MaximizationParameter.ActualValue.Value; double leftQuality = LeftSideParameter.ActualValue.Value; bool resultDiversity; double threshold = 0; DataTable spDetailsTable; if (ResultsParameter.ActualValue.ContainsKey(spDetailsParameterName)) { spDetailsTable = (DataTable)ResultsParameter.ActualValue[spDetailsParameterName].Value; } else { spDetailsTable = new DataTable(spDetailsParameterName); spDetailsTable.Rows.Add(new DataRow(divDataRowName)); spDetailsTable.Rows.Add(new DataRow(qualityDataRowName)); spDetailsTable.Rows.Add(new DataRow(overallCountDataRowName)); spDetailsTable.Rows.Add(new DataRow(successCountDataRowName)); ResultsParameter.ActualValue.Add(new Result(spDetailsParameterName, spDetailsTable)); } if (GenerationsParameter.ActualValue.Value != currentGeneration) { spDetailsTable.Rows[divDataRowName].Values.Add(divCount); divCount = 0; spDetailsTable.Rows[qualityDataRowName].Values.Add(qualityCount); qualityCount = 0; spDetailsTable.Rows[overallCountDataRowName].Values.Add(overallCount); overallCount = 0; spDetailsTable.Rows[successCountDataRowName].Values.Add(successCount); successCount = 0; currentGeneration = GenerationsParameter.ActualValue.Value; } #region Calculate threshold if (rightQualities.Length == 2) { var sim1 = SimilarityCalculator.CalculateSolutionSimilarity(ExecutionContext.Scope, ExecutionContext.Scope.SubScopes[0]); var sim2 = SimilarityCalculator.CalculateSolutionSimilarity(ExecutionContext.Scope, ExecutionContext.Scope.SubScopes[1]); var simAvg = (sim1 + sim2) / 2.0; //TODO: try out different things //resultDiversity = simAvg < diversityComFact; resultDiversity = sim1 < diversityComFact || sim2 < diversityComFact; double minQuality = Math.Min(rightQualities[0].Value, rightQualities[1].Value); double maxQuality = Math.Max(rightQualities[0].Value, rightQualities[1].Value); if (maximization) threshold = minQuality + (maxQuality - minQuality) * compFact; else threshold = maxQuality - (maxQuality - minQuality) * compFact; } else { throw new NotImplementedException("Only 2 parents are supported."); } #endregion bool result = maximization && leftQuality > threshold || !maximization && leftQuality < threshold; //collect statistics if (result) { qualityCount++; } if (resultDiversity) { divCount++; } if (result && resultDiversity) { successCount++; } overallCount++; //use diveristiy criteria or not if (EnableDivCriteriaParameter.Value.Value) { result = result && resultDiversity; } BoolValue resultValue = ResultParameter.ActualValue; if (resultValue == null) { ResultParameter.ActualValue = new BoolValue(result); } else { resultValue.Value = result; } //like the placeholder, though we create child operations OperationCollection next = new OperationCollection(base.Apply()); IOperator op = ComparisonFactorModifierParameter.Value; if (op != null) next.Insert(0, ExecutionContext.CreateChildOperation(op)); return next; } } }