Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 321 was 320, checked in by gkronber, 17 years ago

fixed serialization of function-trees (deactivated with r317) (ticket #168)

File size: 11.0 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 {
[317]33
34  class LightWeightFunction {
35    public int arity = 0;
36    public IFunction functionType;
37    public List<double> data = new List<double>();
38
39    public LightWeightFunction Clone() {
40      LightWeightFunction clone = new LightWeightFunction();
41      clone.arity = arity;
42      clone.functionType = functionType;
43      clone.data.AddRange(data);
44      return clone;
45    }
46  }
47
[203]48  class BakedFunctionTree : ItemBase, IFunctionTree {
[317]49    private List<LightWeightFunction> linearRepresentation;
50    private bool treesExpanded = false;
51    private List<IFunctionTree> subTrees;
52    private bool variablesExpanded = false;
53    private List<IVariable> variables;
54    private BakedTreeEvaluator evaluator = null;
55
[224]56    public BakedFunctionTree() {
[317]57      linearRepresentation = new List<LightWeightFunction>();
[203]58    }
59
[206]60    internal BakedFunctionTree(IFunction function)
61      : this() {
[317]62      LightWeightFunction fun = new LightWeightFunction();
63      fun.functionType = function;
64      linearRepresentation.Add(fun);
[203]65      treesExpanded = true;
66      subTrees = new List<IFunctionTree>();
67      variables = new List<IVariable>();
68      variablesExpanded = true;
69      foreach(IVariableInfo variableInfo in function.VariableInfos) {
70        if(variableInfo.Local) {
71          variables.Add((IVariable)function.GetVariable(variableInfo.FormalName).Clone());
72        }
73      }
74    }
75
[206]76    internal BakedFunctionTree(IFunctionTree tree)
77      : this() {
[317]78      LightWeightFunction fun = new LightWeightFunction();
79      fun.functionType = tree.Function;
80      linearRepresentation.Add(fun);
[203]81      foreach(IVariable variable in tree.LocalVariables) {
82        IItem value = variable.Value;
[317]83        fun.data.Add(GetDoubleValue(value));
[203]84      }
85      foreach(IFunctionTree subTree in tree.SubTrees) {
86        AddSubTree(new BakedFunctionTree(subTree));
87      }
88    }
89
90    private double GetDoubleValue(IItem value) {
91      if(value is DoubleData) {
92        return ((DoubleData)value).Data;
93      } else if(value is ConstrainedDoubleData) {
94        return ((ConstrainedDoubleData)value).Data;
95      } else if(value is IntData) {
96        return ((IntData)value).Data;
97      } else if(value is ConstrainedIntData) {
98        return ((ConstrainedIntData)value).Data;
99      } else throw new NotSupportedException("Invalid datatype of local variable for GP");
100    }
101
[317]102    private int BranchLength(int branchRoot) {
103      int arity = linearRepresentation[branchRoot].arity;
104      int length = 1;
[203]105      for(int i = 0; i < arity; i++) {
[317]106        length += BranchLength(branchRoot + length);
[203]107      }
[317]108      return length;
[203]109    }
110
111    private void FlattenTrees() {
112      if(treesExpanded) {
[317]113        linearRepresentation[0].arity = subTrees.Count;
[203]114        foreach(BakedFunctionTree subTree in subTrees) {
115          subTree.FlattenVariables();
116          subTree.FlattenTrees();
[317]117          linearRepresentation.AddRange(subTree.linearRepresentation);
[203]118        }
119        treesExpanded = false;
[206]120        subTrees = null;
[203]121      }
122    }
123
124    private void FlattenVariables() {
125      if(variablesExpanded) {
[317]126        linearRepresentation[0].data.Clear();
[203]127        foreach(IVariable variable in variables) {
[317]128          linearRepresentation[0].data.Add(GetDoubleValue(variable.Value));
[203]129        }
130        variablesExpanded = false;
[206]131        variables = null;
[203]132      }
133    }
134
135    public IList<IFunctionTree> SubTrees {
136      get {
137        if(!treesExpanded) {
138          subTrees = new List<IFunctionTree>();
[317]139          int arity = linearRepresentation[0].arity;
140          int branchIndex = 1;
[203]141          for(int i = 0; i < arity; i++) {
142            BakedFunctionTree subTree = new BakedFunctionTree();
[317]143            int length = BranchLength(branchIndex);
144            for(int j = branchIndex; j < branchIndex + length; j++) {
145              subTree.linearRepresentation.Add(linearRepresentation[j].Clone());
146            }
147            branchIndex += length;
[203]148            subTrees.Add(subTree);
149          }
150          treesExpanded = true;
[317]151          linearRepresentation.RemoveRange(1, linearRepresentation.Count - 1);
152          linearRepresentation[0].arity = 0;
[203]153        }
154        return subTrees;
155      }
156    }
157
158    public ICollection<IVariable> LocalVariables {
159      get {
160        if(!variablesExpanded) {
161          variables = new List<IVariable>();
[317]162          IFunction function = Function;
[220]163          int localVariableIndex = 0;
[203]164          foreach(IVariableInfo variableInfo in function.VariableInfos) {
165            if(variableInfo.Local) {
166              IVariable clone = (IVariable)function.GetVariable(variableInfo.FormalName).Clone();
167              IItem value = clone.Value;
168              if(value is ConstrainedDoubleData) {
[317]169                ((ConstrainedDoubleData)value).Data = linearRepresentation[0].data[localVariableIndex];
[203]170              } else if(value is ConstrainedIntData) {
[317]171                ((ConstrainedIntData)value).Data = (int)linearRepresentation[0].data[localVariableIndex];
[203]172              } else if(value is DoubleData) {
[317]173                ((DoubleData)value).Data = linearRepresentation[0].data[localVariableIndex];
[203]174              } else if(value is IntData) {
[317]175                ((IntData)value).Data = (int)linearRepresentation[0].data[localVariableIndex];
[203]176              } else throw new NotSupportedException("Invalid local variable type for GP.");
177              variables.Add(clone);
178              localVariableIndex++;
179            }
180          }
181          variablesExpanded = true;
[317]182          linearRepresentation[0].data.Clear();
[203]183        }
184        return variables;
185      }
186    }
187
188    public IFunction Function {
[317]189      get { return linearRepresentation[0].functionType; }
[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
223    public double Evaluate(Dataset dataset, int sampleIndex) {
224      FlattenVariables();
225      FlattenTrees();
[317]226      if(evaluator == null) evaluator = new BakedTreeEvaluator(linearRepresentation);
[239]227      return evaluator.Evaluate(dataset, sampleIndex);
[203]228    }
229
230
[224]231    public override XmlNode GetXmlNode(string name, XmlDocument document, IDictionary<Guid, IStorable> persistedObjects) {
[259]232      FlattenVariables();
233      FlattenTrees();
[224]234      XmlNode node = base.GetXmlNode(name, document, persistedObjects);
[320]235      XmlNode linearRepresentationNode = document.CreateElement("LinearRepresentation");
236      foreach(LightWeightFunction f in linearRepresentation) {
237        XmlNode entryNode = PersistenceManager.Persist("FunctionType", f.functionType, document, persistedObjects);
238        XmlAttribute arityAttribute = document.CreateAttribute("Arity");
239        arityAttribute.Value = f.arity+"";
240        entryNode.Attributes.Append(arityAttribute);
241        if(f.data.Count > 0) {
242          XmlAttribute dataAttribute = document.CreateAttribute("Data");
243          dataAttribute.Value = GetString<double>(f.data);
244          entryNode.Attributes.Append(dataAttribute);
245        }
246        linearRepresentationNode.AppendChild(entryNode);
247      }
248
249      node.AppendChild(linearRepresentationNode);
250      return node;
[203]251    }
252
[224]253    public override void Populate(XmlNode node, IDictionary<Guid, IStorable> restoredObjects) {
[320]254      base.Populate(node, restoredObjects);
255      XmlNode linearRepresentationNode = node.SelectSingleNode("LinearRepresentation");
256      foreach(XmlNode entryNode in linearRepresentationNode.ChildNodes) {
257        LightWeightFunction f = new LightWeightFunction();
258        f.arity = int.Parse(entryNode.Attributes["Arity"].Value, CultureInfo.InvariantCulture);
259        if(entryNode.Attributes["Data"]!=null)
260          f.data = GetList<double>(entryNode.Attributes["Data"].Value, s => double.Parse(s, CultureInfo.InvariantCulture));
261        f.functionType = (IFunction)PersistenceManager.Restore(entryNode, restoredObjects);
262        linearRepresentation.Add(f);
263      }
264      treesExpanded = false;
265      variablesExpanded = false;
[203]266    }
267
[320]268    private string GetString<T>(IEnumerable<T> xs) where T : IConvertible {
269      StringBuilder builder = new StringBuilder();
270      foreach(T x in xs) {
271        builder.Append(x.ToString(CultureInfo.InvariantCulture) + "; ");
272      }
273      if(builder.Length > 0) builder.Remove(builder.Length - 2, 2);
274      return builder.ToString();
275    }
[259]276
[320]277    private List<T> GetList<T>(string s, Converter<string, T> converter) {
278      List<T> result = new List<T>();
279      string[] tokens = s.Split(new char[] { ';', ' ' }, StringSplitOptions.RemoveEmptyEntries);
280      foreach(string token in tokens) {
281        T x = converter(token.Trim());
282        result.Add(x);
283      }
284      return result;
285    }
[259]286
[203]287    public override object Clone(IDictionary<Guid, object> clonedObjects) {
288      BakedFunctionTree clone = new BakedFunctionTree();
[224]289      // in case the user (de)serialized the tree between evaluation and selection we have to flatten the tree again.
[259]290      if(treesExpanded) FlattenTrees();
[224]291      if(variablesExpanded) FlattenVariables();
[317]292      foreach(LightWeightFunction f in linearRepresentation) {
293        clone.linearRepresentation.Add(f.Clone());
294      }
[203]295      return clone;
296    }
[220]297
298    public override IView CreateView() {
299      return new FunctionTreeView(this);
300    }
[203]301  }
302}
Note: See TracBrowser for help on using the repository browser.