mod error_bound;
mod expr;
mod parse;
use crate::parse::Position;
pub use error_bound::{ErrorBound, MAX_ROUNDS, error_bound};
pub(crate) use error_bound::{ErrorProgram, Term};
pub use parse::parse_points;
pub(crate) use parse::read_declaration;
pub const MAX_POINT_NODES: usize = 1024;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ParamType {
F64x3,
F64,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PointParam {
pub name: String,
pub ty: ParamType,
pub position: Position,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum PointNode {
Coord {
param: usize,
axis: u8,
},
Scalar(usize),
Int(i64),
Neg(usize),
Add(usize, usize),
Sub(usize, usize),
Mul(usize, usize),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PointGraph {
pub nodes: Vec<PointNode>,
pub roots: [usize; 3],
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct LinearSum {
pub params: Vec<usize>,
pub constant: i64,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Constraint {
pub lhs: LinearSum,
pub rhs: LinearSum,
pub position: Position,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PointType {
pub name: String,
pub position: Position,
pub params: Vec<PointParam>,
pub graph: PointGraph,
pub constraints: Vec<Constraint>,
}
impl PointType {
#[must_use]
pub fn is_explicit(&self) -> bool {
let [param] = self.params.as_slice() else {
return false;
};
param.ty == ParamType::F64x3
&& self.constraints.is_empty()
&& self.graph.roots.iter().enumerate().all(|(axis, &root)| {
self.graph.nodes[root]
== PointNode::Coord {
param: 0,
axis: axis as u8,
}
})
}
}
#[derive(Default)]
pub(crate) struct PointBuilder {
nodes: Vec<PointNode>,
index: std::collections::BTreeMap<PointNode, usize>,
}
impl PointBuilder {
pub(crate) fn intern(&mut self, node: PointNode) -> usize {
*self.index.entry(node).or_insert_with(|| {
self.nodes.push(node);
self.nodes.len() - 1
})
}
pub(crate) fn finish(self, roots: [usize; 3]) -> PointGraph {
let mut live = vec![false; self.nodes.len()];
for root in roots {
live[root] = true;
}
for id in (0..self.nodes.len()).rev() {
if !live[id] {
continue;
}
match self.nodes[id] {
PointNode::Neg(x) => live[x] = true,
PointNode::Add(x, y) | PointNode::Sub(x, y) | PointNode::Mul(x, y) => {
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 {
PointNode::Neg(x) => PointNode::Neg(new_id[x]),
PointNode::Add(x, y) => PointNode::Add(new_id[x], new_id[y]),
PointNode::Sub(x, y) => PointNode::Sub(new_id[x], new_id[y]),
PointNode::Mul(x, y) => PointNode::Mul(new_id[x], new_id[y]),
leaf => leaf,
});
}
PointGraph {
nodes,
roots: roots.map(|root| new_id[root]),
}
}
}