chakravala / AbstractTensors.jl
Showing 15 of 16 files from the diff.
Newly tracked file
src/FixedVector.jl created.
Newly tracked file
src/convert.jl created.
Newly tracked file
src/mapreduce.jl created.
Newly tracked file
src/indexing.jl created.
Newly tracked file
src/util.jl created.
Newly tracked file
src/arraymath.jl created.
Newly tracked file
src/SOneTo.jl created.
Newly tracked file
src/initializers.jl created.
Newly tracked file
src/Values.jl created.
Newly tracked file
src/linalg.jl created.
Newly tracked file
src/abstractvector.jl created.
Newly tracked file
src/Variables.jl created.
Newly tracked file
src/broadcast.jl created.
Newly tracked file
src/traits.jl created.
Other files ignored by Codecov
Project.toml has changed.

@@ -0,0 +1,50 @@
Loading
1 +
2 +
struct FixedVector{N,T} <: TupleVector{N,T}
3 +
    v::Vector{T}
4 +
    function FixedVector{N,T}(a::Vector) where {N,T}
5 +
        if length(a) != N
6 +
            throw(DimensionMismatch("Dimensions $(size(a)) don't match static size $S"))
7 +
        end
8 +
        new{N,T}(a)
9 +
    end
10 +
    function FixedVector{N,T}(::UndefInitializer) where {N,T}
11 +
        new{N,T}(Vector{T}(undef,N))
12 +
    end
13 +
end
14 +
15 +
@inline FixedVector{N}(a::Vector{T}) where {N,T} = FixedVector{N,T}(a)
16 +
17 +
@generated function FixedVector{N,T}(x::NTuple{N,Any}) where {N,T}
18 +
    exprs = [:(a[$i] = x[$i]) for i = 1:N]
19 +
    return quote
20 +
        $(Expr(:meta, :inline))
21 +
        a = FixedVector{N,T}(undef)
22 +
        @inbounds $(Expr(:block, exprs...))
23 +
        return a
24 +
    end
25 +
end
26 +
27 +
@inline FixedVector{N,T}(x::Tuple) where {N,T} = FixedVector{N,T}(x)
28 +
@inline FixedVector{N}(x::NTuple{N,T}) where {N,T} = FixedVector{N,T}(x)
29 +
30 +
# Overide some problematic default behaviour
31 +
@inline Base.convert(::Type{SA}, sa::FixedVector) where {SA<:FixedVector} = SA(sa.v)
32 +
@inline Base.convert(::Type{SA}, sa::SA) where {SA<:FixedVector} = sa
33 +
34 +
# Back to Array (unfortunately need both convert and construct to overide other methods)
35 +
@inline Base.Array(sa::FixedVector) = Vector(sa.v)
36 +
@inline Base.Array{T}(sa::FixedVector{N,T}) where {N,T} = Vector{T}(sa.v)
37 +
@inline Base.Array{T,1}(sa::FixedVector{N,T}) where {N,T} = Vector{T}(sa.v)
38 +
39 +
@inline Base.convert(::Type{Array}, sa::FixedVector) = sa.v
40 +
@inline Base.convert(::Type{Array{T}}, sa::FixedVector{N,T}) where {N,T} = sa.v
41 +
@inline Base.convert(::Type{Array{T,1}}, sa::FixedVector{N,T}) where {N,T} = sa.v
42 +
43 +
@propagate_inbounds Base.getindex(a::FixedVector, i::Int) = getindex(a.v, i)
44 +
@propagate_inbounds Base.setindex!(a::FixedVector, v, i::Int) = setindex!(a.v, v, i)
45 +
46 +
Base.dataids(sa::FixedVector) = Base.dataids(sa.v)
47 +
48 +
function Base.promote_rule(::Type{<:FixedVector{N,T}}, ::Type{<:FixedVector{N,U}}) where {N,T,U}
49 +
    FixedVector{N,promote_type(T,U)}
50 +
end

@@ -0,0 +1,50 @@
Loading
1 +
(::Type{SA})(x::Tuple{Tuple{Tuple{<:Tuple}}}) where {SA <: TupleVector} =
2 +
    throw(DimensionMismatch("No precise constructor for $SA found. Val of input was $(length(x[1][1][1]))."))
3 +
4 +
@inline (::Type{SA})(x...) where {SA <: TupleVector} = SA(x)
5 +
@inline (::Type{SA})(a::TupleVector) where {SA<:TupleVector} = SA(Tuple(a))
6 +
@propagate_inbounds (::Type{SA})(a::AbstractArray) where {SA <: TupleVector} = convert(SA, a)
7 +
8 +
# this covers most conversions and "statically-sized reshapes"
9 +
#@inline Base.convert(::Type{SA}, sa::TupleVector) where {SA<:TupleVector} = SA(Tuple(sa))
10 +
#@inline Base.convert(::Type{SA}, sa::SA) where {SA<:TupleVector} = sa
11 +
@inline Base.convert(::Type{SA}, x::Tuple) where {SA<:TupleVector} = SA(x) # convert -> constructor. Hopefully no loops...
12 +
13 +
# support conversion to AbstractArray
14 +
Base.AbstractArray{T}(sa::TupleVector{N,T}) where {N,T} = sa
15 +
Base.AbstractArray{T,1}(sa::TupleVector{N,T}) where {N,T} = sa
16 +
Base.AbstractArray{T}(sa::TupleVector{N,U}) where {N,T,U} = similar_type(typeof(sa),T,Val(N))(sa)
17 +
Base.AbstractArray{T,1}(sa::TupleVector{N,U}) where {N,T,U} = similar_type(typeof(sa),T,Val(N))(sa)
18 +
19 +
# Constructing a Tuple from a TupleVector
20 +
@inline Base.Tuple(a::TupleVector{N}) where N = unroll_tuple(a, Val(N))
21 +
22 +
@noinline function dimension_mismatch_fail(SA::Type, a::AbstractArray)
23 +
    throw(DimensionMismatch("expected input array of length $(length(SA)), got length $(length(a))"))
24 +
end
25 +
26 +
@propagate_inbounds function Base.convert(::Type{SA}, a::AbstractArray) where {SA<:TupleVector{N}} where N
27 +
    @boundscheck if length(a) != length(SA)
28 +
        dimension_mismatch_fail(SA, a)
29 +
    end
30 +
31 +
    return _convert(SA, a, Val(N))
32 +
end
33 +
34 +
@inline _convert(SA, a, l::Val) = SA(unroll_tuple(a, l))
35 +
@inline _convert(SA::Type{<:TupleVector{N,T}}, a, ::Val{0}) where {N,T} = similar_type(SA, T)(())
36 +
@inline _convert(SA, a, ::Val{0}) = similar_type(SA, eltype(a))(())
37 +
38 +
@pure length_val(n::Val{S}) where S = n
39 +
@pure length_val(n::TupleVector{S}) where S = Val(S)
40 +
@pure length_val(n::Type{<:TupleVector{S}}) where S = Val(S)
41 +
@pure length_val(a::T) where {T <: TupleMatrixLike{S}} where S = Val(S)
42 +
@pure length_val(a::Type{T}) where {T<:TupleMatrixLike{S}} where S = Val(S)
43 +
44 +
@generated function unroll_tuple(a::AbstractArray, ::Val{N}) where N
45 +
    exprs = [:(a[$j]) for j = 1:N]
46 +
    quote
47 +
        @_inline_meta
48 +
        @inbounds return $(Expr(:tuple, exprs...))
49 +
    end
50 +
end

@@ -0,0 +1,335 @@
Loading
1 +
2 +
"""
3 +
    _InitialValue
4 +
5 +
A singleton type for representing "universal" initial value (identity element).
6 +
7 +
The idea is that, given `op` for `mapfoldl`, virtually, we define an "extended"
8 +
version of it by
9 +
10 +
    op′(::_InitialValue, x) = x
11 +
    op′(acc, x) = op(acc, x)
12 +
13 +
This is just a conceptually useful model to have in mind and we don't actually
14 +
define `op′` here  (yet?).  But see `Base.BottomRF` for how it might work in
15 +
action.
16 +
17 +
(It is related to that you can always turn a semigroup without an identity into
18 +
a monoid by "adjoining" an element that acts as the identity.)
19 +
"""
20 +
struct _InitialValue end
21 +
22 +
@inline _first(a1, as...) = a1
23 +
24 +
################
25 +
## map / map! ##
26 +
################
27 +
28 +
# In 0.6 the three methods below could be replaced with
29 +
# `map(f, as::Union{<:StaticArray,AbstractArray}...)` which included at least one `StaticArray`
30 +
# this is not the case on 0.7 and we instead hope to find a StaticArray in the first two arguments.
31 +
@inline function Base.map(f, a1::TupleVector, as::AbstractArray...)
32 +
    _map(f, a1, as...)
33 +
end
34 +
@inline function Base.map(f, a1::AbstractArray, a2::TupleVector, as::AbstractArray...)
35 +
    _map(f, a1, a2, as...)
36 +
end
37 +
@inline function Base.map(f, a1::TupleVector, a2::TupleVector, as::AbstractArray...)
38 +
    _map(f, a1, a2, as...)
39 +
end
40 +
41 +
@generated function _map(f, a::AbstractArray...)
42 +
    first_tuplevector = findfirst(ai -> ai <: TupleVector, a)
43 +
    if first_tuplevector === nothing
44 +
        return :(throw(ArgumentError("No TupleVector found in argument list")))
45 +
    end
46 +
    # Passing the Val as an argument to _map leads to inference issues when
47 +
    # recursively mapping over nested TupleVectors (see issue #593). Calling
48 +
    # Val in the generator here is valid because a[first_staticarray] is known to be a
49 +
    # TupleVector for which the default Val method is correct. If wrapped
50 +
    # TupleVector (with a custom Val method) are to be supported, this will
51 +
    # no longer be valid.
52 +
    S = length(a[first_tuplevector])
53 +
54 +
    if S == 0
55 +
        # In the empty case only, use inference to try figuring out a sensible
56 +
        # eltype, as is done in Base.collect and broadcast.
57 +
        # See https://github.com/JuliaArrays/StaticArrays.jl/issues/528
58 +
        eltys = [:(eltype(a[$i])) for i ∈ 1:length(a)]
59 +
        return quote
60 +
            @_inline_meta
61 +
            S = same_size(a...)
62 +
            T = Core.Compiler.return_type(f, Tuple{$(eltys...)})
63 +
            @inbounds return similar_type(a[$first_staticarray], T, S)()
64 +
        end
65 +
    end
66 +
67 +
    exprs = Vector{Expr}(undef, S)
68 +
    for i ∈ 1:S
69 +
        tmp = [:(a[$j][$i]) for j ∈ 1:length(a)]
70 +
        exprs[i] = :(f($(tmp...)))
71 +
    end
72 +
73 +
    return quote
74 +
        @_inline_meta
75 +
        S = same_size(a...)
76 +
        @inbounds elements = tuple($(exprs...))
77 +
        @inbounds return similar_type(typeof(_first(a...)), eltype(elements), S)(elements)
78 +
    end
79 +
end
80 +
81 +
@inline function Base.map!(f, dest::TupleVector{n}, a::TupleVector{n}...) where n
82 +
    _map!(f, dest, Val(n), a...)
83 +
end
84 +
85 +
# Ambiguities with Base:
86 +
@inline function map!(f, dest::TupleVector{n}, a::TupleVector{n}) where n
87 +
    _map!(f, dest, Val(n), a)
88 +
end
89 +
@inline function map!(f,dest::TupleVector{n},a::TupleVector{n},b::TupleVector{n}) where n
90 +
    _map!(f, dest, Val(n), a, b)
91 +
end
92 +
93 +
94 +
@generated function _map!(f, dest, ::Val{S}, a::TupleVector...) where {S}
95 +
    exprs = Vector{Expr}(undef, S)
96 +
    for i ∈ 1:S
97 +
        tmp = [:(a[$j][$i]) for j ∈ 1:length(a)]
98 +
        exprs[i] = :(dest[$i] = f($(tmp...)))
99 +
    end
100 +
    return quote
101 +
        @_inline_meta
102 +
        @inbounds $(Expr(:block, exprs...))
103 +
    end
104 +
end
105 +
106 +
###############
107 +
## mapreduce ##
108 +
###############
109 +
110 +
@inline function Base.mapreduce(f, op, a::TupleVector, b::TupleVector...; dims=:, init = _InitialValue())
111 +
    _mapreduce(f, op, dims, init, same_size(a, b...), a, b...)
112 +
end
113 +
114 +
@inline _mapreduce(args::Vararg{Any,N}) where N = _mapfoldl(args...)
115 +
116 +
@generated function _mapfoldl(f, op, dims::Colon, init, ::Val{S}, a::TupleVector...) where {S}
117 +
    if S == 0
118 +
        if init === _InitialValue
119 +
            if length(a) == 1
120 +
                return :(Base.mapreduce_empty(f, op, $(eltype(a[1]))))
121 +
            else
122 +
                return :(throw(ArgumentError("reducing over an empty collection is not allowed")))
123 +
            end
124 +
        else
125 +
            return :init
126 +
        end
127 +
    end
128 +
    tmp = [:(a[$j][1]) for j ∈ 1:length(a)]
129 +
    expr = :(f($(tmp...)))
130 +
    if init === _InitialValue
131 +
        expr = :(Base.reduce_first(op, $expr))
132 +
    else
133 +
        expr = :(op(init, $expr))
134 +
    end
135 +
    for i ∈ 2:S
136 +
        tmp = [:(a[$j][$i]) for j ∈ 1:length(a)]
137 +
        expr = :(op($expr, f($(tmp...))))
138 +
    end
139 +
    return quote
140 +
        @_inline_meta
141 +
        @inbounds return $expr
142 +
    end
143 +
end
144 +
145 +
@inline function _mapreduce(f, op, D::Int, init, sz::Val{S}, a::TupleVector) where {S}
146 +
    # Body of this function is split because constant propagation (at least
147 +
    # as of Julia 1.2) can't always correctly propagate here and
148 +
    # as a result the function is not type stable and very slow.
149 +
    # This makes it at least fast for three dimensions but people should use
150 +
    # for example any(a; dims=Val(1)) instead of any(a; dims=1) anyway.
151 +
    if D == 1
152 +
        return _mapreduce(f, op, Val(1), init, sz, a)
153 +
    else
154 +
        return _mapreduce(f, op, Val(D), init, sz, a)
155 +
    end
156 +
end
157 +
158 +
@generated function _mapfoldl(f, op, dims::Val{1}, init,
159 +
                               ::Val{S}, a::TupleVector) where {S,D}
160 +
161 +
    exprs = Array{Expr}(undef, 1)
162 +
    for i ∈ Base.product(1:1)
163 +
        expr = :(f(a[$(i...)]))
164 +
        if init === _InitialValue
165 +
            expr = :(Base.reduce_first(op, $expr))
166 +
        else
167 +
            expr = :(op(init, $expr))
168 +
        end
169 +
170 +
        exprs[i...] = expr
171 +
    end
172 +
173 +
    return quote
174 +
        @_inline_meta
175 +
        @inbounds elements = tuple($(exprs...))
176 +
        @inbounds return similar_type(a, eltype(elements), Val(1))(elements)
177 +
    end
178 +
end
179 +
180 +
############
181 +
## reduce ##
182 +
############
183 +
184 +
@inline Base.reduce(op, a::TupleVector; dims = :, init = _InitialValue()) =
185 +
    _reduce(op, a, dims, init)
186 +
187 +
# disambiguation
188 +
Base.reduce(::typeof(vcat), A::TupleVector{n,<:AbstractVecOrMat}) where n =
189 +
    Base._typed_vcat(mapreduce(eltype, promote_type, A), A)
190 +
Base.reduce(::typeof(vcat), A::TupleVector{n,<:TupleVectorLike}) where n =
191 +
    _reduce(vcat, A, :, _InitialValue())
192 +
193 +
Base.reduce(::typeof(hcat), A::TupleVector{n,<:AbstractVecOrMat}) where n =
194 +
    Base._typed_hcat(mapreduce(eltype, promote_type, A), A)
195 +
Base.reduce(::typeof(hcat), A::TupleVector{n,<:TupleVectorLike}) where n =
196 +
    _reduce(hcat, A, :, _InitialValue())
197 +
198 +
@inline _reduce(op, a::TupleVector, dims, init = _InitialValue()) =
199 +
    _mapreduce(identity, op, dims, init, length_val(a), a)
