Ejemplo n.º 1
0
        public static void PrepareInstructions(LinearInstruction[] code, IDataset dataset)
        {
            for (int i = 0; i != code.Length; ++i)
            {
                var instr = code[i];
                #region opcode switch
                switch (instr.opCode)
                {
                case OpCodes.Constant: {
                    var constTreeNode = (ConstantTreeNode)instr.dynamicNode;
                    instr.value = constTreeNode.Value;
                    instr.skip  = true; // the value is already set so this instruction should be skipped in the evaluation phase
                }
                break;

                case OpCodes.Variable: {
                    var variableTreeNode = (VariableTreeNode)instr.dynamicNode;
                    instr.data = dataset.GetReadOnlyDoubleValues(variableTreeNode.VariableName);
                }
                break;

                case OpCodes.LagVariable: {
                    var laggedVariableTreeNode = (LaggedVariableTreeNode)instr.dynamicNode;
                    instr.data = dataset.GetReadOnlyDoubleValues(laggedVariableTreeNode.VariableName);
                }
                break;

                case OpCodes.VariableCondition: {
                    var variableConditionTreeNode = (VariableConditionTreeNode)instr.dynamicNode;
                    instr.data = dataset.GetReadOnlyDoubleValues(variableConditionTreeNode.VariableName);
                }
                break;

                case OpCodes.TimeLag:
                case OpCodes.Integral:
                case OpCodes.Derivative: {
                    var seq = GetPrefixSequence(code, i);
                    var interpreterState = new InterpreterState(seq, 0);
                    instr.data = interpreterState;
                    for (int j = 1; j != seq.Length; ++j)
                    {
                        seq[j].skip = true;
                    }
                }
                break;
                }
                #endregion
            }
        }
        public virtual double Evaluate(IDataset dataset, ref int row, InterpreterState state)
        {
            Instruction currentInstr = state.NextInstruction();

            switch (currentInstr.opCode)
            {
            case OpCodes.Add: {
                double s = Evaluate(dataset, ref row, state);
                for (int i = 1; i < currentInstr.nArguments; i++)
                {
                    s += Evaluate(dataset, ref row, state);
                }
                return(s);
            }

            case OpCodes.Sub: {
                double s = Evaluate(dataset, ref row, state);
                for (int i = 1; i < currentInstr.nArguments; i++)
                {
                    s -= Evaluate(dataset, ref row, state);
                }
                if (currentInstr.nArguments == 1)
                {
                    s = -s;
                }
                return(s);
            }

            case OpCodes.Mul: {
                double p = Evaluate(dataset, ref row, state);
                for (int i = 1; i < currentInstr.nArguments; i++)
                {
                    p *= Evaluate(dataset, ref row, state);
                }
                return(p);
            }

            case OpCodes.Div: {
                double p = Evaluate(dataset, ref row, state);
                for (int i = 1; i < currentInstr.nArguments; i++)
                {
                    p /= Evaluate(dataset, ref row, state);
                }
                if (currentInstr.nArguments == 1)
                {
                    p = 1.0 / p;
                }
                return(p);
            }

            case OpCodes.Average: {
                double sum = Evaluate(dataset, ref row, state);
                for (int i = 1; i < currentInstr.nArguments; i++)
                {
                    sum += Evaluate(dataset, ref row, state);
                }
                return(sum / currentInstr.nArguments);
            }

            case OpCodes.Absolute: {
                return(Math.Abs(Evaluate(dataset, ref row, state)));
            }

            case OpCodes.Tanh: {
                return(Math.Tanh(Evaluate(dataset, ref row, state)));
            }

            case OpCodes.Cos: {
                return(Math.Cos(Evaluate(dataset, ref row, state)));
            }

            case OpCodes.Sin: {
                return(Math.Sin(Evaluate(dataset, ref row, state)));
            }

            case OpCodes.Tan: {
                return(Math.Tan(Evaluate(dataset, ref row, state)));
            }

            case OpCodes.Square: {
                return(Math.Pow(Evaluate(dataset, ref row, state), 2));
            }

            case OpCodes.Cube: {
                return(Math.Pow(Evaluate(dataset, ref row, state), 3));
            }

            case OpCodes.Power: {
                double x = Evaluate(dataset, ref row, state);
                double y = Math.Round(Evaluate(dataset, ref row, state));
                return(Math.Pow(x, y));
            }

            case OpCodes.SquareRoot: {
                return(Math.Sqrt(Evaluate(dataset, ref row, state)));
            }

            case OpCodes.CubeRoot: {
                var arg = Evaluate(dataset, ref row, state);
                return(arg < 0 ? -Math.Pow(-arg, 1.0 / 3.0) : Math.Pow(arg, 1.0 / 3.0));
            }

            case OpCodes.Root: {
                double x = Evaluate(dataset, ref row, state);
                double y = Math.Round(Evaluate(dataset, ref row, state));
                return(Math.Pow(x, 1 / y));
            }

            case OpCodes.Exp: {
                return(Math.Exp(Evaluate(dataset, ref row, state)));
            }

            case OpCodes.Log: {
                return(Math.Log(Evaluate(dataset, ref row, state)));
            }

            case OpCodes.Gamma: {
                var x = Evaluate(dataset, ref row, state);
                if (double.IsNaN(x))
                {
                    return(double.NaN);
                }
                else
                {
                    return(alglib.gammafunction(x));
                }
            }

            case OpCodes.Psi: {
                var x = Evaluate(dataset, ref row, state);
                if (double.IsNaN(x))
                {
                    return(double.NaN);
                }
                else if (x <= 0 && (Math.Floor(x) - x).IsAlmost(0))
                {
                    return(double.NaN);
                }
                return(alglib.psi(x));
            }

            case OpCodes.Dawson: {
                var x = Evaluate(dataset, ref row, state);
                if (double.IsNaN(x))
                {
                    return(double.NaN);
                }
                return(alglib.dawsonintegral(x));
            }

            case OpCodes.ExponentialIntegralEi: {
                var x = Evaluate(dataset, ref row, state);
                if (double.IsNaN(x))
                {
                    return(double.NaN);
                }
                return(alglib.exponentialintegralei(x));
            }

            case OpCodes.SineIntegral: {
                double si, ci;
                var    x = Evaluate(dataset, ref row, state);
                if (double.IsNaN(x))
                {
                    return(double.NaN);
                }
                else
                {
                    alglib.sinecosineintegrals(x, out si, out ci);
                    return(si);
                }
            }

            case OpCodes.CosineIntegral: {
                double si, ci;
                var    x = Evaluate(dataset, ref row, state);
                if (double.IsNaN(x))
                {
                    return(double.NaN);
                }
                else
                {
                    alglib.sinecosineintegrals(x, out si, out ci);
                    return(ci);
                }
            }

            case OpCodes.HyperbolicSineIntegral: {
                double shi, chi;
                var    x = Evaluate(dataset, ref row, state);
                if (double.IsNaN(x))
                {
                    return(double.NaN);
                }
                else
                {
                    alglib.hyperbolicsinecosineintegrals(x, out shi, out chi);
                    return(shi);
                }
            }

            case OpCodes.HyperbolicCosineIntegral: {
                double shi, chi;
                var    x = Evaluate(dataset, ref row, state);
                if (double.IsNaN(x))
                {
                    return(double.NaN);
                }
                else
                {
                    alglib.hyperbolicsinecosineintegrals(x, out shi, out chi);
                    return(chi);
                }
            }

            case OpCodes.FresnelCosineIntegral: {
                double c = 0, s = 0;
                var    x = Evaluate(dataset, ref row, state);
                if (double.IsNaN(x))
                {
                    return(double.NaN);
                }
                else
                {
                    alglib.fresnelintegral(x, ref c, ref s);
                    return(c);
                }
            }

            case OpCodes.FresnelSineIntegral: {
                double c = 0, s = 0;
                var    x = Evaluate(dataset, ref row, state);
                if (double.IsNaN(x))
                {
                    return(double.NaN);
                }
                else
                {
                    alglib.fresnelintegral(x, ref c, ref s);
                    return(s);
                }
            }

            case OpCodes.AiryA: {
                double ai, aip, bi, bip;
                var    x = Evaluate(dataset, ref row, state);
                if (double.IsNaN(x))
                {
                    return(double.NaN);
                }
                else
                {
                    alglib.airy(x, out ai, out aip, out bi, out bip);
                    return(ai);
                }
            }

            case OpCodes.AiryB: {
                double ai, aip, bi, bip;
                var    x = Evaluate(dataset, ref row, state);
                if (double.IsNaN(x))
                {
                    return(double.NaN);
                }
                else
                {
                    alglib.airy(x, out ai, out aip, out bi, out bip);
                    return(bi);
                }
            }

            case OpCodes.Norm: {
                var x = Evaluate(dataset, ref row, state);
                if (double.IsNaN(x))
                {
                    return(double.NaN);
                }
                else
                {
                    return(alglib.normaldistribution(x));
                }
            }

            case OpCodes.Erf: {
                var x = Evaluate(dataset, ref row, state);
                if (double.IsNaN(x))
                {
                    return(double.NaN);
                }
                else
                {
                    return(alglib.errorfunction(x));
                }
            }

            case OpCodes.Bessel: {
                var x = Evaluate(dataset, ref row, state);
                if (double.IsNaN(x))
                {
                    return(double.NaN);
                }
                else
                {
                    return(alglib.besseli0(x));
                }
            }

            case OpCodes.AnalyticQuotient: {
                var x1 = Evaluate(dataset, ref row, state);
                var x2 = Evaluate(dataset, ref row, state);
                return(x1 / Math.Pow(1 + x2 * x2, 0.5));
            }

            case OpCodes.IfThenElse: {
                double condition = Evaluate(dataset, ref row, state);
                double result;
                if (condition > 0.0)
                {
                    result = Evaluate(dataset, ref row, state); state.SkipInstructions();
                }
                else
                {
                    state.SkipInstructions(); result = Evaluate(dataset, ref row, state);
                }
                return(result);
            }

            case OpCodes.AND: {
                double result = Evaluate(dataset, ref row, state);
                for (int i = 1; i < currentInstr.nArguments; i++)
                {
                    if (result > 0.0)
                    {
                        result = Evaluate(dataset, ref row, state);
                    }
                    else
                    {
                        state.SkipInstructions();
                    }
                }
                return(result > 0.0 ? 1.0 : -1.0);
            }

            case OpCodes.OR: {
                double result = Evaluate(dataset, ref row, state);
                for (int i = 1; i < currentInstr.nArguments; i++)
                {
                    if (result <= 0.0)
                    {
                        result = Evaluate(dataset, ref row, state);
                    }
                    else
                    {
                        state.SkipInstructions();
                    }
                }
                return(result > 0.0 ? 1.0 : -1.0);
            }

            case OpCodes.NOT: {
                return(Evaluate(dataset, ref row, state) > 0.0 ? -1.0 : 1.0);
            }

            case OpCodes.XOR: {
                //mkommend: XOR on multiple inputs is defined as true if the number of positive signals is odd
                // this is equal to a consecutive execution of binary XOR operations.
                int positiveSignals = 0;
                for (int i = 0; i < currentInstr.nArguments; i++)
                {
                    if (Evaluate(dataset, ref row, state) > 0.0)
                    {
                        positiveSignals++;
                    }
                }
                return(positiveSignals % 2 != 0 ? 1.0 : -1.0);
            }

            case OpCodes.GT: {
                double x = Evaluate(dataset, ref row, state);
                double y = Evaluate(dataset, ref row, state);
                if (x > y)
                {
                    return(1.0);
                }
                else
                {
                    return(-1.0);
                }
            }

            case OpCodes.LT: {
                double x = Evaluate(dataset, ref row, state);
                double y = Evaluate(dataset, ref row, state);
                if (x < y)
                {
                    return(1.0);
                }
                else
                {
                    return(-1.0);
                }
            }

            case OpCodes.TimeLag: {
                var timeLagTreeNode = (LaggedTreeNode)currentInstr.dynamicNode;
                row += timeLagTreeNode.Lag;
                double result = Evaluate(dataset, ref row, state);
                row -= timeLagTreeNode.Lag;
                return(result);
            }

            case OpCodes.Integral: {
                int    savedPc         = state.ProgramCounter;
                var    timeLagTreeNode = (LaggedTreeNode)currentInstr.dynamicNode;
                double sum             = 0.0;
                for (int i = 0; i < Math.Abs(timeLagTreeNode.Lag); i++)
                {
                    row += Math.Sign(timeLagTreeNode.Lag);
                    sum += Evaluate(dataset, ref row, state);
                    state.ProgramCounter = savedPc;
                }
                row -= timeLagTreeNode.Lag;
                sum += Evaluate(dataset, ref row, state);
                return(sum);
            }

            //mkommend: derivate calculation taken from:
            //http://www.holoborodko.com/pavel/numerical-methods/numerical-derivative/smooth-low-noise-differentiators/
            //one sided smooth differentiatior, N = 4
            // y' = 1/8h (f_i + 2f_i-1, -2 f_i-3 - f_i-4)
            case OpCodes.Derivative: {
                int    savedPc = state.ProgramCounter;
                double f_0     = Evaluate(dataset, ref row, state); row--;
                state.ProgramCounter = savedPc;
                double f_1 = Evaluate(dataset, ref row, state); row -= 2;
                state.ProgramCounter = savedPc;
                double f_3 = Evaluate(dataset, ref row, state); row--;
                state.ProgramCounter = savedPc;
                double f_4 = Evaluate(dataset, ref row, state);
                row += 4;

                return((f_0 + 2 * f_1 - 2 * f_3 - f_4) / 8); // h = 1
            }

            case OpCodes.Call: {
                // evaluate sub-trees
                double[] argValues = new double[currentInstr.nArguments];
                for (int i = 0; i < currentInstr.nArguments; i++)
                {
                    argValues[i] = Evaluate(dataset, ref row, state);
                }
                // push on argument values on stack
                state.CreateStackFrame(argValues);

                // save the pc
                int savedPc = state.ProgramCounter;
                // set pc to start of function
                state.ProgramCounter = (ushort)currentInstr.data;
                // evaluate the function
                double v = Evaluate(dataset, ref row, state);

                // delete the stack frame
                state.RemoveStackFrame();

                // restore the pc => evaluation will continue at point after my subtrees
                state.ProgramCounter = savedPc;
                return(v);
            }

            case OpCodes.Arg: {
                return(state.GetStackFrameValue((ushort)currentInstr.data));
            }

            case OpCodes.Variable: {
                if (row < 0 || row >= dataset.Rows)
                {
                    return(double.NaN);
                }
                var variableTreeNode = (VariableTreeNode)currentInstr.dynamicNode;
                return(((IList <double>)currentInstr.data)[row] * variableTreeNode.Weight);
            }

            case OpCodes.BinaryFactorVariable: {
                if (row < 0 || row >= dataset.Rows)
                {
                    return(double.NaN);
                }
                var factorVarTreeNode = currentInstr.dynamicNode as BinaryFactorVariableTreeNode;
                return(((IList <string>)currentInstr.data)[row] == factorVarTreeNode.VariableValue ? factorVarTreeNode.Weight : 0);
            }

            case OpCodes.FactorVariable: {
                if (row < 0 || row >= dataset.Rows)
                {
                    return(double.NaN);
                }
                var factorVarTreeNode = currentInstr.dynamicNode as FactorVariableTreeNode;
                return(factorVarTreeNode.GetValue(((IList <string>)currentInstr.data)[row]));
            }

            case OpCodes.LagVariable: {
                var laggedVariableTreeNode = (LaggedVariableTreeNode)currentInstr.dynamicNode;
                int actualRow = row + laggedVariableTreeNode.Lag;
                if (actualRow < 0 || actualRow >= dataset.Rows)
                {
                    return(double.NaN);
                }
                return(((IList <double>)currentInstr.data)[actualRow] * laggedVariableTreeNode.Weight);
            }

            case OpCodes.Constant: {
                var constTreeNode = (ConstantTreeNode)currentInstr.dynamicNode;
                return(constTreeNode.Value);
            }

            //mkommend: this symbol uses the logistic function f(x) = 1 / (1 + e^(-alpha * x) )
            //to determine the relative amounts of the true and false branch see http://en.wikipedia.org/wiki/Logistic_function
            case OpCodes.VariableCondition: {
                if (row < 0 || row >= dataset.Rows)
                {
                    return(double.NaN);
                }
                var variableConditionTreeNode = (VariableConditionTreeNode)currentInstr.dynamicNode;
                if (!variableConditionTreeNode.Symbol.IgnoreSlope)
                {
                    double variableValue = ((IList <double>)currentInstr.data)[row];
                    double x             = variableValue - variableConditionTreeNode.Threshold;
                    double p             = 1 / (1 + Math.Exp(-variableConditionTreeNode.Slope * x));

                    double trueBranch  = Evaluate(dataset, ref row, state);
                    double falseBranch = Evaluate(dataset, ref row, state);

                    return(trueBranch * p + falseBranch * (1 - p));
                }
                else
                {
                    // strict threshold
                    double variableValue = ((IList <double>)currentInstr.data)[row];
                    if (variableValue <= variableConditionTreeNode.Threshold)
                    {
                        var left = Evaluate(dataset, ref row, state);
                        state.SkipInstructions();
                        return(left);
                    }
                    else
                    {
                        state.SkipInstructions();
                        return(Evaluate(dataset, ref row, state));
                    }
                }
            }

            default:
                throw new NotSupportedException();
            }
        }
