Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionCompiledTreeInterpreter.cs @ 18242

Last change on this file since 18242 was 18220, checked in by gkronber, 3 years ago

#3136: reintegrated structure-template GP branch into trunk

File size: 33.8 KB
RevLine 
[12807]1#region License Information
2/* HeuristicLab
[17180]3 * Copyright (C) Heuristic and Evolutionary Algorithms Laboratory (HEAL)
[12807]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.Collections.Generic;
24using System.Linq;
25using System.Linq.Expressions;
26using System.Reflection;
27using HeuristicLab.Common;
28using HeuristicLab.Core;
29using HeuristicLab.Data;
30using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
31using HeuristicLab.Parameters;
[16565]32using HEAL.Attic;
[12807]33
34namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
[16565]35  [StorableType("DFA06F28-E224-4D93-9907-69792D24D1F9")]
[12807]36  [Item("SymbolicDataAnalysisExpressionCompiledTreeInterpreter", "Interpreter that converts the tree into a Linq.Expression then compiles it.")]
37  public sealed class SymbolicDataAnalysisExpressionCompiledTreeInterpreter : ParameterizedNamedItem, ISymbolicDataAnalysisExpressionTreeInterpreter {
38    private const string CheckExpressionsWithIntervalArithmeticParameterName = "CheckExpressionsWithIntervalArithmetic";
[13222]39    private const string CheckExpressionsWithIntervalArithmeticParameterDescription = "Switch that determines if the interpreter checks the validity of expressions with interval arithmetic before evaluating the expression.";
[12807]40    private const string EvaluatedSolutionsParameterName = "EvaluatedSolutions";
41
42    #region method info for the commonly called functions
[16356]43    private static readonly MethodInfo Abs = typeof(Math).GetMethod("Abs", new[] { typeof(double) });
[12807]44    private static readonly MethodInfo Sin = typeof(Math).GetMethod("Sin", new[] { typeof(double) });
45    private static readonly MethodInfo Cos = typeof(Math).GetMethod("Cos", new[] { typeof(double) });
46    private static readonly MethodInfo Tan = typeof(Math).GetMethod("Tan", new[] { typeof(double) });
[16668]47    private static readonly MethodInfo Tanh = typeof(Math).GetMethod("Tanh", new[] { typeof(double) });
[12807]48    private static readonly MethodInfo Sqrt = typeof(Math).GetMethod("Sqrt", new[] { typeof(double) });
49    private static readonly MethodInfo Floor = typeof(Math).GetMethod("Floor", new[] { typeof(double) });
[13288]50    private static readonly MethodInfo Round = typeof(Math).GetMethod("Round", new[] { typeof(double) });
[12807]51    private static readonly MethodInfo Exp = typeof(Math).GetMethod("Exp", new[] { typeof(double) });
52    private static readonly MethodInfo Log = typeof(Math).GetMethod("Log", new[] { typeof(double) });
53    private static readonly MethodInfo IsNaN = typeof(double).GetMethod("IsNaN");
[17351]54    private static readonly MethodInfo IsAlmost = typeof(DoubleExtensions).GetMethod("IsAlmost", new Type[] { typeof(double), typeof(double)});
[12807]55    private static readonly MethodInfo Gamma = typeof(alglib).GetMethod("gammafunction", new[] { typeof(double) });
56    private static readonly MethodInfo Psi = typeof(alglib).GetMethod("psi", new[] { typeof(double) });
57    private static readonly MethodInfo DawsonIntegral = typeof(alglib).GetMethod("dawsonintegral", new[] { typeof(double) });
58    private static readonly MethodInfo ExponentialIntegralEi = typeof(alglib).GetMethod("exponentialintegralei", new[] { typeof(double) });
59    private static readonly MethodInfo SineCosineIntegrals = typeof(alglib).GetMethod("sinecosineintegrals", new[] { typeof(double), typeof(double).MakeByRefType(), typeof(double).MakeByRefType() });
60    private static readonly MethodInfo HyperbolicSineCosineIntegrals = typeof(alglib).GetMethod("hyperbolicsinecosineintegrals", new[] { typeof(double), typeof(double).MakeByRefType(), typeof(double).MakeByRefType() });
61    private static readonly MethodInfo FresnelIntegral = typeof(alglib).GetMethod("fresnelintegral", new[] { typeof(double), typeof(double).MakeByRefType(), typeof(double).MakeByRefType() });
62    private static readonly MethodInfo Airy = typeof(alglib).GetMethod("airy", new[] { typeof(double), typeof(double).MakeByRefType(), typeof(double).MakeByRefType(), typeof(double).MakeByRefType(), typeof(double).MakeByRefType() });
63    private static readonly MethodInfo NormalDistribution = typeof(alglib).GetMethod("normaldistribution", new[] { typeof(double) });
64    private static readonly MethodInfo ErrorFunction = typeof(alglib).GetMethod("errorfunction", new[] { typeof(double) });
65    private static readonly MethodInfo Bessel = typeof(alglib).GetMethod("besseli0", new[] { typeof(double) });
66    #endregion
67
68    public override bool CanChangeName { get { return false; } }
69    public override bool CanChangeDescription { get { return false; } }
70
71    #region parameter properties
[13141]72    public IFixedValueParameter<BoolValue> CheckExpressionsWithIntervalArithmeticParameter {
73      get { return (IFixedValueParameter<BoolValue>)Parameters[CheckExpressionsWithIntervalArithmeticParameterName]; }
[12807]74    }
75
[13141]76    public IFixedValueParameter<IntValue> EvaluatedSolutionsParameter {
77      get { return (IFixedValueParameter<IntValue>)Parameters[EvaluatedSolutionsParameterName]; }
[12807]78    }
79    #endregion
80
81    #region properties
[13141]82    public bool CheckExpressionsWithIntervalArithmetic {
83      get { return CheckExpressionsWithIntervalArithmeticParameter.Value.Value; }
84      set { CheckExpressionsWithIntervalArithmeticParameter.Value.Value = value; }
[12807]85    }
[13141]86    public int EvaluatedSolutions {
87      get { return EvaluatedSolutionsParameter.Value.Value; }
88      set { EvaluatedSolutionsParameter.Value.Value = value; }
[12807]89    }
90    #endregion
91
92    public override IDeepCloneable Clone(Cloner cloner) {
93      return new SymbolicDataAnalysisExpressionCompiledTreeInterpreter(this, cloner);
94    }
95
96    private SymbolicDataAnalysisExpressionCompiledTreeInterpreter(SymbolicDataAnalysisExpressionCompiledTreeInterpreter original, Cloner cloner)
97      : base(original, cloner) {
98    }
99
100    [StorableConstructor]
[16565]101    private SymbolicDataAnalysisExpressionCompiledTreeInterpreter(StorableConstructorFlag _) : base(_) {
[12807]102    }
103
[13141]104    public SymbolicDataAnalysisExpressionCompiledTreeInterpreter() :
105      base("SymbolicDataAnalysisExpressionCompiledTreeInterpreter", "Interpreter which compiles the tree into a lambda") {
[13222]106      Parameters.Add(new FixedValueParameter<BoolValue>(CheckExpressionsWithIntervalArithmeticParameterName, CheckExpressionsWithIntervalArithmeticParameterDescription, new BoolValue(false)));
[13141]107      Parameters.Add(new FixedValueParameter<IntValue>(EvaluatedSolutionsParameterName, "A counter for the total number of solutions the interpreter has evaluated", new IntValue(0)));
[12807]108    }
109
[13141]110    public SymbolicDataAnalysisExpressionCompiledTreeInterpreter(string name, string description) :
111      base(name, description) {
[13222]112      Parameters.Add(new FixedValueParameter<BoolValue>(CheckExpressionsWithIntervalArithmeticParameterName, CheckExpressionsWithIntervalArithmeticParameterDescription, new BoolValue(false)));
[13141]113      Parameters.Add(new FixedValueParameter<IntValue>(EvaluatedSolutionsParameterName, "A counter for the total number of solutions the interpreter has evaluated", new IntValue(0)));
114    }
115
[12807]116    public void InitializeState() {
[13141]117      EvaluatedSolutions = 0;
[12807]118    }
119
[13222]120    public void ClearState() { }
[12807]121
[13251]122    private readonly object syncRoot = new object();
[12807]123    public IEnumerable<double> GetSymbolicExpressionTreeValues(ISymbolicExpressionTree tree, IDataset dataset, IEnumerable<int> rows) {
[13141]124      if (CheckExpressionsWithIntervalArithmetic)
[12807]125        throw new NotSupportedException("Interval arithmetic is not yet supported in the symbolic data analysis interpreter.");
126
[13251]127      lock (syncRoot) {
[13141]128        EvaluatedSolutions++; // increment the evaluated solutions counter
[12807]129      }
[13222]130      var columns = dataset.DoubleVariables.Select(x => (IList<double>)dataset.GetReadOnlyDoubleValues(x)).ToArray();
[12807]131      var compiled = CompileTree(tree, dataset);
[13140]132      return rows.Select(x => compiled(x, columns));
[12807]133    }
134
[13222]135    public static Func<int, IList<double>[], double> CompileTree(ISymbolicExpressionTree tree, IDataset dataset) {
[13313]136      var lambda = CreateDelegate(tree, dataset);
137      return lambda.Compile();
138    }
139
140    public static Expression<Func<int, IList<double>[], double>> CreateDelegate(ISymbolicExpressionTree tree, IDataset dataset) {
[12807]141      var row = Expression.Parameter(typeof(int));
[13222]142      var columns = Expression.Parameter(typeof(IList<double>[]));
[13140]143      var variableIndices = dataset.DoubleVariables.Select((x, i) => new { x, i }).ToDictionary(e => e.x, e => e.i);
144      var expr = MakeExpr(tree, variableIndices, row, columns);
[13222]145      var lambda = Expression.Lambda<Func<int, IList<double>[], double>>(expr, row, columns);
[13313]146      return lambda;
[12807]147    }
148
[13141]149    private static Expression MakeExpr(ISymbolicExpressionTree tree, Dictionary<string, int> variableIndices, Expression row, Expression columns) {
[12807]150      var actualRoot = tree.Root.GetSubtree(0).GetSubtree(0);
[13140]151      return MakeExpr(actualRoot, variableIndices, row, columns);
[12807]152    }
153
[13222]154    private static readonly PropertyInfo Indexer = typeof(IList<double>).GetProperty("Item");
[13141]155    private static Expression MakeExpr(ISymbolicExpressionTreeNode node, Dictionary<string, int> variableIndices, Expression row, Expression columns) {
[12807]156      var opcode = OpCodes.MapSymbolToOpCode(node);
[13141]157      #region switch opcode
[12807]158      switch (opcode) {
[18132]159        case OpCodes.Constant: // fall through
160        case OpCodes.Number: {
161          var numberTreeNode = (INumericTreeNode)node;
162          return Expression.Constant(numberTreeNode.Value);
[12807]163          }
[13222]164        case OpCodes.Variable: {
[12807]165            var variableTreeNode = (VariableTreeNode)node;
166            var variableWeight = Expression.Constant(variableTreeNode.Weight);
[13140]167            var variableName = variableTreeNode.VariableName;
168            var indexExpr = Expression.Constant(variableIndices[variableName]);
169            var valuesExpr = Expression.ArrayIndex(columns, indexExpr);
[13288]170            return Expression.Multiply(variableWeight, Expression.Property(valuesExpr, Indexer, row));
[12807]171          }
[13222]172        case OpCodes.Add: {
[13140]173            Expression result = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]174            for (int i = 1; i < node.SubtreeCount; ++i) {
[13140]175              result = Expression.Add(result, MakeExpr(node.GetSubtree(i), variableIndices, row, columns));
[12807]176            }
177            return result;
178          }
[13222]179        case OpCodes.Sub: {
[13140]180            Expression result = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]181            if (node.SubtreeCount == 1)
182              return Expression.Negate(result);
183            for (int i = 1; i < node.SubtreeCount; ++i) {
[13140]184              result = Expression.Subtract(result, MakeExpr(node.GetSubtree(i), variableIndices, row, columns));
[12807]185            }
186            return result;
187          }
[13222]188        case OpCodes.Mul: {
[13140]189            Expression result = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]190            for (int i = 1; i < node.SubtreeCount; ++i) {
[13140]191              result = Expression.Multiply(result, MakeExpr(node.GetSubtree(i), variableIndices, row, columns));
[12807]192            }
193            return result;
194          }
[13222]195        case OpCodes.Div: {
[13140]196            Expression result = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]197            if (node.SubtreeCount == 1)
198              return Expression.Divide(Expression.Constant(1.0), result);
199            for (int i = 1; i < node.SubtreeCount; ++i) {
[13140]200              result = Expression.Divide(result, MakeExpr(node.GetSubtree(i), variableIndices, row, columns));
[12807]201            }
202            return result;
203          }
[13222]204        case OpCodes.Average: {
[13140]205            Expression result = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]206            for (int i = 1; i < node.SubtreeCount; ++i) {
[13140]207              result = Expression.Add(result, MakeExpr(node.GetSubtree(i), variableIndices, row, columns));
[12807]208            }
209            return Expression.Divide(result, Expression.Constant((double)node.SubtreeCount));
210          }
[16356]211        case OpCodes.Absolute: {
212            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
213            return Expression.Call(Abs, arg);
214          }
[13222]215        case OpCodes.Cos: {
[13140]216            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]217            return Expression.Call(Cos, arg);
218          }
[13222]219        case OpCodes.Sin: {
[13140]220            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]221            return Expression.Call(Sin, arg);
222          }
[13222]223        case OpCodes.Tan: {
[13140]224            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]225            return Expression.Call(Tan, arg);
226          }
[16668]227        case OpCodes.Tanh: {
228            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
229            return Expression.Call(Tanh, arg);
230          }
[13222]231        case OpCodes.Square: {
[13140]232            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[13288]233            return Expression.Power(arg, Expression.Constant(2.0));
[12807]234          }
[16356]235        case OpCodes.Cube: {
236            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
237            return Expression.Power(arg, Expression.Constant(3.0));
238          }
[13222]239        case OpCodes.Power: {
[13140]240            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
241            var power = MakeExpr(node.GetSubtree(1), variableIndices, row, columns);
[13288]242            return Expression.Power(arg, Expression.Call(Round, power));
[12807]243          }
[13222]244        case OpCodes.SquareRoot: {
[13140]245            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]246            return Expression.Call(Sqrt, arg);
247          }
[16356]248        case OpCodes.CubeRoot: {
249            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[16905]250            return Expression.Condition(Expression.LessThan(arg, Expression.Constant(0.0)),
251              Expression.Negate(Expression.Power(Expression.Negate(arg), Expression.Constant(1.0 / 3.0))),
252              Expression.Power(arg, Expression.Constant(1.0 / 3.0)));
[16356]253          }
[13222]254        case OpCodes.Root: {
[13140]255            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
256            var power = MakeExpr(node.GetSubtree(1), variableIndices, row, columns);
[13288]257            return Expression.Power(arg, Expression.Divide(Expression.Constant(1.0), Expression.Call(Round, power)));
[12807]258          }
[13222]259        case OpCodes.Exp: {
[13140]260            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]261            return Expression.Call(Exp, arg);
262          }
[13222]263        case OpCodes.Log: {
[13140]264            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]265            return Expression.Call(Log, arg);
266          }
[13222]267        case OpCodes.Gamma: {
[13140]268            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]269            var isNaN = Expression.Call(IsNaN, arg);
270
271            var result = Expression.Variable(typeof(double));
272            var expr = Expression.Block(
273              new[] { result },
274              Expression.IfThenElse(
275                isNaN,
276                Expression.Assign(result, Expression.Constant(double.NaN)),
[13313]277                Expression.Assign(result, Expression.Call(Gamma, arg))
[12807]278                ),
279              result
280              );
281            return expr;
282          }
[13222]283        case OpCodes.Psi: {
[13140]284            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]285            var isNaN = Expression.Call(IsNaN, arg);
286
287            var result = Expression.Variable(typeof(double));
288            var floor = Expression.Call(Floor, arg);
289            var expr = Expression.Block(
290              new[] { result },
291              Expression.IfThenElse(
292                isNaN,
293                Expression.Assign(result, Expression.Constant(double.NaN)),
294                Expression.IfThenElse(
[13288]295                  Expression.AndAlso(
296                    Expression.LessThanOrEqual(arg, Expression.Constant(0.0)),
297                    Expression.Call(IsAlmost, Expression.Subtract(floor, arg), Expression.Constant(0.0))),
[12807]298                  Expression.Assign(result, Expression.Constant(double.NaN)),
[13313]299                  Expression.Assign(result, Expression.Call(Psi, arg)))
[12807]300                ),
301              result);
302
303            return expr;
304          }
[13222]305        case OpCodes.Dawson: {
[13140]306            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]307            var isNaN = Expression.Call(IsNaN, arg);
308            var result = Expression.Variable(typeof(double));
309            var expr = Expression.Block(
310              new[] { result },
311              Expression.IfThenElse(isNaN,
312                Expression.Assign(result, Expression.Constant(double.NaN)),
[13313]313                Expression.Assign(result, Expression.Call(DawsonIntegral, arg))),
[12807]314              result
315              );
316
317            return expr;
318          }
[13222]319        case OpCodes.ExponentialIntegralEi: {
[13140]320            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]321            var isNaN = Expression.Call(IsNaN, arg);
322            var result = Expression.Variable(typeof(double));
323            var expr = Expression.Block(
324              new[] { result },
325              Expression.IfThenElse(isNaN,
326                Expression.Assign(result, Expression.Constant(double.NaN)),
[13313]327                Expression.Assign(result, Expression.Call(ExponentialIntegralEi, arg))),
[12807]328              result
329              );
330
331            return expr;
332          }
[13222]333        case OpCodes.SineIntegral: {
[13140]334            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]335            var isNaN = Expression.Call(IsNaN, arg);
336            var si = Expression.Variable(typeof(double));
337            var ci = Expression.Variable(typeof(double));
338            var block = Expression.Block(
339              new[] { si, ci },
[13313]340              Expression.Call(SineCosineIntegrals, arg, si, ci),
[12807]341              si
342              );
343            var result = Expression.Variable(typeof(double));
344            var expr = Expression.Block(new[] { result },
345              Expression.IfThenElse(isNaN,
346                Expression.Assign(result, Expression.Constant(double.NaN)),
347                Expression.Assign(result, block)),
348              result
349              );
350
351            return expr;
352          }
[13222]353        case OpCodes.CosineIntegral: {
[13140]354            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]355            var isNaN = Expression.Call(IsNaN, arg);
356            var si = Expression.Variable(typeof(double));
357            var ci = Expression.Variable(typeof(double));
358            var block = Expression.Block(
359              new[] { si, ci },
[13313]360              Expression.Call(SineCosineIntegrals, arg, si, ci),
[12807]361              ci
362              );
363            var result = Expression.Variable(typeof(double));
364            var expr = Expression.Block(new[] { result },
365              Expression.IfThenElse(isNaN,
366                Expression.Assign(result, Expression.Constant(double.NaN)),
367                Expression.Assign(result, block)),
368              result
369              );
370
371            return expr;
372          }
[13222]373        case OpCodes.HyperbolicSineIntegral: {
[13140]374            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]375            var isNaN = Expression.Call(IsNaN, arg);
376            var shi = Expression.Variable(typeof(double));
377            var chi = Expression.Variable(typeof(double));
378            var block = Expression.Block(
379              new[] { shi, chi },
[13288]380              Expression.Call(HyperbolicSineCosineIntegrals, arg, shi, chi),
[12807]381              shi
382              );
383            var result = Expression.Variable(typeof(double));
384            var expr = Expression.Block(new[] { result },
385              Expression.IfThenElse(isNaN,
386                Expression.Assign(result, Expression.Constant(double.NaN)),
387                Expression.Assign(result, block)),
388              result
389              );
390
391            return expr;
392          }
[13222]393        case OpCodes.HyperbolicCosineIntegral: {
[13140]394            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]395            var isNaN = Expression.Call(IsNaN, arg);
396            var shi = Expression.Variable(typeof(double));
397            var chi = Expression.Variable(typeof(double));
398            var block = Expression.Block(
399              new[] { shi, chi },
[13288]400              Expression.Call(HyperbolicSineCosineIntegrals, arg, shi, chi),
[12807]401              chi
402              );
403            var result = Expression.Variable(typeof(double));
404            var expr = Expression.Block(new[] { result },
405              Expression.IfThenElse(isNaN,
406                Expression.Assign(result, Expression.Constant(double.NaN)),
407                Expression.Assign(result, block)),
408              result
409              );
410
411            return expr;
412          }
[13222]413        case OpCodes.FresnelSineIntegral: {
[13140]414            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]415            var isNaN = Expression.Call(IsNaN, arg);
416            var s = Expression.Variable(typeof(double));
417            var c = Expression.Variable(typeof(double));
[13313]418            var block = Expression.Block(new[] { s, c }, Expression.Call(FresnelIntegral, arg, c, s), s);
[12807]419            var result = Expression.Variable(typeof(double));
420            var expr = Expression.Block(new[] { result },
421              Expression.IfThenElse(isNaN,
422                Expression.Assign(result, Expression.Constant(double.NaN)),
423                Expression.Assign(result, block)),
424              result
425              );
426
427            return expr;
428          }
[13222]429        case OpCodes.FresnelCosineIntegral: {
[13140]430            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]431            var isNaN = Expression.Call(IsNaN, arg);
432            var s = Expression.Variable(typeof(double));
433            var c = Expression.Variable(typeof(double));
[13313]434            var block = Expression.Block(new[] { s, c }, Expression.Call(FresnelIntegral, arg, c, s), c);
[12807]435            var result = Expression.Variable(typeof(double));
436            var expr = Expression.Block(new[] { result },
437              Expression.IfThenElse(isNaN,
438                Expression.Assign(result, Expression.Constant(double.NaN)),
439                Expression.Assign(result, block)),
440              result
441              );
442
443            return expr;
444          }
[13222]445        case OpCodes.AiryA: {
[13140]446            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]447            var isNaN = Expression.Call(IsNaN, arg);
448            var ai = Expression.Variable(typeof(double));
449            var aip = Expression.Variable(typeof(double));
450            var bi = Expression.Variable(typeof(double));
451            var bip = Expression.Variable(typeof(double));
[13313]452            var block = Expression.Block(new[] { ai, aip, bi, bip }, Expression.Call(Airy, arg, ai, aip, bi, bip), ai);
[12807]453            var result = Expression.Variable(typeof(double));
454            var expr = Expression.Block(new[] { result },
455              Expression.IfThenElse(isNaN,
456                Expression.Assign(result, Expression.Constant(double.NaN)),
457                Expression.Assign(result, block)),
458              result
459              );
460
461            return expr;
462          }
[13222]463        case OpCodes.AiryB: {
[13140]464            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]465            var isNaN = Expression.Call(IsNaN, arg);
466            var ai = Expression.Variable(typeof(double));
467            var aip = Expression.Variable(typeof(double));
468            var bi = Expression.Variable(typeof(double));
469            var bip = Expression.Variable(typeof(double));
[13313]470            var block = Expression.Block(new[] { ai, aip, bi, bip }, Expression.Call(Airy, arg, ai, aip, bi, bip), bi);
[12807]471            var result = Expression.Variable(typeof(double));
472            var expr = Expression.Block(new[] { result },
473              Expression.IfThenElse(isNaN,
474                Expression.Assign(result, Expression.Constant(double.NaN)),
475                Expression.Assign(result, block)),
476              result
477              );
478
479            return expr;
480          }
[13222]481        case OpCodes.Norm: {
[13140]482            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]483            var result = Expression.Variable(typeof(double));
[13288]484            return Expression.Block(
485              new[] { result },
486              Expression.IfThenElse(
[13313]487                Expression.Call(IsNaN, arg),
488                Expression.Assign(result, arg),
[13288]489                Expression.Assign(result, Expression.Call(NormalDistribution, arg))),
490              result);
[12807]491          }
[13222]492        case OpCodes.Erf: {
[13140]493            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]494            var isNaN = Expression.Call(IsNaN, arg);
495            var result = Expression.Variable(typeof(double));
[13288]496            return Expression.Block(
497              new[] { result },
498              Expression.IfThenElse(
499                isNaN,
500                Expression.Assign(result, Expression.Constant(double.NaN)),
501                Expression.Assign(result, Expression.Call(ErrorFunction, arg))),
502              result);
[12807]503          }
[13222]504        case OpCodes.Bessel: {
[13140]505            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]506            var isNaN = Expression.Call(IsNaN, arg);
507            var result = Expression.Variable(typeof(double));
[13288]508            return Expression.Block(
[12807]509              new[] { result },
510              Expression.IfThenElse(
511                isNaN,
512                Expression.Assign(result, Expression.Constant(double.NaN)),
[13288]513                Expression.Assign(result, Expression.Call(Bessel, arg))),
[12807]514              result);
515          }
[16360]516        case OpCodes.AnalyticQuotient: {
[16356]517            var x1 = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
518            var x2 = MakeExpr(node.GetSubtree(1), variableIndices, row, columns);
[16905]519            return Expression.Divide(x1,
520              Expression.Call(Sqrt,
[16356]521              Expression.Add(
522                Expression.Constant(1.0),
523                Expression.Multiply(x2, x2))));
524          }
[13222]525        case OpCodes.IfThenElse: {
[13140]526            var test = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]527            var result = Expression.Variable(typeof(double));
528            var condition = Expression.IfThenElse(Expression.GreaterThan(test, Expression.Constant(0.0)),
[13140]529              Expression.Assign(result, MakeExpr(node.GetSubtree(1), variableIndices, row, columns)),
530              Expression.Assign(result, MakeExpr(node.GetSubtree(2), variableIndices, row, columns)));
[12807]531            return Expression.Block(new[] { result }, condition, result);
532          }
[13222]533        case OpCodes.AND: {
[12807]534            var result = Expression.Variable(typeof(double));
[13140]535            var expr = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]536
537            for (int i = 1; i < node.SubtreeCount; ++i) {
538              expr = Expression.Block(new[] { result },
539                Expression.IfThenElse(
540                  Expression.GreaterThan(expr, Expression.Constant(0.0)),
[13140]541                  Expression.Assign(result, MakeExpr(node.GetSubtree(i), variableIndices, row, columns)),
[12807]542                  Expression.Assign(result, expr)),
543                result
544                );
545            }
546
547            return Expression.Block(
548              new[] { result },
549              Expression.Assign(result, expr),
550              Expression.IfThenElse(
551                Expression.GreaterThan(result, Expression.Constant(0.0)),
552                Expression.Assign(result, Expression.Constant(1.0)),
553                Expression.Assign(result, Expression.Constant(-1.0))
554                ),
555              result
556              );
557          }
[13222]558        case OpCodes.OR: {
[12807]559            var result = Expression.Variable(typeof(double));
[13140]560            var expr = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]561
562            for (int i = 1; i < node.SubtreeCount; ++i) {
563              expr = Expression.Block(new[] { result },
564                Expression.IfThenElse(
565                  Expression.LessThanOrEqual(expr, Expression.Constant(0.0)),
[13140]566                  Expression.Assign(result, MakeExpr(node.GetSubtree(i), variableIndices, row, columns)),
[12807]567                  Expression.Assign(result, expr)),
568                result
569                );
570            }
571
572            return Expression.Block(
573              new[] { result },
574              Expression.Assign(result, expr),
575              Expression.IfThenElse(
576                Expression.GreaterThan(result, Expression.Constant(0.0)),
577                Expression.Assign(result, Expression.Constant(1.0)),
578                Expression.Assign(result, Expression.Constant(-1.0))
579                ),
580              result
581              );
582          }
[13222]583        case OpCodes.NOT: {
[13140]584            var value = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]585            var result = Expression.Variable(typeof(double));
586            var condition = Expression.IfThenElse(Expression.GreaterThan(value, Expression.Constant(0.0)),
587              Expression.Assign(result, Expression.Constant(-1.0)),
588              Expression.Assign(result, Expression.Constant(1.0)));
589            return Expression.Block(new[] { result }, condition, result);
590          }
[13222]591        case OpCodes.XOR: {
[12807]592            var ps = Expression.Variable(typeof(int));
593            var block = Expression.Block(
594              new[] { ps },
595              Expression.Assign(ps, Expression.Constant(0)),
596              ps
597              );
598
599            foreach (var subtree in node.Subtrees) {
[13140]600              var expr = MakeExpr(subtree, variableIndices, row, columns);
[12807]601              block = Expression.Block(
602                new[] { ps },
603                Expression.Assign(ps, block),
604                Expression.IfThen(Expression.GreaterThan(expr, Expression.Constant(0.0)),
605                  Expression.PostIncrementAssign(ps)),
606                ps
607                );
608            }
609
610            var result = Expression.Variable(typeof(double));
611            var xorExpr = Expression.Block(
612              new[] { result },
613              Expression.IfThenElse(
614                Expression.Equal(Expression.Modulo(block, Expression.Constant(2)), Expression.Constant(0)),
615                Expression.Assign(result, Expression.Constant(-1.0)),
616                Expression.Assign(result, Expression.Constant(1.0))
617                ),
618              result
619              );
620            return xorExpr;
621          }
[13222]622        case OpCodes.GT: {
[13140]623            var left = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
624            var right = MakeExpr(node.GetSubtree(1), variableIndices, row, columns);
[12807]625            var result = Expression.Variable(typeof(double));
626
627            var condition = Expression.IfThenElse(Expression.GreaterThan(left, right),
628              Expression.Assign(result, Expression.Constant(1.0)), Expression.Assign(result, Expression.Constant(-1.0)));
629            return Expression.Block(
630              new[] { result },
631              condition,
632              result);
633          }
[13222]634        case OpCodes.LT: {
[13140]635            var left = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
636            var right = MakeExpr(node.GetSubtree(1), variableIndices, row, columns);
[12807]637            var result = Expression.Variable(typeof(double));
638
639            var condition = Expression.IfThenElse(Expression.LessThan(left, right),
640              Expression.Assign(result, Expression.Constant(1.0)), Expression.Assign(result, Expression.Constant(-1.0)));
641            return Expression.Block(new[] { result }, condition, result);
642          }
[13222]643        case OpCodes.VariableCondition: {
[12807]644            var variableConditionTreeNode = (VariableConditionTreeNode)node;
[14345]645            if (variableConditionTreeNode.Symbol.IgnoreSlope) throw new NotSupportedException("Strict variable conditionals are not supported");
[13140]646            var variableName = variableConditionTreeNode.VariableName;
647            var indexExpr = Expression.Constant(variableIndices[variableName]);
648            var valuesExpr = Expression.ArrayIndex(columns, indexExpr);
[13288]649            var variableValue = Expression.Property(valuesExpr, Indexer, row);
[12807]650            var variableThreshold = Expression.Constant(variableConditionTreeNode.Threshold);
651            var variableSlope = Expression.Constant(variableConditionTreeNode.Slope);
652
653            var x = Expression.Subtract(variableValue, variableThreshold);
654            var xSlope = Expression.Multiply(Expression.Negate(variableSlope), x);
655            var xSlopeExp = Expression.Call(Exp, xSlope);
656            var p = Expression.Divide(Expression.Constant(1), Expression.Add(Expression.Constant(1), xSlopeExp));
[13140]657            var trueBranch = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
658            var falseBranch = MakeExpr(node.GetSubtree(1), variableIndices, row, columns);
[12807]659            return Expression.Add(
660              Expression.Multiply(trueBranch, p),
661              Expression.Multiply(falseBranch, Expression.Subtract(Expression.Constant(1), p))
662              );
663          }
[18220]664        case OpCodes.SubFunction: {
665          return MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
666        }
[12807]667        default:
668          throw new NotSupportedException("Unsupported symbol: " + node.Symbol);
669      }
[13141]670      #endregion
[12807]671    }
672  }
673}
Note: See TracBrowser for help on using the repository browser.