Free cookie consent management tool by TermsFeed Policy Generator

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

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

Fixed bugs in wiring of data analysis and symbolic regression problems. #938 (Data types and operators for regression problems)

File size: 6.3 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            return s;
118          }
119        case OpCodes.Mul: {
120            double p = Evaluate();
121            for (int i = 1; i < currentInstr.nArguments; i++) {
122              p *= Evaluate();
123            }
124            return p;
125          }
126        case OpCodes.Div: {
127            double p = Evaluate();
128            for (int i = 1; i < currentInstr.nArguments; i++) {
129              p /= Evaluate();
130            }
131            return p;
132          }
133        case OpCodes.Call: {
134            // evaluate sub-trees
135            // push on argStack in reverse order
136            for (int i = 0; i < currentInstr.nArguments; i++) {
137              argumentStack[argStackPointer + currentInstr.nArguments - i] = Evaluate();
138              argStackPointer++;
139            }
140
141            // save the pc
142            int nextPc = pc;
143            // set pc to start of function 
144            pc = currentInstr.iArg0;
145            // evaluate the function
146            double v = Evaluate();
147
148            // decrease the argument stack pointer by the number of arguments pushed
149            // to set the argStackPointer back to the original location
150            argStackPointer -= currentInstr.nArguments;
151
152            // restore the pc => evaluation will continue at point after my subtrees 
153            pc = nextPc;
154            return v;
155          }
156        case OpCodes.Arg: {
157            return argumentStack[argStackPointer - currentInstr.iArg0];
158          }
159        case OpCodes.Variable: {
160            var variableTreeNode = currentInstr.dynamicNode as VariableTreeNode;
161            return dataset[row, currentInstr.iArg0] * variableTreeNode.Weight;
162          }
163        case OpCodes.Constant: {
164            var constTreeNode = currentInstr.dynamicNode as ConstantTreeNode;
165            return constTreeNode.Value;
166          }
167        default: throw new NotSupportedException();
168      }
169    }
170  }
171}
Note: See TracBrowser for help on using the repository browser.