Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.GP.StructureIdentification/BakedTreeEvaluator.cs @ 771

Last change on this file since 771 was 767, checked in by gkronber, 16 years ago

worked on #364 (Improve GP evaluation performance)

  • removed list of Instr
  • changes that didn't affect performance directly: reduced size of Instr class, added 'constant-folding' and pre-calculation of skip-lengths


File size: 11.3 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2008 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 System.Linq;
25using System.Text;
26using HeuristicLab.Core;
27using System.Xml;
28using System.Diagnostics;
29using HeuristicLab.DataAnalysis;
30
31namespace HeuristicLab.GP.StructureIdentification {
32  /// <summary>
33  /// Evaluates FunctionTrees recursively by interpretation of the function symbols in each node.
34  /// Not thread-safe!
35  /// </summary>
36  public class BakedTreeEvaluator {
37    private const double EPSILON = 1.0e-7;
38    private double estimatedValueMax;
39    private double estimatedValueMin;
40
41    private class Instr {
42      public double d_arg0;
43      public short i_arg0;
44      public short i_arg1;
45      public byte arity;
46      public byte symbol;
47      public ushort exprLength;
48      public IFunction function;
49    }
50
51    private Instr[] codeArr;
52    private int PC;
53    private Dataset dataset;
54    private int sampleIndex;
55
56    public void ResetEvaluator(BakedFunctionTree functionTree, Dataset dataset, int targetVariable, int start, int end, double punishmentFactor) {
57      this.dataset = dataset;
58      double maximumPunishment = punishmentFactor * dataset.GetRange(targetVariable);
59
60      // get the mean of the values of the target variable to determine the max and min bounds of the estimated value
61      double targetMean = dataset.GetMean(targetVariable, start, end - 1);
62      estimatedValueMin = targetMean - maximumPunishment;
63      estimatedValueMax = targetMean + maximumPunishment;
64
65      List<LightWeightFunction> linearRepresentation = functionTree.LinearRepresentation;
66      codeArr = new Instr[linearRepresentation.Count];
67      int i = 0;
68      foreach (LightWeightFunction f in linearRepresentation) {
69        codeArr[i++] = TranslateToInstr(f);
70      }
71      exprIndex = 0;
72      ushort exprLength;
73      bool constExpr;
74      PatchExpressionLengthsAndConstants(0, out constExpr, out exprLength);
75    }
76
77    ushort exprIndex;
78    private void PatchExpressionLengthsAndConstants(ushort index, out bool constExpr, out ushort exprLength) {
79      exprLength = 1;
80      if (codeArr[index].arity == 0) {
81        // when no children then it's a constant expression only if the terminal is a constant
82        constExpr = codeArr[index].symbol == EvaluatorSymbolTable.CONSTANT;
83      } else {
84        constExpr = true; // when there are children it's a constant expression if all children are constant;
85      }
86      for (int i = 0; i < codeArr[index].arity; i++) {
87        exprIndex++;
88        ushort branchLength;
89        bool branchConstExpr;
90        PatchExpressionLengthsAndConstants(exprIndex, out branchConstExpr, out branchLength);
91        exprLength += branchLength;
92        constExpr &= branchConstExpr;
93      }
94      codeArr[index].exprLength = exprLength;
95
96      if (constExpr) {
97        codeArr[index].symbol = EvaluatorSymbolTable.CONSTANT;
98        PC = index;
99        codeArr[index].d_arg0 = EvaluateBakedCode();
100      }
101    }
102
103    private Instr TranslateToInstr(LightWeightFunction f) {
104      Instr instr = new Instr();
105      instr.arity = f.arity;
106      instr.symbol = EvaluatorSymbolTable.MapFunction(f.functionType);
107      switch (instr.symbol) {
108        case EvaluatorSymbolTable.DIFFERENTIAL:
109        case EvaluatorSymbolTable.VARIABLE: {
110            instr.i_arg0 = (byte)f.data[0]; // var
111            instr.d_arg0 = f.data[1]; // weight
112            instr.i_arg1 = (byte)f.data[2]; // sample-offset
113            instr.exprLength = 1;
114            break;
115          }
116        case EvaluatorSymbolTable.CONSTANT: {
117            instr.d_arg0 = f.data[0]; // value
118            instr.exprLength = 1;
119            break;
120          }
121        case EvaluatorSymbolTable.UNKNOWN: {
122            instr.function = f.functionType;
123            instr.exprLength = 1;
124            break;
125          }
126      }
127      return instr;
128    }
129
130    public double Evaluate(int sampleIndex) {
131      PC = 0;
132      this.sampleIndex = sampleIndex;
133
134      double estimated = EvaluateBakedCode();
135      if (double.IsNaN(estimated) || double.IsInfinity(estimated)) {
136        estimated = estimatedValueMax;
137      } else if (estimated > estimatedValueMax) {
138        estimated = estimatedValueMax;
139      } else if (estimated < estimatedValueMin) {
140        estimated = estimatedValueMin;
141      }
142      return estimated;
143    }
144
145    // skips a whole branch
146    private void SkipBakedCode() {
147      PC += codeArr[PC].exprLength;
148    }
149
150    private double EvaluateBakedCode() {
151      Instr currInstr = codeArr[PC++];
152      switch (currInstr.symbol) {
153        case EvaluatorSymbolTable.VARIABLE: {
154            int row = sampleIndex + currInstr.i_arg1;
155            if (row < 0 || row >= dataset.Rows) return double.NaN;
156            else return currInstr.d_arg0 * dataset.GetValue(row, currInstr.i_arg0);
157          }
158        case EvaluatorSymbolTable.CONSTANT: {
159            PC += currInstr.exprLength - 1;
160            return currInstr.d_arg0;
161          }
162        case EvaluatorSymbolTable.DIFFERENTIAL: {
163            int row = sampleIndex + currInstr.i_arg1;
164            if (row < 1 || row >= dataset.Rows) return double.NaN;
165            else return currInstr.d_arg0 * (dataset.GetValue(row, currInstr.i_arg0) - dataset.GetValue(row - 1, currInstr.i_arg0));
166          }
167        case EvaluatorSymbolTable.MULTIPLICATION: {
168            double result = EvaluateBakedCode();
169            for (int i = 1; i < currInstr.arity; i++) {
170              result *= EvaluateBakedCode();
171            }
172            return result;
173          }
174        case EvaluatorSymbolTable.ADDITION: {
175            double sum = EvaluateBakedCode();
176            for (int i = 1; i < currInstr.arity; i++) {
177              sum += EvaluateBakedCode();
178            }
179            return sum;
180          }
181        case EvaluatorSymbolTable.SUBTRACTION: {
182            if (currInstr.arity == 1) {
183              return -EvaluateBakedCode();
184            } else {
185              double result = EvaluateBakedCode();
186              for (int i = 1; i < currInstr.arity; i++) {
187                result -= EvaluateBakedCode();
188              }
189              return result;
190            }
191          }
192        case EvaluatorSymbolTable.DIVISION: {
193            double result;
194            if (currInstr.arity == 1) {
195              result = 1.0 / EvaluateBakedCode();
196            } else {
197              result = EvaluateBakedCode();
198              for (int i = 1; i < currInstr.arity; i++) {
199                result /= EvaluateBakedCode();
200              }
201            }
202            if (double.IsInfinity(result)) return 0.0;
203            else return result;
204          }
205        case EvaluatorSymbolTable.AVERAGE: {
206            double sum = EvaluateBakedCode();
207            for (int i = 1; i < currInstr.arity; i++) {
208              sum += EvaluateBakedCode();
209            }
210            return sum / currInstr.arity;
211          }
212        case EvaluatorSymbolTable.COSINUS: {
213            return Math.Cos(EvaluateBakedCode());
214          }
215        case EvaluatorSymbolTable.SINUS: {
216            return Math.Sin(EvaluateBakedCode());
217          }
218        case EvaluatorSymbolTable.EXP: {
219            return Math.Exp(EvaluateBakedCode());
220          }
221        case EvaluatorSymbolTable.LOG: {
222            return Math.Log(EvaluateBakedCode());
223          }
224        case EvaluatorSymbolTable.POWER: {
225            double x = EvaluateBakedCode();
226            double p = EvaluateBakedCode();
227            return Math.Pow(x, p);
228          }
229        case EvaluatorSymbolTable.SIGNUM: {
230            double value = EvaluateBakedCode();
231            if (double.IsNaN(value)) return double.NaN;
232            else return Math.Sign(value);
233          }
234        case EvaluatorSymbolTable.SQRT: {
235            return Math.Sqrt(EvaluateBakedCode());
236          }
237        case EvaluatorSymbolTable.TANGENS: {
238            return Math.Tan(EvaluateBakedCode());
239          }
240        case EvaluatorSymbolTable.AND: { // only defined for inputs 1 and 0
241            double result = EvaluateBakedCode();
242            for (int i = 1; i < currInstr.arity; i++) {
243              if (result == 0.0) SkipBakedCode();
244              else {
245                result = EvaluateBakedCode();
246              }
247              Debug.Assert(result == 0.0 || result == 1.0);
248            }
249            return result;
250          }
251        case EvaluatorSymbolTable.EQU: {
252            double x = EvaluateBakedCode();
253            double y = EvaluateBakedCode();
254            if (Math.Abs(x - y) < EPSILON) return 1.0; else return 0.0;
255          }
256        case EvaluatorSymbolTable.GT: {
257            double x = EvaluateBakedCode();
258            double y = EvaluateBakedCode();
259            if (x > y) return 1.0;
260            else return 0.0;
261          }
262        case EvaluatorSymbolTable.IFTE: { // only defined for condition 0 or 1
263            double condition = EvaluateBakedCode();
264            Debug.Assert(condition == 0.0 || condition == 1.0);
265            double result;
266            if (condition == 0.0) {
267              result = EvaluateBakedCode(); SkipBakedCode();
268            } else {
269              SkipBakedCode(); result = EvaluateBakedCode();
270            }
271            return result;
272          }
273        case EvaluatorSymbolTable.LT: {
274            double x = EvaluateBakedCode();
275            double y = EvaluateBakedCode();
276            if (x < y) return 1.0;
277            else return 0.0;
278          }
279        case EvaluatorSymbolTable.NOT: { // only defined for inputs 0 or 1
280            double result = EvaluateBakedCode();
281            Debug.Assert(result == 0.0 || result == 1.0);
282            return Math.Abs(result - 1.0);
283          }
284        case EvaluatorSymbolTable.OR: { // only defined for inputs 0 or 1
285            double result = EvaluateBakedCode();
286            for (int i = 1; i < currInstr.arity; i++) {
287              if (result > 0.0) SkipBakedCode();
288              else {
289                result = EvaluateBakedCode();
290                Debug.Assert(result == 0.0 || result == 1.0);
291              }
292            }
293            return result;
294          }
295        case EvaluatorSymbolTable.XOR: { // only defined for inputs 0 or 1
296            double x = EvaluateBakedCode();
297            double y = EvaluateBakedCode();
298            return Math.Abs(x - y);
299          }
300        case EvaluatorSymbolTable.UNKNOWN: { // evaluate functions which are not statically defined directly
301            return currInstr.function.Apply();
302          }
303        default: {
304            throw new NotImplementedException();
305          }
306      }
307    }
308  }
309}
Note: See TracBrowser for help on using the repository browser.