-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fast Hadamard Transform #49
base: master
Are you sure you want to change the base?
Changes from 17 commits
c0e55ab
054acc9
20e6c85
f0c01e2
e1a0ef6
699b1a1
f38f2ce
5aa0c91
8562145
cf1b1ba
362520c
052e04c
aefbf89
c96d3ca
49cb963
2a8c963
5e77713
a82691b
7d150ba
1ea1969
ed42c49
135d30b
c1b8644
9f763a2
6d7d809
aea41fe
ad57568
7578849
3cac0fe
e60b187
9b3ff07
ae2cb96
b3ecad0
d44dac7
a513978
8e4fed8
bc2a5a0
4883898
b373485
dfd9e53
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
## Internal Helper Functions | ||
|
||
```@contents | ||
Pages = ["helper_functions.md"] | ||
``` | ||
## Fast Hadamard transform | ||
|
||
```@docs | ||
RLinearAlgebra.fwht! | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
""" | ||
LinSysBlockColFJLT <: LinSysBlkColSampler | ||
|
||
A mutable structure with fields to handle FJLT row sketching. For this procedure, | ||
the hadamard transform and random sign swaps are applied once, then that matrix is repeatably | ||
sampled. | ||
|
||
# Fields | ||
- `blockSize::Int64`, the size of the sketching dimension | ||
- `sparsity::Float64`, the sparsity of the sampling matrix | ||
nathanielpritchard marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- `paddedSize::Int64`, the size of the matrix when padded | ||
- `Sketch::Union{SparseMatrixCSC, Nothing}`, storage for sparse sketching matrix | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I do not think this is a good name for this field as it is its own sketch, certainly, but in this context it is part of a larger sketching procedure. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have renamed it to sampling matrix because the sparse matrix is essentially sampling the random Hadamard matrix. |
||
- `Ap::Union{AbstractMatrix, Nothing}`, storage for padded matrix | ||
- `bp::Union{AbstractMatrix, Nothing}`, storage for padded vector | ||
- `signs::Union{Vector{Bool}, Nothing}`, storage for random sign flips. | ||
- `scaling::Float64`, storage for the scaling of the sketches. | ||
|
||
Calling `LinSysBlockColFJLT()` defaults to setting `sparsity` to .3 and the blocksize to 2. | ||
|
||
Nir Ailon and Bernard Chazelle. 2006. Approximate nearest neighbors and the fast Johnson-Lindenstrauss transform. In Proceedings of the thirty-eighth annual ACM symposium on Theory of Computing (STOC '06). Association for Computing Machinery, New York, NY, USA, 557–563. https://doi.org/10.1145/1132516.1132597 | ||
""" | ||
mutable struct LinSysBlockColFJLT <: LinSysBlkColSampler | ||
blockSize::Int64 | ||
sparsity::Float64 | ||
paddedSize::Int64 | ||
Sketch::Union{SparseMatrixCSC, Nothing} | ||
Ap::Union{AbstractMatrix, Nothing} | ||
bp::Union{AbstractVector, Nothing} | ||
signs::Union{Vector{Bool}, Nothing} | ||
scaling::Float64 | ||
end | ||
|
||
LinSysBlockColFJLT(;blocksize = 2, sparsity = .3) = LinSysBlockColFJLT( | ||
blocksize, | ||
sparsity, | ||
0, | ||
nothing, | ||
nothing, | ||
nothing, | ||
nothing, | ||
0.0 | ||
) | ||
vp314 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
# Common sample interface for linear systems | ||
function sample( | ||
type::LinSysBlockColFJLT, | ||
A::AbstractArray, | ||
b::AbstractVector, | ||
x::AbstractVector, | ||
iter::Int64 | ||
) | ||
if iter == 1 | ||
m, n = size(A) | ||
# If matrix is not a power of 2 then pad the rows | ||
if rem(log(2, n), 1) != 0 | ||
type.paddedSize = Int64(2^(div(log(2, n), 1) + 1)) | ||
# Find nearest power 2 and allocate | ||
type.Ap = zeros(m, type.paddedSize) | ||
# Pad matrix and constant vector | ||
@views type.Ap[:, 1:n] .= A | ||
nathanielpritchard marked this conversation as resolved.
Show resolved
Hide resolved
|
||
else | ||
type.paddedSize = n | ||
type.Ap = A | ||
end | ||
# Compute scaling and sign flips | ||
type.scaling = sqrt(type.blockSize / (type.paddedSize * type.sparsity)) | ||
type.signs = bitrand(type.paddedSize) | ||
# Apply FWHT to padded matrix and vector | ||
for i = 1:m | ||
@views fwht!(type.Ap[i, :], signs = type.signs, scaling = type.scaling) | ||
nathanielpritchard marked this conversation as resolved.
Show resolved
Hide resolved
|
||
end | ||
|
||
end | ||
|
||
type.Sketch = sprandn(type.paddedSize, type.blockSize, type.sparsity) | ||
AS = type.Ap * type.Sketch | ||
# Residual of the linear system | ||
res = A * x - b | ||
grad = AS'res | ||
nathanielpritchard marked this conversation as resolved.
Show resolved
Hide resolved
|
||
H = hadamard(type.paddedSize) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It should be used when returning the actual sketching matrix. I have revised the code to actually accomplish this, instead partially return the sketching matrix. |
||
sgn = [type.signs[i] ? 1 : -1 for i in 1:type.paddedSize] | ||
return [sgn, type.Sketch .* type.scaling], AS, res, grad | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are not returning the actual sketch, just pieces of it? Is that correct? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unlike the row case, this one is a bit harder to justify in terms of transforming the problem since you need to get the residual from the original problem. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Justifying the padded transformation in this case is certainly harder; however, we probably should still provide the functionality of column sketching with these Hadamard matrices if we are going to provide it for the row versions. |
||
end |
vp314 marked this conversation as resolved.
Show resolved
Hide resolved
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
|
||
""" | ||
LinSysBlockColSRHT <: LinSysBlkColSampler | ||
|
||
A mutable structure with fields to handle SRHT column sketching. For this procedure, | ||
the hadamard transform and random sign swaps are applied once, then that matrix is repeatably | ||
sampled. | ||
|
||
# Fields | ||
- `blockSize::Int64`, the size of blocks being chosen | ||
- `paddedSize::Int64`, the size of the matrix when padded | ||
- `block::Union{Vector{Int64}, Nothing}`, storage for block indices | ||
- `Ap::Union{AbstractMatrix, Nothing}`, storage for padded matrix | ||
- `signs::Union{Vector{Bool}, Nothing}`, storage for random sign flips. | ||
- `scaling::Float64`, storage for the scaling of the sketches. | ||
|
||
Calling `LinSysBlockColSRHT()` defaults to setting `blockSize` to 2. | ||
|
||
Nir Ailon and Bernard Chazelle. 2006. Approximate nearest neighbors and the fast Johnson-Lindenstrauss transform. In Proceedings of the thirty-eighth annual ACM symposium on Theory of Computing (STOC '06). Association for Computing Machinery, New York, NY, USA, 557–563. https://doi.org/10.1145/1132516.1132597 | ||
""" | ||
mutable struct LinSysBlockColSRHT <: LinSysBlkColSampler | ||
blockSize::Int64 | ||
paddedSize::Int64 | ||
block::Union{Vector{Int64}, Nothing} | ||
Ap::Union{AbstractMatrix, Nothing} | ||
signs::Union{Vector{Bool}, Nothing} | ||
scaling::Float64 | ||
end | ||
|
||
LinSysBlockColSRHT(blockSize) = LinSysBlockColSRHT( | ||
blockSize, | ||
0, | ||
nothing, | ||
nothing, | ||
nothing, | ||
0.0 | ||
) | ||
LinSysBlockColSRHT() = LinSysBlockColSRHT(2, 0, nothing, nothing, nothing, 0.0) | ||
|
||
# Common sample interface for linear systems | ||
function sample( | ||
type::LinSysBlockColSRHT, | ||
A::AbstractArray, | ||
b::AbstractVector, | ||
x::AbstractVector, | ||
iter::Int64 | ||
) | ||
if iter == 1 | ||
m, n = size(A) | ||
# If matrix is not a power of 2 then pad the rows | ||
if rem(log(2, n), 1) != 0 | ||
type.paddedSize = Int64(2^(div(log(2, n), 1) + 1)) | ||
# Find nearest power 2 and allocate | ||
type.Ap = zeros(m, type.paddedSize) | ||
# Pad matrix and constant vector | ||
type.Ap[:, 1:n] .= A | ||
else | ||
type.paddedSize = n | ||
type.Ap = A | ||
end | ||
# Compute scaling and sign flips | ||
type.scaling = sqrt(type.blockSize / type.paddedSize) | ||
type.signs = bitrand(type.paddedSize) | ||
for i = 1:m | ||
@views fwht!(type.Ap[i, :], signs = type.signs, scaling = type.scaling) | ||
end | ||
|
||
type.block = zeros(Int64, type.blockSize) | ||
end | ||
|
||
type.block .= randperm(type.paddedSize)[1:type.blockSize] | ||
AS = type.Ap[:, type.block] | ||
# Residual of the linear system | ||
res = A * x - b | ||
grad = AS'res | ||
H = hadamard(type.paddedSize) | ||
sgn = [type.signs[i] ? 1 : -1 for i in 1:type.paddedSize] | ||
return [sgn .* type.scaling, type.block], AS, res, grad | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
""" | ||
LinSysBlockRowFJLT <: LinSysBlkRowSampler | ||
|
||
A mutable structure with fields to handle FJLT row sketching. For this procedure, | ||
the hadamard transform and random sign swaps are applied once, then that matrix is repeatably | ||
sampled. | ||
|
||
# Fields | ||
- `blockSize::Int64`, the size of the sketching dimension | ||
- `sparsity::Float64`, the sparsity of the sampling matrix | ||
- `paddedSize::Int64`, the size of the matrix when padded | ||
- `Sketch::Union{SparseMatrixCSC, Nothing}`, storage for sparse sketching matrix | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comment regarding the naming choice as in the column case. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same response as in the column case. |
||
- `Ap::Union{AbstractMatrix, Nothing}`, storage for padded matrix | ||
- `bp::Union{AbstractMatrix, Nothing}`, storage for padded vector | ||
- `signs::Union{Vector{Bool}, Nothing}`, storage for random sign flips. | ||
- `scaling::Float64`, storage for the scaling of the sketches. | ||
|
||
Calling `LinSysBlockRowFJLT()` defaults to setting `sparsity` to .3 and the blocksize to 2. | ||
|
||
Nir Ailon and Bernard Chazelle. 2006. Approximate nearest neighbors and the fast Johnson-Lindenstrauss transform. In Proceedings of the thirty-eighth annual ACM symposium on Theory of Computing (STOC '06). Association for Computing Machinery, New York, NY, USA, 557–563. https://doi.org/10.1145/1132516.1132597 | ||
""" | ||
mutable struct LinSysBlockRowFJLT <: LinSysBlkRowSampler | ||
blockSize::Int64 | ||
sparsity::Float64 | ||
paddedSize::Int64 | ||
Sketch::Union{SparseMatrixCSC, Nothing} | ||
Ap::Union{AbstractMatrix, Nothing} | ||
bp::Union{AbstractVector, Nothing} | ||
signs::Union{Vector{Bool}, Nothing} | ||
scaling::Float64 | ||
end | ||
|
||
LinSysBlockRowFJLT(;blocksize = 2, sparsity = .3) = LinSysBlockRowFJLT( | ||
blocksize, | ||
sparsity, | ||
0, | ||
nothing, | ||
nothing, | ||
nothing, | ||
nothing, | ||
0.0 | ||
) | ||
|
||
# Common sample interface for linear systems | ||
function sample( | ||
type::LinSysBlockRowFJLT, | ||
A::AbstractArray, | ||
b::AbstractVector, | ||
x::AbstractVector, | ||
iter::Int64 | ||
) | ||
if iter == 1 | ||
m, n = size(A) | ||
# If matrix is not a power of 2 then pad the rows | ||
if rem(log(2, m), 1) != 0 | ||
type.paddedSize = Int64(2^(div(log(2, m), 1) + 1)) | ||
# Find nearest power 2 and allocate | ||
type.Ap = zeros(type.paddedSize, n) | ||
type.bp = zeros(type.paddedSize) | ||
# Pad matrix and constant vector | ||
@views type.Ap[1:m, :] .= A | ||
@views type.bp[1:m] .= b | ||
nathanielpritchard marked this conversation as resolved.
Show resolved
Hide resolved
|
||
else | ||
type.paddedSize = m | ||
type.Ap = A | ||
type.bp = b | ||
end | ||
# Compute scaling and sign flips | ||
type.scaling = sqrt(type.blockSize / (type.paddedSize * type.sparsity)) | ||
type.signs = bitrand(type.paddedSize) | ||
# Apply FWHT to padded matrix and vector | ||
fwht!(type.bp, signs = type.signs, scaling = type.scaling) | ||
for i = 1:n | ||
@views fwht!(type.Ap[:, i], signs = type.signs, scaling = type.scaling) | ||
end | ||
nathanielpritchard marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
end | ||
|
||
type.Sketch = sprandn(type.blockSize, type.paddedSize, type.sparsity) | ||
SA = type.Sketch * type.Ap | ||
Sb = type.Sketch * type.bp | ||
# Residual of the linear system | ||
res = SA * x - Sb | ||
return type.Sketch, SA, res | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are not actually returning the sketch here, just a piece of it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, I think I see. You are transforming the original problem. You have created a new problem and so you are sketching the new problem with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That was correct, but to align with the other sampling/sketching methods the full matrix should be returned. I have made this adjustment in all the files. |
||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nathanielpritchard we need to be more disciplined about incrementing the version.