Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Problems.ExternalEvaluation.GP/3.3/Interpretation/TreeInterpreter.cs @ 4108

Last change on this file since 4108 was 4108, checked in by abeham, 14 years ago

#1033

  • Changed collection to list
  • Rebuilding dispatcher after every change to the list

#1110

  • Added clone method
File size: 9.0 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 System.Collections.Generic;
24using HeuristicLab.Core;
25using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
26using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Compiler;
27using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Symbols;
28using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
29
30namespace HeuristicLab.Problems.ExternalEvaluation.GP {
31  [StorableClass]
32  [Item("TreeInterpreter", "Interpreter for arithmetic symbolic expression trees including function calls.")]
33  // not thread safe!
34  public class TreeInterpreter : NamedItem, ISymbolicExpressionTreeInterpreter {
35    private class OpCodes {
36      public const byte Add = 1;
37      public const byte Sub = 2;
38      public const byte Mul = 3;
39      public const byte Div = 4;
40
41      public const byte Sin = 5;
42      public const byte Cos = 6;
43      public const byte Tan = 7;
44
45      public const byte Log = 8;
46      public const byte Exp = 9;
47
48      public const byte IfThenElse = 10;
49
50      public const byte GT = 11;
51      public const byte LT = 12;
52
53      public const byte AND = 13;
54      public const byte OR = 14;
55      public const byte NOT = 15;
56
57
58      public const byte Average = 16;
59
60      public const byte Call = 17;
61
62      public const byte Variable = 18;
63      public const byte Constant = 19;
64      public const byte Arg = 20;
65    }
66
67    private Dictionary<Type, byte> symbolToOpcode = new Dictionary<Type, byte>() {
68      { typeof(Addition), OpCodes.Add },
69      { typeof(Subtraction), OpCodes.Sub },
70      { typeof(Multiplication), OpCodes.Mul },
71      { typeof(Division), OpCodes.Div },
72      { typeof(Sine), OpCodes.Sin },
73      { typeof(Cosine), OpCodes.Cos },
74      { typeof(Tangent), OpCodes.Tan },
75      { typeof(Logarithm), OpCodes.Log },
76      { typeof(Exponential), OpCodes.Exp },
77      { typeof(IfThenElse), OpCodes.IfThenElse },
78      { typeof(GreaterThan), OpCodes.GT },
79      { typeof(LessThan), OpCodes.LT },
80      { typeof(And), OpCodes.AND },
81      { typeof(Or), OpCodes.OR },
82      { typeof(Not), OpCodes.NOT},
83      { typeof(Average), OpCodes.Average},
84      { typeof(InvokeFunction), OpCodes.Call },
85      { typeof(Variable), OpCodes.Variable },
86      { typeof(Constant), OpCodes.Constant },
87      { typeof(Argument), OpCodes.Arg },
88    };
89    private const int ARGUMENT_STACK_SIZE = 1024;
90
91    private Dictionary<string, double> variables;
92    private Instruction[] code;
93    private int pc;
94   
95    public override bool CanChangeName {
96      get { return false; }
97    }
98    public override bool CanChangeDescription {
99      get { return false; }
100    }
101
102    public TreeInterpreter()
103      : base() {
104    }
105
106    public void Prepare(SymbolicExpressionTree tree) {
107      var compiler = new SymbolicExpressionTreeCompiler();
108      code = compiler.Compile(tree, MapSymbolToOpCode);
109    }
110
111    public double InterpretTree(Dictionary<string, double> variables) {
112      this.variables = variables;
113      pc = 0;
114      argStackPointer = 0;
115      return Evaluate();
116    }
117
118    private byte MapSymbolToOpCode(SymbolicExpressionTreeNode treeNode) {
119      if (symbolToOpcode.ContainsKey(treeNode.Symbol.GetType()))
120        return symbolToOpcode[treeNode.Symbol.GetType()];
121      else
122        throw new NotSupportedException("Symbol: " + treeNode.Symbol);
123    }
124
125    private double[] argumentStack = new double[ARGUMENT_STACK_SIZE];
126    private int argStackPointer;
127
128    private double Evaluate() {
129      var currentInstr = code[pc++];
130      switch (currentInstr.opCode) {
131        case OpCodes.Add: {
132            double s = 0.0;
133            for (int i = 0; i < currentInstr.nArguments; i++) {
134              s += Evaluate();
135            }
136            return s;
137          }
138        case OpCodes.Sub: {
139            double s = Evaluate();
140            for (int i = 1; i < currentInstr.nArguments; i++) {
141              s -= Evaluate();
142            }
143            if (currentInstr.nArguments == 1) s = -s;
144            return s;
145          }
146        case OpCodes.Mul: {
147            double p = Evaluate();
148            for (int i = 1; i < currentInstr.nArguments; i++) {
149              p *= Evaluate();
150            }
151            return p;
152          }
153        case OpCodes.Div: {
154            double p = Evaluate();
155            for (int i = 1; i < currentInstr.nArguments; i++) {
156              p /= Evaluate();
157            }
158            if (currentInstr.nArguments == 1) p = 1.0 / p;
159            return p;
160          }
161        case OpCodes.Average: {
162            double sum = Evaluate();
163            for (int i = 1; i < currentInstr.nArguments; i++) {
164              sum += Evaluate();
165            }
166            return sum / currentInstr.nArguments;
167          }
168        case OpCodes.Cos: {
169            return Math.Cos(Evaluate());
170          }
171        case OpCodes.Sin: {
172            return Math.Sin(Evaluate());
173          }
174        case OpCodes.Tan: {
175            return Math.Tan(Evaluate());
176          }
177        case OpCodes.Exp: {
178            return Math.Exp(Evaluate());
179          }
180        case OpCodes.Log: {
181            return Math.Log(Evaluate());
182          }
183        case OpCodes.IfThenElse: {
184            double condition = Evaluate();
185            double result;
186            if (condition > 0.0) {
187              result = Evaluate(); SkipBakedCode();
188            } else {
189              SkipBakedCode(); result = Evaluate();
190            }
191            return result;
192          }
193        case OpCodes.AND: {
194            double result = Evaluate();
195            for (int i = 1; i < currentInstr.nArguments; i++) {
196              if (result <= 0.0) SkipBakedCode();
197              else {
198                result = Evaluate();
199              }
200            }
201            return result <= 0.0 ? -1.0 : 1.0;
202          }
203        case OpCodes.OR: {
204            double result = Evaluate();
205            for (int i = 1; i < currentInstr.nArguments; i++) {
206              if (result > 0.0) SkipBakedCode();
207              else {
208                result = Evaluate();
209              }
210            }
211            return result > 0.0 ? 1.0 : -1.0;
212          }
213        case OpCodes.NOT: {
214            return -Evaluate();
215          }
216        case OpCodes.GT: {
217            double x = Evaluate();
218            double y = Evaluate();
219            if (x > y) return 1.0;
220            else return -1.0;
221          }
222        case OpCodes.LT: {
223            double x = Evaluate();
224            double y = Evaluate();
225            if (x < y) return 1.0;
226            else return -1.0;
227          }
228        case OpCodes.Call: {
229            // evaluate sub-trees
230            // push on argStack in reverse order
231            for (int i = 0; i < currentInstr.nArguments; i++) {
232              argumentStack[argStackPointer + currentInstr.nArguments - i] = Evaluate();
233            }
234            argStackPointer += currentInstr.nArguments;
235
236            // save the pc
237            int nextPc = pc;
238            // set pc to start of function 
239            pc = currentInstr.iArg0;
240            // evaluate the function
241            double v = Evaluate();
242
243            // decrease the argument stack pointer by the number of arguments pushed
244            // to set the argStackPointer back to the original location
245            argStackPointer -= currentInstr.nArguments;
246
247            // restore the pc => evaluation will continue at point after my subtrees 
248            pc = nextPc;
249            return v;
250          }
251        case OpCodes.Arg: {
252            return argumentStack[argStackPointer - currentInstr.iArg0];
253          }
254        case OpCodes.Variable: {
255            var variableTreeNode = currentInstr.dynamicNode as VariableTreeNode;
256            return variables[variableTreeNode.VariableName] * variableTreeNode.Weight;
257          }
258        case OpCodes.Constant: {
259            var constTreeNode = currentInstr.dynamicNode as ConstantTreeNode;
260            return constTreeNode.Value;
261          }
262        default: throw new NotSupportedException();
263      }
264    }
265
266    // skips a whole branch
267    protected void SkipBakedCode() {
268      int i = 1;
269      while (i > 0) {
270        i += code[pc++].nArguments;
271        i--;
272      }
273    }
274  }
275}
Note: See TracBrowser for help on using the repository browser.