use {
bitvec::{prelude::{bitvec, bitbox, BitVec}},
crate::error::K2TreeError as Error,
crate::tree::*,
crate::matrix::BitMatrix,
};
type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, Clone)]
pub struct K2Tree {
pub matrix_width: usize,
pub k: usize,
pub max_slayers: usize,
pub slayer_starts: Vec<usize>,
pub stems: BitVec,
pub stem_to_leaf: Vec<usize>,
pub leaves: BitVec,
}
impl K2Tree {
pub fn new() -> Self {
let k: usize = 2;
let mw = k.pow(3);
K2Tree {
matrix_width: mw,
k,
max_slayers: (mw as f64).log(k as f64) as usize - 1,
slayer_starts: vec![0],
stems: bitvec![0; k*k],
stem_to_leaf: Vec::new(),
leaves: BitVec::new(),
}
}
pub fn is_empty(&self) -> bool {
ones_in_range(&self.leaves, 0, self.leaves.len()) == 0
}
pub fn get(&self, x: usize, y: usize) -> Result<bool> {
if x >= self.matrix_width || y >= self.matrix_width {
return Err(Error::Read {
source: Box::new(Error::OutOfBounds {
x_y: [x, y],
min_x_y: [0, 0],
max_x_y: [self.matrix_width-1; 2]
})
})
}
let descend_result = match self.matrix_bit(x, y, self.matrix_width) {
Ok(dr) => dr,
Err(e) => return Err(Error::Read {
source: Box::new(e)
}),
};
match descend_result {
DescendResult::Leaf(leaf_start, leaf_range) => {
if leaf_range[0][1] - leaf_range[0][0] != 1
|| leaf_range[1][1] - leaf_range[1][0] != 1 {
return Err(Error::Read {
source: Box::new(Error::TraverseError{x, y})
})
}
let offset = (2 * (y - leaf_range[1][0])) + (x - leaf_range[0][0]);
Ok(self.leaves[leaf_start+offset])
},
DescendResult::Stem(_, _) => Ok(false),
}
}
pub fn get_row(&self, y: usize) -> Result<Vec<bool>> {
if y >= self.matrix_width {
return Err(Error::Read {
source: Box::new(Error::OutOfBounds {
x_y: [0, y],
min_x_y: [0, 0],
max_x_y: [self.matrix_width-1; 2]
})
})
}
let mut ret_v = Vec::new();
for x in (0..self.matrix_width).step_by(self.k) {
match self.matrix_bit(x, y, self.matrix_width)? {
DescendResult::Leaf(leaf_start, leaf_range) => {
if leaf_range[0][1] - leaf_range[0][0] != 1
|| leaf_range[1][1] - leaf_range[1][0] != 1 {
return Err(Error::Read {
source: Box::new(Error::TraverseError{x, y})
})
}
let offset = (2 * (y - leaf_range[1][0])) + (x - leaf_range[0][0]);
for i in 0..self.k { ret_v.push(self.leaves[leaf_start+offset+i]); }
},
DescendResult::Stem(_, _) => {
for _ in 0..self.k { ret_v.push(false); }
},
}
};
Ok(ret_v)
}
pub fn get_column(&self, x: usize) -> Result<Vec<bool>> {
if x >= self.matrix_width {
return Err(Error::Read {
source: Box::new(Error::OutOfBounds {
x_y: [x, 0],
min_x_y: [0, 0],
max_x_y: [self.matrix_width-1; 2]
})
})
}
let mut ret_v = Vec::new();
for y in (0..self.matrix_width).step_by(self.k) {
match self.matrix_bit(x, y, self.matrix_width)? {
DescendResult::Leaf(leaf_start, leaf_range) => {
if leaf_range[0][1] - leaf_range[0][0] != 1
|| leaf_range[1][1] - leaf_range[1][0] != 1 {
return Err(Error::Read {
source: Box::new(Error::TraverseError{x, y})
})
}
let offset = (2 * (y - leaf_range[1][0])) + (x - leaf_range[0][0]);
for i in 0..self.k { ret_v.push(self.leaves[leaf_start+offset+(i*self.k)]); }
},
DescendResult::Stem(_, _) => {
for _ in 0..self.k { ret_v.push(false); }
},
}
};
Ok(ret_v)
}
pub fn set(&mut self, x: usize, y: usize, state: bool) -> Result<()> {
let descend_result = match self.matrix_bit(x, y, self.matrix_width) {
Ok(dr) => dr,
Err(e) => return Err(Error::Write {
source: Box::new(e)
}),
};
match descend_result {
DescendResult::Leaf(leaf_start, leaf_range) => {
if leaf_range[0][1] - leaf_range[0][0] != 1
|| leaf_range[1][1] - leaf_range[1][0] != 1 {
return Err(Error::Write {
source: Box::new(Error::TraverseError{x, y})
})
}
let offset = (2 * (y - leaf_range[1][0])) + (x - leaf_range[0][0]);
self.leaves.set(leaf_start+offset, state);
if !state && all_zeroes(&self.leaves, leaf_start, leaf_start+4) {
if let Err(()) = remove_block(&mut self.leaves, leaf_start) {
return Err(Error::CorruptedK2Tree {
source: Box::new(Error::Write {
source: Box::new(Error::LeafRemovalError {
pos: leaf_start,
len: 4
})
})
})
}
let stem_bit_pos = self.stem_to_leaf[leaf_start/4];
self.stem_to_leaf.remove(leaf_start/4);
if self.stem_to_leaf.is_empty() {
self.stems = bitvec![0,0,0,0];
self.slayer_starts = vec![0];
return Ok(())
}
let layer_start = self.slayer_starts[self.max_slayers-1];
self.stems.set(layer_start + stem_bit_pos, false);
let mut curr_layer = self.max_slayers-1;
let mut stem_start = layer_start + block_start(stem_bit_pos);
while curr_layer > 0
&& all_zeroes(&self.stems, stem_start, stem_start+4) {
if curr_layer == self.max_slayers-1 {
for stem_to_leaf_bit in &mut self.stem_to_leaf[leaf_start/4..] {
*stem_to_leaf_bit -= 4;
}
}
for layer_start in &mut self.slayer_starts[curr_layer+1..] {
*layer_start -= 4;
}
let (parent_stem_start, bit_offset) = self.parent(stem_start);
if let Err(()) = remove_block(&mut self.stems, stem_start) {
return Err(Error::CorruptedK2Tree {
source: Box::new(Error::Write {
source: Box::new(Error::StemRemovalError {
pos: stem_start,
len: 4
})
})
})
}
self.stems.set(parent_stem_start + bit_offset, false);
stem_start = parent_stem_start;
curr_layer -= 1;
}
}
},
DescendResult::Stem(mut stem_start, mut stem_range) if state => {
let mut layer_starts_len = self.slayer_starts.len();
let mut layer = self.layer_from_range(stem_range);
let mut subranges: [Range; 4];
let mut fresh_stem = false;
while layer < self.max_slayers-1 {
fresh_stem = true;
subranges = to_4_subranges(stem_range);
let (child_pos, &subrange) =
match subranges.iter().enumerate().find(
|(_, subrange)| within_range(subrange, x, y)
) {
Some(val) => val,
None => return Err(Error::CorruptedK2Tree {
source: Box::new(Error::Write {
source: Box::new(Error::TraverseError{x, y})
})
})
};
self.stems.set(stem_start + child_pos, true);
if layer == layer_starts_len-1 {
stem_start = self.stems.len();
self.slayer_starts.push(stem_start);
layer_starts_len += 1;
}
else {
stem_start = match self.child_stem(layer, stem_start, child_pos) {
Ok(ss) => ss,
Err(()) => return Err(Error::CorruptedK2Tree {
source: Box::new(Error::Write {
source: Box::new(Error::TraverseError{x, y})
})
}),
};
}
layer += 1;
stem_range = subrange;
if let Err(()) = insert_block(&mut self.stems, stem_start) {
return Err(Error::CorruptedK2Tree {
source: Box::new(Error::Write {
source: Box::new(Error::StemInsertionError {
pos: stem_start,
len: 4
})
})
})
}
for layer_start in &mut self.slayer_starts[layer+1..] {
*layer_start += 4;
}
}
subranges = to_4_subranges(stem_range);
let (child_pos, &subrange) =
match subranges.iter().enumerate().find(
|(_, subrange)| within_range(subrange, x, y)
) {
Some(val) => val,
None => return Err(Error::CorruptedK2Tree {
source: Box::new(Error::Write {
source: Box::new(Error::TraverseError{x, y})
})
})
};
self.stems.set(stem_start + child_pos, true);
let layer_bit_pos = (stem_start + child_pos) - self.slayer_starts[layer_starts_len-1];
if fresh_stem {
let block_start = (layer_bit_pos / 4) * 4;
self.stem_to_leaf = self.stem_to_leaf.iter().map(
|&n|
if n >= block_start { n+4 }
else { n }
).collect();
}
let mut stem_to_leaf_pos: usize = 0;
while stem_to_leaf_pos < self.stem_to_leaf.len()
&& self.stem_to_leaf[stem_to_leaf_pos] < layer_bit_pos {
stem_to_leaf_pos += 1;
}
self.stem_to_leaf.insert(stem_to_leaf_pos, layer_bit_pos);
let leaf_start = stem_to_leaf_pos * 4;
if let Err(()) = insert_block(&mut self.leaves, leaf_start) {
return Err(Error::CorruptedK2Tree {
source: Box::new(Error::Write {
source: Box::new(Error::LeafInsertionError {
pos: leaf_start,
len: 4
})
})
})
}
let leaf_range = subrange;
let offset = (2 * (y - leaf_range[1][0])) + (x - leaf_range[0][0]);
self.leaves.set(leaf_start+offset, true);
return Ok(())
}
_ => {},
};
Ok(())
}
pub fn stems(&self) -> iterators::Stems<'_> {
iterators::Stems::new(self)
}
pub fn stems_raw(&self) -> iterators::StemsRaw<'_> {
iterators::StemsRaw::new(self)
}
pub fn leaves(&self) -> iterators::Leaves<'_> {
iterators::Leaves::new(self)
}
pub fn into_leaves(self) -> iterators::IntoLeaves {
iterators::IntoLeaves::new(self)
}
pub fn leaves_raw(&self) -> iterators::LeavesRaw<'_> {
iterators::LeavesRaw::new(self)
}
pub fn grow(&mut self) {
self.matrix_width *= self.k;
self.max_slayers += 1;
if self.leaves.len() > 0 {
for slayer_start in &mut self.slayer_starts {
*slayer_start += 4;
}
self.slayer_starts.insert(0, 0);
for _ in 0..3 { self.stems.insert(0, false); }
self.stems.insert(0, true);
}
}
pub fn shrink_if_possible(&mut self) {
match self.shrink() {
_ => ()
}
}
pub fn shrink(&mut self) -> Result<()> {
if self.matrix_width <= self.k.pow(3) {
return Err(Error::CouldNotShrink {
reason: format!("Already at minimum size: {}", self.matrix_width)
})
}
else if self.stems[1..4] != bitbox![0,0,0] {
return Err(Error::CouldNotShrink {
reason: "Shrinking would lose information about the matrix".into()
})
}
self.matrix_width /= self.k;
self.max_slayers -= 1;
self.slayer_starts.remove(0);
for slayer_start in &mut self.slayer_starts {
*slayer_start -= 4;
}
for _ in 0..4 { self.stems.remove(0); }
Ok(())
}
pub unsafe fn shrink_unchecked(&mut self) {
self.matrix_width /= self.k;
self.max_slayers -= 1;
self.slayer_starts.remove(0);
for slayer_start in &mut self.slayer_starts {
*slayer_start -= 4;
}
for _ in 0..4 { self.stems.remove(0); }
}
pub fn into_matrix(self) -> Result<BitMatrix> {
let mut m = BitMatrix::with_dimensions(self.matrix_width, self.matrix_width);
for y in 0..self.matrix_width {
for x in 0..self.matrix_width {
if let Err(e) = m.set(x, y, self.get(x, y)?) {
return Err(Error::BitMatrixError {
source: Box::new(e),
})
}
}
}
Ok(m)
}
pub fn to_matrix(&self) -> Result<BitMatrix> {
let mut m = BitMatrix::with_dimensions(self.matrix_width, self.matrix_width);
for y in 0..self.matrix_width {
for x in 0..self.matrix_width {
if let Err(e) = m.set(x, y, self.get(x, y)?) {
return Err(Error::BitMatrixError {
source: Box::new(e),
})
}
}
}
Ok(m)
}
pub fn from_matrix(matrix: BitMatrix) -> Result<Self> {
let mut tree = K2Tree::new();
while matrix.width > tree.matrix_width
|| matrix.height > tree.matrix_width {
tree.grow();
}
let rows = matrix.into_rows();
for (y, row) in rows.into_iter().enumerate() {
for (x, state) in row.into_iter().enumerate() {
tree.set(x, y, state)?;
}
}
Ok(tree)
}
}
impl core::fmt::Display for K2Tree {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
if self.leaves.len() == 0 { return write!(f, "[0000]") }
let mut s = String::new();
let mut i: usize = 1;
for layer_num in 0..self.slayer_starts.len() {
for bit_pos in self.layer_start(layer_num)..self.layer_start(layer_num+1) {
if self.stems[bit_pos] { s.push('1'); }
else { s.push('0'); }
if i == self.k*self.k
&& (bit_pos - self.layer_start(layer_num)) < self.layer_len(layer_num)-1 {
s.push(',');
i = 1;
}
else { i += 1; }
}
i = 1;
s.push_str("::");
}
i = 1;
for bit_pos in 0..self.leaves.len() {
if self.leaves[bit_pos] { s.push('1'); }
else { s.push('0'); }
if i == self.k*self.k
&& bit_pos < self.leaves.len()-1 {
s.push(',');
i = 1;
}
else { i += 1; }
}
write!(f, "[{}]", s)
}
}
impl PartialEq for K2Tree {
fn eq(&self, other: &Self) -> bool {
self.k == other.k
&& self.matrix_width == other.matrix_width
&& self.stems == other.stems
&& self.leaves == other.leaves
}
}
impl Eq for K2Tree {}
impl Default for K2Tree {
fn default() -> Self {
Self::new()
}
}
impl std::hash::Hash for K2Tree {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.k.hash(state);
self.matrix_width.hash(state);
self.stems.hash(state);
self.leaves.hash(state);
}
}
impl std::convert::TryFrom<BitMatrix> for K2Tree {
type Error = Error;
fn try_from(matrix: BitMatrix) -> Result<Self> {
Self::from_matrix(matrix)
}
}
enum DescendResult {
Leaf(usize, Range),
Stem(usize, Range),
}
struct DescendEnv {
x: usize,
y: usize,
slayer_max: usize,
}
impl K2Tree {
fn layer_from_range(&self, r: Range) -> usize {
let r_width = r[0][1]-r[0][0]+1;
((self.matrix_width as f64).log(self.k as f64) as usize)
- ((r_width as f64).log(self.k as f64) as usize)
}
fn matrix_bit(&self, x: usize, y: usize, m_width: usize) -> Result<DescendResult> {
let env = DescendEnv {
x,
y,
slayer_max: self.max_slayers-1,
};
self.descend(&env, 0, 0, [[0, m_width-1], [0, m_width-1]])
}
fn descend(&self, env: &DescendEnv, layer: usize, stem_pos: usize, range: Range) -> Result<DescendResult> {
let subranges = to_4_subranges(range);
for (child_pos, child) in self.stems[stem_pos..stem_pos+4].iter().enumerate() {
if within_range(&subranges[child_pos], env.x, env.y) {
if !child { return Ok(DescendResult::Stem(stem_pos, range)) }
else if layer == env.slayer_max {
let leaf_start = match self.leaf_start(stem_pos + child_pos) {
Ok(ls) => ls,
Err(_) => return Err(Error::TraverseError {
x: env.x,
y: env.y
}),
};
return Ok(DescendResult::Leaf(leaf_start, subranges[child_pos]))
}
else {
let child_stem = match self.child_stem(layer, stem_pos, child_pos) {
Ok(cs) => cs,
Err(_) => return Err(Error::TraverseError {
x: env.x,
y: env.y
}),
};
return self.descend(env,
layer+1,
child_stem,
subranges[child_pos])
}
}
}
unreachable!()
}
fn num_stems_before_child(&self, bit_pos: usize, layer: usize) -> usize {
ones_in_range(&self.stems, self.layer_start(layer), bit_pos)
}
fn leaf_start(&self, stem_bitpos: usize) -> std::result::Result<usize, ()> {
if !self.stems[stem_bitpos] { return Err(()) }
if let Some(leaf_num) = self.stem_to_leaf.iter().position(|&n|
n == (stem_bitpos - self.slayer_starts[self.max_slayers-1])
) {
return Ok(leaf_num * 4)
}
Err(())
}
fn child_stem(&self, layer: usize, stem_start: usize, nth_child: usize) -> std::result::Result<usize, ()> {
if !self.stems[stem_start+nth_child]
|| layer == self.max_slayers-1 {
return Err(())
}
Ok(self.layer_start(layer+1)
+ (self.num_stems_before_child(stem_start+nth_child, layer) * 4))
}
}
#[cfg(test)]
impl K2Tree {
fn test_tree() -> Self {
K2Tree {
matrix_width: 8,
k: 2,
max_slayers: 2,
slayer_starts: vec![0, 4],
stems: bitvec![0,1,1,1, 1,1,0,1, 1,0,0,0, 1,0,0,0],
stem_to_leaf: vec![0, 1, 3, 4, 8],
leaves: bitvec![0,1,1,0, 0,1,0,1, 1,1,0,0, 1,0,0,0, 0,1,1,0],
}
}
fn parent_stem(&self, stem_start: usize) -> usize {
self.parent(stem_start).0
}
fn parent_bit(&self, stem_start: usize) -> usize {
let (stem_start, bit_offset) = self.parent(stem_start);
stem_start + bit_offset
}
#[allow(dead_code)]
fn footprint(&self) -> usize {
let mut size: usize = std::mem::size_of_val(self);
size += std::mem::size_of::<usize>() * self.slayer_starts.len();
size += self.stems.len() / 8;
size += std::mem::size_of::<usize>() * self.stem_to_leaf.len();
size += self.leaves.len() / 8;
size
}
#[allow(dead_code)]
fn theoretical_size(&self) -> usize {
(self.stems.len() + self.leaves.len()) / 8
}
}
#[cfg(test)]
mod api {
use super::*;
use bitvec::bitbox;
#[test]
fn new() {
let expected = K2Tree {
matrix_width: 8,
k: 2,
max_slayers: 2,
slayer_starts: vec![0],
stems: bitvec![0,0,0,0],
stem_to_leaf: vec![],
leaves: bitvec![],
};
assert_eq!(K2Tree::new(), expected);
}
#[test]
fn is_empty_0() {
let tree = K2Tree::new();
assert!(tree.is_empty());
}
#[test]
fn is_empty_1() -> Result<()> {
let mut tree = K2Tree::new();
tree.set(0, 0, true)?;
assert!(!tree.is_empty());
tree.set(0, 0, false)?;
assert!(tree.is_empty());
Ok(())
}
#[test]
fn get() -> Result<()> {
let tree = K2Tree::test_tree();
let quad_1 = bitvec![0; 16];
let quad_2 = bitvec![0,1,0,1, 1,0,0,1, 0,0,1,1, 0,0,0,0];
let quad_3 = {
let mut q3 = bitvec![0; 15];
q3.insert(0, true);
q3
};
let quad_4 = {
let mut q4 = bitvec![0; 14];
q4.insert(1, true);
q4.insert(4, true);
q4
};
for i in 0..16 {
let [x, y] = [i%4, i/4];
assert_eq!(quad_1[i], tree.get(x, y)?);
};
for i in 0..16 {
let [x, y] = [4+i%4, i/4];
assert_eq!(quad_2[i], tree.get(x, y)?);
};
for i in 0..16 {
let [x, y] = [i%4, 4+i/4];
assert_eq!(quad_3[i], tree.get(x, y)?);
};
for i in 0..16 {
let [x, y] = [4+i%4, 4+i/4];
assert_eq!(quad_4[i], tree.get(x, y)?);
};
Ok(())
}
#[test]
fn get_row() -> Result<()> {
let tree = K2Tree::test_tree();
let rows = [
vec![false,false,false,false,false,true,false,true],
vec![false,false,false,false,true,false,false,true],
vec![false,false,false,false,false,false,true,true],
vec![false; 8],
vec![true,false,false,false,false,true,false,false],
vec![false,false,false,false,true,false,false,false],
vec![false; 8],
vec![false; 8]
];
for i in 0..8 {
assert_eq!(rows[i], tree.get_row(i)?);
}
Ok(())
}
#[test]
fn get_column() -> Result<()> {
let tree = K2Tree::test_tree();
let cols = [
vec![false,false,false,false,true,false,false,false],
vec![false; 8],
vec![false; 8],
vec![false; 8],
vec![false,true,false,false,false,true,false,false],
vec![true,false,false,false,true,false,false,false],
vec![false,false,true,false,false,false,false,false],
vec![true,true,true,false,false,false,false,false],
];
for i in 0..8 {
assert_eq!(cols[i], tree.get_column(i)?);
}
Ok(())
}
#[test]
fn set_0() -> Result<()> {
let mut tree = K2Tree::new();
assert_eq!(false, tree.get(0, 0).unwrap());
tree.set(0, 0, true)?;
assert_eq!(true, tree.get(0, 0).unwrap());
tree.set(0, 0, false)?;
assert_eq!(false, tree.get(0, 0).unwrap());
assert_eq!(false, tree.get(7, 7).unwrap());
tree.set(7, 7, true)?;
assert_eq!(true, tree.get(7, 7).unwrap());
tree.set(7, 7, false)?;
assert_eq!(false, tree.get(7, 7).unwrap());
assert_eq!(false, tree.get(2, 6).unwrap());
tree.set(2, 6, true)?;
assert_eq!(true, tree.get(2, 6).unwrap());
tree.set(6, 2, true)?;
assert_eq!(true, tree.get(2, 6).unwrap());
assert_eq!(true, tree.get(6, 2).unwrap());
Ok(())
}
#[test]
fn set_1() -> Result<()> {
let mut tree = K2Tree::new();
tree.grow();
for i in 0..256 {
let [x, y] = [i%16, i/16];
assert_eq!(false, tree.get(x, y)?);
tree.set(x, y, true)?;
assert_eq!(true, tree.get(x, y)?);
tree.set(x, y, false)?;
}
Ok(())
}
#[test]
fn matrix_width_and_grow() {
assert_eq!(8, K2Tree::new().matrix_width);
assert_eq!(8, K2Tree::test_tree().matrix_width);
let mut grown_tree = K2Tree::new(); grown_tree.grow();
assert_eq!(16, grown_tree.matrix_width);
grown_tree.grow();
assert_eq!(32, grown_tree.matrix_width);
for _ in 0..3 { grown_tree.grow(); }
assert_eq!(256, grown_tree.matrix_width);
}
#[test]
fn k() {
assert_eq!(2, K2Tree::new().k);
assert_eq!(2, K2Tree::test_tree().k);
}
#[test]
fn stems() {
let tree = K2Tree::test_tree();
let values = bitvec![0,1,1,1, 1,1,0,1, 1,0,0,0, 1,0,0,0];
let stems = [0, 0, 1, 2];
let bits = [0, 1, 2, 3];
for (i, stem) in tree.stems().enumerate() {
assert_eq!(
iterators::StemBit{
value: values[i],
layer: if i < 4 { 0 } else { 1 },
stem: stems[i/4],
bit: bits[i%4],
},
stem
);
}
}
#[test]
fn stems_raw() {
let tree = K2Tree::test_tree();
let values = bitbox![0,1,1,1, 1,1,0,1, 1,0,0,0, 1,0,0,0];
for (i, stem) in tree.stems_raw().enumerate() {
assert_eq!(values[i], stem);
}
}
#[test]
fn leaves() {
let tree = K2Tree::test_tree();
let values = bitbox![0,1,1,0, 0,1,0,1, 1,1,0,0, 1,0,0,0, 0,1,1,0];
let xs = [4,5,4,5, 6,7,6,7, 6,7,6,7, 0,1,0,1, 4,5,4,5];
let ys = [0,0,1,1, 0,0,1,1, 2,2,3,3, 4,4,5,5, 4,4,5,5];
for (i, leaf) in tree.leaves().enumerate() {
assert_eq!(
iterators::LeafBit {
value: values[i],
x: xs[i],
y: ys[i],
},
leaf
);
}
}
#[test]
fn leaves_raw() {
let tree = K2Tree::test_tree();
let values = bitbox![0,1,1,0, 0,1,0,1, 1,1,0,0, 1,0,0,0, 0,1,1,0];
for (i, leaf) in tree.leaves_raw().enumerate() {
assert_eq!(values[i], leaf);
}
}
#[test]
fn shrink_if_possible() {
let mut tree = K2Tree::new();
tree.grow();
assert_eq!(16, tree.matrix_width);
tree.shrink_if_possible();
assert_eq!(8, tree.matrix_width);
tree.shrink_if_possible();
assert_eq!(8, tree.matrix_width);
}
#[test]
fn shrink() {
let mut tree = K2Tree::new();
tree.grow();
assert_eq!(16, tree.matrix_width);
assert!(tree.shrink().is_ok());
assert_eq!(8, tree.matrix_width);
assert!(tree.shrink().is_err());
assert_eq!(8, tree.matrix_width);
}
#[test]
fn shrink_unchecked() {
let mut tree = K2Tree::new();
tree.grow();
assert_eq!(16, tree.matrix_width);
unsafe { tree.shrink_unchecked(); }
assert_eq!(8, tree.matrix_width);
}
#[test]
fn from_matrix() -> Result<()> {
let bits = bitvec![
0,0,0,0, 0,1,0,1,
0,0,0,0, 1,0,0,1,
0,0,0,0, 0,0,1,1,
0,0,0,0, 0,0,0,0,
1,0,0,0, 0,1,0,0,
0,0,0,0, 1,0,0,0,
0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0,
];
let m = BitMatrix::from_bits(8, 8, bits);
let tree = K2Tree {
matrix_width: 8,
k: 2,
max_slayers: 2,
slayer_starts: vec![0, 4],
stems: bitvec![0,1,1,1, 1,1,0,1, 1,0,0,0, 1,0,0,0],
stem_to_leaf: vec![0, 1, 3, 4, 8],
leaves: bitvec![0,1,1,0, 0,1,0,1, 1,1,0,0, 1,0,0,0, 0,1,1,0]
};
assert_eq!(tree, K2Tree::from_matrix(m)?);
Ok(())
}
#[test]
fn to_matrix() -> Result<()> {
let bits = bitvec![
0,0,0,0, 0,1,0,1,
0,0,0,0, 1,0,0,1,
0,0,0,0, 0,0,1,1,
0,0,0,0, 0,0,0,0,
1,0,0,0, 0,1,0,0,
0,0,0,0, 1,0,0,0,
0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0,
];
let m = BitMatrix::from_bits(8, 8, bits);
let new_m = K2Tree::from_matrix(m.clone())?.to_matrix()?;
assert_eq!(m, new_m);
Ok(())
}
#[test]
fn into_matrix() -> Result<()> {
let bits = bitvec![
0,0,0,0, 0,1,0,1,
0,0,0,0, 1,0,0,1,
0,0,0,0, 0,0,1,1,
0,0,0,0, 0,0,0,0,
1,0,0,0, 0,1,0,0,
0,0,0,0, 1,0,0,0,
0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0,
];
let m = BitMatrix::from_bits(8, 8, bits);
let new_m = K2Tree::from_matrix(m.clone())?.into_matrix()?;
assert_eq!(m, new_m);
Ok(())
}
}
#[cfg(test)]
mod util {
use super::*;
#[test]
fn all_zeroes_0() {
let zeroes = bitvec![0,0,0,0, 0,0,0,0, 0,0];
let one = bitvec![0,0,0,0, 0,1,0,0, 0];
let ones = bitvec![1,1,1,1, 1];
let edge = bitvec![0,0,0,1];
assert!(all_zeroes(&zeroes, 0, 10));
assert!(!all_zeroes(&one, 0, 9));
assert!(!all_zeroes(&ones, 0, 5));
assert!(!all_zeroes(&edge, 0, 4));
}
#[test]
fn one_positions_0() {
let bv = bitvec![0,1,0,1,0,1,0,0,0,1];
assert_eq!(vec![1,3,5,9], one_positions(&bv));
}
#[test]
fn to_4_subranges_0() {
let ranges = [[[0, 7], [0, 7]], [[4, 7], [0, 3]], [[8, 15], [8, 15]]];
let subranges = [
[[[0, 3], [0, 3]], [[4, 7], [0, 3]], [[0, 3], [4, 7]], [[4, 7], [4, 7]]],
[[[4, 5], [0, 1]], [[6, 7], [0, 1]], [[4, 5], [2, 3]], [[6, 7], [2, 3]]],
[[[8, 11], [8, 11]], [[12, 15], [8, 11]], [[8, 11], [12, 15]], [[12, 15], [12, 15]]]
];
for i in 0..ranges.len() {
assert_eq!(to_4_subranges(ranges[i]), subranges[i]);
}
}
#[test]
fn within_range_0() {
let coords = [[0, 0], [5, 6], [87, 2],[5, 5]];
let ranges = [[[0, 3], [0, 3]], [[0, 7], [0, 7]], [[50, 99], [0, 49]], [[5, 9], [5, 9]]];
for i in 0..coords.len() {
assert!(within_range(&ranges[i], coords[i][0], coords[i][1]));
}
}
#[test]
fn ones_in_range_0() {
let ranges = [
bitvec![0,1,1,1,0,0,1,0,1,1,0,0],
bitvec![0,0,0,0,0,0,1],
bitvec![0,1,1,1,1,1,1,0,1,0,0,1]
];
let num_ones = [6, 1, 8];
for i in 0..ranges.len() {
assert_eq!(ones_in_range(&ranges[i], 0, ranges[i].len()), num_ones[i]);
}
}
#[test]
fn stem_layer_start_0() {
let tree = K2Tree::test_tree();
assert_eq!(tree.layer_start(0), 0);
assert_eq!(tree.layer_start(1), 4);
}
#[test]
fn stem_layer_len_0() {
let tree = K2Tree::test_tree();
assert_eq!(tree.layer_len(0), 4);
assert_eq!(tree.layer_len(1), 12);
}
#[test]
fn leaf_start_0() {
let tree = K2Tree::test_tree();
assert_eq!(tree.leaf_start(4), Ok(0));
assert_eq!(tree.leaf_start(5), Ok(4));
assert_eq!(tree.leaf_start(7), Ok(8));
assert_eq!(tree.leaf_start(8), Ok(12));
assert_eq!(tree.leaf_start(12), Ok(16));
assert_eq!(tree.leaf_start(9), Err(()));
}
#[test]
fn child_stem_0() {
let tree = K2Tree::test_tree();
assert_eq!(tree.child_stem(0, 0, 0), Err(()));
assert_eq!(tree.child_stem(0, 0, 1), Ok(4));
assert_eq!(tree.child_stem(0, 0, 2), Ok(8));
assert_eq!(tree.child_stem(0, 0, 3), Ok(12));
assert_eq!(tree.child_stem(1, 4, 0), Err(()));
}
#[test]
fn parent_stem_0() {
let tree = K2Tree::test_tree();
assert_eq!(tree.parent_stem(4), 0);
assert_eq!(tree.parent_stem(8), 0);
assert_eq!(tree.parent_stem(12), 0);
}
#[test]
fn parent_bit_0() {
let tree = K2Tree::test_tree();
assert_eq!(tree.parent_bit(4), 1);
assert_eq!(tree.parent_bit(8), 2);
assert_eq!(tree.parent_bit(12), 3);
}
#[test]
fn get_coords_0() {
let tree = K2Tree::test_tree();
assert_eq!(tree.get_coords(12), [0, 4]);
}
}
#[cfg(test)]
mod misc {
use super::*;
#[test]
fn flood() -> Result<()> {
use rand::Rng;
let mut rng = rand::thread_rng();
let mut tree = K2Tree::new();
for _ in 0..10 { tree.grow(); }
for _ in 0..500 {
let x: usize = rng.gen_range(0, 512);
let y: usize = rng.gen_range(0, 512);
tree.set(x, y, true)?;
}
Ok(())
}
#[test]
fn is_send() {
fn assert_send<T: Send>() {}
assert_send::<K2Tree>();
}
#[test]
fn is_sync() {
fn assert_sync<T: Sync>() {}
assert_sync::<K2Tree>();
}
}