Free cookie consent management tool by TermsFeed Policy Generator

source: stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Formatters/SymbolicDataAnalysisExpressionMATLABFormatter.cs @ 17863

Last change on this file since 17863 was 17181, checked in by swagner, 5 years ago

#2875: Merged r17180 from trunk to stable

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