def test_insert(self): h = IndexedHeap() inserted1 = h.insert({'key': 'z', 'value': 300}) self.assertEqual(inserted1, {'key': 'z', 'value': 300, 'index': 0}, 'correctly inserted and returned new item') inserted2 = h.insert({'key': 'y', 'value': 200}) self.assertEqual(inserted2, {'key': 'y', 'value': 200, 'index': 0}, 'correctly inserted and returned new item') self.assertEqual(inserted1, {'key': 'z', 'value': 300, 'index': 1}, 'correctly updated existing items') inserted3 = h.insert({'key': 'x', 'value': 100}) self.assertEqual(inserted3, {'key': 'x', 'value': 100, 'index': 0}, 'correctly inserted and returned new item') self.assertEqual(inserted2, {'key': 'y', 'value': 200, 'index': 2}, 'correctly inserted and returned item') self.assertEqual(inserted1, {'key': 'z', 'value': 300, 'index': 1}, 'correctly updated existing items')
def test_insert(self): h = IndexedHeap() inserted1 = h.insert({'key': 'z', 'value': 300}) self.assertEqual(inserted1, { 'key': 'z', 'value': 300, 'index': 0 }, 'correctly inserted and returned new item') inserted2 = h.insert({'key': 'y', 'value': 200}) self.assertEqual(inserted2, { 'key': 'y', 'value': 200, 'index': 0 }, 'correctly inserted and returned new item') self.assertEqual(inserted1, { 'key': 'z', 'value': 300, 'index': 1 }, 'correctly updated existing items') inserted3 = h.insert({'key': 'x', 'value': 100}) self.assertEqual(inserted3, { 'key': 'x', 'value': 100, 'index': 0 }, 'correctly inserted and returned new item') self.assertEqual(inserted2, { 'key': 'y', 'value': 200, 'index': 2 }, 'correctly inserted and returned item') self.assertEqual(inserted1, { 'key': 'z', 'value': 300, 'index': 1 }, 'correctly updated existing items')
class LFUCache(Cache): """ Least Frequently Used cache implementation. To implement fast least frequently used key retrieval this class uses a heap. Args: data: dict, data structure containing the items. heap: object, instance of LFUHeap """ def __init__(self, max_size): Cache.__init__(self, max_size) self.data = {} self.heap = IndexedHeap() def __len__(self): """ Returns the number of items in the cache. """ return len(self.data) def write(self, key, value): """ Writes the data to the cache. When writing, the frequency of the key is also incremented. Complexity: Args: key, the key to write the data under. value, the value to store. """ # Evict item if necessare before inserting. evicted = None if len(self.data) == self.max_size and key not in self.data: evicted = self.evict() # Write the cache item. if key not in self.data: item = {'key': 0, 'value': value, '_key': key} self.heap.insert(item) self.data[key] = item else: item = self.data[key] item['value'] = value self.increment_frequency(item) return evicted def read(self, key): """ Reads the value for the given key from the cache. The key gets its frequency incremented whenever it is read. Raises: Exception, when a cache miss occurs. """ if key not in self.data: raise Exception('Cache miss for key={key}'.format(key=key)) item = self.data[key] self.increment_frequency(item) return item['value'] def increment_frequency(self, item): """ Increments the frequency of the given key. Method also normalizes frequencies whenever the values reach the top limit for integers in python. See: src.heap.IndexedHeap for the way objects are inserted in the heap. Complexity: O(n) because of the index lookup. Args: item: format: {key, _key, value, index} where key is the frequency by which items are sorted in the heap. """ index = item['index'] item = self.heap.remove(index) item['key'] += 1 self.heap.insert(item) def evict(self): """ Evicts the element with the least usage frequency. Complexity: O(log n) because of the heap. Returns: dict, in case a value had to be evicted. Format {key, value}. key: str value: anything None, in case no eviction takes place """ node = self.heap.extract_min() key = node['_key'] del self.data[key] return {'key': node['_key'], 'value': node['value']}
def test_remove_from_single_item_heap(self): h = IndexedHeap() h.insert({'key': 'x', 'value': 1000}) h.remove(0) self.assertEqual(h.data, [], 'empty data in the heap')