Free cookie consent management tool by TermsFeed Policy Generator

source: stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Formatters/SymbolicDataAnalysisExpressionLatexFormatter.cs @ 17101

Last change on this file since 17101 was 17101, checked in by mkommend, 5 years ago

#2866: Merged 16656, 16668, 16670, 16701, 16702 into stable.

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