]> gitweb.michael.orlitzky.com - sage.d.git/commitdiff
mjo/clan/jordan_spin_clan.py: first steps towards an implementation
authorMichael Orlitzky <michael@orlitzky.com>
Wed, 4 Mar 2026 02:00:57 +0000 (21:00 -0500)
committerMichael Orlitzky <michael@orlitzky.com>
Wed, 4 Mar 2026 02:00:57 +0000 (21:00 -0500)
mjo/clan/jordan_spin_clan.py [new file with mode: 0644]

diff --git a/mjo/clan/jordan_spin_clan.py b/mjo/clan/jordan_spin_clan.py
new file mode 100644 (file)
index 0000000..12282f9
--- /dev/null
@@ -0,0 +1,112 @@
+from mjo.clan.normal_decomposition import NormalDecomposition
+
+class JordanSpinClan(NormalDecomposition):
+    r"""
+    The clan associated with the T-algebra associated with the
+    Jordan spin (Euclidean Jordan) algebra.
+
+    Named after :class:`mjo.eja.eja_algebra.JordanSpinEJA`. This could
+    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 + <a12,b21> and similarly
+    for (a*b)_22; otherwise, the identity isn't an identity.
+
+    SETUP::
+
+        sage: from mjo.clan.jordan_spin_clan import JordanSpinClan
+
+    TESTS:
+
+    Verifying the axioms::
+
+        sage: n = ZZ.random_element(2,10)
+        sage: C = JordanSpinClan(n)
+        sage: e = C.basis()
+        sage: r = C.rank()
+        sage: all( e[i,j,k]*e[i,j,k] == e[i,j,k]
+        ....:      for (i,j,k) in e.keys()
+        ....:      if i == j )
+        True
+        sage: all( C.idempotent(i)*e[j,i,k] == e[j,i,k]/2
+        ....:      for (i,j,k) in e.keys()
+        ....:      if i < j )
+        True
+        sage: all( C.idempotent(i)*e[i,k,z] == e[i,k,z]/2
+        ....:      for (i,k,z) in e.keys()
+        ....:      if k < i)
+        True
+        sage: all( (C.idempotent(i)*e[j,k,l]).is_zero()
+        ....:      for i in range(r)
+        ....:      for (j,k,l) in e.keys()
+        ....:      if k <= j and i not in [j,k] )
+        True
+        sage: all( (e[i,k,l]*C.idempotent(i)).is_zero()
+        ....:      for (i,k,l) in e.keys()
+        ....:      if k < i )
+        True
+        sage: all( (e[j,k,l]*C.idempotent(i)).is_zero()
+        ....:      for i in range(r)
+        ....:      for (j,k,l) in e.keys()
+        ....:      if i not in [j,k] )
+        True
+
+    """
+    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)
+
+        two = scalar_field(2)
+
+        def cp(x,y):
+            # 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()
+            y11 = y[0]
+            y_bar = y[1:-1]
+            y22 = y[-1]
+
+            # z = x*y
+            V = x.parent()
+            z11 = x11*y11
+            z21 = y_bar*(x11 + x22)/two + y11*x_bar
+            z22 = x22*y22 + x_bar.inner_product(y_bar)
+            z_coords = [z11] + list(z21) + [z22]
+            return RN.from_vector(V(z_coords))
+
+        def ip(x,y):
+            p = cp(x,y) / two
+            return p[(0,0,1)] + p[(1,1,1)]  # sum of diagonals
+
+        super().__init__(RN, cp, ip, **kwargs)
+
+
+    def __repr__(self) -> str:
+        r"""
+        The string representation of this clan.
+
+        SETUP::
+
+            sage: from mjo.clan.jordan_spin_clan import JordanSpinClan
+
+        EXAMPLES::
+
+            sage: JordanSpinClan(3)
+            Jordan spin clan of dimension 3 over Rational Field
+
+        """
+        return (f"Jordan spin clan of dimension {self.dimension()} "
+                f"over {self.base_ring()}")
+