#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();
}
}
}