Index: trunk/sources/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/FeatureSelection/FeatureSelection.cs
===================================================================
--- trunk/sources/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/FeatureSelection/FeatureSelection.cs	(revision 9156)
+++ trunk/sources/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/FeatureSelection/FeatureSelection.cs	(revision 9217)
@@ -24,14 +24,17 @@
 using System.Linq;
 using HeuristicLab.Common;
+using HeuristicLab.Core;
 using HeuristicLab.Random;
 
 namespace HeuristicLab.Problems.Instances.DataAnalysis {
   public class FeatureSelection : ArtificialRegressionDataDescriptor {
-    private int trainingSamples;
-    private const int TestSamples = 5000;
+    private int nTrainingSamples;
+    private int nTestSamples;
 
     private int numberOfFeatures;
     private double selectionProbability;
     private double noiseRatio;
+    private IRandom xRandom;
+    private IRandom weightRandom;
 
     public override string Name { get { return string.Format("FeatSel-{0}-{1:0%}-{2:0%}", numberOfFeatures, selectionProbability, noiseRatio); } }
@@ -39,5 +42,5 @@
       get {
         return "This problem is specifically designed to test feature selection." + Environment.NewLine
-               + "In this instance the number of rows for training (" + trainingSamples +
+               + "In this instance the number of rows for training (" + nTrainingSamples +
                ") is only slightly larger than the number of columns (" + numberOfFeatures +
                ") and only a subset of the columns must be selected for the predictive model." + Environment.NewLine
@@ -47,6 +50,6 @@
                + "X(i,j) ~ N(0, 1) iid, w(i) ~ U(0, 10) iid, n ~ N(0, sigma(w*S) * SQRT(" + noiseRatio + "))" + Environment.NewLine
                + "The noise level is " + noiseRatio + " * sigma, thus an optimal model has R² = "
-               + Math.Round(1 - noiseRatio, 2) + " (or equivalently: NMSE = " + noiseRatio + ")" + Environment.NewLine
-               + "N = " + (trainingSamples + TestSamples) + " (" + trainingSamples + " training, " + TestSamples + " test)" + Environment.NewLine
+               + Math.Round(optimalRSquared) + " (or equivalently: NMSE = " + noiseRatio + ")" + Environment.NewLine
+               + "N = " + (nTrainingSamples + nTestSamples) + " (" + nTrainingSamples + " training, " + nTestSamples + " test)" + Environment.NewLine
                + "k = " + numberOfFeatures;
         ;
@@ -54,9 +57,33 @@
     }
 
-    public FeatureSelection(int numberOfFeatures, double selectionProbability, double noiseRatio) {
+    private double[] w;
+    public double[] Weights {
+      get { return w; }
+    }
+
+    private string[] selectedFeatures;
+    public string[] SelectedFeatures {
+      get { return selectedFeatures; }
+    }
+
+    private double optimalRSquared;
+    public double OptimalRSquared {
+      get { return optimalRSquared; }
+    }
+
+
+    public FeatureSelection(int numberOfFeatures, double selectionProbability, double noiseRatio, IRandom xGenerator, IRandom weightGenerator)
+      : this((int)Math.Round(numberOfFeatures * 1.2), 5000, numberOfFeatures,
+      selectionProbability, noiseRatio, xGenerator, weightGenerator) { }
+
+    public FeatureSelection(int nTrainingSamples, int nTestSamples, int numberOfFeatures,
+      double selectionProbability, double noiseRatio, IRandom xGenerator, IRandom weightGenerator) {
       this.numberOfFeatures = numberOfFeatures;
-      this.trainingSamples = (int)Math.Round(numberOfFeatures * 1.2); // 20% more rows than columns
+      this.nTrainingSamples = nTrainingSamples;
+      this.nTestSamples = nTestSamples;
       this.selectionProbability = selectionProbability;
       this.noiseRatio = noiseRatio;
+      this.xRandom = xGenerator;
+      this.weightRandom = weightGenerator;
     }
 
@@ -74,13 +101,17 @@
       }
     }
+
     protected override int TrainingPartitionStart { get { return 0; } }
-    protected override int TrainingPartitionEnd { get { return trainingSamples; } }
-    protected override int TestPartitionStart { get { return trainingSamples; } }
-    protected override int TestPartitionEnd { get { return trainingSamples + TestSamples; } }
+    protected override int TrainingPartitionEnd { get { return nTrainingSamples; } }
+    protected override int TestPartitionStart { get { return nTrainingSamples; } }
+    protected override int TestPartitionEnd { get { return nTrainingSamples + nTestSamples; } }
+
 
     protected override List<List<double>> GenerateValues() {
       List<List<double>> data = new List<List<double>>();
       for (int i = 0; i < AllowedInputVariables.Count(); i++) {
-        data.Add(ValueGenerator.GenerateNormalDistributedValues(TestPartitionEnd, 0, 1).ToList());
+        data.Add(Enumerable.Range(0, TestPartitionEnd)
+          .Select(_ => xRandom.NextDouble())
+          .ToList());
       }
 
@@ -90,6 +121,6 @@
         .Where(_ => random.NextDouble() < selectionProbability)
         .ToArray();
-      var w = ValueGenerator.GenerateUniformDistributedValues(selectedFeatures.Length, 0, 10)
-        .ToArray();
+
+      w = selectedFeatures.Select(_ => weightRandom.NextDouble()).ToArray();
       var target = new List<double>();
       for (int i = 0; i < data[0].Count; i++) {
@@ -104,4 +135,7 @@
       data.Add(target.Select(t => t + noisePrng.NextDouble()).ToList());
 
+      // set property listing the selected features as string[]
+      this.selectedFeatures = selectedFeatures.Select(i => AllowedInputVariables[i]).ToArray();
+      optimalRSquared = 1 - noiseRatio;
       return data;
     }
Index: trunk/sources/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/FeatureSelection/FeatureSelectionInstanceProvider.cs
===================================================================
--- trunk/sources/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/FeatureSelection/FeatureSelectionInstanceProvider.cs	(revision 9156)
+++ trunk/sources/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/FeatureSelection/FeatureSelectionInstanceProvider.cs	(revision 9217)
@@ -22,4 +22,8 @@
 using System;
 using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Data;
+using HeuristicLab.Problems.DataAnalysis;
+using HeuristicLab.Random;
 
 namespace HeuristicLab.Problems.Instances.DataAnalysis {
@@ -39,16 +43,38 @@
 
     public override IEnumerable<IDataDescriptor> GetDataDescriptors() {
-      List<IDataDescriptor> descriptorList = new List<IDataDescriptor>();
       var sizes = new int[] { 50, 100, 200 };
       var pp = new double[] { 0.1, 0.25, 0.5 };
       var noiseRatios = new double[] { 0.01, 0.05, 0.1, 0.2 };
-      foreach (var size in sizes) {
-        foreach (var p in pp) {
-          foreach (var noiseRatio in noiseRatios) {
-            descriptorList.Add(new FeatureSelection(size, p, noiseRatio));
-          }
-        }
-      }
-      return descriptorList;
+      var mt = new MersenneTwister();
+      var xGenerator = new NormalDistributedRandom(mt, 0, 1);
+      var weightGenerator = new UniformDistributedRandom(mt, 0, 10);
+      return (from size in sizes
+              from p in pp
+              from noiseRatio in noiseRatios
+              select new FeatureSelection(size, p, noiseRatio, xGenerator, weightGenerator))
+              .Cast<IDataDescriptor>()
+              .ToList();
+    }
+
+    public override IRegressionProblemData LoadData(IDataDescriptor descriptor) {
+      var featureSelectionDescriptor = descriptor as FeatureSelection;
+      if (featureSelectionDescriptor == null) throw new ArgumentException("FeatureSelectionInstanceProvider expects an FeatureSelection data descriptor.");
+      // base call generates a regression problem data
+      var regProblemData = base.LoadData(featureSelectionDescriptor);
+      var problemData =
+        new FeatureSelectionRegressionProblemData(
+          regProblemData.Dataset, regProblemData.AllowedInputVariables, regProblemData.TargetVariable,
+          featureSelectionDescriptor.SelectedFeatures, featureSelectionDescriptor.Weights,
+          featureSelectionDescriptor.OptimalRSquared);
+
+      // copy values from regProblemData to feature selection problem data
+      problemData.Name = regProblemData.Name;
+      problemData.Description = regProblemData.Description;
+      problemData.TrainingPartition.Start = regProblemData.TrainingPartition.Start;
+      problemData.TrainingPartition.End = regProblemData.TrainingPartition.End;
+      problemData.TestPartition.Start = regProblemData.TestPartition.Start;
+      problemData.TestPartition.End = regProblemData.TestPartition.End;
+
+      return problemData;
     }
   }
Index: trunk/sources/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/FeatureSelection/FeatureSelectionRegressionProblemData.cs
===================================================================
--- trunk/sources/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/FeatureSelection/FeatureSelectionRegressionProblemData.cs	(revision 9217)
+++ trunk/sources/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/FeatureSelection/FeatureSelectionRegressionProblemData.cs	(revision 9217)
@@ -0,0 +1,81 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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 System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+using HeuristicLab.Random;
+
+namespace HeuristicLab.Problems.Instances.DataAnalysis {
+  public class FeatureSelectionRegressionProblemData : RegressionProblemData {
+    private const string SelectedFeaturesParameterName = "SelectedFeatures";
+    private const string WeightsParameterName = "Weights";
+    private const string OptimalRSquaredParameterName = "R² (best solution)";
+
+    public IValueParameter<StringArray> SelectedFeaturesParameter {
+      get { return (IValueParameter<StringArray>)Parameters[SelectedFeaturesParameterName]; }
+    }
+
+    public IValueParameter<DoubleArray> WeightsParameter {
+      get { return (IValueParameter<DoubleArray>)Parameters[WeightsParameterName]; }
+    }
+
+    public IValueParameter<DoubleValue> OptimalRSquaredParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters[OptimalRSquaredParameterName]; }
+    }
+
+    [StorableConstructor]
+    protected FeatureSelectionRegressionProblemData(bool deserializing)
+      : base(deserializing) {
+    }
+    protected FeatureSelectionRegressionProblemData(FeatureSelectionRegressionProblemData original, Cloner cloner)
+      : base(original, cloner) {
+    }
+
+    public FeatureSelectionRegressionProblemData(Dataset ds, IEnumerable<string> allowedInputVariables, string targetVariable, string[] selectedFeatures, double[] weights, double optimalRSquared)
+      : base(ds, allowedInputVariables, targetVariable) {
+      if (selectedFeatures.Length != weights.Length) throw new ArgumentException("Length of selected features vector does not match the length of the weights vector");
+      if (optimalRSquared < 0 || optimalRSquared > 1) throw new ArgumentException("Optimal R² is not in range [0..1]");
+      Parameters.Add(new FixedValueParameter<StringArray>(
+        SelectedFeaturesParameterName,
+        "Array of features used to generate the target values.",
+        new StringArray(selectedFeatures).AsReadOnly()));
+      Parameters.Add(new FixedValueParameter<DoubleArray>(
+        WeightsParameterName,
+        "Array of weights used to generate the target values.",
+        (DoubleArray)(new DoubleArray(weights).AsReadOnly())));
+      Parameters.Add(new FixedValueParameter<DoubleValue>(
+        OptimalRSquaredParameterName,
+        "R² of the optimal solution.",
+        (DoubleValue)(new DoubleValue(optimalRSquared).AsReadOnly())));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new FeatureSelectionRegressionProblemData(this, cloner);
+    }
+  }
+}
