source: branches/HeuristicLab.LinqExpressionTreeInterpreter/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionCompiledTreeInterpreter.cs @ 13139

Last change on this file since 13139 was 13139, checked in by bburlacu, 6 years ago

#2442: Commit code version using an IDataset as a parameter for the returned lambda

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