Skip to content

Absolute value in short vectors (iteration) #1327

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Dec 19, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 37 additions & 21 deletions src/QuadForm/ShortVectors.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ export short_vectors, short_vectors_iterator, shortest_vectors, kissing_number
short_vectors(L::ZZLat, [lb = 0], ub, [elem_type = ZZRingElem]; check::Bool = true)
-> Vector{Tuple{Vector{elem_type}, QQFieldElem}}

Returns all tuples `(v, n)` such that `n = v G v^t` satisfies `lb <= n <= ub`, where `G` is the
Gram matrix of `L` and `v` is non-zero.
Return all tuples `(v, n)` such that $n = |v G v^t|$ satisfies `lb <= n <= ub`,
where `G` is the Gram matrix of `L` and `v` is non-zero.

Note that the vectors are computed up to sign (so only one of `v` and `-v`
appears).

It is assumed and checked that `L` is positive definite.
It is assumed and checked that `L` is definite.

See also [`short_vectors_iterator`](@ref) for an iterator version.
"""
Expand All @@ -21,59 +21,71 @@ short_vectors
[elem_type = ZZRingElem]; check::Bool = true)
-> Tuple{Vector{elem_type}, QQFieldElem} (iterator)

Returns an iterator for all tuples `(v, n)` such that `n = v G v^t` satisfies
Return an iterator for all tuples `(v, n)` such that $n = |v G v^t|$ satisfies
`lb <= n <= ub`, where `G` is the Gram matrix of `L` and `v` is non-zero.

Note that the vectors are computed up to sign (so only one of `v` and `-v`
appears).

It is assumed and checked that `L` is positive definite.
It is assumed and checked that `L` is definite.

See also [`short_vectors`](@ref).
"""
short_vectors_iterator

function short_vectors(L::ZZLat, ub, elem_type::Type{S} = ZZRingElem; check::Bool = true) where {S}
if check
@req ub >= 0 "the upper bound must be non-negative"
@req is_definite(L) && (rank(L)==0 || gram_matrix(L)[1, 1]>0) "integer_lattice must be positive definite"
@req ub >= 0 "The upper bound must be non-negative"
@req is_definite(L) "Lattice must be definite"
end
if rank(L) == 0
return Tuple{Vector{S}, QQFieldElem}[]
end
_G = gram_matrix(L)
if _G[1, 1] < 0
_G = -_G
end
return _short_vectors_gram(Vector, _G, ub, S)
end

function short_vectors_iterator(L::ZZLat, ub, elem_type::Type{S} = ZZRingElem; check::Bool = true) where {S}
if check
@req ub >= 0 "the upper bound must be non-negative"
@req is_definite(L) && (rank(L)==0 || gram_matrix(L)[1, 1]>0) "integer_lattice must be positive definite"
@req ub >= 0 "The upper bound must be non-negative"
@req is_definite(L) "Lattice must be definite"
end
_G = gram_matrix(L)
if rank(L) != 0 && _G[1, 1] < 0
_G = -_G
end
return _short_vectors_gram(LatEnumCtx, _G, ub, S)
end

function short_vectors(L::ZZLat, lb, ub, elem_type::Type{S} = ZZRingElem; check=true) where {S}
if check
@req lb >= 0 "the lower bound must be non-negative"
@req ub >= 0 "the upper bound must be non-negative"
@req is_definite(L) && (rank(L)==0 || gram_matrix(L)[1, 1]>0) "integer_lattice must be positive definite"
@req lb >= 0 "The lower bound must be non-negative"
@req ub >= 0 "The upper bound must be non-negative"
@req is_definite(L) "Lattice must be definite"
end
if rank(L) == 0
return Tuple{Vector{S}, QQFieldElem}[]
end
_G = gram_matrix(L)
if _G[1, 1] < 0
_G = -_G
end
return _short_vectors_gram(Vector, _G, lb, ub, S)
end

function short_vectors_iterator(L::ZZLat, lb, ub, elem_type::Type{S} = ZZRingElem; check=true) where {S}
if check
@req lb >= 0 "the lower bound must be non-negative"
@req ub >= 0 "the upper bound must be non-negative"
@req is_definite(L) && (rank(L) == 0 || gram_matrix(L)[1, 1]>0) "integer_lattice must be positive definite"
@req lb >= 0 "The lower bound must be non-negative"
@req ub >= 0 "The upper bound must be non-negative"
@req is_definite(L) "Lattice must be definite"
end
_G = gram_matrix(L)
if rank(L) != 0 && _G[1, 1] < 0
_G = -_G
end
return _short_vectors_gram(LatEnumCtx, _G, lb, ub, S)
end

