Skip to content

Commit 5d7234f

Browse files
authored
Update for Base.stack, Julia 1.9 (#14)
* update for Base.stack * don't test on 1.3 * tidy
1 parent 24c5c42 commit 5d7234f

File tree

8 files changed

+740
-525
lines changed

8 files changed

+740
-525
lines changed

.github/workflows/ci.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
fail-fast: false
1717
matrix:
1818
version:
19-
- '1.3'
19+
- '1.6'
2020
- '1' # Leave this line unchanged. '1' will automatically expand to the latest stable 1.x release of Julia.
2121
- 'nightly'
2222
os:

.travis.yml

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

Project.toml

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,26 @@
11
name = "LazyStack"
22
uuid = "1fad7336-0346-5a1a-a56f-a06ba010965b"
33
authors = ["Michael Abbott"]
4-
version = "0.0.8"
4+
version = "0.1.0"
55

66
[deps]
77
ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
8+
Compat = "34da2185-b29b-5c13-b0c7-acf172513d20"
89
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
9-
NamedDims = "356022a1-0364-5f58-8944-0da4b18d706f"
10-
OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
10+
# NamedDims = "356022a1-0364-5f58-8944-0da4b18d706f"
11+
# OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
1112

1213
[compat]
13-
ChainRulesCore = "0.10.9, 1"
14-
NamedDims = "0.2.16, 0.3, 1.0"
15-
OffsetArrays = "1"
16-
julia = "1.3"
14+
ChainRulesCore = "1"
15+
Compat = "3.46, 4.2"
16+
# NamedDims = "0.2.16, 0.3, 1.0" # try to remove
17+
# OffsetArrays = "1" # try to remove
18+
julia = "1.6"
1719

1820
[extras]
1921
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
22+
OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
2023
Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f"
2124

2225
[targets]
23-
test = ["Test", "Zygote"]
26+
test = ["Test", "OffsetArrays", "Zygote"]

README.md

Lines changed: 39 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,72 @@
11
# LazyStack.jl
22

3-
[![Travis CI](https://travis-ci.org/mcabbott/LazyStack.jl.svg?branch=master)](https://travis-ci.org/mcabbott/LazyStack.jl)
43
[![Github CI](https://github.com/mcabbott/LazyStack.jl/workflows/CI/badge.svg)](https://github.com/mcabbott/LazyStack.jl/actions?query=workflow%3ACI+branch%3Amaster)
54

6-
This package exports one function, `stack`, for turning a list of arrays
5+
This package exports one function, `lazystack`, for turning a list of arrays
76
into one `AbstractArray`. Given several arrays with the same `eltype`,
87
or an array of such arrays, it returns a lazy `Stacked{T,N}` view of these:
98

109
```julia
11-
stack([zeros(2,2), ones(2,2)]) # isa Stacked{Float64, 3, <:Vector{<:Matrix}}
12-
stack([1,2,3], 4:6) # isa Stacked{Int, 2, <:Tuple{<:Vector, <:UnitRange}}
10+
julia> lazystack([1:2, 3:4, 5:6])
11+
2×3 lazystack(::Vector{UnitRange{Int64}}) with eltype Int64:
12+
1 3 5
13+
2 4 6
14+
15+
julia> lazystack([pi^ℯ], [ℯ^pi])
16+
1×2 lazystack(::Tuple{Vector{Float64}, Vector{Float64}}) with eltype Float64:
17+
22.4592 23.1407
1318
```
1419

15-
Given a generator, it instead iterates through the elements and writes into a new array.
16-
Given a function and then some arrays, it behaves like `map(f, A, B)` but immediately writes
17-
into a new array:
20+
Before v0.1 this function used to be called `stack`, but that name is now exported by Base (from Julia 1.9).
21+
Like this package, `Base.stack` makes an array with `size(result) = (size(inner)..., size(outer)...)`.
22+
It always returns a new dense array, not a lazy container.
23+
And instead of two vectors (in the above example) it would want a tuple `stack(([pi^ℯ], [ℯ^pi]))`.
1824

19-
```julia
20-
stack([i,2i] for i in 1:5) # isa Matrix{Int} # size(ans) == (2, 5)
21-
stack(*, eachcol(ones(2,4)), 1:4) # == Matrix(stack(map(*, eachcol(...), 1:4)))
22-
```
23-
24-
The same `stack_iter` method is also used for any list of arrays of heterogeneous element type,
25-
and for arrays of tuples. Notice that like `map(identity, Any[1, 1.0, 5im])`, this promotes using
26-
`promote_typejoin`, to `Number` here, rather than to `Complex{Float64}`:
27-
28-
```julia
29-
stack([1,2], [3.0, 4.0], [5im, 6im]) # isa Matrix{Number} # size(ans) == (2, 3)
30-
stack([(i,2.0,3//j) for i=1:4, j=1:5])# isa Array{Real, 3} # size(ans) == (3, 4, 5)
31-
```
25+
Generators such as `lazystack([i,2i] for i in 1:5)` and arrays of mixed eltype like `lazystack([1,2], [3.0, 4.0], [5im, 6im])` used to be be handled here, making a dense array, but are now simply passed through to `Base.stack`.
3226

33-
The slices must all have the same `size`, but they (and the container)
34-
can have any number of dimensions. `stack` always places the slice dimensions first.
35-
There are no options.
27+
When the individual slices aren't backed by an `Array`, as for instance with `CuArray`s on a GPU, then again `Base.stack` is called.
28+
This should make one big `CuArray`, since scalar indexing of individual slices won't work well.
3629

3730
### Ragged stack
3831

39-
There is also a version which does not demand that slices have equal `size` (or equal `ndims`),
40-
which always returns a new `Array`. You can control the position of slices `using OffsetArrays`:
32+
There is also a version which does not demand that slices have equal `size` (or equal `ndims`).
33+
For now this is not lazy:
4134

4235
```julia
43-
rstack([1:n for n in 1:10]) # upper triangular Matrix{Int}
44-
rstack(OffsetArray(fill(n,4), rand(-2:2)) for n in 1:10; fill=NaN)
36+
julia> raggedstack([10:10+n for n in 1:3])
37+
4×3 Matrix{Int64}:
38+
10 10 10
39+
11 11 11
40+
0 12 12
41+
0 0 13
42+
43+
julia> using OffsetArrays
44+
45+
julia> raggedstack(OffsetArray(fill(1.0n, 3), rand(-1:1)) for n in 1:10; fill=NaN)
46+
5×10 OffsetArray(::Matrix{Float64}, 0:4, 1:10) with eltype Float64 with indices 0:4×1:10:
47+
NaN 2.0 NaN 4.0 NaN 6.0 7.0 NaN 9.0 NaN
48+
1.0 2.0 3.0 4.0 5.0 6.0 7.0 NaN 9.0 10.0
49+
1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0
50+
1.0 NaN 3.0 NaN 5.0 NaN NaN 8.0 NaN 10.0
51+
NaN NaN NaN NaN NaN NaN NaN 8.0 NaN NaN
4552
```
4653

4754
### Other packages
4855

49-
This one plays well with [OffsetArrays.jl](https://github.com/JuliaArrays/OffsetArrays.jl),
50-
[NamedDims.jl](https://github.com/invenia/NamedDims.jl), and
51-
[Zygote.jl](https://github.com/FluxML/Zygote.jl).
56+
This one plays well with [OffsetArrays.jl](https://github.com/JuliaArrays/OffsetArrays.jl), and [ChainRules.jl](https://github.com/JuliaDiff/ChainRules.jl)-compatible AD such as [Zygote.jl](https://github.com/FluxML/Zygote.jl). It's also used internally by [TensorCast.jl](https://github.com/mcabbott/TensorCast.jl).
5257

5358
Besides which, there are several other ways to achieve similar things:
5459

5560
* For an array of arrays, you can also use [`JuliennedArrays.Align`](https://bramtayl.github.io/JuliennedArrays.jl/latest/#JuliennedArrays.Align). This requires (or enables) you to specify which dimensions of the output belong to the sub-arrays, instead of writing `PermutedDimsArray(stack(...), ...)`.
56-
* There is also [`RecursiveArrayTools.VectorOfArray`](https://github.com/JuliaDiffEq/RecursiveArrayTools.jl#vectorofarray) which as its name hints only allows a one-dimensional container. Linear indexing retreives a slice, not an element, which is sometimes surprising.
61+
* There is also [`RecursiveArrayTools.VectorOfArray`](https://github.com/JuliaDiffEq/RecursiveArrayTools.jl#vectorofarray) which as its name hints only allows a one-dimensional container. (And unlike the package name, nothing is recursive.) Linear indexing retreives a slice, not an element, which is sometimes surprising.
5762
* For a tuple of arrays, [`LazyArrays.Hcat`](https://github.com/JuliaArrays/LazyArrays.jl#concatenation) is at present faster to index than `stack`, but doesn't allow arbitrary dimensions.
58-
* For a generator of arrays, the built-in `reduce(hcat,...)` may work, but it slow compared to `stack`: see [test/speed.jl](test/speed.jl) for some examples.
5963

6064
And a few more:
6165

6266
* When writing this I missed [`SplitApplyCombine.combinedimsview`](https://github.com/JuliaData/SplitApplyCombine.jl#combinedimsviewarray), which is very similar to `stack`, but doesn't handle tuples.
6367
* Newer than this package is [StackViews.jl](https://github.com/JuliaArrays/StackViews.jl) handles both, with `StackView(A,B,dims=4) == StackView([A,B],4)` creating a 4th dimension; the container is always one-dimensional.
6468
* [`Flux.stack`](https://fluxml.ai/Flux.jl/stable/utilities/#Flux.stack) similarly takes a dimension, but eagerly creates an `Array`.
69+
* Finally, [CatViews.jl](https://github.com/ahwillia/CatViews.jl) offers a lazy `vcat`. But the package is old and I think not so fast.
6570

6671
The lazy inverse:
6772

@@ -71,10 +76,10 @@ The lazy inverse:
7176

7277
* As does [`PackedVectorsOfVectors`](https://github.com/synchronoustechnologies/PackedVectorsOfVectors.jl), although only 1+1 dimensions. Also has an eager `pack` method which turns a vector of vectors into view of a single larger matrix.
7378

74-
* [`Base.eachslice`](https://docs.julialang.org/en/v1/base/arrays/#Base.eachslice) also views one large array as many slices. This is a generator, but [JuliaLang#32310](https://github.com/JuliaLang/julia/pull/32310) should upgrade it to a multi-dimensional container indexable container.
79+
* [`Base.eachslice`](https://docs.julialang.org/en/v1/base/arrays/#Base.eachslice) also views one large array as many slices. This was a generator, but [JuliaLang#32310](https://github.com/JuliaLang/julia/pull/32310) upgrades it to a multi-dimensional indexable container, in Julia 1.9.
7580

7681
Eager:
7782

7883
* After writing this I learned of [JuliaLang#31644](https://github.com/JuliaLang/julia/pull/31644) which extends `reduce(hcat,...)` to work on generators.
7984

80-
* Later, [JuliaLang#31644](https://github.com/JuliaLang/julia/pull/43334) proposes to add the eager `stack_iter` method of this package to Base.
85+
* Later, [JuliaLang#43334](https://github.com/JuliaLang/julia/pull/43334) has added a better version of this package's `stack_iter` method to Base.

0 commit comments

Comments
 (0)