From 32f9e9948daa4b2c7469ff1179273ec8de2bfb41 Mon Sep 17 00:00:00 2001 From: Dimitris Floros Date: Fri, 1 Mar 2024 19:42:24 +0200 Subject: [PATCH] Refactoring codes, tests, README * tests & README * fix README * remove unnecessary combat entries * remove manifest from docs --- .JuliaFormatter.toml | 7 + .gitignore | 2 + Project.toml | 11 +- README.md | 14 +- benchmarks/run_benchmarks.jl | 153 +++++++------ docs/Manifest.toml | 127 ----------- docs/make.jl | 13 +- src/CompressedSparseBlocks.jl | 11 +- src/libcsb.jl | 412 +++++++++++++++++++++------------- test/libcsb.jl | 189 ++++++++-------- test/runtests.jl | 50 ++++- 11 files changed, 524 insertions(+), 465 deletions(-) create mode 100644 .JuliaFormatter.toml delete mode 100644 docs/Manifest.toml diff --git a/.JuliaFormatter.toml b/.JuliaFormatter.toml new file mode 100644 index 0000000..cde6d6f --- /dev/null +++ b/.JuliaFormatter.toml @@ -0,0 +1,7 @@ +style = "blue" +margin = 92 +indent = 4 +remove_extra_newlines = false +conditional_to_if = true +always_use_return = true +separate_kwargs_with_semicolon = true \ No newline at end of file diff --git a/.gitignore b/.gitignore index 20fe29d..08fdef0 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ *.jl.mem /Manifest.toml /docs/build/ +test/Manifest.toml +.vscode/settings.json diff --git a/Project.toml b/Project.toml index 8abdc54..7a411c2 100644 --- a/Project.toml +++ b/Project.toml @@ -13,11 +13,20 @@ SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" [compat] CSB_jll = "1" DocStringExtensions = "0.8, 0.9" +Documenter = "1.2" julia = "1" +Libdl = "1" +LinearAlgebra = "1" +SparseArrays = "1" [extras] +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" +JuliaFormatter = "98e50ef6-434e-11e9-1051-2b60c6c9e899" +Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] -test = ["Test", "Random"] +test = ["Aqua", "Documenter", "JET", "JuliaFormatter", "Pkg", "Test", "Random"] diff --git a/README.md b/README.md index 5867f3a..c3ec1dd 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # Julia Interface to Matrix-Vector Multiplications in CSB Format -| **Documentation** | **Build Status** | **Contributing** | -|:-------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------:|:-----:| -| [![][docs-stable-img]][docs-stable-url] [![][docs-latest-img]][docs-latest-url] | [![CI][github-action-img]][github-action-url] [![][codecov-img]][codecov-url] | [![][issues-img]][issues-url] [![][license-img]][license-url] | +| **Documentation** | **Build Status** | **Contributing** | **Extras** | +|:-------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------:|:-----:|:------:| +| [![][docs-stable-img]][docs-stable-url] [![][docs-latest-img]][docs-latest-url] | [![CI][github-action-img]][github-action-url] [![][codecov-img]][codecov-url] | [![][issues-img]][issues-url] [![][license-img]][license-url] | [![][style-img]][style-url] [![][aqua-img]][aqua-url] | We provide a `Julia` interface (a wrapper) to the `Compressed Sparse @@ -46,6 +46,8 @@ following command pkg> add CompressedSparseBlocks ``` +> :warning: **CompressedSparseBlocks is currently not working on Windows and native M1 Macs**: Either use WSL2 on Windows or use the package via `Rosetta 2` on the M-processor Macs (that means by using the `x86` and not the `arm64` `julia`). + ## Documentation - [**STABLE**][docs-stable-url] — **most recently tagged version of the documentation.** @@ -108,3 +110,9 @@ Aristotle University of Thessaloniki, Thessaloniki 54124, Greece [issues-img]: https://img.shields.io/github/issues/fcdimitr/CompressedSparseBlocks.jl.svg [issues-url]: https://github.com/fcdimitr/CompressedSparseBlocks.jl/issues + +[style-img]: https://img.shields.io/badge/code%20style-blue-4495d1.svg +[style-url]: https://github.com/invenia/BlueStyle + +[aqua-img]: https://raw.githubusercontent.com/JuliaTesting/Aqua.jl/master/badge.svg +[aqua-url]: https://github.com/JuliaTesting/Aqua.jl diff --git a/benchmarks/run_benchmarks.jl b/benchmarks/run_benchmarks.jl index d59164d..b2bc11b 100644 --- a/benchmarks/run_benchmarks.jl +++ b/benchmarks/run_benchmarks.jl @@ -7,88 +7,103 @@ using CairoMakie # to enable plotting function benchmark_csr_mv(sizes, densities, dims) - times_csc = zeros(length(sizes), length(densities), length(dims)) - times_csct = zeros(length(sizes), length(densities), length(dims)) - times_csb = zeros(length(sizes), length(densities), length(dims)) - times_csbt = zeros(length(sizes), length(densities), length(dims)) - - for (i, n) in enumerate(sizes) - for (j, d) in enumerate(densities) - for (k, r) in enumerate(dims) - - @info "Running ($n, $n) with average degree $d and $r RHS vectors" - - A = sprand( n, n, d/n ); - B = SparseMatrixCSB( A ); - - if r == 1 - x = rand(n ) - y1 = zeros(n) - y2 = zeros(n) - y3 = zeros(n) - y4 = zeros(n) - else - x = rand( n, r) - y1 = zeros(n, r) - y2 = zeros(n, r) - y3 = zeros(n, r) - y4 = zeros(n, r) + times_csc = zeros(length(sizes), length(densities), length(dims)) + times_csct = zeros(length(sizes), length(densities), length(dims)) + times_csb = zeros(length(sizes), length(densities), length(dims)) + times_csbt = zeros(length(sizes), length(densities), length(dims)) + + for (i, n) in enumerate(sizes) + for (j, d) in enumerate(densities) + for (k, r) in enumerate(dims) + + @info "Running ($n, $n) with average degree $d and $r RHS vectors" + + A = sprand(n, n, d / n) + B = SparseMatrixCSB(A) + + if r == 1 + x = rand(n) + y1 = zeros(n) + y2 = zeros(n) + y3 = zeros(n) + y4 = zeros(n) + else + x = rand(n, r) + y1 = zeros(n, r) + y2 = zeros(n, r) + y3 = zeros(n, r) + y4 = zeros(n, r) + end + times_csc[i, j, k] = @belapsed mul!($y1, $A, $x) + times_csct[i, j, k] = @belapsed mul!($y2, $(A'), $x) + times_csb[i, j, k] = @belapsed mul!($y3, $B, $x) + times_csbt[i, j, k] = @belapsed mul!($y4, $(B'), $x) + + @assert y1 ≈ y3 + @assert y2 ≈ y4 + + end end - times_csc[ i,j,k] = @belapsed mul!($y1, $A, $x) - times_csct[i,j,k] = @belapsed mul!($y2, $(A'), $x) - times_csb[ i,j,k] = @belapsed mul!($y3, $B, $x) - times_csbt[i,j,k] = @belapsed mul!($y4, $(B'), $x) - - @assert y1 ≈ y3 - @assert y2 ≈ y4 - - end end - end - return times_csc, times_csct, times_csb, times_csbt + return times_csc, times_csct, times_csb, times_csbt end -function make_figure( - sizes, densities, dims, - times_csc, times_csct, times_csb, times_csbt ) - - f = Figure( ; resolution = (1600,1200) ); - - m = length(sizes) - n = length(densities) - l = length(dims) - - axs = [ - Axis( f[i,j]; xscale = log2, # yscale = log10, - xlabel = i == l ? "matrix size" : "", - ylabel = j == 1 ? "relative speedup over CSC" : "", - title = "avg. degree = $(densities[j]) | $(dims[i]) vectors" ) - for i = 1:l, j = 1:n - ] - - for i = 1 : l - for j = 1:n - # scatterlines!( axs[i,j], sizes, vec( times_csc[: ,j,i] ) .* 1e6; label = "CSC" ) - scatterlines!( axs[i,j], sizes, vec( times_csct[:,j,i] ) .\ vec( times_csc[: ,j,i] ); label = "CSC transp." ) - scatterlines!( axs[i,j], sizes, vec( times_csb[: ,j,i] ) .\ vec( times_csc[: ,j,i] ); label = "CSB" ) - scatterlines!( axs[i,j], sizes, vec( times_csbt[:,j,i] ) .\ vec( times_csc[: ,j,i] ); label = "CSB transp." ) +function make_figure(sizes, densities, dims, times_csc, times_csct, times_csb, times_csbt) + + f = Figure(; resolution=(1600, 1200)) + + m = length(sizes) + n = length(densities) + l = length(dims) + + axs = [ + Axis( + f[i, j]; + xscale=log2, # yscale = log10, + xlabel=i == l ? "matrix size" : "", + ylabel=j == 1 ? "relative speedup over CSC" : "", + title="avg. degree = $(densities[j]) | $(dims[i]) vectors", + ) for i in 1:l, j in 1:n + ] + + for i in 1:l + for j in 1:n + # scatterlines!( axs[i,j], sizes, vec( times_csc[: ,j,i] ) .* 1e6; label = "CSC" ) + scatterlines!( + axs[i, j], + sizes, + vec(times_csct[:, j, i]) .\ vec(times_csc[:, j, i]); + label="CSC transp.", + ) + scatterlines!( + axs[i, j], + sizes, + vec(times_csb[:, j, i]) .\ vec(times_csc[:, j, i]); + label="CSB", + ) + scatterlines!( + axs[i, j], + sizes, + vec(times_csbt[:, j, i]) .\ vec(times_csc[:, j, i]); + label="CSB transp.", + ) + end end - end - [linkyaxes!(axs[i,:]...) for i = 1:size(axs,1)] - axislegend( axs[end,end]; position = :lt ) + [linkyaxes!(axs[i, :]...) for i in 1:size(axs, 1)] + axislegend(axs[end, end]; position=:lt) - f + return f end -sizes = 2 .^ (16:2:22) +sizes = 2 .^ (16:2:22) densities = [10, 15, 20] -dims = [1, 3, 10, 32] +dims = [1, 3, 10, 32] times = benchmark_csr_mv(sizes, densities, dims) -f = make_figure( sizes, densities, dims, times... ) -save( joinpath( @__DIR__, "benchmark-rel-results.png" ), f ) +f = make_figure(sizes, densities, dims, times...) +save(joinpath(@__DIR__, "benchmark-rel-results.png"), f) diff --git a/docs/Manifest.toml b/docs/Manifest.toml deleted file mode 100644 index 9c045fd..0000000 --- a/docs/Manifest.toml +++ /dev/null @@ -1,127 +0,0 @@ -# This file is machine-generated - editing it directly is not advised - -julia_version = "1.7.2" -manifest_format = "2.0" - -[[deps.ANSIColoredPrinters]] -git-tree-sha1 = "574baf8110975760d391c710b6341da1afa48d8c" -uuid = "a4c015fc-c6ff-483c-b24f-f7ea428134e9" -version = "0.0.1" - -[[deps.Artifacts]] -uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" - -[[deps.Base64]] -uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" - -[[deps.CompilerSupportLibraries_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" - -[[deps.CompressedSparseBlocks]] -deps = ["DocStringExtensions", "Libdl", "LinearAlgebra", "SparseArrays"] -path = ".." -uuid = "c9633620-f88e-4e67-b3af-074911471b78" -version = "0.1.0" - -[[deps.Dates]] -deps = ["Printf"] -uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" - -[[deps.DocStringExtensions]] -deps = ["LibGit2"] -git-tree-sha1 = "b19534d1895d702889b219c382a6e18010797f0b" -uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" -version = "0.8.6" - -[[deps.Documenter]] -deps = ["ANSIColoredPrinters", "Base64", "Dates", "DocStringExtensions", "IOCapture", "InteractiveUtils", "JSON", "LibGit2", "Logging", "Markdown", "REPL", "Test", "Unicode"] -git-tree-sha1 = "2498c3704e9cd26bf586a351473417881676bb2d" -uuid = "e30172f5-a6a5-5a46-863b-614d45cd2de4" -version = "0.27.21" - -[[deps.IOCapture]] -deps = ["Logging", "Random"] -git-tree-sha1 = "f7be53659ab06ddc986428d3a9dcc95f6fa6705a" -uuid = "b5f81e59-6552-4d32-b1f0-c071b021bf89" -version = "0.2.2" - -[[deps.InteractiveUtils]] -deps = ["Markdown"] -uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" - -[[deps.JSON]] -deps = ["Dates", "Mmap", "Parsers", "Unicode"] -git-tree-sha1 = "3c837543ddb02250ef42f4738347454f95079d4e" -uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" -version = "0.21.3" - -[[deps.LibGit2]] -deps = ["Base64", "NetworkOptions", "Printf", "SHA"] -uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" - -[[deps.Libdl]] -uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" - -[[deps.LinearAlgebra]] -deps = ["Libdl", "libblastrampoline_jll"] -uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" - -[[deps.Logging]] -uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" - -[[deps.Markdown]] -deps = ["Base64"] -uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" - -[[deps.Mmap]] -uuid = "a63ad114-7e13-5084-954f-fe012c677804" - -[[deps.NetworkOptions]] -uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" - -[[deps.OpenBLAS_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] -uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" - -[[deps.Parsers]] -deps = ["Dates"] -git-tree-sha1 = "0044b23da09b5608b4ecacb4e5e6c6332f833a7e" -uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" -version = "2.3.2" - -[[deps.Printf]] -deps = ["Unicode"] -uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" - -[[deps.REPL]] -deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] -uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" - -[[deps.Random]] -deps = ["SHA", "Serialization"] -uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" - -[[deps.SHA]] -uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" - -[[deps.Serialization]] -uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" - -[[deps.Sockets]] -uuid = "6462fe0b-24de-5631-8697-dd941f90decc" - -[[deps.SparseArrays]] -deps = ["LinearAlgebra", "Random"] -uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" - -[[deps.Test]] -deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] -uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" - -[[deps.Unicode]] -uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" - -[[deps.libblastrampoline_jll]] -deps = ["Artifacts", "Libdl", "OpenBLAS_jll"] -uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" diff --git a/docs/make.jl b/docs/make.jl index b763e06..41e4381 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,7 +1,9 @@ using CompressedSparseBlocks using Documenter -DocMeta.setdocmeta!(CompressedSparseBlocks, :DocTestSetup, :(using CompressedSparseBlocks); recursive=true) +DocMeta.setdocmeta!( + CompressedSparseBlocks, :DocTestSetup, :(using CompressedSparseBlocks); recursive=true +) makedocs(; modules=[CompressedSparseBlocks], @@ -13,12 +15,7 @@ makedocs(; canonical="https://fcdimitr.github.io/CompressedSparseBlocks.jl", assets=String[], ), - pages=[ - "Introduction" => "index.md", - ], + pages=["Introduction" => "index.md"], ) -deploydocs(; - repo="github.com/fcdimitr/CompressedSparseBlocks.jl", - devbranch="main", -) +deploydocs(; repo="github.com/fcdimitr/CompressedSparseBlocks.jl", devbranch="main") diff --git a/src/CompressedSparseBlocks.jl b/src/CompressedSparseBlocks.jl index 795a018..81587aa 100644 --- a/src/CompressedSparseBlocks.jl +++ b/src/CompressedSparseBlocks.jl @@ -4,18 +4,15 @@ export SparseMatrixCSB using Libdl, LinearAlgebra, SparseArrays, DocStringExtensions, CSB_jll -import LinearAlgebra: - mul! +import LinearAlgebra: mul! -import Base: - size, array_summary, print_array +import Base: size, array_summary, print_array -import SparseArrays: - nnz +import SparseArrays: nnz const SLACKNESS = 8 -include( "libcsb.jl" ) +include("libcsb.jl") end diff --git a/src/libcsb.jl b/src/libcsb.jl index d5e2a18..c785a98 100644 --- a/src/libcsb.jl +++ b/src/libcsb.jl @@ -7,20 +7,24 @@ to pass a `SparseMatrixCSC` object, see the constructors. """ mutable struct SparseMatrixCSB{Tv,Ti} <: SparseArrays.AbstractSparseMatrix{Tv,Ti} - m::Ti - n::Ti - nz::Ti - ptr::Ptr{Cvoid} - function SparseMatrixCSB{Tv,Ti}(m::Ti,n::Ti,nz::Ti,ptr::Ptr{Cvoid}) where {Tv, Ti} - A = new(m,n,nz,ptr) - function f(X) - @async deallocateCSB!( X ) + m::Ti + n::Ti + nz::Ti + ptr::Ptr{Cvoid} + function SparseMatrixCSB{Tv,Ti}(m::Ti, n::Ti, nz::Ti, ptr::Ptr{Cvoid}) where {Tv,Ti} + A = new(m, n, nz, ptr) + function f(X) + @async deallocateCSB!(X) + end + return finalizer(f, A) end - finalizer(f, A) - end end -CSBTYPES = Union{SparseMatrixCSB{Tv,Ti},LinearAlgebra.Adjoint{Tv,SparseMatrixCSB{Tv,Ti}},Transpose{Tv,SparseMatrixCSB{Tv,Ti}}} where {Tv,Ti} +CSBTYPES = Union{ + SparseMatrixCSB{Tv,Ti}, + LinearAlgebra.Adjoint{Tv,SparseMatrixCSB{Tv,Ti}}, + Transpose{Tv,SparseMatrixCSB{Tv,Ti}}, +} where {Tv,Ti} @@ -36,7 +40,8 @@ Convert a `SparseMatrixCSC` matrix `A` into a `SparseMatrixCSB` matrix. decides the block size internally. """ -SparseMatrixCSB(A::SparseMatrixCSC{Tv,Ti}, beta::Integer = 0) where {Tv,Ti<:Integer} = prepareCSB( A, beta ) +SparseMatrixCSB(A::SparseMatrixCSC{Tv,Ti}, beta::Integer=0) where {Tv,Ti<:Integer} = + prepareCSB(A, beta) @doc """ @@ -44,7 +49,7 @@ $(TYPEDSIGNATURES) Query the number of `Cilk` workers. """ -getWorkers() = Int64( @ccall libcsb.getWorkers()::Cint ) +getWorkers() = Int64(@ccall libcsb.getWorkers()::Cint) @doc """ $(TYPEDSIGNATURES) @@ -53,100 +58,187 @@ Set the number of `Cilk` workers to `np`. """ setWorkers(np::Int64) = @ccall libcsb.setWorkers(np::Int64)::Cvoid -function prepareCSB(A::SparseMatrixCSC{Tv,Ti}, beta = 0) where {Tv, Ti <: Integer} - size(A,1) == 0 && error( "Matrix too small." ) - size(A,2) == 0 && error( "Matrix too small." ) - nextpow(2, size(A,1)) <= SLACKNESS * getWorkers() && error( "Matrix too small." ) - nextpow(2, size(A,2)) <= SLACKNESS * getWorkers() && error( "Matrix too small." ) - mktemp() do path, io - redirect_stdout(io) do - SparseMatrixCSB{Tv,Ti}( - Ti(size(A,1)), Ti(size(A,2)), Ti(nnz(A)), - _prepareCSB( A.nzval, - A.rowval .- one(Ti), - A.colptr .- one(Ti), - Ti(nnz(A)), Ti(size(A,1)), - Ti(size(A,2)), getWorkers(), beta ) - ) +function prepareCSB(A::SparseMatrixCSC{Tv,Ti}, beta=0) where {Tv,Ti<:Integer} + size(A, 1) == 0 && error("Matrix too small.") + size(A, 2) == 0 && error("Matrix too small.") + nextpow(2, size(A, 1)) <= SLACKNESS * getWorkers() && error("Matrix too small.") + nextpow(2, size(A, 2)) <= SLACKNESS * getWorkers() && error("Matrix too small.") + mktemp() do path, io + redirect_stdout(io) do + SparseMatrixCSB{Tv,Ti}( + Ti(size(A, 1)), + Ti(size(A, 2)), + Ti(nnz(A)), + _prepareCSB( + A.nzval, + A.rowval .- one(Ti), + A.colptr .- one(Ti), + Ti(nnz(A)), + Ti(size(A, 1)), + Ti(size(A, 2)), + getWorkers(), + beta, + ), + ) + end end - end end -for (Tv, Tvname) in ((Cdouble, "double"), ) - for (Ti, Tiname) in ((Cuint, "uint32"), (Cintmax_t, "int64")) - @eval @inline function _prepareCSB( - val::Vector{$Tv}, row::Vector{$Ti}, colptr::Vector{$Ti}, - nzmax::$Ti, m::$Ti, n::$Ti, workers::Integer, - forcelogbeta::Integer) - ccall( ($("prepareCSB_" * Tvname * "_" * Tiname), libcsb), Ptr{Cvoid}, - (Ptr{$Tv}, Ptr{$Ti}, Ptr{$Ti}, $Ti, $Ti, $Ti, Cint, Cint), - val, row, colptr, nzmax, m, n, workers, forcelogbeta) +for (Tv, Tvname) in ((Cdouble, "double"),) + for (Ti, Tiname) in ((Cuint, "uint32"), (Cintmax_t, "int64")) + @eval @inline function _prepareCSB( + val::Vector{$Tv}, + row::Vector{$Ti}, + colptr::Vector{$Ti}, + nzmax::$Ti, + m::$Ti, + n::$Ti, + workers::Integer, + forcelogbeta::Integer, + ) + return ccall( + ($("prepareCSB_" * Tvname * "_" * Tiname), libcsb), + Ptr{Cvoid}, + (Ptr{$Tv}, Ptr{$Ti}, Ptr{$Ti}, $Ti, $Ti, $Ti, Cint, Cint), + val, + row, + colptr, + nzmax, + m, + n, + workers, + forcelogbeta, + ) + + end + + @eval @inline function _gespmvCSB!( + y::Vector{$Tv}, A::SparseMatrixCSB{$Tv,$Ti}, x::Vector{$Tv} + ) + return ccall( + ($("gespmv_" * Tvname * "_" * Tiname), libcsb), + Ptr{Cvoid}, + (Ptr{Cvoid}, Ptr{$Tv}, Ptr{$Tv}), + A.ptr, + x, + y, + ) + + end + + @eval @inline function _gespmvtCSB!( + y::Vector{$Tv}, + A::LinearAlgebra.Adjoint{$Tv,SparseMatrixCSB{$Tv,$Ti}}, + x::Vector{$Tv}, + ) + return ccall( + ($("gespmvt_" * Tvname * "_" * Tiname), libcsb), + Ptr{Cvoid}, + (Ptr{Cvoid}, Ptr{$Tv}, Ptr{$Tv}), + A.parent.ptr, + x, + y, + ) + + end + @eval @inline function _gespmvtCSB!( + y::Vector{$Tv}, + A::LinearAlgebra.Transpose{$Tv,SparseMatrixCSB{$Tv,$Ti}}, + x::Vector{$Tv}, + ) + return ccall( + ($("gespmvt_" * Tvname * "_" * Tiname), libcsb), + Ptr{Cvoid}, + (Ptr{Cvoid}, Ptr{$Tv}, Ptr{$Tv}), + A.parent.ptr, + x, + y, + ) + + end + + for DIM in 2:32 + @eval @inline function _gespmmCSB!( + y::Matrix{$Tv}, A::SparseMatrixCSB{$Tv,$Ti}, x::Matrix{$Tv}, ::Val{$DIM} + ) + return ccall( + ( + $("gespmm_" * Tvname * "_" * Tiname * "_" * string(DIM) * "_rhs"), + libcsb, + ), + Ptr{Cvoid}, + (Ptr{Cvoid}, Ptr{$Tv}, Ptr{$Tv}, Cint, Cint), + A.ptr, + x, + y, + size(y, 1), + size(x, 1), + ) + + end + @eval @inline function _gespmmtCSB!( + y::Matrix{$Tv}, + A::LinearAlgebra.Adjoint{$Tv,SparseMatrixCSB{$Tv,$Ti}}, + x::Matrix{$Tv}, + ::Val{$DIM}, + ) + return ccall( + ( + $("gespmmt_" * Tvname * "_" * Tiname * "_" * string(DIM) * "_rhs"), + libcsb, + ), + Ptr{Cvoid}, + (Ptr{Cvoid}, Ptr{$Tv}, Ptr{$Tv}, Cint, Cint), + A.parent.ptr, + x, + y, + size(y, 1), + size(x, 1), + ) + + end + @eval @inline function _gespmmtCSB!( + y::Matrix{$Tv}, + A::LinearAlgebra.Transpose{$Tv,SparseMatrixCSB{$Tv,$Ti}}, + x::Matrix{$Tv}, + ::Val{$DIM}, + ) + return ccall( + ( + $("gespmmt_" * Tvname * "_" * Tiname * "_" * string(DIM) * "_rhs"), + libcsb, + ), + Ptr{Cvoid}, + (Ptr{Cvoid}, Ptr{$Tv}, Ptr{$Tv}, Cint, Cint), + A.parent.ptr, + x, + y, + size(y, 1), + size(x, 1), + ) + + end + end + + @eval @inline function _deallocate!(A::SparseMatrixCSB{$Tv,$Ti}) + return ccall( + ($("deallocate_" * Tvname * "_" * Tiname), libcsb), + Ptr{Cvoid}, + (Ptr{Cvoid},), + A.ptr, + ) + + end end - - @eval @inline function _gespmvCSB!( - y::Vector{$Tv}, A::SparseMatrixCSB{$Tv,$Ti}, x::Vector{$Tv}) - ccall( ($("gespmv_" * Tvname * "_" * Tiname), libcsb), Ptr{Cvoid}, - (Ptr{Cvoid}, Ptr{$Tv}, Ptr{$Tv}), - A.ptr, x, y) - - end - - @eval @inline function _gespmvtCSB!( - y::Vector{$Tv}, A::LinearAlgebra.Adjoint{$Tv,SparseMatrixCSB{$Tv,$Ti}}, x::Vector{$Tv}) - ccall( ($("gespmvt_" * Tvname * "_" * Tiname), libcsb), Ptr{Cvoid}, - (Ptr{Cvoid}, Ptr{$Tv}, Ptr{$Tv}), - A.parent.ptr, x, y) - - end - @eval @inline function _gespmvtCSB!( - y::Vector{$Tv}, A::LinearAlgebra.Transpose{$Tv,SparseMatrixCSB{$Tv,$Ti}}, x::Vector{$Tv}) - ccall( ($("gespmvt_" * Tvname * "_" * Tiname), libcsb), Ptr{Cvoid}, - (Ptr{Cvoid}, Ptr{$Tv}, Ptr{$Tv}), - A.parent.ptr, x, y) - - end - - for DIM in 2:32 - @eval @inline function _gespmmCSB!( - y::Matrix{$Tv}, A::SparseMatrixCSB{$Tv,$Ti}, x::Matrix{$Tv}, ::Val{$DIM}) - ccall( ($("gespmm_" * Tvname * "_" * Tiname * "_" * string(DIM) * "_rhs"), libcsb), Ptr{Cvoid}, - (Ptr{Cvoid}, Ptr{$Tv}, Ptr{$Tv}, Cint, Cint), - A.ptr, x, y, size(y,1), size(x,1) ) - - end - @eval @inline function _gespmmtCSB!( - y::Matrix{$Tv}, A::LinearAlgebra.Adjoint{$Tv,SparseMatrixCSB{$Tv,$Ti}}, x::Matrix{$Tv}, ::Val{$DIM}) - ccall( ($("gespmmt_" * Tvname * "_" * Tiname * "_" * string(DIM) * "_rhs"), libcsb), Ptr{Cvoid}, - (Ptr{Cvoid}, Ptr{$Tv}, Ptr{$Tv}, Cint, Cint), - A.parent.ptr, x, y, size(y,1), size(x,1) ) - - end - @eval @inline function _gespmmtCSB!( - y::Matrix{$Tv}, A::LinearAlgebra.Transpose{$Tv,SparseMatrixCSB{$Tv,$Ti}}, x::Matrix{$Tv}, ::Val{$DIM}) - ccall( ($("gespmmt_" * Tvname * "_" * Tiname * "_" * string(DIM) * "_rhs"), libcsb), Ptr{Cvoid}, - (Ptr{Cvoid}, Ptr{$Tv}, Ptr{$Tv}, Cint, Cint), - A.parent.ptr, x, y, size(y,1), size(x,1) ) - - end - end - - @eval @inline function _deallocate!( - A::SparseMatrixCSB{$Tv,$Ti}) - ccall( ($("deallocate_" * Tvname * "_" * Tiname), libcsb), Ptr{Cvoid}, - (Ptr{Cvoid}, ), A.ptr) - - end - - end end function deallocateCSB!(A::SparseMatrixCSB) - A.ptr == C_NULL && error( "Invalid CSB object" ) - _deallocate!(A) - A.ptr = C_NULL - A.m = A.n = A.nz = 0 - nothing + A.ptr == C_NULL && error("Invalid CSB object") + _deallocate!(A) + A.ptr = C_NULL + A.m = A.n = A.nz = 0 + return nothing end @@ -155,76 +247,84 @@ end function mul!(y::AbstractVecOrMat, A::SparseMatrixCSB, x::AbstractVector) - @assert size(y,1) == size(A,1) - @assert size(x,1) == size(A,2) + @assert size(y, 1) == size(A, 1) + @assert size(x, 1) == size(A, 2) - fill!( y, 0 ) - _gespmvCSB!( y, A, x ) - y + fill!(y, 0) + _gespmvCSB!(y, A, x) + return y end function mul!(y::AbstractVecOrMat, A::SparseMatrixCSB, x::AbstractMatrix) - @assert size(y,1) == size(A,1) - @assert size(x,1) == size(A,2) - @assert size(y,2) == size(x,2) - - fill!( y, 0 ) - if size(x,2) == 1 - _gespmvCSB!( vec(y), A, vec(x) ) - elseif size(x,2) > 32 - throw( DimensionMismatch("This CSB wrapper has been compiled to support up to 32 columns at a time.") ) - else - _gespmmCSB!( y, A, x, Val(size(x,2)) ) - end - y + @assert size(y, 1) == size(A, 1) + @assert size(x, 1) == size(A, 2) + @assert size(y, 2) == size(x, 2) + + fill!(y, 0) + if size(x, 2) == 1 + _gespmvCSB!(vec(y), A, vec(x)) + elseif size(x, 2) > 32 + throw( + DimensionMismatch( + "This CSB wrapper has been compiled to support up to 32 columns at a time." + ), + ) + else + _gespmmCSB!(y, A, x, Val(size(x, 2))) + end + return y end # transpose function mul!( - y::AbstractVecOrMat, - A::Union{Adjoint{Tv,SparseMatrixCSB{Tv,Ti}}, - Transpose{Tv,SparseMatrixCSB{Tv,Ti}}}, - x::AbstractVector) where {Tv,Ti} + y::AbstractVecOrMat, + A::Union{Adjoint{Tv,SparseMatrixCSB{Tv,Ti}},Transpose{Tv,SparseMatrixCSB{Tv,Ti}}}, + x::AbstractVector, +) where {Tv,Ti} - @assert size(y,1) == size(A,1) - @assert size(x,1) == size(A,2) + @assert size(y, 1) == size(A, 1) + @assert size(x, 1) == size(A, 2) - fill!( y, 0 ) - _gespmvtCSB!( y, A, x ) - y + fill!(y, 0) + _gespmvtCSB!(y, A, x) + return y end function mul!( - y::AbstractVecOrMat, - A::Union{Adjoint{Tv,SparseMatrixCSB{Tv,Ti}}, - Transpose{Tv,SparseMatrixCSB{Tv,Ti}}}, - x::AbstractMatrix) where {Tv,Ti} - - @assert size(y,1) == size(A,1) - @assert size(x,1) == size(A,2) - @assert size(y,2) == size(x,2) - - fill!( y, 0 ) - if size(x,2) == 1 - _gespmvtCSB!( vec(y), A, vec(x) ) - elseif size(x,2) > 32 - throw( DimensionMismatch("This CSB wrapper has been compiled to support up to 32 columns at a time.") ) - else - _gespmmtCSB!( y, A, x, Val(size(x,2)) ) - end - y + y::AbstractVecOrMat, + A::Union{Adjoint{Tv,SparseMatrixCSB{Tv,Ti}},Transpose{Tv,SparseMatrixCSB{Tv,Ti}}}, + x::AbstractMatrix, +) where {Tv,Ti} + + @assert size(y, 1) == size(A, 1) + @assert size(x, 1) == size(A, 2) + @assert size(y, 2) == size(x, 2) + + fill!(y, 0) + if size(x, 2) == 1 + _gespmvtCSB!(vec(y), A, vec(x)) + elseif size(x, 2) > 32 + throw( + DimensionMismatch( + "This CSB wrapper has been compiled to support up to 32 columns at a time." + ), + ) + else + _gespmmtCSB!(y, A, x, Val(size(x, 2))) + end + return y end -size( A::SparseMatrixCSB ) = (A.m, A.n) -nnz( A::SparseMatrixCSB ) = A.nz -nnz( A::LinearAlgebra.Adjoint{Tv,SparseMatrixCSB{Tv,Ti}} ) where {Tv,Ti} = A.parent.nz -nnz( A::LinearAlgebra.Transpose{Tv,SparseMatrixCSB{Tv,Ti}} ) where {Tv,Ti} = A.parent.nz +size(A::SparseMatrixCSB) = (A.m, A.n) +nnz(A::SparseMatrixCSB) = A.nz +nnz(A::LinearAlgebra.Adjoint{Tv,SparseMatrixCSB{Tv,Ti}}) where {Tv,Ti} = A.parent.nz +nnz(A::LinearAlgebra.Transpose{Tv,SparseMatrixCSB{Tv,Ti}}) where {Tv,Ti} = A.parent.nz function Base.print_matrix(io::IO, S::CSBTYPES) @@ -233,9 +333,19 @@ end function array_summary(io::IO, S::CSBTYPES, dims::Tuple{Vararg{Base.OneTo}}) xnnz = nnz(S) m, n = size(S) - print(io, m, "×", n, " ", typeof(S), " with ", xnnz, " stored ", - xnnz == 1 ? "entry" : "entries") - nothing + print( + io, + m, + "×", + n, + " ", + typeof(S), + " with ", + xnnz, + " stored ", + xnnz == 1 ? "entry" : "entries", + ) + return nothing end function print_array(io::IO, A::CSBTYPES) diff --git a/test/libcsb.jl b/test/libcsb.jl index 3c9c364..b4e9708 100644 --- a/test/libcsb.jl +++ b/test/libcsb.jl @@ -1,138 +1,143 @@ -m, n, d = 10_134, 39_439, 10 -A = sprand( m, n, d/m ) -Auint32 = SparseMatrixCSC{Float64,UInt32}( A ); -x = rand( n ) -xt = rand( m ) +m, n, d = 10_134, 39_439, 10 +A = sprand(m, n, d / m) +Auint32 = SparseMatrixCSC{Float64,UInt32}(A); +x = rand(n) +xt = rand(m) -import CompressedSparseBlocks: - getWorkers, setWorkers +import CompressedSparseBlocks: getWorkers, setWorkers @testset "Cilk RTS" begin - np = getWorkers(); - setWorkers(3) - @test getWorkers() == 3 - setWorkers(np) - @test getWorkers() == np + np = getWorkers() + setWorkers(3) + @test getWorkers() == 3 + setWorkers(np) + @test getWorkers() == np end @testset "CSB construction/deconstruction" begin - B = SparseMatrixCSB( A ) - @test nnz(B) == nnz(A) - @test size(B) == size(A) - - @test repr( Base.print_array(Base.stdout, B) ) == "nothing" - @test repr( Base.print_matrix(Base.stdout, B) ) == "nothing" - @test repr( summary(B) ) == "\"$(m)×$(n) SparseMatrixCSB{Float64, Int64} with $(nnz(A)) stored entries\"" - @test repr( summary(B') ) == "\"$(n)×$(m) Adjoint{Float64, SparseMatrixCSB{Float64, Int64}} with $(nnz(A)) stored entries\"" - - finalize( B ) - sleep(0.1) - @test B.ptr == C_NULL - - B = SparseMatrixCSB( Auint32 ) - @test nnz(B) == nnz(A) - @test nnz(B') == nnz(A) - @test nnz(transpose(B)) == nnz(A) - @test size(B) == size(A) - finalize( B ) - sleep(0.1) - @test B.ptr == C_NULL + B = SparseMatrixCSB(A) + @test nnz(B) == nnz(A) + @test size(B) == size(A) + + @test repr(Base.print_array(Base.stdout, B)) == "nothing" + @test repr(Base.print_matrix(Base.stdout, B)) == "nothing" + @test repr(summary(B)) == + "\"$(m)×$(n) SparseMatrixCSB{Float64, Int64} with $(nnz(A)) stored entries\"" + @test repr(summary(B')) == + "\"$(n)×$(m) Adjoint{Float64, SparseMatrixCSB{Float64, Int64}} with $(nnz(A)) stored entries\"" + + finalize(B) + sleep(0.1) + @test B.ptr == C_NULL + + B = SparseMatrixCSB(Auint32) + @test nnz(B) == nnz(A) + @test nnz(B') == nnz(A) + @test nnz(transpose(B)) == nnz(A) + @test size(B) == size(A) + finalize(B) + sleep(0.1) + @test B.ptr == C_NULL end @testset "CSB too small matrices" begin - min_size = Int( 2^floor( log2( CompressedSparseBlocks.SLACKNESS * CompressedSparseBlocks.getWorkers() ) ) ) + min_size = Int( + 2^floor( + log2(CompressedSparseBlocks.SLACKNESS * CompressedSparseBlocks.getWorkers()) + ), + ) - for i = 0 : min_size - @test_throws ErrorException("Matrix too small.") SparseMatrixCSB( sprand(i, i, 0.5) ); - end + for i in 0:min_size + @test_throws ErrorException("Matrix too small.") SparseMatrixCSB(sprand(i, i, 0.5)) + end - B = SparseMatrixCSB( sprand(min_size+1, min_size+1, 0.5) ); + B = SparseMatrixCSB(sprand(min_size + 1, min_size + 1, 0.5)) - @test size( B ) == (min_size+1, min_size+1) + @test size(B) == (min_size + 1, min_size + 1) end @testset "matrix-vector multiplication" begin - B = SparseMatrixCSB( A ) - @test A * x ≈ B * x + B = SparseMatrixCSB(A) + @test A * x ≈ B * x - B = SparseMatrixCSB( Auint32 ) - @test Auint32 * x ≈ B * x + B = SparseMatrixCSB(Auint32) + @test Auint32 * x ≈ B * x end @testset "matrix-matrix multiplication" begin - B = SparseMatrixCSB( A ) - @testset "d = $d" for d = 1:32 - xx = rand( n, d ) - @test A * xx ≈ B * xx - end + B = SparseMatrixCSB(A) + @testset "d = $d" for d in 1:32 + xx = rand(n, d) + @test A * xx ≈ B * xx + end - @testset "d = 33" begin - xx = rand( n, 33 ) - @test_throws DimensionMismatch B*xx; - end + @testset "d = 33" begin + xx = rand(n, 33) + @test_throws DimensionMismatch B * xx + end - B = SparseMatrixCSB( Auint32 ) - @testset "d = $d" for d = 1:32 - xx = rand( n, d ) - @test Auint32 * xx ≈ B * xx - end + B = SparseMatrixCSB(Auint32) + @testset "d = $d" for d in 1:32 + xx = rand(n, d) + @test Auint32 * xx ≈ B * xx + end - @testset "d = 33" begin - xx = rand( n, 33 ) - @test_throws DimensionMismatch B*xx; - end + @testset "d = 33" begin + xx = rand(n, 33) + @test_throws DimensionMismatch B * xx + end end @testset "matrix-vector transpose multiplication" begin - B = SparseMatrixCSB( A ) - @test A' * xt ≈ B' * xt - @test transpose(A) * xt ≈ transpose(B) * xt + B = SparseMatrixCSB(A) + @test A' * xt ≈ B' * xt + @test transpose(A) * xt ≈ transpose(B) * xt - B = SparseMatrixCSB( Auint32 ) - @test Auint32' * xt ≈ B' * xt - @test transpose(Auint32) * xt ≈ transpose(B) * xt + B = SparseMatrixCSB(Auint32) + @test Auint32' * xt ≈ B' * xt + @test transpose(Auint32) * xt ≈ transpose(B) * xt end @testset "matrix-matrix transpose multiplication" begin - B = SparseMatrixCSB( A ) - @testset "d = $d" for d = 1:32 - xx = rand( m, d ) - @test A' * xx ≈ B' * xx - @test transpose(A) * xx ≈ transpose(B) * xx - end - - @testset "d = 33" begin - xx = rand( m, 33 ) - @test_throws DimensionMismatch B'*xx; - @test_throws DimensionMismatch transpose(B)*xx; - end - - B = SparseMatrixCSB( Auint32 ) - @testset "d = $d" for d = 1:32 - xx = rand( m, d ) - @test Auint32' * xx ≈ B' * xx - @test transpose(Auint32) * xx ≈ transpose(B) * xx - end - - @testset "d = 33" begin - xx = rand( m, 33 ) - @test_throws DimensionMismatch B'*xx; - @test_throws DimensionMismatch transpose(B)*xx; - end + B = SparseMatrixCSB(A) + @testset "d = $d" for d in 1:32 + xx = rand(m, d) + @test A' * xx ≈ B' * xx + @test transpose(A) * xx ≈ transpose(B) * xx + end + + @testset "d = 33" begin + xx = rand(m, 33) + @test_throws DimensionMismatch B' * xx + @test_throws DimensionMismatch transpose(B) * xx + end + + B = SparseMatrixCSB(Auint32) + @testset "d = $d" for d in 1:32 + xx = rand(m, d) + @test Auint32' * xx ≈ B' * xx + @test transpose(Auint32) * xx ≈ transpose(B) * xx + end + + @testset "d = 33" begin + xx = rand(m, 33) + @test_throws DimensionMismatch B' * xx + @test_throws DimensionMismatch transpose(B) * xx + end end diff --git a/test/runtests.jl b/test/runtests.jl index d5b92ad..6b5e2e4 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,17 +1,53 @@ using CompressedSparseBlocks, SparseArrays, LinearAlgebra using Test, Random +using JuliaFormatter +using Aqua +using JET +using Documenter +using Pkg + +function get_pkg_version(name::AbstractString) + for dep in values(Pkg.dependencies()) + if dep.name == name + return dep.version + end + end + return error("Dependency not available") +end enabled_tests = lowercase.(ARGS) function addtests(fname) - key = lowercase(splitext(fname)[1]) - if isempty(enabled_tests) || key in enabled_tests - Random.seed!(0) - @testset "$(titlecase(fname)) tests" begin - include("$fname.jl") + key = lowercase(splitext(fname)[1]) + if isempty(enabled_tests) || key in enabled_tests + Random.seed!(0) + @testset "$(titlecase(fname)) tests" begin + include("$fname.jl") + end end - end end @testset "CSB.jl" begin - addtests("libcsb") + @testset "Code quality" begin + if VERSION >= v"1.6" + Aqua.test_all( + CompressedSparseBlocks; ambiguities=false, deps_compat=(check_extras=false,) + ) + end + end + @testset "Code formatting" begin + @test JuliaFormatter.format(CompressedSparseBlocks; verbose=false, overwrite=false) + end + @testset "Code quality (JET.jl)" begin + if VERSION >= v"1.9" + @assert get_pkg_version("JET") >= v"0.8.4" + JET.test_package( + CompressedSparseBlocks; + target_defined_modules=true, + ignore_missing_comparison=true, + ) + end + end + doctest(CompressedSparseBlocks) + + addtests("libcsb") end