Index: /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/Analyzers/HypervolumeAnalyzer.cs
===================================================================
--- /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/Analyzers/HypervolumeAnalyzer.cs	(revision 13770)
+++ /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/Analyzers/HypervolumeAnalyzer.cs	(revision 13771)
@@ -72,5 +72,5 @@
 
     public override void Analyze(Individual[] individuals, double[][] qualities, ResultCollection results) {
-      if (qualities == null || qualities.Length < 2) return;
+      if (qualities == null || qualities.Length < 1) return;
       int objectives = qualities[0].Length;
       double best = BestKnownHyperVolumeParameter.Value.Value;
Index: /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/Analyzers/NormalizedHypervolumeAnalyzer.cs
===================================================================
--- /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/Analyzers/NormalizedHypervolumeAnalyzer.cs	(revision 13771)
+++ /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/Analyzers/NormalizedHypervolumeAnalyzer.cs	(revision 13771)
@@ -0,0 +1,172 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.MultiObjectiveTestFunctions {
+  [StorableClass]
+  [Item("GenerationalDistanceAnalyzer", "Computes the enclosed Hypervolume between the current front and a given reference Point")]
+  public class NormalizedHypervolumeAnalyzer : MOTFAnalyzer {
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+    }
+    [StorableConstructor]
+    protected NormalizedHypervolumeAnalyzer(bool deserializing) : base(deserializing) { }
+    public NormalizedHypervolumeAnalyzer(NormalizedHypervolumeAnalyzer original, Cloner cloner) : base(original, cloner) { }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NormalizedHypervolumeAnalyzer(this, cloner);
+    }
+
+
+    #region Names
+    private const string bestKnownFront = "BestKnownFront_2";
+    private const string resultsHV = "NormalizedHypervolume";
+    private const string resultsDist = "Absolute Distance to Normalized BestKnownHypervolume";
+
+    private const string bestknownHV = "NormalizedBestKnownHyperVolume";
+    #endregion
+
+    #region parameters
+    public IValueParameter<DoubleMatrix> OptimalFrontParameter {
+      get {
+        return (IValueParameter<DoubleMatrix>)Parameters[bestKnownFront];
+      }
+    }
+
+    public IValueParameter<DoubleValue> BestKnownHyperVolumeParameter {
+      get {
+        return (IValueParameter<DoubleValue>)Parameters[bestknownHV];
+      }
+      set {
+        Parameters[bestknownHV].ActualValue = value;
+      }
+    }
+    #endregion
+
+    public NormalizedHypervolumeAnalyzer() {
+      if (!Parameters.ContainsKey(bestKnownFront)) Parameters.Add(new ValueParameter<DoubleMatrix>(bestKnownFront, "The true / best known pareto front"));
+      if (!Parameters.ContainsKey(bestknownHV)) Parameters.Add(new ValueParameter<DoubleValue>(bestknownHV, "The currently best known hypervolume"));
+    }
+
+    private void RegisterEventHandlers() {
+      OptimalFrontParameter.ValueChanged += OptimalFrontParameterOnValueChanged;
+    }
+
+    private void OptimalFrontParameterOnValueChanged(object sender, EventArgs e) {
+      BestKnownHyperVolumeParameter.Value = new DoubleValue(0);
+    }
+
+    public override void Analyze(Individual[] individuals, double[][] qualities, ResultCollection results) {
+      if (qualities == null || qualities.Length < 1) return;
+      int objectives = qualities[0].Length;
+      double best = BestKnownHyperVolumeParameter.Value.Value;
+      if (OptimalFrontParameter.Value == null || OptimalFrontParameter.Value.Rows < 1 || OptimalFrontParameter.Value.Columns != qualities[0].Length) {
+        return; // too pareto front nonexistant or with wrong number of dimensions
+      }
+
+      double diff;
+
+      if (!results.ContainsKey(resultsHV)) results.Add(new Result(resultsHV, typeof(DoubleValue)));
+      IEnumerable<double[]> front = NonDominatedSelect.selectNonDominatedVectors(qualities, TestFunctionParameter.ActualValue.Maximization(objectives), true);
+      if (!results.ContainsKey(bestknownHV)) results.Add(new Result(bestknownHV, typeof(DoubleValue)));
+      else {
+        DoubleValue dv = (DoubleValue)(results[bestknownHV].Value);
+        best = dv.Value;
+      }
+      if (!results.ContainsKey(resultsDist)) results.Add(new Result(resultsDist, typeof(DoubleValue)));
+
+      double hv = Double.NaN;
+
+      bool[] maximization = TestFunctionParameter.ActualValue.Maximization(objectives);
+      double[] invPoint = GetBestPoint(OptimalFrontParameter.Value, maximization);
+      double[] refPoint = GetWorstPoint(OptimalFrontParameter.Value, maximization);
+      double normalization = GetHypervolume(refPoint, invPoint);
+
+
+      try {
+        if (objectives == 2) { //Hypervolume analysis only with 2 objectives for now
+          hv = Hypervolume.Calculate(front, refPoint, maximization);
+        } else if (Array.TrueForAll(maximization, x => !x)) {
+          hv = MultiDimensionalHypervolume.Calculate(front, refPoint);
+        }
+      }
+      catch (ArgumentException) {
+
+      }
+
+      hv /= normalization;
+
+      if (best < 0) {
+        best = hv;
+      }
+      diff = best - hv;
+      if (!Double.IsNaN(hv) && (diff < 0 || best < 0)) {
+        best = hv;
+        diff = 0;
+        BestKnownFrontParameter.ActualValue = new DoubleMatrix(MultiObjectiveTestFunctionProblem.To2D(qualities));
+      }
+
+      results[resultsHV].Value = new DoubleValue(hv);
+      results[resultsDist].Value = new DoubleValue(diff);
+      results[bestknownHV].Value = new DoubleValue(best);
+
+    }
+
+    private double GetHypervolume(double[] refPoint, double[] invPoint) {
+      if (refPoint.Length == 0) return 0;
+      double hv = 1;
+      for (int i = 0; i < refPoint.Length; i++) {
+        hv *= Math.Abs(refPoint[i] - invPoint[i]);
+      }
+      return hv;
+    }
+
+    private double[] GetWorstPoint(DoubleMatrix value, bool[] maximization) {
+      bool[] invMax = new bool[maximization.Length];
+      int i = 0;
+      foreach (bool b in maximization) {
+        invMax[i++] = !b;
+      }
+      return GetBestPoint(value, invMax);
+    }
+
+    private double[] GetBestPoint(DoubleMatrix value, bool[] maximization) {
+      double[] res = new double[maximization.Length];
+      for (int i = 0; i < maximization.Length; i++) {
+        res[i] = maximization[i] ? Double.MinValue : Double.MaxValue;
+      }
+
+      for (int r = 0; r < value.Rows; r++) {
+        for (int c = 0; c < maximization.Length; c++) {
+          res[c] = maximization[c] ? Math.Max(res[c], value[r, c]) : Math.Min(res[c], value[r, c]);
+        }
+      }
+      return res;
+    }
+  }
+}
Index: /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/Calculators/Utilities.cs
===================================================================
--- /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/Calculators/Utilities.cs	(revision 13770)
+++ /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/Calculators/Utilities.cs	(revision 13771)
@@ -39,4 +39,5 @@
         if (!reflexive && ReferenceEquals(r, point)) continue;
         double d = 0;
