Free cookie consent management tool by TermsFeed Policy Generator

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

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

#1081 worked on multi-variate time series prognosis

File size: 29.7 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2011 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.ObjectModel;
24using System.Linq;
25using System.Collections.Generic;
26using System.Reflection;
27using System.Reflection.Emit;
28using HeuristicLab.Common;
29using HeuristicLab.Core;
30using HeuristicLab.Data;
31using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
32using HeuristicLab.Parameters;
33using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
34
35namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
36  [StorableClass]
37  [Item("SymbolicDataAnalysisExpressionTreeILEmittingInterpreter", "Interpreter for symbolic expression trees.")]
38  public sealed class SymbolicDataAnalysisExpressionTreeILEmittingInterpreter : ParameterizedNamedItem, ISymbolicDataAnalysisExpressionTreeInterpreter {
39    private static MethodInfo listGetValue = typeof(IList<double>).GetProperty("Item", new Type[] { typeof(int) }).GetGetMethod();
40    private static MethodInfo cos = typeof(Math).GetMethod("Cos", new Type[] { typeof(double) });
41    private static MethodInfo sin = typeof(Math).GetMethod("Sin", new Type[] { typeof(double) });
42    private static MethodInfo tan = typeof(Math).GetMethod("Tan", new Type[] { typeof(double) });
43    private static MethodInfo exp = typeof(Math).GetMethod("Exp", new Type[] { typeof(double) });
44    private static MethodInfo log = typeof(Math).GetMethod("Log", new Type[] { typeof(double) });
45    private static MethodInfo power = typeof(Math).GetMethod("Pow", new Type[] { typeof(double), typeof(double) });
46    private static MethodInfo round = typeof(Math).GetMethod("Round", new Type[] { typeof(double) });
47
48    internal delegate double CompiledFunction(int sampleIndex, IList<double>[] columns);
49    private const string CheckExpressionsWithIntervalArithmeticParameterName = "CheckExpressionsWithIntervalArithmetic";
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    #endregion
159
160    #region properties
161    public BoolValue CheckExpressionsWithIntervalArithmetic {
162      get { return CheckExpressionsWithIntervalArithmeticParameter.Value; }
163      set { CheckExpressionsWithIntervalArithmeticParameter.Value = value; }
164    }
165    #endregion
166
167
168    [StorableConstructor]
169    private SymbolicDataAnalysisExpressionTreeILEmittingInterpreter(bool deserializing) : base(deserializing) { }
170    private SymbolicDataAnalysisExpressionTreeILEmittingInterpreter(SymbolicDataAnalysisExpressionTreeILEmittingInterpreter original, Cloner cloner) : base(original, cloner) { }
171    public override IDeepCloneable Clone(Cloner cloner) {
172      return new SymbolicDataAnalysisExpressionTreeILEmittingInterpreter(this, cloner);
173    }
174
175    public SymbolicDataAnalysisExpressionTreeILEmittingInterpreter()
176      : base("SymbolicDataAnalysisExpressionTreeILEmittingInterpreter", "Interpreter for symbolic expression trees.") {
177      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)));
178    }
179
180    public IEnumerable<double> GetSymbolicExpressionTreeValues(ISymbolicExpressionTree tree, Dataset dataset, IEnumerable<int> rows) {
181      return from prog in GetSymbolicExpressionTreeValues(tree, dataset, new string[] { "#NOTHING#" }, rows, 1)
182             select prog.First().First();
183    }
184
185    // for each row for each target variable one prognosis (=enumerable of future values)
186    public IEnumerable<IEnumerable<IEnumerable<double>>> GetSymbolicExpressionTreeValues(ISymbolicExpressionTree tree, Dataset dataset, string[] targetVariables, IEnumerable<int> rows, int horizon) {
187      if (CheckExpressionsWithIntervalArithmetic.Value)
188        throw new NotSupportedException("Interval arithmetic is not yet supported in the symbolic data analysis interpreter.");
189      var compiler = new SymbolicExpressionTreeCompiler();
190      Instruction[] code = compiler.Compile(tree, MapSymbolToOpCode);
191      int necessaryArgStackSize = 0;
192
193      Dictionary<string, int> doubleVariableNames = dataset.DoubleVariables.Select((x, i) => new { x, i }).ToDictionary(e => e.x, e => e.i);
194
195      for (int i = 0; i < code.Length; i++) {
196        Instruction instr = code[i];
197        if (instr.opCode == OpCodes.Variable) {
198          var variableTreeNode = instr.dynamicNode as VariableTreeNode;
199          instr.iArg0 = doubleVariableNames[variableTreeNode.VariableName];
200          code[i] = instr;
201        } else if (instr.opCode == OpCodes.LagVariable) {
202          var variableTreeNode = instr.dynamicNode as LaggedVariableTreeNode;
203          instr.iArg0 = doubleVariableNames[variableTreeNode.VariableName];
204          code[i] = instr;
205        } else if (instr.opCode == OpCodes.VariableCondition) {
206          var variableConditionTreeNode = instr.dynamicNode as VariableConditionTreeNode;
207          instr.iArg0 = doubleVariableNames[variableConditionTreeNode.VariableName];
208        } else if (instr.opCode == OpCodes.Call) {
209          necessaryArgStackSize += instr.nArguments + 1;
210        }
211      }
212      var state = new InterpreterState(code);
213      Type[] methodArgs = { typeof(int), typeof(IList<double>[]) };
214
215      CompiledFunction[] function = new CompiledFunction[targetVariables.Length];
216      for (int i = 0; i < function.Length; i++) {
217        DynamicMethod testFun = new DynamicMethod("TestFun", typeof(double), methodArgs, typeof(SymbolicDataAnalysisExpressionTreeILEmittingInterpreter).Module);
218        ILGenerator il = testFun.GetILGenerator();
219        CompileInstructions(il, state, dataset);
220        il.Emit(System.Reflection.Emit.OpCodes.Conv_R8);
221        il.Emit(System.Reflection.Emit.OpCodes.Ret);
222        function[i] = (CompiledFunction)testFun.CreateDelegate(typeof(CompiledFunction));
223      }
224      int nComponents = tree.Root.GetSubtree(0).SubtreeCount;
225      // produce a n-step forecast for each target variable for all rows
226      var values = doubleVariableNames.Keys
227        .Select(v => targetVariables.Contains(v) ?
228          (IList<double>)dataset.GetDoubleValues(v).ToList() :
229          dataset.GetReadOnlyDoubleValues(v))
230        .Concat(new List<double>[] { Enumerable.Repeat(0.0, dataset.Rows).ToList() }) // append list for calculated target variable
231        .ToArray();
232      doubleVariableNames.Add("#NOTHING#", values.Count() - 1);
233      foreach (var rowEnum in rows) {
234        int row = rowEnum;
235        foreach (var horizonRow in Enumerable.Range(row, horizon)) {
236          for (int i = 0; i < nComponents; i++) {
237            var componentProg = function[i](horizonRow, values);
238            // set cachedValues for prognosis of future values
239            values[doubleVariableNames[targetVariables[i]]][horizonRow] = componentProg;
240          }
241        }
242
243        yield return from component in Enumerable.Range(0, nComponents)
244                     select from horizonRow in Enumerable.Range(row, horizon)
245                            select values[doubleVariableNames[targetVariables[component]]][horizonRow];
246        // reset start value
247        foreach (var v in targetVariables) {
248          if (v != "#NOTHING#")
249            values[doubleVariableNames[v]][row] = dataset.GetDoubleValue(v, row);
250        }
251      }
252    }
253
254    private void CompileInstructions(ILGenerator il, InterpreterState state, Dataset ds) {
255      Instruction currentInstr = state.NextInstruction();
256      int nArgs = currentInstr.nArguments;
257
258      switch (currentInstr.opCode) {
259        case OpCodes.Add: {
260            if (nArgs > 0) {
261              CompileInstructions(il, state, ds);
262            }
263            for (int i = 1; i < nArgs; i++) {
264              CompileInstructions(il, state, ds);
265              il.Emit(System.Reflection.Emit.OpCodes.Add);
266            }
267            return;
268          }
269        case OpCodes.Sub: {
270            if (nArgs == 1) {
271              CompileInstructions(il, state, ds);
272              il.Emit(System.Reflection.Emit.OpCodes.Neg);
273              return;
274            }
275            if (nArgs > 0) {
276              CompileInstructions(il, state, ds);
277            }
278            for (int i = 1; i < nArgs; i++) {
279              CompileInstructions(il, state, ds);
280              il.Emit(System.Reflection.Emit.OpCodes.Sub);
281            }
282            return;
283          }
284        case OpCodes.Mul: {
285            if (nArgs > 0) {
286              CompileInstructions(il, state, ds);
287            }
288            for (int i = 1; i < nArgs; i++) {
289              CompileInstructions(il, state, ds);
290              il.Emit(System.Reflection.Emit.OpCodes.Mul);
291            }
292            return;
293          }
294        case OpCodes.Div: {
295            if (nArgs == 1) {
296              il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0);
297              CompileInstructions(il, state, ds);
298              il.Emit(System.Reflection.Emit.OpCodes.Div);
299              return;
300            }
301            if (nArgs > 0) {
302              CompileInstructions(il, state, ds);
303            }
304            for (int i = 1; i < nArgs; i++) {
305              CompileInstructions(il, state, ds);
306              il.Emit(System.Reflection.Emit.OpCodes.Div);
307            }
308            return;
309          }
310        case OpCodes.Average: {
311            CompileInstructions(il, state, ds);
312            for (int i = 1; i < nArgs; i++) {
313              CompileInstructions(il, state, ds);
314              il.Emit(System.Reflection.Emit.OpCodes.Add);
315            }
316            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, nArgs);
317            il.Emit(System.Reflection.Emit.OpCodes.Div);
318            return;
319          }
320        case OpCodes.Cos: {
321            CompileInstructions(il, state, ds);
322            il.Emit(System.Reflection.Emit.OpCodes.Call, cos);
323            return;
324          }
325        case OpCodes.Sin: {
326            CompileInstructions(il, state, ds);
327            il.Emit(System.Reflection.Emit.OpCodes.Call, sin);
328            return;
329          }
330        case OpCodes.Tan: {
331            CompileInstructions(il, state, ds);
332            il.Emit(System.Reflection.Emit.OpCodes.Call, tan);
333            return;
334          }
335        case OpCodes.Power: {
336            CompileInstructions(il, state, ds);
337            CompileInstructions(il, state, ds);
338            il.Emit(System.Reflection.Emit.OpCodes.Call, round);
339            il.Emit(System.Reflection.Emit.OpCodes.Call, power);
340            return;
341          }
342        case OpCodes.Root: {
343            CompileInstructions(il, state, ds);
344            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // 1 / round(...)
345            CompileInstructions(il, state, ds);
346            il.Emit(System.Reflection.Emit.OpCodes.Call, round);
347            il.Emit(System.Reflection.Emit.OpCodes.Div);
348            il.Emit(System.Reflection.Emit.OpCodes.Call, power);
349            return;
350          }
351        case OpCodes.Exp: {
352            CompileInstructions(il, state, ds);
353            il.Emit(System.Reflection.Emit.OpCodes.Call, exp);
354            return;
355          }
356        case OpCodes.Log: {
357            CompileInstructions(il, state, ds);
358            il.Emit(System.Reflection.Emit.OpCodes.Call, log);
359            return;
360          }
361        case OpCodes.IfThenElse: {
362            Label end = il.DefineLabel();
363            Label c1 = il.DefineLabel();
364            CompileInstructions(il, state, ds);
365            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // > 0
366            il.Emit(System.Reflection.Emit.OpCodes.Cgt);
367            il.Emit(System.Reflection.Emit.OpCodes.Brfalse, c1);
368            CompileInstructions(il, state, ds);
369            il.Emit(System.Reflection.Emit.OpCodes.Br, end);
370            il.MarkLabel(c1);
371            CompileInstructions(il, state, ds);
372            il.MarkLabel(end);
373            return;
374          }
375        case OpCodes.AND: {
376            Label falseBranch = il.DefineLabel();
377            Label end = il.DefineLabel();
378            CompileInstructions(il, state, ds);
379            for (int i = 1; i < nArgs; i++) {
380              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // > 0
381              il.Emit(System.Reflection.Emit.OpCodes.Cgt);
382              il.Emit(System.Reflection.Emit.OpCodes.Brfalse, falseBranch);
383              CompileInstructions(il, state, ds);
384            }
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, falseBranch);
388            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // 1
389            il.Emit(System.Reflection.Emit.OpCodes.Br, end);
390            il.MarkLabel(falseBranch);
391            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // -1
392            il.Emit(System.Reflection.Emit.OpCodes.Neg);
393            il.MarkLabel(end);
394            return;
395          }
396        case OpCodes.OR: {
397            Label trueBranch = il.DefineLabel();
398            Label end = il.DefineLabel();
399            Label resultBranch = il.DefineLabel();
400            CompileInstructions(il, state, ds);
401            for (int i = 1; i < nArgs; i++) {
402              Label nextArgBranch = il.DefineLabel();
403              // complex definition because of special properties of NaN 
404              il.Emit(System.Reflection.Emit.OpCodes.Dup);
405              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // <= 0       
406              il.Emit(System.Reflection.Emit.OpCodes.Ble, nextArgBranch);
407              il.Emit(System.Reflection.Emit.OpCodes.Br, resultBranch);
408              il.MarkLabel(nextArgBranch);
409              il.Emit(System.Reflection.Emit.OpCodes.Pop);
410              CompileInstructions(il, state, ds);
411            }
412            il.MarkLabel(resultBranch);
413            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // > 0
414            il.Emit(System.Reflection.Emit.OpCodes.Cgt);
415            il.Emit(System.Reflection.Emit.OpCodes.Brtrue, trueBranch);
416            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // -1
417            il.Emit(System.Reflection.Emit.OpCodes.Neg);
418            il.Emit(System.Reflection.Emit.OpCodes.Br, end);
419            il.MarkLabel(trueBranch);
420            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // 1
421            il.MarkLabel(end);
422            return;
423          }
424        case OpCodes.NOT: {
425            CompileInstructions(il, state, ds);
426            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // > 0
427            il.Emit(System.Reflection.Emit.OpCodes.Cgt);
428            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0); // * 2
429            il.Emit(System.Reflection.Emit.OpCodes.Mul);
430            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // - 1
431            il.Emit(System.Reflection.Emit.OpCodes.Sub);
432            il.Emit(System.Reflection.Emit.OpCodes.Neg); // * -1
433            return;
434          }
435        case OpCodes.GT: {
436            CompileInstructions(il, state, ds);
437            CompileInstructions(il, state, ds);
438
439            il.Emit(System.Reflection.Emit.OpCodes.Cgt); // 1 (>) / 0 (otherwise)
440            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0); // * 2
441            il.Emit(System.Reflection.Emit.OpCodes.Mul);
442            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // - 1
443            il.Emit(System.Reflection.Emit.OpCodes.Sub);
444            return;
445          }
446        case OpCodes.LT: {
447            CompileInstructions(il, state, ds);
448            CompileInstructions(il, state, ds);
449            il.Emit(System.Reflection.Emit.OpCodes.Clt);
450            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0); // * 2
451            il.Emit(System.Reflection.Emit.OpCodes.Mul);
452            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // - 1
453            il.Emit(System.Reflection.Emit.OpCodes.Sub);
454            return;
455          }
456        case OpCodes.TimeLag: {
457            LaggedTreeNode laggedTreeNode = (LaggedTreeNode)currentInstr.dynamicNode;
458            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row -= lag
459            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, laggedTreeNode.Lag);
460            il.Emit(System.Reflection.Emit.OpCodes.Add);
461            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
462            var prevLaggedContext = state.InLaggedContext;
463            state.InLaggedContext = true;
464            CompileInstructions(il, state, ds);
465            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row += lag
466            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, laggedTreeNode.Lag);
467            il.Emit(System.Reflection.Emit.OpCodes.Sub);
468            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
469            state.InLaggedContext = prevLaggedContext;
470            return;
471          }
472        case OpCodes.Integral: {
473            int savedPc = state.ProgramCounter;
474            LaggedTreeNode laggedTreeNode = (LaggedTreeNode)currentInstr.dynamicNode;
475            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row -= lag
476            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, laggedTreeNode.Lag);
477            il.Emit(System.Reflection.Emit.OpCodes.Add);
478            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
479            var prevLaggedContext = state.InLaggedContext;
480            state.InLaggedContext = true;
481            CompileInstructions(il, state, ds);
482            for (int l = laggedTreeNode.Lag; l < 0; l++) {
483              il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row += lag
484              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_1);
485              il.Emit(System.Reflection.Emit.OpCodes.Add);
486              il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
487              state.ProgramCounter = savedPc;
488              CompileInstructions(il, state, ds);
489              il.Emit(System.Reflection.Emit.OpCodes.Add);
490            }
491            state.InLaggedContext = prevLaggedContext;
492            return;
493          }
494
495        //mkommend: derivate calculation taken from:
496        //http://www.holoborodko.com/pavel/numerical-methods/numerical-derivative/smooth-low-noise-differentiators/
497        //one sided smooth differentiatior, N = 4
498        // y' = 1/8h (f_i + 2f_i-1, -2 f_i-3 - f_i-4)
499        case OpCodes.Derivative: {
500            int savedPc = state.ProgramCounter;
501            CompileInstructions(il, state, ds);
502            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row --
503            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_M1);
504            il.Emit(System.Reflection.Emit.OpCodes.Add);
505            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
506            state.ProgramCounter = savedPc;
507            var prevLaggedContext = state.InLaggedContext;
508            state.InLaggedContext = true;
509            CompileInstructions(il, state, ds);
510            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0); // f_0 + 2 * f_1
511            il.Emit(System.Reflection.Emit.OpCodes.Mul);
512            il.Emit(System.Reflection.Emit.OpCodes.Add);
513
514            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row -=2
515            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_2);
516            il.Emit(System.Reflection.Emit.OpCodes.Sub);
517            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
518            state.ProgramCounter = savedPc;
519            CompileInstructions(il, state, ds);
520            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0); // f_0 + 2 * f_1 - 2 * f_3
521            il.Emit(System.Reflection.Emit.OpCodes.Mul);
522            il.Emit(System.Reflection.Emit.OpCodes.Sub);
523
524            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row --
525            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_M1);
526            il.Emit(System.Reflection.Emit.OpCodes.Add);
527            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
528            state.ProgramCounter = savedPc;
529            CompileInstructions(il, state, ds);
530            il.Emit(System.Reflection.Emit.OpCodes.Sub); // f_0 + 2 * f_1 - 2 * f_3 - f_4
531            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 8.0); // / 8
532            il.Emit(System.Reflection.Emit.OpCodes.Div);
533
534            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row +=4
535            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_4);
536            il.Emit(System.Reflection.Emit.OpCodes.Add);
537            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
538            state.InLaggedContext = prevLaggedContext;
539            return;
540          }
541        case OpCodes.Call: {
542            throw new NotSupportedException("Automatically defined functions are not supported by the SymbolicDataAnalysisTreeILEmittingInterpreter. Either turn of ADFs or change the interpeter.");
543          }
544        case OpCodes.Arg: {
545            throw new NotSupportedException("Automatically defined functions are not supported by the SymbolicDataAnalysisTreeILEmittingInterpreter. Either turn of ADFs or change the interpeter.");
546          }
547        case OpCodes.Variable: {
548            VariableTreeNode varNode = (VariableTreeNode)currentInstr.dynamicNode;
549            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_1); // load columns array
550            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, (int)currentInstr.iArg0);
551            // load correct column of the current variable
552            il.Emit(System.Reflection.Emit.OpCodes.Ldelem_Ref);
553            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // rowIndex
554            if (!state.InLaggedContext) {
555              il.Emit(System.Reflection.Emit.OpCodes.Call, listGetValue);
556              il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, varNode.Weight); // load weight
557              il.Emit(System.Reflection.Emit.OpCodes.Mul);
558            } else {
559              var nanResult = il.DefineLabel();
560              var normalResult = il.DefineLabel();
561              il.Emit(System.Reflection.Emit.OpCodes.Dup);
562              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0);
563              il.Emit(System.Reflection.Emit.OpCodes.Blt, nanResult);
564              il.Emit(System.Reflection.Emit.OpCodes.Dup);
565              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, ds.Rows);
566              il.Emit(System.Reflection.Emit.OpCodes.Bge, nanResult);
567              il.Emit(System.Reflection.Emit.OpCodes.Call, listGetValue);
568              il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, varNode.Weight); // load weight
569              il.Emit(System.Reflection.Emit.OpCodes.Mul);
570              il.Emit(System.Reflection.Emit.OpCodes.Br, normalResult);
571              il.MarkLabel(nanResult);
572              il.Emit(System.Reflection.Emit.OpCodes.Pop); // rowIndex
573              il.Emit(System.Reflection.Emit.OpCodes.Pop); // column reference
574              il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, double.NaN);
575              il.MarkLabel(normalResult);
576            }
577            return;
578          }
579        case OpCodes.LagVariable: {
580            var nanResult = il.DefineLabel();
581            var normalResult = il.DefineLabel();
582            LaggedVariableTreeNode varNode = (LaggedVariableTreeNode)currentInstr.dynamicNode;
583            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_1); // load columns array
584            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, (int)currentInstr.iArg0); // load correct column of the current variable
585            il.Emit(System.Reflection.Emit.OpCodes.Ldelem_Ref);
586            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, varNode.Lag); // lag
587            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // rowIndex
588            il.Emit(System.Reflection.Emit.OpCodes.Add); // actualRowIndex = rowIndex + sampleOffset
589            il.Emit(System.Reflection.Emit.OpCodes.Dup);
590            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0);
591            il.Emit(System.Reflection.Emit.OpCodes.Blt, nanResult);
592            il.Emit(System.Reflection.Emit.OpCodes.Dup);
593            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, ds.Rows);
594            il.Emit(System.Reflection.Emit.OpCodes.Bge, nanResult);
595            il.Emit(System.Reflection.Emit.OpCodes.Call, listGetValue);
596            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, varNode.Weight); // load weight
597            il.Emit(System.Reflection.Emit.OpCodes.Mul);
598            il.Emit(System.Reflection.Emit.OpCodes.Br, normalResult);
599            il.MarkLabel(nanResult);
600            il.Emit(System.Reflection.Emit.OpCodes.Pop); // sample index
601            il.Emit(System.Reflection.Emit.OpCodes.Pop); // column reference
602            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, double.NaN);
603            il.MarkLabel(normalResult);
604            return;
605          }
606        case OpCodes.Constant: {
607            ConstantTreeNode constNode = (ConstantTreeNode)currentInstr.dynamicNode;
608            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, constNode.Value);
609            return;
610          }
611
612        //mkommend: this symbol uses the logistic function f(x) = 1 / (1 + e^(-alpha * x) )
613        //to determine the relative amounts of the true and false branch see http://en.wikipedia.org/wiki/Logistic_function
614        case OpCodes.VariableCondition: {
615            throw new NotSupportedException("Interpretation of symbol " + currentInstr.dynamicNode.Symbol.Name + " is not supported by the SymbolicDataAnalysisTreeILEmittingInterpreter");
616          }
617        default: throw new NotSupportedException("Interpretation of symbol " + currentInstr.dynamicNode.Symbol.Name + " is not supported by the SymbolicDataAnalysisTreeILEmittingInterpreter");
618      }
619    }
620
621    private byte MapSymbolToOpCode(ISymbolicExpressionTreeNode treeNode) {
622      if (symbolToOpcode.ContainsKey(treeNode.Symbol.GetType()))
623        return symbolToOpcode[treeNode.Symbol.GetType()];
624      else
625        throw new NotSupportedException("Symbol: " + treeNode.Symbol);
626    }
627  }
628}
Note: See TracBrowser for help on using the repository browser.