• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

kunzaatko / TransferFunctions.jl / 16332147989

16 Jul 2025 11:04PM UTC coverage: 73.494%. Remained the same
16332147989

push

github

kunzaatko
chore(CI): Test on nightly

305 of 415 relevant lines covered (73.49%)

2807564.81 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.89
/src/types/flattened-array.jl
1
using Base: OneTo
2
# FIX: When #58389 is merged into Base, I should reduce the number of printed type parameters <22-05-25> 
3
# TODO: I should fill in outer or inner dims if only one is provided. This should be done with something like this:
4
# `Tuple(n for n in OneTo(N) if !in(outer|inner)(n))` <18-05-25> 
5
"""
6
    Flattened{P,OM,IM,AX,IA,T,N} <: AbstractArray{T,N}
7

8
An `N`-dimensional `AbstractArray` stored as an `M`-dimensional 'outer' parent array `::P` of `K`-dimensional `T`-valued
9
'inner' arrays, where `N=M+K`.
10

11
It should be constructed by [`flatten`](@ref).
12

13
The constructor ensures the inner arrays have the same axes. In a sense, this can be thought as the inverse of
14
[`Slices`](@extref `Base.Slices`) from `Base`, which allows you to view a single array as multiple arrays. `Flattened` lets you see
15
multiple arrays that are nested in one container array as a single flat array.
16

17
[`parent(f::Flattened)`](@ref Flattened) will return the nested parent array.
18

19
See also [`Slices`](@extref `Base.Slices`)
20

21
# Fields
22
`outermap::OM` and `innermap::IM` are `M` and `K` integer long tuples respectively of the dimensions that the outer and
23
inner arrays represent. They are ensured to be unique and to comprise the total of `1:N` dimensions. `axes::AX` contains
24
the axes of the flattened array. `parent::P` holds the nested array.
25

26
# Examples
27
```jldoctest
28
julia> flatten(eachslice(reshape(1:12,3,4); dims=1)) == reshape(1:12,3,4)
29
true
30
```
31
"""
32
struct Flattened{P,OM,IM,AX,IA,T,N} <: AbstractArray{T,N}
33
    parent::P
292✔
34
    outermap::OM
35
    innermap::IM
36
    axes::AX
37
end
38

39
function Flattened(A::AbstractArray{IA}, outermap::OM, innermap::IM, axes::AX) where{T,OM,IM,AX,IA<:AbstractArray{T}}
214✔
40
    N = length(outermap) + length(innermap)
292✔
41
    P = typeof(A)
292✔
42
    Flattened{P,OM,IM,AX,IA,T,N}(A, outermap, innermap, axes) 
292✔
43
end
44

45
_flatten_check_dims(N) = nothing
148✔
46
function _flatten_check_dims(N, dim, dims...)
788✔
47
    1 <= dim <= N || throw(DimensionMismatch("Invalid dimension $dim"))
1,006✔
48
    dim in dims && throw(DimensionMismatch("Dimensions $dims are not unique"))
1,866✔
49
    _flatten_check_dims(N,dims...)
994✔
50
end
51
_flatten_check_axes(A) = allequal(axes, A) || throw(DimensionMismatch("Inner axes are not all the equal"))
300✔
52
function _flatten(A::AbstractArray{IA, NO}, outer::Dims{NO}, inner::Dims{NI}) where {T,NO,NI,IA<:AbstractArray{T,NI}}
298✔
53
    N = NO + NI
304✔
54
    _flatten_check_dims(N, inner..., outer...)
388✔
55
    _flatten_check_axes(A)
300✔
56
    ax = ntuple(Val(N)) do dim
395✔
57
        outerdim = findfirst(==(dim), outer)
1,486✔
58
        if !isnothing(outerdim) 
1,444✔
59
            axes(A)[outerdim]
474✔
60
        else # if not "outer" dim, it must be "inner", else bad arguments where supplied
61
            axes(first(A))[findfirst(==(dim), inner)]
496✔
62
        end
63
    end
64
    return Flattened(A, outer, inner, ax)
292✔
65
end
66

67
_default_outer(A) = Dims(1:ndims(A))
36✔
68
_default_inner(A) = Dims((ndims(A)+1):(ndims(A)+ndims(first(A))))
398✔
69

70
"""
71
    flatten(A; outer, inner)
72

73
Create a [`Flattened`](@ref) object that is a flat array of view of the nested array `A` with the dimensions of `A`
74
spanning `outer` dimensions of the resulting array and the dimensions of the elements of `A` spanning `inner` dimensions
75
of the resulting array.
76

77
See also [`eachslice`](@extref Base.eachslice)
78

79
# Examples
80
```jldoctest
81
julia> flatten([[1,2], [3,4]])
82
2×2 flatten(::Vector{Vector{Int64}}) with eltype Int64:
83
 1  2
84
 3  4
85

86
julia> flatten([[1,2], [3,4]]; outer=(2,), inner=(1,))
87
2×2 flatten(::Vector{Vector{Int64}}; outer=(2,), inner=(1,)) with eltype Int64:
88
 1  3
89
 2  4
90

91
julia> size(flatten([rand(2,3,4) for _ in 1:5, _ in 1:6])) # default is outer dimensions preceding inner dimensions
92
(5, 6, 2, 3, 4)
93
```
94
"""
95
@inline flatten(A; outer=_default_outer(A),inner=_default_inner(A)) = _flatten(A, outer, inner)
719✔
96

97
Base.axes(A::Flattened) = A.axes
95,090,596✔
98
Base.size(A::Flattened) = map(length, A.axes)
12,889,030✔
99

100
@inline function _inner_index(A::Flattened, c...)
41,092,938✔
101
    return map(l -> c[l], A.innermap)
210,543,396✔
102
end
103

104
@inline function _outer_index(A::Flattened, c...)
41,092,938✔
105
    return map(l -> c[l], A.outermap)
210,542,596✔
106
end
107

108
@inline function Base.getindex(A::Flattened{P,OM,IM,AX,IA,T,N}, I::Vararg{Int,N}) where {P,OM,IM,AX,IA,T,N}
43,412,443✔
109
    @boundscheck checkbounds(A, I...)
82,185,876✔
110
    @inbounds @views A.parent[_outer_index(A,I...)...][_inner_index(A,I...)...]
82,185,876✔
111
end
112
@inline function Base.setindex!(A::Flattened{P,OM,IM,AX,IA,T,N}, val, I::Vararg{Int,N}) where {P,OM,IM,AX,IA,T,N}
×
113
    @boundscheck checkbounds(A, I...)
×
114
    @inbounds A.parent[_outer_index(A,I...)...][_inner_index(A,I...)...] = val
×
115
end
116

117
Base.parent(s::Flattened) = s.parent
8✔
118

119
export flatten
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc