Index: stable/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/SingleObjective/Evaluators/SymbolicRegressionConstantOptimizationEvaluator.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/SingleObjective/Evaluators/SymbolicRegressionConstantOptimizationEvaluator.cs	(revision 14962)
+++ stable/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/SingleObjective/Evaluators/SymbolicRegressionConstantOptimizationEvaluator.cs	(revision 15131)
@@ -176,23 +176,35 @@
 
 
-    public static double OptimizeConstants(ISymbolicDataAnalysisExpressionTreeInterpreter interpreter, ISymbolicExpressionTree tree, IRegressionProblemData problemData, IEnumerable<int> rows, bool applyLinearScaling, int maxIterations, bool updateVariableWeights = true, double lowerEstimationLimit = double.MinValue, double upperEstimationLimit = double.MaxValue, bool updateConstantsInTree = true) {
-
-      List<AutoDiff.Variable> variables = new List<AutoDiff.Variable>();
-      List<AutoDiff.Variable> parameters = new List<AutoDiff.Variable>();
-      List<string> variableNames = new List<string>();
-      List<int> lags = new List<int>();
+
+    public static double OptimizeConstants(ISymbolicDataAnalysisExpressionTreeInterpreter interpreter,
+      ISymbolicExpressionTree tree, IRegressionProblemData problemData, IEnumerable<int> rows, bool applyLinearScaling,
+      int maxIterations, bool updateVariableWeights = true,
+      double lowerEstimationLimit = double.MinValue, double upperEstimationLimit = double.MaxValue,
+      bool updateConstantsInTree = true) {
+
+      // numeric constants in the tree become variables for constant opt
+      // variables in the tree become parameters (fixed values) for constant opt
+      // for each parameter (variable in the original tree) we store the 
+      // variable name, variable value (for factor vars) and lag as a DataForVariable object.
+      // A dictionary is used to find parameters
+      var variables = new List<AutoDiff.Variable>();
+      var parameters = new Dictionary<DataForVariable, AutoDiff.Variable>();
 
       AutoDiff.Term func;
-      if (!TryTransformToAutoDiff(tree.Root.GetSubtree(0), variables, parameters, variableNames, lags, updateVariableWeights, out func))
+      if (!TryTransformToAutoDiff(tree.Root.GetSubtree(0), variables, parameters, updateVariableWeights, out func))
         throw new NotSupportedException("Could not optimize constants of symbolic expression tree due to not supported symbols used in the tree.");
-      if (variableNames.Count == 0) return 0.0;
-
-      AutoDiff.IParametricCompiledTerm compiledFunc = func.Compile(variables.ToArray(), parameters.ToArray());
-
-      List<SymbolicExpressionTreeTerminalNode> terminalNodes = null;
+      if (parameters.Count == 0) return 0.0; // gkronber: constant expressions always have a R² of 0.0 
+
+      var parameterEntries = parameters.ToArray(); // order of entries must be the same for x
+      AutoDiff.IParametricCompiledTerm compiledFunc = func.Compile(variables.ToArray(), parameterEntries.Select(kvp => kvp.Value).ToArray());
+
+      List<SymbolicExpressionTreeTerminalNode> terminalNodes = null; // gkronber only used for extraction of initial constants
       if (updateVariableWeights)
         terminalNodes = tree.Root.IterateNodesPrefix().OfType<SymbolicExpressionTreeTerminalNode>().ToList();
       else
-        terminalNodes = new List<SymbolicExpressionTreeTerminalNode>(tree.Root.IterateNodesPrefix().OfType<ConstantTreeNode>());
+        terminalNodes = new List<SymbolicExpressionTreeTerminalNode>
+          (tree.Root.IterateNodesPrefix()
+          .OfType<SymbolicExpressionTreeTerminalNode>()
+          .Where(node => node is ConstantTreeNode || node is FactorVariableTreeNode));
 
       //extract inital constants
@@ -205,8 +217,16 @@
           ConstantTreeNode constantTreeNode = node as ConstantTreeNode;
           VariableTreeNode variableTreeNode = node as VariableTreeNode;
+          BinaryFactorVariableTreeNode binFactorVarTreeNode = node as BinaryFactorVariableTreeNode;
+          FactorVariableTreeNode factorVarTreeNode = node as FactorVariableTreeNode;
           if (constantTreeNode != null)
             c[i++] = constantTreeNode.Value;
           else if (updateVariableWeights && variableTreeNode != null)
             c[i++] = variableTreeNode.Weight;
+          else if (updateVariableWeights && binFactorVarTreeNode != null)
+            c[i++] = binFactorVarTreeNode.Weight;
+          else if (factorVarTreeNode != null) {
+            // gkronber: a factorVariableTreeNode holds a category-specific constant therefore we can consider factors to be the same as constants
+            foreach (var w in factorVarTreeNode.Weights) c[i++] = w;
+          }
         }
       }
