Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 16724 was 16668, checked in by gkronber, 6 years ago

#2866: added support for tanh to the remaining interpreters (native is missing)

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