source: trunk/sources/HeuristicLab.GP/3.3/BaseClasses/Function.cs @ 2700

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

Renamed FunctionBase to Function and FunctionTreeBase to FunctionTree. #748 (FunctionLibraryView is empty).

File size: 9.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.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 Function : 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    private string name;
43    public virtual string Name {
44      get { return name; }
45      set {
46        if (string.IsNullOrEmpty(value)) throw new ArgumentException();
47        if (value != name) {
48          name = value;
49          FireChanged();
50        }
51      }
52    }
53
54    protected Function() {
55      name = this.GetType().Name;
56    }
57
58    public virtual string Description {
59      get { return "Description for this function is missing (TODO)"; }
60    }
61
62    public int MinSubTrees {
63      get {
64        return minArity;
65      }
66      protected internal set {
67        if (value < 0) throw new ArgumentException();
68        if (minArity != value) {
69          minArity = value;
70          while (minArity > allowedSubFunctions.Count) allowedSubFunctions.Add(new List<IFunction>());
71          ResetCachedValues();
72          FireChanged();
73        }
74      }
75    }
76
77    public int MaxSubTrees {
78      get {
79        return maxArity;
80      }
81      protected internal set {
82        if (value < 0) throw new ArgumentException();
83        if (value < minArity) throw new ArgumentException();
84        if (value != maxArity) {
85          maxArity = value;
86          while (allowedSubFunctions.Count > maxArity) allowedSubFunctions.RemoveAt(allowedSubFunctions.Count - 1);
87          while (maxArity > allowedSubFunctions.Count) {
88            if (allowedSubFunctions.Count > 0) {
89              // copy the list of allowed sub-functions from the previous slot
90              allowedSubFunctions.Add(new List<IFunction>(allowedSubFunctions[allowedSubFunctions.Count - 1]));
91            } else {
92              // add empty list
93              allowedSubFunctions.Add(new List<IFunction>());
94            }
95          }
96          ResetCachedValues();
97          FireChanged();
98        }
99      }
100    }
101
102
103    public int MinTreeSize {
104      get {
105        if (minTreeSize <= 0) {
106          RecalculateMinimalTreeSize();
107          FireChanged();
108        }
109        Debug.Assert(minTreeSize > 0);
110        return minTreeSize;
111      }
112    }
113
114    public int MinTreeHeight {
115      get {
116        if (minTreeHeight <= 0) {
117          RecalculateMinimalTreeHeight();
118          FireChanged();
119        }
120        Debug.Assert(minTreeHeight > 0);
121        return minTreeHeight;
122      }
123    }
124
125    public double Tickets {
126      get { return tickets; }
127      set {
128        if (value < 0.0) throw new ArgumentException("Number of tickets must be positive");
129        if (value != tickets) {
130          tickets = value;
131          FireChanged();
132        }
133      }
134    }
135
136    public IOperator Initializer {
137      get { return initializer; }
138      set {
139        if (initializer != value) {
140          initializer = value;
141          FireChanged();
142        }
143      }
144    }
145
146    public IOperator Manipulator {
147      get { return manipulator; }
148      set {
149        if (manipulator != value) {
150          manipulator = value;
151          FireChanged();
152        }
153      }
154    }
155
156    public virtual IFunctionTree GetTreeNode() {
157      return new FunctionTree(this);
158    }
159
160    public ICollection<IFunction> GetAllowedSubFunctions(int index) {
161      if (index < 0 || index > MaxSubTrees) throw new ArgumentException("Index outside of allowed range. index = " + index);
162      return allowedSubFunctions[index];
163    }
164
165    public void AddAllowedSubFunction(IFunction function, int index) {
166      if (index < 0 || index > MaxSubTrees) throw new ArgumentException("Index outside of allowed range. index = " + index);
167      if (allowedSubFunctions[index] == null) {
168        allowedSubFunctions[index] = new List<IFunction>();
169      }
170      if (!allowedSubFunctions[index].Contains(function)) {
171        allowedSubFunctions[index].Add(function);
172      }
173      ResetCachedValues();
174      FireChanged();
175    }
176    public void RemoveAllowedSubFunction(IFunction function, int index) {
177      if (index < 0 || index > MaxSubTrees) throw new ArgumentException("Index outside of allowed range. index = " + index);
178      if (allowedSubFunctions[index].Contains(function)) {
179        allowedSubFunctions[index].Remove(function);
180        ResetCachedValues();
181        FireChanged();
182      }
183    }
184
185    private void ResetCachedValues() {
186      minTreeHeight = -1;
187      minTreeSize = -1;
188    }
189
190    public bool IsAllowedSubFunction(IFunction function, int index) {
191      return GetAllowedSubFunctions(index).Contains(function);
192    }
193
194    private void RecalculateMinimalTreeSize() {
195      if (MinSubTrees == 0) minTreeSize = 1;
196      else {
197        minTreeSize = int.MaxValue; // prevent infinite recursion       
198        minTreeSize = 1 + (from slot in Enumerable.Range(0, MinSubTrees)
199                           let minForSlot = (from function in GetAllowedSubFunctions(slot)
200                                             where function != this
201                                             select function.MinTreeSize).DefaultIfEmpty(0).Min()
202                           select minForSlot).Sum();
203      }
204    }
205
206    private void RecalculateMinimalTreeHeight() {
207      if (MinSubTrees == 0) minTreeHeight = 1;
208      else {
209        minTreeHeight = int.MaxValue;
210        minTreeHeight = 1 + (from slot in Enumerable.Range(0, MinSubTrees)
211                             let minForSlot = (from function in GetAllowedSubFunctions(slot)
212                                               where function != this
213                                               select function.MinTreeHeight).DefaultIfEmpty(0).Min()
214                             select minForSlot).Max();
215      }
216    }
217
218    public override IView CreateView() {
219      return new FunctionView(this);
220    }
221
222    public override string ToString() {
223      return name;
224    }
225
226    #region persistence
227    public override object Clone(IDictionary<Guid, object> clonedObjects) {
228      Function clone = (Function)base.Clone(clonedObjects);
229      clone.initializer = (IOperator)Auxiliary.Clone(initializer, clonedObjects);
230      clone.manipulator = (IOperator)Auxiliary.Clone(manipulator, clonedObjects);
231      clone.maxArity = maxArity;
232      clone.minArity = minArity;
233      clone.minTreeHeight = minTreeHeight;
234      clone.minTreeSize = minTreeSize;
235      clone.tickets = tickets;
236      for (int i = 0; i < MaxSubTrees; i++) {
237        var allowedSubFunctionsForSlot = new List<IFunction>();
238        foreach (IFunction f in GetAllowedSubFunctions(i)) {
239          allowedSubFunctionsForSlot.Add((IFunction)Auxiliary.Clone(f, clonedObjects));
240        }
241        clone.allowedSubFunctions.Add(allowedSubFunctionsForSlot);
242      }
243      return clone;
244    }
245
246    public override XmlNode GetXmlNode(string name, XmlDocument document, IDictionary<Guid, IStorable> persistedObjects) {
247      XmlNode node = base.GetXmlNode(name, document, persistedObjects);
248      XmlAttribute minSubTreesAttr = document.CreateAttribute("MinSubTrees");
249      minSubTreesAttr.Value = XmlConvert.ToString(MinSubTrees);
250      XmlAttribute maxSubTreesAttr = document.CreateAttribute("MaxSubTrees");
251      maxSubTreesAttr.Value = XmlConvert.ToString(MaxSubTrees);
252      node.Attributes.Append(minSubTreesAttr);
253      node.Attributes.Append(maxSubTreesAttr);
254      for (int i = 0; i < MaxSubTrees; i++) {
255        XmlNode slotNode = document.CreateElement("AllowedSubFunctions");
256        XmlAttribute slotAttr = document.CreateAttribute("Slot");
257        slotAttr.Value = XmlConvert.ToString(i);
258        slotNode.Attributes.Append(slotAttr);
259        node.AppendChild(slotNode);
260        foreach (IFunction f in GetAllowedSubFunctions(i)) {
261          slotNode.AppendChild(PersistenceManager.Persist(f, document, persistedObjects));
262        }
263      }
264      return node;
265    }
266
267    public override void Populate(XmlNode node, IDictionary<Guid, IStorable> restoredObjects) {
268      base.Populate(node, restoredObjects);
269      MinSubTrees = XmlConvert.ToInt32(node.Attributes["MinSubTrees"].Value);
270      MaxSubTrees = XmlConvert.ToInt32(node.Attributes["MaxSubTrees"].Value);
271      foreach (XmlNode allowedSubFunctionsNode in node.SelectNodes("AllowedSubFunctions")) {
272        int slot = XmlConvert.ToInt32(allowedSubFunctionsNode.Attributes["Slot"].Value);
273        foreach (XmlNode fNode in allowedSubFunctionsNode.ChildNodes) {
274          AddAllowedSubFunction((IFunction)PersistenceManager.Restore(fNode, restoredObjects), slot);
275        }
276      }
277    }
278    #endregion
279  }
280}
Note: See TracBrowser for help on using the repository browser.