diff --git a/README.md b/README.md index 4b760ed..357cdd7 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ repository. ### Basic Construction and Usage ```julia -using BandedMatrices, FastAlmostBandedMatrices, LinearAlgebra +using FastAlmostBandedMatrices, LinearAlgebra m = 2 # Fill rank n = 10 # Matrix dimension @@ -58,7 +58,7 @@ Q, R = fact.Q, fact.R
```julia -using BandedMatrices, BenchmarkTools, FastAlmostBandedMatrices, SparseArrays, FillArrays, LinearAlgebra +using BenchmarkTools, FastAlmostBandedMatrices, SparseArrays, FillArrays, LinearAlgebra import SemiseparableMatrices m = 5 @@ -191,6 +191,19 @@ almostbandedrank finish_part_setindex! ``` +Because the documented constructor is `AlmostBandedMatrix(bands::BandedMatrix, fill)`, +`using FastAlmostBandedMatrices` also brings along the +[BandedMatrices.jl](https://github.com/JuliaLinearAlgebra/BandedMatrices.jl) names needed to +build, populate and query that `bands` argument. They remain owned and documented by +BandedMatrices.jl: + +``` +BandedMatrix brand brandn +Band BandRange band bandrange +bandwidth bandwidths colrange rowrange +BandError +``` + ## Some Considerations 1. Not all operations are meant to be fast. Currently only the following operations are diff --git a/docs/src/api.md b/docs/src/api.md index 6b70217..93eb415 100644 --- a/docs/src/api.md +++ b/docs/src/api.md @@ -28,3 +28,23 @@ almostbandedrank ```@docs finish_part_setindex! ``` + +## Reexported from BandedMatrices.jl + +The documented constructor is `AlmostBandedMatrix(bands::BandedMatrix, fill)`, and the +examples on the home page build `bands` with `brand`. So `using FastAlmostBandedMatrices` +also brings the +[BandedMatrices.jl](https://github.com/JuliaLinearAlgebra/BandedMatrices.jl) names needed to +construct, populate and query that banded argument: + +| Purpose | Names | +|:--------|:------| +| Construction | `BandedMatrix`, `brand`, `brandn` | +| Band indexing | `Band`, `BandRange`, `band`, `bandrange` | +| Structure queries | `bandwidth`, `bandwidths`, `colrange`, `rowrange` | +| Errors | `BandError` | + +These names are owned and documented by BandedMatrices.jl; see its documentation for their +full behaviour. Nothing else from BandedMatrices.jl is reexported, and neither are the +names it reexports from its own dependencies (for example the FillArrays.jl names `Fill`, +`Ones`, `Zeros` and `Eye`). Use `using BandedMatrices` or `using FillArrays` for those. diff --git a/docs/src/index.md b/docs/src/index.md index 0ea1cd2..4cd086d 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -22,7 +22,7 @@ Pkg.add("FastAlmostBandedMatrices") ## Basic Construction and Usage ```julia -using BandedMatrices, FastAlmostBandedMatrices, LinearAlgebra +using FastAlmostBandedMatrices, LinearAlgebra m = 2 # Fill rank n = 10 # Matrix dimension diff --git a/src/FastAlmostBandedMatrices.jl b/src/FastAlmostBandedMatrices.jl index d93cb49..6d0ca48 100644 --- a/src/FastAlmostBandedMatrices.jl +++ b/src/FastAlmostBandedMatrices.jl @@ -4,8 +4,13 @@ import PrecompileTools: @setup_workload, @compile_workload using ArrayInterface, ArrayLayouts, ConcreteStructs, LazyArrays, LinearAlgebra, MatrixFactorizations -import BandedMatrices -using BandedMatrices: bandwidth, bandwidths + +# The BandedMatrices.jl surface that FastAlmostBandedMatrices reexports (see the second +# `export` below), so that `using FastAlmostBandedMatrices` on its own is enough to build +# the `bands` argument of an `AlmostBandedMatrix`, populate it, and query its band +# structure. Everything stays owned and documented upstream in BandedMatrices.jl. +using BandedMatrices: Band, BandError, BandRange, BandedMatrix, band, bandrange, bandwidth, + bandwidths, brand, brandn, colrange, rowrange import ArrayLayouts: MemoryLayout, sublayout, MatLdivVec, materialize!, triangularlayout, triangulardata, colsupport, @@ -95,7 +100,7 @@ abstract type AbstractAlmostBandedLayout <: MemoryLayout end struct AlmostBandedLayout <: AbstractAlmostBandedLayout end """ - AlmostBandedMatrix(bands::BandedMatrices.BandedMatrix, fill) + AlmostBandedMatrix(bands::BandedMatrix, fill) AlmostBandedMatrix{T}(bands, fill) AlmostBandedMatrix(::UndefInitializer, [::Type{T} = Float64], mn::NTuple{2, Integer}, lu::NTuple{2, Integer}, rank::Integer) @@ -149,7 +154,7 @@ part. # Example ```julia -bands = BandedMatrices.brand(Float64, 8, 8, 3, 2) +bands = brand(Float64, 8, 8, 3, 2) fill = rand(2, 8) A = AlmostBandedMatrix(bands, fill) ``` @@ -170,7 +175,7 @@ function AlmostBandedMatrix( ) where {T} @assert lu[2] ≥ rank - 1 @assert rank ≥ 1 "Rank 0 fill array makes it a BandedMatrix." - bands = BandedMatrices.BandedMatrix{T}(undef, mn, lu) + bands = BandedMatrix{T}(undef, mn, lu) fill = Matrix{T}(undef, rank, mn[2]) return AlmostBandedMatrix{T}(bands, fill) end @@ -190,7 +195,7 @@ function AlmostBandedMatrix( return AlmostBandedMatrix(undef, Float64, mn, lu, rank) end -function AlmostBandedMatrix(bands::BandedMatrices.BandedMatrix, fill::AbstractMatrix) +function AlmostBandedMatrix(bands::BandedMatrix, fill::AbstractMatrix) @assert size(fill, 2) == size(bands, 2) @assert size(fill, 1) ≥ 1 "Rank 0 fill array makes it a BandedMatrix." T = promote_type(eltype(fill), eltype(bands)) @@ -228,7 +233,7 @@ not mutated. # Example ```julia -A = AlmostBandedMatrix(BandedMatrices.brand(Float64, 8, 8, 3, 2), rand(2, 8)) +A = AlmostBandedMatrix(brand(Float64, 8, 8, 3, 2), rand(2, 8)) fillpart(A)[1, 1] = 1 finish_part_setindex!(A) ``` @@ -262,7 +267,7 @@ Returns the mutable `BandedMatrix` stored by `A`; it is not a copy. # Example ```julia -A = AlmostBandedMatrix(BandedMatrices.brand(Float64, 10, 10, 3, 2), rand(Float64, 2, 10)) +A = AlmostBandedMatrix(brand(Float64, 10, 10, 3, 2), rand(Float64, 2, 10)) B = bandpart(A) # Returns the BandedMatrix component ``` """ @@ -286,7 +291,7 @@ Returns the mutable fill matrix stored by `A`; it is not a copy. Call # Example ```julia -A = AlmostBandedMatrix(BandedMatrices.brand(Float64, 10, 10, 3, 2), rand(Float64, 2, 10)) +A = AlmostBandedMatrix(brand(Float64, 10, 10, 3, 2), rand(Float64, 2, 10)) F = fillpart(A) # Returns the fill matrix (2×10) ``` """ @@ -309,7 +314,7 @@ Returns a view into `bandpart(A)`, not a copy. # Example ```julia -A = AlmostBandedMatrix(BandedMatrices.brand(Float64, 10, 10, 3, 2), rand(Float64, 2, 10)) +A = AlmostBandedMatrix(brand(Float64, 10, 10, 3, 2), rand(Float64, 2, 10)) E = exclusive_bandpart(A) # Returns a view of rows 3:10 of the banded part ``` """ @@ -335,7 +340,7 @@ Returns `(l, u)`, where `l` is the lower bandwidth and `u` is the upper bandwidt # Example ```julia -A = AlmostBandedMatrix(BandedMatrices.brand(Float64, 10, 10, 3, 2), rand(Float64, 2, 10)) +A = AlmostBandedMatrix(brand(Float64, 10, 10, 3, 2), rand(Float64, 2, 10)) almostbandwidths(A) # Returns (3, 2) ``` """ @@ -361,7 +366,7 @@ Returns the number of rows in `fillpart(A)`. # Example ```julia -A = AlmostBandedMatrix(BandedMatrices.brand(Float64, 10, 10, 3, 2), rand(Float64, 2, 10)) +A = AlmostBandedMatrix(brand(Float64, 10, 10, 3, 2), rand(Float64, 2, 10)) almostbandedrank(A) # Returns 2 ``` """ @@ -539,9 +544,7 @@ function _almostbanded_qr(_, A) # Expand the bandsize for the QR factorization ## Bypass the safety checks in `AlmostBandedMatrix` return almostbanded_qr!( - AlmostBandedMatrix{eltype(A)}( - BandedMatrices.BandedMatrix(copy(B), (l, l + u)), copy(L) - ), Val(true) + AlmostBandedMatrix{eltype(A)}(BandedMatrix(copy(B), (l, l + u)), copy(L)), Val(true) ) end @@ -549,7 +552,7 @@ end function almostbanded_qr!(R::AbstractMatrix{T}, ::Val{false}) where {T} l, u = almostbandwidths(R) B, L = bandpart(R), fillpart(R) - R′ = AlmostBandedMatrix{eltype(R)}(BandedMatrices.BandedMatrix(B, (l, l + u)), L) + R′ = AlmostBandedMatrix{eltype(R)}(BandedMatrix(B, (l, l + u)), L) return almostbanded_qr!(R′, Val(true)) end @@ -766,7 +769,7 @@ end m = 2 n = 10 for T in (Float32, Float64) - B = BandedMatrices.brand(T, n, n, m + 1, m) + B = brand(T, n, n, m + 1, m) F = rand(T, m, n) @compile_workload begin @@ -784,4 +787,11 @@ end export AlmostBandedMatrix, bandpart, fillpart, exclusive_bandpart, finish_part_setindex!, almostbandwidths, almostbandedrank +# Reexported BandedMatrices.jl names; approved via `reexports_allow` in test/qa/qa.jl. +# `AlmostBandedMatrix(bands::BandedMatrix, fill)` is the documented constructor and every +# documented example builds `bands` with `brand`, so these must keep coming along with +# `using FastAlmostBandedMatrices`. +export Band, BandError, BandRange, BandedMatrix, band, bandrange, bandwidth, bandwidths, + brand, brandn, colrange, rowrange + end diff --git a/test/core_tests.jl b/test/core_tests.jl index 2b091ff..e990663 100644 --- a/test/core_tests.jl +++ b/test/core_tests.jl @@ -1,25 +1,45 @@ using SafeTestsets -@safetestset "Documented construction API" begin - using BandedMatrices, FastAlmostBandedMatrices - - exported = Set(names(FastAlmostBandedMatrices; all = false)) - @test :brand ∉ exported - @test all(name ∉ exported for name in (:Band, :BandedMatrix, :Fill, :band, :bandwidth, :brandn)) - +@safetestset "Reexported BandedMatrices API" begin + using FastAlmostBandedMatrices + import BandedMatrices + + # Kept in sync with the reexport `export` block in src/FastAlmostBandedMatrices.jl and + # with `REEXPORTED_API` in test/qa/qa.jl. + reexports = ( + :Band, :BandError, :BandRange, :BandedMatrix, :band, :bandrange, :bandwidth, + :bandwidths, :brand, :brandn, :colrange, :rowrange, + ) + + exported = Set(names(FastAlmostBandedMatrices)) + for name in reexports + # Exported, in scope from a bare `using FastAlmostBandedMatrices`, and still the + # upstream binding rather than a copy. + @test name in exported + @test isdefined(@__MODULE__, name) + @test getfield(FastAlmostBandedMatrices, name) === getfield(BandedMatrices, name) + end + + # Whole dependencies are not reexported: BandedMatrices' own reexports (FillArrays) + # and unrelated names stay out. + for name in (:Fill, :Ones, :Zeros, :Eye, :symrcm, :BandedMatrices) + @test name ∉ exported + end + + # The documented construction path works with `using FastAlmostBandedMatrices` alone. A = AlmostBandedMatrix(brand(Float64, 10, 10, 3, 2), rand(Float64, 2, 10)) - bands = BandedMatrices.BandedMatrix(fill(1.0, 10, 10), (3, 2)) - B = AlmostBandedMatrix(bands, rand(Float64, 2, 10)) + B = AlmostBandedMatrix(BandedMatrix(fill(1.0, 10, 10), (3, 2)), rand(Float64, 2, 10)) @test A isa AlmostBandedMatrix - @test bandpart(A) isa BandedMatrices.BandedMatrix + @test B isa AlmostBandedMatrix + @test bandpart(A) isa BandedMatrix + @test bandwidths(bandpart(A)) == (3, 2) @test almostbandwidths(A) == (3, 2) @test almostbandedrank(A) == 2 - @test B isa AlmostBandedMatrix end @safetestset "Constructors" begin - using BandedMatrices, FastAlmostBandedMatrices + using FastAlmostBandedMatrices A = AlmostBandedMatrix{Float64}(undef, (10, 11), (2, 1), 2) A[1, 1] = 2 @@ -35,7 +55,7 @@ end end @safetestset "similar" begin - using BandedMatrices, FastAlmostBandedMatrices + using FastAlmostBandedMatrices A = AlmostBandedMatrix(brand(Float64, 10, 10, 2, 1), rand(Float64, 2, 10)) @@ -48,7 +68,7 @@ end end @safetestset "Copy" begin - using BandedMatrices, FastAlmostBandedMatrices + using FastAlmostBandedMatrices n = 5 m = 2 @@ -66,7 +86,7 @@ end end @safetestset "QR" begin - using BandedMatrices, LinearAlgebra, FastAlmostBandedMatrices + using LinearAlgebra, FastAlmostBandedMatrices import MatrixFactorizations: QRPackedQ n = 80 @@ -94,7 +114,7 @@ end end @safetestset "Triangular" begin - using BandedMatrices, LinearAlgebra, ArrayLayouts, FastAlmostBandedMatrices + using LinearAlgebra, ArrayLayouts, FastAlmostBandedMatrices import FastAlmostBandedMatrices: AlmostBandedLayout n = 80 @@ -110,7 +130,7 @@ end # https://github.com/SciML/FastAlmostBandedMatrices.jl/issues/19 @safetestset "fill! on sparse array with BigFloat" begin - using BandedMatrices, FastAlmostBandedMatrices, SparseArrays + using FastAlmostBandedMatrices, SparseArrays A = sparse([1, 2], [1, 5], big.([1.0, 1.0])) A1 = AlmostBandedMatrix(brand(BigFloat, 5, 5, 1, 1), A) diff --git a/test/qa/alloc_tests.jl b/test/qa/alloc_tests.jl index 98c9eb9..c24ba51 100644 --- a/test/qa/alloc_tests.jl +++ b/test/qa/alloc_tests.jl @@ -1,5 +1,4 @@ using AllocCheck -using BandedMatrices using FastAlmostBandedMatrices using FastAlmostBandedMatrices: DisjointRange using ArrayLayouts: colsupport, rowsupport diff --git a/test/qa/qa.jl b/test/qa/qa.jl index 45fb9ad..a77dba6 100644 --- a/test/qa/qa.jl +++ b/test/qa/qa.jl @@ -1,7 +1,20 @@ using SciMLTesting, FastAlmostBandedMatrices +# The BandedMatrices.jl names FastAlmostBandedMatrices intentionally reexports, because they +# are needed for its own documented use: `AlmostBandedMatrix(bands::BandedMatrix, fill)` is +# the documented constructor and the documented examples build `bands` with `brand`. +# Kept in sync with the reexport `export` block in src/FastAlmostBandedMatrices.jl. +const REEXPORTED_API = ( + :Band, :BandError, :BandRange, :BandedMatrix, + :band, :bandrange, :bandwidth, :bandwidths, :brand, :brandn, :colrange, :rowrange, +) + run_qa( FastAlmostBandedMatrices; + reexports_allow = REEXPORTED_API, + # `Band` and `BandError` are reexported but carry no docstring upstream in + # BandedMatrices.jl, so the public-API docstring check has nothing to find for them. + api_docs_kwargs = (; ignore = (:Band, :BandError)), # 19 method ambiguities, all in FastAlmostBandedMatrices' own ldiv!/__arguments # against ArrayLayouts/LinearAlgebra Triangular/Factorization methods. # https://github.com/SciML/FastAlmostBandedMatrices.jl/issues/71 @@ -30,8 +43,8 @@ run_qa( ), ), # 31 names implicitly imported via the package's `using ArrayInterface, ArrayLayouts, - # BandedMatrices, ConcreteStructs, LazyArrays, LinearAlgebra, ...`; explicit-import - # conversion tracked separately. + # ConcreteStructs, LazyArrays, LinearAlgebra, ...`; explicit-import conversion tracked + # separately. # https://github.com/SciML/FastAlmostBandedMatrices.jl/issues/71 ei_broken = (:no_implicit_imports,), )