Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.GP/3.3/BakedFunctionTree.cs @ 2219

Last change on this file since 2219 was 2174, checked in by gkronber, 16 years ago

Implemented #302 (Show variable names instead of var<index> in GP function trees).

  • Added a new operator that chooses a random value from a list of possible values.
  • Changed mutation operator for variables and differentials
  • Changed internal linear representation of function trees to support different types for local data.
File size: 12.8 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.Data;
28using System.Xml;
29using System.Globalization;
30
31namespace HeuristicLab.GP {
32
33  public class LightWeightFunction {
34    public byte arity = 0;
35    public IFunction functionType;
36    public List<object> localData = new List<object>();
37
38    public LightWeightFunction Clone() {
39      LightWeightFunction clone = new LightWeightFunction();
40      clone.arity = arity;
41      clone.functionType = functionType;
42      clone.localData.AddRange(localData);
43      return clone;
44    }
45  }
46
47  public class BakedFunctionTree : ItemBase, IFunctionTree {
48    private List<LightWeightFunction> linearRepresentation;
49    public List<LightWeightFunction> LinearRepresentation {
50      get {
51        FlattenVariables();
52        FlattenTrees();
53        return linearRepresentation;
54      }
55    }
56    private bool treesExpanded = false;
57    private List<IFunctionTree> subTrees;
58    private bool variablesExpanded = false;
59    private List<IVariable> variables;
60
61    public BakedFunctionTree() {
62      linearRepresentation = new List<LightWeightFunction>();
63    }
64
65    internal BakedFunctionTree(IFunction function)
66      : this() {
67      LightWeightFunction fun = new LightWeightFunction();
68      fun.functionType = function;
69      linearRepresentation.Add(fun);
70      treesExpanded = true;
71      subTrees = new List<IFunctionTree>();
72      variables = new List<IVariable>();
73      variablesExpanded = true;
74      foreach (IVariableInfo variableInfo in function.VariableInfos) {
75        if (variableInfo.Local) {
76          variables.Add((IVariable)function.GetVariable(variableInfo.FormalName).Clone());
77        }
78      }
79    }
80
81    internal BakedFunctionTree(IFunctionTree tree)
82      : this() {
83      LightWeightFunction fun = new LightWeightFunction();
84      fun.functionType = tree.Function;
85      linearRepresentation.Add(fun);
86      foreach (IVariable variable in tree.LocalVariables) {
87        IObjectData value = (IObjectData)variable.Value;
88        fun.localData.Add(value.Data);
89      }
90      foreach (IFunctionTree subTree in tree.SubTrees) {
91        AddSubTree(new BakedFunctionTree(subTree));
92      }
93    }
94
95    private int BranchLength(int branchRoot) {
96      int arity = linearRepresentation[branchRoot].arity;
97      int length = 1;
98      for (int i = 0; i < arity; i++) {
99        length += BranchLength(branchRoot + length);
100      }
101      return length;
102    }
103
104    private void FlattenTrees() {
105      if (treesExpanded) {
106        linearRepresentation[0].arity = (byte)subTrees.Count;
107        foreach (BakedFunctionTree subTree in subTrees) {
108          subTree.FlattenVariables();
109          subTree.FlattenTrees();
110          linearRepresentation.AddRange(subTree.linearRepresentation);
111        }
112        treesExpanded = false;
113        subTrees = null;
114      }
115    }
116
117    private void FlattenVariables() {
118      if (variablesExpanded) {
119        linearRepresentation[0].localData.Clear();
120        foreach (IVariable variable in variables) {
121          object objData = variable.Value;
122          while (objData is IObjectData) objData = ((IObjectData)objData).Data;
123          linearRepresentation[0].localData.Add(objData);
124        }
125        variablesExpanded = false;
126        variables = null;
127      }
128    }
129
130    public int Size {
131      get {
132        if (treesExpanded) {
133          int size = 1;
134          foreach (BakedFunctionTree tree in subTrees) {
135            size += tree.Size;
136          }
137          return size;
138        } else
139          return linearRepresentation.Count;
140      }
141    }
142
143    public int Height {
144      get {
145        if (treesExpanded) {
146          int height = 0;
147          foreach (IFunctionTree subTree in subTrees) {
148            int curHeight = subTree.Height;
149            if (curHeight > height) height = curHeight;
150          }
151          return height + 1;
152        } else {
153          int nextBranchStart;
154          return BranchHeight(0, out nextBranchStart);
155        }
156      }
157    }
158
159    private int BranchHeight(int branchStart, out int nextBranchStart) {
160      LightWeightFunction f = linearRepresentation[branchStart];
161      int height = 0;
162      branchStart++;
163      for (int i = 0; i < f.arity; i++) {
164        int curHeight = BranchHeight(branchStart, out nextBranchStart);
165        if (curHeight > height) height = curHeight;
166        branchStart = nextBranchStart;
167      }
168      nextBranchStart = branchStart;
169      return height + 1;
170    }
171
172    public IList<IFunctionTree> SubTrees {
173      get {
174        if (!treesExpanded) {
175          subTrees = new List<IFunctionTree>();
176          int arity = linearRepresentation[0].arity;
177          int branchIndex = 1;
178          for (int i = 0; i < arity; i++) {
179            BakedFunctionTree subTree = new BakedFunctionTree();
180            int length = BranchLength(branchIndex);
181            for (int j = branchIndex; j < branchIndex + length; j++) {
182              subTree.linearRepresentation.Add(linearRepresentation[j]);
183            }
184            branchIndex += length;
185            subTrees.Add(subTree);
186          }
187          treesExpanded = true;
188          linearRepresentation.RemoveRange(1, linearRepresentation.Count - 1);
189          linearRepresentation[0].arity = 0;
190        }
191        return subTrees;
192      }
193    }
194
195    public ICollection<IVariable> LocalVariables {
196      get {
197        if (!variablesExpanded) {
198          variables = new List<IVariable>();
199          IFunction function = Function;
200          int localVariableIndex = 0;
201          foreach (IVariableInfo variableInfo in function.VariableInfos) {
202            if (variableInfo.Local) {
203              IVariable clone = (IVariable)function.GetVariable(variableInfo.FormalName).Clone();
204              IObjectData objData = (IObjectData)clone.Value;
205              if (objData is ConstrainedDoubleData) {
206                ((ConstrainedDoubleData)objData).Data = (double)linearRepresentation[0].localData[localVariableIndex];
207              } else if (objData is ConstrainedIntData) {
208                ((ConstrainedIntData)objData).Data = (int)linearRepresentation[0].localData[localVariableIndex];
209              } else {
210                objData.Data = linearRepresentation[0].localData[localVariableIndex];
211              }
212              variables.Add(clone);
213              localVariableIndex++;
214            }
215          }
216          variablesExpanded = true;
217          linearRepresentation[0].localData.Clear();
218        }
219        return variables;
220      }
221    }
222
223    public IFunction Function {
224      get { return linearRepresentation[0].functionType; }
225    }
226
227    public IVariable GetLocalVariable(string name) {
228      foreach (IVariable var in LocalVariables) {
229        if (var.Name == name) return var;
230      }
231      return null;
232    }
233
234    public void AddVariable(IVariable variable) {
235      throw new NotSupportedException();
236    }
237
238    public void RemoveVariable(string name) {
239      throw new NotSupportedException();
240    }
241
242    public void AddSubTree(IFunctionTree tree) {
243      if (!treesExpanded) throw new InvalidOperationException();
244      subTrees.Add(tree);
245    }
246
247    public void InsertSubTree(int index, IFunctionTree tree) {
248      if (!treesExpanded) throw new InvalidOperationException();
249      subTrees.Insert(index, tree);
250    }
251
252    public void RemoveSubTree(int index) {
253      // sanity check
254      if (!treesExpanded) throw new InvalidOperationException();
255      subTrees.RemoveAt(index);
256    }
257
258    public override XmlNode GetXmlNode(string name, XmlDocument document, IDictionary<Guid, IStorable> persistedObjects) {
259      FlattenVariables();
260      FlattenTrees();
261      XmlNode node = base.GetXmlNode(name, document, persistedObjects);
262      XmlNode linearRepresentationNode = document.CreateElement("LinearRepresentation");
263      foreach (LightWeightFunction f in linearRepresentation) {
264        XmlNode entryNode = PersistenceManager.Persist("Function", f.functionType, document, persistedObjects);
265        XmlAttribute arityAttribute = document.CreateAttribute("Arity");
266        arityAttribute.Value = XmlConvert.ToString(f.arity);
267        entryNode.Attributes.Append(arityAttribute);
268        foreach (object o in f.localData) {
269          if (f.localData.Count > 0) {
270            entryNode.AppendChild(CreateDataNode(document, o));
271          }
272        }
273        linearRepresentationNode.AppendChild(entryNode);
274      }
275
276      node.AppendChild(linearRepresentationNode);
277      return node;
278    }
279
280    private XmlNode CreateDataNode(XmlDocument doc, object o) {
281      XmlNode node = doc.CreateElement("Data");
282      XmlAttribute typeAttr = doc.CreateAttribute("Type");
283      node.Attributes.Append(typeAttr);
284      if (o is double) {
285        node.Value = XmlConvert.ToString((double)o);
286        typeAttr.Value = "d";
287      } else if (o is int) {
288        node.Value = XmlConvert.ToString((int)o);
289        typeAttr.Value = "i";
290      } else if (o is string) {
291        node.Value = (string)o;
292        typeAttr.Value = "s";
293      } else throw new ArgumentException("Invalid type for local data element: " + o);
294      return node;
295    }
296
297    public override void Populate(XmlNode node, IDictionary<Guid, IStorable> restoredObjects) {
298      base.Populate(node, restoredObjects);
299      XmlNode linearRepresentationNode = node.SelectSingleNode("LinearRepresentation");
300      foreach (XmlNode entryNode in linearRepresentationNode.ChildNodes) {
301        LightWeightFunction f = new LightWeightFunction();
302        f.arity = XmlConvert.ToByte(entryNode.Attributes["Arity"].Value);
303        foreach (XmlNode dataNode in entryNode.ChildNodes) {
304          f.localData.Add(ParseDataNode(dataNode));
305        }
306        f.functionType = (IFunction)PersistenceManager.Restore(entryNode, restoredObjects);
307        linearRepresentation.Add(f);
308      }
309      treesExpanded = false;
310      variablesExpanded = false;
311    }
312
313    private object ParseDataNode(XmlNode dataNode) {
314      string type = dataNode.Attributes["Type"].Value;
315      if (type == "d") {
316        return XmlConvert.ToDouble(dataNode.Value);
317      } else if (type == "i") {
318        return XmlConvert.ToInt32(dataNode.Value);
319      } else if (type == "s") {
320        return dataNode.Value;
321      } else throw new FormatException("Can't parse type \"" + type + "\" \"" + dataNode.Value + "\" as local data for GP trees");
322    }
323
324    //private string GetString(IEnumerable<double> xs) {
325    //  StringBuilder builder = new StringBuilder();
326    //  foreach (double x in xs) {
327    //    builder.Append(x.ToString("r", CultureInfo.InvariantCulture) + "; ");
328    //  }
329    //  if (builder.Length > 0) builder.Remove(builder.Length - 2, 2);
330    //  return builder.ToString();
331    //}
332
333    //private List<T> GetList<T>(string s, Converter<string, T> converter) {
334    //  List<T> result = new List<T>();
335    //  string[] tokens = s.Split(new char[] { ';', ' ' }, StringSplitOptions.RemoveEmptyEntries);
336    //  foreach (string token in tokens) {
337    //    T x = converter(token.Trim());
338    //    result.Add(x);
339    //  }
340    //  return result;
341    //}
342
343    public override object Clone(IDictionary<Guid, object> clonedObjects) {
344      BakedFunctionTree clone = new BakedFunctionTree();
345      // in case the user (de)serialized the tree between evaluation and selection we have to flatten the tree again.
346      if (treesExpanded) FlattenTrees();
347      if (variablesExpanded) FlattenVariables();
348      foreach (LightWeightFunction f in linearRepresentation) {
349        clone.linearRepresentation.Add(f.Clone());
350      }
351      return clone;
352    }
353
354    public override IView CreateView() {
355      return new FunctionTreeView(this);
356    }
357
358    //public override string ToString() {
359    //  SymbolicExpressionExporter exporter = new SymbolicExpressionExporter();
360    //  exporter.Visit(this);
361    //  return exporter.GetStringRepresentation();
362    //}
363  }
364}
Note: See TracBrowser for help on using the repository browser.