Index: trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/GradientBoostedTreesAlgorithm.cs
===================================================================
--- trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/GradientBoostedTreesAlgorithm.cs	(revision 12819)
+++ trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/GradientBoostedTreesAlgorithm.cs	(revision 12868)
@@ -233,7 +233,10 @@
       // produce solution 
       if (CreateSolution) {
+        var surrogateModel = new GradientBoostedTreesModelSurrogate(problemData, (uint)Seed, lossFunction.ToString(),
+          Iterations, MaxSize, R, M, Nu, state.GetModel());
+
         // for logistic regression we produce a classification solution
         if (lossFunction is LogisticRegressionLoss) {
-          var model = new DiscriminantFunctionClassificationModel(state.GetModel(),
+          var model = new DiscriminantFunctionClassificationModel(surrogateModel,
             new AccuracyMaximizationThresholdCalculator());
           var classificationProblemData = new ClassificationProblemData(problemData.Dataset,
@@ -245,5 +248,5 @@
         } else {
           // otherwise we produce a regression solution
-          Results.Add(new Result("Solution", new RegressionSolution(state.GetModel(), problemData)));
+          Results.Add(new Result("Solution", new RegressionSolution(surrogateModel, problemData)));
         }
       }
Index: trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/GradientBoostedTreesModel.cs
===================================================================
--- trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/GradientBoostedTreesModel.cs	(revision 12819)
+++ trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/GradientBoostedTreesModel.cs	(revision 12868)
@@ -34,18 +34,45 @@
   // this is essentially a collection of weighted regression models
   public sealed class GradientBoostedTreesModel : NamedItem, IRegressionModel {
-    [Storable]
+    // BackwardsCompatibility3.4 for allowing deserialization & serialization of old models
+    #region Backwards compatible code, remove with 3.5
+    private bool isCompatibilityLoaded = false; // only set to true if the model is deserialized from the old format, needed to make sure that information is serialized again if it was loaded from the old format
+
+    [Storable(Name = "models")]
+    private IList<IRegressionModel> __persistedModels {
+      set {
+        this.isCompatibilityLoaded = true;
+        this.models.Clear();
+        foreach (var m in value) this.models.Add(m);
+      }
+      get { if (this.isCompatibilityLoaded) return models; else return null; }
+    }
+    [Storable(Name = "weights")]
+    private IList<double> __persistedWeights {
+      set {
+        this.isCompatibilityLoaded = true;
+        this.weights.Clear();
+        foreach (var w in value) this.weights.Add(w);
+      }
+      get { if (this.isCompatibilityLoaded) return weights; else return null; }
+    }
+    #endregion
+
     private readonly IList<IRegressionModel> models;
     public IEnumerable<IRegressionModel> Models { get { return models; } }
 
-    [Storable]
     private readonly IList<double> weights;
     public IEnumerable<double> Weights { get { return weights; } }
 
     [StorableConstructor]
-    private GradientBoostedTreesModel(bool deserializing) : base(deserializing) { }
+    private GradientBoostedTreesModel(bool deserializing)
+      : base(deserializing) {
+      models = new List<IRegressionModel>();
+      weights = new List<double>();
+    }
     private GradientBoostedTreesModel(GradientBoostedTreesModel original, Cloner cloner)
       : base(original, cloner) {
       this.weights = new List<double>(original.weights);
       this.models = new List<IRegressionModel>(original.models.Select(m => cloner.Clone(m)));
+      this.isCompatibilityLoaded = original.isCompatibilityLoaded;
     }
     public GradientBoostedTreesModel(IEnumerable<IRegressionModel> models, IEnumerable<double> weights)
@@ -64,5 +91,5 @@
       // allocate target array go over all models and add up weighted estimation for each row
       if (!rows.Any()) return Enumerable.Empty<double>(); // return immediately if rows is empty. This prevents multiple iteration over lazy rows enumerable.
-                                                          // (which essentially looks up indexes in a dictionary)
+      // (which essentially looks up indexes in a dictionary)
       var res = new double[rows.Count()];
       for (int i = 0; i < models.Count; i++) {
Index: trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/GradientBoostedTreesModelSurrogate.cs
===================================================================
--- trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/GradientBoostedTreesModelSurrogate.cs	(revision 12868)
+++ trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/GradientBoostedTreesModelSurrogate.cs	(revision 12868)
@@ -0,0 +1,116 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ * and the BEACON Center for the Study of Evolution in Action.
+ * 
+ * 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.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.PluginInfrastructure;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  // this class is used as a surrogate for persistence of an actual GBT model 
+  // since the actual GBT model would be very large when persisted we only store all necessary information to
+  // recalculate the actual GBT model on demand
+  [Item("Gradient boosted tree model", "")]
+  public sealed class GradientBoostedTreesModelSurrogate : NamedItem, IRegressionModel {
+    // don't store the actual model!
+    private IRegressionModel actualModel; // the actual model is only recalculated when necessary
+
+    [Storable]
+    private readonly IRegressionProblemData trainingProblemData;
+    [Storable]
+    private readonly uint seed;
+    [Storable]
+    private string lossFunctionName;
+    [Storable]
+    private double r;
+    [Storable]
+    private double m;
+    [Storable]
+    private double nu;
+    [Storable]
+    private int iterations;
+    [Storable]
+    private int maxSize;
+
+
+    [StorableConstructor]
+    private GradientBoostedTreesModelSurrogate(bool deserializing) : base(deserializing) { }
+
+    private GradientBoostedTreesModelSurrogate(GradientBoostedTreesModelSurrogate original, Cloner cloner)
+      : base(original, cloner) {
+      if (original.actualModel != null) this.actualModel = cloner.Clone(original.actualModel);
+
+      this.trainingProblemData = cloner.Clone(original.trainingProblemData);
+      this.seed = original.seed;
+      this.lossFunctionName = original.lossFunctionName;
+      this.iterations = original.iterations;
+      this.maxSize = original.maxSize;
+      this.r = original.r;
+      this.m = original.m;
+      this.nu = original.nu;
+    }
+
+    // create only the surrogate model without an actual model
+    public GradientBoostedTreesModelSurrogate(IRegressionProblemData trainingProblemData, uint seed, string lossFunctionName, int iterations, int maxSize, double r, double m, double nu)
+      : base("Gradient boosted tree model", string.Empty) {
+      this.trainingProblemData = trainingProblemData;
+      this.seed = seed;
+      this.lossFunctionName = lossFunctionName;
+      this.iterations = iterations;
+      this.maxSize = maxSize;
+      this.r = r;
+      this.m = m;
+      this.nu = nu;
+    }
+
+    // wrap an actual model in a surrograte
+    public GradientBoostedTreesModelSurrogate(IRegressionProblemData trainingProblemData, uint seed, string lossFunctionName, int iterations, int maxSize, double r, double m, double nu, IRegressionModel model)
+      : this(trainingProblemData, seed, lossFunctionName, iterations, maxSize, r, m, nu) {
+      this.actualModel = model;
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new GradientBoostedTreesModelSurrogate(this, cloner);
+    }
+
+    // forward message to actual model (recalculate model first if necessary)
+    public IEnumerable<double> GetEstimatedValues(IDataset dataset, IEnumerable<int> rows) {
+      if (actualModel == null) actualModel = RecalculateModel();
+      return actualModel.GetEstimatedValues(dataset, rows);
+    }
+
+    public IRegressionSolution CreateRegressionSolution(IRegressionProblemData problemData) {
+      return new RegressionSolution(this, (IRegressionProblemData)problemData.Clone());
+    }
+
+
+    private IRegressionModel RecalculateModel() {
+      var lossFunction = ApplicationManager.Manager.GetInstances<ILossFunction>().Single(l => l.ToString() == lossFunctionName);
+      return GradientBoostedTreesAlgorithmStatic.TrainGbm(trainingProblemData, lossFunction, maxSize, nu, r, m, iterations, seed).Model;
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/RegressionTreeModel.cs
===================================================================
--- trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/RegressionTreeModel.cs	(revision 12819)
+++ trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/RegressionTreeModel.cs	(revision 12868)
@@ -82,4 +82,5 @@
     [Storable]
     // to prevent storing the references to data caches in nodes
+    // seemingly it is bad (performance-wise) to persist tuples (tuples are used as keys in a dictionary) TODO
     private Tuple<string, double, int, int>[] SerializedTree {
       get { return tree.Select(t => Tuple.Create(t.VarName, t.Val, t.LeftIdx, t.RightIdx)).ToArray(); }
Index: trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/HeuristicLab.Algorithms.DataAnalysis-3.4.csproj
===================================================================
--- trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/HeuristicLab.Algorithms.DataAnalysis-3.4.csproj	(revision 12819)
+++ trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/HeuristicLab.Algorithms.DataAnalysis-3.4.csproj	(revision 12868)
@@ -195,4 +195,5 @@
     <Compile Include="GaussianProcess\GaussianProcessRegressionSolution.cs" />
     <Compile Include="GaussianProcess\ICovarianceFunction.cs" />
+    <Compile Include="GradientBoostedTrees\GradientBoostedTreesModelSurrogate.cs" />
     <Compile Include="GradientBoostedTrees\GradientBoostedTreesAlgorithm.cs" />
     <Compile Include="GradientBoostedTrees\GradientBoostedTreesAlgorithmStatic.cs" />