200 +
201 +
################
202 +
## (map)foldl ##
203 +
################
204 +
205 +
# Using `where {R}` to force specialization. See:
206 +
# https://docs.julialang.org/en/v1.5-dev/manual/performance-tips/#Be-aware-of-when-Julia-avoids-specializing-1
207 +
# https://github.com/JuliaLang/julia/pull/33917
208 +
209 +
@inline Base.mapfoldl(f::F, op::R, a::TupleVector; init = _InitialValue()) where {F,R} =
210 +
    _mapfoldl(f, op, :, init, length_val(a), a)
211 +
@inline Base.foldl(op::R, a::TupleVector; init = _InitialValue()) where {R} =
212 +
    _foldl(op, a, :, init)
213 +
@inline _foldl(op::R, a, dims, init = _InitialValue()) where {R} =
214 +
    _mapfoldl(identity, op, dims, init, length_val(a), a)
215 +
216 +
#######################
217 +
## related functions ##
218 +
#######################
219 +
220 +
# These are all similar in Base but not @inline'd
221 +
#
222 +
# Implementation notes:
223 +
#
224 +
# 1. mapreduce and mapreducedim usually do not take initial value, because we don't
225 +
# always know the return type of an arbitrary mapping function f.  (We usually want to use
226 +
# some initial value such as one(T) or zero(T), where T is the return type of f, but
227 +
# if users provide type-unstable f, its return type cannot be known.)  Therefore, mapped
228 +
# versions of the functions implemented below usually require the collection to have at
229 +
# least two entries.
230 +
#
231 +
# 2. Exceptions are the ones that require Boolean mapping functions.  For example, f in
232 +
# all and any must return Bool, so we know the appropriate initial value is true and false,
233 +
# respectively.  Therefore, all(f, ...) and any(f, ...) are implemented by mapreduce(f, ...)
234 +
# with an initial value v0 = true and false.
235 +
#
236 +
# TODO: change to use Base.reduce_empty/Base.reduce_first
237 +
@inline Base.iszero(a::TupleVector{N,T}) where {N,T} = reduce((x,y) -> x && iszero(y), a, init=true)
238 +
239 +
@inline Base.sum(a::TupleVector{N,T}; dims=:) where {N,T} = _reduce(+, a, dims)
240 +
@inline Base.sum(f, a::TupleVector{N,T}; dims=:) where {N,T} = _mapreduce(f, +, dims, _InitialValue(), Val(N), a)
241 +
@inline Base.sum(f::Union{Function, Type}, a::TupleVector{N,T}; dims=:) where {N,T} = _mapreduce(f, +, dims, _InitialValue(), Val(N), a) # avoid ambiguity
242 +
243 +
@inline Base.prod(a::TupleVector{N,T}; dims=:) where {N,T} = _reduce(*, a, dims)
244 +
@inline Base.prod(f, a::TupleVector{N,T}; dims=:) where {N,T} = _mapreduce(f, *, dims, _InitialValue(), Val(N), a)
245 +
@inline Base.prod(f::Union{Function, Type}, a::TupleVector{N,T}; dims=:) where {N,T} = _mapreduce(f, *, dims, _InitialValue(), Val(N), a)
246 +
247 +
@inline Base.count(a::TupleVector{N,Bool}; dims=:) where N = _reduce(+, a, dims)
248 +
@inline Base.count(f, a::TupleVector{N}; dims=:) where N = _mapreduce(x->f(x)::Bool, +, dims, _InitialValue(), Val(N), a)
249 +
250 +
@inline Base.all(a::TupleVector{N,Bool}; dims=:) where N = _reduce(&, a, dims, true)  # non-branching versions
251 +
@inline Base.all(f::Function, a::TupleVector{N}; dims=:) where N = _mapreduce(x->f(x)::Bool, &, dims, true, Val(N), a)
252 +
253 +
@inline Base.any(a::TupleVector{N,Bool}; dims=:) where N = _reduce(|, a, dims, false) # (benchmarking needed)
254 +
@inline Base.any(f::Function, a::TupleVector{N}; dims=:) where N = _mapreduce(x->f(x)::Bool, |, dims, false, Val(N), a) # (benchmarking needed)
255 +
256 +
@inline Base.in(x, a::TupleVector{N}) where N = _mapreduce(==(x), |, :, false, Val(N), a)
257 +
258 +
#=_mean_denom(a, dims::Colon) = length(a)
259 +
_mean_denom(a, dims::Int) = size(a, dims)
260 +
_mean_denom(a, ::Val{D}) where {D} = size(a, D)
261 +
_mean_denom(a, ::Type{Val{D}}) where {D} = size(a, D)
262 +
263 +
@inline Statistics.mean(a::TupleVector; dims=:) = _reduce(+, a, dims) / _mean_denom(a, dims)
264 +
@inline Statistics.mean(f::Function, a::TupleVector{N}; dims=:) = _mapreduce(f, +, dims, _InitialValue(), Val(N), a) / _mean_denom(a, dims)=#
265 +
266 +
@inline Base.minimum(a::TupleVector; dims=:) = _reduce(min, a, dims) # base has mapreduce(idenity, scalarmin, a)
267 +
@inline Base.minimum(f::Function, a::TupleVector{N}; dims=:) where N = _mapreduce(f, min, dims, _InitialValue(), Val{N}, a)
268 +
269 +
@inline Base.maximum(a::TupleVector; dims=:) = _reduce(max, a, dims) # base has mapreduce(idenity, scalarmax, a)
270 +
@inline Base.maximum(f::Function, a::TupleVector; dims=:) = _mapreduce(f, max, dims, _InitialValue(), Val(N), a)
271 +
272 +
# Diff is slightly different
273 +
@inline LinearAlgebra.diff(a::TupleVector{N};dims=Val(1)) where N = _diff(Val(N),a,dims)
274 +
275 +
@inline function _diff(sz::Val, a::TupleVector, D::Int)
276 +
    _diff(sz,a,Val(D))
277 +
end
278 +
@generated function _diff(::Val{N}, a::TupleVector, ::Val{1}) where N
279 +
    Snew = N-1
280 +
    exprs = Array{Expr}(undef, Snew)
281 +
    for i1 = Base.product(1:Snew)
282 +
        i2 = copy([i1...])
283 +
        i2[1] = i1[1] + 1
284 +
        exprs[i1...] = :(a[$(i2...)] - a[$(i1...)])
285 +
    end
286 +
    return quote
287 +
        @_inline_meta
288 +
        elements = tuple($(exprs...))
289 +
        @inbounds return similar_type(a, eltype(elements), Val($Snew))(elements)
290 +
    end
291 +
end
292 +
293 +
_maybe_val(dims::Integer) = Val(Int(dims))
294 +
_maybe_val(dims) = dims
295 +
_valof(::Val{D}) where D = D
296 +
297 +
@inline Base.accumulate(op::F, a::TupleVector; dims = :, init = _InitialValue()) where {F} =
298 +
    _accumulate(op, a, _maybe_val(dims), init)
299 +
300 +
@inline function _accumulate(op::F, a::TupleVector, dims::Union{Val,Colon}, init) where {F}
301 +
    # Adjoin the initial value to `op` (one-line version of `Base.BottomRF`):
302 +
    rf(x, y) = x isa _InitialValue ? Base.reduce_first(op, y) : op(x, y)
303 +
304 +
    if isempty(a)
305 +
        T = return_type(rf, Tuple{typeof(init), eltype(a)})
306 +
        return similar_type(a, T)()
307 +
    end
308 +
309 +
    results = _foldl(
310 +
        a,
311 +
        dims,
312 +
        (similar_type(a, Union{}, Val(0))(), init),
313 +
    ) do (ys, acc), x
314 +
        y = rf(acc, x)
315 +
        # Not using `push(ys, y)` here since we need to widen element type as
316 +
        # we iterate.
317 +
        (vcat(ys, TV[y]), y)
318 +
    end
319 +
    dims === (:) && return first(results)
320 +
321 +
    ys = map(first, results)
322 +
    # Now map over all indices of `a`.  Since `_map` needs at least
323 +
    # one `TupleVector` to be passed, we pass `a` here, even though
324 +
    # the values of `a` are not used.
325 +
    data = _map(a, CartesianIndices(a)) do _, CI
326 +
        D = _valof(dims)
327 +
        I = Tuple(CI)
328 +
        J = Base.setindex(I, 1, D)
329 +
        ys[J...][I[D]]
330 +
    end
331 +
    return similar_type(a, eltype(data))(data)
332 +
end
333 +
334 +
@inline Base.cumsum(a::TupleVector; kw...) = accumulate(Base.add_sum, a; kw...)
335 +
@inline Base.cumprod(a::TupleVector; kw...) = accumulate(Base.mul_prod, a; kw...)

@@ -0,0 +1,98 @@
Loading
1 +
2 +
################################
3 +
## Non-scalar linear indexing ##
4 +
################################
5 +
6 +
@inline function Base.getindex(a::TupleVector{N}, ::Colon) where N
7 +
    _getindex(a::TupleVector, Val(N), :)
8 +
end
9 +
10 +
@generated function _getindex(a::TupleVector, s::Val{N}, ::Colon) where N
11 +
    exprs = [:(a[$i]) for i = 1:N]
12 +
    return quote
13 +
        @_inline_meta
14 +
        @inbounds return similar_type(a,s)(tuple($(exprs...)))
15 +
    end
16 +
end
17 +
18 +
@propagate_inbounds function Base.getindex(a::TupleVector, inds::TupleVector{N,Int}) where N
19 +
    _getindex(a, Val(N), inds)
20 +
end
21 +
22 +
@generated function _getindex(a::TupleVector, s::Val{N}, inds::TupleVector{N, Int}) where N
23 +
    exprs = [:(a[inds[$i]]) for i = 1:N]
24 +
    return quote
25 +
        Base.@_propagate_inbounds_meta
26 +
        similar_type(a, s)(tuple($(exprs...)))
27 +
    end
28 +
end
29 +
30 +
@inline function Base.setindex!(a::TupleVector{N}, v, ::Colon) where N
31 +
    _setindex!(a::TupleVector, v, Val(N), :)
32 +
    return v
33 +
end
34 +
35 +
@generated function _setindex!(a::TupleVector, v, ::Val{L}, ::Colon) where {L}
36 +
    exprs = [:(a[$i] = v) for i = 1:L]
37 +
    return quote
38 +
        @_inline_meta
39 +
        @inbounds $(Expr(:block, exprs...))
40 +
    end
41 +
end
42 +
43 +
@generated function _setindex!(a::TupleVector, v::AbstractVector, ::Val{L}, ::Colon) where {L}
44 +
    exprs = [:(a[$i] = v[$i]) for i = 1:L]
45 +
    return quote
46 +
        Base.@_propagate_inbounds_meta
47 +
        @boundscheck if length(v) != L
48 +
            throw(DimensionMismatch("tried to assign $(length(v))-element array to length-$L destination"))
49 +
        end
50 +
        @inbounds $(Expr(:block, exprs...))
51 +
    end
52 +
end
53 +
54 +
@generated function _setindex!(a::TupleVector, v::TupleVector{M}, ::Val{L}, ::Colon) where {M,L}
55 +
    exprs = [:(a[$i] = v[$i]) for i = 1:L]
56 +
    return quote
57 +
        Base.@_propagate_inbounds_meta
58 +
        @boundscheck if M != L
59 +
            throw(DimensionMismatch("tried to assign $M-element array to length-$L destination"))
60 +
        end
61 +
        $(Expr(:block, exprs...))
62 +
    end
63 +
end
64 +
65 +
@propagate_inbounds function Base.setindex!(a::TupleVector, v, inds::TupleVector{N,Int}) where N
66 +
    _setindex!(a, v, Val(N), inds)
67 +
    return v
68 +
end
69 +
70 +
@generated function _setindex!(a::TupleVector, v, ::Val{N}, inds::TupleVector{N,Int}) where N
71 +
    exprs = [:(a[inds[$i]] = v) for i = 1:N]
72 +
    return quote
73 +
        Base.@_propagate_inbounds_meta
74 +
        similar_type(a, s)(tuple($(exprs...)))
75 +
    end
76 +
end
77 +
78 +
@generated function _setindex!(a::TupleVector, v::AbstractVector, ::Val{N}, inds::TupleVector{N,Int}) where N
79 +
    exprs = [:(a[inds[$i]] = v[$i]) for i = 1:N]
80 +
    return quote
81 +
        Base.@_propagate_inbounds_meta
82 +
        @boundscheck if length(v) != $N
83 +
            throw(DimensionMismatch("tried to assign $(length(v))-element array to length-$N destination"))
84 +
        end
85 +
        $(Expr(:block, exprs...))
86 +
    end
87 +
end
88 +
89 +
@generated function _setindex!(a::TupleVector, v::TupleVector{M}, ::Val{N}, inds::TupleVector{N,Int}) where {N,M}
90 +
    exprs = [:(a[inds[$i]] = v[$i]) for i = 1:N]
91 +
    return quote
92 +
        Base.@_propagate_inbounds_meta
93 +
        @boundscheck if M != N
94 +
            throw(DimensionMismatch("tried to assign $M-element array to length-$N destination"))
95 +
        end
96 +
        $(Expr(:block, exprs...))
97 +
    end
98 +
end

@@ -0,0 +1,28 @@
Loading
1 +
2 +
# Cast any Tuple to an TupleN{T}
3 +
@inline convert_ntuple(::Type{T},d::T) where {T} = T # For zero-dimensional arrays
4 +
@inline convert_ntuple(::Type{T},d::NTuple{N,T}) where {N,T} = d
5 +
@generated function convert_ntuple(::Type{T}, d::NTuple{N,Any}) where {N,T}
6 +
    exprs = ntuple(i -> :(convert(T, d[$i])), Val(N))
7 +
    return quote
8 +
        @_inline_meta
9 +
        $(Expr(:tuple, exprs...))
10 +
    end
11 +
end
12 +
13 +
# Base gives up on tuples for promote_eltype... (TODO can we improve Base?)
14 +
@generated function promote_tuple_eltype(::Union{T,Type{T}}) where T <: Tuple
15 +
    t = Union{}
16 +
    for i = 1:length(T.parameters)
17 +
        tmp = T.parameters[i]
18 +
        if tmp <: Vararg
19 +
            tmp = tmp.parameters[1]
20 +
        end
21 +
        t = :(promote_type($t, $tmp))
22 +
    end
23 +
    return quote
24 +
        @_inline_meta
25 +
        $t
26 +
    end
27 +
end
28 +

@@ -0,0 +1,145 @@
Loading
1 +
2 +
@inline Base.zero(a::SA) where {SA<:TupleVector} = zeros(SA)
3 +
@inline Base.zero(a::Type{SA}) where {SA<:TupleVector} = zeros(SA)
4 +
5 +
@inline Base.zeros(::Type{SA}) where {SA<:TupleVector{N}} where N = _zeros(Val(N), SA)
6 +
@generated function _zeros(::Val{N}, ::Type{SA}) where SA<:TupleVector{N} where N
7 +
    T = eltype(SA)
8 +
    if T == Any
9 +
        T = Float64
10 +
    end
11 +
    v = [:(zero($T)) for i = 1:N]
12 +
    return quote
13 +
        @_inline_meta
14 +
        $SA(tuple($(v...)))
15 +
    end
16 +
end
17 +
18 +
@inline Base.ones(::Type{SA}) where {SA<:TupleVector{N}} where N = _ones(Val(N), SA)
19 +
@generated function _ones(::Val{N}, ::Type{SA}) where SA<:TupleVector{N} where N
20 +
    T = eltype(SA)
21 +
    if T == Any
22 +
        T = Float64
23 +
    end
24 +
    v = [:(one($T)) for i = 1:N]
25 +
    return quote
26 +
        @_inline_meta
27 +
        $SA(tuple($(v...)))
28 +
    end
29 +
end
30 +
31 +
@inline Base.fill(val,::SA) where {SA<:TupleVector{N}} where N = _fill(val, Val(N), SA)
32 +
@inline Base.fill(val,::Type{SA}) where {SA<:TupleVector{N}} where N = _fill(val, Val(N), SA)
33 +
@generated function _fill(val,::Val{N},::Type{SA}) where SA<:TupleVector{N} where N
34 +
    v = [:val for i = 1:N]
35 +
    return quote
36 +
        @_inline_meta
37 +
        $SA(tuple($(v...)))
38 +
    end
