From 347256c2b3e1f2150a5058700aae977e0630f603 Mon Sep 17 00:00:00 2001 From: Mateusz Baran Date: Mon, 19 Sep 2022 21:52:17 +0200 Subject: [PATCH 1/3] Move `Size` from StaticArrays.jl --- Project.toml | 2 +- README.md | 6 ++- src/StaticArraysCore.jl | 81 +++++++++++++++++++++++++++++++++++++++++ test/runtests.jl | 12 ++++++ 4 files changed, 98 insertions(+), 3 deletions(-) diff --git a/Project.toml b/Project.toml index 35a4f50..d542fd4 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "StaticArraysCore" uuid = "1e83bf80-4336-4d27-bf5d-d5a4f845583c" -version = "1.3.0" +version = "1.4.0" [compat] julia = "1.6" diff --git a/README.md b/README.md index 176d1d3..1a1b42a 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,10 @@ Interface package for [StaticArrays.jl](https://github.com/JuliaArrays/StaticArr [![Build Status](https://github.com/JuliaArrays/StaticArraysCore.jl/workflows/CI/badge.svg)](https://github.com/JuliaArrays/StaticArraysCore.jl/actions?query=workflow%3ACI) [![codecov.io](https://codecov.io/github/JuliaArrays/StaticArraysCore.jl/branch/main/graph/badge.svg)](http://codecov.io/github/JuliaArrays/StaticArraysCore.jl/branch/main) -Contains definitions for the following types: +Contains definitions for the following types and functions: * immutable: `SArray`, `SVector` and `SMatrix`, * mutable: `MArray`, `MVector` and `MMatrix`, -* wrapper: `SizedArray`, `SizedVector` and `SizedMatrix`. +* wrapper: `SizedArray`, `SizedVector` and `SizedMatrix`, +* `Size` and `Dynamic`, +* `similar_type`. diff --git a/src/StaticArraysCore.jl b/src/StaticArraysCore.jl index f5d920a..3cb21d2 100644 --- a/src/StaticArraysCore.jl +++ b/src/StaticArraysCore.jl @@ -411,4 +411,85 @@ if they wish to overload the default behavior. """ function similar_type end +""" + Dynamic() + +Used to signify that a dimension of an array is not known statically. +""" +struct Dynamic end + +const StaticDimension = Union{Int, Dynamic} + +""" + Size(dims::Int...) + +`Size` is used extensively throughout the `StaticArrays` API to describe _compile-time_ +knowledge of the size of an array. The dimensions are stored as a type parameter and are +statically propagated by the compiler, resulting in efficient, type-inferrable code. For +example, to create a static matrix of zeros, use `A = zeros(SMatrix{3,3})`. The static +size of `A` can be obtained by `Size(A)`. (rather than `size(zeros(3,3))`, which returns +`Base.Tuple{2,Int}`). + +Note that if dimensions are not known statically (e.g., for standard `Array`s), +[`Dynamic()`](@ref) should be used instead of an `Int`. + + Size(a::AbstractArray) + Size(::Type{T<:AbstractArray}) + +The `Size` constructor can be used to extract static dimension information from a given +array. For example: + +```julia-repl +julia> Size(zeros(SMatrix{3, 4})) +Size(3, 4) + +julia> Size(zeros(3, 4)) +Size(StaticArrays.Dynamic(), StaticArrays.Dynamic()) +``` + +This has multiple uses, including "trait"-based dispatch on the size of a statically-sized +array. For example: + +```julia +det(x::StaticMatrix) = _det(Size(x), x) +_det(::Size{(1,1)}, x::StaticMatrix) = x[1,1] +_det(::Size{(2,2)}, x::StaticMatrix) = x[1,1]*x[2,2] - x[1,2]*x[2,1] +# and other definitions as necessary +``` + +""" +struct Size{S} + function Size{S}() where {S} + new{S::Tuple{Vararg{StaticDimension}}}() + end +end + +Base.@pure Size(s::Tuple{Vararg{StaticDimension}}) = Size{s}() +Base.@pure Size(s::StaticDimension...) = Size{s}() +Base.@pure Size(s::Type{<:Tuple}) = Size{tuple(s.parameters...)}() + +Base.show(io::IO, ::Size{S}) where {S} = print(io, "Size", S) + +function missing_size_error(::Type{SA}) where SA + error(""" + The size of type `$SA` is not known. + + If you were trying to construct (or `convert` to) a `StaticArray` you + may need to add the size explicitly as a type parameter so its size is + inferrable to the Julia compiler (or performance would be terrible). For + example, you might try + + m = zeros(3,3) + SMatrix(m) # this error + SMatrix{3,3}(m) # correct - size is inferrable + SArray{Tuple{3,3}}(m) # correct, note Tuple{3,3} + """) +end + +Size(a::T) where {T<:AbstractArray} = Size(T) +Size(::Type{SA}) where {SA <: StaticArray} = missing_size_error(SA) +Size(::Type{SA}) where {SA <: StaticArray{S}} where {S<:Tuple} = @isdefined(S) ? Size(S) : missing_size_error(SA) + +Base.@pure Size(::Type{<:AbstractArray{<:Any, N}}) where {N} = Size(ntuple(_ -> Dynamic(), N)) + end # module diff --git a/test/runtests.jl b/test/runtests.jl index 0e2c251..8b47d70 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,4 +1,5 @@ using StaticArraysCore, Test +using StaticArraysCore: Size @testset "types" begin @test SArray{Tuple{2},Int,1}((1, 2)) isa SArray @@ -25,3 +26,14 @@ using StaticArraysCore, Test @test StaticArraysCore.StaticArrayStyle{1}(Val(2)) === StaticArraysCore.StaticArrayStyle{2}() end + +@testset "Size" begin + M = SArray{Tuple{2,3,4},Int,3}(tuple(rand(Int, 24)...)) + @test (@inferred Size(M)) === Size(2, 3, 4) + Ms = Size(M) + @test repr(Ms) == "Size(2, 3, 4)" + @test Size(2, StaticArraysCore.Dynamic(), 5) === Size{(2, StaticArraysCore.Dynamic(), 5)}() + @test Size((2, StaticArraysCore.Dynamic(), 5)) === Size{(2, StaticArraysCore.Dynamic(), 5)}() + @test Size(Tuple{2, StaticArraysCore.Dynamic(), 5}) === Size{(2, StaticArraysCore.Dynamic(), 5)}() + @test_throws ErrorException Size(SArray) +end From 64e9425c3b59bf4e265d342760d5683751ab9a0f Mon Sep 17 00:00:00 2001 From: Mateusz Baran Date: Mon, 19 Sep 2022 22:55:35 +0200 Subject: [PATCH 2/3] one more test --- test/runtests.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/runtests.jl b/test/runtests.jl index 8b47d70..e393df5 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -35,5 +35,7 @@ end @test Size(2, StaticArraysCore.Dynamic(), 5) === Size{(2, StaticArraysCore.Dynamic(), 5)}() @test Size((2, StaticArraysCore.Dynamic(), 5)) === Size{(2, StaticArraysCore.Dynamic(), 5)}() @test Size(Tuple{2, StaticArraysCore.Dynamic(), 5}) === Size{(2, StaticArraysCore.Dynamic(), 5)}() + @test Size([2 3; 4 5]) === Size{(StaticArraysCore.Dynamic(), StaticArraysCore.Dynamic())}() + @test_throws ErrorException Size(SArray) end From 7810953b284f17bb89eff040c331c66d6e83f7b3 Mon Sep 17 00:00:00 2001 From: Mateusz Baran Date: Tue, 20 Sep 2022 18:11:08 +0200 Subject: [PATCH 3/3] export Size --- src/StaticArraysCore.jl | 1 + test/runtests.jl | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/StaticArraysCore.jl b/src/StaticArraysCore.jl index 3cb21d2..2b56fe2 100644 --- a/src/StaticArraysCore.jl +++ b/src/StaticArraysCore.jl @@ -4,6 +4,7 @@ export SArray, SMatrix, SVector export MArray, MMatrix, MVector export SizedArray, SizedMatrix, SizedVector export FieldArray, FieldMatrix, FieldVector +export Size """ abstract type StaticArray{S, T, N} <: AbstractArray{T, N} end diff --git a/test/runtests.jl b/test/runtests.jl index e393df5..1f97d03 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,5 +1,4 @@ using StaticArraysCore, Test -using StaticArraysCore: Size @testset "types" begin @test SArray{Tuple{2},Int,1}((1, 2)) isa SArray