1use hashbrown::{HashMap, HashSet};
2use itertools::Itertools;
3use std::{fmt::Debug, hash::Hash};
4
5use crate::{
6 HypergraphErrors, HypergraphResult,
7 core::{DiGraph, directed::TarjanState},
8 impl_graph_basics, impl_weights,
9 traits::*,
10};
11
12use super::Node;
13
14#[derive(Debug, Clone, PartialEq, Eq, Hash)]
16pub struct UniformEdge<E, const ORDER: usize> {
17 pub weight: E,
18 pub(crate) source: [usize; ORDER],
19 pub(crate) target: [usize; ORDER],
20}
21
22impl<E, const ORDER: usize> UniformEdge<E, ORDER> {
23 pub fn connects(&self, a: usize, b: usize) -> bool {
24 self.source.contains(&a) && self.target.contains(&b)
25 }
26}
27
28#[derive(Debug, Clone)]
29pub struct UniformHypergraph<N, E, const ORDER: usize> {
30 pub(crate) nodes: Vec<Node<N>>,
31 pub(crate) edges: Vec<UniformEdge<E, ORDER>>,
32}
33
34impl<N, E, const ORDER: usize> UniformHypergraph<N, E, ORDER> {
35 pub fn new() -> Self {
36 Self {
37 nodes: Vec::new(),
38 edges: Vec::new(),
39 }
40 }
41
42 pub fn add_node(&mut self, weight: N) -> usize {
43 self.nodes.push(Node {
44 weight,
45 in_edges: Vec::new(),
46 out_edges: Vec::new(),
47 });
48 self.nodes.len() - 1
49 }
50
51 pub fn add_edge(
52 &mut self,
53 weight: E,
54 source_indices: [usize; ORDER],
55 target_indices: [usize; ORDER],
56 ) -> Result<usize, HypergraphErrors> {
57 if source_indices.iter().any(|&n| n >= self.nodes.len())
58 || target_indices.iter().any(|&n| n >= self.nodes.len())
59 {
60 return Err(HypergraphErrors::Nonexistent);
61 }
62 let edge = UniformEdge {
63 weight,
64 source: source_indices.clone(),
65 target: target_indices.clone(),
66 };
67 self.edges.push(edge);
68 let edge_index = self.edges.len() - 1;
69
70 for &node_index in &self.edges[edge_index].source {
71 if let Some(node) = self.nodes.get_mut(node_index) {
72 node.out_edges.push(edge_index);
73 }
74 }
75
76 for &node_index in &self.edges[edge_index].target {
77 if let Some(node) = self.nodes.get_mut(node_index) {
78 node.in_edges.push(edge_index);
79 }
80 }
81
82 Ok(edge_index)
83 }
84
85 pub fn add_nodes(&mut self, weights: impl Iterator<Item = N>) {
86 self.nodes.extend(weights.map(|w| Node {
87 weight: w,
88 in_edges: Vec::new(),
89 out_edges: Vec::new(),
90 }));
91 }
92
93 pub fn add_edges(
94 &mut self,
95 edges: impl Iterator<Item = (E, [usize; ORDER], [usize; ORDER])>,
96 ) -> HypergraphResult<()> {
97 for (weight, source, target) in edges {
98 self.add_edge(weight, source, target)?;
99 }
100
101 Ok(())
102 }
103
104 pub fn remove_node(&mut self, node_index: usize) -> HypergraphResult<Node<N>> {
105 if node_index < self.nodes.len() {
106 let removed_node = &self.nodes[node_index];
107 let mut out_edges = removed_node
108 .out_edges
109 .iter()
110 .chain(removed_node.in_edges.iter())
111 .cloned()
112 .collect::<Vec<_>>();
113
114 out_edges.sort_unstable();
115 out_edges.dedup();
116 self.remove_edges(out_edges);
117 let removed_node = self.nodes.swap_remove(node_index);
118
119 let l = self.nodes.len();
120 if l > node_index {
121 let moved_node = &mut self.nodes[node_index];
122 for &edge_index in moved_node.out_edges.iter() {
123 if let Some(edge) = self.edges.get_mut(edge_index) {
124 edge.source.iter_mut().for_each(|n| {
125 if *n == l {
126 *n = node_index; }
128 });
129 }
130 }
131 for &edge_index in moved_node.in_edges.iter() {
132 if let Some(edge) = self.edges.get_mut(edge_index) {
133 edge.target.iter_mut().for_each(|n| {
134 if *n == l {
135 *n = node_index; }
137 });
138 }
139 }
140 }
141 Ok(removed_node)
142 } else {
143 Err(HypergraphErrors::Nonexistent)
144 }
145 }
146
147 pub fn remove_nodes(&mut self, node_indices: Vec<usize>) -> Vec<Node<N>> {
148 for &node_index in node_indices.iter() {
149 let removed_node = &self.nodes[node_index];
150 let mut out_edges = removed_node
151 .out_edges
152 .iter()
153 .chain(removed_node.in_edges.iter())
154 .cloned()
155 .collect::<Vec<_>>();
156
157 out_edges.sort_unstable();
158 out_edges.dedup();
159 self.remove_edges(out_edges);
160 }
161
162 for (count, &node_index) in node_indices.iter().enumerate() {
163 let l = self.nodes.len() - count - 1;
164 if l > node_index {
165 let moved_node = &mut self.nodes[l];
166 for &edge_index in moved_node.in_edges.iter() {
167 if let Some(edge) = self.edges.get_mut(edge_index) {
168 edge.target.iter_mut().for_each(|n| {
169 if *n == l {
170 *n = node_index; }
172 });
173 }
174 }
175
176 for &edge_index in moved_node.out_edges.iter() {
177 if let Some(edge) = self.edges.get_mut(edge_index) {
178 edge.source.iter_mut().for_each(|n| {
179 if *n == l {
180 *n = node_index; }
182 });
183 }
184 }
185 }
186 }
187
188 node_indices
189 .into_iter()
190 .filter_map(|node_index| {
191 if node_index < self.nodes.len() {
192 Some(self.nodes.swap_remove(node_index))
193 } else {
194 None
195 }
196 })
197 .collect()
198 }
199
200 pub fn remove_edge(&mut self, edge_index: usize) -> Option<UniformEdge<E, ORDER>> {
201 if edge_index < self.edges.len() {
202 let removed_edge = &self.edges[edge_index];
203 for &node_index in &removed_edge.source {
205 if let Some(node) = self.nodes.get_mut(node_index) {
206 node.out_edges.retain(|&e| e != edge_index);
207 }
208 }
209
210 for &node_index in &removed_edge.target {
211 if let Some(node) = self.nodes.get_mut(node_index) {
212 node.in_edges.retain(|&e| e != edge_index);
213 }
214 }
215
216 let removed_edge = self.edges.swap_remove(edge_index);
217
218 let l = self.edges.len();
219 if l > edge_index {
220 let moved_edge = &mut self.edges[edge_index];
221 for &node_index in moved_edge.source.iter() {
222 if let Some(node) = self.nodes.get_mut(node_index) {
223 node.out_edges.iter_mut().for_each(|e| {
224 if *e == l {
225 *e = edge_index; }
227 });
228 }
229 }
230
231 for &node_index in moved_edge.target.iter() {
232 if let Some(node) = self.nodes.get_mut(node_index) {
233 node.in_edges.iter_mut().for_each(|e| {
234 if *e == l {
235 *e = edge_index; }
237 });
238 }
239 }
240 }
241
242 Some(removed_edge)
243 } else {
244 None
245 }
246 }
247
248 pub fn remove_edges(&mut self, edge_indices: Vec<usize>) -> Vec<UniformEdge<E, ORDER>> {
249 for &edge_index in edge_indices.iter() {
250 if edge_index < self.edges.len() {
251 let removed_edge = &self.edges[edge_index];
252 for &node_index in &removed_edge.source {
254 if let Some(node) = self.nodes.get_mut(node_index) {
255 node.out_edges.retain(|&e| e != edge_index);
256 }
257 }
258
259 for &node_index in &removed_edge.target {
260 if let Some(node) = self.nodes.get_mut(node_index) {
261 node.in_edges.retain(|&e| e != edge_index);
262 }
263 }
264 }
265 }
266
267 for (count, &edge_index) in edge_indices.iter().rev().enumerate() {
268 let l = self.edges.len() - count - 1;
269 if l > edge_index {
270 let moved_edge = &mut self.edges[l];
271 for &node_index in moved_edge.source.iter() {
272 if let Some(node) = self.nodes.get_mut(node_index) {
273 node.out_edges.iter_mut().for_each(|e| {
274 if *e == l {
275 *e = edge_index; }
277 });
278 }
279 }
280
281 for &node_index in moved_edge.target.iter() {
282 if let Some(node) = self.nodes.get_mut(node_index) {
283 node.in_edges.iter_mut().for_each(|e| {
284 if *e == l {
285 *e = edge_index; }
287 });
288 }
289 }
290 }
291 }
292
293 edge_indices
294 .into_iter()
295 .rev()
296 .filter_map(|edge_index| {
297 if edge_index < self.edges.len() {
298 Some(self.edges.swap_remove(edge_index))
299 } else {
300 None
301 }
302 })
303 .collect()
304 }
305
306 pub fn get_in_neighbours(&self, node_index: usize) -> Option<HashSet<&usize>> {
307 if node_index >= self.nodes.len() {
308 return None; }
310 let mut out = self.nodes[node_index]
311 .in_edges
312 .iter()
313 .flat_map(|e| {
314 if let Some(edge) = self.edges.get(*e) {
315 edge.source.iter().collect::<Vec<_>>()
316 } else {
317 std::iter::empty().collect()
318 }
319 })
320 .collect::<HashSet<_>>();
321
322 out.remove(&node_index);
323 Some(out)
324 }
325
326 pub fn get_out_neighbours(&self, node_index: usize) -> Option<HashSet<&usize>> {
327 if node_index >= self.nodes.len() {
328 return None; }
330 let mut out = self.nodes[node_index]
331 .out_edges
332 .iter()
333 .flat_map(|e| {
334 if let Some(edge) = self.edges.get(*e) {
335 edge.target.iter().collect::<Vec<_>>()
336 } else {
337 std::iter::empty().collect()
338 }
339 })
340 .collect::<HashSet<_>>();
341
342 out.remove(&node_index);
343 Some(out)
344 }
345
346 pub fn get_in_edges(&self, node_index: usize) -> Option<&Vec<usize>> {
347 if node_index >= self.nodes.len() {
348 return None; }
350 Some(&self.nodes[node_index].in_edges)
351 }
352 pub fn get_out_edges(&self, node_index: usize) -> Option<&Vec<usize>> {
353 if node_index >= self.nodes.len() {
354 return None; }
356 Some(&self.nodes[node_index].out_edges)
357 }
358
359 pub fn induced_shgraph(&self, node_indices: &[usize]) -> Self
360 where
361 E: Clone,
362 N: Clone,
363 {
364 let mut subgraph = Self::new();
365 let mut node_map = vec![None; self.nodes.len()];
366
367 let mut new_nodes = vec![];
368
369 for &node_index in node_indices {
370 if let Some(node) = self.nodes.get(node_index) {
371 let new_index = new_nodes.len();
372 new_nodes.push(node.clone());
373 node_map[node_index] = Some(new_index);
374 }
375 }
376
377 let mut u = new_nodes
378 .iter()
379 .flat_map(|n| {
380 n.in_edges
381 .iter()
382 .chain(n.out_edges.iter())
383 .map(|x| (*x, &self.edges[*x]))
384 })
385 .collect::<Vec<_>>();
386 u.retain(|(_i, e)| {
387 !e.source.is_empty()
388 && e.source.iter().all(|&n| node_map[n].is_some())
389 && !e.target.is_empty()
390 && e.target.iter().all(|&n| node_map[n].is_some())
391 });
392
393 let edge_map = u
394 .iter()
395 .enumerate()
396 .map(|(i, (j, _))| (*j, i))
397 .collect::<HashMap<_, _>>();
398
399 for node in new_nodes.iter_mut() {
400 node.in_edges = node
401 .in_edges
402 .iter()
403 .filter_map(|&e| edge_map.get(&e))
404 .cloned()
405 .collect();
406
407 node.out_edges = node
408 .out_edges
409 .iter()
410 .filter_map(|&e| edge_map.get(&e))
411 .cloned()
412 .collect();
413 }
414
415 subgraph.nodes = new_nodes;
416
417 for (_, edge) in &u {
418 let new_source: Vec<usize> = edge.source.iter().filter_map(|&n| node_map[n]).collect();
419 let new_target: Vec<usize> = edge.target.iter().filter_map(|&n| node_map[n]).collect();
420
421 if new_source.len() != ORDER || new_target.len() != ORDER {
422 continue; }
424
425 let new_source: [usize; ORDER] = new_source.try_into().unwrap();
426 let new_target: [usize; ORDER] = new_target.try_into().unwrap();
427 subgraph
428 .add_edge(edge.weight.clone(), new_source, new_target)
429 .unwrap();
430 }
431
432 subgraph
433 }
434
435 pub fn shgraph_by_order(&self, order: usize) -> Self
436 where
437 E: Clone,
438 N: Clone,
439 {
440 let new_edges = self
442 .edges
443 .iter()
444 .filter(|e| e.source.len() <= order && e.target.len() <= order)
445 .cloned()
446 .collect::<Vec<_>>();
447
448 let new_nodes = new_edges
449 .iter()
450 .flat_map(|e| e.source.iter().chain(e.target.iter()))
451 .cloned()
452 .collect::<Vec<_>>();
453
454 let mut subgraph = self.induced_shgraph(&new_nodes);
455
456 let v = subgraph
457 .edges
458 .iter()
459 .enumerate()
460 .filter(|(_, e)| e.source.len() > order || e.target.len() > order)
461 .map(|(i, _)| i)
462 .collect::<Vec<_>>();
463
464 subgraph.remove_edges(v);
465
466 subgraph
467 }
468
469 fn tarjan_inner(
470 &self,
471 curr_idx: &mut usize,
472 curr: usize,
473 aux: &mut Vec<TarjanState>,
474 stack: &mut Vec<usize>,
475 components: &mut Vec<Vec<usize>>,
476 ) where
477 E: Clone + Eq + Hash + Debug,
478 N: Clone + Eq + Hash + Debug,
479 {
480 let neighbours = {
481 let state = &mut aux[curr];
482
483 state.index = Some(*curr_idx);
484 state.lowlink = Some(*curr_idx);
485 *curr_idx += 1;
486 state.on_stack = true;
487
488 let neighbours = self.get_out_neighbours(curr);
489
490 stack.push(curr);
491 neighbours
492 }
493 .unwrap();
494
495 for n in neighbours {
496 let nb = aux[*n];
497 if nb.index.is_none() {
498 self.tarjan_inner(curr_idx, *n, aux, stack, components);
500 let nb = aux[*n];
501 let state = &mut aux[curr];
502 state.lowlink = Some(state.lowlink.unwrap().min(nb.lowlink.unwrap()));
503 } else if nb.on_stack {
504 let state = &mut aux[curr];
506 state.lowlink = Some(state.lowlink.unwrap().min(nb.index.unwrap()));
507 }
508 }
509
510 let state = aux[curr];
511 if state.lowlink == state.index {
512 let mut component = Vec::new();
514 while let Some(node_index) = stack.pop() {
515 let node_state = &mut aux[node_index];
516 node_state.on_stack = false;
517 component.push(node_index);
518 if node_index == curr {
519 break;
520 }
521 }
522
523 components.push(component);
524 }
525 }
526}
527
528impl_graph_basics!(
529 UniformHypergraph<N, E, ORDER>,
530 &'a Node<N>,
531 &'a UniformEdge<E, ORDER>,
532 false,
533 |const ORDER: usize|
534);
535
536impl<'a, N: 'a, E: 'a, const ORDER: usize> DiGraphProperties<'a> for UniformHypergraph<N, E, ORDER>
601where
602 N: Clone + Eq + Hash + Debug,
603 E: Clone + Eq + Hash + Debug,
604{
605 fn in_neighbours(&self, node_index: usize) -> Option<hashbrown::HashSet<usize>> {
606 Some(
607 self.get_in_neighbours(node_index)?
608 .into_iter()
609 .map(|&n| n)
611 .collect(),
612 )
613 }
614 fn out_neighbours(&self, node_index: usize) -> Option<hashbrown::HashSet<usize>> {
615 Some(
616 self.get_out_neighbours(node_index)?
617 .into_iter()
618 .map(|&n| n)
620 .collect(),
621 )
622 }
623
624 fn in_edges(&self, node_index: usize) -> Option<hashbrown::HashSet<usize>> {
625 Some(
626 self.get_in_edges(node_index)?
627 .iter()
628 .map(|&n| n)
630 .collect(),
631 )
632 }
633
634 fn out_edges(&self, node_index: usize) -> Option<hashbrown::HashSet<usize>> {
635 Some(
636 self.get_out_edges(node_index)?
637 .iter()
638 .map(|&n| n)
640 .collect(),
641 )
642 }
643
644 fn in_degree(&self, node_index: usize) -> Option<usize> {
645 self.nodes.get(node_index).map(|node| node.in_edges.len())
646 }
647
648 fn out_degree(&self, node_index: usize) -> Option<usize> {
649 self.nodes.get(node_index).map(|node| node.out_edges.len())
650 }
651
652 fn weakly_connected_components(&self) -> Vec<Vec<usize>> {
653 let mut visited = vec![false; self.nodes.len()];
654 let mut components = Vec::new();
655
656 for i in 0..self.nodes.len() {
657 if !visited[i] {
658 let mut component = Vec::new();
659 let mut stack = vec![i];
660
661 while let Some(node_index) = stack.pop() {
662 if !visited[node_index] {
663 visited[node_index] = true;
664 component.push(node_index);
665 stack.extend(
666 self.get_out_neighbours(node_index)
667 .unwrap()
668 .iter()
669 .chain(self.get_in_neighbours(node_index).unwrap().iter())
670 .cloned(),
671 );
672 }
673 }
674
675 components.push(component);
676 }
677 }
678
679 components
680 }
681
682 fn weak_component(&self, node_index: usize) -> Option<Vec<usize>> {
683 if node_index >= self.nodes.len() {
684 return None; }
686 let mut visited = vec![false; self.nodes.len()];
687 let mut component = Vec::new();
688 let mut stack = vec![node_index];
689
690 while let Some(node_index) = stack.pop() {
691 if !visited[node_index] {
692 visited[node_index] = true;
693 component.push(node_index);
694 stack.extend(
695 self.get_in_neighbours(node_index)
696 .unwrap()
697 .iter()
698 .chain(self.get_out_neighbours(node_index).unwrap().iter())
699 .cloned(),
700 );
701 }
702 }
703
704 Some(component)
705 }
706
707 type Subgraph = Self;
708
709 fn strongly_connected_components(&self) -> Vec<Vec<usize>> {
710 let mut idx = 0;
711 let mut aux = vec![TarjanState::default(); self.node_count()];
712
713 let mut stack = vec![];
714 let mut out = vec![];
715 for x in 0..aux.len() {
716 if aux[x].index.is_none() {
717 self.tarjan_inner(&mut idx, x, &mut aux, &mut stack, &mut out);
718 }
719 }
720 out
721 }
722
723 fn is_strongly_connected(&self) -> bool {
724 self.strongly_connected_components().len() == 1
725 }
726
727 fn strong_component(&self, node_index: usize) -> Option<Vec<usize>> {
728 if node_index >= self.node_count() {
729 return None; }
731 let mut idx = 0;
732 let mut aux = vec![TarjanState::default(); self.node_count()];
733
734 let mut stack = vec![];
735 let mut out = vec![];
736 self.tarjan_inner(&mut idx, node_index, &mut aux, &mut stack, &mut out);
737 out.pop()
738 }
739
740 fn extract_strong_component(&self, node_index: usize) -> Option<Self::Subgraph> {
741 let component = self.strong_component(node_index)?;
742 Some(self.induced_shgraph(&component))
743 }
744
745 fn condense(&self) -> DiGraph<(), ()> {
746 let mut idx = 0;
747 let mut aux = vec![TarjanState::default(); self.node_count()];
748
749 let mut stack = vec![];
750 let mut out = vec![];
751 let mut lens = vec![0];
752 for x in 0..aux.len() {
753 if aux[x].index.is_none() {
754 self.tarjan_inner(&mut idx, x, &mut aux, &mut stack, &mut out);
755 lens.push(out.len());
756 }
757 }
758 let mut dag = DiGraph::new();
760 dag.add_nodes(vec![(); out.len()].into_iter());
761 for (i, j) in lens.iter().tuple_windows() {
762 for (s, t) in (*j..*i).tuple_windows() {
763 dag.add_edge((), [s], [t]).unwrap();
764 }
765 }
766
767 dag
768 }
769
770 fn extract_weak_component(&self, node_index: usize) -> Option<Self::Subgraph> {
771 let component = self.weak_component(node_index)?;
772 Some(self.induced_shgraph(&component))
773 }
774
775 fn in_edge_count(&self, node_index: usize) -> Option<usize> {
776 self.nodes.get(node_index).map(|node| node.in_edges.len())
777 }
778
779 fn out_edge_count(&self, node_index: usize) -> Option<usize> {
780 self.nodes.get(node_index).map(|node| node.out_edges.len())
781 }
782
783 fn in_neighbour_count(&self, node_index: usize) -> Option<usize> {
784 self.nodes.get(node_index).map(|node| {
785 node.in_edges
786 .iter()
787 .map(|e| self.edges[*e].source.len())
788 .sum()
789 })
790 }
791
792 fn out_neighbour_count(&self, node_index: usize) -> Option<usize> {
793 self.nodes.get(node_index).map(|node| {
794 node.out_edges
795 .iter()
796 .map(|e| self.edges[*e].target.len())
797 .sum()
798 })
799 }
800
801 fn source(
802 &'a self,
803 edge_index: <Self as GraphBasics<'a>>::EdgeIndex,
804 ) -> Option<hashbrown::HashSet<usize>> {
805 let edge = self.edges.get(edge_index)?;
806 let sources = edge
807 .source
808 .iter()
809 .map(|&n| n)
810 .collect::<hashbrown::HashSet<_>>();
811 Some(sources)
812 }
813
814 fn target(
815 &self,
816 edge_index: <Self as GraphBasics<'a>>::EdgeIndex,
817 ) -> Option<hashbrown::HashSet<usize>> {
818 let edge = self.edges.get(edge_index)?;
819 let targets = edge
820 .target
821 .iter()
822 .map(|&n| n)
823 .collect::<hashbrown::HashSet<_>>();
824 Some(targets)
825 }
826}
827
828impl<'a, N, E, const ORDER: usize> HypergraphBasics<'a> for UniformHypergraph<N, E, ORDER>
829where
830 N: 'a + Clone + Eq + Hash,
831 E: 'a + Clone + Eq + Hash,
832{
833 fn uniform(&self) -> bool {
834 true
835 }
836
837 type DualType = super::Hypergraph<E, N>;
838
839 fn dual(&self) -> Self::DualType {
840 let mut out = super::Hypergraph::new();
841
842 out.nodes = self
843 .edges
844 .iter()
845 .map(|e| Node {
846 weight: e.weight.clone(),
847 in_edges: e.source.clone().to_vec(),
848 out_edges: e.target.clone().to_vec(),
849 })
850 .collect();
851
852 out.edges = self
853 .nodes
854 .iter()
855 .map(|n| super::Edge {
856 weight: n.weight.clone(),
857 source: n.in_edges.clone(),
858 target: n.out_edges.clone(),
859 })
860 .collect();
861 out
862 }
863}
864
865impl<'a, N: 'a, E: 'a, const ORDER: usize> DirectedHypergraphProperties<'a, N, E>
866 for UniformHypergraph<N, E, ORDER>
867where
868 N: Clone + Eq + Hash + Debug,
869 E: Clone + Eq + Hash + Debug,
870{
871 fn in_order(&self, edge_index: usize) -> Option<usize> {
872 self.edges.get(edge_index).map(|edge| edge.source.len())
873 }
874 fn out_order(&self, edge_index: usize) -> Option<usize> {
875 self.edges.get(edge_index).map(|edge| edge.target.len())
876 }
877
878 fn digraph_view(&self) -> DiGraph<&N, &E> {
879 let mut out = DiGraph::new();
880 out.add_nodes(self.nodes.iter().map(|n| &n.weight));
881 for e in &self.edges {
882 for u in e.source.iter() {
883 for v in e.target.iter() {
884 out.add_edge(&e.weight, [*u], [*v]).unwrap();
885 }
886 }
887 }
888
889 out
890 }
891}
892
893impl_weights!(UniformHypergraph<N, E, ORDER>, |const ORDER: usize|);
894
895impl<N, E, const ORDER: usize> TryFrom<super::Hypergraph<N, E>> for UniformHypergraph<N, E, ORDER> {
896 fn try_from(value: super::Hypergraph<N, E>) -> Result<Self, HypergraphErrors> {
897 let mut edges = vec![];
898 for x in value.edges {
899 if x.source.len() != ORDER || x.target.len() != ORDER {
900 return Err(HypergraphErrors::InvariantViolation {
901 err: "Edges don't have the right length".to_string(),
902 });
903 }
904 edges.push(UniformEdge {
905 weight: x.weight,
906 source: unsafe { x.source.as_chunks_unchecked::<ORDER>()[0] },
907 target: unsafe { x.target.as_chunks_unchecked()[0] },
908 });
909 }
910 Ok(Self {
911 nodes: value.nodes,
912 edges,
913 })
914 }
915
916 type Error = HypergraphErrors;
917}