39 +
end
40 +
41 +
# Also consider randcycle, randperm? Also faster rand!(staticarray, collection)
42 +
43 +
using Random
44 +
import Random: SamplerType, AbstractRNG
45 +
@inline Base.rand(rng::AbstractRNG,::Type{SA},dims::Dims) where SA<:TupleVector = rand!(rng, Array{SA}(undef, dims), SA)
46 +
@inline Base.rand(rng::AbstractRNG,::SamplerType{SA}) where SA<:TupleVector{N} where N = _rand(rng, Val(N), SA)
47 +
48 +
@generated function _rand(rng::AbstractRNG,::Val{N},::Type{SA}) where {SA <: TupleVector{N}} where N
49 +
    T = eltype(SA)
50 +
    if T == Any
51 +
        T = Float64
52 +
    end
53 +
    v = [:(rand(rng, $T)) for i = 1:N]
54 +
    return quote
55 +
        @_inline_meta
56 +
        $SA(tuple($(v...)))
57 +
    end
58 +
end
59 +
60 +
@inline Base.rand(rng::AbstractRNG,range::AbstractArray, ::Type{SA}) where {SA<:TupleVector{N}} where N = _rand(rng, range, Val(N), SA)
61 +
@inline Base.rand(range::AbstractArray,::Type{SA}) where {SA<:TupleVector{N}} where N = _rand(Random.GLOBAL_RNG, range, Val(N), SA)
62 +
@generated function _rand(rng::AbstractRNG, range::AbstractArray, ::Val{N}, ::Type{SA}) where SA<:TupleVector{N} where N
63 +
    v = [:(rand(rng, range)) for i = 1:N]
64 +
    return quote
65 +
        @_inline_meta
66 +
        $SA(tuple($(v...)))
67 +
    end
68 +
end
69 +
70 +
#@inline Base.rand(rng::MersenneTwister, range::AbstractArray, ::Type{SA}) where {SA <: TupleVector} = _rand(rng, range, Val(SA), SA)
71 +
72 +
@inline Base.randn(rng::AbstractRNG,::Type{SA}) where SA<:TupleVector{N} where N = _randn(rng, Val(N), SA)
73 +
@generated function _randn(rng::AbstractRNG,::Val{N},::Type{SA}) where SA<:TupleVector{N} where N
74 +
    T = eltype(SA)
75 +
    if T == Any
76 +
        T = Float64
77 +
    end
78 +
    v = [:(randn(rng, $T)) for i = 1:N]
79 +
    return quote
80 +
        @_inline_meta
81 +
        $SA(tuple($(v...)))
82 +
    end
83 +
end
84 +
85 +
@inline Random.randexp(rng::AbstractRNG,::Type{SA}) where SA<:TupleVector{N} where N = _randexp(rng, Val(N), SA)
86 +
@generated function _randexp(rng::AbstractRNG,::Val{N},::Type{SA}) where SA <: TupleVector{N} where N
87 +
    T = eltype(SA)
88 +
    if T == Any
89 +
        T = Float64
90 +
    end
91 +
    v = [:(randexp(rng, $T)) for i = 1:N]
92 +
    return quote
93 +
        @_inline_meta
94 +
        $SA(tuple($(v...)))
95 +
    end
96 +
end
97 +
98 +
# Mutable versions
99 +
100 +
# Why don't these two exist in Base?
101 +
# @generated function Base.zeros!{SA <: TupleVector}(a::SA)
102 +
# @generated function Base.ones!{SA <: TupleVector}(a::SA)
103 +
104 +
@inline Base.fill!(a::SA,val) where SA<:TupleVector{N} where N = _fill!(Val(N), a, val)
105 +
@generated function _fill!(::Val{N},a::SA,val) where SA<:TupleVector{N} where N
106 +
    exprs = [:(a[$i] = valT) for i = 1:N]
107 +
    return quote
108 +
        @_inline_meta
109 +
        valT = convert(eltype(SA), val)
110 +
        @inbounds $(Expr(:block, exprs...))
111 +
        return a
112 +
    end
113 +
end
114 +
115 +
@inline Random.rand!(rng::AbstractRNG,a::SA) where SA<:TupleVector{N} where N = _rand!(rng, Val(N), a)
116 +
@generated function _rand!(rng::AbstractRNG,::Val{N},a::SA) where SA <: TupleVector{N} where N
117 +
    exprs = [:(a[$i] = rand(rng, eltype(SA))) for i = 1:N]
118 +
    return quote
119 +
        @_inline_meta
120 +
        @inbounds $(Expr(:block, exprs...))
121 +
        return a
122 +
    end
123 +
end
124 +
125 +
@inline Random.rand!(rng::MersenneTwister,a::SA) where SA<:TupleVector{N,Float64} where N = _rand!(rng, Val(N), a)
126 +
127 +
@inline Random.randn!(rng::AbstractRNG,a::SA) where SA<:TupleVector{N} where N = _randn!(rng, Val(N), a)
128 +
@generated function _randn!(rng::AbstractRNG,::Val{N},a::SA) where SA<:TupleVector{N} where N
129 +
    exprs = [:(a[$i] = randn(rng, eltype(SA))) for i = 1:N]
130 +
    return quote
131 +
        @_inline_meta
132 +
        @inbounds $(Expr(:block, exprs...))
133 +
        return a
134 +
    end
135 +
end
136 +
137 +
@inline Random.randexp!(rng::AbstractRNG,a::SA) where SA<:TupleVector{N} where N = _randexp!(rng, Val(N), a)
138 +
@generated function _randexp!(rng::AbstractRNG,::Val{N},a::SA) where SA<:TupleVector{N} where N
139 +
    exprs = [:(a[$i] = randexp(rng, eltype(SA))) for i = 1:N]
140 +
    return quote
141 +
        @_inline_meta
142 +
        @inbounds $(Expr(:block, exprs...))
143 +
        return a
144 +
    end
145 +
end

@@ -0,0 +1,59 @@
Loading
1 +
2 +
struct SOneTo{n} <: AbstractUnitRange{Int} end
3 +
4 +
@pure SOneTo(n::Int) = SOneTo{n}()
5 +
function SOneTo{n}(r::AbstractUnitRange) where n
6 +
    ((first(r) == 1) & (last(r) == n)) && return SOneTo{n}()
7 +
8 +
    errmsg(r) = throw(DimensionMismatch("$r is inconsistent with SOneTo{$n}")) # avoid GC frame
9 +
    errmsg(r)
10 +
end
11 +
Base.Tuple(::SOneTo{N}) where N = ntuple(identity, Val(N))
12 +
13 +
@pure Base.axes(s::SOneTo) = (s,)
14 +
@pure Base.size(s::SOneTo{n}) where n = (n,)
15 +
@pure Base.length(s::SOneTo{n}) where n = n
16 +
17 +
# The axes of a Slice'd SOneTo use the SOneTo itself
18 +
Base.axes(S::Base.Slice{<:SOneTo}) = (S.indices,)
19 +
Base.unsafe_indices(S::Base.Slice{<:SOneTo}) = (S.indices,)
20 +
Base.axes1(S::Base.Slice{<:SOneTo}) = S.indices
21 +
22 +
@propagate_inbounds function Base.getindex(s::SOneTo, i::Int)
23 +
    @boundscheck checkbounds(s, i)
24 +
    return i
25 +
end
26 +
@propagate_inbounds function Base.getindex(s::SOneTo, s2::SOneTo)
27 +
    @boundscheck checkbounds(s, s2)
28 +
    return s2
29 +
end
30 +
31 +
@pure Base.first(::SOneTo) = 1
32 +
@pure Base.last(::SOneTo{n}) where n = n::Int
33 +
@pure Base.iterate(::SOneTo{n}) where n = n::Int < 1 ? nothing : (1, 1)
34 +
@pure function Base.iterate(::SOneTo{n}, s::Int) where {n}
35 +
    if s < n::Int
36 +
        s2 = s + 1
37 +
        return (s2, s2)
38 +
    else
39 +
        return nothing
40 +
    end
41 +
end
42 +
43 +
function Base.getproperty(::SOneTo{n}, s::Symbol) where {n}
44 +
    if s === :start
45 +
        return 1
46 +
    elseif s === :stop
47 +
        return n::Int
48 +
    else
49 +
        error("type SOneTo has no property $s")
50 +
    end
51 +
end
52 +
53 +
Base.show(io::IO, ::SOneTo{n}) where {n} = print(io, "SOneTo(", n::Int, ")")
54 +
Base.@pure function Base.checkindex(::Type{Bool}, ::SOneTo{n1}, ::SOneTo{n2}) where {n1, n2}
55 +
    return n1::Int >= n2::Int
56 +
end
57 +
58 +
Base.promote_rule(a::Type{Base.OneTo{T}}, ::Type{SOneTo{n}}) where {T,n} =
59 +
    Base.OneTo{promote_type(T, Int)}

@@ -0,0 +1,60 @@
Loading
1 +
2 +
"""
3 +
    TV[ elements ]
4 +
    TV{T}[ elements ]
5 +
6 +
Create `Values` literals using array construction syntax. The element type is
7 +
inferred by promoting `elements` to a common type or set to `T` when `T` is
8 +
provided explicitly.
9 +
10 +
# Examples:
11 +
12 +
* `TV[1.0, 2.0]` creates a length-2 `Values` of `Float64` elements.
13 +
* `TV{Float32}[1, 2]` creates a length-2 `Values` of `Float32` elements.
14 +
15 +
A couple of helpful type aliases are also provided:
16 +
17 +
* `TV_F64[1, 2]` creates a lenght-2 `Values` of `Float64` elements
18 +
* `TV_F32[1, 2]` creates a lenght-2 `Values` of `Float32` elements
19 +
"""
20 +
struct TV{T} ; end
21 +
22 +
const TV_F32 = TV{Float32}
23 +
const TV_F64 = TV{Float64}
24 +
25 +
@inline similar_type(::Type{TV}, ::Val{S}) where {S} = Values{S}
26 +
@inline similar_type(::Type{TV{T}}, ::Val{S}) where {T,S} = Values{S,T}
27 +
28 +
# These definitions are duplicated to avoid matching `sa === Union{}` in the
29 +
# neater-looking alternative `sa::Type{<:TV}`.
30 +
@inline Base.getindex(sa::Type{TV}, xs...)            = similar_type(sa, Val(length(xs)))(xs)
31 +
@inline Base.getindex(sa::Type{TV{T}}, xs...) where T = similar_type(sa, Val(length(xs)))(xs)
32 +
33 +
@inline Base.typed_vcat(sa::Type{TV}, xs::Number...)            = similar_type(sa, Val(length(xs)))(xs)
34 +
@inline Base.typed_vcat(sa::Type{TV{T}}, xs::Number...) where T = similar_type(sa, Val(length(xs)))(xs)
35 +
36 +
#=@inline Base.typed_hcat(sa::Type{TV}, xs::Number...)            = similar_type(sa, Val(length(xs)))(xs)
37 +
@inline Base.typed_hcat(sa::Type{TV{T}}, xs::Number...) where T = similar_type(sa, Val(length(xs)))(xs)
38 +
39 +
Base.@pure function _TV_hvcat_transposed_size(rows)
40 +
    M = rows[1]
41 +
    if any(r->r != M, rows)
42 +
        # @pure may not throw... probably. See
43 +
        # https://discourse.julialang.org/t/can-pure-functions-throw-an-error/18459
44 +
        return nothing
45 +
    end
46 +
    Val(length(rows))
47 +
end
48 +
49 +
@inline function _TV_typed_hvcat(sa, rows, xs)
50 +
    msize = _TV_hvcat_transposed_size(rows)
51 +
    if msize === nothing
52 +
        throw(ArgumentError("TV[...] matrix rows of length $rows are inconsistent"))
53 +
    end
54 +
    # hvcat lowering is row major ordering, so we must transpose
55 +
    transpose(similar_type(sa, msize)(xs))
56 +
end
57 +
58 +
@inline Base.typed_hvcat(sa::Type{TV}, rows::Dims, xs::Number...)            = _TV_typed_hvcat(sa, rows, xs)
59 +
@inline Base.typed_hvcat(sa::Type{TV{T}}, rows::Dims, xs::Number...) where T = _TV_typed_hvcat(sa, rows, xs)
60 +
=#

@@ -0,0 +1,42 @@
Loading
1 +
2 +
# SArray.jl
3 +
4 +
struct Values{N,T} <: TupleVector{N,T}
5 +
    v::NTuple{N,T}
6 +
    Values{N,T}(x::NTuple{N,T}) where {N,T} = new{N,T}(x)
7 +
    Values{N,T}(x::NTuple{N,Any}) where {N,T} = new{N,T}(convert_ntuple(T, x))
8 +
end
9 +
10 +
@pure @generated function (::Type{Values{N,T}})(x::Tuple) where {T, N}
11 +
    return quote
12 +
        @_inline_meta
13 +
        Values{N,T}(x)
14 +
    end
15 +
end
16 +
17 +
@inline Values(a::TupleVector{N}) where N = Values{N}(Tuple(a))
18 +
@propagate_inbounds Base.getindex(v::Values, i::Int) = v.v[i]
19 +
@inline Tuple(v::Values) = v.v
20 +
Base.dataids(::Values) = ()
21 +
22 +
# See #53
23 +
Base.cconvert(::Type{Ptr{T}}, a::Values) where {T} = Base.RefValue(a)
24 +
Base.unsafe_convert(::Type{Ptr{T}}, a::Base.RefValue{SA}) where {N,T,SA<:Values{N,T}} = Ptr{T}(Base.unsafe_convert(Ptr{Values{N,T}}, a))
25 +
26 +
# SVector.jl
27 +
28 +
@inline Values(x::NTuple{N,Any}) where N = Values{N}(x)
29 +
@inline Values{N}(x::NTuple{N,T}) where {N,T} = Values{N,T}(x)
30 +
@inline Values{N}(x::T) where {N,T<:Tuple} = Values{N,promote_tuple_eltype(T)}(x)
31 +
32 +
# Some more advanced constructor-like functions
33 +
@pure @inline Base.zeros(::Type{Values{N}}) where N = zeros(Values{N,Float64})
34 +
@pure @inline Base.ones(::Type{Values{N}}) where N = ones(Values{N,Float64})
35 +
36 +
# Converting a CartesianIndex to an SVector
37 +
Base.convert(::Type{Values}, I::CartesianIndex) = Values(I.I)
38 +
Base.convert(::Type{Values{N}}, I::CartesianIndex{N}) where {N} = Values{N}(I.I)
39 +
Base.convert(::Type{Values{N,T}}, I::CartesianIndex{N}) where {N,T} = Values{N,T}(I.I)
40 +
41 +
@pure Base.promote_rule(::Type{Values{N,T}}, ::Type{CartesianIndex{N}}) where {N,T} = Values{N,promote_type(T,Int)}
42 +

