Index: branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/BinaryFactorVariable.cs
===================================================================
--- branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/BinaryFactorVariable.cs	(revision 14878)
+++ branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/BinaryFactorVariable.cs	(revision 14878)
@@ -0,0 +1,76 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 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.Encodings.SymbolicExpressionTreeEncoding;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+  [StorableClass]
+  [Item("BinaryFactorVariable", "Represents a categorical variable (comparable to factors as in R) and it's value.")]
+  public sealed class BinaryFactorVariable : VariableBase {
+
+    private readonly Dictionary<string, List<string>> variableValues;
+
+    [Storable]
+    public IEnumerable<KeyValuePair<string, List<string>>> VariableValues {
+      get { return variableValues; }
+      set {
+        if (value == null) throw new ArgumentNullException();
+        variableValues.Clear();
+        foreach (var kvp in value) {
+          variableValues.Add(kvp.Key, new List<string>(kvp.Value));
+        }
+      }
+    }
+
+    [StorableConstructor]
+    private BinaryFactorVariable(bool deserializing)
+      : base(deserializing) {
+      variableValues = new Dictionary<string, List<string>>();
+    }
+    private BinaryFactorVariable(BinaryFactorVariable original, Cloner cloner)
+      : base(original, cloner) {
+      variableValues =
+        original.variableValues.ToDictionary(kvp => kvp.Key, kvp => new List<string>(kvp.Value));
+    }
+    public BinaryFactorVariable() : this("BinaryFactorVariable", "Represents a categorical variable (comparable to factors as in R) and it's value.") { }
+    public BinaryFactorVariable(string name, string description)
+      : base(name, description) {
+      variableValues = new Dictionary<string, List<string>>();
+    }
+
+    public override ISymbolicExpressionTreeNode CreateTreeNode() {
+      return new BinaryFactorVariableTreeNode(this);
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new BinaryFactorVariable(this, cloner);
+    }
+
+    public IEnumerable<string> GetVariableValues(string variableName) {
+      return variableValues[variableName];
+    }
+  }
+}
Index: branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/BinaryFactorVariableTreeNode.cs
===================================================================
--- branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/BinaryFactorVariableTreeNode.cs	(revision 14878)
+++ branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/BinaryFactorVariableTreeNode.cs	(revision 14878)
@@ -0,0 +1,84 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Random;
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+  [StorableClass]
+  public sealed class BinaryFactorVariableTreeNode : VariableTreeNodeBase {
+    public new BinaryFactorVariable Symbol {
+      get { return (BinaryFactorVariable)base.Symbol; }
+    }
+
+    [Storable]
+    private string variableValue;
+    public string VariableValue {
+      get { return variableValue; }
+      set { variableValue = value; }
+    }
+
+    [StorableConstructor]
+    private BinaryFactorVariableTreeNode(bool deserializing) : base(deserializing) { }
+    private BinaryFactorVariableTreeNode(BinaryFactorVariableTreeNode original, Cloner cloner)
+      : base(original, cloner) {
+      variableValue = original.variableValue;
+    }
+    public BinaryFactorVariableTreeNode(BinaryFactorVariable variableSymbol) : base(variableSymbol) { }
+
+    public override bool HasLocalParameters {
+      get { return true; }
+    }
+
+    public override void ResetLocalParameters(IRandom random) {
+      base.ResetLocalParameters(random);
+      variableValue = Symbol.GetVariableValues(VariableName).SampleRandom(random);
+    }
+
+    public override void ShakeLocalParameters(IRandom random, double shakingFactor) {
+      // 50% additive & 50% multiplicative (override of functionality of base class because of a BUG)
+      if (random.NextDouble() < 0.5) {
+        double x = NormalDistributedRandom.NextDouble(random, Symbol.WeightManipulatorMu, Symbol.WeightManipulatorSigma);
+        Weight = Weight + x * shakingFactor;
+      } else {
+        double x = NormalDistributedRandom.NextDouble(random, 1.0, Symbol.MultiplicativeWeightManipulatorSigma);
+        Weight = Weight * x;
+      }
+      if (random.NextDouble() < Symbol.VariableChangeProbability) {
+        var oldName = VariableName;
+        VariableName = Symbol.VariableNames.SampleRandom(random);
+        // reinitialize weights if variable has changed (similar to FactorVariableTreeNode)
+        if (oldName != VariableName)
+          Weight = NormalDistributedRandom.NextDouble(random, Symbol.WeightMu, Symbol.WeightSigma);
+      }
+      variableValue = Symbol.GetVariableValues(VariableName).SampleRandom(random);
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new BinaryFactorVariableTreeNode(this, cloner);
+    }
+
+    public override string ToString() {
+      return base.ToString() + " = " + variableValue;
+    }
+  }
+}
Index: branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/FactorVariable.cs
===================================================================
--- branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/FactorVariable.cs	(revision 14878)
+++ branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/FactorVariable.cs	(revision 14878)
@@ -0,0 +1,78 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 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.Encodings.SymbolicExpressionTreeEncoding;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+  [StorableClass]
+  [Item("FactorVariable", "Represents a categorical variable (comparable to factors as in R).")]
+  public sealed class FactorVariable : VariableBase {
+    private readonly Dictionary<string, Dictionary<string, int>> variableValues; // for each variable value also store a zero-based index
+    [Storable]
+    public IEnumerable<KeyValuePair<string, Dictionary<string, int>>> VariableValues {
+      get { return variableValues; }
+      set {
+        if(value == null) throw new ArgumentNullException();
+        variableValues.Clear();
+        foreach(var kvp in value) {
+          variableValues.Add(kvp.Key, new Dictionary<string, int>(kvp.Value));
+        }
+      }
+    }
+
+    [StorableConstructor]
+    private FactorVariable(bool deserializing)
+      : base(deserializing) {
+      variableValues = new Dictionary<string, Dictionary<string, int>>();
+    }
+    private FactorVariable(FactorVariable original, Cloner cloner)
+      : base(original, cloner) {
+      variableValues =
+        original.variableValues.ToDictionary(kvp => kvp.Key, kvp => new Dictionary<string, int>(kvp.Value));
+    }
+    public FactorVariable() : this("FactorVariable", "Represents a categorical variable (comparable to factors as in R).") { }
+    public FactorVariable(string name, string description)
+      : base(name, description) {
+      variableValues = new Dictionary<string, Dictionary<string,int>>();
+    }
+
+    public override ISymbolicExpressionTreeNode CreateTreeNode() {
+      return new FactorVariableTreeNode(this);
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new FactorVariable(this, cloner);
+    }
+
+    public IEnumerable<string> GetVariableValues(string variableName) {
+      return variableValues[variableName].Keys;
+    }
+
+    public int GetIndexForValue(string variableName, string variableValue) {
+      return variableValues[variableName][variableValue];
+    }
+  }
+}
Index: branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/FactorVariableTreeNode.cs
===================================================================
--- branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/FactorVariableTreeNode.cs	(revision 14878)
+++ branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/FactorVariableTreeNode.cs	(revision 14878)
@@ -0,0 +1,116 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 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.Encodings.SymbolicExpressionTreeEncoding;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Random;
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+  [StorableClass]
+  public sealed class FactorVariableTreeNode : SymbolicExpressionTreeTerminalNode, IVariableTreeNode {
+    public new FactorVariable Symbol {
+      get { return (FactorVariable)base.Symbol; }
+    }
+    [Storable]
+    private double[] weights;
+    public double[] Weights {
+      get { return weights; }
+      set { weights = value; }
+    }
+    [Storable]
+    private string variableName;
+    public string VariableName {
+      get { return variableName; }
+      set { variableName = value; }
+    }
+
+    [StorableConstructor]
+    private FactorVariableTreeNode(bool deserializing) : base(deserializing) { }
+    private FactorVariableTreeNode(FactorVariableTreeNode original, Cloner cloner)
+      : base(original, cloner) {
+      variableName = original.variableName;
+      if (original.weights != null) {
+        this.weights = new double[original.Weights.Length];
+        Array.Copy(original.Weights, weights, weights.Length);
+      }
+    }
+
+    public FactorVariableTreeNode(FactorVariable variableSymbol)
+      : base(variableSymbol) {
+    }
+
+    public override bool HasLocalParameters {
+      get { return true; }
+    }
+
+    public override void ResetLocalParameters(IRandom random) {
+      base.ResetLocalParameters(random);
+      variableName = Symbol.VariableNames.SampleRandom(random);
+      weights =
+        Symbol.GetVariableValues(variableName)
+        .Select(_ => NormalDistributedRandom.NextDouble(random, 0, 1)).ToArray();
+    }
+
+    public override void ShakeLocalParameters(IRandom random, double shakingFactor) {
+      // mutate only one randomly selected weight
+      var idx = random.Next(weights.Length);
+      // 50% additive & 50% multiplicative
+      if (random.NextDouble() < 0.5) {
+        double x = NormalDistributedRandom.NextDouble(random, Symbol.WeightManipulatorMu,
+          Symbol.WeightManipulatorSigma);
+        weights[idx] = weights[idx] + x * shakingFactor;
+      } else {
+        double x = NormalDistributedRandom.NextDouble(random, 1.0, Symbol.MultiplicativeWeightManipulatorSigma);
+        weights[idx] = weights[idx] * x;
+      }
+      if (random.NextDouble() < Symbol.VariableChangeProbability) {
+        VariableName = Symbol.VariableNames.SampleRandom(random);
+        if (weights.Length != Symbol.GetVariableValues(VariableName).Count()) {
+          // if the length of the weight array does not match => re-initialize weights
+          weights =
+            Symbol.GetVariableValues(variableName)
+              .Select(_ => NormalDistributedRandom.NextDouble(random, 0, 1))
+              .ToArray();
+        }
+      }
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new FactorVariableTreeNode(this, cloner);
+    }
+
+    public double GetValue(string cat) {
+      return weights[Symbol.GetIndexForValue(VariableName, cat)];
+    }
+
+    public override string ToString() {
+      var weightStr = string.Join("; ",
+        Symbol.GetVariableValues(VariableName).Select(value => value + ": " + GetValue(value).ToString("E4")));
+      return VariableName + " (factor) "
+        + "[" + weightStr + "]";
+    }
+  }
+}
+
Index: branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/LaggedVariable.cs
===================================================================
--- branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/LaggedVariable.cs	(revision 14576)
+++ branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/LaggedVariable.cs	(revision 14878)
@@ -27,5 +27,5 @@
   [StorableClass]
   [Item("LaggedVariable", "Represents a variable value with a time offset.")]
