Free cookie consent management tool by TermsFeed Policy Generator

source: branches/DataAnalysis.Extensions/HeuristicLab.Problems.DataAnalysis/3.3/Symbolic/Formatters/SymbolicExpressionTreeLatexFormatter.cs @ 5551

Last change on this file since 5551 was 4969, checked in by gkronber, 14 years ago

Improved LaTeX string formatter to support all available function symbols and output all constant values. #1152

File size: 10.6 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2010 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.Text;
23using System.Linq;
24using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
25using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
26using System.Collections.Generic;
27using HeuristicLab.Problems.DataAnalysis.Symbolic.Symbols;
28using System;
29using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Symbols;
30using HeuristicLab.Core;
31using HeuristicLab.Common;
32
33namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Formatters {
34  [Item("LaTeX String Formatter", "Formatter for symbolic expression trees for import into LaTeX documents.")]
35  public sealed class SymbolicExpressionTreeLatexFormatter : NamedItem, ISymbolicExpressionTreeStringFormatter {
36    private List<double> constants;
37
38    public SymbolicExpressionTreeLatexFormatter()
39      : base("LaTeX String Formatter", "Formatter for symbolic expression trees for import into LaTeX documents.") {
40      constants = new List<double>();
41    }
42    private SymbolicExpressionTreeLatexFormatter(SymbolicExpressionTreeLatexFormatter original, Cloner cloner)
43      : base(original, cloner) {
44      constants = new List<double>(original.constants);
45    }
46
47    public override IDeepCloneable Clone(Cloner cloner) {
48      return new SymbolicExpressionTreeLatexFormatter(this, cloner);
49    }
50
51    public string Format(SymbolicExpressionTree symbolicExpressionTree) {
52      try {
53        StringBuilder strBuilder = new StringBuilder();
54        constants.Clear();
55        strBuilder.AppendLine("% needs \\usepackage{amsmath}");
56        strBuilder.AppendLine("\\begin{align}");
57        strBuilder.AppendLine(FormatRecursively(symbolicExpressionTree.Root));
58        strBuilder.AppendLine("\\end{align}");
59        return strBuilder.ToString();
60      }
61      catch (NotImplementedException ex) {
62        return ex.Message + Environment.NewLine + ex.StackTrace;
63      }
64    }
65
66    private string FormatRecursively(SymbolicExpressionTreeNode node) {
67      StringBuilder strBuilder = new StringBuilder();
68
69      FormatBegin(node, strBuilder);
70
71      if (node.SubTrees.Count > 0) {
72        strBuilder.Append(FormatRecursively(node.SubTrees[0]));
73      }
74      foreach (SymbolicExpressionTreeNode subTree in node.SubTrees.Skip(1)) {
75        FormatSep(node, strBuilder);
76        // format the whole subtree
77        strBuilder.Append(FormatRecursively(subTree));
78      }
79
80      FormatEnd(node, strBuilder);
81
82      return strBuilder.ToString();
83    }
84
85    private void FormatBegin(SymbolicExpressionTreeNode node, StringBuilder strBuilder) {
86      if (node.Symbol is Addition) {
87        strBuilder.Append(@" \left( ");
88      } else if (node.Symbol is Subtraction) {
89        strBuilder.Append(@" \left( ");
90      } else if (node.Symbol is Multiplication) {
91      } else if (node.Symbol is Division) {
92        if (node.SubTrees.Count != 2) throw new NotImplementedException("Division with more than 2 arguments is not implemented.");
93        strBuilder.Append(@" \frac{ ");
94      } else if (node.Symbol is Average) {
95        strBuilder.Append(@" \frac{1}{" + node.SubTrees.Count + @"} \left(");
96      } else if (node.Symbol is Logarithm) {
97        strBuilder.Append(@"\log \left(");
98      } else if (node.Symbol is Exponential) {
99        strBuilder.Append(@"\exp \left(");
100      } else if (node.Symbol is Sine) {
101        strBuilder.Append(@"\sin \left(");
102      } else if (node.Symbol is Cosine) {
103        strBuilder.Append(@"\cos \left(");
104      } else if (node.Symbol is Tangent) {
105        strBuilder.Append(@"\tan \left(");
106      } else if (node.Symbol is GreaterThan) {
107        strBuilder.Append(@" \left( ");
108      } else if (node.Symbol is LessThan) {
109        strBuilder.Append(@" \left( ");
110      } else if (node.Symbol is And) {
111        strBuilder.Append(@" \left( \left( ");
112      } else if (node.Symbol is Or) {
113        strBuilder.Append(@" \left( \left( ");
114      } else if (node.Symbol is Not) {
115        strBuilder.Append(@" -1.0 \times \left( ");
116      } else if (node.Symbol is IfThenElse) {
117        strBuilder.Append(@"\left( \operatorname{if} \left( 0 < ");
118      } else if (node.Symbol is Constant) {
119        strBuilder.Append("c_{" + constants.Count+"} ");
120        var constNode = node as ConstantTreeNode;
121        constants.Add(constNode.Value);
122      } else if (node.Symbol is HeuristicLab.Problems.DataAnalysis.Symbolic.Symbols.Variable) {
123        var varNode = node as VariableTreeNode;
124        strBuilder.Append("c_{" + constants.Count + "} " + varNode.VariableName + " ");
125        constants.Add(varNode.Weight);
126      } else if (node.Symbol is LaggedVariable) {
127        var laggedVarNode = node as LaggedVariableTreeNode;
128        strBuilder.Append("c_{" + constants.Count + "} " + laggedVarNode.VariableName + "(t" + laggedVarNode.Lag + ")");
129        constants.Add(laggedVarNode.Weight);
130      } else if (node.Symbol is ProgramRootSymbol) {
131      } else if (node.Symbol is Defun) {
132        var defunNode = node as DefunTreeNode;
133        strBuilder.Append(defunNode.FunctionName + " & = ");
134      } else if (node.Symbol is InvokeFunction) {
135        var invokeNode = node as InvokeFunctionTreeNode;
136        strBuilder.Append(invokeNode.Symbol.FunctionName + @" \left( ");
137      } else if (node.Symbol is StartSymbol) {
138        strBuilder.Append("Result & = ");
139      } else if (node.Symbol is Argument) {
140        var argSym = node.Symbol as Argument;
141        strBuilder.Append(" ARG+" + argSym.ArgumentIndex + " ");
142      } else {
143        throw new NotImplementedException("Export of " + node.Symbol + " is not implemented.");
144      }
145    }
146
147    private void FormatSep(SymbolicExpressionTreeNode node, StringBuilder strBuilder) {
148      if (node.Symbol is Addition) {
149        strBuilder.Append(" + ");
150      } else if (node.Symbol is Subtraction) {
151        strBuilder.Append(" - ");
152      } else if (node.Symbol is Multiplication) {
153        strBuilder.Append(@" \times ");
154      } else if (node.Symbol is Division) {
155        strBuilder.Append(" }{ ");
156      } else if (node.Symbol is Average) {
157        strBuilder.Append(@" + ");
158      } else if (node.Symbol is Logarithm) {
159        throw new InvalidOperationException();
160      } else if (node.Symbol is Exponential) {
161        throw new InvalidOperationException();
162      } else if (node.Symbol is Sine) {
163        throw new InvalidOperationException();
164      } else if (node.Symbol is Cosine) {
165        throw new InvalidOperationException();
166      } else if (node.Symbol is Tangent) {
167        throw new InvalidOperationException();
168      } else if (node.Symbol is GreaterThan) {
169        strBuilder.Append(@" > ");
170      } else if (node.Symbol is LessThan) {
171        strBuilder.Append(@" < ");
172      } else if (node.Symbol is And) {
173        strBuilder.Append(@" > 0 \right) \land \left(");
174      } else if (node.Symbol is Or) {
175        strBuilder.Append(@" > 0 \right) \lor \left(");
176      } else if (node.Symbol is Not) {
177        throw new InvalidOperationException();
178      } else if (node.Symbol is IfThenElse) {
179        strBuilder.Append(@" \right) , \left(");
180      } else if (node.Symbol is ProgramRootSymbol) {
181        strBuilder.Append(@"\\" + Environment.NewLine);
182      } else if (node.Symbol is Defun) {
183      } else if (node.Symbol is InvokeFunction) {
184        strBuilder.Append(" , ");
185      } else if (node.Symbol is StartSymbol) {
186        strBuilder.Append(@"\\" + Environment.NewLine + " & ");
187      } else {
188        throw new NotImplementedException("Export of " + node.Symbol + " is not implemented.");
189      }
190    }
191
192    private void FormatEnd(SymbolicExpressionTreeNode node, StringBuilder strBuilder) {
193      if (node.Symbol is Addition) {
194        strBuilder.Append(@" \right) ");
195      } else if (node.Symbol is Subtraction) {
196        strBuilder.Append(@" \right) ");
197      } else if (node.Symbol is Multiplication) {
198      } else if (node.Symbol is Division) {
199        strBuilder.Append(" } ");
200      } else if (node.Symbol is Average) {
201        strBuilder.Append(@" \right)");
202      } else if (node.Symbol is Logarithm) {
203        strBuilder.Append(@" \right) ");
204      } else if (node.Symbol is Exponential) {
205        strBuilder.Append(@" \right) ");
206      } else if (node.Symbol is Sine) {
207        strBuilder.Append(@" \right) ");
208      } else if (node.Symbol is Cosine) {
209        strBuilder.Append(@" \right) ");
210      } else if (node.Symbol is Tangent) {
211        strBuilder.Append(@" \right) ");
212      } else if (node.Symbol is GreaterThan) {
213        strBuilder.Append(@" \right) ");
214      } else if (node.Symbol is LessThan) {
215        strBuilder.Append(@" \right) ");
216      } else if (node.Symbol is And) {
217        strBuilder.Append(@" > 0 \right) \right) ");
218      } else if (node.Symbol is Or) {
219        strBuilder.Append(@" > 0 \right) \right) ");
220      } else if (node.Symbol is Not) {
221        strBuilder.Append(@" \right) ");
222      } else if (node.Symbol is IfThenElse) {
223        strBuilder.Append(@" \right) \right) ");
224      } else if (node.Symbol is Constant) {
225      } else if (node.Symbol is HeuristicLab.Problems.DataAnalysis.Symbolic.Symbols.Variable) {
226      } else if (node.Symbol is LaggedVariable) {
227      } else if (node.Symbol is ProgramRootSymbol) {
228        // output all constant values
229        if (constants.Count > 0) {
230          int i = 0;
231          foreach (var constant in constants) {
232            strBuilder.AppendLine(@"\\");
233            strBuilder.Append("c_{" + i + "} & = " + constant);
234            i++;
235          }
236        }
237      } else if (node.Symbol is Defun) {
238      } else if (node.Symbol is InvokeFunction) {
239        strBuilder.Append(@" \right) ");
240      } else if (node.Symbol is StartSymbol) {
241      } else if (node.Symbol is Argument) {
242      } else {
243        throw new NotImplementedException("Export of " + node.Symbol + " is not implemented.");
244      }
245    }
246  }
247}
Note: See TracBrowser for help on using the repository browser.