@@ -0,0 +1,128 @@
Loading
1 +
2 +
#--------------------------------------------------
3 +
# Vector space algebra
4 +
5 +
# Unary ops
6 +
@inline Base.:-(a::TupleVector) = map(-, a)
7 +
@inline Base.:-(a::TupleVector{n,<:Number}) where n = map(Base.:-, a)
8 +
9 +
# Binary ops
10 +
# Between arrays
11 +
@inline Base.:+(a::TupleVector, b::TupleVector) = map(∑, a, b)
12 +
@inline Base.:+(a::AbstractArray, b::TupleVector) = map(∑, a, b)
13 +
@inline Base.:+(a::TupleVector, b::AbstractArray) = map(∑, a, b)
14 +
15 +
@inline Base.:+(a::TupleVector{n,<:Number}, b::TupleVector{n,<:Number}) where n = map(Base.:+, a, b)
16 +
@inline Base.:+(a::AbstractArray{<:Number}, b::TupleVector{n,<:Number}) where n = map(Base.:+, a, b)
17 +
@inline Base.:+(a::TupleVector{n,<:Number}, b::AbstractArray{<:Number}) where n = map(Base.:+, a, b)
18 +
19 +
@inline Base.:-(a::TupleVector, b::TupleVector) = map(-, a, b)
20 +
@inline Base.:-(a::AbstractArray, b::TupleVector) = map(-, a, b)
21 +
@inline Base.:-(a::TupleVector, b::AbstractArray) = map(-, a, b)
22 +
23 +
@inline Base.:-(a::TupleVector{n,<:Number}, b::TupleVector{n,<:Number}) where n = map(Base.:-, a, b)
24 +
@inline Base.:-(a::AbstractArray{<:Number}, b::TupleVector{n,<:Number}) where n = map(Base.:-, a, b)
25 +
@inline Base.:-(a::TupleVector{n,<:Number}, b::AbstractArray{<:Number}) where n = map(Base.:-, a, b)
26 +
27 +
# Scalar-array
28 +
@inline Base.:*(a::Number, b::TupleVector{n,<:Number}) where n = broadcast(Base.:*, a, b)
29 +
@inline Base.:*(a::TupleVector{n,<:Number}, b::Number) where n = broadcast(Base.:*, a, b)
30 +
31 +
@inline Base.:*(a, b::TupleVector) = broadcast(∏, a, b)
32 +
@inline Base.:*(a::TupleVector, b) = broadcast(∏, a, b)
33 +
34 +
@inline Base.:*(a::Expr, b::TupleVector) = broadcast(∏, Ref(a), b)
35 +
@inline Base.:*(a::TupleVector, b::Expr) = broadcast(∏, a, Ref(b))
36 +
37 +
@inline Base.:*(a::Symbol, b::TupleVector) = broadcast(∏, Ref(a), b)
38 +
@inline Base.:*(a::TupleVector, b::Symbol) = broadcast(∏, a, Ref(b))
39 +
40 +
@inline Base.:/(a::TupleVector{n,<:Number}, b::Number) where n = broadcast(Base.:/, a, b)
41 +
@inline Base.:\(a::Number, b::TupleVector{n,<:Number}) where n = broadcast(Base.:\, a, b)
42 +
43 +
@inline Base.:/(a::TupleVector, b) = broadcast(/, a, b)
44 +
@inline Base.:\(a, b::TupleVector) = broadcast(\, a, b)
45 +
46 +
#--------------------------------------------------
47 +
# Vector products
48 +
@inline LinearAlgebra.dot(a::TupleVector, b::TupleVector) = _vecdot(a, b, LinearAlgebra.dot)
49 +
@inline bilinear_vecdot(a::TupleVector, b::TupleVector) = _vecdot(a, b, Base.:*)
50 +
51 +
@inline function _vecdot(a::TupleVector{S}, b::TupleVector{S}, product) where S
52 +
    if S == 0
53 +
        za, zb = zero(eltype(a)), zero(eltype(b))
54 +
    else
55 +
        # Use an actual element if there is one, to support e.g. Vector{<:Number}
56 +
        # element types for which runtime size information is required to construct
57 +
        # a zero element.
58 +
        za, zb = zero(a[1]), zero(b[1])
59 +
    end
60 +
    ret = product(za, zb) + product(za, zb)
61 +
    @inbounds @simd for j = 1:S
62 +
        ret += product(a[j], b[j])
63 +
    end
64 +
    return ret
65 +
end
66 +
67 +
#--------------------------------------------------
68 +
# Norms
69 +
@inline LinearAlgebra.norm_sqr(v::TupleVector) = mapreduce(Base.abs2, Base.:+, v; init=zero(real(eltype(v))))
70 +
71 +
@inline LinearAlgebra.norm(a::TupleVector) = _norm(a)
72 +
@generated function _norm(a::TupleVector{S}) where S
73 +
    if S == 0
74 +
        return :(zero(real(eltype(a))))
75 +
    end
76 +
    expr = :(Base.abs2(a[1]))
77 +
    for j = 2:S
78 +
        expr = :($expr + Base.abs2(a[$j]))
79 +
    end
80 +
    return quote
81 +
        $(Expr(:meta, :inline))
82 +
        @inbounds return Base.sqrt($expr)
83 +
    end
84 +
end
85 +
86 +
_norm_p0(x) = x == 0 ? zero(x) : one(x)
87 +
88 +
@inline LinearAlgebra.norm(a::TupleVector, p::Real) = _norm(a, p)
89 +
@generated function _norm(a::TupleVector{S,T}, p::Real) where {S,T}
90 +
    if S == 0
91 +
        return :(zero(real(eltype(a))))
92 +
    end
93 +
    fun = T<:Number ? :(Base.abs) : :abs
94 +
    expr = :($fun(a[1])^p)
95 +
    for j = 2:S
96 +
        expr = :($expr + $fun(a[$j])^p)
97 +
    end
98 +
    expr_p1 = :($fun(a[1]))
99 +
    for j = 2:S
100 +
        expr_p1 = :($expr_p1 + $fun(a[$j]))
101 +
    end
102 +
    return quote
103 +
        $(Expr(:meta, :inline))
104 +
        if p == Inf
105 +
            return mapreduce(Base.abs, max, a)
106 +
        elseif p == 1
107 +
            @inbounds return $expr_p1
108 +
        elseif p == 2
109 +
            return LinearAlgebra.norm(a)
110 +
        elseif p == 0
111 +
            return mapreduce(_norm_p0, $(T<:Number ? :(Base.:+) : :∑), a)
112 +
        else
113 +
            @inbounds return $(T<:Number ? :(Base.:^) : :^)($expr,$(T<:Number ? :(Base.inv) : :inv)(p))
114 +
        end
115 +
    end
116 +
end
117 +
118 +
@inline LinearAlgebra.normalize(a::TupleVector) = ∏(inv(LinearAlgebra.norm(a)),a)
119 +
@inline LinearAlgebra.normalize(a::TupleVector, p::Real) = ∏(inv(LinearAlgebra.norm(a, p)),a)
120 +
121 +
@inline LinearAlgebra.normalize!(a::TupleVector) = (a .*= inv(LinearAlgebra.norm(a)); return a)
122 +
@inline LinearAlgebra.normalize!(a::TupleVector, p::Real) = (a .*= inv(LinearAlgebra.norm(a, p)); return a)
123 +
124 +
@inline LinearAlgebra.normalize(a::TupleVector{n,<:Number}) where n = Base.:*(Base.inv(LinearAlgebra.norm(a)),a)
125 +
@inline LinearAlgebra.normalize(a::TupleVector{n,<:Number}, p::Real) where n = Base.:*(Base.inv(LinearAlgebra.norm(a, p)),a)
126 +
127 +
@inline LinearAlgebra.normalize!(a::TupleVector{n,<:Number}) where n = (a .*= Base.inv(LinearAlgebra.norm(a)); return a)
128 +
@inline LinearAlgebra.normalize!(a::TupleVector{n,<:Number}, p::Real) where n = (a .*= Base.inv(LinearAlgebra.norm(a, p)); return a)

@@ -0,0 +1,125 @@
Loading
1 +
2 +
Base.axes(::TupleVector{N}) where N = _axes(Val(N))
3 +
@pure function _axes(::Val{sizes}) where {sizes}
4 +
    map(SOneTo, (sizes,))
5 +
end
6 +
Base.axes(rv::LinearAlgebra.Adjoint{<:Any,<:Values})   = (SOneTo(1), axes(rv.parent)...)
7 +
Base.axes(rv::LinearAlgebra.Transpose{<:Any,<:Values}) = (SOneTo(1), axes(rv.parent)...)
8 +
9 +
# Base.strides is intentionally not defined for SArray, see PR #658 for discussion
10 +
Base.strides(a::Variables) = Base.size_to_strides(1, size(a)...)
11 +
Base.strides(a::FixedVector) = strides(a.v)
12 +
13 +
Base.IndexStyle(::Type{T}) where {T<:TupleVector} = IndexLinear()
14 +
15 +
similar_type(::SA) where {SA<:TupleVector} = similar_type(SA,eltype(SA))
16 +
similar_type(::Type{SA}) where {SA<:TupleVector} = similar_type(SA,eltype(SA))
17 +
18 +
similar_type(::SA,::Type{T}) where {SA<:TupleVector{N},T} where N = similar_type(SA,T,Val(N))
19 +
similar_type(::Type{SA},::Type{T}) where {SA<:TupleVector{N},T} where N = similar_type(SA,T,Val(N))
20 +
21 +
similar_type(::A,n::Val) where {A<:AbstractArray} = similar_type(A,eltype(A),n)
22 +
similar_type(::Type{A},n::Val) where {A<:AbstractArray} = similar_type(A,eltype(A),n)
23 +
24 +
similar_type(::A,::Type{T},n::Val) where {A<:AbstractArray,T} = similar_type(A,T,n)
25 +
26 +
# We should be able to deal with SOneTo axes
27 +
similar_type(s::SOneTo) = similar_type(typeof(s))
28 +
similar_type(::Type{SOneTo{n}}) where n = similar_type(SOneTo{n}, Int, Val(n))
29 +
30 +
# Default types
31 +
# Generally, use SArray
32 +
similar_type(::Type{A},::Type{T},n::Val) where {A<:AbstractArray,T} = default_similar_type(T,n)
33 +
default_similar_type(::Type{T},::Val{N}) where {N,T} = Values{N,T}
34 +
35 +
similar_type(::Type{SA},::Type{T},n::Val) where {SA<:Variables,T} = mutable_similar_type(T,n)
36 +
37 +
mutable_similar_type(::Type{T},::Val{N}) where {N,T} = Variables{N,T}
38 +
39 +
similar_type(::Type{<:FixedVector},::Type{T},n::Val) where T = sizedarray_similar_type(T,n)
40 +
# Should FixedVector also be used for normal Array?
41 +
#similar_type(::Type{<:Array},::Type{T},n::Val) where T = sizedarray_similar_type(T,n)
42 +
43 +
sizedarray_similar_type(::Type{T},::Val{N}) where {N,T} = FixedVector{N,T}
44 +
45 +
Base.similar(::SA) where {SA<:TupleVector} = similar(SA,eltype(SA))
46 +
Base.similar(::Type{SA}) where {SA<:TupleVector} = similar(SA,eltype(SA))
47 +
48 +
Base.similar(::SA,::Type{T}) where {SA<:TupleVector{N},T} where N = similar(SA,T,Val(N))
49 +
Base.similar(::Type{SA},::Type{T}) where {SA<:TupleVector{N},T} where N = similar(SA,T,Val(N))
50 +
51 +
# Cases where a Val is given as the dimensions
52 +
Base.similar(::A,n::Val) where A<:AbstractArray = similar(A,eltype(A),n)
53 +
Base.similar(::Type{A},n::Val) where A<:AbstractArray = similar(A,eltype(A),n)
54 +
55 +
Base.similar(::A,::Type{T},n::Val) where {A<:AbstractArray,T} = similar(A,T,n)
56 +
57 +
# defaults to built-in mutable types
58 +
Base.similar(::Type{A},::Type{T},n::Val) where {A<:AbstractArray,T} = mutable_similar_type(T,n)(undef)
59 +
60 +
# both FixedVector and Array return FixedVector
61 +
Base.similar(::Type{SA},::Type{T},n::Val) where {SA<:FixedVector,T} = sizedarray_similar_type(T,n)(undef)
62 +
Base.similar(::Type{A},::Type{T},n::Val) where {A<:Array,T} = sizedarray_similar_type(T,n)(undef)
63 +
64 +
# Support tuples of mixtures of `SOneTo`s alongside the normal `Integer` and `OneTo` options
65 +
# by simply converting them to either a tuple of Ints or a Val, re-dispatching to either one
66 +
# of the above methods (in the case of Val) or a base fallback (in the case of Ints).
67 +
const HeterogeneousShape = Union{Integer, Base.OneTo, SOneTo}
68 +
69 +
Base.similar(A::AbstractArray, ::Type{T}, shape::Tuple{HeterogeneousShape, Vararg{HeterogeneousShape}}) where {T} = similar(A, T, homogenize_shape(shape))
70 +
Base.similar(::Type{A}, shape::Tuple{HeterogeneousShape, Vararg{HeterogeneousShape}}) where {A<:AbstractArray} = similar(A, homogenize_shape(shape))
71 +
# Use an Array for TupleVectors if we don't have a statically-known size
72 +
Base.similar(::Type{A}, shape::Tuple{Int, Vararg{Int}}) where {A<:TupleVector} = Array{eltype(A)}(undef, shape)
73 +
74 +
homogenize_shape(::Tuple{}) = ()
75 +
homogenize_shape(shape::Tuple{Vararg{SOneTo}}) = Val(prod(map(last, shape)))
76 +
homogenize_shape(shape::Tuple{Vararg{HeterogeneousShape}}) = map(last, shape)
77 +
78 +
79 +
@inline Base.copy(a::TupleVector) = typeof(a)(Tuple(a))
80 +
@inline Base.copy(a::FixedVector) = typeof(a)(copy(a.v))
81 +
82 +
@inline Base.reverse(v::Values) = typeof(v)(_reverse(v))
83 +
84 +
@generated function _reverse(v::Values{N,T}) where {N,T}
85 +
    return Expr(:tuple, (:(v[$i]) for i = N:(-1):1)...)
86 +
end
87 +
88 +
#--------------------------------------------------
89 +
# Concatenation
90 +
@inline Base.vcat(a::TupleVectorLike) = a
91 +
@inline Base.vcat(a::TupleVectorLike{N}, b::TupleVectorLike{M}) where {N,M} = _vcat(Val(N), Val(M), a, b)
92 +
@inline Base.vcat(a::TupleVectorLike, b::TupleVectorLike, c::TupleVectorLike...) = vcat(vcat(a,b), vcat(c...))
93 +
94 +
@generated function _vcat(::Val{Sa}, ::Val{Sb}, a::TupleVectorLike, b::TupleVectorLike) where {Sa, Sb}
95 +
96 +
    # TODO cleanup?
97 +
    Snew = Sa + Sb
98 +
    exprs = vcat([:(a[$i]) for i = 1:Sa],
99 +
                 [:(b[$i]) for i = 1:Sb])
100 +
    return quote
101 +
        @_inline_meta
102 +
        @inbounds return similar_type(a, promote_type(eltype(a), eltype(b)), Val($Snew))(tuple($(exprs...)))
103 +
    end
104 +
end
105 +
106 +
#=@inline hcat(a::StaticVector) = similar_type(a, Size(Size(a)[1],1))(a)
107 +
@inline hcat(a::StaticMatrixLike) = a
108 +
@inline hcat(a::StaticVecOrMatLike, b::StaticVecOrMatLike) = _hcat(Size(a), Size(b), a, b)
109 +
@inline hcat(a::StaticVecOrMatLike, b::StaticVecOrMatLike, c::StaticVecOrMatLike...) = hcat(hcat(a,b), hcat(c...))
110 +
111 +
@generated function _hcat(::Size{Sa}, ::Size{Sb}, a::StaticVecOrMatLike, b::StaticVecOrMatLike) where {Sa, Sb}
112 +
    if Sa[1] != Sb[1]
113 +
        return :(throw(DimensionMismatch("Tried to hcat arrays of size $Sa and $Sb")))
114 +
    end
115 +
116 +
    exprs = vcat([:(a[$i]) for i = 1:prod(Sa)],
117 +
                 [:(b[$i]) for i = 1:prod(Sb)])
118 +
119 +
    Snew = (Sa[1], Size(Sa)[2] + Size(Sb)[2])
120 +
121 +
    return quote
122 +
        @_inline_meta
123 +
        @inbounds return similar_type(a, promote_type(eltype(a), eltype(b)), Size($Snew))(tuple($(exprs...)))
124 +
    end
125 +
end=#

@@ -0,0 +1,65 @@
Loading
1 +
2 +
# MArray.jl
3 +
4 +
mutable struct Variables{N,T} <: TupleVector{N,T}
5 +
    v::NTuple{N,T}
6 +
    Variables{N,T}(x::NTuple{N,T}) where {N,T} = new{N,T}(x)
7 +
    Variables{N,T}(x::NTuple{N,Any}) where {N,T} = new{N,T}(convert_ntuple(T, x))
8 +
    Variables{N,T}(::UndefInitializer) where {N,T} = new{N,T}()
9 +
end
10 +
11 +
@inline Variables(a::TupleVector{N}) where N = Variables{N}(Tuple(a))
12 +
@generated function (::Type{Variables{N,T}})(x::Tuple) where {N,T}
13 +
    return quote
14 +
        $(Expr(:meta, :inline))
15 +
        Variables{N,T}(x)
16 +
    end
17 +
end
18 +
@generated function (::Type{Variables{N}})(x::T) where {N,T<:Tuple}
19 +
    return quote
20 +
        $(Expr(:meta, :inline))
21 +
        Variables{N,promote_tuple_eltype(T)}(x)
22 +
    end
23 +
end
24 +
25 +
@propagate_inbounds function Base.getindex(v::Variables, i::Int)
26 +
    @boundscheck checkbounds(v,i)
