//! `nerve` — el grafo de qué réplicas comparten datos con cuáles (§6.2). //! //! Vértices = réplicas, aristas = pares que comparten un dato. use petgraph::graph::{NodeIndex, UnGraph}; /// Identificador de una réplica (vértice del nervio). #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct ReplicaId(pub usize); /// Qué coordenadas del estado se comparten en una arista. /// /// M0: forma únicamente; el detalle de la proyección se fija en `sheaf` (T1/T2). #[derive(Debug, Clone, Default, PartialEq)] pub struct SharedLink { /// Índices de las coordenadas compartidas en esta arista. pub shared_coords: Vec, } /// El nervio: grafo no dirigido de réplicas y sus enlaces compartidos. #[derive(Debug, Default, Clone)] pub struct Nerve { /// Grafo no dirigido: vértices = réplicas, aristas = pares que comparten datos. pub graph: UnGraph, } impl Nerve { /// Nervio vacío. pub fn new() -> Self { Self { graph: UnGraph::new_undirected(), } } /// Construye el nervio de `num_vertices` réplicas y una lista de aristas. /// Los índices de nodo coinciden con los `ReplicaId` (0..num_vertices). pub fn from_edges(num_vertices: usize, edges: &[(usize, usize)]) -> Self { let mut graph = UnGraph::new_undirected(); let nodes: Vec = (0..num_vertices).map(|i| graph.add_node(ReplicaId(i))).collect(); for &(a, b) in edges { graph.add_edge(nodes[a], nodes[b], SharedLink::default()); } Self { graph } } /// Número de réplicas (vértices). pub fn num_replicas(&self) -> usize { self.graph.node_count() } /// Las aristas como pares `(u, v)` de índices de réplica. pub fn edges(&self) -> Vec<(usize, usize)> { self.graph .edge_indices() .filter_map(|e| self.graph.edge_endpoints(e)) .map(|(a, b)| (a.index(), b.index())) .collect() } /// Vecinas de la réplica `v` en el nervio. pub fn neighbors(&self, v: usize) -> Vec { self.graph .neighbors(NodeIndex::new(v)) .map(|n| n.index()) .collect() } }