From 6246ef4fffdaf3e79cda967a43c7bb75baf2bed7 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Wed, 4 Mar 2026 07:47:14 -0500 Subject: [PATCH] mjo/clan/jordan_spin_clan.py: support n=1 (the real numbers) --- mjo/clan/jordan_spin_clan.py | 71 ++++++++++++++++++++++++++---------- 1 file changed, 52 insertions(+), 19 deletions(-) diff --git a/mjo/clan/jordan_spin_clan.py b/mjo/clan/jordan_spin_clan.py index 7eabc84..54fc623 100644 --- a/mjo/clan/jordan_spin_clan.py +++ b/mjo/clan/jordan_spin_clan.py @@ -9,10 +9,18 @@ class JordanSpinClan(NormalDecomposition): be a :class:`mjo.clan.t_algebra_clan.TAlgebraClan`, but it isn't implemented that way because the T-algebra is not readily available (we'd have to built it, too). The T-algebra formulation - is described in *T-algebras and linear optimization over symmetric - cones* by Chek Beng Chua, but the formula for the diagonals is actually - wrong. It has to be (a*b)_11 = a11*b11 + and similarly - for (a*b)_22; otherwise, the identity isn't an identity. + is perhaps best described by [Gindikin1992]_ in his example (e), + on pages 89-90. + + We make minor adjustments to support `n=1` as an argument. + + REFERENCES: + + .. [Gindikin1992] Simon Gindikin. + *Tube domains and the Cauchy problem*, + vol. 111 of Translations of Mathematical Monographs. + American Mathematical Society, Providence, Rhode Island, 1992. + ISBN 0821845667. SETUP:: @@ -35,6 +43,20 @@ class JordanSpinClan(NormalDecomposition): TESTS: + One-dimensional instances (the real numbers, essentially) work:: + + sage: C = JordanSpinClan(1); C + Jordan spin clan of dimension 1 over Rational Field + sage: C.dimension() + 1 + sage: C.basis() + Finite family {(0, 0, 1): B(0, 0, 1)} + sage: C.one() + B(0, 0, 1) + sage: x = C.from_vector(vector(QQ,[7])) + sage: x.D(0) + 7 + Verifying the axioms:: sage: n = ZZ.random_element(2,10) @@ -71,34 +93,46 @@ class JordanSpinClan(NormalDecomposition): """ from sage.rings.rational_field import QQ def __init__(self, n, scalar_field=QQ, **kwargs): - if n < 2: - raise ValueError("You want the real numbers?") from sage.modules.free_module import VectorSpace - # We need an Ishi basis (i,j,k) for R^N if we want to use - # NormalDecomposition. - indices = [(0,0,1)] + [(1,0,k) for k in range(1, n-1)] + [(1,1,1)] - RN = VectorSpace(scalar_field, indices) + if n == 1: + # The T-algebra construction requires n >= 2, but we + # know that in dimension one this clan corresponds to + # a single ray, and is essentially the real numbers. + indices = [(0,0,1)] + else: + # We need an Ishi basis (i,j,k) for R^N if we want to use + # NormalDecomposition. + indices = [(0,0,1)] + [(1,0,k) for k in range(1, n-1)] + [(1,1,1)] + RN = VectorSpace(scalar_field, indices) two = scalar_field(2) def cp(x,y): - # keep in mind, x and y will be (basis) elements of RN + # Keep in mind, x and y will be (basis) elements of RN x = x.to_vector() - x11 = x[0] - x_bar = x[1:-1] - x22 = x[-1] y = y.to_vector() + V = x.parent() + + x11 = x[0] y11 = y[0] + z11 = x11*y11 # z = x*y + + if n == 1: + return RN.from_vector(V([z11])) + + # Will be empty for n=2 + x_bar = x[1:-1] y_bar = y[1:-1] + + x22 = x[-1] y22 = y[-1] - # z = x*y - V = x.parent() - z11 = x11*y11 + # Computed by hand using down-hat and up-hat z21 = y_bar*(x11 + x22)/two + y11*x_bar z22 = x22*y22 + 2*x_bar.inner_product(y_bar) z_coords = [z11] + list(z21) + [z22] + return RN.from_vector(V(z_coords)) def ip(x,y): @@ -110,7 +144,7 @@ class JordanSpinClan(NormalDecomposition): # # (The off-diagonals are weighted more than usual.) p = cp(x,y) / two - return p[(0,0,1)] + p[(1,1,1)] + return sum( p[idx] for idx in indices if idx[0] == idx[1] ) super().__init__(RN, cp, ip, **kwargs) @@ -131,4 +165,3 @@ class JordanSpinClan(NormalDecomposition): """ return (f"Jordan spin clan of dimension {self.dimension()} " f"over {self.base_ring()}") - -- 2.51.0