Skip to content
Open
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
1 change: 1 addition & 0 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ makedocs(
],
"Approximators" => [
"Approximators API" => "api/approximators.md",
"Selectors API" => "api/selectors.md",
"ApproximatorErrors API" => "api/approximator_errors.md",
],
],
Expand Down
33 changes: 33 additions & 0 deletions docs/src/api/selectors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Selectors
```@contents
Pages = ["selectors.md"]
```

## Abstract Types
```@docs
Selector
SelectorRecipe
```

## Selector Structures
```@docs
RLinearAlgebra.LUPP
LUPPRecipe
```

## Exported Functions
```@docs
complete_selector
update_selector!
select_indices!
```

## Internal Functions
```@docs
```
10 changes: 10 additions & 0 deletions src/Approximators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ randomized rangefinder.
"""
abstract type RangeApproximatorRecipe <: ApproximatorRecipe end


###################################
# Docstring Components
###################################
Expand All @@ -72,6 +73,7 @@ approx_arg_list = Dict{Symbol,String}(
:A => "`A::AbstractMatrix`, a target matrix for approximation.",
:compressor_recipe => "`S::CompressorRecipe`, a fully initialized realization for a
compression method for a specific matrix or collection of matrices and vectors.",

)

approx_output_list = Dict{Symbol,String}(
Expand All @@ -82,8 +84,10 @@ approx_output_list = Dict{Symbol,String}(
approx_method_description = Dict{Symbol,String}(
:complete_approximator => "A function that generates an `ApproximatorRecipe` given
arguments.",

:update_approximator => "A function that updates the `ApproximatorRecipe` in place
given the arguments.",

:rapproximate => "A function that computes a low-rank approximation of the matrix `A`
using the information in the provided `Approximator` data structure.",
:complete_approximator_error => "A function that generates an `ApproximatorErrorRecipe`
Expand Down Expand Up @@ -161,6 +165,7 @@ function complete_approximator(approximator::Approximator, A::AbstractMatrix)
)
end


###################################
# rapproximate Interface
###################################
Expand Down Expand Up @@ -430,3 +435,8 @@ end
include("Approximators/RangeApproximators/rangefinder.jl")
include("Approximators/RangeApproximators/randsvd.jl")
include("Approximators/RangeApproximators/helpers/power_its.jl")

############################################
# Include the selector files
############################################
include("Approximators/Selectors.jl")
147 changes: 147 additions & 0 deletions src/Approximators/Selectors.jl
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to either update docstring list or arguments (I think docstring list is easier) to make SelectorRecipe consistent

Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
###################################
# Abstract Types
###################################
"""
Selector

An abstract type containing user controlled parameters for a technique that selects indices
from a matrix.
"""
abstract type Selector end

"""
SelectorRecipe

An abstract type containing user controlled parameters and preallocated memory for a
technique that selects indices from a matrix.
"""
abstract type SelectorRecipe end

select_arg_list = Dict{Symbol,String}(
:selector => "`selector::Selector`, a data structure containing the user-defined
parameters associated with a particular selection method.",
:selector_recipe => "`selector_recipe::SelectorRecipe`, a fully initialized realization
for a selector method for a particular matrix.",
:idx => "`idx::vector`, a vector where selected indices will be placed.",
:n_idx => "`n_idx::Int64`, the number of indices to be selected.",
:start_idx => "`start_idx::Int64`. the starting location in `idx` where the indices
will be placed.",
:A => "`A::AbstractMatrix`, a target matrix for approximation.",
)
select_output_list = Dict{Symbol,String}(
:selector_recipe => "A `SelectorRecipe` object.",
)
select_method_description = Dict{Symbol,String}(
:update_selector => "A function that updates the `SelectorRecipe` in place given the
arguments.",
:complete_selector => "A function that generates a `SelectorRecipe` given
arguments.",
:select_indices => "A function that selects indices from a matrix `A` using a specific
`SelectorRecipe`. It updates the vector `idx` in place with `n_idx` new indices starting
at index `start_idx`."
)
##################################
# Complete Selector Interface
##################################
"""
complete_selector(selector::Selector, A::AbstractMatrix)

$(select_method_description[:complete_selector])

# Arguments
- $(select_arg_list[:selector])
- $(select_arg_list[:A])

# Outputs
- $(select_output_list[:selector_recipe])
"""
function complete_selector(selector::Selector, A::AbstractMatrix)
return throw(
ArgumentError(
"No method `complete_selector` exists for selector of type\
$(typeof(selector)) and matrix of type $(typeof(A))."
)
)
end

##################################
# update_selector!
##################################
"""
update_selector!(selector::SelectorRecipe)

$(select_method_description[:update_selector])

# Arguments
- $(select_arg_list[:selector_recipe])

# Outputs
- $(select_output_list[:selector_recipe])
"""
function update_selector!(selector::SelectorRecipe)
return throw(
ArgumentError(
"No method `update_selector!` exists for selector of type\
$(typeof(selector))."
)
)
end

"""
update_selector!(selector::SelectorRecipe, A::AbstractMatrix)

$(select_method_description[:update_selector])

# Arguments
- $(select_arg_list[:selector_recipe])
- $(select_arg_list[:A])

