Skip to content

Commit

Permalink
Move eigenspaces etc to new matrix.jl file
Browse files Browse the repository at this point in the history
  • Loading branch information
joschmitt committed Feb 23, 2024
1 parent 42fd431 commit fc0ea6d
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 97 deletions.
95 changes: 0 additions & 95 deletions src/HeckeMiscMatrix.jl
Original file line number Diff line number Diff line change
Expand Up @@ -614,98 +614,3 @@ function map_entries(R::ZZModRing, M::ZZMatrix)
end
return N
end

################################################################################
#
# Eigenvalues and eigenspaces
#
################################################################################

@doc raw"""
eigenvalues(M::MatElem{T}) where T <: FieldElem
Return the eigenvalues of `M`.
"""
function eigenvalues(M::MatElem{T}) where T <: FieldElem
@assert is_square(M)
K = base_ring(M)
f = charpoly(M)
return roots(f)
end

@doc raw"""
eigenvalues_with_multiplicities(M::MatElem{T}) where T <: FieldElem
Return the eigenvalues of `M` together with their algebraic multiplicities as a
vector of tuples.
"""
function eigenvalues_with_multiplicities(M::MatElem{T}) where T <: FieldElem
@assert is_square(M)
K = base_ring(M)
Kx, x = polynomial_ring(K, "x", cached = false)
f = charpoly(Kx, M)
r = roots(f)
return [ (a, valuation(f, x - a)) for a in r ]
end

@doc raw"""
eigenvalues(L::Field, M::MatElem{T}) where T <: RingElem
Return the eigenvalues of `M` over the field `L`.
"""
function eigenvalues(L::Field, M::MatElem{T}) where T <: RingElem
@assert is_square(M)
M1 = change_base_ring(L, M)
return eigenvalues(M1)
end

@doc raw"""
eigenvalues_with_multiplicities(L::Field, M::MatElem{T}) where T <: RingElem
Return the eigenvalues of `M` over the field `L` together with their algebraic
multiplicities as a vector of tuples.
"""
function eigenvalues_with_multiplicities(L::Field, M::MatElem{T}) where T <: RingElem
@assert is_square(M)
M1 = change_base_ring(L, M)
return eigenvalues_with_multiplicities(M1)
end

@doc raw"""
eigenspace(M::MatElem{T}, lambda::T; side::Symbol = :left)
where T <: FieldElem -> Vector{MatElem{T}}
Return a basis of the eigenspace of $M$ with respect to the eigenvalue $\lambda$.
If side is `:right`, the right eigenspace is computed, i.e. vectors $v$ such that
$Mv = \lambda v$. If side is `:left`, the left eigenspace is computed, i.e. vectors
$v$ such that $vM = \lambda v$.
"""
function eigenspace(M::MatElem{T}, lambda::T; side::Symbol = :left) where T <: FieldElem
@assert is_square(M)
N = deepcopy(M)
for i = 1:ncols(N)
N[i, i] -= lambda
end
return kernel(N, side = side)
end

@doc raw"""
eigenspaces(M::MatElem{T}; side::Symbol = :left)
where T <: FieldElem -> Dict{T, MatElem{T}}
Return a dictionary containing the eigenvalues of $M$ as keys and bases for the
corresponding eigenspaces as values.
If side is `:right`, the right eigenspaces are computed, if it is `:left` then the
left eigenspaces are computed.
See also `eigenspace`.
"""
function eigenspaces(M::MatElem{T}; side::Symbol = :left) where T<:FieldElem

S = eigenvalues(M)
L = Dict{elem_type(base_ring(M)), typeof(M)}()
for k in S
push!(L, k => vcat(eigenspace(M, k, side = side)))
end
return L
end
114 changes: 112 additions & 2 deletions src/matrix.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
# Support for view(A, :, i) and view(A, i, :)
################################################################################
#
# Support for view(A, :, i) and view(A, i, :)
#
################################################################################

struct MatrixView{S, T} <: AbstractVector{T}
A::S
Expand Down Expand Up @@ -26,7 +30,12 @@ function Base.view(x::_MatTypes, r::UnitRange{Int}, c::Int)
return MatrixView{typeof(x), typeof(base_ring(x))}(A)
end