+        if (r.Length != point.Length) throw new ArgumentException("dimensions of Front and Point do not match");
         for (int i = 0; i < r.Length; i++) {
           d += (point[i] - r[i]) * (point[i] - r[i]);
Index: /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/HeuristicLab.Problems.MultiObjectiveTestFunctions-3.3.csproj
===================================================================
--- /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/HeuristicLab.Problems.MultiObjectiveTestFunctions-3.3.csproj	(revision 13770)
+++ /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/HeuristicLab.Problems.MultiObjectiveTestFunctions-3.3.csproj	(revision 13771)
@@ -132,4 +132,5 @@
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="Analyzers\NormalizedHypervolumeAnalyzer.cs" />
     <Compile Include="Analyzers\ScatterPlotAnalyzer.cs" />
     <Compile Include="Analyzers\CrowdingAnalyzer.cs" />
Index: /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/MultiObjectiveTestFunctionProblem.cs
===================================================================
--- /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/MultiObjectiveTestFunctionProblem.cs	(revision 13770)
+++ /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/MultiObjectiveTestFunctionProblem.cs	(revision 13771)
@@ -161,4 +161,10 @@
     }
 
+    public IEnumerable<double[]> BestKnownFront {
+      get {
+        return Parameters.ContainsKey("BestKnownFront") ? TestFunction.OptimalParetoFront(Objectives) : null;
+      }
+    }
+
     public double[] Evaluate(RealVector individual, IRandom random) {
       return TestFunction.Evaluate(individual, Objectives);
@@ -228,4 +234,6 @@
         || ProblemSize > TestFunction.MaximumSolutionLength)
         ProblemSize = Math.Min(TestFunction.MaximumSolutionLength, Math.Max(TestFunction.MinimumSolutionLength, ProblemSize));
