Index: /branches/PerformanceComparison/HeuristicLab.Analysis/3.3/HeuristicLab.Analysis-3.3.csproj
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Analysis/3.3/HeuristicLab.Analysis-3.3.csproj	(revision 13749)
+++ /branches/PerformanceComparison/HeuristicLab.Analysis/3.3/HeuristicLab.Analysis-3.3.csproj	(revision 13750)
@@ -157,4 +157,9 @@
       <SpecificVersion>False</SpecificVersion>
       <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.PluginInfrastructure-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Random-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Random-3.3.dll</HintPath>
       <Private>False</Private>
     </Reference>
@@ -217,4 +222,6 @@
     <Compile Include="QualityAnalysis\QualityPerEvaluationsAnalyzer.cs" />
     <Compile Include="QualityAnalysis\ScaledQualityDifferenceAnalyzer.cs" />
+    <Compile Include="SelfOrganizingMaps\RelationalSOM.cs" />
+    <Compile Include="SelfOrganizingMaps\SOM.cs" />
     <Compile Include="Statistics\BonferroniHolm.cs" />
     <Compile Include="Statistics\EnumerableStatisticsExtension.cs" />
Index: /branches/PerformanceComparison/HeuristicLab.Analysis/3.3/SelfOrganizingMaps/RelationalSOM.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Analysis/3.3/SelfOrganizingMaps/RelationalSOM.cs	(revision 13750)
+++ /branches/PerformanceComparison/HeuristicLab.Analysis/3.3/SelfOrganizingMaps/RelationalSOM.cs	(revision 13750)
@@ -0,0 +1,127 @@
+﻿#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 HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Random;
+using System;
+using System.Linq;
+
+namespace HeuristicLab.Analysis.SelfOrganizingMaps {
+  public static class RelationalSOM {
+    /// <summary>
+    /// This is the online algorithm described in
+    /// Olteanu, M. and Villa-Vialaneix, N. 2015.
+    /// On-line relational and multiple relational SOM.
+    /// Neurocomputing 147, pp. 15-30.
+    /// </summary>
+    /// <param name="dissimilarities">The full NxN matrix containing all dissimilarities between N points.</param>
+    /// <param name="random">The random number generator to use.</param>
+    /// <param name="somSize">The length of a side of the SOM grid (there are somSize * somSize neurons).</param>
+    /// <param name="iterations">The amount of iterations to perform in learning.</param>
+    /// <param name="learningRate">The initial learning rate.</param>
+    /// <param name="learningRadius">The initial learning radius.</param>
+    /// <param name="jittering">If the final coordinates should be jittered slightly within the grid.</param>
+    /// <returns>A matrix of coordinates having N rows and 2 columns.</returns>
+    public static DoubleMatrix Map(DoubleMatrix dissimilarities, IRandom random = null, int somSize = 5, int iterations = 100, double learningRate = double.NaN, double learningRadius = 5.0, bool jittering = true) {
+      if (random == null) random = new MersenneTwister();
+      var K = somSize * somSize;
+      var N = dissimilarities.Rows;
+      if (double.IsNaN(learningRate)) learningRate = 1.0 / Math.Sqrt(2.0 * N);
+      var fixedLearningRate = learningRate / 10.0;
+      var varLearningRate = 9.0 * fixedLearningRate;
+      Func<int, int> getX = (neuron) => neuron % somSize;
+      Func<int, int> getY = (neuron) => neuron / somSize;
+      Func<int, int, int, int, double> neighborhood = (maxIter, iter, k, bmu) => {
+        var sigma = learningRadius * ((maxIter - iter) / (double)maxIter) + 0.0001;
+        var xK = getX(k);
+        var yK = getY(k);
+        var xW = getX(bmu);
+        var yW = getY(bmu);
+        var d = (xK - xW) * (xK - xW) + (yK - yW) * (yK - yW);
+        return Math.Exp(-d / (2.0 * sigma * sigma));
+      };
+      var alphas = Enumerable.Range(0, K).Select(k => Enumerable.Range(0, N).Select(_ => random.NextDouble()).ToArray()).ToArray();
+      // normalize s.t. sum(alphas[k]) = 1
+      for (var k = 0; k < K; k++) {
+        var sum = alphas[k].Sum();
+        for (var i = 0; i < alphas[k].Length; i++) alphas[k][i] /= sum;
+      }
+      var oldAlphas = alphas.Select(x => (double[])x.Clone()).ToArray();
+
+      for (var iter = 0; iter < iterations; iter++) {
+        learningRate = varLearningRate * ((iterations - iter) / (double)iterations) + fixedLearningRate;
+        var pointShuffle = Enumerable.Range(0, N).Shuffle(random).ToArray();
+        for (var p = 0; p < N; p++) {
+          var i = pointShuffle[p];
+          var bmu = GetBestMatchingUnit(dissimilarities, alphas, i);
+
+          for (var k = 0; k < K; k++) {
+            for (var j = 0; j < N; j++) {
+              alphas[k][j] = oldAlphas[k][j] + learningRate * neighborhood(iterations, iter, k, bmu) * ((i == j ? 1.0 : 0.0) - oldAlphas[k][j]);
+            }
+          }
+        }
+        for (var k = 0; k < K; k++) {
+          for (var j = 0; j < N; j++) {
+            oldAlphas[k][j] = alphas[k][j];
+          }
+        }
+      }
+
+      var result = new DoubleMatrix(N, 2);
+      for (var i = 0; i < N; i++) {
+        var bmu = GetBestMatchingUnit(dissimilarities, alphas, i);
+        if (!jittering) {
+          result[i, 0] = getX(bmu);
+          result[i, 1] = getY(bmu);
+        } else {
+          result[i, 0] = getX(bmu) + random.NextDouble() * 0.8;
+          result[i, 1] = getY(bmu) + random.NextDouble() * 0.8;
+        }
+      }
+      return result;
+    }
+
+    private static int GetBestMatchingUnit(DoubleMatrix D, double[][] alphas, int i) {
+      var bmu = -1;
+      var minV = double.MaxValue;
+      for (var k = 0; k < alphas.Length; k++) {
+        var Daki = 0.0;
+        var akDak = 0.0;
+        for (var r = 0; r < D.Rows; r++) {
+          var Dakr = 0.0;
+          for (var s = 0; s < D.Rows; s++) {
+            Dakr += D[r, s] * alphas[k][s];
+          }
+          if (r == i) Daki = Dakr;
+          akDak += alphas[k][r] * Dakr;
+        }
+        var v = Daki - 0.5 * akDak;
+        if (v < minV) {
+          bmu = k;
+          minV = v;
+        }
+      }
+      return bmu;
+    }
+  }
+}
Index: /branches/PerformanceComparison/HeuristicLab.Analysis/3.3/SelfOrganizingMaps/SOM.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Analysis/3.3/SelfOrganizingMaps/SOM.cs	(revision 13750)
+++ /branches/PerformanceComparison/HeuristicLab.Analysis/3.3/SelfOrganizingMaps/SOM.cs	(revision 13750)
@@ -0,0 +1,132 @@
+﻿#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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Random;
+using System;
+using System.Linq;
+
+namespace HeuristicLab.Analysis.SelfOrganizingMaps {
+  public static class SOM {
+    /// <summary>
+    /// Performs a self-organizing map to a range of feature column-vectors organized in a matrix.
+    /// </summary>
+    /// <param name="features">The feature matrix containing the column-vectors.</param>
+    /// <param name="random">The random number generator to use.</param>
+    /// <param name="somSize">The length of a side of the SOM grid (there are somSize * somSize neurons).</param>
+    /// <param name="iterations">The amount of iterations to perform in learning.</param>
+    /// <param name="learningRate">The initial learning rate.</param>
+    /// <param name="learningRadius">The initial learning radius.</param>
+    /// <param name="jittering">If the final coordinates should be jittered slightly within the grid.</param>
+    /// <returns>A matrix of coordinates having N rows and 2 columns.</returns>
+    public static DoubleMatrix Map(DoubleMatrix features, IRandom random = null, int somSize = 5, int iterations = 100, double learningRate = double.NaN, double learningRadius = 5.0, bool jittering = true) {
+      if (random == null) random = new MersenneTwister();
+      var K = somSize * somSize;
+      var N = features.Columns;
+      var L = features.Rows;
+
+      if (double.IsNaN(learningRate)) learningRate = 1.0 / Math.Sqrt(2.0 * L);
+      var fixedLearningRate = learningRate / 10.0;
+      var varLearningRate = 9.0 * fixedLearningRate;
+      Func<int, int> getX = (neuron) => neuron % somSize;
+      Func<int, int> getY = (neuron) => neuron / somSize;
+      Func<int, int, int, int, double> neighborhood = (maxIter, iter, k, bmu) => {
+        var sigma = learningRadius * ((maxIter - iter) / (double)maxIter) + 0.0001;
+        var xK = getX(k);
+        var yK = getY(k);
+        var xW = getX(bmu);
+        var yW = getY(bmu);
+        var d = (xK - xW) * (xK - xW) + (yK - yW) * (yK - yW);
+        return Math.Exp(-d / (2.0 * sigma * sigma));
+      };
+      var scaledFeatures = Scale(features);
+      var weights = Enumerable.Range(0, K).Select(k => Enumerable.Range(0, L).Select(_ => random.NextDouble()).ToArray()).ToArray();
+      // normalize s.t. sum(alphas[k]) = 1
+      for (var k = 0; k < K; k++) {
+        var sum = weights[k].Sum();
+        for (var i = 0; i < weights[k].Length; i++) weights[k][i] /= sum;
+      }
+      var oldWeights = weights.Select(x => (double[])x.Clone()).ToArray();
+
+      for (var iter = 0; iter < iterations; iter++) {
+        learningRate = varLearningRate * ((iterations - iter) / (double)iterations) + fixedLearningRate;
+        var pointShuffle = Enumerable.Range(0, N).Shuffle(random).ToArray();
+        for (var p = 0; p < N; p++) {
+          var i = pointShuffle[p];
+          var bmu = GetBestMatchingUnit(scaledFeatures, weights, i);
+
+          for (var k = 0; k < K; k++) {
+            for (var j = 0; j < L; j++) {
+              weights[k][j] = oldWeights[k][j] + learningRate * neighborhood(iterations, iter, k, bmu) * (scaledFeatures[j, i] - oldWeights[k][j]);
+            }
+          }
+        }
+        for (var k = 0; k < K; k++) {
+          for (var j = 0; j < L; j++) {
+            oldWeights[k][j] = weights[k][j];
+          }
+        }
+      }
+
+      var result = new DoubleMatrix(N, 2);
+      for (var i = 0; i < N; i++) {
+        var bmu = GetBestMatchingUnit(scaledFeatures, weights, i);
+        if (!jittering) {
+          result[i, 0] = getX(bmu);
+          result[i, 1] = getY(bmu);
+        } else {
+          result[i, 0] = getX(bmu) + random.NextDouble() * 0.8;
+          result[i, 1] = getY(bmu) + random.NextDouble() * 0.8;
+        }
+      }
+      return result;
+    }
+
+    private static int GetBestMatchingUnit(DoubleMatrix D, double[][] weights, int i) {
+      var bmu = -1;
+      var minV = double.MaxValue;
+      for (var k = 0; k < weights.Length; k++) {
+        var d = 0.0;
+        for (var r = 0; r < weights[k].Length; r++) {
+          d += (D[r, i] - weights[k][r]) * (D[r, i] - weights[k][r]);
+        }
+        if (d < minV) {
+          minV = d;
+          bmu = k;
+        }
+      }
+      return bmu;
+    }
+
+    private static DoubleMatrix Scale(DoubleMatrix features) {
+      var scaledFeatures = new DoubleMatrix(features.Rows, features.Columns);
+      for (var i = 0; i < features.Rows; i++) {
+        var rowSum = 0.0;
+        for (var j = 0; j < features.Columns; j++) rowSum += features[i, j];
+        if (rowSum.IsAlmost(0.0)) rowSum = 1.0;
+        for (var j = 0; j < features.Columns; j++) scaledFeatures[i, j] = features[i, j] / rowSum;
+      }
+      return scaledFeatures;
+    }
+  }
+}
Index: /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/HeuristicLab.OptimizationExpertSystem.Common-3.3.csproj
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/HeuristicLab.OptimizationExpertSystem.Common-3.3.csproj	(revision 13749)
+++ /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/HeuristicLab.OptimizationExpertSystem.Common-3.3.csproj	(revision 13750)
@@ -132,4 +132,9 @@
       <Private>False</Private>
     </Reference>
