diff --git a/Project.toml b/Project.toml index afdf8685..22da39df 100644 --- a/Project.toml +++ b/Project.toml @@ -16,21 +16,27 @@ ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" SpecialFunctionsChainRulesCoreExt = "ChainRulesCore" [compat] +Aqua = "0.8.14" ChainRulesCore = "0.9.44, 0.10, 1" ChainRulesTestUtils = "0.6.8, 0.7, 1" +ExplicitImports = "1.13.2" IrrationalConstants = "0.1, 0.2" JET = "0.9, 0.10" LogExpFunctions = "0.3.2" OpenLibm_jll = "0.7, 0.8" OpenSpecFun_jll = "0.5" +Random = "<0.0.1, 1" +Test = "<0.0.1, 1" julia = "1.10" [extras] +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" ChainRulesTestUtils = "cdddcdb0-9152-4a09-a978-84456f9df70a" +ExplicitImports = "7d51a73a-1435-4ff3-83d9-f097790105c7" JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] -test = ["ChainRulesCore", "ChainRulesTestUtils", "JET", "Random", "Test"] +test = ["Aqua", "ChainRulesCore", "ChainRulesTestUtils", "ExplicitImports", "JET", "Random", "Test"] diff --git a/ext/SpecialFunctionsChainRulesCoreExt.jl b/ext/SpecialFunctionsChainRulesCoreExt.jl index 169ee237..580f2c4c 100644 --- a/ext/SpecialFunctionsChainRulesCoreExt.jl +++ b/ext/SpecialFunctionsChainRulesCoreExt.jl @@ -1,8 +1,9 @@ module SpecialFunctionsChainRulesCoreExt -using SpecialFunctions, ChainRulesCore +using SpecialFunctions +using ChainRulesCore: ChainRulesCore -import SpecialFunctions: sqrtπ, invπ +using SpecialFunctions: sqrtπ, invπ const BESSEL_ORDER_INFO = """ derivatives of Bessel functions with respect to the order are not implemented currently: diff --git a/src/SpecialFunctions.jl b/src/SpecialFunctions.jl index 864d2883..8b6c289e 100644 --- a/src/SpecialFunctions.jl +++ b/src/SpecialFunctions.jl @@ -15,8 +15,8 @@ using IrrationalConstants: import LogExpFunctions -using OpenLibm_jll -using OpenSpecFun_jll +using OpenLibm_jll: libopenlibm +using OpenSpecFun_jll: libopenspecfun export airyai, diff --git a/src/ellip.jl b/src/ellip.jl index 4bb43548..2f13880a 100644 --- a/src/ellip.jl +++ b/src/ellip.jl @@ -36,13 +36,11 @@ As suggested in this paper, the domain is restricted to ``(-\infty,1]``. ellipk(m::Real) = _ellipk(float(m)) function _ellipk(m::Float64) - flag_is_m_neg = false - if m < 0.0 + flag_is_m_neg = m < 0.0 + if flag_is_m_neg x = m / (m-1) #dealing with negative args - flag_is_m_neg = true - elseif m >= 0.0 + else x = m - flag_is_m_neg = false end if x == 0.0 @@ -54,7 +52,7 @@ function _ellipk(m::Float64) elseif x > 1.0 throw(DomainError(m, "`m` must lie between -Inf and 1 ---- Domain: (-Inf,1.0]")) - elseif 0.0 <= x < 0.1 #Table 2 from paper + elseif 0.0 < x < 0.1 #Table 2 from paper t = x-0.05 t = @horner(t, 1.591003453790792180 , 0.416000743991786912 , 0.245791514264103415 , @@ -146,7 +144,8 @@ function _ellipk(m::Float64) 1170222242422.439893 , 8777948323668.937971 , 66101242752484.95041 , 499488053713388.7989 , 37859743397240299.20) - elseif x >= 0.9 + else + @assert 0.9 <= x < 1 td = 1-x td1 = td-0.05 qd = @horner(td, @@ -207,13 +206,11 @@ As suggested in this paper, the domain is restricted to ``(-\infty,1]``. ellipe(m::Real) = _ellipe(float(m)) function _ellipe(m::Float64) - flag_is_m_neg = false - if m < 0.0 + flag_is_m_neg = m < 0.0 + if flag_is_m_neg x = m / (m-1) #dealing with negative args - flag_is_m_neg = true - elseif m >= 0.0 + else x = m - flag_is_m_neg = false end if x == 0.0 @@ -224,7 +221,7 @@ function _ellipe(m::Float64) elseif x > 1.0 throw(DomainError(m,"`m` must lie between -Inf and 1 ---- Domain : (-inf,1.0]")) - elseif 0.0 <= x < 0.1 #Table 2 from paper + elseif 0.0 < x < 0.1 #Table 2 from paper t = x-0.05 t = @horner(t , +1.550973351780472328 , -0.400301020103198524 , -0.078498619442941939 , @@ -311,7 +308,8 @@ function _ellipe(m::Float64) -16120097.81581656797 , -109209938.5203089915 , -749380758.1942496220 , -5198725846.725541393 , -36409256888.12139973) - elseif x >= 0.9 + else + @assert 0.9 <= x < 1.0 td = 1-x td1 = td-0.05 diff --git a/src/gamma_inc.jl b/src/gamma_inc.jl index 8d1dbd72..77f5316b 100644 --- a/src/gamma_inc.jl +++ b/src/gamma_inc.jl @@ -1015,6 +1015,7 @@ end function __gamma_inc_inv(a::Float64, minpq::Float64, pcase::Bool) haseta = false + fp = NaN logp = pcase ? log(minpq) : log1p(-minpq) loggamma1pa = a <= 1.0 ? loggamma1p(a) : loggamma(a + 1.0) diff --git a/test/qa.jl b/test/qa.jl new file mode 100644 index 00000000..3c1959f9 --- /dev/null +++ b/test/qa.jl @@ -0,0 +1,62 @@ +@testset "Aqua" begin + Aqua.test_all(SpecialFunctions) +end + +@testset "ExplicitImports" begin + # No implicit imports (`using XY`) + @test ExplicitImports.check_no_implicit_imports(SpecialFunctions) === nothing + + # All explicit imports (`using XY: Z`) are loaded via their owners + @test ExplicitImports.check_all_explicit_imports_via_owners( + SpecialFunctions; + ignore = ( + # Ref https://github.com/JuliaTesting/ExplicitImports.jl/issues/92 + :invπ, # SpecialFunctions + :sqrtπ, # SpecialFunctions + ), + ) === nothing + + # Limit explicit imports (`using XY: Z`) of non-public names to a minimum + @test ExplicitImports.check_all_explicit_imports_are_public( + SpecialFunctions; + ignore = ( + :MPFRRoundingMode, # Base.MPFR + :ROUNDING_MODE, # Base.MPFR + :nan_dom_err, # Base.Math + # Ref https://github.com/JuliaTesting/ExplicitImports.jl/issues/92 + :invπ, # SpecialFunctions + :sqrtπ, # SpecialFunctions + ), + ) === nothing + + # No explicit imports (`using XY: Z`) that are not used + @test ExplicitImports.check_no_stale_explicit_imports(SpecialFunctions) === nothing + + # Nothing is accessed via modules other than its owner + @test ExplicitImports.check_all_qualified_accesses_via_owners(SpecialFunctions) === nothing + + # Limit accesses of non-public names to a minimum + @test ExplicitImports.check_all_qualified_accesses_are_public( + SpecialFunctions; + ignore = ( + :IEEEFloat, # Base + :MPFR, # Base + :MPFRRoundingMode, # Base.MPFR + :ROUNDING_MODE, # Base.MPFR + :_fact_table64, # Base + :version, # Base.MPFR + (VERSION < v"1.11" ? (:depwarn,) : ())..., # Base + ), + ) === nothing + + # No self-qualified accesses + @test ExplicitImports.check_no_self_qualified_accesses(SpecialFunctions) === nothing +end + +@testset "JET" begin + # Check that there are no undefined global references and undefined field accesses + JET.test_package(SpecialFunctions; target_defined_modules = true, mode = :typo) + + # Analyze methods based on their declared signature + JET.report_package(SpecialFunctions; target_defined_modules = true) +end diff --git a/test/runtests.jl b/test/runtests.jl index 7f2baa75..87b51d4c 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -7,6 +7,8 @@ using Random using Test using Base.MathConstants: γ +using Aqua: Aqua +using ExplicitImports: ExplicitImports using JET: JET using SpecialFunctions: AmosException, f64 @@ -35,7 +37,8 @@ tests = [ "logabsgamma", "sincosint", "other_tests", - "chainrules" + "chainrules", + "qa" ] const testdir = dirname(@__FILE__)