source: trunk/sources/HeuristicLab.GP/3.3/BaseClasses/FunctionBase.cs @ 2675

Last change on this file since 2675 was 2675, checked in by gkronber, 10 years ago

Implemented a fix in TreeGardener for #836 (Initial population doesn't contain all functions in combination with SimpleFunctionLibraryInjector). Added test cases for SimpleFunctionLibraryInjector. Changed code for calculation of minTreeHeight and minTreeSize in FunctionBase

File size: 7.9 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.Text;
25using HeuristicLab.Core;
26using System.Xml;
27using System.Diagnostics;
28using HeuristicLab.GP.Interfaces;
29using System.Linq;
30
31namespace HeuristicLab.GP {
32  public abstract class FunctionBase : ItemBase, IFunction {
33    private List<List<IFunction>> allowedSubFunctions = new List<List<IFunction>>();
34    private int minArity = -1;
35    private int maxArity = -1;
36    private double tickets = 1.0;
37    private IOperator initializer;
38    private IOperator manipulator;
39    private int minTreeHeight = -1;
40    private int minTreeSize = -1;
41
42    public virtual string Name {
43      get { return this.GetType().Name; }
44    }
45
46    public virtual string Description {
47      get { return "Description for this function is missing (TODO)"; }
48    }
49
50    public int MinSubTrees {
51      get {
52        return minArity;
53      }
54      protected set {
55        minArity = value;
56        while (minArity > allowedSubFunctions.Count) allowedSubFunctions.Add(new List<IFunction>());
57      }
58    }
59
60    public int MaxSubTrees {
61      get {
62        return maxArity;
63      }
64      protected set {
65        maxArity = value;
66        while (allowedSubFunctions.Count > maxArity) allowedSubFunctions.RemoveAt(allowedSubFunctions.Count - 1);
67        while (maxArity > allowedSubFunctions.Count) allowedSubFunctions.Add(new List<IFunction>());
68      }
69    }
70
71
72    public int MinTreeSize {
73      get {
74        if (minTreeSize <= 0) RecalculateMinimalTreeSize();
75        Debug.Assert(minTreeSize > 0);
76        return minTreeSize;
77      }
78    }
79
80    public int MinTreeHeight {
81      get {
82        if (minTreeHeight <= 0) RecalculateMinimalTreeHeight();
83        Debug.Assert(minTreeHeight > 0);
84        return minTreeHeight;
85      }
86    }
87
88    public double Tickets {
89      get { return tickets; }
90      set {
91        if (value < 0.0) throw new ArgumentException("Number of tickets must be positive");
92        else tickets = value;
93      }
94    }
95
96    public IOperator Initializer {
97      get { return initializer; }
98      set { initializer = value; }
99    }
100
101    public IOperator Manipulator {
102      get { return manipulator; }
103      set { manipulator = value; }
104    }
105
106    public virtual IFunctionTree GetTreeNode() {
107      return new FunctionTreeBase(this);
108    }
109
110    public ICollection<IFunction> GetAllowedSubFunctions(int index) {
111      if (index < 0 || index > MaxSubTrees) throw new ArgumentException("Index outside of allowed range. index = " + index);
112      return allowedSubFunctions[index];
113    }
114
115    public void AddAllowedSubFunction(IFunction function, int index) {
116      if (index < 0 || index > MaxSubTrees) throw new ArgumentException("Index outside of allowed range. index = " + index);
117      if (allowedSubFunctions[index] == null) {
118        allowedSubFunctions[index] = new List<IFunction>();
119      }
120      if (!allowedSubFunctions[index].Contains(function)) {
121        allowedSubFunctions[index].Add(function);
122      }
123    }
124
125    public void RemoveAllowedSubFunction(IFunction function, int index) {
126      if (index < 0 || index > MaxSubTrees) throw new ArgumentException("Index outside of allowed range. index = " + index);
127      allowedSubFunctions[index].Add(function);
128    }
129
130    public bool IsAllowedSubFunction(IFunction function, int index) {
131      return GetAllowedSubFunctions(index).Contains(function);
132    }
133
134    private void RecalculateMinimalTreeSize() {
135      if (MinSubTrees == 0) minTreeSize = 1;
136      else {
137        minTreeSize = int.MaxValue; // prevent infinite recursion
138        minTreeSize = 1 + (from slot in Enumerable.Range(0, MinSubTrees)
139                           let minForSlot = (from function in GetAllowedSubFunctions(slot)
140                                             where function != this
141                                             select function.MinTreeSize).Min()
142                           select minForSlot).Sum();
143      }
144    }
145
146    private void RecalculateMinimalTreeHeight() {
147      if (MinSubTrees == 0) minTreeHeight = 1;
148      else {
149        minTreeHeight = int.MaxValue;
150        minTreeHeight = 1 + (from slot in Enumerable.Range(0, MinSubTrees)
151                             let minForSlot = (from function in GetAllowedSubFunctions(slot)
152                                               where function != this
153                                               select function.MinTreeHeight).Min()
154                             select minForSlot).Max();
155      }
156    }
157
158    public override object Clone(IDictionary<Guid, object> clonedObjects) {
159      FunctionBase clone = (FunctionBase)base.Clone(clonedObjects);
160      clone.initializer = (IOperator)Auxiliary.Clone(initializer, clonedObjects);
161      clone.manipulator = (IOperator)Auxiliary.Clone(manipulator, clonedObjects);
162      clone.maxArity = maxArity;
163      clone.minArity = minArity;
164      clone.minTreeHeight = minTreeHeight;
165      clone.minTreeSize = minTreeSize;
166      clone.tickets = tickets;
167      for (int i = 0; i < MaxSubTrees; i++) {
168        var allowedSubFunctionsForSlot = new List<IFunction>();
169        foreach (IFunction f in GetAllowedSubFunctions(i)) {
170          allowedSubFunctionsForSlot.Add((IFunction)Auxiliary.Clone(f, clonedObjects));
171        }
172        clone.allowedSubFunctions.Add(allowedSubFunctionsForSlot);
173      }
174      return clone;
175    }
176
177    public override XmlNode GetXmlNode(string name, XmlDocument document, IDictionary<Guid, IStorable> persistedObjects) {
178      XmlNode node = base.GetXmlNode(name, document, persistedObjects);
179      XmlAttribute minSubTreesAttr = document.CreateAttribute("MinSubTrees");
180      minSubTreesAttr.Value = XmlConvert.ToString(MinSubTrees);
181      XmlAttribute maxSubTreesAttr = document.CreateAttribute("MaxSubTrees");
182      maxSubTreesAttr.Value = XmlConvert.ToString(MaxSubTrees);
183      node.Attributes.Append(minSubTreesAttr);
184      node.Attributes.Append(maxSubTreesAttr);
185      for (int i = 0; i < MaxSubTrees; i++) {
186        XmlNode slotNode = document.CreateElement("AllowedSubFunctions");
187        XmlAttribute slotAttr = document.CreateAttribute("Slot");
188        slotAttr.Value = XmlConvert.ToString(i);
189        slotNode.Attributes.Append(slotAttr);
190        node.AppendChild(slotNode);
191        foreach (IFunction f in GetAllowedSubFunctions(i)) {
192          slotNode.AppendChild(PersistenceManager.Persist(f, document, persistedObjects));
193        }
194      }
195      return node;
196    }
197
198    public override void Populate(XmlNode node, IDictionary<Guid, IStorable> restoredObjects) {
199      base.Populate(node, restoredObjects);
200      MinSubTrees = XmlConvert.ToInt32(node.Attributes["MinSubTrees"].Value);
201      MaxSubTrees = XmlConvert.ToInt32(node.Attributes["MaxSubTrees"].Value);
202      foreach (XmlNode allowedSubFunctionsNode in node.SelectNodes("AllowedSubFunctions")) {
203        int slot = XmlConvert.ToInt32(allowedSubFunctionsNode.Attributes["Slot"].Value);
204        foreach (XmlNode fNode in allowedSubFunctionsNode.ChildNodes) {
205          AddAllowedSubFunction((IFunction)PersistenceManager.Restore(fNode, restoredObjects), slot);
206        }
207      }
208    }
209  }
210}
Note: See TracBrowser for help on using the repository browser.