source: trunk/sources/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Formatters/SymbolicDataAnalysisExpressionMATLABFormatter.cs @ 14826

Last change on this file since 14826 was 14826, checked in by gkronber, 6 months ago

#2650: merged the factors branch into trunk

File size: 17.7 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2016 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.Globalization;
23using System.Linq;
24using System.Text;
25using HeuristicLab.Common;
26using HeuristicLab.Core;
27using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
28using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
29
30namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
31
32  [Item("MATLAB String Formatter", "String formatter for string representations of symbolic data analysis expressions in MATLAB syntax.")]
33  [StorableClass]
34  public sealed class SymbolicDataAnalysisExpressionMATLABFormatter : NamedItem, ISymbolicExpressionTreeStringFormatter {
35    private int currentLag;
36
37    [StorableConstructor]
38    private SymbolicDataAnalysisExpressionMATLABFormatter(bool deserializing) : base(deserializing) { }
39    private SymbolicDataAnalysisExpressionMATLABFormatter(SymbolicDataAnalysisExpressionMATLABFormatter original, Cloner cloner) : base(original, cloner) { }
40    public SymbolicDataAnalysisExpressionMATLABFormatter()
41      : base() {
42      Name = ItemName;
43      Description = ItemDescription;
44    }
45    public override IDeepCloneable Clone(Cloner cloner) {
46      return new SymbolicDataAnalysisExpressionMATLABFormatter(this, cloner);
47    }
48    private int currentIndexNumber;
49    public string CurrentIndexVariable {
50      get {
51        return "i" + currentIndexNumber;
52      }
53    }
54    private void ReleaseIndexVariable() {
55      currentIndexNumber--;
56    }
57
58    private string AllocateIndexVariable() {
59      currentIndexNumber++;
60      return CurrentIndexVariable;
61    }
62
63    public string Format(ISymbolicExpressionTree symbolicExpressionTree) {
64      currentLag = 0;
65      currentIndexNumber = 0;
66
67      var stringBuilder = new StringBuilder();
68      stringBuilder.AppendLine("rows = ???");
69      stringBuilder.AppendLine(FormatOnlyExpression(symbolicExpressionTree.Root) + ";");
70      stringBuilder.AppendLine();
71      stringBuilder.AppendLine("function y = log_(x)");
72      stringBuilder.AppendLine("  if(x<=0) y = NaN;");
73      stringBuilder.AppendLine("  else     y = log(x);");
74      stringBuilder.AppendLine("  end");
75      stringBuilder.AppendLine("end");
76      stringBuilder.AppendLine();
77      stringBuilder.AppendLine("function y = fivePoint(f0, f1, f3, f4)");
78      stringBuilder.AppendLine("  y = (f0 + 2*f1 - 2*f3 - f4) / 8;");
79      stringBuilder.AppendLine("end");
80
81      var factorVariableNames =
82        symbolicExpressionTree.IterateNodesPostfix()
83          .OfType<FactorVariableTreeNode>()
84          .Select(n => n.VariableName)
85          .Distinct();
86
87      foreach (var factorVarName in factorVariableNames) {
88        var factorSymb = symbolicExpressionTree.IterateNodesPostfix()
89          .OfType<FactorVariableTreeNode>()
90          .First(n => n.VariableName == factorVarName)
91          .Symbol;
92        stringBuilder.AppendFormat("function y = switch_{0}(val, v)", factorVarName).AppendLine();
93        var values = factorSymb.GetVariableValues(factorVarName).ToArray();
94        stringBuilder.AppendLine("switch val");
95        for (int i = 0; i < values.Length; i++) {
96          stringBuilder.AppendFormat(CultureInfo.InvariantCulture, "  case \"{0}\" y = v({1})", values[i], i).AppendLine();
97        }
98        stringBuilder.AppendLine("end");
99        stringBuilder.AppendLine();
100      }
101
102      return stringBuilder.ToString();
103    }
104
105    public string FormatOnlyExpression(ISymbolicExpressionTreeNode expressionNode) {
106      var stringBuilder = new StringBuilder();
107      stringBuilder.AppendLine("  for " + CurrentIndexVariable + " = 1:1:rows");
108      stringBuilder.AppendLine("    estimated(" + CurrentIndexVariable + ") = " + FormatRecursively(expressionNode.GetSubtree(0)) + ";");
109      stringBuilder.AppendLine("  end;");
110      return stringBuilder.ToString();
111    }
112
113    private string FormatRecursively(ISymbolicExpressionTreeNode node) {
114      ISymbol symbol = node.Symbol;
115      StringBuilder stringBuilder = new StringBuilder();
116
117      if (symbol is ProgramRootSymbol) {
118        stringBuilder.AppendLine(FormatRecursively(node.GetSubtree(0)));
119      } else if (symbol is StartSymbol)
120        return FormatRecursively(node.GetSubtree(0));
121      else if (symbol is Addition) {
122        stringBuilder.Append("(");
123        for (int i = 0; i < node.SubtreeCount; i++) {
124          if (i > 0) stringBuilder.Append("+");
125          stringBuilder.Append(FormatRecursively(node.GetSubtree(i)));
126        }
127        stringBuilder.Append(")");
128      } else if (symbol is And) {
129        stringBuilder.Append("((");
130        for (int i = 0; i < node.SubtreeCount; i++) {
131          if (i > 0) stringBuilder.Append("&");
132          stringBuilder.Append("((");
133          stringBuilder.Append(FormatRecursively(node.GetSubtree(i)));
134          stringBuilder.Append(")>0)");
135        }
136        stringBuilder.Append(")-0.5)*2");
137        // MATLAB maps false and true to 0 and 1, resp., we map this result to -1.0 and +1.0, resp.
138      } else if (symbol is Average) {
139        stringBuilder.Append("(1/");
140        stringBuilder.Append(node.SubtreeCount);
141        stringBuilder.Append(")*(");
142        for (int i = 0; i < node.SubtreeCount; i++) {
143          if (i > 0) stringBuilder.Append("+");
144          stringBuilder.Append("(");
145          stringBuilder.Append(FormatRecursively(node.GetSubtree(i)));
146          stringBuilder.Append(")");
147        }
148        stringBuilder.Append(")");
149      } else if (symbol is Constant) {
150        ConstantTreeNode constantTreeNode = node as ConstantTreeNode;
151        stringBuilder.Append(constantTreeNode.Value.ToString(CultureInfo.InvariantCulture));
152      } else if (symbol is Cosine) {
153        stringBuilder.Append("cos(");
154        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
155        stringBuilder.Append(")");
156      } else if (symbol is Division) {
157        if (node.SubtreeCount == 1) {
158          stringBuilder.Append("1/");
159          stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
160        } else {
161          stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
162          stringBuilder.Append("/(");
163          for (int i = 1; i < node.SubtreeCount; i++) {
164            if (i > 1) stringBuilder.Append("*");
165            stringBuilder.Append(FormatRecursively(node.GetSubtree(i)));
166          }
167          stringBuilder.Append(")");
168        }
169      } else if (symbol is Exponential) {
170        stringBuilder.Append("exp(");
171        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
172        stringBuilder.Append(")");
173      } else if (symbol is Square) {
174        stringBuilder.Append("(");
175        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
176        stringBuilder.Append(").^2");
177      } else if (symbol is SquareRoot) {
178        stringBuilder.Append("sqrt(");
179        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
180        stringBuilder.Append(")");
181      } else if (symbol is GreaterThan) {
182        stringBuilder.Append("((");
183        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
184        stringBuilder.Append(">");
185        stringBuilder.Append(FormatRecursively(node.GetSubtree(1)));
186        stringBuilder.Append(")-0.5)*2");
187        // MATLAB maps false and true to 0 and 1, resp., we map this result to -1.0 and +1.0, resp.
188      } else if (symbol is IfThenElse) {
189        stringBuilder.Append("(");
190        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
191        stringBuilder.Append(">0)*");
192        stringBuilder.Append(FormatRecursively(node.GetSubtree(1)));
193        stringBuilder.Append("+");
194        stringBuilder.Append("(");
195        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
196        stringBuilder.Append("<=0)*");
197        stringBuilder.Append(FormatRecursively(node.GetSubtree(2)));
198      } else if (symbol is LaggedVariable) {
199        // this if must be checked before if(symbol is LaggedVariable)
200        LaggedVariableTreeNode laggedVariableTreeNode = node as LaggedVariableTreeNode;
201        stringBuilder.Append(laggedVariableTreeNode.Weight.ToString(CultureInfo.InvariantCulture));
202        stringBuilder.Append("*");
203        stringBuilder.Append(laggedVariableTreeNode.VariableName +
204                             LagToString(currentLag + laggedVariableTreeNode.Lag));
205      } else if (symbol is LessThan) {
206        stringBuilder.Append("((");
207        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
208        stringBuilder.Append("<");
209        stringBuilder.Append(FormatRecursively(node.GetSubtree(1)));
210        stringBuilder.Append(")-0.5)*2");
211        // MATLAB maps false and true to 0 and 1, resp., we map this result to -1.0 and +1.0, resp.
212      } else if (symbol is Logarithm) {
213        stringBuilder.Append("log_(");
214        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
215        stringBuilder.Append(")");
216      } else if (symbol is Multiplication) {
217        for (int i = 0; i < node.SubtreeCount; i++) {
218          if (i > 0) stringBuilder.Append("*");
219          stringBuilder.Append(FormatRecursively(node.GetSubtree(i)));
220        }
221      } else if (symbol is Not) {
222        stringBuilder.Append("~(");
223        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
224        stringBuilder.Append(" > 0 )");
225      } else if (symbol is Or) {
226        stringBuilder.Append("((");
227        for (int i = 0; i < node.SubtreeCount; i++) {
228          if (i > 0) stringBuilder.Append("|");
229          stringBuilder.Append("((");
230          stringBuilder.Append(FormatRecursively(node.GetSubtree(i)));
231          stringBuilder.Append(")>0)");
232        }
233        stringBuilder.Append(")-0.5)*2");
234        // MATLAB maps false and true to 0 and 1, resp., we map this result to -1.0 and +1.0, resp.
235      } else if (symbol is Sine) {
236        stringBuilder.Append("sin(");
237        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
238        stringBuilder.Append(")");
239      } else if (symbol is Subtraction) {
240        stringBuilder.Append("(");
241        if (node.SubtreeCount == 1) {
242          stringBuilder.Append("-");
243          stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
244        } else {
245          stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
246          for (int i = 1; i < node.SubtreeCount; i++) {
247            stringBuilder.Append("-");
248            stringBuilder.Append(FormatRecursively(node.GetSubtree(i)));
249          }
250        }
251        stringBuilder.Append(")");
252      } else if (symbol is Tangent) {
253        stringBuilder.Append("tan(");
254        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
255        stringBuilder.Append(")");
256      } else if (node.Symbol is AiryA) {
257        stringBuilder.Append("airy(");
258        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
259        stringBuilder.Append(")");
260      } else if (node.Symbol is AiryB) {
261        stringBuilder.Append("airy(2, ");
262        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
263        stringBuilder.Append(")");
264      } else if (node.Symbol is Bessel) {
265        stringBuilder.Append("besseli(0.0,");
266        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
267        stringBuilder.Append(")");
268      } else if (node.Symbol is CosineIntegral) {
269        stringBuilder.Append("cosint(");
270        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
271        stringBuilder.Append(")");
272      } else if (node.Symbol is Dawson) {
273        stringBuilder.Append("dawson(");
274        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
275        stringBuilder.Append(")");
276      } else if (node.Symbol is Erf) {
277        stringBuilder.Append("erf(");
278        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
279        stringBuilder.Append(")");
280      } else if (node.Symbol is ExponentialIntegralEi) {
281        stringBuilder.Append("expint(");
282        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
283        stringBuilder.Append(")");
284      } else if (node.Symbol is FresnelCosineIntegral) {
285        stringBuilder.Append("FresnelC(");
286        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
287        stringBuilder.Append(")");
288      } else if (node.Symbol is FresnelSineIntegral) {
289        stringBuilder.Append("FresnelS(");
290        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
291        stringBuilder.Append(")");
292      } else if (node.Symbol is Gamma) {
293        stringBuilder.Append("gamma(");
294        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
295        stringBuilder.Append(")");
296      } else if (node.Symbol is HyperbolicCosineIntegral) {
297        stringBuilder.Append("Chi(");
298        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
299        stringBuilder.Append(")");
300      } else if (node.Symbol is HyperbolicSineIntegral) {
301        stringBuilder.Append("Shi(");
302        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
303        stringBuilder.Append(")");
304      } else if (node.Symbol is Norm) {
305        stringBuilder.Append("normpdf(");
306        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
307        stringBuilder.Append(")");
308      } else if (node.Symbol is Psi) {
309        stringBuilder.Append("psi(");
310        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
311        stringBuilder.Append(")");
312      } else if (node.Symbol is SineIntegral) {
313        stringBuilder.Append("sinint(");
314        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
315        stringBuilder.Append(")");
316      } else if (symbol is HeuristicLab.Problems.DataAnalysis.Symbolic.Variable) {
317        VariableTreeNode variableTreeNode = node as VariableTreeNode;
318        stringBuilder.Append(variableTreeNode.Weight.ToString(CultureInfo.InvariantCulture));
319        stringBuilder.Append("*");
320        stringBuilder.Append(variableTreeNode.VariableName + LagToString(currentLag));
321      } else if (symbol is HeuristicLab.Problems.DataAnalysis.Symbolic.FactorVariable) {
322        var factorNode = node as FactorVariableTreeNode;
323        var weights = string.Join(" ", factorNode.Weights.Select(w => w.ToString("G17", CultureInfo.InvariantCulture)));
324        stringBuilder.AppendFormat("switch_{0}(\"{1}\",[{2}])",
325          factorNode.VariableName, factorNode.VariableName, weights)
326          .AppendLine();
327      } else if (symbol is HeuristicLab.Problems.DataAnalysis.Symbolic.BinaryFactorVariable) {
328        var factorNode = node as BinaryFactorVariableTreeNode;
329        stringBuilder.AppendFormat(CultureInfo.InvariantCulture,
330          "((strcmp({0},\"{1}\")==1) * {2:G17})", factorNode.VariableName, factorNode.VariableValue, factorNode.Weight);
331      } else if (symbol is Power) {
332        stringBuilder.Append("(");
333        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
334        stringBuilder.Append(")^round(");
335        stringBuilder.Append(FormatRecursively(node.GetSubtree(1)));
336        stringBuilder.Append(")");
337      } else if (symbol is Root) {
338        stringBuilder.Append("(");
339        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
340        stringBuilder.Append(")^(1 / round(");
341        stringBuilder.Append(FormatRecursively(node.GetSubtree(1)));
342        stringBuilder.Append("))");
343      } else if (symbol is Derivative) {
344        stringBuilder.Append("fivePoint(");
345        // f0
346        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
347        stringBuilder.Append(", ");
348        // f1
349        currentLag--;
350        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
351        stringBuilder.Append(", ");
352        // f3
353        currentLag -= 2;
354        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
355        stringBuilder.Append(", ");
356        currentLag--;
357        // f4
358        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
359        stringBuilder.Append(")");
360        currentLag += 4;
361      } else if (symbol is Integral) {
362        var laggedNode = node as LaggedTreeNode;
363        string prevCounterVariable = CurrentIndexVariable;
364        string counterVariable = AllocateIndexVariable();
365        stringBuilder.AppendLine(" sum (map(@(" + counterVariable + ") " + FormatRecursively(node.GetSubtree(0)) +
366                                 ", (" + prevCounterVariable + "+" + laggedNode.Lag + "):" + prevCounterVariable +
367                                 "))");
368        ReleaseIndexVariable();
369      } else if (symbol is TimeLag) {
370        var laggedNode = node as LaggedTreeNode;
371        currentLag += laggedNode.Lag;
372        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
373        currentLag -= laggedNode.Lag;
374      } else {
375        stringBuilder.Append("ERROR");
376      }
377      return stringBuilder.ToString();
378    }
379
380
381    private string LagToString(int lag) {
382      if (lag < 0) {
383        return "(" + CurrentIndexVariable + "" + lag + ")";
384      } else if (lag > 0) {
385        return "(" + CurrentIndexVariable + "+" + lag + ")";
386      } else return "(" + CurrentIndexVariable + ")";
387    }
388
389  }
390}
Note: See TracBrowser for help on using the repository browser.