Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 3668 was 3545, checked in by gkronber, 15 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
RevLine 
[3253]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;
[3376]24using HeuristicLab.Common;
[3253]25using HeuristicLab.Core;
26using System.Collections.Generic;
27using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
[3462]28using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Symbols;
[3373]29using HeuristicLab.Problems.DataAnalysis.Symbolic.Symbols;
[3462]30using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Compiler;
[3253]31
[3373]32namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
[3253]33  [StorableClass]
[3462]34  [Item("SimpleArithmeticExpressionInterpreter", "Interpreter for arithmetic symbolic expression trees including function calls.")]
[3491]35  // not thread safe!
[3513]36  public class SimpleArithmeticExpressionInterpreter : NamedItem, ISymbolicExpressionTreeInterpreter {
[3462]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
[3491]48    private const int ARGUMENT_STACK_SIZE = 1024;
[3513]49
[3257]50    private Dataset dataset;
51    private int row;
[3294]52    private Instruction[] code;
53    private int pc;
[3462]54
[3545]55    public override bool CanChangeName {
56      get { return false; }
57    }
58    public override bool CanChangeDescription {
59      get { return false; }
60    }
61
[3513]62    public SimpleArithmeticExpressionInterpreter()
63      : base() {
64    }
65
[3462]66    public IEnumerable<double> GetSymbolicExpressionTreeValues(SymbolicExpressionTree tree, Dataset dataset, IEnumerable<int> rows) {
[3257]67      this.dataset = dataset;
[3294]68      var compiler = new SymbolicExpressionTreeCompiler();
[3462]69      compiler.AddInstructionPostProcessingHook(PostProcessInstruction);
70      code = compiler.Compile(tree, MapSymbolToOpCode);
[3253]71      foreach (var row in rows) {
[3257]72        this.row = row;
[3294]73        pc = 0;
[3491]74        argStackPointer = 0;
[3513]75        yield return Evaluate();
[3253]76      }
77    }
78
[3462]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
[3491]99    private double[] argumentStack = new double[ARGUMENT_STACK_SIZE];
100    private int argStackPointer;
101
[3294]102    public double Evaluate() {
103      var currentInstr = code[pc++];
[3462]104      switch (currentInstr.opCode) {
105        case OpCodes.Add: {
[3294]106            double s = 0.0;
107            for (int i = 0; i < currentInstr.nArguments; i++) {
108              s += Evaluate();
109            }
110            return s;
111          }
[3462]112        case OpCodes.Sub: {
[3294]113            double s = Evaluate();
114            for (int i = 1; i < currentInstr.nArguments; i++) {
115              s -= Evaluate();
116            }
117            return s;
118          }
[3462]119        case OpCodes.Mul: {
[3294]120            double p = Evaluate();
121            for (int i = 1; i < currentInstr.nArguments; i++) {
122              p *= Evaluate();
123            }
124            return p;
125          }
[3462]126        case OpCodes.Div: {
[3294]127            double p = Evaluate();
128            for (int i = 1; i < currentInstr.nArguments; i++) {
129              p /= Evaluate();
130            }
131            return p;
132          }
[3462]133        case OpCodes.Call: {
[3409]134            // evaluate sub-trees
[3491]135            // push on argStack in reverse order
[3409]136            for (int i = 0; i < currentInstr.nArguments; i++) {
[3491]137              argumentStack[argStackPointer + currentInstr.nArguments - i] = Evaluate();
138              argStackPointer++;
[3409]139            }
[3491]140
[3409]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();
[3491]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
[3409]152            // restore the pc => evaluation will continue at point after my subtrees 
153            pc = nextPc;
154            return v;
155          }
[3462]156        case OpCodes.Arg: {
[3491]157            return argumentStack[argStackPointer - currentInstr.iArg0];
[3409]158          }
[3462]159        case OpCodes.Variable: {
[3373]160            var variableTreeNode = currentInstr.dynamicNode as VariableTreeNode;
[3462]161            return dataset[row, currentInstr.iArg0] * variableTreeNode.Weight;
162          }
163        case OpCodes.Constant: {
[3373]164            var constTreeNode = currentInstr.dynamicNode as ConstantTreeNode;
[3462]165            return constTreeNode.Value;
[3294]166          }
167        default: throw new NotSupportedException();
[3253]168      }
169    }
170  }
171}
Note: See TracBrowser for help on using the repository browser.