Skip to content

Commit 03dd36d

Browse files
committed
Squashed commit of the following:
commit 401a711 Author: Johannes Schmitt <schmitt@mathematik.uni-kl.de> Date: Fri Oct 6 15:47:13 2023 +0200 Fix `_order(::NumField, ::Vector{NumFieldElem})` commit 48c9923 Author: Tommy Hofmann <thofma@gmail.com> Date: Mon Sep 25 09:19:26 2023 +0200 Fixing Order([...])
1 parent 41b61f3 commit 03dd36d

File tree

4 files changed

+111
-84
lines changed

4 files changed

+111
-84
lines changed

src/Misc/Matrix.jl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1468,3 +1468,20 @@ function solve(L::LinearSolveCtx, b::Vector)
14681468
#end
14691469
return fl, deepcopy(w)
14701470
end
1471+
1472+
################################################################################
1473+
#
1474+
# Determinant of triangular matrix
1475+
#
1476+
################################################################################
1477+
1478+
# Compute the determinant of a (lower-left or upper-right) triangular matrix by
1479+
# multiplying the diagonal entries. Nothing is checked.
1480+
function _det_triangular(M::MatElem)
1481+
R = base_ring(M)
1482+
d = one(R)
1483+
for i in 1:nrows(M)
1484+
mul!(d, d, M[i, i])
1485+
end
1486+
return d
1487+
end

src/NumFieldOrd/NfOrd/NfOrd.jl

Lines changed: 78 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -747,9 +747,8 @@ checked by computing minimal polynomials. If `isbasis` is set, then elements are
747747
assumed to form a $\mathbf{Z}$-basis. If `cached` is set, then the constructed
748748
order is cached for future use.
749749
"""
750-
function Order(::S, a::Vector{T}; check::Bool = true, isbasis::Bool = false,
750+
function Order(K::S, a::Vector{T}; check::Bool = true, isbasis::Bool = false,
751751
cached::Bool = false) where {S <: NumField{QQFieldElem}, T <: NumFieldElem{QQFieldElem}}
752-
K = parent(a[1])
753752
@assert all(x->K == parent(x), a)
754753
if isbasis
755754
if check
@@ -769,9 +768,10 @@ end
769768

770769
function Order(K, a::Vector; check::Bool = true, isbasis::Bool = false,
771770
cached::Bool = true)
772-
local b
771+
local b::Vector{elem_type(K)}
773772
try
774773
b = map(K, a)
774+
b = convert(Vector{elem_type(K)}, b)
775775
catch
776776
error("Cannot coerce elements from array into the number field")
777777
end
@@ -886,20 +886,13 @@ function any_order(K::NfAbsNS)
886886
g = gens(K)
887887
for i in 1:ngens(K)
888888
f = denominator(K.pol[i]) * K.pol[i]
889-
@show f
890-
@show isone(coeff(f, 1))
891-
@show coeff(f, 1)
892-
@show typeof(f)
893-
@show g[i]
894889
if isone(coeff(f, 1))
895890
normalized_gens[i] = g[i]
896891
else
897892
normalized_gens[i] = coeff(f, 1) * g[i]
898893
end
899894
end
900895

901-
@show normalized_gens
902-
903896
b = Vector{NfAbsNSElem}(undef, degree(K))
904897
ind = 1
905898
it = cartesian_product_iterator([1:degrees(K)[i] for i in 1:ngens(K)], inplace = true)
@@ -999,114 +992,116 @@ The equation order of the number field.
999992
"""
1000993
equation_order(M::NfAbsOrd) = equation_order(nf(M))
1001994

995+
# Construct the smallest order of K containing the elements in elt.
996+
# If check == true, it is checked whether the given elements in elt are integral
997+
# and whether the constructed order is actually an order.
998+
# Via extends one may supply an order which will then be extended by the elements
999+
# in elt.
10021000
function _order(K::S, elt::Vector{T}; cached::Bool = true, check::Bool = true, extends = nothing) where {S <: NumField{QQFieldElem}, T}
1003-
#=
1004-
check == true: the elements are known to be integral
1005-
extends !== nothing: then extends is an order, which we are extending
1006-
=#
1001+
elt = unique(elt)
10071002
n = degree(K)
10081003

1009-
extending = false
1010-
1011-
local B::FakeFmpqMat = FakeFmpqMat()
1012-
10131004
if extends !== nothing
10141005
extended_order::order_type(K) = extends
10151006
@assert K === nf(extended_order)
1016-
extend = true
10171007

