Index: /trunk/sources/HeuristicLab.Analysis/3.3/PopulationSimilarityAnalysis/PopulationSimilarityAnalyzer.cs
===================================================================
--- /trunk/sources/HeuristicLab.Analysis/3.3/PopulationSimilarityAnalysis/PopulationSimilarityAnalyzer.cs	(revision 13004)
+++ /trunk/sources/HeuristicLab.Analysis/3.3/PopulationSimilarityAnalysis/PopulationSimilarityAnalyzer.cs	(revision 13005)
@@ -39,4 +39,6 @@
   public class PopulationSimilarityAnalyzer : SingleSuccessorOperator, IAnalyzer, ISimilarityBasedOperator {
     private const string DiversityResultNameParameterName = "DiversityResultsName";
+    private const string ExecuteInParallelParameterName = "ExecuteInParallel";
+    private const string MaxDegreeOfParallelismParameterName = "MaxDegreeOfParallelism";
 
     #region Backwards compatible code, remove with 3.4
@@ -71,4 +73,10 @@
       get { return (FixedValueParameter<StringValue>)Parameters[DiversityResultNameParameterName]; }
     }
+    public IFixedValueParameter<BoolValue> ExecuteInParallelParameter {
+      get { return (IFixedValueParameter<BoolValue>)Parameters[ExecuteInParallelParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> MaxDegreeOfParallelismParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[MaxDegreeOfParallelismParameterName]; }
+    }
 
     public string DiversityResultName {
@@ -77,7 +85,22 @@
     }
 
+    public bool ExecuteInParallel {
+      get { return ExecuteInParallelParameter.Value.Value; }
+      set { ExecuteInParallelParameter.Value.Value = value; }
+    }
+
+    public int MaxDegreeOfParallelism {
+      get { return MaxDegreeOfParallelismParameter.Value.Value; }
+      set { MaxDegreeOfParallelismParameter.Value.Value = value; }
+    }
+
     [StorableConstructor]
     protected PopulationSimilarityAnalyzer(bool deserializing) : base(deserializing) { }
-    protected PopulationSimilarityAnalyzer(PopulationSimilarityAnalyzer original, Cloner cloner) : base(original, cloner) { }
+
+    protected PopulationSimilarityAnalyzer(PopulationSimilarityAnalyzer original, Cloner cloner)
+      : base(original, cloner) {
+      RegisterParametersEventHandlers();
+    }
+
     public PopulationSimilarityAnalyzer(IEnumerable<ISolutionSimilarityCalculator> validSimilarityCalculators)
       : base() {
@@ -89,12 +112,31 @@
       Parameters.Add(new LookupParameter<IntValue>("UpdateCounter", "The value which counts how many times the operator was called since the last update.", "PopulationDiversityAnalyzerUpdateCounter"));
       Parameters.Add(new FixedValueParameter<StringValue>(DiversityResultNameParameterName, "Specifies how the diversity results should be named.", new StringValue("PopulationDiversity")));
+      Parameters.Add(new FixedValueParameter<BoolValue>(ExecuteInParallelParameterName, "Specifies whether similarity calculations should be parallelized.", new BoolValue(false)));
+      Parameters.Add(new FixedValueParameter<IntValue>(MaxDegreeOfParallelismParameterName, "Specifies the maximum number of threads when calculating similarities in parallel.", new IntValue(-1)));
 
       var similarityCalculators = SimilarityCalculatorParameter.ValidValues;
-      foreach (var sc in validSimilarityCalculators)
+      foreach (var sc in validSimilarityCalculators) {
         similarityCalculators.Add(sc);
-
+      }
 
       ResultsParameter.Hidden = true;
       UpdateCounterParameter.Hidden = true;
+      ExecuteInParallelParameter.Hidden = true;
+      MaxDegreeOfParallelismParameter.Hidden = true;
+
+      RegisterParametersEventHandlers();
+    }
+
+    private void RegisterParametersEventHandlers() {
+      ExecuteInParallelParameter.Value.ValueChanged += Value_ValueChanged;
+      MaxDegreeOfParallelismParameter.Value.ValueChanged += Value_ValueChanged;
+    }
+
+    private void Value_ValueChanged(object sender, EventArgs e) {
+      var similarityCalculators = SimilarityCalculatorParameter.ValidValues;
+      foreach (var similarityCalculator in similarityCalculators) {
+        similarityCalculator.ExecuteInParallel = ExecuteInParallel;
+        similarityCalculator.MaxDegreeOfParallelism = MaxDegreeOfParallelism;
+      }
     }
 
@@ -113,5 +155,19 @@
         Parameters.Add(new ConstrainedValueParameter<ISolutionSimilarityCalculator>("SimilarityCalculator", "The similarity calculator that should be used to calculate solution similarity."));
 
-      SimilarityCalculatorParameter.ValidValues.Add(oldSimilarityCalculator);
+      if (oldSimilarityCalculator != null)
+        SimilarityCalculatorParameter.ValidValues.Add(oldSimilarityCalculator);
+
+      if (!Parameters.ContainsKey(ExecuteInParallelParameterName)) {
+        Parameters.Add(new FixedValueParameter<BoolValue>(ExecuteInParallelParameterName,
+          "Specifies whether similarity calculations should be parallelized.", new BoolValue(false)));
+        ExecuteInParallelParameter.Hidden = true;
+      }
+      if (!Parameters.ContainsKey(MaxDegreeOfParallelismParameterName)) {
+        Parameters.Add(new FixedValueParameter<IntValue>(MaxDegreeOfParallelismParameterName,
+          "Specifies the maximum number of threads when calculating similarities in parallel.", new IntValue(-1)));
+        MaxDegreeOfParallelismParameter.Hidden = true;
+      }
+
+      RegisterParametersEventHandlers();
       #endregion
     }
