Index: branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Analyzers/SymbolicDataAnalysisInternalDiversityAnalyzer.cs
===================================================================
--- branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Analyzers/SymbolicDataAnalysisInternalDiversityAnalyzer.cs	(revision 11232)
+++ branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Analyzers/SymbolicDataAnalysisInternalDiversityAnalyzer.cs	(revision 11232)
@@ -0,0 +1,144 @@
+﻿#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 <http://www.gnu.org/licenses/>.
+ */
+#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<ISymbolicExpressionTree>(SymbolicExpressionTreeParameterName));
+      Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>(QualityParameterName));
+      Parameters.Add(new LookupParameter<ResultCollection>(ResultCollectionParameterName));
+      Parameters.Add(new FixedValueParameter<PercentValue>(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<ISymbolicExpressionTree> SymbolicExpressionTreeParameter {
+      get { return (IScopeTreeLookupParameter<ISymbolicExpressionTree>)Parameters[SymbolicExpressionTreeParameterName]; }
+    }
+
+    public IScopeTreeLookupParameter<DoubleValue> QualityParameter {
+      get { return (IScopeTreeLookupParameter<DoubleValue>)Parameters[QualityParameterName]; }
+    }
+
+    public ILookupParameter<ResultCollection> ResultCollectionParameter {
+      get { return (ILookupParameter<ResultCollection>)Parameters[ResultCollectionParameterName]; }
+    }
+
+    public IFixedValueParameter<PercentValue> PercentageOfBestSolutionsParameter {
+      get { return (IFixedValueParameter<PercentValue>)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<DoubleValue> {
+    public int Compare(DoubleValue x, DoubleValue y) {
+      return y.CompareTo(x);
+    }
+  }
+}
