Skip to content

Lattices

Creation of lattices

Inside a given ambient space

# latticeMethod.
julia
lattice(V::AbstractSpace) -> AbstractLat

Given an ambient space V, return the lattice with the standard basis matrix. If V is hermitian (resp. quadratic) then the output is a hermitian (resp. quadratic) lattice.

source


# latticeMethod.
julia
lattice(V::AbstractSpace, B::PMat ; check::Bool = true) -> AbstractLat

Given an ambient space V and a pseudo-matrix B, return the lattice spanned by the pseudo-matrix B inside V. If V is hermitian (resp. quadratic) then the output is a hermitian (resp. quadratic) lattice.

By default, B is checked to be of full rank. This test can be disabled by setting check to false.

source


# latticeMethod.
julia
lattice(V::AbstractSpace, basis::MatElem ; check::Bool = true) -> AbstractLat

Given an ambient space V and a matrix basis, return the lattice spanned by the rows of basis inside V. If V is hermitian (resp. quadratic) then the output is a hermitian (resp. quadratic) lattice.

By default, basis is checked to be of full rank. This test can be disabled by setting check to false.

source


# latticeMethod.
julia
lattice(V::AbstractSpace, gens::Vector) -> AbstractLat

Given an ambient space V and a list of generators gens, return the lattice spanned by gens in V. If V is hermitian (resp. quadratic) then the output is a hermitian (resp. quadratic) lattice.

If gens is empty, the function returns the zero lattice in V.

source


Quadratic lattice over a number field

# quadratic_latticeMethod.
julia
quadratic_lattice(K::Field ; gram::MatElem) -> Union{ZZLat, QuadLat}

Given a matrix gram and a field K, return the free quadratic lattice inside the quadratic space over K with Gram matrix gram.

If K=Q, then the output lattice is of type ZZLat, seen as a lattice over the ring Z.

source


# quadratic_latticeMethod.
julia
quadratic_lattice(K::Field, B::PMat ; gram = nothing,
                                      check:::Bool = true) -> QuadLat

Given a pseudo-matrix B with entries in a field K return the quadratic lattice spanned by the pseudo-matrix B inside the quadratic space over K with Gram matrix gram.

If gram is not supplied, the Gram matrix of the ambient space will be the identity matrix over K of size the number of columns of B.

By default, B is checked to be of full rank. This test can be disabled by setting check to false.

source


# quadratic_latticeMethod.
julia
quadratic_lattice(K::Field, basis::MatElem ; gram = nothing,
                                             check::Bool = true)
                                                      -> Union{ZZLat, QuadLat}

Given a matrix basis and a field K, return the quadratic lattice spanned by the rows of basis inside the quadratic space over K with Gram matrix gram.

If gram is not supplied, the Gram matrix of the ambient space will be the identity matrix over K of size the number of columns of basis.

By default, basis is checked to be of full rank. This test can be disabled by setting check to false.

If K=Q, then the output lattice is of type ZZLat, seen as a lattice over the ring Z.

source


# quadratic_latticeMethod.
julia
quadratic_lattice(K::Field, gens::Vector ; gram = nothing) -> Union{ZZLat, QuadLat}

Given a list of vectors gens and a field K, return the quadratic lattice spanned by the elements of gens inside the quadratic space over K with Gram matrix gram.

If gram is not supplied, the Gram matrix of the ambient space will be the identity matrix over K of size the length of the elements of gens.

If gens is empty, gram must be supplied and the function returns the zero lattice in the quadratic space over K with gram matrix gram.

If K=Q, then the output lattice is of type ZZLat, seen as a lattice over the ring Z.

source


Hermitian lattice over a degree 2 extension

# hermitian_latticeMethod.
julia
hermitian_lattice(E::NumField; gram::MatElem) -> HermLat

Given a matrix gram and a number field E of degree 2, return the free hermitian lattice inside the hermitian space over E with Gram matrix gram.

source


# hermitian_latticeMethod.
julia
hermitian_lattice(E::NumField, B::PMat; gram = nothing,
			             check::Bool = true) -> HermLat

Given a pseudo-matrix B with entries in a number field E of degree 2, return the hermitian lattice spanned by the pseudo-matrix B inside the hermitian space over E with Gram matrix gram.

If gram is not supplied, the Gram matrix of the ambient space will be the identity matrix over E of size the number of columns of B.

By default, B is checked to be of full rank. This test can be disabled by setting check to false.

source


# hermitian_latticeMethod.
julia
hermitian_lattice(E::NumField, basis::MatElem; gram = nothing,
			                    check::Bool = true) -> HermLat

Given a matrix basis and a number field E of degree 2, return the hermitian lattice spanned by the rows of basis inside the hermitian space over E with Gram matrix gram.

If gram is not supplied, the Gram matrix of the ambient space will be the identity matrix over E of size the number of columns of basis.

By default, basis is checked to be of full rank. This test can be disabled by setting check to false.

source


# hermitian_latticeMethod.
julia
hermitian_lattice(E::NumField, gens::Vector ; gram = nothing) -> HermLat

Given a list of vectors gens and a number field E of degree 2, return the hermitian lattice spanned by the elements of gens inside the hermitian space over E with Gram matrix gram.

If gram is not supplied, the Gram matrix of the ambient space will be the identity matrix over E of size the length of the elements of gens.

If gens is empty, gram must be supplied and the function returns the zero lattice in the hermitan space over E with Gram matrix gram.

source


Examples

The two following examples will be used all along this section:

julia

julia> K, a = rationals_as_number_field();

julia> Kt, t = K["t"];

julia> g = t^2 + 7;

julia> E, b = number_field(g, "b");

julia> D = matrix(K, 3, 3, [2, 0, 0, 0, 2, 0, 0, 0, 2]);

julia> gens = Vector{AbsSimpleNumFieldElem}[map(K, [1, 1, 0]), map(K, [1, 0, 1]), map(K, [2, 0, 0])];

julia> Lquad = quadratic_lattice(K, gens, gram = D)
Quadratic lattice of rank 3 and degree 3
  over maximal order of Number field of degree 1 over QQ
  with basis AbsSimpleNumFieldElem[1]

julia> D = matrix(E, 4, 4, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);

julia> gens = Vector{Hecke.RelSimpleNumFieldElem{AbsSimpleNumFieldElem}}[map(E, [2, -1, 0, 0]), map(E, [-3, 0, -1, 0]), map(E, [0, 0, 0, -1]), map(E, [b, 0, 0, 0])];

