# Octonion Algebras#

AUTHORS:

• Travis Scrimshaw (2023-05-06): Initial version

class sage.algebras.octonion_algebra.Octonion#

An octonion.

This is an element of the octonion algebra with parameters $$a = b = c = -1$$, which is a classical octonion number.

norm()#

Return the norm of self.

The norm of an octonion $$x$$ is $$\lVert x \rVert = \sqrt{x x^*}$$, where $$x^*$$ is the conjugate() of $$x$$.

This is the square root of quadratic_form().

EXAMPLES:

sage: O = OctonionAlgebra(QQ)
sage: elt = sum(i * b for i, b in enumerate(O.basis(), start=2))
sage: elt.norm()
2*sqrt(71)
sage: elt = sum(O.basis())
sage: elt.norm()
2*sqrt(2)


Return the quadratic form of self.

The octonion algebra has a distinguished quadratic form given by $$N(x) = x x^*$$, where $$x^*$$ is the conjugate() of $$x$$.

EXAMPLES:

sage: O = OctonionAlgebra(QQ)
sage: elt = sum(O.basis()); elt
1 + i + j + k + l + li + lj + lk
8
sage: elt * elt.conjugate()
8

class sage.algebras.octonion_algebra.OctonionAlgebra(R, a, b, c, names)#

The octonion algebra.

Let $$R$$ be a commutative ring of characteristic not equal to $$2$$. The octonion algebra with parameters $$a, b, c$$ is a non-associative non-commutative unital 8-dimensional $$R$$-algebra that is a deformation of the usual octonions, which are when $$a = b = c = -1$$. The octonions were originally constructed by Graves and independently discovered by Cayley (due to being published first, these are sometimes called the Cayley numbers) and can also be built from the Cayley-Dickson construction with the quaternions.

We use the multiplication table from [Scha1996]. The octonion algebra $$\mathbf{O}_{a,b,c}(R)$$ is a composition (Hurwitz) algebra, which means it is also an alternative algebra as it satisfies $$x^2 y = (x x) y = x (x y)$$ and $$y x^2 = y (x x) = (y x) x$$ for all $$x, y \in \mathbf{O}_{a,b,c}$$.

EXAMPLES:

We first create the classical octonions and perform some basic computations:

sage: O = OctonionAlgebra(QQ)
sage: O
Octonion algebra over Rational Field
sage: i, j, k, l = O.gens()
sage: i * j * k
1
sage: k * j * i
-1
sage: (i * k) * l
-lj
sage: i * (k * l)
lj
sage: elt = sum(O.basis())
sage: elt^2
-6 + 2*i + 2*j + 2*k + 2*l + 2*li + 2*lj + 2*lk
sage: prod(O.basis())
1
sage: (i + l)^2
-2
sage: (1 + l) * (1 + l).conjugate()
2
sage: S = O.some_elements()
sage: B = O.basis()
sage: S.extend(x * (i + j/2 - 5*k/3) for x in O.some_elements())
sage: all((x * x) * y == (x * (x * y)) for x in S for y in S)
True
sage: all(y * (x * x) == (y * x) * x for x in S for y in S)
True
sage: all((x + x.conjugate()) / 2 == x.real_part() for x in S)
True
sage: all((x - x.conjugate()) / 2 == x.imag_part() for x in S)
True
sage: all(sum((b*x)*b for b in B) == -6 * x.conjugate() for x in S)
True


