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.
+ 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::
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)
"""
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):
#
# (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)
"""
return (f"Jordan spin clan of dimension {self.dimension()} "
f"over {self.base_ring()}")
-