Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2913_MatlabScriptProblemInstanceProvider/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Formatters/SymbolicDataAnalysisExpressionMATLABFunctionFormatter.cs @ 15958

Last change on this file since 15958 was 15958, checked in by rhanghof, 6 years ago

#2913:

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