pub fn indices<const D: usize>(level: usize) -> impl std::iter::Iterator<Item=usize> {
0..2usize.pow((D*level) as u32)
}
const fn max<const D: usize>() -> usize { !( {std::usize::MAX}<<D ) }
#[inline]
fn gc(i: usize) -> usize { i^(i >> 1) }
#[inline]
fn gc_inv<const D: usize>(g: usize) -> usize { (1..D).fold(g, |i, j| i^(g>>j)) }
#[inline]
fn g(i: usize) -> usize {
(!i).trailing_zeros() as usize
}
#[inline]
fn dmap<const D: usize>(i: usize) -> usize {
if i == 0 { 0 } else if i&1 == 0 { g(i-1) % D } else { g(i) % D }
}
#[inline]
fn emap(i: usize) -> usize {
if i == 0 { 0 } else { gc(2*( (i-1)/2 )) }
}
#[inline]
fn rotate_right<const D: usize>(b: usize, i: usize) -> usize {
let i = i.rem_euclid(D);
(b >> i)^(b << (D-i))&max::<D>()
}
#[inline]
fn rotate_left<const D: usize>(b: usize, i: usize) -> usize {
let i = i.rem_euclid(D);
max::<D>() & (b << i)^(b >> (D-i))
}
#[inline]
fn t<const D: usize>(b: usize, e: usize, d: usize) -> usize { rotate_right::<D>(b^e, d+1) }
#[inline]
fn t_inv<const D: usize>(b: usize, e: usize, d: usize) -> usize { rotate_left::<D>(b, d+1)^e }
#[inline]
fn reduce<const D: usize>(p: &[usize; D], i: usize) -> usize {
p.iter().enumerate()
.fold(0, |l, (k, p)| l^( ((p >> i)&1) << k))
}
pub trait ToHilbertIndex<const D: usize> {
fn to_hilbert_index(&self, level: usize) -> usize;
fn to_hindex(&self, level: usize) -> usize {
self.to_hilbert_index(level)
}
}
pub trait FromHilbertIndex<const D: usize> {
fn from_hilbert_index(&self, level: usize) -> [usize; D];
fn from_hindex(&self, level: usize) -> [usize; D] {
self.from_hilbert_index(level)
}
}
impl<const D: usize> ToHilbertIndex::<D> for [usize; D] {
fn to_hilbert_index(&self, level: usize) -> usize {
let (mut h, mut e, mut d) = (0, 0, 0);
for i in(0..level).rev() {
let l = t::<D>(reduce(&self, i), e, d);
let w = gc_inv::<D>(l);
e = e^( rotate_left::<D>(emap(w), d+1) );
d = ( d + dmap::<D>(w) + 1 )%D;
h = (h << D) | w;
}
h
}
}
impl<const D: usize> FromHilbertIndex::<D> for usize {
fn from_hilbert_index(&self, level: usize) -> [usize; D] {
let (mut e, mut d) = (0, 0);
let mut p = [0; D];
for i in (0..level).rev() {
let w = (0..D).fold(0, |w, k| w^( ((self >> (i*D + k)) & 1 ) << k ));
let l = t_inv::<D>(gc(w), e, d);
for j in 0..D {
p[j] = (p[j] << 1)|((l >> j)&1);
}
e = e^rotate_left::<D>( emap(w), d+1 );
d = ( d + dmap::<D>(w) + 1 )%D;
}
p
}
}
#[cfg(test)]
mod tests {
use crate::{FromHilbertIndex, ToHilbertIndex};
fn check<const D: usize>(level: usize) {
let max = 2usize.pow((D*level) as u32) - 1;
for key in 0..2usize.pow((D*level) as u32) {
let xyz: [usize; D] = key.from_hilbert_index(level);
println!("p[{}] = {:?}", key, xyz);
assert_eq!(key, xyz.to_hilbert_index(level));
for x in xyz.iter() {
assert!((&0 <= x) && (x <= &max));
}
if key > 0 {
let prv: [usize; D] = (key-1).from_hilbert_index(level);
let diff = prv.iter().zip(xyz.iter())
.map(|(&p, &c)| (p as isize - c as isize).abs())
.sum::<isize>();
assert_eq!(diff, 1);
}
}
}
#[test]
fn dim_two() {
const D: usize = 2;
for level in 1..8 { check::<D>(level); }
}
#[test]
fn dim_three() {
const D: usize = 3;
for level in 1..7 { check::<D>(level); }
}
#[test]
fn dim_four() {
const D: usize = 4;
for level in 1..6 { check::<D>(level); }
}
#[test]
fn dim_five() {
const D: usize = 5;
for level in 1..5 { check::<D>(level); }
}
#[test]
fn dim_six() {
const D: usize = 6;
for level in 1..4 { check::<D>(level); }
}
}