Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.LinqExpressionTreeInterpreter/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Formatters/SymbolicDataAnalysisExpressionCSharpFormatter.cs @ 13141

Last change on this file since 13141 was 13141, checked in by bburlacu, 8 years ago

#2442: Merged files from trunk and updated project file. Implemented missing operations in the CompiledTreeInterpreter: Integral, Derivative, Lag, TimeLag. Adapted lambda signature to accept an array of List<double> in order to make it easier to work with compiled trees. Changed value parameters to fixed value parameters and adjusted interpreter constructors and after serialization hooks. Removed function symbol.

From the performance point of view, compiling the tree into a lambda accepting a double[][] parameter (an array of arrays for the values of each double variable), accessed with Expression.ArrayIndex is the fastest, but it can be cumbersome to provide the data as a double[][]. Therefore the variant with List<double>[] was chosen. Internally, for each variable node the List's underlying double array is used, result in an overall decent speed compromise.

File size: 9.1 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.Globalization;
25using System.Linq;
26using System.Text;
27using HeuristicLab.Common;
28using HeuristicLab.Core;
29using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
30using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
31
32namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
33  [Item("C# Symbolic Expression Tree Formatter", "A string formatter that converts symbolic expression trees to C# code.")]
34  [StorableClass]
35  public sealed class CSharpSymbolicExpressionTreeStringFormatter : NamedItem, ISymbolicExpressionTreeStringFormatter {
36    [StorableConstructor]
37    private CSharpSymbolicExpressionTreeStringFormatter(bool deserializing) : base(deserializing) { }
38    private CSharpSymbolicExpressionTreeStringFormatter(CSharpSymbolicExpressionTreeStringFormatter original, Cloner cloner) : base(original, cloner) { }
39    public CSharpSymbolicExpressionTreeStringFormatter()
40      : base() {
41      Name = ItemName;
42      Description = ItemDescription;
43    }
44    public override IDeepCloneable Clone(Cloner cloner) {
45      return new CSharpSymbolicExpressionTreeStringFormatter(this, cloner);
46    }
47
48    public string Format(ISymbolicExpressionTree symbolicExpressionTree) {
49      // skip root and start symbols
50      StringBuilder strBuilder = new StringBuilder();
51      GenerateHeader(strBuilder, symbolicExpressionTree);
52      FormatRecursively(symbolicExpressionTree.Root.GetSubtree(0).GetSubtree(0), strBuilder);
53      GenerateFooter(strBuilder);
54      return strBuilder.ToString();
55    }
56
57    private void FormatRecursively(ISymbolicExpressionTreeNode node, StringBuilder strBuilder) {
58      // TODO: adapt to interpreter semantics. The HL interpreter also allows Boolean operations on reals
59      if (node.Subtrees.Any()) {
60        if (node.Symbol is Addition) {
61          FormatOperator(node, "+", strBuilder);
62        } else if (node.Symbol is And) {
63          FormatOperator(node, "&&", strBuilder);
64        } else if (node.Symbol is Average) {
65          FormatFunction(node, "Average", strBuilder);
66        } else if (node.Symbol is Cosine) {
67          FormatFunction(node, "Math.Cos", strBuilder);
68        } else if (node.Symbol is Division) {
69          FormatDivision(node, strBuilder);
70        } else if (node.Symbol is Exponential) {
71          FormatFunction(node, "Math.Exp", strBuilder);
72        } else if (node.Symbol is GreaterThan) {
73          FormatOperator(node, ">", strBuilder);
74        } else if (node.Symbol is IfThenElse) {
75          FormatFunction(node, "EvaluateIf", strBuilder);
76        } else if (node.Symbol is LessThan) {
77          FormatOperator(node, "<", strBuilder);
78        } else if (node.Symbol is Logarithm) {
79          FormatFunction(node, "Math.Log", strBuilder);
80        } else if (node.Symbol is Multiplication) {
81          FormatOperator(node, "*", strBuilder);
82        } else if (node.Symbol is Not) {
83          FormatOperator(node, "!", strBuilder);
84        } else if (node.Symbol is Or) {
85          FormatOperator(node, "||", strBuilder);
86        } else if (node.Symbol is Xor) {
87          FormatOperator(node, "^", strBuilder);
88        } else if (node.Symbol is Sine) {
89          FormatFunction(node, "Math.Sin", strBuilder);
90        } else if (node.Symbol is Subtraction) {
91          FormatOperator(node, "-", strBuilder);
92        } else if (node.Symbol is Tangent) {
93          FormatFunction(node, "Math.Tan", strBuilder);
94        } else if (node.Symbol is Square) {
95          FormatSquare(node, strBuilder);
96        } else if (node.Symbol is SquareRoot) {
97          FormatFunction(node, "Math.Sqrt", strBuilder);
98        } else if (node.Symbol is Power) {
99          FormatFunction(node, "Math.Pow", strBuilder);
100        } else if (node.Symbol is Root) {
101          FormatRoot(node, strBuilder);
102        } else {
103          throw new NotSupportedException("Formatting of symbol: " + node.Symbol + " not supported for C# symbolic expression tree formatter.");
104        }
105      } else {
106        if (node is VariableTreeNode) {
107          var varNode = node as VariableTreeNode;
108          strBuilder.AppendFormat("{0} * {1}", varNode.VariableName, varNode.Weight.ToString("g17", CultureInfo.InvariantCulture));
109        } else if (node is ConstantTreeNode) {
110          var constNode = node as ConstantTreeNode;
111          strBuilder.Append(constNode.Value.ToString("g17", CultureInfo.InvariantCulture));
112        } else {
113          throw new NotSupportedException("Formatting of symbol: " + node.Symbol + " not supported for C# symbolic expression tree formatter.");
114        }
115      }
116    }
117
118    private void FormatSquare(ISymbolicExpressionTreeNode node, StringBuilder strBuilder) {
119      strBuilder.Append("Math.Pow(");
120      FormatRecursively(node.GetSubtree(0), strBuilder);
121      strBuilder.Append(", 2)");
122    }
123
124    private void FormatRoot(ISymbolicExpressionTreeNode node, StringBuilder strBuilder) {
125      strBuilder.Append("Math.Pow(");
126      FormatRecursively(node.GetSubtree(0), strBuilder);
127      strBuilder.Append(", 1.0 / (");
128      FormatRecursively(node.GetSubtree(1), strBuilder);
129      strBuilder.Append("))");
130    }
131
132    private void FormatDivision(ISymbolicExpressionTreeNode node, StringBuilder strBuilder) {
133      if (node.SubtreeCount == 1) {
134        strBuilder.Append("1.0 / ");
135        FormatRecursively(node.GetSubtree(0), strBuilder);
136      } else {
137        FormatRecursively(node.GetSubtree(0), strBuilder);
138        strBuilder.Append("/ (");
139        for (int i = 1; i < node.SubtreeCount; i++) {
140          if (i > 1) strBuilder.Append(" * ");
141          FormatRecursively(node.GetSubtree(i), strBuilder);
142        }
143        strBuilder.Append(")");
144      }
145    }
146
147    private void FormatOperator(ISymbolicExpressionTreeNode node, string symbol, StringBuilder strBuilder) {
148      strBuilder.Append("(");
149      foreach (var child in node.Subtrees) {
150        FormatRecursively(child, strBuilder);
151        if (child != node.Subtrees.Last())
152          strBuilder.Append(" " + symbol + " ");
153      }
154      strBuilder.Append(")");
155    }
156
157    private void FormatFunction(ISymbolicExpressionTreeNode node, string function, StringBuilder strBuilder) {
158      strBuilder.Append(function + "(");
159      foreach (var child in node.Subtrees) {
160        FormatRecursively(child, strBuilder);
161        if (child != node.Subtrees.Last())
162          strBuilder.Append(", ");
163      }
164      strBuilder.Append(")");
165    }
166
167    private void GenerateHeader(StringBuilder strBuilder, ISymbolicExpressionTree symbolicExpressionTree) {
168      strBuilder.AppendLine("using System;");
169      strBuilder.AppendLine("using System.Linq;" + Environment.NewLine);
170      strBuilder.AppendLine("namespace HeuristicLab.Models {");
171      strBuilder.AppendLine("public static class Model {");
172      GenerateAverageSource(strBuilder);
173      GenerateIfThenElseSource(strBuilder);
174      strBuilder.Append(Environment.NewLine + "public static double Evaluate (");
175
176      HashSet<string> varNames = new HashSet<string>();
177      foreach (var node in symbolicExpressionTree.IterateNodesPostfix().Where(x => x is VariableTreeNode)) {
178        varNames.Add(((VariableTreeNode)node).VariableName);
179      }
180
181      var orderedNames = varNames.OrderBy(n => n, new NaturalStringComparer()).Select(n=> "double " + n);
182      strBuilder.Append(string.Join(", ", orderedNames));
183
184      strBuilder.AppendLine(") {");
185      strBuilder.Append("double result = ");
186    }
187
188    private void GenerateFooter(StringBuilder strBuilder) {
189      strBuilder.AppendLine(";");
190      strBuilder.AppendLine("return result;");
191      strBuilder.AppendLine("}");
192      strBuilder.AppendLine("}");
193      strBuilder.AppendLine("}");
194    }
195
196    private void GenerateAverageSource(StringBuilder strBuilder) {
197      strBuilder.AppendLine("private static double Average(params double[] values) {");
198      strBuilder.AppendLine("  return values.Average();");
199      strBuilder.AppendLine("}");
200    }
201
202    private void GenerateIfThenElseSource(StringBuilder strBuilder) {
203      strBuilder.AppendLine("private static double EvaluateIf(bool condition, double then, double @else) {");
204      strBuilder.AppendLine("   return condition ? then : @else;");
205      strBuilder.AppendLine("}");
206    }
207  }
208}
Note: See TracBrowser for help on using the repository browser.