Index: trunk/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Analyzers/SymbolicDataAnalysisBuildingBlockAnalyzer.cs
===================================================================
--- trunk/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Analyzers/SymbolicDataAnalysisBuildingBlockAnalyzer.cs	(revision 16271)
+++ trunk/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Analyzers/SymbolicDataAnalysisBuildingBlockAnalyzer.cs	(revision 16272)
@@ -20,4 +20,5 @@
 #endregion
 
+using System;
 using System.Collections.Generic;
 using System.Linq;
@@ -38,4 +39,5 @@
   public sealed class SymbolicDataAnalysisBuildingBlockAnalyzer : SymbolicDataAnalysisAnalyzer {
     private const string BuildingBlocksResultName = "BuildingBlocks";
+    private const string SolutionUniquenessResultName = "SolutionUniqueness";
     private const string MinimumSubtreeLengthParameterName = "MinimumSubtreeLength";
     private const string SimplifyTreesParameterName = "SimplifyTrees";
@@ -90,4 +92,6 @@
     [StorableConstructor]
     private SymbolicDataAnalysisBuildingBlockAnalyzer(bool deserializing) : base(deserializing) { }
+
+    private readonly Func<byte[], ulong> hashFunction = HashUtil.JSHash;
 
     public override IOperation Apply() {
@@ -109,8 +113,10 @@
       int totalCount = 0; // total number of examined subtrees
 
+      var hashes = new List<ulong>();
       // count hashes
       foreach (var tree in SymbolicExpressionTree) {
         var hashNodes = tree.Root.GetSubtree(0).GetSubtree(0).MakeNodes();
-        var simplified = simplify ? hashNodes.Simplify() : hashNodes.Sort();
+        var simplified = simplify ? hashNodes.Simplify(hashFunction) : hashNodes.Sort(hashFunction);
+        hashes.Add(simplified.Last().CalculatedHashValue); // maybe calculate aggregate hash instead
 
         for (int i = 0; i < simplified.Length; i++) {
@@ -165,4 +171,28 @@
       }
 
+      // compute solution uniqueness
+      DataTableHistory dth;
+      var counts = hashes.GroupBy(x => x).ToDictionary(x => x.Key, x => x.Count());
+      if (!ResultCollection.ContainsKey(SolutionUniquenessResultName)) {
+        dth = new DataTableHistory();
+        ResultCollection.Add(new Result(SolutionUniquenessResultName, dth));
+      } else {
+        dth = (DataTableHistory)ResultCollection[SolutionUniquenessResultName].Value;
+      }
+
+      var ct = new DataTable("Unique Solutions");
+      var ctr = new DataRow { VisualProperties = { StartIndexZero = true, ChartType = DataRowVisualProperties.DataRowChartType.Columns } };
+      ctr.Values.AddRange(hashes.Select(x => (double)counts[x]).OrderByDescending(x => x));
+      ct.Rows.Add(ctr);
+      dth.Add(ct);
+
+      var max = dth.Max(x => x.Rows.First().Values.Max());
+      foreach (var table in dth) {
+        table.VisualProperties.YAxisMinimumAuto = false;
+        table.VisualProperties.YAxisMaximumAuto = false;
+        table.VisualProperties.YAxisMinimumFixedValue = 0;
+        table.VisualProperties.YAxisMaximumFixedValue = max;
+      }
+
       return base.Apply();
     }
Index: trunk/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Crossovers/SymbolicDataAnalysisExpressionDiversityPreservingCrossover.cs
===================================================================
--- trunk/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Crossovers/SymbolicDataAnalysisExpressionDiversityPreservingCrossover.cs	(revision 16271)
+++ trunk/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Crossovers/SymbolicDataAnalysisExpressionDiversityPreservingCrossover.cs	(revision 16272)
@@ -20,4 +20,6 @@
     private const string WindowingParameterName = "Windowing";
     private const string ProportionalSamplingParameterName = "ProportionalSampling";
+
+    private static readonly Func<byte[], ulong> hashFunction = HashUtil.JSHash;
 
     #region Parameter Properties
@@ -73,6 +75,6 @@
       var leafCrossoverPointProbability = 1 - internalCrossoverPointProbability;
 
-      var nodes0 = ActualRoot(parent0).MakeNodes().Sort();
-      var nodes1 = ActualRoot(parent1).MakeNodes().Sort();
+      var nodes0 = ActualRoot(parent0).MakeNodes().Sort(hashFunction);
+      var nodes1 = ActualRoot(parent1).MakeNodes().Sort(hashFunction);
 
       IList<HashNode<ISymbolicExpressionTreeNode>> sampled0;
Index: trunk/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Hashing/HashExtensions.cs
===================================================================
--- trunk/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Hashing/HashExtensions.cs	(revision 16271)
+++ trunk/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Hashing/HashExtensions.cs	(revision 16272)
@@ -67,6 +67,5 @@
 
       public override int GetHashCode() {
-        //return CalculatedHashValue;
-        return Data.GetHashCode();
+        return (int)CalculatedHashValue;
       }
 
@@ -80,16 +79,25 @@
     }
 
-    public static ulong ComputeHash<T>(this HashNode<T>[] nodes, int i) where T : class {
+    public static ulong ComputeHash<T>(this HashNode<T>[] nodes, int i, Func<byte[], ulong> hashFunction) where T : class {
       var node = nodes[i];
-      var hashes = new ulong[node.Arity + 1];
-      for (int j = i - 1, k = 0; k < node.Arity; j -= 1 + nodes[j].Size, k++) {
-        hashes[k] = nodes[j].CalculatedHashValue;
-      }
-      hashes[node.Arity] = node.HashValue;
-      return HashUtil.JSHash(hashes);
-    }
-
-    public static HashNode<T>[] Simplify<T>(this HashNode<T>[] nodes) where T : class {
-      var reduced = nodes.UpdateNodeSizes().Reduce().Sort();
+      const int size = sizeof(ulong);
+      var hashes = new byte[(node.Arity + 1) * size];
+
+      for (int j = i - 1, k = 0; k < node.Arity; ++k, j -= 1 + nodes[j].Size) {
+        Array.Copy(BitConverter.GetBytes(nodes[j].CalculatedHashValue), 0, hashes, k * size, size);
+      }
+      Array.Copy(BitConverter.GetBytes(node.HashValue), 0, hashes, node.Arity * size, size);
+      return hashFunction(hashes);
+    }
+
+    // set the enabled state for the whole subtree rooted at this node 
+    public static void SetEnabled<T>(this HashNode<T>[] nodes, int i, bool enabled) where T : class {
+      nodes[i].Enabled = enabled;
+      for (int j = i - nodes[i].Size; j < i; ++j)
+        nodes[j].Enabled = enabled;
+    }
+
+    public static HashNode<T>[] Simplify<T>(this HashNode<T>[] nodes, Func<byte[], ulong> hashFunction) where T : class {
+      var reduced = nodes.UpdateNodeSizes().Reduce().Sort(hashFunction);
 
       for (int i = 0; i < reduced.Length; ++i) {
@@ -116,8 +124,8 @@
         }
       }
-      return simplified.UpdateNodeSizes().Reduce().Sort();
-    }
-
-    public static HashNode<T>[] Sort<T>(this HashNode<T>[] nodes) where T : class {
+      return simplified.UpdateNodeSizes().Reduce().Sort(hashFunction);
+    }
+
+    public static HashNode<T>[] Sort<T>(this HashNode<T>[] nodes, Func<byte[], ulong> hashFunction) where T : class {
       int sort(int a, int b) => nodes[a].CompareTo(nodes[b]);
 
@@ -155,5 +163,5 @@
           }
         }
