#region License Information
/* HeuristicLab
* Copyright (C) 2002-2008 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
*
* This file is part of HeuristicLab.
*
* HeuristicLab is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HeuristicLab is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with HeuristicLab. If not, see .
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HeuristicLab.DataAnalysis;
using HeuristicLab.Core;
using System.Xml;
namespace HeuristicLab.Functions {
internal static class BakedTreeEvaluator {
private const int MAX_TREE_SIZE = 4096;
private const int MAX_TREE_DEPTH = 20;
private class Instr {
public double result;
public double d_arg0;
public int i_arg0;
public int i_arg1;
public int arity;
public int symbol;
}
private static int[] nInstr;
private static Instr[,] evaluationTable;
private static Dataset dataset;
private static int sampleIndex;
static BakedTreeEvaluator() {
evaluationTable = new Instr[MAX_TREE_SIZE, MAX_TREE_DEPTH];
nInstr = new int[MAX_TREE_DEPTH];
for(int j = 0; j < MAX_TREE_DEPTH; j++) {
for(int i = 0; i < MAX_TREE_SIZE; i++) {
evaluationTable[i, j] = new Instr();
}
}
}
public static void ResetEvaluator(List linearRepresentation) {
int length;
for(int i = 0; i < MAX_TREE_DEPTH; i++) nInstr[i] = 0;
//TranslateToInstr(0, linearRepresentation, out length);
int[] heights = new int[linearRepresentation.Count];
CalcHeights(linearRepresentation, heights, 0, out length);
TranslateToTable(0, linearRepresentation, heights);
}
private static int CalcHeights(List linearRepresentation, int[] heights, int p, out int branchLength) {
if(linearRepresentation[p].arity == 0) {
heights[p] = 1;
branchLength = 1;
return 1;
}
int height = 0;
int length = 1;
for(int i = 0; i < linearRepresentation[p].arity; i++) {
int curBranchLength;
int curHeight = CalcHeights(linearRepresentation, heights, p + length, out curBranchLength);
if(curHeight > height) {
height = curHeight;
}
length += curBranchLength;
}
heights[p] = height+1;
branchLength = length;
return height+1;
}
private static int TranslateToTable(int pos, List list, int[] heights) {
LightWeightFunction f = list[pos];
if(f.arity == 0) {
Instr instr = evaluationTable[nInstr[0], 0];
instr.symbol = EvaluatorSymbolTable.MapFunction(f.functionType);
switch(instr.symbol) {
case EvaluatorSymbolTable.VARIABLE: {
instr.i_arg0 = (int)f.data[0]; // var
instr.d_arg0 = f.data[1]; // weight
instr.i_arg1 = (int)f.data[2]; // sample-offset
break;
}
case EvaluatorSymbolTable.CONSTANT: {
instr.result = f.data[0]; // value
break;
}
}
nInstr[0]++;
return 1;
} else {
int length = 1;
int height = heights[pos];
for(int i = 0; i < f.arity; i++) {
int curBranchHeight = heights[pos + length];
if(curBranchHeight < height - 1) {
for(int j = curBranchHeight; j < height - 1; j++) {
evaluationTable[nInstr[j], j].symbol = EvaluatorSymbolTable.IDENTITY;
nInstr[j]++;
}
}
int curBranchLength = TranslateToTable(pos + length, list, heights);
length += curBranchLength;
}
Instr cell = evaluationTable[nInstr[height-1], height-1];
nInstr[height-1]++;
cell.arity = f.arity;
cell.symbol = EvaluatorSymbolTable.MapFunction(f.functionType);
return length;
}
}
//private static int TranslateToInstr(int pos, List linearRepresentation, out int branchLength) {
// int height = 0;
// int length = 1;
// LightWeightFunction f = linearRepresentation[pos];
// for(int i = 0; i < f.arity; i++) {
// int curBranchLength;
// int curBranchHeight = TranslateToInstr(pos + length, linearRepresentation, out curBranchLength);
// if(curBranchHeight > height) height = curBranchHeight;
// length += curBranchLength;
// }
// Instr instr = evaluationTable[nInstr[height], height];
// instr.arity = f.arity;
// instr.symbol = EvaluatorSymbolTable.MapFunction(f.functionType);
// switch(instr.symbol) {
// case EvaluatorSymbolTable.VARIABLE: {
// instr.i_arg0 = (int)f.data[0]; // var
// instr.d_arg0 = f.data[1]; // weight
// instr.i_arg1 = (int)f.data[2]; // sample-offset
// break;
// }
// case EvaluatorSymbolTable.CONSTANT: {
// instr.result = f.data[0]; // value
// break;
// }
// }
// nInstr[height]++;
// branchLength = length;
// return height + 1;
//}
internal static double Evaluate(Dataset dataset, int sampleIndex) {
BakedTreeEvaluator.sampleIndex = sampleIndex;
BakedTreeEvaluator.dataset = dataset;
return EvaluateTable();
}
private static double EvaluateTable() {
int terminalP = 0;
// process remaining instr first
for(int i = 0; i < nInstr[0] % 4; i++) {
Instr curInstr = evaluationTable[terminalP++, 0];
if(curInstr.symbol == EvaluatorSymbolTable.VARIABLE) {
int row = sampleIndex + curInstr.i_arg1;
if(row < 0 || row >= dataset.Rows) curInstr.result = double.NaN;
else curInstr.result = curInstr.d_arg0 * dataset.GetValue(row, curInstr.i_arg0);
}
}
// unrolled loop
for(; terminalP < nInstr[0] - 4; terminalP += 4) {
Instr curInstr0 = evaluationTable[terminalP, 0];
Instr curInstr1 = evaluationTable[terminalP + 1, 0];
Instr curInstr2 = evaluationTable[terminalP + 2, 0];
Instr curInstr3 = evaluationTable[terminalP + 3, 0];
if(curInstr0.symbol == EvaluatorSymbolTable.VARIABLE) {
int row = sampleIndex + curInstr0.i_arg1;
if(row < 0 || row >= dataset.Rows) curInstr0.result = double.NaN;
else curInstr0.result = curInstr0.d_arg0 * dataset.GetValue(row, curInstr0.i_arg0);
}
if(curInstr1.symbol == EvaluatorSymbolTable.VARIABLE) {
int row = sampleIndex + curInstr1.i_arg1;
if(row < 0 || row >= dataset.Rows) curInstr1.result = double.NaN;
else curInstr1.result = curInstr1.d_arg0 * dataset.GetValue(row, curInstr1.i_arg0);
}
if(curInstr2.symbol == EvaluatorSymbolTable.VARIABLE) {
int row = sampleIndex + curInstr2.i_arg1;
if(row < 0 || row >= dataset.Rows) curInstr2.result = double.NaN;
else curInstr2.result = curInstr2.d_arg0 * dataset.GetValue(row, curInstr2.i_arg0);
}
if(curInstr3.symbol == EvaluatorSymbolTable.VARIABLE) {
int row = sampleIndex + curInstr3.i_arg1;
if(row < 0 || row >= dataset.Rows) curInstr3.result = double.NaN;
else curInstr3.result = curInstr3.d_arg0 * dataset.GetValue(row, curInstr3.i_arg0);
}
}
int curLevel = 1;
while(nInstr[curLevel] > 0) {
int lastLayerInstrP = 0;
for(int curLayerInstrP = 0; curLayerInstrP < nInstr[curLevel]; curLayerInstrP++) {
Instr curInstr = evaluationTable[curLayerInstrP, curLevel];
switch(curInstr.symbol) {
case EvaluatorSymbolTable.MULTIPLICATION: {
curInstr.result = evaluationTable[lastLayerInstrP++, curLevel - 1].result;
for(int i = 1; i < curInstr.arity; i++) {
curInstr.result *= evaluationTable[lastLayerInstrP++, curLevel - 1].result;
}
break;
}
case EvaluatorSymbolTable.ADDITION: {
curInstr.result = evaluationTable[lastLayerInstrP++, curLevel - 1].result;
for(int i = 1; i < curInstr.arity; i++) {
curInstr.result += evaluationTable[lastLayerInstrP++, curLevel - 1].result;
}
break;
}
case EvaluatorSymbolTable.SUBTRACTION: {
if(curInstr.arity == 1) {
curInstr.result = -evaluationTable[lastLayerInstrP++, curLevel - 1].result;
} else {
curInstr.result = evaluationTable[lastLayerInstrP++, curLevel - 1].result;
for(int i = 1; i < curInstr.arity; i++) {
curInstr.result -= evaluationTable[lastLayerInstrP++, curLevel - 1].result;
}
}
break;
}
case EvaluatorSymbolTable.DIVISION: {
if(curInstr.arity == 1) {
curInstr.result = 1.0 / evaluationTable[lastLayerInstrP++, curLevel - 1].result;
} else {
curInstr.result = evaluationTable[lastLayerInstrP++, curLevel - 1].result;
for(int i = 1; i < curInstr.arity; i++) {
curInstr.result /= evaluationTable[lastLayerInstrP++, curLevel - 1].result;
}
}
if(double.IsInfinity(curInstr.result)) curInstr.result = 0.0;
break;
}
case EvaluatorSymbolTable.AVERAGE: {
curInstr.result = evaluationTable[lastLayerInstrP++, curLevel - 1].result;
for(int i = 1; i < curInstr.arity; i++) {
curInstr.result += evaluationTable[lastLayerInstrP++, curLevel - 1].result;
}
curInstr.result /= curInstr.arity;
break;
}
case EvaluatorSymbolTable.COSINUS: {
curInstr.result = Math.Cos(evaluationTable[lastLayerInstrP++, curLevel - 1].result);
break;
}
case EvaluatorSymbolTable.SINUS: {
curInstr.result = Math.Sin(evaluationTable[lastLayerInstrP++, curLevel - 1].result);
break;
}
case EvaluatorSymbolTable.EXP: {
curInstr.result = Math.Exp(evaluationTable[lastLayerInstrP++, curLevel - 1].result);
break;
}
case EvaluatorSymbolTable.LOG: {
curInstr.result = Math.Log(evaluationTable[lastLayerInstrP++, curLevel - 1].result);
break;
}
case EvaluatorSymbolTable.POWER: {
double x = evaluationTable[lastLayerInstrP++, curLevel - 1].result;
double p = evaluationTable[lastLayerInstrP++, curLevel - 1].result;
curInstr.result = Math.Pow(x, p);
break;
}
case EvaluatorSymbolTable.SIGNUM: {
double value = evaluationTable[lastLayerInstrP++, curLevel - 1].result;
if(double.IsNaN(value)) curInstr.result = double.NaN;
else curInstr.result = Math.Sign(value);
break;
}
case EvaluatorSymbolTable.SQRT: {
curInstr.result = Math.Sqrt(evaluationTable[lastLayerInstrP++, curLevel - 1].result);
break;
}
case EvaluatorSymbolTable.TANGENS: {
curInstr.result = Math.Tan(evaluationTable[lastLayerInstrP++, curLevel - 1].result);
break;
}
//case EvaluatorSymbolTable.AND: {
// double result = 1.0;
// // have to evaluate all sub-trees, skipping would probably not lead to a big gain because
// // we have to iterate over the linear structure anyway
// for(int i = 0; i < currInstr.arity; i++) {
// double x = Math.Round(EvaluateBakedCode());
// if(x == 0 || x == 1.0) result *= x;
// else result = double.NaN;
// }
// return result;
// }
//case EvaluatorSymbolTable.EQU: {
// double x = EvaluateBakedCode();
// double y = EvaluateBakedCode();
// if(x == y) return 1.0; else return 0.0;
// }
//case EvaluatorSymbolTable.GT: {
// double x = EvaluateBakedCode();
// double y = EvaluateBakedCode();
// if(x > y) return 1.0;
// else return 0.0;
// }
//case EvaluatorSymbolTable.IFTE: {
// double condition = Math.Round(EvaluateBakedCode());
// double x = EvaluateBakedCode();
// double y = EvaluateBakedCode();
// if(condition < .5) return x;
// else if(condition >= .5) return y;
// else return double.NaN;
// }
//case EvaluatorSymbolTable.LT: {
// double x = EvaluateBakedCode();
// double y = EvaluateBakedCode();
// if(x < y) return 1.0;
// else return 0.0;
// }
//case EvaluatorSymbolTable.NOT: {
// double result = Math.Round(EvaluateBakedCode());
// if(result == 0.0) return 1.0;
// else if(result == 1.0) return 0.0;
// else return double.NaN;
// }
//case EvaluatorSymbolTable.OR: {
// double result = 0.0; // default is false
// for(int i = 0; i < currInstr.arity; i++) {
// double x = Math.Round(EvaluateBakedCode());
// if(x == 1.0 && result == 0.0) result = 1.0; // found first true (1.0) => set to true
// else if(x != 0.0) result = double.NaN; // if it was not true it can only be false (0.0) all other cases are undefined => (NaN)
// }
// return result;
// }
//case EvaluatorSymbolTable.XOR: {
// double x = Math.Round(EvaluateBakedCode());
// double y = Math.Round(EvaluateBakedCode());
// if(x == 0.0 && y == 0.0) return 0.0;
// if(x == 1.0 && y == 0.0) return 1.0;
// if(x == 0.0 && y == 1.0) return 1.0;
// if(x == 1.0 && y == 1.0) return 0.0;
// return double.NaN;
// }
case EvaluatorSymbolTable.IDENTITY: {
curInstr.result = evaluationTable[lastLayerInstrP++, curLevel - 1].result;
break;
}
default: {
throw new NotImplementedException();
}
}
}
curLevel++;
}
return evaluationTable[0, curLevel - 1].result;
}
}
}