Index: /branches/VOSGA/HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm/HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm-3.3.csproj
===================================================================
--- /branches/VOSGA/HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm/HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm-3.3.csproj	(revision 11512)
+++ /branches/VOSGA/HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm/HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm-3.3.csproj	(revision 11513)
@@ -161,4 +161,5 @@
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="ISubScopesQualityComparatorOperator.cs" />
     <Compile Include="OffspringCollector.cs" />
     <Compile Include="OffspringSelectors\IOffspringSelector.cs" />
@@ -171,4 +172,5 @@
     <Compile Include="VOffspringSelectionGeneticAlgorithmMainLoop.cs" />
     <Compile Include="VOffspringSelectionGeneticAlgorithmMainOperator.cs" />
+    <Compile Include="WeightedParentsQualityComparator.cs" />
   </ItemGroup>
   <ItemGroup>
Index: /branches/VOSGA/HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm/VOffspringSelectionGeneticAlgorithm.cs
===================================================================
--- /branches/VOSGA/HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm/VOffspringSelectionGeneticAlgorithm.cs	(revision 11512)
+++ /branches/VOSGA/HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm/VOffspringSelectionGeneticAlgorithm.cs	(revision 11513)
@@ -118,4 +118,7 @@
       get { return (IConstrainedValueParameter<IOffspringSelector>)Parameters["OffspringSelector"]; }
     }
+    public ConstrainedValueParameter<ISubScopesQualityComparatorOperator> SubScopesQualityComparatorParameter {
+      get { return (ConstrainedValueParameter<ISubScopesQualityComparatorOperator>)Parameters["SubScopesQualityComparator"]; }
+    }
     #endregion
 
@@ -205,4 +208,9 @@
       set { FillPopulationWithParentsParameter.Value.Value = value; }
     }
+    public ISubScopesQualityComparatorOperator SubScopesQualityComparator {
+      get { return SubScopesQualityComparatorParameter.Value; }
+      set { SubScopesQualityComparatorParameter.Value = value; }
+    }
+
     private RandomCreator RandomCreator {
       get { return (RandomCreator)OperatorGraph.InitialOperator; }
@@ -272,5 +280,5 @@
       Parameters.Add(new FixedValueParameter<BoolValue>("FillPopulationWithParents", "True if the population should be filled with parent individual or false if worse children should be used when the maximum selection pressure is exceeded.", new BoolValue(false)) { Hidden = true });
       Parameters.Add(new ConstrainedValueParameter<IOffspringSelector>("OffspringSelector", "The operator used as selection criterea for deciding which individuals are successful and which should be disgarded."));
-
+      Parameters.Add(new ConstrainedValueParameter<ISubScopesQualityComparatorOperator>("SubScopesQualityComparator", "The operator used to compare solution candidates with."));
 
       RandomCreator randomCreator = new RandomCreator();
@@ -336,4 +344,10 @@
       ParameterizeOffspringSelectors();
 
+      foreach (ISubScopesQualityComparatorOperator comparator in ApplicationManager.Manager.GetInstances<ISubScopesQualityComparatorOperator>().OrderBy(x => x.Name))
+        SubScopesQualityComparatorParameter.ValidValues.Add(comparator);
+      ISubScopesQualityComparatorOperator standardComparator = SubScopesQualityComparatorParameter.ValidValues.FirstOrDefault(x => x.GetType().Name.Equals("WeightedParentsQualityComparator"));
+      if (standardComparator != null) SubScopesQualityComparatorParameter.Value = standardComparator;
+      ParameterizeSubScopesQualityComparators();
+
       qualityAnalyzer = new BestAverageWorstQualityAnalyzer();
       selectionPressureAnalyzer = new ValueAnalyzer();
@@ -362,4 +376,6 @@
       UpdateMutators();
       UpdateAnalyzers();
+      ParameterizeSubScopesQualityComparators();
+      ParameterizeOffspringSelectors();
       Problem.Evaluator.QualityParameter.ActualNameChanged += new EventHandler(Evaluator_QualityParameter_ActualNameChanged);
       base.OnProblemChanged();
@@ -457,4 +473,15 @@
         selector.SuccessfulOffspringParameter.ActualName = "SuccessfulOffspring";
         selector.FillPopulationWithParentsParameter.ActualName = FillPopulationWithParentsParameter.Name;
+      }
+    }
+    private void ParameterizeSubScopesQualityComparators() {
+      foreach (var comp in SubScopesQualityComparatorParameter.ValidValues) {
+        comp.ComparisonFactorParameter.ActualName = "ComparisonFactor";
+        if (Problem != null) {
+          comp.LeftSideParameter.ActualName = Problem.Evaluator.QualityParameter.Name;
+          comp.MaximizationParameter.ActualName = Problem.MaximizationParameter.Name;
+          comp.RightSideParameter.ActualName = Problem.Evaluator.QualityParameter.Name;
+        }
+        comp.ResultParameter.ActualName = "SuccessfulOffspring";
       }
     }
