# \[ANN\] ArrayPadding.jl - periodic, symmetric, smooth or constants padding

**URL:** <https://discourse.julialang.org/t/ann-arraypadding-jl-periodic-symmetric-smooth-or-constants-padding/104403>\
**Category:** Package Announcements\
**Tags:** package, announcement\
**Created:** [September 29, 2023, 4:43pm UTC](https://discourse.julialang.org/t/ann-arraypadding-jl-periodic-symmetric-smooth-or-constants-padding/104403 "2023-09-29T16:43:30Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![pxshen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pxshen/32/38776_2.png) [@pxshen](https://discourse.julialang.org/u/pxshen)\
**Post date:** [September 29, 2023, 4:43pm UTC](https://discourse.julialang.org/t/ann-arraypadding-jl-periodic-symmetric-smooth-or-constants-padding/104403/1 "2023-09-29T16:43:30Z")

</div>

[ArrayPadding.jl](https://github.com/paulxshen/ArrayPadding.jl) Pads arrays of any dimension with various border options including constants, periodic, symmetric, mirror and smooth. Can control amount of padding applied to the left and right side of each dimension. Fully differentiable (compatible with `Zygote.jl` `Flux.jl` )

---

<div class="post-metadata">

**Author:** ![tbeason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tbeason/32/15898_2.png) [@tbeason](https://discourse.julialang.org/u/tbeason)\
**Post date:** [September 29, 2023, 4:46pm UTC](https://discourse.julialang.org/t/ann-arraypadding-jl-periodic-symmetric-smooth-or-constants-padding/104403/2 "2023-09-29T16:46:50Z")

</div>

Is your approach more performant or more flexible than [GitHub - JuliaArrays/PaddedViews.jl: Add virtual padding to the edges of an array](https://github.com/JuliaArrays/PaddedViews.jl)?

---

<div class="post-metadata">

**Author:** ![pxshen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pxshen/32/38776_2.png) [@pxshen](https://discourse.julialang.org/u/pxshen)\
**Post date:** [September 29, 2023, 4:48pm UTC](https://discourse.julialang.org/t/ann-arraypadding-jl-periodic-symmetric-smooth-or-constants-padding/104403/3 "2023-09-29T16:48:13Z")

</div>

PaddedViews.jl only supports padding of constants TMK

---

<div class="post-metadata">

**Author:** ![RoyiAvital](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/royiavital/32/571_2.png) [@RoyiAvital](https://discourse.julialang.org/u/RoyiAvital)\
**Post date:** [September 29, 2023, 5:12pm UTC](https://discourse.julialang.org/t/ann-arraypadding-jl-periodic-symmetric-smooth-or-constants-padding/104403/4 "2023-09-29T17:12:37Z")

</div>

Your current approach creates a new array.  
I wonder if you can add a feature to have a view of the data.

A bigger challenge, if possible, to have such view with no run time overhead.

---

<div class="post-metadata">

**Author:** ![pxshen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pxshen/32/38776_2.png) [@pxshen](https://discourse.julialang.org/u/pxshen)\
**Post date:** [September 29, 2023, 10:21pm UTC](https://discourse.julialang.org/t/ann-arraypadding-jl-periodic-symmetric-smooth-or-constants-padding/104403/5 "2023-09-29T22:21:26Z")

</div>

Yeah it’s tricky doing virtual padding for non-constant border options. There’s always PaddedViews.jl for virtual padding constants. Also a key goal is being fully differentiable (with Zygote.jl Flux.jl) and GPU compatible - so virtual indexing was deemed too much trouble vs a clean eager implementation.

As a suggestion, we call `Base.cat` which potentially can be modified to virtually concatenate arrays instead of allocating memory - probably cleanest way to do virtual indexing

---

<div class="post-metadata">

**Author:** ![RoyiAvital](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/royiavital/32/571_2.png) [@RoyiAvital](https://discourse.julialang.org/u/RoyiAvital)\
**Post date:** [September 30, 2023, 2:37pm UTC](https://discourse.julialang.org/t/ann-arraypadding-jl-periodic-symmetric-smooth-or-constants-padding/104403/6 "2023-09-30T14:37:19Z")

</div>

> [@pxshen](#):
>
> As a suggestion, we call `Base.cat` which potentially can be modified to virtually concatenate arrays instead of allocating memory - probably cleanest way to do virtual indexing

Could you elaborate?

Also, I didn’t see the option to have inplace functionality.  
Namely given a pre allocated buffer to use.

---

<div class="post-metadata">

**Author:** ![pxshen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pxshen/32/38776_2.png) [@pxshen](https://discourse.julialang.org/u/pxshen)\
**Post date:** [September 30, 2023, 8:57pm UTC](https://discourse.julialang.org/t/ann-arraypadding-jl-periodic-symmetric-smooth-or-constants-padding/104403/7 "2023-09-30T20:57:33Z")

</div>

malloc in my pkg results from calling `Base.cat` of the original array and its sliced views. If `cat` were lazy, then my pkg wouldn’t alloc new array. I think `LazyArrays.jl` has lazy `vcat` `hcat` but not `cat` in general unless I’m mistaken. A lazy non-allocating version of `cat` might benefit other folks too

---

<div class="post-metadata">

**Author:** ![cirobr](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cirobr/32/219994_2.png) [@cirobr](https://discourse.julialang.org/u/cirobr)\
**Post date:** [October 15, 2023, 12:40am UTC](https://discourse.julialang.org/t/ann-arraypadding-jl-periodic-symmetric-smooth-or-constants-padding/104403/8 "2023-10-15T00:40:05Z")

</div>

@pxshen Thanks for creating the package, it indeed fulfills the gap from PaddedViews.jl. Have tried mirror padding size (1,1) as follows, and it worked as expected. Size (2,2) apparently failed, as I expected a 9x9 matrix output, but function returned same 5x5 matrix:

```julia
julia> a = reshape(1:25, (5,5))
5×5 reshape(::UnitRange{Int64}, 5, 5) with eltype Int64:
 1 6 11 16 21
 2 7 12 17 22
 3 8 13 18 23
 4 9 14 19 24
 5 10 15 20 25

julia> pad(a, :mirror, (1,1))
7×7 Matrix{Int64}:
  7 2 7 12 17 22 17
  6 1 6 11 16 21 16
  7 2 7 12 17 22 17
  8 3 8 13 18 23 18
  9 4 9 14 19 24 19
 10 5 10 15 20 25 20
  9 4 9 14 19 24 19

julia> pad(a, :mirror, (2,2))
5×5 Matrix{Int64}:
 1 6 11 16 21
 2 7 12 17 22
 3 8 13 18 23
 4 9 14 19 24
 5 10 15 20 25

```

Would appreciate your advise. Thanks.

---

<div class="post-metadata">

**Author:** ![pxshen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pxshen/32/38776_2.png) [@pxshen](https://discourse.julialang.org/u/pxshen)\
**Post date:** [October 15, 2023, 4:52am UTC](https://discourse.julialang.org/t/ann-arraypadding-jl-periodic-symmetric-smooth-or-constants-padding/104403/9 "2023-10-15T04:52:39Z")

</div>

Thanks for finding bug for mirror and symmetric - fixed and pushed - might take few hours to update on general registry. Also if there’s enough need I can make the package non-allocating / virtually indexed.

---

<div class="post-metadata">

**Author:** ![RoyiAvital](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/royiavital/32/571_2.png) [@RoyiAvital](https://discourse.julialang.org/u/RoyiAvital)\
**Post date:** [October 16, 2023, 8:53am UTC](https://discourse.julialang.org/t/ann-arraypadding-jl-periodic-symmetric-smooth-or-constants-padding/104403/10 "2023-10-16T08:53:06Z")

</div>

> [@pxshen](#):
>
> Also if there’s enough need I can make the package non-allocating / virtually indexed.

A virtual / non allocating mode would be great.  
So the user can chose.

I wonder if it also can be done with no overhead for the elements which are not in the boundary.

---

<div class="post-metadata">

**Author:** ![pxshen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pxshen/32/38776_2.png) [@pxshen](https://discourse.julialang.org/u/pxshen)\
**Post date:** [October 18, 2023, 12:20am UTC](https://discourse.julialang.org/t/ann-arraypadding-jl-periodic-symmetric-smooth-or-constants-padding/104403/11 "2023-10-18T00:20:11Z")

</div>

`pad` now takes `lazy=true` for non-allocating virtually indexed result. It uses `LazyArrays.jl` so only up to 2d arrays are supported in lazy mode. I think there’s minor indexing overhead

Also added `:replicate` border option

---

<div class="post-metadata">

**Author:** ![pxshen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pxshen/32/38776_2.png) [@pxshen](https://discourse.julialang.org/u/pxshen)\
**Post date:** [December 21, 2023, 2:50am UTC](https://discourse.julialang.org/t/ann-arraypadding-jl-periodic-symmetric-smooth-or-constants-padding/104403/12 "2023-12-21T02:50:48Z")

</div>

Lazy mode (using LazyArrays.jl underneath) doesn’t work with Zygote.jl autodiff. I’ll try fixing this

---

<div class="post-metadata">

**Author:** ![pxshen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pxshen/32/38776_2.png) [@pxshen](https://discourse.julialang.org/u/pxshen)\
**Post date:** [February 18, 2024, 10:56pm UTC](https://discourse.julialang.org/t/ann-arraypadding-jl-periodic-symmetric-smooth-or-constants-padding/104403/13 "2024-02-18T22:56:20Z")

</div>

Actually I think the cleanest way to avoid both allocation and indexing overhead is to preallocate the bigger array as has been mentioned by Roy. For that I added `pad!` which pads inwards and mutates original array in place. docs updated. the effective border is set back by the padding amount when evaluating various border options. It’s still AD (automatic differentiation) compatible thru `Zygote.bufferfrom` internally

---

<div class="post-metadata">

**Author:** ![pxshen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pxshen/32/38776_2.png) [@pxshen](https://discourse.julialang.org/u/pxshen)\
**Post date:** [February 21, 2024, 10:52pm UTC](https://discourse.julialang.org/t/ann-arraypadding-jl-periodic-symmetric-smooth-or-constants-padding/104403/14 "2024-02-21T22:52:33Z")

</div>

Sorry - for mutating `pad!` , `Zygote.gradient` is wrong - will get fixed this wk

---

<div class="post-metadata">

**Author:** ![pxshen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pxshen/32/38776_2.png) [@pxshen](https://discourse.julialang.org/u/pxshen)\
**Post date:** [February 26, 2024, 9:56pm UTC](https://discourse.julialang.org/t/ann-arraypadding-jl-periodic-symmetric-smooth-or-constants-padding/104403/15 "2024-02-26T21:56:54Z")

</div>

For `pad!` I decided to let user allocate `Zygote.Buffer` if AD is needed (see Github page for example). This is an extra allocation to track mutations. `pad!` doesn’t malloc otherwise

---

<div class="post-metadata">

**Author:** ![Salmon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/salmon/32/22968_2.png) [@Salmon](https://discourse.julialang.org/u/Salmon)\
**Post date:** [February 27, 2024, 10:53am UTC](https://discourse.julialang.org/t/ann-arraypadding-jl-periodic-symmetric-smooth-or-constants-padding/104403/16 "2024-02-27T10:53:53Z")

</div>

A few design questions:  
Any reason behind the choice to make `PaddedArray` not a subtype of `AbstractArray`? Also why is not not a parametric struct?  
I.e. why do you define it to be

```julia
struct PaddedArray
    a
    l
    r
    function PaddedArray(a, l=left(a), r=right(a))
        new(a, l, r)
    end
end

```

instead of

```julia
struct PaddedArray{T,N,ArrayType} <: AbstractArray{T,N}
    a::ArrayType
    l::Vector{Int}
    r::Vector{Int}
    function PaddedArray(a::A, l=left(a), r=right(a)) where {T,N,A <: AbstractArray{T,N}}
        new{T,N,A}(a, l, r)
    end
end

```

or something along those lines?

---

<div class="post-metadata">

**Author:** ![pxshen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pxshen/32/38776_2.png) [@pxshen](https://discourse.julialang.org/u/pxshen)\
**Post date:** [February 27, 2024, 12:39pm UTC](https://discourse.julialang.org/t/ann-arraypadding-jl-periodic-symmetric-smooth-or-constants-padding/104403/17 "2024-02-27T12:39:53Z")

</div>

Thanks `PaddedArray` is actually a private type that I use to track the amount of padding in some experiments but it’s not used by other functions and shouldn’t have been exported. Your version is the right way - it’s just that parametric types mess up `Zygote` sometimes causing "need custom adjoints " errors

---

<div class="post-metadata">

**Author:** ![Salmon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/salmon/32/22968_2.png) [@Salmon](https://discourse.julialang.org/u/Salmon)\
**Post date:** [February 27, 2024, 1:57pm UTC](https://discourse.julialang.org/t/ann-arraypadding-jl-periodic-symmetric-smooth-or-constants-padding/104403/18 "2024-02-27T13:57:07Z")

</div>

ah ok, I see now that `pad` just returns a regular Julia array! That makes sense
