Index: branches/VOSGA/HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm/Comparators/UnwantedMutationsComparator.cs
===================================================================
--- branches/VOSGA/HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm/Comparators/UnwantedMutationsComparator.cs	(revision 11884)
+++ branches/VOSGA/HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm/Comparators/UnwantedMutationsComparator.cs	(revision 11884)
@@ -0,0 +1,297 @@
+﻿#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.Linq;
+using HeuristicLab.Analysis;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.PermutationEncoding;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Optimization.Operators;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.PluginInfrastructure;
+
+namespace HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm {
+  [Item("UnwantedMutationsComparator", "Compares the similarity against that of its parents (assumes the parents are subscopes to the child scope). This operator works with any number of subscopes > 0.")]
+  [StorableClass]
+  public class UnwantedMutationsComparator : SingleSuccessorOperator, ISubScopesQualityComparatorOperator, ISimilarityBasedOperator {
+    [Storable]
+    public ISolutionSimilarityCalculator SimilarityCalculator { get; set; }
+    public IValueLookupParameter<BoolValue> MaximizationParameter {
+      get { return (IValueLookupParameter<BoolValue>)Parameters["Maximization"]; }
+    }
+    public ILookupParameter<DoubleValue> LeftSideParameter {
+      get { return (ILookupParameter<DoubleValue>)Parameters["LeftSide"]; }
+    }
+    public ILookupParameter<ItemArray<DoubleValue>> RightSideParameter {
+      get { return (ILookupParameter<ItemArray<DoubleValue>>)Parameters["RightSide"]; }
+    }
+    public ILookupParameter<BoolValue> ResultParameter {
+      get { return (ILookupParameter<BoolValue>)Parameters["Result"]; }
+    }
+    public ValueLookupParameter<DoubleValue> ComparisonFactorParameter {
+      get { return (ValueLookupParameter<DoubleValue>)Parameters["ComparisonFactor"]; }
+    }
+    public ValueLookupParameter<DoubleValue> DiversityComparisonFactorParameter {
+      get { return (ValueLookupParameter<DoubleValue>)Parameters["DiversityComparisonFactor"]; }
+    }
+    private ValueLookupParameter<DoubleValue> ComparisonFactorLowerBoundParameter {
+      get { return (ValueLookupParameter<DoubleValue>)Parameters["DiversityComparisonFactorLowerBound"]; }
+    }
+    private ValueLookupParameter<DoubleValue> ComparisonFactorUpperBoundParameter {
+      get { return (ValueLookupParameter<DoubleValue>)Parameters["DiversityComparisonFactorUpperBound"]; }
+    }
+    public IConstrainedValueParameter<IDiscreteDoubleValueModifier> ComparisonFactorModifierParameter {
+      get { return (IConstrainedValueParameter<IDiscreteDoubleValueModifier>)Parameters["ComparisonFactorModifier"]; }
+    }
+    public ValueLookupParameter<ResultCollection> ResultsParameter {
+      get { return (ValueLookupParameter<ResultCollection>)Parameters["Results"]; }
+    }
+    public ILookupParameter<IntValue> GenerationsParameter {
+      get { return (LookupParameter<IntValue>)Parameters["Generations"]; }
+    }
+    public ValueParameter<BoolValue> EnableDivCriteriaParameter {
+      get { return (ValueParameter<BoolValue>)Parameters["EnableDivCriteria"]; }
+    }
+    public ValueParameter<BoolValue> EnableQualityCriteriaParameter {
+      get { return (ValueParameter<BoolValue>)Parameters["EnableQualityCriteria"]; }
+    }
+
+    private const string spDetailsParameterName = "SPDetails";
+    private const string divDataRowName = "DiversitySuccessCount";
+    private const string qualityDataRowName = "QualitySuccessCount";
+    private const string divFailDataRowName = "DiversityFailCount";
+    private const string qualityFailDataRowName = "QualityFailCount";
+    private const string overallCountDataRowName = "OverallCount";
+    private const string successCountDataRowName = "SuccessCount";
+    private const string unwantedMutationsDataRowName = "UnwantedMutations";
+
+    [Storable]
+    private int currentGeneration;
+    [Storable]
+    private int divCount;
+    [Storable]
+    private int qualityCount;
+    [Storable]
+    private int badQualityCount;
+    [Storable]
+    private int badDivCount;
+    [Storable]
+    private int overallCount;
+    [Storable]
+    private int successCount;
+    [Storable]
+    private double umRatio;
+
+    [StorableConstructor]
+    protected UnwantedMutationsComparator(bool deserializing) : base(deserializing) { }
+    protected UnwantedMutationsComparator(UnwantedMutationsComparator original, Cloner cloner)
+      : base(original, cloner) {
+      SimilarityCalculator = cloner.Clone(original.SimilarityCalculator);
+      currentGeneration = original.currentGeneration;
+      divCount = original.divCount;
+      qualityCount = original.qualityCount;
+      overallCount = original.overallCount;
+      successCount = original.successCount;
+      badDivCount = original.badDivCount;
+      badQualityCount = original.badQualityCount;
+      umRatio = original.umRatio;
+    }
+    public UnwantedMutationsComparator()
+      : base() {
+      Parameters.Add(new ValueLookupParameter<BoolValue>("Maximization", "True if the problem is a maximization problem, false otherwise"));
+      Parameters.Add(new LookupParameter<DoubleValue>("LeftSide", "The quality of the child."));
+      Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>("RightSide", "The qualities of the parents."));
+      Parameters.Add(new LookupParameter<BoolValue>("Result", "The result of the comparison: True means Quality is better, False means it is worse than parents."));
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("ComparisonFactor", "Determines if the quality should be compared to the better parent (1.0), to the worse (0.0) or to any linearly interpolated value between them."));
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("DiversityComparisonFactor", "Determines if the quality should be compared to the better parent (1.0), to the worse (0.0) or to any linearly interpolated value between them.", new DoubleValue(0.0)));
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("DiversityComparisonFactorLowerBound", "The lower bound of the comparison factor (start).", new DoubleValue(0.7)));
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("DiversityComparisonFactorUpperBound", "The upper bound of the comparison factor (end).", new DoubleValue(1.0)));
+      Parameters.Add(new OptionalConstrainedValueParameter<IDiscreteDoubleValueModifier>("ComparisonFactorModifier", "The operator used to modify the comparison factor.", new ItemSet<IDiscreteDoubleValueModifier>(new IDiscreteDoubleValueModifier[] { new LinearDiscreteDoubleValueModifier() }), new LinearDiscreteDoubleValueModifier()));
+      Parameters.Add(new ValueLookupParameter<ResultCollection>("Results", "The result collection where the population diversity analysis results should be stored."));
+      Parameters.Add(new LookupParameter<IntValue>("Generations", "The current number of generations."));
+      Parameters.Add(new ValueParameter<BoolValue>("EnableDivCriteria", "Use diversity as additional offspring selection criteria.", new BoolValue(true)));
+      Parameters.Add(new ValueParameter<BoolValue>("EnableQualityCriteria", "Use quality as additional offspring selection criteria.", new BoolValue(false)));
+
+      foreach (IDiscreteDoubleValueModifier modifier in ApplicationManager.Manager.GetInstances<IDiscreteDoubleValueModifier>().OrderBy(x => x.Name))
+        ComparisonFactorModifierParameter.ValidValues.Add(modifier);
+      IDiscreteDoubleValueModifier linearModifier = ComparisonFactorModifierParameter.ValidValues.FirstOrDefault(x => x.GetType().Name.Equals("LinearDiscreteDoubleValueModifier"));
+      if (linearModifier != null) ComparisonFactorModifierParameter.Value = linearModifier;
+      ParameterizeComparisonFactorModifiers();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new UnwantedMutationsComparator(this, cloner);
+    }
+
+    private void ParameterizeComparisonFactorModifiers() {
+      //TODO: does not work if Generations parameter names are changed
+      foreach (IDiscreteDoubleValueModifier modifier in ComparisonFactorModifierParameter.ValidValues) {
+        modifier.IndexParameter.ActualName = "Generations";
+        modifier.EndIndexParameter.ActualName = "MaximumGenerations";
+        modifier.EndValueParameter.ActualName = ComparisonFactorUpperBoundParameter.Name;
+        modifier.StartIndexParameter.Value = new IntValue(0);
+        modifier.StartValueParameter.ActualName = ComparisonFactorLowerBoundParameter.Name;
+        modifier.ValueParameter.ActualName = "DiversityComparisonFactor";
+      }
+    }
+
+    public override IOperation Apply() {
+      ItemArray<DoubleValue> rightQualities = RightSideParameter.ActualValue;
+      if (rightQualities.Length < 1) throw new InvalidOperationException(Name + ": No subscopes found.");
+      double compFact = ComparisonFactorParameter.ActualValue.Value;
+      double diversityComFact = DiversityComparisonFactorParameter.ActualValue.Value;
+      bool maximization = MaximizationParameter.ActualValue.Value;
+      double leftQuality = LeftSideParameter.ActualValue.Value;
+      double threshold = 0;
+
+      DataTable spDetailsTable;
+      if (ResultsParameter.ActualValue.ContainsKey(spDetailsParameterName)) {
+        spDetailsTable = (DataTable)ResultsParameter.ActualValue[spDetailsParameterName].Value;
+      } else {
+        spDetailsTable = new DataTable(spDetailsParameterName);
+        spDetailsTable.Rows.Add(new DataRow(divDataRowName));
+        spDetailsTable.Rows.Add(new DataRow(qualityDataRowName));
+        spDetailsTable.Rows.Add(new DataRow(overallCountDataRowName));
+        spDetailsTable.Rows.Add(new DataRow(successCountDataRowName));
+        spDetailsTable.Rows.Add(new DataRow(divFailDataRowName));
+        spDetailsTable.Rows.Add(new DataRow(qualityFailDataRowName));
+        spDetailsTable.Rows.Add(new DataRow(unwantedMutationsDataRowName));
+        ResultsParameter.ActualValue.Add(new Result(spDetailsParameterName, spDetailsTable));
+      }
+
+      if (GenerationsParameter.ActualValue.Value != currentGeneration) {
+        spDetailsTable.Rows[divDataRowName].Values.Add(divCount);
+        divCount = 0;
+        spDetailsTable.Rows[qualityDataRowName].Values.Add(qualityCount);
+        qualityCount = 0;
+        spDetailsTable.Rows[overallCountDataRowName].Values.Add(overallCount);
+        spDetailsTable.Rows[successCountDataRowName].Values.Add(successCount);
+        successCount = 0;
+        spDetailsTable.Rows[qualityFailDataRowName].Values.Add(badQualityCount);
+        badQualityCount = 0;
+        spDetailsTable.Rows[divFailDataRowName].Values.Add(badDivCount);
+        badDivCount = 0;
+        if (overallCount != 0) {
+          spDetailsTable.Rows[unwantedMutationsDataRowName].Values.Add(umRatio / (double)overallCount);
+        }
+        umRatio = 0.0;
+        overallCount = 0;
+        currentGeneration = GenerationsParameter.ActualValue.Value;
+      }
+
+      string solutionVariableName = ((ISingleObjectiveSolutionSimilarityCalculator)SimilarityCalculator).SolutionVariableName;
+      double resultVal = AnalyzeUnwantedMutations(ExecutionContext.Scope.SubScopes[0],
+        ExecutionContext.Scope.SubScopes[1], ExecutionContext.Scope, solutionVariableName);
+
+      bool resultDiversity = resultVal < diversityComFact;
+      umRatio += resultVal;
+
+      double minQuality = Math.Min(rightQualities[0].Value, rightQualities[1].Value);
+      double maxQuality = Math.Max(rightQualities[0].Value, rightQualities[1].Value);
+      if (maximization)
+        threshold = minQuality + (maxQuality - minQuality) * compFact;
+      else
+        threshold = maxQuality - (maxQuality - minQuality) * compFact;
+
+      bool result = maximization && leftQuality > threshold || !maximization && leftQuality < threshold;
+
+      //collect statistics
+      if (result) {
+        qualityCount++;
+      } else {
+        badQualityCount++;
+      }
+      if (resultDiversity) {
+        divCount++;
+      } else {
+        badDivCount++;
+      }
+      if (result && resultDiversity) {
+        successCount++;
+      }
+      overallCount++;
+
+      if (EnableDivCriteriaParameter.Value.Value && !EnableQualityCriteriaParameter.Value.Value) {
+        result = resultDiversity;
+      }                          
+      //use diveristiy criteria or not
+      if (EnableDivCriteriaParameter.Value.Value && EnableQualityCriteriaParameter.Value.Value) {
+        result = result && resultDiversity;
+      }
+
+      BoolValue resultValue = ResultParameter.ActualValue;
+      if (resultValue == null) {
+        ResultParameter.ActualValue = new BoolValue(result);
+      } else {
+        resultValue.Value = result;
+      }
+
+      //like the placeholder, though we create child operations
+      OperationCollection next = new OperationCollection(base.Apply());
+      IOperator op = ComparisonFactorModifierParameter.Value;
+      if (op != null)
+        next.Insert(0, ExecutionContext.CreateChildOperation(op));
+      return next;
+    }
+
+    public double AnalyzeUnwantedMutations(IScope parent1, IScope parent2, IScope child, string solutionVariableName) {
+      Permutation p1 = parent1.Variables[solutionVariableName].Value as Permutation;
+      Permutation p2 = parent2.Variables[solutionVariableName].Value as Permutation;
+      Permutation c = child.Variables[solutionVariableName].Value as Permutation;
+
+      return AnalyzeUnwantedMutations(p1, p2, c);
+    }
+
+    private double AnalyzeUnwantedMutations(Permutation parent1, Permutation parent2, Permutation child) {
+      int cnt = 0;
+      int[] edgesP1 = CalculateEdgesVector(parent1);
+      int[] edgesP2 = CalculateEdgesVector(parent2);
+      int[] edgesC = CalculateEdgesVector(child);
+
+      for (int i = 0; i < edgesP1.Length; i++) {
+        if (edgesC[i] != edgesP1[i] &&
+            edgesC[i] != edgesP2[i] &&
+            edgesP1[edgesC[i]] != i &&
+            edgesP2[edgesC[i]] != i) {
+          cnt += 1;
+        }
+      }
+
+      //reverse so that it matches the other diversity charts
+      return 1.0 - (((double)cnt) / parent1.Length);
+    }
+
+    //copied from PermutationEqualityComparer
+    private int[] CalculateEdgesVector(Permutation permutation) {
+      // transform path representation into adjacency representation
+      int[] edgesVector = new int[permutation.Length];
+      for (int i = 0; i < permutation.Length - 1; i++)
+        edgesVector[permutation[i]] = permutation[i + 1];
+      edgesVector[permutation[permutation.Length - 1]] = permutation[0];
+      return edgesVector;
+    }
+  }
+}
Index: branches/VOSGA/HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm/HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm-3.3.csproj
===================================================================
--- branches/VOSGA/HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm/HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm-3.3.csproj	(revision 11845)
+++ branches/VOSGA/HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm/HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm-3.3.csproj	(revision 11884)
@@ -119,4 +119,9 @@
       <Private>False</Private>
     </Reference>