Expand All @@ -87,10 +99,10 @@ end
shortest_vectors(L::ZZLat, [elem_type = ZZRingElem]; check::Bool = true)
-> QQFieldElem, Vector{elem_type}, QQFieldElem}

Returns the list of shortest non-zero vectors. Note that the vectors are
computed up to sign (so only one of `v` and `-v` appears).
Return the list of shortest non-zero vectors in absolute value. Note that the
vectors are computed up to sign (so only one of `v` and `-v` appears).

It is assumed and checked that `L` is positive definite.
It is assumed and checked that `L` is definite.

See also [`minimum`](@ref).
"""
Expand All @@ -99,9 +111,12 @@ shortest_vectors(L::ZZLat, ::ZZRingElem)
function shortest_vectors(L::ZZLat, elem_type::Type{S} = ZZRingElem; check::Bool = true) where {S}
if check
@req rank(L) > 0 "Lattice must have positive rank"
@req is_definite(L) && (rank(L) == 0 || gram_matrix(L)[1,1]>0) "integer_lattice must be positive definite"
@req is_definite(L) "Lattice must be definite"
end
_G = gram_matrix(L)
if _G[1, 1] < 0
_G = -_G
end
min, V = _shortest_vectors_gram(_G)
L.minimum = min
return V
Expand All @@ -116,7 +131,7 @@ end
@doc raw"""
minimum(L::ZZLat) -> QQFieldElem

Return the minimum squared length among the non-zero vectors in `L`.
Return the minimum absolute squared length among the non-zero vectors in `L`.
"""
function minimum(L::ZZLat)
@req rank(L) > 0 "Lattice must have positive rank"
Expand All @@ -136,7 +151,8 @@ end
@doc raw"""
kissing_number(L::ZZLat) -> Int

Return the Kissing number of the sphere packing defined by `L`.
Return the Kissing number of the sphere packing defined by the absolute value
of the quadratic form defined by `L`.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Return the Kissing number of the sphere packing defined by the absolute value
of the quadratic form defined by `L`.
Return the Kissing number of the sphere packing defined by `L`.


This is the number of non-overlapping spheres touching any
other given sphere.
Expand Down
1 change: 0 additions & 1 deletion test/QuadForm/CloseVectors.jl
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,6 @@
@test_throws ArgumentError close_vectors(L, v, -1)
Lm = rescale(L,-1)
@test_throws ArgumentError close_vectors(Lm, v, 1)
@test_throws ArgumentError short_vectors(Lm, 1)

# Test the legacy interface

Expand Down
12 changes: 10 additions & 2 deletions test/QuadForm/ShortVectors.jl
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
2448, 4320, 2982, 2402, 2364, 512, 256, 306 ]

# Floating point bounds
L = integer_lattice(gram = QQ[1//2 0; 0 1//3])
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would duplicate the tests instead of removing the old tests.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I will modify this.

L = integer_lattice(gram = QQ[-1//2 0; 0 -1//3])
v = short_vectors(L, 0.1, 0.6)
@test length(v) == 2
v = short_vectors(L, 0.4, 0.6)
Expand All @@ -68,7 +68,7 @@

gram = QQ[1 0 0 1; 0 1 0 0; 0 0 1 0; 1 0 0 13//10]
delta = 9//10
L = integer_lattice(;gram = gram)
L = integer_lattice(;gram = -gram)
sv = @inferred short_vectors_iterator(L, delta, Int)
@test collect(sv) == Tuple{Vector{Int64}, QQFieldElem}[([1, 0, 0, -1], 3//10)]
sv = @inferred short_vectors_iterator(L, delta, ZZRingElem)
Expand All @@ -89,4 +89,12 @@
L = integer_lattice(;gram = identity_matrix(ZZ, 2))
sv = @inferred shortest_vectors(L)
@test length(sv) == 2

L = rescale(root_lattice(:A, 4), -1)
@test minimum(L) == 2
sv = short_vectors_iterator(L, 2, 3)
for (_v, n) in sv
v = matrix(QQ, 1, 4, _v)
@test (v*gram_matrix(L)*transpose(v))[1] == -n
end
end