Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 14764 was 14764, checked in by gkronber, 7 years ago

#2650 adapted formatters to handle factor symbols

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      {
89        var factorSymb = symbolicExpressionTree.IterateNodesPostfix()
90          .OfType<FactorVariableTreeNode>()
91          .First(n => n.VariableName == factorVarName)
92          .Symbol;
93        stringBuilder.AppendFormat("function y = switch_{0}(val, v)", factorVarName).AppendLine();
94        var values = factorSymb.GetVariableValues(factorVarName).ToArray();
95        stringBuilder.AppendLine("switch val");
96        for(int i = 0; i < values.Length; i++) {
97          stringBuilder.AppendFormat(CultureInfo.InvariantCulture, "  case \"{0}\" y = v({1})", values[i], i).AppendLine();
98        }
99        stringBuilder.AppendLine("end");
100        stringBuilder.AppendLine();
101      }
102
103      return stringBuilder.ToString();
104    }
105
106    public string FormatOnlyExpression(ISymbolicExpressionTreeNode expressionNode) {
107      var stringBuilder = new StringBuilder();
108      stringBuilder.AppendLine("  for " + CurrentIndexVariable + " = 1:1:rows");
109      stringBuilder.AppendLine("    estimated(" + CurrentIndexVariable + ") = " + FormatRecursively(expressionNode.GetSubtree(0)) + ";");
110      stringBuilder.AppendLine("  end;");
111      return stringBuilder.ToString();
112    }
113
114    private string FormatRecursively(ISymbolicExpressionTreeNode node) {
115      ISymbol symbol = node.Symbol;
116      StringBuilder stringBuilder = new StringBuilder();
117
118      if(symbol is ProgramRootSymbol) {
119        stringBuilder.AppendLine(FormatRecursively(node.GetSubtree(0)));
120      } else if(symbol is StartSymbol)
121        return FormatRecursively(node.GetSubtree(0));
122      else if(symbol is Addition) {
123        stringBuilder.Append("(");
124        for(int i = 0; i < node.SubtreeCount; i++) {
125          if(i > 0) stringBuilder.Append("+");
126          stringBuilder.Append(FormatRecursively(node.GetSubtree(i)));
127        }
128        stringBuilder.Append(")");
129      } else if(symbol is And) {
130        stringBuilder.Append("((");
131        for(int i = 0; i < node.SubtreeCount; i++) {
132          if(i > 0) stringBuilder.Append("&");
133          stringBuilder.Append("((");
134          stringBuilder.Append(FormatRecursively(node.GetSubtree(i)));
135          stringBuilder.Append(")>0)");
136        }
137        stringBuilder.Append(")-0.5)*2");
138        // MATLAB maps false and true to 0 and 1, resp., we map this result to -1.0 and +1.0, resp.
139      } else if(symbol is Average) {
140        stringBuilder.Append("(1/");
141        stringBuilder.Append(node.SubtreeCount);
142        stringBuilder.Append(")*(");
143        for(int i = 0; i < node.SubtreeCount; i++) {
144          if(i > 0) stringBuilder.Append("+");
145          stringBuilder.Append("(");
146          stringBuilder.Append(FormatRecursively(node.GetSubtree(i)));
147          stringBuilder.Append(")");
148        }
149        stringBuilder.Append(")");
150      } else if(symbol is Constant) {
151        ConstantTreeNode constantTreeNode = node as ConstantTreeNode;
152        stringBuilder.Append(constantTreeNode.Value.ToString(CultureInfo.InvariantCulture));
153      } else if(symbol is Cosine) {
154        stringBuilder.Append("cos(");
155        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
156        stringBuilder.Append(")");
157      } else if(symbol is Division) {
158        if(node.SubtreeCount == 1) {
159          stringBuilder.Append("1/");
160          stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
161        } else {
162          stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
163          stringBuilder.Append("/(");
164          for(int i = 1; i < node.SubtreeCount; i++) {
165            if(i > 1) stringBuilder.Append("*");
166            stringBuilder.Append(FormatRecursively(node.GetSubtree(i)));
167          }
168          stringBuilder.Append(")");
169        }
170      } else if(symbol is Exponential) {
171        stringBuilder.Append("exp(");
172        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
173        stringBuilder.Append(")");
174      } else if(symbol is Square) {
175        stringBuilder.Append("(");
176        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
177        stringBuilder.Append(").^2");
178      } else if(symbol is SquareRoot) {
179        stringBuilder.Append("sqrt(");
180        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
181        stringBuilder.Append(")");
182      } else if(symbol is GreaterThan) {
183        stringBuilder.Append("((");
184        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
185        stringBuilder.Append(">");
186        stringBuilder.Append(FormatRecursively(node.GetSubtree(1)));
187        stringBuilder.Append(")-0.5)*2");
188        // MATLAB maps false and true to 0 and 1, resp., we map this result to -1.0 and +1.0, resp.
189      } else if(symbol is IfThenElse) {
190        stringBuilder.Append("(");
191        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
192        stringBuilder.Append(">0)*");
193        stringBuilder.Append(FormatRecursively(node.GetSubtree(1)));
194        stringBuilder.Append("+");
195        stringBuilder.Append("(");
196        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
197        stringBuilder.Append("<=0)*");
198        stringBuilder.Append(FormatRecursively(node.GetSubtree(2)));
199      } else if(symbol is LaggedVariable) {
200        // this if must be checked before if(symbol is LaggedVariable)
201        LaggedVariableTreeNode laggedVariableTreeNode = node as LaggedVariableTreeNode;
202        stringBuilder.Append(laggedVariableTreeNode.Weight.ToString(CultureInfo.InvariantCulture));
203        stringBuilder.Append("*");
204        stringBuilder.Append(laggedVariableTreeNode.VariableName +
205                             LagToString(currentLag + laggedVariableTreeNode.Lag));
206      } else if(symbol is LessThan) {
207        stringBuilder.Append("((");
208        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
209        stringBuilder.Append("<");
210        stringBuilder.Append(FormatRecursively(node.GetSubtree(1)));
211        stringBuilder.Append(")-0.5)*2");
212        // MATLAB maps false and true to 0 and 1, resp., we map this result to -1.0 and +1.0, resp.
213      } else if(symbol is Logarithm) {
214        stringBuilder.Append("log_(");
215        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
216        stringBuilder.Append(")");
217      } else if(symbol is Multiplication) {
218        for(int i = 0; i < node.SubtreeCount; i++) {
219          if(i > 0) stringBuilder.Append("*");
220          stringBuilder.Append(FormatRecursively(node.GetSubtree(i)));
221        }
222      } else if(symbol is Not) {
223        stringBuilder.Append("~(");
224        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
225        stringBuilder.Append(" > 0 )");
226      } else if(symbol is Or) {
227        stringBuilder.Append("((");
228        for(int i = 0; i < node.SubtreeCount; i++) {
229          if(i > 0) stringBuilder.Append("|");
230          stringBuilder.Append("((");
231          stringBuilder.Append(FormatRecursively(node.GetSubtree(i)));
232          stringBuilder.Append(")>0)");
233        }
234        stringBuilder.Append(")-0.5)*2");
235        // MATLAB maps false and true to 0 and 1, resp., we map this result to -1.0 and +1.0, resp.
236      } else if(symbol is Sine) {
237        stringBuilder.Append("sin(");
238        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
239        stringBuilder.Append(")");
240      } else if(symbol is Subtraction) {
241        stringBuilder.Append("(");
242        if(node.SubtreeCount == 1) {
243          stringBuilder.Append("-");
244          stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
245        } else {
246          stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
247          for(int i = 1; i < node.SubtreeCount; i++) {
248            stringBuilder.Append("-");
249            stringBuilder.Append(FormatRecursively(node.GetSubtree(i)));
250          }
251        }
252        stringBuilder.Append(")");
253      } else if(symbol is Tangent) {
254        stringBuilder.Append("tan(");
255        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
256        stringBuilder.Append(")");
257      } else if(node.Symbol is AiryA) {
258        stringBuilder.Append("airy(");
259        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
260        stringBuilder.Append(")");
261      } else if(node.Symbol is AiryB) {
262        stringBuilder.Append("airy(2, ");
263        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
264        stringBuilder.Append(")");
265      } else if(node.Symbol is Bessel) {
266        stringBuilder.Append("besseli(0.0,");
267        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
268        stringBuilder.Append(")");
269      } else if(node.Symbol is CosineIntegral) {
270        stringBuilder.Append("cosint(");
271        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
272        stringBuilder.Append(")");
273      } else if(node.Symbol is Dawson) {
274        stringBuilder.Append("dawson(");
275        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
276        stringBuilder.Append(")");
277      } else if(node.Symbol is Erf) {
278        stringBuilder.Append("erf(");
279        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
280        stringBuilder.Append(")");
281      } else if(node.Symbol is ExponentialIntegralEi) {
282        stringBuilder.Append("expint(");
283        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
284        stringBuilder.Append(")");
285      } else if(node.Symbol is FresnelCosineIntegral) {
286        stringBuilder.Append("FresnelC(");
287        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
288        stringBuilder.Append(")");
289      } else if(node.Symbol is FresnelSineIntegral) {
290        stringBuilder.Append("FresnelS(");
291        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
292        stringBuilder.Append(")");
293      } else if(node.Symbol is Gamma) {
294        stringBuilder.Append("gamma(");
295        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
296        stringBuilder.Append(")");
297      } else if(node.Symbol is HyperbolicCosineIntegral) {
298        stringBuilder.Append("Chi(");
299        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
300        stringBuilder.Append(")");
301      } else if(node.Symbol is HyperbolicSineIntegral) {
302        stringBuilder.Append("Shi(");
303        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
304        stringBuilder.Append(")");
305      } else if(node.Symbol is Norm) {
306        stringBuilder.Append("normpdf(");
307        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
308        stringBuilder.Append(")");
309      } else if(node.Symbol is Psi) {
310        stringBuilder.Append("psi(");
311        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
312        stringBuilder.Append(")");
313      } else if(node.Symbol is SineIntegral) {
314        stringBuilder.Append("sinint(");
315        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
316        stringBuilder.Append(")");
317      } else if(symbol is HeuristicLab.Problems.DataAnalysis.Symbolic.Variable) {
318        VariableTreeNode variableTreeNode = node as VariableTreeNode;
319        stringBuilder.Append(variableTreeNode.Weight.ToString(CultureInfo.InvariantCulture));
320        stringBuilder.Append("*");
321        stringBuilder.Append(variableTreeNode.VariableName + LagToString(currentLag));
322      } else if(symbol is HeuristicLab.Problems.DataAnalysis.Symbolic.FactorVariable) {
323        var factorNode = node as FactorVariableTreeNode;
324        var weights = string.Join(" ", factorNode.Weights.Select(w => w.ToString("G17", CultureInfo.InvariantCulture)));
325        stringBuilder.AppendFormat("switch_{0}(\"{1}\",[{2}])",
326          factorNode.VariableName, factorNode.VariableName, weights)
327          .AppendLine();
328      } else if(symbol is HeuristicLab.Problems.DataAnalysis.Symbolic.BinaryFactorVariable) {
329        var factorNode = node as BinaryFactorVariableTreeNode;
330        stringBuilder.AppendFormat(CultureInfo.InvariantCulture,
331          "((strcmp({0},\"{1}\")==1) * {2:G17})", factorNode.VariableName, factorNode.VariableValue, factorNode.Weight);
332      } else if(symbol is Power) {
333        stringBuilder.Append("(");
334        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
335        stringBuilder.Append(")^round(");
336        stringBuilder.Append(FormatRecursively(node.GetSubtree(1)));
337        stringBuilder.Append(")");
338      } else if(symbol is Root) {
339        stringBuilder.Append("(");
340        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
341        stringBuilder.Append(")^(1 / round(");
342        stringBuilder.Append(FormatRecursively(node.GetSubtree(1)));
343        stringBuilder.Append("))");
344      } else if(symbol is Derivative) {
345        stringBuilder.Append("fivePoint(");
346        // f0
347        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
348        stringBuilder.Append(", ");
349        // f1
350        currentLag--;
351        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
352        stringBuilder.Append(", ");
353        // f3
354        currentLag -= 2;
355        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
356        stringBuilder.Append(", ");
357        currentLag--;
358        // f4
359        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
360        stringBuilder.Append(")");
361        currentLag += 4;
362      } else if(symbol is Integral) {
363        var laggedNode = node as LaggedTreeNode;
364        string prevCounterVariable = CurrentIndexVariable;
365        string counterVariable = AllocateIndexVariable();
366        stringBuilder.AppendLine(" sum (map(@(" + counterVariable + ") " + FormatRecursively(node.GetSubtree(0)) +
367                                 ", (" + prevCounterVariable + "+" + laggedNode.Lag + "):" + prevCounterVariable +
368                                 "))");
369        ReleaseIndexVariable();
370      } else if(symbol is TimeLag) {
371        var laggedNode = node as LaggedTreeNode;
372        currentLag += laggedNode.Lag;
373        stringBuilder.Append(FormatRecursively(node.GetSubtree(0)));
374        currentLag -= laggedNode.Lag;
375      } else {
376        stringBuilder.Append("ERROR");
377      }
378      return stringBuilder.ToString();
379    }
380
381
382    private string LagToString(int lag) {
383      if(lag < 0) {
384        return "(" + CurrentIndexVariable + "" + lag + ")";
385      } else if(lag > 0) {
386        return "(" + CurrentIndexVariable + "+" + lag + ")";
387      } else return "(" + CurrentIndexVariable + ")";
388    }
389
390  }
391}
Note: See TracBrowser for help on using the repository browser.