Index: stable/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/NcaModel.cs
===================================================================
--- stable/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/NcaModel.cs	(revision 17159)
+++ stable/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/NcaModel.cs	(revision 17164)
@@ -65,5 +65,5 @@
 
       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: classValues);
+      nnModel = new NearestNeighbourModel(ds, Enumerable.Range(0, ds.Rows), k, false, ds.VariableNames.Last(), ds.VariableNames.Take(transformationMatrix.GetLength(1)), classValues: classValues);
     }
 
Index: stable/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourClassification.cs
===================================================================
--- stable/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourClassification.cs	(revision 17159)
+++ stable/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourClassification.cs	(revision 17164)
@@ -1,3 +1,3 @@
-#region License Information
+﻿#region License Information
 /* HeuristicLab
  * Copyright (C) 2002-2019 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
@@ -42,9 +42,12 @@
     private const string NearestNeighbourClassificationModelResultName = "Nearest neighbour classification solution";
     private const string WeightsParameterName = "Weights";
-
+    private const string SelfMatchParameterName = "SelfMatch";
 
     #region parameter properties
     public IFixedValueParameter<IntValue> KParameter {
       get { return (IFixedValueParameter<IntValue>)Parameters[KParameterName]; }
+    }
+    public IFixedValueParameter<BoolValue> SelfMatchParameter {
+      get { return (IFixedValueParameter<BoolValue>)Parameters[SelfMatchParameterName]; }
     }
     public IValueParameter<DoubleArray> WeightsParameter {
@@ -53,4 +56,8 @@
     #endregion
     #region properties
+    public bool SelfMatch {
+      get { return SelfMatchParameter.Value.Value; }
+      set { SelfMatchParameter.Value.Value = value; }
+    }
     public int K {
       get { return KParameter.Value.Value; }
@@ -73,4 +80,5 @@
     public NearestNeighbourClassification()
       : base() {
+      Parameters.Add(new FixedValueParameter<BoolValue>(SelfMatchParameterName, "Should we use equal points for classification?", new BoolValue(false)));
       Parameters.Add(new FixedValueParameter<IntValue>(KParameterName, "The number of nearest neighbours to consider for regression.", new IntValue(3)));
       Parameters.Add(new OptionalValueParameter<DoubleArray>(WeightsParameterName, "Optional: use weights to specify individual scaling values for all features. If not set the weights are calculated automatically (each feature is scaled to unit variance)"));
@@ -83,4 +91,7 @@
       if (!Parameters.ContainsKey(WeightsParameterName)) {
         Parameters.Add(new OptionalValueParameter<DoubleArray>(WeightsParameterName, "Optional: use weights to specify individual scaling values for all features. If not set the weights are calculated automatically (each feature is scaled to unit variance)"));
+      }
+      if (!Parameters.ContainsKey(SelfMatchParameterName)) {
+        Parameters.Add(new FixedValueParameter<BoolValue>(SelfMatchParameterName, "Should we use equal points for classification?", new BoolValue(false)));
       }
       #endregion
@@ -95,17 +106,18 @@
       double[] weights = null;
       if (Weights != null) weights = Weights.CloneAsArray();
-      var solution = CreateNearestNeighbourClassificationSolution(Problem.ProblemData, K, weights);
+      var solution = CreateNearestNeighbourClassificationSolution(Problem.ProblemData, K, SelfMatch, weights);
       Results.Add(new Result(NearestNeighbourClassificationModelResultName, "The nearest neighbour classification solution.", solution));
     }
 
-    public static IClassificationSolution CreateNearestNeighbourClassificationSolution(IClassificationProblemData problemData, int k, double[] weights = null) {
+    public static IClassificationSolution CreateNearestNeighbourClassificationSolution(IClassificationProblemData problemData, int k, bool selfMatch = false, double[] weights = null) {
       var problemDataClone = (IClassificationProblemData)problemData.Clone();
-      return new NearestNeighbourClassificationSolution(Train(problemDataClone, k, weights), problemDataClone);
+      return new NearestNeighbourClassificationSolution(Train(problemDataClone, k, selfMatch, weights), problemDataClone);
     }
 
-    public static INearestNeighbourModel Train(IClassificationProblemData problemData, int k, double[] weights = null) {
+    public static INearestNeighbourModel Train(IClassificationProblemData problemData, int k, bool selfMatch = false, double[] weights = null) {
       return new NearestNeighbourModel(problemData.Dataset,
         problemData.TrainingIndices,
         k,
+        selfMatch,
         problemData.TargetVariable,
         problemData.AllowedInputVariables,
Index: stable/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourModel.cs
===================================================================
--- stable/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourModel.cs	(revision 17159)
+++ stable/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourModel.cs	(revision 17164)
@@ -1,3 +1,3 @@
-#region License Information
+﻿#region License Information
 /* HeuristicLab
  * Copyright (C) 2002-2019 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
@@ -37,4 +37,5 @@
 
     private readonly object kdTreeLockObject = new object();
+
     private alglib.nearestneighbor.kdtree kdTree;
     public alglib.nearestneighbor.kdtree KDTree {
@@ -49,5 +50,4 @@
     }
 
-
     public override IEnumerable<string> VariablesUsedForPrediction {
       get { return allowedInputVariables; }
@@ -60,4 +60,6 @@
     [Storable]
     private int k;
+    [Storable(DefaultValue = false)]
+    private bool selfMatch;
     [Storable(DefaultValue = null)]
     private double[] weights; // not set for old versions loaded from disk
@@ -95,5 +97,5 @@
       kdTree.x = (double[])original.kdTree.x.Clone();
       kdTree.xy = (double[,])original.kdTree.xy.Clone();
-
+      selfMatch = original.selfMatch;
       k = original.k;
       isCompatibilityLoaded = original.IsCompatibilityLoaded;
@@ -108,8 +110,9 @@
         this.classValues = (double[])original.classValues.Clone();
     }
-    public NearestNeighbourModel(IDataset dataset, IEnumerable<int> rows, int k, string targetVariable, IEnumerable<string> allowedInputVariables, IEnumerable<double> weights = null, double[] classValues = null)
+    public NearestNeighbourModel(IDataset dataset, IEnumerable<int> rows, int k, bool selfMatch, string targetVariable, IEnumerable<string> allowedInputVariables, IEnumerable<double> weights = null, double[] classValues = null)
       : base(targetVariable) {
       Name = ItemName;
       Description = ItemDescription;
+      this.selfMatch = selfMatch;
       this.k = k;
       this.allowedInputVariables = allowedInputVariables.ToArray();
@@ -130,5 +133,5 @@
             .Select(name => {
               var pop = dataset.GetDoubleValues(name, rows).StandardDeviationPop();
-              return  pop.IsAlmost(0) ? 1.0 : 1.0/pop;
+              return pop.IsAlmost(0) ? 1.0 : 1.0 / pop;
             })
             .Concat(new double[] { 1.0 }) // no scaling for target variable
@@ -199,9 +202,25 @@
         int numNeighbours;
         lock (kdTreeLockObject) { // gkronber: the following calls change the kdTree data structure
-          numNeighbours = alglib.nearestneighbor.kdtreequeryknn(kdTree, x, k, false);
+          numNeighbours = alglib.nearestneighbor.kdtreequeryknn(kdTree, x, k, selfMatch);
           alglib.nearestneighbor.kdtreequeryresultsdistances(kdTree, ref dists);
           alglib.nearestneighbor.kdtreequeryresultsxy(kdTree, ref neighbours);
         }
-
+        if (selfMatch) {
+          // weights for neighbours are 1/d.
+          // override distances (=0) of exact matches using 1% of the distance of the next closest non-self-match neighbour -> selfmatches weight 100x more than the next closest neighbor.
+          // if all k neighbours are selfmatches then they all have weight 0.01.
+          double minDist = dists[0] + 1;
+          for (int i = 0; i < numNeighbours; i++) {
+            if ((minDist > dists[i]) && (dists[i] != 0)) {
+              minDist = dists[i];
+            }
+          }
+          minDist /= 100.0;
+          for (int i = 0; i < numNeighbours; i++) {
+            if (dists[i] == 0) {
+              dists[i] = minDist;
+            }
+          }
+        }
         double distanceWeightedValue = 0.0;
         double distsSum = 0.0;
@@ -236,5 +255,5 @@
         lock (kdTreeLockObject) {
           // gkronber: the following calls change the kdTree data structure
-          numNeighbours = alglib.nearestneighbor.kdtreequeryknn(kdTree, x, k, false);
+          numNeighbours = alglib.nearestneighbor.kdtreequeryknn(kdTree, x, k, selfMatch);
           alglib.nearestneighbor.kdtreequeryresultsdistances(kdTree, ref dists);
           alglib.nearestneighbor.kdtreequeryresultsxy(kdTree, ref neighbours);
Index: stable/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourRegression.cs
===================================================================
--- stable/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourRegression.cs	(revision 17159)
+++ stable/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourRegression.cs	(revision 17164)
@@ -41,4 +41,5 @@
     private const string NearestNeighbourRegressionModelResultName = "Nearest neighbour regression solution";
     private const string WeightsParameterName = "Weights";
+    private const string SelfMatchParameterName = "SelfMatch";
 
     #region parameter properties
@@ -46,5 +47,7 @@
       get { return (IFixedValueParameter<IntValue>)Parameters[KParameterName]; }
     }
-
+    public IFixedValueParameter<BoolValue> SelfMatchParameter {
+      get { return (IFixedValueParameter<BoolValue>)Parameters[SelfMatchParameterName]; }
+    }
     public IValueParameter<DoubleArray> WeightsParameter {
       get { return (IValueParameter<DoubleArray>)Parameters[WeightsParameterName]; }
@@ -59,5 +62,8 @@
       }
     }
-
+    public bool SelfMatch {
+      get { return SelfMatchParameter.Value.Value; }
+      set { SelfMatchParameter.Value.Value = value; }
+    }
     public DoubleArray Weights {
       get { return WeightsParameter.Value; }
@@ -75,4 +81,5 @@
       Parameters.Add(new FixedValueParameter<IntValue>(KParameterName, "The number of nearest neighbours to consider for regression.", new IntValue(3)));
       Parameters.Add(new OptionalValueParameter<DoubleArray>(WeightsParameterName, "Optional: use weights to specify individual scaling values for all features. If not set the weights are calculated automatically (each feature is scaled to unit variance)"));
+      Parameters.Add(new FixedValueParameter<BoolValue>(SelfMatchParameterName, "Should we use equal points for classification?", new BoolValue(false)));
       Problem = new RegressionProblem();
     }
@@ -84,4 +91,7 @@
       if (!Parameters.ContainsKey(WeightsParameterName)) {
         Parameters.Add(new OptionalValueParameter<DoubleArray>(WeightsParameterName, "Optional: use weights to specify individual scaling values for all features. If not set the weights are calculated automatically (each feature is scaled to unit variance)"));
+      }
+      if (!Parameters.ContainsKey(SelfMatchParameterName)) {
+        Parameters.Add(new FixedValueParameter<BoolValue>(SelfMatchParameterName, "Should we use equal points for classification?", new BoolValue(false)));
       }
       #endregion
@@ -96,17 +106,18 @@
       double[] weights = null;
       if (Weights != null) weights = Weights.CloneAsArray();
-      var solution = CreateNearestNeighbourRegressionSolution(Problem.ProblemData, K, weights);
+      var solution = CreateNearestNeighbourRegressionSolution(Problem.ProblemData, K, SelfMatch, weights);
       Results.Add(new Result(NearestNeighbourRegressionModelResultName, "The nearest neighbour regression solution.", solution));
     }
 
-    public static IRegressionSolution CreateNearestNeighbourRegressionSolution(IRegressionProblemData problemData, int k, double[] weights = null) {
+    public static IRegressionSolution CreateNearestNeighbourRegressionSolution(IRegressionProblemData problemData, int k, bool selfMatch = false, double[] weights = null) {
       var clonedProblemData = (IRegressionProblemData)problemData.Clone();
-      return new NearestNeighbourRegressionSolution(Train(problemData, k, weights), clonedProblemData);
+      return new NearestNeighbourRegressionSolution(Train(problemData, k, selfMatch, weights), clonedProblemData);
     }
 
-    public static INearestNeighbourModel Train(IRegressionProblemData problemData, int k, double[] weights = null) {
+    public static INearestNeighbourModel Train(IRegressionProblemData problemData, int k, bool selfMatch = false, double[] weights = null) {
       return new NearestNeighbourModel(problemData.Dataset,
         problemData.TrainingIndices,
         k,
+        selfMatch,
         problemData.TargetVariable,
         problemData.AllowedInputVariables,
