Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 17607 was 17351, checked in by chaider, 5 years ago

#3032 Added type information for MethodInfo in SymbolicDataAnalysisExpressionCompiledTreeInterpreter class for the IsAlmost method to fix ambiguous reflection

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