Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 275 was 260, checked in by gkronber, 17 years ago

fixed #146 (serialization of function-trees in linear form)

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