Changeset 5223
- Timestamp:
- 01/05/11 14:53:11 (14 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/sources/HeuristicLab.Problems.DataAnalysis/3.3/Symbolic/SimpleArithmeticExpressionInterpreter.cs
r4722 r5223 33 33 [StorableClass] 34 34 [Item("SimpleArithmeticExpressionInterpreter", "Interpreter for arithmetic symbolic expression trees including function calls.")] 35 // not thread safe!36 35 public sealed class SimpleArithmeticExpressionInterpreter : NamedItem, ISymbolicExpressionTreeInterpreter { 37 36 private class OpCodes { … … 93 92 private const int ARGUMENT_STACK_SIZE = 1024; 94 93 95 private Dataset dataset;96 private int row;97 private Instruction[] code;98 private int pc;99 private double[] argumentStack = new double[ARGUMENT_STACK_SIZE];100 private int argStackPointer;101 102 94 public override bool CanChangeName { 103 95 get { return false; } … … 110 102 private SimpleArithmeticExpressionInterpreter(bool deserializing) : base(deserializing) { } 111 103 private SimpleArithmeticExpressionInterpreter(SimpleArithmeticExpressionInterpreter original, Cloner cloner) : base(original, cloner) { } 112 113 104 public override IDeepCloneable Clone(Cloner cloner) { 114 105 return new SimpleArithmeticExpressionInterpreter(this, cloner); … … 120 111 121 112 public IEnumerable<double> GetSymbolicExpressionTreeValues(SymbolicExpressionTree tree, Dataset dataset, IEnumerable<int> rows) { 122 this.dataset = dataset;123 113 var compiler = new SymbolicExpressionTreeCompiler(); 124 compiler.AddInstructionPostProcessingHook(PostProcessInstruction); 125 code = compiler.Compile(tree, MapSymbolToOpCode); 126 foreach (var row in rows) { 127 this.row = row; 128 pc = 0; 129 argStackPointer = 0; 130 yield return Evaluate(); 131 } 132 } 133 134 private Instruction PostProcessInstruction(Instruction instr) { 135 if (instr.opCode == OpCodes.Variable) { 136 var variableTreeNode = instr.dynamicNode as VariableTreeNode; 137 instr.iArg0 = (ushort)dataset.GetVariableIndex(variableTreeNode.VariableName); 138 } else if (instr.opCode == OpCodes.LagVariable) { 139 var variableTreeNode = instr.dynamicNode as LaggedVariableTreeNode; 140 instr.iArg0 = (ushort)dataset.GetVariableIndex(variableTreeNode.VariableName); 141 } 142 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 } 143 280 } 144 281 … … 150 287 } 151 288 152 private double Evaluate() {153 Instruction currentInstr = code[pc++];154 switch (currentInstr.opCode) {155 case OpCodes.Add: {156 double s = Evaluate();157 for (int i = 1; i < currentInstr.nArguments; i++) {158 s += Evaluate();159 }160 return s;161 }162 case OpCodes.Sub: {163 double s = Evaluate();164 for (int i = 1; i < currentInstr.nArguments; i++) {165 s -= Evaluate();166 }167 if (currentInstr.nArguments == 1) s = -s;168 return s;169 }170 case OpCodes.Mul: {171 double p = Evaluate();172 for (int i = 1; i < currentInstr.nArguments; i++) {173 p *= Evaluate();174 }175 return p;176 }177 case OpCodes.Div: {178 double p = Evaluate();179 for (int i = 1; i < currentInstr.nArguments; i++) {180 p /= Evaluate();181 }182 if (currentInstr.nArguments == 1) p = 1.0 / p;183 return p;184 }185 case OpCodes.Average: {186 double sum = Evaluate();187 for (int i = 1; i < currentInstr.nArguments; i++) {188 sum += Evaluate();189 }190 return sum / currentInstr.nArguments;191 }192 case OpCodes.Cos: {193 return Math.Cos(Evaluate());194 }195 case OpCodes.Sin: {196 return Math.Sin(Evaluate());197 }198 case OpCodes.Tan: {199 return Math.Tan(Evaluate());200 }201 case OpCodes.Exp: {202 return Math.Exp(Evaluate());203 }204 case OpCodes.Log: {205 return Math.Log(Evaluate());206 }207 case OpCodes.IfThenElse: {208 double condition = Evaluate();209 double result;210 if (condition > 0.0) {211 result = Evaluate(); SkipBakedCode();212 } else {213 SkipBakedCode(); result = Evaluate();214 }215 return result;216 }217 case OpCodes.AND: {218 double result = Evaluate();219 for (int i = 1; i < currentInstr.nArguments; i++) {220 if (result <= 0.0) SkipBakedCode();221 else {222 result = Evaluate();223 }224 }225 return result <= 0.0 ? -1.0 : 1.0;226 }227 case OpCodes.OR: {228 double result = Evaluate();229 for (int i = 1; i < currentInstr.nArguments; i++) {230 if (result > 0.0) SkipBakedCode();231 else {232 result = Evaluate();233 }234 }235 return result > 0.0 ? 1.0 : -1.0;236 }237 case OpCodes.NOT: {238 return -Evaluate();239 }240 case OpCodes.GT: {241 double x = Evaluate();242 double y = Evaluate();243 if (x > y) return 1.0;244 else return -1.0;245 }246 case OpCodes.LT: {247 double x = Evaluate();248 double y = Evaluate();249 if (x < y) return 1.0;250 else return -1.0;251 }252 case OpCodes.Call: {253 // evaluate sub-trees254 // push on argStack in reverse order255 for (int i = 0; i < currentInstr.nArguments; i++) {256 argumentStack[argStackPointer + currentInstr.nArguments - i] = Evaluate();257 }258 argStackPointer += currentInstr.nArguments;259 260 // save the pc261 int nextPc = pc;262 // set pc to start of function263 pc = currentInstr.iArg0;264 // evaluate the function265 double v = Evaluate();266 267 // decrease the argument stack pointer by the number of arguments pushed268 // to set the argStackPointer back to the original location269 argStackPointer -= currentInstr.nArguments;270 271 // restore the pc => evaluation will continue at point after my subtrees272 pc = nextPc;273 return v;274 }275 case OpCodes.Arg: {276 return argumentStack[argStackPointer - currentInstr.iArg0];277 }278 case OpCodes.Variable: {279 var variableTreeNode = currentInstr.dynamicNode as VariableTreeNode;280 return dataset[row, currentInstr.iArg0] * variableTreeNode.Weight;281 }282 case OpCodes.LagVariable: {283 var lagVariableTreeNode = currentInstr.dynamicNode as LaggedVariableTreeNode;284 int actualRow = row + lagVariableTreeNode.Lag;285 if (actualRow < 0 || actualRow >= dataset.Rows) throw new ArgumentException("Out of range access to dataset row: " + row);286 return dataset[actualRow, currentInstr.iArg0] * lagVariableTreeNode.Weight;287 }288 case OpCodes.Constant: {289 var constTreeNode = currentInstr.dynamicNode as ConstantTreeNode;290 return constTreeNode.Value;291 }292 default: throw new NotSupportedException();293 }294 }295 296 289 // skips a whole branch 297 private void SkipBakedCode( ) {290 private void SkipBakedCode(Instruction[] code, ref int pc) { 298 291 int i = 1; 299 292 while (i > 0) {
Note: See TracChangeset
for help on using the changeset viewer.