From e0bd0910fae6447212b6b1771e457f795ae6c575 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Fri, 6 Sep 2024 14:28:50 +0200 Subject: [PATCH 1/4] Add `is_nilpotent(::MatrixElem)` --- docs/src/matrix.md | 6 ++++++ src/Matrix.jl | 26 ++++++++++++++++++++++++++ src/exports.jl | 1 + test/Matrix-test.jl | 6 ++++++ 4 files changed, 39 insertions(+) diff --git a/docs/src/matrix.md b/docs/src/matrix.md index a5223ebc5..3729f642d 100644 --- a/docs/src/matrix.md +++ b/docs/src/matrix.md @@ -916,6 +916,12 @@ det{T <: RingElem}(::MatElem{T}) rank{T <: RingElem}(::MatElem{T}) ``` +### Nilpotency + +```@docs +is_nilpotent(::MatrixElem{T}) where {T <: RingElement} +``` + ### Minors ```@docs diff --git a/src/Matrix.jl b/src/Matrix.jl index 3ffbb8c4e..b52390798 100644 --- a/src/Matrix.jl +++ b/src/Matrix.jl @@ -3686,6 +3686,32 @@ function nullspace(M::MatElem{T}) where {T <: FieldElement} return nullity, X end +############################################################################### +# +# Nilpotency +# +############################################################################### + +@doc raw""" + is_nilpotent(A::MatrixElem{T}) where {T <: RingElement} + +Return if `A` is nilpotent, i.e. if there exists a natural number $k$ +such that $A^k = 0$. If `A` is not square an exception is raised. +""" +function is_nilpotent(A::MatrixElem{T}) where {T <: RingElement} + !is_square(A) && error("Dimensions don't match in is_nilpotent") + A = deepcopy(A) + n = nrows(A) + i = 1 + is_zero(A) && return true + while i < n + i *= 2 + A = mul!(A, A, A) + is_zero(A) && return true + end + return false +end + ############################################################################### # # Hessenberg form diff --git a/src/exports.jl b/src/exports.jl index a44e04209..f28d97f04 100644 --- a/src/exports.jl +++ b/src/exports.jl @@ -294,6 +294,7 @@ export is_monic export is_monomial export is_monomial_recursive export is_negative +export is_nilpotent export is_odd export is_one export is_perfect diff --git a/test/Matrix-test.jl b/test/Matrix-test.jl index 904e25eac..5f5776699 100644 --- a/test/Matrix-test.jl +++ b/test/Matrix-test.jl @@ -64,6 +64,12 @@ end @test is_upper_triangular(matrix(ZZ, A)) end +@testset "Matrix.is_nilpotent" begin + @test is_nilpotent(zero_matrix(QQ, 3, 3)) + @test !is_nilpotent(identity_matrix(QQ, 3)) + @test is_nilpotent(upper_triangular_matrix(QQ.([0,1,1,0,1,0]))) +end + @testset "Matrix.concat" begin for R in [ZZ, QQ, polynomial_ring(QQ, [:x, :y])[1]] S = matrix_space(R, 3, 3) From 28f6068c38f4707d3c6cbb24cb335480d0bbe605 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Fri, 6 Sep 2024 14:29:23 +0200 Subject: [PATCH 2/4] Bump version to 0.42.5 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 071510107..95ebfc01b 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "AbstractAlgebra" uuid = "c3fe647b-3220-5bb0-a1ea-a7954cac585d" -version = "0.42.4" +version = "0.42.5" [deps] InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240" From 553bb9bbaf8cb11afbcc3f8b3751c078f110e747 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Fri, 6 Sep 2024 17:00:34 +0200 Subject: [PATCH 3/4] Add tr shortcut --- src/Matrix.jl | 3 ++- test/Matrix-test.jl | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Matrix.jl b/src/Matrix.jl index b52390798..08f4eb49e 100644 --- a/src/Matrix.jl +++ b/src/Matrix.jl @@ -3700,8 +3700,9 @@ such that $A^k = 0$. If `A` is not square an exception is raised. """ function is_nilpotent(A::MatrixElem{T}) where {T <: RingElement} !is_square(A) && error("Dimensions don't match in is_nilpotent") - A = deepcopy(A) + is_zero(tr(A)) || return false n = nrows(A) + A = deepcopy(A) i = 1 is_zero(A) && return true while i < n diff --git a/test/Matrix-test.jl b/test/Matrix-test.jl index 5f5776699..dd206c611 100644 --- a/test/Matrix-test.jl +++ b/test/Matrix-test.jl @@ -66,8 +66,9 @@ end @testset "Matrix.is_nilpotent" begin @test is_nilpotent(zero_matrix(QQ, 3, 3)) - @test !is_nilpotent(identity_matrix(QQ, 3)) @test is_nilpotent(upper_triangular_matrix(QQ.([0,1,1,0,1,0]))) + @test !is_nilpotent(identity_matrix(QQ, 3)) + @test !is_nilpotent(diagonal_matrix(QQ, [1,-1,0])) end @testset "Matrix.concat" begin From 1bbf5b6a6a5f058e4b7703609f401a2bc444eb53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Tue, 10 Sep 2024 15:49:21 +0200 Subject: [PATCH 4/4] Update src/Matrix.jl --- src/Matrix.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Matrix.jl b/src/Matrix.jl index 08f4eb49e..bf9d47840 100644 --- a/src/Matrix.jl +++ b/src/Matrix.jl @@ -3699,6 +3699,7 @@ Return if `A` is nilpotent, i.e. if there exists a natural number $k$ such that $A^k = 0$. If `A` is not square an exception is raised. """ function is_nilpotent(A::MatrixElem{T}) where {T <: RingElement} + is_domain_type(T) || error("Only supported over integral domains") !is_square(A) && error("Dimensions don't match in is_nilpotent") is_zero(tr(A)) || return false n = nrows(A)