Changeset 5275 for branches/DataAnalysis/HeuristicLab.Problems.DataAnalysis/3.3/Symbolic/SimpleArithmeticExpressionInterpreter.cs
- Timestamp:
- 01/11/11 15:03:46 (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/DataAnalysis/HeuristicLab.Problems.DataAnalysis/3.3/Symbolic/SimpleArithmeticExpressionInterpreter.cs
r4193 r5275 22 22 using System; 23 23 using System.Collections.Generic; 24 using HeuristicLab.Common; 24 25 using HeuristicLab.Core; 25 26 using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding; … … 32 33 [StorableClass] 33 34 [Item("SimpleArithmeticExpressionInterpreter", "Interpreter for arithmetic symbolic expression trees including function calls.")] 34 // not thread safe! 35 public class SimpleArithmeticExpressionInterpreter : NamedItem, ISymbolicExpressionTreeInterpreter { 35 public sealed class SimpleArithmeticExpressionInterpreter : NamedItem, ISymbolicExpressionTreeInterpreter { 36 36 private class OpCodes { 37 37 public const byte Add = 1; … … 65 65 public const byte Constant = 20; 66 66 public const byte Arg = 21; 67 public const byte Differential = 22;68 67 } 69 68 … … 90 89 { typeof(Constant), OpCodes.Constant }, 91 90 { typeof(Argument), OpCodes.Arg }, 92 { typeof(DifferentialVariable), OpCodes.Differential},93 91 }; 94 92 private const int ARGUMENT_STACK_SIZE = 1024; 95 93 96 private Dataset dataset;97 private int row;98 private Instruction[] code;99 private int pc;100 private double[] argumentStack = new double[ARGUMENT_STACK_SIZE];101 private int argStackPointer;102 103 94 public override bool CanChangeName { 104 95 get { return false; } … … 108 99 } 109 100 101 [StorableConstructor] 102 private SimpleArithmeticExpressionInterpreter(bool deserializing) : base(deserializing) { } 103 private SimpleArithmeticExpressionInterpreter(SimpleArithmeticExpressionInterpreter original, Cloner cloner) : base(original, cloner) { } 104 public override IDeepCloneable Clone(Cloner cloner) { 105 return new SimpleArithmeticExpressionInterpreter(this, cloner); 106 } 107 110 108 public SimpleArithmeticExpressionInterpreter() 111 109 : base() { … … 113 111 114 112 public IEnumerable<double> GetSymbolicExpressionTreeValues(SymbolicExpressionTree tree, Dataset dataset, IEnumerable<int> rows) { 115 this.dataset = dataset;116 113 var compiler = new SymbolicExpressionTreeCompiler(); 117 compiler.AddInstructionPostProcessingHook(PostProcessInstruction); 118 code = compiler.Compile(tree, MapSymbolToOpCode); 119 foreach (var row in rows) { 120 this.row = row; 121 pc = 0; 122 argStackPointer = 0; 123 yield return Evaluate(); 124 } 125 } 126 127 private Instruction PostProcessInstruction(Instruction instr) { 128 if (instr.opCode == OpCodes.Variable) { 129 var variableTreeNode = instr.dynamicNode as VariableTreeNode; 130 instr.iArg0 = (ushort)dataset.GetVariableIndex(variableTreeNode.VariableName); 131 } else if (instr.opCode == OpCodes.LagVariable) { 132 var variableTreeNode = instr.dynamicNode as LaggedVariableTreeNode; 133 instr.iArg0 = (ushort)dataset.GetVariableIndex(variableTreeNode.VariableName); 134 } else if (instr.opCode == OpCodes.Differential) { 135 var variableTreeNode = instr.dynamicNode as DifferentialVariableTreeNode; 136 instr.iArg0 = (ushort)dataset.GetVariableIndex(variableTreeNode.VariableName); 137 } 138 return instr; 114 Instruction[] code = compiler.Compile(tree, MapSymbolToOpCode); 115 116 for (int i = 0; i < code.Length; i++) { 117 Instruction instr = code[i]; 118 if (instr.opCode == OpCodes.Variable) { 119 var variableTreeNode = instr.dynamicNode as VariableTreeNode; 120 instr.iArg0 = (ushort)dataset.GetVariableIndex(variableTreeNode.VariableName); 121 code[i] = instr; 122 } else if (instr.opCode == OpCodes.LagVariable) { 123 var variableTreeNode = instr.dynamicNode as LaggedVariableTreeNode; 124 instr.iArg0 = (ushort)dataset.GetVariableIndex(variableTreeNode.VariableName); 125 code[i] = instr; 126 } 127 } 128 129 double[] argumentStack = new double[ARGUMENT_STACK_SIZE]; 130 foreach (var rowEnum in rows) { 131 int row = rowEnum; 132 int pc = 0; 133 int argStackPointer = 0; 134 yield return Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer); 135 } 136 } 137 138 private double Evaluate(Dataset dataset, ref int row, Instruction[] code, ref int pc, double[] argumentStack, ref int argStackPointer) { 139 Instruction currentInstr = code[pc++]; 140 switch (currentInstr.opCode) { 141 case OpCodes.Add: { 142 double s = Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer); 143 for (int i = 1; i < currentInstr.nArguments; i++) { 144 s += Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer); 145 } 146 return s; 147 } 148 case OpCodes.Sub: { 149 double s = Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer); 150 for (int i = 1; i < currentInstr.nArguments; i++) { 151 s -= Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer); 152 } 153 if (currentInstr.nArguments == 1) s = -s; 154 return s; 155 } 156 case OpCodes.Mul: { 157 double p = Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer); 158 for (int i = 1; i < currentInstr.nArguments; i++) { 159 p *= Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer); 160 } 161 return p; 162 } 163 case OpCodes.Div: { 164 double p = Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer); 165 for (int i = 1; i < currentInstr.nArguments; i++) { 166 p /= Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer); 167 } 168 if (currentInstr.nArguments == 1) p = 1.0 / p; 169 return p; 170 } 171 case OpCodes.Average: { 172 double sum = Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer); 173 for (int i = 1; i < currentInstr.nArguments; i++) { 174 sum += Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer); 175 } 176 return sum / currentInstr.nArguments; 177 } 178 case OpCodes.Cos: { 179 return Math.Cos(Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer)); 180 } 181 case OpCodes.Sin: { 182 return Math.Sin(Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer)); 183 } 184 case OpCodes.Tan: { 185 return Math.Tan(Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer)); 186 } 187 case OpCodes.Exp: { 188 return Math.Exp(Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer)); 189 } 190 case OpCodes.Log: { 191 return Math.Log(Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer)); 192 } 193 case OpCodes.IfThenElse: { 194 double condition = Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer); 195 double result; 196 if (condition > 0.0) { 197 result = Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer); SkipBakedCode(code, ref pc); 198 } else { 199 SkipBakedCode(code, ref pc); result = Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer); 200 } 201 return result; 202 } 203 case OpCodes.AND: { 204 double result = Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer); 205 for (int i = 1; i < currentInstr.nArguments; i++) { 206 if (result <= 0.0) SkipBakedCode(code, ref pc); 207 else { 208 result = Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer); 209 } 210 } 211 return result <= 0.0 ? -1.0 : 1.0; 212 } 213 case OpCodes.OR: { 214 double result = Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer); 215 for (int i = 1; i < currentInstr.nArguments; i++) { 216 if (result > 0.0) SkipBakedCode(code, ref pc); 217 else { 218 result = Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer); 219 } 220 } 221 return result > 0.0 ? 1.0 : -1.0; 222 } 223 case OpCodes.NOT: { 224 return -Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer); 225 } 226 case OpCodes.GT: { 227 double x = Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer); 228 double y = Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer); 229 if (x > y) return 1.0; 230 else return -1.0; 231 } 232 case OpCodes.LT: { 233 double x = Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer); 234 double y = Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer); 235 if (x < y) return 1.0; 236 else return -1.0; 237 } 238 case OpCodes.Call: { 239 // evaluate sub-trees 240 // push on argStack in reverse order 241 for (int i = 0; i < currentInstr.nArguments; i++) { 242 argumentStack[argStackPointer + currentInstr.nArguments - i] = Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer); 243 } 244 argStackPointer += currentInstr.nArguments; 245 246 // save the pc 247 int nextPc = pc; 248 // set pc to start of function 249 pc = currentInstr.iArg0; 250 // evaluate the function 251 double v = Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer); 252 253 // decrease the argument stack pointer by the number of arguments pushed 254 // to set the argStackPointer back to the original location 255 argStackPointer -= currentInstr.nArguments; 256 257 // restore the pc => evaluation will continue at point after my subtrees 258 pc = nextPc; 259 return v; 260 } 261 case OpCodes.Arg: { 262 return argumentStack[argStackPointer - currentInstr.iArg0]; 263 } 264 case OpCodes.Variable: { 265 var variableTreeNode = currentInstr.dynamicNode as VariableTreeNode; 266 return dataset[row, currentInstr.iArg0] * variableTreeNode.Weight; 267 } 268 case OpCodes.LagVariable: { 269 var laggedVariableTreeNode = currentInstr.dynamicNode as LaggedVariableTreeNode; 270 int actualRow = row + laggedVariableTreeNode.Lag; 271 if (actualRow < 0 || actualRow >= dataset.Rows) throw new ArgumentException("Out of range access to dataset row: " + row); 272 return dataset[actualRow, currentInstr.iArg0] * laggedVariableTreeNode.Weight; 273 } 274 case OpCodes.Constant: { 275 var constTreeNode = currentInstr.dynamicNode as ConstantTreeNode; 276 return constTreeNode.Value; 277 } 278 default: throw new NotSupportedException(); 279 } 139 280 } 140 281 … … 146 287 } 147 288 148 private double Evaluate() {149 Instruction currentInstr = code[pc++];150 switch (currentInstr.opCode) {151 case OpCodes.Add: {152 double s = Evaluate();153 for (int i = 1; i < currentInstr.nArguments; i++) {154 s += Evaluate();155 }156 return s;157 }158 case OpCodes.Sub: {159 double s = Evaluate();160 for (int i = 1; i < currentInstr.nArguments; i++) {161 s -= Evaluate();162 }163 if (currentInstr.nArguments == 1) s = -s;164 return s;165 }166 case OpCodes.Mul: {167 double p = Evaluate();168 for (int i = 1; i < currentInstr.nArguments; i++) {169 p *= Evaluate();170 }171 return p;172 }173 case OpCodes.Div: {174 double p = Evaluate();175 for (int i = 1; i < currentInstr.nArguments; i++) {176 p /= Evaluate();177 }178 if (currentInstr.nArguments == 1) p = 1.0 / p;179 return p;180 }181 case OpCodes.Average: {182 double sum = Evaluate();183 for (int i = 1; i < currentInstr.nArguments; i++) {184 sum += Evaluate();185 }186 return sum / currentInstr.nArguments;187 }188 case OpCodes.Cos: {189 return Math.Cos(Evaluate());190 }191 case OpCodes.Sin: {192 return Math.Sin(Evaluate());193 }194 case OpCodes.Tan: {195 return Math.Tan(Evaluate());196 }197 case OpCodes.Exp: {198 return Math.Exp(Evaluate());199 }200 case OpCodes.Log: {201 return Math.Log(Evaluate());202 }203 case OpCodes.IfThenElse: {204 double condition = Evaluate();205 double result;206 if (condition > 0.0) {207 result = Evaluate(); SkipBakedCode();208 } else {209 SkipBakedCode(); result = Evaluate();210 }211 return result;212 }213 case OpCodes.AND: {214 double result = Evaluate();215 for (int i = 1; i < currentInstr.nArguments; i++) {216 if (result <= 0.0) SkipBakedCode();217 else {218 result = Evaluate();219 }220 }221 return result <= 0.0 ? -1.0 : 1.0;222 }223 case OpCodes.OR: {224 double result = Evaluate();225 for (int i = 1; i < currentInstr.nArguments; i++) {226 if (result > 0.0) SkipBakedCode();227 else {228 result = Evaluate();229 }230 }231 return result > 0.0 ? 1.0 : -1.0;232 }233 case OpCodes.NOT: {234 return -Evaluate();235 }236 case OpCodes.GT: {237 double x = Evaluate();238 double y = Evaluate();239 if (x > y) return 1.0;240 else return -1.0;241 }242 case OpCodes.LT: {243 double x = Evaluate();244 double y = Evaluate();245 if (x < y) return 1.0;246 else return -1.0;247 }248 case OpCodes.Call: {249 // evaluate sub-trees250 // push on argStack in reverse order251 for (int i = 0; i < currentInstr.nArguments; i++) {252 argumentStack[argStackPointer + currentInstr.nArguments - i] = Evaluate();253 }254 argStackPointer += currentInstr.nArguments;255 256 // save the pc257 int nextPc = pc;258 // set pc to start of function259 pc = currentInstr.iArg0;260 // evaluate the function261 double v = Evaluate();262 263 // decrease the argument stack pointer by the number of arguments pushed264 // to set the argStackPointer back to the original location265 argStackPointer -= currentInstr.nArguments;266 267 // restore the pc => evaluation will continue at point after my subtrees268 pc = nextPc;269 return v;270 }271 case OpCodes.Arg: {272 return argumentStack[argStackPointer - currentInstr.iArg0];273 }274 case OpCodes.Variable: {275 var variableTreeNode = currentInstr.dynamicNode as VariableTreeNode;276 return dataset[row, currentInstr.iArg0] * variableTreeNode.Weight;277 }278 case OpCodes.LagVariable: {279 var lagVariableTreeNode = currentInstr.dynamicNode as LaggedVariableTreeNode;280 int actualRow = row + lagVariableTreeNode.Lag;281 if (actualRow < 0 || actualRow >= dataset.Rows) throw new ArgumentException("Out of range access to dataset row: " + row);282 return dataset[actualRow, currentInstr.iArg0] * lagVariableTreeNode.Weight;283 }284 case OpCodes.Differential: {285 var diffTreeNode = currentInstr.dynamicNode as DifferentialVariableTreeNode;286 if (row < 2 || row >= dataset.Rows - 2) throw new ArgumentException("Out of range access to dataset row: " + row);287 return (-dataset[row + 2, currentInstr.iArg0] + 8 * dataset[row + 1, currentInstr.iArg0] - 8 * dataset[row - 1, currentInstr.iArg0] + dataset[row - 2, currentInstr.iArg0]) * (1.0/12.0) * diffTreeNode.Weight;288 }289 290 case OpCodes.Constant: {291 var constTreeNode = currentInstr.dynamicNode as ConstantTreeNode;292 return constTreeNode.Value;293 }294 default: throw new NotSupportedException();295 }296 }297 298 289 // skips a whole branch 299 pr otected void SkipBakedCode() {290 private void SkipBakedCode(Instruction[] code, ref int pc) { 300 291 int i = 1; 301 292 while (i > 0) {
Note: See TracChangeset
for help on using the changeset viewer.