use std::fmt::Display;
use crate::{
fast_sets::FastSet,
partitions::{BasePartition, Partition},
};
#[derive(Debug, Clone, PartialEq, Eq)]
struct Splitter {
block: u32, char: u32, class: u32, active: bool,
}
impl Display for Splitter {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Splitter({}, {}, {}, {})",
self.block, self.char, self.class, self.active
)
}
}
#[derive(Debug, Clone)]
struct SplitterItem {
char: u32,
class: u32,
active: bool,
}
impl SplitterItem {
fn to_splitter(&self, block: u32) -> Splitter {
Splitter {
block,
char: self.char,
class: self.class,
active: self.active,
}
}
fn from_splitter(s: &Splitter) -> SplitterItem {
SplitterItem {
char: s.char,
class: s.class,
active: s.active,
}
}
}
#[derive(Debug, Clone)]
struct CharClassPair {
char: u32,
class: u32,
}
#[derive(Debug, Clone, Default)]
struct SplitterList {
num_active: usize,
list: Vec<CharClassPair>,
}
struct SplitterListIterator<'a> {
list: &'a SplitterList,
index: usize,
}
impl SplitterList {
fn add(&mut self, s: SplitterItem) {
let list = &mut self.list;
let i = list.len();
list.push(CharClassPair {
char: s.char,
class: s.class,
});
if s.active {
if self.num_active < i {
list.swap(self.num_active, i);
}
self.num_active += 1;
}
}
fn pick_active(&mut self) -> &CharClassPair {
debug_assert!(self.num_active > 0);
let list = &self.list;
self.num_active -= 1;
&list[self.num_active]
}
fn has_active_items(&self) -> bool {
self.num_active > 0
}
fn iter(&self) -> SplitterListIterator<'_> {
SplitterListIterator {
list: self,
index: 0,
}
}
}
impl<'a> Iterator for SplitterListIterator<'a> {
type Item = SplitterItem;
fn next(&mut self) -> Option<Self::Item> {
let i = self.index;
let list = &self.list.list;
if i < list.len() {
self.index += 1;
let active = i < self.list.num_active;
let pair = &list[i];
Some(SplitterItem {
char: pair.char,
class: pair.class,
active,
})
} else {
None
}
}
}
#[derive(Debug, Clone)]
struct SplitterSet {
list: Vec<SplitterList>,
active_block: usize,
}
impl SplitterSet {
fn new() -> SplitterSet {
let list = Vec::with_capacity(8);
SplitterSet {
list,
active_block: 0,
}
}
fn take_list(&mut self, b: u32) -> SplitterList {
std::mem::take(&mut self.list[b as usize])
}
fn add_splitter(&mut self, s: &Splitter) {
let b = s.block as usize;
if self.list.len() <= b {
self.list.resize_with(b + 1, Default::default);
}
self.list[b].add(SplitterItem::from_splitter(s))
}
fn has_active_splitter(&mut self) -> bool {
let l = &self.list;
let b = self.active_block;
if l[b].has_active_items() {
true
} else {
for (b, list) in l.iter().enumerate() {
if list.has_active_items() {
self.active_block = b;
return true;
}
}
false
}
}
fn pick_splitter(&mut self) -> Option<Splitter> {
if self.has_active_splitter() {
let b = self.active_block;
let l = &mut self.list[b];
let pair = l.pick_active();
Some(Splitter {
block: b as u32,
char: pair.char,
class: pair.class,
active: false,
})
} else {
None
}
}
fn iter(&self) -> impl Iterator<Item = &SplitterList> {
self.list.iter()
}
}
#[derive(Debug, Clone)]
pub struct Minimizer<D, F> {
num_states: u32,
alphabet_size: u32,
delta: D,
is_final: F,
main_partition: Partition,
pred_classes: Box<[BasePartition]>,
splitters: SplitterSet,
}
impl<D, F> Display for Minimizer<D, F> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(
f,
"Minimizer: {} states, {} chars",
self.num_states, self.alphabet_size
)?;
writeln!(f, "main partition")?;
writeln!(f, "{}", self.main_partition)?;
for (i, p) in self.pred_classes.iter().enumerate() {
writeln!(f, "pred_class[{i}]")?;
writeln!(f, "{p}")?;
}
writeln!(f, "Active splitters")?;
for (i, l) in self.splitters.iter().enumerate() {
for s in l.iter() {
if s.active {
writeln!(f, " {}", s.to_splitter(i as u32))?;
}
}
}
writeln!(f, "Inactive splitters")?;
for (i, l) in self.splitters.iter().enumerate() {
for s in l.iter() {
if !s.active {
writeln!(f, " {}", s.to_splitter(i as u32))?;
}
}
}
Ok(())
}
}
impl<D, F> Minimizer<D, F>
where
D: Fn(u32, u32) -> u32,
F: Fn(u32) -> bool,
{
fn upate_splitters_after_refinement(&mut self, i: u32, j: u32) {
let main = &self.main_partition;
let delta = &self.delta;
let old_splitters = self.splitters.take_list(i);
for s in old_splitters.iter() {
debug_assert!(s.class != 0);
let c = s.char;
let p = &mut self.pred_classes[c as usize];
let (class1, class2) = p.refine_block(s.class, |x| main.block_id(delta(x, c)) == i);
let active1;
let active2;
if s.active {
active1 = true;
active2 = true;
} else if p.smaller_block(class1, class2) {
active1 = true;
active2 = false;
} else {
active1 = false;
active2 = true;
}
if class1 != 0 {
self.splitters.add_splitter(&Splitter {
block: i,
char: c,
class: class1,
active: active1,
});
}
if class2 != 0 {
self.splitters.add_splitter(&Splitter {
block: j,
char: c,
class: class2,
active: active2,
});
}
}
}
fn init_main_partition(&mut self) {
let main_partition = &mut self.main_partition;
debug_assert_eq!(main_partition.num_blocks(), 2);
let (i, j) = main_partition.refine_block(1, &self.is_final);
if i != 0 && j != 0 {
debug_assert!(i == 1 && j == 2);
self.upate_splitters_after_refinement(i, j);
}
}
fn collect_refinement_candidates(&self, s: &Splitter, set: &mut FastSet) {
set.reset();
let p = &self.pred_classes[s.char as usize];
for x in p.block_elements(s.class) {
let b = self.main_partition.block_id(x);
if self.main_partition.block_size(b) > 1 {
set.insert(b)
}
}
}
fn refine_block_with_splitter(&mut self, s: &Splitter, b: u32) {
let main = &mut self.main_partition;
let delta = &self.delta;
let (i, j) = main.refine_block_with_fun(b, |x| delta(x, s.char), s.block);
debug_assert!(i != 0); if j != 0 {
debug_assert_eq!(i, b);
self.upate_splitters_after_refinement(i, j)
}
}
fn refine_with_splitter(&mut self, s: &Splitter) {
let set = &mut FastSet::new(self.main_partition.num_blocks());
self.collect_refinement_candidates(s, set);
let self_refine = set.contains(s.block);
if self_refine {
set.remove(s.block);
}
for b in set.iter() {
self.refine_block_with_splitter(s, b)
}
if self_refine {
self.refine_block_with_splitter(s, s.block)
}
}
fn pick_splitter(&mut self) -> Option<Splitter> {
self.splitters.pick_splitter()
}
#[allow(dead_code)]
fn print_splitters(&self) {
println!("Splitters");
for (i, l) in self.splitters.iter().enumerate() {
for s in l.iter() {
print!(
" {}: pred({}, {}) = {{",
s.to_splitter(i as u32),
i,
s.char
);
for x in self.pred_classes[s.char as usize].block_elements(s.class) {
print!(" {x}");
}
println!(" }}");
}
}
println!();
}
#[allow(dead_code)]
pub fn refine_and_trace(&mut self) {
let mut round = 0;
println!("Initial partition");
println!("{}", self.main_partition);
while self.main_partition.index() < self.num_states {
round += 1;
match self.pick_splitter() {
Some(s) => {
println!("--- round {round} ---");
println!("{s}");
print!("pre({}, {}) = {{", s.block, s.char);
for x in self.pred_classes[s.char as usize].block_elements(s.class) {
print!(" {x}");
}
println!(" }}");
self.refine_with_splitter(&s);
println!("After refinement");
println!("{}", self.main_partition);
}
None => break,
}
}
}
pub fn refine(&mut self) -> &Partition {
while self.main_partition.index() < self.num_states {
match self.pick_splitter() {
Some(s) => self.refine_with_splitter(&s),
None => break,
}
}
&self.main_partition
}
pub fn new(num_states: u32, alphabet_size: u32, delta: D, is_final: F) -> Self {
let main_partition = Partition::new(num_states);
let alpha_size = alphabet_size as usize;
let mut classes = Vec::with_capacity(alpha_size);
for _ in 0..alpha_size {
classes.push(BasePartition::new(num_states));
}
let mut splitters = SplitterSet::new();
for c in 0..alphabet_size {
splitters.add_splitter(&Splitter {
block: 1,
char: c,
class: 1,
active: false,
});
}
let mut m = Minimizer {
num_states,
alphabet_size,
delta,
is_final,
main_partition,
pred_classes: classes.into_boxed_slice(),
splitters,
};
m.init_main_partition();
m
}
}