Index: stable/HeuristicLab.Algorithms.DataAnalysis/3.4/TSNE/TSNEAlgorithm.cs
===================================================================
--- trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/TSNE/TSNEAlgorithm.cs	(revision 14863)
+++ stable/HeuristicLab.Algorithms.DataAnalysis/3.4/TSNE/TSNEAlgorithm.cs	(revision 15249)
@@ -32,4 +32,5 @@
 using HeuristicLab.Parameters;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.PluginInfrastructure;
 using HeuristicLab.Problems.DataAnalysis;
 using HeuristicLab.Random;
@@ -41,5 +42,5 @@
   /// </summary>
   [Item("tSNE", "t-distributed stochastic neighbourhood embedding projects the data in a low " +
-                "dimensional space to allow visual cluster identification.")]
+                "dimensional space to allow visual cluster identification. Implemented similar to: https://lvdmaaten.github.io/tsne/#implementations (Barnes-Hut t-SNE). Described in : https://lvdmaaten.github.io/publications/papers/JMLR_2014.pdf")]
   [Creatable(CreatableAttribute.Categories.DataAnalysis, Priority = 100)]
   [StorableClass]
@@ -57,5 +58,5 @@
 
     #region parameter names
-    private const string DistanceParameterName = "DistanceFunction";
+    private const string DistanceFunctionParameterName = "DistanceFunction";
     private const string PerplexityParameterName = "Perplexity";
     private const string ThetaParameterName = "Theta";
@@ -69,5 +70,5 @@
     private const string SetSeedRandomlyParameterName = "SetSeedRandomly";
     private const string SeedParameterName = "Seed";
-    private const string ClassesParameterName = "ClassNames";
+    private const string ClassesNameParameterName = "ClassesName";
     private const string NormalizationParameterName = "Normalization";
     private const string UpdateIntervalParameterName = "UpdateInterval";
@@ -86,12 +87,12 @@
       get { return Parameters[PerplexityParameterName] as IFixedValueParameter<DoubleValue>; }
     }