@@ -216,13 +236,20 @@
       alglib.lsfitstate state;
       alglib.lsfitreport rep;
-      int info;
+      int retVal;
 
       IDataset ds = problemData.Dataset;
-      double[,] x = new double[rows.Count(), variableNames.Count];
+      double[,] x = new double[rows.Count(), parameters.Count];
       int row = 0;
       foreach (var r in rows) {
-        for (int col = 0; col < variableNames.Count; col++) {
-          int lag = lags[col];
-          x[row, col] = ds.GetDoubleValue(variableNames[col], r + lag);
+        int col = 0;
+        foreach (var kvp in parameterEntries) {
+          var info = kvp.Key;
+          int lag = info.lag;
+          if (ds.VariableHasType<double>(info.variableName)) {
+            x[row, col] = ds.GetDoubleValue(info.variableName, r + lag);
+          } else if (ds.VariableHasType<string>(info.variableName)) {
+            x[row, col] = ds.GetStringValue(info.variableName, r) == info.variableValue ? 1 : 0;
+          } else throw new InvalidProgramException("found a variable of unknown type");
+          col++;
         }
         row++;
@@ -241,5 +268,5 @@
         //alglib.lsfitsetgradientcheck(state, 0.001);
         alglib.lsfitfit(state, function_cx_1_func, function_cx_1_grad, null, null);
-        alglib.lsfitresults(state, out info, out c, out rep);
+        alglib.lsfitresults(state, out retVal, out c, out rep);
       } catch (ArithmeticException) {
         return originalQuality;
@@ -248,6 +275,6 @@
       }
 
-      //info == -7  => constant optimization failed due to wrong gradient
-      if (info != -7) UpdateConstants(tree, c.Skip(2).ToArray(), updateVariableWeights);
+      //retVal == -7  => constant optimization failed due to wrong gradient
+      if (retVal != -7) UpdateConstants(tree, c.Skip(2).ToArray(), updateVariableWeights);
       var quality = SymbolicRegressionSingleObjectivePearsonRSquaredEvaluator.Calculate(interpreter, tree, lowerEstimationLimit, upperEstimationLimit, problemData, rows, applyLinearScaling);
 
@@ -265,8 +292,16 @@
         ConstantTreeNode constantTreeNode = node as ConstantTreeNode;
         VariableTreeNode variableTreeNode = node as VariableTreeNode;
+        BinaryFactorVariableTreeNode binFactorVarTreeNode = node as BinaryFactorVariableTreeNode;
+        FactorVariableTreeNode factorVarTreeNode = node as FactorVariableTreeNode;
         if (constantTreeNode != null)
           constantTreeNode.Value = constants[i++];
         else if (updateVariableWeights && variableTreeNode != null)
           variableTreeNode.Weight = constants[i++];
+        else if (updateVariableWeights && binFactorVarTreeNode != null)
+          binFactorVarTreeNode.Weight = constants[i++];
+        else if (factorVarTreeNode != null) {
+          for (int j = 0; j < factorVarTreeNode.Weights.Length; j++)
+            factorVarTreeNode.Weights[j] = constants[i++];
+        }
       }
     }
@@ -286,5 +321,7 @@
     }
 
