Free cookie consent management tool by TermsFeed Policy Generator

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

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

#2886: refactor code

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