Free cookie consent management tool by TermsFeed Policy Generator

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

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

#2886: implement LRU cache for storing search nodes, introduce SortedSet for handling priorities, fix serialization and cloning

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