tawasuyu/hifas
Motor en Rust para decidir, con demostración y no a ojo, cuándo un conjunto de réplicas local-first puede operar sin coordinación y cuándo no — y, cuando la respuesta es "sí, dentro de límites", proveer el mecanismo que lo garantiza.
M0/T0: scaffold del crate sheafsync
1//! `sheaf` — el haz celular y el ensamblado del coboundary `δ` (§6.3, §7).
2//!
3//! M0: forma de los tipos y firma de `coboundary`. El ensamblado real
4//! (bloque por arista, `+R_{u⊴e}` / `−R_{v⊴e}`) llega en T1.
5
6use crate::error::{Result, SheafError};
7use crate::linalg::Matrix;
8
9/// Mapa de restricción `F(v ⊴ e): F(v) → F(e)`: proyección lineal del estado
10/// de una réplica sobre el dato de una arista. Matriz `edge_dim × vertex_dim`.
11pub type RestrictionMap = Matrix;
12
13/// Un haz celular sobre el nervio.
14#[derive(Debug, Default)]
15pub struct Sheaf {
16 /// Para cada réplica: la dimensión de su stalk `F(v)`.
17 pub vertex_stalks: Vec<usize>,
18 /// Para cada arista: la dimensión de su stalk `F(e)`.
19 pub edge_stalks: Vec<usize>,
20 /// Mapas de restricción: por arista, dos matrices (una por extremo).
21 pub restrictions: Vec<(RestrictionMap, RestrictionMap)>,
22 /// Extremos `(u, v)` de cada arista, como índices en `vertex_stalks`.
23 pub edge_endpoints: Vec<(usize, usize)>,
24}
25
26impl Sheaf {
27 /// Dimensión de `C⁰ = ⊕_v F(v)` (espacio de cocadenas de vértice).
28 pub fn dim_c0(&self) -> usize {
29 self.vertex_stalks.iter().sum()
30 }
31
32 /// Dimensión de `C¹ = ⊕_e F(e)` (espacio de cocadenas de arista).
33 pub fn dim_c1(&self) -> usize {
34 self.edge_stalks.iter().sum()
35 }
36
37 /// Ensambla la matriz global de coboundary `δ: C⁰ → C¹`.
38 ///
39 /// Convención (§6.3): para arista `e=(u,v)`,
40 /// `(δx)_e = R_{u⊴e}·x_u − R_{v⊴e}·x_v`.
41 ///
42 /// M0: no implementado; llega en T1.
43 pub fn coboundary(&self) -> Result<Matrix> {
44 Err(SheafError::NotImplemented("Sheaf::coboundary llega en T1"))
45 }
46}