source: branches/2968_infix_string_formatter/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Formatters/InfixExpressionStringFormatter.cs @ 16340

Last change on this file since 16340 was 16340, checked in by chaider, 9 months ago

#2968 Changed formating of constant list

File size: 8.2 KB
Line 
1using HeuristicLab.Core;
2using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
3using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
4using System.Collections.Generic;
5using HeuristicLab.Common;
6using System.Text;
7using System.Globalization;
8using System.Linq;
9using System;
10
11namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Formatters {
12  [Item("Infix String Formater", "Formatter for symbolic expressions, which produces an infix expression " +
13    "as well as a list of all coefficient values")]
14  [StorableClass]
15  public sealed class InfixExpressionStringFormatter : NamedItem, ISymbolicExpressionTreeStringFormatter {
16    private readonly List<KeyValuePair<string, double>> constants;
17    private int constantCounter = 0;
18
19    [StorableConstructor]
20    private InfixExpressionStringFormatter(bool deserializing): base(deserializing) {}
21    private InfixExpressionStringFormatter(InfixExpressionStringFormatter original, Cloner cloner) 
22      : base(original, cloner) {
23      constants = new List<KeyValuePair<string, double>>(original.constants);
24      constantCounter = original.constantCounter;
25    }
26    public InfixExpressionStringFormatter() : base() {
27      Name = ItemName;
28      Description = ItemDescription;
29      constants = new List<KeyValuePair<string, double>>();
30    }
31    public override IDeepCloneable Clone(Cloner cloner) {
32      return new InfixExpressionStringFormatter(this, cloner);
33    }
34
35    public string Format(ISymbolicExpressionTree symbolicExpressionTree) {
36      StringBuilder strBuilder = new StringBuilder();
37      constants.Clear();
38      constantCounter = 0;
39      FormatRecursively(symbolicExpressionTree.Root.GetSubtree(0).GetSubtree(0), strBuilder);
40      strBuilder.Append($"{Environment.NewLine}{Environment.NewLine}");
41
42      int maxDigits = GetDigits(constantCounter);
43      int padding = constants.Max(x => x.Value.ToString("F12", CultureInfo.InvariantCulture).Length);
44      foreach (var constant in constants) {
45        int digits = GetDigits(Int32.Parse(constant.Key.Substring(2)));
46        strBuilder.Append($"{constant.Key}{new String(' ', maxDigits - digits)} = " +
47          string.Format($"{{0,{padding}:F12}}", constant.Value, CultureInfo.InvariantCulture) + Environment.NewLine);
48      }
49      return strBuilder.ToString();
50    }
51
52    private void FormatRecursively(ISymbolicExpressionTreeNode node, StringBuilder strBuilder) {
53      if (node.SubtreeCount > 1) {
54        var token = GetToken(node.Symbol);
55        if (token == "+" || token == "-" || token == "OR" || token == "XOR") {
56          strBuilder.Append("(");
57          FormatRecursively(node.Subtrees.First(), strBuilder);
58
59          foreach (var subtree in node.Subtrees.Skip(1)) {
60            strBuilder.Append(" ").Append(token).Append(" ");
61            FormatRecursively(subtree, strBuilder);
62          }
63          strBuilder.Append(")");
64
65        } else if (token == "*" || token == "/" || token == "AND") {
66          strBuilder.Append("(");
67          FormatRecursively(node.Subtrees.First(), strBuilder);
68
69          foreach (var subtree in node.Subtrees.Skip(1)) {
70            strBuilder.Append(" ").Append(token).Append(" ");
71            FormatRecursively(subtree, strBuilder);
72          }
73          strBuilder.Append(")");
74        } else {
75          // function with multiple arguments
76          strBuilder.Append(token).Append("(");
77          FormatRecursively(node.Subtrees.First(), strBuilder);
78          foreach (var subtree in node.Subtrees.Skip(1)) {
79            strBuilder.Append(", ");
80            FormatRecursively(subtree, strBuilder);
81          }
82          strBuilder.Append(")");
83        }
84      } else if (node.SubtreeCount == 1) {
85        var token = GetToken(node.Symbol);
86        if (token == "-" || token == "NOT") {
87          strBuilder.Append("(").Append(token).Append("(");
88          FormatRecursively(node.GetSubtree(0), strBuilder);
89          strBuilder.Append("))");
90        } else if (token == "/") {
91          strBuilder.Append("1/");
92          FormatRecursively(node.GetSubtree(0), strBuilder);
93        } else if (token == "+" || token == "*") {
94          FormatRecursively(node.GetSubtree(0), strBuilder);
95        } else {
96          // function with only one argument
97          strBuilder.Append(token).Append("(");
98          FormatRecursively(node.GetSubtree(0), strBuilder);
99          strBuilder.Append(")");
100        }
101      } else {
102        if (node.Symbol is LaggedVariable) {
103          var varNode = node as LaggedVariableTreeNode;
104          if (!varNode.Weight.IsAlmost(1.0)) {
105            strBuilder.Append("(");
106            strBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}", varNode.Weight);
107            strBuilder.Append("*");
108          }
109          strBuilder.Append("LAG(");
110          if (varNode.VariableName.Contains("'")) {
111            strBuilder.AppendFormat("\"{0}\"", varNode.VariableName);
112          } else {
113            strBuilder.AppendFormat("'{0}'", varNode.VariableName);
114          }
115          strBuilder.Append(", ")
116            .AppendFormat(CultureInfo.InvariantCulture, "{0}", varNode.Lag)
117            .Append(")");
118        } else if (node.Symbol is Variable) {
119          var varNode = node as VariableTreeNode;
120          if (!varNode.Weight.IsAlmost(1.0)) {
121            string constantKey = $"c_{constantCounter}";
122            strBuilder.Append("(");
123            strBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}", constantKey);
124            strBuilder.Append("*");
125            constants.Add(new KeyValuePair<string, double>(constantKey, varNode.Weight));
126            constantCounter++;
127          }
128          if (varNode.VariableName.Contains("'")) {
129            strBuilder.AppendFormat("\"{0}\"", varNode.VariableName);
130          } else {
131            strBuilder.AppendFormat("'{0}'", varNode.VariableName);
132          }
133          if (!varNode.Weight.IsAlmost(1.0)) {
134            strBuilder.Append(")");
135          }
136        } else if (node.Symbol is FactorVariable) {
137          var factorNode = node as FactorVariableTreeNode;
138          if (factorNode.VariableName.Contains("'")) {
139            strBuilder.AppendFormat("\"{0}\"", factorNode.VariableName);
140          } else {
141            strBuilder.AppendFormat("'{0}'", factorNode.VariableName);
142          }
143          strBuilder.AppendFormat("[{0}]",
144            string.Join(", ", factorNode.Weights.Select(w => w.ToString(CultureInfo.InvariantCulture))));
145        } else if (node.Symbol is BinaryFactorVariable) {
146          var factorNode = node as BinaryFactorVariableTreeNode;
147          if (!factorNode.Weight.IsAlmost(1.0)) {
148            strBuilder.Append("(");
149            strBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}", factorNode.Weight);
150            strBuilder.Append("*");
151          }
152          if (factorNode.VariableName.Contains("'")) {
153            strBuilder.AppendFormat("\"{0}\"", factorNode.VariableName);
154          } else {
155            strBuilder.AppendFormat("'{0}'", factorNode.VariableName);
156          }
157          strBuilder.Append(" = ");
158          if (factorNode.VariableValue.Contains("'")) {
159            strBuilder.AppendFormat("\"{0}\"", factorNode.VariableValue);
160          } else {
161            strBuilder.AppendFormat("'{0}'", factorNode.VariableValue);
162          }
163
164          if (!factorNode.Weight.IsAlmost(1.0)) {
165            strBuilder.Append(")");
166          }
167
168        } else if (node.Symbol is Constant) {
169          var constNode = node as ConstantTreeNode;
170          string constantKey = $"c_{constantCounter}";
171
172          strBuilder.AppendFormat(CultureInfo.InvariantCulture, constantKey);
173          constants.Add(new KeyValuePair<string, double>(constantKey, constNode.Value));
174          constantCounter++;
175        }
176      }
177    }
178
179    private int GetDigits(int x) {
180      if (x < 10)
181        return 1;
182      else
183        return (int)Math.Floor(Math.Log10(x) + 1);
184    }
185
186    private string GetToken(ISymbol symbol) {
187      var tok = InfixExpressionParser.knownSymbols.GetBySecond(symbol).SingleOrDefault();
188      if (tok == null)
189        throw new ArgumentException(string.Format("Unknown symbol {0} found.", symbol.Name));
190      return tok;
191    }
192  }
193}
Note: See TracBrowser for help on using the repository browser.