#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.Collections.Generic;
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;
namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Analyzers {
[StorableClass]
[Item("SymbolicDataAnalysisInternalDiversityAnalyzer", "An analyzer that determines the average diversity of symbolic expression trees.")]
public class SymbolicDataAnalysisInternalDiversityAnalyzer : SingleSuccessorOperator, ISymbolicDataAnalysisAnalyzer {
private const string SymbolicExpressionTreeParameterName = "SymbolicExpressionTree";
private const string QualityParameterName = "Quality";
private const string PercentageOfBestSolutionsParameterName = "PercentageOfBestSolutions";
private const string ResultCollectionParameterName = "Results";
private readonly BottomUpSimilarityCalculator busCalculator;
public SymbolicDataAnalysisInternalDiversityAnalyzer() {
busCalculator = new BottomUpSimilarityCalculator();
Parameters.Add(new ScopeTreeLookupParameter(SymbolicExpressionTreeParameterName));
Parameters.Add(new ScopeTreeLookupParameter(QualityParameterName));
Parameters.Add(new LookupParameter(ResultCollectionParameterName));
Parameters.Add(new FixedValueParameter(PercentageOfBestSolutionsParameterName));
}
protected SymbolicDataAnalysisInternalDiversityAnalyzer(SymbolicDataAnalysisInternalDiversityAnalyzer original, Cloner cloner)
: base(original, cloner) {
}
public override IDeepCloneable Clone(Cloner cloner) {
return new SymbolicDataAnalysisInternalDiversityAnalyzer(this, cloner);
}
#region parameter properties
public IScopeTreeLookupParameter SymbolicExpressionTreeParameter {
get { return (IScopeTreeLookupParameter)Parameters[SymbolicExpressionTreeParameterName]; }
}
public IScopeTreeLookupParameter QualityParameter {
get { return (IScopeTreeLookupParameter)Parameters[QualityParameterName]; }
}
public ILookupParameter ResultCollectionParameter {
get { return (ILookupParameter)Parameters[ResultCollectionParameterName]; }
}
public IFixedValueParameter PercentageOfBestSolutionsParameter {
get { return (IFixedValueParameter)Parameters[PercentageOfBestSolutionsParameterName]; }
}
#endregion
public double PercentageOfBestSolutions {
get { return PercentageOfBestSolutionsParameter.Value.Value; }
set { PercentageOfBestSolutionsParameter.Value.Value = value; }
}
public bool EnabledByDefault { get { return true; } }
public override IOperation Apply() {
var results = ResultCollectionParameter.ActualValue;
DataTable table;
if (!results.ContainsKey("Avg. Internal Diversity")) {
table = new DataTable("Internal Diversity") { VisualProperties = { YAxisTitle = "Internal Diversity" } };
var row = new DataRow("Avg. Internal Diversity") { VisualProperties = { StartIndexZero = true } };
table.Rows.Add(row);
results.Add(new Result("Avg. Internal Diversity", table));
} else {
table = (DataTable)results["Avg. Internal Diversity"].Value;
}
var trees = SymbolicExpressionTreeParameter.ActualValue.ToArray();
var qualities = QualityParameter.ActualValue.ToArray();
Array.Sort(qualities, trees, new ReverseComparer());
int n = (int)Math.Floor(trees.Length * PercentageOfBestSolutions);
double avgInternalDiversity = trees.Take(n).Average(tree => CalculateInternalDiversity(tree));
table.Rows["Avg. Internal Diversity"].Values.Add(avgInternalDiversity);
return base.Apply();
}
private double CalculateInternalDiversity(ISymbolicExpressionTree tree) {
var branchPoint = tree.IterateNodesPrefix().FirstOrDefault(x => x.SubtreeCount == 2);
if (branchPoint == null)
return 1;
var s1 = branchPoint.GetSubtree(0);
var s2 = branchPoint.GetSubtree(1);
// set parents to null because otherwise the bottom-up calculator will throw an exception
var p1 = s1.Parent;
s1.Parent = null;
var p2 = s2.Parent;
s2.Parent = null;
var m = busCalculator.ComputeBottomUpMapping(s1, s2);
var diversity = 1 - 2.0 * m.Count / (s1.GetLength() + s2.GetLength());
// restore parents
s1.Parent = p1;
s2.Parent = p2;
return diversity;
}
}
internal class ReverseComparer : IComparer {
public int Compare(DoubleValue x, DoubleValue y) {
return y.CompareTo(x);
}
}
}