+
+
       Parameterize();
     }
@@ -244,4 +252,5 @@
       Operators.Add(new SpacingAnalyzer());
       Operators.Add(new ScatterPlotAnalyzer());
+      Operators.Add(new NormalizedHypervolumeAnalyzer());
       ParameterizeAnalyzers();
       Parameterize();
@@ -250,4 +259,7 @@
     private void Parameterize() {
       MaximizationParameter.ActualValue = new BoolArray(Maximization);
+      var front = BestKnownFront;
+      if (front != null) { BestKnownFrontParameter.ActualValue = new DoubleMatrix(To2D(front.ToArray<double[]>())); }
+
     }
 
@@ -259,5 +271,9 @@
         analyzer.BestKnownFrontParameter.ActualName = BestKnownFrontParameter.Name;
 
-        BestKnownFrontParameter.ActualValue = new DoubleMatrix(To2D(TestFunction.OptimalParetoFront(Objectives).ToArray<double[]>()));
+
+        var front = BestKnownFront;
+        if (front != null) { BestKnownFrontParameter.ActualValue = new DoubleMatrix(To2D(front.ToArray<double[]>())); }
+
+
         if (analyzer is HypervolumeAnalyzer) {
           ((HypervolumeAnalyzer)analyzer).ReferencePointParameter.Value = new DoubleArray(TestFunction.ReferencePoint(Objectives));
@@ -265,4 +281,8 @@
         }
 
+        if (analyzer is NormalizedHypervolumeAnalyzer) {
+          ((NormalizedHypervolumeAnalyzer)analyzer).OptimalFrontParameter.ActualValue = (DoubleMatrix)BestKnownFrontParameter.ActualValue;
+        }
+
       }
     }
Index: /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/Testfunctions/DTLZ/DTLZ.cs
===================================================================
--- /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/Testfunctions/DTLZ/DTLZ.cs	(revision 13770)
+++ /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/Testfunctions/DTLZ/DTLZ.cs	(revision 13771)
@@ -68,5 +68,5 @@
     protected DTLZ(bool deserializing) : base(deserializing) { }
     protected DTLZ(DTLZ original, Cloner cloner) : base(original, cloner) { }
-    public DTLZ() : base() { }
+    public DTLZ() : base(minimumObjectives: 2, minimumSolutionLength: 2, maximumSolutionLength: int.MaxValue) { }
 
     public abstract override double[] Evaluate(RealVector r, int objecitves);
Index: /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/Testfunctions/Fonseca.cs
===================================================================
--- /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/Testfunctions/Fonseca.cs	(revision 13770)
+++ /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/Testfunctions/Fonseca.cs	(revision 13771)
@@ -74,5 +74,5 @@
       return new Fonseca(this, cloner);
     }
-    public Fonseca() : base() { }
+    public Fonseca() : base(minimumObjectives: 2, maximumObjectives: 2, minimumSolutionLength: 1) { }
 
 
Index: /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/Testfunctions/Kursawe.cs
===================================================================
--- /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/Testfunctions/Kursawe.cs	(revision 13770)
+++ /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/Testfunctions/Kursawe.cs	(revision 13771)
@@ -69,5 +69,5 @@
       return new Kursawe(this, cloner);
     }
-    public Kursawe() : base() { }
+    public Kursawe() : base(minimumObjectives: 2, maximumObjectives: 2, minimumSolutionLength: 3) { }
 
 
Index: /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/Testfunctions/MultiObjectiveTestFunction.cs
===================================================================
--- /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/Testfunctions/MultiObjectiveTestFunction.cs	(revision 13770)
+++ /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/Testfunctions/MultiObjectiveTestFunction.cs	(revision 13771)
@@ -106,11 +106,10 @@
       this.objectives = original.objectives;
     }
