Free cookie consent management tool by TermsFeed Policy Generator

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

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

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

File size: 33.2 KB
RevLine 
[6732]1#region License Information
2/* HeuristicLab
[7268]3 * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
[6732]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;
[7615]23using System.Collections.Generic;
[6741]24using System.Linq;
[6732]25using System.Reflection;
26using System.Reflection.Emit;
27using HeuristicLab.Common;
28using HeuristicLab.Core;
[6740]29using HeuristicLab.Data;
[6732]30using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
[6740]31using HeuristicLab.Parameters;
[6732]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 {
[6741]38    private static MethodInfo listGetValue = typeof(IList<double>).GetProperty("Item", new Type[] { typeof(int) }).GetGetMethod();
[6732]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) });
[6755]45    private static MethodInfo round = typeof(Math).GetMethod("Round", new Type[] { typeof(double) });
[6732]46
[7154]47    internal delegate double CompiledFunction(int sampleIndex, IList<double>[] columns, IList<double>[] cachedValues, int cacheStartIndex);
[6732]48    private const string CheckExpressionsWithIntervalArithmeticParameterName = "CheckExpressionsWithIntervalArithmetic";
[7615]49    private const string EvaluatedSolutionsParameterName = "EvaluatedSolutions";
[6732]50    #region private classes
51    private class InterpreterState {
52      private Instruction[] code;
53      private int pc;
[6849]54
[6732]55      public int ProgramCounter {
56        get { return pc; }
57        set { pc = value; }
58      }
[6849]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;
[6732]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    }
[7615]158
159    public IValueParameter<IntValue> EvaluatedSolutionsParameter {
160      get { return (IValueParameter<IntValue>)Parameters[EvaluatedSolutionsParameterName]; }
161    }
[6732]162    #endregion
163
164    #region properties
165    public BoolValue CheckExpressionsWithIntervalArithmetic {
166      get { return CheckExpressionsWithIntervalArithmeticParameter.Value; }
167      set { CheckExpressionsWithIntervalArithmeticParameter.Value = value; }
168    }
[7615]169
170    public IntValue EvaluatedSolutions {
171      get { return EvaluatedSolutionsParameter.Value; }
172      set { EvaluatedSolutionsParameter.Value = value; }
173    }
[6732]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)));
[7615]187      Parameters.Add(new ValueParameter<IntValue>(EvaluatedSolutionsParameterName, "A counter for the total number of solutions the interpreter has evaluated", new IntValue(0)));
[6732]188    }
189
[7615]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
[6732]206    public IEnumerable<double> GetSymbolicExpressionTreeValues(ISymbolicExpressionTree tree, Dataset dataset, IEnumerable<int> rows) {
[7154]207      return GetSymbolicExpressionTreeValues(tree, dataset, new string[] { "#NOTHING#" }, rows);
[7129]208    }
[7154]209    public IEnumerable<double> GetSymbolicExpressionTreeValues(ISymbolicExpressionTree tree, Dataset dataset, string[] targetVariables, IEnumerable<int> rows) {
210      return GetSymbolicExpressionTreeValues(tree, dataset, targetVariables, rows, 1);
211    }
212    // for each row for each horizon for each target variable one value
213    public IEnumerable<double> GetSymbolicExpressionTreeValues(ISymbolicExpressionTree tree, Dataset dataset, string[] targetVariables, IEnumerable<int> rows, int horizon) {
[6732]214      if (CheckExpressionsWithIntervalArithmetic.Value)
215        throw new NotSupportedException("Interval arithmetic is not yet supported in the symbolic data analysis interpreter.");
[7615]216      EvaluatedSolutions.Value++; // increment the evaluated solutions counter
[6732]217      var compiler = new SymbolicExpressionTreeCompiler();
218      Instruction[] code = compiler.Compile(tree, MapSymbolToOpCode);
219      int necessaryArgStackSize = 0;
[6741]220
221      Dictionary<string, int> doubleVariableNames = dataset.DoubleVariables.Select((x, i) => new { x, i }).ToDictionary(e => e.x, e => e.i);
222
[6732]223      for (int i = 0; i < code.Length; i++) {
224        Instruction instr = code[i];
225        if (instr.opCode == OpCodes.Variable) {
226          var variableTreeNode = instr.dynamicNode as VariableTreeNode;
[6741]227          instr.iArg0 = doubleVariableNames[variableTreeNode.VariableName];
[6732]228          code[i] = instr;
229        } else if (instr.opCode == OpCodes.LagVariable) {
230          var variableTreeNode = instr.dynamicNode as LaggedVariableTreeNode;
[6741]231          instr.iArg0 = doubleVariableNames[variableTreeNode.VariableName];
[6732]232          code[i] = instr;
233        } else if (instr.opCode == OpCodes.VariableCondition) {
234          var variableConditionTreeNode = instr.dynamicNode as VariableConditionTreeNode;
[6741]235          instr.iArg0 = doubleVariableNames[variableConditionTreeNode.VariableName];
[6732]236        } else if (instr.opCode == OpCodes.Call) {
237          necessaryArgStackSize += instr.nArguments + 1;
238        }
239      }
[6849]240      var state = new InterpreterState(code);
[7154]241      Type[] methodArgs = { typeof(int), typeof(IList<double>[]), typeof(IList<double>[]), typeof(int) };
[6732]242
[7129]243      CompiledFunction[] function = new CompiledFunction[targetVariables.Length];
244      for (int i = 0; i < function.Length; i++) {
245        DynamicMethod testFun = new DynamicMethod("TestFun", typeof(double), methodArgs, typeof(SymbolicDataAnalysisExpressionTreeILEmittingInterpreter).Module);
246        ILGenerator il = testFun.GetILGenerator();
247        CompileInstructions(il, state, dataset);
248        il.Emit(System.Reflection.Emit.OpCodes.Conv_R8);
249        il.Emit(System.Reflection.Emit.OpCodes.Ret);
250        function[i] = (CompiledFunction)testFun.CreateDelegate(typeof(CompiledFunction));
251      }
252      var values = doubleVariableNames.Keys
[7154]253        .Select(v => dataset.GetReadOnlyDoubleValues(v))
[7129]254        .ToArray();
[7154]255      var cachedValues = (from var in doubleVariableNames.Keys
256                          select new double[horizon]).ToArray();
257      foreach (var row in rows) {
258        // init first line of cache
259        int c = 0;
260        foreach (var var in doubleVariableNames.Keys)
261          cachedValues[c++][0] = dataset.GetDoubleValue(var, row);
262        for (int horizonRow = row; horizonRow < row + horizon; horizonRow++) {
263          for (int i = 0; i < function.Length; i++) {
264            var componentProg = function[i](horizonRow, values, cachedValues, row);
[7129]265            // set cachedValues for prognosis of future values
[7154]266            if (horizon > 1)
267              cachedValues[doubleVariableNames[targetVariables[i]]][horizonRow - row] = componentProg;
268            yield return componentProg;
[7129]269          }
270        }
[6732]271      }
272    }
273
[6809]274    private void CompileInstructions(ILGenerator il, InterpreterState state, Dataset ds) {
[6732]275      Instruction currentInstr = state.NextInstruction();
276      int nArgs = currentInstr.nArguments;
277
278      switch (currentInstr.opCode) {
279        case OpCodes.Add: {
280            if (nArgs > 0) {
[6809]281              CompileInstructions(il, state, ds);
[6732]282            }
283            for (int i = 1; i < nArgs; i++) {
[6809]284              CompileInstructions(il, state, ds);
[6732]285              il.Emit(System.Reflection.Emit.OpCodes.Add);
286            }
287            return;
288          }
289        case OpCodes.Sub: {
290            if (nArgs == 1) {
[6809]291              CompileInstructions(il, state, ds);
[6732]292              il.Emit(System.Reflection.Emit.OpCodes.Neg);
293              return;
294            }
295            if (nArgs > 0) {
[6809]296              CompileInstructions(il, state, ds);
[6732]297            }
298            for (int i = 1; i < nArgs; i++) {
[6809]299              CompileInstructions(il, state, ds);
[6732]300              il.Emit(System.Reflection.Emit.OpCodes.Sub);
301            }
302            return;
303          }
304        case OpCodes.Mul: {
305            if (nArgs > 0) {
[6809]306              CompileInstructions(il, state, ds);
[6732]307            }
308            for (int i = 1; i < nArgs; i++) {
[6809]309              CompileInstructions(il, state, ds);
[6732]310              il.Emit(System.Reflection.Emit.OpCodes.Mul);
311            }
312            return;
313          }
314        case OpCodes.Div: {
315            if (nArgs == 1) {
316              il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0);
[6809]317              CompileInstructions(il, state, ds);
[6732]318              il.Emit(System.Reflection.Emit.OpCodes.Div);
319              return;
320            }
321            if (nArgs > 0) {
[6809]322              CompileInstructions(il, state, ds);
[6732]323            }
324            for (int i = 1; i < nArgs; i++) {
[6809]325              CompileInstructions(il, state, ds);
[6732]326              il.Emit(System.Reflection.Emit.OpCodes.Div);
327            }
328            return;
329          }
330        case OpCodes.Average: {
[6809]331            CompileInstructions(il, state, ds);
[6732]332            for (int i = 1; i < nArgs; i++) {
[6809]333              CompileInstructions(il, state, ds);
[6732]334              il.Emit(System.Reflection.Emit.OpCodes.Add);
335            }
336            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, nArgs);
337            il.Emit(System.Reflection.Emit.OpCodes.Div);
338            return;
339          }
340        case OpCodes.Cos: {
[6809]341            CompileInstructions(il, state, ds);
[6732]342            il.Emit(System.Reflection.Emit.OpCodes.Call, cos);
343            return;
344          }
345        case OpCodes.Sin: {
[6809]346            CompileInstructions(il, state, ds);
[6732]347            il.Emit(System.Reflection.Emit.OpCodes.Call, sin);
348            return;
349          }
350        case OpCodes.Tan: {
[6809]351            CompileInstructions(il, state, ds);
[6732]352            il.Emit(System.Reflection.Emit.OpCodes.Call, tan);
353            return;
354          }
355        case OpCodes.Power: {
[6809]356            CompileInstructions(il, state, ds);
357            CompileInstructions(il, state, ds);
[6755]358            il.Emit(System.Reflection.Emit.OpCodes.Call, round);
[6732]359            il.Emit(System.Reflection.Emit.OpCodes.Call, power);
360            return;
361          }
362        case OpCodes.Root: {
[6809]363            CompileInstructions(il, state, ds);
[6755]364            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // 1 / round(...)
[6809]365            CompileInstructions(il, state, ds);
[6755]366            il.Emit(System.Reflection.Emit.OpCodes.Call, round);
367            il.Emit(System.Reflection.Emit.OpCodes.Div);
368            il.Emit(System.Reflection.Emit.OpCodes.Call, power);
369            return;
[6732]370          }
371        case OpCodes.Exp: {
[6809]372            CompileInstructions(il, state, ds);
[6732]373            il.Emit(System.Reflection.Emit.OpCodes.Call, exp);
374            return;
375          }
376        case OpCodes.Log: {
[6809]377            CompileInstructions(il, state, ds);
[6732]378            il.Emit(System.Reflection.Emit.OpCodes.Call, log);
379            return;
380          }
381        case OpCodes.IfThenElse: {
382            Label end = il.DefineLabel();
383            Label c1 = il.DefineLabel();
[6809]384            CompileInstructions(il, state, ds);
[6732]385            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // > 0
386            il.Emit(System.Reflection.Emit.OpCodes.Cgt);
387            il.Emit(System.Reflection.Emit.OpCodes.Brfalse, c1);
[6809]388            CompileInstructions(il, state, ds);
[6732]389            il.Emit(System.Reflection.Emit.OpCodes.Br, end);
390            il.MarkLabel(c1);
[6809]391            CompileInstructions(il, state, ds);
[6732]392            il.MarkLabel(end);
393            return;
394          }
395        case OpCodes.AND: {
396            Label falseBranch = il.DefineLabel();
397            Label end = il.DefineLabel();
[6809]398            CompileInstructions(il, state, ds);
[6732]399            for (int i = 1; i < nArgs; i++) {
400              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // > 0
401              il.Emit(System.Reflection.Emit.OpCodes.Cgt);
402              il.Emit(System.Reflection.Emit.OpCodes.Brfalse, falseBranch);
[6809]403              CompileInstructions(il, state, ds);
[6732]404            }
405            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // > 0
406            il.Emit(System.Reflection.Emit.OpCodes.Cgt);
407            il.Emit(System.Reflection.Emit.OpCodes.Brfalse, falseBranch);
408            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // 1
409            il.Emit(System.Reflection.Emit.OpCodes.Br, end);
410            il.MarkLabel(falseBranch);
411            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // -1
412            il.Emit(System.Reflection.Emit.OpCodes.Neg);
413            il.MarkLabel(end);
414            return;
415          }
416        case OpCodes.OR: {
417            Label trueBranch = il.DefineLabel();
418            Label end = il.DefineLabel();
419            Label resultBranch = il.DefineLabel();
[6809]420            CompileInstructions(il, state, ds);
[6732]421            for (int i = 1; i < nArgs; i++) {
422              Label nextArgBranch = il.DefineLabel();
423              // complex definition because of special properties of NaN 
424              il.Emit(System.Reflection.Emit.OpCodes.Dup);
425              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // <= 0       
426              il.Emit(System.Reflection.Emit.OpCodes.Ble, nextArgBranch);
427              il.Emit(System.Reflection.Emit.OpCodes.Br, resultBranch);
428              il.MarkLabel(nextArgBranch);
429              il.Emit(System.Reflection.Emit.OpCodes.Pop);
[6809]430              CompileInstructions(il, state, ds);
[6732]431            }
432            il.MarkLabel(resultBranch);
433            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // > 0
434            il.Emit(System.Reflection.Emit.OpCodes.Cgt);
435            il.Emit(System.Reflection.Emit.OpCodes.Brtrue, trueBranch);
436            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // -1
437            il.Emit(System.Reflection.Emit.OpCodes.Neg);
438            il.Emit(System.Reflection.Emit.OpCodes.Br, end);
439            il.MarkLabel(trueBranch);
440            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // 1
441            il.MarkLabel(end);
442            return;
443          }
444        case OpCodes.NOT: {
[6809]445            CompileInstructions(il, state, ds);
[6732]446            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // > 0
447            il.Emit(System.Reflection.Emit.OpCodes.Cgt);
448            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0); // * 2
449            il.Emit(System.Reflection.Emit.OpCodes.Mul);
450            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // - 1
451            il.Emit(System.Reflection.Emit.OpCodes.Sub);
452            il.Emit(System.Reflection.Emit.OpCodes.Neg); // * -1
453            return;
454          }
455        case OpCodes.GT: {
[6809]456            CompileInstructions(il, state, ds);
457            CompileInstructions(il, state, ds);
458
[6732]459            il.Emit(System.Reflection.Emit.OpCodes.Cgt); // 1 (>) / 0 (otherwise)
460            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0); // * 2
461            il.Emit(System.Reflection.Emit.OpCodes.Mul);
462            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // - 1
463            il.Emit(System.Reflection.Emit.OpCodes.Sub);
464            return;
465          }
466        case OpCodes.LT: {
[6809]467            CompileInstructions(il, state, ds);
468            CompileInstructions(il, state, ds);
[6732]469            il.Emit(System.Reflection.Emit.OpCodes.Clt);
470            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0); // * 2
471            il.Emit(System.Reflection.Emit.OpCodes.Mul);
472            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // - 1
473            il.Emit(System.Reflection.Emit.OpCodes.Sub);
474            return;
475          }
476        case OpCodes.TimeLag: {
[6809]477            LaggedTreeNode laggedTreeNode = (LaggedTreeNode)currentInstr.dynamicNode;
478            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row -= lag
479            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, laggedTreeNode.Lag);
480            il.Emit(System.Reflection.Emit.OpCodes.Add);
481            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
[6849]482            var prevLaggedContext = state.InLaggedContext;
483            state.InLaggedContext = true;
[6809]484            CompileInstructions(il, state, ds);
485            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row += lag
486            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, laggedTreeNode.Lag);
487            il.Emit(System.Reflection.Emit.OpCodes.Sub);
488            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
[6849]489            state.InLaggedContext = prevLaggedContext;
[6809]490            return;
[6732]491          }
492        case OpCodes.Integral: {
[6809]493            int savedPc = state.ProgramCounter;
494            LaggedTreeNode laggedTreeNode = (LaggedTreeNode)currentInstr.dynamicNode;
495            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row -= lag
496            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, laggedTreeNode.Lag);
497            il.Emit(System.Reflection.Emit.OpCodes.Add);
498            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
[6849]499            var prevLaggedContext = state.InLaggedContext;
500            state.InLaggedContext = true;
[6809]501            CompileInstructions(il, state, ds);
502            for (int l = laggedTreeNode.Lag; l < 0; l++) {
503              il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row += lag
504              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_1);
505              il.Emit(System.Reflection.Emit.OpCodes.Add);
506              il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
507              state.ProgramCounter = savedPc;
508              CompileInstructions(il, state, ds);
509              il.Emit(System.Reflection.Emit.OpCodes.Add);
510            }
[6849]511            state.InLaggedContext = prevLaggedContext;
[6809]512            return;
[6732]513          }
514
515        //mkommend: derivate calculation taken from:
516        //http://www.holoborodko.com/pavel/numerical-methods/numerical-derivative/smooth-low-noise-differentiators/
517        //one sided smooth differentiatior, N = 4
518        // y' = 1/8h (f_i + 2f_i-1, -2 f_i-3 - f_i-4)
519        case OpCodes.Derivative: {
[6809]520            int savedPc = state.ProgramCounter;
521            CompileInstructions(il, state, ds);
522            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row --
523            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_M1);
524            il.Emit(System.Reflection.Emit.OpCodes.Add);
525            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
526            state.ProgramCounter = savedPc;
[6849]527            var prevLaggedContext = state.InLaggedContext;
528            state.InLaggedContext = true;
[6809]529            CompileInstructions(il, state, ds);
530            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0); // f_0 + 2 * f_1
531            il.Emit(System.Reflection.Emit.OpCodes.Mul);
532            il.Emit(System.Reflection.Emit.OpCodes.Add);
533
534            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row -=2
535            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_2);
536            il.Emit(System.Reflection.Emit.OpCodes.Sub);
537            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
538            state.ProgramCounter = savedPc;
539            CompileInstructions(il, state, ds);
540            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0); // f_0 + 2 * f_1 - 2 * f_3
541            il.Emit(System.Reflection.Emit.OpCodes.Mul);
542            il.Emit(System.Reflection.Emit.OpCodes.Sub);
543
544            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row --
545            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_M1);
546            il.Emit(System.Reflection.Emit.OpCodes.Add);
547            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
548            state.ProgramCounter = savedPc;
549            CompileInstructions(il, state, ds);
550            il.Emit(System.Reflection.Emit.OpCodes.Sub); // f_0 + 2 * f_1 - 2 * f_3 - f_4
551            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 8.0); // / 8
552            il.Emit(System.Reflection.Emit.OpCodes.Div);
553
554            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row +=4
555            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_4);
556            il.Emit(System.Reflection.Emit.OpCodes.Add);
557            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
[6849]558            state.InLaggedContext = prevLaggedContext;
[6809]559            return;
[6732]560          }
561        case OpCodes.Call: {
[6770]562            throw new NotSupportedException("Automatically defined functions are not supported by the SymbolicDataAnalysisTreeILEmittingInterpreter. Either turn of ADFs or change the interpeter.");
[6732]563          }
564        case OpCodes.Arg: {
[6770]565            throw new NotSupportedException("Automatically defined functions are not supported by the SymbolicDataAnalysisTreeILEmittingInterpreter. Either turn of ADFs or change the interpeter.");
[6732]566          }
567        case OpCodes.Variable: {
[6741]568            VariableTreeNode varNode = (VariableTreeNode)currentInstr.dynamicNode;
[6849]569            if (!state.InLaggedContext) {
[7154]570              il.Emit(System.Reflection.Emit.OpCodes.Ldarg_1); // load columns array
571              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, (int)currentInstr.iArg0);
572              // load correct column of the current variable
573              il.Emit(System.Reflection.Emit.OpCodes.Ldelem_Ref);
574              il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // rowIndex
[6849]575              il.Emit(System.Reflection.Emit.OpCodes.Call, listGetValue);
576              il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, varNode.Weight); // load weight
577              il.Emit(System.Reflection.Emit.OpCodes.Mul);
578            } else {
579              var nanResult = il.DefineLabel();
580              var normalResult = il.DefineLabel();
[7154]581              var cachedValue = il.DefineLabel();
582              var multiplyValue = il.DefineLabel();
583              il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // rowIndex
[6849]584              il.Emit(System.Reflection.Emit.OpCodes.Dup);
585              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0);
586              il.Emit(System.Reflection.Emit.OpCodes.Blt, nanResult);
587              il.Emit(System.Reflection.Emit.OpCodes.Dup);
588              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, ds.Rows);
589              il.Emit(System.Reflection.Emit.OpCodes.Bge, nanResult);
[7154]590              il.Emit(System.Reflection.Emit.OpCodes.Ldarg_3);
591              il.Emit(System.Reflection.Emit.OpCodes.Bge, cachedValue);
592              il.Emit(System.Reflection.Emit.OpCodes.Ldarg_1); // load columns array
593              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, (int)currentInstr.iArg0);
594              il.Emit(System.Reflection.Emit.OpCodes.Ldelem_Ref);
595              il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // rowIndex
[6849]596              il.Emit(System.Reflection.Emit.OpCodes.Call, listGetValue);
[7154]597              il.Emit(System.Reflection.Emit.OpCodes.Br, multiplyValue);
598              il.MarkLabel(cachedValue);
599              il.Emit(System.Reflection.Emit.OpCodes.Ldarg_2); // load cached values array
600              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, (int)currentInstr.iArg0);
601              il.Emit(System.Reflection.Emit.OpCodes.Ldelem_Ref);
602              il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // rowIndex
603              il.Emit(System.Reflection.Emit.OpCodes.Ldarg_3); // startRow
604              il.Emit(System.Reflection.Emit.OpCodes.Sub); // startRow
605              il.Emit(System.Reflection.Emit.OpCodes.Call, listGetValue);
606              il.MarkLabel(multiplyValue);
[6849]607              il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, varNode.Weight); // load weight
608              il.Emit(System.Reflection.Emit.OpCodes.Mul);
609              il.Emit(System.Reflection.Emit.OpCodes.Br, normalResult);
610              il.MarkLabel(nanResult);
611              il.Emit(System.Reflection.Emit.OpCodes.Pop); // rowIndex
612              il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, double.NaN);
613              il.MarkLabel(normalResult);
614            }
[6732]615            return;
616          }
617        case OpCodes.LagVariable: {
[6809]618            var nanResult = il.DefineLabel();
619            var normalResult = il.DefineLabel();
[7154]620            var cachedValue = il.DefineLabel();
621            var multiplyValue = il.DefineLabel();
[6770]622            LaggedVariableTreeNode varNode = (LaggedVariableTreeNode)currentInstr.dynamicNode;
623            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, varNode.Lag); // lag
[6849]624            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // rowIndex
625            il.Emit(System.Reflection.Emit.OpCodes.Add); // actualRowIndex = rowIndex + sampleOffset
[6809]626            il.Emit(System.Reflection.Emit.OpCodes.Dup);
627            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0);
628            il.Emit(System.Reflection.Emit.OpCodes.Blt, nanResult);
629            il.Emit(System.Reflection.Emit.OpCodes.Dup);
630            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, ds.Rows);
631            il.Emit(System.Reflection.Emit.OpCodes.Bge, nanResult);
[7154]632            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_3); // startindex
633            il.Emit(System.Reflection.Emit.OpCodes.Bge, cachedValue);
634            // normal value
635            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_1); // load columns array
636            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, (int)currentInstr.iArg0); // load correct column of the current variable
637            il.Emit(System.Reflection.Emit.OpCodes.Ldelem_Ref);
638            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, varNode.Lag); // lag
639            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // rowIndex
640            il.Emit(System.Reflection.Emit.OpCodes.Add); // actualRowIndex = rowIndex + sampleOffset
[6770]641            il.Emit(System.Reflection.Emit.OpCodes.Call, listGetValue);
[7154]642            il.Emit(System.Reflection.Emit.OpCodes.Br, multiplyValue);
643            il.MarkLabel(cachedValue);
644            // cached value
645            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_2); // load cached values
646            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, (int)currentInstr.iArg0); // load correct column of the current variable
647            il.Emit(System.Reflection.Emit.OpCodes.Ldelem_Ref);
648            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, varNode.Lag); // lag
649            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // rowIndex
650            il.Emit(System.Reflection.Emit.OpCodes.Add); // actualRowIndex = rowIndex + sampleOffset
651            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_3); // startRow
652            il.Emit(System.Reflection.Emit.OpCodes.Sub); // startRow           
653            il.Emit(System.Reflection.Emit.OpCodes.Call, listGetValue);
654
655            il.MarkLabel(multiplyValue);
[6770]656            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, varNode.Weight); // load weight
657            il.Emit(System.Reflection.Emit.OpCodes.Mul);
[6809]658            il.Emit(System.Reflection.Emit.OpCodes.Br, normalResult);
659            il.MarkLabel(nanResult);
[7154]660            il.Emit(System.Reflection.Emit.OpCodes.Pop); // pop the row index
[6809]661            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, double.NaN);
662            il.MarkLabel(normalResult);
[6770]663            return;
[6732]664          }
665        case OpCodes.Constant: {
666            ConstantTreeNode constNode = (ConstantTreeNode)currentInstr.dynamicNode;
667            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, constNode.Value);
668            return;
669          }
670
671        //mkommend: this symbol uses the logistic function f(x) = 1 / (1 + e^(-alpha * x) )
672        //to determine the relative amounts of the true and false branch see http://en.wikipedia.org/wiki/Logistic_function
673        case OpCodes.VariableCondition: {
[7077]674            throw new NotSupportedException("Interpretation of symbol " + currentInstr.dynamicNode.Symbol.Name + " is not supported by the SymbolicDataAnalysisTreeILEmittingInterpreter");
[6732]675          }
[7077]676        default: throw new NotSupportedException("Interpretation of symbol " + currentInstr.dynamicNode.Symbol.Name + " is not supported by the SymbolicDataAnalysisTreeILEmittingInterpreter");
[6732]677      }
678    }
679
680    private byte MapSymbolToOpCode(ISymbolicExpressionTreeNode treeNode) {
681      if (symbolToOpcode.ContainsKey(treeNode.Symbol.GetType()))
682        return symbolToOpcode[treeNode.Symbol.GetType()];
683      else
684        throw new NotSupportedException("Symbol: " + treeNode.Symbol);
685    }
686  }
687}
Note: See TracBrowser for help on using the repository browser.