-    public IFixedValueParameter<DoubleValue> ThetaParameter {
-      get { return Parameters[ThetaParameterName] as IFixedValueParameter<DoubleValue>; }
+    public IFixedValueParameter<PercentValue> ThetaParameter {
+      get { return Parameters[ThetaParameterName] as IFixedValueParameter<PercentValue>; }
     }
     public IFixedValueParameter<IntValue> NewDimensionsParameter {
       get { return Parameters[NewDimensionsParameterName] as IFixedValueParameter<IntValue>; }
     }
-    public IValueParameter<IDistance<double[]>> DistanceParameter {
-      get { return Parameters[DistanceParameterName] as IValueParameter<IDistance<double[]>>; }
+    public IConstrainedValueParameter<IDistance<double[]>> DistanceFunctionParameter {
+      get { return Parameters[DistanceFunctionParameterName] as IConstrainedValueParameter<IDistance<double[]>>; }
     }
     public IFixedValueParameter<IntValue> MaxIterationsParameter {
@@ -119,6 +120,6 @@
       get { return Parameters[SeedParameterName] as IFixedValueParameter<IntValue>; }
     }
-    public IFixedValueParameter<StringValue> ClassesParameter {
-      get { return Parameters[ClassesParameterName] as IFixedValueParameter<StringValue>; }
+    public IConstrainedValueParameter<StringValue> ClassesNameParameter {
+      get { return Parameters[ClassesNameParameterName] as IConstrainedValueParameter<StringValue>; }
     }
     public IFixedValueParameter<BoolValue> NormalizationParameter {
@@ -131,6 +132,6 @@
 
     #region  Properties
-    public IDistance<double[]> Distance {
-      get { return DistanceParameter.Value; }
+    public IDistance<double[]> DistanceFunction {
+      get { return DistanceFunctionParameter.Value; }
     }
     public double Perplexity {
@@ -178,7 +179,7 @@
       set { SeedParameter.Value.Value = value; }
     }
-    public string Classes {
-      get { return ClassesParameter.Value.Value; }
-      set { ClassesParameter.Value.Value = value; }
+    public string ClassesName {
+      get { return ClassesNameParameter.Value != null ? ClassesNameParameter.Value.Value : null; }
+      set { ClassesNameParameter.Value.Value = value; }
     }
     public bool Normalization {
@@ -198,6 +199,6 @@
 
     private TSNEAlgorithm(TSNEAlgorithm original, Cloner cloner) : base(original, cloner) {
-      if(original.dataRowNames!=null)
-      this.dataRowNames = new Dictionary<string, List<int>>(original.dataRowNames);
+      if (original.dataRowNames != null)
+        this.dataRowNames = new Dictionary<string, List<int>>(original.dataRowNames);
       if (original.dataRows != null)
         this.dataRows = original.dataRows.ToDictionary(kvp => kvp.Key, kvp => cloner.Clone(kvp.Value));
@@ -208,13 +209,13 @@
     public override IDeepCloneable Clone(Cloner cloner) { return new TSNEAlgorithm(this, cloner); }
     public TSNEAlgorithm() {
-      Problem = new RegressionProblem();
-      Parameters.Add(new ValueParameter<IDistance<double[]>>(DistanceParameterName, "The distance function used to differentiate similar from non-similar points", new EuclideanDistance()));
+      var distances = new ItemSet<IDistance<double[]>>(ApplicationManager.Manager.GetInstances<IDistance<double[]>>());
+      Parameters.Add(new ConstrainedValueParameter<IDistance<double[]>>(DistanceFunctionParameterName, "The distance function used to differentiate similar from non-similar points", distances, distances.OfType<EuclideanDistance>().FirstOrDefault()));
       Parameters.Add(new FixedValueParameter<DoubleValue>(PerplexityParameterName, "Perplexity-parameter of tSNE. Comparable to k in a k-nearest neighbour algorithm. Recommended value is floor(number of points /3) or lower", new DoubleValue(25)));
-      Parameters.Add(new FixedValueParameter<DoubleValue>(ThetaParameterName, "Value describing how much appoximated " +
+      Parameters.Add(new FixedValueParameter<PercentValue>(ThetaParameterName, "Value describing how much appoximated " +
                                                                               "gradients my differ from exact gradients. Set to 0 for exact calculation and in [0,1] otherwise. " +
                                                                               "Appropriate values for theta are between 0.1 and 0.7 (default = 0.5). CAUTION: exact calculation of " +
                                                                               "forces requires building a non-sparse N*N matrix where N is the number of data points. This may " +
                                                                               "exceed memory limitations. The function is designed to run on large (N > 5000) data sets. It may give" +
-                                                                              " poor performance on very small data sets(it is better to use a standard t - SNE implementation on such data).", new DoubleValue(0)));
+                                                                              " poor performance on very small data sets(it is better to use a standard t - SNE implementation on such data).", new PercentValue(0)));
       Parameters.Add(new FixedValueParameter<IntValue>(NewDimensionsParameterName, "Dimensionality of projected space (usually 2 for easy visual analysis)", new IntValue(2)));
       Parameters.Add(new FixedValueParameter<IntValue>(MaxIterationsParameterName, "Maximum number of iterations for gradient descent.", new IntValue(1000)));
@@ -226,7 +227,7 @@
       Parameters.Add(new FixedValueParameter<BoolValue>(SetSeedRandomlyParameterName, "If the seed should be random.", new BoolValue(true)));
       Parameters.Add(new FixedValueParameter<IntValue>(SeedParameterName, "The seed used if it should not be random.", new IntValue(0)));
-      Parameters.Add(new FixedValueParameter<StringValue>(ClassesParameterName, "name of the column specifying the class lables of each data point. If the label column can not be found training/test is used as labels.", new StringValue("none")));
+      Parameters.Add(new OptionalConstrainedValueParameter<StringValue>(ClassesNameParameterName, "Name of the column specifying the class lables of each data point. If this is not set training/test is used as labels."));
       Parameters.Add(new FixedValueParameter<BoolValue>(NormalizationParameterName, "Whether the data should be zero centered and have variance of 1 for each variable, so different scalings are ignored.", new BoolValue(true)));
-      Parameters.Add(new FixedValueParameter<IntValue>(UpdateIntervalParameterName, "", new IntValue(50)));
+      Parameters.Add(new FixedValueParameter<IntValue>(UpdateIntervalParameterName, "The interval after which the results will be updated.", new IntValue(50)));
       Parameters[UpdateIntervalParameterName].Hidden = true;
 
@@ -236,4 +237,5 @@
       StopLyingIterationParameter.Hidden = true;
       EtaParameter.Hidden = false;
+      Problem = new RegressionProblem();
     }
     #endregion
@@ -269,5 +271,5 @@
         if (Normalization) data = NormalizeData(data);
 
-        state = TSNEStatic<double[]>.CreateState(data, Distance, random, NewDimensions, Perplexity, Theta,
+        state = TSNEStatic<double[]>.CreateState(data, DistanceFunction, random, NewDimensions, Perplexity, Theta,
           StopLyingIteration, MomentumSwitchIteration, InitialMomentum, FinalMomentum, Eta);
 
@@ -283,4 +285,30 @@
     }
 
+    #region Events
+    protected override void OnProblemChanged() {
+      base.OnProblemChanged();
+      if (Problem == null) return;
+      OnProblemDataChanged(this, null);
+    }
+
+    protected override void RegisterProblemEvents() {
+      base.RegisterProblemEvents();
+      Problem.ProblemDataChanged += OnProblemDataChanged;
+    }
+    protected override void DeregisterProblemEvents() {
+      base.DeregisterProblemEvents();
+      Problem.ProblemDataChanged -= OnProblemDataChanged;
+    }
+
+    private void OnProblemDataChanged(object sender, EventArgs args) {
+      if (Problem == null || Problem.ProblemData == null) return;
+      if (!Parameters.ContainsKey(ClassesNameParameterName)) return;
+      ClassesNameParameter.ValidValues.Clear();
+      foreach (var input in Problem.ProblemData.InputVariables) ClassesNameParameter.ValidValues.Add(input);
+    }
+
+    #endregion
+
+    #region Helpers
     private void SetUpResults(IReadOnlyCollection<double[]> data) {
       if (Results == null) return;
@@ -291,13 +319,13 @@
 
       //color datapoints acording to classes variable (be it double or string)
-      if (problemData.Dataset.VariableNames.Contains(Classes)) {
-        if ((problemData.Dataset as Dataset).VariableHasType<string>(Classes)) {
-          var classes = problemData.Dataset.GetStringValues(Classes).ToArray();
+      if (problemData.Dataset.VariableNames.Contains(ClassesName)) {
+        if ((problemData.Dataset as Dataset).VariableHasType<string>(ClassesName)) {
+          var classes = problemData.Dataset.GetStringValues(ClassesName).ToArray();
           for (var i = 0; i < classes.Length; i++) {
             if (!dataRowNames.ContainsKey(classes[i])) dataRowNames.Add(classes[i], new List<int>());
             dataRowNames[classes[i]].Add(i);
           }
-        } else if ((problemData.Dataset as Dataset).VariableHasType<double>(Classes)) {
-          var classValues = problemData.Dataset.GetDoubleValues(Classes).ToArray();
+        } else if ((problemData.Dataset as Dataset).VariableHasType<double>(ClassesName)) {
+          var classValues = problemData.Dataset.GetDoubleValues(ClassesName).ToArray();
           var max = classValues.Max() + 0.1;
           var min = classValues.Min() - 0.1;
@@ -377,5 +405,8 @@
       for (var i = 0; i < data.GetLength(0); i++) {
         for (var j = 0; j < data.GetLength(1); j++) {
-          res[i, j] = (data[i, j] - (max[j] + min[j]) / 2) / (max[j] - min[j]);
+          var d = max[j] - min[j];
+          var s = data[i, j] - (max[j] + min[j]) / 2;  //shift data
+          if (d.IsAlmost(0)) res[i, j] = data[i, j];   //no scaling possible
+          else res[i, j] = s / d;  //scale data
         }
       }
@@ -395,5 +426,5 @@
       for (var i = 0; i < data.Count; i++) {
         nData[i] = new double[n];
-        for (var j = 0; j < n; j++) nData[i][j] = (data[i][j] - mean[j]) / max[j];
+        for (var j = 0; j < n; j++) nData[i][j] = max[j].IsAlmost(0) ? data[i][j] - mean[j] : (data[i][j] - mean[j]) / max[j];
       }
       return nData;
@@ -416,4 +447,5 @@
       return "[" + (min + i * size) + ";" + (min + (i + 1) * size) + ")";
     }
+    #endregion
   }
 }