# Outputs
- $(select_output_list[:selector_recipe])
"""
function update_selector!(selector::SelectorRecipe, A::AbstractMatrix)
return update_selector!(selector)
end

####################################
# select_indices!
####################################
"""
select_indices!(
selector::SelectorRecipe,
A::AbstractMatrix,
idx::AbstractVector,
Comment on lines +111 to +113
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These need to be permuted to match the function

n_idx::Int64,
start_idx::Int64
)

$(select_method_description[:select_indices])

# Arguments
- $(select_arg_list[:idx])
- $(select_arg_list[:selector_recipe])
- $(select_arg_list[:A])
- $(select_arg_list[:n_idx])
- $(select_arg_list[:start_idx])

# Outputs
- Returns `nothing`
"""
function select_indices!(
idx::AbstractVector,
selector::SelectorRecipe,
A::AbstractMatrix,
n_idx::Int64,
start_idx::Int64
)
return throw(
ArgumentError(
"No method `select_indices` exists for selector of type $(typeof(selector)),\
matrix of type $(typeof(A)), idx of type $(typeof(idx)), n_idx of type \
$(typeof(n_idx)), and start_idx of type $(typeof(start_idx))."
)
)
end

# Include the selector files
include("Selectors/lupp.jl")
110 changes: 110 additions & 0 deletions src/Approximators/Selectors/lupp.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
"""
LUPP <: Selector

A `Selector` that implements LU with partial pivoting for selecting column indices from a
matrix.

# Fields
- `compressor::Compressor`, the compression technique that will be applied to the matrix,
before selecting indices.

# Constructor
LUPP(;compressor = Identity())

## Keywords
- `compressor::Compressor`, the compression technique that will be applied to the matrix,
before selecting indices. Defaults to the `Identity` compressor.

## Returns
- A `LUPP` object.

!!! note "Implementation Note"
LU with partial pivoting is classically implemented to select rows of a matrix. Here we
apply LU with partial pivoting to the transpose of the inputted matrix to select
columns.
"""
mutable struct LUPP <: Selector
compressor::Compressor
end

function LUPP(;compressor = Identity())
return LUPP(compressor)
end

"""
LUPPRecipe <: SelectorRecipe

A `SelectorRecipe` that contains all the necessary preallocations for selecting column
indices from a matrix using LU with partial pivoting.


# Fields
- `compressor::CompressorRecipe`, the compression technique that will applied to the matrix,
before selecting indices.
- `SA::AbstractMatrix`, a buffer matrix for storing the sketched matrix.

!!! note "Implementation Note"
LU with partial pivoting is classically implemented to select rows of a matrix. Here we
apply LU with partial pivoting to the transpose of the inputted matrix to select
columns.
"""
mutable struct LUPPRecipe <: SelectorRecipe
compressor::CompressorRecipe
SA::AbstractMatrix
end

function complete_selector(ingredients::LUPP, A::AbstractMatrix)
compressor = complete_compressor(ingredients.compressor, A)
n_rows, n_cols = size(compressor)
SA = Matrix{eltype(A)}(undef, n_rows, n_cols)
return LUPPRecipe(compressor, SA)
end

function update_selector!(selector::LUPPRecipe)
update_compressor!(selector.compressor)
return nothing
end

function select_indices!(
idx::AbstractVector,
selector::LUPPRecipe,
A::AbstractMatrix,
n_idx::Int64,
start_idx::Int64
)
# you cannot select more column indices than there are columns in the matrix
if n_idx > size(A, 2)
throw(
DimensionMismatch(
"`n_idx` cannot be larger than the number of columns in `A`."
)
)
end

# start_idx + n_idx must be less than the length of the idx vector
if start_idx + n_idx - 1 > size(idx, 1)
throw(
DimensionMismatch(
"`start_idx` + `n_idx` - 1 cannot be larger than the lenght of `idx`."
)
)
end

# you cannot select more indices than the compression dimension because that is when
# LUPP will stop selecting new pivots because the LU factorization will have been formed
if n_idx > selector.compressor.n_rows
throw(
DimensionMismatch(
"Must select fewer indices then the `compression_dim`."
)
)

end

mul!(selector.SA, selector.compressor, A)
# because LUPP selects rows and selectors select columns we need to pivot on A'
p = lu!(selector.SA').p
# store n_idx indices in the appropriate part of the idx
idx[start_idx:start_idx + n_idx - 1] = p[1:n_idx]
return nothing
end
7 changes: 6 additions & 1 deletion src/RLinearAlgebra.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
module RLinearAlgebra
import Base.:*
import Base: transpose, adjoint
import LinearAlgebra: Adjoint, axpby!, dot, I, ldiv!, lmul!, lq!, lq, LQ, mul!, norm, qr!, svd
import LinearAlgebra: Adjoint, axpby!, dot, I, ldiv!, lmul!, lq!, lq, LQ, lu!
import LinearAlgebra: mul!, norm, qr!, svd
import StatsBase: sample, sample!, ProbabilityWeights, wsample!
import Random: bitrand, rand!, randn!
import SparseArrays: SparseMatrixCSC, sprandn, sparse
Expand Down Expand Up @@ -62,4 +63,8 @@ export FullResidual, FullResidualRecipe
export ApproximatorError, ApproximatorErrorRecipe
export complete_approximator_error, compute_approximator_error, compute_approximator_error!

# Export Selector types and functions
export Selector, SelectorRecipe
export LUPP, LUPPRecipe
export complete_selector, update_selector!, select_indices!
end #module
Loading
Loading