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

Last change on this file since 7506 was 7506, checked in by mkommend, 8 years ago

#1682: Integrated new gp crossovers into the trunk and corrected the parameter wiring.

File size: 29.1 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);
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      if (CheckExpressionsWithIntervalArithmetic.Value)
208        throw new NotSupportedException("Interval arithmetic is not yet supported in the symbolic data analysis interpreter.");
209      EvaluatedSolutions.Value++; // increment the evaluated solutions counter
210      var compiler = new SymbolicExpressionTreeCompiler();
211      Instruction[] code = compiler.Compile(tree, MapSymbolToOpCode);
212      int necessaryArgStackSize = 0;
213
214      Dictionary<string, int> doubleVariableNames = dataset.DoubleVariables.Select((x, i) => new { x, i }).ToDictionary(e => e.x, e => e.i);
215      IList<double>[] columns = (from v in doubleVariableNames.Keys
216                                 select dataset.GetReadOnlyDoubleValues(v))
217                                .ToArray();
218
219      for (int i = 0; i < code.Length; i++) {
220        Instruction instr = code[i];
221        if (instr.opCode == OpCodes.Variable) {
222          var variableTreeNode = instr.dynamicNode as VariableTreeNode;
223          instr.iArg0 = doubleVariableNames[variableTreeNode.VariableName];
224          code[i] = instr;
225        } else if (instr.opCode == OpCodes.LagVariable) {
226          var variableTreeNode = instr.dynamicNode as LaggedVariableTreeNode;
227          instr.iArg0 = doubleVariableNames[variableTreeNode.VariableName];
228          code[i] = instr;
229        } else if (instr.opCode == OpCodes.VariableCondition) {
230          var variableConditionTreeNode = instr.dynamicNode as VariableConditionTreeNode;
231          instr.iArg0 = doubleVariableNames[variableConditionTreeNode.VariableName];
232        } else if (instr.opCode == OpCodes.Call) {
233          necessaryArgStackSize += instr.nArguments + 1;
234        }
235      }
236      var state = new InterpreterState(code);
237
238      Type[] methodArgs = { typeof(int), typeof(IList<double>[]) };
239      DynamicMethod testFun = new DynamicMethod("TestFun", typeof(double), methodArgs, typeof(SymbolicDataAnalysisExpressionTreeILEmittingInterpreter).Module);
240
241      ILGenerator il = testFun.GetILGenerator();
242      CompileInstructions(il, state, dataset);
243      il.Emit(System.Reflection.Emit.OpCodes.Conv_R8);
244      il.Emit(System.Reflection.Emit.OpCodes.Ret);
245      var function = (CompiledFunction)testFun.CreateDelegate(typeof(CompiledFunction));
246
247      foreach (var row in rows) {
248        yield return function(row, columns);
249      }
250    }
251
252    private void CompileInstructions(ILGenerator il, InterpreterState state, Dataset ds) {
253      Instruction currentInstr = state.NextInstruction();
254      int nArgs = currentInstr.nArguments;
255
256      switch (currentInstr.opCode) {
257        case OpCodes.Add: {
258            if (nArgs > 0) {
259              CompileInstructions(il, state, ds);
260            }
261            for (int i = 1; i < nArgs; i++) {
262              CompileInstructions(il, state, ds);
263              il.Emit(System.Reflection.Emit.OpCodes.Add);
264            }
265            return;
266          }
267        case OpCodes.Sub: {
268            if (nArgs == 1) {
269              CompileInstructions(il, state, ds);
270              il.Emit(System.Reflection.Emit.OpCodes.Neg);
271              return;
272            }
273            if (nArgs > 0) {
274              CompileInstructions(il, state, ds);
275            }
276            for (int i = 1; i < nArgs; i++) {
277              CompileInstructions(il, state, ds);
278              il.Emit(System.Reflection.Emit.OpCodes.Sub);
279            }
280            return;
281          }
282        case OpCodes.Mul: {
283            if (nArgs > 0) {
284              CompileInstructions(il, state, ds);
285            }
286            for (int i = 1; i < nArgs; i++) {
287              CompileInstructions(il, state, ds);
288              il.Emit(System.Reflection.Emit.OpCodes.Mul);
289            }
290            return;
291          }
292        case OpCodes.Div: {
293            if (nArgs == 1) {
294              il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0);
295              CompileInstructions(il, state, ds);
296              il.Emit(System.Reflection.Emit.OpCodes.Div);
297              return;
298            }
299            if (nArgs > 0) {
300              CompileInstructions(il, state, ds);
301            }
302            for (int i = 1; i < nArgs; i++) {
303              CompileInstructions(il, state, ds);
304              il.Emit(System.Reflection.Emit.OpCodes.Div);
305            }
306            return;
307          }
308        case OpCodes.Average: {
309            CompileInstructions(il, state, ds);
310            for (int i = 1; i < nArgs; i++) {
311              CompileInstructions(il, state, ds);
312              il.Emit(System.Reflection.Emit.OpCodes.Add);
313            }
314            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, nArgs);
315            il.Emit(System.Reflection.Emit.OpCodes.Div);
316            return;
317          }
318        case OpCodes.Cos: {
319            CompileInstructions(il, state, ds);
320            il.Emit(System.Reflection.Emit.OpCodes.Call, cos);
321            return;
322          }
323        case OpCodes.Sin: {
324            CompileInstructions(il, state, ds);
325            il.Emit(System.Reflection.Emit.OpCodes.Call, sin);
326            return;
327          }
328        case OpCodes.Tan: {
329            CompileInstructions(il, state, ds);
330            il.Emit(System.Reflection.Emit.OpCodes.Call, tan);
331            return;
332          }
333        case OpCodes.Power: {
334            CompileInstructions(il, state, ds);
335            CompileInstructions(il, state, ds);
336            il.Emit(System.Reflection.Emit.OpCodes.Call, round);
337            il.Emit(System.Reflection.Emit.OpCodes.Call, power);
338            return;
339          }
340        case OpCodes.Root: {
341            CompileInstructions(il, state, ds);
342            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // 1 / round(...)
343            CompileInstructions(il, state, ds);
344            il.Emit(System.Reflection.Emit.OpCodes.Call, round);
345            il.Emit(System.Reflection.Emit.OpCodes.Div);
346            il.Emit(System.Reflection.Emit.OpCodes.Call, power);
347            return;
348          }
349        case OpCodes.Exp: {
350            CompileInstructions(il, state, ds);
351            il.Emit(System.Reflection.Emit.OpCodes.Call, exp);
352            return;
353          }
354        case OpCodes.Log: {
355            CompileInstructions(il, state, ds);
356            il.Emit(System.Reflection.Emit.OpCodes.Call, log);
357            return;
358          }
359        case OpCodes.IfThenElse: {
360            Label end = il.DefineLabel();
361            Label c1 = il.DefineLabel();
362            CompileInstructions(il, state, ds);
363            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // > 0
364            il.Emit(System.Reflection.Emit.OpCodes.Cgt);
365            il.Emit(System.Reflection.Emit.OpCodes.Brfalse, c1);
366            CompileInstructions(il, state, ds);
367            il.Emit(System.Reflection.Emit.OpCodes.Br, end);
368            il.MarkLabel(c1);
369            CompileInstructions(il, state, ds);
370            il.MarkLabel(end);
371            return;
372          }
373        case OpCodes.AND: {
374            Label falseBranch = il.DefineLabel();
375            Label end = il.DefineLabel();
376            CompileInstructions(il, state, ds);
377            for (int i = 1; i < nArgs; i++) {
378              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // > 0
379              il.Emit(System.Reflection.Emit.OpCodes.Cgt);
380              il.Emit(System.Reflection.Emit.OpCodes.Brfalse, falseBranch);
381              CompileInstructions(il, state, ds);
382            }
383            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // > 0
384            il.Emit(System.Reflection.Emit.OpCodes.Cgt);
385            il.Emit(System.Reflection.Emit.OpCodes.Brfalse, falseBranch);
386            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // 1
387            il.Emit(System.Reflection.Emit.OpCodes.Br, end);
388            il.MarkLabel(falseBranch);
389            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // -1
390            il.Emit(System.Reflection.Emit.OpCodes.Neg);
391            il.MarkLabel(end);
392            return;
393          }
394        case OpCodes.OR: {
395            Label trueBranch = il.DefineLabel();
396            Label end = il.DefineLabel();
397            Label resultBranch = il.DefineLabel();
398            CompileInstructions(il, state, ds);
399            for (int i = 1; i < nArgs; i++) {
400              Label nextArgBranch = il.DefineLabel();
401              // complex definition because of special properties of NaN 
402              il.Emit(System.Reflection.Emit.OpCodes.Dup);
403              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // <= 0       
404              il.Emit(System.Reflection.Emit.OpCodes.Ble, nextArgBranch);
405              il.Emit(System.Reflection.Emit.OpCodes.Br, resultBranch);
406              il.MarkLabel(nextArgBranch);
407              il.Emit(System.Reflection.Emit.OpCodes.Pop);
408              CompileInstructions(il, state, ds);
409            }
410            il.MarkLabel(resultBranch);
411            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // > 0
412            il.Emit(System.Reflection.Emit.OpCodes.Cgt);
413            il.Emit(System.Reflection.Emit.OpCodes.Brtrue, trueBranch);
414            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // -1
415            il.Emit(System.Reflection.Emit.OpCodes.Neg);
416            il.Emit(System.Reflection.Emit.OpCodes.Br, end);
417            il.MarkLabel(trueBranch);
418            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // 1
419            il.MarkLabel(end);
420            return;
421          }
422        case OpCodes.NOT: {
423            CompileInstructions(il, state, ds);
424            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // > 0
425            il.Emit(System.Reflection.Emit.OpCodes.Cgt);
426            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0); // * 2
427            il.Emit(System.Reflection.Emit.OpCodes.Mul);
428            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // - 1
429            il.Emit(System.Reflection.Emit.OpCodes.Sub);
430            il.Emit(System.Reflection.Emit.OpCodes.Neg); // * -1
431            return;
432          }
433        case OpCodes.GT: {
434            CompileInstructions(il, state, ds);
435            CompileInstructions(il, state, ds);
436
437            il.Emit(System.Reflection.Emit.OpCodes.Cgt); // 1 (>) / 0 (otherwise)
438            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0); // * 2
439            il.Emit(System.Reflection.Emit.OpCodes.Mul);
440            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // - 1
441            il.Emit(System.Reflection.Emit.OpCodes.Sub);
442            return;
443          }
444        case OpCodes.LT: {
445            CompileInstructions(il, state, ds);
446            CompileInstructions(il, state, ds);
447            il.Emit(System.Reflection.Emit.OpCodes.Clt);
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            return;
453          }
454        case OpCodes.TimeLag: {
455            LaggedTreeNode laggedTreeNode = (LaggedTreeNode)currentInstr.dynamicNode;
456            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row -= lag
457            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, laggedTreeNode.Lag);
458            il.Emit(System.Reflection.Emit.OpCodes.Add);
459            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
460            var prevLaggedContext = state.InLaggedContext;
461            state.InLaggedContext = true;
462            CompileInstructions(il, state, ds);
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.Sub);
466            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
467            state.InLaggedContext = prevLaggedContext;
468            return;
469          }
470        case OpCodes.Integral: {
471            int savedPc = state.ProgramCounter;
472            LaggedTreeNode laggedTreeNode = (LaggedTreeNode)currentInstr.dynamicNode;
473            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row -= lag
474            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, laggedTreeNode.Lag);
475            il.Emit(System.Reflection.Emit.OpCodes.Add);
476            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
477            var prevLaggedContext = state.InLaggedContext;
478            state.InLaggedContext = true;
479            CompileInstructions(il, state, ds);
480            for (int l = laggedTreeNode.Lag; l < 0; l++) {
481              il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row += lag
482              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_1);
483              il.Emit(System.Reflection.Emit.OpCodes.Add);
484              il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
485              state.ProgramCounter = savedPc;
486              CompileInstructions(il, state, ds);
487              il.Emit(System.Reflection.Emit.OpCodes.Add);
488            }
489            state.InLaggedContext = prevLaggedContext;
490            return;
491          }
492
493        //mkommend: derivate calculation taken from:
494        //http://www.holoborodko.com/pavel/numerical-methods/numerical-derivative/smooth-low-noise-differentiators/
495        //one sided smooth differentiatior, N = 4
496        // y' = 1/8h (f_i + 2f_i-1, -2 f_i-3 - f_i-4)
497        case OpCodes.Derivative: {
498            int savedPc = state.ProgramCounter;
499            CompileInstructions(il, state, ds);
500            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row --
501            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_M1);
502            il.Emit(System.Reflection.Emit.OpCodes.Add);
503            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
504            state.ProgramCounter = savedPc;
505            var prevLaggedContext = state.InLaggedContext;
506            state.InLaggedContext = true;
507            CompileInstructions(il, state, ds);
508            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0); // f_0 + 2 * f_1
509            il.Emit(System.Reflection.Emit.OpCodes.Mul);
510            il.Emit(System.Reflection.Emit.OpCodes.Add);
511
512            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row -=2
513            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_2);
514            il.Emit(System.Reflection.Emit.OpCodes.Sub);
515            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
516            state.ProgramCounter = savedPc;
517            CompileInstructions(il, state, ds);
518            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0); // f_0 + 2 * f_1 - 2 * f_3
519            il.Emit(System.Reflection.Emit.OpCodes.Mul);
520            il.Emit(System.Reflection.Emit.OpCodes.Sub);
521
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            CompileInstructions(il, state, ds);
528            il.Emit(System.Reflection.Emit.OpCodes.Sub); // f_0 + 2 * f_1 - 2 * f_3 - f_4
529            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 8.0); // / 8
530            il.Emit(System.Reflection.Emit.OpCodes.Div);
531
532            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row +=4
533            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_4);
534            il.Emit(System.Reflection.Emit.OpCodes.Add);
535            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
536            state.InLaggedContext = prevLaggedContext;
537            return;
538          }
539        case OpCodes.Call: {
540            throw new NotSupportedException("Automatically defined functions are not supported by the SymbolicDataAnalysisTreeILEmittingInterpreter. Either turn of ADFs or change the interpeter.");
541          }
542        case OpCodes.Arg: {
543            throw new NotSupportedException("Automatically defined functions are not supported by the SymbolicDataAnalysisTreeILEmittingInterpreter. Either turn of ADFs or change the interpeter.");
544          }
545        case OpCodes.Variable: {
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);
549            // load correct column of the current variable
550            il.Emit(System.Reflection.Emit.OpCodes.Ldelem_Ref);
551            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // rowIndex
552            if (!state.InLaggedContext) {
553              il.Emit(System.Reflection.Emit.OpCodes.Call, listGetValue);
554              il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, varNode.Weight); // load weight
555              il.Emit(System.Reflection.Emit.OpCodes.Mul);
556            } else {
557              var nanResult = il.DefineLabel();
558              var normalResult = il.DefineLabel();
559              il.Emit(System.Reflection.Emit.OpCodes.Dup);
560              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0);
561              il.Emit(System.Reflection.Emit.OpCodes.Blt, nanResult);
562              il.Emit(System.Reflection.Emit.OpCodes.Dup);
563              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, ds.Rows);
564              il.Emit(System.Reflection.Emit.OpCodes.Bge, nanResult);
565              il.Emit(System.Reflection.Emit.OpCodes.Call, listGetValue);
566              il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, varNode.Weight); // load weight
567              il.Emit(System.Reflection.Emit.OpCodes.Mul);
568              il.Emit(System.Reflection.Emit.OpCodes.Br, normalResult);
569              il.MarkLabel(nanResult);
570              il.Emit(System.Reflection.Emit.OpCodes.Pop); // rowIndex
571              il.Emit(System.Reflection.Emit.OpCodes.Pop); // column reference
572              il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, double.NaN);
573              il.MarkLabel(normalResult);
574            }
575            return;
576          }
577        case OpCodes.LagVariable: {
578            var nanResult = il.DefineLabel();
579            var normalResult = il.DefineLabel();
580            LaggedVariableTreeNode varNode = (LaggedVariableTreeNode)currentInstr.dynamicNode;
581            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_1); // load columns array
582            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, (int)currentInstr.iArg0); // load correct column of the current variable
583            il.Emit(System.Reflection.Emit.OpCodes.Ldelem_Ref);
584            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, varNode.Lag); // lag
585            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // rowIndex
586            il.Emit(System.Reflection.Emit.OpCodes.Add); // actualRowIndex = rowIndex + sampleOffset
587            il.Emit(System.Reflection.Emit.OpCodes.Dup);
588            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0);
589            il.Emit(System.Reflection.Emit.OpCodes.Blt, nanResult);
590            il.Emit(System.Reflection.Emit.OpCodes.Dup);
591            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, ds.Rows);
592            il.Emit(System.Reflection.Emit.OpCodes.Bge, nanResult);
593            il.Emit(System.Reflection.Emit.OpCodes.Call, listGetValue);
594            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, varNode.Weight); // load weight
595            il.Emit(System.Reflection.Emit.OpCodes.Mul);
596            il.Emit(System.Reflection.Emit.OpCodes.Br, normalResult);
597            il.MarkLabel(nanResult);
598            il.Emit(System.Reflection.Emit.OpCodes.Pop); // sample index
599            il.Emit(System.Reflection.Emit.OpCodes.Pop); // column reference
600            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, double.NaN);
601            il.MarkLabel(normalResult);
602            return;
603          }
604        case OpCodes.Constant: {
605            ConstantTreeNode constNode = (ConstantTreeNode)currentInstr.dynamicNode;
606            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, constNode.Value);
607            return;
608          }
609
610        //mkommend: this symbol uses the logistic function f(x) = 1 / (1 + e^(-alpha * x) )
611        //to determine the relative amounts of the true and false branch see http://en.wikipedia.org/wiki/Logistic_function
612        case OpCodes.VariableCondition: {
613            throw new NotSupportedException("Interpretation of symbol " + currentInstr.dynamicNode.Symbol.Name + " is not supported by the SymbolicDataAnalysisTreeILEmittingInterpreter");
614          }
615        default: throw new NotSupportedException("Interpretation of symbol " + currentInstr.dynamicNode.Symbol.Name + " is not supported by the SymbolicDataAnalysisTreeILEmittingInterpreter");
616      }
617    }
618
619    private byte MapSymbolToOpCode(ISymbolicExpressionTreeNode treeNode) {
620      if (symbolToOpcode.ContainsKey(treeNode.Symbol.GetType()))
621        return symbolToOpcode[treeNode.Symbol.GetType()];
622      else
623        throw new NotSupportedException("Symbol: " + treeNode.Symbol);
624    }
625  }
626}
Note: See TracBrowser for help on using the repository browser.