Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Problems.DataAnalysis/3.3/Symbolic/Formatters/SymbolicExpressionTreeLatexFormatter.cs @ 5429

Last change on this file since 5429 was 5429, checked in by gkronber, 13 years ago

Made LaTeX formatter storable. #1152

File size: 12.9 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  [StorableClass]
36  public sealed class SymbolicExpressionTreeLatexFormatter : NamedItem, ISymbolicExpressionTreeStringFormatter {
37    private List<double> constants;
38    private int currentLag;
39
40    [StorableConstructor]
41    private SymbolicExpressionTreeLatexFormatter(bool deserializing) : base(deserializing) { }
42    private SymbolicExpressionTreeLatexFormatter(SymbolicExpressionTreeLatexFormatter original, Cloner cloner)
43      : base(original, cloner) {
44      constants = new List<double>(original.constants);
45    }
46    public SymbolicExpressionTreeLatexFormatter()
47      : base("LaTeX String Formatter", "Formatter for symbolic expression trees for import into LaTeX documents.") {
48      constants = new List<double>();
49    }
50
51    public override IDeepCloneable Clone(Cloner cloner) {
52      return new SymbolicExpressionTreeLatexFormatter(this, cloner);
53    }
54
55    public string Format(SymbolicExpressionTree symbolicExpressionTree) {
56      try {
57        StringBuilder strBuilder = new StringBuilder();
58        constants.Clear();
59        strBuilder.AppendLine("% needs \\usepackage{amsmath}");
60        strBuilder.AppendLine("\\begin{align}");
61        strBuilder.AppendLine(FormatRecursively(symbolicExpressionTree.Root));
62        strBuilder.AppendLine("\\end{align}");
63        return strBuilder.ToString();
64      }
65      catch (NotImplementedException ex) {
66        return ex.Message + Environment.NewLine + ex.StackTrace;
67      }
68    }
69
70    private string FormatRecursively(SymbolicExpressionTreeNode node) {
71      StringBuilder strBuilder = new StringBuilder();
72      currentLag = 0;
73      FormatBegin(node, strBuilder);
74
75      if (node.SubTrees.Count > 0) {
76        strBuilder.Append(FormatRecursively(node.SubTrees[0]));
77      }
78      foreach (SymbolicExpressionTreeNode subTree in node.SubTrees.Skip(1)) {
79        FormatSep(node, strBuilder);
80        // format the whole subtree
81        strBuilder.Append(FormatRecursively(subTree));
82      }
83
84      FormatEnd(node, strBuilder);
85
86      return strBuilder.ToString();
87    }
88
89    private void FormatBegin(SymbolicExpressionTreeNode node, StringBuilder strBuilder) {
90      if (node.Symbol is Addition) {
91        strBuilder.Append(@" \left( ");
92      } else if (node.Symbol is Subtraction) {
93        if (node.SubTrees.Count == 1) {
94          strBuilder.Append(@"- \left(");
95        } else {
96          strBuilder.Append(@" \left( ");
97        }
98      } else if (node.Symbol is Multiplication) {
99      } else if (node.Symbol is Division) {
100        if (node.SubTrees.Count == 1) {
101          strBuilder.Append(@" \cfrac{1}{");
102        } else {
103          strBuilder.Append(@" \cfrac{ ");
104        }
105      } else if (node.Symbol is Average) {
106        // skip output of (1/1) if only one subtree
107        if (node.SubTrees.Count > 1) {
108          strBuilder.Append(@" \cfrac{1}{" + node.SubTrees.Count + @"}");
109        }
110        strBuilder.Append(@" \left(");
111      } else if (node.Symbol is Logarithm) {
112        strBuilder.Append(@"\log \left(");
113      } else if (node.Symbol is Exponential) {
114        strBuilder.Append(@"\exp \left(");
115      } else if (node.Symbol is Sine) {
116        strBuilder.Append(@"\sin \left(");
117      } else if (node.Symbol is Cosine) {
118        strBuilder.Append(@"\cos \left(");
119      } else if (node.Symbol is Tangent) {
120        strBuilder.Append(@"\tan \left(");
121      } else if (node.Symbol is GreaterThan) {
122        strBuilder.Append(@" \left( ");
123      } else if (node.Symbol is LessThan) {
124        strBuilder.Append(@" \left( ");
125      } else if (node.Symbol is And) {
126        strBuilder.Append(@" \left( \left( ");
127      } else if (node.Symbol is Or) {
128        strBuilder.Append(@" \left( \left( ");
129      } else if (node.Symbol is Not) {
130        strBuilder.Append(@" -1.0 \cdot \left( ");
131      } else if (node.Symbol is IfThenElse) {
132        strBuilder.Append(@"\left( \operatorname{if} \left( 0 < ");
133      } else if (node.Symbol is Constant) {
134        strBuilder.Append("c_{" + constants.Count + "} ");
135        var constNode = node as ConstantTreeNode;
136        constants.Add(constNode.Value);
137      } else if (node.Symbol is LaggedVariable) {
138        var laggedVarNode = node as LaggedVariableTreeNode;
139        strBuilder.Append("c_{" + constants.Count + "} " + laggedVarNode.VariableName);
140        strBuilder.Append(LagToString(currentLag + laggedVarNode.Lag));
141        constants.Add(laggedVarNode.Weight);
142      } else if (node.Symbol is HeuristicLab.Problems.DataAnalysis.Symbolic.Symbols.Variable) {
143        var varNode = node as VariableTreeNode;
144        strBuilder.Append("c_{" + constants.Count + "} " + varNode.VariableName);
145        strBuilder.Append(LagToString(currentLag));
146        constants.Add(varNode.Weight);
147      } else if (node.Symbol is ProgramRootSymbol) {
148      } else if (node.Symbol is Defun) {
149        var defunNode = node as DefunTreeNode;
150        strBuilder.Append(defunNode.FunctionName + " & = ");
151      } else if (node.Symbol is InvokeFunction) {
152        var invokeNode = node as InvokeFunctionTreeNode;
153        strBuilder.Append(invokeNode.Symbol.FunctionName + @" \left( ");
154      } else if (node.Symbol is StartSymbol) {
155        strBuilder.Append("Result & = ");
156      } else if (node.Symbol is Argument) {
157        var argSym = node.Symbol as Argument;
158        strBuilder.Append(" ARG+" + argSym.ArgumentIndex + " ");
159      } else if (node.Symbol is Derivative) {
160        strBuilder.Append(@" \cfrac{d \left(");
161      } else if (node.Symbol is TimeLag) {
162        var laggedNode = node as ILaggedTreeNode;
163        currentLag += laggedNode.Lag;
164      } else if (node.Symbol is Power) {
165        strBuilder.Append(@"\left(");
166      } else if (node.Symbol is Root) {
167        strBuilder.Append(@"\left(");
168      } else if (node.Symbol is Integral) {
169        // actually a new variable for t is needed in all subtrees (TODO)
170        var laggedTreeNode = node as ILaggedTreeNode;
171        strBuilder.Append(@"\sum_{t=" + (laggedTreeNode.Lag + currentLag) + @"}^0 \left(");
172      } else {
173        throw new NotImplementedException("Export of " + node.Symbol + " is not implemented.");
174      }
175    }
176
177    private void FormatSep(SymbolicExpressionTreeNode node, StringBuilder strBuilder) {
178      if (node.Symbol is Addition) {
179        strBuilder.Append(" + ");
180      } else if (node.Symbol is Subtraction) {
181        strBuilder.Append(" - ");
182      } else if (node.Symbol is Multiplication) {
183        strBuilder.Append(@" \cdot ");
184      } else if (node.Symbol is Division) {
185        strBuilder.Append(@" }{ \cfrac{ ");
186      } else if (node.Symbol is Average) {
187        strBuilder.Append(@" + ");
188      } else if (node.Symbol is Logarithm) {
189        throw new InvalidOperationException();
190      } else if (node.Symbol is Exponential) {
191        throw new InvalidOperationException();
192      } else if (node.Symbol is Sine) {
193        throw new InvalidOperationException();
194      } else if (node.Symbol is Cosine) {
195        throw new InvalidOperationException();
196      } else if (node.Symbol is Tangent) {
197        throw new InvalidOperationException();
198      } else if (node.Symbol is GreaterThan) {
199        strBuilder.Append(@" > ");
200      } else if (node.Symbol is LessThan) {
201        strBuilder.Append(@" < ");
202      } else if (node.Symbol is And) {
203        strBuilder.Append(@" > 0 \right) \land \left(");
204      } else if (node.Symbol is Or) {
205        strBuilder.Append(@" > 0 \right) \lor \left(");
206      } else if (node.Symbol is Not) {
207        throw new InvalidOperationException();
208      } else if (node.Symbol is IfThenElse) {
209        strBuilder.Append(@" \right) , \left(");
210      } else if (node.Symbol is ProgramRootSymbol) {
211        strBuilder.Append(@"\\" + Environment.NewLine);
212      } else if (node.Symbol is Defun) {
213      } else if (node.Symbol is InvokeFunction) {
214        strBuilder.Append(" , ");
215      } else if (node.Symbol is StartSymbol) {
216        strBuilder.Append(@"\\" + Environment.NewLine + " & ");
217      } else if (node.Symbol is Power) {
218        strBuilder.Append(@"\right) ^ { \operatorname{round} \left(");
219      } else if (node.Symbol is Root) {
220        strBuilder.Append(@"\right) ^ { \left( \cfrac{1}{ \operatorname{round} \left(");
221      } else {
222        throw new NotImplementedException("Export of " + node.Symbol + " is not implemented.");
223      }
224    }
225
226    private void FormatEnd(SymbolicExpressionTreeNode node, StringBuilder strBuilder) {
227      if (node.Symbol is Addition) {
228        strBuilder.Append(@" \right) ");
229      } else if (node.Symbol is Subtraction) {
230        strBuilder.Append(@" \right) ");
231      } else if (node.Symbol is Multiplication) {
232      } else if (node.Symbol is Division) {
233        strBuilder.Append("} ");
234        if (node.SubTrees.Count > 1)
235          strBuilder.Append("{1} ");
236        for (int i = 1; i < node.SubTrees.Count; i++) {
237          strBuilder.Append(" } ");
238        }
239      } else if (node.Symbol is Average) {
240        strBuilder.Append(@" \right)");
241      } else if (node.Symbol is Logarithm) {
242        strBuilder.Append(@" \right) ");
243      } else if (node.Symbol is Exponential) {
244        strBuilder.Append(@" \right) ");
245      } else if (node.Symbol is Sine) {
246        strBuilder.Append(@" \right) ");
247      } else if (node.Symbol is Cosine) {
248        strBuilder.Append(@" \right) ");
249      } else if (node.Symbol is Tangent) {
250        strBuilder.Append(@" \right) ");
251      } else if (node.Symbol is GreaterThan) {
252        strBuilder.Append(@" \right) ");
253      } else if (node.Symbol is LessThan) {
254        strBuilder.Append(@" \right) ");
255      } else if (node.Symbol is And) {
256        strBuilder.Append(@" > 0 \right) \right) ");
257      } else if (node.Symbol is Or) {
258        strBuilder.Append(@" > 0 \right) \right) ");
259      } else if (node.Symbol is Not) {
260        strBuilder.Append(@" \right) ");
261      } else if (node.Symbol is IfThenElse) {
262        strBuilder.Append(@" \right) \right) ");
263      } else if (node.Symbol is Constant) {
264      } else if (node.Symbol is LaggedVariable) {
265      } else if (node.Symbol is HeuristicLab.Problems.DataAnalysis.Symbolic.Symbols.Variable) {
266      } else if (node.Symbol is ProgramRootSymbol) {
267        // output all constant values
268        if (constants.Count > 0) {
269          int i = 0;
270          foreach (var constant in constants) {
271            strBuilder.AppendLine(@"\\");
272            strBuilder.Append("c_{" + i + "} & = " + constant);
273            i++;
274          }
275        }
276      } else if (node.Symbol is Defun) {
277      } else if (node.Symbol is InvokeFunction) {
278        strBuilder.Append(@" \right) ");
279      } else if (node.Symbol is StartSymbol) {
280      } else if (node.Symbol is Argument) {
281      } else if (node.Symbol is Derivative) {
282        strBuilder.Append(@" \right) }{dt} ");
283      } else if (node.Symbol is TimeLag) {
284        var laggedNode = node as ILaggedTreeNode;
285        currentLag -= laggedNode.Lag;
286      } else if (node.Symbol is Power) {
287        strBuilder.Append(@"\right) } ");
288      } else if (node.Symbol is Root) {
289        strBuilder.Append(@"\right) } \right) } ");
290      } else if (node.Symbol is Integral) {
291        var laggedTreeNode = node as ILaggedTreeNode;
292        strBuilder.Append(@"\right) ");
293      } else {
294        throw new NotImplementedException("Export of " + node.Symbol + " is not implemented.");
295      }
296    }
297    private string LagToString(int lag) {
298      if (lag < 0) {
299        return "(t" + lag + ")";
300      } else if (lag > 0) {
301        return "(t+" + lag + ")";
302      } else return "(t)";
303    }
304  }
305}
Note: See TracBrowser for help on using the repository browser.