use std::collections::BTreeMap;
pub type NodeId = usize;
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum Node {
Coord {
point: usize,
axis: u8,
},
Int(i64),
Add(NodeId, NodeId),
Sub(NodeId, NodeId),
Mul(NodeId, NodeId),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Graph {
pub nodes: Vec<Node>,
pub root: NodeId,
}
impl Graph {
pub(crate) fn degree_bound(&self) -> u64 {
let mut degrees: Vec<u64> = Vec::with_capacity(self.nodes.len());
for node in &self.nodes {
degrees.push(match *node {
Node::Coord { .. } => 1,
Node::Int(_) => 0,
Node::Add(x, y) | Node::Sub(x, y) => degrees[x].max(degrees[y]),
Node::Mul(x, y) => degrees[x].saturating_add(degrees[y]),
});
}
degrees[self.root]
}
}
#[derive(Default)]
pub(crate) struct Builder {
nodes: Vec<Node>,
index: BTreeMap<Node, NodeId>,
}
impl Builder {
pub(crate) fn intern(&mut self, node: Node) -> NodeId {
*self.index.entry(node).or_insert_with(|| {
self.nodes.push(node);
self.nodes.len() - 1
})
}
pub(crate) fn negate(&mut self, x: NodeId) -> NodeId {
let zero = self.intern(Node::Int(0));
self.intern(Node::Sub(zero, x))
}
pub(crate) fn finish(self, root: NodeId) -> Graph {
let mut live = vec![false; self.nodes.len()];
live[root] = true;
for id in (0..self.nodes.len()).rev() {
if !live[id] {
continue;
}
if let Node::Add(x, y) | Node::Sub(x, y) | Node::Mul(x, y) = self.nodes[id] {
live[x] = true;
live[y] = true;
}
}
let mut new_id = vec![0; self.nodes.len()];
let mut nodes = Vec::new();
for (id, node) in self.nodes.iter().enumerate().filter(|&(id, _)| live[id]) {
new_id[id] = nodes.len();
nodes.push(match *node {
Node::Add(x, y) => Node::Add(new_id[x], new_id[y]),
Node::Sub(x, y) => Node::Sub(new_id[x], new_id[y]),
Node::Mul(x, y) => Node::Mul(new_id[x], new_id[y]),
leaf => leaf,
});
}
Graph {
root: nodes.len() - 1,
nodes,
}
}
}