const WINDOW: usize = 32;
#[derive(Clone, Copy, Debug)]
pub struct ObservationConfig {
pub window: usize,
pub contested_threshold: f32,
pub contested_min_gap: usize,
}
impl Default for ObservationConfig {
fn default() -> Self {
Self {
window: WINDOW,
contested_threshold: 0.2,
contested_min_gap: 8,
}
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct ObservationFrame {
pub causal: f32,
pub anticausal: f32,
pub centered: f32,
pub disagreement: f32,
}
#[derive(Clone, Debug, Default)]
pub struct ObservationField {
pub len: usize,
pub frames: Vec<ObservationFrame>,
pub contested: Vec<usize>,
}
impl ObservationField {
#[must_use]
pub fn causal_at(&self, byte: usize) -> f32 {
self.frames.get(byte).map_or(0.0, |f| f.causal)
}
#[must_use]
pub fn anticausal_at(&self, byte: usize) -> f32 {
self.frames.get(byte).map_or(0.0, |f| f.anticausal)
}
#[must_use]
pub fn centered_at(&self, byte: usize) -> f32 {
self.frames.get(byte).map_or(0.0, |f| f.centered)
}
#[must_use]
pub fn disagreement_at(&self, byte: usize) -> f32 {
self.frames.get(byte).map_or(0.0, |f| f.disagreement)
}
#[must_use]
pub fn is_contested(&self, byte: usize) -> bool {
self.contested.binary_search(&byte).is_ok()
}
#[must_use]
pub fn any_contested_in(&self, lo: usize, hi: usize) -> bool {
if lo >= hi {
return false;
}
let i = self.contested.partition_point(|&c| c < lo);
self.contested.get(i).is_some_and(|&c| c < hi)
}
}
fn class(b: u8) -> usize {
if b.is_ascii_digit() {
0
} else if b.is_ascii_alphabetic() {
1
} else if b.is_ascii_whitespace() {
2
} else if b < 128 {
3
} else {
4
}
}
const N_CLASSES: usize = 5;
struct Vantage<'a> {
counts: Vec<u32>,
len: u32,
counted: u32,
sum_clog: i64,
lut: &'a [i64],
log2_len: &'a [f64],
}
impl<'a> Vantage<'a> {
fn new(alphabet: usize, lut: &'a [i64], log2_len: &'a [f64]) -> Self {
Self { counts: vec![0; alphabet], len: 0, counted: 0, sum_clog: 0, lut, log2_len }
}
#[inline]
fn add(&mut self, sym: u32) {
self.len += 1;
if let Some(c) = self.counts.get_mut(sym as usize) {
let old = *c;
*c = old + 1;
self.counted += 1;
self.sum_clog +=
crate::spectral::fixed_term(self.lut, old + 1) - crate::spectral::fixed_term(self.lut, old);
}
}
#[inline]
fn remove(&mut self, sym: u32) {
self.len -= 1;
if let Some(c) = self.counts.get_mut(sym as usize) {
let old = *c;
*c = old - 1;
self.counted -= 1;
self.sum_clog -=
crate::spectral::fixed_term(self.lut, old) - crate::spectral::fixed_term(self.lut, old - 1);
}
}
#[inline]
fn entropy(&self, norm: f64) -> f32 {
if self.len == 0 || norm == 0.0 {
return 0.0;
}
let len = f64::from(self.len);
let log2_len = self.log2_len.get(self.len as usize).copied().unwrap_or_else(|| len.log2());
let h = f64::from(self.counted) / len * log2_len
- self.sum_clog as f64 / (crate::spectral::FIXED_LOG_SCALE * len);
(h / norm).max(0.0) as f32
}
}
fn read_vantages(n: usize, alphabet: usize, w: usize, sym: impl Fn(usize) -> u32) -> Vec<ObservationFrame> {
let mut frames = Vec::with_capacity(n);
if n == 0 {
return frames;
}
let half = (w / 2).max(1);
let norm = if alphabet > 1 { (alphabet as f64).log2() } else { 0.0 };
let lut = crate::spectral::fixed_log_table();
let log2_len: Vec<f64> = (0..=(w + 2).min(n + 1)).map(|l| (l as f64).log2()).collect();
let mut causal = Vantage::new(alphabet, lut, &log2_len);
let mut anticausal = Vantage::new(alphabet, lut, &log2_len);
let mut centered = Vantage::new(alphabet, lut, &log2_len);
for j in 1..(1 + w).min(n) {
anticausal.add(sym(j));
}
for j in 0..(1 + half).min(n) {
centered.add(sym(j));
}
for t in 0..n {
causal.add(sym(t));
if t > w {
causal.remove(sym(t - w - 1));
}
let c = causal.entropy(norm);
let a = anticausal.entropy(norm);
frames.push(ObservationFrame {
causal: c,
anticausal: a,
centered: centered.entropy(norm),
disagreement: (c - a).abs(),
});
if t + 1 < n {
anticausal.remove(sym(t + 1));
if t + 1 + w < n {
anticausal.add(sym(t + 1 + w));
}
if t + 1 + half < n {
centered.add(sym(t + 1 + half));
}
if t >= half {
centered.remove(sym(t - half));
}
}
}
frames
}
#[must_use]
pub fn analyze_symbols(
symbols: &[u32],
alphabet: usize,
cfg: &ObservationConfig,
) -> ObservationField {
let n = symbols.len();
let mut field = ObservationField {
len: n,
frames: read_vantages(n, alphabet, cfg.window.max(1), |j| symbols[j]),
contested: Vec::new(),
};
if n == 0 {
return field;
}
for t in 1..n.saturating_sub(1) {
let d = field.frames[t].disagreement;
if d >= cfg.contested_threshold
&& d >= field.frames[t - 1].disagreement
&& d >= field.frames[t + 1].disagreement
{
field.contested.push(t);
}
}
field
}
#[must_use]
pub fn analyze_tokens(toks: &[crate::token::Token], cfg: &ObservationConfig) -> ObservationField {
let symbols: Vec<u32> =
toks.iter().filter(|t| t.is_significant()).map(|t| t.kind.code()).collect();
let alphabet = symbols.iter().copied().max().map_or(1, |m| m as usize + 1);
analyze_symbols(&symbols, alphabet, cfg)
}
#[must_use]
pub fn analyze_supertokens(
units: &[crate::supertoken::SuperToken],
cfg: &ObservationConfig,
) -> ObservationField {
let symbols: Vec<u32> = units.iter().map(|u| u.role.code()).collect();
let alphabet = symbols.iter().copied().max().map_or(1, |m| m as usize + 1);
analyze_symbols(&symbols, alphabet, cfg)
}
#[must_use]
pub fn contested_tokens(toks: &[crate::token::Token], cfg: &ObservationConfig) -> Vec<usize> {
let sig: Vec<&crate::token::Token> = toks.iter().filter(|t| t.is_significant()).collect();
let symbols: Vec<u32> = sig.iter().map(|t| t.kind.code()).collect();
let alphabet = symbols.iter().copied().max().map_or(1, |m| m as usize + 1);
let mut out: Vec<usize> = analyze_symbols(&symbols, alphabet, cfg)
.contested
.into_iter()
.filter_map(|i| sig.get(i).map(|t| t.start()))
.collect();
out.sort_unstable();
out
}
#[must_use]
pub fn contested_supertokens(
units: &[crate::supertoken::SuperToken],
cfg: &ObservationConfig,
) -> Vec<usize> {
let symbols: Vec<u32> = units.iter().map(|u| u.role.code()).collect();
let alphabet = symbols.iter().copied().max().map_or(1, |m| m as usize + 1);
let mut out: Vec<usize> = analyze_symbols(&symbols, alphabet, cfg)
.contested
.into_iter()
.filter_map(|i| units.get(i).map(|u| u.start))
.collect();
out.sort_unstable();
out
}
#[must_use]
pub fn analyze(input: &[u8]) -> ObservationField {
analyze_with(input, &ObservationConfig::default())
}
#[must_use]
pub fn analyze_with(input: &[u8], cfg: &ObservationConfig) -> ObservationField {
let n = input.len();
let w = cfg.window.max(1);
let half = (w / 2).max(1);
let mut field = ObservationField {
len: n,
frames: read_vantages(n, N_CLASSES, w, |j| class(input[j]) as u32),
contested: Vec::new(),
};
if n == 0 {
return field;
}
let margin = if n > 2 * w { half } else { 0 };
let mut last = None::<usize>;
for t in margin..n.saturating_sub(margin) {
let d = field.frames[t].disagreement;
if d < cfg.contested_threshold {
continue;
}
let left = t.checked_sub(1).map_or(0.0, |j| field.frames[j].disagreement);
let right = field.frames.get(t + 1).map_or(0.0, |f| f.disagreement);
let is_peak = d >= left && d >= right && (d > left || d > right);
if is_peak && last.is_none_or(|l| t - l >= cfg.contested_min_gap) {
field.contested.push(t);
last = Some(t);
}
}
field
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn any_contested_in_range_probe() {
let f = ObservationField { len: 100, frames: Vec::new(), contested: vec![10, 50, 90] };
assert!(f.any_contested_in(0, 20), "10 is in [0,20)");
assert!(f.any_contested_in(40, 60), "50 is in [40,60)");
assert!(!f.any_contested_in(20, 50), "[20,50) excludes 10 and the exclusive 50");
assert!(!f.any_contested_in(91, 100), "[91,100) is past 90");
assert!(!f.any_contested_in(30, 30), "an empty range never matches");
assert!(f.any_contested_in(90, 91), "90 is in [90,91) (inclusive lo)");
}
#[test]
fn transition_is_contested() {
let mut input = b"let x = 5; let y = 6; let z = 7; ".to_vec();
input.extend_from_slice(b"f8KZ3pQ9wX7mB2nL5vR1tY6uA4cE0dG8hJ3kP9sW7xZ2");
let f = analyze(&input);
assert!(
!f.contested.is_empty(),
"the code -> blob transition should be contested"
);
assert!(f.contested.iter().any(|&c| c > 20));
}
#[test]
fn homogeneous_stream_has_low_disagreement() {
let f = analyze(
b"the quick brown fox jumps over the lazy dog again and again now and forever more",
);
assert!(f.contested.is_empty(), "homogeneous text has no contested point");
let n = f.frames.len();
let interior = if n > 32 { &f.frames[16..n - 16] } else { &f.frames[..] };
let maxd = interior.iter().map(|fr| fr.disagreement).fold(0.0f32, f32::max);
assert!(maxd < 0.4, "homogeneous interior should barely disagree, got {maxd}");
}
#[test]
fn causal_lags_the_centered_reading_at_a_change() {
let mut input = vec![b'a'; 40];
input.extend(std::iter::repeat_n(b'9', 40));
let f = analyze(&input);
let at = 40; assert!(
(f.causal_at(at) - f.frames[at].centered).abs() > 0.0,
"causal and centered should differ at a change"
);
}
#[test]
fn empty_is_safe() {
let f = analyze(b"");
assert_eq!(f.len, 0);
assert!(f.frames.is_empty());
assert!(f.contested.is_empty());
assert_eq!(f.causal_at(0), 0.0);
assert!(!f.is_contested(0));
}
}