Skip to content

Commit a7666b1

Browse files
add other junk
1 parent cd581c2 commit a7666b1

File tree

5 files changed

+296
-81
lines changed

5 files changed

+296
-81
lines changed

src/StaticArrayInterface.jl

Lines changed: 9 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ import ArrayInterface: allowed_getindex, allowed_setindex!, aos_to_soa, buffer,
88
lu_instance,
99
safevec, zeromatrix, undefmatrix, ColoringAlgorithm,
1010
fast_scalar_indexing, parameterless_type,
11-
ndims_index, ndims_shape, is_splat_index, is_forwarding_wrapper,
12-
IndicesInfo, childdims,
13-
parentdims, map_tuple_type, flatten_tuples, GetIndex, SetIndex!,
11+
is_forwarding_wrapper,
12+
childdims,
13+
map_tuple_type, flatten_tuples, GetIndex, SetIndex!,
1414
defines_strides,
1515
stride_preserving_index
1616

@@ -25,8 +25,6 @@ import ArrayInterface: MatAdjTrans, VecAdjTrans, UpTri, LoTri
2525
import ArrayInterface: AbstractDevice, AbstractCPU, CPUPointer, CPUTuple, CheckParent,
2626
CPUIndex, GPU, can_avx, device
2727

28-
import ArrayInterface: known_first, known_step, known_last
29-
3028
using Static
3129
using Static: Zero, One, nstatic, eq, ne, gt, ge, lt, le, eachop, eachop_tuple,
3230
permute, invariant_permutation, field_type, reduce_tup, find_first_eq,
@@ -45,80 +43,6 @@ using LinearAlgebra
4543

4644
import Compat
4745

48-
"""
49-
known_first(::Type{T}) -> Union{Int,Nothing}
50-
51-
If `first` of an instance of type `T` is known at compile time, return it.
52-
Otherwise, return `nothing`.
53-
54-
```julia
55-
julia> ArrayInterface.known_first(typeof(1:4))
56-
nothing
57-
58-
julia> ArrayInterface.known_first(typeof(Base.OneTo(4)))
59-
1
60-
```
61-
"""
62-
known_first(x) = known_first(typeof(x))
63-
known_first(T::Type) = is_forwarding_wrapper(T) ? known_first(parent_type(T)) : nothing
64-
known_first(::Type{<:Base.OneTo}) = 1
65-
known_first(@nospecialize T::Type{<:LinearIndices}) = 1
66-
known_first(@nospecialize T::Type{<:Base.IdentityUnitRange}) = known_first(parent_type(T))
67-
function known_first(::Type{<:CartesianIndices{N, R}}) where {N, R}
68-
_cartesian_index(ntuple(i -> known_first(R.parameters[i]), Val(N)))
69-
end
70-
71-
"""
72-
known_last(::Type{T}) -> Union{Int,Nothing}
73-
74-
If `last` of an instance of type `T` is known at compile time, return it.
75-
Otherwise, return `nothing`.
76-
77-
```julia
78-
julia> ArrayInterface.known_last(typeof(1:4))
79-
nothing
80-
81-
julia> ArrayInterface.known_first(typeof(static(1):static(4)))
82-
4
83-
84-
```
85-
"""
86-
known_last(x) = known_last(typeof(x))
87-
known_last(T::Type) = is_forwarding_wrapper(T) ? known_last(parent_type(T)) : nothing
88-
function known_last(::Type{<:CartesianIndices{N, R}}) where {N, R}
89-
_cartesian_index(ntuple(i -> known_last(R.parameters[i]), Val(N)))
90-
end
91-
92-
"""
93-
known_step(::Type{T}) -> Union{Int,Nothing}
94-
95-
If `step` of an instance of type `T` is known at compile time, return it.
96-
Otherwise, return `nothing`.
97-
98-
```julia
99-
julia> ArrayInterface.known_step(typeof(1:2:8))
100-
nothing
101-
102-
julia> ArrayInterface.known_step(typeof(1:4))
103-
1
104-
105-
```
106-
"""
107-
known_step(x) = known_step(typeof(x))
108-
known_step(T::Type) = is_forwarding_wrapper(T) ? known_step(parent_type(T)) : nothing
109-
known_step(@nospecialize T::Type{<:AbstractUnitRange}) = 1
110-
111-
"""
112-
is_splat_index(::Type{T}) -> Bool
113-
114-
Returns `static(true)` if `T` is a type that splats across multiple dimensions.
115-
"""
116-
is_splat_index(T::Type) = false
117-
is_splat_index(@nospecialize(x)) = is_splat_index(typeof(x))
118-
119-
_add1(@nospecialize x) = x + oneunit(x)
120-
_sub1(@nospecialize x) = x - oneunit(x)
121-
12246
@generated function merge_tuple_type(::Type{X}, ::Type{Y}) where {X <: Tuple, Y <: Tuple}
12347
Tuple{X.parameters..., Y.parameters...}
12448
end
@@ -338,14 +262,18 @@ include("indexing.jl")
338262
include("stridelayout.jl")
339263
include("broadcast.jl")
340264

