use super::hypergraph::*;
use crate::strict::vec::{FiniteFunction, VecKind};
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
feature = "serde",
serde(
bound = "O: serde::Serialize + serde::de::DeserializeOwned, A: serde::Serialize + serde::de::DeserializeOwned"
)
)]
pub struct OpenHypergraph<O, A> {
pub sources: Vec<NodeId>,
pub targets: Vec<NodeId>,
pub hypergraph: Hypergraph<O, A>,
}
impl<O, A> OpenHypergraph<O, A> {
pub fn empty() -> Self {
OpenHypergraph {
sources: vec![],
targets: vec![],
hypergraph: Hypergraph::empty(),
}
}
pub fn from_strict(f: crate::strict::open_hypergraph::OpenHypergraph<VecKind, O, A>) -> Self {
let sources = f.s.table.0.into_iter().map(NodeId).collect();
let targets = f.t.table.0.into_iter().map(NodeId).collect();
let hypergraph = Hypergraph::from_strict(f.h);
OpenHypergraph {
sources,
targets,
hypergraph,
}
}
pub fn new_node(&mut self, w: O) -> NodeId {
self.hypergraph.new_node(w)
}
pub fn new_edge(&mut self, x: A, interface: impl Into<Hyperedge>) -> EdgeId {
self.hypergraph.new_edge(x, interface)
}
pub fn new_operation(
&mut self,
x: A,
source_type: Vec<O>,
target_type: Vec<O>,
) -> (EdgeId, Interface) {
self.hypergraph.new_operation(x, source_type, target_type)
}
pub fn singleton(x: A, source_type: Vec<O>, target_type: Vec<O>) -> Self {
let mut f = Self::empty();
let (_, (s, t)) = f.new_operation(x, source_type, target_type);
f.sources = s;
f.targets = t;
f
}
pub fn unify(&mut self, v: NodeId, w: NodeId) {
self.hypergraph.unify(v, w);
}
pub fn delete_edges(&mut self, edge_ids: &[EdgeId]) {
self.hypergraph.delete_edges(edge_ids);
}
pub fn delete_nodes(&mut self, node_ids: &[NodeId]) {
let new_index = self.hypergraph.delete_nodes_witness(node_ids);
self.sources = self
.sources
.iter()
.filter_map(|n| new_index[n.0].map(NodeId))
.collect();
self.targets = self
.targets
.iter()
.filter_map(|n| new_index[n.0].map(NodeId))
.collect();
}
pub fn add_edge_source(&mut self, edge_id: EdgeId, w: O) -> NodeId {
self.hypergraph.add_edge_source(edge_id, w)
}
pub fn add_edge_target(&mut self, edge_id: EdgeId, w: O) -> NodeId {
self.hypergraph.add_edge_target(edge_id, w)
}
pub fn with_nodes<T, F: FnOnce(Vec<O>) -> Vec<T>>(self, f: F) -> Option<OpenHypergraph<T, A>> {
self.hypergraph
.with_nodes(f)
.map(|hypergraph| OpenHypergraph {
sources: self.sources,
targets: self.targets,
hypergraph,
})
}
pub fn map_nodes<F: Fn(O) -> T, T>(self, f: F) -> OpenHypergraph<T, A> {
OpenHypergraph {
sources: self.sources,
targets: self.targets,
hypergraph: self.hypergraph.map_nodes(f),
}
}
pub fn with_edges<T, F: FnOnce(Vec<A>) -> Vec<T>>(self, f: F) -> Option<OpenHypergraph<O, T>> {
self.hypergraph
.with_edges(f)
.map(|hypergraph| OpenHypergraph {
sources: self.sources,
targets: self.targets,
hypergraph,
})
}
pub fn map_edges<F: Fn(A) -> T, T>(self, f: F) -> OpenHypergraph<O, T> {
OpenHypergraph {
sources: self.sources,
targets: self.targets,
hypergraph: self.hypergraph.map_edges(f),
}
}
}
impl<O, A> OpenHypergraph<O, A> {
pub fn identity(a: Vec<O>) -> Self {
let mut f = OpenHypergraph::empty();
f.sources = (0..a.len()).map(NodeId).collect();
f.targets = (0..a.len()).map(NodeId).collect();
f.hypergraph.nodes = a;
f
}
pub fn spider(s: FiniteFunction, t: FiniteFunction, w: Vec<O>) -> Option<Self> {
if s.target != t.target || s.target != w.len() {
return None;
}
let mut f = OpenHypergraph::empty();
f.hypergraph.nodes = w;
f.sources = s.table.0.into_iter().map(NodeId).collect();
f.targets = t.table.0.into_iter().map(NodeId).collect();
Some(f)
}
}
impl<O: Clone, A: Clone> OpenHypergraph<O, A> {
pub fn tensor(&self, other: &Self) -> Self {
let hypergraph = Hypergraph::coproduct(&self.hypergraph, &other.hypergraph);
let n = self.hypergraph.nodes.len();
let sources = self
.sources
.iter()
.cloned()
.chain(other.sources.iter().map(|&i| NodeId(i.0 + n)))
.collect();
let targets = self
.targets
.iter()
.cloned()
.chain(other.targets.iter().map(|&i| NodeId(i.0 + n)))
.collect();
OpenHypergraph {
sources,
targets,
hypergraph,
}
}
}
impl<O: Clone + PartialEq, A: Clone> OpenHypergraph<O, A> {
pub fn quotient(&mut self) -> Result<FiniteFunction, FiniteFunction> {
let q = self.hypergraph.quotient()?;
self.sources
.iter_mut()
.for_each(|x| *x = NodeId(q.table[x.0]));
self.targets
.iter_mut()
.for_each(|x| *x = NodeId(q.table[x.0]));
Ok(q)
}
#[deprecated(since = "0.2.10", note = "use OpenHypergraph::quotient")]
pub fn quotient_witness(&mut self) -> Result<FiniteFunction, FiniteFunction> {
self.quotient()
}
pub fn to_strict(mut self) -> crate::strict::OpenHypergraph<VecKind, O, A> {
use crate::array::vec::VecArray;
use crate::finite_function::FiniteFunction;
use crate::strict::open_hypergraph::OpenHypergraph;
self.quotient().unwrap();
let target = self.hypergraph.nodes.len();
let s = {
let table = self.sources.iter().map(|x| x.0).collect();
FiniteFunction::new(VecArray(table), target).expect("Valid by construction")
};
let t = {
let table = self.targets.iter().map(|x| x.0).collect();
FiniteFunction::new(VecArray(table), target).expect("Valid by construction")
};
let h = self.hypergraph.to_hypergraph();
OpenHypergraph::new(s, t, h).expect("any valid lax::Hypergraph must be quotientable!")
}
#[deprecated(since = "0.2.4", note = "renamed to_strict")]
pub fn to_open_hypergraph(self) -> crate::strict::OpenHypergraph<VecKind, O, A> {
self.to_strict()
}
}