diff --git a/Project.toml b/Project.toml index 1636f13..e3fa553 100644 --- a/Project.toml +++ b/Project.toml @@ -7,6 +7,7 @@ version = "0.0.3" ArrayLayouts = "4c555306-a7a7-4459-81d9-ec55ddd5c99a" BandedMatrices = "aae01518-5342-5314-be14-df237901396f" CircularArrays = "7a955b69-7140-5f4e-a0ed-f168c5e2e749" +EltypeExtensions = "583f92f5-06d6-4306-8236-316410defc98" Infinities = "e1ba4f0e-776d-440f-acd9-e1d2e9742647" LazyArrays = "5078a376-72f3-5289-bfd5-ec5146d43c02" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" @@ -19,6 +20,7 @@ BandedMatrices = "0.15, 0.16, 0.17, 1" CircularArrays = "1" ClassicalOrthogonalPolynomials = "0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 0.10, 0.11, 0.12" Documenter = "0.19, 0.20, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 1" +EltypeExtensions = "0.0.2" InfiniteArrays = "0.10, 0.11, 0.12, 0.13" Infinities = "0.1" LazyArrays = "0.19, 0.20, 0.21, 0.22, 1" diff --git a/src/EltypeExtensions.jl b/src/EltypeExtensions.jl deleted file mode 100644 index 19dbd8a..0000000 --- a/src/EltypeExtensions.jl +++ /dev/null @@ -1,129 +0,0 @@ -# will be a new package -""" - elconvert(T, A) - -Similar to `convert(T, A)`, but `T` refers to the eltype. - -# Examples -```jldoctest; setup = :(using PseudostableRecurrences: elconvert) -julia> elconvert(Float64, 1:10) -1.0:1.0:10.0 - -julia> typeof(elconvert(Float64, rand(Int, 3, 3))) -$(repr("text/plain", Matrix{Float64})) -``` -""" -elconvert(::Type{T}, A::AbstractArray) where T = AbstractArray{T}(A) -elconvert(::Type{T}, A::AbstractRange) where T = T(first(A)):T(step(A)):T(last(A)) -elconvert(::Type{T}, A::AbstractSet) where T = AbstractSet{T}(A) - -""" - _to_eltype(T, S) - -Convert type `S` to have the `eltype` of `T`. -""" -_to_eltype(::Type{T}, ::Type{Array{S,N}}) where {T,S,N} = Array{T,N} -_to_eltype(::Type{T}, ::Type{Set}) where T = Set{T} -_to_eltype(::Type{T}, ::Type{S}) where {T,S} = Base.return_types(elconvert, (Type{T}, S)) - -nutype(x) = nutype(typeof(x)) -nutype(T::Type) = throw(MethodError(nutype, T)) - -""" - basetype(T::Type) - -Recursively apply `eltype` to `T` until convergence. - -# Examples -```jldoctest; setup = :(using PseudostableRecurrences: basetype) -julia> basetype(Matrix{BitArray}) -Bool - -julia> basetype(Vector{Set{Complex{Float64}}}) -$(repr("text/plain", Complex{Float64})) - -julia> basetype([1:n for n in 1:10]) -Int64 -``` -""" -basetype(x) = basetype(typeof(x)) -basetype(::Type{T}) where T = eltype(T) == T ? T : basetype(eltype(T)) - -""" - _to_basetype(T::Type, S::Type) - -Convert type `S` to have the [`basetype`](@ref) of `T`. -""" -_to_basetype(::Type{T}, ::Type{S}) where {T,S} = eltype(S) == S ? T : _to_eltype(_to_basetype(T, eltype(S)), S) - -""" - baseconvert(T::Type, A) - -Similar to `convert(T, A)`, but `T` refers to the [`basetype`](@ref). -""" -baseconvert(::Type{T}, A::S) where {T,S} = convert(_to_basetype(T,S), A) - -""" - precisiontype(T::Type) - -Returns the type that decides the precision of `T`. The difference from [`basetype`](@ref) is that `precisiontype` unwraps composite basetypes such as `Complex` and that `precisiontype` is not generalised. - -# Examples -```jldoctest; setup = :(using PseudostableRecurrences: precisiontype) -julia> precisiontype(Complex{Float32}) -Float32 - -julia> precisiontype(Matrix{ComplexF64}) -Float64 -``` -""" -precisiontype(x) = precisiontype(typeof(x)) -precisiontype(::Type{T}) where T<:Real = T -precisiontype(::Type{Complex{T}}) where T = T -precisiontype(::Type{T}) where T = eltype(T) == T ? throw(MethodError(precisiontype, T)) : precisiontype(basetype(T)) - -""" - _to_precisiontype(T::Type, S::Type) - -Convert type `S` to have the [`precisiontype`](@ref) of `T`. An exception is that if `T<:Integer`, then `Rational` will also be unwrapped. - -# Examples -```jldoctest; setup = :(using PseudostableRecurrences: _to_precisiontype) -julia> _to_precisiontype(Float64, Complex{Rational{Int}}) -$(repr("text/plain", Complex{Float64})) - -julia> _to_precisiontype(BigFloat, Matrix{Complex{Bool}}) -$(repr("text/plain", Matrix{Complex{BigFloat}})) - -julia> _to_precisiontype(Int, Complex{Rational{BigInt}}) -Complex{Rational{Int64}} -``` -""" -_to_precisiontype(::Type{T}, ::Type{Complex}) where T = Complex{T} -_to_precisiontype(::Type{T}, ::Type{Complex{S}}) where {T,S} = Complex{_to_precisiontype(T,S)} -_to_precisiontype(::Type{T}, ::Type{<:Rational}) where T<:Integer = Rational{T} -_to_precisiontype(::Type{T}, ::Type{S}) where {T,S} = eltype(S) == S ? T : _to_eltype(_to_precisiontype(T, eltype(S)), S) - -""" - precisionconvert(T::Type, A, prec=precision(T)) - -Convert `A` to have the [`precisiontype`](@ref) of `T`. If `T` has adjustable precision such as `BigFloat`, the precision can be specified by `prec`, otherwise `prec` takes no effect. - -# Examples -```jldoctest; setup = :(using PseudostableRecurrences: precisionconvert) -julia> precisionconvert(BigFloat, 1//3+im, 128) -0.3333333333333333333333333333333333333338 + 1.0im - -julia> precisionconvert(Float16, [[m/n for n in 1:3] for m in 1:3]) -3-element $(repr(Vector{Vector{Float16}})): - [1.0, 0.5, 0.3333] - [2.0, 1.0, 0.6665] - [3.0, 1.5, 1.0] -``` -""" -precisionconvert(T,A) = precisionconvert(T,A,precision(T)) -precisionconvert(::Type{T}, A::S, prec) where {T,S} = convert(_to_precisiontype(T,S), A) -precisionconvert(::Type{BigFloat}, A::S) where {S} = convert(_to_precisiontype(BigFloat,S), A) -precisionconvert(::Type{BigFloat}, x::Real, prec) = BigFloat(x, precision=prec) -precisionconvert(::Type{BigFloat}, x::Complex, prec) = Complex(BigFloat(real(x), precision=prec), BigFloat(imag(x), precision=prec)) -precisionconvert(::Type{BigFloat}, A, prec) = precisionconvert.(BigFloat, A, precision=prec) \ No newline at end of file diff --git a/src/PseudostableRecurrences.jl b/src/PseudostableRecurrences.jl index 11b4b5f..b87501f 100644 --- a/src/PseudostableRecurrences.jl +++ b/src/PseudostableRecurrences.jl @@ -1,6 +1,7 @@ module PseudostableRecurrences -# Write your package code here. +using EltypeExtensions +using EltypeExtensions: _to_precisiontype include("Utils.jl") include("CircularArraysExt.jl") @@ -11,7 +12,7 @@ include("StencilRecurrences.jl") include("BandedSylvesters.jl") import LinearAlgebra: norm -export stable_recurrence +export stable_recurrence, precision_shift """ precision_shift(P::AbstractLinearRecurrencePlan) diff --git a/src/Utils.jl b/src/Utils.jl index bd2f348..1e59576 100644 --- a/src/Utils.jl +++ b/src/Utils.jl @@ -33,15 +33,18 @@ iscircular(A::AbstractArray) = iscircular(parent(A)) tocircular(A::AbstractArray) = iscircular(A) ? A : CircularArray(A) # not to be confused with LinearAlgebra.BLAS.dotu -_dotu(x, y) = mapreduce(*, +, x, y) +""" + _dotu(x, y) = mapreduce(*, +, x, y) -include("EltypeExtensions.jl") +Not to be confused with LinearAlgebra.BLAS.dotu. See [https://github.com/JuliaLang/julia/pull/27677](https://github.com/JuliaLang/julia/pull/27677) +""" +_dotu(x, y) = mapreduce(*, +, x, y) """ ToPrecision{F}(f::F) <: Function -Create a function where the first argument specifies the returned [`precisiontype`](@ref): - (f::ToPrecision)(T, args...) = to_precision(T, f.f(args...)) +Create a function where the first argument specifies the returned `precisiontype`: + (f::ToPrecision)(T, args...) = precisionconvert(precisiontype(T), f.f(args...)) # Examples ```jldoctest; setup = :(import PseudostableRecurrences: ToPrecision)