use std::fmt;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Perm {
inv: PermVec,
}
#[derive(Clone, PartialEq, Eq, Hash)]
struct PermVec( Vec<usize>, );
impl fmt::Debug for PermVec {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.0, f)
}
}
#[derive(Debug)]
pub struct InvalidPermutationError { _private: () }
impl fmt::Display for InvalidPermutationError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt("Tried to construct an invalid permutation.", f)
}
}
impl Perm {
pub fn eye(n: usize) -> Perm
{ Perm { inv: PermVec::eye(n) } }
pub fn len(&self) -> usize
{ self.inv.0.len() }
pub fn argsort<T: Ord>(xs: &[T]) -> Perm
{ Perm { inv: PermVec::argsort(xs).inverted() } }
pub fn argsort_unstable<T: Ord>(xs: &[T]) -> Perm
{ Perm { inv: PermVec::argsort_unstable(xs).inverted() } }
pub fn from_vec(vec: Vec<usize>) -> Result<Perm, InvalidPermutationError>
{ Ok(Perm { inv: PermVec::from_vec(vec)? }.inverted()) }
pub fn from_raw_inv(inv: Vec<usize>) -> Result<Perm, InvalidPermutationError>
{ Ok(Perm { inv: PermVec::from_vec(inv)? }) }
pub unsafe fn from_raw_inv_unchecked(inv: Vec<usize>) -> Perm
{ Perm { inv: PermVec(inv).debug_validated() } }
pub fn append_mut(&mut self, other: &Perm)
{
self.inv.append_mut(&other.inv);
}
pub fn random(n: usize) -> Perm
{
use rand::Rng;
let mut inv: Vec<_> = (0..n).collect();
rand::thread_rng().shuffle(&mut inv);
Perm { inv: PermVec(inv) }
}
pub fn into_vec(self) -> Vec<usize>
{ self.inverted().inv.0 }
pub fn into_raw_inv(self) -> Vec<usize>
{ self.inv.0 }
#[must_use = "not an in-place operation"]
pub fn inverted(&self) -> Perm
{
Perm { inv: self.inv.inverted() }
}
pub fn shift_right(self, amt: usize) -> Self
{ Perm { inv: self.inv.prefix_shift_left(amt) } }
pub fn shift_left(self, amt: usize) -> Self
{ Perm { inv: self.inv.prefix_shift_right(amt) } }
pub fn shift_signed(self, n: isize) -> Self
{
if n < 0 {
assert_ne!(n, std::isize::MIN, "(exasperated sigh)");
self.shift_left((-n) as usize)
} else {
self.shift_right(n as usize)
}
}
pub fn permute_index(&self, i: usize) -> usize {
self.inv.0[i]
}
pub fn with_outer(&self, slower: &Perm) -> Perm
{
Perm { inv: self.inv.with_outer(&slower.inv) }
}
pub fn with_inner(&self, faster: &Perm) -> Perm
{ faster.with_outer(self) }
pub fn pow_unsigned(&self, mut exp: u64) -> Perm {
let mut acc = Perm::eye(self.len());
let mut base = self.clone();
while exp > 0 {
if (exp & 1) == 1 {
acc = acc.permuted_by(&base);
}
base = base.clone().permuted_by(&base);
exp /= 2;
}
acc
}
pub fn pow_signed(&self, exp: i64) -> Perm {
if exp < 0 {
assert_ne!(exp, std::i64::MIN); self.inverted().pow_unsigned((-exp) as u64)
} else {
self.pow_unsigned(exp as u64)
}
}
}
impl PermVec {
fn eye(n: usize) -> PermVec
{ PermVec((0..n).collect()) }
fn argsort<T: Ord>(xs: &[T]) -> PermVec
{
let mut perm: Vec<_> = (0..xs.len()).collect();
perm.sort_by(|&a, &b| xs[a].cmp(&xs[b]));
PermVec(perm)
}
fn argsort_unstable<T: Ord>(xs: &[T]) -> PermVec
{
let mut perm: Vec<_> = (0..xs.len()).collect();
perm.sort_unstable_by(|&a, &b| xs[a].cmp(&xs[b]));
PermVec(perm)
}
fn from_vec(vec: Vec<usize>) -> Result<PermVec, InvalidPermutationError>
{
if !Self::validate_data(&vec) {
return Err(InvalidPermutationError { _private: () });
}
Ok(PermVec(vec))
}
#[must_use = "doesn't assert"]
fn validate_data(xs: &[usize]) -> bool {
let mut vec = xs.to_vec();
vec.sort();
vec.into_iter().eq(0..xs.len())
}
fn debug_validated(self) -> PermVec {
debug_assert!(PermVec::validate_data(&self.0));
self
}
fn append_mut(&mut self, other: &Self)
{
let offset = self.0.len();
self.0.extend(other.0.iter().map(|&i| i + offset));
debug_assert!(PermVec::validate_data(&self.0));
}
#[must_use = "not an in-place operation"]
fn inverted(&self) -> Self
{
let mut inv = vec![::std::usize::MAX; self.0.len()]; for (i, &x) in self.0.iter().enumerate() { inv[x] = i;
}
PermVec(inv).debug_validated()
}
#[allow(unused)]
fn postfix_shift_right(mut self, amt: usize) -> PermVec
{
let n = self.0.len();
self.0.rotate_right(amt % n);
self.debug_validated()
}
#[allow(unused)]
fn postfix_shift_left(mut self, amt: usize) -> PermVec
{
let n = self.0.len();
self.0.rotate_left(amt % n);
self.debug_validated()
}
fn prefix_shift_left(mut self, amt: usize) -> PermVec {
let n = self.0.len();
let amt = amt % n;
for x in &mut self.0 {
*x = (*x + amt) % n;
}
self.debug_validated()
}
fn prefix_shift_right(self, amt: usize) -> PermVec {
let len = self.0.len();
self.prefix_shift_left(len - amt % len)
}
fn with_outer(&self, slower: &PermVec) -> PermVec
{
assert!(self.0.len().checked_mul(slower.0.len()).is_some());
let mut perm = Vec::with_capacity(self.0.len() * slower.0.len());
for &block_index in &slower.0 {
let offset = self.0.len() * block_index;
perm.extend(self.0.iter().map(|&x| x + offset));
}
PermVec(perm).debug_validated()
}
fn then(&self, other: &PermVec) -> PermVec
{
assert_eq!(self.0.len(), other.0.len(), "Incorrect permutation length");
let mut out = vec![::std::usize::MAX; self.0.len()];
for (out_i, &self_i) in other.0.iter().enumerate() {
out[out_i] = self.0[self_i];
}
PermVec(out).debug_validated()
}
}
impl Perm {
pub fn then(&self, other: &Perm) -> Perm
{
Perm { inv: other.inv.then(&self.inv) }
}
pub fn of(&self, other: &Perm) -> Perm
{ other.then(self) }
}
pub trait Permute: Sized {
fn permuted_by(self, perm: &Perm) -> Self;
}
mod unsafe_impls {
use super::*;
pub(super) fn inv_permute_to_new_vec<T>(vec: Vec<T>, inv: &PermVec) -> Vec<T> {
let mut out = Vec::with_capacity(vec.len());
inv_permute_to_mut_vec(vec, inv, &mut out);
out
}
pub(super) fn inv_permute_to_mut_vec<T>(mut vec: Vec<T>, inv: &PermVec, out: &mut Vec<T>) {
assert_eq!(
vec.len(), inv.0.len(),
"Incorrect permutation length",
);
out.clear();
out.reserve_exact(inv.0.len());
{ let vec_ptr = vec.as_ptr();
let out_ptr = out.as_mut_ptr();
for (vec_i, &out_i) in inv.0.iter().enumerate() {
let value = unsafe { vec_ptr.offset(vec_i as isize).read() };
let dest_ptr = unsafe { out_ptr.offset(out_i as isize) };
unsafe { dest_ptr.write(value) };
}
}
unsafe { out.set_len(vec.len()); }
unsafe { vec.set_len(0); }
}
}
impl<T> Permute for Vec<T> {
fn permuted_by(self, perm: &Perm) -> Vec<T>
{ self::unsafe_impls::inv_permute_to_new_vec(self, &perm.inv) }
}
impl Permute for PermVec {
fn permuted_by(self, perm: &Perm) -> PermVec
{ PermVec(self.0.permuted_by(perm)) }
}
impl Permute for Perm {
fn permuted_by(self, other: &Perm) -> Perm
{ self.then(other) }
}
impl<T: Clone> Permute for std::rc::Rc<[T]> {
fn permuted_by(self, perm: &Perm) -> Self
{
let vec = self.to_vec(); let vec = vec.permuted_by(perm); let slice = vec.into_boxed_slice();
slice.into() }
}
impl<T: Permute + Clone> Permute for std::rc::Rc<T> {
fn permuted_by(self, perm: &Perm) -> Self {
Box::new((*self).clone().permuted_by(perm)).into()
}
}
#[cfg(test)]
#[deny(unused)]
mod tests {
use super::*;
use self::drop_pusher::DropPusher;
mod drop_pusher {
use std::rc::Rc;
use std::cell::RefCell;
pub struct DropPusher<T: Copy>(Rc<RefCell<Vec<T>>>, T);
impl<T: Copy + 'static> DropPusher<T> {
pub fn new_trial() -> (Rc<RefCell<Vec<T>>>, Box<dyn Fn(T) -> DropPusher<T>>)
{
let history = Rc::new(RefCell::new(vec![]));
let new = {
let history = history.clone();
Box::new(move |x| DropPusher(history.clone(), x))
};
(history, new)
}
}
impl<T: Copy> Drop for DropPusher<T> {
fn drop(&mut self) {
self.0.borrow_mut().push(self.1);
}
}
}
#[test]
fn inverse()
{
let perm = Perm::random(20);
let inv = perm.inverted();
assert_eq!(perm.clone().permuted_by(&inv), Perm::eye(20));
assert_eq!(inv.permuted_by(&perm), Perm::eye(20));
}
#[test]
fn inverse_is_argsort()
{
let perm = Perm::random(20);
assert_eq!(
Perm::argsort(&perm.clone().into_vec()).into_vec(),
perm.inverted().into_vec(),
);
}
#[test]
fn invalid() {
assert!(matches!(
Perm::from_vec(vec![0, 1, 3, 3]),
Err(InvalidPermutationError {..}),
));
assert!(matches!(
Perm::from_vec(vec![1, 2, 3]),
Err(InvalidPermutationError {..}),
));
}
#[test]
#[should_panic(expected = "permutation length")]
fn incompatible() {
let _ = vec![4, 2, 1].permuted_by(&Perm::eye(2));
}
#[test]
fn drop_safety() {
let (drop_history, dp) = DropPusher::new_trial();
{
let vec = vec![dp(0), dp(1), dp(2), dp(3), dp(4)];
let vec2 = vec.permuted_by(&Perm::from_vec(vec![3, 1, 0, 4, 2]).unwrap());
assert_eq!(drop_history.borrow().len(), 0);
drop(vec2);
assert_eq!(drop_history.borrow().len(), 5);
}
assert_eq!(drop_history.borrow().len(), 5);
}
#[test]
fn argsort_is_stable()
{
use rand::Rng;
let n = 300;
let values: Vec<_> = (0..n).map(|_| rand::thread_rng().gen_range(0, 2)).collect();
let perm = Perm::argsort(&values);
let permuted_indices = (0..n).collect::<Vec<_>>().permuted_by(&perm);
let permuted_values = values.permuted_by(&perm);
let error = format!("not your lucky day, Mister one-in-{:e}", 2f64.powi(n));
let first_one = permuted_values.iter().position(|&x| x == 1).expect(&error);
let is_strictly_sorted = |xs: &[_]| xs.windows(2).all(|w| w[0] < w[1]);
assert!(is_strictly_sorted(&permuted_indices[..first_one]));
assert!(is_strictly_sorted(&permuted_indices[first_one..]));
let error = format!("DEFINITELY not your lucky day, Mister one-in-{}-factorial!!", n);
assert!(!is_strictly_sorted(&permuted_indices[..]), "{}", error);
}
#[test]
fn associativity()
{
let xy = Perm::from_vec(vec![1, 0, 2]).unwrap();
let zx = Perm::from_vec(vec![2, 1, 0]).unwrap();
let xyzx = Perm::from_vec(vec![2, 0, 1]).unwrap();
assert_eq!(xy.clone().permuted_by(&zx), xyzx);
assert_eq!(xy.then(&zx), xyzx);
assert_eq!(zx.of(&xy), xyzx);
assert_eq!(
vec![0,1,2].permuted_by(&xy).permuted_by(&zx),
vec![0,1,2].permuted_by(&xyzx),
);
assert_eq!(
vec![0,1,2].permuted_by(&xy).permuted_by(&zx),
vec![2,0,1],
);
for _ in 0..10 {
use rand::Rng;
let mut rng = rand::thread_rng();
let n = rng.gen_range(10, 20);
let s = b"abcdefghijklmnopqrstuvwxyz"[..n].to_vec();
let a = Perm::random(n);
let b = Perm::random(n);
let c = Perm::random(n);
let bc = b.clone().permuted_by(&c);
assert_eq!(
a.clone().permuted_by(&b).permuted_by(&c),
a.clone().permuted_by(&bc),
"compatibility, for Self = Perm (a.k.a. associativity)",
);
assert_eq!(
a.inv.clone().permuted_by(&b).permuted_by(&c),
a.inv.clone().permuted_by(&bc),
"compatibility, for Self = PermVec",
);
assert_eq!(
s.clone().permuted_by(&b).permuted_by(&c),
s.clone().permuted_by(&bc),
"compatibility, for Self = Vec",
);
}
}
#[test]
fn append()
{
let mut a = Perm::from_vec(vec![1, 0]).unwrap();
let b = Perm::from_vec(vec![1, 2, 0]).unwrap();
a.append_mut(&b);
assert_eq!(
vec![00, 01, 10, 11, 12].permuted_by(&a),
vec![01, 00, 11, 12, 10],
);
}
#[test]
fn outer()
{
let use_outer = |a, b| {
let a = Perm::from_vec(a).unwrap();
let b = Perm::from_vec(b).unwrap();
let xs: Vec<_> =
(0..b.len()).flat_map(|slow| {
(0..a.len()).map(move |fast| 10 * slow + fast)
}).collect();
xs.permuted_by(&a.with_outer(&b))
};
assert_eq!(
use_outer(
vec![1, 0, 2, 3],
vec![1, 2, 0],
),
vec![
11, 10, 12, 13,
21, 20, 22, 23,
01, 00, 02, 03,
],
);
assert_eq!(use_outer(vec![1, 0], vec![]), vec![]);
assert_eq!(use_outer(vec![], vec![1, 0]), vec![]);
}
#[test]
fn shift() {
assert_eq!(
vec![0, 1, 2, 3, 4, 5].permuted_by(&Perm::eye(6).shift_right(8)),
vec![4, 5, 0, 1, 2, 3],
);
assert_eq!(
vec![0, 1, 2, 3, 4, 5].permuted_by(&Perm::eye(6).shift_left(8)),
vec![2, 3, 4, 5, 0, 1],
);
assert_eq!(
vec![0, 1, 2, 3, 4, 5].permuted_by(&Perm::eye(6).shift_signed(8)),
vec![4, 5, 0, 1, 2, 3],
);
assert_eq!(
vec![0, 1, 2, 3, 4, 5].permuted_by(&Perm::eye(6).shift_signed(-8)),
vec![2, 3, 4, 5, 0, 1],
);
assert_eq!(
vec![0, 1, 2, 3, 4, 5].permuted_by(&Perm::eye(6).shift_signed(6)),
vec![0, 1, 2, 3, 4, 5],
);
assert_eq!(
vec![0, 1, 2, 3, 4, 5].permuted_by(&Perm::eye(6).shift_signed(-6)),
vec![0, 1, 2, 3, 4, 5],
);
}
#[test]
fn pow_unsigned() {
for &len in &[0, 1, 4, 20] {
for _ in 0..5 {
let perm = Perm::random(len);
for &exp in &[0, 1, 4, 20, 21] {
let original = b"abcdefghijklmnopqrstuvwxyz"[..len as usize].to_owned();
let mut brute_force = original.clone();
for _ in 0..exp {
brute_force = brute_force.permuted_by(&perm);
}
let fast = original.permuted_by(&perm.pow_unsigned(exp));
assert_eq!(fast, brute_force);
}
}
}
}
#[test]
fn _readme_doctest() {}
}