-    private static bool TryTransformToAutoDiff(ISymbolicExpressionTreeNode node, List<AutoDiff.Variable> variables, List<AutoDiff.Variable> parameters, List<string> variableNames, List<int> lags, bool updateVariableWeights, out AutoDiff.Term term) {
+    private static bool TryTransformToAutoDiff(ISymbolicExpressionTreeNode node,
+      List<AutoDiff.Variable> variables, Dictionary<DataForVariable, AutoDiff.Variable> parameters,
+      bool updateVariableWeights, out AutoDiff.Term term) {
       if (node.Symbol is Constant) {
         var var = new AutoDiff.Variable();
@@ -293,10 +330,10 @@
         return true;
       }
-      if (node.Symbol is Variable) {
-        var varNode = node as VariableTreeNode;
-        var par = new AutoDiff.Variable();
-        parameters.Add(par);
-        variableNames.Add(varNode.VariableName);
-        lags.Add(0);
+      if (node.Symbol is Variable || node.Symbol is BinaryFactorVariable) {
+        var varNode = node as VariableTreeNodeBase;
+        var factorVarNode = node as BinaryFactorVariableTreeNode;
+        // factor variable values are only 0 or 1 and set in x accordingly
+        var varValue = factorVarNode != null ? factorVarNode.VariableValue : string.Empty;
+        var par = FindOrCreateParameter(parameters, varNode.VariableName, varValue);
 
         if (updateVariableWeights) {
@@ -309,10 +346,21 @@
         return true;
       }
+      if (node.Symbol is FactorVariable) {
+        var factorVarNode = node as FactorVariableTreeNode;
+        var products = new List<Term>();
+        foreach (var variableValue in factorVarNode.Symbol.GetVariableValues(factorVarNode.VariableName)) {
+          var par = FindOrCreateParameter(parameters, factorVarNode.VariableName, variableValue);
+
+          var wVar = new AutoDiff.Variable();
+          variables.Add(wVar);
+
+          products.Add(AutoDiff.TermBuilder.Product(wVar, par));
+        }
+        term = AutoDiff.TermBuilder.Sum(products);
+        return true;
+      }
       if (node.Symbol is LaggedVariable) {
         var varNode = node as LaggedVariableTreeNode;
-        var par = new AutoDiff.Variable();
-        parameters.Add(par);
-        variableNames.Add(varNode.VariableName);
-        lags.Add(varNode.Lag);
+        var par = FindOrCreateParameter(parameters, varNode.VariableName, string.Empty, varNode.Lag);
 
         if (updateVariableWeights) {
@@ -329,5 +377,5 @@
         foreach (var subTree in node.Subtrees) {
           AutoDiff.Term t;
-          if (!TryTransformToAutoDiff(subTree, variables, parameters, variableNames, lags, updateVariableWeights, out t)) {
+          if (!TryTransformToAutoDiff(subTree, variables, parameters, updateVariableWeights, out t)) {
             term = null;
             return false;
@@ -342,5 +390,5 @@
         for (int i = 0; i < node.SubtreeCount; i++) {
           AutoDiff.Term t;
-          if (!TryTransformToAutoDiff(node.GetSubtree(i), variables, parameters, variableNames, lags, updateVariableWeights, out t)) {
+          if (!TryTransformToAutoDiff(node.GetSubtree(i), variables, parameters, updateVariableWeights, out t)) {
             term = null;
             return false;
@@ -357,5 +405,5 @@
         foreach (var subTree in node.Subtrees) {
           AutoDiff.Term t;
-          if (!TryTransformToAutoDiff(subTree, variables, parameters, variableNames, lags, updateVariableWeights, out t)) {
+          if (!TryTransformToAutoDiff(subTree, variables, parameters, updateVariableWeights, out t)) {
             term = null;
             return false;
@@ -372,5 +420,5 @@
         foreach (var subTree in node.Subtrees) {
           AutoDiff.Term t;
-          if (!TryTransformToAutoDiff(subTree, variables, parameters, variableNames, lags, updateVariableWeights, out t)) {
+          if (!TryTransformToAutoDiff(subTree, variables, parameters, updateVariableWeights, out t)) {
             term = null;
             return false;
@@ -384,5 +432,5 @@
       if (node.Symbol is Logarithm) {
         AutoDiff.Term t;
-        if (!TryTransformToAutoDiff(node.GetSubtree(0), variables, parameters, variableNames, lags, updateVariableWeights, out t)) {
+        if (!TryTransformToAutoDiff(node.GetSubtree(0), variables, parameters, updateVariableWeights, out t)) {
           term = null;
           return false;
@@ -394,5 +442,5 @@
       if (node.Symbol is Exponential) {
         AutoDiff.Term t;
-        if (!TryTransformToAutoDiff(node.GetSubtree(0), variables, parameters, variableNames, lags, updateVariableWeights, out t)) {
+        if (!TryTransformToAutoDiff(node.GetSubtree(0), variables, parameters, updateVariableWeights, out t)) {
           term = null;
           return false;
@@ -404,5 +452,5 @@
       if (node.Symbol is Square) {
         AutoDiff.Term t;
-        if (!TryTransformToAutoDiff(node.GetSubtree(0), variables, parameters, variableNames, lags, updateVariableWeights, out t)) {
+        if (!TryTransformToAutoDiff(node.GetSubtree(0), variables, parameters, updateVariableWeights, out t)) {
           term = null;
           return false;
@@ -414,5 +462,5 @@
       if (node.Symbol is SquareRoot) {
         AutoDiff.Term t;
-        if (!TryTransformToAutoDiff(node.GetSubtree(0), variables, parameters, variableNames, lags, updateVariableWeights, out t)) {
+        if (!TryTransformToAutoDiff(node.GetSubtree(0), variables, parameters, updateVariableWeights, out t)) {
           term = null;
           return false;
@@ -424,5 +472,5 @@
       if (node.Symbol is Sine) {
         AutoDiff.Term t;
-        if (!TryTransformToAutoDiff(node.GetSubtree(0), variables, parameters, variableNames, lags, updateVariableWeights, out t)) {
+        if (!TryTransformToAutoDiff(node.GetSubtree(0), variables, parameters, updateVariableWeights, out t)) {
           term = null;
           return false;
@@ -434,5 +482,5 @@
       if (node.Symbol is Cosine) {
         AutoDiff.Term t;
-        if (!TryTransformToAutoDiff(node.GetSubtree(0), variables, parameters, variableNames, lags, updateVariableWeights, out t)) {
+        if (!TryTransformToAutoDiff(node.GetSubtree(0), variables, parameters, updateVariableWeights, out t)) {
           term = null;
           return false;
@@ -444,5 +492,5 @@
       if (node.Symbol is Tangent) {
         AutoDiff.Term t;
-        if (!TryTransformToAutoDiff(node.GetSubtree(0), variables, parameters, variableNames, lags, updateVariableWeights, out t)) {
+        if (!TryTransformToAutoDiff(node.GetSubtree(0), variables, parameters, updateVariableWeights, out t)) {
           term = null;
           return false;
@@ -454,5 +502,5 @@
       if (node.Symbol is Erf) {
         AutoDiff.Term t;
-        if (!TryTransformToAutoDiff(node.GetSubtree(0), variables, parameters, variableNames, lags, updateVariableWeights, out t)) {
+        if (!TryTransformToAutoDiff(node.GetSubtree(0), variables, parameters, updateVariableWeights, out t)) {
           term = null;
           return false;
@@ -464,5 +512,5 @@
       if (node.Symbol is Norm) {
         AutoDiff.Term t;
-        if (!TryTransformToAutoDiff(node.GetSubtree(0), variables, parameters, variableNames, lags, updateVariableWeights, out t)) {
+        if (!TryTransformToAutoDiff(node.GetSubtree(0), variables, parameters, updateVariableWeights, out t)) {
           term = null;
           return false;
@@ -478,5 +526,5 @@
         variables.Add(alpha);
         AutoDiff.Term branchTerm;
-        if (TryTransformToAutoDiff(node.GetSubtree(0), variables, parameters, variableNames, lags, updateVariableWeights, out branchTerm)) {
+        if (TryTransformToAutoDiff(node.GetSubtree(0), variables, parameters, updateVariableWeights, out branchTerm)) {
           term = branchTerm * alpha + beta;
           return true;
@@ -488,4 +536,19 @@
       term = null;
       return false;
+    }
+
+    // for each factor variable value we need a parameter which represents a binary indicator for that variable & value combination
+    // each binary indicator is only necessary once. So we only create a parameter if this combination is not yet available
+    private static Term FindOrCreateParameter(Dictionary<DataForVariable, AutoDiff.Variable> parameters,
+      string varName, string varValue = "", int lag = 0) {
+      var data = new DataForVariable(varName, varValue, lag);
+
+      AutoDiff.Variable par = null;
+      if (!parameters.TryGetValue(data, out par)) {
+        // not found -> create new parameter and entries in names and values lists
+        par = new AutoDiff.Variable();
+        parameters.Add(data, par);
+      }
+      return par;
     }
 
@@ -495,4 +558,6 @@
         where
          !(n.Symbol is Variable) &&
+         !(n.Symbol is BinaryFactorVariable) &&
+         !(n.Symbol is FactorVariable) &&
          !(n.Symbol is LaggedVariable) &&
          !(n.Symbol is Constant) &&
@@ -515,4 +580,31 @@
       return !containsUnknownSymbol;
     }
+
+
+    #region helper class
+    private class DataForVariable {
+      public readonly string variableName;
+      public readonly string variableValue; // for factor vars
+      public readonly int lag;
+
+      public DataForVariable(string varName, string varValue, int lag) {
+        this.variableName = varName;
+        this.variableValue = varValue;
+        this.lag = lag;
+      }
+
+      public override bool Equals(object obj) {
+        var other = obj as DataForVariable;
+        if (other == null) return false;
+        return other.variableName.Equals(this.variableName) &&
+               other.variableValue.Equals(this.variableValue) &&
+               other.lag == this.lag;
+      }
+
+      public override int GetHashCode() {
+        return variableName.GetHashCode() ^ variableValue.GetHashCode() ^ lag;
+      }
+    }
+    #endregion
   }
 }
