Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 7624 was 7615, checked in by gkronber, 13 years ago

#1081 merged r7462:7609 from trunk into time series branch

File size: 33.2 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, ISymbolicDataAnalysisExpressionTreeInterpreter {
38    private static MethodInfo listGetValue = typeof(IList<double>).GetProperty("Item", new Type[] { typeof(int) }).GetGetMethod();
39    private static MethodInfo cos = typeof(Math).GetMethod("Cos", new Type[] { typeof(double) });
40    private static MethodInfo sin = typeof(Math).GetMethod("Sin", new Type[] { typeof(double) });
41    private static MethodInfo tan = typeof(Math).GetMethod("Tan", new Type[] { typeof(double) });
42    private static MethodInfo exp = typeof(Math).GetMethod("Exp", new Type[] { typeof(double) });
43    private static MethodInfo log = typeof(Math).GetMethod("Log", new Type[] { typeof(double) });
44    private static MethodInfo power = typeof(Math).GetMethod("Pow", new Type[] { typeof(double), typeof(double) });
45    private static MethodInfo round = typeof(Math).GetMethod("Round", new Type[] { typeof(double) });
46
47    internal delegate double CompiledFunction(int sampleIndex, IList<double>[] columns, IList<double>[] cachedValues, int cacheStartIndex);
48    private const string CheckExpressionsWithIntervalArithmeticParameterName = "CheckExpressionsWithIntervalArithmetic";
49    private const string EvaluatedSolutionsParameterName = "EvaluatedSolutions";
50    #region private classes
51    private class InterpreterState {
52      private Instruction[] code;
53      private int pc;
54
55      public int ProgramCounter {
56        get { return pc; }
57        set { pc = value; }
58      }
59
60      private bool inLaggedContext;
61      public bool InLaggedContext {
62        get { return inLaggedContext; }
63        set { inLaggedContext = value; }
64      }
65      internal InterpreterState(Instruction[] code) {
66        this.inLaggedContext = false;
67        this.code = code;
68        this.pc = 0;
69      }
70
71      internal Instruction NextInstruction() {
72        return code[pc++];
73      }
74    }
75    private class OpCodes {
76      public const byte Add = 1;
77      public const byte Sub = 2;
78      public const byte Mul = 3;
79      public const byte Div = 4;
80
81      public const byte Sin = 5;
82      public const byte Cos = 6;
83      public const byte Tan = 7;
84
85      public const byte Log = 8;
86      public const byte Exp = 9;
87
88      public const byte IfThenElse = 10;
89
90      public const byte GT = 11;
91      public const byte LT = 12;
92
93      public const byte AND = 13;
94      public const byte OR = 14;
95      public const byte NOT = 15;
96
97
98      public const byte Average = 16;
99
100      public const byte Call = 17;
101
102      public const byte Variable = 18;
103      public const byte LagVariable = 19;
104      public const byte Constant = 20;
105      public const byte Arg = 21;
106
107      public const byte Power = 22;
108      public const byte Root = 23;
109      public const byte TimeLag = 24;
110      public const byte Integral = 25;
111      public const byte Derivative = 26;
112
113      public const byte VariableCondition = 27;
114    }
115    #endregion
116
117    private Dictionary<Type, byte> symbolToOpcode = new Dictionary<Type, byte>() {
118      { typeof(Addition), OpCodes.Add },
119      { typeof(Subtraction), OpCodes.Sub },
120      { typeof(Multiplication), OpCodes.Mul },
121      { typeof(Division), OpCodes.Div },
122      { typeof(Sine), OpCodes.Sin },
123      { typeof(Cosine), OpCodes.Cos },
124      { typeof(Tangent), OpCodes.Tan },
125      { typeof(Logarithm), OpCodes.Log },
126      { typeof(Exponential), OpCodes.Exp },
127      { typeof(IfThenElse), OpCodes.IfThenElse },
128      { typeof(GreaterThan), OpCodes.GT },
129      { typeof(LessThan), OpCodes.LT },
130      { typeof(And), OpCodes.AND },
131      { typeof(Or), OpCodes.OR },
132      { typeof(Not), OpCodes.NOT},
133      { typeof(Average), OpCodes.Average},
134      { typeof(InvokeFunction), OpCodes.Call },
135      { typeof(HeuristicLab.Problems.DataAnalysis.Symbolic.Variable), OpCodes.Variable },
136      { typeof(LaggedVariable), OpCodes.LagVariable },
137      { typeof(Constant), OpCodes.Constant },
138      { typeof(Argument), OpCodes.Arg },
139      { typeof(Power),OpCodes.Power},
140      { typeof(Root),OpCodes.Root},
141      { typeof(TimeLag), OpCodes.TimeLag},
142      { typeof(Integral), OpCodes.Integral},
143      { typeof(Derivative), OpCodes.Derivative},
144      { typeof(VariableCondition),OpCodes.VariableCondition}
145    };
146
147    public override bool CanChangeName {
148      get { return false; }
149    }
150    public override bool CanChangeDescription {
151      get { return false; }
152    }
153
154    #region parameter properties
155    public IValueParameter<BoolValue> CheckExpressionsWithIntervalArithmeticParameter {
156      get { return (IValueParameter<BoolValue>)Parameters[CheckExpressionsWithIntervalArithmeticParameterName]; }
157    }
158
159    public IValueParameter<IntValue> EvaluatedSolutionsParameter {
160      get { return (IValueParameter<IntValue>)Parameters[EvaluatedSolutionsParameterName]; }
161    }
162    #endregion
163
164    #region properties
165    public BoolValue CheckExpressionsWithIntervalArithmetic {
166      get { return CheckExpressionsWithIntervalArithmeticParameter.Value; }
167      set { CheckExpressionsWithIntervalArithmeticParameter.Value = value; }
168    }
169
170    public IntValue EvaluatedSolutions {
171      get { return EvaluatedSolutionsParameter.Value; }
172      set { EvaluatedSolutionsParameter.Value = value; }
173    }
174    #endregion
175
176
177    [StorableConstructor]
178    private SymbolicDataAnalysisExpressionTreeILEmittingInterpreter(bool deserializing) : base(deserializing) { }
179    private SymbolicDataAnalysisExpressionTreeILEmittingInterpreter(SymbolicDataAnalysisExpressionTreeILEmittingInterpreter original, Cloner cloner) : base(original, cloner) { }
180    public override IDeepCloneable Clone(Cloner cloner) {
181      return new SymbolicDataAnalysisExpressionTreeILEmittingInterpreter(this, cloner);
182    }
183
184    public SymbolicDataAnalysisExpressionTreeILEmittingInterpreter()
185      : base("SymbolicDataAnalysisExpressionTreeILEmittingInterpreter", "Interpreter for symbolic expression trees.") {
186      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)));
187      Parameters.Add(new ValueParameter<IntValue>(EvaluatedSolutionsParameterName, "A counter for the total number of solutions the interpreter has evaluated", new IntValue(0)));
188    }
189
190    [StorableHook(HookType.AfterDeserialization)]
191    private void AfterDeserialization() {
192      if (!Parameters.ContainsKey(EvaluatedSolutionsParameterName))
193        Parameters.Add(new ValueParameter<IntValue>(EvaluatedSolutionsParameterName, "A counter for the total number of solutions the interpreter has evaluated", new IntValue(0)));
194    }
195
196    #region IStatefulItem
197    public void InitializeState() {
198      EvaluatedSolutions.Value = 0;
199    }
200
201    public void ClearState() {
202      EvaluatedSolutions.Value = 0;
203    }
204    #endregion
205
206    public IEnumerable<double> GetSymbolicExpressionTreeValues(ISymbolicExpressionTree tree, Dataset dataset, IEnumerable<int> rows) {
207      return GetSymbolicExpressionTreeValues(tree, dataset, new string[] { "#NOTHING#" }, rows);
208    }
209    public IEnumerable<double> GetSymbolicExpressionTreeValues(ISymbolicExpressionTree tree, Dataset dataset, string[] targetVariables, IEnumerable<int> rows) {
210      return GetSymbolicExpressionTreeValues(tree, dataset, targetVariables, rows, 1);
211    }
212    // for each row for each horizon for each target variable one value
213    public IEnumerable<double> GetSymbolicExpressionTreeValues(ISymbolicExpressionTree tree, Dataset dataset, string[] targetVariables, IEnumerable<int> rows, int horizon) {
214      if (CheckExpressionsWithIntervalArithmetic.Value)
215        throw new NotSupportedException("Interval arithmetic is not yet supported in the symbolic data analysis interpreter.");
216      EvaluatedSolutions.Value++; // increment the evaluated solutions counter
217      var compiler = new SymbolicExpressionTreeCompiler();
218      Instruction[] code = compiler.Compile(tree, MapSymbolToOpCode);
219      int necessaryArgStackSize = 0;
220
221      Dictionary<string, int> doubleVariableNames = dataset.DoubleVariables.Select((x, i) => new { x, i }).ToDictionary(e => e.x, e => e.i);
222
223      for (int i = 0; i < code.Length; i++) {
224        Instruction instr = code[i];
225        if (instr.opCode == OpCodes.Variable) {
226          var variableTreeNode = instr.dynamicNode as VariableTreeNode;
227          instr.iArg0 = doubleVariableNames[variableTreeNode.VariableName];
228          code[i] = instr;
229        } else if (instr.opCode == OpCodes.LagVariable) {
230          var variableTreeNode = instr.dynamicNode as LaggedVariableTreeNode;
231          instr.iArg0 = doubleVariableNames[variableTreeNode.VariableName];
232          code[i] = instr;
233        } else if (instr.opCode == OpCodes.VariableCondition) {
234          var variableConditionTreeNode = instr.dynamicNode as VariableConditionTreeNode;
235          instr.iArg0 = doubleVariableNames[variableConditionTreeNode.VariableName];
236        } else if (instr.opCode == OpCodes.Call) {
237          necessaryArgStackSize += instr.nArguments + 1;
238        }
239      }
240      var state = new InterpreterState(code);
241      Type[] methodArgs = { typeof(int), typeof(IList<double>[]), typeof(IList<double>[]), typeof(int) };
242
243      CompiledFunction[] function = new CompiledFunction[targetVariables.Length];
244      for (int i = 0; i < function.Length; i++) {
245        DynamicMethod testFun = new DynamicMethod("TestFun", typeof(double), methodArgs, typeof(SymbolicDataAnalysisExpressionTreeILEmittingInterpreter).Module);
246        ILGenerator il = testFun.GetILGenerator();
247        CompileInstructions(il, state, dataset);
248        il.Emit(System.Reflection.Emit.OpCodes.Conv_R8);
249        il.Emit(System.Reflection.Emit.OpCodes.Ret);
250        function[i] = (CompiledFunction)testFun.CreateDelegate(typeof(CompiledFunction));
251      }
252      var values = doubleVariableNames.Keys
253        .Select(v => dataset.GetReadOnlyDoubleValues(v))
254        .ToArray();
255      var cachedValues = (from var in doubleVariableNames.Keys
256                          select new double[horizon]).ToArray();
257      foreach (var row in rows) {
258        // init first line of cache
259        int c = 0;
260        foreach (var var in doubleVariableNames.Keys)
261          cachedValues[c++][0] = dataset.GetDoubleValue(var, row);
262        for (int horizonRow = row; horizonRow < row + horizon; horizonRow++) {
263          for (int i = 0; i < function.Length; i++) {
264            var componentProg = function[i](horizonRow, values, cachedValues, row);
265            // set cachedValues for prognosis of future values
266            if (horizon > 1)
267              cachedValues[doubleVariableNames[targetVariables[i]]][horizonRow - row] = componentProg;
268            yield return componentProg;
269          }
270        }
271      }
272    }
273
274    private void CompileInstructions(ILGenerator il, InterpreterState state, Dataset ds) {
275      Instruction currentInstr = state.NextInstruction();
276      int nArgs = currentInstr.nArguments;
277
278      switch (currentInstr.opCode) {
279        case OpCodes.Add: {
280            if (nArgs > 0) {
281              CompileInstructions(il, state, ds);
282            }
283            for (int i = 1; i < nArgs; i++) {
284              CompileInstructions(il, state, ds);
285              il.Emit(System.Reflection.Emit.OpCodes.Add);
286            }
287            return;
288          }
289        case OpCodes.Sub: {
290            if (nArgs == 1) {
291              CompileInstructions(il, state, ds);
292              il.Emit(System.Reflection.Emit.OpCodes.Neg);
293              return;
294            }
295            if (nArgs > 0) {
296              CompileInstructions(il, state, ds);
297            }
298            for (int i = 1; i < nArgs; i++) {
299              CompileInstructions(il, state, ds);
300              il.Emit(System.Reflection.Emit.OpCodes.Sub);
301            }
302            return;
303          }
304        case OpCodes.Mul: {
305            if (nArgs > 0) {
306              CompileInstructions(il, state, ds);
307            }
308            for (int i = 1; i < nArgs; i++) {
309              CompileInstructions(il, state, ds);
310              il.Emit(System.Reflection.Emit.OpCodes.Mul);
311            }
312            return;
313          }
314        case OpCodes.Div: {
315            if (nArgs == 1) {
316              il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0);
317              CompileInstructions(il, state, ds);
318              il.Emit(System.Reflection.Emit.OpCodes.Div);
319              return;
320            }
321            if (nArgs > 0) {
322              CompileInstructions(il, state, ds);
323            }
324            for (int i = 1; i < nArgs; i++) {
325              CompileInstructions(il, state, ds);
326              il.Emit(System.Reflection.Emit.OpCodes.Div);
327            }
328            return;
329          }
330        case OpCodes.Average: {
331            CompileInstructions(il, state, ds);
332            for (int i = 1; i < nArgs; i++) {
333              CompileInstructions(il, state, ds);
334              il.Emit(System.Reflection.Emit.OpCodes.Add);
335            }
336            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, nArgs);
337            il.Emit(System.Reflection.Emit.OpCodes.Div);
338            return;
339          }
340        case OpCodes.Cos: {
341            CompileInstructions(il, state, ds);
342            il.Emit(System.Reflection.Emit.OpCodes.Call, cos);
343            return;
344          }
345        case OpCodes.Sin: {
346            CompileInstructions(il, state, ds);
347            il.Emit(System.Reflection.Emit.OpCodes.Call, sin);
348            return;
349          }
350        case OpCodes.Tan: {
351            CompileInstructions(il, state, ds);
352            il.Emit(System.Reflection.Emit.OpCodes.Call, tan);
353            return;
354          }
355        case OpCodes.Power: {
356            CompileInstructions(il, state, ds);
357            CompileInstructions(il, state, ds);
358            il.Emit(System.Reflection.Emit.OpCodes.Call, round);
359            il.Emit(System.Reflection.Emit.OpCodes.Call, power);
360            return;
361          }
362        case OpCodes.Root: {
363            CompileInstructions(il, state, ds);
364            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // 1 / round(...)
365            CompileInstructions(il, state, ds);
366            il.Emit(System.Reflection.Emit.OpCodes.Call, round);
367            il.Emit(System.Reflection.Emit.OpCodes.Div);
368            il.Emit(System.Reflection.Emit.OpCodes.Call, power);
369            return;
370          }
371        case OpCodes.Exp: {
372            CompileInstructions(il, state, ds);
373            il.Emit(System.Reflection.Emit.OpCodes.Call, exp);
374            return;
375          }
376        case OpCodes.Log: {
377            CompileInstructions(il, state, ds);
378            il.Emit(System.Reflection.Emit.OpCodes.Call, log);
379            return;
380          }
381        case OpCodes.IfThenElse: {
382            Label end = il.DefineLabel();
383            Label c1 = il.DefineLabel();
384            CompileInstructions(il, state, ds);
385            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // > 0
386            il.Emit(System.Reflection.Emit.OpCodes.Cgt);
387            il.Emit(System.Reflection.Emit.OpCodes.Brfalse, c1);
388            CompileInstructions(il, state, ds);
389            il.Emit(System.Reflection.Emit.OpCodes.Br, end);
390            il.MarkLabel(c1);
391            CompileInstructions(il, state, ds);
392            il.MarkLabel(end);
393            return;
394          }
395        case OpCodes.AND: {
396            Label falseBranch = il.DefineLabel();
397            Label end = il.DefineLabel();
398            CompileInstructions(il, state, ds);
399            for (int i = 1; i < nArgs; i++) {
400              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // > 0
401              il.Emit(System.Reflection.Emit.OpCodes.Cgt);
402              il.Emit(System.Reflection.Emit.OpCodes.Brfalse, falseBranch);
403              CompileInstructions(il, state, ds);
404            }
405            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // > 0
406            il.Emit(System.Reflection.Emit.OpCodes.Cgt);
407            il.Emit(System.Reflection.Emit.OpCodes.Brfalse, falseBranch);
408            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // 1
409            il.Emit(System.Reflection.Emit.OpCodes.Br, end);
410            il.MarkLabel(falseBranch);
411            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // -1
412            il.Emit(System.Reflection.Emit.OpCodes.Neg);
413            il.MarkLabel(end);
414            return;
415          }
416        case OpCodes.OR: {
417            Label trueBranch = il.DefineLabel();
418            Label end = il.DefineLabel();
419            Label resultBranch = il.DefineLabel();
420            CompileInstructions(il, state, ds);
421            for (int i = 1; i < nArgs; i++) {
422              Label nextArgBranch = il.DefineLabel();
423              // complex definition because of special properties of NaN 
424              il.Emit(System.Reflection.Emit.OpCodes.Dup);
425              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // <= 0       
426              il.Emit(System.Reflection.Emit.OpCodes.Ble, nextArgBranch);
427              il.Emit(System.Reflection.Emit.OpCodes.Br, resultBranch);
428              il.MarkLabel(nextArgBranch);
429              il.Emit(System.Reflection.Emit.OpCodes.Pop);
430              CompileInstructions(il, state, ds);
431            }
432            il.MarkLabel(resultBranch);
433            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // > 0
434            il.Emit(System.Reflection.Emit.OpCodes.Cgt);
435            il.Emit(System.Reflection.Emit.OpCodes.Brtrue, trueBranch);
436            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // -1
437            il.Emit(System.Reflection.Emit.OpCodes.Neg);
438            il.Emit(System.Reflection.Emit.OpCodes.Br, end);
439            il.MarkLabel(trueBranch);
440            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // 1
441            il.MarkLabel(end);
442            return;
443          }
444        case OpCodes.NOT: {
445            CompileInstructions(il, state, ds);
446            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // > 0
447            il.Emit(System.Reflection.Emit.OpCodes.Cgt);
448            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0); // * 2
449            il.Emit(System.Reflection.Emit.OpCodes.Mul);
450            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // - 1
451            il.Emit(System.Reflection.Emit.OpCodes.Sub);
452            il.Emit(System.Reflection.Emit.OpCodes.Neg); // * -1
453            return;
454          }
455        case OpCodes.GT: {
456            CompileInstructions(il, state, ds);
457            CompileInstructions(il, state, ds);
458
459            il.Emit(System.Reflection.Emit.OpCodes.Cgt); // 1 (>) / 0 (otherwise)
460            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0); // * 2
461            il.Emit(System.Reflection.Emit.OpCodes.Mul);
462            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // - 1
463            il.Emit(System.Reflection.Emit.OpCodes.Sub);
464            return;
465          }
466        case OpCodes.LT: {
467            CompileInstructions(il, state, ds);
468            CompileInstructions(il, state, ds);
469            il.Emit(System.Reflection.Emit.OpCodes.Clt);
470            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0); // * 2
471            il.Emit(System.Reflection.Emit.OpCodes.Mul);
472            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // - 1
473            il.Emit(System.Reflection.Emit.OpCodes.Sub);
474            return;
475          }
476        case OpCodes.TimeLag: {
477            LaggedTreeNode laggedTreeNode = (LaggedTreeNode)currentInstr.dynamicNode;
478            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row -= lag
479            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, laggedTreeNode.Lag);
480            il.Emit(System.Reflection.Emit.OpCodes.Add);
481            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
482            var prevLaggedContext = state.InLaggedContext;
483            state.InLaggedContext = true;
484            CompileInstructions(il, state, ds);
485            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row += lag
486            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, laggedTreeNode.Lag);
487            il.Emit(System.Reflection.Emit.OpCodes.Sub);
488            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
489            state.InLaggedContext = prevLaggedContext;
490            return;
491          }
492        case OpCodes.Integral: {
493            int savedPc = state.ProgramCounter;
494            LaggedTreeNode laggedTreeNode = (LaggedTreeNode)currentInstr.dynamicNode;
495            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row -= lag
496            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, laggedTreeNode.Lag);
497            il.Emit(System.Reflection.Emit.OpCodes.Add);
498            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
499            var prevLaggedContext = state.InLaggedContext;
500            state.InLaggedContext = true;
501            CompileInstructions(il, state, ds);
502            for (int l = laggedTreeNode.Lag; l < 0; l++) {
503              il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row += lag
504              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_1);
505              il.Emit(System.Reflection.Emit.OpCodes.Add);
506              il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
507              state.ProgramCounter = savedPc;
508              CompileInstructions(il, state, ds);
509              il.Emit(System.Reflection.Emit.OpCodes.Add);
510            }
511            state.InLaggedContext = prevLaggedContext;
512            return;
513          }
514
515        //mkommend: derivate calculation taken from:
516        //http://www.holoborodko.com/pavel/numerical-methods/numerical-derivative/smooth-low-noise-differentiators/
517        //one sided smooth differentiatior, N = 4
518        // y' = 1/8h (f_i + 2f_i-1, -2 f_i-3 - f_i-4)
519        case OpCodes.Derivative: {
520            int savedPc = state.ProgramCounter;
521            CompileInstructions(il, state, ds);
522            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row --
523            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_M1);
524            il.Emit(System.Reflection.Emit.OpCodes.Add);
525            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
526            state.ProgramCounter = savedPc;
527            var prevLaggedContext = state.InLaggedContext;
528            state.InLaggedContext = true;
529            CompileInstructions(il, state, ds);
530            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0); // f_0 + 2 * f_1
531            il.Emit(System.Reflection.Emit.OpCodes.Mul);
532            il.Emit(System.Reflection.Emit.OpCodes.Add);
533
534            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row -=2
535            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_2);
536            il.Emit(System.Reflection.Emit.OpCodes.Sub);
537            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
538            state.ProgramCounter = savedPc;
539            CompileInstructions(il, state, ds);
540            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0); // f_0 + 2 * f_1 - 2 * f_3
541            il.Emit(System.Reflection.Emit.OpCodes.Mul);
542            il.Emit(System.Reflection.Emit.OpCodes.Sub);
543
544            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row --
545            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_M1);
546            il.Emit(System.Reflection.Emit.OpCodes.Add);
547            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
548            state.ProgramCounter = savedPc;
549            CompileInstructions(il, state, ds);
550            il.Emit(System.Reflection.Emit.OpCodes.Sub); // f_0 + 2 * f_1 - 2 * f_3 - f_4
551            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 8.0); // / 8
552            il.Emit(System.Reflection.Emit.OpCodes.Div);
553
554            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row +=4
555            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_4);
556            il.Emit(System.Reflection.Emit.OpCodes.Add);
557            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
558            state.InLaggedContext = prevLaggedContext;
559            return;
560          }
561        case OpCodes.Call: {
562            throw new NotSupportedException("Automatically defined functions are not supported by the SymbolicDataAnalysisTreeILEmittingInterpreter. Either turn of ADFs or change the interpeter.");
563          }
564        case OpCodes.Arg: {
565            throw new NotSupportedException("Automatically defined functions are not supported by the SymbolicDataAnalysisTreeILEmittingInterpreter. Either turn of ADFs or change the interpeter.");
566          }
567        case OpCodes.Variable: {
568            VariableTreeNode varNode = (VariableTreeNode)currentInstr.dynamicNode;
569            if (!state.InLaggedContext) {
570              il.Emit(System.Reflection.Emit.OpCodes.Ldarg_1); // load columns array
571              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, (int)currentInstr.iArg0);
572              // load correct column of the current variable
573              il.Emit(System.Reflection.Emit.OpCodes.Ldelem_Ref);
574              il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // rowIndex
575              il.Emit(System.Reflection.Emit.OpCodes.Call, listGetValue);
576              il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, varNode.Weight); // load weight
577              il.Emit(System.Reflection.Emit.OpCodes.Mul);
578            } else {
579              var nanResult = il.DefineLabel();
580              var normalResult = il.DefineLabel();
581              var cachedValue = il.DefineLabel();
582              var multiplyValue = il.DefineLabel();
583              il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // rowIndex
584              il.Emit(System.Reflection.Emit.OpCodes.Dup);
585              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0);
586              il.Emit(System.Reflection.Emit.OpCodes.Blt, nanResult);
587              il.Emit(System.Reflection.Emit.OpCodes.Dup);
588              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, ds.Rows);
589              il.Emit(System.Reflection.Emit.OpCodes.Bge, nanResult);
590              il.Emit(System.Reflection.Emit.OpCodes.Ldarg_3);
591              il.Emit(System.Reflection.Emit.OpCodes.Bge, cachedValue);
592              il.Emit(System.Reflection.Emit.OpCodes.Ldarg_1); // load columns array
593              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, (int)currentInstr.iArg0);
594              il.Emit(System.Reflection.Emit.OpCodes.Ldelem_Ref);
595              il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // rowIndex
596              il.Emit(System.Reflection.Emit.OpCodes.Call, listGetValue);
597              il.Emit(System.Reflection.Emit.OpCodes.Br, multiplyValue);
598              il.MarkLabel(cachedValue);
599              il.Emit(System.Reflection.Emit.OpCodes.Ldarg_2); // load cached values array
600              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, (int)currentInstr.iArg0);
601              il.Emit(System.Reflection.Emit.OpCodes.Ldelem_Ref);
602              il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // rowIndex
603              il.Emit(System.Reflection.Emit.OpCodes.Ldarg_3); // startRow
604              il.Emit(System.Reflection.Emit.OpCodes.Sub); // startRow
605              il.Emit(System.Reflection.Emit.OpCodes.Call, listGetValue);
606              il.MarkLabel(multiplyValue);
607              il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, varNode.Weight); // load weight
608              il.Emit(System.Reflection.Emit.OpCodes.Mul);
609              il.Emit(System.Reflection.Emit.OpCodes.Br, normalResult);
610              il.MarkLabel(nanResult);
611              il.Emit(System.Reflection.Emit.OpCodes.Pop); // rowIndex
612              il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, double.NaN);
613              il.MarkLabel(normalResult);
614            }
615            return;
616          }
617        case OpCodes.LagVariable: {
618            var nanResult = il.DefineLabel();
619            var normalResult = il.DefineLabel();
620            var cachedValue = il.DefineLabel();
621            var multiplyValue = il.DefineLabel();
622            LaggedVariableTreeNode varNode = (LaggedVariableTreeNode)currentInstr.dynamicNode;
623            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, varNode.Lag); // lag
624            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // rowIndex
625            il.Emit(System.Reflection.Emit.OpCodes.Add); // actualRowIndex = rowIndex + sampleOffset
626            il.Emit(System.Reflection.Emit.OpCodes.Dup);
627            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0);
628            il.Emit(System.Reflection.Emit.OpCodes.Blt, nanResult);
629            il.Emit(System.Reflection.Emit.OpCodes.Dup);
630            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, ds.Rows);
631            il.Emit(System.Reflection.Emit.OpCodes.Bge, nanResult);
632            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_3); // startindex
633            il.Emit(System.Reflection.Emit.OpCodes.Bge, cachedValue);
634            // normal value
635            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_1); // load columns array
636            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, (int)currentInstr.iArg0); // load correct column of the current variable
637            il.Emit(System.Reflection.Emit.OpCodes.Ldelem_Ref);
638            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, varNode.Lag); // lag
639            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // rowIndex
640            il.Emit(System.Reflection.Emit.OpCodes.Add); // actualRowIndex = rowIndex + sampleOffset
641            il.Emit(System.Reflection.Emit.OpCodes.Call, listGetValue);
642            il.Emit(System.Reflection.Emit.OpCodes.Br, multiplyValue);
643            il.MarkLabel(cachedValue);
644            // cached value
645            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_2); // load cached values
646            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, (int)currentInstr.iArg0); // load correct column of the current variable
647            il.Emit(System.Reflection.Emit.OpCodes.Ldelem_Ref);
648            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, varNode.Lag); // lag
649            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // rowIndex
650            il.Emit(System.Reflection.Emit.OpCodes.Add); // actualRowIndex = rowIndex + sampleOffset
651            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_3); // startRow
652            il.Emit(System.Reflection.Emit.OpCodes.Sub); // startRow           
653            il.Emit(System.Reflection.Emit.OpCodes.Call, listGetValue);
654
655            il.MarkLabel(multiplyValue);
656            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, varNode.Weight); // load weight
657            il.Emit(System.Reflection.Emit.OpCodes.Mul);
658            il.Emit(System.Reflection.Emit.OpCodes.Br, normalResult);
659            il.MarkLabel(nanResult);
660            il.Emit(System.Reflection.Emit.OpCodes.Pop); // pop the row index
661            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, double.NaN);
662            il.MarkLabel(normalResult);
663            return;
664          }
665        case OpCodes.Constant: {
666            ConstantTreeNode constNode = (ConstantTreeNode)currentInstr.dynamicNode;
667            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, constNode.Value);
668            return;
669          }
670
671        //mkommend: this symbol uses the logistic function f(x) = 1 / (1 + e^(-alpha * x) )
672        //to determine the relative amounts of the true and false branch see http://en.wikipedia.org/wiki/Logistic_function
673        case OpCodes.VariableCondition: {
674            throw new NotSupportedException("Interpretation of symbol " + currentInstr.dynamicNode.Symbol.Name + " is not supported by the SymbolicDataAnalysisTreeILEmittingInterpreter");
675          }
676        default: throw new NotSupportedException("Interpretation of symbol " + currentInstr.dynamicNode.Symbol.Name + " is not supported by the SymbolicDataAnalysisTreeILEmittingInterpreter");
677      }
678    }
679
680    private byte MapSymbolToOpCode(ISymbolicExpressionTreeNode treeNode) {
681      if (symbolToOpcode.ContainsKey(treeNode.Symbol.GetType()))
682        return symbolToOpcode[treeNode.Symbol.GetType()];
683      else
684        throw new NotSupportedException("Symbol: " + treeNode.Symbol);
685    }
686  }
687}
Note: See TracBrowser for help on using the repository browser.