1use crate::array::vec::{VecArray, VecKind};
2use crate::finite_function::*;
3
4use core::fmt::Debug;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8pub struct NodeId(pub usize);
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12pub struct EdgeId(pub usize);
13
14#[derive(Debug, Clone, PartialEq)]
15#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
16pub struct Hyperedge {
17 pub sources: Vec<NodeId>,
18 pub targets: Vec<NodeId>,
19}
20
21impl<S, T> From<(S, T)> for Hyperedge
30where
31 S: Into<Vec<NodeId>>,
32 T: Into<Vec<NodeId>>,
33{
34 fn from((sources, targets): (S, T)) -> Self {
35 Hyperedge {
36 sources: sources.into(),
37 targets: targets.into(),
38 }
39 }
40}
41
42pub type Interface = (Vec<NodeId>, Vec<NodeId>);
43
44#[derive(Debug, Clone, PartialEq)]
49#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
50#[cfg_attr(
51 feature = "serde",
52 serde(
53 bound = "O: serde::Serialize + serde::de::DeserializeOwned, A: serde::Serialize + serde::de::DeserializeOwned"
54 )
55)]
56pub struct Hypergraph<O, A> {
57 pub nodes: Vec<O>,
59
60 pub edges: Vec<A>,
62
63 pub adjacency: Vec<Hyperedge>,
65
66 pub quotient: (Vec<NodeId>, Vec<NodeId>),
69}
70
71impl<O, A> Hypergraph<O, A> {
72 pub fn empty() -> Self {
74 Hypergraph {
75 nodes: vec![],
76 edges: vec![],
77 adjacency: vec![],
78 quotient: (vec![], vec![]),
79 }
80 }
81
82 pub fn is_strict(&self) -> bool {
84 self.quotient.0.is_empty()
85 }
86
87 pub fn from_strict(h: crate::strict::hypergraph::Hypergraph<VecKind, O, A>) -> Self {
88 let mut adjacency = Vec::with_capacity(h.x.0.len());
89 for (sources, targets) in h.s.into_iter().zip(h.t.into_iter()) {
90 adjacency.push(Hyperedge {
91 sources: sources.table.iter().map(|i| NodeId(*i)).collect(),
92 targets: targets.table.iter().map(|i| NodeId(*i)).collect(),
93 })
94 }
95
96 Hypergraph {
97 nodes: h.w.0 .0,
98 edges: h.x.0 .0,
99 adjacency,
100 quotient: (vec![], vec![]),
101 }
102 }
103
104 pub fn discrete(nodes: Vec<O>) -> Self {
105 let mut h = Self::empty();
106 h.nodes = nodes;
107 h
108 }
109
110 pub fn new_node(&mut self, w: O) -> NodeId {
112 let index = self.nodes.len();
113 self.nodes.push(w);
114 NodeId(index)
115 }
116
117 pub fn new_edge(&mut self, x: A, interface: impl Into<Hyperedge>) -> EdgeId {
121 let edge_idx = self.edges.len();
122 self.edges.push(x);
123 self.adjacency.push(interface.into());
124 EdgeId(edge_idx)
125 }
126
127 pub fn new_operation(
135 &mut self,
136 x: A,
137 source_type: Vec<O>,
138 target_type: Vec<O>,
139 ) -> (EdgeId, Interface) {
140 let sources: Vec<NodeId> = source_type.into_iter().map(|t| self.new_node(t)).collect();
141 let targets: Vec<NodeId> = target_type.into_iter().map(|t| self.new_node(t)).collect();
142 let interface = (sources.clone(), targets.clone());
143 let edge_id = self.new_edge(x, Hyperedge { sources, targets });
144 (edge_id, interface)
145 }
146
147 pub fn unify(&mut self, v: NodeId, w: NodeId) {
154 self.quotient.0.push(v);
156 self.quotient.1.push(w);
157 }
158
159 pub fn add_edge_source(&mut self, edge_id: EdgeId, w: O) -> NodeId {
161 let node_id = self.new_node(w);
162 self.adjacency[edge_id.0].sources.push(node_id);
163 node_id
164 }
165
166 pub fn add_edge_target(&mut self, edge_id: EdgeId, w: O) -> NodeId {
168 let node_id = self.new_node(w);
169 self.adjacency[edge_id.0].targets.push(node_id);
170 node_id
171 }
172
173 pub fn with_nodes<T, F: FnOnce(Vec<O>) -> Vec<T>>(self, f: F) -> Option<Hypergraph<T, A>> {
176 let n = self.nodes.len();
177 let nodes = f(self.nodes);
178 if nodes.len() != n {
179 return None;
180 }
181
182 Some(Hypergraph {
183 nodes,
184 edges: self.edges,
185 adjacency: self.adjacency,
186 quotient: self.quotient,
187 })
188 }
189
190 pub fn map_nodes<F: Fn(O) -> T, T>(self, f: F) -> Hypergraph<T, A> {
192 self.with_nodes(|nodes| nodes.into_iter().map(f).collect())
194 .unwrap()
195 }
196
197 pub fn with_edges<T, F: FnOnce(Vec<A>) -> Vec<T>>(self, f: F) -> Option<Hypergraph<O, T>> {
200 let n = self.edges.len();
201 let edges = f(self.edges);
202 if edges.len() != n {
203 return None;
204 }
205
206 Some(Hypergraph {
207 nodes: self.nodes,
208 edges,
209 adjacency: self.adjacency,
210 quotient: self.quotient,
211 })
212 }
213
214 pub fn map_edges<F: Fn(A) -> T, T>(self, f: F) -> Hypergraph<O, T> {
216 self.with_edges(|edges| edges.into_iter().map(f).collect())
218 .unwrap()
219 }
220
221 pub fn delete_edges(&mut self, edge_ids: &[EdgeId]) {
225 let edge_count = self.edges.len();
226 assert_eq!(
227 edge_count,
228 self.adjacency.len(),
229 "malformed hypergraph: edges and adjacency lengths differ"
230 );
231
232 if edge_ids.is_empty() {
233 return;
234 }
235
236 let mut remove = vec![false; edge_count];
237 let mut any_removed = false;
238 let mut remove_count = 0usize;
239 for edge_id in edge_ids {
240 assert!(
241 edge_id.0 < edge_count,
242 "edge id {:?} is out of bounds",
243 edge_id
244 );
245 if !remove[edge_id.0] {
246 remove[edge_id.0] = true;
247 any_removed = true;
248 remove_count += 1;
249 }
250 }
251
252 if !any_removed {
253 return;
254 }
255
256 let mut edges = Vec::with_capacity(edge_count - remove_count);
257 let mut adjacency = Vec::with_capacity(edge_count - remove_count);
258 for (i, (edge, adj)) in self
259 .edges
260 .drain(..)
261 .zip(self.adjacency.drain(..))
262 .enumerate()
263 {
264 if !remove[i] {
265 edges.push(edge);
266 adjacency.push(adj);
267 }
268 }
269
270 self.edges = edges;
271 self.adjacency = adjacency;
272 }
273
274 #[deprecated(since = "0.2.10", note = "renamed delete_edges")]
276 pub fn delete_edge(&mut self, edge_ids: &[EdgeId]) {
277 self.delete_edges(edge_ids)
278 }
279
280 pub fn delete_nodes_witness(&mut self, node_ids: &[NodeId]) -> Vec<Option<usize>> {
285 if node_ids.is_empty() {
286 return (0..self.nodes.len()).map(Some).collect();
287 }
288
289 let node_count = self.nodes.len();
290 let mut remove = vec![false; node_count];
291 let mut any_removed = false;
292 let mut remove_count = 0usize;
293 for node_id in node_ids {
294 assert!(
295 node_id.0 < node_count,
296 "node id {:?} is out of bounds",
297 node_id
298 );
299 if !remove[node_id.0] {
300 remove[node_id.0] = true;
301 any_removed = true;
302 remove_count += 1;
303 }
304 }
305
306 if !any_removed {
307 return (0..node_count).map(Some).collect();
308 }
309
310 let mut new_index = vec![None; node_count];
311 let mut nodes = Vec::with_capacity(node_count - remove_count);
312 for (i, node) in self.nodes.drain(..).enumerate() {
313 if !remove[i] {
314 let next = nodes.len();
315 new_index[i] = Some(next);
316 nodes.push(node);
317 }
318 }
319 self.nodes = nodes;
320
321 for edge in &mut self.adjacency {
322 edge.sources = edge
323 .sources
324 .iter()
325 .filter_map(|node| new_index[node.0].map(NodeId))
326 .collect();
327 edge.targets = edge
328 .targets
329 .iter()
330 .filter_map(|node| new_index[node.0].map(NodeId))
331 .collect();
332 }
333
334 let mut quotient_left = Vec::with_capacity(self.quotient.0.len());
335 let mut quotient_right = Vec::with_capacity(self.quotient.1.len());
336 for (v, w) in self.quotient.0.iter().zip(self.quotient.1.iter()) {
337 if let (Some(v_new), Some(w_new)) = (new_index[v.0], new_index[w.0]) {
338 quotient_left.push(NodeId(v_new));
339 quotient_right.push(NodeId(w_new));
340 }
341 }
342 self.quotient = (quotient_left, quotient_right);
343
344 new_index
345 }
346
347 pub fn delete_nodes(&mut self, node_ids: &[NodeId]) {
351 self.delete_nodes_witness(node_ids);
352 }
353}
354
355impl<O: Clone + PartialEq, A: Clone> Hypergraph<O, A> {
356 pub fn quotient(&mut self) -> Result<FiniteFunction<VecKind>, FiniteFunction<VecKind>> {
361 use std::mem::take;
362 let q = self.coequalizer();
363
364 self.nodes = match coequalizer_universal(&q, &VecArray(take(&mut self.nodes))) {
365 Some(nodes) => nodes.0,
366 None => return Err(q),
367 };
368
369 for e in &mut self.adjacency {
371 e.sources.iter_mut().for_each(|x| *x = NodeId(q.table[x.0]));
372 e.targets.iter_mut().for_each(|x| *x = NodeId(q.table[x.0]));
373 }
374
375 self.quotient = (vec![], vec![]); Ok(q)
378 }
379}
380
381impl<O: Clone, A: Clone> Hypergraph<O, A> {
382 pub fn to_hypergraph(&self) -> crate::strict::Hypergraph<VecKind, O, A> {
383 make_hypergraph(self)
384 }
385
386 pub fn coequalizer(&self) -> FiniteFunction<VecKind> {
387 let s: FiniteFunction<VecKind> = FiniteFunction {
389 table: VecArray(self.quotient.0.iter().map(|x| x.0).collect()),
390 target: self.nodes.len(),
391 };
392
393 let t: FiniteFunction<VecKind> = FiniteFunction {
394 table: VecArray(self.quotient.1.iter().map(|x| x.0).collect()),
395 target: self.nodes.len(),
396 };
397
398 s.coequalizer(&t)
399 .expect("coequalizer must exist for any graph")
400 }
401}
402
403pub(crate) fn finite_function_coproduct(
404 v1: &[NodeId],
405 v2: &[NodeId],
406 target: usize,
407) -> Vec<NodeId> {
408 v1.iter()
409 .cloned()
410 .chain(v2.iter().map(|&s| NodeId(s.0 + target)))
411 .collect()
412}
413
414pub(crate) fn concat<T: Clone>(v1: &[T], v2: &[T]) -> Vec<T> {
415 v1.iter().cloned().chain(v2.iter().cloned()).collect()
416}
417
418impl<O: Clone, A: Clone> Hypergraph<O, A> {
419 pub(crate) fn coproduct(&self, other: &Hypergraph<O, A>) -> Hypergraph<O, A> {
420 let n = self.nodes.len();
421
422 let adjacency = self
423 .adjacency
424 .iter()
425 .cloned()
426 .chain(other.adjacency.iter().map(|edge| Hyperedge {
427 sources: edge.sources.iter().map(|&s| NodeId(s.0 + n)).collect(),
428 targets: edge.targets.iter().map(|&t| NodeId(t.0 + n)).collect(),
429 }))
430 .collect();
431
432 let quotient = (
433 finite_function_coproduct(&self.quotient.0, &other.quotient.0, n),
434 finite_function_coproduct(&self.quotient.1, &other.quotient.1, n),
435 );
436
437 Hypergraph {
438 nodes: concat(&self.nodes, &other.nodes),
439 edges: concat(&self.edges, &other.edges),
440 adjacency,
441 quotient,
442 }
443 }
444}
445
446fn make_hypergraph<O: Clone, A: Clone>(
448 h: &Hypergraph<O, A>,
449) -> crate::strict::hypergraph::Hypergraph<VecKind, O, A> {
450 use crate::finite_function::*;
451 use crate::indexed_coproduct::*;
452 use crate::semifinite::*;
453
454 let s = {
455 let mut lengths = Vec::<usize>::with_capacity(h.edges.len());
456 let mut values = Vec::<usize>::new();
457 for e in h.adjacency.iter() {
458 lengths.push(e.sources.len());
459 values.extend(e.sources.iter().map(|x| x.0));
460 }
461
462 let sources = SemifiniteFunction(VecArray(lengths));
463 let values =
464 FiniteFunction::new(VecArray(values), h.nodes.len()).expect("invalid lax::Hypergraph!");
465 IndexedCoproduct::from_semifinite(sources, values).expect("valid IndexedCoproduct")
466 };
467
468 let t = {
469 let mut lengths = Vec::<usize>::with_capacity(h.edges.len());
470 let mut values = Vec::<usize>::new();
471 for e in h.adjacency.iter() {
472 lengths.push(e.targets.len());
473 values.extend(e.targets.iter().map(|x| x.0));
474 }
475
476 let sources = SemifiniteFunction(VecArray(lengths));
477 let values =
478 FiniteFunction::new(VecArray(values), h.nodes.len()).expect("invalid lax::Hypergraph!");
479 IndexedCoproduct::from_semifinite(sources, values).expect("valid IndexedCoproduct")
480 };
481
482 let w = SemifiniteFunction(VecArray(h.nodes.clone()));
483 let x = SemifiniteFunction(VecArray(h.edges.clone()));
484
485 crate::strict::hypergraph::Hypergraph { s, t, w, x }
486}