From 3ba1f1ec917d90f24fd412f0c0286bdacbc2bbad Mon Sep 17 00:00:00 2001 From: Moritz Carmesin Date: Thu, 14 Nov 2024 11:15:54 +0100 Subject: [PATCH 1/4] Disallow computing the exponential of a sparse matrix --- src/exp.jl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/exp.jl b/src/exp.jl index 9ad97b6..6605e7f 100644 --- a/src/exp.jl +++ b/src/exp.jl @@ -70,3 +70,10 @@ struct ExpMethodNative end function exponential!(A, method::ExpMethodNative, cache = nothing) return exp(A) end + +function exponential!(A::AbstractSparseArray,method=nothing, cache=nothing) + throw("exp(A) on a sparse matrix is generally dense. This operation is "* + "not allowed with exponential. If you wished to compute exp(At)*v, see expv. "* + "Otherwise to override this error, densify the matrix before calling, "* + "i.e. exponential!(Matrix(A))") +end From 56dcb1cd0f33a9f6a27dd9744937d790bed9aac5 Mon Sep 17 00:00:00 2001 From: Moritz Carmesin Date: Thu, 14 Nov 2024 11:25:39 +0100 Subject: [PATCH 2/4] Add documentation. --- src/exp.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/exp.jl b/src/exp.jl index 6605e7f..1587dab 100644 --- a/src/exp.jl +++ b/src/exp.jl @@ -33,6 +33,7 @@ ExpMethodDiagonalization() = ExpMethodDiagonalization(true); Computes the matrix exponential with the method specified in `method`. The contents of `A` are modified, allowing for fewer allocations. The `method` parameter specifies the implementation and implementation parameters, e.g. [`ExpMethodNative`](@ref), [`ExpMethodDiagonalization`](@ref), [`ExpMethodGeneric`](@ref), [`ExpMethodHigham2005`](@ref). Memory needed can be preallocated and provided in the parameter `cache` such that the memory can be recycled when calling `exponential!` several times. The preallocation is done with the command [`alloc_mem`](@ref): `cache=alloc_mem(A,method)`. +A may not be sparse matrix type, since exp(A) is likely to be dense. Example @@ -71,7 +72,7 @@ function exponential!(A, method::ExpMethodNative, cache = nothing) return exp(A) end -function exponential!(A::AbstractSparseArray,method=nothing, cache=nothing) +function exponential!(A::AbstractSparseArray, method=nothing, cache=nothing) throw("exp(A) on a sparse matrix is generally dense. This operation is "* "not allowed with exponential. If you wished to compute exp(At)*v, see expv. "* "Otherwise to override this error, densify the matrix before calling, "* From 8dcf2456035bbff28af832f43770daa6a662a41a Mon Sep 17 00:00:00 2001 From: Moritz Carmesin Date: Thu, 14 Nov 2024 11:51:05 +0100 Subject: [PATCH 3/4] Add test for throwing error --- src/exp.jl | 4 ++-- test/basictests.jl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/exp.jl b/src/exp.jl index 1587dab..d0bf722 100644 --- a/src/exp.jl +++ b/src/exp.jl @@ -73,8 +73,8 @@ function exponential!(A, method::ExpMethodNative, cache = nothing) end function exponential!(A::AbstractSparseArray, method=nothing, cache=nothing) - throw("exp(A) on a sparse matrix is generally dense. This operation is "* + throw(ErrorException("exp(A) on a sparse matrix is generally dense. This operation is "* "not allowed with exponential. If you wished to compute exp(At)*v, see expv. "* "Otherwise to override this error, densify the matrix before calling, "* - "i.e. exponential!(Matrix(A))") + "i.e. exponential!(Matrix(A))")) end diff --git a/test/basictests.jl b/test/basictests.jl index 6cb644e..08da3b7 100644 --- a/test/basictests.jl +++ b/test/basictests.jl @@ -99,7 +99,7 @@ end if VERSION >= v"1.9" @testset "exponential! sparse" begin A = sparse([1, 2, 1], [2, 1, 1], [1.0, 2.0, 3.0]) - exponential!(copy(A), ExpMethodGeneric()) ≈ exp(Array(A)) + @test_throws ErrorException exponential!(A) end end From 230e046f3f946c40a27f5f00a05d972295dc618a Mon Sep 17 00:00:00 2001 From: Moritz Carmesin Date: Thu, 14 Nov 2024 12:56:39 +0100 Subject: [PATCH 4/4] Fix Ambiguities --- src/ExponentialUtilities.jl | 1 + src/exp.jl | 9 +-------- src/exp_sparse.jl | 9 +++++++++ 3 files changed, 11 insertions(+), 8 deletions(-) create mode 100644 src/exp_sparse.jl diff --git a/src/ExponentialUtilities.jl b/src/ExponentialUtilities.jl index 1dd4919..0b79f55 100644 --- a/src/ExponentialUtilities.jl +++ b/src/ExponentialUtilities.jl @@ -27,6 +27,7 @@ include("exp.jl") include("exp_baseexp.jl") include("exp_noalloc.jl") include("exp_generic.jl") +include("exp_sparse.jl") include("phi.jl") include("arnoldi.jl") include("krylov_phiv.jl") diff --git a/src/exp.jl b/src/exp.jl index d0bf722..50a7f08 100644 --- a/src/exp.jl +++ b/src/exp.jl @@ -33,7 +33,7 @@ ExpMethodDiagonalization() = ExpMethodDiagonalization(true); Computes the matrix exponential with the method specified in `method`. The contents of `A` are modified, allowing for fewer allocations. The `method` parameter specifies the implementation and implementation parameters, e.g. [`ExpMethodNative`](@ref), [`ExpMethodDiagonalization`](@ref), [`ExpMethodGeneric`](@ref), [`ExpMethodHigham2005`](@ref). Memory needed can be preallocated and provided in the parameter `cache` such that the memory can be recycled when calling `exponential!` several times. The preallocation is done with the command [`alloc_mem`](@ref): `cache=alloc_mem(A,method)`. -A may not be sparse matrix type, since exp(A) is likely to be dense. +`A` may not be sparse matrix type, since exp(A) is likely to be dense. Example @@ -71,10 +71,3 @@ struct ExpMethodNative end function exponential!(A, method::ExpMethodNative, cache = nothing) return exp(A) end - -function exponential!(A::AbstractSparseArray, method=nothing, cache=nothing) - throw(ErrorException("exp(A) on a sparse matrix is generally dense. This operation is "* - "not allowed with exponential. If you wished to compute exp(At)*v, see expv. "* - "Otherwise to override this error, densify the matrix before calling, "* - "i.e. exponential!(Matrix(A))")) -end diff --git a/src/exp_sparse.jl b/src/exp_sparse.jl new file mode 100644 index 0000000..3b771db --- /dev/null +++ b/src/exp_sparse.jl @@ -0,0 +1,9 @@ + +for expmeth in [ExpMethodDiagonalization, ExpMethodGeneric, ExpMethodHigham2005, ExpMethodHigham2005Base, ExpMethodNative] + @eval function exponential!(A::AbstractSparseArray, method::$expmeth, cache=nothing) + throw(ErrorException("exp(A) on a sparse matrix is generally dense. This operation is "* + "not allowed with exponential. If you wished to compute exp(At)*v, see expv. "* + "Otherwise to override this error, densify the matrix before calling, "* + "i.e. exponential!(Matrix(A))")) + end +end \ No newline at end of file