+    <Reference Include="HeuristicLab.Encodings.PermutationEncoding-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\trunk\sources\bin\HeuristicLab.Encodings.PermutationEncoding-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
     <Reference Include="HeuristicLab.Operators-3.3">
       <HintPath>..\..\trunk\sources\bin\HeuristicLab.Operators-3.3.dll</HintPath>
@@ -169,4 +174,5 @@
     <Compile Include="Comparators\PopulationQualityComparator.cs" />
     <Compile Include="Comparators\PopulationDiversityComparator.cs" />
+    <Compile Include="Comparators\UnwantedMutationsComparator.cs" />
     <Compile Include="Comparators\WeightedParentsDiversityComparator.cs" />
     <Compile Include="Comparators\WeightedParentsQualityComparator.cs" />
Index: branches/VOSGA/HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm/Plugin.cs.frame
===================================================================
--- branches/VOSGA/HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm/Plugin.cs.frame	(revision 11845)
+++ branches/VOSGA/HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm/Plugin.cs.frame	(revision 11884)
@@ -40,4 +40,5 @@
   [PluginDependency("HeuristicLab.Random", "3.3")]
   [PluginDependency("HeuristicLab.Selection", "3.3")]
+  [PluginDependency("HeuristicLab.Encodings.PermutationEncoding","3.3")]
   public class HeuristicLabAlgorithmsVOffspringSelectionGeneticAlgorithmPlugin : PluginBase {
   }
