#region License Information /* HeuristicLab * Copyright (C) 2002-2012 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.Linq; using HeuristicLab.Analysis; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Data; using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding; using HeuristicLab.Operators; using HeuristicLab.Optimization; using HeuristicLab.Parameters; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; using HeuristicLab.Problems.DataAnalysis.Symbolic; // type definitions for ease of use using CloneMapType = HeuristicLab.Core.ItemDictionary; namespace HeuristicLab.EvolutionaryTracking { /// /// Population diversity analyzer /// [Item("SymbolicExpressionTreePopulationDiversityAnalyzer", "An operator that tracks population diversity")] [StorableClass] public sealed class SymbolicExpressionTreePopulationDiversityAnalyzer : SingleSuccessorOperator, IAnalyzer { #region Parameter names private const string MaximumSymbolicExpressionTreeDepthParameterName = "MaximumSymbolicExpressionTreeDepth"; private const string SymbolicExpressionTreeParameterName = "SymbolicExpressionTree"; private const string UpdateIntervalParameterName = "UpdateInterval"; private const string UpdateCounterParameterName = "UpdateCounter"; private const string ResultsParameterName = "Results"; private const string GenerationsParameterName = "Generations"; private const string StoreHistoryParameterName = "StoreHistory"; // comparer parameters private const string MatchVariablesParameterName = "MatchVariableNames"; private const string MatchVariableWeightsParameterName = "MatchVariableWeights"; private const string MatchConstantValuesParameterName = "MatchConstantValues"; private const string SortSubtreesParameterName = "SortSubtrees"; private const string SimilarityValuesParmeterName = "Similarity"; // clone map private const string GlobalCloneMapParameterName = "GlobalCloneMap"; #endregion #region Parameters public IValueLookupParameter MaximumSymbolicExpressionTreeDepthParameter { get { return (IValueLookupParameter)Parameters[MaximumSymbolicExpressionTreeDepthParameterName]; } } public ValueParameter UpdateIntervalParameter { get { return (ValueParameter)Parameters[UpdateIntervalParameterName]; } } public ValueParameter UpdateCounterParameter { get { return (ValueParameter)Parameters[UpdateCounterParameterName]; } } public LookupParameter ResultsParameter { get { return (LookupParameter)Parameters[ResultsParameterName]; } } public LookupParameter GenerationsParameter { get { return (LookupParameter)Parameters[GenerationsParameterName]; } } public ValueParameter StoreHistoryParameter { get { return (ValueParameter)Parameters[StoreHistoryParameterName]; } } public IScopeTreeLookupParameter SymbolicExpressionTreeParameter { get { return (IScopeTreeLookupParameter)Parameters[SymbolicExpressionTreeParameterName]; } } public ValueParameter MatchVariableNamesParameter { get { return (ValueParameter)Parameters[MatchVariablesParameterName]; } } public ValueParameter MatchVariableWeightsParameter { get { return (ValueParameter)Parameters[MatchVariableWeightsParameterName]; } } public ValueParameter MatchConstantValuesParameter { get { return (ValueParameter)Parameters[MatchConstantValuesParameterName]; } } public ValueParameter SortSubtreesParameter { get { return (ValueParameter)Parameters[SortSubtreesParameterName]; } } public LookupParameter GlobalCloneMapParameter { get { return (LookupParameter)Parameters[GlobalCloneMapParameterName]; } } public ILookupParameter SimilarityParameter { get { return (ILookupParameter)Parameters[SimilarityValuesParmeterName]; } } #endregion #region Parameter properties public IntValue MaximumSymbolicExpressionTreeDepth { get { return MaximumSymbolicExpressionTreeDepthParameter.ActualValue; } } public IntValue UpdateInterval { get { return UpdateIntervalParameter.Value; } } public IntValue UpdateCounter { get { return UpdateCounterParameter.Value; } } public ResultCollection Results { get { return ResultsParameter.ActualValue; } } public CloneMapType GlobalCloneMap { get { return GlobalCloneMapParameter.ActualValue; } } public IntValue Generations { get { return GenerationsParameter.ActualValue; } } public BoolValue StoreHistory { get { return StoreHistoryParameter.Value; } } #endregion [StorableConstructor] private SymbolicExpressionTreePopulationDiversityAnalyzer(bool deserializing) : base(deserializing) { } private SymbolicExpressionTreePopulationDiversityAnalyzer( SymbolicExpressionTreePopulationDiversityAnalyzer original, Cloner cloner) : base(original, cloner) { } public override IDeepCloneable Clone(Cloner cloner) { return new SymbolicExpressionTreePopulationDiversityAnalyzer(this, cloner); } public SymbolicExpressionTreePopulationDiversityAnalyzer() { // add parameters Parameters.Add(new ScopeTreeLookupParameter(SymbolicExpressionTreeParameterName, "The symbolic expression trees to analyze.")); Parameters.Add(new ValueParameter(UpdateIntervalParameterName, "The interval in which the tree length analysis should be applied.", new IntValue(1))); Parameters.Add(new ValueParameter(UpdateCounterParameterName, "The value which counts how many times the operator was called since the last update", new IntValue(0))); Parameters.Add(new ValueLookupParameter(ResultsParameterName, "The results collection where the analysis values should be stored.")); Parameters.Add(new LookupParameter(GenerationsParameterName, "The number of generations so far.")); Parameters.Add(new ValueParameter(MatchVariablesParameterName, "Specify if the symbolic expression tree comparer should match variable names.", new BoolValue(true))); Parameters.Add(new ValueParameter(MatchVariableWeightsParameterName, "Specify if the symbolic expression tree comparer should match variable weights.", new BoolValue(true))); Parameters.Add(new ValueParameter(MatchConstantValuesParameterName, "Specify if the symbolic expression tree comparer should match constant values.", new BoolValue(true))); Parameters.Add(new ValueParameter(SortSubtreesParameterName, "Specifies whether the subtrees of a tree should be sorted before comparison.")); Parameters.Add(new LookupParameter(GlobalCloneMapParameterName, "A global map keeping track of trees and their clones (made during selection).")); Parameters.Add(new ValueParameter(StoreHistoryParameterName, "True if the tree lengths history of the population should be stored.", new BoolValue(false))); Parameters.Add(new LookupParameter(SimilarityValuesParmeterName, "")); Parameters.Add(new ValueLookupParameter(MaximumSymbolicExpressionTreeDepthParameterName, "The maximal depth of the symbolic expression tree (a tree with one node has depth = 0).")); UpdateCounterParameter.Hidden = true; UpdateIntervalParameter.Hidden = true; } [StorableHook(HookType.AfterDeserialization)] private void AfterDeserialization() { if (!Parameters.ContainsKey(MaximumSymbolicExpressionTreeDepthParameterName)) { Parameters.Add(new ValueLookupParameter(MaximumSymbolicExpressionTreeDepthParameterName, "The maximal depth of the symbolic expression tree (a tree with one node has depth = 0).")); } } #region IStatefulItem members public override void InitializeState() { UpdateCounter.Value = 0; base.InitializeState(); } #endregion public bool EnabledByDefault { get { return true; } } public override IOperation Apply() { if (SimilarityParameter.ActualValue == null || SimilarityParameter.ActualValue.Value.IsAlmost(-1.0)) { UpdateCounter.Value++; if (UpdateCounter.Value != UpdateInterval.Value) return base.Apply(); UpdateCounter.Value = 0; var trees = SymbolicExpressionTreeParameter.ActualValue.ToList(); if (SortSubtreesParameter.Value.Value) { var canonicalSorter = new SymbolicExpressionTreeCanonicalSorter(); foreach (var t in trees) canonicalSorter.SortSubtrees(t); } SimilarityParameter.ActualValue = new DoubleValue(); // needed only with the old (and inefficient) geneticitem-based similarity measure // var geneticItems = trees.ToDictionary(tree => tree, tree => tree.GetGeneticItems(1, MaximumSymbolicExpressionTreeDepth.Value - 2).ToArray()); var comp = new SymbolicExpressionTreeNodeSimilarityComparer { MatchConstantValues = MatchConstantValuesParameter.Value.Value, MatchVariableNames = MatchVariableNamesParameter.Value.Value, MatchVariableWeights = MatchVariableWeightsParameter.Value.Value }; var operations = new OperationCollection { Parallel = true }; foreach (var tree in trees) { var op = new SymbolicDataAnalysisExpressionTreeSimilarityCalculator { CurrentSymbolicExpressionTree = tree, SimilarityComparer = comp, MaximumTreeDepth = MaximumSymbolicExpressionTreeDepth.Value }; var operation = ExecutionContext.CreateChildOperation(op, ExecutionContext.Scope); operations.Add(operation); } return new OperationCollection { operations, ExecutionContext.CreateOperation(this) }; } ResultCollection results = ResultsParameter.ActualValue; // population diversity DataTable populationDiversityTable; if (!results.ContainsKey("PopulationDiversity")) { populationDiversityTable = new DataTable("PopulationDiversity") { VisualProperties = { YAxisTitle = "Diversity" } }; results.Add(new Result("PopulationDiversity", populationDiversityTable)); } populationDiversityTable = (DataTable)results["PopulationDiversity"].Value; if (!populationDiversityTable.Rows.ContainsKey("Diversity")) populationDiversityTable.Rows.Add(new DataRow("Diversity") { VisualProperties = { StartIndexZero = true } }); int length = SymbolicExpressionTreeParameter.ActualValue.Length; var similarity = SimilarityParameter.ActualValue.Value / (length * (length - 1) / 2.0); var diversity = 1 - similarity; SimilarityParameter.ActualValue.Value = -1.0; populationDiversityTable.Rows["Diversity"].Values.Add(diversity); // selection diversity if (GlobalCloneMap == null) return base.Apply(); DataTable relativeSelectionCountsTable; if (!results.ContainsKey("SelectedIndividuals")) { relativeSelectionCountsTable = new DataTable("SelectedIndividuals") { VisualProperties = { YAxisTitle = "% Selected Individuals" } }; results.Add(new Result("SelectedIndividuals", relativeSelectionCountsTable)); } relativeSelectionCountsTable = (DataTable)Results["SelectedIndividuals"].Value; if (!relativeSelectionCountsTable.Rows.ContainsKey("SelectedIndividuals")) { relativeSelectionCountsTable.Rows.Add(new DataRow("SelectedIndividuals") { VisualProperties = { StartIndexZero = true } }); } double relativeSelectionCount = GlobalCloneMap.Values.Distinct().Count() / (double)SymbolicExpressionTreeParameter.ActualValue.Length; relativeSelectionCountsTable.Rows["SelectedIndividuals"].Values.Add(relativeSelectionCount); return base.Apply(); } } }