From 13243f3a6cd4a0ecf4de115022b07c52be607871 Mon Sep 17 00:00:00 2001 From: Andy Ferris Date: Wed, 12 Oct 2016 10:04:32 +1000 Subject: [PATCH 1/4] Added a `Scalar` type for 0-dimensional array Better than `Array{T,0}` and `Ref` as scalar containers. --- src/Scalar.jl | 20 ++++++++++++++++++++ src/StaticArrays.jl | 5 +++-- src/abstractarray.jl | 3 +++ 3 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 src/Scalar.jl diff --git a/src/Scalar.jl b/src/Scalar.jl new file mode 100644 index 00000000..828642c0 --- /dev/null +++ b/src/Scalar.jl @@ -0,0 +1,20 @@ +""" + Scalar{T}(x::T) + +Construct a statically-sized 0-dimensional array that contains a single element, +`x`. This type is particularly useful for influencing broadcasting operations. +""" +immutable Scalar{T} <: StaticArray{T,0} + data::T +end + +@inline (::Type{Scalar}){T}(x::Tuple{T}) = Scalar{T}(x[1]) + +@pure size(::Type{Scalar}) = () +@pure size{T}(::Type{Scalar{T}}) = () + +@inline function getindex(v::Scalar) + v.data +end + +@inline Tuple(v::Scalar) = (v.data,) diff --git a/src/StaticArrays.jl b/src/StaticArrays.jl index a6af4ed5..b6674c51 100644 --- a/src/StaticArrays.jl +++ b/src/StaticArrays.jl @@ -8,8 +8,8 @@ import Base: @pure, @propagate_inbounds, getindex, setindex!, size, similar, ones, zeros, eye, cross, vecdot, reshape, fill, fill!, det, inv, eig, trace, vecnorm, dot -export StaticArray, StaticVector, StaticMatrix -export SArray, SVector, SMatrix +export StaticScalar, StaticArray, StaticVector, StaticMatrix +export Scalar, SArray, SVector, SMatrix export MArray, MVector, MMatrix export FieldVector, MutableFieldVector @@ -21,6 +21,7 @@ export similar_type include("util.jl") include("core.jl") +include("Scalar.jl") include("SVector.jl") include("FieldVector.jl") include("SMatrix.jl") diff --git a/src/abstractarray.jl b/src/abstractarray.jl index c6b807a6..88f2a2da 100644 --- a/src/abstractarray.jl +++ b/src/abstractarray.jl @@ -1,4 +1,7 @@ +typealias StaticScalar{T} StaticArray{T,0} + @pure length{T<:StaticArray}(a::Union{T,Type{T}}) = prod(size(a)) +@pure length{T<:StaticScalar}(a::Union{T,Type{T}}) = 1 @pure function size{T<:StaticArray}(a::Union{T,Type{T}}, d::Integer) s = size(a) From df69c1f0b717e59c54c8926e6379dfb594af2059 Mon Sep 17 00:00:00 2001 From: Andy Ferris Date: Wed, 12 Oct 2016 10:25:32 +1000 Subject: [PATCH 2/4] Tests for Scalar --- test/Scalar.jl | 4 ++++ test/runtests.jl | 1 + 2 files changed, 5 insertions(+) create mode 100644 test/Scalar.jl diff --git a/test/Scalar.jl b/test/Scalar.jl new file mode 100644 index 00000000..b880dda5 --- /dev/null +++ b/test/Scalar.jl @@ -0,0 +1,4 @@ +@testset "Scalar" begin + @test Scalar(2) .* [1, 2, 3] == [2, 4, 6] + @test Scalar([1 2; 3 4]) .+ [[1 1; 1 1], [2 2; 2 2]] == [[2 3; 4 5], [3 4; 5 6]] +end diff --git a/test/runtests.jl b/test/runtests.jl index f29fe817..ac5dc007 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -9,6 +9,7 @@ using Base.Test include("SArray.jl") include("MArray.jl") include("FieldVector.jl") + include("Scalar.jl") include("core.jl") include("abstractarray.jl") From f00c7f6a025e6130581a52881d85a4b3bdca069e Mon Sep 17 00:00:00 2001 From: Andy Ferris Date: Wed, 12 Oct 2016 10:28:37 +1000 Subject: [PATCH 3/4] Docs for `Scalar` --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 43cce183..8b2ce950 100644 --- a/README.md +++ b/README.md @@ -229,6 +229,18 @@ easier to define the types without the extra tuple characters (compare because it is so easy to define new `StaticArray` subtypes, and they naturally work together. +### `Scalar` + +Sometimes you want to broadcast an operation, but not over one of your inputs. +A classic example is attempting to displace a collection of vectors by the +same vector. We can now do this with the `Scalar` type: + +```julia +[[1,2,3], [4,5,6]] .+ Scalar([1,0,-1]) # [[2,2,2], [5,5,5]] +``` + +`Scalar` is simply an implementation of an immutable, 0-dimensional `StaticArray`. + ### Mutable arrays: `MVector`, `MMatrix` and `MArray` These statically sized arrays are identical to the above, but are defined as From bba07c36215dbb7eca0a1172759b52decf68a43d Mon Sep 17 00:00:00 2001 From: Andy Ferris Date: Wed, 12 Oct 2016 11:06:19 +1000 Subject: [PATCH 4/4] Better integration of Scalar --- src/Scalar.jl | 11 +++++++++-- src/abstractarray.jl | 1 + test/Scalar.jl | 1 + 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Scalar.jl b/src/Scalar.jl index 828642c0..eb092749 100644 --- a/src/Scalar.jl +++ b/src/Scalar.jl @@ -8,13 +8,20 @@ immutable Scalar{T} <: StaticArray{T,0} data::T end -@inline (::Type{Scalar}){T}(x::Tuple{T}) = Scalar{T}(x[1]) +@inline (::Type{Scalar{T}}){T}(x::Tuple{T}) = Scalar{T}(x[1]) @pure size(::Type{Scalar}) = () @pure size{T}(::Type{Scalar{T}}) = () -@inline function getindex(v::Scalar) +getindex(v::Scalar) = v.data +@inline function getindex(v::Scalar, i::Int) + @boundscheck if i != 1 + error("Attempt to index Scalar at index $i") + end v.data end @inline Tuple(v::Scalar) = (v.data,) + +# A lot more compact than the default array show +Base.show{T}(io::IO, ::MIME"text/plain", x::Scalar{T}) = print(io, "Scalar{$T}(", x.data, ")") diff --git a/src/abstractarray.jl b/src/abstractarray.jl index 88f2a2da..c258a048 100644 --- a/src/abstractarray.jl +++ b/src/abstractarray.jl @@ -107,6 +107,7 @@ end # Some fallbacks +@pure similar_type{SA<:StaticArray}(::Union{SA,Type{SA}}, size::Tuple{}) = Scalar{eltype(SA)} # No mutable fallback here... @pure similar_type{SA<:StaticArray}(::Union{SA,Type{SA}}, size::Int) = SVector{size, eltype(SA)} @pure similar_type{SA<:StaticArray}(::Union{SA,Type{SA}}, sizes::Tuple{Int}) = SVector{sizes[1], eltype(SA)} diff --git a/test/Scalar.jl b/test/Scalar.jl index b880dda5..6cabb031 100644 --- a/test/Scalar.jl +++ b/test/Scalar.jl @@ -1,4 +1,5 @@ @testset "Scalar" begin @test Scalar(2) .* [1, 2, 3] == [2, 4, 6] @test Scalar([1 2; 3 4]) .+ [[1 1; 1 1], [2 2; 2 2]] == [[2 3; 4 5], [3 4; 5 6]] + @test (Scalar(1) + Scalar(1.0))::Scalar{Float64} ≈ Scalar(2.0) end