265+
266+
## Precompilation
267+
341268
using SnoopPrecompile
342269
@precompile_setup begin
343270
# Putting some things in `setup` can reduce the size of the
344271
# precompile file and potentially make loading faster.
345272
arrays = [rand(4), Base.oneto(5)]
346273
@precompile_all_calls begin for x in arrays
347-
known_size(x)
348-
known_length(x)
274+
known_first(x)
275+
known_step(x)
276+
known_last(x)
349277
end end
350278
end
351279

src/indexing.jl

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,3 +436,236 @@ unsafe_setindex!(a, v, i::Vararg{Any}) = unsafe_set_collection!(a, v, i)
436436
Sets `inds` of `A` to `val`. `inds` is assumed to have been bounds-checked.
437437
=#
438438
unsafe_set_collection!(A, v, i) = Base._unsafe_setindex!(IndexStyle(A), A, v, i...)
439+
440+
## Index Information
441+
442+
"""
443+
known_first(::Type{T}) -> Union{Int,Nothing}
444+
445+
If `first` of an instance of type `T` is known at compile time, return it.
446+
Otherwise, return `nothing`.
447+
448+
```julia
449+
julia> ArrayInterface.known_first(typeof(1:4))
450+
nothing
451+
452+
julia> ArrayInterface.known_first(typeof(Base.OneTo(4)))
453+
1
454+
```
455+
"""
456+
known_first(x) = known_first(typeof(x))
457+
known_first(T::Type) = is_forwarding_wrapper(T) ? known_first(parent_type(T)) : nothing
458+
known_first(::Type{<:Base.OneTo}) = 1
459+
known_first(@nospecialize T::Type{<:LinearIndices}) = 1
460+
known_first(@nospecialize T::Type{<:Base.IdentityUnitRange}) = known_first(parent_type(T))
461+
function known_first(::Type{<:CartesianIndices{N, R}}) where {N, R}
462+
_cartesian_index(ntuple(i -> known_first(R.parameters[i]), Val(N)))
463+
end
464+
465+
"""
466+
known_last(::Type{T}) -> Union{Int,Nothing}
467+
468+
If `last` of an instance of type `T` is known at compile time, return it.
469+
Otherwise, return `nothing`.
470+
471+
```julia
472+
julia> ArrayInterface.known_last(typeof(1:4))
473+
nothing
474+
475+
julia> ArrayInterface.known_first(typeof(static(1):static(4)))
476+
4
477+
478+
```
479+
"""
480+
known_last(x) = known_last(typeof(x))
481+
known_last(T::Type) = is_forwarding_wrapper(T) ? known_last(parent_type(T)) : nothing
482+
function known_last(::Type{<:CartesianIndices{N, R}}) where {N, R}
483+
_cartesian_index(ntuple(i -> known_last(R.parameters[i]), Val(N)))
484+
end
485+
486+
"""
487+
known_step(::Type{T}) -> Union{Int,Nothing}
488+
489+
If `step` of an instance of type `T` is known at compile time, return it.
490+
Otherwise, return `nothing`.
491+
492+
```julia
493+
julia> StaticArrayInterface.known_step(typeof(1:2:8))
494+
nothing
495+
496+
julia> StaticArrayInterface.known_step(typeof(1:4))
497+
1
498+
499+
```
500+
"""
501+
known_step(x) = known_step(typeof(x))
502+
known_step(T::Type) = is_forwarding_wrapper(T) ? known_step(parent_type(T)) : nothing
503+
known_step(@nospecialize T::Type{<:AbstractUnitRange}) = 1
504+
505+
"""
506+
is_splat_index(::Type{T}) -> Bool
507+
508+
Returns `static(true)` if `T` is a type that splats across multiple dimensions.
509+
"""
510+
is_splat_index(T::Type) = false
511+
is_splat_index(@nospecialize(x)) = is_splat_index(typeof(x))
512+
513+
_add1(@nospecialize x) = x + oneunit(x)
514+
_sub1(@nospecialize x) = x - oneunit(x)
515+
516+
"""
517+
IndicesInfo{N}(inds::Tuple) -> IndicesInfo{N}(typeof(inds))
518+
IndicesInfo{N}(T::Type{<:Tuple}) -> IndicesInfo{N,pdims,cdims}()
519+
IndicesInfo(inds::Tuple) -> IndicesInfo(typeof(inds))
520+
IndicesInfo(T::Type{<:Tuple}) -> IndicesInfo{maximum(pdims),pdims,cdims}()
521+
522+
523+
Maps a tuple of indices to `N` dimensions. The resulting `pdims` is a tuple where each
524+
field in `inds` (or field type in `T`) corresponds to the parent dimensions accessed.
525+
`cdims` similarly maps indices to the resulting child array produced after indexing with
526+
`inds`. If `N` is not provided then it is assumed that all indices are represented by parent
527+
dimensions and there are no trailing dimensions accessed. These may be accessed by through
528+
`parentdims(info::IndicesInfo)` and `childdims(info::IndicesInfo)`. If `N` is not provided,
529+
it is assumed that no indices are accessing trailing dimensions (which are represented as
530+
`0` in `parentdims(info)[index_position]`).
531+
532+
The the fields and types of `IndicesInfo` should not be accessed directly.
533+
Instead [`parentdims`](@ref), [`childdims`](@ref), [`ndims_index`](@ref), and
534+
[`ndims_shape`](@ref) should be used to extract relevant information.
535+
536+
# Examples
537+
538+
```julia
539+
julia> using StaticArrayInterface: IndicesInfo, parentdims, childdims, ndims_index, ndims_shape
540+
541+
julia> info = IndicesInfo{5}(typeof((:,[CartesianIndex(1,1),CartesianIndex(1,1)], 1, ones(Int, 2, 2), :, 1)));
542+
543+
julia> parentdims(info) # the last two indices access trailing dimensions
544+
(1, (2, 3), 4, 5, 0, 0)
545+
546+
julia> childdims(info)
547+
(1, 2, 0, (3, 4), 5, 0)
548+
549+
julia> childdims(info)[3] # index 3 accesses a parent dimension but is dropped in the child array
550+
0
551+
552+
julia> ndims_index(info)
553+
5
554+
555+
julia> ndims_shape(info)
556+
5
557+
558+
julia> info = IndicesInfo(typeof((:,[CartesianIndex(1,1),CartesianIndex(1,1)], 1, ones(Int, 2, 2), :, 1)));
559+
560+
julia> parentdims(info) # assumed no trailing dimensions
561+
(1, (2, 3), 4, 5, 6, 7)
562+
563+
julia> ndims_index(info) # assumed no trailing dimensions
564+
7
565+
566+
```
567+
"""
568+
struct IndicesInfo{Np, pdims, cdims, Nc}
569+
function IndicesInfo{N}(@nospecialize(T::Type{<:Tuple})) where {N}
570+
SI = _find_first_true(map_tuple_type(is_splat_index, T))
571+
NI = map_tuple_type(ndims_index, T)
572+
NS = map_tuple_type(ndims_shape, T)
573+
if SI === nothing
574+
ndi = NI
575+
nds = NS
576+
else
577+
nsplat = N - sum(NI)
578+
if nsplat === 0
579+
ndi = NI
580+
nds = NS
581+
else
582+
splatmul = max(0, nsplat + 1)
583+
ndi = _map_splats(splatmul, SI, NI)
584+
nds = _map_splats(splatmul, SI, NS)
585+
end
586+
end
587+
if ndi === (1,) && N !== 1
588+
ns1 = getfield(nds, 1)
589+
new{N, (:,), (ns1 > 1 ? ntuple(identity, ns1) : ns1,), ns1}()
590+
else
591+
nds_cumsum = cumsum(nds)
592+
if sum(ndi) > N
593+
init_pdims = _accum_dims(cumsum(ndi), ndi)
594+
pdims = ntuple(nfields(init_pdims)) do i
595+
dim_i = getfield(init_pdims, i)
596+
if dim_i isa Tuple
597+
ntuple(length(dim_i)) do j
598+
dim_i_j = getfield(dim_i, j)
599+
dim_i_j > N ? 0 : dim_i_j
600+
end
601+
else
602+
dim_i > N ? 0 : dim_i
603+
end
604+
end
605+
new{N, pdims, _accum_dims(nds_cumsum, nds), last(nds_cumsum)}()
606+
else
607+
new{N, _accum_dims(cumsum(ndi), ndi), _accum_dims(nds_cumsum, nds),
608+
last(nds_cumsum)}()
609+
end
610+
end
611+
end
612+
IndicesInfo{N}(@nospecialize(t::Tuple)) where {N} = IndicesInfo{N}(typeof(t))
613+
function IndicesInfo(@nospecialize(T::Type{<:Tuple}))
614+
ndi = map_tuple_type(ndims_index, T)
615+
nds = map_tuple_type(ndims_shape, T)
616+
ndi_sum = cumsum(ndi)
617+
nds_sum = cumsum(nds)
618+
nf = nfields(ndi_sum)
619+
pdims = _accum_dims(ndi_sum, ndi)
620+
cdims = _accum_dims(nds_sum, nds)
621+
new{getfield(ndi_sum, nf), pdims, cdims, getfield(nds_sum, nf)}()
622+
end
623+
IndicesInfo(@nospecialize t::Tuple) = IndicesInfo(typeof(t))
624+
@inline function IndicesInfo(@nospecialize T::Type{<:SubArray})
625+
IndicesInfo{ndims(parent_type(T))}(fieldtype(T, :indices))
626+
end
627+
IndicesInfo(x::SubArray) = IndicesInfo{ndims(parent(x))}(typeof(x.indices))
628+
end
629+
630+
@inline function _map_splats(nsplat::Int, splat_index::Int, dims::Tuple{Vararg{Int}})
631+
ntuple(length(dims)) do i
632+
i === splat_index ? (nsplat * getfield(dims, i)) : getfield(dims, i)
633+
end
634+
end
635+
@inline function _accum_dims(csdims::NTuple{N, Int}, nd::NTuple{N, Int}) where {N}
636+
ntuple(N) do i
637+
nd_i = getfield(nd, i)
638+
if nd_i === 0
639+
0
640+
elseif nd_i === 1
641+
getfield(csdims, i)
642+
else
643+
ntuple(Base.Fix1(+, getfield(csdims, i) - nd_i), nd_i)
644+
end
645+
end
646+
end
647+
648+
function _lower_info(::IndicesInfo{Np, pdims, cdims, Nc}) where {Np, pdims, cdims, Nc}
649+
Np, pdims, cdims, Nc
650+
end
651+
652+
ndims_index(@nospecialize(info::IndicesInfo)) = getfield(_lower_info(info), 1)
653+
ndims_shape(@nospecialize(info::IndicesInfo)) = getfield(_lower_info(info), 4)
654+
655+
"""
656+
parentdims(::IndicesInfo) -> Tuple
657+
658+
Returns the parent dimension mapping from `IndicesInfo`.
659+
660+
See also: [`IndicesInfo`](@ref), [`childdims`](@ref)
661+
"""
662+
parentdims(@nospecialize info::IndicesInfo) = getfield(_lower_info(info), 2)
663+
664+
"""
665+
childdims(::IndicesInfo) -> Tuple
666+
667+
Returns the child dimension mapping from `IndicesInfo`.
668+
669+
See also: [`IndicesInfo`](@ref), [`parentdims`](@ref)
670+
"""
671+
childdims(@nospecialize info::IndicesInfo) = getfield(_lower_info(info), 3)

