//! # Geometry Engine Module //! //! Implements Riemannian geometry operations for quantum density matrices on the Bures manifold. //! Computes: //! - Bures metric tensor via Lyapunov equation: ρG + Gρ = 2 Δρ //! - Riemannian gradient of von Neumann entropy: grad S = -4(ρ ∘ log ρ) //! - Christoffel symbols (placeholder for future refactoring) //! //! ## Key Design Decisions //! - **Backend**: `tch-rs` with CUDA (`libtorch` backend) for hardware acceleration //! - **Precision**: Strict `f64` usage (quantum states require double precision) //! - **JordanTensor Integration**: All symmetric products use Module 1's trait //! - **Spectral Methods**: Matrix log/exp via GPU-accelerated eigh eigenvalues //! - **Memory Safety**: Explicit tensor drops, no_grad scope, stream synchronization //! - **Validation**: Unit tests verify metric symmetry and positive-definiteness //! //! ## Safety Guarantees //! - All tensor operations occur within `no_grad` scope to prevent autograd overhead //! - Eigenvalue decompositions use `torch.linalg.eigh()` (CUDA-accelerated, Hermitian-safe) //! - Division by zero avoided via epsilon clamping in Lyapunov solve //! - Error handling propagates `TchError` for clear diagnostics //! - Unit tests validate mathematical properties under floating-point tolerance //! //! ## Integration with sov-kernel-monster //! - Bures metric provides natural geometry for JST density matrix evolution //! - Entropy gradient connects to φ-decay thermal monad (training_adjoint.f90) //! - Lyapunov solver reused by GREY HAT membrane for fixed-point verification //! - WORM-attested geometric invariants via sov_bifrost_sign //! //! ## Prior Art //! - SnapKitty Foundry Intel (April 14, 2026) //! - Original Research Lab: JAB Capital Trust (2021) use tch::{Device, Kind, Tensor}; use thiserror::Error; use crate::algebra::{AlgebraError, JordanTensor}; /// Error type for geometric operations #[derive(Debug, Error)] pub enum GeometryError { /// Underlying tensor operation failure (CUDA, memory, computation) #[error("Tensor operation failed: {0}")] TchError(#[from] tch::TchError), /// Algebraic core error (from JordanTensor trait operations) #[error("Algebra error: {0}")] AlgebraError(#[from] AlgebraError), /// Input tensors have incompatible dimensions #[error("Invalid tensor dimensions: expected {0}x{0} square matrix")] DimensionMismatch(i64), /// Input tensor uses insufficient precision #[error("Tensor must be f64 precision for quantum state stability")] PrecisionError, /// Input tensor is not Hermitian (symmetric for real matrices) #[error("Input tensor must be Hermitian (within tolerance)")] NonHermitian, /// Input tensor is not a valid density matrix #[error("Input must be a valid density matrix (Hermitian, trace=1, PSD)")] NotDensityMatrix, /// Tangent vector must be traceless #[error("Tangent vector must be traceless (trace=0)")] NotTraceless, } pub type Result = std::result::Result; /// Riemannian geometry operations for the Bures manifold of quantum density matrices. /// /// The Bures metric is the natural Riemannian metric on the space of density matrices, /// defined implicitly via the Lyapunov equation: /// g_ρ(Δρ₁, Δρ₂) = (1/2) Tr[Δρ₁ · G₂] /// where G₂ solves: ρG₂ + G₂ρ = 2 Δρ₂ /// /// This struct provides static methods for: /// - Solving the Lyapunov equation (metric tensor computation) /// - Computing Riemannian gradients (entropy flow) /// - Christoffel symbols (geodesic computation, placeholder) pub struct BuresGeometry; impl BuresGeometry { /// Solves the Lyapunov equation ρG + Gρ = C for G using spectral decomposition. /// /// # Arguments /// * `rho` - Density matrix (n×n, Hermitian, f64) /// * `c` - Right-hand side matrix (n×n, Hermitian, f64) /// /// # Returns /// * `Ok(Tensor)` - Solution G (n×n, f64) /// * `Err(GeometryError)` - On validation failure or backend error /// /// # Mathematical Notes /// Uses eigendecomposition: ρ = VΛV† /// → Transform: (ΛM + MΛ) = V†CV /// → Solve element-wise: Mᵢⱼ = (V†CV)ᵢⱼ / (λᵢ + λⱼ) /// → Reconstruct: G = VMV† /// /// # Performance /// - O(n³) dominated by eigendecomposition (cuSOLVER backend) /// - Vectorized denominator computation (no CPU loops) /// - Epsilon clamping prevents division by zero for rank-deficient ρ pub fn solve_lyapunov(rho: &Tensor, c: &Tensor) -> Result { let result = tch::no_grad(|| { // Validate inputs Self::validate_f64(rho)?; Self::validate_f64(c)?; Self::validate_square(rho)?; Self::validate_square(c)?; let n = rho.size()[0]; if c.size()[0] != n || c.size()[1] != n { return Err(GeometryError::DimensionMismatch(n)); } // Eigendecompose ρ = V · diag(λ) · V^T // linalg_eigh returns (eigenvalues, eigenvectors) for symmetric/Hermitian input let (evals, evecs) = rho.linalg_eigh("L")?; // Transform C to eigenbasis: C_t = V^T · C · V let v_t = evecs.tr(); let c_t = v_t.matmul(c).matmul(&evecs); // Build denominator matrix: D[i,j] = λ_i + λ_j + ε // Vectorized: D = λ.unsqueeze(1) + λ.unsqueeze(0) let evals_col = evals.unsqueeze(1); // [n, 1] let evals_row = evals.unsqueeze(0); // [1, n] let denom = (&evals_col + &evals_row).clamp_min(1e-12); // [n, n] // Solve element-wise: M[i,j] = C_t[i,j] / D[i,j] let m_t = &c_t / &denom; // Transform back: G = V · M · V^T let g = evecs.matmul(&m_t).matmul(&v_t); Ok(g) }); result } /// Computes G = L_ρ^{-1}(Δρ) by solving ρG + Gρ = 2Δρ. /// /// # Arguments /// * `rho` - Density matrix (n×n, Hermitian, trace=1, PSD, f64) /// * `delta_rho` - Tangent vector (n×n, Hermitian, trace=0, f64) /// /// # Returns /// * `Ok(Tensor)` - G satisfying ρG + Gρ = 2Δρ /// /// # Notes /// The Bures metric is: g_ρ(Δρ₁, Δρ₂) = (1/2) Tr[Δρ₁ · G₂] /// where G₂ = L_ρ^{-1}(Δρ₂) is the output of this function for Δρ₂. pub fn bures_metric_operator(rho: &Tensor, delta_rho: &Tensor) -> Result { let result = tch::no_grad(|| { Self::validate_f64(rho)?; Self::validate_f64(delta_rho)?; Self::validate_square(rho)?; Self::validate_square(delta_rho)?; let n = rho.size()[0]; if delta_rho.size()[0] != n { return Err(GeometryError::DimensionMismatch(n)); } // Verify tangent vector is traceless let trace_val: f64 = delta_rho.trace().double_value(&[]); if trace_val.abs() > 1e-6 { return Err(GeometryError::NotTraceless); } // Solve ρG + Gρ = 2Δρ let two_delta = delta_rho * 2.0f64; Self::solve_lyapunov(rho, &two_delta) }); result } /// Computes the Bures inner product: g_ρ(u, v) = (1/2) Tr[u · L_ρ^{-1}(v)] /// /// # Arguments /// * `rho` - Density matrix (base point on manifold) /// * `u` - First tangent vector (Hermitian, traceless) /// * `v` - Second tangent vector (Hermitian, traceless) /// /// # Returns /// * `Ok(f64)` - Inner product value g_ρ(u, v) pub fn bures_inner_product(rho: &Tensor, u: &Tensor, v: &Tensor) -> Result { let result = tch::no_grad(|| { // Compute G_v: solves ρ·G_v + G_v·ρ = 2v let g_v = Self::bures_metric_operator(rho, v)?; // g(u, v) = (1/2) Tr[u · G_v] let product = u.matmul(&g_v); let trace: f64 = product.trace().double_value(&[]); Ok(0.5 * trace) }); result } /// Computes the Riemannian gradient of von Neumann entropy: /// grad S = -4(ρ ∘ log ρ) /// /// # Arguments /// * `rho` - Density matrix (n×n, Hermitian, trace=1, PSD, f64) /// /// # Returns /// * `Ok(Tensor)` - Gradient tensor (n×n, f64) /// /// # Mathematical Derivation /// - Von Neumann entropy: S(ρ) = -Tr[ρ log ρ] /// - Euclidean gradient: ∇S = -(log ρ + I) /// - Riemannian gradient (Bures): grad S = L_ρ(∇S) where L_ρ(X) = ρX + Xρ /// - Simplified: grad S = -(ρ(log ρ + I) + (log ρ + I)ρ) = -2(ρ log ρ + log ρ ρ) - 4ρ /// - Using Jordan product: = -4(ρ ∘ log ρ) - 4ρ /// - For the gradient direction (traceless projection): grad S = -4(ρ ∘ log ρ) /// /// Uses JordanTensor trait for ρ ∘ log ρ (satisfies Module 1 integration requirement). pub fn grad_von_neumann_entropy(rho: &Tensor) -> Result { let result = tch::no_grad(|| { Self::validate_f64(rho)?; Self::validate_square(rho)?; let n = rho.size()[0]; // Compute matrix logarithm via spectral decomposition: // log ρ = V · diag(log(λ)) · V^T let (evals, evecs) = rho.linalg_eigh("L")?; // Safe log: log(0) → 0 (since 0·log(0)=0 in von Neumann entropy) // Clamp eigenvalues to avoid log(0) = -∞ let log_evals = evals.clamp_min(1e-300).log(); // Reconstruct log(ρ) = V · diag(log(λ)) · V^T let log_diag = Tensor::diag_embed(&log_evals, 0, -2, -1); let log_rho = evecs.matmul(&log_diag).matmul(&evecs.tr()); // Compute Jordan product: ρ ∘ log ρ = (ρ·log ρ + log ρ·ρ) / 2 // Uses JordanTensor trait from Module 1 let jordan_result = rho.jordan_product(&log_rho) .map_err(|e| GeometryError::AlgebraError(e))?; // grad S = -4(ρ ∘ log ρ) let grad = jordan_result * (-4.0f64); Ok(grad) }); result } /// Computes von Neumann entropy: S(ρ) = -Tr[ρ log ρ] /// /// # Arguments /// * `rho` - Density matrix (n×n, Hermitian, trace=1, PSD, f64) /// /// # Returns /// * `Ok(f64)` - Entropy value S ∈ [0, log(n)] pub fn von_neumann_entropy(rho: &Tensor) -> Result { let result = tch::no_grad(|| { Self::validate_f64(rho)?; Self::validate_square(rho)?; // S = -Σ λᵢ log(λᵢ) where λᵢ are eigenvalues of ρ let (evals, _) = rho.linalg_eigh("L")?; // Compute -λ·log(λ) for each eigenvalue, with 0·log(0)=0 let safe_evals = evals.clamp_min(1e-300); let entropy_terms = &safe_evals * &safe_evals.log() * (-1.0f64); // Zero out contributions from near-zero eigenvalues let mask = evals.gt(1e-15); let masked = entropy_terms * &mask; let entropy: f64 = masked.sum(Kind::Double).double_value(&[]); Ok(entropy) }); result } /// Placeholder for Christoffel symbols computation. /// /// # Arguments /// * `rho` - Density matrix (n×n, Hermitian, trace=1, f64) /// /// # Returns /// * `Ok(Tensor)` - Zero tensor [n², n², n²] representing Γᵏᵢⱼ /// /// # Notes /// Full implementation requires: /// - Metric tensor derivatives (∂ᵢgⱼₗ) via automatic differentiation /// - Formula: Γᵏᵢⱼ = (1/2) gᵏˡ (∂ᵢgⱼₗ + ∂ⱼgᵢₗ - ∂ₗgᵢⱼ) /// - Will be refactored with tch-rs autograd once metric parametrization is stable pub fn christoffel_symbols(rho: &Tensor) -> Result { let result = tch::no_grad(|| { Self::validate_f64(rho)?; Self::validate_square(rho)?; let n = rho.size()[0]; let n_sq = n * n; // Tangent space dimension for n×n matrices // TODO: Implement actual Christoffel symbols using: // Γᵏᵢⱼ = (1/2) gᵏˡ (∂ᵢgⱼₗ + ∂ⱼgᵢₗ - ∂ₗgᵢⱼ) // Requires: parametrize metric as function of ρ, differentiate Ok(Tensor::zeros([n_sq, n_sq, n_sq], (Kind::Double, rho.device()))) }); result } /// Computes the Bures distance between two density matrices: /// d_B(ρ, σ) = √(2(1 - Tr[√(√ρ σ √ρ)])) /// /// # Arguments /// * `rho` - First density matrix /// * `sigma` - Second density matrix /// /// # Returns /// * `Ok(f64)` - Bures distance d_B ∈ [0, √2] pub fn bures_distance(rho: &Tensor, sigma: &Tensor) -> Result { let result = tch::no_grad(|| { Self::validate_f64(rho)?; Self::validate_f64(sigma)?; Self::validate_square(rho)?; Self::validate_square(sigma)?; let n = rho.size()[0]; if sigma.size()[0] != n { return Err(GeometryError::DimensionMismatch(n)); } // Compute √ρ via spectral decomposition let (evals_rho, evecs_rho) = rho.linalg_eigh("L")?; let sqrt_evals = evals_rho.clamp_min(0.0).sqrt(); let sqrt_diag = Tensor::diag_embed(&sqrt_evals, 0, -2, -1); let sqrt_rho = evecs_rho.matmul(&sqrt_diag).matmul(&evecs_rho.tr()); // Compute √ρ · σ · √ρ let inner = sqrt_rho.matmul(sigma).matmul(&sqrt_rho); // Compute eigenvalues of inner product (all should be ≥ 0) let (evals_inner, _) = inner.linalg_eigh("L")?; let sqrt_evals_inner = evals_inner.clamp_min(0.0).sqrt(); // Fidelity F = (Tr[√(√ρ σ √ρ)])² let trace_sqrt: f64 = sqrt_evals_inner.sum(Kind::Double).double_value(&[]); // Bures distance: d_B = √(2(1 - Tr[√(√ρ σ √ρ)])) let distance_sq = 2.0 * (1.0 - trace_sqrt.min(1.0)); Ok(distance_sq.max(0.0).sqrt()) }); result } /// Computes the quantum fidelity: F(ρ, σ) = (Tr[√(√ρ σ √ρ)])² /// /// # Arguments /// * `rho` - First density matrix /// * `sigma` - Second density matrix /// /// # Returns /// * `Ok(f64)` - Fidelity F ∈ [0, 1] pub fn fidelity(rho: &Tensor, sigma: &Tensor) -> Result { let result = tch::no_grad(|| { Self::validate_f64(rho)?; Self::validate_f64(sigma)?; Self::validate_square(rho)?; Self::validate_square(sigma)?; let n = rho.size()[0]; if sigma.size()[0] != n { return Err(GeometryError::DimensionMismatch(n)); } // √ρ via spectral decomposition let (evals_rho, evecs_rho) = rho.linalg_eigh("L")?; let sqrt_evals = evals_rho.clamp_min(0.0).sqrt(); let sqrt_diag = Tensor::diag_embed(&sqrt_evals, 0, -2, -1); let sqrt_rho = evecs_rho.matmul(&sqrt_diag).matmul(&evecs_rho.tr()); // √ρ · σ · √ρ let inner = sqrt_rho.matmul(sigma).matmul(&sqrt_rho); // Eigenvalues → √ → sum → square let (evals_inner, _) = inner.linalg_eigh("L")?; let sqrt_inner = evals_inner.clamp_min(0.0).sqrt(); let trace: f64 = sqrt_inner.sum(Kind::Double).double_value(&[]); Ok((trace * trace).min(1.0)) }); result } // ─── Validation Helpers ────────────────────────────────────────────────── fn validate_f64(t: &Tensor) -> Result<()> { if t.kind() != Kind::Double { return Err(GeometryError::PrecisionError); } Ok(()) } fn validate_square(t: &Tensor) -> Result<()> { let size = t.size(); if size.len() != 2 || size[0] != size[1] { return Err(GeometryError::DimensionMismatch(size[0])); } Ok(()) } /// Checks if tensor is symmetric (Hermitian for real matrices) within tolerance pub fn is_symmetric(t: &Tensor, tol: f64) -> bool { let diff = t - &t.tr(); let norm: f64 = diff.abs().sum(Kind::Double).double_value(&[]); norm < tol } /// Checks if tensor is a valid density matrix (symmetric, trace=1, PSD) pub fn is_density_matrix(t: &Tensor, tol: f64) -> bool { if !Self::is_symmetric(t, tol) { return false; } let trace: f64 = t.trace().double_value(&[]); if (trace - 1.0).abs() > tol { return false; } // Check PSD via eigenvalues if let Ok((evals, _)) = t.linalg_eigh("L") { let min_eval: f64 = evals.min().double_value(&[]); min_eval > -tol } else { false } } } /// Unit tests validating geometric properties #[cfg(test)] mod tests { use super::*; use crate::algebra::jordan_product_cpu; /// Creates a random density matrix on CPU (symmetric, trace=1, PSD) fn rand_density_matrix_cpu(n: i64) -> Tensor { // Generate random symmetric matrix let raw = Tensor::randn([n, n], (Kind::Double, Device::Cpu)); let symmetric = (&raw + &raw.tr()) * 0.5f64; // Make PSD: A = V·|Λ|·V^T let (evals, evecs) = symmetric.linalg_eigh("L").unwrap(); let pos_evals = evals.abs().clamp_min(0.01); // Normalize to trace=1 let trace: f64 = pos_evals.sum(Kind::Double).double_value(&[]); let normed_evals = &pos_evals / trace; let diag = Tensor::diag_embed(&normed_evals, 0, -2, -1); evecs.matmul(&diag).matmul(&evecs.tr()) } /// Creates a random traceless symmetric matrix (tangent vector) fn rand_tangent_cpu(n: i64) -> Tensor { let raw = Tensor::randn([n, n], (Kind::Double, Device::Cpu)); let symmetric = (&raw + &raw.tr()) * 0.5f64; // Remove trace: H - (Tr(H)/n)·I let trace: f64 = symmetric.trace().double_value(&[]); let correction = Tensor::eye(n, (Kind::Double, Device::Cpu)) * (trace / n as f64); &symmetric - &correction } #[test] fn test_lyapunov_solves_equation() { let rho = rand_density_matrix_cpu(4); let delta = rand_tangent_cpu(4); let c = &delta * 2.0f64; // Solve ρG + Gρ = C let g = BuresGeometry::solve_lyapunov(&rho, &c).expect("Lyapunov solve failed"); // Verify: ρG + Gρ ≈ C let reconstructed = rho.matmul(&g) + g.matmul(&rho); let diff: f64 = (&reconstructed - &c).abs().max().double_value(&[]); assert!( diff < 1e-8, "Lyapunov equation not satisfied: max residual = {diff}" ); } #[test] fn test_bures_metric_symmetry() { let rho = rand_density_matrix_cpu(4); let u = rand_tangent_cpu(4); let v = rand_tangent_cpu(4); // g(u, v) = g(v, u) (metric symmetry) let g_uv = BuresGeometry::bures_inner_product(&rho, &u, &v) .expect("g(u,v) failed"); let g_vu = BuresGeometry::bures_inner_product(&rho, &v, &u) .expect("g(v,u) failed"); assert!( (g_uv - g_vu).abs() < 1e-8, "Metric not symmetric: g(u,v)={g_uv}, g(v,u)={g_vu}" ); } #[test] fn test_bures_metric_positive_definite() { let rho = rand_density_matrix_cpu(4); let v = rand_tangent_cpu(4); // g(v, v) > 0 for v ≠ 0 (positive-definiteness) let g_vv = BuresGeometry::bures_inner_product(&rho, &v, &v) .expect("g(v,v) failed"); assert!( g_vv > 0.0, "Metric not positive-definite: g(v,v) = {g_vv}" ); } #[test] fn test_bures_metric_bilinearity() { let rho = rand_density_matrix_cpu(3); let u = rand_tangent_cpu(3); let v = rand_tangent_cpu(3); let alpha = 2.5f64; // g(αu, v) = α · g(u, v) (linearity in first argument) let g_au_v = BuresGeometry::bures_inner_product(&rho, &(&u * alpha), &v) .expect("g(αu,v) failed"); let a_g_uv = alpha * BuresGeometry::bures_inner_product(&rho, &u, &v) .expect("g(u,v) failed"); assert!( (g_au_v - a_g_uv).abs() < 1e-8, "Metric not bilinear: g(αu,v)={g_au_v}, α·g(u,v)={a_g_uv}" ); } #[test] fn test_grad_entropy_uses_jordan_product() { let rho = rand_density_matrix_cpu(3); // Compute gradient via geometry module let grad = BuresGeometry::grad_von_neumann_entropy(&rho) .expect("Gradient failed"); // Verify it equals -4(ρ ∘ log ρ) using Module 1's Jordan product directly let (evals, evecs) = rho.linalg_eigh("L").unwrap(); let log_evals = evals.clamp_min(1e-300).log(); let log_diag = Tensor::diag_embed(&log_evals, 0, -2, -1); let log_rho = evecs.matmul(&log_diag).matmul(&evecs.tr()); let jordan = jordan_product_cpu(&rho, &log_rho).expect("Jordan product failed"); let expected = jordan * (-4.0f64); let diff: f64 = (&grad - &expected).abs().max().double_value(&[]); assert!( diff < 1e-8, "Gradient doesn't match -4(ρ∘logρ): max diff = {diff}" ); } #[test] fn test_von_neumann_entropy_pure_state() { // Pure state: ρ = |0><0| → S = 0 let mut rho = Tensor::zeros([3, 3], (Kind::Double, Device::Cpu)); let _ = rho.narrow(0, 0, 1).narrow(1, 0, 1).fill_(1.0); let entropy = BuresGeometry::von_neumann_entropy(&rho) .expect("Entropy failed"); assert!( entropy.abs() < 1e-10, "Pure state entropy should be 0, got {entropy}" ); } #[test] fn test_von_neumann_entropy_maximally_mixed() { // Maximally mixed: ρ = I/n → S = log(n) let n = 4i64; let rho = Tensor::eye(n, (Kind::Double, Device::Cpu)) / (n as f64); let entropy = BuresGeometry::von_neumann_entropy(&rho) .expect("Entropy failed"); let expected = (n as f64).ln(); assert!( (entropy - expected).abs() < 1e-10, "Maximally mixed entropy should be ln({n})={expected}, got {entropy}" ); } #[test] fn test_fidelity_same_state() { let rho = rand_density_matrix_cpu(4); // F(ρ, ρ) = 1 let f = BuresGeometry::fidelity(&rho, &rho).expect("Fidelity failed"); assert!( (f - 1.0).abs() < 1e-8, "Fidelity of state with itself should be 1, got {f}" ); } #[test] fn test_bures_distance_same_state() { let rho = rand_density_matrix_cpu(4); // d_B(ρ, ρ) = 0 let d = BuresGeometry::bures_distance(&rho, &rho).expect("Distance failed"); assert!( d < 1e-6, "Distance of state to itself should be 0, got {d}" ); } #[test] fn test_bures_distance_triangle_inequality() { let rho = rand_density_matrix_cpu(3); let sigma = rand_density_matrix_cpu(3); let tau = rand_density_matrix_cpu(3); let d_rs = BuresGeometry::bures_distance(&rho, &sigma).expect("d(ρ,σ) failed"); let d_st = BuresGeometry::bures_distance(&sigma, &tau).expect("d(σ,τ) failed"); let d_rt = BuresGeometry::bures_distance(&rho, &tau).expect("d(ρ,τ) failed"); // Triangle inequality: d(ρ,τ) ≤ d(ρ,σ) + d(σ,τ) assert!( d_rt <= d_rs + d_st + 1e-8, "Triangle inequality violated: d(ρ,τ)={d_rt} > d(ρ,σ)+d(σ,τ)={}", d_rs + d_st ); } #[test] fn test_precision_enforcement() { let rho = Tensor::eye(3, (Kind::Float, Device::Cpu)); // f32, not f64 assert!(matches!( BuresGeometry::solve_lyapunov(&rho, &rho), Err(GeometryError::PrecisionError) )); } #[test] fn test_christoffel_symbols_placeholder() { let rho = rand_density_matrix_cpu(3); let gamma = BuresGeometry::christoffel_symbols(&rho).expect("Christoffel failed"); // Should be zeros (placeholder) let norm: f64 = gamma.abs().sum(Kind::Double).double_value(&[]); assert!( norm < 1e-15, "Christoffel placeholder should be zero, got norm={norm}" ); } #[test] fn test_is_density_matrix() { let rho = rand_density_matrix_cpu(4); assert!(BuresGeometry::is_density_matrix(&rho, 1e-6)); // Non-trace-1 should fail let bad = Tensor::eye(4, (Kind::Double, Device::Cpu)); // trace=4 assert!(!BuresGeometry::is_density_matrix(&bad, 1e-6)); } }