# Multiply each slice of an array by a different number

**URL:** <https://discourse.julialang.org/t/multiply-each-slice-of-an-array-by-a-different-number/32501>\
**Category:** General Usage\
**Created:** [December 20, 2019, 7:28am UTC](https://discourse.julialang.org/t/multiply-each-slice-of-an-array-by-a-different-number/32501 "2019-12-20T07:28:48Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![jw3126](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jw3126/32/3086_2.png) [@jw3126](https://discourse.julialang.org/u/jw3126)\
**Post date:** [December 20, 2019, 7:28am UTC](https://discourse.julialang.org/t/multiply-each-slice-of-an-array-by-a-different-number/32501/1 "2019-12-20T07:28:48Z")

</div>

I want to multiply each slice of an array by a different number. I want to do it for arbitrary array and slice dimensions, inplace and efficient if possible. How to do this? Here is an example:

Multipy each row of a matrix by a different number:

```julia
function multiply_slices!(A, v; dims)
    # only one special case implemented
    @assert dims == 2
    @assert ndims(A) == 2
    @assert ndims(v) == 1
    
    @assert axes(A, 1) == axes(v,1)
    @inbounds @simd for j in axes(A, 2)
        for i in axes(A, 1)
            A[i, j] *= v[i]
        end
    end
    A
end

nrows = 2
ncols = 3
A = collect(reshape(1:(nrows*ncols), (nrows, ncols)))
v = 1:nrows
multiply_slices!(A, v)

```

---

<div class="post-metadata">

**Author:** ![tkf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkf/32/17635_2.png) [@tkf](https://discourse.julialang.org/u/tkf)\
**Post date:** [December 20, 2019, 8:02am UTC](https://discourse.julialang.org/t/multiply-each-slice-of-an-array-by-a-different-number/32501/2 "2019-12-20T08:02:42Z")

</div>

Does this work?

```julia
using LazyArrays: @~

function multiply_slices!(A, v; dims)
    select1 = ntuple(i -> i in dims ? axes(A, i) : Ref(:), ndims(A))
    select2 = ntuple(i -> i in dims ? axes(v, i) : Ref(:), ndims(v))
    RefA = Ref(A)
    Refv = Ref(v)
    slices = @~ tuple.(view.(RefA, select1...), view.(Refv, select2...))
    for (x, y) in slices
        x .*= y
    end
    return A
end

```

---

<div class="post-metadata">

**Author:** ![jw3126](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jw3126/32/3086_2.png) [@jw3126](https://discourse.julialang.org/u/jw3126)\
**Post date:** [December 20, 2019, 8:17am UTC](https://discourse.julialang.org/t/multiply-each-slice-of-an-array-by-a-different-number/32501/3 "2019-12-20T08:17:14Z")

</div>

Thanks! This does look good. It is not as fast as the hand coded variant, but fast enough for my use case. It can be made a little faster by adding a function barrier.

```julia
using LazyArrays: @~

function multiply_slices_hand!(A, v; dims)
    # only one special case implemented
    @assert dims == 2
    @assert ndims(A) == 2
    @assert ndims(v) == 1
    
    @assert axes(A, 1) == axes(v,1)
    @inbounds @simd for j in axes(A, 2)
        for i in axes(A, 1)
            A[i, j] *= v[i]
        end
    end
    A
end

function multiply_slices_lazy!(A, v; dims)
    select1 = ntuple(i -> i in dims ? axes(A, i) : Ref(:), ndims(A))
    select2 = ntuple(i -> i in dims ? axes(v, i) : Ref(:), ndims(v))
    RefA = Ref(A)
    Refv = Ref(v)
    # @show select1
    # @show select2
    slices = @~ tuple.(view.(RefA, select1...), view.(Refv, select2...))
    for (x, y) in slices
        x .*= y
    end
    return A
end

function multiply_slices_barrier!(A, v; dims)
    select1 = ntuple(i -> i in dims ? axes(A, i) : Ref(:), ndims(A))
    select2 = ntuple(i -> i in dims ? axes(v, i) : Ref(:), ndims(v))
    RefA = Ref(A)
    Refv = Ref(v)
    # @show select1
    # @show select2
    slices = @~ tuple.(view.(RefA, select1...), view.(Refv, select2...))
    kernel!(slices)
    return A
end
@noinline function kernel!(slices)
    for (x, y) in slices
        x .*= y
    end
end

using BenchmarkTools
nrows = 100
ncols = 2000
A = randn(nrows, ncols)
v = randn(nrows)
@btime multiply_slices_hand!(A, v, dims=2)
@btime multiply_slices_lazy!(A, v, dims=2)
@btime multiply_slices_barrier!(A, v, dims=2)

```

```julia
  1.423 ms (1 allocation: 16 bytes)
  3.376 ms (18013 allocations: 594.00 KiB)
  2.095 ms (4013 allocations: 187.75 KiB)

```

---

<div class="post-metadata">

**Author:** ![tkf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkf/32/17635_2.png) [@tkf](https://discourse.julialang.org/u/tkf)\
**Post date:** [December 20, 2019, 8:29am UTC](https://discourse.julialang.org/t/multiply-each-slice-of-an-array-by-a-different-number/32501/4 "2019-12-20T08:29:40Z")

</div>

> [@jw3126](#):
>
> adding a function barrier

That’s a good idea!

But, actually, I think the slowness might be coming from overflow/underflow. I think it’s better to use `setup` here.

```julia
@btime multiply_slices_hand!(A, v, dims=2) setup=(A = randn(nrows, ncols))
@btime multiply_slices_lazy!(A, v, dims=2) setup=(A = randn(nrows, ncols))
@btime multiply_slices_barrier!(A, v, dims=2) setup=(A = randn(nrows, ncols))

```

gives me

```julia
  65.471 μs (1 allocation: 16 bytes)
  1.423 ms (18013 allocations: 594.00 KiB)
  155.574 μs (4013 allocations: 187.75 KiB)

```

…so 2+ times slower than hand-coded version… (But we can observe that the function barrier does a great job here.)

---

<div class="post-metadata">

**Author:** ![jw3126](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jw3126/32/3086_2.png) [@jw3126](https://discourse.julialang.org/u/jw3126)\
**Post date:** [December 20, 2019, 8:36am UTC](https://discourse.julialang.org/t/multiply-each-slice-of-an-array-by-a-different-number/32501/5 "2019-12-20T08:36:52Z")

</div>

> [@tkf](#):
>
> But, actually, I think the slowness might be coming from overflow/underflow. I think it’s better to use `setup` here.

Thanks! I can see that my above timings are far too long and that your timings are much more reasonable. But I don’t understand what slowness from underflow/overflow is. Can you explain?

---

<div class="post-metadata">

**Author:** ![tkf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkf/32/17635_2.png) [@tkf](https://discourse.julialang.org/u/tkf)\
**Post date:** [December 20, 2019, 8:44am UTC](https://discourse.julialang.org/t/multiply-each-slice-of-an-array-by-a-different-number/32501/6 "2019-12-20T08:44:18Z")

</div>

My guess was that the slowness was due to [denormals (Wikipedia)](https://en.wikipedia.org/wiki/Denormal_number) since you are keep multiplying by some numbers (and many of them are smaller than one).

```julia
using BenchmarkTools
n = 2^15
@btime x .*= 0.5 setup = (x = ones(n))
@btime x .*= 0.5 setup = (x = nextfloat.(zeros(n)))

```

prints

```julia
  3.851 μs (0 allocations: 0 bytes)
  42.459 μs (0 allocations: 0 bytes)

```

---

<div class="post-metadata">

**Author:** ![jw3126](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jw3126/32/3086_2.png) [@jw3126](https://discourse.julialang.org/u/jw3126)\
**Post date:** [December 20, 2019, 8:54am UTC](https://discourse.julialang.org/t/multiply-each-slice-of-an-array-by-a-different-number/32501/7 "2019-12-20T08:54:42Z")

</div>

Makes perfect sense and frightenly makes a lot of benchmarks I did questionable.

---

<div class="post-metadata">

**Author:** ![tkf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkf/32/17635_2.png) [@tkf](https://discourse.julialang.org/u/tkf)\
**Post date:** [December 20, 2019, 9:05am UTC](https://discourse.julialang.org/t/multiply-each-slice-of-an-array-by-a-different-number/32501/8 "2019-12-20T09:05:59Z")

</div>

Yea, benchmark is hard…

BTW, in Julia 1.4.0-DEV.634, the broadcast-based version is much closer to the hand-coded version:

```julia
  63.656 μs (1 allocation: 16 bytes) # multiply_slices_hand!
  82.218 μs (2013 allocations: 94.00 KiB) # multiply_slices_barrier!

```