-    protected MultiObjectiveTestFunction() : base() {
-      Parameters.Add(new FixedValueParameter<IntValue>("MinimumObjectives", "The dimensionality of the problem instance (number of variables in the function).", new IntValue(MinimumObjectives)));
-      Parameters.Add(new FixedValueParameter<IntValue>("MaximumObjectives", "The dimensionality of the problem instance (number of variables in the function).", new IntValue(MaximumObjectives)));
-      Parameters.Add(new FixedValueParameter<IntValue>("MinimumSolutionLength", "The dimensionality of the problem instance (number of variables in the function).", new IntValue(MinimumSolutionLength)));
-      Parameters.Add(new FixedValueParameter<IntValue>("MaximumSolutionLength", "The dimensionality of the problem instance (number of variables in the function).", new IntValue(MaximumSolutionLength)));
+    protected MultiObjectiveTestFunction(int minimumObjectives = 1, int maximumObjectives = int.MaxValue, int minimumSolutionLength = 1, int maximumSolutionLength = int.MaxValue) : base() {
+      Parameters.Add(new FixedValueParameter<IntValue>("MinimumObjectives", "The dimensionality of the problem instance (number of variables in the function).", new IntValue(minimumObjectives)));
+      Parameters.Add(new FixedValueParameter<IntValue>("MaximumObjectives", "The dimensionality of the problem instance (number of variables in the function).", new IntValue(maximumObjectives)));
+      Parameters.Add(new FixedValueParameter<IntValue>("MinimumSolutionLength", "The dimensionality of the problem instance (number of variables in the function).", new IntValue(minimumSolutionLength)));
+      Parameters.Add(new FixedValueParameter<IntValue>("MaximumSolutionLength", "The dimensionality of the problem instance (number of variables in the function).", new IntValue(maximumSolutionLength)));
     }
-
 
     /// <summary>
Index: /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/Testfunctions/SchafferN1.cs
===================================================================
--- /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/Testfunctions/SchafferN1.cs	(revision 13770)
+++ /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/Testfunctions/SchafferN1.cs	(revision 13771)
@@ -76,5 +76,5 @@
     }
 
-    public SchafferN1() : base() { }
+    public SchafferN1() : base(minimumObjectives: 2, maximumObjectives: 2, minimumSolutionLength: 1, maximumSolutionLength: 1) { }
 
     public override double[] Evaluate(RealVector r, int objectives) {
Index: /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/Testfunctions/SchafferN2.cs
===================================================================
--- /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/Testfunctions/SchafferN2.cs	(revision 13770)
+++ /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/Testfunctions/SchafferN2.cs	(revision 13771)
@@ -71,5 +71,5 @@
     }
 
-    public SchafferN2() : base() { }
+    public SchafferN2() : base(minimumObjectives: 2, maximumObjectives: 2, minimumSolutionLength: 1, maximumSolutionLength: 1) { }
 
 
Index: /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/Testfunctions/ZDT/ZDT.cs
===================================================================
--- /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/Testfunctions/ZDT/ZDT.cs	(revision 13770)
+++ /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/Testfunctions/ZDT/ZDT.cs	(revision 13771)
@@ -70,5 +70,5 @@
     protected ZDT(MultiObjectiveTestFunction original, Cloner cloner) : base(original, cloner) {
     }
-    protected ZDT() : base() { }
+    protected ZDT() : base(minimumObjectives: 2, maximumObjectives: 2, minimumSolutionLength: 1) { }
 
     public override double[] Evaluate(RealVector r, int objectives) {
Index: /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/Views/MOFrontScatterPlotView.cs
===================================================================
--- /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/Views/MOFrontScatterPlotView.cs	(revision 13770)
+++ /branches/HeuristicLab.Problems.MultiObjectiveTestFunctions/HeuristicLab.Problems.MultiObjectiveTestFunctions/3.3/Views/MOFrontScatterPlotView.cs	(revision 13771)
@@ -335,4 +335,5 @@
     private void fillSeries(double[][] qualities, double[][] solutions, Series series) {
       series.Points.Clear();
+      if (qualities == null || qualities.Length == 0) return;
       int jx = xDim - qualities[0].Length;
       int jy = yDim - qualities[0].Length;
