Skip to content

Commit 5856123

Browse files
committed
2 parents 51d8cd0 + 70dfcad commit 5856123

File tree

17 files changed

+425
-149
lines changed

17 files changed

+425
-149
lines changed

.github/workflows/TagBot.yml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
name: TagBot
22
on:
3-
schedule:
4-
- cron: 0 0 * * *
3+
issue_comment:
4+
types:
5+
- created
6+
workflow_dispatch:
57
jobs:
68
TagBot:
9+
if: github.event_name == 'workflow_dispatch' || github.actor == 'JuliaTagBot'
710
runs-on: ubuntu-latest
811
steps:
912
- uses: JuliaRegistries/TagBot@v1
1013
with:
11-
token: ${{ secrets.GITHUB_TOKEN }}
14+
token: ${{ secrets.GITHUB_TOKEN }}
15+
ssh: ${{ secrets.DOCUMENTER_KEY }}

.github/workflows/ci.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ jobs:
1616
matrix:
1717
version:
1818
- '1.2'
19+
- '1.3'
20+
- '1.4'
1921
- '1.5'
2022
- '1' # Leave this line unchanged. '1' will automatically expand to the latest stable 1.x release of Julia.
2123
- 'nightly'

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ research/
1010
/examples/wip
1111
/examples/ignore
1212
/examples/.ipynb_checkpoints
13-
.vscode/settings.json
13+
.vscode
1414
/issue_debug
1515
Manifest.toml

Manifest.toml

Lines changed: 0 additions & 49 deletions
This file was deleted.

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "ComponentArrays"
22
uuid = "b0b7db55-cfe3-40fc-9ded-d10e2dbeff66"
33
authors = ["Jonnie Diegelman <47193959+jonniedie@users.noreply.github.com>"]
4-
version = "0.9.6"
4+
version = "0.9.11"
55

66
[deps]
77
ArrayInterface = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9"

