Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Hive_Milestone2/sources/HeuristicLab.GP.StructureIdentification/3.3/BakedTreeEvaluator.cs @ 7005

Last change on this file since 7005 was 1796, checked in by gkronber, 15 years ago

Refactored GP evaluation to make it possible to use different evaluators to interpret function trees. #615 (Evaluation of HL3 function trees should be equivalent to evaluation in HL2)

File size: 10.2 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 : ItemBase, ITreeEvaluator {
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 IFunction function;
48    }
49
50    private Instr[] codeArr;
51    private int PC;
52    private Dataset dataset;
53    private int sampleIndex;
54
55    public void ResetEvaluator(Dataset dataset, int targetVariable, int start, int end, double punishmentFactor) {
56      this.dataset = dataset;
57      double maximumPunishment = punishmentFactor * dataset.GetRange(targetVariable, start, end);
58
59      // get the mean of the values of the target variable to determine the max and min bounds of the estimated value
60      double targetMean = dataset.GetMean(targetVariable, start, end);
61      estimatedValueMin = targetMean - maximumPunishment;
62      estimatedValueMax = targetMean + maximumPunishment;
63
64    }
65
66    private Instr TranslateToInstr(LightWeightFunction f) {
67      Instr instr = new Instr();
68      instr.arity = f.arity;
69      instr.symbol = EvaluatorSymbolTable.MapFunction(f.functionType);
70      switch (instr.symbol) {
71        case EvaluatorSymbolTable.DIFFERENTIAL:
72        case EvaluatorSymbolTable.VARIABLE: {
73            instr.i_arg0 = (short)f.data[0]; // var
74            instr.d_arg0 = f.data[1]; // weight
75            instr.i_arg1 = (short)f.data[2]; // sample-offset
76            break;
77          }
78        case EvaluatorSymbolTable.CONSTANT: {
79            instr.d_arg0 = f.data[0]; // value
80            break;
81          }
82        case EvaluatorSymbolTable.UNKNOWN: {
83            instr.function = f.functionType;
84            break;
85          }
86      }
87      return instr;
88    }
89
90    public double Evaluate(IFunctionTree functionTree, int sampleIndex) {
91      BakedFunctionTree bakedTree = functionTree as BakedFunctionTree;
92      if (bakedTree == null) throw new ArgumentException("BakedTreeEvaluator can only evaluate BakedFunctionTrees");
93
94      List<LightWeightFunction> linearRepresentation = bakedTree.LinearRepresentation;
95      codeArr = new Instr[linearRepresentation.Count];
96      int i = 0;
97      foreach (LightWeightFunction f in linearRepresentation) {
98        codeArr[i++] = TranslateToInstr(f);
99      }
100
101      PC = 0;
102      this.sampleIndex = sampleIndex;
103
104      double estimated = EvaluateBakedCode();
105      if (double.IsNaN(estimated) || double.IsInfinity(estimated)) {
106        estimated = estimatedValueMax;
107      } else if (estimated > estimatedValueMax) {
108        estimated = estimatedValueMax;
109      } else if (estimated < estimatedValueMin) {
110        estimated = estimatedValueMin;
111      }
112      return estimated;
113    }
114
115    // skips a whole branch
116    private void SkipBakedCode() {
117      int i = 1;
118      while (i > 0) {
119        i += codeArr[PC++].arity;
120        i--;
121      }
122    }
123
124    private double EvaluateBakedCode() {
125      Instr currInstr = codeArr[PC++];
126      switch (currInstr.symbol) {
127        case EvaluatorSymbolTable.VARIABLE: {
128            int row = sampleIndex + currInstr.i_arg1;
129            if (row < 0 || row >= dataset.Rows) return double.NaN;
130            else return currInstr.d_arg0 * dataset.GetValue(row, currInstr.i_arg0);
131          }
132        case EvaluatorSymbolTable.CONSTANT: {
133            return currInstr.d_arg0;
134          }
135        case EvaluatorSymbolTable.DIFFERENTIAL: {
136            int row = sampleIndex + currInstr.i_arg1;
137            if (row < 0 || row >= dataset.Rows) return double.NaN;
138            else if (row < 1) return 0.0;
139            else {
140              double prevValue = dataset.GetValue(row - 1, currInstr.i_arg0);
141              if (double.IsNaN(prevValue) || double.IsInfinity(prevValue)) return 0.0;
142              else return currInstr.d_arg0 * (dataset.GetValue(row, currInstr.i_arg0) - prevValue);
143            }
144          }
145        case EvaluatorSymbolTable.MULTIPLICATION: {
146            double result = EvaluateBakedCode();
147            for (int i = 1; i < currInstr.arity; i++) {
148              result *= EvaluateBakedCode();
149            }
150            return result;
151          }
152        case EvaluatorSymbolTable.ADDITION: {
153            double sum = EvaluateBakedCode();
154            for (int i = 1; i < currInstr.arity; i++) {
155              sum += EvaluateBakedCode();
156            }
157            return sum;
158          }
159        case EvaluatorSymbolTable.SUBTRACTION: {
160            double result = EvaluateBakedCode();
161            for (int i = 1; i < currInstr.arity; i++) {
162              result -= EvaluateBakedCode();
163            }
164            return result;
165          }
166        case EvaluatorSymbolTable.DIVISION: {
167            double result;
168            result = EvaluateBakedCode();
169            for (int i = 1; i < currInstr.arity; i++) {
170              result /= EvaluateBakedCode();
171            }
172            if (double.IsInfinity(result)) return 0.0;
173            else return result;
174          }
175        case EvaluatorSymbolTable.AVERAGE: {
176            double sum = EvaluateBakedCode();
177            for (int i = 1; i < currInstr.arity; i++) {
178              sum += EvaluateBakedCode();
179            }
180            return sum / currInstr.arity;
181          }
182        case EvaluatorSymbolTable.COSINUS: {
183            return Math.Cos(EvaluateBakedCode());
184          }
185        case EvaluatorSymbolTable.SINUS: {
186            return Math.Sin(EvaluateBakedCode());
187          }
188        case EvaluatorSymbolTable.EXP: {
189            return Math.Exp(EvaluateBakedCode());
190          }
191        case EvaluatorSymbolTable.LOG: {
192            return Math.Log(EvaluateBakedCode());
193          }
194        case EvaluatorSymbolTable.POWER: {
195            double x = EvaluateBakedCode();
196            double p = EvaluateBakedCode();
197            return Math.Pow(x, p);
198          }
199        case EvaluatorSymbolTable.SIGNUM: {
200            double value = EvaluateBakedCode();
201            if (double.IsNaN(value)) return double.NaN;
202            else return Math.Sign(value);
203          }
204        case EvaluatorSymbolTable.SQRT: {
205            return Math.Sqrt(EvaluateBakedCode());
206          }
207        case EvaluatorSymbolTable.TANGENS: {
208            return Math.Tan(EvaluateBakedCode());
209          }
210        case EvaluatorSymbolTable.AND: { // only defined for inputs 1 and 0
211            double result = EvaluateBakedCode();
212            for (int i = 1; i < currInstr.arity; i++) {
213              if (result == 0.0) SkipBakedCode();
214              else {
215                result = EvaluateBakedCode();
216              }
217              Debug.Assert(result == 0.0 || result == 1.0);
218            }
219            return result;
220          }
221        case EvaluatorSymbolTable.EQU: {
222            double x = EvaluateBakedCode();
223            double y = EvaluateBakedCode();
224            if (Math.Abs(x - y) < EPSILON) return 1.0; else return 0.0;
225          }
226        case EvaluatorSymbolTable.GT: {
227            double x = EvaluateBakedCode();
228            double y = EvaluateBakedCode();
229            if (x > y) return 1.0;
230            else return 0.0;
231          }
232        case EvaluatorSymbolTable.IFTE: { // only defined for condition 0 or 1
233            double condition = EvaluateBakedCode();
234            Debug.Assert(condition == 0.0 || condition == 1.0);
235            double result;
236            if (condition == 0.0) {
237              result = EvaluateBakedCode(); SkipBakedCode();
238            } else {
239              SkipBakedCode(); result = EvaluateBakedCode();
240            }
241            return result;
242          }
243        case EvaluatorSymbolTable.LT: {
244            double x = EvaluateBakedCode();
245            double y = EvaluateBakedCode();
246            if (x < y) return 1.0;
247            else return 0.0;
248          }
249        case EvaluatorSymbolTable.NOT: { // only defined for inputs 0 or 1
250            double result = EvaluateBakedCode();
251            Debug.Assert(result == 0.0 || result == 1.0);
252            return Math.Abs(result - 1.0);
253          }
254        case EvaluatorSymbolTable.OR: { // only defined for inputs 0 or 1
255            double result = EvaluateBakedCode();
256            for (int i = 1; i < currInstr.arity; i++) {
257              if (result > 0.0) SkipBakedCode();
258              else {
259                result = EvaluateBakedCode();
260                Debug.Assert(result == 0.0 || result == 1.0);
261              }
262            }
263            return result;
264          }
265        case EvaluatorSymbolTable.XOR: { // only defined for inputs 0 or 1
266            double x = EvaluateBakedCode();
267            double y = EvaluateBakedCode();
268            return Math.Abs(x - y);
269          }
270        case EvaluatorSymbolTable.UNKNOWN: { // evaluate functions which are not statically defined directly
271            return currInstr.function.Apply();
272          }
273        default: {
274            throw new NotImplementedException();
275          }
276      }
277    }
278  }
279}
Note: See TracBrowser for help on using the repository browser.