use crate::geom::rat::lex_min_rot;
use crate::stringmatch::repetition_factor;
pub fn is_achiral(canonical: &[i8]) -> bool {
let mut reflected: Vec<i8> = canonical.iter().rev().copied().collect();
let offset = lex_min_rot(&reflected);
reflected.rotate_left(offset);
reflected == canonical
}
pub fn print_stats(rats: &[Vec<i8>]) {
use std::collections::BTreeMap;
let mut per_len: BTreeMap<usize, (usize, usize, BTreeMap<usize, usize>)> = BTreeMap::new();
for seq in rats {
let n = seq.len();
let entry = per_len.entry(n).or_default();
entry.0 += 1;
if is_achiral(seq) {
entry.1 += 1;
}
let rf = repetition_factor(seq);
*entry.2.entry(rf).or_insert(0) += 1;
}
println!("statistics by boundary length:");
println!(" length | total | achiral (%) | rotational symmetry histogram (rep_factor: count)");
println!(" -------+--------+-------------+--------------------------------------------------");
for (n, (total, achiral, hist)) in &per_len {
let pct = if *total > 0 {
100.0 * (*achiral as f64) / (*total as f64)
} else {
0.0
};
let mut hist_str = String::new();
for (rf, cnt) in hist {
if !hist_str.is_empty() {
hist_str.push_str(" ");
}
hist_str.push_str(&format!("x{rf}={cnt}"));
}
println!(" {n:>6} | {total:>6} | {achiral:>5} ({pct:>5.1}%) | {hist_str}");
}
}