Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2886_SymRegGrammarEnumeration/HeuristicLab.Algorithms.DataAnalysis.SymRegGrammarEnumeration/GrammarEnumeration/SearchDataStructure.cs @ 16053

Last change on this file since 16053 was 16053, checked in by bburlacu, 6 years ago

#2886: Refactor RSquaredEvaluator as a standalone ParameterizedNamedItem which is a parameter of the algorithm. Implement BestSolutionAnalyzer analyzer for quality statistics. Add license headers where missing.

File size: 10.9 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2018 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;
24using System.Collections.Generic;
25using System.Linq;
26using HeuristicLab.Common;
27using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
28
29namespace HeuristicLab.Algorithms.DataAnalysis.SymRegGrammarEnumeration {
30  [StorableClass]
31  public class SearchNode : DeepCloneable {
32    [Storable]
33    public readonly int Hash;
34
35    [Storable]
36    public readonly SymbolList SymbolList;
37
38    [Storable]
39    public readonly double Priority;
40
41    [Storable]
42    public readonly double R2;
43
44    private SearchNode() { }
45
46    public SearchNode(int hash, double priority, double r2, SymbolList symbolList) {
47      Hash = hash;
48      Priority = priority;
49      SymbolList = symbolList;
50      R2 = r2;
51    }
52
53    protected SearchNode(SearchNode original, Cloner cloner) : base(original, cloner) {
54      Hash = original.Hash;
55      Priority = original.Priority;
56      SymbolList = original.SymbolList;
57      R2 = original.R2;
58    }
59
60    [StorableConstructor]
61    protected SearchNode(bool deserializing) { }
62
63    public override IDeepCloneable Clone(Cloner cloner) {
64      return new SearchNode(this, cloner);
65    }
66  }
67
68  public enum StorageType {
69    PriorityQueue, Stack, Queue, RandomList, SortedSet
70  }
71
72  [StorableClass]
73  class SearchDataStore : DeepCloneable, IEnumerable<SearchNode> {
74    [Storable]
75    private Dictionary<int, SearchNode> storedValues; // Store hash-references and associated, actual values
76
77    [Storable]
78    private StorageType storageType;
79
80    [Storable]
81    private Queue<int> queue;
82
83    [Storable]
84    private Stack<int> stack;
85
86    [Storable]
87    private List<int> list;
88
89    [Storable]
90    private SortedSet<Tuple<double, int>> sortedSet;
91
92    [Storable]
93    private int searchDataStructureSize; // storage size for search nodes
94
95    [ExcludeFromObjectGraphTraversal]
96    PriorityQueue<double, int> priorityQueue; // does not support [Storable], we rebuild it from the storedValues
97
98    private Action<int, double> storeInternal; // Store hash-references
99    private Func<int> fetchInternal; // Fetch hash-reference
100
101    public SearchDataStore() : this(StorageType.SortedSet) { }
102
103    [StorableConstructor]
104    protected SearchDataStore(bool deserializing) : this() { }
105
106    public SearchDataStore(StorageType storageType, int searchDataStructureSize = (int)1e5) {
107      this.storageType = storageType;
108
109      this.searchDataStructureSize = searchDataStructureSize;
110
111      storedValues = new Dictionary<int, SearchNode>();
112      InitSearchDataStructure();
113    }
114
115    private void InitSearchDataStructure() {
116      switch (storageType) {
117        case StorageType.PriorityQueue:
118          InitPriorityQueue();
119          break;
120        case StorageType.Stack:
121          InitStack();
122          break;
123        case StorageType.Queue:
124          InitQueue();
125          break;
126        case StorageType.RandomList:
127          InitRandomList();
128          break;
129        case StorageType.SortedSet:
130          InitSortedSet();
131          break;
132      }
133    }
134
135    private void ClearSearchDataStructure() {
136      switch (storageType) {
137        case StorageType.PriorityQueue:
138          priorityQueue = null;
139          break;
140        case StorageType.Stack:
141          stack.Clear();
142          break;
143        case StorageType.Queue:
144          queue.Clear();
145          break;
146        case StorageType.RandomList:
147          list.Clear();
148          break;
149        case StorageType.SortedSet:
150          sortedSet.Clear();
151          break;
152      }
153    }
154
155    public override IDeepCloneable Clone(Cloner cloner) {
156      return new SearchDataStore(this, cloner);
157    }
158
159    protected SearchDataStore(SearchDataStore original, Cloner cloner) : base(original, cloner) {
160      storedValues = original.storedValues.ToDictionary(x => x.Key, x => cloner.Clone(x.Value));
161      storageType = original.storageType;
162      searchDataStructureSize = original.searchDataStructureSize;
163
164      InitSearchDataStructure();
165      switch (storageType) {
166        case StorageType.PriorityQueue:
167          foreach (var t in storedValues)
168            storeInternal(t.Key, t.Value.Priority);
169          break;
170        case StorageType.Stack:
171          foreach (var v in original.stack.Reverse()) {
172            stack.Push(v);
173          }
174          break;
175        case StorageType.Queue:
176          foreach (var v in original.queue) {
177            queue.Enqueue(v);
178          }
179          break;
180        case StorageType.RandomList:
181          list.AddRange(original.list);
182          break;
183        case StorageType.SortedSet:
184          sortedSet = new SortedSet<Tuple<double, int>>(original.sortedSet);
185          break;
186      }
187    }
188
189    [StorableHook(HookType.AfterDeserialization)]
190    private void AfterDeserialization() {
191      // access lambdas need to be reinitialized
192      switch (storageType) {
193        case StorageType.PriorityQueue:
194          InitPriorityQueue();
195          foreach (var t in storedValues)
196            storeInternal(t.Key, t.Value.Priority);
197          break;
198        case StorageType.Stack:
199          storeInternal = (hash, prio) => stack.Push(hash);
200          fetchInternal = () => stack.Pop();
201          break;
202        case StorageType.Queue:
203          storeInternal = (hash, prio) => queue.Enqueue(hash);
204          fetchInternal = () => queue.Dequeue();
205          break;
206        case StorageType.RandomList:
207          System.Random rand = new System.Random(999);
208          storeInternal = (hash, prio) => list.Add(hash);
209          fetchInternal = () => {
210            int indexOfHash = rand.Next(list.Count);
211            int result = list[indexOfHash];
212            list.RemoveAt(indexOfHash);  // TODO: beware this is O(n), at some point in time we should fix this. Maybe change to priority queue with random key.
213            return result;
214          };
215          break;
216        case StorageType.SortedSet:
217          storeInternal = (hash, prio) => {
218            if (sortedSet.Count >= searchDataStructureSize) {
219              var max = sortedSet.Max;
220              sortedSet.Remove(max);
221              storedValues.Remove(max.Item2); // should always be in sync with the sorted set
222            }
223            sortedSet.Add(Tuple.Create(prio, hash));
224          };
225          fetchInternal = () => {
226            var elem = sortedSet.FirstOrDefault();
227            if (elem == null)
228              return default(int);
229            sortedSet.Remove(elem);
230            return elem.Item2;
231          };
232          break;
233      }
234    }
235    #region SearchStrategies
236
237    private void InitPriorityQueue() {
238      int capacity = searchDataStructureSize;
239      priorityQueue = new PriorityQueue<double, int>(double.MaxValue, double.MinValue, capacity);
240      storeInternal = (hash, prio) => {
241        // size is the 0-based index of the last used element
242        if (priorityQueue.Size == capacity - 1) {
243          return; // if the queue is at capacity we have to return
244        }
245        priorityQueue.Insert(prio, hash);
246      };
247      fetchInternal = () => {
248        int ret = priorityQueue.PeekMinValue();
249        if (priorityQueue.Size > 0) {
250          priorityQueue.RemoveMin();
251        }
252        return ret;
253      };
254    }
255
256    private void InitStack() {
257      stack = new Stack<int>();
258
259      storeInternal = (hash, prio) => stack.Push(hash);
260      fetchInternal = () => stack.Pop();
261    }
262
263    private void InitQueue() {
264      queue = new Queue<int>();
265
266      storeInternal = (hash, prio) => queue.Enqueue(hash);
267      fetchInternal = () => queue.Dequeue();
268    }
269
270    private void InitRandomList() {
271      list = new List<int>();
272      System.Random rand = new System.Random(999);
273
274      storeInternal = (hash, prio) => list.Add(hash);
275      fetchInternal = () => {
276        int indexOfHash = rand.Next(list.Count);
277        int result = list[indexOfHash];
278        list.RemoveAt(indexOfHash);  // TODO: beware this is O(n), at some point in time we should fix this. Maybe change to priority queue with random key.
279        return result;
280      };
281    }
282
283    private void InitSortedSet() {
284      sortedSet = new SortedSet<Tuple<double, int>>();
285      storeInternal = (hash, prio) => {
286        if (sortedSet.Count >= searchDataStructureSize) {
287          var max = sortedSet.Max;
288          sortedSet.Remove(max);
289          storedValues.Remove(max.Item2);
290        }
291        sortedSet.Add(Tuple.Create(prio, hash));
292      };
293      fetchInternal = () => {
294        var elem = sortedSet.FirstOrDefault();
295        if (elem == null)
296          return default(int);
297        sortedSet.Remove(elem);
298        return elem.Item2;
299      };
300    }
301
302    #endregion
303
304    #region Interface
305
306    public SearchNode GetNext() {
307      int hash = fetchInternal.Invoke();
308      SearchNode result = null;
309      if (storedValues.TryGetValue(hash, out result)) {
310        storedValues.Remove(hash);
311      }
312      return result;
313    }
314
315    public void Store(SearchNode sn) {
316      storeInternal(sn.Hash, sn.Priority);
317      storedValues[sn.Hash] = sn;
318    }
319
320    public bool Contains(int hash) {
321      SearchNode result;
322      return storedValues.TryGetValue(hash, out result);
323    }
324
325    public void Clear() {
326      storedValues.Clear();
327    }
328
329    #endregion
330
331    #region Collection-Interface
332
333    public int Count {
334      get {
335        switch (storageType) {
336          case StorageType.PriorityQueue:
337            return priorityQueue.Size;
338          case StorageType.Queue:
339            return queue.Count;
340          case StorageType.RandomList:
341            return list.Count;
342          case StorageType.Stack:
343            return stack.Count;
344          case StorageType.SortedSet:
345            return sortedSet.Count;
346          default:
347            throw new InvalidOperationException("");
348        }
349      }
350    }
351
352    public IEnumerator<SearchNode> GetEnumerator() {
353      return storedValues.Select(x => x.Value).GetEnumerator();
354    }
355
356    IEnumerator IEnumerable.GetEnumerator() {
357      return GetEnumerator();
358    }
359
360    #endregion
361  }
362}
Note: See TracBrowser for help on using the repository browser.