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}