From 9903e423db99519a740eb30f3dbba4ef988091cc Mon Sep 17 00:00:00 2001 From: roflmaostc Date: Thu, 23 Jun 2022 17:04:05 +0200 Subject: [PATCH 01/26] Add insertdims --- base/abstractarraymath.jl | 77 +++++++++++++++++++++++++++++++++++++++ base/exports.jl | 1 + test/arrayops.jl | 11 ++++++ 3 files changed, 89 insertions(+) diff --git a/base/abstractarraymath.jl b/base/abstractarraymath.jl index 70c304d9060c1..710d1e9fa9717 100644 --- a/base/abstractarraymath.jl +++ b/base/abstractarraymath.jl @@ -93,6 +93,83 @@ function _dropdims(A::AbstractArray, dims::Dims) end _dropdims(A::AbstractArray, dim::Integer) = _dropdims(A, (Int(dim),)) + +""" + insertdims(A; dims) + +Return an array with the same data as `A`, but with singleton dimensions specified by +`dims` inserted. +The dimensions of `A` and `dims` must be contiguous. +If dimensions occur multiple times in `dims`, several singleton dimensions are inserted. + +The result shares the same underlying data as `A`, such that the +result is mutable if and only if `A` is mutable, and setting elements of one +alters the values of the other. + +See also: [`reshape`](@ref), [`dropdims`](@ref), [`vec`](@ref). + +# Examples +```jldoctest +julia> a = [1 2; 3 4] +2×2 Matrix{Int64}: + 1 2 + 3 4 + +julia> b = insertdims(a, dims=(1,1)) +1×1×2×2 Array{Int64, 4}: +[:, :, 1, 1] = + 5 + +[:, :, 2, 1] = + 3 + +[:, :, 1, 2] = + 2 + +[:, :, 2, 2] = + 4 + +julia> b = insertdims(a, dims=(1,2)) +1×2×1×2 Array{Int64, 4}: +[:, :, 1, 1] = + 5 3 + +[:, :, 1, 2] = + 2 4 + +julia> b = insertdims(a, dims=(1,3)) +1×2×2×1 Array{Int64, 4}: +[:, :, 1, 1] = + 1 3 + +[:, :, 2, 1] = + 2 4 + +julia> b[1,1,1,1] = 5; a +2×2 Matrix{Int64}: + 5 2 + 3 4 +``` +""" +insertdims(A; dims) = _insertdims(A, dims) +function _insertdims(A::AbstractArray{T, N}, dims::Tuple{Vararg{Int64, M}}) where {T, N, M} + maximum(dims) ≤ ndims(A)+1 || throw(ArgumentError("The largest entry in dims must be ≤ ndims(A) + 1.")) + 1 ≤ minimum(dims) || throw(ArgumentError("The smallest entry in dims must be ≥ 1.")) + issorted(dims) || throw(ArgumentError("dims=$(dims) are not sorted")) + + # n is the amount of the dims already inserted + ax_n = _foldoneto(((ds, n, dims), _) -> + dims != Tuple(()) && n == first(dims) ? + ((ds..., Base.OneTo(1)), n, tail(dims)) : + ((ds..., axes(A,n)), n+1, dims), + ((), 1, dims), Val(ndims(A) + length(dims))) + # we need only the new shape and not n + reshape(A, ax_n[1]) +end +_insertdims(A::AbstractArray, dim::Integer) = _insertdims(A, (Int(dim),)) + + + ## Unary operators ## """ diff --git a/base/exports.jl b/base/exports.jl index 304d48d24bdcd..38679f3813aad 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -402,6 +402,7 @@ export indexin, argmax, argmin, + insertdims, invperm, invpermute!, isassigned, diff --git a/test/arrayops.jl b/test/arrayops.jl index b11731d394b65..26f1ed073c37e 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -304,6 +304,17 @@ end @test_throws ArgumentError dropdims(a, dims=4) @test_throws ArgumentError dropdims(a, dims=6) + + a = rand(8, 7) + @test @inferred(insertdims(a, dims=1)) == @inferred(insertdims(a, dims=(1,))) == reshape(a, (1, 8, 7)) + @test @inferred(insertdims(a, dims=(1, 3))) == reshape(a, (1, 8, 7, 1)) + @test @inferred(insertdims(a, dims=(1, 2, 3))) == reshape(a, (1, 8, 1, 7, 1)) + @test_throws UndefKeywordError insertdims(a) + @test_throws ArgumentError insertdims(a, dims=0) + @test_throws ArgumentError insertdims(a, dims=(1, 2, 1)) + @test_throws ArgumentError insertdims(a, dims=4) + @test_throws ArgumentError insertdims(a, dims=6) + sz = (5,8,7) A = reshape(1:prod(sz),sz...) @test A[2:6] == [2:6;] From 0f93207321d44e0ef53dbd4fe1b7adf02a2e421c Mon Sep 17 00:00:00 2001 From: "Felix Wechsler (he/him)" Date: Thu, 23 Jun 2022 17:08:28 +0200 Subject: [PATCH 02/26] Update abstractarraymath.jl --- base/abstractarraymath.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/abstractarraymath.jl b/base/abstractarraymath.jl index 710d1e9fa9717..3ca3dc4fcbf83 100644 --- a/base/abstractarraymath.jl +++ b/base/abstractarraymath.jl @@ -157,7 +157,7 @@ function _insertdims(A::AbstractArray{T, N}, dims::Tuple{Vararg{Int64, M}}) wher 1 ≤ minimum(dims) || throw(ArgumentError("The smallest entry in dims must be ≥ 1.")) issorted(dims) || throw(ArgumentError("dims=$(dims) are not sorted")) - # n is the amount of the dims already inserted + # n is the current index where we maybe insert ax_n = _foldoneto(((ds, n, dims), _) -> dims != Tuple(()) && n == first(dims) ? ((ds..., Base.OneTo(1)), n, tail(dims)) : From bd6e45e91edf9fade91004abc23f583569c49d39 Mon Sep 17 00:00:00 2001 From: roflmaostc Date: Fri, 24 Jun 2022 09:58:10 +0200 Subject: [PATCH 03/26] Fix some whitespaces and doctest [skip ci] --- base/abstractarraymath.jl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/base/abstractarraymath.jl b/base/abstractarraymath.jl index 710d1e9fa9717..e9d24f213ec13 100644 --- a/base/abstractarraymath.jl +++ b/base/abstractarraymath.jl @@ -98,7 +98,7 @@ _dropdims(A::AbstractArray, dim::Integer) = _dropdims(A, (Int(dim),)) insertdims(A; dims) Return an array with the same data as `A`, but with singleton dimensions specified by -`dims` inserted. +`dims` inserted. The dimensions of `A` and `dims` must be contiguous. If dimensions occur multiple times in `dims`, several singleton dimensions are inserted. @@ -118,7 +118,7 @@ julia> a = [1 2; 3 4] julia> b = insertdims(a, dims=(1,1)) 1×1×2×2 Array{Int64, 4}: [:, :, 1, 1] = - 5 + 1 [:, :, 2, 1] = 3 @@ -132,7 +132,7 @@ julia> b = insertdims(a, dims=(1,1)) julia> b = insertdims(a, dims=(1,2)) 1×2×1×2 Array{Int64, 4}: [:, :, 1, 1] = - 5 3 + 1 3 [:, :, 1, 2] = 2 4 @@ -158,9 +158,9 @@ function _insertdims(A::AbstractArray{T, N}, dims::Tuple{Vararg{Int64, M}}) wher issorted(dims) || throw(ArgumentError("dims=$(dims) are not sorted")) # n is the amount of the dims already inserted - ax_n = _foldoneto(((ds, n, dims), _) -> - dims != Tuple(()) && n == first(dims) ? - ((ds..., Base.OneTo(1)), n, tail(dims)) : + ax_n = _foldoneto(((ds, n, dims), _) -> + dims != Tuple(()) && n == first(dims) ? + ((ds..., Base.OneTo(1)), n, tail(dims)) : ((ds..., axes(A,n)), n+1, dims), ((), 1, dims), Val(ndims(A) + length(dims))) # we need only the new shape and not n From 4f53621bce624b5b4c9bfc6100f00fef5be7f239 Mon Sep 17 00:00:00 2001 From: roflmaostc Date: Thu, 30 May 2024 19:22:38 +0200 Subject: [PATCH 04/26] Fix bug in _foldoneto call --- base/abstractarraymath.jl | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/base/abstractarraymath.jl b/base/abstractarraymath.jl index 6f1c1fa81304d..db16f9a6d1c0c 100644 --- a/base/abstractarraymath.jl +++ b/base/abstractarraymath.jl @@ -157,12 +157,15 @@ function _insertdims(A::AbstractArray{T, N}, dims::Tuple{Vararg{Int64, M}}) wher 1 ≤ minimum(dims) || throw(ArgumentError("The smallest entry in dims must be ≥ 1.")) issorted(dims) || throw(ArgumentError("dims=$(dims) are not sorted")) - # n is the current index where we maybe insert - ax_n = _foldoneto(((ds, n, dims), _) -> - dims != Tuple(()) && n == first(dims) ? - ((ds..., Base.OneTo(1)), n, tail(dims)) : - ((), 1, dims), Val(ndims(A) + length(dims))) - # we need only the new shape + # n is the amount of the dims already inserted + ax_n = Base._foldoneto(((ds, n, dims), _) -> + dims != Tuple(()) && n == first(dims) ? + ((ds..., Base.OneTo(1)), n, Base.tail(dims)) : + ((ds..., axes(A,n)), n+1, dims), + ((), 1, dims), Val(ndims(A) + length(dims))) + # we need only the new shape and not n + reshape(A, ax_n[1]) + reshape(A, ax_n[1]) end _insertdims(A::AbstractArray, dim::Integer) = _insertdims(A, (Int(dim),)) From 1196b8f84bd3aaabdef667a0adc33375964db414 Mon Sep 17 00:00:00 2001 From: roflmaostc Date: Fri, 31 May 2024 12:30:55 +0200 Subject: [PATCH 05/26] Add test for multiple singleton dimensions at one dim --- test/arrayops.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/arrayops.jl b/test/arrayops.jl index eb4b90614641d..c439c2774083a 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -313,6 +313,9 @@ end @test @inferred(insertdims(a, dims=1)) == @inferred(insertdims(a, dims=(1,))) == reshape(a, (1, 8, 7)) @test @inferred(insertdims(a, dims=(1, 3))) == reshape(a, (1, 8, 7, 1)) @test @inferred(insertdims(a, dims=(1, 2, 3))) == reshape(a, (1, 8, 1, 7, 1)) + @test @inferred(insertdims(a, dims=(1, 1, 2, 3))) == reshape(a, (1, 1, 8, 1, 7, 1)) + @test @inferred(insertdims(a, dims=(1, 2, 2, 3))) == reshape(a, (1, 8, 1, 1, 7, 1)) + @test @inferred(insertdims(a, dims=(1, 2, 3, 3))) == reshape(a, (1, 8, 1, 7, 1, 1)) @test_throws UndefKeywordError insertdims(a) @test_throws ArgumentError insertdims(a, dims=0) @test_throws ArgumentError insertdims(a, dims=(1, 2, 1)) From 6f986dcf189ab9d8e766526c0fd55ba01b33eebb Mon Sep 17 00:00:00 2001 From: Felix Wechsler Date: Thu, 25 Jul 2024 18:24:39 +0200 Subject: [PATCH 06/26] Update base/abstractarraymath.jl Co-authored-by: Neven Sajko --- base/abstractarraymath.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/abstractarraymath.jl b/base/abstractarraymath.jl index db16f9a6d1c0c..52dfdece31e24 100644 --- a/base/abstractarraymath.jl +++ b/base/abstractarraymath.jl @@ -158,7 +158,7 @@ function _insertdims(A::AbstractArray{T, N}, dims::Tuple{Vararg{Int64, M}}) wher issorted(dims) || throw(ArgumentError("dims=$(dims) are not sorted")) # n is the amount of the dims already inserted - ax_n = Base._foldoneto(((ds, n, dims), _) -> + ax_n = Base._foldoneto(((ds, n, dims), _) -> dims != Tuple(()) && n == first(dims) ? ((ds..., Base.OneTo(1)), n, Base.tail(dims)) : ((ds..., axes(A,n)), n+1, dims), From 16e020363167f974e302973bb42d267da893d4ff Mon Sep 17 00:00:00 2001 From: Felix Wechsler Date: Thu, 25 Jul 2024 18:24:50 +0200 Subject: [PATCH 07/26] Update base/abstractarraymath.jl Co-authored-by: Neven Sajko --- base/abstractarraymath.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/abstractarraymath.jl b/base/abstractarraymath.jl index 52dfdece31e24..55f86adb03a33 100644 --- a/base/abstractarraymath.jl +++ b/base/abstractarraymath.jl @@ -159,7 +159,7 @@ function _insertdims(A::AbstractArray{T, N}, dims::Tuple{Vararg{Int64, M}}) wher # n is the amount of the dims already inserted ax_n = Base._foldoneto(((ds, n, dims), _) -> - dims != Tuple(()) && n == first(dims) ? + dims != Tuple(()) && n == first(dims) ? ((ds..., Base.OneTo(1)), n, Base.tail(dims)) : ((ds..., axes(A,n)), n+1, dims), ((), 1, dims), Val(ndims(A) + length(dims))) From cf23193954d5cafea881a171408ebf84a7146652 Mon Sep 17 00:00:00 2001 From: Felix Wechsler Date: Thu, 25 Jul 2024 18:24:59 +0200 Subject: [PATCH 08/26] Update base/abstractarraymath.jl Co-authored-by: Neven Sajko --- base/abstractarraymath.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/abstractarraymath.jl b/base/abstractarraymath.jl index 55f86adb03a33..51a182347d33a 100644 --- a/base/abstractarraymath.jl +++ b/base/abstractarraymath.jl @@ -160,7 +160,7 @@ function _insertdims(A::AbstractArray{T, N}, dims::Tuple{Vararg{Int64, M}}) wher # n is the amount of the dims already inserted ax_n = Base._foldoneto(((ds, n, dims), _) -> dims != Tuple(()) && n == first(dims) ? - ((ds..., Base.OneTo(1)), n, Base.tail(dims)) : + ((ds..., Base.OneTo(1)), n, Base.tail(dims)) : ((ds..., axes(A,n)), n+1, dims), ((), 1, dims), Val(ndims(A) + length(dims))) # we need only the new shape and not n From 6057e227002c046201922a2bed606173ed663cae Mon Sep 17 00:00:00 2001 From: roflmaostc Date: Thu, 25 Jul 2024 18:25:40 +0200 Subject: [PATCH 09/26] Add docs --- doc/src/base/arrays.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/src/base/arrays.md b/doc/src/base/arrays.md index 9c58d80505c77..073bc6f46c5b2 100644 --- a/doc/src/base/arrays.md +++ b/doc/src/base/arrays.md @@ -136,6 +136,7 @@ Base.parentindices Base.selectdim Base.reinterpret Base.reshape +Base.insertdims Base.dropdims Base.vec Base.SubArray From 84d069328779143a7b9f3b988cd8db9152989943 Mon Sep 17 00:00:00 2001 From: Felix Wechsler Date: Thu, 25 Jul 2024 18:36:52 +0200 Subject: [PATCH 10/26] Update base/abstractarraymath.jl Co-authored-by: Neven Sajko --- base/abstractarraymath.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/base/abstractarraymath.jl b/base/abstractarraymath.jl index 51a182347d33a..92711e8b2e1a6 100644 --- a/base/abstractarraymath.jl +++ b/base/abstractarraymath.jl @@ -150,6 +150,9 @@ julia> b[1,1,1,1] = 5; a 5 2 3 4 ``` + +!!! compat "Julia 1.12" + Requires Julia 1.12 or later. """ insertdims(A; dims) = _insertdims(A, dims) function _insertdims(A::AbstractArray{T, N}, dims::Tuple{Vararg{Int64, M}}) where {T, N, M} From 8648d84f5a910344acc8573828924fb843b95639 Mon Sep 17 00:00:00 2001 From: roflmaostc Date: Thu, 25 Jul 2024 23:19:16 +0200 Subject: [PATCH 11/26] Add news --- NEWS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/NEWS.md b/NEWS.md index b842012bfc33b..c8f7189060cf8 100644 --- a/NEWS.md +++ b/NEWS.md @@ -70,6 +70,7 @@ New library functions * The new `isfull(c::Channel)` function can be used to check if `put!(c, some_value)` will block. ([#53159]) * `waitany(tasks; throw=false)` and `waitall(tasks; failfast=false, throw=false)` which wait multiple tasks at once ([#53341]). * `uuid7()` creates an RFC 9652 compliant UUID with version 7 ([#54834]). +* `insertdims(array; dims)` allows to insert singleton dimensions into an array which is the inverse operation to `dropdims` New library features -------------------- From 080c83c985249161d197de68af33b3ab96ba8402 Mon Sep 17 00:00:00 2001 From: roflmaostc Date: Fri, 26 Jul 2024 16:49:08 +0200 Subject: [PATCH 12/26] Fix merge mistake --- base/abstractarraymath.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/base/abstractarraymath.jl b/base/abstractarraymath.jl index 92711e8b2e1a6..9e8d4ce2ffd57 100644 --- a/base/abstractarraymath.jl +++ b/base/abstractarraymath.jl @@ -166,9 +166,8 @@ function _insertdims(A::AbstractArray{T, N}, dims::Tuple{Vararg{Int64, M}}) wher ((ds..., Base.OneTo(1)), n, Base.tail(dims)) : ((ds..., axes(A,n)), n+1, dims), ((), 1, dims), Val(ndims(A) + length(dims))) - # we need only the new shape and not n - reshape(A, ax_n[1]) + # we need only the new shape and not n reshape(A, ax_n[1]) end _insertdims(A::AbstractArray, dim::Integer) = _insertdims(A, (Int(dim),)) From ec383d92fea46f704c1d72c5a11db6608567ec74 Mon Sep 17 00:00:00 2001 From: roflmaostc Date: Sat, 27 Jul 2024 16:00:30 +0200 Subject: [PATCH 13/26] Rebase [skip ci] --- base/abstractarraymath.jl | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/base/abstractarraymath.jl b/base/abstractarraymath.jl index 9e8d4ce2ffd57..f0a87d4e1006b 100644 --- a/base/abstractarraymath.jl +++ b/base/abstractarraymath.jl @@ -156,19 +156,19 @@ julia> b[1,1,1,1] = 5; a """ insertdims(A; dims) = _insertdims(A, dims) function _insertdims(A::AbstractArray{T, N}, dims::Tuple{Vararg{Int64, M}}) where {T, N, M} - maximum(dims) ≤ ndims(A)+1 || throw(ArgumentError("The largest entry in dims must be ≤ ndims(A) + 1.")) + maximum(dims) ≤ N+M || throw(ArgumentError("The largest entry in dims must be not larger than the dimension of the array and the length of dims")) 1 ≤ minimum(dims) || throw(ArgumentError("The smallest entry in dims must be ≥ 1.")) - issorted(dims) || throw(ArgumentError("dims=$(dims) are not sorted")) - # n is the amount of the dims already inserted - ax_n = Base._foldoneto(((ds, n, dims), _) -> - dims != Tuple(()) && n == first(dims) ? - ((ds..., Base.OneTo(1)), n, Base.tail(dims)) : - ((ds..., axes(A,n)), n+1, dims), - ((), 1, dims), Val(ndims(A) + length(dims))) - - # we need only the new shape and not n - reshape(A, ax_n[1]) + # acc is a tuple, where the first entry is the final shape + # the second entry conists of the initial dimensions of the array but + # we chop them from the head + inds= Base._foldoneto((acc, i) -> + i ∈ dims + ? ((acc[1]..., Base.OneTo(1)), acc[2]) + : ((acc[1]..., axes(A, acc[2])), acc[2] + 1), + ((), 1), Val(N+M)) + new_shape = inds[1] + return reshape(A, new_shape) end _insertdims(A::AbstractArray, dim::Integer) = _insertdims(A, (Int(dim),)) From 66d0561f416ae0c0dec04e18898581c7325b2de5 Mon Sep 17 00:00:00 2001 From: Felix Wechsler Date: Sat, 27 Jul 2024 16:02:55 +0200 Subject: [PATCH 14/26] Update test/arrayops.jl [skip ci] Co-authored-by: Lilith Orion Hafner --- test/arrayops.jl | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/test/arrayops.jl b/test/arrayops.jl index c68c7d8d91274..63fd8adc2fc05 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -311,16 +311,30 @@ end a = rand(8, 7) @test @inferred(insertdims(a, dims=1)) == @inferred(insertdims(a, dims=(1,))) == reshape(a, (1, 8, 7)) - @test @inferred(insertdims(a, dims=(1, 3))) == reshape(a, (1, 8, 7, 1)) - @test @inferred(insertdims(a, dims=(1, 2, 3))) == reshape(a, (1, 8, 1, 7, 1)) - @test @inferred(insertdims(a, dims=(1, 1, 2, 3))) == reshape(a, (1, 1, 8, 1, 7, 1)) - @test @inferred(insertdims(a, dims=(1, 2, 2, 3))) == reshape(a, (1, 8, 1, 1, 7, 1)) - @test @inferred(insertdims(a, dims=(1, 2, 3, 3))) == reshape(a, (1, 8, 1, 7, 1, 1)) + @test @inferred(insertdims(a, dims=3)) == @inferred(insertdims(a, dims=(3,))) == reshape(a, (8, 7, 1)) + @test @inferred(insertdims(a, dims=(1, 3))) == reshape(a, (1, 8, 1, 7)) + @test @inferred(insertdims(a, dims=(1, 2, 3))) == reshape(a, (1, 1, 1, 8, 7)) + @test @inferred(insertdims(a, dims=(1, 4))) == reshape(a, (1, 8, 7, 1)) + @test @inferred(insertdims(a, dims=(1, 3, 5))) == reshape(a, (1, 8, 1, 7, 1)) + @test @inferred(insertdims(a, dims=(1, 2, 4, 6))) == reshape(a, (1, 1, 8, 1, 7, 1)) + @test @inferred(insertdims(a, dims=(1, 3, 4, 6))) == reshape(a, (1, 8, 1, 1, 7, 1)) + @test @inferred(insertdims(a, dims=(1, 3, 5, 6))) == reshape(a, (1, 8, 1, 7, 1, 1)) + + @test_throws ArgumentError insertdims(a, dims=(1, 1, 2, 3)) + @test_throws ArgumentError insertdims(a, dims=(1, 2, 2, 3)) + @test_throws ArgumentError insertdims(a, dims=(1, 2, 3, 3)) @test_throws UndefKeywordError insertdims(a) @test_throws ArgumentError insertdims(a, dims=0) @test_throws ArgumentError insertdims(a, dims=(1, 2, 1)) @test_throws ArgumentError insertdims(a, dims=4) @test_throws ArgumentError insertdims(a, dims=6) + + # insertdims and dropdims are inverses + b = rand(1,1,1,5,1,1,7) + for dims in [1, (1,), 2, (2,), 3, (3,), (1,3), (1,2,3), (1,2), (1,3,5), (1,2,5,6), (1,3,5,6), (1,3,5,6)] + @test dropdims(insertdims(a; dims); dims) == a + @test insertdims(dropdims(b; dims); dims) == a + end sz = (5,8,7) A = reshape(1:prod(sz),sz...) From bdb32580062d42701db73969bfe1267058b94cb8 Mon Sep 17 00:00:00 2001 From: Felix Wechsler Date: Sat, 27 Jul 2024 16:03:16 +0200 Subject: [PATCH 15/26] Update base/abstractarraymath.jl Co-authored-by: Lilith Orion Hafner --- base/abstractarraymath.jl | 64 +++++++++++++-------------------------- 1 file changed, 21 insertions(+), 43 deletions(-) diff --git a/base/abstractarraymath.jl b/base/abstractarraymath.jl index f0a87d4e1006b..26c23a54dd8e7 100644 --- a/base/abstractarraymath.jl +++ b/base/abstractarraymath.jl @@ -95,60 +95,38 @@ _dropdims(A::AbstractArray, dim::Integer) = _dropdims(A, (Int(dim),)) """ - insertdims(A; dims) + inserdims(A; dims) -Return an array with the same data as `A`, but with singleton dimensions specified by -`dims` inserted. -The dimensions of `A` and `dims` must be contiguous. -If dimensions occur multiple times in `dims`, several singleton dimensions are inserted. +Inverse of [`dropdims`](@ref); return an array with new singleton dimensions +at every dimension in `dims`. + +Repeated dimensions will throw. The result shares the same underlying data as `A`, such that the result is mutable if and only if `A` is mutable, and setting elements of one alters the values of the other. -See also: [`reshape`](@ref), [`dropdims`](@ref), [`vec`](@ref). - +See also: [`dropdims`](@ref), [`reshape`](@ref), [`vec`](@ref). # Examples ```jldoctest -julia> a = [1 2; 3 4] -2×2 Matrix{Int64}: - 1 2 - 3 4 - -julia> b = insertdims(a, dims=(1,1)) -1×1×2×2 Array{Int64, 4}: -[:, :, 1, 1] = - 1 - -[:, :, 2, 1] = - 3 - -[:, :, 1, 2] = - 2 - -[:, :, 2, 2] = - 4 - -julia> b = insertdims(a, dims=(1,2)) -1×2×1×2 Array{Int64, 4}: -[:, :, 1, 1] = - 1 3 - -[:, :, 1, 2] = - 2 4 +julia> x = [1 2 3; 4 5 6] +2×3 Matrix{Int64}: + 1 2 3 + 4 5 6 -julia> b = insertdims(a, dims=(1,3)) -1×2×2×1 Array{Int64, 4}: -[:, :, 1, 1] = - 1 3 +julia> insertdims(x, dims=3) +2×3×1 Array{Int64, 3}: +[:, :, 1] = + 1 2 3 + 4 5 6 -[:, :, 2, 1] = - 2 4 +julia> insertdims(x, dims=(1,2,5)) == reshape(x, 1, 1, 2, 3, 1) +true -julia> b[1,1,1,1] = 5; a -2×2 Matrix{Int64}: - 5 2 - 3 4 +julia> dropdims(insertdims(x, dims=(1,2,5)), dims=(1,2,5)) +2×3 Matrix{Int64}: + 1 2 3 + 4 5 6 ``` !!! compat "Julia 1.12" From 0ddee55832b39752c1dbca8263d9796ec461b103 Mon Sep 17 00:00:00 2001 From: roflmaostc Date: Sat, 27 Jul 2024 16:04:16 +0200 Subject: [PATCH 16/26] Update comment in code [skip ci] --- base/abstractarraymath.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/base/abstractarraymath.jl b/base/abstractarraymath.jl index 26c23a54dd8e7..83b7a4ee08409 100644 --- a/base/abstractarraymath.jl +++ b/base/abstractarraymath.jl @@ -138,8 +138,7 @@ function _insertdims(A::AbstractArray{T, N}, dims::Tuple{Vararg{Int64, M}}) wher 1 ≤ minimum(dims) || throw(ArgumentError("The smallest entry in dims must be ≥ 1.")) # acc is a tuple, where the first entry is the final shape - # the second entry conists of the initial dimensions of the array but - # we chop them from the head + # the second entry off acc is a counter for the axes of A inds= Base._foldoneto((acc, i) -> i ∈ dims ? ((acc[1]..., Base.OneTo(1)), acc[2]) From 76b31f7f2772af940b5e0996e28f245abee9007a Mon Sep 17 00:00:00 2001 From: roflmaostc Date: Sat, 27 Jul 2024 16:06:48 +0200 Subject: [PATCH 17/26] Remove parts in docstring [skip ci] --- base/abstractarraymath.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/base/abstractarraymath.jl b/base/abstractarraymath.jl index 83b7a4ee08409..b6dd21c0346d3 100644 --- a/base/abstractarraymath.jl +++ b/base/abstractarraymath.jl @@ -100,7 +100,6 @@ _dropdims(A::AbstractArray, dim::Integer) = _dropdims(A, (Int(dim),)) Inverse of [`dropdims`](@ref); return an array with new singleton dimensions at every dimension in `dims`. -Repeated dimensions will throw. The result shares the same underlying data as `A`, such that the result is mutable if and only if `A` is mutable, and setting elements of one From 490b103cc66e902bd4a90bc15963d07f289107dc Mon Sep 17 00:00:00 2001 From: roflmaostc Date: Sat, 27 Jul 2024 16:22:55 +0200 Subject: [PATCH 18/26] Adapt docstring --- base/abstractarraymath.jl | 11 +++++++++-- test/arrayops.jl | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/base/abstractarraymath.jl b/base/abstractarraymath.jl index b6dd21c0346d3..36976f22fae9e 100644 --- a/base/abstractarraymath.jl +++ b/base/abstractarraymath.jl @@ -100,6 +100,8 @@ _dropdims(A::AbstractArray, dim::Integer) = _dropdims(A, (Int(dim),)) Inverse of [`dropdims`](@ref); return an array with new singleton dimensions at every dimension in `dims`. +Repeated dimensions are forbidden and the largest entry in `dims` must be +smaller than the dimensionality of the array and the length of `dims` together. The result shares the same underlying data as `A`, such that the result is mutable if and only if `A` is mutable, and setting elements of one @@ -133,8 +135,13 @@ julia> dropdims(insertdims(x, dims=(1,2,5)), dims=(1,2,5)) """ insertdims(A; dims) = _insertdims(A, dims) function _insertdims(A::AbstractArray{T, N}, dims::Tuple{Vararg{Int64, M}}) where {T, N, M} - maximum(dims) ≤ N+M || throw(ArgumentError("The largest entry in dims must be not larger than the dimension of the array and the length of dims")) - 1 ≤ minimum(dims) || throw(ArgumentError("The smallest entry in dims must be ≥ 1.")) + for i in eachindex(dims) + 1 ≤ dims[i] || throw(ArgumentError("the smallest entry in dims must be ≥ 1.")) + dims[i] ≤ N+M || throw(ArgumentError("the largest entry in dims must be not larger than the dimension of the array and the length of dims added")) + for j = 1:i-1 + dims[j] == dims[i] && throw(ArgumentError("inserted dims must be unique")) + end + end # acc is a tuple, where the first entry is the final shape # the second entry off acc is a counter for the axes of A diff --git a/test/arrayops.jl b/test/arrayops.jl index 63fd8adc2fc05..aa2efaba94d10 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -333,7 +333,7 @@ end b = rand(1,1,1,5,1,1,7) for dims in [1, (1,), 2, (2,), 3, (3,), (1,3), (1,2,3), (1,2), (1,3,5), (1,2,5,6), (1,3,5,6), (1,3,5,6)] @test dropdims(insertdims(a; dims); dims) == a - @test insertdims(dropdims(b; dims); dims) == a + @test insertdims(dropdims(b; dims); dims) == b end sz = (5,8,7) From 98283db41d91a7ae4aa9d312d3ea89cfbaac7e85 Mon Sep 17 00:00:00 2001 From: roflmaostc Date: Sat, 27 Jul 2024 20:04:26 +0200 Subject: [PATCH 19/26] Remove trailing whitespace --- base/abstractarraymath.jl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/base/abstractarraymath.jl b/base/abstractarraymath.jl index 36976f22fae9e..1a334c1db8ea3 100644 --- a/base/abstractarraymath.jl +++ b/base/abstractarraymath.jl @@ -100,7 +100,7 @@ _dropdims(A::AbstractArray, dim::Integer) = _dropdims(A, (Int(dim),)) Inverse of [`dropdims`](@ref); return an array with new singleton dimensions at every dimension in `dims`. -Repeated dimensions are forbidden and the largest entry in `dims` must be +Repeated dimensions are forbidden and the largest entry in `dims` must be smaller than the dimensionality of the array and the length of `dims` together. The result shares the same underlying data as `A`, such that the @@ -144,11 +144,11 @@ function _insertdims(A::AbstractArray{T, N}, dims::Tuple{Vararg{Int64, M}}) wher end # acc is a tuple, where the first entry is the final shape - # the second entry off acc is a counter for the axes of A - inds= Base._foldoneto((acc, i) -> - i ∈ dims - ? ((acc[1]..., Base.OneTo(1)), acc[2]) - : ((acc[1]..., axes(A, acc[2])), acc[2] + 1), + # the second entry off acc is a counter for the axes of A + inds= Base._foldoneto((acc, i) -> + i ∈ dims + ? ((acc[1]..., Base.OneTo(1)), acc[2]) + : ((acc[1]..., axes(A, acc[2])), acc[2] + 1), ((), 1), Val(N+M)) new_shape = inds[1] return reshape(A, new_shape) From c321d510dd033d7e54f6a4c095b191e96aa9d847 Mon Sep 17 00:00:00 2001 From: roflmaostc Date: Sat, 27 Jul 2024 20:18:18 +0200 Subject: [PATCH 20/26] Remove trailing whitespace in test [skip ci] --- test/arrayops.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/arrayops.jl b/test/arrayops.jl index aa2efaba94d10..358c1e3231e50 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -328,7 +328,7 @@ end @test_throws ArgumentError insertdims(a, dims=(1, 2, 1)) @test_throws ArgumentError insertdims(a, dims=4) @test_throws ArgumentError insertdims(a, dims=6) - + # insertdims and dropdims are inverses b = rand(1,1,1,5,1,1,7) for dims in [1, (1,), 2, (2,), 3, (3,), (1,3), (1,2,3), (1,2), (1,3,5), (1,2,5,6), (1,3,5,6), (1,3,5,6)] From 2a9e3ac2c8f4b8b2eab994901d8ee581a0573b4e Mon Sep 17 00:00:00 2001 From: Felix Wechsler Date: Sat, 27 Jul 2024 21:14:58 +0200 Subject: [PATCH 21/26] Update base/abstractarraymath.jl [skip ci] Co-authored-by: Lilith Orion Hafner --- base/abstractarraymath.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/abstractarraymath.jl b/base/abstractarraymath.jl index 1a334c1db8ea3..987f21d835e16 100644 --- a/base/abstractarraymath.jl +++ b/base/abstractarraymath.jl @@ -95,7 +95,7 @@ _dropdims(A::AbstractArray, dim::Integer) = _dropdims(A, (Int(dim),)) """ - inserdims(A; dims) + insertdims(A; dims) Inverse of [`dropdims`](@ref); return an array with new singleton dimensions at every dimension in `dims`. From d7cb35c9ffaeabc9b801d4c9997667fd92fca269 Mon Sep 17 00:00:00 2001 From: roflmaostc Date: Sat, 27 Jul 2024 21:21:28 +0200 Subject: [PATCH 22/26] Rewrite doc [skip ci] --- base/abstractarraymath.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/abstractarraymath.jl b/base/abstractarraymath.jl index 987f21d835e16..fe151c1410d00 100644 --- a/base/abstractarraymath.jl +++ b/base/abstractarraymath.jl @@ -101,7 +101,7 @@ Inverse of [`dropdims`](@ref); return an array with new singleton dimensions at every dimension in `dims`. Repeated dimensions are forbidden and the largest entry in `dims` must be -smaller than the dimensionality of the array and the length of `dims` together. +less than or equal than `ndims(A) + length(dims)`. The result shares the same underlying data as `A`, such that the result is mutable if and only if `A` is mutable, and setting elements of one From 514b4fc4ec364964bbbffc7c63592c13357c5cf1 Mon Sep 17 00:00:00 2001 From: Felix Wechsler Date: Thu, 1 Aug 2024 17:18:19 +0200 Subject: [PATCH 23/26] Update test/arrayops.jl Co-authored-by: Lilith Orion Hafner --- test/arrayops.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/test/arrayops.jl b/test/arrayops.jl index 358c1e3231e50..14409ffef100a 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -318,6 +318,7 @@ end @test @inferred(insertdims(a, dims=(1, 3, 5))) == reshape(a, (1, 8, 1, 7, 1)) @test @inferred(insertdims(a, dims=(1, 2, 4, 6))) == reshape(a, (1, 1, 8, 1, 7, 1)) @test @inferred(insertdims(a, dims=(1, 3, 4, 6))) == reshape(a, (1, 8, 1, 1, 7, 1)) + @test @inferred(insertdims(a, dims=(1, 4, 6, 3))) == reshape(a, (1, 8, 1, 1, 7, 1)) @test @inferred(insertdims(a, dims=(1, 3, 5, 6))) == reshape(a, (1, 8, 1, 7, 1, 1)) @test_throws ArgumentError insertdims(a, dims=(1, 1, 2, 3)) From 4f07e18c94be3a29dc4debdc32c1d7db697708c4 Mon Sep 17 00:00:00 2001 From: Felix Wechsler Date: Thu, 1 Aug 2024 17:18:47 +0200 Subject: [PATCH 24/26] Update test/arrayops.jl Co-authored-by: Lilith Orion Hafner --- test/arrayops.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/arrayops.jl b/test/arrayops.jl index 14409ffef100a..1b81a3e315727 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -332,7 +332,7 @@ end # insertdims and dropdims are inverses b = rand(1,1,1,5,1,1,7) - for dims in [1, (1,), 2, (2,), 3, (3,), (1,3), (1,2,3), (1,2), (1,3,5), (1,2,5,6), (1,3,5,6), (1,3,5,6)] + for dims in [1, (1,), 2, (2,), 3, (3,), (1,3), (1,2,3), (1,2), (1,3,5), (1,2,5,6), (1,3,5,6), (1,3,5,6), (1,6,5,3)] @test dropdims(insertdims(a; dims); dims) == a @test insertdims(dropdims(b; dims); dims) == b end From cfa1465f201cff00059e37fc6b82553ba1fd0414 Mon Sep 17 00:00:00 2001 From: Felix Wechsler Date: Thu, 1 Aug 2024 17:18:59 +0200 Subject: [PATCH 25/26] Update base/abstractarraymath.jl Co-authored-by: Lilith Orion Hafner --- base/abstractarraymath.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/abstractarraymath.jl b/base/abstractarraymath.jl index fe151c1410d00..dd45c3f6120bc 100644 --- a/base/abstractarraymath.jl +++ b/base/abstractarraymath.jl @@ -134,7 +134,7 @@ julia> dropdims(insertdims(x, dims=(1,2,5)), dims=(1,2,5)) Requires Julia 1.12 or later. """ insertdims(A; dims) = _insertdims(A, dims) -function _insertdims(A::AbstractArray{T, N}, dims::Tuple{Vararg{Int64, M}}) where {T, N, M} +function _insertdims(A::AbstractArray{T, N}, dims::NTuple{M, Int}}) where {T, N, M} for i in eachindex(dims) 1 ≤ dims[i] || throw(ArgumentError("the smallest entry in dims must be ≥ 1.")) dims[i] ≤ N+M || throw(ArgumentError("the largest entry in dims must be not larger than the dimension of the array and the length of dims added")) From 9f174b7c84fd0aec2f79518ad8122d36487919b5 Mon Sep 17 00:00:00 2001 From: Felix Wechsler Date: Thu, 1 Aug 2024 18:18:06 +0200 Subject: [PATCH 26/26] Update base/abstractarraymath.jl Co-authored-by: Mark Kittisopikul --- base/abstractarraymath.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/abstractarraymath.jl b/base/abstractarraymath.jl index dd45c3f6120bc..0f028a0f66729 100644 --- a/base/abstractarraymath.jl +++ b/base/abstractarraymath.jl @@ -134,7 +134,7 @@ julia> dropdims(insertdims(x, dims=(1,2,5)), dims=(1,2,5)) Requires Julia 1.12 or later. """ insertdims(A; dims) = _insertdims(A, dims) -function _insertdims(A::AbstractArray{T, N}, dims::NTuple{M, Int}}) where {T, N, M} +function _insertdims(A::AbstractArray{T, N}, dims::NTuple{M, Int}) where {T, N, M} for i in eachindex(dims) 1 ≤ dims[i] || throw(ArgumentError("the smallest entry in dims must be ≥ 1.")) dims[i] ≤ N+M || throw(ArgumentError("the largest entry in dims must be not larger than the dimension of the array and the length of dims added"))