rssn/symbolic/
differential_geometry.rs

1//! # Differential Geometry
2//!
3//! This module provides symbolic tools for calculus on manifolds, including the
4//! manipulation of differential forms and the application of major integral theorems.
5//! It includes implementations for exterior derivatives, wedge products, and symbolic
6//! representations of generalized Stokes' theorem, Gauss's theorem, and Green's theorem.
7use crate::symbolic::calculus::{definite_integrate, differentiate};
8use crate::symbolic::core::Expr;
9use crate::symbolic::simplify_dag::simplify;
10use crate::symbolic::vector::Vector;
11use num_bigint::BigInt;
12use num_traits::Zero;
13use std::sync::Arc;
14/// Represents a differential k-form.
15///
16/// A k-form is a mathematical object that can be integrated over a k-dimensional manifold.
17/// It is a sum of terms, where each term is a scalar function (coefficient) multiplied by
18/// a wedge product of k basis 1-forms (like dx, dy, etc.).
19///
20/// For example, a 2-form in R^3 could be `f(x,y,z) dx^dy + g(x,y,z) dx^dz`.
21///
22/// Here, the basis wedge products (e.g., `dx^dy`) are represented by a bitmask (`blade`).
23/// If `vars = ["x", "y", "z"]`, then `dx` is `1<<0`, `dy` is `1<<1`, `dz` is `1<<2`.
24/// The wedge product `dx^dy` corresponds to the bitmask `(1<<0) | (1<<1) = 3`.
25#[derive(Debug, Clone, PartialEq, Eq)]
26pub struct DifferentialForm {
27    /// A map from the basis wedge product (represented by a bitmask) to its coefficient expression.
28    pub terms: std::collections::BTreeMap<u32, Expr>,
29}
30/// Computes the exterior derivative of a k-form, resulting in a (k+1)-form.
31///
32/// The exterior derivative `dω` of a k-form `ω` is a central concept in differential geometry.
33/// For a 0-form (a scalar function `f`), `df` is its total differential.
34/// For a k-form `ω = f dx_I`, `dω = df ^ dx_I`.
35///
36/// # Arguments
37/// * `form` - The differential form `ω` to differentiate.
38/// * `vars` - A slice of variable names (e.g., `["x", "y", "z"]`) defining the basis.
39///
40/// # Returns
41/// A new `DifferentialForm` representing `dω`.
42pub fn exterior_derivative(form: &DifferentialForm, vars: &[&str]) -> DifferentialForm {
43    let mut result_terms = std::collections::BTreeMap::new();
44    for (blade, coeff) in &form.terms {
45        for (i, _item) in vars.iter().enumerate() {
46            let new_blade = (1 << i) | blade;
47            if new_blade.count_ones() != blade.count_ones() + 1 {
48                continue;
49            }
50            let d_coeff = differentiate(coeff, vars[i]);
51            let mut sign = 1i64;
52            for j in 0..i {
53                if (blade >> j) & 1 == 1 {
54                    sign *= -1;
55                }
56            }
57            let signed_coeff = if sign == 1 {
58                d_coeff
59            } else {
60                simplify(&Expr::new_neg(d_coeff))
61            };
62            let entry = result_terms
63                .entry(new_blade)
64                .or_insert(Expr::BigInt(BigInt::zero()));
65            *entry = simplify(&Expr::new_add(entry.clone(), signed_coeff));
66        }
67    }
68    DifferentialForm {
69        terms: result_terms,
70    }
71}
72/// Computes the wedge product (exterior product) of two differential forms.
73///
74/// The wedge product is an antisymmetric, associative product.
75/// For basis 1-forms, `dx_i ^ dx_j = -dx_j ^ dx_i`, and `dx_i ^ dx_i = 0`.
76///
77/// # Arguments
78/// * `form1` - The first differential form.
79/// * `form2` - The second differential form.
80///
81/// # Returns
82/// A new `DifferentialForm` representing the wedge product.
83pub fn wedge_product(form1: &DifferentialForm, form2: &DifferentialForm) -> DifferentialForm {
84    let mut result_terms = std::collections::BTreeMap::new();
85    for (blade1, coeff1) in &form1.terms {
86        for (blade2, coeff2) in &form2.terms {
87            if (blade1 & blade2) != 0 {
88                continue;
89            }
90            let new_blade = blade1 | blade2;
91            let mut sign = 1i64;
92            let mut temp_blade2 = *blade2;
93            while temp_blade2 > 0 {
94                let i = temp_blade2.trailing_zeros();
95                let swaps = (blade1 >> (i + 1)).count_ones();
96                if swaps % 2 != 0 {
97                    sign *= -1;
98                }
99                temp_blade2 &= !(1 << i);
100            }
101            let new_coeff = simplify(&Expr::new_mul(coeff1.clone(), coeff2.clone()));
102            let signed_coeff = if sign == 1 {
103                new_coeff
104            } else {
105                simplify(&Expr::new_neg(new_coeff))
106            };
107            let entry = result_terms
108                .entry(new_blade)
109                .or_insert(Expr::BigInt(BigInt::zero()));
110            *entry = simplify(&Expr::new_add(entry.clone(), signed_coeff));
111        }
112    }
113    DifferentialForm {
114        terms: result_terms,
115    }
116}
117/// Represents the boundary of a domain, denoted as `∂M` for a manifold `M`.
118/// This is a symbolic representation used in the integral theorems.
119pub fn boundary(domain: &Expr) -> Expr {
120    Expr::Boundary(Arc::new(domain.clone()))
121}
122/// Represents the generalized Stokes' Theorem.
123///
124/// The theorem states that the integral of the exterior derivative of a differential form `ω`
125/// over some manifold `M` is equal to the integral of `ω` over the boundary of `M` (`∂M`).
126/// Formula: `∫_M dω = ∫_{∂M} ω`
127/// This function returns a symbolic equation representing the theorem.
128pub fn generalized_stokes_theorem(
129    omega: &DifferentialForm,
130    manifold: &Expr,
131    vars: &[&str],
132) -> Expr {
133    let d_omega = exterior_derivative(omega, vars);
134    let integral_d_omega = Expr::Integral {
135        integrand: Arc::new(Expr::Variable(format!("{:?}", d_omega))),
136        var: Arc::new(Expr::Variable(manifold.to_string())),
137        lower_bound: Arc::new(Expr::Variable("M".to_string())),
138        upper_bound: Arc::new(Expr::BigInt(BigInt::zero())),
139    };
140    let integral_omega = Expr::Integral {
141        integrand: Arc::new(Expr::Variable(format!("{:?}", omega))),
142        var: Arc::new(Expr::Variable(manifold.to_string())),
143        lower_bound: Arc::new(boundary(manifold)),
144        upper_bound: Arc::new(Expr::BigInt(BigInt::zero())),
145    };
146    Expr::Eq(Arc::new(integral_d_omega), Arc::new(integral_omega))
147}
148/// Represents Gauss's Theorem (Divergence Theorem) as a special case of Stokes' Theorem.
149///
150/// It relates the flux of a vector field through a closed surface to the divergence
151/// of the field in the volume enclosed.
152/// Formula: `∫_V (∇ · F) dV = ∮_{∂V} (F · n) dS`
153/// This function returns a symbolic equation representing the theorem.
154pub fn gauss_theorem(vector_field: &Vector, volume: &Expr) -> Expr {
155    let div_f = super::vector::divergence(vector_field, ("x", "y", "z"));
156    let integral_div = Expr::VolumeIntegral {
157        scalar_field: Arc::new(div_f),
158        volume: Arc::new(volume.clone()),
159    };
160    let surface_integral = Expr::SurfaceIntegral {
161        vector_field: Arc::new(Expr::Variable("F".to_string())),
162        surface: Arc::new(boundary(volume)),
163    };
164    Expr::Eq(Arc::new(integral_div), Arc::new(surface_integral))
165}
166/// Represents the classical Stokes' Theorem as a special case of the generalized theorem.
167///
168/// It relates the integral of the curl of a vector field over a surface `S` to the
169/// line integral of the vector field over its boundary `∂S`.
170/// Formula: `∫_S (∇ × F) · dS = ∮_{∂S} F · dr`
171/// This function returns a symbolic equation representing the theorem.
172pub fn stokes_theorem(vector_field: &Vector, surface: &Expr) -> Expr {
173    let curl_f = super::vector::curl(vector_field, ("x", "y", "z"));
174    let integral_curl = Expr::SurfaceIntegral {
175        vector_field: Arc::new(curl_f.to_expr()),
176        surface: Arc::new(surface.clone()),
177    };
178    let line_integral = Expr::Integral {
179        integrand: Arc::new(Expr::Variable("F · dr".to_string())),
180        var: Arc::new(Expr::Variable("t".to_string())),
181        lower_bound: Arc::new(boundary(surface)),
182        upper_bound: Arc::new(Expr::BigInt(BigInt::zero())),
183    };
184    Expr::Eq(Arc::new(integral_curl), Arc::new(line_integral))
185}
186/// Represents Green's Theorem as a 2D special case of Stokes' Theorem.
187///
188/// It relates a line integral around a simple closed curve `C` to a double integral
189/// over the plane region `D` bounded by `C`.
190/// Formula: `∬_D (∂Q/∂x - ∂P/∂y) dA = ∮_{∂D} P dx + Q dy`
191/// This function returns a symbolic equation representing the theorem.
192pub fn greens_theorem(p: &Expr, q: &Expr, domain: &Expr) -> Expr {
193    let dq_dx = differentiate(q, "x");
194    let dp_dy = differentiate(p, "y");
195    let integrand_da = simplify(&Expr::new_sub(dq_dx, dp_dy));
196    let integral_da = definite_integrate(
197        &integrand_da,
198        "A",
199        &Expr::Domain(format!("{}", domain)),
200        &Expr::BigInt(BigInt::zero()),
201    );
202    let integrand_line = Expr::new_add(
203        Expr::new_mul(p.clone(), Expr::Variable("dx".to_string())),
204        Expr::new_mul(q.clone(), Expr::Variable("dy".to_string())),
205    );
206    let line_integral = Expr::Integral {
207        integrand: Arc::new(integrand_line),
208        var: Arc::new(Expr::Variable("t".to_string())),
209        lower_bound: Arc::new(boundary(domain)),
210        upper_bound: Arc::new(Expr::BigInt(BigInt::zero())),
211    };
212    Expr::Eq(Arc::new(integral_da), Arc::new(line_integral))
213}