Skip to content

This file is also available as a jupyter notebook and a julia file:

download nbviewer download

Quaternion algebras

Creation

julia
julia> Q = quaternion_algebra(QQ, -1, -1)
Quaternion algebra
  over rational field
  defined by i^2 = -1, j^2 = -1

Construct the standard basis:

julia
julia> _, i, j, k = basis(Q)
4-element Vector{AssociativeAlgebraElem{QQFieldElem, Hecke.QuaternionAlgebra{QQFieldElem}}}:
 1
 i
 j
 k

Verifying the relations:

julia
julia> i^2 == -1 && j^2 == -1 && i * j == k
true

Construction of elements:

julia
julia> alpha = 1 + 2*i + 3*j
1 + 2*i + 3*j

Or via directly supplying the coordinates as a vector:

julia
julia> alpha == Q([1, 2, 3, 0])
true

This works for also for number fields:

julia
julia> K, sqrt2 = quadratic_field(2)
(Real quadratic field defined by x^2 - 2, sqrt(2))

julia> Q = quaternion_algebra(K, sqrt2, K(3))
Quaternion algebra
  over real quadratic field defined by x^2 - 2
  defined by i^2 = sqrt(2), j^2 = 3

julia> alpha = Q([sqrt2, 1, 0, 1])
sqrt(2) + i + k

Properties of elements

Get the coefficients with respect to the canonical basis:

julia
julia> coefficients(alpha)
4-element Vector{AbsSimpleNumFieldElem}:
 sqrt(2)
 1
 0
 1

Trace and norm (also reduced version)

julia
julia> tr(alpha), norm(alpha)
(4*sqrt(2), 8*sqrt(2) + 12)
julia
julia> trred(alpha), normred(alpha)
(2*sqrt(2), 2*sqrt(2) + 2)

Image of elements under canonical involution:

julia
julia> conjugate(alpha)
sqrt(2) - i - k
julia
julia> normred(alpha) == conjugate(alpha) * alpha
true

Division

For division there are the two functions divexact_left and divexact_right. If c = divexact_right(a, b), then a == c * b. So, divexact_right(a, b) returns an element c, such that b becomes a right-divisor of a.

julia
julia> _, i, j, k = basis(Q);
julia
julia> divexact_right(k, j)
i
julia
julia> k == i * j
true
julia
julia> divexact_left(k, j)
-i
julia
julia> k == j * (-i)
true

Polynomials

Polynomials behave very much like polynonomials over commutative rings, except that everything related to divisions needs to specifiy the "side".

julia
julia> Q = quaternion_algebra(QQ, -1, -1)
Quaternion algebra
  over rational field
  defined by i^2 = -1, j^2 = -1

julia> _, i, j, k = basis(Q)
4-element Vector{AssociativeAlgebraElem{QQFieldElem, Hecke.QuaternionAlgebra{QQFieldElem}}}:
 1
 i
 j
 k

julia> Qx, x = Q[:x]
(Univariate polynomial ring in x over quaternion algebra, x)

julia> f = i * x^2 + j * x
i*x^2 + j*x

julia> g = i * x
i*x
julia
julia> divexact_right(f, g) == x + k
true
julia
julia> divexact_left(f, g) == x + (- k)
true
julia
julia> Hecke.divrem_right(f, g)
(x + k, 0)
julia
julia> Hecke.gcd_right(f, g)
i*x

Splitting of quaternion algebras

julia
julia> Q = quaternion_algebra(QQ, -1, -1)
Quaternion algebra
  over rational field
  defined by i^2 = -1, j^2 = -1

julia> is_split(Q)
false
julia
julia> Q = quaternion_algebra(QQ, 1, -1)
Quaternion algebra
  over rational field
  defined by i^2 = 1, j^2 = -1

julia> is_split(Q)
true
julia
julia> is_split_with_zero_divisor(Q)
(true, 1 + i)

Solving norm equations

Let's solve a norm equation. We want to check whether 2 is a norm of Q(2).

julia
julia> K, sqrt2 = quadratic_field(2)
(Real quadratic field defined by x^2 - 2, sqrt(2))
julia
julia> fl, a = is_norm(K, 2);
julia
julia> fl
true

Since elements with given norm are in general large, they are represented in special "factored" form:

julia
julia> a
(sqrt(2) + 64)^1*89^-1*(sqrt(2) + 25)^1*23^-1*1^-1*(sqrt(2) + 5)^1*7^-1*(sqrt(2) + 3)^1

We can turn this into an ordinary elements using evaluate:

julia
julia> b = evaluate(a)
sqrt(2) + 2
julia
julia> norm(b) == 2
true

If we know that a norm equation has a solution, we can directly ask for it:

julia
julia> norm_equation(K, 2)
sqrt(2) + 2

Representation by binary quadratic forms

Assume that we have two diagonal quadratic forms q1=a1,a2 and q2=b1,b2 over a field K. We want to find an element d, which is represented both by q1 and q2.

julia
julia> K = QQ;
julia
julia> a1, a2 = 2, 3
(2, 3)
julia
julia> b1, b2 = 3, 4
(3, 4)

We form the quadratic form q=a1,a2,b1,b2. Then the task becomes finding an isotropic vector.

julia
julia> q = quadratic_space(K, diagonal_matrix(K, [a1, a2, -b1, b2]));

Checking whether such an isotropic vector exists:

julia
julia> is_isotropic(q)
true
julia
julia> fl, v = is_isotropic_with_vector(q)
(true, QQFieldElem[0, -1//6, 1//6, 0])

To extract the element d, we need to evaluate the quadratic form:

julia
julia> d = v[1]^2 * a1 + v[2]^2 * a2
1//12
julia
julia> v[1]^2 * a1 + v[2]^2 * a2 == v[3]^2 * b1 + v[4]^2 * b2
true