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

Unify eigenvalue interface #1611

Merged
merged 11 commits into from
Jan 23, 2024
8 changes: 5 additions & 3 deletions docs/src/algebraic.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ true
Computing exact eigenvalues of a matrix:

```jldoctest
julia> eigenvalues(ZZ[1 1 0; 0 1 1; 1 0 1], QQBar)
julia> eigenvalues(QQBar, ZZ[1 1 0; 0 1 1; 1 0 1])
3-element Vector{qqbar}:
Root 2.00000 of x - 2
Root 0.500000 + 0.866025*im of x^2 - x + 1
Expand All @@ -102,8 +102,10 @@ julia> eigenvalues(ZZ[1 1 0; 0 1 1; 1 0 1], QQBar)
```@docs
roots(R::CalciumQQBarField, f::ZZPolyRingElem)
roots(R::CalciumQQBarField, f::QQPolyRingElem)
eigenvalues(A::ZZMatrix, R::CalciumQQBarField)
eigenvalues(A::QQMatrix, R::CalciumQQBarField)
eigenvalues(R::CalciumQQBarField, A::ZZMatrix)
eigenvalues_with_multiplicities(R::CalciumQQBarField, A::ZZMatrix)
eigenvalues(R::CalciumQQBarField, A::QQMatrix)
eigenvalues_with_multiplicities(R::CalciumQQBarField, A::QQMatrix)
rand(R::CalciumQQBarField; degree::Int, bits::Int, randtype::Symbol=:null)
```

Expand Down
10 changes: 6 additions & 4 deletions docs/src/matrix.md
Original file line number Diff line number Diff line change
Expand Up @@ -471,13 +471,15 @@ In case the matrix cannot be converted without loss, an `InexactError` is thrown
### Eigenvalues and Eigenvectors (experimental)

```@docs
eigvals(::ComplexMat)
eigvals_simple(a::ComplexMat)
eigenvalues(::ComplexMat)
eigenvalues_with_multiplicities(::ComplexMat)
eigenvalues_simple(a::ComplexMat)
```

```julia
A = CC[1 2 3; 0 4 5; 0 0 6]
eigvals_simple(A)
eigenvalues_simple(A)
A = CC[2 2 3; 0 2 5; 0 0 2])
eigvals(A)
eigenvalues(A)
eigenvalues_with_multiplicities(A)
```
2 changes: 2 additions & 0 deletions src/Aliases.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ include(joinpath(pathof(AbstractAlgebra), "..", "Aliases.jl"))
@alias is_less isless
@alias is_real isreal

@alias eigvals_simple eigenvalues_simple # for consistency with eigvals/eigenvalues

# for backwards compatibility
Base.@deprecate_binding isalgebraic is_algebraic
Base.@deprecate_binding isalgebraic_integer is_algebraic_integer
Expand Down
6 changes: 4 additions & 2 deletions src/Exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,11 @@ export divisible
export divisor_lenstra
export divisor_sigma
export divisors
export eigenspace
export eigenspaces
export eigenvalues
export eigvals
export eigvals_simple
export eigenvalues_simple
export eigenvalues_with_multiplicities
export eisenstein_g
export elem_to_mat_row!
export elem_type
Expand Down
95 changes: 95 additions & 0 deletions src/HeckeMiscMatrix.jl
Original file line number Diff line number Diff line change
Expand Up @@ -712,3 +712,98 @@ 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 = :right)
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 = :right) 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)[2]
end

@doc raw"""
eigenspaces(M::MatElem{T}; side::Symbol = :right)
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 = :right) 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
2 changes: 2 additions & 0 deletions src/Nemo.jl
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,8 @@ import AbstractAlgebra: set_attribute!

include("Exports.jl")

const eigenvalues = eigvals # alternative name for the function from LinearAlgebra
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I didn't find a better place to put this. In Aliases.jl it is too late.


###############################################################################
#
# Set up environment / load libraries
Expand Down
30 changes: 21 additions & 9 deletions src/arb/ComplexMat.jl
Original file line number Diff line number Diff line change
Expand Up @@ -947,7 +947,7 @@ function _eig_simple(A::ComplexMat; check::Bool = true, algorithm::Symbol = :def
end

@doc raw"""
eigvals_simple(A::ComplexMat, algorithm::Symbol = :default)
eigenvalues_simple(A::ComplexMat, algorithm::Symbol = :default)

Returns the eigenvalues of `A` as a vector of `acb`. It is assumed that `A`
has only simple eigenvalues.
Expand All @@ -957,23 +957,35 @@ The algorithm used can be changed by setting the `algorithm` keyword to

This function is experimental.
"""
function eigvals_simple(A::ComplexMat, algorithm::Symbol = :default)
function eigenvalues_simple(A::ComplexMat, algorithm::Symbol = :default)
E, _, _ = _eig_simple(A, algorithm = algorithm)
return E
end

@doc raw"""
eigvals(A::ComplexMat)
eigenvalues_with_multiplicities(A::ComplexMat)

Returns the eigenvalues of `A` as a vector of tuples `(ComplexFieldElem, Int)`.
Each tuple `(z, k)` corresponds to a cluster of `k` eigenvalues
of $A$.
Return the eigenvalues of `A` with their algebraic multiplicities as a vector of
tuples `(ComplexFieldElem, Int)`. Each tuple `(z, k)` corresponds to a cluster
of `k` eigenvalues of $A$.

This function is experimental.
"""
function eigvals(A::ComplexMat)
e, _ = _eig_multiple(A)
return e
function eigenvalues_with_multiplicities(A::ComplexMat)
e, _ = _eig_multiple(A)
return e
end

@doc raw"""
eigenvalues(A::ComplexMat)

Return the eigenvalues of `A`.

This function is experimental.
"""
function eigenvalues(A::ComplexMat)
e, _ = _eig_multiple(A)
return [ x[1] for x in e ]
end

###############################################################################
Expand Down
30 changes: 21 additions & 9 deletions src/arb/acb_mat.jl
Original file line number Diff line number Diff line change
Expand Up @@ -961,7 +961,7 @@ function _eig_simple(A::acb_mat; check::Bool = true, algorithm::Symbol = :defaul
end

@doc raw"""
eigvals_simple(A::acb_mat, algorithm::Symbol = :default)
eigenvalues_simple(A::acb_mat, algorithm::Symbol = :default)

Returns the eigenvalues of `A` as a vector of `acb`. It is assumed that `A`
has only simple eigenvalues.
Expand All @@ -971,23 +971,35 @@ The algorithm used can be changed by setting the `algorithm` keyword to

This function is experimental.
"""
function eigvals_simple(A::acb_mat, algorithm::Symbol = :default)
function eigenvalues_simple(A::acb_mat, algorithm::Symbol = :default)
E, _, _ = _eig_simple(A, algorithm = algorithm)
return E
end

@doc raw"""
eigvals(A::acb_mat)
eigenvalues_with_multiplicities(A::acb_mat)

Returns the eigenvalues of `A` as a vector of tuples `(acb, Int)`.
Each tuple `(z, k)` corresponds to a cluster of `k` eigenvalues
of $A$.
Return the eigenvalues of `A` with their algebraic multiplicities as a vector of
tuples `(acb, Int)`. Each tuple `(z, k)` corresponds to a cluster of `k`
eigenvalues of $A$.

This function is experimental.
"""
function eigvals(A::acb_mat)
e, _ = _eig_multiple(A)
return e
function eigenvalues_with_multiplicities(A::acb_mat)
e, _ = _eig_multiple(A)
return e
end

@doc raw"""
eigenvalues(A::acb_mat)

Return the eigenvalues of `A`.

This function is experimental.
"""
function eigenvalues(A::acb_mat)
e, _ = _eig_multiple(A)
return [ x[1] for x in e ]
end

###############################################################################
Expand Down
63 changes: 45 additions & 18 deletions src/calcium/qqbar.jl
Original file line number Diff line number Diff line change
Expand Up @@ -974,15 +974,8 @@ function conjugates(a::qqbar)
return res
end

@doc raw"""
eigenvalues(A::ZZMatrix, R::CalciumQQBarField)

Return all the eigenvalues of the matrix `A` in the field of algebraic
numbers `R`. The output array is sorted in the default sort order for
algebraic numbers. Eigenvalues of multiplicity higher than one are repeated
according to their multiplicity.
"""
function eigenvalues(A::ZZMatrix, R::CalciumQQBarField)
# Return the eigenvalues with repetition according to the algebraic multiplicity
function _eigvals_internal(R::CalciumQQBarField, A::ZZMatrix)
n = nrows(A)
!is_square(A) && throw(DomainError(A, "a square matrix is required"))
if n == 0
Expand All @@ -996,15 +989,8 @@ function eigenvalues(A::ZZMatrix, R::CalciumQQBarField)
return res
end

@doc raw"""
eigenvalues(A::QQMatrix, R::CalciumQQBarField)

Return all the eigenvalues of the matrix `A` in the field of algebraic
numbers `R`. The output array is sorted in the default sort order for
algebraic numbers. Eigenvalues of multiplicity higher than one are repeated
according to their multiplicity.
"""
function eigenvalues(A::QQMatrix, R::CalciumQQBarField)
# Return the eigenvalues with repetition according to the algebraic multiplicity
function _eigvals_internal(R::CalciumQQBarField, A::QQMatrix)
n = nrows(A)
!is_square(A) && throw(DomainError(A, "a square matrix is required"))
if n == 0
Expand All @@ -1018,6 +1004,47 @@ function eigenvalues(A::QQMatrix, R::CalciumQQBarField)
return res
end

@doc raw"""
eigenvalues(R::CalciumQQBarField, A::ZZMatrix)
eigenvalues(R::CalciumQQBarField, A::QQMatrix)

Return the eigenvalues `A` in the field of algebraic numbers `R`.
The output array is sorted in the default sort order for
algebraic numbers.
"""
function eigenvalues(R::CalciumQQBarField, A::Union{ZZMatrix, QQMatrix})
return unique(_eigvals_internal(R, A))
end

@doc raw"""
eigenvalues_with_multiplicities(R::CalciumQQBarField, A::ZZMatrix)
eigenvalues_with_multiplicities(R::CalciumQQBarField, A::QQMatrix)

Return the eigenvalues `A` in the field of algebraic numbers `R` together with
their algebraic multiplicities as a vector of tuples.
The output array is sorted in the default sort order for algebraic numbers.
"""
function eigenvalues_with_multiplicities(R::CalciumQQBarField, A::Union{ZZMatrix, QQMatrix})
eig = _eigvals_internal(R, A)
res = Vector{Tuple{qqbar, Int}}()
k = 1
n = length(eig)
for i in 1:n
if i < n && isequal(eig[i], eig[i + 1])
k = k + 1
if i == n - 1
push!(res, (eig[i], k))
break
end
else
push!(res, (eig[i], k))
k = 1
end
end

return res
end

###############################################################################
#
# Roots of unity and trigonometric functions
Expand Down
Loading
Loading