+    <Reference Include="HeuristicLab.Random-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Random-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
     <Reference Include="System" />
     <Reference Include="System.Core" />
Index: /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/KnowledgeCenter.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/KnowledgeCenter.cs	(revision 13749)
+++ /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/KnowledgeCenter.cs	(revision 13750)
@@ -21,4 +21,5 @@
 
 using HeuristicLab.Analysis;
+using HeuristicLab.Analysis.SelfOrganizingMaps;
 using HeuristicLab.Collections;
 using HeuristicLab.Common;
@@ -29,4 +30,5 @@
 using HeuristicLab.Optimization;
 using HeuristicLab.Persistence.Default.Xml;
+using HeuristicLab.Random;
 using System;
 using System.Collections.Generic;
@@ -232,4 +234,13 @@
       alglib.pcabuildbasis(ds, ds.GetLength(0), ds.GetLength(1), out info, out s2, out v);
       #endregion
+      #region SOM
+      var features = new DoubleMatrix(commonCharacteristics.Count, instances.Count);
+      foreach (var instance in instances) {
+        var arr = instance.Value;
+        for (var feature = 0; feature < arr.Length; feature++)
+          features[feature, key2Idx.GetByFirst(instance.Key)] = arr[feature];
+      }
+      var somCoords = SOM.Map(features, new MersenneTwister(42), somSize: 20, learningRadius: 20, jittering: true);
+      #endregion
 
       ProblemInstances.UpdateOfRunsInProgress = true;
