Index: branches/DataAnalysis Refactoring/HeuristicLab.Problems.DataAnalysis.Symbolic.Classification/3.4/SymbolicDiscriminantFunctionClassificationSolution.cs
===================================================================
--- branches/DataAnalysis Refactoring/HeuristicLab.Problems.DataAnalysis.Symbolic.Classification/3.4/SymbolicDiscriminantFunctionClassificationSolution.cs	(revision 5717)
+++ branches/DataAnalysis Refactoring/HeuristicLab.Problems.DataAnalysis.Symbolic.Classification/3.4/SymbolicDiscriminantFunctionClassificationSolution.cs	(revision 5736)
@@ -39,4 +39,6 @@
   [Item(Name = "SymbolicDiscriminantFunctionClassificationSolution", Description = "Represents a symbolic classification solution (model + data) and attributes of the solution like accuracy and complexity.")]
   public sealed class SymbolicDiscriminantFunctionClassificationSolution : DiscriminantFunctionClassificationSolution, ISymbolicClassificationSolution {
+    private const string ModelLengthResultName = "ModelLength";
+    private const string ModelDepthResultName = "ModelDepth";
 
     public new ISymbolicDiscriminantFunctionClassificationModel Model {
@@ -52,5 +54,13 @@
       get { return Model; }
     }
+    public int ModelLength {
+      get { return ((IntValue)this[ModelLengthResultName].Value).Value; }
+      private set { ((IntValue)this[ModelLengthResultName].Value).Value = value; }
+    }
 
+    public int ModelDepth {
+      get { return ((IntValue)this[ModelDepthResultName].Value).Value; }
+      private set { ((IntValue)this[ModelDepthResultName].Value).Value = value; }
+    }
     [StorableConstructor]
     private SymbolicDiscriminantFunctionClassificationSolution(bool deserializing) : base(deserializing) { }
@@ -60,4 +70,7 @@
     public SymbolicDiscriminantFunctionClassificationSolution(ISymbolicDiscriminantFunctionClassificationModel model, IClassificationProblemData problemData)
       : base(model, problemData) {
+      Add(new Result(ModelLengthResultName, "Length of the symbolic classification model.", new IntValue()));
+      Add(new Result(ModelDepthResultName, "Depth of the symbolic classification model.", new IntValue()));
+      RecalculateResults();
     }
 
@@ -65,4 +78,83 @@
       return new SymbolicDiscriminantFunctionClassificationSolution(this, cloner);
     }
+
+    protected override void OnModelChanged(EventArgs e) {
+      base.OnModelChanged(e);
+      RecalculateResults();
+    }
+
+    private new void RecalculateResults() {
+      ModelLength = Model.SymbolicExpressionTree.Length;
+      ModelDepth = Model.SymbolicExpressionTree.Depth;
+    }
+
+    public void ScaleModel() {
+      var dataset = ProblemData.Dataset;
+      var targetVariable = ProblemData.TargetVariable;
+      var rows = ProblemData.TrainingIndizes;
+      var estimatedValues = GetEstimatedValues(rows);
+      var targetValues = dataset.GetEnumeratedVariableValues(targetVariable, rows);
+      double alpha;
+      double beta;
+      OnlineLinearScalingParameterCalculator.Calculate(estimatedValues, targetValues, out alpha, out beta);
+
+      ConstantTreeNode alphaTreeNode = null;
+      ConstantTreeNode betaTreeNode = null;
+      // check if model has been scaled previously by analyzing the structure of the tree
+      var startNode = Model.SymbolicExpressionTree.Root.GetSubtree(0);
+      if (startNode.GetSubtree(0).Symbol is Addition) {
+        var addNode = startNode.GetSubtree(0);
+        if (addNode.SubtreesCount == 2 && addNode.GetSubtree(0).Symbol is Multiplication && addNode.GetSubtree(1).Symbol is Constant) {
+          alphaTreeNode = addNode.GetSubtree(1) as ConstantTreeNode;
+          var mulNode = addNode.GetSubtree(0);
+          if (mulNode.SubtreesCount == 2 && mulNode.GetSubtree(1).Symbol is Constant) {
+            betaTreeNode = mulNode.GetSubtree(1) as ConstantTreeNode;
+          }
+        }
+      }
+      // if tree structure matches the structure necessary for linear scaling then reuse the existing tree nodes
+      if (alphaTreeNode != null && betaTreeNode != null) {
+        betaTreeNode.Value *= beta;
+        alphaTreeNode.Value *= beta;
+        alphaTreeNode.Value += alpha;
+      } else {
+        var mainBranch = startNode.GetSubtree(0);
+        startNode.RemoveSubtree(0);
+        var scaledMainBranch = MakeSum(MakeProduct(beta, mainBranch), alpha);
+        startNode.AddSubtree(scaledMainBranch);
+      }
+
+      OnModelChanged(EventArgs.Empty);
+    }
+
+    private static ISymbolicExpressionTreeNode MakeSum(ISymbolicExpressionTreeNode treeNode, double alpha) {
+      if (alpha.IsAlmost(0.0)) {
+        return treeNode;
+      } else {
+        var node = (new Addition()).CreateTreeNode();
+        var alphaConst = MakeConstant(alpha);
+        node.AddSubtree(treeNode);
+        node.AddSubtree(alphaConst);
+        return node;
+      }
+    }
+
+    private static ISymbolicExpressionTreeNode MakeProduct(double beta, ISymbolicExpressionTreeNode treeNode) {
+      if (beta.IsAlmost(1.0)) {
+        return treeNode;
+      } else {
+        var node = (new Multiplication()).CreateTreeNode();
+        var betaConst = MakeConstant(beta);
+        node.AddSubtree(treeNode);
+        node.AddSubtree(betaConst);
+        return node;
+      }
+    }
+
+    private static ISymbolicExpressionTreeNode MakeConstant(double c) {
+      var node = (ConstantTreeNode)(new Constant()).CreateTreeNode();
+      node.Value = c;
+      return node;
+    }
   }
 }
