Skip to main content

pumpkin_core/containers/
key_value_heap.rs

1//! A heap where the keys range from [0, ..., n - 1] and the values are nonnegative floating points.
2//! The heap can be queried to return key with the maximum value, and certain keys can be
3//! (temporarily) removed/readded as necessary It allows increasing/decreasing the values of its
4//! entries
5
6// The implementation could be more efficient in the following ways:
7//  - Currently more comparisons are done than necessary when sifting
8//  - Possibly the recursion could be unrolled
9use std::ops::AddAssign;
10use std::ops::DivAssign;
11
12use super::KeyedVec;
13use super::StorageKey;
14use crate::containers::HashSet;
15use crate::pumpkin_assert_moderate;
16
17/// A [max-heap](https://en.wikipedia.org/wiki/Min-max_heap)
18/// which allows for generalised `Key`s (required to implement [StorageKey]) and `Value`s (which are
19/// required to be ordered, divisible and addable).
20#[derive(Debug, Clone)]
21pub struct KeyValueHeap<Key, Value> {
22    /// Contains the values stored as a heap; the value of key `i` is at index
23    /// [`KeyValueHeap::map_key_to_position\[i\]`][KeyValueHeap::map_key_to_position]
24    values: Vec<Value>,
25    /// `map_key_to_position[i]` is the index of the value of the key `i` in
26    /// [`KeyValueHeap::values`]
27    map_key_to_position: KeyedVec<Key, usize>,
28    /// `map_position_to_key[i]` is the key which is associated with `i` in
29    /// [`KeyValueHeap::values`]
30    map_position_to_key: Vec<Key>,
31    /// The index of the last element in [`KeyValueHeap::values`]
32    end_position: usize,
33}
34
35impl<Key: StorageKey, Value> Default for KeyValueHeap<Key, Value> {
36    fn default() -> Self {
37        Self {
38            values: Default::default(),
39            map_key_to_position: Default::default(),
40            map_position_to_key: Default::default(),
41            end_position: Default::default(),
42        }
43    }
44}
45
46impl<Key, Value> KeyValueHeap<Key, Value> {
47    pub(crate) const fn new() -> Self {
48        Self {
49            values: Vec::new(),
50            map_key_to_position: KeyedVec::new(),
51            map_position_to_key: Vec::new(),
52            end_position: 0,
53        }
54    }
55}
56
57impl<Key, Value> KeyValueHeap<Key, Value>
58where
59    Key: StorageKey + Copy,
60    Value: AddAssign<Value> + DivAssign<Value> + PartialOrd + Default + Copy,
61{
62    /// Get the keys in the heap.
63    ///
64    /// The order in which the keys are yielded is unspecified.
65    pub fn keys(&self) -> impl Iterator<Item = Key> + '_ {
66        self.map_position_to_key[..self.end_position]
67            .iter()
68            .copied()
69    }
70
71    /// Return the key with maximum value from the heap, or None if the heap is empty. Note that
72    /// this does not delete the key (see [`KeyValueHeap::pop_max`] to get and delete).
73    ///
74    /// The time-complexity of this operation is O(1)
75    pub fn peek_max(&self) -> Option<(&Key, &Value)> {
76        if self.has_no_nonremoved_elements() {
77            None
78        } else {
79            Some((
80                &self.map_position_to_key[0],
81                &self.values[self.map_key_to_position[&self.map_position_to_key[0]]],
82            ))
83        }
84    }
85
86    pub fn get_value(&self, key: Key) -> &Value {
87        pumpkin_assert_moderate!(
88            key.index() < self.map_key_to_position.len(),
89            "Attempted to get key with index {} for a map with length {}",
90            key.index(),
91            self.map_key_to_position.len()
92        );
93        &self.values[self.map_key_to_position[key]]
94    }
95
96    /// Deletes the key with maximum value from the heap and returns it, or None if the heap is
97    /// empty.
98    ///
99    ///  The time-complexity of this operation is O(logn).
100    pub fn pop_max(&mut self) -> Option<Key> {
101        if !self.has_no_nonremoved_elements() {
102            let best_key = self.map_position_to_key[0];
103            pumpkin_assert_moderate!({
104                let best_value = *self.get_value(best_key);
105                if let Some((_, value)) = self.peek_max() {
106                    *value <= best_value
107                } else {
108                    true
109                }
110            });
111            pumpkin_assert_moderate!(0 == self.map_key_to_position[best_key]);
112            self.delete_key(best_key);
113
114            Some(best_key)
115        } else {
116            None
117        }
118    }
119
120    /// Increments the value of the element of 'key' by 'increment'
121    ///
122    /// The worst-case time-complexity of this operation is O(logn); average case is likely to be
123    /// better
124    pub fn increment(&mut self, key: Key, increment: Value) {
125        let position = self.map_key_to_position[key];
126        self.values[position] += increment;
127        // Recall that increment may be applied to keys not present
128        // So we only apply sift up in case the key is present
129        if self.is_key_present(key) {
130            self.sift_up(position);
131        }
132    }
133
134    /// Sets the value of the element of `key` to `value`.
135    ///
136    /// The worst-case time-complexity of this operation is O(logn); average case is likely to be
137    /// better.
138    pub fn set_value(&mut self, key: Key, value: Value) {
139        if key.index() < self.len() {
140            let position = self.map_key_to_position[key];
141            let value_before = *self.get_value(key);
142            self.values[position] = value;
143            if self.is_key_present(key) {
144                if value_before < *self.get_value(key) {
145                    // We sift up if the new value is larger than the previous value.
146                    self.sift_up(position);
147                } else if value_before > *self.get_value(key) {
148                    // We sift down if the new value is smaller than the previous value.
149                    self.sift_down(position);
150                }
151            }
152        }
153    }
154
155    /// Restores the entry with key 'key' to the heap if the key is not present, otherwise does
156    /// nothing. Its value is the previous value used before 'delete_key' was called.
157    ///
158    ///  The run-time complexity of this operation is O(logn)
159    pub fn restore_key(&mut self, key: Key) {
160        if !self.is_key_present(key) {
161            // The key is somewhere in the range [end_position, max_size-1]
162            // We place the key at the end of the heap, increase end_position, and sift up
163            let position = self.map_key_to_position[key];
164            pumpkin_assert_moderate!(position >= self.end_position);
165            self.swap_positions(position, self.end_position);
166            self.end_position += 1;
167            self.sift_up(self.end_position - 1);
168        }
169    }
170
171    /// Removes the entry with key 'key' (temporarily) from the heap if the key is present,
172    /// otherwise does nothing. Its value remains recorded internally and is available upon
173    /// calling [`KeyValueHeap::restore_key`]. The value can still be subjected to
174    /// [`KeyValueHeap::divide_values`].
175    ///
176    /// The run-time complexity of this operation is O(logn)
177    pub fn delete_key(&mut self, key: Key) {
178        if self.is_key_present(key) {
179            // Place the key at the end of the heap, decrement the heap, and sift down to ensure a
180            // valid heap
181            let position = self.map_key_to_position[key];
182
183            let value_key = *self.get_value(key);
184            let value_replacer = *self.get_value(self.map_position_to_key[self.end_position - 1]);
185
186            self.swap_positions(position, self.end_position - 1);
187            self.end_position -= 1;
188            if position < self.end_position {
189                if value_key > value_replacer {
190                    self.sift_down(position);
191                } else if value_key < value_replacer {
192                    self.sift_up(position);
193                }
194            }
195        }
196    }
197
198    /// Returns how many elements are in the heap (including the (temporarily) "removed" values)
199    pub fn len(&self) -> usize {
200        self.values.len()
201    }
202
203    /// Returns whether there are no elements in the heap (including the (temporarily) "removed"
204    /// values)
205    pub fn is_empty(&self) -> bool {
206        self.len() == 0
207    }
208
209    pub fn num_nonremoved_elements(&self) -> usize {
210        self.end_position
211    }
212
213    /// Returns whether there are elements left in the heap (excluding the "removed" values)
214    pub(crate) fn has_no_nonremoved_elements(&self) -> bool {
215        self.num_nonremoved_elements() == 0
216    }
217
218    /// Returns whether the key is currently not (temporarily) remove
219    pub fn is_key_present(&self, key: Key) -> bool {
220        key.index() < self.map_key_to_position.len()
221            && self.map_key_to_position[key] < self.end_position
222    }
223
224    /// Increases the size of the heap by one and adjust the data structures appropriately by adding
225    /// `Key` and `Value`
226    pub fn grow(&mut self, key: Key, value: Value) {
227        let last_index = self.values.len();
228        self.values.push(value);
229        // Initially the key is placed placed at the very end, will be placed in the correct
230        // position below to ensure a valid heap structure
231        let _ = self.map_key_to_position.push(last_index);
232        self.map_position_to_key.push(key);
233        pumpkin_assert_moderate!(
234            self.map_position_to_key[last_index].index() == key.index()
235                && self.map_key_to_position[key] == last_index
236        );
237        self.swap_positions(self.end_position, last_index);
238        self.end_position += 1;
239        self.sift_up(self.end_position - 1);
240    }
241
242    pub fn clear(&mut self) {
243        self.values.clear();
244        self.map_key_to_position.clear();
245        self.map_position_to_key.clear();
246        self.end_position = 0;
247    }
248
249    /// Divides all the values in the heap by 'divisor'. This will also affect the values of keys
250    /// that have been [`KeyValueHeap::delete_key`].
251    ///
252    /// The run-time complexity of this operation is O(n)
253    pub fn divide_values(&mut self, divisor: Value) {
254        for value in self.values.iter_mut() {
255            *value /= divisor;
256        }
257    }
258
259    fn swap_positions(&mut self, a: usize, b: usize) {
260        let key_i = self.map_position_to_key[a];
261        pumpkin_assert_moderate!(self.map_key_to_position[key_i] == a);
262        let key_j = self.map_position_to_key[b];
263        pumpkin_assert_moderate!(self.map_key_to_position[key_j] == b);
264
265        self.values.swap(a, b);
266        self.map_position_to_key.swap(a, b);
267        self.map_key_to_position.swap(key_i.index(), key_j.index());
268
269        pumpkin_assert_moderate!(
270            self.map_key_to_position[key_i] == b && self.map_key_to_position[key_j] == a
271        );
272
273        pumpkin_assert_moderate!(
274            self.map_key_to_position
275                .iter()
276                .collect::<HashSet<&usize>>()
277                .len()
278                == self.map_key_to_position.len()
279        )
280    }
281
282    fn sift_up(&mut self, position: usize) {
283        // Only sift up if not at the root
284        if position > 0 {
285            let parent_position = KeyValueHeap::<Key, Value>::get_parent_position(position);
286            // Continue sift up if the heap property is violated
287            if self.values[parent_position] < self.values[position] {
288                self.swap_positions(parent_position, position);
289                self.sift_up(parent_position);
290            }
291        }
292    }
293
294    fn sift_down(&mut self, position: usize) {
295        pumpkin_assert_moderate!(position < self.end_position);
296
297        if !self.is_heap_locally(position) {
298            let largest_child_position = self.get_largest_child_position(position);
299            self.swap_positions(largest_child_position, position);
300            self.sift_down(largest_child_position);
301        }
302    }
303
304    fn is_heap_locally(&self, position: usize) -> bool {
305        // Either the node is a leaf, or it satisfies the heap property (the value of the parent is
306        // at least as large as the values of its child)
307        let left_child_position = KeyValueHeap::<Key, Value>::get_left_child_position(position);
308        let right_child_position = KeyValueHeap::<Key, Value>::get_right_child_position(position);
309
310        if self.is_leaf(position) {
311            return true;
312        }
313
314        // if does not have right child, then just compare with left child.
315        if right_child_position >= self.end_position {
316            return self.values[position] >= self.values[left_child_position];
317        }
318
319        // Otherwise the node has two children, compare with both.
320        self.values[position] >= self.values[left_child_position]
321            && self.values[position] >= self.values[right_child_position]
322    }
323
324    fn is_leaf(&self, position: usize) -> bool {
325        KeyValueHeap::<Key, Value>::get_left_child_position(position) >= self.end_position
326    }
327
328    fn get_largest_child_position(&self, position: usize) -> usize {
329        pumpkin_assert_moderate!(!self.is_leaf(position));
330
331        let left_child_position = KeyValueHeap::<Key, Value>::get_left_child_position(position);
332        let right_child_position = KeyValueHeap::<Key, Value>::get_right_child_position(position);
333
334        if right_child_position < self.end_position
335            && self.values[right_child_position] > self.values[left_child_position]
336        {
337            right_child_position
338        } else {
339            left_child_position
340        }
341    }
342
343    fn get_parent_position(child_position: usize) -> usize {
344        pumpkin_assert_moderate!(child_position > 0, "Root has no parent.");
345        (child_position - 1) / 2
346    }
347
348    fn get_left_child_position(position: usize) -> usize {
349        2 * position + 1
350    }
351
352    fn get_right_child_position(position: usize) -> usize {
353        2 * position + 2
354    }
355}
356
357#[cfg(test)]
358mod test {
359    use super::KeyValueHeap;
360
361    #[test]
362    fn failing_test_case() {
363        let mut heap: KeyValueHeap<usize, u32> = KeyValueHeap::default();
364
365        heap.grow(0, 7);
366        heap.grow(1, 5);
367
368        assert_eq!(heap.pop_max().unwrap(), 0);
369
370        heap.grow(2, 7);
371        heap.grow(3, 6);
372
373        assert_eq!(heap.pop_max().unwrap(), 2);
374        assert_eq!(heap.pop_max().unwrap(), 3);
375    }
376
377    #[test]
378    fn failing_test_case2() {
379        let mut heap: KeyValueHeap<usize, u32> = KeyValueHeap::default();
380
381        heap.grow(0, 5);
382        heap.grow(1, 7);
383        heap.grow(2, 6);
384
385        assert_eq!(heap.pop_max().unwrap(), 1);
386        assert_eq!(heap.pop_max().unwrap(), 2);
387    }
388
389    // Uses the heap to sort the input vectors, and compare with a sorted version of the vector.
390    fn heap_sort_test_helper(numbers: Vec<usize>) {
391        let mut sorted_numbers = numbers.clone();
392        sorted_numbers.sort();
393        sorted_numbers.reverse();
394
395        let mut heap: KeyValueHeap<usize, usize> = KeyValueHeap::default();
396        for n in numbers.iter().enumerate() {
397            heap.grow(n.0, *n.1);
398        }
399
400        let mut heap_sorted_vector: Vec<usize> = vec![];
401        while let Some(index) = heap.pop_max() {
402            heap_sorted_vector.push(numbers[index]);
403        }
404
405        assert_eq!(heap_sorted_vector, sorted_numbers);
406    }
407
408    #[test]
409    fn trivial() {
410        let mut heap: KeyValueHeap<usize, usize> = KeyValueHeap::default();
411        heap.grow(0, 5);
412        assert_eq!(heap.pop_max(), Some(0));
413        assert!(heap.has_no_nonremoved_elements());
414        assert_eq!(heap.pop_max(), None);
415    }
416
417    #[test]
418    fn trivial_sort() {
419        heap_sort_test_helper(vec![5]);
420    }
421
422    #[test]
423    fn simple() {
424        heap_sort_test_helper(vec![5, 10]);
425    }
426
427    #[test]
428    fn random1() {
429        heap_sort_test_helper(vec![5, 10, 3]);
430    }
431
432    #[test]
433    fn random2() {
434        heap_sort_test_helper(vec![3, 10, 5]);
435    }
436
437    #[test]
438    fn random3() {
439        heap_sort_test_helper(vec![1, 2, 3, 4]);
440    }
441
442    #[test]
443    fn duplicates() {
444        heap_sort_test_helper(vec![2, 2, 1, 1, 3, 3, 3]);
445    }
446
447    #[test]
448    fn test_set_value_to_lower() {
449        let mut heap: KeyValueHeap<usize, usize> = KeyValueHeap::default();
450        heap.grow(0, 1);
451        heap.grow(1, 2);
452        heap.grow(2, 3);
453        heap.grow(3, 4);
454
455        heap.set_value(1, 0);
456
457        let mut result = vec![];
458        while let Some(max_element) = heap.pop_max() {
459            result.push(max_element);
460        }
461
462        assert_eq!(vec![3, 2, 0, 1], result);
463    }
464
465    #[test]
466    fn test_set_value_to_higher() {
467        let mut heap: KeyValueHeap<usize, usize> = KeyValueHeap::default();
468        heap.grow(0, 1);
469        heap.grow(1, 2);
470        heap.grow(2, 3);
471        heap.grow(3, 4);
472
473        heap.set_value(1, 20);
474
475        let mut result = vec![];
476        while let Some(max_element) = heap.pop_max() {
477            result.push(max_element);
478        }
479
480        assert_eq!(vec![1, 3, 2, 0], result);
481    }
482
483    #[test]
484    fn test_set_value_further() {
485        let mut heap: KeyValueHeap<usize, usize> = KeyValueHeap::default();
486        heap.grow(0, 1);
487        heap.grow(1, 2);
488        heap.grow(2, 3);
489        heap.grow(3, 4);
490
491        heap.delete_key(1);
492        heap.set_value(1, 20);
493        heap.set_value(1, 0);
494        heap.set_value(0, 0);
495        heap.restore_key(1);
496        heap.delete_key(0);
497        heap.set_value(0, 20);
498        heap.restore_key(0);
499
500        let mut result = vec![];
501        while let Some(max_element) = heap.pop_max() {
502            result.push(max_element);
503        }
504
505        assert_eq!(vec![0, 3, 2, 1], result);
506    }
507}