test/array_index.jl

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,37 @@ let v = Float64.(1:10)', v2 = transpose(parent(v))
2323
@test @inferred(ArrayInterface.StrideIndex(sv)) === @inferred(ArrayInterface.StrideIndex(sv2)) === ArrayInterface.StrideIndex{2, (2, 1), 2}((StaticInt(1), StaticInt(1)), (StaticInt(1), StaticInt(1)))
2424
@test @inferred(ArrayInterface.stride_rank(parent(sv))) === @inferred(ArrayInterface.stride_rank(parent(sv2))) === (StaticInt(1),)
2525
end
26+
27+
28+
@testset "IndicesInfo" begin
29+
30+
struct SplatFirst end
31+
32+
StaticArrayInterface.is_splat_index(::Type{SplatFirst}) = true
33+
34+
@test @inferred(IndicesInfo(SubArray{Float64, 2, Vector{Float64}, Tuple{Base.ReshapedArray{Int64, 2, UnitRange{Int64}, Tuple{}}}, true})) isa
35+
IndicesInfo{1,(1,),((1,2),)}
36+
37+
@test @inferred(IndicesInfo{1}((Tuple{Vector{Int}}))) isa IndicesInfo{1, (1,), (1,)}
38+
39+
@test @inferred(IndicesInfo{2}(Tuple{Vector{Int}})) isa IndicesInfo{2, (:,), (1,)}
40+
41+
@test @inferred(IndicesInfo{1}(Tuple{SplatFirst})) isa IndicesInfo{1, (1,), (1,)}
42+
43+
@test @inferred(IndicesInfo{2}(Tuple{SplatFirst})) isa IndicesInfo{2, ((1,2),), ((1, 2),)}
44+
45+
@test @inferred(IndicesInfo{5}(typeof((:,[CartesianIndex(1,1),CartesianIndex(1,1)], 1, ones(Int, 2, 2), :, 1)))) isa
46+
IndicesInfo{5, (1, (2, 3), 4, 5, 0, 0), (1, 2, 0, (3, 4), 5, 0)}
47+
48+
@test @inferred(IndicesInfo{10}(Tuple{Vararg{Int,10}})) isa
49+
IndicesInfo{10, (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), (0, 0, 0, 0, 0, 0, 0, 0, 0, 0)}
50+
51+
@test @inferred(IndicesInfo{10}(typeof((1, CartesianIndex(2, 1), 2, CartesianIndex(1, 2), 1, CartesianIndex(2, 1), 2)))) isa
52+
IndicesInfo{10, (1, (2, 3), 4, (5, 6), 7, (8, 9), 10), (0, 0, 0, 0, 0, 0, 0)}
53+
54+
@test @inferred(IndicesInfo{10}(typeof((fill(true, 4, 4), 2, fill(true, 4, 4), 2, 1, fill(true, 4, 4), 1)))) isa
55+
IndicesInfo{10, ((1, 2), 3, (4, 5), 6, 7, (8, 9), 10), (1, 0, 2, 0, 0, 3, 0)}
56+
57+
@test @inferred(IndicesInfo{10}(typeof((1, SplatFirst(), 2, SplatFirst(), CartesianIndex(1, 1))))) isa
58+
IndicesInfo{10, (1, (2, 3, 4, 5, 6), 7, 8, (9, 10)), (0, (1, 2, 3, 4, 5), 0, 6, 0)}
59+
end

0 commit comments

Comments
 (0)