Free cookie consent management tool by TermsFeed Policy Generator

source: branches/symbreg-factors-2650/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Formatters/SymbolicDataAnalysisExpressionLatexFormatter.cs @ 14277

Last change on this file since 14277 was 14277, checked in by gkronber, 8 years ago

#2650: merged r14245:14273 from trunk to branch (fixing conflicts in RegressionSolutionTargetResponseGradientView)

File size: 22.6 KB
RevLine 
[4327]1#region License Information
2/* HeuristicLab
[14185]3 * Copyright (C) 2002-2016 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 {
[14259]35    private readonly List<KeyValuePair<string, double>> constants;
36    private int constIndex;
[8798]37    private int targetCount;
[5428]38    private int currentLag;
[14277]39    private string targetVariable;
40    private bool containsTimeSeriesSymbol;
[4969]41
[5429]42    [StorableConstructor]
[5745]43    private SymbolicDataAnalysisExpressionLatexFormatter(bool deserializing) : base(deserializing) { }
44    private SymbolicDataAnalysisExpressionLatexFormatter(SymbolicDataAnalysisExpressionLatexFormatter original, Cloner cloner)
[5429]45      : base(original, cloner) {
[14259]46      constants = new List<KeyValuePair<string, double>>(original.constants);
47      constIndex = original.constIndex;
48      currentLag = original.currentLag;
49      targetCount = original.targetCount;
[5429]50    }
[5745]51    public SymbolicDataAnalysisExpressionLatexFormatter()
52      : base() {
53      Name = ItemName;
54      Description = ItemDescription;
[14259]55      constants = new List<KeyValuePair<string, double>>();
[4969]56    }
[4327]57
[4900]58    public override IDeepCloneable Clone(Cloner cloner) {
[5745]59      return new SymbolicDataAnalysisExpressionLatexFormatter(this, cloner);
[4900]60    }
61
[5745]62    public string Format(ISymbolicExpressionTree symbolicExpressionTree) {
[14277]63      return Format(symbolicExpressionTree, null);
64    }
65    public string Format(ISymbolicExpressionTree symbolicExpressionTree, string targetVariable) {
[4327]66      try {
67        StringBuilder strBuilder = new StringBuilder();
[4969]68        constants.Clear();
[14259]69        constIndex = 0;
[14277]70        this.targetVariable = targetVariable;
71        containsTimeSeriesSymbol = symbolicExpressionTree.IterateNodesBreadth().Any(n => IsTimeSeriesSymbol(n.Symbol));
[4327]72        strBuilder.AppendLine(FormatRecursively(symbolicExpressionTree.Root));
73        return strBuilder.ToString();
[14259]74      } catch (NotImplementedException ex) {
[4327]75        return ex.Message + Environment.NewLine + ex.StackTrace;
76      }
77    }
[14277]78    static bool IsTimeSeriesSymbol(ISymbol s) {
79      return s is TimeLag || s is Integral || s is Derivative || s is LaggedVariable;
80    }
[4327]81
[5745]82    private string FormatRecursively(ISymbolicExpressionTreeNode node) {
[4327]83      StringBuilder strBuilder = new StringBuilder();
[5428]84      currentLag = 0;
[4327]85      FormatBegin(node, strBuilder);
86
[6803]87      if (node.SubtreeCount > 0) {
[5745]88        strBuilder.Append(FormatRecursively(node.GetSubtree(0)));
[4327]89      }
[7140]90      int i = 1;
[14259]91      foreach (var subTree in node.Subtrees.Skip(1)) {
[7140]92        FormatSep(node, strBuilder, i);
[4327]93        // format the whole subtree
94        strBuilder.Append(FormatRecursively(subTree));
[7140]95        i++;
[4327]96      }
97
98      FormatEnd(node, strBuilder);
99
100      return strBuilder.ToString();
101    }
102
[5745]103    private void FormatBegin(ISymbolicExpressionTreeNode node, StringBuilder strBuilder) {
[4327]104      if (node.Symbol is Addition) {
[7446]105        strBuilder.Append(@" \left( ");
[4327]106      } else if (node.Symbol is Subtraction) {
[6803]107        if (node.SubtreeCount == 1) {
[7446]108          strBuilder.Append(@"- \left( ");
[5428]109        } else {
[7446]110          strBuilder.Append(@" \left( ");
[5428]111        }
[4327]112      } else if (node.Symbol is Multiplication) {
113      } else if (node.Symbol is Division) {
[6803]114        if (node.SubtreeCount == 1) {
[8798]115          strBuilder.Append(@" \cfrac{1");
[5428]116        } else {
117          strBuilder.Append(@" \cfrac{ ");
118        }
[4969]119      } else if (node.Symbol is Average) {
[5428]120        // skip output of (1/1) if only one subtree
[6803]121        if (node.SubtreeCount > 1) {
122          strBuilder.Append(@" \cfrac{1}{" + node.SubtreeCount + @"}");
[5428]123        }
[7446]124        strBuilder.Append(@" \left( ");
[4969]125      } else if (node.Symbol is Logarithm) {
[7446]126        strBuilder.Append(@"\log \left( ");
[4969]127      } else if (node.Symbol is Exponential) {
[7446]128        strBuilder.Append(@"\exp \left( ");
[7695]129      } else if (node.Symbol is Square) {
130        strBuilder.Append(@"\left(");
131      } else if (node.Symbol is SquareRoot) {
132        strBuilder.Append(@"\sqrt{");
[4969]133      } else if (node.Symbol is Sine) {
[7446]134        strBuilder.Append(@"\sin \left( ");
[4969]135      } else if (node.Symbol is Cosine) {
[7446]136        strBuilder.Append(@"\cos \left( ");
[4969]137      } else if (node.Symbol is Tangent) {
[7446]138        strBuilder.Append(@"\tan \left( ");
[7696]139      } else if (node.Symbol is AiryA) {
140        strBuilder.Append(@"\operatorname{airy}_a \left( ");
141      } else if (node.Symbol is AiryB) {
142        strBuilder.Append(@"\operatorname{airy}_b \left( ");
143      } else if (node.Symbol is Bessel) {
144        strBuilder.Append(@"\operatorname{bessel}_1 \left( ");
145      } else if (node.Symbol is CosineIntegral) {
146        strBuilder.Append(@"\operatorname{cosInt} \left( ");
147      } else if (node.Symbol is Dawson) {
148        strBuilder.Append(@"\operatorname{dawson} \left( ");
149      } else if (node.Symbol is Erf) {
150        strBuilder.Append(@"\operatorname{erf} \left( ");
151      } else if (node.Symbol is ExponentialIntegralEi) {
152        strBuilder.Append(@"\operatorname{expInt}_i \left( ");
153      } else if (node.Symbol is FresnelCosineIntegral) {
[7708]154        strBuilder.Append(@"\operatorname{fresnel}_\operatorname{cosInt} \left( ");
[7696]155      } else if (node.Symbol is FresnelSineIntegral) {
[7708]156        strBuilder.Append(@"\operatorname{fresnel}_\operatorname{sinInt} \left( ");
[7696]157      } else if (node.Symbol is Gamma) {
158        strBuilder.Append(@"\Gamma \left( ");
159      } else if (node.Symbol is HyperbolicCosineIntegral) {
160        strBuilder.Append(@"\operatorname{hypCosInt} \left( ");
161      } else if (node.Symbol is HyperbolicSineIntegral) {
162        strBuilder.Append(@"\operatorname{hypSinInt} \left( ");
[7697]163      } else if (node.Symbol is Norm) {
164        strBuilder.Append(@"\operatorname{norm} \left( ");
[7696]165      } else if (node.Symbol is Psi) {
166        strBuilder.Append(@"\operatorname{digamma} \left( ");
167      } else if (node.Symbol is SineIntegral) {
168        strBuilder.Append(@"\operatorname{sinInt} \left( ");
[4969]169      } else if (node.Symbol is GreaterThan) {
[7446]170        strBuilder.Append(@"  \left( ");
[4969]171      } else if (node.Symbol is LessThan) {
[7446]172        strBuilder.Append(@"  \left( ");
[4969]173      } else if (node.Symbol is And) {
[7451]174        strBuilder.Append(@"  \left( \left( ");
[4969]175      } else if (node.Symbol is Or) {
[7451]176        strBuilder.Append(@"   \left( \left( ");
[4969]177      } else if (node.Symbol is Not) {
[7446]178        strBuilder.Append(@" \neg \left( ");
[4969]179      } else if (node.Symbol is IfThenElse) {
[7446]180        strBuilder.Append(@" \operatorname{if}  \left( ");
[4327]181      } else if (node.Symbol is Constant) {
[14259]182        var constName = "c_{" + constIndex + "}";
183        constIndex++;
184        strBuilder.Append(constName + " ");
[4969]185        var constNode = node as ConstantTreeNode;
[14259]186        constants.Add(new KeyValuePair<string, double>(constName, constNode.Value));
187      } else if (node.Symbol is FactorVariable) {
188        var factorNode = node as FactorVariableTreeNode;
189        var constName = "c_{" + constIndex + "}";
190        strBuilder.Append(constName + " ");
191        foreach (var e in factorNode.Symbol.GetVariableValues(factorNode.VariableName)
192          .Zip(factorNode.Weights, Tuple.Create)) {
193          constants.Add(new KeyValuePair<string, double>("c_{" + constIndex + ", " + EscapeLatexString(factorNode.VariableName) + "=" + EscapeLatexString(e.Item1) + "}", e.Item2));
194        }
195        constIndex++;
196      } else if (node.Symbol is BinaryFactorVariable) {
197        var binFactorNode = node as BinaryFactorVariableTreeNode;
198        if (!binFactorNode.Weight.IsAlmost((1.0))) {
199          var constName = "c_{" + constIndex + "}";
200          strBuilder.Append(constName + "  \\cdot");
201          constants.Add(new KeyValuePair<string, double>(constName, binFactorNode.Weight));
202          constIndex++;
203        }
204        strBuilder.Append(EscapeLatexString(binFactorNode.VariableName));
205        strBuilder.Append(LagToString(currentLag));
206        strBuilder.Append(" = " + EscapeLatexString(binFactorNode.VariableValue));
[5428]207      } else if (node.Symbol is LaggedVariable) {
208        var laggedVarNode = node as LaggedVariableTreeNode;
[7038]209        if (!laggedVarNode.Weight.IsAlmost(1.0)) {
[14259]210          var constName = "c_{" + constIndex + "}";
211          strBuilder.Append(constName + "  \\cdot");
212          constants.Add(new KeyValuePair<string, double>(constName, laggedVarNode.Weight));
213          constIndex++;
[7038]214        }
215        strBuilder.Append(EscapeLatexString(laggedVarNode.VariableName));
[5428]216        strBuilder.Append(LagToString(currentLag + laggedVarNode.Lag));
[7038]217
218      } else if (node.Symbol is Variable) {
[4327]219        var varNode = node as VariableTreeNode;
[7038]220        if (!varNode.Weight.IsAlmost((1.0))) {
[14259]221          var constName = "c_{" + constIndex + "}";
222          strBuilder.Append(constName + "  \\cdot");
223          constants.Add(new KeyValuePair<string, double>(constName, varNode.Weight));
224          constIndex++;
[7038]225        }
226        strBuilder.Append(EscapeLatexString(varNode.VariableName));
[5428]227        strBuilder.Append(LagToString(currentLag));
[4327]228      } else if (node.Symbol is ProgramRootSymbol) {
[7446]229        strBuilder
230          .AppendLine("\\begin{align*}")
231          .AppendLine("\\nonumber");
[4327]232      } else if (node.Symbol is Defun) {
233        var defunNode = node as DefunTreeNode;
[4969]234        strBuilder.Append(defunNode.FunctionName + " & = ");
[4327]235      } else if (node.Symbol is InvokeFunction) {
236        var invokeNode = node as InvokeFunctionTreeNode;
[7446]237        strBuilder.Append(invokeNode.Symbol.FunctionName + @" \left( ");
[4327]238      } else if (node.Symbol is StartSymbol) {
[14277]239        FormatStartSymbol(strBuilder);
[4900]240      } else if (node.Symbol is Argument) {
[4327]241        var argSym = node.Symbol as Argument;
[4900]242        strBuilder.Append(" ARG+" + argSym.ArgumentIndex + " ");
[5428]243      } else if (node.Symbol is Derivative) {
[7446]244        strBuilder.Append(@" \cfrac{d \left( ");
[5428]245      } else if (node.Symbol is TimeLag) {
246        var laggedNode = node as ILaggedTreeNode;
247        currentLag += laggedNode.Lag;
248      } else if (node.Symbol is Power) {
[7446]249        strBuilder.Append(@" \left( ");
[5428]250      } else if (node.Symbol is Root) {
[7446]251        strBuilder.Append(@" \left( ");
[5428]252      } else if (node.Symbol is Integral) {
253        // actually a new variable for t is needed in all subtrees (TODO)
254        var laggedTreeNode = node as ILaggedTreeNode;
[7446]255        strBuilder.Append(@"\sum_{t=" + (laggedTreeNode.Lag + currentLag) + @"}^0 \left( ");
[5468]256      } else if (node.Symbol is VariableCondition) {
257        var conditionTreeNode = node as VariableConditionTreeNode;
[14259]258        var constName = "c_{" + constants.Count + "}";
259        string p = @"1 /  1 + \exp  - " + constName + " ";
260        constants.Add(new KeyValuePair<string, double>(constName, conditionTreeNode.Slope));
261        constIndex++;
262        var const2Name = "c_{" + constants.Count + @"}";
263        p += @" \cdot " + EscapeLatexString(conditionTreeNode.VariableName) + LagToString(currentLag) + " - " + const2Name + "   ";
264        constants.Add(new KeyValuePair<string, double>(const2Name, conditionTreeNode.Threshold));
265        constIndex++;
[7446]266        strBuilder.Append(@" \left( " + p + @"\cdot ");
[4327]267      } else {
268        throw new NotImplementedException("Export of " + node.Symbol + " is not implemented.");
269      }
270    }
271
[7140]272    private void FormatSep(ISymbolicExpressionTreeNode node, StringBuilder strBuilder, int step) {
[4327]273      if (node.Symbol is Addition) {
274        strBuilder.Append(" + ");
275      } else if (node.Symbol is Subtraction) {
276        strBuilder.Append(" - ");
277      } else if (node.Symbol is Multiplication) {
[5428]278        strBuilder.Append(@" \cdot ");
[4327]279      } else if (node.Symbol is Division) {
[7140]280        if (step + 1 == node.SubtreeCount)
281          strBuilder.Append(@"}{");
282        else
283          strBuilder.Append(@" }{ \cfrac{ ");
[4969]284      } else if (node.Symbol is Average) {
285        strBuilder.Append(@" + ");
286      } else if (node.Symbol is Logarithm) {
287        throw new InvalidOperationException();
288      } else if (node.Symbol is Exponential) {
289        throw new InvalidOperationException();
[7695]290      } else if (node.Symbol is Square) {
291        throw new InvalidOperationException();
292      } else if (node.Symbol is SquareRoot) {
293        throw new InvalidOperationException();
[4969]294      } else if (node.Symbol is Sine) {
295        throw new InvalidOperationException();
296      } else if (node.Symbol is Cosine) {
297        throw new InvalidOperationException();
298      } else if (node.Symbol is Tangent) {
299        throw new InvalidOperationException();
[7696]300      } else if (node.Symbol is AiryA) {
301        throw new InvalidOperationException();
302      } else if (node.Symbol is AiryB) {
303        throw new InvalidOperationException();
304      } else if (node.Symbol is Bessel) {
305        throw new InvalidOperationException();
306      } else if (node.Symbol is CosineIntegral) {
307        throw new InvalidOperationException();
308      } else if (node.Symbol is Dawson) {
309        throw new InvalidOperationException();
310      } else if (node.Symbol is Erf) {
311        throw new InvalidOperationException();
312      } else if (node.Symbol is ExponentialIntegralEi) {
313        throw new InvalidOperationException();
314      } else if (node.Symbol is FresnelCosineIntegral) {
315        throw new InvalidOperationException();
316      } else if (node.Symbol is FresnelSineIntegral) {
317        throw new InvalidOperationException();
318      } else if (node.Symbol is Gamma) {
319        throw new InvalidOperationException();
320      } else if (node.Symbol is HyperbolicCosineIntegral) {
321        throw new InvalidOperationException();
322      } else if (node.Symbol is HyperbolicSineIntegral) {
323        throw new InvalidOperationException();
[7697]324      } else if (node.Symbol is Norm) {
325        throw new InvalidOperationException();
[7696]326      } else if (node.Symbol is Psi) {
327        throw new InvalidOperationException();
328      } else if (node.Symbol is SineIntegral) {
329        throw new InvalidOperationException();
[4969]330      } else if (node.Symbol is GreaterThan) {
331        strBuilder.Append(@" > ");
332      } else if (node.Symbol is LessThan) {
333        strBuilder.Append(@" < ");
334      } else if (node.Symbol is And) {
[7446]335        strBuilder.Append(@" > 0  \right) \land \left(");
[4969]336      } else if (node.Symbol is Or) {
[7446]337        strBuilder.Append(@" > 0  \right) \lor \left(");
[4969]338      } else if (node.Symbol is Not) {
339        throw new InvalidOperationException();
340      } else if (node.Symbol is IfThenElse) {
[7446]341        strBuilder.Append(@" , ");
[4327]342      } else if (node.Symbol is ProgramRootSymbol) {
343        strBuilder.Append(@"\\" + Environment.NewLine);
344      } else if (node.Symbol is Defun) {
345      } else if (node.Symbol is InvokeFunction) {
346        strBuilder.Append(" , ");
347      } else if (node.Symbol is StartSymbol) {
[8798]348        strBuilder.Append(@"\\" + Environment.NewLine);
[14277]349        FormatStartSymbol(strBuilder);
[5428]350      } else if (node.Symbol is Power) {
[7446]351        strBuilder.Append(@"\right) ^ { \operatorname{round} \left(");
[5428]352      } else if (node.Symbol is Root) {
[7446]353        strBuilder.Append(@"\right) ^ {  \cfrac{1}{ \operatorname{round} \left(");
[5468]354      } else if (node.Symbol is VariableCondition) {
355        var conditionTreeNode = node as VariableConditionTreeNode;
[14259]356        var const1Name = "c_{" + constants.Count + "}";
357        string p = @"1 / \left( 1 + \exp \left( - " + const1Name + " ";
358        constants.Add(new KeyValuePair<string, double>(const1Name, conditionTreeNode.Slope));
359        constIndex++;
360        var const2Name = "c_{" + constants.Count + "}";
361        p += @" \cdot " + EscapeLatexString(conditionTreeNode.VariableName) + LagToString(currentLag) + " - " + const2Name + " \right) \right) \right)   ";
362        constants.Add(new KeyValuePair<string, double>(const2Name, conditionTreeNode.Threshold));
363        constIndex++;
[7446]364        strBuilder.Append(@" +  \left( 1 - " + p + @" \right) \cdot ");
[4327]365      } else {
366        throw new NotImplementedException("Export of " + node.Symbol + " is not implemented.");
367      }
368    }
369
[5745]370    private void FormatEnd(ISymbolicExpressionTreeNode node, StringBuilder strBuilder) {
[4327]371      if (node.Symbol is Addition) {
[7446]372        strBuilder.Append(@" \right) ");
[4327]373      } else if (node.Symbol is Subtraction) {
[7446]374        strBuilder.Append(@" \right) ");
[4327]375      } else if (node.Symbol is Multiplication) {
376      } else if (node.Symbol is Division) {
[7140]377        strBuilder.Append(" } ");
378        for (int i = 2; i < node.SubtreeCount; i++)
[5428]379          strBuilder.Append(" } ");
[4969]380      } else if (node.Symbol is Average) {
[7446]381        strBuilder.Append(@" \right) ");
[4969]382      } else if (node.Symbol is Logarithm) {
[7446]383        strBuilder.Append(@" \right) ");
[4969]384      } else if (node.Symbol is Exponential) {
[7446]385        strBuilder.Append(@" \right) ");
[7695]386      } else if (node.Symbol is Square) {
387        strBuilder.Append(@"\right)^2");
388      } else if (node.Symbol is SquareRoot) {
389        strBuilder.Append(@"}");
[4969]390      } else if (node.Symbol is Sine) {
[7446]391        strBuilder.Append(@" \right) ");
[4969]392      } else if (node.Symbol is Cosine) {
[7446]393        strBuilder.Append(@" \right) ");
[4969]394      } else if (node.Symbol is Tangent) {
[7446]395        strBuilder.Append(@" \right) ");
[7696]396      } else if (node.Symbol is AiryA) {
397        strBuilder.Append(@" \right) ");
398      } else if (node.Symbol is AiryB) {
399        strBuilder.Append(@" \right) ");
400      } else if (node.Symbol is Bessel) {
401        strBuilder.Append(@" \right) ");
402      } else if (node.Symbol is CosineIntegral) {
403        strBuilder.Append(@" \right) ");
404      } else if (node.Symbol is Dawson) {
405        strBuilder.Append(@" \right) ");
406      } else if (node.Symbol is Erf) {
407        strBuilder.Append(@" \right) ");
408      } else if (node.Symbol is ExponentialIntegralEi) {
409        strBuilder.Append(@" \right) ");
410      } else if (node.Symbol is FresnelCosineIntegral) {
411        strBuilder.Append(@" \right) ");
412      } else if (node.Symbol is FresnelSineIntegral) {
413        strBuilder.Append(@" \right) ");
414      } else if (node.Symbol is Gamma) {
415        strBuilder.Append(@" \right) ");
416      } else if (node.Symbol is HyperbolicCosineIntegral) {
417        strBuilder.Append(@" \right) ");
418      } else if (node.Symbol is HyperbolicSineIntegral) {
419        strBuilder.Append(@" \right) ");
[7697]420      } else if (node.Symbol is Norm) {
421        strBuilder.Append(@" \right) ");
[7696]422      } else if (node.Symbol is Psi) {
423        strBuilder.Append(@" \right) ");
424      } else if (node.Symbol is SineIntegral) {
425        strBuilder.Append(@" \right) ");
[4969]426      } else if (node.Symbol is GreaterThan) {
[7446]427        strBuilder.Append(@" \right) ");
[4969]428      } else if (node.Symbol is LessThan) {
[7446]429        strBuilder.Append(@" \right) ");
[4969]430      } else if (node.Symbol is And) {
[7446]431        strBuilder.Append(@" > 0 \right) \right) ");
[4969]432      } else if (node.Symbol is Or) {
[7446]433        strBuilder.Append(@" > 0 \right) \right) ");
[4969]434      } else if (node.Symbol is Not) {
[7446]435        strBuilder.Append(@" \right) ");
[4969]436      } else if (node.Symbol is IfThenElse) {
[7446]437        strBuilder.Append(@" \right) ");
[4327]438      } else if (node.Symbol is Constant) {
[5428]439      } else if (node.Symbol is LaggedVariable) {
[7038]440      } else if (node.Symbol is Variable) {
[14259]441      } else if (node.Symbol is FactorVariable) {
442      } else if (node.Symbol is BinaryFactorVariable) {
[4327]443      } else if (node.Symbol is ProgramRootSymbol) {
[7446]444        strBuilder
445          .AppendLine("\\end{align*}")
446          .AppendLine("\\begin{align*}")
447          .AppendLine("\\nonumber");
[4969]448        // output all constant values
449        if (constants.Count > 0) {
450          foreach (var constant in constants) {
[7446]451            // replace "." with ".&" to align decimal points
[14259]452            var constStr = string.Format(System.Globalization.NumberFormatInfo.InvariantInfo, "{0:G5}", constant.Value);
[7451]453            if (!constStr.Contains(".")) constStr = constStr + ".0";
[13933]454            constStr = constStr.Replace(".", "&.");  // fix problem in rendering of aligned expressions
[14259]455            strBuilder.Append(constant.Key + "& = & " + constStr);
[7446]456            strBuilder.Append(@"\\");
[4969]457          }
458        }
[7446]459        strBuilder.AppendLine("\\end{align*}");
[4327]460      } else if (node.Symbol is Defun) {
461      } else if (node.Symbol is InvokeFunction) {
[7446]462        strBuilder.Append(@" \right) ");
[4327]463      } else if (node.Symbol is StartSymbol) {
464      } else if (node.Symbol is Argument) {
[5428]465      } else if (node.Symbol is Derivative) {
[7446]466        strBuilder.Append(@" \right) }{dt} ");
[5428]467      } else if (node.Symbol is TimeLag) {
468        var laggedNode = node as ILaggedTreeNode;
469        currentLag -= laggedNode.Lag;
470      } else if (node.Symbol is Power) {
[7446]471        strBuilder.Append(@" \right) } ");
[5428]472      } else if (node.Symbol is Root) {
[7446]473        strBuilder.Append(@" \right) } } ");
[5428]474      } else if (node.Symbol is Integral) {
[7446]475        strBuilder.Append(@" \right) ");
[5468]476      } else if (node.Symbol is VariableCondition) {
[7446]477        strBuilder.Append(@"\right) ");
[4327]478      } else {
479        throw new NotImplementedException("Export of " + node.Symbol + " is not implemented.");
480      }
481    }
[6975]482
[14277]483    private void FormatStartSymbol(StringBuilder strBuilder) {
484      strBuilder.Append(targetVariable ?? "target_" + (targetCount++));
485      if (containsTimeSeriesSymbol)
486        strBuilder.Append("(t)");
487      strBuilder.Append(" & = ");
488    }
489
[5428]490    private string LagToString(int lag) {
491      if (lag < 0) {
492        return "(t" + lag + ")";
493      } else if (lag > 0) {
494        return "(t+" + lag + ")";
[7038]495      } else return "";
[5428]496    }
[6975]497
498    private string EscapeLatexString(string s) {
[7446]499      return "\\text{" +
500        s
501         .Replace("\\", "\\\\")
502         .Replace("{", "\\{")
503         .Replace("}", "\\}")
504        + "}";
[6975]505    }
[4327]506  }
507}
Note: See TracBrowser for help on using the repository browser.