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

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

#2968 Added infix expressen string formatter class

File size: 7.6 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 static 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    }
25    public InfixExpressionStringFormatter() : base() {
26      Name = ItemName;
27      Description = ItemDescription;
28      constants = new List<KeyValuePair<string, double>>();
29    }
30    public override IDeepCloneable Clone(Cloner cloner) {
31      return new InfixExpressionStringFormatter(this, cloner);
32    }
33
34    public string Format(ISymbolicExpressionTree symbolicExpressionTree) {
35      StringBuilder strBuilder = new StringBuilder();
36      FormatRecursively(symbolicExpressionTree.Root.GetSubtree(0).GetSubtree(0), strBuilder);
37      strBuilder.Append($"{Environment.NewLine}{Environment.NewLine}");
38      foreach (var constant in constants) {
39        strBuilder.Append($"{constant.Key} = {constant.Value}{Environment.NewLine}");
40      }
41      return strBuilder.ToString();
42    }
43
44    private void FormatRecursively(ISymbolicExpressionTreeNode node, StringBuilder strBuilder) {
45      if (node.SubtreeCount > 1) {
46        var token = GetToken(node.Symbol);
47        if (token == "+" || token == "-" || token == "OR" || token == "XOR") {
48          strBuilder.Append("(");
49          FormatRecursively(node.Subtrees.First(), strBuilder);
50
51          foreach (var subtree in node.Subtrees.Skip(1)) {
52            strBuilder.Append(" ").Append(token).Append(" ");
53            FormatRecursively(subtree, strBuilder);
54          }
55          strBuilder.Append(")");
56
57        } else if (token == "*" || token == "/" || token == "AND") {
58          strBuilder.Append("(");
59          FormatRecursively(node.Subtrees.First(), strBuilder);
60
61          foreach (var subtree in node.Subtrees.Skip(1)) {
62            strBuilder.Append(" ").Append(token).Append(" ");
63            FormatRecursively(subtree, strBuilder);
64          }
65          strBuilder.Append(")");
66        } else {
67          // function with multiple arguments
68          strBuilder.Append(token).Append("(");
69          FormatRecursively(node.Subtrees.First(), strBuilder);
70          foreach (var subtree in node.Subtrees.Skip(1)) {
71            strBuilder.Append(", ");
72            FormatRecursively(subtree, strBuilder);
73          }
74          strBuilder.Append(")");
75        }
76      } else if (node.SubtreeCount == 1) {
77        var token = GetToken(node.Symbol);
78        if (token == "-" || token == "NOT") {
79          strBuilder.Append("(").Append(token).Append("(");
80          FormatRecursively(node.GetSubtree(0), strBuilder);
81          strBuilder.Append("))");
82        } else if (token == "/") {
83          strBuilder.Append("1/");
84          FormatRecursively(node.GetSubtree(0), strBuilder);
85        } else if (token == "+" || token == "*") {
86          FormatRecursively(node.GetSubtree(0), strBuilder);
87        } else {
88          // function with only one argument
89          strBuilder.Append(token).Append("(");
90          FormatRecursively(node.GetSubtree(0), strBuilder);
91          strBuilder.Append(")");
92        }
93      } else {
94        if (node.Symbol is LaggedVariable) {
95          var varNode = node as LaggedVariableTreeNode;
96          if (!varNode.Weight.IsAlmost(1.0)) {
97            strBuilder.Append("(");
98            strBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}", varNode.Weight);
99            strBuilder.Append("*");
100          }
101          strBuilder.Append("LAG(");
102          if (varNode.VariableName.Contains("'")) {
103            strBuilder.AppendFormat("\"{0}\"", varNode.VariableName);
104          } else {
105            strBuilder.AppendFormat("'{0}'", varNode.VariableName);
106          }
107          strBuilder.Append(", ")
108            .AppendFormat(CultureInfo.InvariantCulture, "{0}", varNode.Lag)
109            .Append(")");
110        } else if (node.Symbol is Variable) {
111          var varNode = node as VariableTreeNode;
112          if (!varNode.Weight.IsAlmost(1.0)) {
113            string constantKey = $"c_{constantCounter}";
114            strBuilder.Append("(");
115            strBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}", constantKey);
116            strBuilder.Append("*");
117            constants.Add(new KeyValuePair<string, double>(constantKey, varNode.Weight));
118            constantCounter++;
119          }
120          if (varNode.VariableName.Contains("'")) {
121            strBuilder.AppendFormat("\"{0}\"", varNode.VariableName);
122          } else {
123            strBuilder.AppendFormat("'{0}'", varNode.VariableName);
124          }
125          if (!varNode.Weight.IsAlmost(1.0)) {
126            strBuilder.Append(")");
127          }
128        } else if (node.Symbol is FactorVariable) {
129          var factorNode = node as FactorVariableTreeNode;
130          if (factorNode.VariableName.Contains("'")) {
131            strBuilder.AppendFormat("\"{0}\"", factorNode.VariableName);
132          } else {
133            strBuilder.AppendFormat("'{0}'", factorNode.VariableName);
134          }
135          strBuilder.AppendFormat("[{0}]",
136            string.Join(", ", factorNode.Weights.Select(w => w.ToString(CultureInfo.InvariantCulture))));
137        } else if (node.Symbol is BinaryFactorVariable) {
138          var factorNode = node as BinaryFactorVariableTreeNode;
139          if (!factorNode.Weight.IsAlmost(1.0)) {
140            strBuilder.Append("(");
141            strBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}", factorNode.Weight);
142            strBuilder.Append("*");
143          }
144          if (factorNode.VariableName.Contains("'")) {
145            strBuilder.AppendFormat("\"{0}\"", factorNode.VariableName);
146          } else {
147            strBuilder.AppendFormat("'{0}'", factorNode.VariableName);
148          }
149          strBuilder.Append(" = ");
150          if (factorNode.VariableValue.Contains("'")) {
151            strBuilder.AppendFormat("\"{0}\"", factorNode.VariableValue);
152          } else {
153            strBuilder.AppendFormat("'{0}'", factorNode.VariableValue);
154          }
155
156          if (!factorNode.Weight.IsAlmost(1.0)) {
157            strBuilder.Append(")");
158          }
159
160        } else if (node.Symbol is Constant) {
161          var constNode = node as ConstantTreeNode;
162          string constantKey = $"c_{constantCounter}";
163
164          strBuilder.AppendFormat(CultureInfo.InvariantCulture, constantKey);
165          constants.Add(new KeyValuePair<string, double>(constantKey, constNode.Value));
166          constantCounter++;
167        }
168      }
169    }
170
171    private string GetToken(ISymbol symbol) {
172      var tok = InfixExpressionParser.knownSymbols.GetBySecond(symbol).SingleOrDefault();
173      if (tok == null)
174        throw new ArgumentException(string.Format("Unknown symbol {0} found.", symbol.Name));
175      return tok;
176    }
177  }
178}
Note: See TracBrowser for help on using the repository browser.