27 +
    T = eltype(v)
28 +
    if isbitstype(T)
29 +
        return GC.@preserve v unsafe_load(Base.unsafe_convert(Ptr{T}, pointer_from_objref(v)), i)
30 +
    end
31 +
    v.v[i]
32 +
end
33 +
@propagate_inbounds function Base.setindex!(v::Variables, val, i::Int)
34 +
    @boundscheck checkbounds(v,i)
35 +
    T = eltype(v)
36 +
    if isbitstype(T)
37 +
        GC.@preserve v unsafe_store!(Base.unsafe_convert(Ptr{T}, pointer_from_objref(v)), convert(T, val), i)
38 +
    else
39 +
        # This one is unsafe (#27)
40 +
        # unsafe_store!(Base.unsafe_convert(Ptr{Ptr{Nothing}}, pointer_from_objref(v.data)), pointer_from_objref(val), i)
41 +
        error("setindex!() with non-isbitstype eltype is not supported by TupleVectors. Consider using FixedVector.")
42 +
    end
43 +
    return val
44 +
end
45 +
46 +
@inline Base.Tuple(v::Variables) = v.v
47 +
Base.dataids(ma::Variables) = (UInt(pointer(ma)),)
48 +
49 +
@inline function Base.unsafe_convert(::Type{Ptr{T}}, a::Variables{N,T}) where {N,T}
50 +
    Base.unsafe_convert(Ptr{T}, pointer_from_objref(a))
51 +
end
52 +
53 +
function Base.promote_rule(::Type{<:Variables{N,T}}, ::Type{<:Variables{N,U}}) where {N,T,U}
54 +
    Variables{N,promote_type(T,U)}
55 +
end
56 +
57 +
# MVector.jl
58 +
59 +
@inline Variables(x::NTuple{N,Any}) where N = Variables{N}(x)
60 +
@inline Variables{N}(x::NTuple{N,T}) where {N,T} = Variables{N,T}(x)
61 +
@inline Variables{N}(x::NTuple{N,Any}) where N = Variables{N, promote_tuple_eltype(typeof(x))}(x)
62 +
63 +
# Some more advanced constructor-like functions
64 +
@inline Base.zeros(::Type{Variables{N}}) where N = zeros(Variables{N,Float64})
65 +
@inline Base.ones(::Type{Variables{N}}) where N = ones(Variables{N,Float64})

@@ -1,11 +1,22 @@
Loading
1 1
2 -
# this file is inspired from TupleVectors.jl
3 -
# https://github.com/JuliaArrays/TupleVectors.jl
2 +
# this file is inspired from StaticArrays.jl
3 +
# https://github.com/JuliaArrays/StaticArrays.jl
4 4
5 5
import Base: @propagate_inbounds, @_inline_meta, @pure
6 6
7 7
abstract type TupleVector{N,T} <: AbstractVector{T} end
8 8
9 +
# Being a member of TupleMatrixLike or TupleVectorLike implies that Val(A)
10 +
# returns a static Val instance (none of the dimensions are Dynamic). The converse may not be true.
11 +
# These are akin to aliases like StridedArray and in similarly bad taste, but the current approach
12 +
# in Base necessitates their existence.
13 +
const TupleMatrixLike{n,T} = Union{
14 +
    LinearAlgebra.Transpose{T, <:TupleVector{n,T}},
15 +
    LinearAlgebra.Adjoint{T, <:TupleVector{n,T}},
16 +
    LinearAlgebra.Diagonal{T, <:TupleVector{n,T}},
17 +
}
18 +
const TupleVectorLike{n,T} = Union{TupleVector{n,T}, TupleMatrixLike{n,T}}
19 +
9 20
@pure Base.length(::T) where T<:TupleVector{N} where N = N
10 21
@pure Base.length(::Type{<:TupleVector{N}}) where N = N
11 22
@pure Base.lastindex(::T) where T<:TupleVector{N} where N = N
@@ -14,907 +25,17 @@
Loading
14 25
@pure @inline Base.size(t::T,d::Int) where T<:TupleVector{N} where N = d > 1 ? 1 : length(t)
15 26
@pure @inline Base.size(t::Type{<:TupleVector},d::Int) = d > 1 ? 1 : length(t)
16 27
17 -
Base.IndexStyle(::Type{T}) where {T<:TupleVector} = IndexLinear()
18 -
19 -
20 -
################################
21 -
## Non-scalar linear indexing ##
22 -
################################
23 -
24 -
@inline function Base.getindex(a::TupleVector{N}, ::Colon) where N
25 -
    _getindex(a::TupleVector, Val(N), :)
26 -
end
27 -
28 -
@generated function _getindex(a::TupleVector, s::Val{N}, ::Colon) where N
29 -
    exprs = [:(a[$i]) for i = 1:N]
30 -
    return quote
31 -
        @_inline_meta
32 -
        @inbounds return similar_type(a,s)(tuple($(exprs...)))
33 -
    end
34 -
end
35 -
36 -
@propagate_inbounds function Base.getindex(a::TupleVector, inds::TupleVector{N,Int}) where N
37 -
    _getindex(a, Val(N), inds)
38 -
end
39 -
40 -
@generated function _getindex(a::TupleVector, s::Val{N}, inds::TupleVector{N, Int}) where N
41 -
    exprs = [:(a[inds[$i]]) for i = 1:N]
42 -
    return quote
43 -
        Base.@_propagate_inbounds_meta
44 -
        similar_type(a, s)(tuple($(exprs...)))
45 -
    end
46 -
end
47 -
48 -
@inline function Base.setindex!(a::TupleVector{N}, v, ::Colon) where N
49 -
    _setindex!(a::TupleVector, v, Val(N), :)
50 -
    return v
51 -
end
52 -
53 -
@generated function _setindex!(a::TupleVector, v, ::Val{L}, ::Colon) where {L}
54 -
    exprs = [:(a[$i] = v) for i = 1:L]
55 -
    return quote
56 -
        @_inline_meta
57 -
        @inbounds $(Expr(:block, exprs...))
58 -
    end
59 -
end
60 -
61 -
@generated function _setindex!(a::TupleVector, v::AbstractVector, ::Val{L}, ::Colon) where {L}
62 -
    exprs = [:(a[$i] = v[$i]) for i = 1:L]
63 -
    return quote
64 -
        Base.@_propagate_inbounds_meta
65 -
        @boundscheck if length(v) != L
66 -
            throw(DimensionMismatch("tried to assign $(length(v))-element array to length-$L destination"))
67 -
        end
68 -
        @inbounds $(Expr(:block, exprs...))
69 -
    end
70 -
end
71 -
72 -
@generated function _setindex!(a::TupleVector, v::TupleVector{M}, ::Val{L}, ::Colon) where {M,L}
73 -
    exprs = [:(a[$i] = v[$i]) for i = 1:L]
74 -
    return quote
75 -
        Base.@_propagate_inbounds_meta
76 -
        @boundscheck if M != L
77 -
            throw(DimensionMismatch("tried to assign $M-element array to length-$L destination"))
78 -
        end
79 -
        $(Expr(:block, exprs...))
80 -
    end
81 -
end
82 -
83 -
@propagate_inbounds function Base.setindex!(a::TupleVector, v, inds::TupleVector{N,Int}) where N
84 -
    _setindex!(a, v, Val(N), inds)
85 -
    return v
86 -
end
87 -
88 -
@generated function _setindex!(a::TupleVector, v, ::Val{N}, inds::TupleVector{N,Int}) where N
89 -
    exprs = [:(a[inds[$i]] = v) for i = 1:N]
90 -
    return quote
91 -
        Base.@_propagate_inbounds_meta
92 -
        similar_type(a, s)(tuple($(exprs...)))
93 -
    end
94 -
end
95 -
96 -
@generated function _setindex!(a::TupleVector, v::AbstractVector, ::Val{N}, inds::TupleVector{N,Int}) where N
97 -
    exprs = [:(a[inds[$i]] = v[$i]) for i = 1:N]
98 -
    return quote
99 -
        Base.@_propagate_inbounds_meta
100 -
        @boundscheck if length(v) != $N
101 -
            throw(DimensionMismatch("tried to assign $(length(v))-element array to length-$N destination"))
102 -
        end
103 -
        $(Expr(:block, exprs...))
104 -
    end
105 -
end
106 -
107 -
@generated function _setindex!(a::TupleVector, v::TupleVector{M}, ::Val{N}, inds::TupleVector{N,Int}) where {N,M}
108 -
    exprs = [:(a[inds[$i]] = v[$i]) for i = 1:N]
109 -
    return quote
110 -
        Base.@_propagate_inbounds_meta
111 -
        @boundscheck if M != N
112 -
            throw(DimensionMismatch("tried to assign $M-element array to length-$N destination"))
113 -
        end
114 -
        $(Expr(:block, exprs...))
115 -
    end
116 -
end
117 -
118 -
# generators
119 -
120 -
@inline Base.zero(a::SA) where {SA<:TupleVector} = zeros(SA)
121 -
@inline Base.zero(a::Type{SA}) where {SA<:TupleVector} = zeros(SA)
122 -
123 -
@inline Base.zeros(::Type{SA}) where {SA<:TupleVector{N}} where N = _zeros(Val(N), SA)
124 -
@generated function _zeros(::Val{N}, ::Type{SA}) where SA<:TupleVector{N} where N
125 -
    T = eltype(SA)
126 -
    if T == Any
127 -
        T = Float64
128 -
    end
129 -
    v = [:(zero($T)) for i = 1:N]
130 -
    return quote
131 -
        @_inline_meta
132 -
        $SA(tuple($(v...)))
133 -
    end
134 -
end
135 -
136 -
@inline Base.ones(::Type{SA}) where {SA<:TupleVector{N}} where N = _ones(Val(N), SA)
137 -
@generated function _ones(::Val{N}, ::Type{SA}) where SA<:TupleVector{N} where N
138 -
    T = eltype(SA)
139 -
    if T == Any
140 -
        T = Float64
141 -
    end
142 -
    v = [:(one($T)) for i = 1:N]
143 -
    return quote
144 -
        @_inline_meta
145 -
        $SA(tuple($(v...)))
146 -
    end
147 -
end
148 -
149 -
@inline Base.fill(val,::SA) where {SA<:TupleVector{N}} where N = _fill(val, Val(N), SA)
150 -
@inline Base.fill(val,::Type{SA}) where {SA<:TupleVector{N}} where N = _fill(val, Val(N), SA)
151 -
@generated function _fill(val,::Val{N},::Type{SA}) where SA<:TupleVector{N} where N
152 -
    v = [:val for i = 1:N]
153 -
    return quote
154 -
        @_inline_meta
155 -
        $SA(tuple($(v...)))
156 -
    end
157 -
end
158 -
159 -
# Also consider randcycle, randperm? Also faster rand!(staticarray, collection)
160 -
161 -
using Random
162 -
import Random: SamplerType, AbstractRNG
163 -
@inline Base.rand(rng::AbstractRNG,::Type{SA},dims::Dims) where SA<:TupleVector = rand!(rng, Array{SA}(undef, dims), SA)
164 -
@inline Base.rand(rng::AbstractRNG,::SamplerType{SA}) where SA<:TupleVector{N} where N = _rand(rng, Val(N), SA)
165 -
166 -
@generated function _rand(rng::AbstractRNG,::Val{N},::Type{SA}) where {SA <: TupleVector{N}} where N
167 -
    T = eltype(SA)
168 -
    if T == Any
169 -
        T = Float64
170 -
    end
171 -
    v = [:(rand(rng, $T)) for i = 1:N]
172 -
    return quote
173 -
        @_inline_meta
174 -
        $SA(tuple($(v...)))
175 -
    end
176 -
end
177 -
178 -
@inline Base.rand(rng::AbstractRNG,range::AbstractArray, ::Type{SA}) where {SA<:TupleVector{N}} where N = _rand(rng, range, Val(N), SA)
179 -
@inline Base.rand(range::AbstractArray,::Type{SA}) where {SA<:TupleVector{N}} where N = _rand(Random.GLOBAL_RNG, range, Val(N), SA)
180 -
@generated function _rand(rng::AbstractRNG, range::AbstractArray, ::Val{N}, ::Type{SA}) where SA<:TupleVector{N} where N
181 -
    v = [:(rand(rng, range)) for i = 1:N]
182 -
    return quote
183 -
        @_inline_meta
184 -
        $SA(tuple($(v...)))
185 -
    end
186 -
end
187 -
188 -
#@inline Base.rand(rng::MersenneTwister, range::AbstractArray, ::Type{SA}) where {SA <: TupleVector} = _rand(rng, range, Val(SA), SA)
189 -
190 -
@inline Base.randn(rng::AbstractRNG,::Type{SA}) where SA<:TupleVector{N} where N = _randn(rng, Val(N), SA)
191 -
@generated function _randn(rng::AbstractRNG,::Val{N},::Type{SA}) where SA<:TupleVector{N} where N
192 -
    T = eltype(SA)
193 -
    if T == Any
194 -
        T = Float64
195 -
    end
196 -
    v = [:(randn(rng, $T)) for i = 1:N]
197 -
    return quote
198 -
        @_inline_meta
199 -
        $SA(tuple($(v...)))
200 -
    end
201 -
end
202 -
203 -
@inline Random.randexp(rng::AbstractRNG,::Type{SA}) where SA<:TupleVector{N} where N = _randexp(rng, Val(N), SA)
204 -
@generated function _randexp(rng::AbstractRNG,::Val{N},::Type{SA}) where SA <: TupleVector{N} where N
205 -
    T = eltype(SA)
206 -
    if T == Any
207 -
        T = Float64
208 -
    end
209 -
    v = [:(randexp(rng, $T)) for i = 1:N]
210 -
    return quote
211 -
        @_inline_meta
212 -
        $SA(tuple($(v...)))
213 -
    end
214 -
end
215 -
216 -
# Mutable versions
217 -
218 -
# Why don't these two exist in Base?
219 -
# @generated function Base.zeros!{SA <: TupleVector}(a::SA)
220 -
# @generated function Base.ones!{SA <: TupleVector}(a::SA)
221 -
222 -
@inline Base.fill!(a::SA,val) where SA<:TupleVector{N} where N = _fill!(Val(N), a, val)
223 -
@generated function _fill!(::Val{N},a::SA,val) where SA<:TupleVector{N} where N
224 -
    exprs = [:(a[$i] = valT) for i = 1:N]
225 -
    return quote
226 -
        @_inline_meta
227 -
        valT = convert(eltype(SA), val)
228 -
        @inbounds $(Expr(:block, exprs...))
229 -
        return a
230 -
    end
231 -
end
232 -
233 -
@inline Random.rand!(rng::AbstractRNG,a::SA) where SA<:TupleVector{N} where N = _rand!(rng, Val(N), a)
234 -
@generated function _rand!(rng::AbstractRNG,::Val{N},a::SA) where SA <: TupleVector{N} where N
235 -
    exprs = [:(a[$i] = rand(rng, eltype(SA))) for i = 1:N]
236 -
    return quote
237 -
        @_inline_meta
238 -
        @inbounds $(Expr(:block, exprs...))
239 -
        return a
240 -
    end
241 -
end
242 -
243 -
@inline Random.rand!(rng::MersenneTwister,a::SA) where SA<:TupleVector{N,Float64} where N = _rand!(rng, Val(N), a)
244 -
245 -
@inline Random.randn!(rng::AbstractRNG,a::SA) where SA<:TupleVector{N} where N = _randn!(rng, Val(N), a)
246 -
@generated function _randn!(rng::AbstractRNG,::Val{N},a::SA) where SA<:TupleVector{N} where N
247 -
    exprs = [:(a[$i] = randn(rng, eltype(SA))) for i = 1:N]
248 -
    return quote
249 -
        @_inline_meta
250 -
        @inbounds $(Expr(:block, exprs...))
251 -
        return a
252 -
    end
253 -
end
254 -
255 -
@inline Random.randexp!(rng::AbstractRNG,a::SA) where SA<:TupleVector{N} where N = _randexp!(rng, Val(N), a)
256 -
@generated function _randexp!(rng::AbstractRNG,::Val{N},a::SA) where SA<:TupleVector{N} where N
257 -
    exprs = [:(a[$i] = randexp(rng, eltype(SA))) for i = 1:N]
258 -
    return quote
259 -
        @_inline_meta
260 -
        @inbounds $(Expr(:block, exprs...))
261 -
        return a
262 -
    end
