qudit-expr 0.3.3

Accelerated and Extensible Quantum Library
Documentation
use super::*;
use indexmap::IndexMap;
use rustc_hash::FxHashMap;

pub type Cost = NotNan<f64>;
pub const INFINITY: Cost = unsafe { NotNan::new_unchecked(std::f64::INFINITY) };

#[derive(Default, Debug, Clone)]
pub struct ExtractionResult {
    pub choices: IndexMap<Id, TrigLanguage>,
}

impl ExtractionResult {
    pub fn node_sum_cost(&self, _egraph: &EGraph, node: &TrigLanguage, costs: &FxHashMap<Id, Cost>) -> Cost {
        NotNan::new(node_cost(node)).unwrap()
            + node
                .children()
                .iter()
                .map(|child| {
                    costs.get(child).unwrap_or(&INFINITY)
                })
                .sum::<Cost>()
    }
    
    pub fn choose(&mut self, class_id: Id, node: TrigLanguage) {
        self.choices.insert(class_id, node);
    }
}

fn node_cost(enode: &TrigLanguage) -> f64 {
    let op_cost = match enode {
        TrigLanguage::Constant(_) => 0.5,
        TrigLanguage::Neg(_) => 1.0,
        TrigLanguage::Add(_) | TrigLanguage::Sub(_) => 1.0,
        TrigLanguage::Mul(_) | TrigLanguage::Div(_) => 5.0,
        TrigLanguage::Pow(_) | TrigLanguage::Sqrt(_) | TrigLanguage::Sin(_) | TrigLanguage::Cos(_) => 50.0,
        _ => 0.0,
    };
    op_cost
}

pub struct BottomUpExtractor;
impl BottomUpExtractor {
    pub fn extract(&self, egraph: &EGraph, _roots: &[Id]) -> ExtractionResult {
        let mut result = ExtractionResult::default();
        let mut costs = FxHashMap::<Id, Cost>::with_capacity_and_hasher(
            egraph.classes().len(),
            Default::default(),
        );
        let mut did_something = false;

        loop {
            for class in egraph.classes() {
                for node in &class.nodes {
                    let cost = result.node_sum_cost(egraph, node, &costs);
                    if &cost < costs.get(&class.id).unwrap_or(&INFINITY) {
                        result.choose(class.id.clone(), node.clone());
                        costs.insert(class.id.clone(), cost);
                        did_something = true;
                    }
                }
            }

            if did_something {
                did_something = false;
            } else {
                break;
            }
        }

        result
    }
}