Index: /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessCovarianceOptimizationProblem.cs
===================================================================
--- /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessCovarianceOptimizationProblem.cs	(revision 13199)
+++ /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessCovarianceOptimizationProblem.cs	(revision 13200)
@@ -138,4 +138,15 @@
       get { return true; } // return log likelihood (instead of negative log likelihood as in GPR
     }
+
+    // problem stores a few variables for information exchange from Evaluate() to Analyze()
+    private object problemStateLocker = new object();
+    [Storable]
+    private double bestQ;
+    [Storable]
+    private double[] bestHyperParameters;
+    [Storable]
+    private IMeanFunction meanFunc;
+    [Storable]
+    private ICovarianceFunction covFunc;
 
     public GaussianProcessCovarianceOptimizationProblem()
@@ -173,4 +184,11 @@
     }
 
+    protected override void OnReset() {
+      base.OnReset();
+      meanFunc = null;
+      covFunc = null;
+      bestQ = double.NegativeInfinity;
+      bestHyperParameters = null;
+    }
 
     public override double Evaluate(ISymbolicExpressionTree tree, IRandom random) {
@@ -231,5 +249,19 @@
       }
 
+      UpdateBestSoFar(bestObjValue[0], bestHyperParameters, meanFunction, covarianceFunction);
+
       return bestObjValue[0];
+    }
+
+    // updates the overall best quality and overall best model for Analyze()
+    private void UpdateBestSoFar(double bestQ, double[] bestHyperParameters, IMeanFunction meanFunc, ICovarianceFunction covFunc) {
+      lock (problemStateLocker) {
+        if (bestQ > this.bestQ) {
+          this.bestQ = bestQ;
+          this.bestHyperParameters = bestHyperParameters;
+          this.meanFunc = meanFunc;
+          this.covFunc = covFunc;
+        }
+      }
     }
 
@@ -252,57 +284,20 @@
         results["Best Tree"].Value = bestClone;
         results["Best Solution Quality"].Value = new DoubleValue(bestQuality);
-        results["Best Solution"].Value = CreateSolution(bestClone, random);
-      }
-    }
-
-    private IItem CreateSolution(ISymbolicExpressionTree tree, IRandom random) {
-      // again tune the hyper-parameters.
-      // this is suboptimal because 1) more effort and 2) we cannot be sure to find the same local optimum
-      var meanFunction = new MeanConst();
+        results["Best Solution"].Value = CreateSolution();
+      }
+    }
+
+    private IItem CreateSolution() {
       var problemData = ProblemData;
       var ds = problemData.Dataset;
       var targetVariable = problemData.TargetVariable;
       var allowedInputVariables = problemData.AllowedInputVariables.ToArray();
-      var nVars = allowedInputVariables.Length;
       var trainingRows = problemData.TrainingIndices.ToArray();
-      var bestObjValue = new double[1] { double.MinValue };
-
-      // use the same covariance function for each restart
-      var covarianceFunction = TreeToCovarianceFunction(tree);
-      // data that is necessary for the objective function
-      var data = Tuple.Create(ds, targetVariable, allowedInputVariables, trainingRows, (IMeanFunction)meanFunction, covarianceFunction, bestObjValue);
-
-      // allocate hyperparameters
-      var hyperParameters = new double[meanFunction.GetNumberOfParameters(nVars) + covarianceFunction.GetNumberOfParameters(nVars) + 1]; // mean + cov + noise
-
-      // initialize hyperparameters
-      hyperParameters[0] = ds.GetDoubleValues(targetVariable).Average(); // mean const
-
-      for (int i = 0; i < covarianceFunction.GetNumberOfParameters(nVars); i++) {
-        hyperParameters[1 + i] = random.NextDouble() * 2.0 - 1.0;
-      }
-      hyperParameters[hyperParameters.Length - 1] = 1.0; // s² = exp(2), TODO: other inits better?
-
-      // use alglib.bfgs for hyper-parameter optimization ...
-      double epsg = 0;
-      double epsf = 0.00001;
-      double epsx = 0;
-      double stpmax = 1;
-      int maxits = ConstantOptIterations;
-      alglib.mincgstate state;
-      alglib.mincgreport rep;
-
-      alglib.mincgcreate(hyperParameters, out state);
-      alglib.mincgsetcond(state, epsg, epsf, epsx, maxits);
-      alglib.mincgsetstpmax(state, stpmax);
-      alglib.mincgoptimize(state, ObjectiveFunction, null, data);
-
-      alglib.mincgresults(state, out hyperParameters, out rep);
-
-      if (rep.terminationtype >= 0) {
-
-        var model = new GaussianProcessModel(ds, targetVariable, allowedInputVariables, trainingRows, hyperParameters, meanFunction, covarianceFunction);
-        return model.CreateRegressionSolution(ProblemData);
-      } else return null;
+
+      lock (problemStateLocker) {
+        var model = new GaussianProcessModel(ds, targetVariable, allowedInputVariables, trainingRows, bestHyperParameters, (IMeanFunction)meanFunc.Clone(), (ICovarianceFunction)covFunc.Clone());
+        model.FixParameters();
+        return model.CreateRegressionSolution((IRegressionProblemData)ProblemData.Clone());
+      }
     }
 
@@ -387,4 +382,11 @@
     private GaussianProcessCovarianceOptimizationProblem(GaussianProcessCovarianceOptimizationProblem original, Cloner cloner)
       : base(original, cloner) {
+      bestQ = original.bestQ;
+      meanFunc = cloner.Clone(original.meanFunc);
+      covFunc = cloner.Clone(original.covFunc);
+      if (bestHyperParameters != null) {
+        bestHyperParameters = new double[original.bestHyperParameters.Length];
+        Array.Copy(original.bestHyperParameters, bestHyperParameters, bestHyperParameters.Length);
+      }
     }
     public override IDeepCloneable Clone(Cloner cloner) {
