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(); } }
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 } }