Index: stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Formatters/InfixExpressionFormatter.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Formatters/InfixExpressionFormatter.cs	(revision 17863)
+++ stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Formatters/InfixExpressionFormatter.cs	(revision 17869)
@@ -21,25 +21,173 @@
 
 using System;
+using System.Collections.Generic;
 using System.Globalization;
 using System.Linq;
 using System.Text;
+using HEAL.Attic;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
 using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
-using HEAL.Attic;
 
 namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+  public static class BaseInfixExpressionFormatter {
+    public static void FormatRecursively(ISymbolicExpressionTreeNode node, StringBuilder strBuilder,
+                                          NumberFormatInfo numberFormat, string formatString, List<KeyValuePair<string, double>> constants = null) {
+      if (node.SubtreeCount > 1) {
+        var token = GetToken(node.Symbol);
+        // operators
+        if (token == "+" || token == "-" || token == "OR" || token == "XOR" ||
+            token == "*" || token == "/" || token == "AND") {
+          strBuilder.Append("(");
+          FormatRecursively(node.Subtrees.First(), strBuilder, numberFormat, formatString, constants);
+
+          foreach (var subtree in node.Subtrees.Skip(1)) {
+            strBuilder.Append(" ").Append(token).Append(" ");
+            FormatRecursively(subtree, strBuilder, numberFormat, formatString, constants);
+          }
+
+          strBuilder.Append(")");
+        } else if (token == "^") {
+          // handle integer powers directly
+          strBuilder.Append("(");
+          FormatRecursively(node.Subtrees.First(), strBuilder, numberFormat, formatString, constants);
+
+          var power = node.GetSubtree(1);
+          if(power is ConstantTreeNode constNode && Math.Truncate(constNode.Value) == constNode.Value) {
+            strBuilder.Append(" ").Append(token).Append(" ").Append(constNode.Value.ToString(formatString, numberFormat));
+          } else {
+            strBuilder.Append(" ").Append(token).Append(" ");
+            FormatRecursively(power, strBuilder, numberFormat, formatString, constants);
+          }
+
+          strBuilder.Append(")");
+        } else {
+          // function with multiple arguments
+          strBuilder.Append(token).Append("(");
+          FormatRecursively(node.Subtrees.First(), strBuilder, numberFormat, formatString, constants);
+          foreach (var subtree in node.Subtrees.Skip(1)) {
+            strBuilder.Append(", ");
+            FormatRecursively(subtree, strBuilder, numberFormat, formatString, constants);
+          }
+
+          strBuilder.Append(")");
+        }
+      } else if (node.SubtreeCount == 1) {
+        var token = GetToken(node.Symbol);
+        if (token == "-" || token == "NOT") {
+          strBuilder.Append("(").Append(token).Append("(");
+          FormatRecursively(node.GetSubtree(0), strBuilder, numberFormat, formatString, constants);
+          strBuilder.Append("))");
+        } else if (token == "/") {
+          strBuilder.Append("1/");
+          FormatRecursively(node.GetSubtree(0), strBuilder, numberFormat, formatString, constants);
+        } else if (token == "+" || token == "*") {
+          FormatRecursively(node.GetSubtree(0), strBuilder, numberFormat, formatString, constants);
+        } else {
+          // function with only one argument
+          strBuilder.Append(token).Append("(");
+          FormatRecursively(node.GetSubtree(0), strBuilder, numberFormat, formatString, constants);
+          strBuilder.Append(")");
+        }
+      } else {
+        // no subtrees
+        if (node.Symbol is LaggedVariable) {
+          var varNode = node as LaggedVariableTreeNode;
+          if (!varNode.Weight.IsAlmost(1.0)) {
+            strBuilder.Append("(");
+            AppendConstant(strBuilder, constants, varNode.Weight, formatString, numberFormat);
+            strBuilder.Append("*");
+          }
+
+          strBuilder.Append("LAG(");
+          AppendVariableName(strBuilder, varNode.VariableName);
+          strBuilder.Append(", ")
+                    .AppendFormat(numberFormat, "{0}", varNode.Lag)
+                    .Append(")");
+          if (!varNode.Weight.IsAlmost(1.0)) strBuilder.Append(")");
+        } else if (node.Symbol is Variable) {
+          var varNode = node as VariableTreeNode;
+          if (!varNode.Weight.IsAlmost(1.0)) {
+            strBuilder.Append("(");
+            AppendConstant(strBuilder, constants, varNode.Weight, formatString, numberFormat);
+            strBuilder.Append("*");
+          }
+
+          AppendVariableName(strBuilder, varNode.VariableName);
+
+          if (!varNode.Weight.IsAlmost(1.0)) strBuilder.Append(")");
+        } else if (node.Symbol is FactorVariable) {
+          var factorNode = node as FactorVariableTreeNode;
+          AppendVariableName(strBuilder, factorNode.VariableName);
+
+          strBuilder.Append("[");
+          for (int i = 0; i < factorNode.Weights.Length; i++) {
+            if (i > 0) strBuilder.Append(", ");
+            AppendConstant(strBuilder, constants, factorNode.Weights[i], formatString, numberFormat);
+          }
+          strBuilder.Append("]");
+        } else if (node.Symbol is BinaryFactorVariable) {
+          var factorNode = node as BinaryFactorVariableTreeNode;
+          if (!factorNode.Weight.IsAlmost(1.0)) {
+            strBuilder.Append("(");
+            AppendConstant(strBuilder, constants, factorNode.Weight, formatString, numberFormat);
+
+            strBuilder.Append("*");
+          }
+
+          AppendVariableName(strBuilder, factorNode.VariableName);
+          strBuilder.Append(" = ");
+          AppendVariableName(strBuilder, factorNode.VariableValue);
+
+          if (!factorNode.Weight.IsAlmost(1.0)) strBuilder.Append(")");
+        } else if (node.Symbol is Constant) {
+          var constNode = node as ConstantTreeNode;
+          if (constants == null && constNode.Value < 0) {
+            strBuilder.Append("(").Append(constNode.Value.ToString(formatString, numberFormat))
+                      .Append(")"); // (-1
+          } else {
+            AppendConstant(strBuilder, constants, constNode.Value, formatString, numberFormat);
+          }
+        }
+      }
+    }
+
+    private static void AppendConstant(StringBuilder strBuilder, List<KeyValuePair<string, double>> constants, double value, string formatString, NumberFormatInfo numberFormat) {
+      if (constants != null) {
+        string constantKey = $"c_{constants.Count}";
+        strBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}", constantKey);
+        constants.Add(new KeyValuePair<string, double>(constantKey, value));
+      } else {
+        strBuilder.Append(value.ToString(formatString, numberFormat));
+      }
+    }
+
+    private static void AppendVariableName(StringBuilder strBuilder, string name) {
+      if (name.Contains("'"))
+        strBuilder.AppendFormat("\"{0}\"", name);
+      else
+        strBuilder.AppendFormat("'{0}'", name);
+    }
+
+    private static string GetToken(ISymbol symbol) {
+      var tok = InfixExpressionParser.knownSymbols.GetBySecond(symbol).FirstOrDefault();
+      if (tok == null)
+        throw new ArgumentException(string.Format("Unknown symbol {0} found.", symbol.Name));
+      return tok;
+    }
+  }
+
   /// <summary>
   /// Formats mathematical expressions in infix form. E.g. x1 * (3.0 * x2 + x3)
   /// </summary>
   [StorableType("6FE2C83D-A594-4ABF-B101-5AEAEA6D3E3D")]
