Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2913_MatlabScriptProblemInstanceProvider/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Formatters/SymbolicDataAnalysisExpressionCFormatter.cs @ 17714

Last change on this file since 17714 was 15988, checked in by rhanghof, 7 years ago

#2913: Added a new symbolic data expression formater for C code

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