Research-Stack/5-Applications/parquet_compressor/src/shifters/bwt.rs
2026-05-11 23:48:42 -05:00

101 lines
2.7 KiB
Rust

use crate::shifters::{ManifoldState, Shifter};
use divsufsort::sort_in_place;
use serde_json::json;
pub struct BWTShifter;
impl Shifter for BWTShifter {
fn name(&self) -> &'static str {
"bwt"
}
fn encode(&self, state: &mut ManifoldState) -> anyhow::Result<()> {
let data = if !state.encoded.is_empty() {
&state.encoded
} else {
&state.raw_bytes
};
if data.is_empty() {
state.update(Vec::new(), self.name(), json!({"primary_index": 0}));
return Ok(());
}
let n = data.len();
// divsufsort computes the suffix array SA
// The BWT L is defined as: L[i] = data[SA[i] - 1] (with wrap around)
// And we need the primary_index such that SA[primary_index] == 0.
let mut sa = vec![0i32; n];
sort_in_place(data, &mut sa);
let mut primary_index = 0;
let mut result = Vec::with_capacity(n);
for i in 0..n {
let s_idx = sa[i] as usize;
if s_idx == 0 {
primary_index = i;
result.push(data[n - 1]);
} else {
result.push(data[s_idx - 1]);
}
}
state.update(result, self.name(), json!({"primary_index": primary_index}));
Ok(())
}
fn decode(&self, state: &mut ManifoldState) -> anyhow::Result<()> {
let data = &state.encoded;
if data.is_empty() {
return Ok(());
}
let meta = state
.metadata
.get(self.name())
.cloned()
.unwrap_or(json!({}));
let primary_index = meta
.get("primary_index")
.and_then(|v| v.as_u64())
.unwrap_or(0) as usize;
let n = data.len();
// Decoding BWT:
// 1. Count occurrences of each byte
let mut counts = [0usize; 256];
for &b in data {
counts[b as usize] += 1;
}
// 2. Compute starting positions in sorted order
let mut start_pos = [0usize; 256];
let mut sum = 0;
for i in 0..256 {
start_pos[i] = sum;
sum += counts[i];
}
// 3. Compute LF mapping
let mut lf = vec![0usize; n];
let mut current_counts = [0usize; 256];
for i in 0..n {
let b = data[i] as usize;
lf[i] = start_pos[b] + current_counts[b];
current_counts[b] += 1;
}
// 4. Reconstruct string
let mut result = vec![0u8; n];
let mut curr = primary_index;
for i in (0..n).rev() {
result[i] = data[curr];
curr = lf[curr];
}
state.encoded = result;
Ok(())
}
}