orx_priority_queue/
priority_queue_deckey.rs

1use crate::PriorityQueue;
2
3/// A [PriorityQueueDecKey] is a more advanced [PriorityQueue] with additional features
4/// mainly related to accessing or modifying already pushed nodes such as:
5/// * checking if a node is present in the queue,
6/// * getting the key of an already pushed node,
7/// * decreasing or updating the key of an already pushed node.
8///
9/// This is often achieved by additional memory requirement; hence, it is separated from the [PriorityQueue].
10///
11/// Another fundamental difference of [PriorityQueueDecKey] from [PriorityQueue] is that
12/// it behaves as a set enabled by the `contains` method.
13/// In other words,
14/// * the same node can be pushed to a [PriorityQueue] an arbitrary number of times with same or different keys;
15/// * on the other hand, a node can only be pushed to the [PriorityQueueDecKey] only once; however, the node in the queue can be mutated.
16///
17/// The [PriorityQueue] requires more space to handle a problem with lots of decrease key operations;
18/// [PriorityQueueDecKey] aims to be memory efficient in such situations.
19/// On the other hand, [PriorityQueue] could be preferable where number of such updates is limited
20/// due to its lack of additional checks and tracking.
21pub trait PriorityQueueDecKey<N, K>: PriorityQueue<N, K>
22where
23    N: Clone,
24    K: PartialOrd + Clone,
25{
26    /// Returns whether the given `node` is in the queue or not.
27    ///
28    /// # Examples
29    ///
30    /// ```
31    /// use orx_priority_queue::*;
32    ///
33    /// let mut queue = BinaryHeapWithMap::default();
34    /// queue.push('a', 42);
35    ///
36    /// assert!(queue.contains(&'a'));
37    /// assert!(!queue.contains(&'x'));
38    /// ```
39    fn contains(&self, node: &N) -> bool;
40
41    /// Returns the key of the given `node` if it is in the queue;
42    /// returns None otherwise.
43    ///
44    /// # Examples
45    ///
46    /// ```
47    /// use orx_priority_queue::*;
48    ///
49    /// let mut queue = BinaryHeapOfIndices::with_index_bound(12);
50    /// queue.push(7usize, 42.0);
51    ///
52    /// assert_eq!(Some(42.0), queue.key_of(&7));
53    /// assert_eq!(None, queue.key_of(&3));
54    /// ```
55    fn key_of(&self, node: &N) -> Option<K>;
56
57    /// Decreases key of the `node` which is already in the queue to the given `decreased_key`.
58    ///
59    /// This method is commonly used to increase priority of a node putting it closer to the peek of the queue;
60    /// alternative to inserting the same node multiple times with different keys.
61    /// This allows for memory efficient implementations of certain algorithms such as the
62    /// Dijkstra's shortest path algorithm.
63    ///
64    /// # Panics
65    /// This method panics:
66    /// * if the `node` is not in the queue; or
67    ///   (see also [`try_decrease_key_or_push`])
68    /// * if `decreased_key` is strictly larger than key of the `node` in the queue
69    ///   (see also [`try_decrease_key`]).
70    ///
71    /// [`try_decrease_key_or_push`]: PriorityQueueDecKey::try_decrease_key_or_push
72    /// [`try_decrease_key`]: PriorityQueueDecKey::try_decrease_key
73    ///
74    /// # Examples
75    ///
76    /// ```
77    /// use orx_priority_queue::*;
78    ///
79    /// let mut queue = BinaryHeapOfIndices::with_index_bound(12);
80    ///
81    /// queue.push(7usize, 42.0);
82    /// assert_eq!(Some(42.0), queue.key_of(&7));
83    ///
84    /// queue.decrease_key(&7, 21.0);
85    /// assert_eq!(Some(21.0), queue.key_of(&7));
86    ///
87    /// // the following lines would've panicked:
88    /// // queue.decrease_key(&10, 21.0); // due to absent node
89    /// // queue.decrease_key(&7, 100.0); // due to greater new key
90    /// ```
91    fn decrease_key(&mut self, node: &N, decreased_key: K);
92
93    /// Updates key of the `node` which is already in the queue as the given `new_key`;
94    /// and returns the result of the operation:
95    ///
96    /// * `ResUpdateKey::Decreased` if the prior key was strictly greater than the `new_key`;
97    /// * `ResUpdateKey::Increased` if the prior key was less than or equal to the `new_key`.
98    ///
99    /// # Panics
100    /// This method panics if:
101    /// * the `node` is not in the queue (see also [`update_key_or_push`]).
102    ///
103    /// [`update_key_or_push`]: PriorityQueueDecKey::update_key_or_push
104    ///
105    /// # Examples
106    ///
107    /// ```
108    /// use orx_priority_queue::*;
109    ///
110    /// let mut queue = BinaryHeapWithMap::default();
111    ///
112    /// queue.push(7usize, 42.0);
113    /// assert_eq!(Some(42.0), queue.key_of(&7));
114    ///
115    /// let result = queue.update_key(&7, 21.0);
116    /// assert_eq!(Some(21.0), queue.key_of(&7));
117    /// assert!(matches!(result, ResUpdateKey::Decreased));
118    ///
119    /// let result = queue.update_key(&7, 200.0);
120    /// assert_eq!(Some(200.0), queue.key_of(&7));
121    /// assert!(matches!(result, ResUpdateKey::Increased));
122    ///
123    /// // the following line would've panicked:
124    /// // queue.update_key(&10, 21.0); // due to absent node
125    /// ```
126    fn update_key(&mut self, node: &N, new_key: K) -> ResUpdateKey;
127
128    /// Tries to decrease the key of the `node` which is already in the queue if its prior key is strictly larger than the `new_key`;
129    /// otherwise, it does nothing leaving the queue unchanged.
130    ///
131    /// Returns the result of the operation:
132    ///
133    /// * `ResTryDecreaseKey::Decreased` if the prior key was strictly greater than the `new_key`;
134    /// * `ResTryDecreaseKey::Unchanged` if the prior key was less than or equal to the `new_key`.
135    ///
136    /// # Panics
137    /// This method panics if:
138    /// * the `node` is not in the queue.
139    ///
140    /// # Examples
141    ///
142    /// ```
143    /// use orx_priority_queue::*;
144    ///
145    /// let mut queue = BinaryHeapOfIndices::with_index_bound(12);
146    ///
147    /// queue.push(7usize, 42.0);
148    /// assert_eq!(Some(42.0), queue.key_of(&7));
149    ///
150    /// let result = queue.try_decrease_key(&7, 21.0);
151    /// assert_eq!(Some(21.0), queue.key_of(&7));
152    /// assert!(matches!(result, ResTryDecreaseKey::Decreased));
153    ///
154    /// let result = queue.try_decrease_key(&7, 200.0);
155    /// assert_eq!(Some(21.0), queue.key_of(&7));
156    /// assert!(matches!(result, ResTryDecreaseKey::Unchanged));
157    ///
158    /// // the following line would've panicked:
159    /// // queue.decrease_key(&10, 21.0); // due to absent node
160    /// ```
161    #[inline(always)]
162    fn try_decrease_key(&mut self, node: &N, new_key: K) -> ResTryDecreaseKey {
163        let old_key = self.key_of(node).expect("node must exist on the heap.");
164        if new_key < old_key {
165            self.decrease_key(node, new_key);
166            ResTryDecreaseKey::Decreased
167        } else {
168            ResTryDecreaseKey::Unchanged
169        }
170    }
171
172    /// If the `node` is present in the queue:
173    /// * decreases key of the `node` to the given `decreased_key`; `decreased_key` is expected to be less than or equal
174    ///   to the prior key;
175    ///
176    /// otherwise:
177    /// * pushes the new (node, key) pair to the queue.
178    ///
179    /// Returns the result of the operation:
180    ///
181    /// * `ResDecreaseKeyOrPush::Decreased` if the `node` was present in the queue and its key is decreased to `decreased_key`;
182    /// * `ResDecreaseKeyOrPush::Pushed` if the `node` was absent and it is pushed with the given `decreased_key`.
183    ///
184    /// # Panics
185    /// This method panics
186    /// * if the `node` is in the queue; however, its current key is strictly less than the provided `key`
187    ///   (see also [`update_key_or_push`] and [`try_decrease_key_or_push`]).
188    ///
189    /// [`update_key_or_push`]: PriorityQueueDecKey::update_key_or_push
190    /// [`try_decrease_key_or_push`]: PriorityQueueDecKey::try_decrease_key_or_push
191    ///
192    /// # Examples
193    ///
194    /// ```
195    /// use orx_priority_queue::*;
196    ///
197    /// let mut queue = BinaryHeapOfIndices::with_index_bound(12);
198    ///
199    /// queue.push(7usize, 42.0);
200    /// assert_eq!(Some(42.0), queue.key_of(&7));
201    ///
202    /// let result = queue.decrease_key_or_push(&7, 21.0);
203    /// assert_eq!(Some(21.0), queue.key_of(&7));
204    /// assert!(matches!(result, ResDecreaseKeyOrPush::Decreased));
205    ///
206    /// let result = queue.decrease_key_or_push(&0, 10.0);
207    /// assert_eq!(Some(10.0), queue.key_of(&0));
208    /// assert!(matches!(result, ResDecreaseKeyOrPush::Pushed));
209    ///
210    /// // the following line would've panicked:
211    /// // queue.decrease_key_or_push(&7, 100.0); // due to greater new key
212    /// ```
213    #[inline(always)]
214    fn decrease_key_or_push(&mut self, node: &N, key: K) -> ResDecreaseKeyOrPush {
215        if self.contains(node) {
216            self.decrease_key(node, key);
217            ResDecreaseKeyOrPush::Decreased
218        } else {
219            self.push(node.clone(), key.clone());
220            ResDecreaseKeyOrPush::Pushed
221        }
222    }
223
224    /// If the `node` is present in the queue:
225    /// * updates key of the `node` to the given `new_key`;
226    ///
227    /// otherwise:
228    /// * pushes the new (node, key) pair to the queue.
229    ///
230    /// Returns the result of the operation:
231    ///
232    /// * `ResUpdateKeyOrPush::Decreased` if the `node` was present in the queue with a key strictly larger than the `new_key`;
233    /// * `ResUpdateKeyOrPush::Increased` if the `node` was present in the queue with a key less than or equal to the `new_key`;
234    /// * `ResUpdateKeyOrPush::Pushed` if the `node` was absent and it is pushed with the given `new_key`.
235    ///
236    /// # Examples
237    ///
238    /// ```
239    /// use orx_priority_queue::*;
240    ///
241    /// let mut queue = BinaryHeapWithMap::default();
242    ///
243    /// queue.push(7usize, 42.0);
244    /// assert_eq!(Some(42.0), queue.key_of(&7));
245    ///
246    /// let result = queue.update_key_or_push(&7, 21.0);
247    /// assert_eq!(Some(21.0), queue.key_of(&7));
248    /// assert!(matches!(result, ResUpdateKeyOrPush::Decreased));
249    ///
250    /// let result = queue.update_key_or_push(&7, 200.0);
251    /// assert_eq!(Some(200.0), queue.key_of(&7));
252    /// assert!(matches!(result, ResUpdateKeyOrPush::Increased));
253    ///
254    /// let result = queue.update_key_or_push(&0, 10.0);
255    /// assert_eq!(Some(10.0), queue.key_of(&0));
256    /// assert!(matches!(result, ResUpdateKeyOrPush::Pushed));
257    /// ```
258    fn update_key_or_push(&mut self, node: &N, key: K) -> ResUpdateKeyOrPush {
259        if self.contains(node) {
260            self.update_key(node, key).into()
261        } else {
262            self.push(node.clone(), key.clone());
263            ResUpdateKeyOrPush::Pushed
264        }
265    }
266
267    /// If the `node` is present in the queue, tries to decrease its key to the given `key`:
268    /// * its key is set to the new `key` if the prior key was strictly larger than the given key;
269    /// * the queue remains unchanged if the prior key was less than or equal to the given key;
270    ///
271    /// otherwise, if the `node` is absent:
272    /// * the new (node, key) pair is pushed to the queue.
273    ///
274    /// Returns the result of the operation:
275    ///
276    /// * `ResTryDecreaseKeyOrPush::Decreased` if the `node` was present in the queue with a key strictly larger than the `key`;
277    /// * `ResTryDecreaseKeyOrPush::Unchanged` if the `node` was present in the queue with a key less than or equal to the `key`;
278    /// * `ResTryDecreaseKeyOrPush::Pushed` if the `node` was absent and it is pushed with the given `new_key`.
279    ///
280    /// # Examples
281    ///
282    /// ```
283    /// use orx_priority_queue::*;
284    ///
285    /// let mut queue = BinaryHeapOfIndices::with_index_bound(12);
286    ///
287    /// queue.push(7usize, 42.0);
288    /// assert_eq!(Some(42.0), queue.key_of(&7));
289    ///
290    /// let result = queue.try_decrease_key_or_push(&7, 21.0);
291    /// assert_eq!(Some(21.0), queue.key_of(&7));
292    /// assert!(matches!(result, ResTryDecreaseKeyOrPush::Decreased));
293    ///
294    /// let result = queue.try_decrease_key_or_push(&7, 200.0);
295    /// assert_eq!(Some(21.0), queue.key_of(&7));
296    /// assert!(matches!(result, ResTryDecreaseKeyOrPush::Unchanged));
297    ///
298    /// let result = queue.try_decrease_key_or_push(&0, 10.0);
299    /// assert_eq!(Some(10.0), queue.key_of(&0));
300    /// assert!(matches!(result, ResTryDecreaseKeyOrPush::Pushed));
301    /// ```
302    #[inline(always)]
303    fn try_decrease_key_or_push(&mut self, node: &N, key: K) -> ResTryDecreaseKeyOrPush {
304        match self.key_of(node) {
305            Some(old_key) => {
306                if key < old_key {
307                    self.decrease_key(node, key);
308                    ResTryDecreaseKeyOrPush::Decreased
309                } else {
310                    ResTryDecreaseKeyOrPush::Unchanged
311                }
312            }
313            None => {
314                self.push(node.clone(), key.clone());
315                ResTryDecreaseKeyOrPush::Pushed
316            }
317        }
318    }
319
320    /// Removes the `node` from the queue; and returns its current key.
321    ///
322    /// # Panics
323    /// This method panics if:
324    /// * the `node` is not in the queue.
325    ///
326    /// # Examples
327    ///
328    /// ```
329    /// use orx_priority_queue::*;
330    ///
331    /// let mut queue = BinaryHeapWithMap::default();
332    ///
333    /// queue.push(7usize, 42.0);
334    /// assert_eq!(Some(42.0), queue.key_of(&7));
335    ///
336    /// let key = queue.remove(&7);
337    /// assert_eq!(42.0, key);
338    /// assert!(queue.is_empty());
339    ///
340    /// // the following line would've panicked due to absent node
341    /// // let key = queue.remove(&7);
342    /// ```
343    fn remove(&mut self, node: &N) -> K;
344}
345
346/// Result of `queue.update_key(node, new_key)` operation : [`PriorityQueueDecKey::update_key`].
347#[derive(Debug, Clone, Copy, PartialEq, Eq)]
348pub enum ResUpdateKey {
349    /// Existing key of the `node` was higher; and hence, decreased to the `new_key`.
350    Decreased,
351    /// Existing key of the `node` was lower; and hence, increased to the `new_key`.
352    Increased,
353}
354
355/// Result of `queue.try_decrease_key(node, new_key)` operation : [`PriorityQueueDecKey::try_decrease_key`].
356#[derive(Debug, Clone, Copy, PartialEq, Eq)]
357pub enum ResTryDecreaseKey {
358    /// Existing key of the `node` was higher; and hence, decreased to the `new_key`.
359    Decreased,
360    /// Existing key of the `node` was lower; and hence, the queue is not changed.
361    Unchanged,
362}
363
364/// Result of `queue.decrease_key_or_push(node, key)` operation : [`PriorityQueueDecKey::decrease_key_or_push`].
365#[derive(Debug, Clone, Copy, PartialEq, Eq)]
366pub enum ResDecreaseKeyOrPush {
367    /// The `node` did not exist in the queue; and hence, pushed to the queue with the given `key`.
368    Pushed,
369    /// The `node` existed in the queue, its key was higher; and hence, decreased to the given `key`.
370    Decreased,
371}
372
373/// Result of `queue.update_key_or_push(node, key)` operation : [`PriorityQueueDecKey::update_key_or_push`].
374#[derive(Debug, Clone, Copy, PartialEq, Eq)]
375pub enum ResUpdateKeyOrPush {
376    /// The `node` did not exist in the queue; and hence, pushed to the queue with the given `key`.
377    Pushed,
378    /// The `node` existed in the queue, its key was higher; and hence, decreased to the given `key`.
379    Decreased,
380    /// The `node` existed in the queue, its key was lower; and hence, increased to the given `key`.
381    Increased,
382}
383
384/// Result of `queue.try_decrease_key_or_push(node, key)` operation : [`PriorityQueueDecKey::try_decrease_key_or_push`].
385#[derive(Debug, Clone, Copy, PartialEq, Eq)]
386pub enum ResTryDecreaseKeyOrPush {
387    /// The `node` did not exist in the queue; and hence, pushed to the queue with the given `key`.
388    Pushed,
389    /// The `node` existed in the queue, its key was higher; and hence, decreased to the given `key`.
390    Decreased,
391    /// The `node` existed in the queue, its key was lower; and hence, the queue is not changed.
392    Unchanged,
393}
394
395impl From<ResUpdateKey> for ResUpdateKeyOrPush {
396    fn from(value: ResUpdateKey) -> Self {
397        match value {
398            ResUpdateKey::Decreased => Self::Decreased,
399            ResUpdateKey::Increased => Self::Increased,
400        }
401    }
402}
403impl From<ResTryDecreaseKey> for ResTryDecreaseKeyOrPush {
404    fn from(value: ResTryDecreaseKey) -> Self {
405        match value {
406            ResTryDecreaseKey::Decreased => Self::Decreased,
407            ResTryDecreaseKey::Unchanged => Self::Unchanged,
408        }
409    }
410}