Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2915-AbsoluteSymbol/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionCompiledTreeInterpreter.cs @ 16239

Last change on this file since 16239 was 16238, checked in by gkronber, 6 years ago

#2915: implemented all symbols in all interpreters

File size: 33.2 KB
RevLine 
[12807]1#region License Information
2/* HeuristicLab
[15583]3 * Copyright (C) 2002-2018 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;
32using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
33
34namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
35  [StorableClass]
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
[16238]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]
100    private SymbolicDataAnalysisExpressionCompiledTreeInterpreter(bool deserializing)
101      : base(deserializing) {
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) {
[13222]159        case OpCodes.Constant: {
[12807]160            var constantTreeNode = (ConstantTreeNode)node;
161            return Expression.Constant(constantTreeNode.Value);
162          }
[13222]163        case OpCodes.Variable: {
[12807]164            var variableTreeNode = (VariableTreeNode)node;
165            var variableWeight = Expression.Constant(variableTreeNode.Weight);
[13140]166            var variableName = variableTreeNode.VariableName;
167            var indexExpr = Expression.Constant(variableIndices[variableName]);
168            var valuesExpr = Expression.ArrayIndex(columns, indexExpr);
[13288]169            return Expression.Multiply(variableWeight, Expression.Property(valuesExpr, Indexer, row));
[12807]170          }
[13222]171        case OpCodes.Add: {
[13140]172            Expression result = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]173            for (int i = 1; i < node.SubtreeCount; ++i) {
[13140]174              result = Expression.Add(result, MakeExpr(node.GetSubtree(i), variableIndices, row, columns));
[12807]175            }
176            return result;
177          }
[13222]178        case OpCodes.Sub: {
[13140]179            Expression result = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]180            if (node.SubtreeCount == 1)
181              return Expression.Negate(result);
182            for (int i = 1; i < node.SubtreeCount; ++i) {
[13140]183              result = Expression.Subtract(result, MakeExpr(node.GetSubtree(i), variableIndices, row, columns));
[12807]184            }
185            return result;
186          }
[13222]187        case OpCodes.Mul: {
[13140]188            Expression result = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]189            for (int i = 1; i < node.SubtreeCount; ++i) {
[13140]190              result = Expression.Multiply(result, MakeExpr(node.GetSubtree(i), variableIndices, row, columns));
[12807]191            }
192            return result;
193          }
[13222]194        case OpCodes.Div: {
[13140]195            Expression result = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]196            if (node.SubtreeCount == 1)
197              return Expression.Divide(Expression.Constant(1.0), result);
198            for (int i = 1; i < node.SubtreeCount; ++i) {
[13140]199              result = Expression.Divide(result, MakeExpr(node.GetSubtree(i), variableIndices, row, columns));
[12807]200            }
201            return result;
202          }
[13222]203        case OpCodes.Average: {
[13140]204            Expression result = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]205            for (int i = 1; i < node.SubtreeCount; ++i) {
[13140]206              result = Expression.Add(result, MakeExpr(node.GetSubtree(i), variableIndices, row, columns));
[12807]207            }
208            return Expression.Divide(result, Expression.Constant((double)node.SubtreeCount));
209          }
[16238]210        case OpCodes.Absolute: {
211            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
212            return Expression.Call(Abs, arg);
213          }
[13222]214        case OpCodes.Cos: {
[13140]215            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]216            return Expression.Call(Cos, arg);
217          }
[13222]218        case OpCodes.Sin: {
[13140]219            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]220            return Expression.Call(Sin, arg);
221          }
[13222]222        case OpCodes.Tan: {
[13140]223            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]224            return Expression.Call(Tan, arg);
225          }
[13222]226        case OpCodes.Square: {
[13140]227            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[13288]228            return Expression.Power(arg, Expression.Constant(2.0));
[12807]229          }
[16238]230        case OpCodes.Cube: {
231            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
232            return Expression.Power(arg, Expression.Constant(3.0));
233          }
[13222]234        case OpCodes.Power: {
[13140]235            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
236            var power = MakeExpr(node.GetSubtree(1), variableIndices, row, columns);
[13288]237            return Expression.Power(arg, Expression.Call(Round, power));
[12807]238          }
[13222]239        case OpCodes.SquareRoot: {
[13140]240            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]241            return Expression.Call(Sqrt, arg);
242          }
[16238]243        case OpCodes.CubeRoot: {
244            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
245            return Expression.Power(arg, Expression.Constant(1.0 / 3.0));
246          }
[13222]247        case OpCodes.Root: {
[13140]248            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
249            var power = MakeExpr(node.GetSubtree(1), variableIndices, row, columns);
[13288]250            return Expression.Power(arg, Expression.Divide(Expression.Constant(1.0), Expression.Call(Round, power)));
[12807]251          }
[13222]252        case OpCodes.Exp: {
[13140]253            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]254            return Expression.Call(Exp, arg);
255          }
[13222]256        case OpCodes.Log: {
[13140]257            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]258            return Expression.Call(Log, arg);
259          }
[13222]260        case OpCodes.Gamma: {
[13140]261            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]262            var isNaN = Expression.Call(IsNaN, arg);
263
264            var result = Expression.Variable(typeof(double));
265            var expr = Expression.Block(
266              new[] { result },
267              Expression.IfThenElse(
268                isNaN,
269                Expression.Assign(result, Expression.Constant(double.NaN)),
[13313]270                Expression.Assign(result, Expression.Call(Gamma, arg))
[12807]271                ),
272              result
273              );
274            return expr;
275          }
[13222]276        case OpCodes.Psi: {
[13140]277            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]278            var isNaN = Expression.Call(IsNaN, arg);
279
280            var result = Expression.Variable(typeof(double));
281            var floor = Expression.Call(Floor, arg);
282            var expr = Expression.Block(
283              new[] { result },
284              Expression.IfThenElse(
285                isNaN,
286                Expression.Assign(result, Expression.Constant(double.NaN)),
287                Expression.IfThenElse(
[13288]288                  Expression.AndAlso(
289                    Expression.LessThanOrEqual(arg, Expression.Constant(0.0)),
290                    Expression.Call(IsAlmost, Expression.Subtract(floor, arg), Expression.Constant(0.0))),
[12807]291                  Expression.Assign(result, Expression.Constant(double.NaN)),
[13313]292                  Expression.Assign(result, Expression.Call(Psi, arg)))
[12807]293                ),
294              result);
295
296            return expr;
297          }
[13222]298        case OpCodes.Dawson: {
[13140]299            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]300            var isNaN = Expression.Call(IsNaN, arg);
301            var result = Expression.Variable(typeof(double));
302            var expr = Expression.Block(
303              new[] { result },
304              Expression.IfThenElse(isNaN,
305                Expression.Assign(result, Expression.Constant(double.NaN)),
[13313]306                Expression.Assign(result, Expression.Call(DawsonIntegral, arg))),
[12807]307              result
308              );
309
310            return expr;
311          }
[13222]312        case OpCodes.ExponentialIntegralEi: {
[13140]313            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]314            var isNaN = Expression.Call(IsNaN, arg);
315            var result = Expression.Variable(typeof(double));
316            var expr = Expression.Block(
317              new[] { result },
318              Expression.IfThenElse(isNaN,
319                Expression.Assign(result, Expression.Constant(double.NaN)),
[13313]320                Expression.Assign(result, Expression.Call(ExponentialIntegralEi, arg))),
[12807]321              result
322              );
323
324            return expr;
325          }
[13222]326        case OpCodes.SineIntegral: {
[13140]327            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]328            var isNaN = Expression.Call(IsNaN, arg);
329            var si = Expression.Variable(typeof(double));
330            var ci = Expression.Variable(typeof(double));
331            var block = Expression.Block(
332              new[] { si, ci },
[13313]333              Expression.Call(SineCosineIntegrals, arg, si, ci),
[12807]334              si
335              );
336            var result = Expression.Variable(typeof(double));
337            var expr = Expression.Block(new[] { result },
338              Expression.IfThenElse(isNaN,
339                Expression.Assign(result, Expression.Constant(double.NaN)),
340                Expression.Assign(result, block)),
341              result
342              );
343
344            return expr;
345          }
[13222]346        case OpCodes.CosineIntegral: {
[13140]347            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]348            var isNaN = Expression.Call(IsNaN, arg);
349            var si = Expression.Variable(typeof(double));
350            var ci = Expression.Variable(typeof(double));
351            var block = Expression.Block(
352              new[] { si, ci },
[13313]353              Expression.Call(SineCosineIntegrals, arg, si, ci),
[12807]354              ci
355              );
356            var result = Expression.Variable(typeof(double));
357            var expr = Expression.Block(new[] { result },
358              Expression.IfThenElse(isNaN,
359                Expression.Assign(result, Expression.Constant(double.NaN)),
360                Expression.Assign(result, block)),
361              result
362              );
363
364            return expr;
365          }
[13222]366        case OpCodes.HyperbolicSineIntegral: {
[13140]367            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]368            var isNaN = Expression.Call(IsNaN, arg);
369            var shi = Expression.Variable(typeof(double));
370            var chi = Expression.Variable(typeof(double));
371            var block = Expression.Block(
372              new[] { shi, chi },
[13288]373              Expression.Call(HyperbolicSineCosineIntegrals, arg, shi, chi),
[12807]374              shi
375              );
376            var result = Expression.Variable(typeof(double));
377            var expr = Expression.Block(new[] { result },
378              Expression.IfThenElse(isNaN,
379                Expression.Assign(result, Expression.Constant(double.NaN)),
380                Expression.Assign(result, block)),
381              result
382              );
383
384            return expr;
385          }
[13222]386        case OpCodes.HyperbolicCosineIntegral: {
[13140]387            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]388            var isNaN = Expression.Call(IsNaN, arg);
389            var shi = Expression.Variable(typeof(double));
390            var chi = Expression.Variable(typeof(double));
391            var block = Expression.Block(
392              new[] { shi, chi },
[13288]393              Expression.Call(HyperbolicSineCosineIntegrals, arg, shi, chi),
[12807]394              chi
395              );
396            var result = Expression.Variable(typeof(double));
397            var expr = Expression.Block(new[] { result },
398              Expression.IfThenElse(isNaN,
399                Expression.Assign(result, Expression.Constant(double.NaN)),
400                Expression.Assign(result, block)),
401              result
402              );
403
404            return expr;
405          }
[13222]406        case OpCodes.FresnelSineIntegral: {
[13140]407            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]408            var isNaN = Expression.Call(IsNaN, arg);
409            var s = Expression.Variable(typeof(double));
410            var c = Expression.Variable(typeof(double));
[13313]411            var block = Expression.Block(new[] { s, c }, Expression.Call(FresnelIntegral, arg, c, s), s);
[12807]412            var result = Expression.Variable(typeof(double));
413            var expr = Expression.Block(new[] { result },
414              Expression.IfThenElse(isNaN,
415                Expression.Assign(result, Expression.Constant(double.NaN)),
416                Expression.Assign(result, block)),
417              result
418              );
419
420            return expr;
421          }
[13222]422        case OpCodes.FresnelCosineIntegral: {
[13140]423            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]424            var isNaN = Expression.Call(IsNaN, arg);
425            var s = Expression.Variable(typeof(double));
426            var c = Expression.Variable(typeof(double));
[13313]427            var block = Expression.Block(new[] { s, c }, Expression.Call(FresnelIntegral, arg, c, s), c);
[12807]428            var result = Expression.Variable(typeof(double));
429            var expr = Expression.Block(new[] { result },
430              Expression.IfThenElse(isNaN,
431                Expression.Assign(result, Expression.Constant(double.NaN)),
432                Expression.Assign(result, block)),
433              result
434              );
435
436            return expr;
437          }
[13222]438        case OpCodes.AiryA: {
[13140]439            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]440            var isNaN = Expression.Call(IsNaN, arg);
441            var ai = Expression.Variable(typeof(double));
442            var aip = Expression.Variable(typeof(double));
443            var bi = Expression.Variable(typeof(double));
444            var bip = Expression.Variable(typeof(double));
[13313]445            var block = Expression.Block(new[] { ai, aip, bi, bip }, Expression.Call(Airy, arg, ai, aip, bi, bip), ai);
[12807]446            var result = Expression.Variable(typeof(double));
447            var expr = Expression.Block(new[] { result },
448              Expression.IfThenElse(isNaN,
449                Expression.Assign(result, Expression.Constant(double.NaN)),
450                Expression.Assign(result, block)),
451              result
452              );
453
454            return expr;
455          }
[13222]456        case OpCodes.AiryB: {
[13140]457            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]458            var isNaN = Expression.Call(IsNaN, arg);
459            var ai = Expression.Variable(typeof(double));
460            var aip = Expression.Variable(typeof(double));
461            var bi = Expression.Variable(typeof(double));
462            var bip = Expression.Variable(typeof(double));
[13313]463            var block = Expression.Block(new[] { ai, aip, bi, bip }, Expression.Call(Airy, arg, ai, aip, bi, bip), bi);
[12807]464            var result = Expression.Variable(typeof(double));
465            var expr = Expression.Block(new[] { result },
466              Expression.IfThenElse(isNaN,
467                Expression.Assign(result, Expression.Constant(double.NaN)),
468                Expression.Assign(result, block)),
469              result
470              );
471
472            return expr;
473          }
[13222]474        case OpCodes.Norm: {
[13140]475            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]476            var result = Expression.Variable(typeof(double));
[13288]477            return Expression.Block(
478              new[] { result },
479              Expression.IfThenElse(
[13313]480                Expression.Call(IsNaN, arg),
481                Expression.Assign(result, arg),
[13288]482                Expression.Assign(result, Expression.Call(NormalDistribution, arg))),
483              result);
[12807]484          }
[13222]485        case OpCodes.Erf: {
[13140]486            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]487            var isNaN = Expression.Call(IsNaN, arg);
488            var result = Expression.Variable(typeof(double));
[13288]489            return Expression.Block(
490              new[] { result },
491              Expression.IfThenElse(
492                isNaN,
493                Expression.Assign(result, Expression.Constant(double.NaN)),
494                Expression.Assign(result, Expression.Call(ErrorFunction, arg))),
495              result);
[12807]496          }
[13222]497        case OpCodes.Bessel: {
[13140]498            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]499            var isNaN = Expression.Call(IsNaN, arg);
500            var result = Expression.Variable(typeof(double));
[13288]501            return Expression.Block(
[12807]502              new[] { result },
503              Expression.IfThenElse(
504                isNaN,
505                Expression.Assign(result, Expression.Constant(double.NaN)),
[13288]506                Expression.Assign(result, Expression.Call(Bessel, arg))),
[12807]507              result);
508          }
[16238]509        case OpCodes.AnalyticalQuotient: {
510            var x1 = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
511            var x2 = MakeExpr(node.GetSubtree(1), variableIndices, row, columns);
512            return Expression.Divide(x1,
513              Expression.Call(Sqrt,
514              Expression.Add(
515                Expression.Constant(1.0),
516                Expression.Multiply(x2, x2))));
517          }
[13222]518        case OpCodes.IfThenElse: {
[13140]519            var test = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]520            var result = Expression.Variable(typeof(double));
521            var condition = Expression.IfThenElse(Expression.GreaterThan(test, Expression.Constant(0.0)),
[13140]522              Expression.Assign(result, MakeExpr(node.GetSubtree(1), variableIndices, row, columns)),
523              Expression.Assign(result, MakeExpr(node.GetSubtree(2), variableIndices, row, columns)));
[12807]524            return Expression.Block(new[] { result }, condition, result);
525          }
[13222]526        case OpCodes.AND: {
[12807]527            var result = Expression.Variable(typeof(double));
[13140]528            var expr = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]529
530            for (int i = 1; i < node.SubtreeCount; ++i) {
531              expr = Expression.Block(new[] { result },
532                Expression.IfThenElse(
533                  Expression.GreaterThan(expr, Expression.Constant(0.0)),
[13140]534                  Expression.Assign(result, MakeExpr(node.GetSubtree(i), variableIndices, row, columns)),
[12807]535                  Expression.Assign(result, expr)),
536                result
537                );
538            }
539
540            return Expression.Block(
541              new[] { result },
542              Expression.Assign(result, expr),
543              Expression.IfThenElse(
544                Expression.GreaterThan(result, Expression.Constant(0.0)),
545                Expression.Assign(result, Expression.Constant(1.0)),
546                Expression.Assign(result, Expression.Constant(-1.0))
547                ),
548              result
549              );
550          }
[13222]551        case OpCodes.OR: {
[12807]552            var result = Expression.Variable(typeof(double));
[13140]553            var expr = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]554
555            for (int i = 1; i < node.SubtreeCount; ++i) {
556              expr = Expression.Block(new[] { result },
557                Expression.IfThenElse(
558                  Expression.LessThanOrEqual(expr, Expression.Constant(0.0)),
[13140]559                  Expression.Assign(result, MakeExpr(node.GetSubtree(i), variableIndices, row, columns)),
[12807]560                  Expression.Assign(result, expr)),
561                result
562                );
563            }
564
565            return Expression.Block(
566              new[] { result },
567              Expression.Assign(result, expr),
568              Expression.IfThenElse(
569                Expression.GreaterThan(result, Expression.Constant(0.0)),
570                Expression.Assign(result, Expression.Constant(1.0)),
571                Expression.Assign(result, Expression.Constant(-1.0))
572                ),
573              result
574              );
575          }
[13222]576        case OpCodes.NOT: {
[13140]577            var value = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
[12807]578            var result = Expression.Variable(typeof(double));
579            var condition = Expression.IfThenElse(Expression.GreaterThan(value, Expression.Constant(0.0)),
580              Expression.Assign(result, Expression.Constant(-1.0)),
581              Expression.Assign(result, Expression.Constant(1.0)));
582            return Expression.Block(new[] { result }, condition, result);
583          }
[13222]584        case OpCodes.XOR: {
[12807]585            var ps = Expression.Variable(typeof(int));
586            var block = Expression.Block(
587              new[] { ps },
588              Expression.Assign(ps, Expression.Constant(0)),
589              ps
590              );
591
592            foreach (var subtree in node.Subtrees) {
[13140]593              var expr = MakeExpr(subtree, variableIndices, row, columns);
[12807]594              block = Expression.Block(
595                new[] { ps },
596                Expression.Assign(ps, block),
597                Expression.IfThen(Expression.GreaterThan(expr, Expression.Constant(0.0)),
598                  Expression.PostIncrementAssign(ps)),
599                ps
600                );
601            }
602
603            var result = Expression.Variable(typeof(double));
604            var xorExpr = Expression.Block(
605              new[] { result },
606              Expression.IfThenElse(
607                Expression.Equal(Expression.Modulo(block, Expression.Constant(2)), Expression.Constant(0)),
608                Expression.Assign(result, Expression.Constant(-1.0)),
609                Expression.Assign(result, Expression.Constant(1.0))
610                ),
611              result
612              );
613            return xorExpr;
614          }
[13222]615        case OpCodes.GT: {
[13140]616            var left = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
617            var right = MakeExpr(node.GetSubtree(1), variableIndices, row, columns);
[12807]618            var result = Expression.Variable(typeof(double));
619
620            var condition = Expression.IfThenElse(Expression.GreaterThan(left, right),
621              Expression.Assign(result, Expression.Constant(1.0)), Expression.Assign(result, Expression.Constant(-1.0)));
622            return Expression.Block(
623              new[] { result },
624              condition,
625              result);
626          }
[13222]627        case OpCodes.LT: {
[13140]628            var left = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
629            var right = MakeExpr(node.GetSubtree(1), variableIndices, row, columns);
[12807]630            var result = Expression.Variable(typeof(double));
631
632            var condition = Expression.IfThenElse(Expression.LessThan(left, right),
633              Expression.Assign(result, Expression.Constant(1.0)), Expression.Assign(result, Expression.Constant(-1.0)));
634            return Expression.Block(new[] { result }, condition, result);
635          }
[13222]636        case OpCodes.VariableCondition: {
[12807]637            var variableConditionTreeNode = (VariableConditionTreeNode)node;
[14345]638            if (variableConditionTreeNode.Symbol.IgnoreSlope) throw new NotSupportedException("Strict variable conditionals are not supported");
[13140]639            var variableName = variableConditionTreeNode.VariableName;
640            var indexExpr = Expression.Constant(variableIndices[variableName]);
641            var valuesExpr = Expression.ArrayIndex(columns, indexExpr);
[13288]642            var variableValue = Expression.Property(valuesExpr, Indexer, row);
[12807]643            var variableThreshold = Expression.Constant(variableConditionTreeNode.Threshold);
644            var variableSlope = Expression.Constant(variableConditionTreeNode.Slope);
645
646            var x = Expression.Subtract(variableValue, variableThreshold);
647            var xSlope = Expression.Multiply(Expression.Negate(variableSlope), x);
648            var xSlopeExp = Expression.Call(Exp, xSlope);
649            var p = Expression.Divide(Expression.Constant(1), Expression.Add(Expression.Constant(1), xSlopeExp));
[13140]650            var trueBranch = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
651            var falseBranch = MakeExpr(node.GetSubtree(1), variableIndices, row, columns);
[12807]652            return Expression.Add(
653              Expression.Multiply(trueBranch, p),
654              Expression.Multiply(falseBranch, Expression.Subtract(Expression.Constant(1), p))
655              );
656          }
657        default:
658          throw new NotSupportedException("Unsupported symbol: " + node.Symbol);
659      }
[13141]660      #endregion
[12807]661    }
662  }
663}
Note: See TracBrowser for help on using the repository browser.