@@ -256,4 +267,11 @@
             ((DoubleValue)item).Value = coords[key2Idx.GetByFirst(instance.Name), 1];
           } else instance.Results.Add("Projection.MDS.Y", new DoubleValue(coords[key2Idx.GetByFirst(instance.Name), 1]));
+
+          if (instance.Results.TryGetValue("Projection.SOM.X", out item)) {
+            ((DoubleValue)item).Value = somCoords[key2Idx.GetByFirst(instance.Name), 0];
+          } else instance.Results.Add("Projection.SOM.X", new DoubleValue(somCoords[key2Idx.GetByFirst(instance.Name), 0]));
+          if (instance.Results.TryGetValue("Projection.SOM.Y", out item)) {
+            ((DoubleValue)item).Value = somCoords[key2Idx.GetByFirst(instance.Name), 1];
+          } else instance.Results.Add("Projection.SOM.Y", new DoubleValue(somCoords[key2Idx.GetByFirst(instance.Name), 1]));
         }
       } finally { ProblemInstances.UpdateOfRunsInProgress = false; }
Index: /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Menu/900_Tools/910_NewCSharpScriptMenuItem.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Menu/900_Tools/910_NewCSharpScriptMenuItem.cs	(revision 13749)
+++ /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Menu/900_Tools/910_NewCSharpScriptMenuItem.cs	(revision 13750)
@@ -55,5 +55,5 @@
 
 public class MyScript : HeuristicLab.Scripting.CSharpScriptBase {
-  public ExpertSystem Instance { get { return ((OptimizationExpertSystem)HeuristicLab.MainForm.MainFormManager.MainForm).ExpertSystem; } }
+  public KnowledgeCenter Instance { get { return ((OptimizationKnowledgeCenter)HeuristicLab.MainForm.MainFormManager.MainForm).ExpertSystem; } }
 
   public override void Main() {
Index: /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Views/UnderstandingSolutionsView.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Views/UnderstandingSolutionsView.cs	(revision 13749)
+++ /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Views/UnderstandingSolutionsView.cs	(revision 13750)
@@ -22,4 +22,5 @@
 using HeuristicLab.Analysis;
 using HeuristicLab.Analysis.QualityAnalysis;
+using HeuristicLab.Analysis.SelfOrganizingMaps;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -241,5 +242,5 @@
         DoubleMatrix coords = null;
         if (projection == "SOM")
-          coords = Som(dissimilarities, new MersenneTwister(42), jittering: true);
+          coords = RelationalSOM.Map(dissimilarities, new MersenneTwister(42), jittering: true);
         else coords = MultidimensionalScaling.KruskalShepard(dissimilarities);
         var dataPoints = new List<DataPoint>();
@@ -382,108 +383,4 @@
       return dval.Value;
     }
-
-    #region SOM projection
-    /// <summary>
-    /// This is the online algorithm described in
-    /// Olteanu, M. and Villa-Vialaneix, N. 2015.
-    /// On-line relational and multiple relational SOM.
-    /// Neurocomputing 147, pp. 15-30.
-    /// </summary>
-    /// <param name="dissimilarities">The full NxN matrix containing all dissimilarities between N points.</param>
-    /// <param name="random">The random number generator to use.</param>
-    /// <param name="somSize">The length of a side of the SOM grid (there are somSize * somSize neurons).</param>
-    /// <param name="iterations">The amount of iterations to perform in learning.</param>
-    /// <param name="learningRate">The initial learning rate.</param>
-    /// <param name="learningRadius">The initial learning radius.</param>
-    /// <param name="jittering">If the final coordinates should be jittered slightly within the grid.</param>
-    /// <returns>A matrix of coordinates having N rows and 2 columns.</returns>
-    private DoubleMatrix Som(DoubleMatrix dissimilarities, IRandom random, int somSize = 5, int iterations = 100, double learningRate = double.NaN, double learningRadius = 5.0, bool jittering = true) {
-      var K = somSize * somSize;
-      var N = dissimilarities.Rows;
-      if (double.IsNaN(learningRate)) learningRate = 1.0 / Math.Sqrt(2.0 * N);
-      var fixedLearningRate = learningRate / 10.0;
-      var varLearningRate = 9.0 * fixedLearningRate;
-      Func<int, int, double> learningRateT = (maxIter, iter) => {
-        return varLearningRate * ((maxIter - iter) / (double)maxIter) + fixedLearningRate;
-      };
-      Func<int, int> getX = (neuron) => neuron % somSize;
-      Func<int, int> getY = (neuron) => neuron / somSize;
-      Func<int, int, int, int, double> neighborhood = (maxIter, iter, k, bmu) => {
-        var sigma = 1.0 * ((maxIter - iter) / (double)maxIter) + 0.0001;
-        var xK = getX(k);
-        var yK = getY(k);
-        var xW = getX(bmu);
-        var yW = getY(bmu);
-        var d = (xK - xW) * (xK - xW) + (yK - yW) * (yK - yW);
-        return Math.Exp(-d / (2.0 * sigma * sigma));
-      };
-      var alphas = Enumerable.Range(0, K).Select(k => Enumerable.Range(0, N).Select(_ => random.NextDouble()).ToArray()).ToArray();
-      // normalize s.t. sum(alphas[k]) = 1
-      for (var k = 0; k < K; k++) {
-        var sum = alphas[k].Sum();
-        for (var i = 0; i < alphas[k].Length; i++) alphas[k][i] /= sum;
-      }
-      var oldAlphas = alphas.Select(x => (double[])x.Clone()).ToArray();
-
-      for (var iter = 0; iter < iterations; iter++) {
-        var pointShuffle = Enumerable.Range(0, N).Shuffle(random).ToArray();
-        for (var p = 0; p < N; p++) {
-          var i = pointShuffle[p];
-          var bmu = GetBestMatchingUnit(dissimilarities, alphas, i);
-
-          for (var k = 0; k < K; k++) {
-            for (var j = 0; j < N; j++) {
-              alphas[k][j] = oldAlphas[k][j] + learningRateT(iterations, iter) * neighborhood(iterations, iter, k, bmu) * ((i == j ? 1.0 : 0.0) - oldAlphas[k][j]);
-            }
-          }
-        }
-        for (var k = 0; k < K; k++) {
-          for (var j = 0; j < N; j++) {
-            oldAlphas[k][j] = alphas[k][j];
-          }
-        }
-      }
-
-      var result = new DoubleMatrix(N, 2);
-      for (var i = 0; i < N; i++) {
-        var bmu = GetBestMatchingUnit(dissimilarities, alphas, i);
-        if (!jittering) {
-          result[i, 0] = getX(bmu);
-          result[i, 1] = getY(bmu);
-        } else {
-          result[i, 0] = getX(bmu) + random.NextDouble() * 0.8;
-          result[i, 1] = getY(bmu) + random.NextDouble() * 0.8;
-        }
-      }
-      return result;
-    }
-
-    private int GetBestMatchingUnit(DoubleMatrix D, double[][] alphas, int i) {
-      var bmu = -1;
-      var minV = double.MaxValue;
-      for (var k = 0; k < alphas.Length; k++) {
-        var Daki = 0.0;
-        var akDak = 0.0;
-        for (var r = 0; r < D.Rows; r++) {
-          var Dakr = 0.0;
-          for (var s = 0; s < D.Rows; s++) {
-            Dakr += D[r, s] * alphas[k][s];
-          }
-          if (r == i) Daki = Dakr;
-          akDak += alphas[k][r] * Dakr;
-        }
-        var v = Daki - 0.5 * akDak;
-        if (v < minV) {
-          bmu = k;
-          minV = v;
-        }
-      }
-      return bmu;
-    }
-    #endregion
-
-    private DoubleMatrix Mds(DoubleMatrix dissimilarities) {
-      return MultidimensionalScaling.KruskalShepard(dissimilarities);
-    }
     #endregion
   }
