mywheel_rs/bpqueue.rs
1use crate::dllist::{Dllink, Dllist};
2
3#[doc = svgbobdoc::transform!(
4/// The `BPQueue` struct is a bounded priority queue implemented using an array of doubly-linked lists,
5/// with integer keys in a specified range.
6///
7/// Bounded Priority Queue with integer keys in [a..b].
8/// Implemented by an array (bucket) of doubly-linked lists.
9/// Efficient if the keys are bounded by a small integer value.
10///
11/// Note that this class does not own PQ nodes. This feature
12/// allows these nodes sharable in both doubly linked list class and
13/// this class. In the FM algorithm, nodes are either attached to
14/// the gain buckets (PQ) or to the waitinglist (doubly-linked list),
15/// but cannot be in both at the same time.
16///
17/// Another improvement is to increase the size of the array by one
18/// element, i.e. (b - a + 2). The extra dummy array element (called
19/// sentinel) is used to reduce the boundary checking during updates.
20///
21/// All the member functions assume that the keys are inside the bounds.
22///
23/// ```svgbob
24/// ____ bucket
25/// +----+ /
26/// b |high| V
27/// +----+
28/// | |
29/// +----+ +----+ +----+
30/// |max-|--->|{c}-|--->|{c} |
31/// +----+ +----+ +----+
32/// | |
33/// +----+ +----+ +----+ +----+
34/// | -|--->|{c}-|--->|{c}-|--->|{c} |
35/// +----+ +----+ +----+ +----+
36/// : :
37///
38/// : :
39/// +----+ +----+ +----+ +----+ +----+
40/// |2 -|--->|{c}-|--->|{c}-|--->|{c}-|--->|{c} |
41/// +----+ +----+ +----+ +----+ +----+
42/// a |1 |
43/// +----+
44/// sentinel|0 |
45/// +----+^
46/// \
47/// always empty
48/// # Legend:
49/// a = {
50/// fill: lightblue;
51/// }
52/// c = {
53/// fill: papayawhip;
54/// }
55/// ```
56///
57/// Properties:
58///
59/// * `max`: The maximum number of elements that can be stored in the bounded priority queue.
60/// * `offset`: The `offset` property represents the lower bound of the integer keys in the bounded
61/// priority queue. It is of type `i32`, which means it can hold both positive and negative values. The
62/// offset is used to calculate the index of the bucket in the `bucket` array for a given key.
63/// * `high`: The `high` property represents the highest priority level in the bounded priority queue.
64/// It indicates the index of the last bucket in the `bucket` array.
65/// * `sentinel`: A doubly linked list node that serves as a sentinel or dummy node. It is used to
66/// reduce boundary checking during updates.
67/// * `bucket`: The `bucket` property is a vector of doubly-linked lists. Each doubly-linked list
68/// represents a priority level, with the index of the vector representing the priority value. The
69/// elements in the doubly-linked lists are tuples containing a priority value and a value of type `T`.
70)]
71#[derive(Debug)]
72pub struct BPQueue<T> {
73 max: usize,
74 offset: i32,
75 high: usize,
76 sentinel: Dllink<(usize, T)>,
77 pub bucket: Vec<Dllist<(usize, T)>>,
78}
79
80impl<T: Default + Clone> BPQueue<T> {
81 /// Construct a new BPQueue object
82 ///
83 /// # Examples
84 ///
85 /// ```rust
86 /// use mywheel_rs::bpqueue::BPQueue;
87 /// let bpq = BPQueue::<i32>::new(-3, 3);
88 ///
89 /// assert!(bpq.is_empty());
90 /// ```
91 pub fn new(a: i32, b: i32) -> Self {
92 assert!(a <= b);
93 let mut res = Self {
94 max: 0,
95 offset: a - 1,
96 high: (b - a + 1) as usize,
97 sentinel: Dllink::new((1314, T::default())),
98 bucket: vec![Dllist::new((5354, T::default())); (b - a + 2) as usize],
99 };
100 for lst in res.bucket.iter_mut() {
101 lst.clear();
102 }
103 // res.sentinel.clear();
104 res.bucket[0].append(&mut res.sentinel);
105 res
106 }
107
108 /// Whether the %BPQueue is empty.
109 ///
110 /// # Examples
111 ///
112 /// ```rust
113 /// use mywheel_rs::bpqueue::BPQueue;
114 /// let bpq = BPQueue::<i32>::new(-3, 3);
115 ///
116 /// assert!(bpq.is_empty());
117 /// ```
118 pub fn is_empty(&self) -> bool {
119 self.max == 0
120 }
121
122 /// Get the max value
123 ///
124 /// # Examples
125 ///
126 /// ```rust
127 /// use mywheel_rs::bpqueue::BPQueue;
128 /// let bpq = BPQueue::<i32>::new(-3, 3);
129 ///
130 /// assert_eq!(bpq.get_max(), -4);
131 /// ```
132 pub fn get_max(&self) -> i32 {
133 self.offset + self.max as i32
134 }
135
136 /// Clear reset the PQ
137 ///
138 /// # Examples
139 ///
140 /// ```rust
141 /// use mywheel_rs::bpqueue::BPQueue;
142 /// let mut bpq = BPQueue::<i32>::new(-3, 3);
143 /// bpq.clear();
144 ///
145 /// assert!(bpq.is_empty());
146 /// ```
147 pub fn clear(&mut self) {
148 while self.max > 0 {
149 self.bucket[self.max].clear();
150 self.max -= 1;
151 }
152 }
153
154 /// Set the key object
155 ///
156 /// # Examples
157 ///
158 /// ```rust
159 /// use mywheel_rs::bpqueue::BPQueue;
160 /// let mut bpq = BPQueue::<i32>::new(-3, 3);
161 ///
162 /// assert!(bpq.is_empty());
163 /// ```
164 pub fn set_key(&mut self, it: &mut Dllink<(usize, T)>, gain: i32) {
165 it.data.0 = (gain - self.offset) as usize;
166 }
167
168 /// Append item with external key
169 ///
170 /// # Examples
171 ///
172 /// ```rust
173 /// use mywheel_rs::bpqueue::BPQueue;
174 /// use mywheel_rs::dllist::Dllink;
175 ///
176 /// let mut bpq = BPQueue::<i32>::new(-3, 3);
177 /// let mut a = Dllink::<(usize, i32)>::new((0, 3));
178 /// bpq.append(&mut a, 0);
179 ///
180 /// assert!(!bpq.is_empty());
181 /// ```
182 pub fn append(&mut self, it: &mut Dllink<(usize, T)>, k: i32) {
183 assert!(k > self.offset);
184 it.data.0 = (k - self.offset) as usize;
185 if self.max < it.data.0 {
186 self.max = it.data.0;
187 }
188 self.bucket[it.data.0].append(it);
189 }
190
191 /// Append item with external key
192 ///
193 /// # Examples
194 ///
195 /// ```rust
196 /// use mywheel_rs::bpqueue::BPQueue;
197 /// use mywheel_rs::dllist::Dllink;
198 ///
199 /// let mut bpq = BPQueue::<i32>::new(-3, 3);
200 /// let mut a = Dllink::<(usize, i32)>::new((0, 3));
201 /// bpq.appendleft(&mut a, 0);
202 ///
203 /// assert!(!bpq.is_empty());
204 /// ```
205 pub fn appendleft(&mut self, it: &mut Dllink<(usize, T)>, k: i32) {
206 assert!(k > self.offset);
207 it.data.0 = (k - self.offset) as usize;
208 if self.max < it.data.0 {
209 self.max = it.data.0;
210 }
211 self.bucket[it.data.0].appendleft(it);
212 }
213
214 /// Append item with internal key
215 ///
216 /// # Examples
217 ///
218 /// ```rust
219 /// use mywheel_rs::bpqueue::BPQueue;
220 /// use mywheel_rs::dllist::Dllink;
221 ///
222 /// let mut bpq = BPQueue::<i32>::new(-3, 3);
223 /// let mut a = Dllink::<(usize, i32)>::new((0, 3));
224 /// bpq.appendleft_direct(&mut a);
225 ///
226 /// assert!(!bpq.is_empty());
227 /// ```
228 pub fn appendleft_direct(&mut self, it: &mut Dllink<(usize, T)>) {
229 assert!(it.data.0 as i32 > self.offset);
230 self.appendleft(it, it.data.0 as i32);
231 }
232
233 /// Pop node with the highest key
234 ///
235 /// # Examples
236 ///
237 /// ```rust
238 /// use mywheel_rs::bpqueue::BPQueue;
239 /// use mywheel_rs::dllist::Dllink;
240 ///
241 /// let mut bpq = BPQueue::<i32>::new(-3, 3);
242 /// let mut a = Dllink::<(usize, i32)>::new((0, 3));
243 /// bpq.append(&mut a, 0);
244 /// let d = bpq.popleft();
245 /// let (key, v) = unsafe { (*d).data.clone() };
246 ///
247 /// assert_eq!(key, 4);
248 /// assert_eq!(v, 3);
249 /// ```
250 pub fn popleft(&mut self) -> *mut Dllink<(usize, T)> {
251 let res = self.bucket[self.max].popleft();
252 while self.bucket[self.max].is_empty() {
253 self.max -= 1;
254 }
255 res
256 }
257
258 /// Detach the item from BPQueue
259 ///
260 /// # Examples
261 ///
262 /// ```rust
263 /// use mywheel_rs::bpqueue::BPQueue;
264 /// use mywheel_rs::dllist::Dllink;
265 ///
266 /// let mut bpq = BPQueue::<i32>::new(-3, 3);
267 /// let mut a = Dllink::<(usize, i32)>::new((0, 3));
268 /// bpq.append(&mut a, 0);
269 /// bpq.detach(&mut a);
270 ///
271 /// assert!(bpq.is_empty());
272 /// ```
273 pub fn detach(&mut self, it: &mut Dllink<(usize, T)>) {
274 // self.bucket[it.data.second].detach(it)
275 it.detach();
276 while self.bucket[self.max].is_empty() {
277 self.max -= 1;
278 }
279 }
280
281 /// Decrease key by delta
282 ///
283 /// Note that the order of items with same key will not be preserved.
284 /// For the FM algorithm, this is a desired behavior.
285 ///
286 /// # Examples
287 ///
288 /// ```rust
289 /// use mywheel_rs::bpqueue::BPQueue;
290 /// use mywheel_rs::dllist::Dllink;
291 ///
292 /// let mut bpq = BPQueue::<i32>::new(-3, 3);
293 /// let mut a = Dllink::<(usize, i32)>::new((0, 3));
294 /// bpq.append(&mut a, 0);
295 /// bpq.decrease_key(&mut a, 1);
296 ///
297 /// assert_eq!(bpq.get_max(), -1);
298 /// ```
299 pub fn decrease_key(&mut self, it: &mut Dllink<(usize, T)>, delta: usize) {
300 // self.bucket[it.data.second].detach(it)
301 it.detach();
302 it.data.0 -= delta;
303 assert!(it.data.0 > 0);
304 assert!(it.data.0 <= self.high);
305 self.bucket[it.data.0].append(it); // FIFO
306 if self.max < it.data.0 {
307 self.max = it.data.0;
308 return;
309 }
310 while self.bucket[self.max].is_empty() {
311 self.max -= 1;
312 }
313 }
314
315 /// Increase key by delta
316 ///
317 /// Note that the order of items with same key will not be preserved.
318 /// For the FM algorithm, this is a desired behavior.
319 ///
320 /// # Examples
321 ///
322 /// ```rust
323 /// use mywheel_rs::bpqueue::BPQueue;
324 /// use mywheel_rs::dllist::Dllink;
325 ///
326 /// let mut bpq = BPQueue::<i32>::new(-3, 3);
327 /// let mut a = Dllink::<(usize, i32)>::new((0, 3));
328 /// bpq.append(&mut a, 0);
329 /// bpq.increase_key(&mut a, 1);
330 ///
331 /// assert_eq!(bpq.get_max(), 1);
332 /// ```
333 pub fn increase_key(&mut self, it: &mut Dllink<(usize, T)>, delta: usize) {
334 // self.bucket[it.data.second].detach(it)
335 it.detach();
336 it.data.0 += delta;
337 assert!(it.data.0 > 0);
338 assert!(it.data.0 <= self.high);
339 self.bucket[it.data.0].appendleft(it); // LIFO
340 if self.max < it.data.0 {
341 self.max = it.data.0;
342 }
343 }
344
345 /// Modify key by delta
346 ///
347 /// Note that the order of items with same key will not be preserved.
348 /// For the FM algorithm, this is a desired behavior.
349 ///
350 /// # Examples
351 ///
352 /// ```rust
353 /// use mywheel_rs::bpqueue::BPQueue;
354 /// use mywheel_rs::dllist::Dllink;
355 ///
356 /// let mut bpq = BPQueue::<i32>::new(-3, 3);
357 /// let mut a = Dllink::<(usize, i32)>::new((0, 3));
358 /// bpq.append(&mut a, 0);
359 /// bpq.modify_key(&mut a, -1);
360 ///
361 /// assert_eq!(bpq.get_max(), -1);
362 /// ```
363 pub fn modify_key(&mut self, it: &mut Dllink<(usize, T)>, delta: i32) {
364 use core::cmp::Ordering;
365
366 if it.is_locked() {
367 return;
368 }
369 match delta.cmp(&0) {
370 Ordering::Greater => self.increase_key(it, delta as usize),
371 Ordering::Less => self.decrease_key(it, -delta as usize),
372 Ordering::Equal => (),
373 }
374 // if delta > 0 {
375 // self.increase_key(it, delta as usize);
376 // } else if delta < 0 {
377 // self.decrease_key(it, -delta as usize);
378 // }
379 }
380}
381
382/// BPQueue iterator
383///
384/// Traverse the list from the first item. Usually it is safe
385/// to attach/detach list items during the iterator is active.
386#[derive(Debug)]
387pub struct BPQueueIterator<'a, T> {
388 pub bpq: &'a mut BPQueue<T>,
389 pub curkey: usize,
390}
391
392impl<'a, T: Default> BPQueueIterator<'a, T> {
393 /// Construct a new DllIterator object
394 ///
395 /// # Examples
396 ///
397 /// ```rust
398 /// use mywheel_rs::bpqueue::{BPQueue, BPQueueIterator};
399 /// let mut b = BPQueue::<i32>::new(-3, 3);
400 /// let it = BPQueueIterator::new(&mut b);
401 /// ```
402 #[inline]
403 pub fn new(bpq: &'a mut BPQueue<T>) -> Self {
404 let curkey = bpq.max;
405 // let curitem = (*bpq).bucket[bpq.max].iter_mut();
406 Self { bpq, curkey }
407 }
408}
409
410impl<T: Default> BPQueue<T> {
411 /// Return a new DllIterator object
412 pub fn iter_mut(&mut self) -> BPQueueIterator<'_, T> {
413 BPQueueIterator::new(self)
414 }
415}
416
417// impl<'a, T> Iterator for BPQueueIterator<'a, T> {
418// type Item = &'a mut Dllink<T>;
419//
420// /// Return a next item
421// fn next(&mut self) -> Option<Self::Item> {
422// if self.cur as *const Dllink<T> != self.link as *const Dllink<T> {
423// let res = self.cur;
424// unsafe {
425// self.cur = (*self.cur).next;
426// return Some(&mut *res);
427// }
428// }
429// None
430// }
431// }
432//
433
434#[cfg(test)]
435mod tests {
436 use super::*;
437
438 #[test]
439 fn test_bpqueue1() {
440 let mut bpq = BPQueue::<i32>::new(-3, 3);
441 let mut a = Dllink::<(usize, i32)>::new((0, 3));
442 bpq.append(&mut a, 0);
443 assert_eq!(bpq.get_max(), 0);
444 assert!(!bpq.is_empty());
445 bpq.set_key(&mut a, 0);
446 assert_eq!(a.data.0, 4);
447 bpq.popleft();
448 assert!(bpq.is_empty());
449 assert_eq!(bpq.get_max(), -4);
450 }
451
452 #[test]
453 fn test_bpqueue2() {
454 let mut bpq = BPQueue::<i32>::new(-3, 3);
455 let mut a = Dllink::<(usize, i32)>::new((0, 3));
456 bpq.appendleft_direct(&mut a);
457 assert_eq!(bpq.get_max(), 0);
458 bpq.increase_key(&mut a, 1);
459 assert_eq!(bpq.get_max(), 1);
460 bpq.decrease_key(&mut a, 1);
461 assert_eq!(bpq.get_max(), 0);
462
463 bpq.decrease_key(&mut a, 1);
464 bpq.increase_key(&mut a, 1);
465 bpq.modify_key(&mut a, 1);
466 bpq.detach(&mut a);
467 assert_eq!(bpq.get_max(), -4);
468 bpq.clear();
469 assert_eq!(bpq.get_max(), -4);
470
471 let mut c = Dllink::<(usize, i32)>::new((3, 2));
472 let mut waiting_list = Dllist::<(usize, i32)>::new((99, 98));
473 waiting_list.clear();
474 waiting_list.append(&mut c); // will unlock c
475 bpq.modify_key(&mut c, -1); // c is not yet in bpq
476 assert!(!bpq.is_empty());
477 assert_eq!(bpq.get_max(), -2);
478 assert!(waiting_list.is_empty());
479 }
480
481 #[test]
482 fn test_bpqueue3() {
483 // assert!(BPQueue::<i32>::new(-10.4, 10.4).is_err());
484
485 let mut bpq1 = BPQueue::<i32>::new(-10, 10);
486 let mut bpq2 = BPQueue::<i32>::new(-10, 10);
487
488 assert_eq!(bpq1.get_max(), -11);
489
490 let mut d = Dllink::<(usize, i32)>::new((0, 0));
491 let mut e = Dllink::<(usize, i32)>::new((0, 1));
492 let mut f = Dllink::<(usize, i32)>::new((0, 2));
493
494 assert_eq!(d.data.0, 0);
495
496 bpq1.append(&mut e, 3);
497 bpq1.append(&mut f, -10);
498 bpq1.append(&mut d, 5);
499
500 unsafe {
501 bpq2.append(&mut *bpq1.popleft(), -6); // d
502 bpq2.append(&mut *bpq1.popleft(), 3);
503 bpq2.append(&mut *bpq1.popleft(), 0);
504 }
505
506 bpq2.modify_key(&mut d, 15);
507 bpq2.modify_key(&mut d, -3);
508 bpq2.detach(&mut f);
509 // assert_eq!(bpq1._max, 0);
510 assert_eq!(bpq2.get_max(), 6);
511 bpq1.clear();
512 }
513
514 #[test]
515 fn test_bpqueue4() {
516 let mut bpq = BPQueue::<i32>::new(-3, 3);
517 let mut a = Dllink::<(usize, i32)>::new((0, 3));
518 bpq.append(&mut a, 0);
519 bpq.modify_key(&mut a, 0); // unchange
520 assert_eq!(bpq.get_max(), 0);
521
522 bpq.modify_key(&mut a, -1);
523 assert_eq!(bpq.get_max(), -1);
524
525 a.lock();
526 bpq.modify_key(&mut a, 1); // unchange because it is locked
527 assert_eq!(bpq.get_max(), -1);
528
529 let mut b = Dllink::<(usize, i32)>::new((0, 8));
530 bpq.append(&mut b, -3);
531 bpq.modify_key(&mut b, 1);
532 assert_eq!(bpq.get_max(), -1);
533 }
534}