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}