263 -
end
264 -
265 -
# conversion
266 -
267 -
(::Type{SA})(x::Tuple{Tuple{Tuple{<:Tuple}}}) where {SA <: TupleVector} =
268 -
    throw(DimensionMismatch("No precise constructor for $SA found. Val of input was $(length(x[1][1][1]))."))
269 -
270 -
@inline (::Type{SA})(x...) where {SA <: TupleVector} = SA(x)
271 -
@inline (::Type{SA})(a::TupleVector) where {SA<:TupleVector} = SA(Tuple(a))
272 -
@propagate_inbounds (::Type{SA})(a::AbstractArray) where {SA <: TupleVector} = convert(SA, a)
273 -
274 -
# this covers most conversions and "statically-sized reshapes"
275 -
#@inline Base.convert(::Type{SA}, sa::TupleVector) where {SA<:TupleVector} = SA(Tuple(sa))
276 -
#@inline Base.convert(::Type{SA}, sa::SA) where {SA<:TupleVector} = sa
277 -
@inline Base.convert(::Type{SA}, x::Tuple) where {SA<:TupleVector} = SA(x) # convert -> constructor. Hopefully no loops...
278 -
279 -
# support conversion to AbstractArray
280 -
Base.AbstractArray{T}(sa::TupleVector{N,T}) where {N,T} = sa
281 -
Base.AbstractArray{T,1}(sa::TupleVector{N,T}) where {N,T} = sa
282 -
Base.AbstractArray{T}(sa::TupleVector{N,U}) where {N,T,U} = similar_type(typeof(sa),T,Val(N))(sa)
283 -
Base.AbstractArray{T,1}(sa::TupleVector{N,U}) where {N,T,U} = similar_type(typeof(sa),T,Val(N))(sa)
284 -
285 -
# Constructing a Tuple from a TupleVector
286 -
@inline Base.Tuple(a::TupleVector{N}) where N = unroll_tuple(a, Val(N))
287 -
288 -
@noinline function dimension_mismatch_fail(SA::Type, a::AbstractArray)
289 -
    throw(DimensionMismatch("expected input array of length $(length(SA)), got length $(length(a))"))
290 -
end
291 -
292 -
@propagate_inbounds function Base.convert(::Type{SA}, a::AbstractArray) where {SA<:TupleVector{N}} where N
293 -
    @boundscheck if length(a) != length(SA)
294 -
        dimension_mismatch_fail(SA, a)
295 -
    end
296 -
297 -
    return _convert(SA, a, Val(N))
298 -
end
299 -
300 -
@inline _convert(SA, a, l::Val) = SA(unroll_tuple(a, l))
301 -
@inline _convert(SA::Type{<:TupleVector{N,T}}, a, ::Val{0}) where {N,T} = similar_type(SA, T)(())
302 -
@inline _convert(SA, a, ::Val{0}) = similar_type(SA, eltype(a))(())
303 -
304 -
@generated function unroll_tuple(a::AbstractArray, ::Val{N}) where N
305 -
    exprs = [:(a[$j]) for j = 1:N]
306 -
    quote
307 -
        @_inline_meta
308 -
        @inbounds return $(Expr(:tuple, exprs...))
309 -
    end
310 -
end
311 -
312 -
# Cast any Tuple to an TupleN{T}
313 -
@inline convert_ntuple(::Type{T},d::T) where {T} = T # For zero-dimensional arrays
314 -
@inline convert_ntuple(::Type{T},d::NTuple{N,T}) where {N,T} = d
315 -
@generated function convert_ntuple(::Type{T}, d::NTuple{N,Any}) where {N,T}
316 -
    exprs = ntuple(i -> :(convert(T, d[$i])), Val(N))
317 -
    return quote
318 -
        @_inline_meta
319 -
        $(Expr(:tuple, exprs...))
320 -
    end
321 -
end
322 -
323 -
# Base gives up on tuples for promote_eltype... (TODO can we improve Base?)
324 -
@generated function promote_tuple_eltype(::Union{T,Type{T}}) where T <: Tuple
325 -
    t = Union{}
326 -
    for i = 1:length(T.parameters)
327 -
        tmp = T.parameters[i]
328 -
        if tmp <: Vararg
329 -
            tmp = tmp.parameters[1]
330 -
        end
331 -
        t = :(promote_type($t, $tmp))
332 -
    end
333 -
    return quote
334 -
        @_inline_meta
335 -
        $t
336 -
    end
337 -
end
338 -
339 -
# Diff is slightly different
340 -
@inline LinearAlgebra.diff(a::TupleVector{N}; dims=Val(1)) where N = _diff(Val(N),a,dims)
341 -
342 -
@inline function _diff(sz::Val, a::TupleVector, D::Int)
343 -
    _diff(sz,a,Val(D))
344 -
end
345 -
@generated function _diff(::Val{N}, a::TupleVector, ::Val{1}) where N
346 -
    Snew = N-1
347 -
    exprs = Array{Expr}(undef, Snew)
348 -
    for i1 = Base.product(1:Snew)
349 -
        i2 = copy([i1...])
350 -
        i2[1] = i1[1] + 1
351 -
        exprs[i1...] = :(a[$(i2...)] - a[$(i1...)])
352 -
    end
353 -
    return quote
354 -
        @_inline_meta
355 -
        elements = tuple($(exprs...))
356 -
        @inbounds return similar_type(a, eltype(elements), Val($Snew))(elements)
357 -
    end
358 -
end
359 -
360 -
# Values
361 -
362 -
struct Values{N,T} <: TupleVector{N,T}
363 -
    v::NTuple{N,T}
364 -
    Values{N,T}(x::NTuple{N,T}) where {N,T} = new{N,T}(x)
365 -
    Values{N,T}(x::NTuple{N,Any}) where {N,T} = new{N,T}(convert_ntuple(T, x))
366 -
end
367 -
368 -
@pure @generated function (::Type{Values{N,T}})(x::Tuple) where {T, N}
369 -
    return quote
370 -
        @_inline_meta
371 -
        Values{N,T}(x)
372 -
    end
373 -
end
374 -
375 -
@inline Values(a::TupleVector{N}) where N = Values{N}(Tuple(a))
376 -
@propagate_inbounds Base.getindex(v::Values, i::Int) = v.v[i]
377 -
@inline Tuple(v::Values) = v.v
378 -
Base.dataids(::Values) = ()
379 -
380 -
# See #53
381 -
Base.cconvert(::Type{Ptr{T}}, a::Values) where {T} = Base.RefValue(a)
382 -
Base.unsafe_convert(::Type{Ptr{T}}, a::Base.RefValue{SA}) where {N,T,SA<:Values{N,T}} = Ptr{T}(Base.unsafe_convert(Ptr{Values{N,T}}, a))
383 -
384 -
@inline Values(x::NTuple{N,Any}) where N = Values{N}(x)
385 -
@inline Values{N}(x::NTuple{N,T}) where {N,T} = Values{N,T}(x)
386 -
@inline Values{N}(x::T) where {N,T<:Tuple} = Values{N,promote_tuple_eltype(T)}(x)
387 -
388 -
# Some more advanced constructor-like functions
389 -
@pure @inline Base.zeros(::Type{Values{N}}) where N = zeros(Values{N,Float64})
390 -
@pure @inline Base.ones(::Type{Values{N}}) where N = ones(Values{N,Float64})
391 -
392 -
# Converting a CartesianIndex to an SVector
393 -
Base.convert(::Type{Values}, I::CartesianIndex) = Values(I.I)
394 -
Base.convert(::Type{Values{N}}, I::CartesianIndex{N}) where {N} = Values{N}(I.I)
395 -
Base.convert(::Type{Values{N,T}}, I::CartesianIndex{N}) where {N,T} = Values{N,T}(I.I)
396 -
397 -
@pure Base.promote_rule(::Type{Values{N,T}}, ::Type{CartesianIndex{N}}) where {N,T} = Values{N,promote_type(T,Int)}
398 -
399 -
# Variables
400 -
401 -
mutable struct Variables{N,T} <: TupleVector{N,T}
402 -
    v::NTuple{N,T}
403 -
    Variables{N,T}(x::NTuple{N,T}) where {N,T} = new{N,T}(x)
404 -
    Variables{N,T}(x::NTuple{N,Any}) where {N,T} = new{N,T}(convert_ntuple(T, x))
405 -
    Variables{N,T}(::UndefInitializer) where {N,T} = new{N,T}()
406 -
end
407 -
408 -
@inline Variables(a::TupleVector{N}) where N = Variables{N}(Tuple(a))
409 -
@generated function (::Type{Variables{N,T}})(x::Tuple) where {N,T}
410 -
    return quote
411 -
        $(Expr(:meta, :inline))
412 -
        Variables{N,T}(x)
413 -
    end
414 -
end
415 -
@generated function (::Type{Variables{N}})(x::T) where {N,T<:Tuple}
416 -
    return quote
417 -
        $(Expr(:meta, :inline))
418 -
        Variables{N,promote_tuple_eltype(T)}(x)
419 -
    end
420 -
end
421 -
422 -
@propagate_inbounds function Base.getindex(v::Variables, i::Int)
423 -
    @boundscheck checkbounds(v,i)
424 -
    T = eltype(v)
425 -
    if isbitstype(T)
426 -
        return GC.@preserve v unsafe_load(Base.unsafe_convert(Ptr{T}, pointer_from_objref(v)), i)
427 -
    end
428 -
    v.v[i]
429 -
end
430 -
@propagate_inbounds function Base.setindex!(v::Variables, val, i::Int)
431 -
    @boundscheck checkbounds(v,i)
432 -
    T = eltype(v)
433 -
    if isbitstype(T)
434 -
        GC.@preserve v unsafe_store!(Base.unsafe_convert(Ptr{T}, pointer_from_objref(v)), convert(T, val), i)
435 -
    else
436 -
        # This one is unsafe (#27)
437 -
        # unsafe_store!(Base.unsafe_convert(Ptr{Ptr{Nothing}}, pointer_from_objref(v.data)), pointer_from_objref(val), i)
438 -
        error("setindex!() with non-isbitstype eltype is not supported by TupleVectors. Consider using FixedVector.")
439 -
    end
440 -
    return val
441 -
end
442 -
443 -
@inline Base.Tuple(v::Variables) = v.v
444 -
Base.dataids(ma::Variables) = (UInt(pointer(ma)),)
445 -
446 -
@inline function Base.unsafe_convert(::Type{Ptr{T}}, a::Variables{N,T}) where {N,T}
447 -
    Base.unsafe_convert(Ptr{T}, pointer_from_objref(a))
448 -
end
449 -
450 -
function Base.promote_rule(::Type{<:Variables{N,T}}, ::Type{<:Variables{N,U}}) where {N,T,U}
451 -
    Variables{N,promote_type(T,U)}
452 -
end
453 -
454 -
@inline Variables(x::NTuple{N,Any}) where N = Variables{N}(x)
455 -
@inline Variables{N}(x::NTuple{N,T}) where {N,T} = Variables{N,T}(x)
456 -
@inline Variables{N}(x::NTuple{N,Any}) where N = Variables{N, promote_tuple_eltype(typeof(x))}(x)
457 -
458 -
# Some more advanced constructor-like functions
459 -
@inline Base.zeros(::Type{Variables{N}}) where N = zeros(Variables{N,Float64})
460 -
@inline Base.ones(::Type{Variables{N}}) where N = ones(Variables{N,Float64})
461 -
462 -
# FixedVector
463 -
464 -
struct FixedVector{N,T} <: TupleVector{N,T}
465 -
    v::Vector{T}
466 -
    function FixedVector{N,T}(a::Vector) where {N,T}
467 -
        if length(a) != N
468 -
            throw(DimensionMismatch("Dimensions $(size(a)) don't match static size $S"))
469 -
        end
470 -
        new{N,T}(a)
471 -
    end
472 -
    function FixedVector{N,T}(::UndefInitializer) where {N,T}
473 -
        new{N,T}(Vector{T}(undef,N))
474 -
    end
475 -
end
476 -
477 -
@inline FixedVector{N}(a::Vector{T}) where {N,T} = FixedVector{N,T}(a)
478 -
479 -
@generated function FixedVector{N,T}(x::NTuple{N,Any}) where {N,T}
480 -
    exprs = [:(a[$i] = x[$i]) for i = 1:N]
481 -
    return quote
482 -
        $(Expr(:meta, :inline))
483 -
        a = FixedVector{N,T}(undef)
484 -
        @inbounds $(Expr(:block, exprs...))
485 -
        return a
486 -
    end
487 -
end
488 -
489 -
@inline FixedVector{N,T}(x::Tuple) where {N,T} = FixedVector{N,T}(x)
490 -
@inline FixedVector{N}(x::NTuple{N,T}) where {N,T} = FixedVector{N,T}(x)
491 -
492 -
# Overide some problematic default behaviour
493 -
@inline Base.convert(::Type{SA}, sa::FixedVector) where {SA<:FixedVector} = SA(sa.v)
494 -
@inline Base.convert(::Type{SA}, sa::SA) where {SA<:FixedVector} = sa
495 -
496 -
# Back to Array (unfortunately need both convert and construct to overide other methods)
497 -
@inline Base.Array(sa::FixedVector) = Vector(sa.v)
498 -
@inline Base.Array{T}(sa::FixedVector{N,T}) where {N,T} = Vector{T}(sa.v)
499 -
@inline Base.Array{T,1}(sa::FixedVector{N,T}) where {N,T} = Vector{T}(sa.v)
500 -
501 -
@inline Base.convert(::Type{Array}, sa::FixedVector) = sa.v
502 -
@inline Base.convert(::Type{Array{T}}, sa::FixedVector{N,T}) where {N,T} = sa.v
503 -
@inline Base.convert(::Type{Array{T,1}}, sa::FixedVector{N,T}) where {N,T} = sa.v
504 -
505 -
@propagate_inbounds Base.getindex(a::FixedVector, i::Int) = getindex(a.v, i)
506 -
@propagate_inbounds Base.setindex!(a::FixedVector, v, i::Int) = setindex!(a.v, v, i)
507 -
508 -
Base.dataids(sa::FixedVector) = Base.dataids(sa.v)
509 -
510 -
function Base.promote_rule(::Type{<:FixedVector{N,T}}, ::Type{<:FixedVector{N,U}}) where {N,T,U}
511 -
    FixedVector{N,promote_type(T,U)}
512 -
end
513 -
514 -
# SOneTo
515 -
516 -
struct SOneTo{n} <: AbstractUnitRange{Int} end
517 -
518 -
@pure SOneTo(n::Int) = SOneTo{n}()
519 -
function SOneTo{n}(r::AbstractUnitRange) where n
520 -
    ((first(r) == 1) & (last(r) == n)) && return SOneTo{n}()
521 -
522 -
    errmsg(r) = throw(DimensionMismatch("$r is inconsistent with SOneTo{$n}")) # avoid GC frame
523 -
    errmsg(r)
524 -
end
525 -
Base.Tuple(::SOneTo{N}) where N = ntuple(identity, Val(N))
526 -
527 -
@pure Base.axes(s::SOneTo) = (s,)
528 -
@pure Base.size(s::SOneTo{n}) where n = (n,)
529 -
@pure Base.length(s::SOneTo{n}) where n = n
530 -
531 -
# The axes of a Slice'd SOneTo use the SOneTo itself
532 -
Base.axes(S::Base.Slice{<:SOneTo}) = (S.indices,)
533 -
Base.unsafe_indices(S::Base.Slice{<:SOneTo}) = (S.indices,)
534 -
Base.axes1(S::Base.Slice{<:SOneTo}) = S.indices
535 -
536 -
@propagate_inbounds function Base.getindex(s::SOneTo, i::Int)
537 -
    @boundscheck checkbounds(s, i)
538 -
    return i
539 -
end
540 -
@propagate_inbounds function Base.getindex(s::SOneTo, s2::SOneTo)
541 -
    @boundscheck checkbounds(s, s2)
542 -
    return s2
543 -
end
544 -
545 -
@pure Base.first(::SOneTo) = 1
546 -
@pure Base.last(::SOneTo{n}) where n = n::Int
547 -
@pure Base.iterate(::SOneTo{n}) where n = n::Int < 1 ? nothing : (1, 1)
548 -
@pure function Base.iterate(::SOneTo{n}, s::Int) where {n}
549 -
    if s < n::Int
550 -
        s2 = s + 1
551 -
        return (s2, s2)
552 -
    else
553 -
        return nothing
554 -
    end
