use std::fmt::Display;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct BlockHeader {
start: usize,
end: usize,
}
#[derive(Debug, Clone)]
pub struct BasePartition {
size: usize,
block: Vec<BlockHeader>,
segment: Box<[u32]>,
}
#[derive(Debug, Clone)]
pub struct Partition {
base: BasePartition,
block_id: Box<[u32]>,
}
#[allow(dead_code)]
impl BasePartition {
pub fn new(n: u32) -> Self {
let size = n as usize;
let mut segment = vec![0; size].into_boxed_slice();
for i in 0..size {
segment[i] = i as u32;
}
let block = if n == 0 {
vec![BlockHeader { start: 0, end: 0 }]
} else {
vec![
BlockHeader { start: 0, end: 0 },
BlockHeader {
start: 0,
end: size,
},
]
};
BasePartition {
size,
block,
segment,
}
}
pub fn num_blocks(&self) -> u32 {
self.block.len() as u32
}
pub fn index(&self) -> u32 {
self.num_blocks() - 1
}
pub fn size(&self) -> u32 {
self.size as u32
}
pub fn block_size(&self, i: u32) -> u32 {
let BlockHeader { start, end } = self.block[i as usize];
(end - start) as u32
}
pub fn smaller_block(&self, i: u32, j: u32) -> bool {
self.block_size(i) <= self.block_size(j)
}
pub fn sort_block(&mut self, i: u32) {
self.slice_mut(i).sort_unstable()
}
pub fn block_elements(&self, i: u32) -> impl Iterator<Item = u32> + '_ {
self.slice(i).iter().copied()
}
pub fn pick_element(&self, i: u32) -> u32 {
assert!(i > 0);
let start = self.block[i as usize].start;
self.segment[start]
}
fn slice(&self, i: u32) -> &[u32] {
let BlockHeader { start, end } = self.block[i as usize];
&self.segment[start..end]
}
fn slice_mut(&mut self, i: u32) -> &mut [u32] {
let BlockHeader { start, end } = self.block[i as usize];
&mut self.segment[start..end]
}
fn add_block(&mut self, start: usize, end: usize) -> u32 {
debug_assert!(start < end && end <= self.size);
let id = self.num_blocks();
self.block.push(BlockHeader { start, end });
id
}
fn split_block(&mut self, i: u32, n: usize) -> u32 {
let i = i as usize;
let split_point = self.block[i].start + n;
let end_point = self.block[i].end;
debug_assert!(split_point <= end_point);
self.block[i].end = split_point;
self.add_block(split_point, end_point)
}
pub fn refine_block<P>(&mut self, i: u32, p: P) -> (u32, u32)
where
P: Fn(u32) -> bool,
{
let s = self.slice_mut(i);
let mut j = 0;
for k in 0..s.len() {
if p(s[k]) {
if j < k {
s.swap(k, j);
}
j += 1;
}
}
if j == 0 {
(0, i)
} else if j == s.len() {
(i, 0)
} else {
let k = self.split_block(i, j);
(i, k)
}
}
}
#[allow(dead_code)]
impl Partition {
pub fn new(n: u32) -> Self {
let size = n as usize;
let block_id = vec![1; size].into_boxed_slice();
Partition {
base: BasePartition::new(n),
block_id,
}
}
pub fn num_blocks(&self) -> u32 {
self.base.num_blocks()
}
pub fn index(&self) -> u32 {
self.base.index()
}
pub fn size(&self) -> u32 {
self.base.size()
}
pub fn block_size(&self, i: u32) -> u32 {
self.base.block_size(i)
}
pub fn smaller_block(&self, i: u32, j: u32) -> bool {
self.base.smaller_block(i, j)
}
pub fn sort_block(&mut self, i: u32) {
self.base.sort_block(i)
}
pub fn block_elements(&self, i: u32) -> impl Iterator<Item = u32> + '_ {
self.base.block_elements(i)
}
pub fn pick_element(&self, i: u32) -> u32 {
self.base.pick_element(i)
}
pub fn block_id(&self, x: u32) -> u32 {
self.block_id[x as usize]
}
pub fn refine_block<P>(&mut self, i: u32, p: P) -> (u32, u32)
where
P: Fn(u32) -> bool,
{
let result = self.base.refine_block(i, p);
let (b1, b2) = result;
if b1 != 0 && b2 != 0 {
for x in self.base.block_elements(b2) {
self.block_id[x as usize] = b2;
}
}
result
}
pub fn refine_block_with_fun<F>(&mut self, i: u32, f: F, b: u32) -> (u32, u32)
where
F: Fn(u32) -> u32,
{
let base = &mut self.base;
let block_ids = &self.block_id;
let result = base.refine_block(i, |y| block_ids[f(y) as usize] == b);
let (b1, b2) = result;
if b1 != 0 && b2 != 0 {
for x in self.base.block_elements(b2) {
self.block_id[x as usize] = b2;
}
}
result
}
}
impl Display for BasePartition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for i in 1..self.num_blocks() {
write!(f, "block[{i}]: ")?;
for x in self.block_elements(i) {
write!(f, " {x}")?;
}
writeln!(f)?;
}
Ok(())
}
}
impl Display for Partition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.base.fmt(f)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test() {
let mut p = Partition::new(20);
println!("Initial partition:\n{p}");
assert_eq!(p.num_blocks(), 2);
for i in 0..20 {
assert_eq!(p.block_id(i), 1);
}
let split0 = p.refine_block(0, |x| (x & 1) == 0);
assert_eq!(split0, (0, 0));
let split1 = p.refine_block(1, |x| (x & 1) == 0);
assert_eq!(split1, (1, 2));
println!("Even/odd numbers:\n{p}");
for i in 1..p.num_blocks() {
p.refine_block(i, |x| x % 3 == 0);
}
assert_eq!(p.num_blocks(), 5);
for i in 0..p.num_blocks() {
p.sort_block(i);
}
println!("Even/odd/multiples of three:\n{p}");
for i in 0..20 {
let b = p.block_id(i);
let expected = match i % 6 {
0 => 1,
1 | 5 => 4,
2 | 4 => 3,
3 => 2,
_ => panic!(),
};
assert_eq!(b, expected)
}
for i in 0..p.num_blocks() {
let (b1, b2) = p.refine_block(i, |x| x % 6 == 1);
assert_eq!(b1 != 0 && b2 != 0, i == 4);
}
println!("Split in 5 classes\n{p}");
for i in 0..20 {
let b = p.block_id(i);
let expected = match i % 6 {
0 => 1,
1 => 4,
2 | 4 => 3,
3 => 2,
5 => 5,
_ => panic!(),
};
assert_eq!(b, expected);
}
}
}