-  [Item("Infix Symbolic Expression Tree Formatter", "A string formatter that converts symbolic expression trees to infix expressions.")]
-
+  [Item("Infix Symbolic Expression Tree Formatter",
+    "A string formatter that converts symbolic expression trees to infix expressions.")]
   public sealed class InfixExpressionFormatter : NamedItem, ISymbolicExpressionTreeStringFormatter {
-
-
     [StorableConstructor]
     private InfixExpressionFormatter(StorableConstructorFlag _) : base(_) { }
+
     private InfixExpressionFormatter(InfixExpressionFormatter original, Cloner cloner) : base(original, cloner) { }
+
     public InfixExpressionFormatter()
       : base() {
@@ -47,4 +195,5 @@
       Description = ItemDescription;
     }
+
     public override IDeepCloneable Clone(Cloner cloner) {
       return new InfixExpressionFormatter(this, cloner);
@@ -58,8 +207,10 @@
     /// <param name="formatString">The format string for numeric parameters (e.g. \"G4\" to limit to 4 digits, default is \"G\")</param>
     /// <returns>Infix expression</returns>
-    public string Format(ISymbolicExpressionTree symbolicExpressionTree, NumberFormatInfo numberFormat, string formatString="G") {
+    public string Format(ISymbolicExpressionTree symbolicExpressionTree, NumberFormatInfo numberFormat,
+                         string formatString = "G") {
       // skip root and start symbols
       StringBuilder strBuilder = new StringBuilder();
-      FormatRecursively(symbolicExpressionTree.Root.GetSubtree(0).GetSubtree(0), strBuilder, numberFormat, formatString);
+      BaseInfixExpressionFormatter.FormatRecursively(symbolicExpressionTree.Root.GetSubtree(0).GetSubtree(0),
+        strBuilder, numberFormat, formatString);
       return strBuilder.ToString();
     }
@@ -68,127 +219,46 @@
       return Format(symbolicExpressionTree, NumberFormatInfo.InvariantInfo);
     }
-
-    private static void FormatRecursively(ISymbolicExpressionTreeNode node, StringBuilder strBuilder, NumberFormatInfo numberFormat, string formatString) {
-      if (node.SubtreeCount > 1) {
-        var token = GetToken(node.Symbol);
-        // operators
-        if (token == "+" || token == "-" || token == "OR" || token == "XOR" ||
-            token == "*" || token == "/" || token == "AND" ||
-            token == "^") {
-          strBuilder.Append("(");
-          FormatRecursively(node.Subtrees.First(), strBuilder, numberFormat, formatString);
-
-          foreach (var subtree in node.Subtrees.Skip(1)) {
-            strBuilder.Append(" ").Append(token).Append(" ");
-            FormatRecursively(subtree, strBuilder, numberFormat, formatString);
-          }
-          strBuilder.Append(")");
-        } else {
-          // function with multiple arguments
-          strBuilder.Append(token).Append("(");
-          FormatRecursively(node.Subtrees.First(), strBuilder, numberFormat, formatString);
-          foreach (var subtree in node.Subtrees.Skip(1)) {
-            strBuilder.Append(", ");
-            FormatRecursively(subtree, strBuilder, numberFormat, formatString);
-          }
-          strBuilder.Append(")");
-        }
-      } else if (node.SubtreeCount == 1) {
-        var token = GetToken(node.Symbol);
-        if (token == "-" || token == "NOT") {
-          strBuilder.Append("(").Append(token).Append("(");
-          FormatRecursively(node.GetSubtree(0), strBuilder, numberFormat, formatString);
-          strBuilder.Append("))");
-        } else if (token == "/") {
-          strBuilder.Append("1/");
-          FormatRecursively(node.GetSubtree(0), strBuilder, numberFormat, formatString);
-        } else if (token == "+" || token == "*") {
-          FormatRecursively(node.GetSubtree(0), strBuilder, numberFormat, formatString);
-        } else {
-          // function with only one argument
-          strBuilder.Append(token).Append("(");
-          FormatRecursively(node.GetSubtree(0), strBuilder, numberFormat, formatString);
-          strBuilder.Append(")");
-        }
-      } else {
-        // no subtrees
-        if (node.Symbol is LaggedVariable) {
-          var varNode = node as LaggedVariableTreeNode;
-          if (!varNode.Weight.IsAlmost(1.0)) {
-            strBuilder.Append("(");
-            strBuilder.Append(varNode.Weight.ToString(formatString, numberFormat));
-            strBuilder.Append("*");
-          }
-          strBuilder.Append("LAG(");
-          if (varNode.VariableName.Contains("'")) {
-            strBuilder.AppendFormat("\"{0}\"", varNode.VariableName);
-          } else {
-            strBuilder.AppendFormat("'{0}'", varNode.VariableName);
-          }
-          strBuilder.Append(", ")
-            .AppendFormat(numberFormat, "{0}", varNode.Lag)
-            .Append(")");
-        } else if (node.Symbol is Variable) {
-          var varNode = node as VariableTreeNode;
-          if (!varNode.Weight.IsAlmost(1.0)) {
-            strBuilder.Append("(");
-            strBuilder.Append(varNode.Weight.ToString(formatString, numberFormat));
-            strBuilder.Append("*");
-          }
-          if (varNode.VariableName.Contains("'")) {
-            strBuilder.AppendFormat("\"{0}\"", varNode.VariableName);
-          } else {
-            strBuilder.AppendFormat("'{0}'", varNode.VariableName);
-          }
-          if (!varNode.Weight.IsAlmost(1.0)) {
-            strBuilder.Append(")");
-          }
-        } else if (node.Symbol is FactorVariable) {
-          var factorNode = node as FactorVariableTreeNode;
-          if (factorNode.VariableName.Contains("'")) {
-            strBuilder.AppendFormat("\"{0}\"", factorNode.VariableName);
-          } else {
-            strBuilder.AppendFormat("'{0}'", factorNode.VariableName);
-          }
-          strBuilder.AppendFormat("[{0}]",
-            string.Join(", ", factorNode.Weights.Select(w => w.ToString(formatString, numberFormat))));
-        } else if (node.Symbol is BinaryFactorVariable) {
-          var factorNode = node as BinaryFactorVariableTreeNode;
-          if (!factorNode.Weight.IsAlmost(1.0)) {
-            strBuilder.Append("(");
-            strBuilder.Append(factorNode.Weight.ToString(formatString, numberFormat));
-            strBuilder.Append("*");
-          }
-          if (factorNode.VariableName.Contains("'")) {
-            strBuilder.AppendFormat("\"{0}\"", factorNode.VariableName);
-          } else {
-            strBuilder.AppendFormat("'{0}'", factorNode.VariableName);
-          }
-          strBuilder.Append(" = ");
-          if (factorNode.VariableValue.Contains("'")) {
-            strBuilder.AppendFormat("\"{0}\"", factorNode.VariableValue);
-          } else {
-            strBuilder.AppendFormat("'{0}'", factorNode.VariableValue);
-          }
-
-          if (!factorNode.Weight.IsAlmost(1.0)) {
-            strBuilder.Append(")");
-          }
-
-        } else if (node.Symbol is Constant) {
-          var constNode = node as ConstantTreeNode;
-          if (constNode.Value >= 0.0)
-            strBuilder.Append(constNode.Value.ToString(formatString, numberFormat));
-          else
-            strBuilder.Append("(").Append(constNode.Value.ToString(formatString, numberFormat)).Append(")"); // (-1
-        }
+  }
+
+  [StorableType("54D917E8-134E-4066-9A60-2737C12D81DC")]
+  [Item("Infix String Formater", "Formatter for symbolic expressions, which produces an infix expression " +
+                                 "as well as a list of all coefficient values")]
+  public sealed class InfixExpressionStringFormatter : NamedItem, ISymbolicExpressionTreeStringFormatter {
+    [StorableConstructor]
+    private InfixExpressionStringFormatter(StorableConstructorFlag _) : base(_) { }
+
+    private InfixExpressionStringFormatter(InfixExpressionStringFormatter original, Cloner cloner) : base(original, cloner) { }
+
+    public InfixExpressionStringFormatter() : base() {
+      Name = ItemName;
+      Description = ItemDescription;
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new InfixExpressionStringFormatter(this, cloner);
+    }
+
+    public string Format(ISymbolicExpressionTree symbolicExpressionTree) {
+      StringBuilder strBuilder = new StringBuilder();
+      var constants = new List<KeyValuePair<string, double>>();
+      BaseInfixExpressionFormatter.FormatRecursively(symbolicExpressionTree.Root.GetSubtree(0).GetSubtree(0),
+        strBuilder, NumberFormatInfo.InvariantInfo, "G", constants);
+      strBuilder.Append($"{Environment.NewLine}{Environment.NewLine}");
+
+      int maxDigits = GetDigits(constants.Count);
+      int padding = constants.Max(x => x.Value.ToString("F12", CultureInfo.InvariantCulture).Length);
+      foreach (var constant in constants) {
+        int digits = GetDigits(Int32.Parse(constant.Key.Substring(2)));
+        strBuilder.Append($"{constant.Key}{new String(' ', maxDigits - digits)} = " +
+                          string.Format($"{{0,{padding}:F12}}", constant.Value, CultureInfo.InvariantCulture) +
+                          Environment.NewLine);
       }
-    }
-
-    private static string GetToken(ISymbol symbol) {
-      var tok = InfixExpressionParser.knownSymbols.GetBySecond(symbol).FirstOrDefault();
-      if (tok == null)
-        throw new ArgumentException(string.Format("Unknown symbol {0} found.", symbol.Name));
-      return tok;
+
+      return strBuilder.ToString();
+    }
+
+    private int GetDigits(int x) {
+      if (x == 0) return 1;
+      return (int)Math.Floor(Math.Log10(x) + 1);
     }
   }