10181008
if is_maximal_known_and_maximal(extended_order) || length(elt) == 0
10191009
return extended_order
10201010
end
1021-
#in this case we can start with phase 2 directly as we have mult. closed
1022-
#module to start with, so set everything up for it...
10231011
B = basis_matrix(extended_order)
10241012
bas = basis(extended_order, K)
1025-
phase = 2
1013+
full_rank = true
1014+
m = _det_triangular(numerator(B, copy = false))//denominator(B, copy = false)
10261015
else
1016+
if isempty(elt)
1017+
elt = elem_type(K)[one(K)]
1018+
end
10271019
bas = elem_type(K)[one(K)]
1028-
phase = 1
1020+
B = basis_matrix(bas, FakeFmpqMat) # trivially in lower-left HNF
1021+
full_rank = false
10291022
end
10301023

1024+
dummy_vector = elem_type(K)[K()]
1025+
function in_span_of_B(x::T)
1026+
if mod(denominator(B, copy = false), denominator(x)) == 0
1027+
dummy_vector[1] = x
1028+
C = basis_matrix(dummy_vector, FakeFmpqMat)
1029+
return is_zero_mod_hnf!(div(denominator(B, copy = false), denominator(x))*numerator(C, copy = false), numerator(B, copy = false))
1030+
end
1031+
return false
1032+
end
10311033

10321034
for e in elt
1033-
# @show findall(isequal(e), elt)
1034-
if phase == 2
1035-
if denominator(B) % denominator(e) == 0
1036-
C = basis_matrix([e], FakeFmpqMat)
1037-
fl, _ = can_solve_with_solution(B.num, div(B.den, denominator(e))*C.num, side = :left)
1038-
# fl && println("elt known:", :e)
1039-
fl && continue
1040-
end
1041-
end
1035+
# Check if e is already in the multiplicatively closed module generated by
1036+
# the previous elements of elt
1037+
in_span_of_B(e) && continue
1038+
1039+
# Multiply powers of e to the existing basis elements
10421040
if check
10431041
f = minpoly(e)
1044-
isone(denominator(f)) || error("data does not define an order, $e is non-integral")
1045-
df = degree(f)-1
1042+
isone(denominator(f)) || error("The elements do not define an order: $e is non-integral")
1043+
df = degree(f) - 1
10461044
else
1047-
df = n-1
1045+
df = n - 1
10481046
end
1049-
f = one(K)
1050-
for i=1:df
1051-
mul!(f, f, e)
1052-
if phase == 2 # don't understand this part
1053-
if denominator(B) % denominator(f) == 0
1054-
C = basis_matrix(elem_type(K)[f], FakeFmpqMat)
1055-
fl = is_zero_mod_hnf!(div(B.den, denominator(f))*C.num, B.num)
1056-
# fl && println("inner abort: ", :e, " ^ ", i)
1057-
fl && break
1058-
end
1059-
end
1060-
if phase == 1
1061-
# [1] -> [1, e] -> [1, e, e, e^2] -> ... otherwise
1062-
push!(bas, deepcopy(f))
1063-
else
1064-
b = elem_type(K)[e*x for x in bas]
1065-
append!(bas, b)
1047+
1048+
start = 1
1049+
# We only multiply the elements of index start:length(bas) by e .
1050+
# Example: bas = [a_1, ..., a_k] with a_1 = 1. Then
1051+
# new_bas := [e, e*a_2, ..., e*a_k] and we append this to bas and set
1052+
# start := k + 1. In the next iteration, we then have
1053+
# new_bas := [e^2, e^2*a_2, ..., e^2*a_k] (assuming that there was no
1054+
# reduction of the basis in between).
1055+
for i in 1:df
1056+
new_bas = elem_type(K)[]
1057+
for j in start:length(bas)
1058+
t = e*bas[j]
1059+
in_span_of_B(t) && continue
1060+
push!(new_bas, t)
10661061
end
1062+
isempty(new_bas) && break
1063+
start = length(bas) + 1
1064+
append!(bas, new_bas)
1065+
10671066
if length(bas) >= n
1067+
# HNF reduce the basis we have so far, if B is already of full rank,
1068+
# we can do this with the modular algorithm
10681069
B = basis_matrix(bas, FakeFmpqMat)
1069-
if extending
1070-
# We are extending extended_order, which has basis matrix M/d
1071-
# Thus we know that B.den/d * M \subseteq <B.num>
1072-
# So we can take B.den/d * largest_elementary_divisor(M) as the modulus
1073-
B = hnf_modular_eldiv(B, B.den, shape = :lowerleft)
1070+
if full_rank
1071+
# We have M \subseteq B, where M is a former incarnation of B.
1072+
# So we have B.den * M.num/M.den \subseteq B.num \subseteq Z^n, so
1073+
# M.d divides B.den and we can choose (B.den/M.den)*det(M.num) as
1074+
# modulus for the HNF of B.num.
1075+
mm = ZZ(m*denominator(B, copy = false))
1076+
hnf_modular_eldiv!(B, mm, shape = :lowerleft)
1077+
B = sub(B, nrows(B) - n + 1:nrows(B), 1:n)
1078+
1079+
# Check if we have a better modulus
1080+
new_m = _det_triangular(numerator(B, copy = false))//denominator(B, copy = false)
1081+
if new_m < m
1082+
m = new_m
1083+
end
10741084
else
10751085
hnf!(B)
1086+
k = findfirst(k -> !is_zero_row(B, k), nrows(B) - n + 1:nrows(B))
1087+
B = sub(B, nrows(B) - n + k:nrows(B), 1:n)
1088+
if nrows(B) == n
1089+
full_rank = true
1090+
m = _det_triangular(numerator(B, copy = false))//denominator(B, copy = false)
1091+
end
10761092
end
1077-
rk = nrows(B) - n + 1
1078-
while is_zero_row(B, rk)
1079-
rk += 1
1080-
end
1081-
B = sub(B, rk:nrows(B), 1:n)
1082-
phase = 2
1083-
bas = elem_type(K)[ elem_from_mat_row(K, B.num, i, B.den) for i = 1:nrows(B) ]
1093+
bas = elem_type(K)[ elem_from_mat_row(K, numerator(B, copy = false), i, denominator(B, copy = false)) for i = 1:nrows(B) ]
1094+
start = 1
10841095
if check
10851096
@assert isone(bas[1])
10861097
end
10871098
end
10881099
end
10891100
end
1090-
1091-
if length(bas) > n # == n can only happen here after an hnf was computed
1092-
# above. Don't quite see how > n can happen here either
1093-
B = basis_matrix(bas, FakeFmpqMat)
1094-
hnf!(B)
1095-
rk = nrows(B) - n + 1
1096-
if is_zero_row(B.num, rk)
1097-
error("data does not define an order: dimension to small")
1098-
end
1099-
B = sub(B, rk:nrows(B), 1:n)
1100-
bas = elem_type(K)[ elem_from_mat_row(K, B.num, i, B.den) for i = 1:nrows(B) ]
1101-
end
1102-
1103-
if !isdefined(B, :num)
1104-
error("data does not define an order: dimension to small")
1101+
if length(bas) < n
1102+
error("The elements do not define an order: rank too small")
11051103
end
1106-
1107-
# Make an explicit check
1108-
@hassert :NfOrd 1 defines_order(K, B)[1]
1109-
return Order(K, B, cached = cached, check = check)
1104+
return Order(K, B, cached = cached, check = check)::order_type(K)
11101105
end
11111106

