Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisExpressionTreeILEmittingInterpreter.cs @ 6809

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

#1480 added check if row index lies within the possible range of the dataset and implemented interpretation of time series symbols in the IL emitting interpreter. Added test cases for evaluation of time series symbols.

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