"""
return self.from_matrix(self._vector_space.ambient()(l))
+
+
+
+class HnClan(NormalDecomposition):
+ r"""
+ The normally-decomposed clan of complex Hermitian matrices of a
+ given size with the clan product and lower-triangular basis
+ ordering of Ishi, based on the up-hat and down-hat products of
+ Vinberg.
+
+ EXAMPLES:
+
+ The rank of this clan is the size of the matrices::
+
+ sage: n = ZZ.random_element(1,5)
+ sage: C = HnClan(n)
+ sage: C.rank() == n
+ True
+
+ Verifying the axioms::
+
+ sage: n = 3
+ sage: C = HnClan(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
+
+ With a little effort, we can lift elements of the clan back into
+ the original (asymmetric) matrix space::
+
+ sage: C = HnClan(3)
+ sage: x = C.an_element(); x
+ 2*B(0, 0, 1) + 3*B(1, 0, I) + 2*B(1, 0, 1)
+ sage: x.lift().lift()
+ ┌─────────┬──────────┬───┐
+ │ 2 │ -3*I + 2 │ 0 │
+ ├─────────┼──────────┼───┤
+ │ 3*I + 2 │ 0 │ 0 │
+ ├─────────┼──────────┼───┤
+ │ 0 │ 0 │ 0 │
+ └─────────┴──────────┴───┘
+
+ """
+ def __init__(self, n, scalar_field=QQ, **kwargs):
+ from mjo.hurwitz import ComplexMatrixAlgebra
+ from sage.rings.qqbar import QQbar
+ Mn = ComplexMatrixAlgebra(n, QQbar, scalar_field)
+ b = Mn.basis()
+
+ from sage.sets.family import Family
+ Hn_basis = Family({
+ (i,j,k) : z
+ for (i,j,k) in b.keys()
+ if j <= i
+ if (a := 1 - (i == j)/scalar_field(2))
+ if (z := a*(b[i,j,k] + b[i,j,k].conjugate_transpose()))
+ })
+
+ # Mn.submodule() destroys our basis keys, so use
+ # SubmoduleWithBasis directly.
+ Hn = SubmoduleWithBasis(Hn_basis,
+ support_order=b.keys(),
+ ambient=Mn)
+
+ def up_hat(x):
+ return Mn.sum_of_terms(
+ ((i,j,k), a*c)
+ for ((i,j,k),c) in x.items()
+ if i <= j
+ if (a := 1 - (i == j)/scalar_field(2))
+ )
+
+ def down_hat(x):
+ return up_hat(x.transpose()).transpose()
+
+ def cp(x,y):
+ x = x.lift()
+ y = y.lift()
+ return Hn(down_hat(x)*y + y*up_hat(x))
+
+ def ip(x,y):
+ p = cp(x,y) / scalar_field(2)
+ one = QQbar(1) # weird indexing in Hurwitz matrix algebras
+ return sum( p[i,i,one] for i in range(n) )
+
+ super().__init__(Hn, cp, ip, **kwargs)