diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..d60f070 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,7 @@ +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" # Location of package manifests + schedule: + interval: "monthly" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 85f2806..ed47b14 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,33 +8,29 @@ jobs: fail-fast: false matrix: version: + - '1.8' - '1.9' + - '1.10' os: - ubuntu-latest + - windows-latest arch: - x64 steps: - - uses: actions/checkout@v2 - - uses: julia-actions/setup-julia@v1 + - uses: actions/checkout@v4 + - uses: julia-actions/setup-julia@v2 with: version: ${{ matrix.version }} arch: ${{ matrix.arch }} - - uses: actions/cache@v1 - env: - cache-name: cache-artifacts - with: - path: ~/.julia/artifacts - key: ${{ runner.os }}-test-${{ env.cache-name }}-${{ hashFiles('**/Project.toml') }} - restore-keys: | - ${{ runner.os }}-test-${{ env.cache-name }}- - ${{ runner.os }}-test- - ${{ runner.os }}- + - uses: julia-actions/cache@v2 - uses: julia-actions/julia-buildpkg@v1 - uses: julia-actions/julia-runtest@v1 - uses: julia-actions/julia-processcoverage@v1 - - uses: codecov/codecov-action@v1 + - uses: codecov/codecov-action@v4 with: file: lcov.info + verbose: true + docs: name: Documentation runs-on: ubuntu-latest @@ -42,7 +38,7 @@ jobs: - uses: actions/checkout@v2 - uses: julia-actions/setup-julia@v1 with: - version: '1.9' + version: '1.10' - run: | julia --project=docs -e ' using Pkg @@ -52,3 +48,30 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }} + + downgrade: + name: Downgrade ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + version: + - '1.10' + os: + - ubuntu-latest + arch: + - x64 + steps: + - uses: actions/checkout@v4 + - uses: julia-actions/setup-julia@v2 + with: + version: ${{ matrix.version }} + arch: ${{ matrix.arch }} + - uses: julia-actions/cache@v2 + - uses: julia-actions/julia-downgrade-compat@v1 + with: # As per documentation, we exclude packages within the Julia standard library + skip: LinearAlgebra,SparseArrays + - uses: julia-actions/julia-buildpkg@v1 + - uses: julia-actions/julia-runtest@v1 + with: + coverage: false diff --git a/NEWS.md b/NEWS.md index d9b9aee..a4c675e 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,5 @@ # Changelog + All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), @@ -6,25 +7,35 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.6.8] - 2024.08.29 +### Added + +- Added `SparseMatrixCSC` and `AbstractMatrix` constructors. + ### Fixed -- Fixed show method for SparseMatrixCSR + +- Fixed show method for SparseMatrixCSR. +- Fixes related to `TransposeFactorization` (see https://github.com/JuliaLang/julia/pull/46874). ## [0.6.6] - 2021.11.26 ### Added + - Implemented `Base.setindex!`. ## [0.6.5] - 2021.10.20 ### Fixed + - Return value of `LinearAlbegra.fillstored!`. ### Added + - Implemented `LinearAlbegra.rmul!`. ## [0.6.4] - 2021.10.20 ### Added + - Implemented `LinearAlbegra.fillstored!`. *Previous releases are not included in this Changelog* diff --git a/README.md b/README.md index 461ff51..58ccbe6 100644 --- a/README.md +++ b/README.md @@ -7,5 +7,3 @@ Sparse matrices in CSR format (symmetric and non-symmetric) for Julia computatio | [![](https://img.shields.io/badge/docs-stable-blue.svg)](https://gridap.github.io/SparseMatricesCSR.jl/stable) [![](https://img.shields.io/badge/docs-dev-blue.svg)](https://gridap.github.io/SparseMatricesCSR.jl/dev) | |**Build Status** | | [![Build Status](https://github.com/gridap/SparseMatricesCSR.jl/workflows/CI/badge.svg?branch=master)](https://github.com/gridap/SparseMatricesCSR.jl/actions?query=workflow%3ACI) [![Codecov](https://codecov.io/gh/gridap/SparseMatricesCSR.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/gridap/SparseMatricesCSR.jl) | - - diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..4cdc6db --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,2 @@ +Manifest.toml +build \ No newline at end of file diff --git a/docs/Project.toml b/docs/Project.toml index f6759c2..a7b73e8 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -1,3 +1,4 @@ [deps] Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +DocumenterInterLinks = "d12716ef-a0f6-4df4-a9f1-a5a34e75c656" SparseMatricesCSR = "a0a7dd2c-ebf4-11e9-1f05-cf50bc540ca1" diff --git a/docs/make.jl b/docs/make.jl index 9c7a601..15b2438 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,4 +1,9 @@ -using Documenter, SparseMatricesCSR +using Documenter, DocumenterInterLinks +using SparseMatricesCSR + +links = InterLinks( + "SparseArrays" => "https://docs.julialang.org/en/v1/" +) makedocs(; modules=[SparseMatricesCSR], @@ -9,6 +14,7 @@ makedocs(; repo="https://github.com/gridap/SparseMatricesCSR.jl/blob/{commit}{path}#L{line}", sitename="SparseMatricesCSR.jl", authors="Víctor Sande and Francesc Verdugo ", + plugins=[links], ) deploydocs(; diff --git a/src/SparseMatricesCSR.jl b/src/SparseMatricesCSR.jl index e7f6654..44044b4 100644 --- a/src/SparseMatricesCSR.jl +++ b/src/SparseMatricesCSR.jl @@ -6,7 +6,7 @@ using SuiteSparse import Base: convert, copy, size, getindex, setindex!, show, count, *, IndexStyle import LinearAlgebra: mul!, lu, lu! -import SparseArrays: nnz, getnzval, nonzeros, nzrange +import SparseArrays: nnz, getnzval, nonzeros, nzvalview, nzrange import SparseArrays: findnz, rowvals, getnzval, issparse export SparseMatrixCSR diff --git a/src/SparseMatrixCSR.jl b/src/SparseMatrixCSR.jl index 6dd5676..f1e73f6 100644 --- a/src/SparseMatrixCSR.jl +++ b/src/SparseMatrixCSR.jl @@ -55,6 +55,20 @@ function SparseMatrixCSR(a::Transpose{Tv,<:SparseMatrixCSC} where Tv) SparseMatrixCSR{1}(size(a,1),size(a,2),at.colptr,rowvals(at),nonzeros(at)) end +""" + SparseMatrixCSR(a::SparseMatrixCSC} + +Build a 1-based `SparseMatrixCSR` from a `SparseMatrixCSC`. +""" +SparseMatrixCSR(a::SparseMatrixCSC) = SparseMatrixCSR(transpose(sparse(transpose(a)))) + +""" + SparseMatrixCSR(a::AbstractMatrix} + +Build a 1-based `SparseMatrixCSR` from an `AbstractMatrix`. +""" +SparseMatrixCSR(a::AbstractMatrix) = SparseMatrixCSR(sparse(a)) + """ SparseMatrixCSR{Bi}(a::Transpose{Tv,<:SparseMatrixCSC} where Tv) where Bi @@ -77,7 +91,7 @@ SparseMatrixCSR{1}(a::Transpose{Tv,<:SparseMatrixCSC} where Tv) = SparseMatrixCS Create a `SparseMatrixCSR` with `Bi`-based indexing (1 by default) from the same `args...` as one constructs a `SparseMatrixCSC` -with the [`sparse`](@ref) function. +with the [`SparseArrays.sparse`](@extref) function. """ sparsecsr(I,J,V) = SparseMatrixCSR(transpose(sparse(J,I,V,dimlub(J),dimlub(I)))) sparsecsr(I,J,V,m,n) = SparseMatrixCSR(transpose(sparse(J,I,V,n,m))) @@ -133,27 +147,31 @@ end function LinearAlgebra.lu(a::SparseMatrixCSR{0}) rowptr = _copy_and_increment(a.rowptr) colval = _copy_and_increment(a.colval) - Transpose(lu(SparseMatrixCSC(a.m,a.n,rowptr,colval,a.nzval))) + transpose(lu(SparseMatrixCSC(a.m,a.n,rowptr,colval,a.nzval))) end function LinearAlgebra.lu(a::SparseMatrixCSR{1}) - Transpose(lu(SparseMatrixCSC(a.m,a.n,a.rowptr,a.colval,a.nzval))) + transpose(lu(SparseMatrixCSC(a.m,a.n,a.rowptr,a.colval,a.nzval))) end if Base.USE_GPL_LIBS +const TransposeFact = isdefined(LinearAlgebra, :TransposeFactorization) ? + LinearAlgebra.TransposeFactorization : + Transpose + function LinearAlgebra.lu!( - translu::Transpose{T,<:SuiteSparse.UMFPACK.UmfpackLU{T}}, + translu::TransposeFact{T,<:SuiteSparse.UMFPACK.UmfpackLU{T}}, a::SparseMatrixCSR{1}) where {T} - Transpose(lu!(translu.parent,SparseMatrixCSC(a.m,a.n,a.rowptr,a.colval,a.nzval))) + transpose(lu!(translu.parent,SparseMatrixCSC(a.m,a.n,a.rowptr,a.colval,a.nzval))) end function LinearAlgebra.lu!( - translu::Transpose{T,<:SuiteSparse.UMFPACK.UmfpackLU{T}}, + translu::TransposeFact{T,<:SuiteSparse.UMFPACK.UmfpackLU{T}}, a::SparseMatrixCSR{0}) where {T} rowptr = _copy_and_increment(a.rowptr) colval = _copy_and_increment(a.colval) - Transpose(lu!(translu.parent,SparseMatrixCSC(a.m,a.n,rowptr,colval,a.nzval))) + transpose(lu!(translu.parent,SparseMatrixCSC(a.m,a.n,rowptr,colval,a.nzval))) end end # Base.USE_GPL_LIBS @@ -223,7 +241,7 @@ issparse(S::SparseMatrixCSR) = true Returns the number of stored (filled) elements in a sparse array. """ -nnz(S::SparseMatrixCSR) = length(nonzeros(S)) +nnz(S::SparseMatrixCSR{Bi}) where Bi = Int(S.rowptr[size(S, 1) + 1] - Bi) """ nonzeros(S::SparseMatrixCSR) @@ -235,6 +253,8 @@ and any modifications to the returned vector will mutate S as well. """ nonzeros(S::SparseMatrixCSR) = S.nzval +nzvalview(S::SparseMatrixCSR) = view(nonzeros(S), 1:nnz(S)) + """ colvals(S::SparseMatrixCSR{Bi}) where {Bi} @@ -289,8 +309,8 @@ end Count the number of elements in `nonzeros(S)` for which predicate `pred` returns `true`. If `pred` not given, it counts the number of `true` values. """ -count(pred, S::SparseMatrixCSR) = count(pred, nonzeros(S)) -count(S::SparseMatrixCSR) = count(i->true, nonzeros(S)) +count(pred, S::SparseMatrixCSR) = count(pred, nzvalview(S)) +count(S::SparseMatrixCSR) = count(i->true, nzvalview(S)) function mul!(y::AbstractVector,A::SparseMatrixCSR,v::AbstractVector, α::Number, β::Number) A.n == size(v, 1) || throw(DimensionMismatch()) diff --git a/test/SparseMatrixCSR.jl b/test/SparseMatrixCSR.jl index 10b5a3a..79fc2d9 100644 --- a/test/SparseMatrixCSR.jl +++ b/test/SparseMatrixCSR.jl @@ -79,7 +79,7 @@ function test_csr(Bi,Tv,Ti) @test getBi(CSR) == Bi @test getoffset(CSR) == 1-Bi @test nnz(CSR) == nnz(CSC) - @test length(nonzeros(CSR)) == nnz(CSR) + @test length(SparseArrays.nzvalview(CSR)) == nnz(CSR) @test nonzeros(CSR) === CSR.nzval @test colvals(CSR) === CSR.colval i,j,v = findnz(CSR) @@ -106,11 +106,22 @@ function test_csr(Bi,Tv,Ti) mul!(z,CSC,x) @test y ≈ z + # test constructors + @test CSR == SparseMatrixCSR(CSC) + @test CSR == SparseMatrixCSR(Matrix(CSC)) + _CSR = copy(CSR) out = LinearAlgebra.rmul!(CSR,-1) @test out === CSR @test _CSR ≈ -1*CSR + # Test overlong buffers + let A = sparsecsr([1, 2, 3], [1, 2, 3], [4., 5, 6]) + push!(A.nzval, 4.0) + push!(A.rowptr, -1) + @test nnz(A) == length(SparseArrays.nzvalview(A)) == 3 + @test SparseArrays.nzvalview(A) == [4., 5, 6] + end end function test_lu(Bi,I,J,V) @@ -135,13 +146,13 @@ for Bi in (0,1) end if Base.USE_GPL_LIBS # `lu!` requires `SuiteSparse.UMFPACK` - I = [1,1,2,2,2,3,3] - J = [1,2,1,2,3,2,3] - V = [4.0,1.0,-1.0,4.0,1.0,-1.0,4.0] - test_lu(0,I,J,V) - test_lu(1,I,J,V) + I = [1,1,2,2,2,3,3] + J = [1,2,1,2,3,2,3] + V = [4.0,1.0,-1.0,4.0,1.0,-1.0,4.0] + test_lu(0,I,J,V) + test_lu(1,I,J,V) else - @warn "Tests run without GPL libraries." + @warn "Tests run without GPL libraries." end end # module