Free cookie consent management tool by TermsFeed Policy Generator

Changeset 5223


Ignore:
Timestamp:
01/05/11 14:53:11 (14 years ago)
Author:
mkommend
Message:

Made SimpleArithmeticExpressionInterpreter thread safe (ticket #1333).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/sources/HeuristicLab.Problems.DataAnalysis/3.3/Symbolic/SimpleArithmeticExpressionInterpreter.cs

    r4722 r5223  
    3333  [StorableClass]
    3434  [Item("SimpleArithmeticExpressionInterpreter", "Interpreter for arithmetic symbolic expression trees including function calls.")]
    35   // not thread safe!
    3635  public sealed class SimpleArithmeticExpressionInterpreter : NamedItem, ISymbolicExpressionTreeInterpreter {
    3736    private class OpCodes {
     
    9392    private const int ARGUMENT_STACK_SIZE = 1024;
    9493
    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 
    10294    public override bool CanChangeName {
    10395      get { return false; }
     
    110102    private SimpleArithmeticExpressionInterpreter(bool deserializing) : base(deserializing) { }
    111103    private SimpleArithmeticExpressionInterpreter(SimpleArithmeticExpressionInterpreter original, Cloner cloner) : base(original, cloner) { }
    112 
    113104    public override IDeepCloneable Clone(Cloner cloner) {
    114105      return new SimpleArithmeticExpressionInterpreter(this, cloner);
     
    120111
    121112    public IEnumerable<double> GetSymbolicExpressionTreeValues(SymbolicExpressionTree tree, Dataset dataset, IEnumerable<int> rows) {
    122       this.dataset = dataset;
    123113      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      }
    143280    }
    144281
     
    150287    }
    151288
    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-trees
    254             // push on argStack in reverse order
    255             for (int i = 0; i < currentInstr.nArguments; i++) {
    256               argumentStack[argStackPointer + currentInstr.nArguments - i] = Evaluate();
    257             }
    258             argStackPointer += currentInstr.nArguments;
    259 
    260             // save the pc
    261             int nextPc = pc;
    262             // set pc to start of function 
    263             pc = currentInstr.iArg0;
    264             // evaluate the function
    265             double v = Evaluate();
    266 
    267             // decrease the argument stack pointer by the number of arguments pushed
    268             // to set the argStackPointer back to the original location
    269             argStackPointer -= currentInstr.nArguments;
    270 
    271             // restore the pc => evaluation will continue at point after my subtrees 
    272             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 
    296289    // skips a whole branch
    297     private void SkipBakedCode() {
     290    private void SkipBakedCode(Instruction[] code, ref int pc) {
    298291      int i = 1;
    299292      while (i > 0) {
Note: See TracChangeset for help on using the changeset viewer.