Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.TimeSeries/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeILEmittingInterpreter.cs @ 7930

Last change on this file since 7930 was 7930, checked in by mkommend, 12 years ago

#1081: Refactored symbolic expression tree interpreter in preparation for autoregressive single variate prognosis.

File size: 45.8 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2012 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.Reflection;
26using System.Reflection.Emit;
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("SymbolicDataAnalysisExpressionTreeILEmittingInterpreter", "Interpreter for symbolic expression trees.")]
37  public sealed class SymbolicDataAnalysisExpressionTreeILEmittingInterpreter : ParameterizedNamedItem,
38                                                                                ISymbolicDataAnalysisExpressionTreeInterpreter {
39    private static MethodInfo listGetValue =
40      typeof(IList<double>).GetProperty("Item", new Type[] { typeof(int) }).GetGetMethod();
41
42    private static MethodInfo cos = typeof(Math).GetMethod("Cos", new Type[] { typeof(double) });
43    private static MethodInfo sin = typeof(Math).GetMethod("Sin", new Type[] { typeof(double) });
44    private static MethodInfo tan = typeof(Math).GetMethod("Tan", new Type[] { typeof(double) });
45    private static MethodInfo exp = typeof(Math).GetMethod("Exp", new Type[] { typeof(double) });
46    private static MethodInfo log = typeof(Math).GetMethod("Log", new Type[] { typeof(double) });
47    private static MethodInfo power = typeof(Math).GetMethod("Pow", new Type[] { typeof(double), typeof(double) });
48    private static MethodInfo round = typeof(Math).GetMethod("Round", new Type[] { typeof(double) });
49    private static MethodInfo sqrt = typeof(Math).GetMethod("Sqrt", new Type[] { typeof(double) });
50
51    internal delegate double CompiledFunction(int sampleIndex, IList<double>[] columns, IList<double>[] cachedValues, int cacheStartIndex);
52    private static Type thisType = typeof(SymbolicDataAnalysisExpressionTreeILEmittingInterpreter);
53    private static MethodInfo airyA = thisType.GetMethod("AiryA", new Type[] { typeof(double) });
54    private static MethodInfo airyB = thisType.GetMethod("AiryB", new Type[] { typeof(double) });
55    private static MethodInfo gamma = thisType.GetMethod("Gamma", new Type[] { typeof(double) });
56    private static MethodInfo psi = thisType.GetMethod("Psi", new Type[] { typeof(double) });
57    private static MethodInfo dawson = thisType.GetMethod("Dawson", new Type[] { typeof(double) });
58    private static MethodInfo expIntegralEi = thisType.GetMethod("ExpIntegralEi", new Type[] { typeof(double) });
59    private static MethodInfo sinIntegral = thisType.GetMethod("SinIntegral", new Type[] { typeof(double) });
60    private static MethodInfo cosIntegral = thisType.GetMethod("CosIntegral", new Type[] { typeof(double) });
61    private static MethodInfo hypSinIntegral = thisType.GetMethod("HypSinIntegral", new Type[] { typeof(double) });
62    private static MethodInfo hypCosIntegral = thisType.GetMethod("HypCosIntegral", new Type[] { typeof(double) });
63    private static MethodInfo fresnelCosIntegral = thisType.GetMethod("FresnelCosIntegral", new Type[] { typeof(double) });
64    private static MethodInfo fresnelSinIntegral = thisType.GetMethod("FresnelSinIntegral", new Type[] { typeof(double) });
65    private static MethodInfo norm = thisType.GetMethod("Norm", new Type[] { typeof(double) });
66    private static MethodInfo erf = thisType.GetMethod("Erf", new Type[] { typeof(double) });
67    private static MethodInfo bessel = thisType.GetMethod("Bessel", new Type[] { typeof(double) });
68
69
70
71    private const string CheckExpressionsWithIntervalArithmeticParameterName = "CheckExpressionsWithIntervalArithmetic";
72    private const string EvaluatedSolutionsParameterName = "EvaluatedSolutions";
73
74    #region private classes
75
76    private class InterpreterState {
77      private Instruction[] code;
78      private int pc;
79
80      public int ProgramCounter {
81        get { return pc; }
82        set { pc = value; }
83      }
84
85      private bool inLaggedContext;
86
87      public bool InLaggedContext {
88        get { return inLaggedContext; }
89        set { inLaggedContext = value; }
90      }
91
92      internal InterpreterState(Instruction[] code) {
93        this.inLaggedContext = false;
94        this.code = code;
95        this.pc = 0;
96      }
97
98      internal Instruction NextInstruction() {
99        return code[pc++];
100      }
101    }
102
103    private class OpCodes {
104      public const byte Add = 1;
105      public const byte Sub = 2;
106      public const byte Mul = 3;
107      public const byte Div = 4;
108
109      public const byte Sin = 5;
110      public const byte Cos = 6;
111      public const byte Tan = 7;
112
113      public const byte Log = 8;
114      public const byte Exp = 9;
115
116      public const byte IfThenElse = 10;
117
118      public const byte GT = 11;
119      public const byte LT = 12;
120
121      public const byte AND = 13;
122      public const byte OR = 14;
123      public const byte NOT = 15;
124
125
126      public const byte Average = 16;
127
128      public const byte Call = 17;
129
130      public const byte Variable = 18;
131      public const byte LagVariable = 19;
132      public const byte Constant = 20;
133      public const byte Arg = 21;
134
135      public const byte Power = 22;
136      public const byte Root = 23;
137      public const byte TimeLag = 24;
138      public const byte Integral = 25;
139      public const byte Derivative = 26;
140
141      public const byte VariableCondition = 27;
142
143      public const byte Square = 28;
144      public const byte SquareRoot = 29;
145      public const byte Gamma = 30;
146      public const byte Psi = 31;
147      public const byte Dawson = 32;
148      public const byte ExponentialIntegralEi = 33;
149      public const byte CosineIntegral = 34;
150      public const byte SineIntegral = 35;
151      public const byte HyperbolicCosineIntegral = 36;
152      public const byte HyperbolicSineIntegral = 37;
153      public const byte FresnelCosineIntegral = 38;
154      public const byte FresnelSineIntegral = 39;
155      public const byte AiryA = 40;
156      public const byte AiryB = 41;
157      public const byte Norm = 42;
158      public const byte Erf = 43;
159      public const byte Bessel = 44;
160    }
161
162    #endregion
163
164    private Dictionary<Type, byte> symbolToOpcode = new Dictionary<Type, byte>()
165                                                      {
166                                                        {typeof (Addition), OpCodes.Add},
167                                                        {typeof (Subtraction), OpCodes.Sub},
168                                                        {typeof (Multiplication), OpCodes.Mul},
169                                                        {typeof (Division), OpCodes.Div},
170                                                        {typeof (Sine), OpCodes.Sin},
171                                                        {typeof (Cosine), OpCodes.Cos},
172                                                        {typeof (Tangent), OpCodes.Tan},
173                                                        {typeof (Logarithm), OpCodes.Log},
174                                                        {typeof (Exponential), OpCodes.Exp},
175                                                        {typeof (IfThenElse), OpCodes.IfThenElse},
176                                                        {typeof (GreaterThan), OpCodes.GT},
177                                                        {typeof (LessThan), OpCodes.LT},
178                                                        {typeof (And), OpCodes.AND},
179                                                        {typeof (Or), OpCodes.OR},
180                                                        {typeof (Not), OpCodes.NOT},
181                                                        {typeof (Average), OpCodes.Average},
182                                                        {typeof (InvokeFunction), OpCodes.Call},
183                                                        {
184                                                          typeof (HeuristicLab.Problems.DataAnalysis.Symbolic.Variable),
185                                                          OpCodes.Variable
186                                                          },
187                                                        {typeof (LaggedVariable), OpCodes.LagVariable},
188                                                        {typeof (Constant), OpCodes.Constant},
189                                                        {typeof (Argument), OpCodes.Arg},
190                                                        {typeof (Power), OpCodes.Power},
191                                                        {typeof (Root), OpCodes.Root},
192                                                        {typeof (TimeLag), OpCodes.TimeLag},
193                                                        {typeof (Integral), OpCodes.Integral},
194                                                        {typeof (Derivative), OpCodes.Derivative},
195                                                        {typeof (VariableCondition), OpCodes.VariableCondition},
196                                                        {typeof (Square), OpCodes.Square},
197                                                        {typeof (SquareRoot), OpCodes.SquareRoot},
198                                                        {typeof (Gamma), OpCodes.Gamma},
199                                                        {typeof (Psi), OpCodes.Psi},
200                                                        {typeof (Dawson), OpCodes.Dawson},
201                                                        {typeof (ExponentialIntegralEi), OpCodes.ExponentialIntegralEi},
202                                                        {typeof (CosineIntegral), OpCodes.CosineIntegral},
203                                                        {typeof (SineIntegral), OpCodes.SineIntegral},
204                                                        {
205                                                          typeof (HyperbolicCosineIntegral),
206                                                          OpCodes.HyperbolicCosineIntegral
207                                                          },
208                                                        {
209                                                          typeof (HyperbolicSineIntegral), OpCodes.HyperbolicSineIntegral
210                                                          },
211                                                        {typeof (FresnelCosineIntegral), OpCodes.FresnelCosineIntegral},
212                                                        {typeof (FresnelSineIntegral), OpCodes.FresnelSineIntegral},
213                                                        {typeof (AiryA), OpCodes.AiryA},
214                                                        {typeof (AiryB), OpCodes.AiryB},
215                                                        {typeof (Norm), OpCodes.Norm},
216                                                        {typeof (Erf), OpCodes.Erf},
217                                                        {typeof (Bessel), OpCodes.Bessel}
218                                                      };
219
220    public override bool CanChangeName {
221      get { return false; }
222    }
223
224    public override bool CanChangeDescription {
225      get { return false; }
226    }
227
228    #region parameter properties
229
230    public IValueParameter<BoolValue> CheckExpressionsWithIntervalArithmeticParameter {
231      get { return (IValueParameter<BoolValue>)Parameters[CheckExpressionsWithIntervalArithmeticParameterName]; }
232    }
233
234    public IValueParameter<IntValue> EvaluatedSolutionsParameter {
235      get { return (IValueParameter<IntValue>)Parameters[EvaluatedSolutionsParameterName]; }
236    }
237
238    #endregion
239
240    #region properties
241
242    public BoolValue CheckExpressionsWithIntervalArithmetic {
243      get { return CheckExpressionsWithIntervalArithmeticParameter.Value; }
244      set { CheckExpressionsWithIntervalArithmeticParameter.Value = value; }
245    }
246
247    public IntValue EvaluatedSolutions {
248      get { return EvaluatedSolutionsParameter.Value; }
249      set { EvaluatedSolutionsParameter.Value = value; }
250    }
251
252    #endregion
253
254
255    [StorableConstructor]
256    private SymbolicDataAnalysisExpressionTreeILEmittingInterpreter(bool deserializing)
257      : base(deserializing) {
258    }
259
260    private SymbolicDataAnalysisExpressionTreeILEmittingInterpreter(
261      SymbolicDataAnalysisExpressionTreeILEmittingInterpreter original, Cloner cloner)
262      : base(original, cloner) {
263    }
264
265    public override IDeepCloneable Clone(Cloner cloner) {
266      return new SymbolicDataAnalysisExpressionTreeILEmittingInterpreter(this, cloner);
267    }
268
269    public SymbolicDataAnalysisExpressionTreeILEmittingInterpreter()
270      : base("SymbolicDataAnalysisExpressionTreeILEmittingInterpreter", "Interpreter for symbolic expression trees.") {
271      Parameters.Add(new ValueParameter<BoolValue>(CheckExpressionsWithIntervalArithmeticParameterName,
272                                                   "Switch that determines if the interpreter checks the validity of expressions with interval arithmetic before evaluating the expression.",
273                                                   new BoolValue(false)));
274      Parameters.Add(new ValueParameter<IntValue>(EvaluatedSolutionsParameterName,
275                                                  "A counter for the total number of solutions the interpreter has evaluated",
276                                                  new IntValue(0)));
277    }
278
279    [StorableHook(HookType.AfterDeserialization)]
280    private void AfterDeserialization() {
281      if (!Parameters.ContainsKey(EvaluatedSolutionsParameterName))
282        Parameters.Add(new ValueParameter<IntValue>(EvaluatedSolutionsParameterName,
283                                                    "A counter for the total number of solutions the interpreter has evaluated",
284                                                    new IntValue(0)));
285    }
286
287    #region IStatefulItem
288
289    public void InitializeState() {
290      EvaluatedSolutions.Value = 0;
291    }
292
293    public void ClearState() {
294      EvaluatedSolutions.Value = 0;
295    }
296
297    #endregion
298
299    public IEnumerable<double> GetSymbolicExpressionTreeValues(ISymbolicExpressionTree tree, Dataset dataset,
300                                                               IEnumerable<int> rows) {
301      return GetSymbolicExpressionTreeValues(tree, dataset, new string[] { "#NOTHING#" }, rows);
302    }
303    public IEnumerable<double> GetSymbolicExpressionTreeValues(ISymbolicExpressionTree tree, Dataset dataset, string[] targetVariables, IEnumerable<int> rows) {
304      return GetSymbolicExpressionTreeValues(tree, dataset, targetVariables, rows, 1);
305    }
306    // for each row for each horizon for each target variable one value
307    public IEnumerable<double> GetSymbolicExpressionTreeValues(ISymbolicExpressionTree tree, Dataset dataset, string[] targetVariables, IEnumerable<int> rows, int horizon) {
308      if (CheckExpressionsWithIntervalArithmetic.Value)
309        throw new NotSupportedException(
310          "Interval arithmetic is not yet supported in the symbolic data analysis interpreter.");
311      EvaluatedSolutions.Value++; // increment the evaluated solutions counter     
312      Instruction[] code = SymbolicExpressionTreeCompiler.Compile(tree, MapSymbolToOpCode);
313      int necessaryArgStackSize = 0;
314
315      Dictionary<string, int> doubleVariableNames =
316        dataset.DoubleVariables.Select((x, i) => new { x, i }).ToDictionary(e => e.x, e => e.i);
317
318      for (int i = 0; i < code.Length; i++) {
319        Instruction instr = code[i];
320        if (instr.opCode == OpCodes.Variable) {
321          var variableTreeNode = instr.dynamicNode as VariableTreeNode;
322          instr.iArg0 = doubleVariableNames[variableTreeNode.VariableName];
323          code[i] = instr;
324        } else if (instr.opCode == OpCodes.LagVariable) {
325          var variableTreeNode = instr.dynamicNode as LaggedVariableTreeNode;
326          instr.iArg0 = doubleVariableNames[variableTreeNode.VariableName];
327          code[i] = instr;
328        } else if (instr.opCode == OpCodes.VariableCondition) {
329          var variableConditionTreeNode = instr.dynamicNode as VariableConditionTreeNode;
330          instr.iArg0 = doubleVariableNames[variableConditionTreeNode.VariableName];
331        } else if (instr.opCode == OpCodes.Call) {
332          necessaryArgStackSize += instr.nArguments + 1;
333        }
334      }
335      var state = new InterpreterState(code);
336      Type[] methodArgs = { typeof(int), typeof(IList<double>[]), typeof(IList<double>[]), typeof(int) };
337
338      CompiledFunction[] function = new CompiledFunction[targetVariables.Length];
339      for (int i = 0; i < function.Length; i++) {
340        DynamicMethod testFun = new DynamicMethod("TestFun", typeof(double), methodArgs, typeof(SymbolicDataAnalysisExpressionTreeILEmittingInterpreter).Module);
341        ILGenerator il = testFun.GetILGenerator();
342        CompileInstructions(il, state, dataset);
343        il.Emit(System.Reflection.Emit.OpCodes.Conv_R8);
344        il.Emit(System.Reflection.Emit.OpCodes.Ret);
345        function[i] = (CompiledFunction)testFun.CreateDelegate(typeof(CompiledFunction));
346      }
347      var values = doubleVariableNames.Keys
348        .Select(v => dataset.GetReadOnlyDoubleValues(v))
349        .ToArray();
350      var cachedValues = (from var in doubleVariableNames.Keys
351                          select new double[horizon]).ToArray();
352      foreach (var row in rows) {
353        // init first line of cache
354        int c = 0;
355        foreach (var var in doubleVariableNames.Keys)
356          cachedValues[c++][0] = dataset.GetDoubleValue(var, row);
357        for (int horizonRow = row; horizonRow < row + horizon; horizonRow++) {
358          for (int i = 0; i < function.Length; i++) {
359            var componentProg = function[i](horizonRow, values, cachedValues, row);
360            // set cachedValues for prognosis of future values
361            if (horizon > 1)
362              cachedValues[doubleVariableNames[targetVariables[i]]][horizonRow - row] = componentProg;
363            yield return componentProg;
364          }
365        }
366      }
367    }
368
369    private void CompileInstructions(ILGenerator il, InterpreterState state, Dataset ds) {
370      Instruction currentInstr = state.NextInstruction();
371      int nArgs = currentInstr.nArguments;
372
373      switch (currentInstr.opCode) {
374        case OpCodes.Add: {
375            if (nArgs > 0) {
376              CompileInstructions(il, state, ds);
377            }
378            for (int i = 1; i < nArgs; i++) {
379              CompileInstructions(il, state, ds);
380              il.Emit(System.Reflection.Emit.OpCodes.Add);
381            }
382            return;
383          }
384        case OpCodes.Sub: {
385            if (nArgs == 1) {
386              CompileInstructions(il, state, ds);
387              il.Emit(System.Reflection.Emit.OpCodes.Neg);
388              return;
389            }
390            if (nArgs > 0) {
391              CompileInstructions(il, state, ds);
392            }
393            for (int i = 1; i < nArgs; i++) {
394              CompileInstructions(il, state, ds);
395              il.Emit(System.Reflection.Emit.OpCodes.Sub);
396            }
397            return;
398          }
399        case OpCodes.Mul: {
400            if (nArgs > 0) {
401              CompileInstructions(il, state, ds);
402            }
403            for (int i = 1; i < nArgs; i++) {
404              CompileInstructions(il, state, ds);
405              il.Emit(System.Reflection.Emit.OpCodes.Mul);
406            }
407            return;
408          }
409        case OpCodes.Div: {
410            if (nArgs == 1) {
411              il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0);
412              CompileInstructions(il, state, ds);
413              il.Emit(System.Reflection.Emit.OpCodes.Div);
414              return;
415            }
416            if (nArgs > 0) {
417              CompileInstructions(il, state, ds);
418            }
419            for (int i = 1; i < nArgs; i++) {
420              CompileInstructions(il, state, ds);
421              il.Emit(System.Reflection.Emit.OpCodes.Div);
422            }
423            return;
424          }
425        case OpCodes.Average: {
426            CompileInstructions(il, state, ds);
427            for (int i = 1; i < nArgs; i++) {
428              CompileInstructions(il, state, ds);
429              il.Emit(System.Reflection.Emit.OpCodes.Add);
430            }
431            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, nArgs);
432            il.Emit(System.Reflection.Emit.OpCodes.Div);
433            return;
434          }
435        case OpCodes.Cos: {
436            CompileInstructions(il, state, ds);
437            il.Emit(System.Reflection.Emit.OpCodes.Call, cos);
438            return;
439          }
440        case OpCodes.Sin: {
441            CompileInstructions(il, state, ds);
442            il.Emit(System.Reflection.Emit.OpCodes.Call, sin);
443            return;
444          }
445        case OpCodes.Tan: {
446            CompileInstructions(il, state, ds);
447            il.Emit(System.Reflection.Emit.OpCodes.Call, tan);
448            return;
449          }
450        case OpCodes.Power: {
451            CompileInstructions(il, state, ds);
452            CompileInstructions(il, state, ds);
453            il.Emit(System.Reflection.Emit.OpCodes.Call, round);
454            il.Emit(System.Reflection.Emit.OpCodes.Call, power);
455            return;
456          }
457        case OpCodes.Root: {
458            CompileInstructions(il, state, ds);
459            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // 1 / round(...)
460            CompileInstructions(il, state, ds);
461            il.Emit(System.Reflection.Emit.OpCodes.Call, round);
462            il.Emit(System.Reflection.Emit.OpCodes.Div);
463            il.Emit(System.Reflection.Emit.OpCodes.Call, power);
464            return;
465          }
466        case OpCodes.Exp: {
467            CompileInstructions(il, state, ds);
468            il.Emit(System.Reflection.Emit.OpCodes.Call, exp);
469            return;
470          }
471        case OpCodes.Log: {
472            CompileInstructions(il, state, ds);
473            il.Emit(System.Reflection.Emit.OpCodes.Call, log);
474            return;
475          }
476        case OpCodes.Square: {
477            CompileInstructions(il, state, ds);
478            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0);
479            il.Emit(System.Reflection.Emit.OpCodes.Call, power);
480            return;
481          }
482        case OpCodes.SquareRoot: {
483            CompileInstructions(il, state, ds);
484            il.Emit(System.Reflection.Emit.OpCodes.Call, sqrt);
485            return;
486          }
487        case OpCodes.AiryA: {
488            CompileInstructions(il, state, ds);
489            il.Emit(System.Reflection.Emit.OpCodes.Call, airyA);
490            return;
491          }
492        case OpCodes.AiryB: {
493            CompileInstructions(il, state, ds);
494            il.Emit(System.Reflection.Emit.OpCodes.Call, airyB);
495            return;
496          }
497        case OpCodes.Bessel: {
498            CompileInstructions(il, state, ds);
499            il.Emit(System.Reflection.Emit.OpCodes.Call, bessel);
500            return;
501          }
502        case OpCodes.CosineIntegral: {
503            CompileInstructions(il, state, ds);
504            il.Emit(System.Reflection.Emit.OpCodes.Call, cosIntegral);
505            return;
506          }
507        case OpCodes.Dawson: {
508            CompileInstructions(il, state, ds);
509            il.Emit(System.Reflection.Emit.OpCodes.Call, dawson);
510            return;
511          }
512        case OpCodes.Erf: {
513            CompileInstructions(il, state, ds);
514            il.Emit(System.Reflection.Emit.OpCodes.Call, erf);
515            return;
516          }
517        case OpCodes.ExponentialIntegralEi: {
518            CompileInstructions(il, state, ds);
519            il.Emit(System.Reflection.Emit.OpCodes.Call, expIntegralEi);
520            return;
521          }
522        case OpCodes.FresnelCosineIntegral: {
523            CompileInstructions(il, state, ds);
524            il.Emit(System.Reflection.Emit.OpCodes.Call, fresnelCosIntegral);
525            return;
526          }
527        case OpCodes.FresnelSineIntegral: {
528            CompileInstructions(il, state, ds);
529            il.Emit(System.Reflection.Emit.OpCodes.Call, fresnelSinIntegral);
530            return;
531          }
532        case OpCodes.Gamma: {
533            CompileInstructions(il, state, ds);
534            il.Emit(System.Reflection.Emit.OpCodes.Call, gamma);
535            return;
536          }
537        case OpCodes.HyperbolicCosineIntegral: {
538            CompileInstructions(il, state, ds);
539            il.Emit(System.Reflection.Emit.OpCodes.Call, hypCosIntegral);
540            return;
541          }
542        case OpCodes.HyperbolicSineIntegral: {
543            CompileInstructions(il, state, ds);
544            il.Emit(System.Reflection.Emit.OpCodes.Call, hypSinIntegral);
545            return;
546          }
547        case OpCodes.Norm: {
548            CompileInstructions(il, state, ds);
549            il.Emit(System.Reflection.Emit.OpCodes.Call, norm);
550            return;
551          }
552        case OpCodes.Psi: {
553            CompileInstructions(il, state, ds);
554            il.Emit(System.Reflection.Emit.OpCodes.Call, psi);
555            return;
556          }
557        case OpCodes.SineIntegral: {
558            CompileInstructions(il, state, ds);
559            il.Emit(System.Reflection.Emit.OpCodes.Call, sinIntegral);
560            return;
561          }
562        case OpCodes.IfThenElse: {
563            Label end = il.DefineLabel();
564            Label c1 = il.DefineLabel();
565            CompileInstructions(il, state, ds);
566            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // > 0
567            il.Emit(System.Reflection.Emit.OpCodes.Cgt);
568            il.Emit(System.Reflection.Emit.OpCodes.Brfalse, c1);
569            CompileInstructions(il, state, ds);
570            il.Emit(System.Reflection.Emit.OpCodes.Br, end);
571            il.MarkLabel(c1);
572            CompileInstructions(il, state, ds);
573            il.MarkLabel(end);
574            return;
575          }
576        case OpCodes.AND: {
577            Label falseBranch = il.DefineLabel();
578            Label end = il.DefineLabel();
579            CompileInstructions(il, state, ds);
580            for (int i = 1; i < nArgs; i++) {
581              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // > 0
582              il.Emit(System.Reflection.Emit.OpCodes.Cgt);
583              il.Emit(System.Reflection.Emit.OpCodes.Brfalse, falseBranch);
584              CompileInstructions(il, state, ds);
585            }
586            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // > 0
587            il.Emit(System.Reflection.Emit.OpCodes.Cgt);
588            il.Emit(System.Reflection.Emit.OpCodes.Brfalse, falseBranch);
589            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // 1
590            il.Emit(System.Reflection.Emit.OpCodes.Br, end);
591            il.MarkLabel(falseBranch);
592            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // -1
593            il.Emit(System.Reflection.Emit.OpCodes.Neg);
594            il.MarkLabel(end);
595            return;
596          }
597        case OpCodes.OR: {
598            Label trueBranch = il.DefineLabel();
599            Label end = il.DefineLabel();
600            Label resultBranch = il.DefineLabel();
601            CompileInstructions(il, state, ds);
602            for (int i = 1; i < nArgs; i++) {
603              Label nextArgBranch = il.DefineLabel();
604              // complex definition because of special properties of NaN 
605              il.Emit(System.Reflection.Emit.OpCodes.Dup);
606              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // <= 0       
607              il.Emit(System.Reflection.Emit.OpCodes.Ble, nextArgBranch);
608              il.Emit(System.Reflection.Emit.OpCodes.Br, resultBranch);
609              il.MarkLabel(nextArgBranch);
610              il.Emit(System.Reflection.Emit.OpCodes.Pop);
611              CompileInstructions(il, state, ds);
612            }
613            il.MarkLabel(resultBranch);
614            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // > 0
615            il.Emit(System.Reflection.Emit.OpCodes.Cgt);
616            il.Emit(System.Reflection.Emit.OpCodes.Brtrue, trueBranch);
617            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // -1
618            il.Emit(System.Reflection.Emit.OpCodes.Neg);
619            il.Emit(System.Reflection.Emit.OpCodes.Br, end);
620            il.MarkLabel(trueBranch);
621            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // 1
622            il.MarkLabel(end);
623            return;
624          }
625        case OpCodes.NOT: {
626            CompileInstructions(il, state, ds);
627            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // > 0
628            il.Emit(System.Reflection.Emit.OpCodes.Cgt);
629            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0); // * 2
630            il.Emit(System.Reflection.Emit.OpCodes.Mul);
631            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // - 1
632            il.Emit(System.Reflection.Emit.OpCodes.Sub);
633            il.Emit(System.Reflection.Emit.OpCodes.Neg); // * -1
634            return;
635          }
636        case OpCodes.GT: {
637            CompileInstructions(il, state, ds);
638            CompileInstructions(il, state, ds);
639
640            il.Emit(System.Reflection.Emit.OpCodes.Cgt); // 1 (>) / 0 (otherwise)
641            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0); // * 2
642            il.Emit(System.Reflection.Emit.OpCodes.Mul);
643            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // - 1
644            il.Emit(System.Reflection.Emit.OpCodes.Sub);
645            return;
646          }
647        case OpCodes.LT: {
648            CompileInstructions(il, state, ds);
649            CompileInstructions(il, state, ds);
650            il.Emit(System.Reflection.Emit.OpCodes.Clt);
651            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0); // * 2
652            il.Emit(System.Reflection.Emit.OpCodes.Mul);
653            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // - 1
654            il.Emit(System.Reflection.Emit.OpCodes.Sub);
655            return;
656          }
657        case OpCodes.TimeLag: {
658            LaggedTreeNode laggedTreeNode = (LaggedTreeNode)currentInstr.dynamicNode;
659            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row -= lag
660            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, laggedTreeNode.Lag);
661            il.Emit(System.Reflection.Emit.OpCodes.Add);
662            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
663            var prevLaggedContext = state.InLaggedContext;
664            state.InLaggedContext = true;
665            CompileInstructions(il, state, ds);
666            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row += lag
667            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, laggedTreeNode.Lag);
668            il.Emit(System.Reflection.Emit.OpCodes.Sub);
669            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
670            state.InLaggedContext = prevLaggedContext;
671            return;
672          }
673        case OpCodes.Integral: {
674            int savedPc = state.ProgramCounter;
675            LaggedTreeNode laggedTreeNode = (LaggedTreeNode)currentInstr.dynamicNode;
676            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row -= lag
677            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, laggedTreeNode.Lag);
678            il.Emit(System.Reflection.Emit.OpCodes.Add);
679            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
680            var prevLaggedContext = state.InLaggedContext;
681            state.InLaggedContext = true;
682            CompileInstructions(il, state, ds);
683            for (int l = laggedTreeNode.Lag; l < 0; l++) {
684              il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row += lag
685              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_1);
686              il.Emit(System.Reflection.Emit.OpCodes.Add);
687              il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
688              state.ProgramCounter = savedPc;
689              CompileInstructions(il, state, ds);
690              il.Emit(System.Reflection.Emit.OpCodes.Add);
691            }
692            state.InLaggedContext = prevLaggedContext;
693            return;
694          }
695
696        //mkommend: derivate calculation taken from:
697        //http://www.holoborodko.com/pavel/numerical-methods/numerical-derivative/smooth-low-noise-differentiators/
698        //one sided smooth differentiatior, N = 4
699        // y' = 1/8h (f_i + 2f_i-1, -2 f_i-3 - f_i-4)
700        case OpCodes.Derivative: {
701            int savedPc = state.ProgramCounter;
702            CompileInstructions(il, state, ds);
703            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row --
704            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_M1);
705            il.Emit(System.Reflection.Emit.OpCodes.Add);
706            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
707            state.ProgramCounter = savedPc;
708            var prevLaggedContext = state.InLaggedContext;
709            state.InLaggedContext = true;
710            CompileInstructions(il, state, ds);
711            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0); // f_0 + 2 * f_1
712            il.Emit(System.Reflection.Emit.OpCodes.Mul);
713            il.Emit(System.Reflection.Emit.OpCodes.Add);
714
715            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row -=2
716            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_2);
717            il.Emit(System.Reflection.Emit.OpCodes.Sub);
718            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
719            state.ProgramCounter = savedPc;
720            CompileInstructions(il, state, ds);
721            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0); // f_0 + 2 * f_1 - 2 * f_3
722            il.Emit(System.Reflection.Emit.OpCodes.Mul);
723            il.Emit(System.Reflection.Emit.OpCodes.Sub);
724
725            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row --
726            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_M1);
727            il.Emit(System.Reflection.Emit.OpCodes.Add);
728            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
729            state.ProgramCounter = savedPc;
730            CompileInstructions(il, state, ds);
731            il.Emit(System.Reflection.Emit.OpCodes.Sub); // f_0 + 2 * f_1 - 2 * f_3 - f_4
732            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 8.0); // / 8
733            il.Emit(System.Reflection.Emit.OpCodes.Div);
734
735            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row +=4
736            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_4);
737            il.Emit(System.Reflection.Emit.OpCodes.Add);
738            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
739            state.InLaggedContext = prevLaggedContext;
740            return;
741          }
742        case OpCodes.Call: {
743            throw new NotSupportedException(
744              "Automatically defined functions are not supported by the SymbolicDataAnalysisTreeILEmittingInterpreter. Either turn of ADFs or change the interpeter.");
745          }
746        case OpCodes.Arg: {
747            throw new NotSupportedException(
748              "Automatically defined functions are not supported by the SymbolicDataAnalysisTreeILEmittingInterpreter. Either turn of ADFs or change the interpeter.");
749          }
750        case OpCodes.Variable: {
751            VariableTreeNode varNode = (VariableTreeNode)currentInstr.dynamicNode;
752            if (!state.InLaggedContext) {
753              il.Emit(System.Reflection.Emit.OpCodes.Ldarg_1); // load columns array
754              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, (int)currentInstr.iArg0);
755              // load correct column of the current variable
756              il.Emit(System.Reflection.Emit.OpCodes.Ldelem_Ref);
757              il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // rowIndex
758              il.Emit(System.Reflection.Emit.OpCodes.Call, listGetValue);
759              il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, varNode.Weight); // load weight
760              il.Emit(System.Reflection.Emit.OpCodes.Mul);
761            } else {
762              var nanResult = il.DefineLabel();
763              var normalResult = il.DefineLabel();
764              var cachedValue = il.DefineLabel();
765              var multiplyValue = il.DefineLabel();
766              il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // rowIndex
767              il.Emit(System.Reflection.Emit.OpCodes.Dup);
768              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0);
769              il.Emit(System.Reflection.Emit.OpCodes.Blt, nanResult);
770              il.Emit(System.Reflection.Emit.OpCodes.Dup);
771              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, ds.Rows);
772              il.Emit(System.Reflection.Emit.OpCodes.Bge, nanResult);
773              il.Emit(System.Reflection.Emit.OpCodes.Ldarg_3);
774              il.Emit(System.Reflection.Emit.OpCodes.Bge, cachedValue);
775              il.Emit(System.Reflection.Emit.OpCodes.Ldarg_1); // load columns array
776              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, (int)currentInstr.iArg0);
777              il.Emit(System.Reflection.Emit.OpCodes.Ldelem_Ref);
778              il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // rowIndex
779              il.Emit(System.Reflection.Emit.OpCodes.Call, listGetValue);
780              il.Emit(System.Reflection.Emit.OpCodes.Br, multiplyValue);
781              il.MarkLabel(cachedValue);
782              il.Emit(System.Reflection.Emit.OpCodes.Ldarg_2); // load cached values array
783              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, (int)currentInstr.iArg0);
784              il.Emit(System.Reflection.Emit.OpCodes.Ldelem_Ref);
785              il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // rowIndex
786              il.Emit(System.Reflection.Emit.OpCodes.Ldarg_3); // startRow
787              il.Emit(System.Reflection.Emit.OpCodes.Sub); // startRow
788              il.Emit(System.Reflection.Emit.OpCodes.Call, listGetValue);
789              il.MarkLabel(multiplyValue);
790              il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, varNode.Weight); // load weight
791              il.Emit(System.Reflection.Emit.OpCodes.Mul);
792              il.Emit(System.Reflection.Emit.OpCodes.Br, normalResult);
793              il.MarkLabel(nanResult);
794              il.Emit(System.Reflection.Emit.OpCodes.Pop); // rowIndex
795              il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, double.NaN);
796              il.MarkLabel(normalResult);
797            }
798            return;
799          }
800        case OpCodes.LagVariable: {
801            var nanResult = il.DefineLabel();
802            var normalResult = il.DefineLabel();
803            var cachedValue = il.DefineLabel();
804            var multiplyValue = il.DefineLabel();
805            LaggedVariableTreeNode varNode = (LaggedVariableTreeNode)currentInstr.dynamicNode;
806            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, varNode.Lag); // lag
807            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // rowIndex
808            il.Emit(System.Reflection.Emit.OpCodes.Add); // actualRowIndex = rowIndex + sampleOffset
809            il.Emit(System.Reflection.Emit.OpCodes.Dup);
810            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0);
811            il.Emit(System.Reflection.Emit.OpCodes.Blt, nanResult);
812            il.Emit(System.Reflection.Emit.OpCodes.Dup);
813            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, ds.Rows);
814            il.Emit(System.Reflection.Emit.OpCodes.Bge, nanResult);
815            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_3); // startindex
816            il.Emit(System.Reflection.Emit.OpCodes.Bge, cachedValue);
817            // normal value
818            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_1); // load columns array
819            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, (int)currentInstr.iArg0); // load correct column of the current variable
820            il.Emit(System.Reflection.Emit.OpCodes.Ldelem_Ref);
821            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, varNode.Lag); // lag
822            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // rowIndex
823            il.Emit(System.Reflection.Emit.OpCodes.Add); // actualRowIndex = rowIndex + sampleOffset
824            il.Emit(System.Reflection.Emit.OpCodes.Call, listGetValue);
825            il.Emit(System.Reflection.Emit.OpCodes.Br, multiplyValue);
826            il.MarkLabel(cachedValue);
827            // cached value
828            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_2); // load cached values
829            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, (int)currentInstr.iArg0); // load correct column of the current variable
830            il.Emit(System.Reflection.Emit.OpCodes.Ldelem_Ref);
831            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, varNode.Lag); // lag
832            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // rowIndex
833            il.Emit(System.Reflection.Emit.OpCodes.Add); // actualRowIndex = rowIndex + sampleOffset
834            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_3); // startRow
835            il.Emit(System.Reflection.Emit.OpCodes.Sub); // startRow           
836            il.Emit(System.Reflection.Emit.OpCodes.Call, listGetValue);
837
838            il.MarkLabel(multiplyValue);
839            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, varNode.Weight); // load weight
840            il.Emit(System.Reflection.Emit.OpCodes.Mul);
841            il.Emit(System.Reflection.Emit.OpCodes.Br, normalResult);
842            il.MarkLabel(nanResult);
843            il.Emit(System.Reflection.Emit.OpCodes.Pop); // pop the row index
844            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, double.NaN);
845            il.MarkLabel(normalResult);
846            return;
847          }
848        case OpCodes.Constant: {
849            ConstantTreeNode constNode = (ConstantTreeNode)currentInstr.dynamicNode;
850            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, constNode.Value);
851            return;
852          }
853
854        //mkommend: this symbol uses the logistic function f(x) = 1 / (1 + e^(-alpha * x) )
855        //to determine the relative amounts of the true and false branch see http://en.wikipedia.org/wiki/Logistic_function
856        case OpCodes.VariableCondition: {
857            throw new NotSupportedException("Interpretation of symbol " + currentInstr.dynamicNode.Symbol.Name +
858                                            " is not supported by the SymbolicDataAnalysisTreeILEmittingInterpreter");
859          }
860        default:
861          throw new NotSupportedException("Interpretation of symbol " + currentInstr.dynamicNode.Symbol.Name +
862                                          " is not supported by the SymbolicDataAnalysisTreeILEmittingInterpreter");
863      }
864    }
865
866    private byte MapSymbolToOpCode(ISymbolicExpressionTreeNode treeNode) {
867      if (symbolToOpcode.ContainsKey(treeNode.Symbol.GetType()))
868        return symbolToOpcode[treeNode.Symbol.GetType()];
869      else
870        throw new NotSupportedException("Symbol: " + treeNode.Symbol);
871    }
872
873    public static double AiryA(double x) {
874      if (double.IsNaN(x)) return double.NaN;
875      double ai, aip, bi, bip;
876      alglib.airy(x, out ai, out aip, out bi, out bip);
877      return ai;
878    }
879
880    public static double AiryB(double x) {
881      if (double.IsNaN(x)) return double.NaN;
882      double ai, aip, bi, bip;
883      alglib.airy(x, out ai, out aip, out bi, out bip);
884      return bi;
885    }
886    public static double Dawson(double x) {
887      if (double.IsNaN(x)) return double.NaN;
888      return alglib.dawsonintegral(x);
889    }
890
891    public static double Gamma(double x) {
892      if (double.IsNaN(x)) return double.NaN;
893      return alglib.gammafunction(x);
894    }
895
896    public static double Psi(double x) {
897      if (double.IsNaN(x)) return double.NaN;
898      else if (x.IsAlmost(0.0)) return double.NaN;
899      else if ((Math.Floor(x) - x).IsAlmost(0.0)) return double.NaN;
900      return alglib.psi(x);
901    }
902
903    public static double ExpIntegralEi(double x) {
904      if (double.IsNaN(x)) return double.NaN;
905      return alglib.exponentialintegralei(x);
906    }
907
908    public static double SinIntegral(double x) {
909      if (double.IsNaN(x)) return double.NaN;
910      double si, ci;
911      alglib.sinecosineintegrals(x, out si, out ci);
912      return si;
913    }
914
915    public static double CosIntegral(double x) {
916      if (double.IsNaN(x)) return double.NaN;
917      double si, ci;
918      alglib.sinecosineintegrals(x, out si, out ci);
919      return ci;
920    }
921
922    public static double HypSinIntegral(double x) {
923      if (double.IsNaN(x)) return double.NaN;
924      double shi, chi;
925      alglib.hyperbolicsinecosineintegrals(x, out shi, out chi);
926      return chi;
927    }
928
929    public static double HypCosIntegral(double x) {
930      if (double.IsNaN(x)) return double.NaN;
931      double shi, chi;
932      alglib.hyperbolicsinecosineintegrals(x, out shi, out chi);
933      return chi;
934    }
935
936    public static double FresnelCosIntegral(double x) {
937      if (double.IsNaN(x)) return double.NaN;
938      double c = 0, s = 0;
939      alglib.fresnelintegral(x, ref c, ref s);
940      return c;
941    }
942
943    public static double FresnelSinIntegral(double x) {
944      if (double.IsNaN(x)) return double.NaN;
945      double c = 0, s = 0;
946      alglib.fresnelintegral(x, ref c, ref s);
947      return s;
948    }
949
950    public static double Norm(double x) {
951      if (double.IsNaN(x)) return double.NaN;
952      return alglib.normaldistribution(x);
953    }
954
955    public static double Erf(double x) {
956      if (double.IsNaN(x)) return double.NaN;
957      return alglib.errorfunction(x);
958    }
959
960    public static double Bessel(double x) {
961      if (double.IsNaN(x)) return double.NaN;
962      return alglib.besseli0(x);
963    }
964
965  }
966}
Note: See TracBrowser for help on using the repository browser.