#region License Information
/* HeuristicLab
* Copyright (C) 2002-2018 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
*
* This file is part of HeuristicLab.
*
* HeuristicLab is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HeuristicLab is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with HeuristicLab. If not, see .
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using HeuristicLab.Common;
using HeuristicLab.Core;
using HeuristicLab.Data;
using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
using HeuristicLab.Parameters;
using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
[StorableClass]
[Item("SymbolicDataAnalysisExpressionTreeILEmittingInterpreter", "Interpreter for symbolic expression trees.")]
public sealed class SymbolicDataAnalysisExpressionTreeILEmittingInterpreter : ParameterizedNamedItem, ISymbolicDataAnalysisExpressionTreeInterpreter {
private static readonly Type thisType = typeof(SymbolicDataAnalysisExpressionTreeILEmittingInterpreter);
internal delegate double CompiledFunction(int sampleIndex, IList[] columns);
#region method infos
private static MethodInfo listGetValue = typeof(IList).GetProperty("Item", new Type[] { typeof(int) }).GetGetMethod();
private static MethodInfo cos = typeof(Math).GetMethod("Cos", new Type[] { typeof(double) });
private static MethodInfo sin = typeof(Math).GetMethod("Sin", new Type[] { typeof(double) });
private static MethodInfo tan = typeof(Math).GetMethod("Tan", new Type[] { typeof(double) });
private static MethodInfo exp = typeof(Math).GetMethod("Exp", new Type[] { typeof(double) });
private static MethodInfo log = typeof(Math).GetMethod("Log", new Type[] { typeof(double) });
private static MethodInfo power = typeof(Math).GetMethod("Pow", new Type[] { typeof(double), typeof(double) });
private static MethodInfo round = typeof(Math).GetMethod("Round", new Type[] { typeof(double) });
private static MethodInfo sqrt = typeof(Math).GetMethod("Sqrt", new Type[] { typeof(double) });
private static MethodInfo abs = typeof(Math).GetMethod("Abs", new Type[] { typeof(double) });
private static MethodInfo airyA = thisType.GetMethod("AiryA", new Type[] { typeof(double) });
private static MethodInfo airyB = thisType.GetMethod("AiryB", new Type[] { typeof(double) });
private static MethodInfo gamma = thisType.GetMethod("Gamma", new Type[] { typeof(double) });
private static MethodInfo psi = thisType.GetMethod("Psi", new Type[] { typeof(double) });
private static MethodInfo dawson = thisType.GetMethod("Dawson", new Type[] { typeof(double) });
private static MethodInfo expIntegralEi = thisType.GetMethod("ExpIntegralEi", new Type[] { typeof(double) });
private static MethodInfo sinIntegral = thisType.GetMethod("SinIntegral", new Type[] { typeof(double) });
private static MethodInfo cosIntegral = thisType.GetMethod("CosIntegral", new Type[] { typeof(double) });
private static MethodInfo hypSinIntegral = thisType.GetMethod("HypSinIntegral", new Type[] { typeof(double) });
private static MethodInfo hypCosIntegral = thisType.GetMethod("HypCosIntegral", new Type[] { typeof(double) });
private static MethodInfo fresnelCosIntegral = thisType.GetMethod("FresnelCosIntegral", new Type[] { typeof(double) });
private static MethodInfo fresnelSinIntegral = thisType.GetMethod("FresnelSinIntegral", new Type[] { typeof(double) });
private static MethodInfo norm = thisType.GetMethod("Norm", new Type[] { typeof(double) });
private static MethodInfo erf = thisType.GetMethod("Erf", new Type[] { typeof(double) });
private static MethodInfo bessel = thisType.GetMethod("Bessel", new Type[] { typeof(double) });
private static MethodInfo string_eq = typeof(string).GetMethod("Equals", new Type[] { typeof(string) });
#endregion
private const string CheckExpressionsWithIntervalArithmeticParameterName = "CheckExpressionsWithIntervalArithmetic";
private const string CheckExpressionsWithIntervalArithmeticParameterDescription = "Switch that determines if the interpreter checks the validity of expressions with interval arithmetic before evaluating the expression.";
private const string EvaluatedSolutionsParameterName = "EvaluatedSolutions";
public override bool CanChangeName {
get { return false; }
}
public override bool CanChangeDescription {
get { return false; }
}
#region parameter properties
public IFixedValueParameter CheckExpressionsWithIntervalArithmeticParameter {
get { return (IFixedValueParameter)Parameters[CheckExpressionsWithIntervalArithmeticParameterName]; }
}
public IFixedValueParameter EvaluatedSolutionsParameter {
get { return (IFixedValueParameter)Parameters[EvaluatedSolutionsParameterName]; }
}
#endregion
#region properties
public bool CheckExpressionsWithIntervalArithmetic {
get { return CheckExpressionsWithIntervalArithmeticParameter.Value.Value; }
set { CheckExpressionsWithIntervalArithmeticParameter.Value.Value = value; }
}
public int EvaluatedSolutions {
get { return EvaluatedSolutionsParameter.Value.Value; }
set { EvaluatedSolutionsParameter.Value.Value = value; }
}
#endregion
[StorableConstructor]
private SymbolicDataAnalysisExpressionTreeILEmittingInterpreter(bool deserializing) : base(deserializing) { }
private SymbolicDataAnalysisExpressionTreeILEmittingInterpreter(SymbolicDataAnalysisExpressionTreeILEmittingInterpreter original, Cloner cloner) : base(original, cloner) { }
public override IDeepCloneable Clone(Cloner cloner) {
return new SymbolicDataAnalysisExpressionTreeILEmittingInterpreter(this, cloner);
}
public SymbolicDataAnalysisExpressionTreeILEmittingInterpreter()
: base("SymbolicDataAnalysisExpressionTreeILEmittingInterpreter", "Interpreter for symbolic expression trees.") {
Parameters.Add(new FixedValueParameter(CheckExpressionsWithIntervalArithmeticParameterName,
"Switch that determines if the interpreter checks the validity of expressions with interval arithmetic before evaluating the expression.", new BoolValue(false)));
Parameters.Add(new FixedValueParameter(EvaluatedSolutionsParameterName, "A counter for the total number of solutions the interpreter has evaluated", new IntValue(0)));
}
public SymbolicDataAnalysisExpressionTreeILEmittingInterpreter(string name, string description)
: base(name, description) {
Parameters.Add(new FixedValueParameter(CheckExpressionsWithIntervalArithmeticParameterName,
"Switch that determines if the interpreter checks the validity of expressions with interval arithmetic before evaluating the expression.", new BoolValue(false)));
Parameters.Add(new FixedValueParameter(EvaluatedSolutionsParameterName, "A counter for the total number of solutions the interpreter has evaluated", new IntValue(0)));
}
[StorableHook(HookType.AfterDeserialization)]
private void AfterDeserialization() {
var evaluatedSolutions = new IntValue(0);
var checkExpressionsWithIntervalArithmetic = new BoolValue(false);
if (Parameters.ContainsKey(EvaluatedSolutionsParameterName)) {
var evaluatedSolutionsParameter = (IValueParameter)Parameters[EvaluatedSolutionsParameterName];
evaluatedSolutions = evaluatedSolutionsParameter.Value;
Parameters.Remove(EvaluatedSolutionsParameterName);
}
Parameters.Add(new FixedValueParameter(EvaluatedSolutionsParameterName, "A counter for the total number of solutions the interpreter has evaluated", evaluatedSolutions));
if (Parameters.ContainsKey(CheckExpressionsWithIntervalArithmeticParameterName)) {
var checkExpressionsWithIntervalArithmeticParameter = (IValueParameter)Parameters[CheckExpressionsWithIntervalArithmeticParameterName];
Parameters.Remove(CheckExpressionsWithIntervalArithmeticParameterName);
checkExpressionsWithIntervalArithmetic = checkExpressionsWithIntervalArithmeticParameter.Value;
}
Parameters.Add(new FixedValueParameter(CheckExpressionsWithIntervalArithmeticParameterName, CheckExpressionsWithIntervalArithmeticParameterDescription, checkExpressionsWithIntervalArithmetic));
}
#region IStatefulItem
public void InitializeState() {
EvaluatedSolutions = 0;
}
public void ClearState() {
}
#endregion
private readonly object syncRoot = new object();
public IEnumerable GetSymbolicExpressionTreeValues(ISymbolicExpressionTree tree, IDataset dataset, IEnumerable rows) {
if (CheckExpressionsWithIntervalArithmetic)
throw new NotSupportedException("Interval arithmetic is not yet supported in the symbolic data analysis interpreter.");
lock (syncRoot) {
EvaluatedSolutions++; // increment the evaluated solutions counter
}
var state = PrepareInterpreterState(tree, dataset);
Type[] methodArgs = { typeof(int), typeof(IList[]) };
DynamicMethod testFun = new DynamicMethod("TestFun", typeof(double), methodArgs, typeof(SymbolicDataAnalysisExpressionTreeILEmittingInterpreter).Module);
ILGenerator il = testFun.GetILGenerator();
CompileInstructions(il, state, dataset);
il.Emit(System.Reflection.Emit.OpCodes.Conv_R8);
il.Emit(System.Reflection.Emit.OpCodes.Ret);
var function = (CompiledFunction)testFun.CreateDelegate(typeof(CompiledFunction));
IList[] columns = dataset.DoubleVariables.Select(v => dataset.GetReadOnlyDoubleValues(v)).ToArray();
foreach (var row in rows) {
yield return function(row, columns);
}
}
private InterpreterState PrepareInterpreterState(ISymbolicExpressionTree tree, IDataset dataset) {
Instruction[] code = SymbolicExpressionTreeCompiler.Compile(tree, OpCodes.MapSymbolToOpCode);
Dictionary doubleVariableNames = dataset.DoubleVariables.Select((x, i) => new { x, i }).ToDictionary(e => e.x, e => e.i);
int necessaryArgStackSize = 0;
foreach (Instruction instr in code) {
if (instr.opCode == OpCodes.Variable) {
var variableTreeNode = (VariableTreeNode)instr.dynamicNode;
instr.data = doubleVariableNames[variableTreeNode.VariableName];
} else if (instr.opCode == OpCodes.LagVariable) {
var laggedVariableTreeNode = (LaggedVariableTreeNode)instr.dynamicNode;
instr.data = doubleVariableNames[laggedVariableTreeNode.VariableName];
} else if (instr.opCode == OpCodes.VariableCondition) {
var variableConditionTreeNode = (VariableConditionTreeNode)instr.dynamicNode;
instr.data = doubleVariableNames[variableConditionTreeNode.VariableName];
} else if (instr.opCode == OpCodes.Call) {
necessaryArgStackSize += instr.nArguments + 1;
}
}
return new InterpreterState(code, necessaryArgStackSize);
}
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_R8, (double)nArgs);
il.Emit(System.Reflection.Emit.OpCodes.Div);
return;
}
case OpCodes.Absolute: {
CompileInstructions(il, state, ds);
il.Emit(System.Reflection.Emit.OpCodes.Call, abs);
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.Cube: {
CompileInstructions(il, state, ds);
il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 3.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.CubeRoot: {
CompileInstructions(il, state, ds);
il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0 / 3.0);
il.Emit(System.Reflection.Emit.OpCodes.Call, power);
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.AnalyticalQuotient: {
CompileInstructions(il, state, ds); // x1
CompileInstructions(il, state, ds); // x2
il.Emit(System.Reflection.Emit.OpCodes.Dup);
il.Emit(System.Reflection.Emit.OpCodes.Mul); // x2*x2
il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0);
il.Emit(System.Reflection.Emit.OpCodes.Mul); // 1+x2*x2
il.Emit(System.Reflection.Emit.OpCodes.Call, sqrt);
il.Emit(System.Reflection.Emit.OpCodes.Div);
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.Conv_R8); // convert to float64
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.Conv_R8); // convert to float64
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.Conv_R8); // convert to float64
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.Conv_R8); // convert to float64
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 static double AiryA(double x) {
if (double.IsNaN(x)) return double.NaN;
double ai, aip, bi, bip;
alglib.airy(x, out ai, out aip, out bi, out bip);
return ai;
}
public static double AiryB(double x) {
if (double.IsNaN(x)) return double.NaN;
double ai, aip, bi, bip;
alglib.airy(x, out ai, out aip, out bi, out bip);
return bi;
}
public static double Dawson(double x) {
if (double.IsNaN(x)) return double.NaN;
return alglib.dawsonintegral(x);
}
public static double Gamma(double x) {
if (double.IsNaN(x)) return double.NaN;
return alglib.gammafunction(x);
}
public static double Psi(double x) {
if (double.IsNaN(x)) return double.NaN;
else if (x <= 0 && (Math.Floor(x) - x).IsAlmost(0)) return double.NaN;
return alglib.psi(x);
}
public static double ExpIntegralEi(double x) {
if (double.IsNaN(x)) return double.NaN;
return alglib.exponentialintegralei(x);
}
public static double SinIntegral(double x) {
if (double.IsNaN(x)) return double.NaN;
double si, ci;
alglib.sinecosineintegrals(x, out si, out ci);
return si;
}
public static double CosIntegral(double x) {
if (double.IsNaN(x)) return double.NaN;
double si, ci;
alglib.sinecosineintegrals(x, out si, out ci);
return ci;
}
public static double HypSinIntegral(double x) {
if (double.IsNaN(x)) return double.NaN;
double shi, chi;
alglib.hyperbolicsinecosineintegrals(x, out shi, out chi);
return shi;
}
public static double HypCosIntegral(double x) {
if (double.IsNaN(x)) return double.NaN;
double shi, chi;
alglib.hyperbolicsinecosineintegrals(x, out shi, out chi);
return chi;
}
public static double FresnelCosIntegral(double x) {
if (double.IsNaN(x)) return double.NaN;
double c = 0, s = 0;
alglib.fresnelintegral(x, ref c, ref s);
return c;
}
public static double FresnelSinIntegral(double x) {
if (double.IsNaN(x)) return double.NaN;
double c = 0, s = 0;
alglib.fresnelintegral(x, ref c, ref s);
return s;
}
public static double Norm(double x) {
if (double.IsNaN(x)) return double.NaN;
return alglib.normaldistribution(x);
}
public static double Erf(double x) {
if (double.IsNaN(x)) return double.NaN;
return alglib.errorfunction(x);
}
public static double Bessel(double x) {
if (double.IsNaN(x)) return double.NaN;
return alglib.besseli0(x);
}
}
}