docs/make.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ using Documenter, ComponentArrays
33
makedocs(;
44
modules=[ComponentArrays],
55
format=Documenter.HTML(
6-
canonical = "https://jonniedie.github.io/ComponentArrays.jl/stable",
6+
canonical="https://jonniedie.github.io/ComponentArrays.jl/stable",
77
),
88
pages=[
99
"Home" => "index.md",
@@ -19,6 +19,7 @@ makedocs(;
1919
sitename="ComponentArrays.jl",
2020
authors="Jonnie Diegelman",
2121
assets=String[],
22+
doctest=:fix,
2223
)
2324

2425
deploydocs(;

src/array_interface.jl

Lines changed: 96 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,26 @@ Base.axes(x::ComponentArray) = axes(getdata(x))
99

1010
Base.reinterpret(::Type{T}, x::ComponentArray, args...) where T = ComponentArray(reinterpret(T, getdata(x), args...), getaxes(x))
1111

12-
Base.hcat(x::CV...) where {CV<:ComponentVector} = ComponentArray(reduce(hcat, getdata.(x)), getaxes(x[1])[1], FlatAxis())
12+
# Cats
13+
# TODO: Make this a little less copy-pastey
14+
function Base.hcat(x::AbstractComponentVecOrMat, y::AbstractComponentVecOrMat)
15+
ax_x, ax_y = second_axis.((x,y))
16+
if reduce((accum, key) -> accum || (key in keys(ax_x)), keys(ax_y); init=false) || getaxes(x)[1] != getaxes(y)[1]
17+
return hcat(getdata(x), getdata(y))
18+
else
19+
data_x, data_y = getdata.((x, y))
20+
ax_y = reindex(ax_y, size(x,2))
21+
idxmap_x, idxmap_y = indexmap.((ax_x, ax_y))
22+
axs = getaxes(x)
23+
return ComponentArray(hcat(data_x, data_y), axs[1], Axis((;idxmap_x..., idxmap_y...)), axs[3:end]...)
24+
end
25+
end
1326

27+
second_axis(ca::AbstractComponentVecOrMat) = getaxes(ca)[2]
28+
second_axis(::ComponentVector) = FlatAxis()
29+
30+
# Are all these methods necessary?
31+
# TODO: See what we can reduce down to without getting ambiguity errors
1432
Base.vcat(x::ComponentVector, y::AbstractVector) = vcat(getdata(x), y)
1533
Base.vcat(x::AbstractVector, y::ComponentVector) = vcat(x, getdata(y))
1634
function Base.vcat(x::ComponentVector, y::ComponentVector)
@@ -24,11 +42,33 @@ function Base.vcat(x::ComponentVector, y::ComponentVector)
2442
return ComponentArray(vcat(data_x, data_y), Axis((;idxmap_x..., idxmap_y...)))
2543
end
2644
end
45+
function Base.vcat(x::AbstractComponentVecOrMat, y::AbstractComponentVecOrMat)
46+
ax_x, ax_y = getindex.(getaxes.((x, y)), 1)
47+
if reduce((accum, key) -> accum || (key in keys(ax_x)), keys(ax_y); init=false) || getaxes(x)[2:end] != getaxes(y)[2:end]
48+
return vcat(getdata(x), getdata(y))
49+
else
50+
data_x, data_y = getdata.((x, y))
51+
ax_y = reindex(ax_y, size(x,1))
52+
idxmap_x, idxmap_y = indexmap.((ax_x, ax_y))
53+
return ComponentArray(vcat(data_x, data_y), Axis((;idxmap_x..., idxmap_y...)), getaxes(x)[2:end]...)
54+
end
55+
end
2756
Base.vcat(x::CV...) where {CV<:AdjOrTransComponentArray} = ComponentArray(reduce(vcat, map(y->getdata(y.parent)', x)), getaxes(x[1]))
28-
Base.vcat(x::ComponentVector...) = reduce(vcat, x)
2957
Base.vcat(x::ComponentVector, args...) = vcat(getdata(x), getdata.(args)...)
3058
Base.vcat(x::ComponentVector, args::Vararg{AbstractVector{T}, N}) where {T,N} = vcat(getdata(x), getdata.(args)...)
3159

60+
function Base.hvcat(row_lengths::Tuple{Vararg{Int}}, xs::AbstractComponentVecOrMat...)
61+
i = 1
62+
idxs = UnitRange{Int}[]
63+
for row_length in row_lengths
64+
i_last = i + row_length - 1
65+
push!(idxs, i:i_last)
66+
i = i_last + 1
67+
end
68+
rows = [reduce(hcat, xs[idx]) for idx in idxs]
69+
return vcat(rows...)
70+
end
71+
3272
function Base.permutedims(x::ComponentArray, dims)
3373
axs = getaxes(x)
3474
return ComponentArray(permutedims(getdata(x), dims), map(i->axs[i], dims)...)
@@ -59,14 +99,14 @@ Base.@propagate_inbounds function Base.getindex(x::ComponentArray, idx::FlatOrCo
5999
return ComponentArray(getdata(x)[idx...], axs...)
60100
end
61101
Base.@propagate_inbounds Base.getindex(x::ComponentArray, ::Colon) = getdata(x)[:]
62-
@inline Base.getindex(x::ComponentArray, ::Colon...) = x
63-
Base.@propagate_inbounds Base.getindex(x::ComponentArray, idx...) = getindex(x, toval.(idx)...)
102+
Base.@propagate_inbounds Base.getindex(x::ComponentArray, ::Colon...) = x
103+
@inline Base.getindex(x::ComponentArray, idx...) = getindex(x, toval.(idx)...)
64104
@inline Base.getindex(x::ComponentArray, idx::Val...) = _getindex(x, idx...)
65105

66106
# Set ComponentArray index
67-
@inline Base.setindex!(x::ComponentArray, v, idx::FlatIdx...) = setindex!(getdata(x), v, idx...)
107+
Base.@propagate_inbounds Base.setindex!(x::ComponentArray, v, idx::FlatOrColonIdx...) = setindex!(getdata(x), v, idx...)
68108
Base.@propagate_inbounds Base.setindex!(x::ComponentArray, v, ::Colon) = setindex!(getdata(x), v, :)
69-
Base.@propagate_inbounds Base.setindex!(x::ComponentArray, v, idx...) = setindex!(x, v, toval.(idx)...)
109+
@inline Base.setindex!(x::ComponentArray, v, idx...) = setindex!(x, v, toval.(idx)...)
70110
@inline Base.setindex!(x::ComponentArray, v, idx::Val...) = _setindex!(x, v, idx...)
71111

72112
# Explicitly view
@@ -108,6 +148,56 @@ ArrayInterface.lu_instance(jac_prototype::ComponentArray) = ArrayInterface.lu_in
108148

109149
ArrayInterface.parent_type(::Type{ComponentArray{T,N,A,Axes}}) where {T,N,A,Axes} = A
110150

151+
for f in [*, \, /]
152+
op = nameof(f)
153+
@eval begin
154+
function Base.$op(A::ComponentVecOrMat, B::ComponentMatrix)
155+
C = $op(getdata(A), getdata(B))
156+
ax1 = getaxes(A)[1]
157+
ax2 = getaxes(B)[2]
158+
return ComponentArray(C, (ax1, ax2))
159+
end
160+
function Base.$op(A::ComponentVecOrMat, b::ComponentVector)
161+
c = $op(getdata(A), getdata(b))
162+
ax1 = getaxes(A)[1]
163+
return ComponentArray(c, ax1)
164+
end
165+
function Base.$op(Aᵀ::ComponentMatrix{T}, B::AdjOrTransComponentVecOrMat{T}) where {T}
166+
Cᵀ = $op(getdata(Aᵀ), getdata(B))
167+
ax1 = getaxes(Aᵀ)[1]
168+
ax2 = getaxes(B)[2]
169+
return ComponentArray(Cᵀ, ax1, ax2)
170+
end
171+
end
172+
for (adjfun, AdjType) in zip([adjoint, transpose], [Adjoint, Transpose])
173+
adj = nameof(adjfun)
174+
Adj = nameof(AdjType)
175+
@eval begin
176+
function Base.$op(aᵀ::$Adj{T,<:ComponentVector}, B::ComponentMatrix) where {T}
177+
cᵀ = parent($op(getdata(aᵀ), getdata(B)))
178+
ax2 = getaxes(B)[2]
179+
return $adj(ComponentArray(cᵀ, ax2))
180+
end
181+
function Base.$op(Aᵀ::$Adj{T,<:ComponentMatrix}, B::AdjOrTransComponentVecOrMat) where {T}
182+
Cᵀ = $op(getdata(Aᵀ), getdata(B))
183+
ax1 = getaxes(Aᵀ)[1]
184+
ax2 = getaxes(B)[2]
185+
return ComponentArray(Cᵀ, ax1, ax2)
186+
end
187+
function Base.$op(Aᵀ::$Adj{T,<:ComponentMatrix}, B::ComponentMatrix{T}) where {T}
188+
Cᵀ = $op(getdata(Aᵀ), getdata(B))
189+
ax1 = getaxes(Aᵀ)[1]
190+
ax2 = getaxes(B)[2]
191+
return ComponentArray(Cᵀ, ax1, ax2)
192+
end
193+
function Base.$op(Aᵀ::$Adj{T,<:ComponentMatrix}, b::ComponentVector) where {T}
194+
cᵀ = $op(getdata(Aᵀ), getdata(b))
195+
ax1 = getaxes(Aᵀ)[1]
196+
return ComponentArray(cᵀ, ax1)
197+
end
198+
end
199+
end
200+
end
111201

112202

113203
# While there are some cases where these were faster, it is going to be almost impossible to

src/axis.jl

Lines changed: 50 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,56 @@ abstract type AbstractAxis{IdxMap} end
44
@inline indexmap(::Type{<:AbstractAxis{IdxMap}}) where IdxMap = IdxMap
55

66

7-
struct FlatAxis <: AbstractAxis{NamedTuple()} end
7+
# struct FlatAxis <: AbstractAxis{NamedTuple()} end
88

99
struct NullAxis <: AbstractAxis{nothing} end
10+
const VarAxes = Tuple{Vararg{<:AbstractAxis}}
1011

11-
const NullorFlatAxis = Union{NullAxis, FlatAxis}
1212

13-
const VarAxes = Tuple{Vararg{<:AbstractAxis}}
13+
"""
14+
ax = Axis(nt::NamedTuple)
15+
16+
Gives named component access for `ComponentArray`s.
17+
# Examples
18+
19+
```
20+
julia> using ComponentArrays
21+
22+
julia> ax = Axis((a = 1, b = ViewAxis(2:7, PartitionedAxis(2, (a = 1, b = 2))), c = ViewAxis(8:10, (a = 1, b = 2:3))));
23+
24+
julia> A = [100, 4, 1.3, 1, 1, 4.4, 0.4, 2, 1, 45];
25+
26+
julia> ca = ComponentArray(A, ax)
27+
ComponentVector{Float64}(a = 100.0, b = [(a = 4.0, b = 1.3), (a = 1.0, b = 1.0), (a = 4.4, b = 0.4)], c = (a = 2.0, b = [1.0, 45.0]))
28+
29+
julia> ca.a
30+
100.0
31+
32+
julia> ca.b
33+
3-element LazyArray{ComponentVector{Float64,SubArray...}}:
34+
ComponentVector{Float64,SubArray...}(a = 4.0, b = 1.3)
35+
ComponentVector{Float64,SubArray...}(a = 1.0, b = 1.0)
36+
ComponentVector{Float64,SubArray...}(a = 4.4, b = 0.4)
37+
38+
julia> ca.c
39+
ComponentVector{Float64,SubArray...}(a = 2.0, b = [1.0, 45.0])
40+
41+
julia> ca.c.b
42+
2-element view(::Vector{Float64}, 9:10) with eltype Float64:
43+
1.0
44+
45.0
45+
```
46+
"""
47+
struct Axis{IdxMap} <: AbstractAxis{IdxMap} end
48+
@inline Axis(IdxMap::NamedTuple) = Axis{IdxMap}()
49+
Axis(;kwargs...) = Axis((;kwargs...))
50+
function Axis(symbols::Union{AbstractVector{Symbol}, NTuple{N,Symbol}}) where {N}
51+
return Axis((;(symbols .=> eachindex(symbols))...))
52+
end
53+
Axis(symbols::Symbol...) = Axis(symbols)
54+
55+
const FlatAxis = Axis{NamedTuple()}
56+
const NullorFlatAxis = Union{NullAxis, FlatAxis}
1457

1558

1659

@@ -81,49 +124,11 @@ viewindex(::Type{<:ViewAxis{Inds,IdxMap}}) where {Inds,IdxMap} = Inds
81124
viewindex(i) = i
82125

83126

84-
85-
"""
86-
ax = Axis(nt::NamedTuple)
87-
88-
Gives named component access for `ComponentArray`s.
89-
# Examples
90-
91-
```jldoctest
92-
julia> using ComponentArrays
93-
94-
julia> ax = Axis((a = 1, b = ViewAxis(2:7, PartitionedAxis(2, (a = 1, b = 2))), c = ViewAxis(8:10, (a = 1, b = 2:3))));
95-
96-
julia> A = [100, 4, 1.3, 1, 1, 4.4, 0.4, 2, 1, 45];
97-
98-
julia> ca = ComponentArray(A, ax)
99-
ComponentVector{Float64}(a = 100.0, b = [(a = 4.0, b = 1.3), (a = 1.0, b = 1.0), (a = 4.4, b = 0.4)], c = (a = 2.0, b = [1.0, 45.0]))
100-
101-
julia> ca.a
102-
100.0
103-
104-
julia> ca.b
105-
3-element LazyArray{ComponentVector{Float64,SubArray...},1}:
106-
ComponentVector{Float64,SubArray...}(a = 4.0, b = 1.3)
107-
ComponentVector{Float64,SubArray...}(a = 1.0, b = 1.0)
108-
ComponentVector{Float64,SubArray...}(a = 4.4, b = 0.4)
109-
110-
julia> ca.c
111-
ComponentVector{Float64,SubArray...}(a = 2.0, b = [1.0, 45.0])
112-
113-
julia> ca.c.b
114-
2-element view(::Array{Float64,1}, 9:10) with eltype Float64:
115-
1.0
116-
45.0
117-
```
118-
"""
119-
struct Axis{IdxMap} <: AbstractAxis{IdxMap} end
120-
@inline Axis(IdxMap::NamedTuple) = Axis{IdxMap}()
121-
Axis(;kwargs...) = Axis((;kwargs...))
122-
123127
Axis(ax::AbstractAxis) = ax
124128
Axis(ax::PartitionedAxis) = ax.ax
125129
Axis(ax::ViewAxis) = ax.ax
126130

131+
# Get rid of this
127132
Axis(::Number) = NullAxis()
128133
Axis(::NamedTuple{()}) = FlatAxis()
129134
Axis(x) = FlatAxis()
@@ -137,6 +142,9 @@ Base.merge(axs::Axis...) = Axis(merge(indexmap.(axs)...))
137142

138143
Base.lastindex(ax::AbstractAxis) = last(viewindex(last(indexmap(ax))))
139144

145+
Base.keys(ax::AbstractAxis) = keys(indexmap(ax))
146+
140147
reindex(i, offset) = i .+ offset
148+
reindex(ax::FlatAxis, _) = ax
141149
reindex(ax::Axis, offset) = Axis(map(x->reindex(x, offset), indexmap(ax)))
142150
reindex(ax::ViewAxis, offset) = ViewAxis(viewindex(ax) .+ offset, indexmap(ax))

src/broadcasting.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ function Base.similar(bc::BC.Broadcasted{<:CAStyle{<:BC.Unknown, Axes, N}}, T::T
6969
end
7070

7171

72-
BC.broadcasted(f, x::ComponentArray) = ComponentArray(map(f, getdata(x)), getaxes(x))
72+
# BC.broadcasted(f, x::ComponentArray) = ComponentArray(map(f, getdata(x)), getaxes(x))
7373

7474
# Need a special case here because `map` doesn't follow same rules as normal broadcasting. To be safe and avoid ambiguities,
7575
# we'll just handle the case where everything is a ComponentArray. Else it falls back to a plain Array output.
@@ -104,7 +104,8 @@ function fill_flat(Ax1, Ax2, N1, N2)
104104
N = N1
105105
ax1, ax2 = Ax1, Ax2
106106
end
107-
Ax = promote.(getaxes(ax1), getaxes(ax2)) |> typeof
107+
# Ax = Base.promote_typeof(getaxes(ax1), getaxes(ax2))
108+
Ax = broadcast_promote_typeof(getaxes(ax1), getaxes(ax2))
108109
return Ax, N
109110
end
110111
fill_flat(Ax::Type{<:VarAxes}, N) = fill_flat(getaxes(Ax), N) |> typeof

0 commit comments

Comments
 (0)