Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Problems.DataAnalysis/3.3/Symbolic/SimpleArithmeticExpressionInterpreter.cs @ 3747

Last change on this file since 3747 was 3747, checked in by gkronber, 14 years ago

Fixed bugs related to evaluation of ADFs in symbolic expressions. #791

File size: 6.4 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
24using HeuristicLab.Common;
25using HeuristicLab.Core;
26using System.Collections.Generic;
27using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
28using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Symbols;
29using HeuristicLab.Problems.DataAnalysis.Symbolic.Symbols;
30using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Compiler;
31
32namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
33  [StorableClass]
34  [Item("SimpleArithmeticExpressionInterpreter", "Interpreter for arithmetic symbolic expression trees including function calls.")]
35  // not thread safe!
36  public class SimpleArithmeticExpressionInterpreter : NamedItem, ISymbolicExpressionTreeInterpreter {
37    private class OpCodes {
38      public const byte Add = 1;
39      public const byte Sub = 2;
40      public const byte Mul = 3;
41      public const byte Div = 4;
42      public const byte Variable = 5;
43      public const byte Constant = 6;
44      public const byte Call = 100;
45      public const byte Arg = 101;
46    }
47
48    private const int ARGUMENT_STACK_SIZE = 1024;
49
50    private Dataset dataset;
51    private int row;
52    private Instruction[] code;
53    private int pc;
54
55    public override bool CanChangeName {
56      get { return false; }
57    }
58    public override bool CanChangeDescription {
59      get { return false; }
60    }
61
62    public SimpleArithmeticExpressionInterpreter()
63      : base() {
64    }
65
66    public IEnumerable<double> GetSymbolicExpressionTreeValues(SymbolicExpressionTree tree, Dataset dataset, IEnumerable<int> rows) {
67      this.dataset = dataset;
68      var compiler = new SymbolicExpressionTreeCompiler();
69      compiler.AddInstructionPostProcessingHook(PostProcessInstruction);
70      code = compiler.Compile(tree, MapSymbolToOpCode);
71      foreach (var row in rows) {
72        this.row = row;
73        pc = 0;
74        argStackPointer = 0;
75        yield return Evaluate();
76      }
77    }
78
79    private Instruction PostProcessInstruction(Instruction instr) {
80      if (instr.opCode == OpCodes.Variable) {
81        var variableTreeNode = instr.dynamicNode as VariableTreeNode;
82        instr.iArg0 = (ushort)dataset.GetVariableIndex(variableTreeNode.VariableName);
83      }
84      return instr;
85    }
86
87    private byte MapSymbolToOpCode(SymbolicExpressionTreeNode treeNode) {
88      if (treeNode.Symbol is Addition) return OpCodes.Add;
89      if (treeNode.Symbol is Subtraction) return OpCodes.Sub;
90      if (treeNode.Symbol is Multiplication) return OpCodes.Mul;
91      if (treeNode.Symbol is Division) return OpCodes.Div;
92      if (treeNode.Symbol is HeuristicLab.Problems.DataAnalysis.Symbolic.Symbols.Variable) return OpCodes.Variable;
93      if (treeNode.Symbol is Constant) return OpCodes.Constant;
94      if (treeNode.Symbol is InvokeFunction) return OpCodes.Call;
95      if (treeNode.Symbol is Argument) return OpCodes.Arg;
96      throw new NotSupportedException("Symbol: " + treeNode.Symbol);
97    }
98
99    private double[] argumentStack = new double[ARGUMENT_STACK_SIZE];
100    private int argStackPointer;
101
102    public double Evaluate() {
103      var currentInstr = code[pc++];
104      switch (currentInstr.opCode) {
105        case OpCodes.Add: {
106            double s = 0.0;
107            for (int i = 0; i < currentInstr.nArguments; i++) {
108              s += Evaluate();
109            }
110            return s;
111          }
112        case OpCodes.Sub: {
113            double s = Evaluate();
114            for (int i = 1; i < currentInstr.nArguments; i++) {
115              s -= Evaluate();
116            }
117            if (currentInstr.nArguments == 1) s = -s;
118            return s;
119          }
120        case OpCodes.Mul: {
121            double p = Evaluate();
122            for (int i = 1; i < currentInstr.nArguments; i++) {
123              p *= Evaluate();
124            }
125            return p;
126          }
127        case OpCodes.Div: {
128            double p = Evaluate();
129            for (int i = 1; i < currentInstr.nArguments; i++) {
130              p /= Evaluate();
131            }
132            if (currentInstr.nArguments == 1) p = 1.0 / p;
133            return p;
134          }
135        case OpCodes.Call: {
136            // evaluate sub-trees
137            // push on argStack in reverse order
138            for (int i = 0; i < currentInstr.nArguments; i++) {
139              argumentStack[argStackPointer + currentInstr.nArguments - i] = Evaluate();
140            }
141            argStackPointer += currentInstr.nArguments;
142
143            // save the pc
144            int nextPc = pc;
145            // set pc to start of function 
146            pc = currentInstr.iArg0;
147            // evaluate the function
148            double v = Evaluate();
149
150            // decrease the argument stack pointer by the number of arguments pushed
151            // to set the argStackPointer back to the original location
152            argStackPointer -= currentInstr.nArguments;
153
154            // restore the pc => evaluation will continue at point after my subtrees 
155            pc = nextPc;
156            return v;
157          }
158        case OpCodes.Arg: {
159            return argumentStack[argStackPointer - currentInstr.iArg0];
160          }
161        case OpCodes.Variable: {
162            var variableTreeNode = currentInstr.dynamicNode as VariableTreeNode;
163            return dataset[row, currentInstr.iArg0] * variableTreeNode.Weight;
164          }
165        case OpCodes.Constant: {
166            var constTreeNode = currentInstr.dynamicNode as ConstantTreeNode;
167            return constTreeNode.Value;
168          }
169        default: throw new NotSupportedException();
170      }
171    }
172  }
173}
Note: See TracBrowser for help on using the repository browser.