queue.py 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. # min heap used in the FMT*
  2. import collections
  3. import heapq
  4. import itertools
  5. class MinheapPQ:
  6. """
  7. A priority queue based on min heap, which takes O(logn) on element removal
  8. https://docs.python.org/3/library/heapq.html#priority-queue-implementation-notes
  9. """
  10. def __init__(self):
  11. self.pq = [] # lis of the entries arranged in a heap
  12. self.nodes = set()
  13. self.entry_finder = {} # mapping of the item entries
  14. self.counter = itertools.count() # unique sequence count
  15. self.REMOVED = '<removed-item>'
  16. def put(self, item, priority):
  17. '''add a new task or update the priority of an existing item'''
  18. if item in self.entry_finder:
  19. self.check_remove(item)
  20. count = next(self.counter)
  21. entry = [priority, count, item]
  22. self.entry_finder[item] = entry
  23. heapq.heappush(self.pq, entry)
  24. self.nodes.add(item)
  25. def put_set(self, dictin):
  26. '''add a new dict into the priority queue'''
  27. for item, priority in enumerate(dictin):
  28. self.put(item, priority)
  29. def check_remove(self, item):
  30. if item not in self.entry_finder:
  31. return
  32. entry = self.entry_finder.pop(item)
  33. entry[-1] = self.REMOVED
  34. self.nodes.remove(item)
  35. def check_remove_set(self, set_input):
  36. if len(set_input) == 0:
  37. return
  38. for item in set_input:
  39. if item not in self.entry_finder:
  40. continue
  41. entry = self.entry_finder.pop(item)
  42. entry[-1] = self.REMOVED
  43. self.nodes.remove(item)
  44. def priority_filtering(self, threshold, mode):
  45. # mode: bigger: check and remove those key vals bigger than threshold
  46. if mode == 'lowpass':
  47. for entry in self.enumerate():
  48. item = entry[2]
  49. if entry[0] >= threshold: # priority
  50. _ = self.entry_finder.pop(item)
  51. entry[-1] = self.REMOVED
  52. self.nodes.remove(item)
  53. # mode: smaller: check and remove those key vals smaller than threshold
  54. elif mode == 'highpass':
  55. for entry in self.enumerate():
  56. item = entry[2]
  57. if entry[0] <= threshold: # priority
  58. _ = self.entry_finder.pop(item)
  59. entry[-1] = self.REMOVED
  60. self.nodes.remove(item)
  61. def get(self):
  62. """Remove and return the lowest priority task. Raise KeyError if empty."""
  63. while self.pq:
  64. priority, count, item = heapq.heappop(self.pq)
  65. if item is not self.REMOVED:
  66. del self.entry_finder[item]
  67. self.nodes.remove(item)
  68. return item
  69. raise KeyError('pop from an empty priority queue')
  70. def top_key(self):
  71. return self.pq[0][0]
  72. def enumerate(self):
  73. return self.pq
  74. def allnodes(self):
  75. return self.nodes