555 -
end
556 -
557 -
function Base.getproperty(::SOneTo{n}, s::Symbol) where {n}
558 -
    if s === :start
559 -
        return 1
560 -
    elseif s === :stop
561 -
        return n::Int
562 -
    else
563 -
        error("type SOneTo has no property $s")
564 -
    end
565 -
end
566 -
567 -
Base.show(io::IO, ::SOneTo{n}) where {n} = print(io, "SOneTo(", n::Int, ")")
568 -
Base.@pure function Base.checkindex(::Type{Bool}, ::SOneTo{n1}, ::SOneTo{n2}) where {n1, n2}
569 -
    return n1::Int >= n2::Int
570 -
end
571 -
572 -
Base.promote_rule(a::Type{Base.OneTo{T}}, ::Type{SOneTo{n}}) where {T,n} =
573 -
    Base.OneTo{promote_type(T, Int)}
574 -
575 -
# Broadcast
576 -
577 -
import Base.Broadcast: BroadcastStyle, AbstractArrayStyle, Broadcasted, DefaultArrayStyle, materialize!
578 -
import Base.Broadcast: _bcs1  # for SOneTo axis information
579 -
using Base.Broadcast: _bcsm
580 -
# Add a new BroadcastStyle for TupleVectors, derived from AbstractArrayStyle
581 -
# A constructor that changes the style parameter N (array dimension) is also required
582 -
struct TupleVectorStyle{N} <: AbstractArrayStyle{N} end
583 -
TupleVectorStyle{M}(::Val{N}) where {M,N} = TupleVectorStyle{N}()
584 -
BroadcastStyle(::Type{<:TupleVector{N,<:Any}}) where N = TupleVectorStyle{N}()
585 -
BroadcastStyle(::Type{<:LinearAlgebra.Transpose{<:Any,<:TupleVector{N,<:Any}}}) where N = TupleVectorStyle{N}()
586 -
BroadcastStyle(::Type{<:LinearAlgebra.Adjoint{<:Any,<:TupleVector{N,<:Any}}}) where N = TupleVectorStyle{N}()
587 -
# Precedence rules
588 -
BroadcastStyle(::TupleVectorStyle{M}, ::DefaultArrayStyle{N}) where {M,N} =
589 -
    DefaultArrayStyle(Val(max(M, N)))
590 -
BroadcastStyle(::TupleVectorStyle{M}, ::DefaultArrayStyle{0}) where {M} =
591 -
    TupleVectorStyle{M}()
592 -
# copy overload
593 -
@inline function Base.copy(B::Broadcasted{TupleVectorStyle{M}}) where M
594 -
    flat = Broadcast.flatten(B); as = flat.args; f = flat.f
595 -
    argsizes = broadcast_sizes(as...)
596 -
    destsize = combine_sizes(argsizes)
597 -
    _broadcast(f, destsize, argsizes, as...)
598 -
end
599 -
# copyto! overloads
600 -
@inline Base.copyto!(dest, B::Broadcasted{<:TupleVectorStyle}) = _copyto!(dest, B)
601 -
@inline Base.copyto!(dest::AbstractArray, B::Broadcasted{<:TupleVectorStyle}) = _copyto!(dest, B)
602 -
@inline function _copyto!(dest, B::Broadcasted{TupleVectorStyle{M}}) where M
603 -
    flat = Broadcast.flatten(B); as = flat.args; f = flat.f
604 -
    argsizes = broadcast_sizes(as...)
605 -
    destsize = combine_sizes((Val(M), argsizes...))
606 -
    #=if Val(destsize) === Val{Dynamic()}()
607 -
        # destination dimension cannot be determined statically; fall back to generic broadcast!
608 -
        return copyto!(dest, convert(Broadcasted{DefaultArrayStyle{M}}, B))
609 -
    end=#
610 -
    _broadcast!(f, destsize, dest, argsizes, as...)
611 -
end
612 -
613 -
# Resolving priority between dynamic and static axes
614 -
_bcs1(a::SOneTo, b::SOneTo) = _bcsm(b, a) ? b : (_bcsm(a, b) ? a : throw(DimensionMismatch("arrays could not be broadcast to a common size")))
615 -
_bcs1(a::SOneTo, b::Base.OneTo) = _bcs1(Base.OneTo(a), b)
616 -
_bcs1(a::Base.OneTo, b::SOneTo) = _bcs1(a, Base.OneTo(b))
617 -
618 -
###################################################
619 -
## Internal broadcast machinery for TupleVectors ##
620 -
###################################################
621 -
622 -
broadcast_indices(A::TupleVector) = indices(A)
623 -
624 -
# TODO: just use map(broadcast_size, as)?
625 -
@inline broadcast_sizes(a, as...) = (broadcast_size(a), broadcast_sizes(as...)...)
626 -
@inline broadcast_sizes() = ()
627 -
@inline broadcast_size(a) = Val(0)
628 -
@inline broadcast_size(a::AbstractVector) = Val(length(a))
629 -
@inline broadcast_size(a::NTuple{N}) where N = Val(N)
630 -
631 -
function broadcasted_index(oldsize, newindex)
632 -
    index = ones(Int, length(oldsize))
633 -
    for i = 1:length(oldsize)
634 -
        if oldsize[i] != 1
635 -
            index[i] = newindex[i]
636 -
        end
637 -
    end
638 -
    return LinearIndices((oldsize,))[index...]
639 -
end
640 -
641 -
# similar to Base.Broadcast.combine_indices:
642 -
@generated function combine_sizes(s::Tuple{Vararg{Val}})
643 -
    sizes = [sz.parameters[1] for sz ∈ s.parameters]
644 -
    ndims = 0
645 -
    for i = 1:length(sizes)
646 -
        ndims = max(ndims,sizes[i])
647 -
    end 
648 -
    quote
649 -
        @_inline_meta
650 -
        Val($ndims)
651 -
    end
652 -
end
653 -
654 -
scalar_getindex(x) = x
655 -
scalar_getindex(x::Ref) = x[]
656 -
657 -
@generated function _broadcast(f, ::Val{newsize}, s::Tuple{Vararg{Val}}, a...) where newsize
658 -
    first_staticarray = a[findfirst(ai -> ai <: Union{TupleVector, LinearAlgebra.Transpose{<:Any, <:TupleVector}, LinearAlgebra.Adjoint{<:Any, <:TupleVector}}, a)]
659 -
    if newsize == 0
660 -
        # Use inference to get eltype in empty case (see also comments in _map)
661 -
        eltys = [:(eltype(a[$i])) for i ∈ 1:length(a)]
662 -
        return quote
663 -
            @_inline_meta
664 -
            T = Core.Compiler.return_type(f, Tuple{$(eltys...)})
665 -
            @inbounds return similar_type($first_staticarray, T, Val(newsize))()
666 -
        end
667 -
    end
668 -
    sizes = [sz.parameters[1] for sz ∈ s.parameters]
669 -
    indices = CartesianIndices((newsize,))
670 -
    exprs = similar(indices, Expr)
671 -
    for (j, current_ind) ∈ enumerate(indices)
672 -
        exprs_vals = [
673 -
            (!(a[i] <: AbstractArray || a[i] <: Tuple) ? :(scalar_getindex(a[$i])) : :(a[$i][$(broadcasted_index(sizes[i], current_ind))]))
674 -
            for i = 1:length(sizes)
675 -
        ]
676 -
        exprs[j] = :(f($(exprs_vals...)))
677 -
    end
678 -
    return quote
679 -
        @_inline_meta
680 -
        @inbounds elements = tuple($(exprs...))
681 -
        @inbounds return similar_type($first_staticarray, eltype(elements), Val(newsize))(elements)
682 -
    end
683 -
end
684 -
685 -
####################################################
686 -
## Internal broadcast! machinery for TupleVectors ##
687 -
####################################################
688 -
689 -
@generated function _broadcast!(f, ::Val{newsize}, dest::AbstractArray, s::Tuple{Vararg{Val}}, as...) where {newsize}
690 -
    sizes = [sz.parameters[1] for sz ∈ s.parameters]
691 -
    sizes = tuple(sizes...)
692 -
    indices = CartesianIndices((newsize,))
693 -
    exprs = similar(indices, Expr)
694 -
    for (j, current_ind) ∈ enumerate(indices)
695 -
        exprs_vals = [
696 -
            (!(as[i] <: AbstractArray || as[i] <: Tuple) ? :(as[$i][]) : :(as[$i][$(broadcasted_index(sizes[i], current_ind))]))
697 -
            for i = 1:length(sizes)
698 -
        ]
699 -
        exprs[j] = :(dest[$j] = f($(exprs_vals...)))
700 -
    end
701 -
    return quote
702 -
        Base.@_propagate_inbounds_meta
703 -
        @inbounds $(Expr(:block, exprs...))
704 -
        return dest
705 -
    end
706 -
end
707 -
708 -
# Other
709 -
710 -
Base.axes(::TupleVector{N}) where N = _axes(Val(N))
711 -
@pure function _axes(::Val{sizes}) where {sizes}
712 -
    map(SOneTo, (sizes,))
713 -
end
714 -
Base.axes(rv::LinearAlgebra.Adjoint{<:Any,<:Values})   = (SOneTo(1), axes(rv.parent)...)
715 -
Base.axes(rv::LinearAlgebra.Transpose{<:Any,<:Values}) = (SOneTo(1), axes(rv.parent)...)
716 -
717 -
# Base.strides is intentionally not defined for SArray, see PR #658 for discussion
718 -
Base.strides(a::Variables) = Base.size_to_strides(1, size(a)...)
719 -
Base.strides(a::FixedVector) = strides(a.v)
720 -
721 -
similar_type(::SA) where {SA<:TupleVector} = similar_type(SA,eltype(SA))
722 -
similar_type(::Type{SA}) where {SA<:TupleVector} = similar_type(SA,eltype(SA))
723 -
724 -
similar_type(::SA,::Type{T}) where {SA<:TupleVector{N},T} where N = similar_type(SA,T,Val(N))
725 -
similar_type(::Type{SA},::Type{T}) where {SA<:TupleVector{N},T} where N = similar_type(SA,T,Val(N))
726 -
727 -
similar_type(::A,n::Val) where {A<:AbstractArray} = similar_type(A,eltype(A),n)
728 -
similar_type(::Type{A},n::Val) where {A<:AbstractArray} = similar_type(A,eltype(A),n)
729 -
730 -
similar_type(::A,::Type{T},n::Val) where {A<:AbstractArray,T} = similar_type(A,T,n)
731 -
732 -
# We should be able to deal with SOneTo axes
733 -
similar_type(s::SOneTo) = similar_type(typeof(s))
734 -
similar_type(::Type{SOneTo{n}}) where n = similar_type(SOneTo{n}, Int, Val(n))
735 -
736 -
similar_type(::A, shape::Tuple{SOneTo, Vararg{SOneTo}}) where {A<:AbstractArray} = similar_type(A, eltype(A), shape)
737 -
similar_type(::Type{A}, shape::Tuple{SOneTo, Vararg{SOneTo}}) where {A<:AbstractArray} = similar_type(A, eltype(A), shape)
738 -
739 -
similar_type(::A,::Type{T}, shape::Tuple{SOneTo, Vararg{SOneTo}}) where {A<:AbstractArray,T} = similar_type(A, T, Val(length(last.(shape))))
740 -
similar_type(::Type{A},::Type{T}, shape::Tuple{SOneTo, Vararg{SOneTo}}) where {A<:AbstractArray,T} = similar_type(A, T, Val(length(last.(shape))))
741 -
742 -
# Default types
743 -
# Generally, use SArray
744 -
similar_type(::Type{A},::Type{T},n::Val) where {A<:AbstractArray,T} = default_similar_type(T,n)
745 -
default_similar_type(::Type{T},::Val{N}) where {N,T} = Values{N,T}
746 -
747 -
similar_type(::Type{SA},::Type{T},n::Val) where {SA<:Variables,T} = mutable_similar_type(T,n)
748 -
749 -
mutable_similar_type(::Type{T},::Val{N}) where {N,T} = Variables{N,T}
750 -
751 -
similar_type(::Type{<:FixedVector},::Type{T},n::Val) where T = sizedarray_similar_type(T,n)
752 -
# Should FixedVector also be used for normal Array?
753 -
#similar_type(::Type{<:Array},::Type{T},n::Val) where T = sizedarray_similar_type(T,n)
754 -
755 -
sizedarray_similar_type(::Type{T},::Val{N}) where {N,T} = FixedVector{N,T}
756 -
757 -
Base.similar(::SA) where {SA<:TupleVector} = similar(SA,eltype(SA))
758 -
Base.similar(::Type{SA}) where {SA<:TupleVector} = similar(SA,eltype(SA))
759 -
760 -
Base.similar(::SA,::Type{T}) where {SA<:TupleVector{N},T} where N = similar(SA,T,Val(N))
761 -
Base.similar(::Type{SA},::Type{T}) where {SA<:TupleVector{N},T} where N = similar(SA,T,Val(N))
762 -
763 -
# Cases where a Val is given as the dimensions
764 -
Base.similar(::A,n::Val) where A<:AbstractArray = similar(A,eltype(A),n)
765 -
Base.similar(::Type{A},n::Val) where A<:AbstractArray = similar(A,eltype(A),n)
766 -
767 -
Base.similar(::A,::Type{T},n::Val) where {A<:AbstractArray,T} = similar(A,T,n)
768 -
769 -
# defaults to built-in mutable types
770 -
Base.similar(::Type{A},::Type{T},n::Val) where {A<:AbstractArray,T} = mutable_similar_type(T,n)(undef)
771 -
772 -
# both FixedVector and Array return FixedVector
773 -
Base.similar(::Type{SA},::Type{T},n::Val) where {SA<:FixedVector,T} = sizedarray_similar_type(T,n)(undef)
774 -
Base.similar(::Type{A},::Type{T},n::Val) where {A<:Array,T} = sizedarray_similar_type(T,n)(undef)
775 -
776 -
# Support tuples of mixtures of `SOneTo`s alongside the normal `Integer` and `OneTo` options
777 -
# by simply converting them to either a tuple of Ints or a Val, re-dispatching to either one
778 -
# of the above methods (in the case of Val) or a base fallback (in the case of Ints).
779 -
const HeterogeneousShape = Union{Integer, Base.OneTo, SOneTo}
780 -
781 -
Base.similar(A::AbstractArray, ::Type{T}, shape::Tuple{HeterogeneousShape, Vararg{HeterogeneousShape}}) where {T} = similar(A, T, homogenize_shape(shape))
782 -
Base.similar(::Type{A}, shape::Tuple{HeterogeneousShape, Vararg{HeterogeneousShape}}) where {A<:AbstractArray} = similar(A, homogenize_shape(shape))
783 -
# Use an Array for TupleVectors if we don't have a statically-known size
784 -
Base.similar(::Type{A}, shape::Tuple{Int, Vararg{Int}}) where {A<:TupleVector} = Array{eltype(A)}(undef, shape)
785 -
786 -
homogenize_shape(::Tuple{}) = ()
787 -
homogenize_shape(shape::Tuple{Vararg{SOneTo}}) = Val(prod(map(last, shape)))
788 -
homogenize_shape(shape::Tuple{Vararg{HeterogeneousShape}}) = map(last, shape)
789 -
790 -
791 -
@inline Base.copy(a::TupleVector) = typeof(a)(Tuple(a))
792 -
@inline Base.copy(a::FixedVector) = typeof(a)(copy(a.v))
793 -
794 -
@inline Base.reverse(v::Values) = typeof(v)(_reverse(v))
795 -
796 -
@generated function _reverse(v::Values{N,T}) where {N,T}
797 -
    return Expr(:tuple, (:(v[$i]) for i = N:(-1):1)...)
