Skip to main content

hypergraphx/core/directed/
uniform.rs

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/// The graph's edge type.
15#[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; // Update moved node's index
127                            }
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; // Update moved node's index
136                            }
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; // Update moved node's index
171                            }
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; // Update moved node's index
181                            }
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            // Remove this edge from the nodes it connects
204            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; // Update moved edge's index
226                            }
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; // Update moved edge's index
236                            }
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                // Remove this edge from the nodes it connects
253                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; // Update moved edge's index
276                            }
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; // Update moved edge's index
286                            }
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; // Return None if the node index is out of bounds
309        }
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; // Return None if the node index is out of bounds
329        }
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; // Return None if the node index is out of bounds
349        }
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; // Return None if the node index is out of bounds
355        }
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; // Skip edges that do not match the ORDER
423            }
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 mut subgraph = Self::new();
441        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                // Successor has not been visited yet
499                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                // Successor is on the stack
505                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            // Found a strongly connected component
513            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
536/* impl<'a, N: 'a, E: 'a, const ORDER: usize> MatrixRepresentation<'a>
537    for UniformHypergraph<N, E, ORDER>
538where
539    N: Clone + Eq + Hash + Debug,
540    E: Clone + Eq + Hash + Debug,
541{
542    fn binary_incidence_matrix(&self) -> CsMatrix<i8> {
543        let mut irows = Vec::new();
544        let mut icols = Vec::new();
545        let mut vals = Vec::new();
546
547        for (edge_index, edge) in self.edges.iter().enumerate() {
548            for &node_index in &edge.source {
549                irows.push(node_index);
550                icols.push(edge_index);
551                vals.push(1);
552            }
553            for &node_index in &edge.target {
554                irows.push(node_index);
555                icols.push(edge_index);
556                vals.push(-1);
557            }
558        }
559
560        let matrix =
561            CsMatrix::from_triplet(self.nodes.len(), self.edges.len(), &irows, &icols, &vals);
562        matrix
563    }
564    fn adjacency_matrix(&self) -> DMatrix<usize> {
565        let l = self.nodes.len();
566        let mut mat = DMatrix::<usize>::zeros(l, l);
567
568        for (node_index, _) in self.nodes.iter().enumerate() {
569            let n = self.get_out_neighbours(node_index).unwrap();
570            for &neighbour in n {
571                mat[(node_index, neighbour)] += 1;
572            }
573        }
574
575        mat.into()
576    }
577
578    fn dual_adjacency_matrix(&self) -> DMatrix<usize> {
579        let l = self.node_count();
580        let mut mat = DMatrix::<usize>::zeros(l, l);
581
582        for (node_index, _) in self.nodes().enumerate() {
583            let n = self.get_out_neighbours(node_index).unwrap();
584            for &neighbour in n {
585                mat[(neighbour, node_index)] += 1;
586            }
587        }
588
589        mat
590    }
591
592    fn laplacian_matrix(&'a self) -> DMatrix<usize> {
593        let dseq = Matrix::<usize, Dyn, Const<1>, _>::from(self.out_degree_sequence());
594        let out = DMatrix::<usize>::from_diagonal(&dseq);
595
596        return out - self.adjacency_matrix();
597    }
598}
599 */
600impl<'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                // .filter_map(|&n| self.nodes.get(n).map(|node| (n, node)))
610                .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                // .filter_map(|&n| self.nodes.get(n).map(|node| (n, node)))
619                .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                // .filter_map(|&e| self.edges.get(e).map(|edge| (e, edge)))
629                .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                // .filter_map(|&e| self.edges.get(e).map(|edge| (e, edge)))
639                .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; // Return None if the node index is out of bounds
685        }
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; // Return None if the node index is out of bounds
730        }
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        // out
759        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}