# Efficient multiplication between a low-rank matrix approximation and a vector

**URL:** https://discourse.julialang.org/t/efficient-multiplication-between-a-low-rank-matrix-approximation-and-a-vector/100512
**Category:** General Usage
**Tags:** question
**Created:** [June 18, 2023, 12:24pm UTC](https://discourse.julialang.org/t/efficient-multiplication-between-a-low-rank-matrix-approximation-and-a-vector/100512 "2023-06-18T12:24:57Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![danieleavitabile](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/danieleavitabile/32/31966_2.png) [@danieleavitabile](https://discourse.julialang.org/u/danieleavitabile)
#### Post date: [June 18, 2023, 12:24pm UTC](https://discourse.julialang.org/t/efficient-multiplication-between-a-low-rank-matrix-approximation-and-a-vector/100512/1 "2023-06-18T12:24:57Z")

</div>

Dear All,

I am quite new to Julia, and I am searching for a recommendation. Calling `svd(A)`, I obtain a singular-value decomposition object that gives me access to the `U, S, V`, as discussed in the [documentation](https://docs.julialang.org/en/v1/stdlib/LinearAlgebra/#LinearAlgebra.svd).

I am interested in approximating the matrix-vector product `A*z`, where `z` is a vector, by approximating `A` with its k-rank approximation. A direct way to do this is to do

```julia
Ak = U[:,1:k] * Diagonal(S[1:k]) * V[:,1:k]'
w = Ak*z

```

but this does not seem a good idea, because `Ak` has the same size of the original matrix, and this does not buy me anything. A possible alternative is

`w = U[:,1:k] * Diagonal(S[1:k]) * V[:,1:k]' * z`

Of course, one can also write a specific for loop that accomplishes that. I am interested in knowing if there are off-the-shelves solutions for this (that use the SVD object created by `svd`), and if you see ways to write the most efficient

---

<div class="post-metadata">

### Author: ![mohamed82008](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mohamed82008/32/18171_2.png) [@mohamed82008](https://discourse.julialang.org/u/mohamed82008)
#### Post date: [June 18, 2023, 12:37pm UTC](https://discourse.julialang.org/t/efficient-multiplication-between-a-low-rank-matrix-approximation-and-a-vector/100512/2 "2023-06-18T12:37:38Z")

</div>

Look at [GitHub - JuliaArrays/LazyArrays.jl: Lazy arrays and linear algebra in Julia](https://github.com/JuliaArrays/LazyArrays.jl).

Edit: or better [GitHub - JuliaLinearAlgebra/LowRankApprox.jl: Fast low-rank matrix approximation in Julia](https://github.com/JuliaLinearAlgebra/LowRankApprox.jl)

---

<div class="post-metadata">

### Author: ![danieleavitabile](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/danieleavitabile/32/31966_2.png) [@danieleavitabile](https://discourse.julialang.org/u/danieleavitabile)
#### Post date: [June 18, 2023, 12:58pm UTC](https://discourse.julialang.org/t/efficient-multiplication-between-a-low-rank-matrix-approximation-and-a-vector/100512/3 "2023-06-18T12:58:45Z")

</div>

Thanks @mohamed82008. I could not find in the documentation of the package LowRankApprox.jl how to quickly perform matrix-vector multiplies (which is separate from factorizing the matrix).

---

<div class="post-metadata">

### Author: ![mohamed82008](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mohamed82008/32/18171_2.png) [@mohamed82008](https://discourse.julialang.org/u/mohamed82008)
#### Post date: [June 18, 2023, 1:08pm UTC](https://discourse.julialang.org/t/efficient-multiplication-between-a-low-rank-matrix-approximation-and-a-vector/100512/4 "2023-06-18T13:08:58Z")

</div>

It’s already defined under the hood if you call `*` or `mul!` on the output. [LowRankApprox.jl/src/psvd.jl at master · JuliaLinearAlgebra/LowRankApprox.jl · GitHub](https://github.com/JuliaLinearAlgebra/LowRankApprox.jl/blob/master/src/psvd.jl#L65)

---

<div class="post-metadata">

### Author: ![danieleavitabile](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/danieleavitabile/32/31966_2.png) [@danieleavitabile](https://discourse.julialang.org/u/danieleavitabile)
#### Post date: [June 18, 2023, 1:11pm UTC](https://discourse.julialang.org/t/efficient-multiplication-between-a-low-rank-matrix-approximation-and-a-vector/100512/5 "2023-06-18T13:11:32Z")

</div>

Thank you, this was very helpful

---

<div class="post-metadata">

### Author: ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)
#### Post date: [June 18, 2023, 4:42pm UTC](https://discourse.julialang.org/t/efficient-multiplication-between-a-low-rank-matrix-approximation-and-a-vector/100512/6 "2023-06-18T16:42:20Z")

</div>

> [@danieleavitabile](#):
>
> A possible alternative is
> 
> `w = U[:,1:k] * Diagonal(S[1:k]) * V[:,1:k]' * z`

This won’t do what you want because [`*` is left-associative in Julia](https://docs.julialang.org/en/v1/manual/mathematical-operations/#Operator-Precedence-and-Associativity): it is equivalent to `((U[:,1:k] * Diagonal(S[1:k])) * V[:,1:k]') * z`, which still forms the full matrix. You want:

```julia
w = U[:,1:k] * (Diagonal(S[1:k]) * (V[:,1:k]' * z))

```

or (to [avoid allocating slices](https://docs.julialang.org/en/v1/manual/performance-tips/#man-performance-views)):

```julia
@views w = U[:,1:k] * (Diagonal(S[1:k]) * (V[:,1:k]' * z))

```

or to perform the diagonal multiplication in-place:

```julia
@views w = U[:,1:k] * lmul!(Diagonal(S[1:k]), V[:,1:k]' * z)

```

---

<div class="post-metadata">

### Author: ![danieleavitabile](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/danieleavitabile/32/31966_2.png) [@danieleavitabile](https://discourse.julialang.org/u/danieleavitabile)
#### Post date: [June 18, 2023, 6:02pm UTC](https://discourse.julialang.org/t/efficient-multiplication-between-a-low-rank-matrix-approximation-and-a-vector/100512/7 "2023-06-18T18:02:31Z")

</div>

This is great advice, thank you so much!