julia> Lherm = hermitian_lattice(E, gens, gram = D)
Hermitian lattice of rank 4 and degree 4
  over relative maximal order of Relative number field of degree 2 over number field
  with pseudo-basis
  (1, 1//1 * <1, 1>)
  (b + 1, 1//2 * <1, 1>)

Note that the format used here is the one given by the internal function Hecke.to_hecke() which prints REPL commands to get back the input lattice.

julia

julia> K, a = rationals_as_number_field();

julia> Kt, t = K["t"];

julia> g = t^2 + 7;

julia> E, b = number_field(g, "b");

julia> D = matrix(E, 4, 4, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);

julia> gens = Vector{Hecke.RelSimpleNumFieldElem{AbsSimpleNumFieldElem}}[map(E, [2, -1, 0, 0]), map(E, [-3, 0, -1, 0]), map(E, [0, 0, 0, -1]), map(E, [b, 0, 0, 0])];

julia> Lherm = hermitian_lattice(E, gens, gram = D);

julia> Hecke.to_hecke(Lherm)
Qx, x = polynomial_ring(FlintQQ, "x")
f = x - 1
K, a = number_field(f, "a", cached = false)
Kt, t = polynomial_ring(K, "t")
g = t^2 + 7
E, b = number_field(g, "b", cached = false)
D = matrix(E, 4, 4, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1])
gens = Vector{Hecke.RelSimpleNumFieldElem{AbsSimpleNumFieldElem}}[map(E, [2, -1, 0, 0]), map(E, [-3, 0, -1, 0]), map(E, [0, 0, 0, -1]), map(E, [b, 0, 0, 0])]
L = hermitian_lattice(E, gens, gram = D)

Finally, one can access some databases in which are stored several quadratic and hermitian lattices. Up to now, these are not automatically available while running Hecke. It can nonethelss be used in the following way:

julia

julia> qld = Hecke.quadratic_lattice_database()
Quadratic lattices of rank >= 3 with class number 1 or 2
Author: Markus Kirschmer
Source: http://www.math.rwth-aachen.de/~Markus.Kirschmer/forms/
Version: 0.0.1
Number of lattices: 30250

julia> lattice(qld, 1)
Quadratic lattice of rank 3 and degree 3
  over maximal order of Number field of degree 1 over QQ
  with basis AbsSimpleNumFieldElem[1]

julia> hlb = Hecke.hermitian_lattice_database()
Hermitian lattices of rank >= 3 with class number 1 or 2
Author: Markus Kirschmer
Source: http://www.math.rwth-aachen.de/~Markus.Kirschmer/forms/
Version: 0.0.1
Number of lattices: 570

julia> lattice(hlb, 426)
Hermitian lattice of rank 4 and degree 4
  over relative maximal order of Relative number field of degree 2 over number field
  with pseudo-basis
  (1, 1//1 * <1, 1>)
  (b + 1, 1//2 * <1, 1>)

Ambient space and rational span

# ambient_spaceMethod.
julia
ambient_space(L::AbstractLat) -> AbstractSpace

Return the ambient space of the lattice L. If the ambient space is not known, an error is raised.

source


# rational_spanMethod.
julia
rational_span(L::AbstractLat) -> AbstractSpace

Return the rational span of the lattice L.

source


# basis_matrix_of_rational_spanMethod.
julia
basis_matrix_of_rational_span(L::AbstractLat) -> MatElem

Return a basis matrix of the rational span of the lattice L.

source


# gram_matrix_of_rational_spanMethod.
julia
gram_matrix_of_rational_span(L::AbstractLat) -> MatElem

Return the Gram matrix of the rational span of the lattice L.

source


# diagonal_of_rational_spanMethod.
julia
diagonal_of_rational_span(L::AbstractLat) -> Vector

Return the diagonal of the rational span of the lattice L.

source


Examples

julia

julia> K, a = rationals_as_number_field();

julia> Kt, t = K["t"];

julia> g = t^2 + 7;

julia> E, b = number_field(g, "b");

julia> D = matrix(K, 3, 3, [2, 0, 0, 0, 2, 0, 0, 0, 2]);

julia> gens = Vector{AbsSimpleNumFieldElem}[map(K, [1, 1, 0]), map(K, [1, 0, 1]), map(K, [2, 0, 0])];

julia> Lquad = quadratic_lattice(K, gens, gram = D);

julia> D = matrix(E, 4, 4, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);

julia> gens = Vector{Hecke.RelSimpleNumFieldElem{AbsSimpleNumFieldElem}}[map(E, [2, -1, 0, 0]), map(E, [-3, 0, -1, 0]), map(E, [0, 0, 0, -1]), map(E, [b, 0, 0, 0])];

julia> Lherm = hermitian_lattice(E, gens, gram = D);

julia> ambient_space(Lherm)
Hermitian space of dimension 4
  over relative number field with defining polynomial t^2 + 7
    over number field with defining polynomial x - 1
      over rational field
with gram matrix
[1   0   0   0]
[0   1   0   0]
[0   0   1   0]
[0   0   0   1]

julia> rational_span(Lquad)
Quadratic space of dimension 3
  over number field of degree 1 over QQ
with gram matrix
[2   2   2]
[2   4   2]
[2   2   4]

julia> basis_matrix_of_rational_span(Lherm)
[1   0   0   0]
[5   1   0   0]
[3   0   1   0]
[0   0   0   1]

julia> gram_matrix_of_rational_span(Lherm)
[1    5    3   0]
[5   26   15   0]
[3   15   10   0]
[0    0    0   1]

julia> diagonal_of_rational_span(Lquad)
3-element Vector{AbsSimpleNumFieldElem}:
 2
 2
 2

Rational equivalence

# hasse_invariantMethod.
julia
hasse_invariant(L::AbstractLat, p::Union{InfPlc, AbsNumFieldOrderIdeal{AbsSimpleNumField, AbsSimpleNumFieldElem}}) -> Int

Return the Hasse invariant of the rational span of the lattice L at the place p. The lattice must be quadratic.

source


# witt_invariantMethod.
julia
witt_invariant(L::AbstractLat, p::Union{InfPlc, AbsNumFieldOrderIdeal{AbsSimpleNumField, AbsSimpleNumFieldElem}}) -> Int

Return the Witt invariant of the rational span of the lattice L at the place p. The lattice must be quadratic.

source


# is_rationally_isometricMethod.
julia
is_rationally_isometric(L::AbstractLat, M::AbstractLat, p::Union{InfPlc, AbsNumFieldOrderIdeal})
                                                                     -> Bool

Return whether the rational spans of the lattices L and M are isometric over the completion at the place p.

source


# is_rationally_isometricMethod.
julia
is_rationally_isometric(L::AbstractLat, M::AbstractLat) -> Bool

Return whether the rational spans of the lattices L and M are isometric.

source


Examples

For now and for the rest of this section, the examples will include the new lattice Lquad2 which is quadratic. Moreover, all the completions are going to be done at the prime ideal p=7OK.

julia

julia> K, a = rationals_as_number_field();

julia> D = matrix(K, 3, 3, [2, 0, 0, 0, 2, 0, 0, 0, 2]);

julia> gens = Vector{AbsSimpleNumFieldElem}[map(K, [1, 1, 0]), map(K, [1, 0, 1]), map(K, [2, 0, 0])];

julia> Lquad = quadratic_lattice(K, gens, gram = D);

julia> D = matrix(K, 3, 3, [2, 0, 0, 0, 2, 0, 0, 0, 2]);

julia> gens = Vector{AbsSimpleNumFieldElem}[map(K, [-35, 25, 0]), map(K, [30, 40, -20]), map(K, [5, 10, -5])];

julia> Lquad2 = quadratic_lattice(K, gens, gram = D)
Quadratic lattice of rank 3 and degree 3
  over maximal order of Number field of degree 1 over QQ
  with basis AbsSimpleNumFieldElem[1]

julia> OK = maximal_order(K);

julia> p = prime_decomposition(OK, 7)[1][1]
<7, 7>
Norm: 7
Minimum: 7
principal generator 7
two normal wrt: 7

julia> hasse_invariant(Lquad, p), witt_invariant(Lquad, p)
(1, 1)

julia> is_rationally_isometric(Lquad, Lquad2, p)
true

julia> is_rationally_isometric(Lquad, Lquad2)
true

Attributes

Let L be a lattice over E/K. We call a pseudo-basis of L any sequence of pairs (Ai,xi)1in where the Ai's are fractional (left) ideals of OE and (xi)1in is a basis of the rational span of L, and such that

L=i=1nAixi.

Note that a pseudo-basis is not unique. Given a pseudo-basis (Ai,xi)1in of L, we define the corresponding pseudo-matrix of L to be the datum consisting of a list of coefficient ideals corresponding to the ideals Ai's and a matrix whose rows are the coordinates of the xi's in the canonical basis of the ambient space of L (conversely, given any such pseudo-matrix, one can define the corresponding pseudo-basis).

# rankMethod.
julia
rank(L::AbstractLat) -> Int

Return the rank of the underlying module of the lattice L.

source


# degreeMethod.
julia
degree(L::AbstractLat) -> Int

Return the dimension of the ambient space of the lattice L.

source


# discriminantMethod.
julia
discriminant(L::AbstractLat) -> AbsSimpleNumFieldOrderFractionalIdeal

Return the discriminant of the lattice L, that is, the generalized index ideal [L#:L].

source


# base_fieldMethod.
julia
base_field(L::AbstractLat) -> Field

Return the algebra over which the rational span of the lattice L is defined.

source


# base_ringMethod.
julia
base_ring(L::AbstractLat) -> Ring

Return the order over which the lattice L is defined.

source


# fixed_fieldMethod.
julia
fixed_field(L::AbstractLat) -> Field

Returns the fixed field of the involution of the lattice L.

source


# fixed_ringMethod.
julia
fixed_ring(L::AbstractLat) -> Ring

Return the maximal order in the fixed field of the lattice L.

source


# involutionMethod.
julia
involution(L::AbstractLat) -> Map

Return the involution of the rational span of the lattice L.

source


# pseudo_matrixMethod.
julia
pseudo_matrix(L::AbstractLat) -> PMat

Return a basis pseudo-matrix of the lattice L.

source


# pseudo_basisMethod.
julia
pseudo_basis(L::AbstractLat) -> Vector{Tuple{Vector, Ideal}}

Return a pseudo-basis of the lattice L.

source


# coefficient_idealsMethod.
julia
coefficient_ideals(L::AbstractLat) -> Vector{AbsNumFieldOrderIdeal{AbsSimpleNumField, AbsSimpleNumFieldElem}}

Return the coefficient ideals of a pseudo-basis of the lattice L.

source


# absolute_basis_matrixMethod.
julia
absolute_basis_matrix(L::AbstractLat) -> MatElem

Return a Z-basis matrix of the lattice L.

source


# absolute_basisMethod.
julia
absolute_basis(L::AbstractLat) -> Vector

Return a Z-basis of the lattice L.

source


# generatorsMethod.
julia
generators(L::AbstractLat; minimal = false) -> Vector{Vector}

Return a set of generators of the lattice L over the base ring of L.

If minimal == true, the number of generators is minimal. Note that computing minimal generators is expensive.

source


# gram_matrix_of_generatorsMethod.
julia
gram_matrix_of_generators(L::AbstractLat; minimal::Bool = false) -> MatElem

Return the Gram matrix of a generating set of the lattice L.

If minimal == true, then a minimal generating set is used. Note that computing minimal generators is expensive.

source


Examples

julia

julia> K, a = rationals_as_number_field();

julia> Kt, t = K["t"];

julia> g = t^2 + 7;

julia> E, b = number_field(g, "b");

julia> D = matrix(E, 4, 4, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);

julia> gens = Vector{Hecke.RelSimpleNumFieldElem{AbsSimpleNumFieldElem}}[map(E, [2, -1, 0, 0]), map(E, [-3, 0, -1, 0]), map(E, [0, 0, 0, -1]), map(E, [b, 0, 0, 0])];

julia> Lherm = hermitian_lattice(E, gens, gram = D);

julia> rank(Lherm), degree(Lherm)
(4, 4)

julia> discriminant(Lherm)
Fractional ideal of
Relative maximal order with pseudo-basis (1) * 1//1 * <1, 1>, (b + 1) * 1//2 * <1, 1>
with basis pseudo-matrix
(1//1 * <7, 7>) * [1 0]
(1//2 * <7, 7>) * [0 1]

julia> base_field(Lherm)
Relative number field with defining polynomial t^2 + 7
  over number field with defining polynomial x - 1
    over rational field

julia> base_ring(Lherm)
Relative maximal order of Relative number field of degree 2 over number field
with pseudo-basis
(1, 1//1 * <1, 1>)
(b + 1, 1//2 * <1, 1>)

julia> fixed_field(Lherm)
Number field with defining polynomial x - 1
  over rational field

julia> fixed_ring(Lherm)
Maximal order of Number field of degree 1 over QQ
with basis AbsSimpleNumFieldElem[1]

julia> involution(Lherm)
Map
  from relative number field of degree 2 over number field
  to relative number field of degree 2 over number field

julia> pseudo_matrix(Lherm)
Pseudo-matrix over Relative maximal order of Relative number field of degree 2 over number field
with pseudo-basis
(1, 1//1 * <1, 1>)
(b + 1, 1//2 * <1, 1>)
Fractional ideal with row [1 0 0 0]
Fractional ideal with row [5 1 0 0]
Fractional ideal with row [3 0 1 0]
Fractional ideal with row [0 0 0 1]

julia> pseudo_basis(Lherm)
4-element Vector{Tuple{Vector{Hecke.RelSimpleNumFieldElem{AbsSimpleNumFieldElem}}, Hecke.RelNumFieldOrderFractionalIdeal{AbsSimpleNumFieldElem, AbsSimpleNumFieldOrderFractionalIdeal, Hecke.RelSimpleNumFieldElem{AbsSimpleNumFieldElem}}}}:
 ([1, 0, 0, 0], Fractional ideal of
Relative maximal order with pseudo-basis (1) * 1//1 * <1, 1>, (b + 1) * 1//2 * <1, 1>
with basis pseudo-matrix
(1//1 * <7, 28>) * [1 0]
(1//2 * <1, 1>) * [6 1])
 ([5, 1, 0, 0], Fractional ideal of
Relative maximal order with pseudo-basis (1) * 1//1 * <1, 1>, (b + 1) * 1//2 * <1, 1>
with basis pseudo-matrix
(1//1 * <1, 1>) * [1 0]
(1//2 * <1, 1>) * [0 1])
 ([3, 0, 1, 0], Fractional ideal of
Relative maximal order with pseudo-basis (1) * 1//1 * <1, 1>, (b + 1) * 1//2 * <1, 1>
with basis pseudo-matrix
(1//1 * <1, 1>) * [1 0]
(1//2 * <1, 1>) * [0 1])
 ([0, 0, 0, 1], Fractional ideal of
Relative maximal order with pseudo-basis (1) * 1//1 * <1, 1>, (b + 1) * 1//2 * <1, 1>
with basis pseudo-matrix
(1//1 * <1, 1>) * [1 0]
(1//2 * <1, 1>) * [0 1])

julia> coefficient_ideals(Lherm)
4-element Vector{Hecke.RelNumFieldOrderFractionalIdeal{AbsSimpleNumFieldElem, AbsSimpleNumFieldOrderFractionalIdeal, Hecke.RelSimpleNumFieldElem{AbsSimpleNumFieldElem}}}:
 Fractional ideal of
Relative maximal order with pseudo-basis (1) * 1//1 * <1, 1>, (b + 1) * 1//2 * <1, 1>
with basis pseudo-matrix
(1//1 * <7, 28>) * [1 0]
(1//2 * <1, 1>) * [6 1]
 Fractional ideal of
Relative maximal order with pseudo-basis (1) * 1//1 * <1, 1>, (b + 1) * 1//2 * <1, 1>
with basis pseudo-matrix
(1//1 * <1, 1>) * [1 0]
(1//2 * <1, 1>) * [0 1]
 Fractional ideal of
Relative maximal order with pseudo-basis (1) * 1//1 * <1, 1>, (b + 1) * 1//2 * <1, 1>
with basis pseudo-matrix
(1//1 * <1, 1>) * [1 0]
(1//2 * <1, 1>) * [0 1]
 Fractional ideal of
Relative maximal order with pseudo-basis (1) * 1//1 * <1, 1>, (b + 1) * 1//2 * <1, 1>
with basis pseudo-matrix
(1//1 * <1, 1>) * [1 0]
(1//2 * <1, 1>) * [0 1]

julia> absolute_basis_matrix(Lherm)
[            7               0               0               0]
[1//2*b + 7//2               0               0               0]
[            5               1               0               0]
[5//2*b + 5//2   1//2*b + 1//2               0               0]
[            3               0               1               0]
[3//2*b + 3//2               0   1//2*b + 1//2               0]
[            0               0               0               1]
[            0               0               0   1//2*b + 1//2]

julia> absolute_basis(Lherm)
8-element Vector{Vector{Hecke.RelSimpleNumFieldElem{AbsSimpleNumFieldElem}}}:
 [7, 0, 0, 0]
 [1//2*b + 7//2, 0, 0, 0]
 [5, 1, 0, 0]
 [5//2*b + 5//2, 1//2*b + 1//2, 0, 0]
 [3, 0, 1, 0]
 [3//2*b + 3//2, 0, 1//2*b + 1//2, 0]
 [0, 0, 0, 1]
 [0, 0, 0, 1//2*b + 1//2]

julia> generators(Lherm)
4-element Vector{Vector{Hecke.RelSimpleNumFieldElem{AbsSimpleNumFieldElem}}}:
 [2, -1, 0, 0]
 [-3, 0, -1, 0]
 [0, 0, 0, -1]
 [b, 0, 0, 0]

julia> gram_matrix_of_generators(Lherm)
[  5     -6   0   -2*b]
[ -6     10   0    3*b]
[  0      0   1      0]
[2*b   -3*b   0      7]

Module operations

Let L be a lattice over E/K inside the space (V,Φ). The dual lattice of L is defined to be the following lattice over E/K in (V,Φ):

L#={xVΦ(x,L)OE}.

For any fractional (left) ideal a of OE, one can define the lattice aL to be the lattice over E/K, in the same space (V,Φ), obtained by rescaling the coefficient ideals of a pseudo-basis of L by a. In another flavour, for any non-zero element aK, one defines the rescaled lattice La to be the lattice over E/K with the same underlying module as L (i.e. the same pseudo-bases) but in space (V,aΦ).

# +Method.
julia
+(L::AbstractLat, M::AbstractLat) -> AbstractLat

Return the sum of the lattices L and M.

The lattices L and M must have the same ambient space.

source


# *Method.
julia
*(a::NumFieldElem, L::AbstractLat) -> AbstractLat

Return the lattice aL inside the ambient space of the lattice L.

source


# *Method.
julia
*(a::NumFieldOrderIdeal, L::AbstractLat) -> AbstractLat

Return the lattice aL inside the ambient space of the lattice L.

source


# *Method.
julia
*(a::NumFieldOrderFractionalIdeal, L::AbstractLat) -> AbstractLat

Return the lattice aL inside the ambient space of the lattice L.

source


# rescaleMethod.
julia
rescale(L::AbstractLat, a::NumFieldElem) -> AbstractLat

Return the rescaled lattice La. Note that this has a different ambient space than the lattice L.

source


# dualMethod.
julia
dual(L::AbstractLat) -> AbstractLat

Return the dual lattice of the lattice L.

source


# intersectMethod.
julia
intersect(L::AbstractLat, M::AbstractLat) -> AbstractLat

Return the intersection of the lattices L and M.

The lattices L and M must have the same ambient space.

source


# primitive_closureMethod.
julia
primitive_closure(M::AbstractLat, N::AbstractLat) -> AbstractLat

Given two lattices M and N defined over a number field E, with NEM, return the primitive closure MEN of N in M.

One can also use the alias saturate(L, M).

source


# orthogonal_submoduleMethod.
julia
orthogonal_submodule(L::AbstractLat, M::AbstractLat) -> AbstractLat

Return the largest submodule of L orthogonal to M.

source


Examples

julia

julia> K, a = rationals_as_number_field();

julia> D = matrix(K, 3, 3, [2, 0, 0, 0, 2, 0, 0, 0, 2]);

julia> gens = Vector{AbsSimpleNumFieldElem}[map(K, [1, 1, 0]), map(K, [1, 0, 1]), map(K, [2, 0, 0])];

julia> Lquad = quadratic_lattice(K, gens, gram = D);

julia> D = matrix(K, 3, 3, [2, 0, 0, 0, 2, 0, 0, 0, 2]);

julia> gens = Vector{AbsSimpleNumFieldElem}[map(K, [-35, 25, 0]), map(K, [30, 40, -20]), map(K, [5, 10, -5])];

julia> Lquad2 = quadratic_lattice(K, gens, gram = D);

julia> OK = maximal_order(K);

julia> p = prime_decomposition(OK, 7)[1][1];

julia> pseudo_matrix(Lquad + Lquad2)
Pseudo-matrix over Maximal order of Number field of degree 1 over QQ
with basis AbsSimpleNumFieldElem[1]
1//1 * <2, 2> with row [1 0 0]
1//1 * <1, 1> with row [1 1 0]
1//1 * <1, 1> with row [1 0 1]

julia> pseudo_matrix(intersect(Lquad, Lquad2))
Pseudo-matrix over Maximal order of Number field of degree 1 over QQ
with basis AbsSimpleNumFieldElem[1]
1//1 * <10, 10> with row [1 0 0]
1//1 * <25, 25> with row [1//5 1 0]
1//1 * <5, 5> with row [0 3 1]

julia> pseudo_matrix(p*Lquad)
Pseudo-matrix over Maximal order of Number field of degree 1 over QQ
with basis AbsSimpleNumFieldElem[1]
1//1 * <14, 126> with row [1 0 0]
1//1 * <7, 7> with row [1 1 0]
1//1 * <7, 7> with row [1 0 1]

julia> ambient_space(rescale(Lquad,3*a))
Quadratic space of dimension 3
  over number field of degree 1 over QQ
with gram matrix
[6   0   0]
[0   6   0]
[0   0   6]

julia> pseudo_matrix(Lquad)
Pseudo-matrix over Maximal order of Number field of degree 1 over QQ
with basis AbsSimpleNumFieldElem[1]
1//1 * <2, 2> with row [1 0 0]
1//1 * <1, 1> with row [1 1 0]
1//1 * <1, 1> with row [1 0 1]

Categorical constructions

Given finite collections of lattices, one can construct their direct sums, which are also direct products in this context. They are also sometimes called biproducts. Depending on the user usage, it is possible to call one of the following functions.

# direct_sumMethod.
julia
direct_sum(x::Vararg{T}) where T <: AbstractLat -> T, Vector{AbstractSpaceMor}
direct_sum(x::Vector{T}) where T <: AbstractLat -> T, Vector{AbstractSpaceMor}

Given a collection of quadratic or hermitian lattices L1,,Ln, return their direct sum L:=L1Ln, together with the injections LiL (seen as maps between the corresponding ambient spaces).

For objects of type AbstractLat, finite direct sums and finite direct products agree and they are therefore called biproducts. If one wants to obtain L as a direct product with the projections LLi, one should call direct_product(x). If one wants to obtain L as a biproduct with the injections LiL and the projections LLi, one should call biproduct(x).

source

julia
direct_sum(g1::QuadSpaceCls, g2::QuadSpaceCls) -> QuadSpaceCls

Return the isometry class of the direct sum of two representatives.

source


# direct_productMethod.
julia
direct_product(algebras::StructureConstantAlgebra...; task::Symbol = :sum)
  -> StructureConstantAlgebra, Vector{AbsAlgAssMor}, Vector{AbsAlgAssMor}
direct_product(algebras::Vector{StructureConstantAlgebra}; task::Symbol = :sum)
  -> StructureConstantAlgebra, Vector{AbsAlgAssMor}, Vector{AbsAlgAssMor}

Returns the algebra A=A1××Ak. task can be ":sum", ":prod", ":both" or ":none" and determines which canonical maps are computed as well: ":sum" for the injections, ":prod" for the projections.

source

julia
direct_product(x::Vararg{T}) where T <: AbstractLat -> T, Vector{AbstractSpaceMor}
direct_product(x::Vector{T}) where T <: AbstractLat -> T, Vector{AbstractSpaceMor}

Given a collection of quadratic or hermitian lattices L1,,Ln, return their direct product L:=L1××Ln, together with the projections LLi (seen as maps between the corresponding ambient spaces).

For objects of type AbstractLat, finite direct sums and finite direct products agree and they are therefore called biproducts. If one wants to obtain L as a direct sum with the injections LiL, one should call direct_sum(x). If one wants to obtain L as a biproduct with the injections LiL and the projections LLi, one should call biproduct(x).

source


# biproductMethod.
julia
biproduct(x::Vararg{T}) where T <: AbstractLat -> T, Vector{AbstractSpaceMor}, Vector{AbstractSpaceMor}
biproduct(x::Vector{T}) where T <: AbstractLat -> T, Vector{AbstractSpaceMor}, Vector{AbstractSpaceMor}

Given a collection of quadratic or hermitian lattices L1,,Ln, return their biproduct L:=L1Ln, together with the injections LiL and the projections LLi (seen as maps between the corresponding ambient spaces).

For objects of type AbstractLat, finite direct sums and finite direct products agree and they are therefore called biproducts. If one wants to obtain L as a direct sum with the injections LiL, one should call direct_sum(x). If one wants to obtain L as a direct product with the projections LLi, one should call direct_product(x).

source



Invariants

Let L be a lattice over E/K, in the space (V,Φ). We define:

  • the norm n(L) of L to be the ideal of OK generated by the squares {Φ(x,x)xL};

  • the scale s(L) of L to be the set Φ(L,L)={Φ(x,y)x,yL};

  • the volume v(L) of L to be the index ideal

[L#:L]OE:={σσHomOE(L#,L)}OE.
# normMethod.
julia
norm(L::AbstractLat) -> AbsNumFieldOrderFractionalIdeal

Return the norm of the lattice L. This is a fractional ideal of the fixed field of L.

source


# scaleMethod.
julia
scale(L::AbstractLat) -> AbsSimpleNumFieldOrderFractionalIdeal

Return the scale of the lattice L.

source


# volumeMethod.
julia
volume(L::AbstractLat) -> AbsSimpleNumFieldOrderFractionalIdeal

Return the volume of the lattice L.

source


Examples

julia

julia> K, a = rationals_as_number_field();

julia> Kt, t = K["t"];

julia> g = t^2 + 7;

julia> E, b = number_field(g, "b");

julia> D = matrix(E, 4, 4, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);

julia> gens = Vector{Hecke.RelSimpleNumFieldElem{AbsSimpleNumFieldElem}}[map(E, [2, -1, 0, 0]), map(E, [-3, 0, -1, 0]), map(E, [0, 0, 0, -1]), map(E, [b, 0, 0, 0])];

julia> Lherm = hermitian_lattice(E, gens, gram = D);

julia> norm(Lherm)
1//1 * <1, 1>
Norm: 1
Minimum: 1
principal generator 1
basis_matrix
[1]
two normal wrt: 2

julia> scale(Lherm)
Fractional ideal of
Relative maximal order with pseudo-basis (1) * 1//1 * <1, 1>, (b + 1) * 1//2 * <1, 1>
with basis pseudo-matrix
(1//1 * <1, 1>) * [1 0]
(1//2 * <1, 1>) * [0 1]

julia> volume(Lherm)
Fractional ideal of
Relative maximal order with pseudo-basis (1) * 1//1 * <1, 1>, (b + 1) * 1//2 * <1, 1>
with basis pseudo-matrix
(1//1 * <7, 7>) * [1 0]
(1//2 * <7, 7>) * [0 1]

Predicates

Let L be a lattice over E/K. It is said to be integral if its scale is an integral ideal, i.e. it is contained in OE. Moreover, if p is a prime ideal in OK, then L is said to be modular (resp. locally modular at p) if there exists a fractional ideal a of OE (resp. an integer v) such that aL#=L (resp. pvLp#=Lp).

# is_integralMethod.
julia
is_integral(L::AbstractLat) -> Bool

Return whether the lattice L is integral.

source


# is_modularMethod.
julia
is_modular(L::AbstractLat) -> Bool, AbsSimpleNumFieldOrderFractionalIdeal

Return whether the lattice L is modular. In this case, the second returned value is a fractional ideal a of the base algebra of L such that aL#=L, where L# is the dual of L.

source


# is_modularMethod.
julia
is_modular(L::AbstractLat, p) -> Bool, Int

Return whether the completion Lp of the lattice L at the prime ideal or integer p is modular. If it is the case the second returned value is an integer v such that Lp is pv-modular.

source


# is_positive_definiteMethod.
julia
is_positive_definite(L::AbstractLat) -> Bool

Return whether the rational span of the lattice L is positive definite.

source


# is_negative_definiteMethod.
julia
is_negative_definite(L::AbstractLat) -> Bool

Return whether the rational span of the lattice L is negative definite.

source


# is_definiteMethod.
julia
is_definite(L::AbstractLat) -> Bool

Return whether the rational span of the lattice L is definite.

source


# can_scale_totally_positiveMethod.
julia
can_scale_totally_positive(L::AbstractLat) -> Bool, NumFieldElem

Return whether there is a totally positive rescaled lattice of the lattice L. If so, the second returned value is an element a such that La is totally positive.

source


Examples

julia

julia> K, a = rationals_as_number_field();

julia> Kt, t = K["t"];

julia> g = t^2 + 7;

julia> E, b = number_field(g, "b");

julia> D = matrix(E, 4, 4, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);

julia> gens = Vector{Hecke.RelSimpleNumFieldElem{AbsSimpleNumFieldElem}}[map(E, [2, -1, 0, 0]), map(E, [-3, 0, -1, 0]), map(E, [0, 0, 0, -1]), map(E, [b, 0, 0, 0])];

julia> Lherm = hermitian_lattice(E, gens, gram = D);

julia> OK = maximal_order(K);

julia> is_integral(Lherm)
true

julia> is_modular(Lherm)[1]
false

julia> p = prime_decomposition(OK, 7)[1][1];

julia> is_modular(Lherm, p)
(false, 0)

julia> is_positive_definite(Lherm)
true

julia> can_scale_totally_positive(Lherm)
(true, 1)

Local properties

# local_basis_matrixMethod.
julia
local_basis_matrix(L::AbstractLat, p::AbsNumFieldOrderIdeal{AbsSimpleNumField, AbsSimpleNumFieldElem}; type = :any) -> MatElem

Given a prime ideal p and a lattice L, return a basis matrix of a lattice M such that Mp=Lp. Note that if p is an ideal in the base ring of L, the completions are taken at the minimum of p (which is an ideal in the base ring of the order of p).

  • If type == :submodule, the lattice M will be a sublattice of L.

  • If type == :supermodule, the lattice M will be a superlattice of L.

  • If type == :any, there may not be any containment relation between M and L.

source


# jordan_decompositionMethod.
julia
jordan_decomposition(L::AbstractLat, p::AbsNumFieldOrderIdeal{AbsSimpleNumField, AbsSimpleNumFieldElem})
                            -> Vector{MatElem}, Vector{MatElem}, Vector{Int}

Return a Jordan decomposition of the completion of the lattice L at a prime ideal p.

The returned value consists of three lists (Mi)i, (Gi)i and (si)i of the same length r. The completions of the row spans of the matrices Mi yield a Jordan decomposition of Lp into modular sublattices Li with Gram matrices Gi and scale of p-adic valuation si.

source


# is_isotropicMethod.
julia
is_isotropic(L::AbstractLat, p::Union{AbsNumFieldOrderIdeal{AbsSimpleNumField, AbsSimpleNumFieldElem}, InfPlc}) -> Bool

Return whether the completion of the lattice L at the place p is isotropic.

source


Examples

julia

julia> K, a = rationals_as_number_field();

julia> D = matrix(K, 3, 3, [2, 0, 0, 0, 2, 0, 0, 0, 2]);

julia> gens = Vector{AbsSimpleNumFieldElem}[map(K, [1, 1, 0]), map(K, [1, 0, 1]), map(K, [2, 0, 0])];

julia> Lquad = quadratic_lattice(K, gens, gram = D);

julia> OK = maximal_order(K);

julia> p = prime_decomposition(OK, 7)[1][1];

julia> local_basis_matrix(Lquad, p)
[1   0   0]
[1   1   0]
[1   0   1]

julia> jordan_decomposition(Lquad, p)
(AbstractAlgebra.Generic.MatSpaceElem{AbsSimpleNumFieldElem}[[1 0 0; 0 1 0; 0 0 1]], AbstractAlgebra.Generic.MatSpaceElem{AbsSimpleNumFieldElem}[[2 0 0; 0 2 0; 0 0 2]], [0])

julia> is_isotropic(Lquad, p)
true

Automorphisms for definite lattices

Let L and L be two lattices over the same extension E/K, inside their respective ambient spaces (V,Φ) and (V,Φ). Similarly to homomorphisms of spaces, we define a homomorphism of lattices from L to L to be an OE-module$ homomorphism f:LL such that for all x,yL, one has

Φ(f(x),f(y))=Φ(x,y).

Again, any automorphism of lattices is called an isometry and any monomorphism is called an embedding. We refer to the set of isometries from a lattice L to itself as the automorphism group of L.

# automorphism_group_orderMethod.
julia
automorphism_group_order(L::AbstractLat; depth::Int = -1, bacher_depth::Int = 0) -> Int

Given a definite lattice L, return the order of the automorphism group of L.

Setting the parameters depth and bacher_depth to a positive value may improve performance. If set to -1 (default), the used value of depth is chosen heuristically depending on the rank of L. By default, bacher_depth is set to 0.

source


# automorphism_group_generatorsMethod.
julia
automorphism_group_generators(L::AbstractLat; ambient_representation::Bool = true,
                                              depth::Int = -1, bacher_depth::Int = 0)
                                                      -> Vector{MatElem}

Given a definite lattice L, return generators for the automorphism group of L. If ambient_representation == true (the default), the transformations are represented with respect to the ambient space of L. Otherwise, the transformations are represented with respect to the (pseudo-)basis of L.

Setting the parameters depth and bacher_depth to a positive value may improve performance. If set to -1 (default), the used value of depth is chosen heuristically depending on the rank of L. By default, bacher_depth is set to 0.

source


Examples

julia

julia> K, a = rationals_as_number_field();

julia> Kt, t = K["t"];

julia> g = t^2 + 7;

julia> E, b = number_field(g, "b");

julia> D = matrix(K, 3, 3, [2, 0, 0, 0, 2, 0, 0, 0, 2]);

julia> gens = Vector{AbsSimpleNumFieldElem}[map(K, [1, 1, 0]), map(K, [1, 0, 1]), map(K, [2, 0, 0])];

julia> Lquad = quadratic_lattice(K, gens, gram = D);

julia> is_definite(Lquad)
true

julia> automorphism_group_order(Lquad)
48

julia> automorphism_group_generators(Lquad)
6-element Vector{AbstractAlgebra.Generic.MatSpaceElem{AbsSimpleNumFieldElem}}:
 [-1 0 0; 0 -1 0; 0 0 -1]
 [1 0 0; 0 -1 0; 0 0 -1]
 [1 0 0; 0 0 -1; 0 -1 0]
 [0 -1 0; 0 0 -1; 1 0 0]
 [1 0 0; 0 1 0; 0 0 -1]
 [0 1 0; 1 0 0; 0 0 1]

Isometry

# is_isometricMethod.
julia
is_isometric(L::AbstractLat, M::AbstractLat; depth::Int = -1, bacher_depth::Int = 0) -> Bool

Return whether the lattices L and M are isometric.

Setting the parameters depth and bacher_depth to a positive value may improve performance. If set to -1 (default), the used value of depth is chosen heuristically depending on the rank of L. By default, bacher_depth is set to 0.

source


# is_isometric_with_isometryMethod.
julia
is_isometric_with_isometry(L::AbstractLat, M::AbstractLat; ambient_representation::Bool = true
                                                           depth::Int = -1, bacher_depth::Int = 0)
                                                          -> (Bool, MatElem)

Return whether the lattices L and M are isometric. If this is the case, the second returned value is an isometry T from L to M.

By default, that isometry is represented with respect to the bases of the ambient spaces, that is, TVMTt=VL where VL and VM are the Gram matrices of the ambient spaces of L and M respectively. If ambient_representation == false, then the isometry is represented with respect to the (pseudo-)bases of L and M, that is, TGMTt=GL where GM and GL are the Gram matrices of the (pseudo-)bases of L and M respectively.

Setting the parameters depth and bacher_depth to a positive value may improve performance. If set to -1 (default), the used value of depth is chosen heuristically depending on the rank of L. By default, bacher_depth is set to 0.

source


# is_locally_isometricMethod.
julia
is_locally_isometric(L::AbstractLat, M::AbstractLat, p::AbsNumFieldOrderIdeal{AbsSimpleNumField, AbsSimpleNumFieldElem}) -> Bool

Return whether the completions of the lattices L and M at the prime ideal p are isometric.

source


Examples

julia

julia> K, a = rationals_as_number_field();

julia> D = matrix(K, 3, 3, [2, 0, 0, 0, 2, 0, 0, 0, 2]);

julia> gens = Vector{AbsSimpleNumFieldElem}[map(K, [1, 1, 0]), map(K, [1, 0, 1]), map(K, [2, 0, 0])];

julia> Lquad = quadratic_lattice(K, gens, gram = D);

julia> D = matrix(K, 3, 3, [2, 0, 0, 0, 2, 0, 0, 0, 2]);

julia> gens = Vector{AbsSimpleNumFieldElem}[map(K, [-35, 25, 0]), map(K, [30, 40, -20]), map(K, [5, 10, -5])];

julia> Lquad2 = quadratic_lattice(K, gens, gram = D);

julia> OK = maximal_order(K);

julia> p = prime_decomposition(OK, 7)[1][1];

julia> is_isometric(Lquad, Lquad2)
false

julia> is_locally_isometric(Lquad, Lquad2, p)
true

Maximal integral lattices

# is_maximal_integralMethod.
julia
is_maximal_integral(L::AbstractLat, p::AbsNumFieldOrderIdeal{AbsSimpleNumField, AbsSimpleNumFieldElem}) -> Bool, AbstractLat

Given a lattice L and a prime ideal p of the fixed ring OK of L, return whether the completion of L at p has integral norm and that L has no proper overlattice satisfying this property.

If the norm of L is not integral at p, the second output is L by default. Otherwise, either L is maximal at p and the second output is L, or the second output is a lattice M in the ambient space of L whose completion at p is a minimal overlattice of Lp with integral norm.

source


# is_maximal_integralMethod.
julia
is_maximal_integral(L::AbstractLat) -> Bool, AbstractLat

Given a lattice L, return whether L has integral norm and has no proper overlattice satisfying this property.

If the norm of L is not integral, the second output is L by default. Otherwise, either L is maximal and the second output is L, or the second output is a minimal overlattice M of L with integral norm.

source


# is_maximalMethod.
julia
is_maximal(L::AbstractLat, p::AbsNumFieldOrderIdeal{AbsSimpleNumField, AbsSimpleNumFieldElem}) -> Bool, AbstractLat

Given a lattice L and a prime ideal p in the fixed ring OK of L such that the norm of Lp is integral, return whether L is maximal integral at p.

If L is locally maximal at p, the second output is L, otherwise it is a lattice M in the same ambient space of L whose completion at p has integral norm and is a proper overlattice of Lp.

source


# maximal_integral_latticeMethod.
julia
maximal_integral_lattice(L::AbstractLat, p::AbsNumFieldOrderIdeal{AbsSimpleNumField, AbsSimpleNumFieldElem}) -> AbstractLat

Given a lattice L and a prime ideal p of the fixed ring OK of L such that the norm of Lp is integral, return a lattice M in the ambient space of L which is maximal integral at p and which agrees with L locally at all the places different from p.

source


# maximal_integral_latticeMethod.
julia
maximal_integral_lattice(L::AbstractLat) -> AbstractLat

Given a lattice L with integral norm, return a maximal integral overlattice M of L.

source


# maximal_integral_latticeMethod.
julia
maximal_integral_lattice(V::AbstractSpace) -> AbstractLat

Given a space V, return a lattice in V with integral norm and which is maximal in V satisfying this property.

source


Examples

julia

julia> K, a = rationals_as_number_field();

julia> Kt, t = K["t"];

julia> g = t^2 + 7;

julia> E, b = number_field(g, "b");

julia> D = matrix(E, 4, 4, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);

julia> gens = Vector{Hecke.RelSimpleNumFieldElem{AbsSimpleNumFieldElem}}[map(E, [2, -1, 0, 0]), map(E, [-3, 0, -1, 0]), map(E, [0, 0, 0, -1]), map(E, [b, 0, 0, 0])];

julia> Lherm = hermitian_lattice(E, gens, gram = D);

julia> OK = maximal_order(K);

julia> p = prime_decomposition(OK, 7)[1][1];

julia> is_maximal_integral(Lherm, p)
(false, Hermitian lattice of rank 4 and degree 4)

julia> is_maximal_integral(Lherm)
(false, Hermitian lattice of rank 4 and degree 4)

julia> is_maximal(Lherm, p)
(false, Hermitian lattice of rank 4 and degree 4)

julia> pseudo_basis(maximal_integral_lattice(Lherm, p))
4-element Vector{Tuple{Vector{Hecke.RelSimpleNumFieldElem{AbsSimpleNumFieldElem}}, Hecke.RelNumFieldOrderFractionalIdeal{AbsSimpleNumFieldElem, AbsSimpleNumFieldOrderFractionalIdeal, Hecke.RelSimpleNumFieldElem{AbsSimpleNumFieldElem}}}}:
 ([1, 0, 0, 0], Fractional ideal of
Relative maximal order with pseudo-basis (1) * 1//1 * <1, 1>, (b + 1) * 1//2 * <1, 1>
with basis pseudo-matrix
(1//1 * <1, 1>) * [1 0]
(1//2 * <1, 1>) * [0 1])
 ([0, 1, 0, 0], Fractional ideal of
Relative maximal order with pseudo-basis (1) * 1//1 * <1, 1>, (b + 1) * 1//2 * <1, 1>
with basis pseudo-matrix
(1//1 * <1, 1>) * [1 0]
(1//2 * <1, 1>) * [0 1])
 ([2, 4, 1, 0], Fractional ideal of
Relative maximal order with pseudo-basis (1) * 1//1 * <1, 1>, (b + 1) * 1//2 * <1, 1>
with basis pseudo-matrix
(1//1 * <1, 1>) * [1 0]
(1//14 * <1, 1>) * [6 1])
 ([3, 2, 0, 1], Fractional ideal of
Relative maximal order with pseudo-basis (1) * 1//1 * <1, 1>, (b + 1) * 1//2 * <1, 1>
with basis pseudo-matrix
(1//1 * <1, 1>) * [1 0]
(1//14 * <1, 1>) * [6 1])

julia> pseudo_basis(maximal_integral_lattice(Lherm))
4-element Vector{Tuple{Vector{Hecke.RelSimpleNumFieldElem{AbsSimpleNumFieldElem}}, Hecke.RelNumFieldOrderFractionalIdeal{AbsSimpleNumFieldElem, AbsSimpleNumFieldOrderFractionalIdeal, Hecke.RelSimpleNumFieldElem{AbsSimpleNumFieldElem}}}}:
 ([1, 0, 0, 0], Fractional ideal of
Relative maximal order with pseudo-basis (1) * 1//1 * <1, 1>, (b + 1) * 1//2 * <1, 1>
with basis pseudo-matrix
(1//1 * <1, 1>) * [1 0]
(1//2 * <1, 1>) * [0 1])
 ([0, 1, 0, 0], Fractional ideal of
Relative maximal order with pseudo-basis (1) * 1//1 * <1, 1>, (b + 1) * 1//2 * <1, 1>
with basis pseudo-matrix
(1//1 * <1, 1>) * [1 0]
(1//2 * <1, 1>) * [0 1])
 ([2, 4, 1, 0], Fractional ideal of
Relative maximal order with pseudo-basis (1) * 1//1 * <1, 1>, (b + 1) * 1//2 * <1, 1>
with basis pseudo-matrix
(1//1 * <1, 1>) * [1 0]
(1//14 * <1, 1>) * [6 1])
 ([3, 2, 0, 1], Fractional ideal of
Relative maximal order with pseudo-basis (1) * 1//1 * <1, 1>, (b + 1) * 1//2 * <1, 1>
with basis pseudo-matrix
(1//1 * <1, 1>) * [1 0]
(1//14 * <1, 1>) * [6 1])

julia> pseudo_basis(maximal_integral_lattice(ambient_space(Lherm)))
4-element Vector{Tuple{Vector{Hecke.RelSimpleNumFieldElem{AbsSimpleNumFieldElem}}, Hecke.RelNumFieldOrderFractionalIdeal{AbsSimpleNumFieldElem, AbsSimpleNumFieldOrderFractionalIdeal, Hecke.RelSimpleNumFieldElem{AbsSimpleNumFieldElem}}}}:
 ([1, 0, 0, 0], Fractional ideal of
Relative maximal order with pseudo-basis (1) * 1//1 * <1, 1>, (b + 1) * 1//2 * <1, 1>
with basis pseudo-matrix
(1//1 * <1, 1>) * [1 0]
(1//2 * <1, 1>) * [0 1])
 ([0, 1, 0, 0], Fractional ideal of
Relative maximal order with pseudo-basis (1) * 1//1 * <1, 1>, (b + 1) * 1//2 * <1, 1>
with basis pseudo-matrix
(1//1 * <1, 1>) * [1 0]
(1//2 * <1, 1>) * [0 1])
 ([2, 4, 1, 0], Fractional ideal of
Relative maximal order with pseudo-basis (1) * 1//1 * <1, 1>, (b + 1) * 1//2 * <1, 1>
with basis pseudo-matrix
(1//1 * <1, 1>) * [1 0]
(1//14 * <1, 1>) * [6 1])
 ([4, 5, 0, 1], Fractional ideal of
Relative maximal order with pseudo-basis (1) * 1//1 * <1, 1>, (b + 1) * 1//2 * <1, 1>
with basis pseudo-matrix
(1//1 * <1, 1>) * [1 0]
(1//14 * <1, 1>) * [6 1])