Index: /branches/VOSGA/HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm/VOffspringSelectionGeneticAlgorithmMainOperator.cs
===================================================================
--- /branches/VOSGA/HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm/VOffspringSelectionGeneticAlgorithmMainOperator.cs	(revision 11512)
+++ /branches/VOSGA/HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm/VOffspringSelectionGeneticAlgorithmMainOperator.cs	(revision 11513)
@@ -93,4 +93,7 @@
     public ValueLookupParameter<IOffspringSelector> OffspringSelectorParameter {
       get { return (ValueLookupParameter<IOffspringSelector>)Parameters["OffspringSelector"]; }
+    }
+    public ValueLookupParameter<ISubScopesQualityComparatorOperator> SubScopesQualityComparatorParameter {
+      get { return (ValueLookupParameter<ISubScopesQualityComparatorOperator>)Parameters["SubScopesQualityComparator"]; }
     }
     #endregion
@@ -142,4 +145,5 @@
       Parameters.Add(new ValueLookupParameter<BoolValue>("FillPopulationWithParents", "True if the population should be filled with parent individual or false if worse children should be used when the maximum selection pressure is exceeded."));
       Parameters.Add(new ValueLookupParameter<IOffspringSelector>("OffspringSelector", "The operator used as selection criterea for deciding which individuals are successful and which should be disgarded."));
+      Parameters.Add(new ValueLookupParameter<ISubScopesQualityComparatorOperator>("SubScopesQualityComparator", "The operator used to compare solution candidates."));
       #endregion
 
@@ -154,5 +158,5 @@
       Placeholder evaluator1 = new Placeholder();
       SubScopesCounter subScopesCounter1 = new SubScopesCounter();
-      WeightedParentsQualityComparator qualityComparer1 = new WeightedParentsQualityComparator();
+      Placeholder qualityComparer1 = new Placeholder();
       SubScopesRemover subScopesRemover1 = new SubScopesRemover();
       UniformSubScopesProcessor uniformSubScopesProcessor3 = new UniformSubScopesProcessor();
@@ -174,5 +178,5 @@
       Placeholder evaluator3 = new Placeholder();
       SubScopesCounter subScopesCounter3 = new SubScopesCounter();
-      WeightedParentsQualityComparator qualityComparer2 = new WeightedParentsQualityComparator();
+      Placeholder qualityComparer2 = new Placeholder();
       SubScopesRemover subScopesRemover2 = new SubScopesRemover();
       Placeholder offspringSelector = new Placeholder();
@@ -208,9 +212,6 @@
       subScopesCounter1.ValueParameter.ActualName = EvaluatedSolutionsParameter.Name;
 
-      qualityComparer1.ComparisonFactorParameter.ActualName = ComparisonFactorParameter.Name;
-      qualityComparer1.LeftSideParameter.ActualName = QualityParameter.Name;
-      qualityComparer1.MaximizationParameter.ActualName = MaximizationParameter.Name;
-      qualityComparer1.RightSideParameter.ActualName = QualityParameter.Name;
-      qualityComparer1.ResultParameter.ActualName = "SuccessfulOffspring";
+      qualityComparer1.Name = "Quality Comparator (placeholder)";
+      qualityComparer1.OperatorParameter.ActualName = SubScopesQualityComparatorParameter.ActualName;
 
       subScopesRemover1.RemoveAllSubScopes = true;