Index: /trunk/sources/HeuristicLab.Optimization.Operators/3.3/SolutionSimilarityCalculator.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization.Operators/3.3/SolutionSimilarityCalculator.cs	(revision 13004)
+++ /trunk/sources/HeuristicLab.Optimization.Operators/3.3/SolutionSimilarityCalculator.cs	(revision 13005)
@@ -22,4 +22,5 @@
 using System;
 using System.Linq;
+using System.Threading.Tasks;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -41,4 +42,8 @@
     [Storable]
     public string QualityVariableName { get; set; }
+    [Storable]
+    public bool ExecuteInParallel { get; set; }
+    [Storable]
+    public int MaxDegreeOfParallelism { get; set; }
     #endregion
 
@@ -48,8 +53,22 @@
     protected SolutionSimilarityCalculator(SolutionSimilarityCalculator original, Cloner cloner)
       : base(original, cloner) {
-      this.SolutionVariableName = original.SolutionVariableName;
-      this.QualityVariableName = original.QualityVariableName;
-    }
-    protected SolutionSimilarityCalculator() : base() { }
+      SolutionVariableName = original.SolutionVariableName;
+      QualityVariableName = original.QualityVariableName;
+      ExecuteInParallel = original.ExecuteInParallel;
+      MaxDegreeOfParallelism = original.MaxDegreeOfParallelism;
+    }
+
+    protected SolutionSimilarityCalculator() : base() {
+      ExecuteInParallel = false;
+      MaxDegreeOfParallelism = -1;
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      if (MaxDegreeOfParallelism == 0) {
+        ExecuteInParallel = false;
+        MaxDegreeOfParallelism = -1;
+      }
+    }
 
     public double[][] CalculateSolutionCrowdSimilarity(IScope leftSolutionCrowd, IScope rightSolutionCrowd) {
@@ -75,27 +94,51 @@
 
     public double[][] CalculateSolutionCrowdSimilarity(IScope solutionCrowd) {
-      if (solutionCrowd == null)
+      if (solutionCrowd == null) {
         throw new ArgumentException("Cannot calculate similarity because the provided crowd is null.");
-
+      }
       var individuals = solutionCrowd.SubScopes;
 
-      if (!individuals.Any())
+      if (!individuals.Any()) {
         throw new ArgumentException("Cannot calculate similarity because the provided crowd is empty.");
+      }
 
       var similarityMatrix = new double[individuals.Count][];
-      for (int i = 0; i < individuals.Count; i++) similarityMatrix[i] = new double[individuals.Count];
-
-      if (IsCommutative) {
-        for (int i = 0; i < individuals.Count; i++) {
-          for (int j = i; j < individuals.Count; j++) {
-            similarityMatrix[i][j] = similarityMatrix[j][i] = CalculateSolutionSimilarity(individuals[i], individuals[j]);
+      for (int i = 0; i < individuals.Count; i++) {
+        similarityMatrix[i] = new double[individuals.Count];
+      }
+
+      if (ExecuteInParallel) {
+        var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = MaxDegreeOfParallelism };
+        if (IsCommutative) {
+          Parallel.For(0, individuals.Count, parallelOptions, i => {
+            for (int j = i; j < individuals.Count; j++) {
+              similarityMatrix[i][j] =
+                similarityMatrix[j][i] = CalculateSolutionSimilarity(individuals[i], individuals[j]);
+            }
+          });
+        } else {
+          Parallel.For(0, individuals.Count, parallelOptions, i => {
+            for (int j = i; j < individuals.Count; j++) {
+              similarityMatrix[i][j] = CalculateSolutionSimilarity(individuals[i], individuals[j]);
+              if (i == j) continue;
+              similarityMatrix[j][i] = CalculateSolutionSimilarity(individuals[j], individuals[i]);
+            }
+          });
+        }
+      } else {
+        if (IsCommutative) {
+          for (int i = 0; i < individuals.Count; i++) {
+            for (int j = i; j < individuals.Count; j++) {
+              similarityMatrix[i][j] =
+                similarityMatrix[j][i] = CalculateSolutionSimilarity(individuals[i], individuals[j]);
+            }
           }
-        }
-      } else {
-        for (int i = 0; i < individuals.Count; i++) {
-          for (int j = i; j < individuals.Count; j++) {
-            similarityMatrix[i][j] = CalculateSolutionSimilarity(individuals[i], individuals[j]);
-            if (i == j) continue;
-            similarityMatrix[j][i] = CalculateSolutionSimilarity(individuals[j], individuals[i]);
+        } else {
+          for (int i = 0; i < individuals.Count; i++) {
+            for (int j = i; j < individuals.Count; j++) {
+              similarityMatrix[i][j] = CalculateSolutionSimilarity(individuals[i], individuals[j]);
+              if (i == j) continue;
+              similarityMatrix[j][i] = CalculateSolutionSimilarity(individuals[j], individuals[i]);
+            }
           }
         }
Index: /trunk/sources/HeuristicLab.Optimization/3.3/Interfaces/ISolutionSimilarityCalculator.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization/3.3/Interfaces/ISolutionSimilarityCalculator.cs	(revision 13004)
+++ /trunk/sources/HeuristicLab.Optimization/3.3/Interfaces/ISolutionSimilarityCalculator.cs	(revision 13005)
@@ -30,4 +30,6 @@
     string SolutionVariableName { get; set; }
     string QualityVariableName { get; set; }
+    bool ExecuteInParallel { get; set; }
+    int MaxDegreeOfParallelism { get; set; }
 
     /// <summary>
