Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2925_AutoDiffForDynamicalModels/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionCompiledTreeInterpreter.cs @ 16864

Last change on this file since 16864 was 16662, checked in by gkronber, 6 years ago

#2925: merged all changes from trunk to branch (up to r16659)

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