Skip to content

Commit

Permalink
Absolute value in short vectors (iteration) (thofma#1327)
Browse files Browse the repository at this point in the history
* absolute value in short vectors (iteration)

---------

Co-authored-by: Simon Brandhorst <[email protected]>
  • Loading branch information
StevellM and simonbrandhorst authored Dec 19, 2023
1 parent 0900a6a commit fac876f
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 21 deletions.
55 changes: 35 additions & 20 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 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
17 changes: 17 additions & 0 deletions test/QuadForm/ShortVectors.jl
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@
L = integer_lattice(gram = QQ[1//2 0; 0 1//3])
v = short_vectors(L, 0.1, 0.6)
@test length(v) == 2
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)
@test length(v) == 1
@test v[1][1] == [1, 0]
Expand All @@ -74,6 +77,12 @@
sv = @inferred short_vectors_iterator(L, delta, ZZRingElem)
@test collect(sv) == Tuple{Vector{ZZRingElem}, QQFieldElem}[([1, 0, 0, -1], 3//10)]

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)
@test collect(sv) == Tuple{Vector{ZZRingElem}, QQFieldElem}[([1, 0, 0, -1], 3//10)]

L = integer_lattice(;gram = identity_matrix(ZZ, 0))
sv = @inferred short_vectors(L, 1)
@test collect(sv) == Tuple{Vector{ZZRingElem}, QQFieldElem}[]
Expand All @@ -89,4 +98,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

0 comments on commit fac876f

Please sign in to comment.