indxvec/
lib.rs

1#![warn(missing_docs)]
2//! Vecs searching, indexing, ranking, sorting, merging, reversing, intersecting, printing, etc.
3
4/// Implementation of trait Indices for `&[usize]`
5pub mod indices;
6/// Implementation of trait Mutops for `&mut[T]`
7pub mod mutops;
8/// Utilities for serializing, writing and printing (optionally in colours) generic vectors.
9pub mod printing;
10/// Implementation of trait Search for Range<T>
11pub mod search;
12/// Implementation of trait Vecops for `&[T]`
13pub mod vecops;
14
15use core::{
16    cmp::{Ordering, Ordering::*, Reverse},
17    ops::Range
18};
19use printing::*;
20use std::{collections::BinaryHeap, fs::File, io, io::Write};
21
22/// Macro `here!("message")` gives `&str` with the `file:line path::function-name` of where it was invoked,
23/// followed by the passed "message" - useful for informative errors
24#[macro_export]
25macro_rules! here {
26    ($msg:expr) => {{
27        fn f() {}
28        fn type_name_of<T>(_: T) -> &'static str {
29            std::any::type_name::<T>()
30        }
31        let name = type_name_of(f);
32        format!(
33            "\n{}:{} {} - {}",
34            file!(),
35            line!(),
36            &name[..name.len() - 3],
37            $msg
38        )
39    }};
40}
41
42/// struct for minimum value, its index, maximum value, its index
43#[derive(Default)]
44pub struct MinMax<T> {
45    /// Minimum value
46    pub min: T,
47    /// Subscript (index) of the minimum
48    pub minindex: usize,
49    /// Maximum value
50    pub max: T,
51    /// Subscript (index) of the maximum
52    pub maxindex: usize,
53}
54
55/// Display implementation for MinMax struct
56impl<T> std::fmt::Display for MinMax<T>
57where
58    T: Clone + std::fmt::Display,
59{
60    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
61        write!(
62            f,
63            "min: {GR}{}{UN}, minindex: {YL}{}{UN}, max: {GR}{}{UN}, maxindex: {YL}{}{UN}",
64            self.min, self.minindex, self.max, self.maxindex
65        )
66    }
67}
68
69/// function to sort f64s
70pub fn qsortf64(v: &mut [f64]) {
71    v.sort_unstable_by(|a, b| a.total_cmp(b))
72}
73
74/// Trait to serialize tuples `&(T,T)` and `&(T,T,T)` and
75/// slices `&[T]`, `&[&[T]]`, `&[Vec<T>]`.
76/// Suitable for printing or writing to files pairs, triplets,
77/// all kinds of Vecs and slices and irregularly shaped 2D matrices.  
78/// All are converted into Strings and optionally decorated and coloured.
79/// Included are methods and constants to render the resulting String
80/// in six primary bold ANSI terminal colours.
81pub trait Printing<T>
82where
83    Self: Sized,
84{
85    /// Printable in red
86    fn rd(self) -> String {
87        format!("{RD}{}{UN}", self.to_str())
88    }
89    /// Printable in green
90    fn gr(self) -> String {
91        format!("{GR}{}{UN}", self.to_str())
92    }
93    /// Printable in blue    
94    fn bl(self) -> String {
95        format!("{BL}{}{UN}", self.to_str())
96    }
97    /// Printable in yellow
98    fn yl(self) -> String {
99        format!("{YL}{}{UN}", self.to_str())
100    }
101    /// Printable in magenta
102    fn mg(self) -> String {
103        format!("{MG}{}{UN}", self.to_str())
104    }
105    /// Printable in cyan
106    fn cy(self) -> String {
107        format!("{CY}{}{UN}", self.to_str())
108    }
109
110    /// Method to write vector(s) to file f (space separated, no brackets).
111    /// Passes up io errors
112    fn wvec(self, f: &mut File) -> Result<(), io::Error> {
113        Ok(write!(*f, "{} ", self.to_plainstr())?)
114    }
115
116    /// Method to print vector(s) to stdout (space separated, no brackets).
117    fn pvec(self) {
118        print!("{} ", self.to_plainstr())
119    }
120
121    /// Method to serialize.
122    /// Decorates Vecs with square brackets and tuples with round ones.
123    /// Implementation code is in `printing.rs`.
124    fn to_str(self) -> String;
125
126    /// Method to serialize in minimal form (space separated, no brackets)
127    /// Implementation code is in `printing.rs`.
128    fn to_plainstr(self) -> String;
129}
130
131/// Binary search algoritms implemented on RangeInclusive<T>.
132/// Using a closure `cmpr` to sample and compare data to captured target.
133pub trait Search<T> {
134    /// Unchecked first Ok(hit) or Err(insert order for a missing item).
135    fn binary_by(self, cmpr: impl FnMut(T) -> Ordering) -> Result<T, T>;
136    /// Unchecked first hit or insert order, and the final search range.
137    fn binary_any(&self, cmpr: impl FnMut(T) -> Ordering) -> (T, Range<T>);
138    /// General Binary Search, returns the range of all matching items
139    fn binary_all(&self, cmpr: impl FnMut(T) -> Ordering) -> Range<T>;
140}
141
142/// Methods to manipulate and apply indices of `Vec<usize>` type.
143pub trait Indices {
144    /// Indices::newindex(n) creates a new index without rePartialOrdering
145    fn newindex(n: usize) -> Vec<usize> {
146        Vec::from_iter(0..n)
147    }
148    /// Invert an index - turns a sort order into rank order and vice-versa
149    fn invindex(self) -> Vec<usize>;
150    /// complement of an index - reverses the ranking order
151    fn complindex(self) -> Vec<usize>;
152    /// Using a subspace index, projects `v`, into it. 
153    fn select<T:Clone>(self, v: &[T]) -> Vec<T>;
154    /// Given a complete (sort) index, extracts indicated values from `v`
155    fn unindex<T:Clone>(self, v: &[T], ascending: bool) -> Vec<T>;
156    /// Correlation coefficient of two &[usize] slices.
157    /// Pearsons on raw data, Spearman's when applied to ranks.
158    fn ucorrelation(self, v: &[usize]) -> f64;
159    /// Potentially useful clone-recast of &[usize] to Vec<f64>
160    fn indx_to_f64(self) -> Vec<f64>;
161}
162
163/// Methods to manipulate generic Vecs and slices of type `&[T]`
164pub trait Vecops<'a, T> {
165    /// Builds Vec<T> from refs in Vec<&T> (inverse of ref_vec())
166    fn deref_vec(v: &[&T], rng: Range<usize>) -> Vec<T>
167    where
168        T: Clone,
169    {
170        v.iter()
171            .take(rng.end)
172            .skip(rng.start)
173            .map(|&x| x.clone())
174            .collect()
175    }
176    /// Constructs ref wrapped `Vec<&T>` from `&[T] in rng`
177    fn ref_vec(self, rng: Range<usize>) -> Vec<&'a T>;
178    /// Helper function to copy and cast entire &[T] to `Vec<f64>`.
179    fn tof64(self) -> Vec<f64>
180    where
181        T: Clone,
182        f64: From<T>;
183    /// Maximum value in self
184    fn maxt(self) -> T
185    where
186        T: PartialOrd + Clone;
187    /// Minimum value in self
188    fn mint(self) -> T
189    where
190        T: PartialOrd + Clone;
191    /// Minimum and maximum values in self
192    fn minmaxt(self) -> (T, T)
193    where
194        T: PartialOrd + Clone;
195    /// Returns MinMax{min, minindex, max, maxindex}
196    fn minmax(self) -> MinMax<T>
197    where
198        T: PartialOrd + Clone;
199    /// MinMax of n items starting at subscript i
200    fn minmax_slice(self, i: usize, n: usize) -> MinMax<T>
201    where
202        T: PartialOrd + Clone;
203    /// MinMax of a subset of self, defined by its idx subslice between i,i+n.
204    fn minmax_indexed(self, idx: &[usize], i: usize, n: usize) -> MinMax<T>
205    where
206        T: PartialOrd + Clone;
207    /// Reversed copy of self
208    fn revs(self) -> Vec<T>
209    where
210        T: Clone;
211    /// Repeated items removed
212    fn sansrepeat(self) -> Vec<T>
213    where
214        T: PartialEq + Clone;
215    /// Some(subscript) of the first occurence of m, or None
216    fn member(self, m: T, forward: bool) -> Option<usize>
217    where
218        T: PartialEq + Clone;
219    /// Counts partially equal occurrences of val by simple linear search of an unPartialOrdered set
220    fn occurs(self, val: T) -> usize
221    where
222        T: PartialOrd;
223    /// Unites (concatenates) two unsorted slices. For union of sorted slices, use `merge`
224    fn unite_unsorted(self, v: &[T]) -> Vec<T>
225    where
226        T: Clone;
227    /// Unites two ascending index-sorted slices.
228    fn unite_indexed(self, ix1: &[usize], v2: &[T], ix2: &[usize]) -> Vec<T>
229    where
230        T: PartialOrd + Clone;
231    /// Intersects two ascending explicitly sorted generic vectors.
232    fn intersect(self, v2: &[T]) -> Vec<T>
233    where
234        T: PartialOrd + Clone;
235    /// Intersects two ascending index sorted vectors.
236    fn intersect_indexed(self, ix1: &[usize], v2: &[T], ix2: &[usize]) -> Vec<T>
237    where
238        T: PartialOrd + Clone;
239    /// Removes items of sorted v2 from sorted self.
240    fn diff(self, v2: &[T]) -> Vec<T>
241    where
242        T: PartialOrd + Clone;
243    /// Removes items of v2 from self using their sort indices.
244    fn diff_indexed(self, ix1: &[usize], v2: &[T], ix2: &[usize]) -> Vec<T>
245    where
246        T: PartialOrd + Clone;
247    /// Divides an unordered set into three: items smaller than pivot, equal, and greater
248    fn partition(self, pivot: &T) -> (Vec<T>, Vec<T>, Vec<T>)
249    where
250        T: PartialOrd + Clone;
251    /// Divides an unordered set into three by the pivot. The results are subscripts to self   
252    fn partition_indexed(self, pivot: &T) -> (Vec<usize>, Vec<usize>, Vec<usize>)
253    where
254        T: PartialOrd + Clone;
255    /// Binary Search. Automatic descending PartialOrder detection.
256    fn binsearch(self, target: &T) -> Range<usize>
257    where
258        T: PartialOrd + Copy;
259    /// Binary Search via index. Automatic descending PartialOrder detection
260    fn binsearch_indexed(self, idx: &[usize], target: &T) -> Range<usize>
261    where
262        T: PartialOrd + Copy;
263    /// Merges (unites) two sorted sets, result is also sorted    
264    fn merge(self, v2: &[T]) -> Vec<T>
265    where
266        T: PartialOrd + Clone;
267    /// Merges (unites) two sets, using their sort indices, giving also the resulting sort index
268    fn merge_indexed(self, idx1: &[usize], v2: &[T], idx2: &[usize]) -> (Vec<T>, Vec<usize>)
269    where
270        T: PartialOrd + Clone;
271    /// Used by `merge_indexed`
272    fn merge_indices(self, idx1: &[usize], idx2: &[usize]) -> Vec<usize>
273    where
274        T: PartialOrd + Clone;
275    /// Stable Merge sort main method, giving sort index
276    fn mergesort_indexed(self) -> Vec<usize>
277    where
278        T: PartialOrd + Clone;
279    /// Utility used by mergesort_indexed
280    fn mergesortslice(self, i: usize, n: usize) -> Vec<usize>
281    where
282        T: PartialOrd + Clone;
283    /// Stable Merge sort, explicitly sorted result obtained via mergesort_indexed
284    fn sortm(self, ascending: bool) -> Vec<T>
285    where
286        T: PartialOrd + Clone;
287    /// Rank index obtained via mergesort_indexed
288    fn rank(self, ascending: bool) -> Vec<usize>
289    where
290        T: PartialOrd + Clone;
291    /// Utility, swaps any two items into ascending order
292    fn isorttwo(self, idx: &mut [usize], i0: usize, i1: usize)
293    where
294        T: PartialOrd;
295    /// Utility, sorts any three items into ascending order
296    fn isortthree(self, idx: &mut [usize], i0: usize, i1: usize, i2: usize)
297    where
298        T: PartialOrd;
299    /// Stable hash sort giving sort index
300    fn hashsort_indexed(self, quantify: impl Copy + Fn(&T) -> f64) -> Vec<usize>
301    where
302        T: PartialOrd + Clone;
303    /// Utility used by hashsort_indexed
304    fn hashsortslice(
305        self,
306        idx: &mut [usize],
307        i: usize,
308        n: usize,
309        min: f64,
310        max: f64,
311        quantify: impl Copy + Fn(&T) -> f64,
312    ) where
313        T: PartialOrd + Clone;
314    /// Stable hash sort. Returns new sorted data vector (ascending or descending)
315    fn sorth(self, quantify: impl Copy + Fn(&T) -> f64, ascending: bool) -> Vec<T>
316    where
317        T: PartialOrd + Clone;
318    /// Heap of k smallest items in no particular order, except the first one is maximum.
319    /// Best for finding just the one k-ranked item
320    fn smallest_k(&self, k: usize) -> BinaryHeap<&T>
321    where
322        T: Ord;
323    /// Heap of k biggest items in no particular order, except the first one is minimum
324    /// Best for finding just the one k complement ranked item (k-th from the end).
325    fn biggest_k(&self, k: usize) -> BinaryHeap<Reverse<&T>>
326    where
327        T: Ord;
328    /// Insert logsort, returns sort index. Reverse `c` for descending order
329    fn isort_indexed<F>(self, rng: Range<usize>, c: F) -> Vec<usize>
330    where
331        F: Fn(&T, &T) -> Ordering;
332    /// Insert logsort of refs (within range). Suitable for bulky end-types.
333    /// Faster than `isort_indexed`, as it does not construct an explicit index.
334    fn isort_refs<F>(self, rng: Range<usize>, c: F) -> Vec<&'a T>
335    where
336        F: Fn(&T, &T) -> Ordering;
337    /// First k sorted items from rng (ascending or descending, depending on `c`)
338    /// Faster than `smallest/biggest_k, followed by `.to_sorted_vec()`.
339    fn best_k<F>(self, k: usize, rng: Range<usize>, c: F) -> Vec<&'a T>
340    where
341        F: Fn(&T, &T) -> Ordering;
342    /// Sort index of the `best` k items in rng (ascending or descending, depending on `c`)
343    fn best_k_indexed<F>(self, k: usize, rng: Range<usize>, c: F) -> Vec<usize>
344    where
345        F: Fn(&T, &T) -> Ordering;
346    /// Unsorted index of the `best` k items in rng (ascending or descending, depending on `c`)
347    fn best_k_unsorted<F>(self, k: usize, rng: Range<usize>, c: F) -> Vec<usize>
348    where
349        F: Fn(&T, &T) -> Ordering;
350    /// Subspace index: sorted subscripts of only the sufficiently ranking values.
351    fn subspace<F>(self, rank:usize, c:F) -> Vec<usize>
352    where
353        F: Fn(&T, &T) -> Ordering;
354}
355
356/// Mutable Operators on `&mut[T]`
357pub trait Mutops<T> {
358    /// Associated method `part` partitions `s: &mut [&T]` within range `rng`, using comparator `c`.  
359    /// Suitable pivot should be selected and placed in `s[rng.start]`.  
360    /// Returns the boundaries of the rearranged partitions, (eqstart,gtstart), where  
361    /// `rng.start..eqstart` (may be empty) contains references to items lesser than the pivot,  
362    /// `gtstart-eqstart` is the number (>= 1) of items equal to the pivot (contains undefined references)  
363    /// `gtstart..rng.end` (may be empty) contains references to items greater than the pivot.
364    fn part(
365        s: &mut [&T],
366        rng: &Range<usize>,
367        c: &mut impl FnMut(&T, &T) -> Ordering,
368    ) -> (usize, usize) {
369        // get pivot from the first location
370        let pivot = s[rng.start];
371        let mut eqstart = rng.start;
372        let mut gtstart = eqstart + 1;
373        for t in rng.start + 1..rng.end {
374            match c(s[t], pivot) {
375                Less => {
376                    s[eqstart] = s[t];
377                    eqstart += 1;
378                    s[t] = s[gtstart];
379                    gtstart += 1;
380                }
381                Equal => {
382                    s[t] = s[gtstart];
383                    gtstart += 1;
384                }
385                Greater => (),
386            }
387        }
388        (eqstart, gtstart)
389    }
390
391    /// partitions by bitmask
392    fn part_binary(self, rng: &Range<usize>, bitmask: u64) -> usize
393    where
394        T: Copy, u64: From<T>;
395    /// mutable reversal, general utility
396    fn mutrevs(self);
397    /// utility that mutably swaps two indexed items into ascending order
398    fn mutsorttwo(self, i0: usize, i1: usize) -> bool
399    where
400        T: PartialOrd;
401    /// utility that mutably bubble sorts three indexed items into ascending order
402    fn mutsortthree(self, i0: usize, i1: usize, i2: usize)
403    where
404        T: PartialOrd;
405    /// Possibly the fastest sort for long lists. Wrapper for `muthashsortslice`.
406    fn muthashsort(self, quantify: impl Copy + Fn(&T) -> f64)
407    where
408        T: PartialOrd + Clone;
409    /// Sorts n items from i in self. Used by muthashsort.
410    fn muthashsortslice(
411        self,
412        i: usize,
413        n: usize,
414        min: f64,
415        max: f64,
416        quantify: impl Copy + Fn(&T) -> f64,
417    ) where
418        T: PartialOrd + Clone;
419    /// Mutable insert logsort. Pass in reversed comparator `c` for descending sort
420    fn mutisort<F>(self, rng: Range<usize>, c: F)
421    where
422        T: Copy,
423        F: Fn(&T, &T) -> Ordering;
424}