Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Functions/BakedFunctionTree.cs @ 240

Last change on this file since 240 was 239, checked in by gkronber, 16 years ago

fixed #148

File size: 10.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 HeuristicLab.DataAnalysis;
28using HeuristicLab.Data;
29using System.Xml;
30
31namespace HeuristicLab.Functions {
32  class BakedFunctionTree : ItemBase, IFunctionTree {
33    private List<int> code;
34    private List<double> data;
35
36    public BakedFunctionTree() {
37      code = new List<int>();
38      data = new List<double>();
39    }
40
41    internal BakedFunctionTree(IFunction function)
42      : this() {
43      code.Add(0);
44      code.Add(BakedTreeEvaluator.MapFunction(function));
45      code.Add(0);
46      treesExpanded = true;
47      subTrees = new List<IFunctionTree>();
48      variables = new List<IVariable>();
49      variablesExpanded = true;
50      foreach(IVariableInfo variableInfo in function.VariableInfos) {
51        if(variableInfo.Local) {
52          variables.Add((IVariable)function.GetVariable(variableInfo.FormalName).Clone());
53        }
54      }
55    }
56
57    internal BakedFunctionTree(IFunctionTree tree)
58      : this() {
59      code.Add(0);
60      code.Add(BakedTreeEvaluator.MapFunction(tree.Function));
61      code.Add(tree.LocalVariables.Count);
62      foreach(IVariable variable in tree.LocalVariables) {
63        IItem value = variable.Value;
64        data.Add(GetDoubleValue(value));
65      }
66      foreach(IFunctionTree subTree in tree.SubTrees) {
67        AddSubTree(new BakedFunctionTree(subTree));
68      }
69    }
70
71    private double GetDoubleValue(IItem value) {
72      if(value is DoubleData) {
73        return ((DoubleData)value).Data;
74      } else if(value is ConstrainedDoubleData) {
75        return ((ConstrainedDoubleData)value).Data;
76      } else if(value is IntData) {
77        return ((IntData)value).Data;
78      } else if(value is ConstrainedIntData) {
79        return ((ConstrainedIntData)value).Data;
80      } else throw new NotSupportedException("Invalid datatype of local variable for GP");
81    }
82
83    private void BranchLength(int branchRoot, out int codeLength, out int dataLength) {
84      int arity = code[branchRoot];
85      int nLocalVariables = code[branchRoot + 2];
86      codeLength = 3;
87      dataLength = nLocalVariables;
88      int subBranchStart = branchRoot + codeLength;
89      for(int i = 0; i < arity; i++) {
90        int branchCodeLength;
91        int branchDataLength;
92        BranchLength(subBranchStart, out branchCodeLength, out branchDataLength);
93        subBranchStart += branchCodeLength;
94        codeLength += branchCodeLength;
95        dataLength += branchDataLength;
96      }
97    }
98
99    private void FlattenTrees() {
100      if(treesExpanded) {
101        code[0] = subTrees.Count;
102        foreach(BakedFunctionTree subTree in subTrees) {
103          subTree.FlattenVariables();
104          subTree.FlattenTrees();
105          code.AddRange(subTree.code);
106          data.AddRange(subTree.data);
107        }
108        treesExpanded = false;
109        subTrees = null;
110      }
111    }
112
113    private void FlattenVariables() {
114      if(variablesExpanded) {
115        code[2] = variables.Count;
116        foreach(IVariable variable in variables) {
117          data.Add(GetDoubleValue(variable.Value));
118        }
119        variablesExpanded = false;
120        variables = null;
121      }
122    }
123
124    private bool treesExpanded = false;
125    private List<IFunctionTree> subTrees;
126    public IList<IFunctionTree> SubTrees {
127      get {
128        if(!treesExpanded) {
129          subTrees = new List<IFunctionTree>();
130          int arity = code[0];
131          int nLocalVariables = code[2];
132          int branchIndex = 3;
133          int dataIndex = nLocalVariables; // skip my local variables to reach the local variables of the first branch
134          for(int i = 0; i < arity; i++) {
135            BakedFunctionTree subTree = new BakedFunctionTree();
136            int codeLength;
137            int dataLength;
138            BranchLength(branchIndex, out codeLength, out dataLength);
139            subTree.code = code.GetRange(branchIndex, codeLength);
140            subTree.data = data.GetRange(dataIndex, dataLength);
141            branchIndex += codeLength;
142            dataIndex += dataLength;
143            subTrees.Add(subTree);
144          }
145          treesExpanded = true;
146          code.RemoveRange(3, code.Count - 3);
147          code[0] = 0;
148          data.RemoveRange(nLocalVariables, data.Count - nLocalVariables);
149        }
150        return subTrees;
151      }
152    }
153
154    private bool variablesExpanded = false;
155    private List<IVariable> variables;
156    public ICollection<IVariable> LocalVariables {
157      get {
158        if(!variablesExpanded) {
159          variables = new List<IVariable>();
160          IFunction function = BakedTreeEvaluator.MapSymbol(code[1]);
161          int localVariableIndex = 0;
162          foreach(IVariableInfo variableInfo in function.VariableInfos) {
163            if(variableInfo.Local) {
164              IVariable clone = (IVariable)function.GetVariable(variableInfo.FormalName).Clone();
165              IItem value = clone.Value;
166              if(value is ConstrainedDoubleData) {
167                ((ConstrainedDoubleData)value).Data = data[localVariableIndex];
168              } else if(value is ConstrainedIntData) {
169                ((ConstrainedIntData)value).Data = (int)data[localVariableIndex];
170              } else if(value is DoubleData) {
171                ((DoubleData)value).Data = data[localVariableIndex];
172              } else if(value is IntData) {
173                ((IntData)value).Data = (int)data[localVariableIndex];
174              } else throw new NotSupportedException("Invalid local variable type for GP.");
175              variables.Add(clone);
176              localVariableIndex++;
177            }
178          }
179          variablesExpanded = true;
180          code[2] = 0;
181          data.RemoveRange(0, variables.Count);
182        }
183        return variables;
184      }
185    }
186
187    public IFunction Function {
188      get { return BakedTreeEvaluator.MapSymbol(code[1]); }
189    }
190
191    public IVariable GetLocalVariable(string name) {
192      foreach(IVariable var in LocalVariables) {
193        if(var.Name == name) return var;
194      }
195      return null;
196    }
197
198    public void AddVariable(IVariable variable) {
199      throw new NotSupportedException();
200    }
201
202    public void RemoveVariable(string name) {
203      throw new NotSupportedException();
204    }
205
206    public void AddSubTree(IFunctionTree tree) {
207      if(!treesExpanded) throw new InvalidOperationException();
208      subTrees.Add(tree);
209    }
210
211    public void InsertSubTree(int index, IFunctionTree tree) {
212      if(!treesExpanded) throw new InvalidOperationException();
213      subTrees.Insert(index, tree);
214    }
215
216    public void RemoveSubTree(int index) {
217      // sanity check
218      if(!treesExpanded) throw new InvalidOperationException();
219      subTrees.RemoveAt(index);
220    }
221
222    private BakedTreeEvaluator evaluator;
223    public double Evaluate(Dataset dataset, int sampleIndex) {
224      FlattenVariables();
225      FlattenTrees();
226      if(evaluator == null) evaluator = new BakedTreeEvaluator(code, data);
227      return evaluator.Evaluate(dataset, sampleIndex);
228    }
229
230
231    public override XmlNode GetXmlNode(string name, XmlDocument document, IDictionary<Guid, IStorable> persistedObjects) {
232      XmlNode node = base.GetXmlNode(name, document, persistedObjects);
233      node.AppendChild(PersistenceManager.Persist("Function", Function, document, persistedObjects));
234      XmlNode subTreesNode = document.CreateNode(XmlNodeType.Element, "SubTrees", null);
235      for(int i = 0; i < SubTrees.Count; i++)
236        subTreesNode.AppendChild(PersistenceManager.Persist(SubTrees[i], document, persistedObjects));
237      node.AppendChild(subTreesNode);
238      XmlNode variablesNode = document.CreateNode(XmlNodeType.Element, "Variables", null);
239      foreach(IVariable variable in LocalVariables)
240        variablesNode.AppendChild(PersistenceManager.Persist(variable, document, persistedObjects));
241      node.AppendChild(variablesNode);
242      return node;
243    }
244
245    public override void Populate(XmlNode node, IDictionary<Guid, IStorable> restoredObjects) {
246      base.Populate(node, restoredObjects);
247      IFunction function = (IFunction)PersistenceManager.Restore(node.SelectSingleNode("Function"), restoredObjects);
248      code.Add(0);
249      code.Add(BakedTreeEvaluator.MapFunction(function));
250      code.Add(0);
251      treesExpanded = true;
252      subTrees = new List<IFunctionTree>();
253      variables = new List<IVariable>();
254      variablesExpanded = true;
255      XmlNode subTreesNode = node.SelectSingleNode("SubTrees");
256      for(int i = 0; i < subTreesNode.ChildNodes.Count; i++)
257        subTrees.Add((IFunctionTree)PersistenceManager.Restore(subTreesNode.ChildNodes[i], restoredObjects));
258      XmlNode variablesNode = node.SelectSingleNode("Variables");
259      foreach(XmlNode variableNode in variablesNode.ChildNodes)
260        variables.Add((IVariable)PersistenceManager.Restore(variableNode, restoredObjects));
261    }
262
263    public override object Clone(IDictionary<Guid, object> clonedObjects) {
264      BakedFunctionTree clone = new BakedFunctionTree();
265      // in case the user (de)serialized the tree between evaluation and selection we have to flatten the tree again.
266      if(treesExpanded) FlattenTrees();
267      if(variablesExpanded) FlattenVariables();
268      clone.code.AddRange(code);
269      clone.data.AddRange(data);
270      return clone;
271    }
272
273    public override IView CreateView() {
274      return new FunctionTreeView(this);
275    }
276  }
277}
Note: See TracBrowser for help on using the repository browser.