use std::hash::Hash;
use crate::{
expr::{Expression, Node, NodeId},
opt::merger::Merger,
};
mod algo;
mod merger;
pub use merger::{MergeResult, Mergeable, SetRelation};
pub struct OptimizerConfig<M> {
pub merger: M,
pub merger_depth: usize,
pub max_iterations: usize,
}
impl Default for OptimizerConfig<()> {
fn default() -> Self {
Self {
merger: (),
merger_depth: 2,
max_iterations: 0,
}
}
}
impl<T: Hash + PartialEq> Expression<T> {
pub fn optimize<M: Mergeable<T>>(&mut self, config: &mut OptimizerConfig<M>) {
let mut merger = Merger::new(&mut config.merger);
let mut remap = vec![NodeId::MAX; self.nodes.len()];
let mut i = 0;
let mut iter_count = 0;
let mut iter_end = self.nodes.len();
while i < self.nodes.len() {
let new_id = match &self.nodes[i] {
Node::Empty => NodeId::EMPTY,
Node::Set(_) => NodeId::new(i as u32, false),
Node::Union(kids) => {
let kids = kids.iter().map(|&k| resolve(k, &remap)).collect();
self.apply_logic_reduction(kids, true, &mut merger, config.merger_depth)
}
Node::Intersection(kids) => {
let kids = kids.iter().map(|&k| resolve(k, &remap)).collect();
self.apply_logic_reduction(kids, false, &mut merger, config.merger_depth)
}
};
if new_id.idx() < i {
remap[i] = resolve(new_id, &remap);
} else {
remap[i] = new_id;
}
i += 1;
if i >= iter_end {
if config.max_iterations != 0 {
iter_count += 1;
if iter_count >= config.max_iterations {
break;
}
}
iter_end = self.nodes.len();
remap.resize(iter_end, NodeId::MAX);
}
}
for root in &mut self.roots {
*root = resolve(*root, &remap);
}
}
}
fn resolve(mut id: NodeId, remap: &[NodeId]) -> NodeId {
loop {
let idx = id.idx();
if idx >= remap.len() || remap[idx] == NodeId::MAX {
return id; }
let opt = remap[idx];
if opt.idx() == idx {
return id; }
if id.is_neg() {
id = opt.not();
} else {
id = opt;
}
}
}