@@ -257,9 +258,6 @@
       subScopesCounter3.ValueParameter.ActualName = EvaluatedSolutionsParameter.Name;
 
-      qualityComparer2.ComparisonFactorParameter.ActualName = ComparisonFactorParameter.Name;
-      qualityComparer2.LeftSideParameter.ActualName = QualityParameter.Name;
-      qualityComparer2.MaximizationParameter.ActualName = MaximizationParameter.Name;
-      qualityComparer2.RightSideParameter.ActualName = QualityParameter.Name;
-      qualityComparer2.ResultParameter.ActualName = "SuccessfulOffspring";
+      qualityComparer2.Name = "Quality Comparator (placeholder)";
+      qualityComparer2.OperatorParameter.ActualName = SubScopesQualityComparatorParameter.ActualName;
 
       subScopesRemover2.RemoveAllSubScopes = true;
Index: /branches/VOSGA/HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm/WeightedParentsQualityComparator.cs
===================================================================
--- /branches/VOSGA/HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm/WeightedParentsQualityComparator.cs	(revision 11513)
+++ /branches/VOSGA/HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm/WeightedParentsQualityComparator.cs	(revision 11513)
@@ -0,0 +1,127 @@
+﻿#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.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.VOffspringSelectionGeneticAlgorithm {
+  [Item("WeightedParentsQualityComparator", "Compares the quality 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 WeightedParentsQualityComparator : SingleSuccessorOperator, ISubScopesQualityComparatorOperator {
+    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"]; }
+    }
+
+    [StorableConstructor]
+    protected WeightedParentsQualityComparator(bool deserializing) : base(deserializing) { }
+    protected WeightedParentsQualityComparator(WeightedParentsQualityComparator original, Cloner cloner) : base(original, cloner) { }
+    public WeightedParentsQualityComparator()
+      : 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."));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new WeightedParentsQualityComparator(this, cloner);
+    }
+
+    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;
+      bool maximization = MaximizationParameter.ActualValue.Value;
+      double leftQuality = LeftSideParameter.ActualValue.Value;
+
+      double threshold = 0;
+
+      #region Calculate threshold
+      if (rightQualities.Length == 2) { // this case will probably be used most often
+        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;
+      } else if (rightQualities.Length == 1) { // case for just one parent
+        threshold = rightQualities[0].Value;
+      } else { // general case extended to 3 or more parents
+        List<double> sortedQualities = rightQualities.Select(x => x.Value).ToList();
+        sortedQualities.Sort();
+        double minimumQuality = sortedQualities.First();
+
+        double integral = 0;
+        for (int i = 0; i < sortedQualities.Count - 1; i++) {
+          integral += (sortedQualities[i] + sortedQualities[i + 1]) / 2.0; // sum of the trapezoid
+        }
+        integral -= minimumQuality * sortedQualities.Count;
+        if (integral == 0) threshold = sortedQualities[0]; // all qualities are equal
+        else {
+          double selectedArea = integral * (maximization ? compFact : (1 - compFact));
+          integral = 0;
+          for (int i = 0; i < sortedQualities.Count - 1; i++) {
+            double currentSliceArea = (sortedQualities[i] + sortedQualities[i + 1]) / 2.0;
+            double windowedSliceArea = currentSliceArea - minimumQuality;
+            if (windowedSliceArea == 0) continue;
+            integral += windowedSliceArea;
+            if (integral >= selectedArea) {
+              double factor = 1 - ((integral - selectedArea) / (windowedSliceArea));
+              threshold = sortedQualities[i] + (sortedQualities[i + 1] - sortedQualities[i]) * factor;
+              break;
+            }
+          }
+        }
+      }
+      #endregion
+
+      bool result = maximization && leftQuality > threshold || !maximization && leftQuality < threshold;
+      BoolValue resultValue = ResultParameter.ActualValue;
+      if (resultValue == null) {
+        ResultParameter.ActualValue = new BoolValue(result);
+      } else {
+        resultValue.Value = result;
+      }
+
+      return base.Apply();
+    }
+  }
+}
