Free cookie consent management tool by TermsFeed Policy Generator

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

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

#2886: Clear search data structures at the end of the run (huge memory savings)

File size: 10.3 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.SortedSet) { }
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      InitSearchDataStructure();
97    }
98
99    private void InitSearchDataStructure() {
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    private void ClearSearchDataStructure() {
120      switch (storageType) {
121        case StorageType.PriorityQueue:
122          priorityQueue = null;
123          break;
124        case StorageType.Stack:
125          stack.Clear();
126          break;
127        case StorageType.Queue:
128          queue.Clear();
129          break;
130        case StorageType.RandomList:
131          list.Clear();
132          break;
133        case StorageType.SortedSet:
134          sortedSet.Clear();
135          break;
136      }
137    }
138
139    public override IDeepCloneable Clone(Cloner cloner) {
140      return new SearchDataStore(this, cloner);
141    }
142
143    protected SearchDataStore(SearchDataStore original, Cloner cloner) : base(original, cloner) {
144      storedValues = cloner.Clone(original.storedValues);
145      storageType = original.storageType;
146      cacheSize = original.cacheSize;
147      searchDataStructureSize = original.searchDataStructureSize;
148
149      InitSearchDataStructure();
150      switch (storageType) {
151        case StorageType.PriorityQueue:
152          foreach (var t in storedValues)
153            storeInternal(t.Key, t.Value.Priority);
154          break;
155        case StorageType.Stack:
156          foreach (var v in original.stack.Reverse()) {
157            stack.Push(v);
158          }
159          break;
160        case StorageType.Queue:
161          foreach (var v in original.queue) {
162            queue.Enqueue(v);
163          }
164          break;
165        case StorageType.RandomList:
166          list.AddRange(original.list);
167          break;
168        case StorageType.SortedSet:
169          sortedSet = new SortedSet<Tuple<double, int>>(original.sortedSet);
170          break;
171      }
172    }
173
174    [StorableHook(HookType.AfterDeserialization)]
175    private void AfterDeserialization() {
176      // access lambdas need to be reinitialized
177      switch (storageType) {
178        case StorageType.PriorityQueue:
179          InitPriorityQueue();
180          foreach (var t in storedValues)
181            storeInternal(t.Key, t.Value.Priority);
182          break;
183        case StorageType.Stack:
184          storeInternal = (hash, prio) => stack.Push(hash);
185          fetchInternal = () => stack.Pop();
186          break;
187        case StorageType.Queue:
188          storeInternal = (hash, prio) => queue.Enqueue(hash);
189          fetchInternal = () => queue.Dequeue();
190          break;
191        case StorageType.RandomList:
192          System.Random rand = new System.Random(999);
193          storeInternal = (hash, prio) => list.Add(hash);
194          fetchInternal = () => {
195            int indexOfHash = rand.Next(list.Count);
196            int result = list[indexOfHash];
197            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.
198            return result;
199          };
200          break;
201        case StorageType.SortedSet:
202          storeInternal = (hash, prio) => {
203            if (sortedSet.Count >= searchDataStructureSize) {
204              var max = sortedSet.Max;
205              sortedSet.Remove(max);
206              storedValues.Remove(max.Item2);
207            }
208            sortedSet.Add(Tuple.Create(prio, hash));
209          };
210          fetchInternal = () => {
211            var elem = sortedSet.FirstOrDefault();
212            if (elem == null)
213              return 0;
214            sortedSet.Remove(elem);
215            return elem.Item2;
216          };
217          break;
218      }
219    }
220    #region SearchStrategies
221
222    private void InitPriorityQueue() {
223      int capacity = searchDataStructureSize;
224      priorityQueue = new PriorityQueue<double, int>(double.MaxValue, double.MinValue, capacity);
225      storeInternal = (hash, prio) => {
226        // size is the 0-based index of the last used element
227        if (priorityQueue.Size == capacity - 1) {
228          // if the queue is at capacity we have to replace
229          return;
230        }
231        priorityQueue.Insert(prio, hash);
232      };
233      fetchInternal = () => {
234        int ret = priorityQueue.PeekMinValue();
235        if (priorityQueue.Size > 0) {
236          priorityQueue.RemoveMin();
237        }
238        return ret;
239      };
240    }
241
242    private void InitStack() {
243      stack = new Stack<int>();
244
245      storeInternal = (hash, prio) => stack.Push(hash);
246      fetchInternal = () => stack.Pop();
247    }
248
249    private void InitQueue() {
250      queue = new Queue<int>();
251
252      storeInternal = (hash, prio) => queue.Enqueue(hash);
253      fetchInternal = () => queue.Dequeue();
254    }
255
256    private void InitRandomList() {
257      list = new List<int>();
258      System.Random rand = new System.Random(999);
259
260      storeInternal = (hash, prio) => list.Add(hash);
261      fetchInternal = () => {
262        int indexOfHash = rand.Next(list.Count);
263        int result = list[indexOfHash];
264        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.
265        return result;
266      };
267    }
268
269    private void InitSortedSet() {
270      sortedSet = new SortedSet<Tuple<double, int>>();
271      storeInternal = (hash, prio) => {
272        if (sortedSet.Count >= searchDataStructureSize) {
273          var max = sortedSet.Max;
274          sortedSet.Remove(max);
275          storedValues.Remove(max.Item2);
276        }
277        sortedSet.Add(Tuple.Create(prio, hash));
278      };
279      fetchInternal = () => {
280        var elem = sortedSet.FirstOrDefault();
281        if (elem == null)
282          return default(int);
283        sortedSet.Remove(elem);
284        return elem.Item2;
285      };
286    }
287
288    #endregion
289
290    #region Interface
291
292    public SearchNode GetNext() {
293      int hash = fetchInternal.Invoke();
294      SearchNode result = null;
295      if (storedValues.TryGetValue(hash, out result)) {
296        storedValues.Remove(hash);
297      }
298      return result;
299    }
300
301    public void Store(SearchNode sn) {
302      storeInternal(sn.Hash, sn.Priority);
303      storedValues[sn.Hash] = sn;
304    }
305
306    public bool Contains(int hash) {
307      SearchNode result;
308      return storedValues.TryGetValue(hash, out result);
309    }
310
311    public void Clear() {
312      storedValues.Clear();
313    }
314
315    #endregion
316
317    #region Collection-Interface
318
319    public int Count {
320      get {
321        switch (storageType) {
322          case StorageType.PriorityQueue:
323            return priorityQueue.Size;
324          case StorageType.Queue:
325            return queue.Count;
326          case StorageType.RandomList:
327            return list.Count;
328          case StorageType.Stack:
329            return stack.Count;
330          case StorageType.SortedSet:
331            return sortedSet.Count;
332          default:
333            throw new InvalidOperationException("");
334        }
335      }
336    }
337
338    public IEnumerator<SearchNode> GetEnumerator() {
339      return storedValues.Select(x => x.Value).GetEnumerator();
340    }
341
342    IEnumerator IEnumerable.GetEnumerator() {
343      return GetEnumerator();
344    }
345
346    #endregion
347  }
348}
Note: See TracBrowser for help on using the repository browser.