-  public class LaggedVariable : Variable {
+  public class LaggedVariable : VariableBase {
     [Storable]
     private int minLag;
Index: branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/LaggedVariableTreeNode.cs
===================================================================
--- branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/LaggedVariableTreeNode.cs	(revision 14576)
+++ branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/LaggedVariableTreeNode.cs	(revision 14878)
@@ -26,5 +26,5 @@
 namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
   [StorableClass]
-  public sealed class LaggedVariableTreeNode : VariableTreeNode, ILaggedTreeNode {
+  public sealed class LaggedVariableTreeNode : VariableTreeNodeBase, ILaggedTreeNode {
     public new LaggedVariable Symbol {
       get { return (LaggedVariable)base.Symbol; }
Index: branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/Variable.cs
===================================================================
--- branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/Variable.cs	(revision 14576)
+++ branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/Variable.cs	(revision 14878)
@@ -20,6 +20,4 @@
 #endregion
 
-using System;
-using System.Collections.Generic;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -29,143 +27,15 @@
   [StorableClass]
   [Item("Variable", "Represents a variable value.")]
-  public class Variable : Symbol {
-    #region Properties
-    [Storable]
-    private double weightMu;
-    public double WeightMu {
-      get { return weightMu; }
-      set {
-        if (value != weightMu) {
-          weightMu = value;
-          OnChanged(EventArgs.Empty);
-        }
-      }
-    }
-    [Storable]
-    private double weightSigma;
-    public double WeightSigma {
-      get { return weightSigma; }
-      set {
-        if (weightSigma < 0.0) throw new ArgumentException("Negative sigma is not allowed.");
-        if (value != weightSigma) {
-          weightSigma = value;
-          OnChanged(EventArgs.Empty);
-        }
-      }
-    }
-    [Storable]
-    private double weightManipulatorMu;
-    public double WeightManipulatorMu {
-      get { return weightManipulatorMu; }
-      set {
-        if (value != weightManipulatorMu) {
-          weightManipulatorMu = value;
-          OnChanged(EventArgs.Empty);
-        }
-      }
-    }
-    [Storable]
-    private double weightManipulatorSigma;
-    public double WeightManipulatorSigma {
-      get { return weightManipulatorSigma; }
-      set {
-        if (weightManipulatorSigma < 0.0) throw new ArgumentException("Negative sigma is not allowed.");
-        if (value != weightManipulatorSigma) {
-          weightManipulatorSigma = value;
-          OnChanged(EventArgs.Empty);
-        }
-      }
-    }
-    [Storable(DefaultValue = 0.0)]
-    private double multiplicativeWeightManipulatorSigma;
-    public double MultiplicativeWeightManipulatorSigma {
-      get { return multiplicativeWeightManipulatorSigma; }
-      set {
-        if (multiplicativeWeightManipulatorSigma < 0.0) throw new ArgumentException("Negative sigma is not allowed.");
-        if (value != multiplicativeWeightManipulatorSigma) {
-          multiplicativeWeightManipulatorSigma = value;
-          OnChanged(EventArgs.Empty);
-        }
-      }
-    }
-    private List<string> variableNames;
-    [Storable]
-    public IEnumerable<string> VariableNames {
-      get { return variableNames; }
-      set {
-        if (value == null) throw new ArgumentNullException();
-        variableNames.Clear();
-        variableNames.AddRange(value);
-        OnChanged(EventArgs.Empty);
-      }
-    }
-
-    private List<string> allVariableNames;
-    [Storable]
-    public IEnumerable<string> AllVariableNames {
-      get { return allVariableNames; }
-      set {
-        if (value == null) throw new ArgumentNullException();
-        allVariableNames.Clear();
-        allVariableNames.AddRange(value);
-      }
-    }
-
-    public override bool Enabled {
-      get {
-        if (variableNames.Count == 0) return false;
-        return base.Enabled;
-      }
-      set {
-        if (variableNames.Count == 0) base.Enabled = false;
-        else base.Enabled = value;
-      }
-    }
-
-    private const int minimumArity = 0;
-    private const int maximumArity = 0;
-
-    public override int MinimumArity {
-      get { return minimumArity; }
-    }
-    public override int MaximumArity {
-      get { return maximumArity; }
-    }
-    #endregion
-
-    [StorableHook(HookType.AfterDeserialization)]
-    private void AfterDeserialization() {
-      if (allVariableNames == null || (allVariableNames.Count == 0 && variableNames.Count > 0)) {
-        allVariableNames = variableNames;
-      }
-    }
+  public sealed class Variable : VariableBase {
 
     [StorableConstructor]
-    protected Variable(bool deserializing)
+    private Variable(bool deserializing)
       : base(deserializing) {
-      variableNames = new List<string>();
-      allVariableNames = new List<string>();
     }
-    protected Variable(Variable original, Cloner cloner)
+    private Variable(Variable original, Cloner cloner)
       : base(original, cloner) {
-      weightMu = original.weightMu;
-      weightSigma = original.weightSigma;
-      variableNames = new List<string>(original.variableNames);
-      allVariableNames = new List<string>(original.allVariableNames);
-      weightManipulatorMu = original.weightManipulatorMu;
-      weightManipulatorSigma = original.weightManipulatorSigma;
-      multiplicativeWeightManipulatorSigma = original.multiplicativeWeightManipulatorSigma;
     }
-    public Variable() : this("Variable", "Represents a variable value.") { }
-    public Variable(string name, string description)
-      : base(name, description) {
-      weightMu = 1.0;
-      weightSigma = 1.0;
-      weightManipulatorMu = 0.0;
-      weightManipulatorSigma = 0.05;
-      multiplicativeWeightManipulatorSigma = 0.03;
-      variableNames = new List<string>();
-      allVariableNames = new List<string>();
-    }
+    public Variable() : base("Variable", "Represents a variable value.") { }
+    public Variable(string name, string description) : base(name, description) { }
 
     public override ISymbolicExpressionTreeNode CreateTreeNode() {
Index: branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/VariableBase.cs
===================================================================
--- branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/VariableBase.cs	(revision 14878)
+++ branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/VariableBase.cs	(revision 14878)
@@ -0,0 +1,182 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 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 HeuristicLab.Common;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+  [StorableClass]
+  public abstract class VariableBase : Symbol, IVariableSymbol {
+    #region Properties
+    [Storable]
+    private double weightMu;
+    public double WeightMu {
+      get { return weightMu; }
+      set {
+        if (value != weightMu) {
+          weightMu = value;
+          OnChanged(EventArgs.Empty);
+        }
+      }
+    }
+    [Storable]
+    private double weightSigma;
+    public double WeightSigma {
+      get { return weightSigma; }
+      set {
+        if (weightSigma < 0.0) throw new ArgumentException("Negative sigma is not allowed.");
+        if (value != weightSigma) {
+          weightSigma = value;
+          OnChanged(EventArgs.Empty);
+        }
+      }
+    }
+    [Storable]
+    private double weightManipulatorMu;
+    public double WeightManipulatorMu {
+      get { return weightManipulatorMu; }
+      set {
+        if (value != weightManipulatorMu) {
+          weightManipulatorMu = value;
+          OnChanged(EventArgs.Empty);
+        }
+      }
+    }
+    [Storable]
+    private double weightManipulatorSigma;
+    public double WeightManipulatorSigma {
+      get { return weightManipulatorSigma; }
+      set {
+        if (weightManipulatorSigma < 0.0) throw new ArgumentException("Negative sigma is not allowed.");
+        if (value != weightManipulatorSigma) {
+          weightManipulatorSigma = value;
+          OnChanged(EventArgs.Empty);
+        }
+      }
+    }
+    [Storable(DefaultValue = 0.0)]
+    private double multiplicativeWeightManipulatorSigma;
+    public double MultiplicativeWeightManipulatorSigma {
+      get { return multiplicativeWeightManipulatorSigma; }
+      set {
+        if (multiplicativeWeightManipulatorSigma < 0.0) throw new ArgumentException("Negative sigma is not allowed.");
+        if (value != multiplicativeWeightManipulatorSigma) {
+          multiplicativeWeightManipulatorSigma = value;
+          OnChanged(EventArgs.Empty);
+        }
+      }
+    }
+
+    [Storable(DefaultValue = 1.0)]
+    private double variableChangeProbability;
+
+    public double VariableChangeProbability {
+      get { return variableChangeProbability; }
+      set {
+        if (value < 0 || value > 1.0) throw new ArgumentException("Variable change probability must lie in the interval [0..1]");
+        variableChangeProbability = value;
+      }
+    }
+
+    private List<string> variableNames;
+    [Storable]
+    public IEnumerable<string> VariableNames {
+      get { return variableNames; }
+      set {
+        if (value == null) throw new ArgumentNullException();
+        variableNames.Clear();
+        variableNames.AddRange(value);
+        OnChanged(EventArgs.Empty);
+      }
+    }
+
+    private List<string> allVariableNames;
+    [Storable]
+    public IEnumerable<string> AllVariableNames {
+      get { return allVariableNames; }
+      set {
+        if (value == null) throw new ArgumentNullException();
+        allVariableNames.Clear();
+        allVariableNames.AddRange(value);
+      }
+    }
+
+    public override bool Enabled {
+      get {
+        if (variableNames.Count == 0) return false;
+        return base.Enabled;
+      }
+      set {
+        if (variableNames.Count == 0) base.Enabled = false;
+        else base.Enabled = value;
+      }
+    }
+
+    private const int minimumArity = 0;
+    private const int maximumArity = 0;
+
+    public override int MinimumArity {
+      get { return minimumArity; }
+    }
+    public override int MaximumArity {
+      get { return maximumArity; }
+    }
+    #endregion
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      if (allVariableNames == null || (allVariableNames.Count == 0 && variableNames.Count > 0)) {
+        allVariableNames = variableNames;
+      }
+    }
+
+    [StorableConstructor]
+    protected VariableBase(bool deserializing)
+      : base(deserializing) {
+      variableNames = new List<string>();
+      allVariableNames = new List<string>();
+    }
+    protected VariableBase(VariableBase original, Cloner cloner)
+      : base(original, cloner) {
+      weightMu = original.weightMu;
+      weightSigma = original.weightSigma;
+      variableNames = new List<string>(original.variableNames);
+      allVariableNames = new List<string>(original.allVariableNames);
+      weightManipulatorMu = original.weightManipulatorMu;
+      weightManipulatorSigma = original.weightManipulatorSigma;
+      multiplicativeWeightManipulatorSigma = original.multiplicativeWeightManipulatorSigma;
+      variableChangeProbability = original.variableChangeProbability;
+    }
+    protected VariableBase(string name, string description)
+      : base(name, description) {
+      weightMu = 1.0;
+      weightSigma = 1.0;
+      weightManipulatorMu = 0.0;
+      weightManipulatorSigma = 0.05;
+      multiplicativeWeightManipulatorSigma = 0.03;
+      variableChangeProbability = 0.2;
+      variableNames = new List<string>();
+      allVariableNames = new List<string>();
+    }
+  }
+}
Index: branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/VariableCondition.cs
===================================================================
--- branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/VariableCondition.cs	(revision 14576)
+++ branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/VariableCondition.cs	(revision 14878)
@@ -30,5 +30,5 @@
   [StorableClass]
   [Item("Variable Condition", "Represents a condition that tests a given variable against a specified threshold.")]
-  public sealed class VariableCondition : Symbol {
+  public sealed class VariableCondition : Symbol, IVariableSymbol {
     #region properties
     [Storable]
Index: branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/VariableConditionTreeNode.cs
===================================================================
--- branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/VariableConditionTreeNode.cs	(revision 14576)
+++ branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/VariableConditionTreeNode.cs	(revision 14878)
@@ -29,5 +29,5 @@
 namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
   [StorableClass]
-  public sealed class VariableConditionTreeNode : SymbolicExpressionTreeNode {
+  public sealed class VariableConditionTreeNode : SymbolicExpressionTreeNode, IVariableTreeNode {
     #region properties
     public new VariableCondition Symbol {
Index: branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/VariableTreeNode.cs
===================================================================
--- branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/VariableTreeNode.cs	(revision 14576)
+++ branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/VariableTreeNode.cs	(revision 14878)
@@ -21,73 +21,22 @@
 
 using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-using HeuristicLab.Random;
 namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
   [StorableClass]
-  public class VariableTreeNode : SymbolicExpressionTreeTerminalNode {
+  public sealed class VariableTreeNode : VariableTreeNodeBase {
     public new Variable Symbol {
       get { return (Variable)base.Symbol; }
     }
-    [Storable]
-    private double weight;
-    public double Weight {
-      get { return weight; }
-      set { weight = value; }
+    [StorableConstructor]
+    private VariableTreeNode(bool deserializing) : base(deserializing) { }
+    private VariableTreeNode(VariableTreeNode original, Cloner cloner)
+      : base(original, cloner) {
     }
-    [Storable]
-    private string variableName;
-    public string VariableName {
-      get { return variableName; }
-      set { variableName = value; }
-    }
-
-    [StorableConstructor]
-    protected VariableTreeNode(bool deserializing) : base(deserializing) { }
-    protected VariableTreeNode(VariableTreeNode original, Cloner cloner)
-      : base(original, cloner) {
-      weight = original.weight;
-      variableName = original.variableName;
-    }
-    protected VariableTreeNode() { }
+    private VariableTreeNode() { }
     public VariableTreeNode(Variable variableSymbol) : base(variableSymbol) { }
-
-    public override bool HasLocalParameters {
-      get { return true; }
-    }
-
-    public override void ResetLocalParameters(IRandom random) {
-      base.ResetLocalParameters(random);
-      weight = NormalDistributedRandom.NextDouble(random, Symbol.WeightMu, Symbol.WeightSigma);
-
-#pragma warning disable 612, 618
-      variableName = Symbol.VariableNames.SelectRandom(random);
-#pragma warning restore 612, 618
-    }
-
-    public override void ShakeLocalParameters(IRandom random, double shakingFactor) {
-      base.ShakeLocalParameters(random, shakingFactor);
-      // 50% additive & 50% multiplicative
-      if (random.NextDouble() < 0) {
-        double x = NormalDistributedRandom.NextDouble(random, Symbol.WeightManipulatorMu, Symbol.WeightManipulatorSigma);
-        weight = weight + x * shakingFactor;
-      } else {
-        double x = NormalDistributedRandom.NextDouble(random, 1.0, Symbol.MultiplicativeWeightManipulatorSigma);
-        weight = weight * x;
-      }
-#pragma warning disable 612, 618
-      variableName = Symbol.VariableNames.SelectRandom(random);
-#pragma warning restore 612, 618
-    }
 
     public override IDeepCloneable Clone(Cloner cloner) {
       return new VariableTreeNode(this, cloner);
     }
-
-    public override string ToString() {
-      if (weight.IsAlmost(1.0)) return variableName;
-      else return weight.ToString("E4") + " " + variableName;
-    }
   }
 }
Index: branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/VariableTreeNodeBase.cs
===================================================================
--- branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/VariableTreeNodeBase.cs	(revision 14878)
+++ branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/VariableTreeNodeBase.cs	(revision 14878)
@@ -0,0 +1,103 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Random;
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+  [StorableClass]
+  public abstract class VariableTreeNodeBase : SymbolicExpressionTreeTerminalNode, IVariableTreeNode {
+    public new VariableBase Symbol {
+      get { return (VariableBase)base.Symbol; }
+    }
+    [Storable]
+    private double weight;
+    public double Weight {
+      get { return weight; }
+      set { weight = value; }
+    }
+    [Storable]
+    private string variableName;
+    public string VariableName {
+      get { return variableName; }
+      set { variableName = value; }
+    }
+
+    [StorableConstructor]
+    protected VariableTreeNodeBase(bool deserializing) : base(deserializing) { }
+    protected VariableTreeNodeBase(VariableTreeNodeBase original, Cloner cloner)
+      : base(original, cloner) {
+      weight = original.weight;
+      variableName = original.variableName;
+    }
+    protected VariableTreeNodeBase() { }
+    protected VariableTreeNodeBase(VariableBase variableSymbol) : base(variableSymbol) { }
+
+    public override bool HasLocalParameters {
+      get { return true; }
+    }
+
+    public override void ResetLocalParameters(IRandom random) {
+      base.ResetLocalParameters(random);
+      weight = NormalDistributedRandom.NextDouble(random, Symbol.WeightMu, Symbol.WeightSigma);
+
+#pragma warning disable 612, 618
+      variableName = Symbol.VariableNames.SelectRandom(random);
+#pragma warning restore 612, 618
+    }
+
+    public override void ShakeLocalParameters(IRandom random, double shakingFactor) {
+      base.ShakeLocalParameters(random, shakingFactor);
+
+      // 50% additive & 50% multiplicative (TODO: BUG in if statement below -> fix in HL 4.0!)
+      if (random.NextDouble() < 0) {
+        double x = NormalDistributedRandom.NextDouble(random, Symbol.WeightManipulatorMu, Symbol.WeightManipulatorSigma);
+        weight = weight + x * shakingFactor;
+      } else {
+        double x = NormalDistributedRandom.NextDouble(random, 1.0, Symbol.MultiplicativeWeightManipulatorSigma);
+        weight = weight * x;
+      }
+
+      if (Symbol.VariableChangeProbability >= 1.0) {
+        // old behaviour for backwards compatibility
+        #region Backwards compatible code, remove with 3.4
+#pragma warning disable 612, 618
+        variableName = Symbol.VariableNames.SelectRandom(random);
+#pragma warning restore 612, 618
+        #endregion
+      } else if (random.NextDouble() < Symbol.VariableChangeProbability) {
+        var oldName = variableName;
+        variableName = Symbol.VariableNames.SampleRandom(random);
+        if (oldName != variableName) {
+          // re-initialize weight if the variable is changed
+          weight = NormalDistributedRandom.NextDouble(random, Symbol.WeightMu, Symbol.WeightSigma);
+        }
+      }
+    }
+
+    public override string ToString() {
+      if (weight.IsAlmost(1.0)) return variableName;
+      else return weight.ToString("E4") + " " + variableName;
+    }
+  }
+}
