atlas_embeddings/foundations/
primitives.rs

1//! # Chapter 0.1: Primitive Concepts
2//!
3//! We begin by defining the most basic mathematical objects needed for our construction.
4//! No prior knowledge is assumed beyond elementary set theory and basic programming concepts.
5//!
6//! This chapter establishes:
7//! - What is a graph?
8//! - What is exact arithmetic?
9//! - What is a group?
10//! - What are vectors and inner products?
11//!
12//! Each concept is accompanied by minimal Rust implementations that serve as
13//! executable definitions.
14
15// # 0.1.1 Graphs
16
17//! ## 0.1.1 Graphs
18//!
19//! A **graph** is one of the most fundamental structures in mathematics and computer science.
20//!
21//! ### Definition 0.1.1 (Graph)
22//!
23//! A graph G = (V, E) consists of:
24//! - A finite set **V** of **vertices** (also called nodes)
25//! - A set **E ⊆ V × V** of **edges** (pairs of vertices)
26//!
27//! We write `v ~ w` when (v,w) ∈ E, read "v is adjacent to w".
28//!
29//! ### Properties
30//!
31//! - **Undirected**: If v ~ w, then w ~ v (edges have no direction)
32//! - **Simple**: No self-loops (v ≁ v) and no multiple edges
33//! - **Finite**: Both V and E are finite sets
34//!
35//! ### Example 0.1.1: Triangle Graph
36//!
37//! The triangle graph has 3 vertices {A, B, C} with edges forming a cycle:
38//!
39//! ```text
40//!     A
41//!    / \
42//!   B---C
43//! ```
44//!
45//! In set notation: V = {A, B, C}, E = {(A,B), (B,C), (C,A)}.
46//!
47//! ### Computational Representation
48//!
49//! We represent graphs using **adjacency lists**: for each vertex, store its neighbors.
50
51use std::collections::HashSet;
52
53/// A simple undirected graph with vertices labeled by generic type V.
54///
55/// **Implementation note**: This is a minimal educational implementation.
56/// The Atlas uses a more specialized representation in [`crate::atlas`].
57///
58/// # Examples
59///
60/// ```
61/// use atlas_embeddings::foundations::primitives::SimpleGraph;
62///
63/// // Create triangle graph
64/// let mut g = SimpleGraph::new();
65/// g.add_edge(0, 1);
66/// g.add_edge(1, 2);
67/// g.add_edge(2, 0);
68///
69/// assert_eq!(g.vertex_count(), 3);
70/// assert_eq!(g.edge_count(), 3);
71/// assert!(g.is_adjacent(0, 1));
72/// assert!(g.is_adjacent(1, 0)); // Undirected
73/// ```
74#[derive(Debug, Clone)]
75pub struct SimpleGraph {
76    /// Adjacency lists: for each vertex, store its neighbors
77    adjacency: Vec<HashSet<usize>>,
78}
79
80impl SimpleGraph {
81    /// Create an empty graph with no vertices.
82    #[must_use]
83    pub const fn new() -> Self {
84        Self { adjacency: Vec::new() }
85    }
86
87    /// Add a vertex to the graph, returning its index.
88    ///
89    /// Vertices are numbered sequentially: 0, 1, 2, ...
90    pub fn add_vertex(&mut self) -> usize {
91        let idx = self.adjacency.len();
92        self.adjacency.push(HashSet::new());
93        idx
94    }
95
96    /// Add an undirected edge between vertices u and v.
97    ///
98    /// Automatically adds vertices if they don't exist yet.
99    pub fn add_edge(&mut self, u: usize, v: usize) {
100        // Ensure both vertices exist
101        while self.adjacency.len() <= u.max(v) {
102            self.add_vertex();
103        }
104
105        // Add edge in both directions (undirected)
106        self.adjacency[u].insert(v);
107        self.adjacency[v].insert(u);
108    }
109
110    /// Check if vertices u and v are adjacent.
111    #[must_use]
112    pub fn is_adjacent(&self, u: usize, v: usize) -> bool {
113        if u >= self.adjacency.len() || v >= self.adjacency.len() {
114            return false;
115        }
116        self.adjacency[u].contains(&v)
117    }
118
119    /// Get the degree of vertex v (number of neighbors).
120    ///
121    /// **Definition**: The **degree** of a vertex is the number of edges incident to it.
122    #[must_use]
123    pub fn degree(&self, v: usize) -> usize {
124        if v >= self.adjacency.len() {
125            return 0;
126        }
127        self.adjacency[v].len()
128    }
129
130    /// Get the number of vertices in the graph.
131    #[must_use]
132    pub fn vertex_count(&self) -> usize {
133        self.adjacency.len()
134    }
135
136    /// Get the number of edges in the graph.
137    ///
138    /// Since the graph is undirected, we count each edge once.
139    #[must_use]
140    pub fn edge_count(&self) -> usize {
141        self.adjacency.iter().map(HashSet::len).sum::<usize>() / 2
142    }
143
144    /// Get the neighbors of vertex v.
145    #[must_use]
146    pub fn neighbors(&self, v: usize) -> Vec<usize> {
147        if v >= self.adjacency.len() {
148            return Vec::new();
149        }
150        self.adjacency[v].iter().copied().collect()
151    }
152}
153
154impl Default for SimpleGraph {
155    fn default() -> Self {
156        Self::new()
157    }
158}
159
160// # 0.1.2 Exact Arithmetic
161
162// ## 0.1.2 Exact Arithmetic
163//
164// In this work, we use **exact arithmetic** exclusively. No floating-point
165// calculations are permitted.
166//
167// ### Principle 0.1.2 (Exactness)
168//
169// All numerical computations use exact representations:
170// - **Integers**: ℤ represented as `i64` (64-bit signed integers)
171// - **Rationals**: ℚ represented as `Ratio<i64>` (pairs of integers p/q)
172// - **Half-integers**: ½ℤ represented as `HalfInteger` (multiples of 1/2)
173//
174// **NO floating-point arithmetic** is used anywhere in this crate.
175//
176// ### Why Exactness?
177//
178// 1. **Mathematical correctness**: No rounding errors corrupt our results
179// 2. **Reproducibility**: Same results on all platforms (no architecture-dependent floats)
180// 3. **Verifiability**: Equality is decidable (can test if a = b exactly)
181// 4. **Peer review**: Reviewers can verify exact values
182//
183// ### Example 0.1.2: Rational Arithmetic
184//
185// ```
186// use num_rational::Ratio;
187//
188// // Exact: 1/3 + 1/6 = 1/2
189// let a = Ratio::new(1, 3);
190// let b = Ratio::new(1, 6);
191// let c = a + b;
192// assert_eq!(c, Ratio::new(1, 2));
193//
194// // Contrast with floating point:
195// // 0.333... + 0.166... ≈ 0.5 (approximation)
196// ```
197//
198// ### Mathematical Perspective
199//
200// Exact arithmetic aligns with mathematical practice: when a mathematician
201// writes "√2", they mean the exact value, not a decimal approximation like 1.41421356.
202// Similarly, our code manipulates exact values.
203//
204// ### Computer Science Perspective
205//
206// Exact arithmetic trades performance for correctness. Floating-point operations
207// are faster but introduce errors. For mathematical research where correctness
208// is paramount, this tradeoff favors exactness.
209//
210// ### Type Aliases
211//
212// For convenience, we re-export commonly used exact types:
213
214pub use crate::arithmetic::{HalfInteger, Rational, Vector8};
215
216// # 0.1.3 Groups
217
218// ## 0.1.3 Groups
219//
220// A **group** is a fundamental algebraic structure encoding the concept of symmetry.
221//
222// ### Definition 0.1.3 (Group)
223//
224// A group (G, ·, e) consists of:
225// - A set **G**
226// - A binary operation **· : G × G → G** (multiplication)
227// - An identity element **e ∈ G**
228//
229// satisfying:
230//
231// 1. **Associativity**: (a · b) · c = a · (b · c) for all a,b,c ∈ G
232// 2. **Identity**: e · a = a · e = a for all a ∈ G
233// 3. **Inverses**: For each a ∈ G, there exists a⁻¹ ∈ G with a · a⁻¹ = e
234//
235// ### Example 0.1.3 (Integers under Addition)
236//
237// The integers ℤ form a group under addition:
238// - Set: G = ℤ = {..., -2, -1, 0, 1, 2, ...}
239// - Operation: · is ordinary addition +
240// - Identity: e = 0 (since 0 + a = a)
241// - Inverses: a⁻¹ = -a (since a + (-a) = 0)
242//
243// ### Example 0.1.4 (Klein Four-Group)
244//
245// The Klein four-group V₄ has 4 elements {e, a, b, c} with multiplication:
246//
247// ```text
248//   ·  | e  a  b  c
249//  ----+------------
250//   e  | e  a  b  c
251//   a  | a  e  c  b
252//   b  | b  c  e  a
253//   c  | c  b  a  e
254// ```
255//
256// Every element is its own inverse: a² = b² = c² = e.
257//
258// **Physical interpretation**: The Klein group describes the symmetries of a
259// rectangle (rotations by 0°, 180° and reflections through both axes).
260//
261// This group will appear in our construction of G₂ in Chapter 4.
262
263/// Klein four-group: V₄ = {e, a, b, c} with every element its own inverse.
264///
265/// Used in the product construction of G₂.
266///
267/// # Examples
268///
269/// ```
270/// use atlas_embeddings::foundations::primitives::KleinElement;
271///
272/// let a = KleinElement::A;
273/// let b = KleinElement::B;
274///
275/// // Group operation
276/// let c = a.multiply(b);
277/// assert_eq!(c, KleinElement::C);
278///
279/// // Every element is its own inverse
280/// assert_eq!(a.multiply(a), KleinElement::Identity);
281/// ```
282#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
283pub enum KleinElement {
284    /// Identity element e
285    Identity,
286    /// Element a
287    A,
288    /// Element b
289    B,
290    /// Element c = a·b
291    C,
292}
293
294impl KleinElement {
295    /// Group multiplication in V₄.
296    #[must_use]
297    pub const fn multiply(self, other: Self) -> Self {
298        use KleinElement::{Identity, A, B, C};
299        match (self, other) {
300            (Identity, x) | (x, Identity) => x,
301            (A, A) | (B, B) | (C, C) => Identity,
302            (A, B) | (B, A) => C,
303            (A, C) | (C, A) => B,
304            (B, C) | (C, B) => A,
305        }
306    }
307
308    /// Get the inverse element (every element is its own inverse).
309    #[must_use]
310    pub const fn inverse(self) -> Self {
311        self
312    }
313}
314
315// # 0.1.4 Vectors and Inner Products
316
317// ## 0.1.4 Vectors and Inner Products
318//
319// Much of our work takes place in 8-dimensional Euclidean space ℝ⁸.
320//
321// ### Definition 0.1.4 (Vector Space)
322//
323// A **vector space** over ℝ is a set V with operations:
324// - **Addition**: + : V × V → V
325// - **Scalar multiplication**: · : ℝ × V → V
326//
327// satisfying standard axioms (associativity, distributivity, etc.).
328//
329// **For our purposes**: We work with V = ℝ⁸, vectors are 8-tuples of real numbers.
330//
331// ### Definition 0.1.5 (Inner Product)
332//
333// An **inner product** on a vector space V is a function ⟨·,·⟩ : V × V → ℝ
334// satisfying:
335//
336// 1. **Symmetry**: ⟨u, v⟩ = ⟨v, u⟩
337// 2. **Linearity**: ⟨au + bv, w⟩ = a⟨u,w⟩ + b⟨v,w⟩
338// 3. **Positive-definite**: ⟨v, v⟩ ≥ 0, with equality iff v = 0
339//
340// ### The Standard Inner Product on ℝ⁸
341//
342// For vectors u = (u₁, ..., u₈) and v = (v₁, ..., v₈):
343//
344// $$ \langle u, v \rangle = u_1 v_1 + u_2 v_2 + \cdots + u_8 v_8 $$
345//
346// ### Definition 0.1.6 (Norm)
347//
348// The **norm** (or length) of a vector v is:
349//
350// $$ \|v\| = \sqrt{\langle v, v \rangle} $$
351//
352// We often work with **norm squared** to avoid square roots:
353//
354// $$ \|v\|^2 = \langle v, v \rangle = v_1^2 + \cdots + v_8^2 $$
355//
356// ### Example 0.1.5: Computing Norms
357//
358// ```
359// use atlas_embeddings::arithmetic::Vector8;
360// use num_rational::Ratio;
361//
362// // Integer vector (1,1,0,0,0,0,0,0)
363// let v = Vector8::new([
364//     Ratio::from_integer(1),
365//     Ratio::from_integer(1),
366//     Ratio::from_integer(0),
367//     Ratio::from_integer(0),
368//     Ratio::from_integer(0),
369//     Ratio::from_integer(0),
370//     Ratio::from_integer(0),
371//     Ratio::from_integer(0),
372// ]);
373//
374// // Norm squared: 1² + 1² = 2
375// assert_eq!(v.norm_squared(), Ratio::from_integer(2));
376// ```
377//
378// **Significance**: All E₈ roots have norm² = 2, making this the fundamental
379// scale in our construction.
380
381// ## 0.1.5 Summary
382//
383// We have established the primitive concepts needed for our construction:
384//
385// 1. **Graphs**: Vertices and edges, adjacency
386// 2. **Exact arithmetic**: Rationals, no floating point
387// 3. **Groups**: Algebraic structures encoding symmetry
388// 4. **Vectors**: 8-dimensional space with inner products
389//
390// These are the building blocks. In the next section, we introduce the
391// action functional that generates the Atlas.
392//
393// ---
394//
395// **Navigation**:
396// - Next: [§0.2 Action Functionals](super::action)
397// - Up: [Chapter 0: Foundations](super)
398
399#[cfg(test)]
400mod tests {
401    use super::*;
402
403    #[test]
404    fn test_simple_graph_triangle() {
405        let mut g = SimpleGraph::new();
406        g.add_edge(0, 1);
407        g.add_edge(1, 2);
408        g.add_edge(2, 0);
409
410        assert_eq!(g.vertex_count(), 3);
411        assert_eq!(g.edge_count(), 3);
412
413        // Check all edges exist (both directions)
414        assert!(g.is_adjacent(0, 1));
415        assert!(g.is_adjacent(1, 0));
416        assert!(g.is_adjacent(1, 2));
417        assert!(g.is_adjacent(2, 1));
418        assert!(g.is_adjacent(2, 0));
419        assert!(g.is_adjacent(0, 2));
420
421        // Check degrees
422        assert_eq!(g.degree(0), 2);
423        assert_eq!(g.degree(1), 2);
424        assert_eq!(g.degree(2), 2);
425    }
426
427    #[test]
428    fn test_simple_graph_no_self_loops() {
429        let mut g = SimpleGraph::new();
430        g.add_vertex();
431
432        // Graph should not have self-loops
433        assert!(!g.is_adjacent(0, 0));
434    }
435
436    #[test]
437    fn test_klein_group_multiplication() {
438        use KleinElement::{Identity, A, B, C};
439
440        // Identity laws
441        assert_eq!(Identity.multiply(A), A);
442        assert_eq!(A.multiply(Identity), A);
443
444        // Self-inverse property
445        assert_eq!(A.multiply(A), Identity);
446        assert_eq!(B.multiply(B), Identity);
447        assert_eq!(C.multiply(C), Identity);
448
449        // Products
450        assert_eq!(A.multiply(B), C);
451        assert_eq!(B.multiply(A), C);
452        assert_eq!(A.multiply(C), B);
453        assert_eq!(B.multiply(C), A);
454    }
455
456    #[test]
457    fn test_klein_group_associativity() {
458        use KleinElement::{A, B, C};
459
460        // (a·b)·c = a·(b·c)
461        let left = A.multiply(B).multiply(C);
462        let right = A.multiply(B.multiply(C));
463        assert_eq!(left, right);
464    }
465}