# Generic kernel (calling nullspace in flint)
################################################################################
#
# Generic kernel (calling nullspace in flint)
#
################################################################################

const _FieldMatTypes = Union{QQMatrix, fpMatrix, FpMatrix, FqMatrix, fqPolyRepMatrix, FqPolyRepMatrix}

function kernel(A::_FieldMatTypes; side::Symbol = :left)
Expand All @@ -40,6 +49,12 @@ function kernel(A::_FieldMatTypes; side::Symbol = :left)
return nullspace(A)[2]
end

################################################################################
#
# Solve context functionality
#
################################################################################

# Overwrite some solve context functionality so that it uses `transpose` and not
# `lazy_transpose`

Expand Down Expand Up @@ -83,3 +98,98 @@ function Solve.kernel(C::Solve.SolveCtx{S, T}; side::Symbol = :left) where {S <:
return transpose(X)
end
end

################################################################################
#
# Eigenvalues and eigenspaces
#
################################################################################

@doc raw"""
eigenvalues(M::MatElem{T}) where T <: FieldElem
Return the eigenvalues of `M`.
"""
function eigenvalues(M::MatElem{T}) where T <: FieldElem
@assert is_square(M)
K = base_ring(M)
f = charpoly(M)
return roots(f)
end

@doc raw"""
eigenvalues_with_multiplicities(M::MatElem{T}) where T <: FieldElem
Return the eigenvalues of `M` together with their algebraic multiplicities as a
vector of tuples.
"""
function eigenvalues_with_multiplicities(M::MatElem{T}) where T <: FieldElem
@assert is_square(M)
K = base_ring(M)
Kx, x = polynomial_ring(K, "x", cached = false)
f = charpoly(Kx, M)
r = roots(f)
return [ (a, valuation(f, x - a)) for a in r ]
end

@doc raw"""
eigenvalues(L::Field, M::MatElem{T}) where T <: RingElem
Return the eigenvalues of `M` over the field `L`.
"""
function eigenvalues(L::Field, M::MatElem{T}) where T <: RingElem
@assert is_square(M)
M1 = change_base_ring(L, M)
return eigenvalues(M1)
end

@doc raw"""
eigenvalues_with_multiplicities(L::Field, M::MatElem{T}) where T <: RingElem
Return the eigenvalues of `M` over the field `L` together with their algebraic
multiplicities as a vector of tuples.
"""
function eigenvalues_with_multiplicities(L::Field, M::MatElem{T}) where T <: RingElem
@assert is_square(M)
M1 = change_base_ring(L, M)
return eigenvalues_with_multiplicities(M1)
end

@doc raw"""
eigenspace(M::MatElem{T}, lambda::T; side::Symbol = :left)
where T <: FieldElem -> Vector{MatElem{T}}
Return a basis of the eigenspace of $M$ with respect to the eigenvalue $\lambda$.
If side is `:right`, the right eigenspace is computed, i.e. vectors $v$ such that
$Mv = \lambda v$. If side is `:left`, the left eigenspace is computed, i.e. vectors
$v$ such that $vM = \lambda v$.
"""
function eigenspace(M::MatElem{T}, lambda::T; side::Symbol = :left) where T <: FieldElem
@assert is_square(M)
N = deepcopy(M)
for i = 1:ncols(N)
N[i, i] -= lambda
end
return kernel(N, side = side)
end

@doc raw"""
eigenspaces(M::MatElem{T}; side::Symbol = :left)
where T <: FieldElem -> Dict{T, MatElem{T}}
Return a dictionary containing the eigenvalues of $M$ as keys and bases for the
corresponding eigenspaces as values.
If side is `:right`, the right eigenspaces are computed, if it is `:left` then the
left eigenspaces are computed.
See also `eigenspace`.
"""
function eigenspaces(M::MatElem{T}; side::Symbol = :left) where T<:FieldElem

S = eigenvalues(M)
L = Dict{elem_type(base_ring(M)), typeof(M)}()
for k in S
push!(L, k => vcat(eigenspace(M, k, side = side)))
end
return L
end
File renamed without changes.

0 comments on commit fc0ea6d

Please sign in to comment.