Ejemplo n.º 3
0
        private void CompileInstructions(ILGenerator il, InterpreterState state, IDataset ds)
        {
            Instruction currentInstr = state.NextInstruction();
            int         nArgs        = currentInstr.nArguments;

            switch (currentInstr.opCode)
            {
            case OpCodes.Add: {
                if (nArgs > 0)
                {
                    CompileInstructions(il, state, ds);
                }
                for (int i = 1; i < nArgs; i++)
                {
                    CompileInstructions(il, state, ds);
                    il.Emit(System.Reflection.Emit.OpCodes.Add);
                }
                return;
            }

            case OpCodes.Sub: {
                if (nArgs == 1)
                {
                    CompileInstructions(il, state, ds);
                    il.Emit(System.Reflection.Emit.OpCodes.Neg);
                    return;
                }
                if (nArgs > 0)
                {
                    CompileInstructions(il, state, ds);
                }
                for (int i = 1; i < nArgs; i++)
                {
                    CompileInstructions(il, state, ds);
                    il.Emit(System.Reflection.Emit.OpCodes.Sub);
                }
                return;
            }

            case OpCodes.Mul: {
                if (nArgs > 0)
                {
                    CompileInstructions(il, state, ds);
                }
                for (int i = 1; i < nArgs; i++)
                {
                    CompileInstructions(il, state, ds);
                    il.Emit(System.Reflection.Emit.OpCodes.Mul);
                }
                return;
            }

            case OpCodes.Div: {
                if (nArgs == 1)
                {
                    il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0);
                    CompileInstructions(il, state, ds);
                    il.Emit(System.Reflection.Emit.OpCodes.Div);
                    return;
                }
                if (nArgs > 0)
                {
                    CompileInstructions(il, state, ds);
                }
                for (int i = 1; i < nArgs; i++)
                {
                    CompileInstructions(il, state, ds);
                    il.Emit(System.Reflection.Emit.OpCodes.Div);
                }
                return;
            }

            case OpCodes.Average: {
                CompileInstructions(il, state, ds);
                for (int i = 1; i < nArgs; i++)
                {
                    CompileInstructions(il, state, ds);
                    il.Emit(System.Reflection.Emit.OpCodes.Add);
                }
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, nArgs);
                il.Emit(System.Reflection.Emit.OpCodes.Div);
                return;
            }

            case OpCodes.Cos: {
                CompileInstructions(il, state, ds);
                il.Emit(System.Reflection.Emit.OpCodes.Call, cos);
                return;
            }

            case OpCodes.Sin: {
                CompileInstructions(il, state, ds);
                il.Emit(System.Reflection.Emit.OpCodes.Call, sin);
                return;
            }

            case OpCodes.Tan: {
                CompileInstructions(il, state, ds);
                il.Emit(System.Reflection.Emit.OpCodes.Call, tan);
                return;
            }

            case OpCodes.Power: {
                CompileInstructions(il, state, ds);
                CompileInstructions(il, state, ds);
                il.Emit(System.Reflection.Emit.OpCodes.Call, round);
                il.Emit(System.Reflection.Emit.OpCodes.Call, power);
                return;
            }

            case OpCodes.Root: {
                CompileInstructions(il, state, ds);
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // 1 / round(...)
                CompileInstructions(il, state, ds);
                il.Emit(System.Reflection.Emit.OpCodes.Call, round);
                il.Emit(System.Reflection.Emit.OpCodes.Div);
                il.Emit(System.Reflection.Emit.OpCodes.Call, power);
                return;
            }

            case OpCodes.Exp: {
                CompileInstructions(il, state, ds);
                il.Emit(System.Reflection.Emit.OpCodes.Call, exp);
                return;
            }

            case OpCodes.Log: {
                CompileInstructions(il, state, ds);
                il.Emit(System.Reflection.Emit.OpCodes.Call, log);
                return;
            }

            case OpCodes.Square: {
                CompileInstructions(il, state, ds);
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0);
                il.Emit(System.Reflection.Emit.OpCodes.Call, power);
                return;
            }

            case OpCodes.SquareRoot: {
                CompileInstructions(il, state, ds);
                il.Emit(System.Reflection.Emit.OpCodes.Call, sqrt);
                return;
            }

            case OpCodes.AiryA: {
                CompileInstructions(il, state, ds);
                il.Emit(System.Reflection.Emit.OpCodes.Call, airyA);
                return;
            }

            case OpCodes.AiryB: {
                CompileInstructions(il, state, ds);
                il.Emit(System.Reflection.Emit.OpCodes.Call, airyB);
                return;
            }

            case OpCodes.Bessel: {
                CompileInstructions(il, state, ds);
                il.Emit(System.Reflection.Emit.OpCodes.Call, bessel);
                return;
            }

            case OpCodes.CosineIntegral: {
                CompileInstructions(il, state, ds);
                il.Emit(System.Reflection.Emit.OpCodes.Call, cosIntegral);
                return;
            }

            case OpCodes.Dawson: {
                CompileInstructions(il, state, ds);
                il.Emit(System.Reflection.Emit.OpCodes.Call, dawson);
                return;
            }

            case OpCodes.Erf: {
                CompileInstructions(il, state, ds);
                il.Emit(System.Reflection.Emit.OpCodes.Call, erf);
                return;
            }

            case OpCodes.ExponentialIntegralEi: {
                CompileInstructions(il, state, ds);
                il.Emit(System.Reflection.Emit.OpCodes.Call, expIntegralEi);
                return;
            }

            case OpCodes.FresnelCosineIntegral: {
                CompileInstructions(il, state, ds);
                il.Emit(System.Reflection.Emit.OpCodes.Call, fresnelCosIntegral);
                return;
            }

            case OpCodes.FresnelSineIntegral: {
                CompileInstructions(il, state, ds);
                il.Emit(System.Reflection.Emit.OpCodes.Call, fresnelSinIntegral);
                return;
            }

            case OpCodes.Gamma: {
                CompileInstructions(il, state, ds);
                il.Emit(System.Reflection.Emit.OpCodes.Call, gamma);
                return;
            }

            case OpCodes.HyperbolicCosineIntegral: {
                CompileInstructions(il, state, ds);
                il.Emit(System.Reflection.Emit.OpCodes.Call, hypCosIntegral);
                return;
            }

            case OpCodes.HyperbolicSineIntegral: {
                CompileInstructions(il, state, ds);
                il.Emit(System.Reflection.Emit.OpCodes.Call, hypSinIntegral);
                return;
            }

            case OpCodes.Norm: {
                CompileInstructions(il, state, ds);
                il.Emit(System.Reflection.Emit.OpCodes.Call, norm);
                return;
            }

            case OpCodes.Psi: {
                CompileInstructions(il, state, ds);
                il.Emit(System.Reflection.Emit.OpCodes.Call, psi);
                return;
            }

            case OpCodes.SineIntegral: {
                CompileInstructions(il, state, ds);
                il.Emit(System.Reflection.Emit.OpCodes.Call, sinIntegral);
                return;
            }

            case OpCodes.IfThenElse: {
                Label end = il.DefineLabel();
                Label c1  = il.DefineLabel();
                CompileInstructions(il, state, ds);
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // > 0
                il.Emit(System.Reflection.Emit.OpCodes.Cgt);
                il.Emit(System.Reflection.Emit.OpCodes.Brfalse, c1);
                CompileInstructions(il, state, ds);
                il.Emit(System.Reflection.Emit.OpCodes.Br, end);
                il.MarkLabel(c1);
                CompileInstructions(il, state, ds);
                il.MarkLabel(end);
                return;
            }

            case OpCodes.AND: {
                Label falseBranch = il.DefineLabel();
                Label end         = il.DefineLabel();
                CompileInstructions(il, state, ds);
                for (int i = 1; i < nArgs; i++)
                {
                    il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // > 0
                    il.Emit(System.Reflection.Emit.OpCodes.Cgt);
                    il.Emit(System.Reflection.Emit.OpCodes.Brfalse, falseBranch);
                    CompileInstructions(il, state, ds);
                }
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // > 0
                il.Emit(System.Reflection.Emit.OpCodes.Cgt);
                il.Emit(System.Reflection.Emit.OpCodes.Brfalse, falseBranch);
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // 1
                il.Emit(System.Reflection.Emit.OpCodes.Br, end);
                il.MarkLabel(falseBranch);
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // -1
                il.Emit(System.Reflection.Emit.OpCodes.Neg);
                il.MarkLabel(end);
                return;
            }

            case OpCodes.OR: {
                Label trueBranch   = il.DefineLabel();
                Label end          = il.DefineLabel();
                Label resultBranch = il.DefineLabel();
                CompileInstructions(il, state, ds);
                for (int i = 1; i < nArgs; i++)
                {
                    Label nextArgBranch = il.DefineLabel();
                    // complex definition because of special properties of NaN
                    il.Emit(System.Reflection.Emit.OpCodes.Dup);
                    il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // <= 0
                    il.Emit(System.Reflection.Emit.OpCodes.Ble, nextArgBranch);
                    il.Emit(System.Reflection.Emit.OpCodes.Br, resultBranch);
                    il.MarkLabel(nextArgBranch);
                    il.Emit(System.Reflection.Emit.OpCodes.Pop);
                    CompileInstructions(il, state, ds);
                }
                il.MarkLabel(resultBranch);
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // > 0
                il.Emit(System.Reflection.Emit.OpCodes.Cgt);
                il.Emit(System.Reflection.Emit.OpCodes.Brtrue, trueBranch);
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // -1
                il.Emit(System.Reflection.Emit.OpCodes.Neg);
                il.Emit(System.Reflection.Emit.OpCodes.Br, end);
                il.MarkLabel(trueBranch);
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // 1
                il.MarkLabel(end);
                return;
            }

            case OpCodes.NOT: {
                CompileInstructions(il, state, ds);
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0);    // > 0
                il.Emit(System.Reflection.Emit.OpCodes.Cgt);
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0); // * 2
                il.Emit(System.Reflection.Emit.OpCodes.Mul);
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // - 1
                il.Emit(System.Reflection.Emit.OpCodes.Sub);
                il.Emit(System.Reflection.Emit.OpCodes.Neg);         // * -1
                return;
            }

            case OpCodes.XOR: {
                CompileInstructions(il, state, ds);
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0);
                il.Emit(System.Reflection.Emit.OpCodes.Cgt);// > 0

                for (int i = 1; i < nArgs; i++)
                {
                    CompileInstructions(il, state, ds);
                    il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0);
                    il.Emit(System.Reflection.Emit.OpCodes.Cgt);// > 0
                    il.Emit(System.Reflection.Emit.OpCodes.Xor);
                }
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0); // * 2
                il.Emit(System.Reflection.Emit.OpCodes.Mul);
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // - 1
                il.Emit(System.Reflection.Emit.OpCodes.Sub);
                return;
            }

            case OpCodes.GT: {
                CompileInstructions(il, state, ds);
                CompileInstructions(il, state, ds);

                il.Emit(System.Reflection.Emit.OpCodes.Cgt);         // 1 (>) / 0 (otherwise)
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0); // * 2
                il.Emit(System.Reflection.Emit.OpCodes.Mul);
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // - 1
                il.Emit(System.Reflection.Emit.OpCodes.Sub);
                return;
            }

            case OpCodes.LT: {
                CompileInstructions(il, state, ds);
                CompileInstructions(il, state, ds);
                il.Emit(System.Reflection.Emit.OpCodes.Clt);
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0); // * 2
                il.Emit(System.Reflection.Emit.OpCodes.Mul);
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // - 1
                il.Emit(System.Reflection.Emit.OpCodes.Sub);
                return;
            }

            case OpCodes.TimeLag: {
                LaggedTreeNode laggedTreeNode = (LaggedTreeNode)currentInstr.dynamicNode;
                il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row -= lag
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, laggedTreeNode.Lag);
                il.Emit(System.Reflection.Emit.OpCodes.Add);
                il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
                var prevLaggedContext = state.InLaggedContext;
                state.InLaggedContext = true;
                CompileInstructions(il, state, ds);
                il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row += lag
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, laggedTreeNode.Lag);
                il.Emit(System.Reflection.Emit.OpCodes.Sub);
                il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
                state.InLaggedContext = prevLaggedContext;
                return;
            }

            case OpCodes.Integral: {
                int            savedPc        = state.ProgramCounter;
                LaggedTreeNode laggedTreeNode = (LaggedTreeNode)currentInstr.dynamicNode;
                il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row -= lag
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, laggedTreeNode.Lag);
                il.Emit(System.Reflection.Emit.OpCodes.Add);
                il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
                var prevLaggedContext = state.InLaggedContext;
                state.InLaggedContext = true;
                CompileInstructions(il, state, ds);
                for (int l = laggedTreeNode.Lag; l < 0; l++)
                {
                    il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row += lag
                    il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_1);
                    il.Emit(System.Reflection.Emit.OpCodes.Add);
                    il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
                    state.ProgramCounter = savedPc;
                    CompileInstructions(il, state, ds);
                    il.Emit(System.Reflection.Emit.OpCodes.Add);
                }
                state.InLaggedContext = prevLaggedContext;
                return;
            }

            //mkommend: derivate calculation taken from:
            //http://www.holoborodko.com/pavel/numerical-methods/numerical-derivative/smooth-low-noise-differentiators/
            //one sided smooth differentiatior, N = 4
            // y' = 1/8h (f_i + 2f_i-1, -2 f_i-3 - f_i-4)
            case OpCodes.Derivative: {
                int savedPc = state.ProgramCounter;
                CompileInstructions(il, state, ds);
                il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row --
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_M1);
                il.Emit(System.Reflection.Emit.OpCodes.Add);
                il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
                state.ProgramCounter = savedPc;
                var prevLaggedContext = state.InLaggedContext;
                state.InLaggedContext = true;
                CompileInstructions(il, state, ds);
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0); // f_0 + 2 * f_1
                il.Emit(System.Reflection.Emit.OpCodes.Mul);
                il.Emit(System.Reflection.Emit.OpCodes.Add);

                il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row -=2
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_2);
                il.Emit(System.Reflection.Emit.OpCodes.Sub);
                il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
                state.ProgramCounter = savedPc;
                CompileInstructions(il, state, ds);
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0); // f_0 + 2 * f_1 - 2 * f_3
                il.Emit(System.Reflection.Emit.OpCodes.Mul);
                il.Emit(System.Reflection.Emit.OpCodes.Sub);

                il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row --
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_M1);
                il.Emit(System.Reflection.Emit.OpCodes.Add);
                il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
                state.ProgramCounter = savedPc;
                CompileInstructions(il, state, ds);
                il.Emit(System.Reflection.Emit.OpCodes.Sub);         // f_0 + 2 * f_1 - 2 * f_3 - f_4
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 8.0); // / 8
                il.Emit(System.Reflection.Emit.OpCodes.Div);

                il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row +=4
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_4);
                il.Emit(System.Reflection.Emit.OpCodes.Add);
                il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
                state.InLaggedContext = prevLaggedContext;
                return;
            }

            case OpCodes.Call: {
                throw new NotSupportedException(
                          "Automatically defined functions are not supported by the SymbolicDataAnalysisTreeILEmittingInterpreter. Either turn of ADFs or change the interpeter.");
            }

            case OpCodes.Arg: {
                throw new NotSupportedException(
                          "Automatically defined functions are not supported by the SymbolicDataAnalysisTreeILEmittingInterpreter. Either turn of ADFs or change the interpeter.");
            }

            case OpCodes.Variable: {
                VariableTreeNode varNode = (VariableTreeNode)currentInstr.dynamicNode;
                il.Emit(System.Reflection.Emit.OpCodes.Ldarg_1); // load columns array
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, (int)currentInstr.data);
                // load correct column of the current variable
                il.Emit(System.Reflection.Emit.OpCodes.Ldelem_Ref);
                il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // rowIndex
                if (!state.InLaggedContext)
                {
                    il.Emit(System.Reflection.Emit.OpCodes.Call, listGetValue);
                    il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, varNode.Weight); // load weight
                    il.Emit(System.Reflection.Emit.OpCodes.Mul);
                }
                else
                {
                    var nanResult    = il.DefineLabel();
                    var normalResult = il.DefineLabel();
                    il.Emit(System.Reflection.Emit.OpCodes.Dup);
                    il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0);
                    il.Emit(System.Reflection.Emit.OpCodes.Blt, nanResult);
                    il.Emit(System.Reflection.Emit.OpCodes.Dup);
                    il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, ds.Rows);
                    il.Emit(System.Reflection.Emit.OpCodes.Bge, nanResult);
                    il.Emit(System.Reflection.Emit.OpCodes.Call, listGetValue);
                    il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, varNode.Weight); // load weight
                    il.Emit(System.Reflection.Emit.OpCodes.Mul);
                    il.Emit(System.Reflection.Emit.OpCodes.Br, normalResult);
                    il.MarkLabel(nanResult);
                    il.Emit(System.Reflection.Emit.OpCodes.Pop); // rowIndex
                    il.Emit(System.Reflection.Emit.OpCodes.Pop); // column reference
                    il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, double.NaN);
                    il.MarkLabel(normalResult);
                }
                return;
            }

            case OpCodes.LagVariable: {
                var nanResult    = il.DefineLabel();
                var normalResult = il.DefineLabel();
                LaggedVariableTreeNode varNode = (LaggedVariableTreeNode)currentInstr.dynamicNode;
                il.Emit(System.Reflection.Emit.OpCodes.Ldarg_1); // load columns array
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, (int)currentInstr.data);
                // load correct column of the current variable
                il.Emit(System.Reflection.Emit.OpCodes.Ldelem_Ref);
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, varNode.Lag); // lag
                il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0);             // rowIndex
                il.Emit(System.Reflection.Emit.OpCodes.Add);                 // actualRowIndex = rowIndex + sampleOffset
                il.Emit(System.Reflection.Emit.OpCodes.Dup);
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0);
                il.Emit(System.Reflection.Emit.OpCodes.Blt, nanResult);
                il.Emit(System.Reflection.Emit.OpCodes.Dup);
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, ds.Rows);
                il.Emit(System.Reflection.Emit.OpCodes.Bge, nanResult);
                il.Emit(System.Reflection.Emit.OpCodes.Call, listGetValue);
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, varNode.Weight); // load weight
                il.Emit(System.Reflection.Emit.OpCodes.Mul);
                il.Emit(System.Reflection.Emit.OpCodes.Br, normalResult);
                il.MarkLabel(nanResult);
                il.Emit(System.Reflection.Emit.OpCodes.Pop); // sample index
                il.Emit(System.Reflection.Emit.OpCodes.Pop); // column reference
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, double.NaN);
                il.MarkLabel(normalResult);
                return;
            }

            case OpCodes.Constant: {
                ConstantTreeNode constNode = (ConstantTreeNode)currentInstr.dynamicNode;
                il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, constNode.Value);
                return;
            }

            //mkommend: this symbol uses the logistic function f(x) = 1 / (1 + e^(-alpha * x) )
            //to determine the relative amounts of the true and false branch see http://en.wikipedia.org/wiki/Logistic_function
            case OpCodes.VariableCondition: {
                throw new NotSupportedException("Interpretation of symbol " + currentInstr.dynamicNode.Symbol.Name +
                                                " is not supported by the SymbolicDataAnalysisTreeILEmittingInterpreter");
            }

            default:
                throw new NotSupportedException("Interpretation of symbol " + currentInstr.dynamicNode.Symbol.Name +
                                                " is not supported by the SymbolicDataAnalysisTreeILEmittingInterpreter");
            }
        }
    private void CompileInstructions(ILGenerator il, InterpreterState state, IDataset ds) {
      Instruction currentInstr = state.NextInstruction();
      int nArgs = currentInstr.nArguments;

      switch (currentInstr.opCode) {
        case OpCodes.Add: {
            if (nArgs > 0) {
              CompileInstructions(il, state, ds);
            }
            for (int i = 1; i < nArgs; i++) {
              CompileInstructions(il, state, ds);
              il.Emit(System.Reflection.Emit.OpCodes.Add);
            }
            return;
          }
        case OpCodes.Sub: {
            if (nArgs == 1) {
              CompileInstructions(il, state, ds);
              il.Emit(System.Reflection.Emit.OpCodes.Neg);
              return;
            }
            if (nArgs > 0) {
              CompileInstructions(il, state, ds);
            }
            for (int i = 1; i < nArgs; i++) {
              CompileInstructions(il, state, ds);
              il.Emit(System.Reflection.Emit.OpCodes.Sub);
            }
            return;
          }
        case OpCodes.Mul: {
            if (nArgs > 0) {
              CompileInstructions(il, state, ds);
            }
            for (int i = 1; i < nArgs; i++) {
              CompileInstructions(il, state, ds);
              il.Emit(System.Reflection.Emit.OpCodes.Mul);
            }
            return;
          }
        case OpCodes.Div: {
            if (nArgs == 1) {
              il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0);
              CompileInstructions(il, state, ds);
              il.Emit(System.Reflection.Emit.OpCodes.Div);
              return;
            }
            if (nArgs > 0) {
              CompileInstructions(il, state, ds);
            }
            for (int i = 1; i < nArgs; i++) {
              CompileInstructions(il, state, ds);
              il.Emit(System.Reflection.Emit.OpCodes.Div);
            }
            return;
          }
        case OpCodes.Average: {
            CompileInstructions(il, state, ds);
            for (int i = 1; i < nArgs; i++) {
              CompileInstructions(il, state, ds);
              il.Emit(System.Reflection.Emit.OpCodes.Add);
            }
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, nArgs);
            il.Emit(System.Reflection.Emit.OpCodes.Div);
            return;
          }
        case OpCodes.Cos: {
            CompileInstructions(il, state, ds);
            il.Emit(System.Reflection.Emit.OpCodes.Call, cos);
            return;
          }
        case OpCodes.Sin: {
            CompileInstructions(il, state, ds);
            il.Emit(System.Reflection.Emit.OpCodes.Call, sin);
            return;
          }
        case OpCodes.Tan: {
            CompileInstructions(il, state, ds);
            il.Emit(System.Reflection.Emit.OpCodes.Call, tan);
            return;
          }
        case OpCodes.Power: {
            CompileInstructions(il, state, ds);
            CompileInstructions(il, state, ds);
            il.Emit(System.Reflection.Emit.OpCodes.Call, round);
            il.Emit(System.Reflection.Emit.OpCodes.Call, power);
            return;
          }
        case OpCodes.Root: {
            CompileInstructions(il, state, ds);
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // 1 / round(...)
            CompileInstructions(il, state, ds);
            il.Emit(System.Reflection.Emit.OpCodes.Call, round);
            il.Emit(System.Reflection.Emit.OpCodes.Div);
            il.Emit(System.Reflection.Emit.OpCodes.Call, power);
            return;
          }
        case OpCodes.Exp: {
            CompileInstructions(il, state, ds);
            il.Emit(System.Reflection.Emit.OpCodes.Call, exp);
            return;
          }
        case OpCodes.Log: {
            CompileInstructions(il, state, ds);
            il.Emit(System.Reflection.Emit.OpCodes.Call, log);
            return;
          }
        case OpCodes.Square: {
            CompileInstructions(il, state, ds);
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0);
            il.Emit(System.Reflection.Emit.OpCodes.Call, power);
            return;
          }
        case OpCodes.SquareRoot: {
            CompileInstructions(il, state, ds);
            il.Emit(System.Reflection.Emit.OpCodes.Call, sqrt);
            return;
          }
        case OpCodes.AiryA: {
            CompileInstructions(il, state, ds);
            il.Emit(System.Reflection.Emit.OpCodes.Call, airyA);
            return;
          }
        case OpCodes.AiryB: {
            CompileInstructions(il, state, ds);
            il.Emit(System.Reflection.Emit.OpCodes.Call, airyB);
            return;
          }
        case OpCodes.Bessel: {
            CompileInstructions(il, state, ds);
            il.Emit(System.Reflection.Emit.OpCodes.Call, bessel);
            return;
          }
        case OpCodes.CosineIntegral: {
            CompileInstructions(il, state, ds);
            il.Emit(System.Reflection.Emit.OpCodes.Call, cosIntegral);
            return;
          }
        case OpCodes.Dawson: {
            CompileInstructions(il, state, ds);
            il.Emit(System.Reflection.Emit.OpCodes.Call, dawson);
            return;
          }
        case OpCodes.Erf: {
            CompileInstructions(il, state, ds);
            il.Emit(System.Reflection.Emit.OpCodes.Call, erf);
            return;
          }
        case OpCodes.ExponentialIntegralEi: {
            CompileInstructions(il, state, ds);
            il.Emit(System.Reflection.Emit.OpCodes.Call, expIntegralEi);
            return;
          }
        case OpCodes.FresnelCosineIntegral: {
            CompileInstructions(il, state, ds);
            il.Emit(System.Reflection.Emit.OpCodes.Call, fresnelCosIntegral);
            return;
          }
        case OpCodes.FresnelSineIntegral: {
            CompileInstructions(il, state, ds);
            il.Emit(System.Reflection.Emit.OpCodes.Call, fresnelSinIntegral);
            return;
          }
        case OpCodes.Gamma: {
            CompileInstructions(il, state, ds);
            il.Emit(System.Reflection.Emit.OpCodes.Call, gamma);
            return;
          }
        case OpCodes.HyperbolicCosineIntegral: {
            CompileInstructions(il, state, ds);
            il.Emit(System.Reflection.Emit.OpCodes.Call, hypCosIntegral);
            return;
          }
        case OpCodes.HyperbolicSineIntegral: {
            CompileInstructions(il, state, ds);
            il.Emit(System.Reflection.Emit.OpCodes.Call, hypSinIntegral);
            return;
          }
        case OpCodes.Norm: {
            CompileInstructions(il, state, ds);
            il.Emit(System.Reflection.Emit.OpCodes.Call, norm);
            return;
          }
        case OpCodes.Psi: {
            CompileInstructions(il, state, ds);
            il.Emit(System.Reflection.Emit.OpCodes.Call, psi);
            return;
          }
        case OpCodes.SineIntegral: {
            CompileInstructions(il, state, ds);
            il.Emit(System.Reflection.Emit.OpCodes.Call, sinIntegral);
            return;
          }
        case OpCodes.IfThenElse: {
            Label end = il.DefineLabel();
            Label c1 = il.DefineLabel();
            CompileInstructions(il, state, ds);
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // > 0
            il.Emit(System.Reflection.Emit.OpCodes.Cgt);
            il.Emit(System.Reflection.Emit.OpCodes.Brfalse, c1);
            CompileInstructions(il, state, ds);
            il.Emit(System.Reflection.Emit.OpCodes.Br, end);
            il.MarkLabel(c1);
            CompileInstructions(il, state, ds);
            il.MarkLabel(end);
            return;
          }
        case OpCodes.AND: {
            Label falseBranch = il.DefineLabel();
            Label end = il.DefineLabel();
            CompileInstructions(il, state, ds);
            for (int i = 1; i < nArgs; i++) {
              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // > 0
              il.Emit(System.Reflection.Emit.OpCodes.Cgt);
              il.Emit(System.Reflection.Emit.OpCodes.Brfalse, falseBranch);
              CompileInstructions(il, state, ds);
            }
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // > 0
            il.Emit(System.Reflection.Emit.OpCodes.Cgt);
            il.Emit(System.Reflection.Emit.OpCodes.Brfalse, falseBranch);
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // 1
            il.Emit(System.Reflection.Emit.OpCodes.Br, end);
            il.MarkLabel(falseBranch);
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // -1
            il.Emit(System.Reflection.Emit.OpCodes.Neg);
            il.MarkLabel(end);
            return;
          }
        case OpCodes.OR: {
            Label trueBranch = il.DefineLabel();
            Label end = il.DefineLabel();
            Label resultBranch = il.DefineLabel();
            CompileInstructions(il, state, ds);
            for (int i = 1; i < nArgs; i++) {
              Label nextArgBranch = il.DefineLabel();
              // complex definition because of special properties of NaN  
              il.Emit(System.Reflection.Emit.OpCodes.Dup);
              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // <= 0        
              il.Emit(System.Reflection.Emit.OpCodes.Ble, nextArgBranch);
              il.Emit(System.Reflection.Emit.OpCodes.Br, resultBranch);
              il.MarkLabel(nextArgBranch);
              il.Emit(System.Reflection.Emit.OpCodes.Pop);
              CompileInstructions(il, state, ds);
            }
            il.MarkLabel(resultBranch);
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // > 0
            il.Emit(System.Reflection.Emit.OpCodes.Cgt);
            il.Emit(System.Reflection.Emit.OpCodes.Brtrue, trueBranch);
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // -1
            il.Emit(System.Reflection.Emit.OpCodes.Neg);
            il.Emit(System.Reflection.Emit.OpCodes.Br, end);
            il.MarkLabel(trueBranch);
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // 1
            il.MarkLabel(end);
            return;
          }
        case OpCodes.NOT: {
            CompileInstructions(il, state, ds);
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0); // > 0
            il.Emit(System.Reflection.Emit.OpCodes.Cgt);
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0); // * 2
            il.Emit(System.Reflection.Emit.OpCodes.Mul);
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // - 1
            il.Emit(System.Reflection.Emit.OpCodes.Sub);
            il.Emit(System.Reflection.Emit.OpCodes.Neg); // * -1
            return;
          }
        case OpCodes.XOR: {
            CompileInstructions(il, state, ds);
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0);
            il.Emit(System.Reflection.Emit.OpCodes.Cgt);// > 0

            for (int i = 1; i < nArgs; i++) {
              CompileInstructions(il, state, ds);
              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0);
              il.Emit(System.Reflection.Emit.OpCodes.Cgt);// > 0
              il.Emit(System.Reflection.Emit.OpCodes.Xor);
            }
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0); // * 2
            il.Emit(System.Reflection.Emit.OpCodes.Mul);
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // - 1
            il.Emit(System.Reflection.Emit.OpCodes.Sub);
            return;
          }
        case OpCodes.GT: {
            CompileInstructions(il, state, ds);
            CompileInstructions(il, state, ds);

            il.Emit(System.Reflection.Emit.OpCodes.Cgt); // 1 (>) / 0 (otherwise)
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0); // * 2
            il.Emit(System.Reflection.Emit.OpCodes.Mul);
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // - 1
            il.Emit(System.Reflection.Emit.OpCodes.Sub);
            return;
          }
        case OpCodes.LT: {
            CompileInstructions(il, state, ds);
            CompileInstructions(il, state, ds);
            il.Emit(System.Reflection.Emit.OpCodes.Clt);
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0); // * 2
            il.Emit(System.Reflection.Emit.OpCodes.Mul);
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0); // - 1
            il.Emit(System.Reflection.Emit.OpCodes.Sub);
            return;
          }
        case OpCodes.TimeLag: {
            LaggedTreeNode laggedTreeNode = (LaggedTreeNode)currentInstr.dynamicNode;
            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row -= lag
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, laggedTreeNode.Lag);
            il.Emit(System.Reflection.Emit.OpCodes.Add);
            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
            var prevLaggedContext = state.InLaggedContext;
            state.InLaggedContext = true;
            CompileInstructions(il, state, ds);
            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row += lag
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, laggedTreeNode.Lag);
            il.Emit(System.Reflection.Emit.OpCodes.Sub);
            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
            state.InLaggedContext = prevLaggedContext;
            return;
          }
        case OpCodes.Integral: {
            int savedPc = state.ProgramCounter;
            LaggedTreeNode laggedTreeNode = (LaggedTreeNode)currentInstr.dynamicNode;
            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row -= lag
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, laggedTreeNode.Lag);
            il.Emit(System.Reflection.Emit.OpCodes.Add);
            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
            var prevLaggedContext = state.InLaggedContext;
            state.InLaggedContext = true;
            CompileInstructions(il, state, ds);
            for (int l = laggedTreeNode.Lag; l < 0; l++) {
              il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row += lag
              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_1);
              il.Emit(System.Reflection.Emit.OpCodes.Add);
              il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
              state.ProgramCounter = savedPc;
              CompileInstructions(il, state, ds);
              il.Emit(System.Reflection.Emit.OpCodes.Add);
            }
            state.InLaggedContext = prevLaggedContext;
            return;
          }

        //mkommend: derivate calculation taken from: 
        //http://www.holoborodko.com/pavel/numerical-methods/numerical-derivative/smooth-low-noise-differentiators/
        //one sided smooth differentiatior, N = 4
        // y' = 1/8h (f_i + 2f_i-1, -2 f_i-3 - f_i-4)
        case OpCodes.Derivative: {
            int savedPc = state.ProgramCounter;
            CompileInstructions(il, state, ds);
            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row --
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_M1);
            il.Emit(System.Reflection.Emit.OpCodes.Add);
            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
            state.ProgramCounter = savedPc;
            var prevLaggedContext = state.InLaggedContext;
            state.InLaggedContext = true;
            CompileInstructions(il, state, ds);
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0); // f_0 + 2 * f_1
            il.Emit(System.Reflection.Emit.OpCodes.Mul);
            il.Emit(System.Reflection.Emit.OpCodes.Add);

            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row -=2
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_2);
            il.Emit(System.Reflection.Emit.OpCodes.Sub);
            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
            state.ProgramCounter = savedPc;
            CompileInstructions(il, state, ds);
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 2.0); // f_0 + 2 * f_1 - 2 * f_3
            il.Emit(System.Reflection.Emit.OpCodes.Mul);
            il.Emit(System.Reflection.Emit.OpCodes.Sub);

            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row --
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_M1);
            il.Emit(System.Reflection.Emit.OpCodes.Add);
            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
            state.ProgramCounter = savedPc;
            CompileInstructions(il, state, ds);
            il.Emit(System.Reflection.Emit.OpCodes.Sub); // f_0 + 2 * f_1 - 2 * f_3 - f_4
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 8.0); // / 8
            il.Emit(System.Reflection.Emit.OpCodes.Div);

            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // row +=4
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_4);
            il.Emit(System.Reflection.Emit.OpCodes.Add);
            il.Emit(System.Reflection.Emit.OpCodes.Starg, 0);
            state.InLaggedContext = prevLaggedContext;
            return;
          }
        case OpCodes.Call: {
            throw new NotSupportedException(
              "Automatically defined functions are not supported by the SymbolicDataAnalysisTreeILEmittingInterpreter. Either turn of ADFs or change the interpeter.");
          }
        case OpCodes.Arg: {
            throw new NotSupportedException(
              "Automatically defined functions are not supported by the SymbolicDataAnalysisTreeILEmittingInterpreter. Either turn of ADFs or change the interpeter.");
          }
        case OpCodes.Variable: {
            VariableTreeNode varNode = (VariableTreeNode)currentInstr.dynamicNode;
            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_1); // load columns array
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, (int)currentInstr.data);
            // load correct column of the current variable
            il.Emit(System.Reflection.Emit.OpCodes.Ldelem_Ref);
            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // rowIndex
            if (!state.InLaggedContext) {
              il.Emit(System.Reflection.Emit.OpCodes.Call, listGetValue);
              il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, varNode.Weight); // load weight
              il.Emit(System.Reflection.Emit.OpCodes.Mul);
            } else {
              var nanResult = il.DefineLabel();
              var normalResult = il.DefineLabel();
              il.Emit(System.Reflection.Emit.OpCodes.Dup);
              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0);
              il.Emit(System.Reflection.Emit.OpCodes.Blt, nanResult);
              il.Emit(System.Reflection.Emit.OpCodes.Dup);
              il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, ds.Rows);
              il.Emit(System.Reflection.Emit.OpCodes.Bge, nanResult);
              il.Emit(System.Reflection.Emit.OpCodes.Call, listGetValue);
              il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, varNode.Weight); // load weight
              il.Emit(System.Reflection.Emit.OpCodes.Mul);
              il.Emit(System.Reflection.Emit.OpCodes.Br, normalResult);
              il.MarkLabel(nanResult);
              il.Emit(System.Reflection.Emit.OpCodes.Pop); // rowIndex
              il.Emit(System.Reflection.Emit.OpCodes.Pop); // column reference
              il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, double.NaN);
              il.MarkLabel(normalResult);
            }
            return;
          }
        case OpCodes.LagVariable: {
            var nanResult = il.DefineLabel();
            var normalResult = il.DefineLabel();
            LaggedVariableTreeNode varNode = (LaggedVariableTreeNode)currentInstr.dynamicNode;
            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_1); // load columns array
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, (int)currentInstr.data);
            // load correct column of the current variable
            il.Emit(System.Reflection.Emit.OpCodes.Ldelem_Ref);
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, varNode.Lag); // lag
            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); // rowIndex
            il.Emit(System.Reflection.Emit.OpCodes.Add); // actualRowIndex = rowIndex + sampleOffset
            il.Emit(System.Reflection.Emit.OpCodes.Dup);
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4_0);
            il.Emit(System.Reflection.Emit.OpCodes.Blt, nanResult);
            il.Emit(System.Reflection.Emit.OpCodes.Dup);
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, ds.Rows);
            il.Emit(System.Reflection.Emit.OpCodes.Bge, nanResult);
            il.Emit(System.Reflection.Emit.OpCodes.Call, listGetValue);
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, varNode.Weight); // load weight
            il.Emit(System.Reflection.Emit.OpCodes.Mul);
            il.Emit(System.Reflection.Emit.OpCodes.Br, normalResult);
            il.MarkLabel(nanResult);
            il.Emit(System.Reflection.Emit.OpCodes.Pop); // sample index
            il.Emit(System.Reflection.Emit.OpCodes.Pop); // column reference
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, double.NaN);
            il.MarkLabel(normalResult);
            return;
          }
        case OpCodes.Constant: {
            ConstantTreeNode constNode = (ConstantTreeNode)currentInstr.dynamicNode;
            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, constNode.Value);
            return;
          }

        //mkommend: this symbol uses the logistic function f(x) = 1 / (1 + e^(-alpha * x) ) 
        //to determine the relative amounts of the true and false branch see http://en.wikipedia.org/wiki/Logistic_function
        case OpCodes.VariableCondition: {
            throw new NotSupportedException("Interpretation of symbol " + currentInstr.dynamicNode.Symbol.Name +
                                            " is not supported by the SymbolicDataAnalysisTreeILEmittingInterpreter");
          }
        default:
          throw new NotSupportedException("Interpretation of symbol " + currentInstr.dynamicNode.Symbol.Name +
                                          " is not supported by the SymbolicDataAnalysisTreeILEmittingInterpreter");
      }
    }
    public virtual double Evaluate(IDataset dataset, ref int row, InterpreterState state) {
      Instruction currentInstr = state.NextInstruction();
      switch (currentInstr.opCode) {
        case OpCodes.Add: {
            double s = Evaluate(dataset, ref row, state);
            for (int i = 1; i < currentInstr.nArguments; i++) {
              s += Evaluate(dataset, ref row, state);
            }
            return s;
          }
        case OpCodes.Sub: {
            double s = Evaluate(dataset, ref row, state);
            for (int i = 1; i < currentInstr.nArguments; i++) {
              s -= Evaluate(dataset, ref row, state);
            }
            if (currentInstr.nArguments == 1) s = -s;
            return s;
          }
        case OpCodes.Mul: {
            double p = Evaluate(dataset, ref row, state);
            for (int i = 1; i < currentInstr.nArguments; i++) {
              p *= Evaluate(dataset, ref row, state);
            }
            return p;
          }
        case OpCodes.Div: {
            double p = Evaluate(dataset, ref row, state);
            for (int i = 1; i < currentInstr.nArguments; i++) {
              p /= Evaluate(dataset, ref row, state);
            }
            if (currentInstr.nArguments == 1) p = 1.0 / p;
            return p;
          }
        case OpCodes.Average: {
            double sum = Evaluate(dataset, ref row, state);
            for (int i = 1; i < currentInstr.nArguments; i++) {
              sum += Evaluate(dataset, ref row, state);
            }
            return sum / currentInstr.nArguments;
          }
        case OpCodes.Cos: {
            return Math.Cos(Evaluate(dataset, ref row, state));
          }
        case OpCodes.Sin: {
            return Math.Sin(Evaluate(dataset, ref row, state));
          }
        case OpCodes.Tan: {
            return Math.Tan(Evaluate(dataset, ref row, state));
          }
        case OpCodes.Square: {
            return Math.Pow(Evaluate(dataset, ref row, state), 2);
          }
        case OpCodes.Power: {
            double x = Evaluate(dataset, ref row, state);
            double y = Math.Round(Evaluate(dataset, ref row, state));
            return Math.Pow(x, y);
          }
        case OpCodes.SquareRoot: {
            return Math.Sqrt(Evaluate(dataset, ref row, state));
          }
        case OpCodes.Root: {
            double x = Evaluate(dataset, ref row, state);
            double y = Math.Round(Evaluate(dataset, ref row, state));
            return Math.Pow(x, 1 / y);
          }
        case OpCodes.Exp: {
            return Math.Exp(Evaluate(dataset, ref row, state));
          }
        case OpCodes.Log: {
            return Math.Log(Evaluate(dataset, ref row, state));
          }
        case OpCodes.Gamma: {
            var x = Evaluate(dataset, ref row, state);
            if (double.IsNaN(x)) return double.NaN;
            else return alglib.gammafunction(x);
          }
        case OpCodes.Psi: {
            var x = Evaluate(dataset, ref row, state);
            if (double.IsNaN(x)) return double.NaN;
            else if (x <= 0 && (Math.Floor(x) - x).IsAlmost(0)) return double.NaN;
            return alglib.psi(x);
          }
        case OpCodes.Dawson: {
            var x = Evaluate(dataset, ref row, state);
            if (double.IsNaN(x)) return double.NaN;
            return alglib.dawsonintegral(x);
          }
        case OpCodes.ExponentialIntegralEi: {
            var x = Evaluate(dataset, ref row, state);
            if (double.IsNaN(x)) return double.NaN;
            return alglib.exponentialintegralei(x);
          }
        case OpCodes.SineIntegral: {
            double si, ci;
            var x = Evaluate(dataset, ref row, state);
            if (double.IsNaN(x)) return double.NaN;
            else {
              alglib.sinecosineintegrals(x, out si, out ci);
              return si;
            }
          }
        case OpCodes.CosineIntegral: {
            double si, ci;
            var x = Evaluate(dataset, ref row, state);
            if (double.IsNaN(x)) return double.NaN;
            else {
              alglib.sinecosineintegrals(x, out si, out ci);
              return ci;
            }
          }
        case OpCodes.HyperbolicSineIntegral: {
            double shi, chi;
            var x = Evaluate(dataset, ref row, state);
            if (double.IsNaN(x)) return double.NaN;
            else {
              alglib.hyperbolicsinecosineintegrals(x, out shi, out chi);
              return shi;
            }
          }
        case OpCodes.HyperbolicCosineIntegral: {
            double shi, chi;
            var x = Evaluate(dataset, ref row, state);
            if (double.IsNaN(x)) return double.NaN;
            else {
              alglib.hyperbolicsinecosineintegrals(x, out shi, out chi);
              return chi;
            }
          }
        case OpCodes.FresnelCosineIntegral: {
            double c = 0, s = 0;
            var x = Evaluate(dataset, ref row, state);
            if (double.IsNaN(x)) return double.NaN;
            else {
              alglib.fresnelintegral(x, ref c, ref s);
              return c;
            }
          }
        case OpCodes.FresnelSineIntegral: {
            double c = 0, s = 0;
            var x = Evaluate(dataset, ref row, state);
            if (double.IsNaN(x)) return double.NaN;
            else {
              alglib.fresnelintegral(x, ref c, ref s);
              return s;
            }
          }
        case OpCodes.AiryA: {
            double ai, aip, bi, bip;
            var x = Evaluate(dataset, ref row, state);
            if (double.IsNaN(x)) return double.NaN;
            else {
              alglib.airy(x, out ai, out aip, out bi, out bip);
              return ai;
            }
          }
        case OpCodes.AiryB: {
            double ai, aip, bi, bip;
            var x = Evaluate(dataset, ref row, state);
            if (double.IsNaN(x)) return double.NaN;
            else {
              alglib.airy(x, out ai, out aip, out bi, out bip);
              return bi;
            }
          }
        case OpCodes.Norm: {
            var x = Evaluate(dataset, ref row, state);
            if (double.IsNaN(x)) return double.NaN;
            else return alglib.normaldistribution(x);
          }
        case OpCodes.Erf: {
            var x = Evaluate(dataset, ref row, state);
            if (double.IsNaN(x)) return double.NaN;
            else return alglib.errorfunction(x);
          }
        case OpCodes.Bessel: {
            var x = Evaluate(dataset, ref row, state);
            if (double.IsNaN(x)) return double.NaN;
            else return alglib.besseli0(x);
          }
        case OpCodes.IfThenElse: {
            double condition = Evaluate(dataset, ref row, state);
            double result;
            if (condition > 0.0) {
              result = Evaluate(dataset, ref row, state); state.SkipInstructions();
            } else {
              state.SkipInstructions(); result = Evaluate(dataset, ref row, state);
            }
            return result;
          }
        case OpCodes.AND: {
            double result = Evaluate(dataset, ref row, state);
            for (int i = 1; i < currentInstr.nArguments; i++) {
              if (result > 0.0) result = Evaluate(dataset, ref row, state);
              else {
                state.SkipInstructions();
              }
            }
            return result > 0.0 ? 1.0 : -1.0;
          }
        case OpCodes.OR: {
            double result = Evaluate(dataset, ref row, state);
            for (int i = 1; i < currentInstr.nArguments; i++) {
              if (result <= 0.0) result = Evaluate(dataset, ref row, state);
              else {
                state.SkipInstructions();
              }
            }
            return result > 0.0 ? 1.0 : -1.0;
          }
        case OpCodes.NOT: {
            return Evaluate(dataset, ref row, state) > 0.0 ? -1.0 : 1.0;
          }
        case OpCodes.XOR: {
            //mkommend: XOR on multiple inputs is defined as true if the number of positive signals is odd
            // this is equal to a consecutive execution of binary XOR operations.
            int positiveSignals = 0;
            for (int i = 0; i < currentInstr.nArguments; i++) {
              if (Evaluate(dataset, ref row, state) > 0.0) positiveSignals++;
            }
            return positiveSignals % 2 != 0 ? 1.0 : -1.0;
          }
        case OpCodes.GT: {
            double x = Evaluate(dataset, ref row, state);
            double y = Evaluate(dataset, ref row, state);
            if (x > y) return 1.0;
            else return -1.0;
          }
        case OpCodes.LT: {
            double x = Evaluate(dataset, ref row, state);
            double y = Evaluate(dataset, ref row, state);
            if (x < y) return 1.0;
            else return -1.0;
          }
        case OpCodes.TimeLag: {
            var timeLagTreeNode = (LaggedTreeNode)currentInstr.dynamicNode;
            row += timeLagTreeNode.Lag;
            double result = Evaluate(dataset, ref row, state);
            row -= timeLagTreeNode.Lag;
            return result;
          }
        case OpCodes.Integral: {
            int savedPc = state.ProgramCounter;
            var timeLagTreeNode = (LaggedTreeNode)currentInstr.dynamicNode;
            double sum = 0.0;
            for (int i = 0; i < Math.Abs(timeLagTreeNode.Lag); i++) {
              row += Math.Sign(timeLagTreeNode.Lag);
              sum += Evaluate(dataset, ref row, state);
              state.ProgramCounter = savedPc;
            }
            row -= timeLagTreeNode.Lag;
            sum += Evaluate(dataset, ref row, state);
            return sum;
          }

        //mkommend: derivate calculation taken from: 
        //http://www.holoborodko.com/pavel/numerical-methods/numerical-derivative/smooth-low-noise-differentiators/
        //one sided smooth differentiatior, N = 4
        // y' = 1/8h (f_i + 2f_i-1, -2 f_i-3 - f_i-4)
        case OpCodes.Derivative: {
            int savedPc = state.ProgramCounter;
            double f_0 = Evaluate(dataset, ref row, state); row--;
            state.ProgramCounter = savedPc;
            double f_1 = Evaluate(dataset, ref row, state); row -= 2;
            state.ProgramCounter = savedPc;
            double f_3 = Evaluate(dataset, ref row, state); row--;
            state.ProgramCounter = savedPc;
            double f_4 = Evaluate(dataset, ref row, state);
            row += 4;

            return (f_0 + 2 * f_1 - 2 * f_3 - f_4) / 8; // h = 1
          }
        case OpCodes.Call: {
            // evaluate sub-trees
            double[] argValues = new double[currentInstr.nArguments];
            for (int i = 0; i < currentInstr.nArguments; i++) {
              argValues[i] = Evaluate(dataset, ref row, state);
            }
            // push on argument values on stack 
            state.CreateStackFrame(argValues);

            // save the pc
            int savedPc = state.ProgramCounter;
            // set pc to start of function  
            state.ProgramCounter = (ushort)currentInstr.data;
            // evaluate the function
            double v = Evaluate(dataset, ref row, state);

            // delete the stack frame
            state.RemoveStackFrame();

            // restore the pc => evaluation will continue at point after my subtrees  
            state.ProgramCounter = savedPc;
            return v;
          }
        case OpCodes.Arg: {
            return state.GetStackFrameValue((ushort)currentInstr.data);
          }
        case OpCodes.Variable: {
            if (row < 0 || row >= dataset.Rows) return double.NaN;
            var variableTreeNode = (VariableTreeNode)currentInstr.dynamicNode;
            return ((IList<double>)currentInstr.data)[row] * variableTreeNode.Weight;
          }
        case OpCodes.LagVariable: {
            var laggedVariableTreeNode = (LaggedVariableTreeNode)currentInstr.dynamicNode;
            int actualRow = row + laggedVariableTreeNode.Lag;
            if (actualRow < 0 || actualRow >= dataset.Rows) return double.NaN;
            return ((IList<double>)currentInstr.data)[actualRow] * laggedVariableTreeNode.Weight;
          }
        case OpCodes.Constant: {
            var constTreeNode = (ConstantTreeNode)currentInstr.dynamicNode;
            return constTreeNode.Value;
          }

        //mkommend: this symbol uses the logistic function f(x) = 1 / (1 + e^(-alpha * x) ) 
        //to determine the relative amounts of the true and false branch see http://en.wikipedia.org/wiki/Logistic_function
        case OpCodes.VariableCondition: {
            if (row < 0 || row >= dataset.Rows) return double.NaN;
            var variableConditionTreeNode = (VariableConditionTreeNode)currentInstr.dynamicNode;
            double variableValue = ((IList<double>)currentInstr.data)[row];
            double x = variableValue - variableConditionTreeNode.Threshold;
            double p = 1 / (1 + Math.Exp(-variableConditionTreeNode.Slope * x));

            double trueBranch = Evaluate(dataset, ref row, state);
            double falseBranch = Evaluate(dataset, ref row, state);

            return trueBranch * p + falseBranch * (1 - p);
          }
        default: throw new NotSupportedException();
      }
    }
 public static void PrepareInstructions(LinearInstruction[] code, IDataset dataset) {
   for (int i = 0; i != code.Length; ++i) {
     var instr = code[i];
     #region opcode switch
     switch (instr.opCode) {
       case OpCodes.Constant: {
           var constTreeNode = (ConstantTreeNode)instr.dynamicNode;
           instr.value = constTreeNode.Value;
           instr.skip = true; // the value is already set so this instruction should be skipped in the evaluation phase
         }
         break;
       case OpCodes.Variable: {
           var variableTreeNode = (VariableTreeNode)instr.dynamicNode;
           instr.data = dataset.GetReadOnlyDoubleValues(variableTreeNode.VariableName);
         }
         break;
       case OpCodes.LagVariable: {
           var laggedVariableTreeNode = (LaggedVariableTreeNode)instr.dynamicNode;
           instr.data = dataset.GetReadOnlyDoubleValues(laggedVariableTreeNode.VariableName);
         }
         break;
       case OpCodes.VariableCondition: {
           var variableConditionTreeNode = (VariableConditionTreeNode)instr.dynamicNode;
           instr.data = dataset.GetReadOnlyDoubleValues(variableConditionTreeNode.VariableName);
         }
         break;
       case OpCodes.TimeLag:
       case OpCodes.Integral:
       case OpCodes.Derivative: {
           var seq = GetPrefixSequence(code, i);
           var interpreterState = new InterpreterState(seq, 0);
           instr.data = interpreterState;
           for (int j = 1; j != seq.Length; ++j)
             seq[j].skip = true;
         }
         break;
     }
     #endregion
   }
 }