Index: branches/VOSGA/HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm/Comparators/PopulationDiversityComparator.cs
===================================================================
--- branches/VOSGA/HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm/Comparators/PopulationDiversityComparator.cs	(revision 11844)
+++ branches/VOSGA/HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm/Comparators/PopulationDiversityComparator.cs	(revision 11845)
@@ -34,5 +34,5 @@
 
 namespace HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm {
-  [Item("PopulationDiversityComparator", "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.")]
+  [Item("PopulationDiversityComparator", "Structural comparison of child to population.")]
   [StorableClass]
   public class PopulationDiversityComparator : SingleSuccessorOperator, ISubScopesQualityComparatorOperator, ISimilarityBasedOperator {
Index: branches/VOSGA/HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm/Comparators/PopulationQualityComparator.cs
===================================================================
--- branches/VOSGA/HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm/Comparators/PopulationQualityComparator.cs	(revision 11845)
+++ branches/VOSGA/HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm/Comparators/PopulationQualityComparator.cs	(revision 11845)
@@ -0,0 +1,262 @@
+﻿#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.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("PopulationQualityComparator", "Compares the quality of the child to the population.")]
+  [StorableClass]
+  public class PopulationQualityComparator : 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"]; }
+    }
+
+    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";
+
+    [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;
+
+    [StorableConstructor]
+    protected PopulationQualityComparator(bool deserializing) : base(deserializing) { }
+    protected PopulationQualityComparator(PopulationQualityComparator 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;
+    }
+    public PopulationQualityComparator()
+      : 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.5)));
+      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(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 PopulationQualityComparator(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";
+      }
+    }
+
+    private IScope GetRemainingScope() {
+      var scope = ExecutionContext.Scope;
+
+      while (scope != null) {
+        if (scope.SubScopes.Any(x => x.Name == "Remaining")) {
+          return scope.SubScopes.Single(x => x.Name == "Remaining");
+        }
+        scope = scope.Parent;
+      }
+      return null;
+    }
+
+    public override IOperation Apply() {
+      double compFact = ComparisonFactorParameter.ActualValue.Value;
+      double diversityComFact = DiversityComparisonFactorParameter.ActualValue.Value;
+      bool maximization = MaximizationParameter.ActualValue.Value;
+      double leftQuality = LeftSideParameter.ActualValue.Value;
+      bool resultDiversity;
+
+      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));
+        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);
+        overallCount = 0;
+        spDetailsTable.Rows[successCountDataRowName].Values.Add(successCount);
+        successCount = 0;
+        spDetailsTable.Rows[qualityFailDataRowName].Values.Add(badQualityCount);
+        badQualityCount = 0;
+        spDetailsTable.Rows[divFailDataRowName].Values.Add(badDivCount);
+        badDivCount = 0;
+        currentGeneration = GenerationsParameter.ActualValue.Value;
+      }
+
+      string qualityVariableName = ((ISingleObjectiveSolutionSimilarityCalculator)SimilarityCalculator).QualityVariableName;
+      string solutionVariableName = ((ISingleObjectiveSolutionSimilarityCalculator)SimilarityCalculator).SolutionVariableName;
+
+      var remainingScope = GetRemainingScope();
+      double oldPopQuality = 0.0;
+      int popSize = 0;
+      foreach (IScope oldSolScope in remainingScope.SubScopes) {
+        double curQuality = ((DoubleValue)oldSolScope.Variables[qualityVariableName].Value).Value;
+        IItem curSol = oldSolScope.Variables[solutionVariableName].Value;
+        oldPopQuality += curQuality;
+        popSize++;
+      }
+
+      //diversity compared to population
+      Scope fakeScope = new Scope();
+      fakeScope.SubScopes.Add((IScope)ExecutionContext.Scope.Clone());
+      var similarities = SimilarityCalculator.CalculateSolutionCrowdSimilarity(fakeScope, remainingScope);
+      double averageSimilarity = similarities[0].Average();
+      resultDiversity = averageSimilarity < diversityComFact;
+
+
+      //quality compared to population
+      double averageQuality = oldPopQuality / popSize;
+      bool result = maximization && leftQuality > averageQuality || !maximization && leftQuality < averageQuality;
+
+      //collect statistics
+      if (result) {
+        qualityCount++;
+      } else {
+        badQualityCount++;
+      }
+      if (resultDiversity) {
+        divCount++;
+      } else {
+        badDivCount++;
+      }
+      if (result && resultDiversity) {
+        successCount++;
+      }
+      overallCount++;
+
+      //use diveristiy criteria or not
+      if (EnableDivCriteriaParameter.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;
+    }
+  }
+}
