Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Formatters/SymbolicDataAnalysisExpressionLatexFormatter.cs @ 7317

Last change on this file since 7317 was 7259, checked in by swagner, 13 years ago

Updated year of copyrights to 2012 (#1716)

File size: 13.9 KB
RevLine 
[4327]1#region License Information
2/* HeuristicLab
[7259]3 * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
[4327]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
[6975]22using System;
23using System.Collections.Generic;
24using System.Linq;
[4327]25using System.Text;
[6975]26using HeuristicLab.Common;
27using HeuristicLab.Core;
28using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
[4327]29using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
30
[5745]31namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
[4969]32  [Item("LaTeX String Formatter", "Formatter for symbolic expression trees for import into LaTeX documents.")]
[5429]33  [StorableClass]
[5745]34  public sealed class SymbolicDataAnalysisExpressionLatexFormatter : NamedItem, ISymbolicExpressionTreeStringFormatter {
[4969]35    private List<double> constants;
[5428]36    private int currentLag;
[4969]37
[5429]38    [StorableConstructor]
[5745]39    private SymbolicDataAnalysisExpressionLatexFormatter(bool deserializing) : base(deserializing) { }
40    private SymbolicDataAnalysisExpressionLatexFormatter(SymbolicDataAnalysisExpressionLatexFormatter original, Cloner cloner)
[5429]41      : base(original, cloner) {
42      constants = new List<double>(original.constants);
43    }
[5745]44    public SymbolicDataAnalysisExpressionLatexFormatter()
45      : base() {
46      Name = ItemName;
47      Description = ItemDescription;
[4969]48      constants = new List<double>();
49    }
[4327]50
[4900]51    public override IDeepCloneable Clone(Cloner cloner) {
[5745]52      return new SymbolicDataAnalysisExpressionLatexFormatter(this, cloner);
[4900]53    }
54
[5745]55    public string Format(ISymbolicExpressionTree symbolicExpressionTree) {
[4327]56      try {
57        StringBuilder strBuilder = new StringBuilder();
[4969]58        constants.Clear();
59        strBuilder.AppendLine("% needs \\usepackage{amsmath}");
[7038]60        strBuilder.AppendLine("\\begin{align*}");
61        strBuilder.AppendLine("\\nonumber");
[4327]62        strBuilder.AppendLine(FormatRecursively(symbolicExpressionTree.Root));
[7038]63        strBuilder.AppendLine("\\end{align*}");
[4327]64        return strBuilder.ToString();
65      }
66      catch (NotImplementedException ex) {
67        return ex.Message + Environment.NewLine + ex.StackTrace;
68      }
69    }
70
[5745]71    private string FormatRecursively(ISymbolicExpressionTreeNode node) {
[4327]72      StringBuilder strBuilder = new StringBuilder();
[5428]73      currentLag = 0;
[4327]74      FormatBegin(node, strBuilder);
75
[6803]76      if (node.SubtreeCount > 0) {
[5745]77        strBuilder.Append(FormatRecursively(node.GetSubtree(0)));
[4327]78      }
[7140]79      int i = 1;
[5745]80      foreach (SymbolicExpressionTreeNode subTree in node.Subtrees.Skip(1)) {
[7140]81        FormatSep(node, strBuilder, i);
[4327]82        // format the whole subtree
83        strBuilder.Append(FormatRecursively(subTree));
[7140]84        i++;
[4327]85      }
86
87      FormatEnd(node, strBuilder);
88
89      return strBuilder.ToString();
90    }
91
[5745]92    private void FormatBegin(ISymbolicExpressionTreeNode node, StringBuilder strBuilder) {
[4327]93      if (node.Symbol is Addition) {
[7136]94        strBuilder.Append(@" ( ");
[4327]95      } else if (node.Symbol is Subtraction) {
[6803]96        if (node.SubtreeCount == 1) {
[7136]97          strBuilder.Append(@"- ( ");
[5428]98        } else {
[7136]99          strBuilder.Append(@" ( ");
[5428]100        }
[4327]101      } else if (node.Symbol is Multiplication) {
102      } else if (node.Symbol is Division) {
[6803]103        if (node.SubtreeCount == 1) {
[5428]104          strBuilder.Append(@" \cfrac{1}{");
105        } else {
106          strBuilder.Append(@" \cfrac{ ");
107        }
[4969]108      } else if (node.Symbol is Average) {
[5428]109        // skip output of (1/1) if only one subtree
[6803]110        if (node.SubtreeCount > 1) {
111          strBuilder.Append(@" \cfrac{1}{" + node.SubtreeCount + @"}");
[5428]112        }
[7136]113        strBuilder.Append(@" ( ");
[4969]114      } else if (node.Symbol is Logarithm) {
[7136]115        strBuilder.Append(@"\log ( ");
[4969]116      } else if (node.Symbol is Exponential) {
[7136]117        strBuilder.Append(@"\exp ( ");
[4969]118      } else if (node.Symbol is Sine) {
[7136]119        strBuilder.Append(@"\sin ( ");
[4969]120      } else if (node.Symbol is Cosine) {
[7136]121        strBuilder.Append(@"\cos ( ");
[4969]122      } else if (node.Symbol is Tangent) {
[7136]123        strBuilder.Append(@"\tan ( ");
[4969]124      } else if (node.Symbol is GreaterThan) {
[7136]125        strBuilder.Append(@"  ( ");
[4969]126      } else if (node.Symbol is LessThan) {
[7136]127        strBuilder.Append(@"  ( ");
[4969]128      } else if (node.Symbol is And) {
[7136]129        strBuilder.Append(@"   ( ");
[4969]130      } else if (node.Symbol is Or) {
[7136]131        strBuilder.Append(@"   ( ");
[4969]132      } else if (node.Symbol is Not) {
[7136]133        strBuilder.Append(@" \neg ( ");
[4969]134      } else if (node.Symbol is IfThenElse) {
[7136]135        strBuilder.Append(@" \operatorname{if}  ( 0 < ");
[4327]136      } else if (node.Symbol is Constant) {
[5428]137        strBuilder.Append("c_{" + constants.Count + "} ");
[4969]138        var constNode = node as ConstantTreeNode;
139        constants.Add(constNode.Value);
[5428]140      } else if (node.Symbol is LaggedVariable) {
141        var laggedVarNode = node as LaggedVariableTreeNode;
[7038]142        if (!laggedVarNode.Weight.IsAlmost(1.0)) {
143          strBuilder.Append("c_{" + constants.Count + "} \\cdot ");
144          constants.Add(laggedVarNode.Weight);
145        }
146        strBuilder.Append(EscapeLatexString(laggedVarNode.VariableName));
[5428]147        strBuilder.Append(LagToString(currentLag + laggedVarNode.Lag));
[7038]148
149      } else if (node.Symbol is Variable) {
[4327]150        var varNode = node as VariableTreeNode;
[7038]151        if (!varNode.Weight.IsAlmost((1.0))) {
152          strBuilder.Append("c_{" + constants.Count + "} \\cdot ");
153          constants.Add(varNode.Weight);
154        }
155        strBuilder.Append(EscapeLatexString(varNode.VariableName));
[5428]156        strBuilder.Append(LagToString(currentLag));
[4327]157      } else if (node.Symbol is ProgramRootSymbol) {
158      } else if (node.Symbol is Defun) {
159        var defunNode = node as DefunTreeNode;
[4969]160        strBuilder.Append(defunNode.FunctionName + " & = ");
[4327]161      } else if (node.Symbol is InvokeFunction) {
162        var invokeNode = node as InvokeFunctionTreeNode;
[7136]163        strBuilder.Append(invokeNode.Symbol.FunctionName + @" ( ");
[4327]164      } else if (node.Symbol is StartSymbol) {
[4969]165        strBuilder.Append("Result & = ");
[4900]166      } else if (node.Symbol is Argument) {
[4327]167        var argSym = node.Symbol as Argument;
[4900]168        strBuilder.Append(" ARG+" + argSym.ArgumentIndex + " ");
[5428]169      } else if (node.Symbol is Derivative) {
[7136]170        strBuilder.Append(@" \cfrac{d ( ");
[5428]171      } else if (node.Symbol is TimeLag) {
172        var laggedNode = node as ILaggedTreeNode;
173        currentLag += laggedNode.Lag;
174      } else if (node.Symbol is Power) {
[7136]175        strBuilder.Append(@" ( ");
[5428]176      } else if (node.Symbol is Root) {
[7136]177        strBuilder.Append(@" ( ");
[5428]178      } else if (node.Symbol is Integral) {
179        // actually a new variable for t is needed in all subtrees (TODO)
180        var laggedTreeNode = node as ILaggedTreeNode;
[7136]181        strBuilder.Append(@"\sum_{t=" + (laggedTreeNode.Lag + currentLag) + @"}^0 ( ");
[5468]182      } else if (node.Symbol is VariableCondition) {
183        var conditionTreeNode = node as VariableConditionTreeNode;
[7038]184        string p = @"1 /  1 + \exp  - c_{" + constants.Count + "} ";
[5468]185        constants.Add(conditionTreeNode.Slope);
[7038]186        p += @" \cdot " + EscapeLatexString(conditionTreeNode.VariableName) + LagToString(currentLag) + " - c_{" + constants.Count + @"}   ";
[5468]187        constants.Add(conditionTreeNode.Threshold);
[7136]188        strBuilder.Append(@" ( " + p + @"\cdot ");
[4327]189      } else {
190        throw new NotImplementedException("Export of " + node.Symbol + " is not implemented.");
191      }
192    }
193
[7140]194    private void FormatSep(ISymbolicExpressionTreeNode node, StringBuilder strBuilder, int step) {
[4327]195      if (node.Symbol is Addition) {
196        strBuilder.Append(" + ");
197      } else if (node.Symbol is Subtraction) {
198        strBuilder.Append(" - ");
199      } else if (node.Symbol is Multiplication) {
[5428]200        strBuilder.Append(@" \cdot ");
[4327]201      } else if (node.Symbol is Division) {
[7140]202        if (step + 1 == node.SubtreeCount)
203          strBuilder.Append(@"}{");
204        else
205          strBuilder.Append(@" }{ \cfrac{ ");
[4969]206      } else if (node.Symbol is Average) {
207        strBuilder.Append(@" + ");
208      } else if (node.Symbol is Logarithm) {
209        throw new InvalidOperationException();
210      } else if (node.Symbol is Exponential) {
211        throw new InvalidOperationException();
212      } else if (node.Symbol is Sine) {
213        throw new InvalidOperationException();
214      } else if (node.Symbol is Cosine) {
215        throw new InvalidOperationException();
216      } else if (node.Symbol is Tangent) {
217        throw new InvalidOperationException();
218      } else if (node.Symbol is GreaterThan) {
219        strBuilder.Append(@" > ");
220      } else if (node.Symbol is LessThan) {
221        strBuilder.Append(@" < ");
222      } else if (node.Symbol is And) {
[7136]223        strBuilder.Append(@" > 0  ) \land (");
[4969]224      } else if (node.Symbol is Or) {
[7136]225        strBuilder.Append(@" > 0  ) \lor (");
[4969]226      } else if (node.Symbol is Not) {
227        throw new InvalidOperationException();
228      } else if (node.Symbol is IfThenElse) {
[7136]229        strBuilder.Append(@" ) , (");
[4327]230      } else if (node.Symbol is ProgramRootSymbol) {
231        strBuilder.Append(@"\\" + Environment.NewLine);
232      } else if (node.Symbol is Defun) {
233      } else if (node.Symbol is InvokeFunction) {
234        strBuilder.Append(" , ");
235      } else if (node.Symbol is StartSymbol) {
[4969]236        strBuilder.Append(@"\\" + Environment.NewLine + " & ");
[5428]237      } else if (node.Symbol is Power) {
[7136]238        strBuilder.Append(@") ^ { \operatorname{round} (");
[5428]239      } else if (node.Symbol is Root) {
[7136]240        strBuilder.Append(@") ^ {  \cfrac{1}{ \operatorname{round} (");
[5468]241      } else if (node.Symbol is VariableCondition) {
242        var conditionTreeNode = node as VariableConditionTreeNode;
[7136]243        string p = @"1 / ( 1 + \exp ( - c_{" + constants.Count + "} ";
[5468]244        constants.Add(conditionTreeNode.Slope);
[7136]245        p += @" \cdot " + EscapeLatexString(conditionTreeNode.VariableName) + LagToString(currentLag) + " - c_{" + constants.Count + @"} ) ) )   ";
[5468]246        constants.Add(conditionTreeNode.Threshold);
[7136]247        strBuilder.Append(@" +  ( 1 - " + p + @" ) \cdot ");
[4327]248      } else {
249        throw new NotImplementedException("Export of " + node.Symbol + " is not implemented.");
250      }
251    }
252
[5745]253    private void FormatEnd(ISymbolicExpressionTreeNode node, StringBuilder strBuilder) {
[4327]254      if (node.Symbol is Addition) {
[7136]255        strBuilder.Append(@" ) ");
[4327]256      } else if (node.Symbol is Subtraction) {
[7136]257        strBuilder.Append(@" ) ");
[4327]258      } else if (node.Symbol is Multiplication) {
259      } else if (node.Symbol is Division) {
[7140]260        strBuilder.Append(" } ");
261        for (int i = 2; i < node.SubtreeCount; i++)
[5428]262          strBuilder.Append(" } ");
[4969]263      } else if (node.Symbol is Average) {
[7136]264        strBuilder.Append(@" ) ");
[4969]265      } else if (node.Symbol is Logarithm) {
[7136]266        strBuilder.Append(@" ) ");
[4969]267      } else if (node.Symbol is Exponential) {
[7136]268        strBuilder.Append(@" ) ");
[4969]269      } else if (node.Symbol is Sine) {
[7136]270        strBuilder.Append(@" ) ");
[4969]271      } else if (node.Symbol is Cosine) {
[7136]272        strBuilder.Append(@" ) ");
[4969]273      } else if (node.Symbol is Tangent) {
[7136]274        strBuilder.Append(@" ) ");
[4969]275      } else if (node.Symbol is GreaterThan) {
[7136]276        strBuilder.Append(@" ) ");
[4969]277      } else if (node.Symbol is LessThan) {
[7136]278        strBuilder.Append(@" ) ");
[4969]279      } else if (node.Symbol is And) {
[7136]280        strBuilder.Append(@" > 0 ) ) ");
[4969]281      } else if (node.Symbol is Or) {
[7136]282        strBuilder.Append(@" > 0 ) ) ");
[4969]283      } else if (node.Symbol is Not) {
[7136]284        strBuilder.Append(@" ) ");
[4969]285      } else if (node.Symbol is IfThenElse) {
[7136]286        strBuilder.Append(@" ) ) ");
[4327]287      } else if (node.Symbol is Constant) {
[5428]288      } else if (node.Symbol is LaggedVariable) {
[7038]289      } else if (node.Symbol is Variable) {
[4327]290      } else if (node.Symbol is ProgramRootSymbol) {
[4969]291        // output all constant values
292        if (constants.Count > 0) {
293          int i = 0;
294          foreach (var constant in constants) {
295            strBuilder.AppendLine(@"\\");
296            strBuilder.Append("c_{" + i + "} & = " + constant);
297            i++;
298          }
299        }
[4327]300      } else if (node.Symbol is Defun) {
301      } else if (node.Symbol is InvokeFunction) {
[7136]302        strBuilder.Append(@" ) ");
[4327]303      } else if (node.Symbol is StartSymbol) {
304      } else if (node.Symbol is Argument) {
[5428]305      } else if (node.Symbol is Derivative) {
[7136]306        strBuilder.Append(@" ) }{dt} ");
[5428]307      } else if (node.Symbol is TimeLag) {
308        var laggedNode = node as ILaggedTreeNode;
309        currentLag -= laggedNode.Lag;
310      } else if (node.Symbol is Power) {
[7136]311        strBuilder.Append(@" ) } ");
[5428]312      } else if (node.Symbol is Root) {
[7136]313        strBuilder.Append(@" ) } ) } ");
[5428]314      } else if (node.Symbol is Integral) {
315        var laggedTreeNode = node as ILaggedTreeNode;
[7136]316        strBuilder.Append(@" ) ");
[5468]317      } else if (node.Symbol is VariableCondition) {
318        strBuilder.Append(@"\left) ");
[4327]319      } else {
320        throw new NotImplementedException("Export of " + node.Symbol + " is not implemented.");
321      }
322    }
[6975]323
[5428]324    private string LagToString(int lag) {
325      if (lag < 0) {
326        return "(t" + lag + ")";
327      } else if (lag > 0) {
328        return "(t+" + lag + ")";
[7038]329      } else return "";
[5428]330    }
[6975]331
332    private string EscapeLatexString(string s) {
333      return s.Replace(@"_", @"\_");
334    }
[4327]335  }
336}
Note: See TracBrowser for help on using the repository browser.