Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
01/11/11 15:03:46 (13 years ago)
Author:
gkronber
Message:

Merged changes from trunk to data analysis exploration branch and added fractional distance metric evaluator. #1142

File:
1 edited

Legend:

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

    r4193 r5275  
    2222using System;
    2323using System.Collections.Generic;
     24using HeuristicLab.Common;
    2425using HeuristicLab.Core;
    2526using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
     
    3233  [StorableClass]
    3334  [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 {
    3636    private class OpCodes {
    3737      public const byte Add = 1;
     
    6565      public const byte Constant = 20;
    6666      public const byte Arg = 21;
    67       public const byte Differential = 22;
    6867    }
    6968
     
    9089      { typeof(Constant), OpCodes.Constant },
    9190      { typeof(Argument), OpCodes.Arg },
    92       { typeof(DifferentialVariable), OpCodes.Differential},
    9391    };
    9492    private const int ARGUMENT_STACK_SIZE = 1024;
    9593
    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 
    10394    public override bool CanChangeName {
    10495      get { return false; }
     
    10899    }
    109100
     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
    110108    public SimpleArithmeticExpressionInterpreter()
    111109      : base() {
     
    113111
    114112    public IEnumerable<double> GetSymbolicExpressionTreeValues(SymbolicExpressionTree tree, Dataset dataset, IEnumerable<int> rows) {
    115       this.dataset = dataset;
    116113      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      }
    139280    }
    140281
     
    146287    }
    147288
    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-trees
    250             // push on argStack in reverse order
    251             for (int i = 0; i < currentInstr.nArguments; i++) {
    252               argumentStack[argStackPointer + currentInstr.nArguments - i] = Evaluate();
    253             }
    254             argStackPointer += currentInstr.nArguments;
    255 
    256             // save the pc
    257             int nextPc = pc;
    258             // set pc to start of function 
    259             pc = currentInstr.iArg0;
    260             // evaluate the function
    261             double v = Evaluate();
    262 
    263             // decrease the argument stack pointer by the number of arguments pushed
    264             // to set the argStackPointer back to the original location
    265             argStackPointer -= currentInstr.nArguments;
    266 
    267             // restore the pc => evaluation will continue at point after my subtrees 
    268             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 
    298289    // skips a whole branch
    299     protected void SkipBakedCode() {
     290    private void SkipBakedCode(Instruction[] code, ref int pc) {
    300291      int i = 1;
    301292      while (i > 0) {
Note: See TracChangeset for help on using the changeset viewer.