Index: branches/NCA/HeuristicLab.Algorithms.NCA/3.3/NCAModel.cs
===================================================================
--- branches/NCA/HeuristicLab.Algorithms.NCA/3.3/NCAModel.cs	(revision 8454)
+++ branches/NCA/HeuristicLab.Algorithms.NCA/3.3/NCAModel.cs	(revision 8466)
@@ -29,7 +29,7 @@
 
 namespace HeuristicLab.Algorithms.NCA {
-  [Item("NCAModel", "")]
+  [Item("NCA Model", "")]
   [StorableClass]
-  public class NCAModel : NamedItem, INCAModel {
+  public class NcaModel : NamedItem, INcaModel {
 
     [Storable]
@@ -47,11 +47,9 @@
     private INearestNeighbourModel nnModel;
     [Storable]
-    private Dictionary<double, double> nn2ncaClassMapping;
-    [Storable]
-    private Dictionary<double, double> nca2nnClassMapping;
+    private double[] classValues;
 
     [StorableConstructor]
-    protected NCAModel(bool deserializing) : base(deserializing) { }
-    protected NCAModel(NCAModel original, Cloner cloner)
+    protected NcaModel(bool deserializing) : base(deserializing) { }
+    protected NcaModel(NcaModel original, Cloner cloner)
       : base(original, cloner) {
       this.scaling = cloner.Clone(original.scaling);
@@ -60,46 +58,30 @@
       this.targetVariable = original.targetVariable;
       this.nnModel = cloner.Clone(original.nnModel);
-      this.nn2ncaClassMapping = original.nn2ncaClassMapping.ToDictionary(x => x.Key, y => y.Value);
-      this.nca2nnClassMapping = original.nca2nnClassMapping.ToDictionary(x => x.Key, y => y.Value);
+      this.classValues = (double[])original.classValues.Clone();
     }
-    public NCAModel(int k, double[,] scaledData, Scaling scaling, double[,] transformationMatrix, string targetVariable, IEnumerable<double> targetVector, IEnumerable<string> allowedInputVariables) {
+    public NcaModel(int k, double[,] transformationMatrix, Dataset dataset, IEnumerable<int> rows, string targetVariable, IEnumerable<string> allowedInputVariables, Scaling scaling, double[] classValues) {
       Name = ItemName;
       Description = ItemDescription;
       this.scaling = scaling;
-      this.transformationMatrix = transformationMatrix;
+      this.transformationMatrix = (double[,])transformationMatrix.Clone();
       this.allowedInputVariables = allowedInputVariables.ToArray();
       this.targetVariable = targetVariable;
+      this.classValues = (double[])classValues.Clone();
 
-      nca2nnClassMapping = targetVector.Distinct().OrderBy(x => x).Select((v, i) => new { Index = (double)i, Class = v }).ToDictionary(x => x.Class, y => y.Index);
-      nn2ncaClassMapping = nca2nnClassMapping.ToDictionary(x => x.Value, y => y.Key);
-
-      var transformedData = ReduceWithTarget(scaledData, targetVector.Select(x => nca2nnClassMapping[x]));
-
-      var kdtree = new alglib.nearestneighbor.kdtree();
-      alglib.nearestneighbor.kdtreebuild(transformedData, transformedData.GetLength(0), transformedData.GetLength(1) - 1, 1, 2, kdtree);
-
-      nnModel = new NearestNeighbourModel(kdtree, k, targetVariable,
-        Enumerable.Range(0, transformationMatrix.GetLength(1)).Select(x => x.ToString()),
-        nn2ncaClassMapping.Keys.ToArray());
+      var ds = ReduceDataset(dataset, rows);
+      nnModel = new NearestNeighbourModel(ds, Enumerable.Range(0, ds.Rows), k, ds.VariableNames.Last(), ds.VariableNames.Take(transformationMatrix.GetLength(1)), classValues);
     }
 
     public override IDeepCloneable Clone(Cloner cloner) {
-      return new NCAModel(this, cloner);
+      return new NcaModel(this, cloner);
     }
 
     public IEnumerable<double> GetEstimatedClassValues(Dataset dataset, IEnumerable<int> rows) {
-      var unknownClasses = dataset.GetDoubleValues(targetVariable, rows).Where(x => !nca2nnClassMapping.ContainsKey(x));
-      if (unknownClasses.Any())
-        foreach (var uc in unknownClasses) {
-          nca2nnClassMapping[uc] = nca2nnClassMapping.Count;
-          nn2ncaClassMapping[nca2nnClassMapping[uc]] = uc;
-        }
-      var transformedData = ReduceWithTarget(dataset, rows, dataset.GetDoubleValues(targetVariable, rows).Select(x => nca2nnClassMapping[x]));
-      var ds = new Dataset(Enumerable.Range(0, transformationMatrix.GetLength(1)).Select(x => x.ToString()).Concat(targetVariable.ToEnumerable()), transformedData);
-      return nnModel.GetEstimatedClassValues(ds, Enumerable.Range(0, ds.Rows)).Select(x => nn2ncaClassMapping[x]);
+      var ds = ReduceDataset(dataset, rows);
+      return nnModel.GetEstimatedClassValues(ds, Enumerable.Range(0, ds.Rows));
     }
 
-    public NCAClassificationSolution CreateClassificationSolution(IClassificationProblemData problemData) {
-      return new NCAClassificationSolution(problemData, this);
+    public INcaClassificationSolution CreateClassificationSolution(IClassificationProblemData problemData) {
+      return new NcaClassificationSolution(problemData, this);
     }
 
@@ -110,34 +92,22 @@
     public double[,] Reduce(Dataset dataset, IEnumerable<int> rows) {
       var scaledData = AlglibUtil.PrepareAndScaleInputMatrix(dataset, allowedInputVariables, rows, scaling);
-      return Reduce(scaledData);
-    }
-
-    private double[,] Reduce(double[,] scaledData) {
-      var result = new double[scaledData.GetLength(0), transformationMatrix.GetLength(1)];
+      var targets = dataset.GetDoubleValues(targetVariable, rows).ToArray();
+      var result = new double[scaledData.GetLength(0), transformationMatrix.GetLength(1) + 1];
       for (int i = 0; i < scaledData.GetLength(0); i++)
-        for (int j = 0; j < scaledData.GetLength(1); j++)
+        for (int j = 0; j < scaledData.GetLength(1); j++) {
           for (int x = 0; x < transformationMatrix.GetLength(1); x++) {
             result[i, x] += scaledData[i, j] * transformationMatrix[j, x];
           }
+          result[i, transformationMatrix.GetLength(1)] = targets[i];
+        }
       return result;
     }
 
-    private double[,] ReduceWithTarget(Dataset dataset, IEnumerable<int> rows, IEnumerable<double> targetValues) {
-      var scaledData = AlglibUtil.PrepareAndScaleInputMatrix(dataset, allowedInputVariables, rows, scaling);
-      return ReduceWithTarget(scaledData, targetValues);
-    }
-
-    private double[,] ReduceWithTarget(double[,] scaledData, IEnumerable<double> targetValues) {
-      var result = new double[scaledData.GetLength(0), transformationMatrix.GetLength(1) + 1];
-      for (int i = 0; i < scaledData.GetLength(0); i++)
-        for (int j = 0; j < scaledData.GetLength(1); j++)
-          for (int x = 0; x < transformationMatrix.GetLength(1); x++) {
-            result[i, x] += scaledData[i, j] * transformationMatrix[j, x];
-          }
-
-      int r = 0;
-      foreach (var d in targetValues) result[r++, transformationMatrix.GetLength(1)] = d;
-
-      return result;
+    public Dataset ReduceDataset(Dataset dataset, IEnumerable<int> rows) {
+      return new Dataset(Enumerable
+          .Range(0, transformationMatrix.GetLength(1))
+          .Select(x => "X" + x.ToString())
+          .Concat(targetVariable.ToEnumerable()),
+        Reduce(dataset, rows));
     }
   }