798 -
end
799 -
800 -
#--------------------------------------------------
801 -
# Vector space algebra
802 -
803 -
# Unary ops
804 -
@inline Base.:-(a::TupleVector) = map(-, a)
805 -
@inline Base.:-(a::TupleVector{n,<:Number}) where n = map(Base.:-, a)
806 -
807 -
# Binary ops
808 -
# Between arrays
809 -
@inline Base.:+(a::TupleVector, b::TupleVector) = map(∑, a, b)
810 -
@inline Base.:+(a::AbstractArray, b::TupleVector) = map(∑, a, b)
811 -
@inline Base.:+(a::TupleVector, b::AbstractArray) = map(∑, a, b)
812 -
813 -
@inline Base.:+(a::TupleVector{n,<:Number}, b::TupleVector{n,<:Number}) where n = map(Base.:+, a, b)
814 -
@inline Base.:+(a::AbstractArray{<:Number}, b::TupleVector{n,<:Number}) where n = map(Base.:+, a, b)
815 -
@inline Base.:+(a::TupleVector{n,<:Number}, b::AbstractArray{<:Number}) where n = map(Base.:+, a, b)
816 -
817 -
@inline Base.:-(a::TupleVector, b::TupleVector) = map(-, a, b)
818 -
@inline Base.:-(a::AbstractArray, b::TupleVector) = map(-, a, b)
819 -
@inline Base.:-(a::TupleVector, b::AbstractArray) = map(-, a, b)
820 -
821 -
@inline Base.:-(a::TupleVector{n,<:Number}, b::TupleVector{n,<:Number}) where n = map(Base.:-, a, b)
822 -
@inline Base.:-(a::AbstractArray{<:Number}, b::TupleVector{n,<:Number}) where n = map(Base.:-, a, b)
823 -
@inline Base.:-(a::TupleVector{n,<:Number}, b::AbstractArray{<:Number}) where n = map(Base.:-, a, b)
824 -
825 -
# Scalar-array
826 -
@inline Base.:*(a::Number, b::TupleVector{n,<:Number}) where n = broadcast(Base.:*, a, b)
827 -
@inline Base.:*(a::TupleVector{n,<:Number}, b::Number) where n = broadcast(Base.:*, a, b)
828 -
829 -
@inline Base.:*(a, b::TupleVector) = broadcast(∏, a, b)
830 -
@inline Base.:*(a::TupleVector, b) = broadcast(∏, a, b)
831 -
832 -
@inline Base.:/(a::TupleVector{n,<:Number}, b::Number) where n = broadcast(Base.:/, a, b)
833 -
@inline Base.:\(a::Number, b::TupleVector{n,<:Number}) where n = broadcast(Base.:\, a, b)
834 -
835 -
@inline Base.:/(a::TupleVector, b) = broadcast(/, a, b)
836 -
@inline Base.:\(a, b::TupleVector) = broadcast(\, a, b)
837 -
838 -
#--------------------------------------------------
839 -
# Vector products
840 -
@inline LinearAlgebra.dot(a::TupleVector, b::TupleVector) = _vecdot(a, b, LinearAlgebra.dot)
841 -
@inline bilinear_vecdot(a::TupleVector, b::TupleVector) = _vecdot(a, b, Base.:*)
842 -
843 -
@inline function _vecdot(a::TupleVector{S}, b::TupleVector{S}, product) where S
844 -
    if S == 0
845 -
        za, zb = zero(eltype(a)), zero(eltype(b))
846 -
    else
847 -
        # Use an actual element if there is one, to support e.g. Vector{<:Number}
848 -
        # element types for which runtime size information is required to construct
849 -
        # a zero element.
850 -
        za, zb = zero(a[1]), zero(b[1])
851 -
    end
852 -
    ret = product(za, zb) + product(za, zb)
853 -
    @inbounds @simd for j = 1:S
854 -
        ret += product(a[j], b[j])
855 -
    end
856 -
    return ret
857 -
end
858 -
859 -
#--------------------------------------------------
860 -
# Norms
861 -
@inline LinearAlgebra.norm_sqr(v::TupleVector) = mapreduce(Base.abs2, Base.:+, v; init=zero(real(eltype(v))))
862 -
863 -
@inline LinearAlgebra.norm(a::TupleVector) = _norm(a)
864 -
@generated function _norm(a::TupleVector{S}) where S
865 -
    if S == 0
866 -
        return :(zero(real(eltype(a))))
867 -
    end
868 -
    expr = :(Base.abs2(a[1]))
869 -
    for j = 2:S
870 -
        expr = :($expr + Base.abs2(a[$j]))
871 -
    end
872 -
    return quote
873 -
        $(Expr(:meta, :inline))
874 -
        @inbounds return Base.sqrt($expr)
875 -
    end
876 -
end
877 -
878 -
_norm_p0(x) = x == 0 ? zero(x) : one(x)
879 -
880 -
@inline LinearAlgebra.norm(a::TupleVector, p::Real) = _norm(a, p)
881 -
@generated function _norm(a::TupleVector{S,T}, p::Real) where {S,T}
882 -
    if S == 0
883 -
        return :(zero(real(eltype(a))))
884 -
    end
885 -
    fun = T<:Number ? :(Base.abs) : :abs
886 -
    expr = :($fun(a[1])^p)
887 -
    for j = 2:S
888 -
        expr = :($expr + $fun(a[$j])^p)
889 -
    end
890 -
    expr_p1 = :($fun(a[1]))
891 -
    for j = 2:S
892 -
        expr_p1 = :($expr_p1 + $fun(a[$j]))
893 -
    end
894 -
    return quote
895 -
        $(Expr(:meta, :inline))
896 -
        if p == Inf
897 -
            return mapreduce(Base.abs, max, a)
898 -
        elseif p == 1
899 -
            @inbounds return $expr_p1
900 -
        elseif p == 2
901 -
            return LinearAlgebra.norm(a)
902 -
        elseif p == 0
903 -
            return mapreduce(_norm_p0, $(T<:Number ? :(Base.:+) : :∑), a)
904 -
        else
905 -
            @inbounds return $(T<:Number ? :(Base.:^) : :^)($expr,$(T<:Number ? :(Base.inv) : :inv)(p))
906 -
        end
907 -
    end
908 -
end
909 -
910 -
@inline LinearAlgebra.normalize(a::TupleVector) = ∏(inv(LinearAlgebra.norm(a)),a)
911 -
@inline LinearAlgebra.normalize(a::TupleVector, p::Real) = ∏(inv(LinearAlgebra.norm(a, p)),a)
912 -
913 -
@inline LinearAlgebra.normalize!(a::TupleVector) = (a .*= inv(LinearAlgebra.norm(a)); return a)
914 -
@inline LinearAlgebra.normalize!(a::TupleVector, p::Real) = (a .*= inv(LinearAlgebra.norm(a, p)); return a)
915 -
916 -
@inline LinearAlgebra.normalize(a::TupleVector{n,<:Number}) where n = Base.:*(Base.inv(LinearAlgebra.norm(a)),a)
917 -
@inline LinearAlgebra.normalize(a::TupleVector{n,<:Number}, p::Real) where n = Base.:*(Base.inv(LinearAlgebra.norm(a, p)),a)
918 -
919 -
@inline LinearAlgebra.normalize!(a::TupleVector{n,<:Number}) where n = (a .*= Base.inv(LinearAlgebra.norm(a)); return a)
920 -
@inline LinearAlgebra.normalize!(a::TupleVector{n,<:Number}, p::Real) where n = (a .*= Base.inv(LinearAlgebra.norm(a, p)); return a)
28 +
include("SOneTo.jl")
29 +
include("util.jl")
30 +
include("traits.jl")
31 +
include("Values.jl")
32 +
include("Variables.jl")
33 +
include("FixedVector.jl")
34 +
include("initializers.jl")
35 +
include("convert.jl")
36 +
include("abstractvector.jl")
37 +
include("indexing.jl")
38 +
include("broadcast.jl")
39 +
include("mapreduce.jl")
40 +
include("arraymath.jl")
41 +
include("linalg.jl")

@@ -0,0 +1,131 @@
Loading
1 +
2 +
import Base.Broadcast: BroadcastStyle, AbstractArrayStyle, Broadcasted, DefaultArrayStyle, materialize!
3 +
import Base.Broadcast: _bcs1  # for SOneTo axis information
4 +
using Base.Broadcast: _bcsm
5 +
# Add a new BroadcastStyle for TupleVectors, derived from AbstractArrayStyle
6 +
# A constructor that changes the style parameter N (array dimension) is also required
7 +
struct TupleVectorStyle{N} <: AbstractArrayStyle{N} end
8 +
TupleVectorStyle{M}(::Val{N}) where {M,N} = TupleVectorStyle{N}()
9 +
BroadcastStyle(::Type{<:TupleVector{N,<:Any}}) where N = TupleVectorStyle{N}()
10 +
BroadcastStyle(::Type{<:LinearAlgebra.Transpose{<:Any,<:TupleVector{N,<:Any}}}) where N = TupleVectorStyle{N}()
11 +
BroadcastStyle(::Type{<:LinearAlgebra.Adjoint{<:Any,<:TupleVector{N,<:Any}}}) where N = TupleVectorStyle{N}()
12 +
# Precedence rules
13 +
BroadcastStyle(::TupleVectorStyle{M}, ::DefaultArrayStyle{N}) where {M,N} =
14 +
    DefaultArrayStyle(Val(max(M, N)))
15 +
BroadcastStyle(::TupleVectorStyle{M}, ::DefaultArrayStyle{0}) where {M} =
16 +
    TupleVectorStyle{M}()
17 +
# copy overload
18 +
@inline function Base.copy(B::Broadcasted{TupleVectorStyle{M}}) where M
19 +
    flat = Broadcast.flatten(B); as = flat.args; f = flat.f
20 +
    argsizes = broadcast_sizes(as...)
21 +
    destsize = combine_sizes(argsizes)
22 +
    _broadcast(f, destsize, argsizes, as...)
23 +
end
24 +
# copyto! overloads
25 +
@inline Base.copyto!(dest, B::Broadcasted{<:TupleVectorStyle}) = _copyto!(dest, B)
26 +
@inline Base.copyto!(dest::AbstractArray, B::Broadcasted{<:TupleVectorStyle}) = _copyto!(dest, B)
27 +
@inline function _copyto!(dest, B::Broadcasted{TupleVectorStyle{M}}) where M
28 +
    flat = Broadcast.flatten(B); as = flat.args; f = flat.f
29 +
    argsizes = broadcast_sizes(as...)
30 +
    destsize = combine_sizes((Val(M), argsizes...))
31 +
    #=if Val(destsize) === Val{Dynamic()}()
32 +
        # destination dimension cannot be determined statically; fall back to generic broadcast!
33 +
        return copyto!(dest, convert(Broadcasted{DefaultArrayStyle{M}}, B))
34 +
    end=#
35 +
    _broadcast!(f, destsize, dest, argsizes, as...)
36 +
end
37 +
38 +
# Resolving priority between dynamic and static axes
39 +
_bcs1(a::SOneTo, b::SOneTo) = _bcsm(b, a) ? b : (_bcsm(a, b) ? a : throw(DimensionMismatch("arrays could not be broadcast to a common size")))
40 +
_bcs1(a::SOneTo, b::Base.OneTo) = _bcs1(Base.OneTo(a), b)
41 +
_bcs1(a::Base.OneTo, b::SOneTo) = _bcs1(a, Base.OneTo(b))
42 +
43 +
###################################################
44 +
## Internal broadcast machinery for TupleVectors ##
45 +
###################################################
46 +
47 +
broadcast_indices(A::TupleVector) = indices(A)
48 +
49 +
# TODO: just use map(broadcast_size, as)?
50 +
@inline broadcast_sizes(a, as...) = (broadcast_size(a), broadcast_sizes(as...)...)
51 +
@inline broadcast_sizes() = ()
52 +
@inline broadcast_size(a) = Val(0)
53 +
@inline broadcast_size(a::AbstractVector) = Val(length(a))
54 +
@inline broadcast_size(a::NTuple{N}) where N = Val(N)
55 +
56 +
function broadcasted_index(oldsize, newindex)
57 +
    index = ones(Int, length(oldsize))
58 +
    for i = 1:length(oldsize)
59 +
        if oldsize[i] != 1
60 +
            index[i] = newindex[i]
61 +
        end
62 +
    end
63 +
    return LinearIndices((oldsize,))[index...]
64 +
end
65 +
66 +
# similar to Base.Broadcast.combine_indices:
67 +
@generated function combine_sizes(s::Tuple{Vararg{Val}})
68 +
    sizes = [sz.parameters[1] for sz ∈ s.parameters]
69 +
    ndims = 0
70 +
    for i = 1:length(sizes)
71 +
        ndims = max(ndims,sizes[i])
72 +
    end 
73 +
    quote
74 +
        @_inline_meta
75 +
        Val($ndims)
76 +
    end
77 +
end
78 +
79 +
scalar_getindex(x) = x
80 +
scalar_getindex(x::Ref) = x[]
81 +
82 +
@generated function _broadcast(f, ::Val{newsize}, s::Tuple{Vararg{Val}}, a...) where newsize
83 +
    first_staticarray = a[findfirst(ai -> ai <: Union{TupleVector, LinearAlgebra.Transpose{<:Any, <:TupleVector}, LinearAlgebra.Adjoint{<:Any, <:TupleVector}}, a)]
84 +
    if newsize == 0
85 +
        # Use inference to get eltype in empty case (see also comments in _map)
86 +
        eltys = [:(eltype(a[$i])) for i ∈ 1:length(a)]
87 +
        return quote
88 +
            @_inline_meta
89 +
            T = Core.Compiler.return_type(f, Tuple{$(eltys...)})
90 +
            @inbounds return similar_type($first_staticarray, T, Val(newsize))()
91 +
        end
92 +
    end
93 +
    sizes = [sz.parameters[1] for sz ∈ s.parameters]
94 +
    indices = CartesianIndices((newsize,))
95 +
    exprs = similar(indices, Expr)
96 +
    for (j, current_ind) ∈ enumerate(indices)
97 +
        exprs_vals = [
98 +
            (!(a[i] <: AbstractArray || a[i] <: Tuple) ? :(scalar_getindex(a[$i])) : :(a[$i][$(broadcasted_index(sizes[i], current_ind))]))
99 +
            for i = 1:length(sizes)
100 +
        ]
101 +
        exprs[j] = :(f($(exprs_vals...)))
102 +
    end
103 +
    return quote
104 +
        @_inline_meta
105 +
        @inbounds elements = tuple($(exprs...))
106 +
        @inbounds return similar_type($first_staticarray, eltype(elements), Val(newsize))(elements)
107 +
    end
108 +
end
109 +
110 +
####################################################
111 +
## Internal broadcast! machinery for TupleVectors ##
112 +
####################################################
113 +
114 +
@generated function _broadcast!(f, ::Val{newsize}, dest::AbstractArray, s::Tuple{Vararg{Val}}, as...) where {newsize}
115 +
    sizes = [sz.parameters[1] for sz ∈ s.parameters]
116 +
    sizes = tuple(sizes...)
117 +
    indices = CartesianIndices((newsize,))
118 +
    exprs = similar(indices, Expr)
119 +
    for (j, current_ind) ∈ enumerate(indices)
120 +
        exprs_vals = [
121 +
            (!(as[i] <: AbstractArray || as[i] <: Tuple) ? :(as[$i][]) : :(as[$i][$(broadcasted_index(sizes[i], current_ind))]))
122 +
            for i = 1:length(sizes)
123 +
        ]
124 +
        exprs[j] = :(dest[$j] = f($(exprs_vals...)))
125 +
    end
126 +
    return quote
127 +
        Base.@_propagate_inbounds_meta
128 +
        @inbounds $(Expr(:block, exprs...))
129 +
        return dest
130 +
    end
131 +
end

@@ -0,0 +1,25 @@
Loading
1 +
2 +
"""
3 +
Return either the statically known Val() or runtime length()
4 +
"""
5 +
@inline _size(a) = Val(length(a))
6 +
@inline _size(a::TupleVector{n}) where n = Val(n)
7 +
8 +
# Return static array from a set of arrays
9 +
@inline _first_static(a1::TupleVector, as...) = a1
10 +
@inline _first_static(a1, as...) = _first_static(as...)
11 +
@inline _first_static() = throw(ArgumentError("No TupleVector found in argument list"))
12 +
13 +
"""
14 +
Returns the common Val of the inputs (or else throws a DimensionMismatch)
15 +
"""
16 +
@inline function same_size(as...)
17 +
    s = Val(length(_first_static(as...)))
18 +
    _sizes_match(s, as...) || _throw_size_mismatch(as...)
19 +
    s
20 +
end
21 +
@inline _sizes_match(s::Val, a1, as...) = ((s == _size(a1)) ? _sizes_match(s, as...) : false)
22 +
@inline _sizes_match(s::Val) = true
23 +
@noinline function _throw_size_mismatch(as...)
24 +
    throw(DimensionMismatch("Sizes $(map(_size, as)) of input arrays do not match"))
25 +
end
Files Coverage
src 6.09%
Project Totals (16 files) 6.09%