We construct the (rescaled) $$E_8$$ lattice as the integral octonions, which we verify by constructing $$240$$ shortest length elements in the lattice (see also Wikipedia article E8_lattice#Integral_octonions):

sage: m = (i + j + k + l) / 2
sage: basis = [i, j, i*j, i^2, m, i * m, j * m, (i * j) * m]
sage: basis
[i,
j,
-k,
-1,
1/2*i + 1/2*j + 1/2*k + 1/2*l,
-1/2 + 1/2*j - 1/2*k - 1/2*li,
-1/2 - 1/2*i + 1/2*k - 1/2*lj,
1/2 - 1/2*i + 1/2*j + 1/2*lk]
sage: matrix([vector(b) for b in basis]).rank()
8
sage: [b.norm() for b in basis]
[1, 1, 1, 1, 1, 1, 1, 1]
sage: roots = set(basis)
sage: roots.update(-b for b in basis)
sage: new_roots = set(roots)  # make a copy
sage: while new_roots:
....:     prev_roots = new_roots
....:     new_roots = set()
....:     for a in prev_roots:
....:         for b in roots:
....:             c = a + b
....:             if c.quadratic_form() != 1 or c in roots:
....:                 continue
....:             new_roots.update([c, -c])
....:         roots.update(new_roots)
sage: len(roots)
240


A classical construction of the Lie algebra of type $$G_2$$ is the Lie algebra of all derivations of $$\mathbf{O}$$ (as the automorphism group is the Lie group of type $$G_2$$). We verify that the derivations have the correct dimension:

sage: len(O.derivations_basis())
14


We can construct the split octonions by taking the parameter $$c = 1$$:

sage: SO = OctonionAlgebra(QQ, c=1)
sage: SO
Octonion algebra over Rational Field with parameters (-1, -1, 1)
sage: i, j, k, l = SO.gens()
sage: i^2 == j^2 == k^2 == -1
True
sage: l^2
1
sage: (i + l)^2
0
sage: (1 + l) * (1 + l).conjugate()
0


REFERENCES:

Element#

alias of Octonion_generic

basis()#

Return the basis of self.

EXAMPLES:

sage: O = OctonionAlgebra(ZZ)
sage: O.basis()
Family (1, i, j, k, l, li, lj, lk)

gens()#

Return the generators of self.

EXAMPLES:

sage: O = OctonionAlgebra(ZZ)
sage: O.gens()
(i, j, k, l)

one_basis()#

Return the index for the basis element of $$1$$.

EXAMPLES:

sage: O = OctonionAlgebra(ZZ)
sage: O.one_basis()
0

some_elements()#

Return some elements of self.

EXAMPLES:

sage: O = OctonionAlgebra(ZZ)
sage: O.some_elements()
[2, 1, i, j, k, l, li, lj, lk,
2 + 3*i + 4*j + 5*k + 6*l + 7*li + 8*lj + 9*lk,
-2*j + 3*k - li - lj,
8 - 7*i + 2*j + 13*k - 18*l + 45*li - 40*lj + 5*lk]
sage: O = OctonionAlgebra(Zmod(6))
sage: O.some_elements()
[2, 1, i, j, k, l, li, lj, lk,
2 + 3*i + 4*j + 5*k + li + 2*lj + 3*lk,
4*j + 3*k + 5*li + 5*lj,
2 + 5*i + 2*j + k + 3*li + 2*lj + 5*lk]

class sage.algebras.octonion_algebra.Octonion_generic#

Bases: AlgebraElement

An octonion with generic parameters.

abs()#

Return the absolute value of self.

This is equal to the norm().

Warning

If any of the parameters $$a, b, c \not> 0$$, then this does not define a metric.

EXAMPLES:

sage: O = OctonionAlgebra(QQ, 1, 3, 7)
sage: elt = sum(i * b for i, b in enumerate(O.basis(), start=2))
sage: elt.abs()
2*sqrt(-61)
sage: elt = sum(O.basis())
sage: elt.abs()
0

conjugate()#

Return the conjugate of self.

EXAMPLES:

sage: O = OctonionAlgebra(QQ)
sage: elt = sum(O.basis()); elt
1 + i + j + k + l + li + lj + lk
sage: elt.conjugate()
1 - i - j - k - l - li - lj - lk

dict(copy=False)#

Return self as a dict with keys being indices for the basis and the values being the corresponding nonzero coefficients.

INPUT:

• copy – ignored

EXAMPLES:

sage: O = OctonionAlgebra(QQ)
sage: x = O([2/7, 0, 0, 0, 2/3, 0, -5, 0])
sage: x.monomial_coefficients()
{0: 2/7, 4: 2/3, 6: -5}

imag_part()#

Return the imginary part of self.

OUTPUT:

The imaginary part of self as an element in the octonion algebra.

EXAMPLES:

sage: O = OctonionAlgebra(QQ)
sage: elt = sum(i * b for i, b in enumerate(O.basis(), start=2)); elt
2 + 3*i + 4*j + 5*k + 6*l + 7*li + 8*lj + 9*lk
sage: elt.imag_part()
3*i + 4*j + 5*k + 6*l + 7*li + 8*lj + 9*lk

is_unit()#

Return if self is a unit or not.

EXAMPLES:

sage: O = OctonionAlgebra(ZZ)
sage: x = O([1, 0, 1, 0, 0, 0, 0, 0])
2
sage: x.is_unit()
False
sage: O([1, 0, -1, 0, 0, 0, 0, 0]).is_unit()
False
sage: x = O([1, 0, 0, 0, 1, 0, 0, 0])
2
sage: x.is_unit()
False
sage: x = O([0, 0, 0, 0, 1, 0, 0, 0])
1
sage: x.is_unit()
True

sage: O = OctonionAlgebra(ZZ, -1, 1, 2)
sage: x = O([1, 0, 1, 0, 0, 0, 0, 0])
0
sage: x.is_unit()
False
sage: O([1, 0, -1, 0, 0, 0, 0, 0]).is_unit()
False
sage: x = O([1, 0, 0, 0, 1, 0, 0, 0])
-1
sage: x.is_unit()
True
sage: x = O([0, 0, 0, 0, 1, 0, 0, 0])
-2
sage: x.is_unit()
False

monomial_coefficients(copy=False)#

Return self as a dict with keys being indices for the basis and the values being the corresponding nonzero coefficients.

INPUT:

• copy – ignored

EXAMPLES:

sage: O = OctonionAlgebra(QQ)
sage: x = O([2/7, 0, 0, 0, 2/3, 0, -5, 0])
sage: x.monomial_coefficients()
{0: 2/7, 4: 2/3, 6: -5}

norm()#

Return the norm of self.

The norm of an octonion $$x$$ is $$\lVert x \rVert = \sqrt{x x^*}$$, where $$x^*$$ is the conjugate() of $$x$$.

This is the square root of quadratic_form().

Warning

If any of the parameters $$a, b, c \not> 0$$, then this is not an actual norm.

EXAMPLES:

sage: O = OctonionAlgebra(QQ, 1, 3, 7)
sage: elt = sum(i * b for i, b in enumerate(O.basis(), start=2))
sage: elt.norm()
2*sqrt(-61)
sage: elt = sum(O.basis())
sage: elt.norm()
0


Return the quadratic form of self.

The octonion algebra has a distinguished quadratic form given by $$N(x) = x x^*$$, where $$x^*$$ is the conjugate() of $$x$$.

EXAMPLES:

sage: O = OctonionAlgebra(QQ, 1, 3, 7)
sage: elt = sum(O.basis())
0
sage: elt * elt.conjugate()
0

real_part()#

Return the real part of self.

OUTPUT:

The real part of self as an element in the base ring.

EXAMPLES:

sage: O = OctonionAlgebra(QQ)
sage: elt = sum(i * b for i, b in enumerate(O.basis(), start=2)); elt
2 + 3*i + 4*j + 5*k + 6*l + 7*li + 8*lj + 9*lk
sage: r = elt.real_part(); r
2
sage: r.parent() is QQ
True

vector(new_base_ring=None)#

Return self as a vector in $$R^8$$, where $$R$$ is the base ring of self.

EXAMPLES:

sage: O = OctonionAlgebra(QQ)
sage: elt = sum(i * b for i, b in enumerate(O.basis(), start=2))
sage: elt.vector()
(2, 3, 4, 5, 6, 7, 8, 9)