-        node.CalculatedHashValue = nodes.ComputeHash(i);
+        node.CalculatedHashValue = nodes.ComputeHash(i, hashFunction);
       }
       return nodes;
Index: trunk/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Hashing/HashUtil.cs
===================================================================
--- trunk/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Hashing/HashUtil.cs	(revision 16271)
+++ trunk/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Hashing/HashUtil.cs	(revision 16272)
@@ -21,4 +21,7 @@
 
 
+using System;
+using System.Security.Cryptography;
+
 namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
   public static class HashUtil {
@@ -26,5 +29,5 @@
 
     // A simple hash function from Robert Sedgwicks Algorithms in C book.I've added some simple optimizations to the algorithm in order to speed up its hashing process. 
-    public static ulong RSHash(ulong[] input) {
+    public static ulong RSHash(byte[] input) {
       const int b = 378551;
       ulong a = 63689;
@@ -39,5 +42,5 @@
 
     // A bitwise hash function written by Justin Sobel
-    public static ulong JSHash(ulong[] input) {
+    public static ulong JSHash(byte[] input) {
       ulong hash = 1315423911;
       for (int i = 0; i < input.Length; ++i)
@@ -47,5 +50,5 @@
 
     // This hash function comes from Brian Kernighan and Dennis Ritchie's book "The C Programming Language". It is a simple hash function using a strange set of possible seeds which all constitute a pattern of 31....31...31 etc, it seems to be very similar to the DJB hash function. 
-    public static ulong BKDRHash(ulong[] input) {
+    public static ulong BKDRHash(byte[] input) {
       ulong seed = 131;
       ulong hash = 0;
@@ -57,5 +60,5 @@
 
     // This is the algorithm of choice which is used in the open source SDBM project. The hash function seems to have a good over-all distribution for many different data sets. It seems to work well in situations where there is a high variance in the MSBs of the elements in a data set. 
-    public static ulong SDBMHash(ulong[] input) {
+    public static ulong SDBMHash(byte[] input) {
       ulong hash = 0;
       foreach (var v in input) {
@@ -66,5 +69,5 @@
 
     // An algorithm produced by Professor Daniel J. Bernstein and shown first to the world on the usenet newsgroup comp.lang.c. It is one of the most efficient hash functions ever published. 
-    public static ulong DJBHash(ulong[] input) {
+    public static ulong DJBHash(byte[] input) {
       ulong hash = 5381;
       foreach (var v in input) {
@@ -75,5 +78,5 @@
 
     // An algorithm proposed by Donald E.Knuth in The Art Of Computer Programming Volume 3, under the topic of sorting and search chapter 6.4. 
-    public static ulong DEKHash(ulong[] input) {
+    public static ulong DEKHash(byte[] input) {
       ulong hash = (ulong)input.Length;
       foreach (var v in input) {
@@ -83,23 +86,7 @@
     }
 
-    //public static ulong CryptoHash(HashAlgorithm ha, ulong[] input) {
-    //  return BitConverter.ToInt32(ha.ComputeHash(input.ToByteArray()), 0);
-    //}
-
-    //public static byte[] ToByteArray(this ulong[] input) {
-    //  var bytes = new byte[input.Length * sizeof(int)];
-    //  int pos = 0;
-    //  foreach (var v in input) {
-    //    var b0 = (byte)((v >> 24) & 0xFF);
-    //    var b1 = (byte)((v >> 16) & 0xFF);
-    //    var b2 = (byte)((v >> 8) & 0xFF);
-    //    var b3 = (byte)(v & 0xFF);
-    //    bytes[pos++] = b0;
-    //    bytes[pos++] = b1;
-    //    bytes[pos++] = b2;
-    //    bytes[pos++] = b3;
-    //  }
-    //  return bytes;
-    //}
+    public static ulong CryptoHash(HashAlgorithm ha, byte[] input) {
+      return BitConverter.ToUInt64(ha.ComputeHash(input), 0);
+    }
   }
 }
Index: trunk/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Hashing/SymbolicExpressionTreeHash.cs
===================================================================
--- trunk/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Hashing/SymbolicExpressionTreeHash.cs	(revision 16271)
+++ trunk/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Hashing/SymbolicExpressionTreeHash.cs	(revision 16272)
@@ -20,5 +20,4 @@
 #endregion
 
-using System.Collections.Generic;
 using System.Linq;
 using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
@@ -43,31 +42,10 @@
     }
 
-    // compute node hashes without sorting the arguments
-    public static Dictionary<ISymbolicExpressionTreeNode, ulong> ComputeNodeHashes(this ISymbolicExpressionTree tree) {
-      var root = tree.Root.GetSubtree(0).GetSubtree(0);
-      var nodes = root.MakeNodes();
-      nodes.UpdateNodeSizes();
-
-      for (int i = 0; i < nodes.Length; ++i) {
-        if (nodes[i].IsLeaf)
-          continue;
-        nodes[i].CalculatedHashValue = nodes.ComputeHash(i);
-      }
-      return nodes.ToDictionary(x => x.Data, x => x.CalculatedHashValue);
-    }
-
     public static ulong ComputeHash(this ISymbolicExpressionTreeNode treeNode) {
+      ulong hashFunction(byte[] input) => HashUtil.JSHash(input);
       var hashNodes = treeNode.MakeNodes();
-      var simplified = hashNodes.Simplify();
-      //return ComputeHash(simplified);
+      var simplified = hashNodes.Simplify(hashFunction);
       return simplified.Last().CalculatedHashValue;
     }
-
-    //public static int ComputeHash(this HashNode<ISymbolicExpressionTreeNode>[] nodes) {
-    //  int hash = 1315423911;
-    //  foreach (var node in nodes)
-    //    hash ^= (hash << 5) + node.CalculatedHashValue + (hash >> 2);
-    //  return hash;
-    //}
 
     public static HashNode<ISymbolicExpressionTreeNode> ToHashNode(this ISymbolicExpressionTreeNode node) {
@@ -152,7 +130,8 @@
     // (in other words simplification should be applied in a bottom-up fashion) 
     public static ISymbolicExpressionTree Simplify(ISymbolicExpressionTree tree) {
+      ulong hashFunction(byte[] bytes) => HashUtil.JSHash(bytes);
       var root = tree.Root.GetSubtree(0).GetSubtree(0);
       var nodes = root.MakeNodes();
-      var simplified = nodes.Simplify();
+      var simplified = nodes.Simplify(hashFunction);
       return simplified.ToTree();
     }
Index: trunk/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.csproj
===================================================================
--- trunk/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.csproj	(revision 16271)
+++ trunk/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.csproj	(revision 16272)
@@ -142,4 +142,5 @@
     <Compile Include="Converters\DerivativeCalculator.cs" />
     <Compile Include="Converters\TreeToAutoDiffTermConverter.cs" />
+    <Compile Include="Crossovers\SymbolicDataAnalysisExpressionDiversityPreservingCrossover.cs" />
     <Compile Include="Formatters\InfixExpressionFormatter.cs" />
     <Compile Include="Formatters\TSQLExpressionFormatter.cs" />
