From 0309186dd9b1615c7a5b63fb0dde99d1613dbdd0 Mon Sep 17 00:00:00 2001 From: Jishnu Bhattacharya Date: Tue, 30 Aug 2022 21:55:18 +0400 Subject: [PATCH 1/6] specialize sum for FillArrays --- Project.toml | 5 +++-- src/FillArrays.jl | 3 +++ test/runtests.jl | 7 +++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Project.toml b/Project.toml index 4f37c107..2d4d00ac 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "FillArrays" uuid = "1a297f60-69ca-5386-bcde-b61e274b549b" -version = "0.13.3" +version = "0.13.4" [deps] LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" @@ -13,8 +13,9 @@ julia = "1.6" [extras] Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" +InfiniteArrays = "4858937d-0d70-526a-a4dd-2d5cb5dd786c" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] -test = ["Test", "Base64", "StaticArrays"] +test = ["Test", "Base64", "InfiniteArrays", "StaticArrays"] diff --git a/src/FillArrays.jl b/src/FillArrays.jl index 75c02999..9b9f40f1 100644 --- a/src/FillArrays.jl +++ b/src/FillArrays.jl @@ -515,6 +515,9 @@ end # Cumsum ######### +# These methods are necessary to deal with infinite arrays +sum(x::AbstractFill) = getindex_value(x)*length(x) +sum(f, x::AbstractFill) = length(x) * f(getindex_value(x)) sum(x::Zeros) = getindex_value(x) cumsum(x::AbstractFill{<:Any,1}) = range(getindex_value(x); step=getindex_value(x), diff --git a/test/runtests.jl b/test/runtests.jl index 196593dc..637945fb 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,5 +1,6 @@ using FillArrays, LinearAlgebra, SparseArrays, StaticArrays, Random, Base64, Test, Statistics import FillArrays: AbstractFill, RectDiagonal, SquareEye +import InfiniteArrays: OneToInf @testset "fill array constructors and convert" begin for (Typ, funcs) in ((:Zeros, :zeros), (:Ones, :ones)) @@ -620,6 +621,12 @@ end @test diff(Fill(1,10)) ≡ Zeros{Int}(9) @test diff(Ones{Float64}(10)) ≡ Zeros{Float64}(9) @test_throws UndefKeywordError cumsum(Fill(1,1,5)) + + @testset "infinite arrays" begin + A = Ones((InfiniteArrays.OneToInf(),)) + @test isinf(sum(A)) + @test sum(A) == length(A) + end end @testset "Broadcast" begin From b4f6d1bfd5bcae55119691d66fa0047291036242 Mon Sep 17 00:00:00 2001 From: Jishnu Bhattacharya Date: Tue, 30 Aug 2022 22:04:10 +0400 Subject: [PATCH 2/6] fix namespace issue --- test/runtests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/runtests.jl b/test/runtests.jl index 637945fb..72c4dff5 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -623,7 +623,7 @@ end @test_throws UndefKeywordError cumsum(Fill(1,1,5)) @testset "infinite arrays" begin - A = Ones((InfiniteArrays.OneToInf(),)) + A = Ones((OneToInf(),)) @test isinf(sum(A)) @test sum(A) == length(A) end From 033dfcc34247cb2f719514bb39b39769599776d0 Mon Sep 17 00:00:00 2001 From: Jishnu Bhattacharya Date: Sun, 4 Sep 2022 10:25:23 +0400 Subject: [PATCH 3/6] define InfiniteArrays in-house --- Project.toml | 3 +-- test/runtests.jl | 69 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 68 insertions(+), 4 deletions(-) diff --git a/Project.toml b/Project.toml index 2d4d00ac..ad9b3280 100644 --- a/Project.toml +++ b/Project.toml @@ -13,9 +13,8 @@ julia = "1.6" [extras] Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" -InfiniteArrays = "4858937d-0d70-526a-a4dd-2d5cb5dd786c" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] -test = ["Test", "Base64", "InfiniteArrays", "StaticArrays"] +test = ["Test", "Base64", "StaticArrays"] diff --git a/test/runtests.jl b/test/runtests.jl index 72c4dff5..75032d06 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,6 +1,71 @@ using FillArrays, LinearAlgebra, SparseArrays, StaticArrays, Random, Base64, Test, Statistics import FillArrays: AbstractFill, RectDiagonal, SquareEye -import InfiniteArrays: OneToInf + +# Infinite Arrays implementation from +# https://github.com/JuliaLang/julia/blob/master/test/testhelpers/InfiniteArrays.jl +module InfiniteArrays + export OneToInf, Infinity + + """ + Infinity() + Represents infinite cardinality. Note that `Infinity <: Integer` to support + being treated as an index. + """ + struct Infinity <: Integer end + + Base.:(==)(::Infinity, ::Int) = false + Base.:(==)(::Int, ::Infinity) = false + Base.:(<)(::Int, ::Infinity) = true + Base.:(<)(::Infinity, ::Int) = false + Base.:(≤)(::Int, ::Infinity) = true + Base.:(≤)(::Infinity, ::Int) = false + Base.:(≤)(::Infinity, ::Infinity) = true + Base.:(-)(::Infinity, ::Int) = Infinity() + Base.:(+)(::Infinity, ::Int) = Infinity() + Base.:(:)(::Infinity, ::Infinity) = 1:0 + + Base.:(+)(::Integer, ::Infinity) = Infinity() + Base.:(+)(::Infinity, ::Integer) = Infinity() + Base.:(*)(::Integer, ::Infinity) = Infinity() + Base.:(*)(::Infinity, ::Integer) = Infinity() + + Base.isinf(::Infinity) = true + + abstract type AbstractInfUnitRange{T<:Real} <: AbstractUnitRange{T} end + Base.length(r::AbstractInfUnitRange) = Infinity() + Base.size(r::AbstractInfUnitRange) = (Infinity(),) + Base.unitrange(r::AbstractInfUnitRange) = InfUnitRange(r) + Base.last(r::AbstractInfUnitRange) = Infinity() + Base.axes(r::AbstractInfUnitRange) = (OneToInf(),) + + """ + OneToInf(n) + Define an `AbstractInfUnitRange` that behaves like `1:∞`, with the added + distinction that the limits are guaranteed (by the type system) to + be 1 and ∞. + """ + struct OneToInf{T<:Integer} <: AbstractInfUnitRange{T} end + + OneToInf() = OneToInf{Int}() + + Base.axes(r::OneToInf) = (r,) + Base.first(r::OneToInf{T}) where {T} = oneunit(T) + Base.oneto(::Infinity) = OneToInf() + + struct InfUnitRange{T<:Real} <: AbstractInfUnitRange{T} + start::T + end + Base.first(r::InfUnitRange) = r.start + InfUnitRange(a::InfUnitRange) = a + InfUnitRange{T}(a::AbstractInfUnitRange) where T<:Real = InfUnitRange{T}(first(a)) + InfUnitRange(a::AbstractInfUnitRange{T}) where T<:Real = InfUnitRange{T}(first(a)) + unitrange(a::AbstractInfUnitRange) = InfUnitRange(a) + Base.:(:)(start::T, stop::Infinity) where {T<:Integer} = InfUnitRange{T}(start) + function getindex(v::InfUnitRange{T}, i::Integer) where T + @boundscheck i > 0 || Base.throw_boundserror(v, i) + convert(T, first(v) + i - 1) + end +end @testset "fill array constructors and convert" begin for (Typ, funcs) in ((:Zeros, :zeros), (:Ones, :ones)) @@ -623,7 +688,7 @@ end @test_throws UndefKeywordError cumsum(Fill(1,1,5)) @testset "infinite arrays" begin - A = Ones((OneToInf(),)) + A = Ones{Int}((InfiniteArrays.OneToInf(),)) @test isinf(sum(A)) @test sum(A) == length(A) end From d4a32a0c3e7c6d6ee14ef9b280479d641727e07e Mon Sep 17 00:00:00 2001 From: Jishnu Bhattacharya Date: Sun, 4 Sep 2022 10:41:48 +0400 Subject: [PATCH 4/6] move infinitearrays to its own file --- test/infinitearrays.jl | 65 +++++++++++++++++++++++++++++++++++++++++ test/runtests.jl | 66 +----------------------------------------- 2 files changed, 66 insertions(+), 65 deletions(-) create mode 100644 test/infinitearrays.jl diff --git a/test/infinitearrays.jl b/test/infinitearrays.jl new file mode 100644 index 00000000..9145c956 --- /dev/null +++ b/test/infinitearrays.jl @@ -0,0 +1,65 @@ +# Infinite Arrays implementation from +# https://github.com/JuliaLang/julia/blob/master/test/testhelpers/InfiniteArrays.jl +module InfiniteArrays + export OneToInf, Infinity + + """ + Infinity() + Represents infinite cardinality. Note that `Infinity <: Integer` to support + being treated as an index. + """ + struct Infinity <: Integer end + + Base.:(==)(::Infinity, ::Int) = false + Base.:(==)(::Int, ::Infinity) = false + Base.:(<)(::Int, ::Infinity) = true + Base.:(<)(::Infinity, ::Int) = false + Base.:(≤)(::Int, ::Infinity) = true + Base.:(≤)(::Infinity, ::Int) = false + Base.:(≤)(::Infinity, ::Infinity) = true + Base.:(-)(::Infinity, ::Int) = Infinity() + Base.:(+)(::Infinity, ::Int) = Infinity() + Base.:(:)(::Infinity, ::Infinity) = 1:0 + + Base.:(+)(::Integer, ::Infinity) = Infinity() + Base.:(+)(::Infinity, ::Integer) = Infinity() + Base.:(*)(::Integer, ::Infinity) = Infinity() + Base.:(*)(::Infinity, ::Integer) = Infinity() + + Base.isinf(::Infinity) = true + + abstract type AbstractInfUnitRange{T<:Real} <: AbstractUnitRange{T} end + Base.length(r::AbstractInfUnitRange) = Infinity() + Base.size(r::AbstractInfUnitRange) = (Infinity(),) + Base.unitrange(r::AbstractInfUnitRange) = InfUnitRange(r) + Base.last(r::AbstractInfUnitRange) = Infinity() + Base.axes(r::AbstractInfUnitRange) = (OneToInf(),) + + """ + OneToInf(n) + Define an `AbstractInfUnitRange` that behaves like `1:∞`, with the added + distinction that the limits are guaranteed (by the type system) to + be 1 and ∞. + """ + struct OneToInf{T<:Integer} <: AbstractInfUnitRange{T} end + + OneToInf() = OneToInf{Int}() + + Base.axes(r::OneToInf) = (r,) + Base.first(r::OneToInf{T}) where {T} = oneunit(T) + Base.oneto(::Infinity) = OneToInf() + + struct InfUnitRange{T<:Real} <: AbstractInfUnitRange{T} + start::T + end + Base.first(r::InfUnitRange) = r.start + InfUnitRange(a::InfUnitRange) = a + InfUnitRange{T}(a::AbstractInfUnitRange) where T<:Real = InfUnitRange{T}(first(a)) + InfUnitRange(a::AbstractInfUnitRange{T}) where T<:Real = InfUnitRange{T}(first(a)) + unitrange(a::AbstractInfUnitRange) = InfUnitRange(a) + Base.:(:)(start::T, stop::Infinity) where {T<:Integer} = InfUnitRange{T}(start) + function getindex(v::InfUnitRange{T}, i::Integer) where T + @boundscheck i > 0 || Base.throw_boundserror(v, i) + convert(T, first(v) + i - 1) + end +end diff --git a/test/runtests.jl b/test/runtests.jl index 75032d06..766a56ee 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,71 +1,7 @@ using FillArrays, LinearAlgebra, SparseArrays, StaticArrays, Random, Base64, Test, Statistics import FillArrays: AbstractFill, RectDiagonal, SquareEye -# Infinite Arrays implementation from -# https://github.com/JuliaLang/julia/blob/master/test/testhelpers/InfiniteArrays.jl -module InfiniteArrays - export OneToInf, Infinity - - """ - Infinity() - Represents infinite cardinality. Note that `Infinity <: Integer` to support - being treated as an index. - """ - struct Infinity <: Integer end - - Base.:(==)(::Infinity, ::Int) = false - Base.:(==)(::Int, ::Infinity) = false - Base.:(<)(::Int, ::Infinity) = true - Base.:(<)(::Infinity, ::Int) = false - Base.:(≤)(::Int, ::Infinity) = true - Base.:(≤)(::Infinity, ::Int) = false - Base.:(≤)(::Infinity, ::Infinity) = true - Base.:(-)(::Infinity, ::Int) = Infinity() - Base.:(+)(::Infinity, ::Int) = Infinity() - Base.:(:)(::Infinity, ::Infinity) = 1:0 - - Base.:(+)(::Integer, ::Infinity) = Infinity() - Base.:(+)(::Infinity, ::Integer) = Infinity() - Base.:(*)(::Integer, ::Infinity) = Infinity() - Base.:(*)(::Infinity, ::Integer) = Infinity() - - Base.isinf(::Infinity) = true - - abstract type AbstractInfUnitRange{T<:Real} <: AbstractUnitRange{T} end - Base.length(r::AbstractInfUnitRange) = Infinity() - Base.size(r::AbstractInfUnitRange) = (Infinity(),) - Base.unitrange(r::AbstractInfUnitRange) = InfUnitRange(r) - Base.last(r::AbstractInfUnitRange) = Infinity() - Base.axes(r::AbstractInfUnitRange) = (OneToInf(),) - - """ - OneToInf(n) - Define an `AbstractInfUnitRange` that behaves like `1:∞`, with the added - distinction that the limits are guaranteed (by the type system) to - be 1 and ∞. - """ - struct OneToInf{T<:Integer} <: AbstractInfUnitRange{T} end - - OneToInf() = OneToInf{Int}() - - Base.axes(r::OneToInf) = (r,) - Base.first(r::OneToInf{T}) where {T} = oneunit(T) - Base.oneto(::Infinity) = OneToInf() - - struct InfUnitRange{T<:Real} <: AbstractInfUnitRange{T} - start::T - end - Base.first(r::InfUnitRange) = r.start - InfUnitRange(a::InfUnitRange) = a - InfUnitRange{T}(a::AbstractInfUnitRange) where T<:Real = InfUnitRange{T}(first(a)) - InfUnitRange(a::AbstractInfUnitRange{T}) where T<:Real = InfUnitRange{T}(first(a)) - unitrange(a::AbstractInfUnitRange) = InfUnitRange(a) - Base.:(:)(start::T, stop::Infinity) where {T<:Integer} = InfUnitRange{T}(start) - function getindex(v::InfUnitRange{T}, i::Integer) where T - @boundscheck i > 0 || Base.throw_boundserror(v, i) - convert(T, first(v) + i - 1) - end -end +include("infinitearrays.jl") @testset "fill array constructors and convert" begin for (Typ, funcs) in ((:Zeros, :zeros), (:Ones, :ones)) From 8b85ef8dd3d8a8163c5a59ecdc251c4e1951b6c0 Mon Sep 17 00:00:00 2001 From: Jishnu Bhattacharya Date: Sun, 4 Sep 2022 10:46:00 +0400 Subject: [PATCH 5/6] test for sum with map --- test/runtests.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/test/runtests.jl b/test/runtests.jl index 766a56ee..d84f0f53 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -627,6 +627,7 @@ end A = Ones{Int}((InfiniteArrays.OneToInf(),)) @test isinf(sum(A)) @test sum(A) == length(A) + @test sum(x->x^2, A) == length(A) end end From 4516ab647b1c604a947a91d5d6b4689ccf150c51 Mon Sep 17 00:00:00 2001 From: Jishnu Bhattacharya Date: Sun, 4 Sep 2022 10:46:40 +0400 Subject: [PATCH 6/6] compare map with broadcasting --- test/runtests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/runtests.jl b/test/runtests.jl index d84f0f53..de8a0a7b 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -627,7 +627,7 @@ end A = Ones{Int}((InfiniteArrays.OneToInf(),)) @test isinf(sum(A)) @test sum(A) == length(A) - @test sum(x->x^2, A) == length(A) + @test sum(x->x^2, A) == sum(A.^2) end end