Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 52 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,57 @@
# FactoredMatrices

[![CI](https://github.com/HolyLab/FactoredMatrices/actions/workflows/CI.yml/badge.svg)](https://github.com/HolyLab/FactoredMatrices/actions/workflows/CI.yml)
[![codecov](https://codecov.io/gh/HolyLab/FactoredMatrices/branch/master/graph/badge.svg)](https://codecov.io/gh/HolyLab/FactoredMatrices)
[![Aqua QA](https://juliatesting.github.io/Aqua.jl/dev/assets/badge.svg)](https://github.com/JuliaTesting/Aqua.jl)

Originally, this package was a sub package of CellSegmentation.
Store and multiply matrices in factored form `M = U*V` without forming the full dense matrix.
When `U` is `m×k` and `V` is `k×n`, a product `A*B` costs `O(mk²n)` instead of `O(m²kn)` — a
significant saving when `k` is small relative to `m` and `n`.

FactoredMatrices provides efficient multiplication methods for plain, adjoint
and transpose of factorized matrices.
## Installation

```julia
using Pkg
Pkg.add("FactoredMatrices")
```

## Usage

### Basic construction and multiplication

```julia
using FactoredMatrices

U = randn(100, 5) # 100×5
V = randn(5, 80) # 5×80
A = FactoredMatrix(U, V) # represents the 100×80 matrix U*V

x = randn(80)
y = A * x # 100-element result, no 100×80 matrix formed

B = randn(80, 3)
C = A * B # 100×3 result
```

`FactoredMatrix` supports adjoints, transposes, `mul!`, `dot`, and conversion to a
dense `Matrix`.

### Allocation-free repeated multiplication with `Workspace`

For tight loops where allocations matter, pre-allocate a `Workspace` and pass it
via the `cache` keyword:

```julia
using LinearAlgebra

ws = FactoredMatrices.Workspace(A, size(B, 2)) # scratch buffers sized for A*B products

C = similar(A * B) # pre-allocate output
for _ in 1:1000
mul!(C, A, B; cache=ws) # no allocation
end
```

The same `Workspace` can be reused across calls (including adjoint/transpose products)
as long as the operand sizes do not change. Create one `Workspace` per thread when
multiplying concurrently against the same `A`.
16 changes: 12 additions & 4 deletions src/FactoredMatrices.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
"""
FactoredMatrices

Store and operate on matrices in factored form `M = U*V` without forming the full
dense matrix. The main type is [`FactoredMatrix`](@ref). For allocation-free repeated
multiplications, create a [`FactoredMatrices.Workspace`](@ref) and pass it to `mul!`.
"""
module FactoredMatrices

using LinearAlgebra: LinearAlgebra, Adjoint, Factorization, Transpose
Expand All @@ -8,13 +15,14 @@ export FactoredMatrix
VERSION >= v"1.11" && eval(Meta.parse("public Workspace"))

"""
FactoredMatrix(U, V)
FactoredMatrix(U::AbstractMatrix{T}, V::AbstractMatrix{T}) where T

Store the matrix `M = U*V` in factored form for efficient computation.
Multiplications exploit the factored structure without forming the full dense matrix.
Multiplications exploit the factored structure without forming the full dense
matrix.

For allocation-free repeated multiplications, create a [`Workspace`](@ref) and pass it
as `mul!(C, A, B; cache=ws)`.
For allocation-free repeated multiplications, create a
[`FactoredMatrices.Workspace`](@ref) and pass it as `mul!(C, A, B; cache=ws)`.
"""
struct FactoredMatrix{T, UT <: AbstractMatrix{T}, VT <: AbstractMatrix{T}} <: Factorization{T}
U::UT # m × k
Expand Down
Loading