Changeset 8436 for branches/HeuristicLab.TimeSeries/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeILEmittingInterpreter.cs
- Timestamp:
- 08/08/12 16:04:29 (12 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/HeuristicLab.TimeSeries/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeILEmittingInterpreter.cs
r8432 r8436 35 35 [StorableClass] 36 36 [Item("SymbolicDataAnalysisExpressionTreeILEmittingInterpreter", "Interpreter for symbolic expression trees.")] 37 public sealed class SymbolicDataAnalysisExpressionTreeILEmittingInterpreter : ParameterizedNamedItem, 38 ISymbolicDataAnalysisExpressionTreeInterpreter { 39 private static MethodInfo listGetValue = 40 typeof(IList<double>).GetProperty("Item", new Type[] { typeof(int) }).GetGetMethod(); 37 public sealed class SymbolicDataAnalysisExpressionTreeILEmittingInterpreter : ParameterizedNamedItem, ISymbolicDataAnalysisExpressionTreeInterpreter { 38 private static readonly Type thisType = typeof(SymbolicDataAnalysisExpressionTreeILEmittingInterpreter); 39 internal delegate double CompiledFunction(int sampleIndex, IList<double>[] columns); 40 41 #region method infos 42 private static MethodInfo listGetValue = typeof(IList<double>).GetProperty("Item", new Type[] { typeof(int) }).GetGetMethod(); 41 43 42 44 private static MethodInfo cos = typeof(Math).GetMethod("Cos", new Type[] { typeof(double) }); … … 49 51 private static MethodInfo sqrt = typeof(Math).GetMethod("Sqrt", new Type[] { typeof(double) }); 50 52 51 internal delegate double CompiledFunction(int sampleIndex, IList<double>[] columns, IList<double>[] cachedValues, int cacheStartIndex);52 private static Type thisType = typeof(SymbolicDataAnalysisExpressionTreeILEmittingInterpreter);53 53 private static MethodInfo airyA = thisType.GetMethod("AiryA", new Type[] { typeof(double) }); 54 54 private static MethodInfo airyB = thisType.GetMethod("AiryB", new Type[] { typeof(double) }); … … 66 66 private static MethodInfo erf = thisType.GetMethod("Erf", new Type[] { typeof(double) }); 67 67 private static MethodInfo bessel = thisType.GetMethod("Bessel", new Type[] { typeof(double) }); 68 69 68 #endregion 70 69 71 70 private const string CheckExpressionsWithIntervalArithmeticParameterName = "CheckExpressionsWithIntervalArithmetic"; 72 71 private const string EvaluatedSolutionsParameterName = "EvaluatedSolutions"; 73 74 #region private classes75 76 private class InterpreterState {77 private Instruction[] code;78 private int pc;79 80 public int ProgramCounter {81 get { return pc; }82 set { pc = value; }83 }84 85 private bool inLaggedContext;86 87 public bool InLaggedContext {88 get { return inLaggedContext; }89 set { inLaggedContext = value; }90 }91 92 internal InterpreterState(Instruction[] code) {93 this.inLaggedContext = false;94 this.code = code;95 this.pc = 0;96 }97 98 internal Instruction NextInstruction() {99 return code[pc++];100 }101 }102 103 private class OpCodes {104 public const byte Add = 1;105 public const byte Sub = 2;106 public const byte Mul = 3;107 public const byte Div = 4;108 109 public const byte Sin = 5;110 public const byte Cos = 6;111 public const byte Tan = 7;112 113 public const byte Log = 8;114 public const byte Exp = 9;115 116 public const byte IfThenElse = 10;117 118 public const byte GT = 11;119 public const byte LT = 12;120 121 public const byte AND = 13;122 public const byte OR = 14;123 public const byte NOT = 15;124 125 126 public const byte Average = 16;127 128 public const byte Call = 17;129 130 public const byte Variable = 18;131 public const byte LagVariable = 19;132 public const byte Constant = 20;133 public const byte Arg = 21;134 135 public const byte Power = 22;136 public const byte Root = 23;137 public const byte TimeLag = 24;138 public const byte Integral = 25;139 public const byte Derivative = 26;140 141 public const byte VariableCondition = 27;142 143 public const byte Square = 28;144 public const byte SquareRoot = 29;145 public const byte Gamma = 30;146 public const byte Psi = 31;147 public const byte Dawson = 32;148 public const byte ExponentialIntegralEi = 33;149 public const byte CosineIntegral = 34;150 public const byte SineIntegral = 35;151 public const byte HyperbolicCosineIntegral = 36;152 public const byte HyperbolicSineIntegral = 37;153 public const byte FresnelCosineIntegral = 38;154 public const byte FresnelSineIntegral = 39;155 public const byte AiryA = 40;156 public const byte AiryB = 41;157 public const byte Norm = 42;158 public const byte Erf = 43;159 public const byte Bessel = 44;160 }161 162 #endregion163 164 private Dictionary<Type, byte> symbolToOpcode = new Dictionary<Type, byte>()165 {166 {typeof (Addition), OpCodes.Add},167 {typeof (Subtraction), OpCodes.Sub},168 {typeof (Multiplication), OpCodes.Mul},169 {typeof (Division), OpCodes.Div},170 {typeof (Sine), OpCodes.Sin},171 {typeof (Cosine), OpCodes.Cos},172 {typeof (Tangent), OpCodes.Tan},173 {typeof (Logarithm), OpCodes.Log},174 {typeof (Exponential), OpCodes.Exp},175 {typeof (IfThenElse), OpCodes.IfThenElse},176 {typeof (GreaterThan), OpCodes.GT},177 {typeof (LessThan), OpCodes.LT},178 {typeof (And), OpCodes.AND},179 {typeof (Or), OpCodes.OR},180 {typeof (Not), OpCodes.NOT},181 {typeof (Average), OpCodes.Average},182 {typeof (InvokeFunction), OpCodes.Call},183 {184 typeof (HeuristicLab.Problems.DataAnalysis.Symbolic.Variable),185 OpCodes.Variable186 },187 {typeof (LaggedVariable), OpCodes.LagVariable},188 {typeof (Constant), OpCodes.Constant},189 {typeof (Argument), OpCodes.Arg},190 {typeof (Power), OpCodes.Power},191 {typeof (Root), OpCodes.Root},192 {typeof (TimeLag), OpCodes.TimeLag},193 {typeof (Integral), OpCodes.Integral},194 {typeof (Derivative), OpCodes.Derivative},195 {typeof (VariableCondition), OpCodes.VariableCondition},196 {typeof (Square), OpCodes.Square},197 {typeof (SquareRoot), OpCodes.SquareRoot},198 {typeof (Gamma), OpCodes.Gamma},199 {typeof (Psi), OpCodes.Psi},200 {typeof (Dawson), OpCodes.Dawson},201 {typeof (ExponentialIntegralEi), OpCodes.ExponentialIntegralEi},202 {typeof (CosineIntegral), OpCodes.CosineIntegral},203 {typeof (SineIntegral), OpCodes.SineIntegral},204 {205 typeof (HyperbolicCosineIntegral),206 OpCodes.HyperbolicCosineIntegral207 },208 {209 typeof (HyperbolicSineIntegral), OpCodes.HyperbolicSineIntegral210 },211 {typeof (FresnelCosineIntegral), OpCodes.FresnelCosineIntegral},212 {typeof (FresnelSineIntegral), OpCodes.FresnelSineIntegral},213 {typeof (AiryA), OpCodes.AiryA},214 {typeof (AiryB), OpCodes.AiryB},215 {typeof (Norm), OpCodes.Norm},216 {typeof (Erf), OpCodes.Erf},217 {typeof (Bessel), OpCodes.Bessel}218 };219 72 220 73 public override bool CanChangeName { … … 254 107 255 108 [StorableConstructor] 256 private SymbolicDataAnalysisExpressionTreeILEmittingInterpreter(bool deserializing) 257 : base(deserializing) { 258 } 259 260 private SymbolicDataAnalysisExpressionTreeILEmittingInterpreter( 261 SymbolicDataAnalysisExpressionTreeILEmittingInterpreter original, Cloner cloner) 262 : base(original, cloner) { 263 } 264 109 private SymbolicDataAnalysisExpressionTreeILEmittingInterpreter(bool deserializing) : base(deserializing) { } 110 111 private SymbolicDataAnalysisExpressionTreeILEmittingInterpreter(SymbolicDataAnalysisExpressionTreeILEmittingInterpreter original, Cloner cloner) : base(original, cloner) { } 265 112 public override IDeepCloneable Clone(Cloner cloner) { 266 113 return new SymbolicDataAnalysisExpressionTreeILEmittingInterpreter(this, cloner); … … 269 116 public SymbolicDataAnalysisExpressionTreeILEmittingInterpreter() 270 117 : base("SymbolicDataAnalysisExpressionTreeILEmittingInterpreter", "Interpreter for symbolic expression trees.") { 271 Parameters.Add(new ValueParameter<BoolValue>(CheckExpressionsWithIntervalArithmeticParameterName, 272 "Switch that determines if the interpreter checks the validity of expressions with interval arithmetic before evaluating the expression.", 273 new BoolValue(false))); 274 Parameters.Add(new ValueParameter<IntValue>(EvaluatedSolutionsParameterName, 275 "A counter for the total number of solutions the interpreter has evaluated", 276 new IntValue(0))); 118 Parameters.Add(new ValueParameter<BoolValue>(CheckExpressionsWithIntervalArithmeticParameterName, "Switch that determines if the interpreter checks the validity of expressions with interval arithmetic before evaluating the expression.", new BoolValue(false))); 119 Parameters.Add(new ValueParameter<IntValue>(EvaluatedSolutionsParameterName, "A counter for the total number of solutions the interpreter has evaluated", new IntValue(0))); 277 120 } 278 121 … … 280 123 private void AfterDeserialization() { 281 124 if (!Parameters.ContainsKey(EvaluatedSolutionsParameterName)) 282 Parameters.Add(new ValueParameter<IntValue>(EvaluatedSolutionsParameterName, 283 "A counter for the total number of solutions the interpreter has evaluated", 284 new IntValue(0))); 125 Parameters.Add(new ValueParameter<IntValue>(EvaluatedSolutionsParameterName, "A counter for the total number of solutions the interpreter has evaluated", new IntValue(0))); 285 126 } 286 127 … … 297 138 #endregion 298 139 299 public IEnumerable<double> GetSymbolicExpressionTreeValues(ISymbolicExpressionTree tree, Dataset dataset, 300 IEnumerable<int> rows) { 301 return GetSymbolicExpressionTreeValues(tree, dataset, new string[] { "#NOTHING#" }, rows); 302 } 303 public IEnumerable<double> GetSymbolicExpressionTreeValues(ISymbolicExpressionTree tree, Dataset dataset, string[] targetVariables, IEnumerable<int> rows) { 304 return GetSymbolicExpressionTreeValues(tree, dataset, targetVariables, rows, 1); 305 } 306 // for each row for each horizon for each target variable one value 307 public IEnumerable<double> GetSymbolicExpressionTreeValues(ISymbolicExpressionTree tree, Dataset dataset, string[] targetVariables, IEnumerable<int> rows, int horizon) { 140 public IEnumerable<double> GetSymbolicExpressionTreeValues(ISymbolicExpressionTree tree, Dataset dataset, IEnumerable<int> rows) { 308 141 if (CheckExpressionsWithIntervalArithmetic.Value) 309 throw new NotSupportedException( 310 "Interval arithmetic is not yet supported in the symbolic data analysis interpreter."); 142 throw new NotSupportedException("Interval arithmetic is not yet supported in the symbolic data analysis interpreter."); 143 311 144 EvaluatedSolutions.Value++; // increment the evaluated solutions counter 312 var compiler = new SymbolicExpressionTreeCompiler(); 313 Instruction[] code = compiler.Compile(tree, MapSymbolToOpCode); 145 var state = PrepareInterpreterState(tree, dataset); 146 147 Type[] methodArgs = { typeof(int), typeof(IList<double>[]) }; 148 DynamicMethod testFun = new DynamicMethod("TestFun", typeof(double), methodArgs, typeof(SymbolicDataAnalysisExpressionTreeILEmittingInterpreter).Module); 149 150 ILGenerator il = testFun.GetILGenerator(); 151 CompileInstructions(il, state, dataset); 152 il.Emit(System.Reflection.Emit.OpCodes.Conv_R8); 153 il.Emit(System.Reflection.Emit.OpCodes.Ret); 154 var function = (CompiledFunction)testFun.CreateDelegate(typeof(CompiledFunction)); 155 156 IList<double>[] columns = dataset.DoubleVariables.Select(v => dataset.GetReadOnlyDoubleValues(v)).ToArray(); 157 158 foreach (var row in rows) { 159 yield return function(row, columns); 160 } 161 } 162 163 private InterpreterState PrepareInterpreterState(ISymbolicExpressionTree tree, Dataset dataset) { 164 Instruction[] code = SymbolicExpressionTreeCompiler.Compile(tree, OpCodes.MapSymbolToOpCode); 165 Dictionary<string, int> doubleVariableNames = dataset.DoubleVariables.Select((x, i) => new { x, i }).ToDictionary(e => e.x, e => e.i); 314 166 int necessaryArgStackSize = 0; 315 316 Dictionary<string, int> doubleVariableNames = 317 dataset.DoubleVariables.Select((x, i) => new { x, i }).ToDictionary(e => e.x, e => e.i); 318 319 for (int i = 0; i < code.Length; i++) { 320 Instruction instr = code[i]; 167 foreach (Instruction instr in code) { 321 168 if (instr.opCode == OpCodes.Variable) { 322 var variableTreeNode = instr.dynamicNode as VariableTreeNode;169 var variableTreeNode = (VariableTreeNode)instr.dynamicNode; 323 170 instr.iArg0 = doubleVariableNames[variableTreeNode.VariableName]; 324 code[i] = instr;325 171 } else if (instr.opCode == OpCodes.LagVariable) { 326 var variableTreeNode = instr.dynamicNode as LaggedVariableTreeNode; 327 instr.iArg0 = doubleVariableNames[variableTreeNode.VariableName]; 328 code[i] = instr; 172 var laggedVariableTreeNode = (LaggedVariableTreeNode)instr.dynamicNode; 173 instr.iArg0 = doubleVariableNames[laggedVariableTreeNode.VariableName]; 329 174 } else if (instr.opCode == OpCodes.VariableCondition) { 330 var variableConditionTreeNode = instr.dynamicNode as VariableConditionTreeNode;175 var variableConditionTreeNode = (VariableConditionTreeNode)instr.dynamicNode; 331 176 instr.iArg0 = doubleVariableNames[variableConditionTreeNode.VariableName]; 332 177 } else if (instr.opCode == OpCodes.Call) { … … 334 179 } 335 180 } 336 var state = new InterpreterState(code); 337 Type[] methodArgs = { typeof(int), typeof(IList<double>[]), typeof(IList<double>[]), typeof(int) }; 338 339 CompiledFunction[] function = new CompiledFunction[targetVariables.Length]; 340 for (int i = 0; i < function.Length; i++) { 341 DynamicMethod testFun = new DynamicMethod("TestFun", typeof(double), methodArgs, typeof(SymbolicDataAnalysisExpressionTreeILEmittingInterpreter).Module); 342 ILGenerator il = testFun.GetILGenerator(); 343 CompileInstructions(il, state, dataset); 344 il.Emit(System.Reflection.Emit.OpCodes.Conv_R8); 345 il.Emit(System.Reflection.Emit.OpCodes.Ret); 346 function[i] = (CompiledFunction)testFun.CreateDelegate(typeof(CompiledFunction)); 347 } 348 var values = doubleVariableNames.Keys 349 .Select(v => dataset.GetReadOnlyDoubleValues(v)) 350 .ToArray(); 351 var cachedValues = (from var in doubleVariableNames.Keys 352 select new double[horizon]).ToArray(); 353 foreach (var row in rows) { 354 // init first line of cache 355 int c = 0; 356 foreach (var var in doubleVariableNames.Keys) 357 cachedValues[c++][0] = dataset.GetDoubleValue(var, row); 358 for (int horizonRow = row; horizonRow < row + horizon; horizonRow++) { 359 for (int i = 0; i < function.Length; i++) { 360 var componentProg = function[i](horizonRow, values, cachedValues, row); 361 // set cachedValues for prognosis of future values 362 if (horizon > 1) 363 cachedValues[doubleVariableNames[targetVariables[i]]][horizonRow - row] = componentProg; 364 yield return componentProg; 365 } 366 } 367 } 181 return new InterpreterState(code, necessaryArgStackSize); 368 182 } 369 183 … … 865 679 } 866 680 867 private byte MapSymbolToOpCode(ISymbolicExpressionTreeNode treeNode) {868 byte opCode;869 if (!symbolToOpcode.TryGetValue(treeNode.Symbol.GetType(), out opCode))870 throw new NotSupportedException("Symbol: " + treeNode.Symbol);871 return opCode;872 }873 874 875 681 public static double AiryA(double x) { 876 682 if (double.IsNaN(x)) return double.NaN;
Note: See TracChangeset
for help on using the changeset viewer.