pub trait ComplexElement:
Clone
+ Hash
+ Eq
+ PartialOrd
+ Ord {
// Required methods
fn dimension(&self) -> usize;
fn faces(&self) -> Vec<Self>;
fn boundary_with_orientations(&self) -> Vec<(Self, i32)>;
fn id(&self) -> Option<usize>;
fn same_content(&self, other: &Self) -> bool;
fn with_id(&self, new_id: usize) -> Self;
}Expand description
Trait for elements that can be part of a topological complex.
This trait captures the essential behavior needed for elements (simplices, cubes, cells, etc.)
to work with the generic Complex<T> structure. It abstracts over the common operations
that any type of cell complex element must support.
§Mathematical Foundation
In algebraic topology, a complex is built from cells of various dimensions with specific face relations. This trait encapsulates the core properties that any cell type must have:
- Dimension: Each cell has an intrinsic dimension (0 for vertices, 1 for edges, etc.)
- Boundary Structure: Each cell has well-defined boundary cells (faces)
- Orientation: Boundary relationships include orientation information for chain complexes
- Identity: Cells can be uniquely identified when added to complexes
- Content Equality: Mathematical content can be compared regardless of ID assignment
§Design Philosophy
This trait is designed to be:
- Generic: Works with simplices, cubes, and other cell types
- Efficient: Supports ID-based operations for large complexes
- Mathematically Correct: Preserves orientation and boundary relationships
- Flexible: Allows different boundary operator conventions per element type
§Implementation Requirements
Types implementing this trait must:
- Be cloneable, hashable, and orderable for use in collections
- Compute their own faces and boundary operators correctly
- Handle ID assignment and content comparison properly
- Maintain mathematical consistency in their face relationships
§Examples
use harness_space::complexes::{ComplexElement, Simplex};
// Create a triangle (2-simplex)
let triangle = Simplex::new(2, vec![0, 1, 2]);
// Basic properties
assert_eq!(triangle.dimension(), 2);
assert_eq!(triangle.id(), None); // No ID until added to complex
// Compute faces (should be 3 edges)
let faces = triangle.faces();
assert_eq!(faces.len(), 3);
assert!(faces.iter().all(|face| face.dimension() == 1));
// Compute boundary with orientations
let boundary = triangle.boundary_with_orientations();
assert_eq!(boundary.len(), 3);
// Each face has orientation ±1
assert!(boundary.iter().all(|(_, orient)| orient.abs() == 1));Required Methods§
Sourcefn dimension(&self) -> usize
fn dimension(&self) -> usize
Returns the intrinsic dimension of this element.
The dimension determines the element’s place in the chain complex:
- 0-dimensional: vertices/points
- 1-dimensional: edges/curves
- 2-dimensional: faces/surfaces
- k-dimensional: k-cells
§Mathematical Note
For a k-dimensional element, its faces are (k-1)-dimensional, and it can be a face of (k+1)-dimensional elements. This creates the graded structure essential for homological computations.
§Examples
let vertex = Simplex::new(0, vec![42]);
assert_eq!(vertex.dimension(), 0);
let edge = Cube::edge(0, 1);
assert_eq!(edge.dimension(), 1);Sourcefn faces(&self) -> Vec<Self>
fn faces(&self) -> Vec<Self>
Returns all faces (boundary elements) of this element.
For a k-dimensional element, this returns all (k-1)-dimensional faces that form its boundary. This is the combinatorial boundary - it captures the face structure without orientation information.
§Mathematical Background
In topology, the boundary ∂σ of a cell σ consists of all the cells in its boundary. For example:
- Triangle faces: the three edges forming its boundary
- Tetrahedron faces: the four triangular faces
- Square faces: the four edges forming its boundary
§Implementation Notes
- Returned faces should have no ID assigned (will be assigned when added to complex)
- The order may matter for orientation in
ComplexElement::boundary_with_orientations - All faces must have dimension =
self.dimension() - 1 - 0-dimensional elements return empty vector (no (-1)-dimensional faces)
§Examples
// Triangle has 3 edge faces
let triangle = Simplex::new(2, vec![0, 1, 2]);
let faces = triangle.faces();
assert_eq!(faces.len(), 3);
assert!(faces.iter().all(|f| f.dimension() == 1));
// Vertex has no faces
let vertex = Simplex::new(0, vec![0]);
assert_eq!(vertex.faces().len(), 0);Sourcefn boundary_with_orientations(&self) -> Vec<(Self, i32)>
fn boundary_with_orientations(&self) -> Vec<(Self, i32)>
Returns the faces with their correct orientation coefficients for boundary computation.
This is the geometric boundary operator that includes orientation information necessary for chain complex computations. Each face comes with an integer coefficient (typically ±1) indicating its orientation in the boundary.
§Mathematical Foundation
In algebraic topology, the boundary operator ∂ₖ: Cₖ → Cₖ₋₁ is defined as:
∂ₖ(σ) = Σᵢ (-1)ⁱ τᵢwhere the τᵢ are the faces of σ with appropriate orientation signs. The key property is that ∂² = 0 (boundary of boundary is zero), which requires careful orientation handling.
§Orientation Conventions
Different element types may use different orientation conventions:
- Simplicial: Alternating signs based on vertex position
- Cubical: Signs based on coordinate directions
- General CW: Depends on attaching maps
§Return Format
Returns Vec<(face, orientation)> where:
face: A (k-1)-dimensional face element (without ID)orientation: Integer coefficient (usually ±1, could be 0)
§Examples
let triangle = Simplex::new(2, vec![0, 1, 2]);
let boundary = triangle.boundary_with_orientations();
// Triangle boundary: [v₁,v₂] - [v₀,v₂] + [v₀,v₁]
assert_eq!(boundary.len(), 3);
assert_eq!(boundary[0].1, 1); // +[v₁,v₂]
assert_eq!(boundary[1].1, -1); // -[v₀,v₂]
assert_eq!(boundary[2].1, 1); // +[v₀,v₁]Sourcefn id(&self) -> Option<usize>
fn id(&self) -> Option<usize>
Returns the ID if this element has been assigned to a complex, None otherwise.
IDs are automatically assigned when elements are added to a Complex via
Complex::join_element. They serve as unique identifiers for efficient
storage and lookup operations.
§ID Assignment Lifecycle
- Created: Element starts with
id() = None - Added: Complex assigns unique ID via
ComplexElement::with_id - Stored: Element with ID is stored in complex’s HashMap
- Referenced: ID used for lattice operations and lookups
§Examples
let simplex = Simplex::new(1, vec![0, 1]);
assert_eq!(simplex.id(), None);
let mut complex = Complex::new();
let added = complex.join_element(simplex);
assert!(added.id().is_some());Sourcefn same_content(&self, other: &Self) -> bool
fn same_content(&self, other: &Self) -> bool
Checks if this element has the same mathematical content as another.
This comparison ignores ID assignment and focuses purely on the mathematical structure of the elements. It’s used for deduplication when adding elements to complexes.
§Mathematical Equality
Two elements are considered to have the same content if they represent the same mathematical object, regardless of:
- ID assignment (internal bookkeeping)
- Order of discovery (when added to complex)
- Memory location or other implementation details
§Usage in Complexes
When Complex::join_element is called, it first checks if an element
with the same content already exists using this method. If found, it
returns the existing element rather than creating a duplicate.
§Examples
let simplex1 = Simplex::new(1, vec![0, 1]);
let simplex2 = Simplex::new(1, vec![0, 1]);
let simplex3 = simplex1.clone().with_id(42);
assert!(simplex1.same_content(&simplex2)); // Same mathematical content
assert!(simplex1.same_content(&simplex3)); // ID differences ignored
let different = Simplex::new(1, vec![0, 2]);
assert!(!simplex1.same_content(&different)); // Different contentSourcefn with_id(&self, new_id: usize) -> Self
fn with_id(&self, new_id: usize) -> Self
Creates a new element with the same content but a specific ID.
This is used internally by Complex to assign IDs when adding elements.
The returned element should be identical in all mathematical properties
but have the specified ID assigned.
§Implementation Requirements
The returned element must satisfy:
result.same_content(self) == trueresult.id() == Some(new_id)- All other properties unchanged (dimension, faces, etc.)
§Usage
This method is primarily used internally by the complex management system. Users typically don’t need to call it directly.
§Examples
let original = Simplex::new(1, vec![0, 1]);
assert_eq!(original.id(), None);
let with_id = original.with_id(42);
assert_eq!(with_id.id(), Some(42));
assert!(original.same_content(&with_id));
assert_eq!(original.dimension(), with_id.dimension());Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.