pub(crate) const fn full_width_of_row(row: usize) -> usize {
((2 * row + 4) / 3).next_power_of_two()
}
#[cfg(any(test, not(feature = "blitzar")))]
pub(crate) const fn row_start_index(row: usize) -> usize {
let width_of_row = full_width_of_row(row);
width_of_row * (row - width_of_row / 2)
}
pub(crate) const fn row_and_column_from_index(index: usize) -> (usize, usize) {
let width_of_row = 1 << (2 * index + 1).ilog2().div_ceil(2);
let row = index / width_of_row + width_of_row / 2;
let column = index % width_of_row;
(row, column)
}
pub(crate) fn index_from_row_and_column(row: usize, column: usize) -> Option<usize> {
let width_of_row = full_width_of_row(row);
(column < width_of_row && (row, column) != (1, 0))
.then_some(width_of_row * (row - width_of_row / 2) + column)
}
pub(crate) const fn matrix_size(data_len: usize, offset: usize) -> (usize, usize) {
if data_len == 0 && offset == 0 {
return (0, 0);
}
let (last_row, _) = row_and_column_from_index(offset + data_len - 1);
let width_of_last_row = full_width_of_row(last_row);
(last_row + 1, width_of_last_row)
}
#[cfg(test)]
mod tests {
use super::*;
fn create_position_matrix(nu: usize) -> Vec<Vec<Option<usize>>> {
let max_index = 1 << (2 * nu - 1);
let mut matrix = vec![];
for i in 0..max_index {
let (row, column) = row_and_column_from_index(i);
if matrix.len() <= row {
matrix.resize_with(row + 1, Vec::new);
}
if matrix[row].len() <= column {
matrix[row].resize(column + 1, None);
}
matrix[row][column] = Some(i);
}
matrix
}
#[test]
fn we_can_compute_positions_from_indexes() {
assert_eq!(
create_position_matrix(2),
vec![
vec![Some(0)], vec![None, Some(1)], vec![Some(2), Some(3)], vec![Some(4), Some(5), Some(6), Some(7)], ],
);
assert_eq!(
create_position_matrix(4),
vec![
vec![Some(0)], vec![None, Some(1)], vec![Some(2), Some(3)], vec![Some(4), Some(5), Some(6), Some(7)], vec![Some(8), Some(9), Some(10), Some(11)], vec![Some(12), Some(13), Some(14), Some(15)], (16..=23).map(Some).collect(), (24..=31).map(Some).collect(), (32..=39).map(Some).collect(), (40..=47).map(Some).collect(), (48..=55).map(Some).collect(), (56..=63).map(Some).collect(), (64..=79).map(Some).collect(), (80..=95).map(Some).collect(), (96..=111).map(Some).collect(), (112..=127).map(Some).collect() ],
);
}
#[test]
fn we_can_fill_matrix_with_no_collisions_and_correct_size_and_row_starts() {
for nu in 1..10 {
let num_vars = nu * 2 - 1;
let matrix = create_position_matrix(nu);
assert_eq!(
matrix.iter().flatten().filter(|&x| x.is_some()).count(),
1 << num_vars
);
assert_eq!(matrix.len(), 1 << nu);
assert_eq!(matrix.iter().map(Vec::len).max().unwrap(), 1 << nu);
for (index, row) in matrix.iter().enumerate() {
assert_eq!(
row_start_index(index),
match index {
1 => 0, _ => row[0]
.expect("Every row except 1 should have a value in the 0th position."),
}
);
}
}
}
#[test]
fn we_can_find_the_full_width_of_row() {
let n = 20;
let mut expected_widths = Vec::new();
expected_widths.extend(std::iter::repeat_n(1, 1));
expected_widths.extend(std::iter::repeat_n(2, 2));
for n in 0..n {
let repeat_count = 3 * 2_usize.pow(n);
let value = 4 * 2_usize.pow(n);
expected_widths.extend(std::iter::repeat_n(value, repeat_count));
}
for (row, width) in expected_widths.iter().enumerate() {
let width_of_row = full_width_of_row(row);
assert_eq!(
width_of_row, *width,
"row: {row} does not produce expected width"
);
}
}
#[test]
fn we_can_produce_the_correct_matrix_size() {
assert_eq!(matrix_size(0, 0), (0, 0));
assert_eq!(matrix_size(1, 0), (1, 1));
assert_eq!(matrix_size(2, 0), (2, 2));
assert_eq!(matrix_size(3, 0), (3, 2));
assert_eq!(matrix_size(4, 0), (3, 2));
assert_eq!(matrix_size(5, 0), (4, 4));
assert_eq!(matrix_size(6, 0), (4, 4));
assert_eq!(matrix_size(7, 0), (4, 4));
assert_eq!(matrix_size(8, 0), (4, 4));
assert_eq!(matrix_size(9, 0), (5, 4));
assert_eq!(matrix_size(10, 0), (5, 4));
assert_eq!(matrix_size(11, 0), (5, 4));
assert_eq!(matrix_size(12, 0), (5, 4));
assert_eq!(matrix_size(13, 0), (6, 4));
assert_eq!(matrix_size(14, 0), (6, 4));
assert_eq!(matrix_size(15, 0), (6, 4));
assert_eq!(matrix_size(16, 0), (6, 4));
assert_eq!(matrix_size(17, 0), (7, 8));
assert_eq!(matrix_size(64, 0), (12, 8));
assert_eq!(matrix_size(71, 0), (13, 16));
assert_eq!(matrix_size(81, 0), (14, 16));
assert_eq!(matrix_size(98, 0), (15, 16));
assert_eq!(matrix_size(115, 0), (16, 16));
}
#[test]
fn we_can_produce_the_correct_matrix_size_with_offset() {
assert_eq!(matrix_size(0, 0), (0, 0));
assert_eq!(matrix_size(0, 1), (1, 1));
assert_eq!(matrix_size(0, 2), (2, 2));
assert_eq!(matrix_size(1, 1), (2, 2));
assert_eq!(matrix_size(1, 2), (3, 2));
assert_eq!(matrix_size(1, 3), (3, 2));
assert_eq!(matrix_size(1, 4), (4, 4));
assert_eq!(matrix_size(1, 5), (4, 4));
assert_eq!(matrix_size(1, 6), (4, 4));
assert_eq!(matrix_size(1, 7), (4, 4));
assert_eq!(matrix_size(1, 8), (5, 4));
assert_eq!(matrix_size(1, 9), (5, 4));
assert_eq!(matrix_size(1, 10), (5, 4));
assert_eq!(matrix_size(1, 11), (5, 4));
assert_eq!(matrix_size(1, 12), (6, 4));
assert_eq!(matrix_size(1, 13), (6, 4));
assert_eq!(matrix_size(1, 14), (6, 4));
assert_eq!(matrix_size(1, 15), (6, 4));
assert_eq!(matrix_size(1, 16), (7, 8));
assert_eq!(matrix_size(1, 63), (12, 8));
assert_eq!(matrix_size(1, 70), (13, 16));
assert_eq!(matrix_size(1, 80), (14, 16));
assert_eq!(matrix_size(1, 97), (15, 16));
assert_eq!(matrix_size(1, 114), (16, 16));
}
#[test]
fn we_can_find_the_index_for_row_column_pairs() {
use std::collections::HashSet;
const MAX_INDEX: usize = 1 << 16;
let mut valid_pairs = HashSet::new();
for i in 0..MAX_INDEX {
let (row, column) = row_and_column_from_index(i);
valid_pairs.insert((row, column));
}
let (max_row, max_column) = valid_pairs
.iter()
.fold((0, 0), |(max_row, max_column), &(row, column)| {
(max_row.max(row), max_column.max(column))
});
for row in 0..max_row {
for column in 0..max_column {
let index = index_from_row_and_column(row, column);
if valid_pairs.contains(&(row, column)) {
assert!(
index.is_some(),
"Valid pair ({row}, {column}) generated no index"
);
} else {
assert!(
index.is_none(),
"Invalid pair ({row}, {column}) generated a valid index"
);
}
}
}
}
}