11121107
################################################################################

test/NfOrd/NfOrd.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
#@test O7 == O77
6565
#@test !(O7 === O77)
6666

67-
O8 = Order(K6, [a1])
67+
O8 = Order(K1, [a1])
6868
@test O8 == EquationOrder(K1)
6969

7070
@test_throws ErrorException Order(K1, [a1, a1, a1], isbasis = true)

test/NumFieldOrd/NumFieldOrd.jl

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,5 +124,20 @@ end
124124
@test extend(R, []) == R
125125
@test extend(R, [1//2 + a//2]) == maximal_order(K)
126126
@test extend(maximal_order(R), [a]) == maximal_order(R)
127+
128+
K, a = number_field(x, "a")
129+
@test Order(K, [1]) == equation_order(K)
130+
@test Order(K, []) == equation_order(K)
131+
132+
K, a = NumberField(x^4 - 10*x^2 + 1, "a")
133+
x = 1//2*a^3 - 9//2*a # sqrt(2)
134+
y = 1//2*a^3 - 11//2*a # sqrt(3)
135+
O = Order(K, [x, y, x*y])
136+
@test O == Order(K, [x, y])
137+
@test O == Order(K, [x, y], check = false)
138+
z = 1//4*a^3 + 1//4*a^2 + 3//4*a + 3//4
139+
OO = Hecke._order(K, [z], extends = O)
140+
@test is_maximal(OO)
141+
@test_throws ErrorException Order(K, [x])
127142
end
128143

0 commit comments

Comments
 (0)