Skip to content
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

feat: multiplicative dependencies for matrices #1671

Merged
merged 1 commit into from
Nov 6, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
93 changes: 93 additions & 0 deletions src/AlgAss/AbsAlgAss.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1241,3 +1241,96 @@ function _skolem_noether(h::AbsAlgAssMor)
error("Not impelemented yet")
end
end

################################################################################
#
# Maximal separable subalgebra
#
################################################################################

# (Part of) Algorithm 5.5 of Lenstra-Silverberg, Algorithms for Commutative Algebras Over the Rational Numbers
# (they only state it for QQ, but should be valid in charcteristic zero)
function maximal_separable_subalgebra(A::AbstractAssociativeAlgebra)
@req is_commutative(A) "Algebra must be commutative"
@req is_zero(characteristic(base_ring(A))) "Characteristic of base ring must be zero"

B = basis(A)
BU = eltype(B)[]
for b in B
u, v = jordan_chevalley_decomposition(b)
push!(BU, u)
end
R = echelon_form(basis_matrix(BU); trim = true)
return _subalgebra(A, [elem_from_mat_row(A, R, i) for i in 1:nrows(R)])
end

################################################################################
#
# Multiplicative dependencies
#
################################################################################

function _multiplicative_dependencies(A::AbstractAssociativeAlgebra, S::Vector)
@req is_commutative(A) "Algebra must be commutative"
@req is_zero(characteristic(base_ring(A))) "Characteristic of base ring must be zero"

B, BtoA = maximal_separable_subalgebra(A)

nfs = _as_number_fields(B)

jcs = first.(jordan_chevalley_decomposition.(S))
jc = [has_preimage_with_preimage(BtoA, x)[2] for x in first.(jordan_chevalley_decomposition.(S))]

F = free_abelian_group(length(S))

kernels = ZZMatrix[]

for (K, BtoK) in nfs
eltsinK = BtoK.(jc)
if any(is_zero, eltsinK)
error("oopsie, elements not invertible")
end
# hack to get something
v = _mult_dep(K, eltsinK)
Hm = reduce(vcat, v)
push!(kernels, Hm)
end

J = radical(A)
m = dim(A) # TODO: compute the nilpotency index
logimgs = elem_type(A)[]
for (s, pis) in zip(S, jcs)
w = s*inv(pis)
v = 1 - w
logimg = -sum(v^i * QQ(1//i) for i in 1:m)
push!(logimgs, logimg)
end
Blog, = integral_split(basis_matrix(logimgs), ZZ)

push!(kernels, kernel(Blog, side = :left))

RtoF = reduce((x, y) -> intersect(x, y, false)[2], [sub(F, k, false)[2] for k in kernels])
return [_eltseq(x.coeff) for x in RtoF.(gens(domain(RtoF)))]
end

function _multiplicative_dependencies(v::Vector{<:MatElem})
A = matrix_algebra(QQ, v)
S = A.(v)
_multiplicative_dependencies(A, S)
end

# TODO: Use Ge
function _mult_dep(K::AbsSimpleNumField, S::Vector)
OK = maximal_order(K)
sup = reduce(vcat, [ support(s, OK) for s in S])
# I don't know why noone ever implemented this
if isempty(sup)
push!(sup, prime_ideals_over(OK, 2)[1])
end
U, mU = sunit_group(unique!(sup))
SinU = .\(mU, S)
F = free_abelian_group(length(SinU))
h = hom(F, U, SinU)
K, mK = kernel(h)
[x.coeff for x in mK.(gens(K))]
end
47 changes: 47 additions & 0 deletions src/AlgAss/Elem.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1227,3 +1227,50 @@ end
function denominator(x::AbstractAssociativeAlgebraElem)
return lcm([ denominator(y) for y in coefficients(x, copy = false) ])
end

################################################################################
#
# Jordan-Chevalley decomposition
#
################################################################################

function _gcdx3(a, b, c)
g, u, v = gcdx(b, c)
g, s, t = gcdx(a, g)
@assert s * a + u * t * b + v * t * c == g
return g, s, u * t, v * t
end

# Algorithm 5.1 of Lenstra-Silverberg, Algorithms for Commutative Algebras Over the Rational Numbers
# (they only state it for QQ, but should be valid in charcteristic zero
function jordan_chevalley_decomposition(x::AbstractAssociativeAlgebraElem)
@req is_commutative(parent(x)) "Algebra must be commutative"
@req is_zero(characteristic(base_ring(parent(x)))) "Base field must be of characteristic zero"
g = minpoly(x)
gp = derivative(g)
ggpgcd = gcd(g, gp)
ghat = divexact(g, ggpgcd)
ghatp = derivative(ghat)
m = zero_matrix(base_ring(gp), degree(ggpgcd), degree(ggpgcd))
h = mod(ghatp, ggpgcd)
for l in 0:degree(h)
m[1, l + 1] = coeff(h, l)
end
for i in 1:(degree(ggpgcd)-1)
h = mod(i * shift_left(ghat, i - 1) + shift_left(ghatp, i), ggpgcd)
for l in 0:degree(h)
m[i + 1, l + 1] = coeff(h, l)
end
end
v = [zero(QQ) for k in 1:degree(ggpgcd)]
if length(v) > 0
v[1] = 1
end
fl, _q = can_solve_with_solution(m, v; side = :left)
@assert fl
q = parent(g)(_q)
v = q(x)*ghat(x)
u = x - v
return u, v
end

1 change: 1 addition & 0 deletions src/GrpAb/stable_sub.jl
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,7 @@ Given a ZpnGModule $M$, the function returns all the submodules of $M$.

"""
function submodules(M::ZpnGModule; typequo=Int[-1], typesub=Int[-1], ord=-1)
@show typequo

if typequo!=[-1]
return submodules_with_quo_struct(M,typequo)
Expand Down
22 changes: 22 additions & 0 deletions test/AlgAss/AbsAlgAss.jl
Original file line number Diff line number Diff line change
Expand Up @@ -247,4 +247,26 @@
h = hom(A, A, inv(X) .* basis(A) .* X)
a = Hecke._skolem_noether(h)
@test all(h(b) == inv(a) * b * a for b in basis(A))

let
# maximal separable subalgebra
Qx, x = QQ[:x]
A = associative_algebra((x^2 + 1)^2)
B, BtoA = Hecke.maximal_separable_subalgebra(A)
@test domain(BtoA) === B
@test codomain(BtoA) == A
@test dim(B) == 2
@test is_simple(B)
end

let
# multiplicative depdendencies
a = QQ[1 2; 3 4]
c = QQ[-3 2; 3 0]
v = [a, a^2, c, c*a]
m = Hecke._multiplicative_dependencies([a, a^2, c, c*a])
for w in m
@test isone(prod(v[i]^Int(w[i]) for i in 1:length(v)))
end
end
end
11 changes: 11 additions & 0 deletions test/AlgAss/Elem.jl
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,15 @@
QG = Hecke._group_algebra(QQ, G; sparse = true);
@test QG(Dict(a => 2, zero(G) => 1)) == 2 * QG(a) + 1 * QG(zero(G))
@test QG(a => ZZ(2), zero(G) => QQ(1)) == 2 * QG(a) + 1 * QG(zero(G))

let
# Jordan-Chevalley
Qx, x = QQ[:x]
A = associative_algebra((x^2 + 1)^2)
alpha = basis(A)[2]
u, v = Hecke.jordan_chevalley_decomposition(alpha)
@test u == A(QQ.([0, 3//2, 0, 1//2]))
@test v == A(QQ.([0, -1//2, 0, -1//2]))
@test u + v == alpha
end
end
Loading