Skip to main content

Quotient

Trait Quotient 

Source
pub trait Quotient<G: LieGroup<V>, H: LieGroup<V>, V: Vector>: Point {
    // Required methods
    fn new(g: G) -> Self;
    fn lift(&self) -> G;
    fn embed(h: H) -> G;

    // Provided methods
    fn quotient_identity() -> Self { ... }
    fn quotient_compose(&self, other: &Self) -> Self { ... }
    fn quotient_inverse(&self) -> Self { ... }
    fn quotient_identity_exp(v: V) -> Self { ... }
    fn quotient_identity_log(p: &Self) -> Option<V> { ... }
    fn check_new_respects_coset(g: G, h: H) -> bool
       where Self: PartialEq { ... }
}
Expand description

A quotient of a Lie group by a central subgroup.

The space of all values of a type Q: Quotient<G, H, V> is interpreted as the quotient group G/H — the set of cosets gH, with the group operation inherited from G. This requires H to be central in G (so the quotient is well-defined and the cosets gH and Hg coincide), which in particular makes H automatically normal.

§The lift/canonical pattern

Rather than representing a coset abstractly, Quotient requires a concrete representation via two operations:

  • Quotient::new maps a value g: G to the Quotient value representing its coset gH. It must satisfy canonical(g) == canonical(h.compose(g)) for every h: H (acting on g via G’s own composition) — i.e. it must not distinguish between elements of the same coset. Beyond that one algebraic requirement, canonical is free to be any deterministic, even discontinuous, choice function; it need not be smooth or continuous, since it carries no geometric content of its own. For S³ / {±1} → SO(3), canonical is a sign comparison on the real component; for (R\{0}, ×) / {±1} → (R⁺, ×), it is |x|.

  • Quotient::lift recovers some representative g: G of the coset, satisfying canonical(self.lift()) == self for every self: Q. Which representative is returned is unspecified beyond that round-trip property — only one of possibly several valid choices needs to be produced.

All group structure on Q — composition, inverse, the exponential map at the identity — is defined generically in terms of G’s own structure by lifting, operating in G, and re-applying canonical: a.compose(b) = canonical(a.lift().compose(&b.lift())). This works because all the differential structure lives in G, which is already known to be smooth; canonical is purely a bookkeeping step applied after the smooth operation completes, never a smoothness-bearing operation in its own right. The map G → G/H being a covering map (a local diffeomorphism) is what makes G/H itself a smooth manifold, even though canonical — being a global choice of representative — is typically forced to be discontinuous somewhere, an unavoidable topological obstruction rather than evidence that canonical was chosen poorly.

§Why H must be central

Centrality (h.compose(g) == g.compose(h) for all g: G, h: H) is what makes left cosets and right cosets coincide, which is what makes G/H a group rather than merely a set of cosets with no induced operation. Sphere<0, V>{1, -1} under the relevant composition — is central in every Sphere<N, V> for N ∈ {0, 1, 3} precisely because -1 commutes with everything (it is, after all, just a scalar multiple of the identity), which is what makes S³/{±1} → SO(3) and (R\{0}, ×)/{±1} → (R⁺, ×) both legitimate instances of this trait.

Required Methods§

Source

fn new(g: G) -> Self

Maps g to the Quotient value representing its coset gH.

Source

fn lift(&self) -> G

Recovers a representative of self’s coset, satisfying new(self.lift()) == self.

This is not merely “some” representative: lift must return the one nearest the identity, in the sense that identity_log’s result (built from lift, see quotient_identity_log) reports the same norm as Metric::distance from the identity. A lift that satisfies new(self.lift()) == self without also being nearest will still pass every Quotient/Group/LieGroup axiom test — those are satisfied by any valid representative choice — but will silently produce a geometrically wrong identity_log, and hence a wrong Chart/ExpMap/Metric for the whole type. This is exactly what test_riemannian!’s chart_metric_compatibility catches: it is the test that certifies lift chose correctly, not a separate property to verify independently.

Source

fn embed(h: H) -> G

the subgroup inclusion H ↪ G

Provided Methods§

Source

fn quotient_identity() -> Self

Source

fn quotient_compose(&self, other: &Self) -> Self

Source

fn quotient_inverse(&self) -> Self

Source

fn quotient_identity_exp(v: V) -> Self

Source

fn quotient_identity_log(p: &Self) -> Option<V>

Source

fn check_new_respects_coset(g: G, h: H) -> bool
where Self: PartialEq,

The sole independent Quotient axiom: new must not distinguish elements of the same coset. Everything else (group structure, differential structure) follows from this plus the inherited LieGroup axioms.

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§

Source§

impl<R: Real> Quotient<Sl<Coords<Complex<R>, 2>, 2>, RootOfUnity<Complex<R>, 2>, SlAlgebra<Complex<R>, 2, 3>> for Lorentz<R>

Source§

impl<V: Euclidean<F: Real> + From<[<V as Vector>::F; 1]>> Quotient<V, Z<V>, V> for S1<V>

Source§

impl<V: Euclidean> Quotient<S3<V>, RootOfUnity<<V as Vector>::F, 2>, V> for So3<V>