Index: branches/HeuristicLab.Analysis.AlgorithmBehavior/HeuristicLab.Analysis.AlgorithmBehavior/3.3/Analyzers/BuildingBlockAnalyzer.cs
===================================================================
--- branches/HeuristicLab.Analysis.AlgorithmBehavior/HeuristicLab.Analysis.AlgorithmBehavior/3.3/Analyzers/BuildingBlockAnalyzer.cs	(revision 8191)
+++ branches/HeuristicLab.Analysis.AlgorithmBehavior/HeuristicLab.Analysis.AlgorithmBehavior/3.3/Analyzers/BuildingBlockAnalyzer.cs	(revision 8191)
@@ -0,0 +1,194 @@
+﻿#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 <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis.AlgorithmBehavior {
+  using System.Collections.Generic;
+  using HeuristicLab.Data;
+  using HeuristicLab.Encodings.PermutationEncoding;
+  using TraceMapType = HeuristicLab.Core.ItemDictionary<HeuristicLab.Core.IItem, HeuristicLab.Core.IItemList<HeuristicLab.Core.IItem>>;
+
+  /// <summary>
+  /// An operator that analyzes building blocks.
+  /// </summary>
+  [Item("BuildingBlockAnalyzer", "An operator that tracks the genealogy of every individual.")]
+  [StorableClass]
+  public sealed class BuildingBlockAnalyzer : SingleSuccessorOperator, IAnalyzer {
+    private const string GlobalTraceMapParameterName = "GlobalTraceMap";
+    private const string ResultsParameterName = "Results";
+    private const string PopulationGraphResultParameterName = "PopulationGraph";
+    private const string BuildingBlockSchemaMatrixParameterName = "BuildingBlockSchemaMatrix";
+    private const string BuildingBlockPatternMatrixParameterName = "BuildingBlockPatternMatrix";
+
+    #region IAnalyzer Members
+    public bool EnabledByDefault {
+      get { return true; }
+    }
+    #endregion
+
+    #region Parameter properties
+    public ILookupParameter<TraceMapType> GlobalTraceMapParameter {
+      get { return (ILookupParameter<TraceMapType>)Parameters[GlobalTraceMapParameterName]; }
+    }
+    public ILookupParameter<ResultCollection> ResultsParameter {
+      get { return (ILookupParameter<ResultCollection>)Parameters[ResultsParameterName]; }
+    }
+    #endregion
+
+    #region Properties
+    public TraceMapType GlobalTraceMap {
+      get { return GlobalTraceMapParameter.ActualValue; }
+    }
+    public ResultCollection Results {
+      get { return ResultsParameter.ActualValue; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    private BuildingBlockAnalyzer(bool deserializing) : base(deserializing) { }
+    private BuildingBlockAnalyzer(BuildingBlockAnalyzer original, Cloner cloner) : base(original, cloner) { }
+    public BuildingBlockAnalyzer()
+      : base() {
+      Parameters.Add(new LookupParameter<TraceMapType>(GlobalTraceMapParameterName, "A global cache containing the whole genealogy."));
+      Parameters.Add(new LookupParameter<ResultCollection>(ResultsParameterName, "The results collection where the analysis values should are stored."));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new BuildingBlockAnalyzer(this, cloner);
+    }
+
+    public override IOperation Apply() {
+      var graph = (GenealogyGraph<Permutation>)Results[PopulationGraphResultParameterName].Value;
+      var generationZero = graph.Values.Where(x => x.Rank == 0);
+
+      // extract all subtours for each individual in generation zero
+      var subtours = new Dictionary<Permutation, IList<int[]>>();
+      foreach (var individual in generationZero) {
+        subtours[(Permutation)individual.Data] = ExtractSubtours((Permutation)individual.Data);
+      }
+
+      // process all schemata
+      var schemataMatrix = new Dictionary<int[], int[]>(new SchemaEqualityComparer());
+      foreach (var entry in subtours) {
+        foreach (var schema in entry.Value) {
+          if (!schemataMatrix.ContainsKey(schema)) {
+            var categories = new int[3];
+            categories[0] = ExploreGlobalSchemaOccurrence(graph, schema);
+            categories[1] = ExploreBrokenInteritanceSchemaOccurrence(graph, schema);
+            categories[2] = ExploreUnbrokenInteritanceSchemaOccurrence(graph, schema);
+            schemataMatrix.Add(schema, categories);
+          }
+        }
+      }
+
+      // order schemas according to their global occurrence count
+      var sortedSchemataMatrix = schemataMatrix.OrderByDescending(x => x.Value[0]).ToDictionary(x => x.Key, x => x.Value);
+
+      var stringMatrix = new StringMatrix(sortedSchemataMatrix.Keys.Count, 4);
+      for (int i = 0; i < sortedSchemataMatrix.Keys.Count; i++) {
+        var element = sortedSchemataMatrix.ElementAt(i);
+        stringMatrix[i, 0] = new Permutation(PermutationTypes.RelativeUndirected, element.Key).ToString();
+        for (int j = 0; j < element.Value.Count(); j++) {
+          stringMatrix[i, j + 1] = element.Value[j].ToString();
+        }
+      }
+      stringMatrix.ColumnNames = new[] { "Schema", "GlobalSchemaOccurrence", "BrokenInteritanceSchemaOccurrence", "UnbrokenInteritanceSchemaOccurrence" };
+
+      Results.Add(new Result(BuildingBlockSchemaMatrixParameterName, stringMatrix));
+
+      return base.Apply();
+    }
+
+    private int ExploreGlobalSchemaOccurrence(GenealogyGraph<Permutation> graph, int[] schema) {
+      int occurrences = 0;
+      foreach (var individual in graph.Values)
+        if (IsSubtour(schema, (Permutation)individual.Data)) occurrences++;
+      return occurrences;
+    }
+
+    private int ExploreBrokenInteritanceSchemaOccurrence(GenealogyGraph<Permutation> graph, int[] schema) {
+      // TODO
+      return 0;
+    }
+
+    private int ExploreUnbrokenInteritanceSchemaOccurrence(GenealogyGraph<Permutation> graph, int[] schema) {
+      // TODO
+      return 0;
+    }
+
+    private IList<int[]> ExtractSubtours(Permutation permutation) {
+      var subtours = new List<int[]>();
+      for (int i = 2; i <= permutation.Count() / 2; i++) { // increase schema length from 2 to n/2
+        for (int j = 0; j < permutation.Count(); j++) { // visit all positions in the permutation
+          var schema = new int[i];
+          for (int k = 0; k < i; k++) schema[k] = permutation[(j + k) % permutation.Length]; // copy edge to schema
+          subtours.Add(schema);
+        }
+      }
+      return subtours;
+    }
+
+    private bool IsSubtour(int[] tour, Permutation permutation) {
+      // determine starting position for subtour match
+      int idx = permutation.Select((x, index) => new { Value = x, Index = index }).Single(x => x.Value == tour[0]).Index;
+      bool isSubtour = true;
+      for (int i = 1; i < tour.Length; i++) {
+        if (tour[i] == permutation[(idx + 1) % permutation.Length]) { // check right side
+          idx = (idx + 1) % permutation.Length;
+        } else if (tour[i] == permutation[(idx - 1 + permutation.Length) % permutation.Length]) { // check left side
+          idx = (idx - 1 + permutation.Length) % permutation.Length;
+        } else {
+          isSubtour = false;
+          break;
+        }
+      }
+      return isSubtour;
+    }
+
+    private class SchemaEqualityComparer : EqualityComparer<int[]> {
+      public override bool Equals(int[] x, int[] y) {
+        if (object.ReferenceEquals(x, y)) return true;
+        if (x == null || y == null || x.Length != y.Length) return false;
+        EqualityComparer<int> comparer = EqualityComparer<int>.Default;
+        bool match = true;
+        for (int i = 0; i < x.Length && match; i++) // check normal tour
+          if (!comparer.Equals(x[i], y[i])) match = false;
+        if (!match) {
+          match = true;
+          for (int i = x.Length - 1; i >= 0 && match; i--) // check inverse tour
+            if (!comparer.Equals(x[i], y[i])) match = false;
+        }
+        return match;
+      }
+
+      public override int GetHashCode(int[] obj) {
+        return 0; // return the same hash code for each object, otherwise Equals will not be called
+      }
+    }
+  }
+}
Index: branches/HeuristicLab.Analysis.AlgorithmBehavior/HeuristicLab.Analysis.AlgorithmBehavior/3.3/HeuristicLab.Analysis.AlgorithmBehavior-3.3.csproj
===================================================================
--- branches/HeuristicLab.Analysis.AlgorithmBehavior/HeuristicLab.Analysis.AlgorithmBehavior/3.3/HeuristicLab.Analysis.AlgorithmBehavior-3.3.csproj	(revision 8177)
+++ branches/HeuristicLab.Analysis.AlgorithmBehavior/HeuristicLab.Analysis.AlgorithmBehavior/3.3/HeuristicLab.Analysis.AlgorithmBehavior-3.3.csproj	(revision 8191)
@@ -74,4 +74,5 @@
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="Analyzers\BuildingBlockAnalyzer.cs" />
     <Compile Include="Analyzers\GenealogyAnalyzer.cs" />
     <Compile Include="GenealogyGraph.cs" />
