From d9eec3b7dbae069318bb27964d54b382efcbace9 Mon Sep 17 00:00:00 2001 From: Alberto Mercurio Date: Mon, 26 Jan 2026 20:00:45 +0100 Subject: [PATCH] Rename to GenericSparseArrays --- .github/copilot-instructions.md | 6 +- .github/workflows/CI.yml | 6 +- GEMINI.md | 4 +- Project.toml | 4 +- README.md | 24 +-- benchmarks/Project.toml | 2 +- benchmarks/README.md | 8 +- benchmarks/benchmark_utils.jl | 10 +- benchmarks/conversion_benchmarks.jl | 14 +- benchmarks/matrix_benchmarks.jl | 48 +++--- benchmarks/runbenchmarks.jl | 2 +- benchmarks/vector_benchmarks.jl | 4 +- docs/Project.toml | 2 +- docs/make.jl | 14 +- docs/src/api.md | 16 +- docs/src/index.md | 32 ++-- ext/DeviceSparseArraysJLArraysExt.jl | 11 -- ext/GenericSparseArraysJLArraysExt.jl | 11 ++ ...SparseArrays.jl => GenericSparseArrays.jl} | 10 +- src/conversions/conversions.jl | 92 ++++++------ src/core.jl | 50 +++--- src/matrix_coo/matrix_coo.jl | 136 ++++++++--------- src/matrix_csc/matrix_csc.jl | 136 ++++++++--------- src/matrix_csr/matrix_csr.jl | 142 +++++++++--------- src/vector/vector.jl | 74 ++++----- test/cuda/Project.toml | 2 +- test/metal/Project.toml | 2 +- test/runtests.jl | 36 ++--- test/shared/code_quality.jl | 54 +++---- test/shared/conversions.jl | 72 ++++----- test/shared/matrix_coo.jl | 50 +++--- test/shared/matrix_csc.jl | 50 +++--- test/shared/matrix_csr.jl | 50 +++--- test/shared/vector.jl | 18 +-- 34 files changed, 596 insertions(+), 596 deletions(-) delete mode 100644 ext/DeviceSparseArraysJLArraysExt.jl create mode 100644 ext/GenericSparseArraysJLArraysExt.jl rename src/{DeviceSparseArrays.jl => GenericSparseArrays.jl} (79%) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 0aa5981..e423770 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1,15 +1,15 @@ -# Copilot Instructions for DeviceSparseArrays.jl +# Copilot Instructions for GenericSparseArrays.jl These guidelines give AI coding agents the minimum project-specific context to be productive. They reflect the repository as it exists now and should NOT assume unimplemented features. ## 1. Purpose & Current State -- Package name: `DeviceSparseArrays` — intended focus: backend-agnostic sparse array types & operations for CPU/GPU/accelerators. +- Package name: `GenericSparseArrays` — intended focus: backend-agnostic sparse array types & operations for CPU/GPU/accelerators. - Unlike traditional SparseArrays.jl, this package aims to provide a unified interface for sparse data structures that can seamlessly operate across different hardware backends. - Any new functionality you add must be inside this module and accompanied by tests + docstrings. ## 2. Repository Layout - `Project.toml` / `Manifest.toml`: Project environment. Add deps with compat bounds in alphabetical order; do not remove existing `[compat]` or test extras. -- `src/DeviceSparseArrays.jl`: Single entry point. Keep exports explicit (add an `export` block when you introduce public APIs). Keep imports explicit (use `import PackageName: symbol` or `using PackageName: symbol` as needed). +- `src/GenericSparseArrays.jl`: Single entry point. Keep exports explicit (add an `export` block when you introduce public APIs). Keep imports explicit (use `import PackageName: symbol` or `using PackageName: symbol` as needed). - `docs/` (Documenter): `make.jl` sets up docs + doctests. `docs/src/index.md` auto-docs the module; adding docstrings automatically surfaces them. ## 3. Development Workflows diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 3a2fa40..bb93cf2 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -100,6 +100,6 @@ jobs: shell: julia --project=docs --color=yes {0} run: | using Documenter: DocMeta, doctest - using DeviceSparseArrays - DocMeta.setdocmeta!(DeviceSparseArrays, :DocTestSetup, :(using DeviceSparseArrays); recursive=true) - doctest(DeviceSparseArrays) + using GenericSparseArrays + DocMeta.setdocmeta!(GenericSparseArrays, :DocTestSetup, :(using GenericSparseArrays); recursive=true) + doctest(GenericSparseArrays) diff --git a/GEMINI.md b/GEMINI.md index 0a1bc97..00a5357 100644 --- a/GEMINI.md +++ b/GEMINI.md @@ -1,8 +1,8 @@ -# Gemini Project Context: DeviceSparseArrays.jl +# Gemini Project Context: GenericSparseArrays.jl ## Project Overview -`DeviceSparseArrays.jl` is a Julia package that provides backend-agnostic sparse array types and operations for CPUs, GPUs, and other accelerators. It aims to offer a unified interface for sparse data structures that can seamlessly operate across different hardware backends. +`GenericSparseArrays.jl` is a Julia package that provides backend-agnostic sparse array types and operations for CPUs, GPUs, and other accelerators. It aims to offer a unified interface for sparse data structures that can seamlessly operate across different hardware backends. The package supports various sparse formats like CSC, CSR, and COO, and can be used with backends such as: - CPU (standard Julia arrays) diff --git a/Project.toml b/Project.toml index c98a673..2854d2e 100644 --- a/Project.toml +++ b/Project.toml @@ -1,4 +1,4 @@ -name = "DeviceSparseArrays" +name = "GenericSparseArrays" uuid = "da3fe0eb-88a8-4d14-ae1a-857c283e9c70" authors = ["Alberto Mercurio and contributors"] version = "0.1.0" @@ -15,7 +15,7 @@ SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" JLArrays = "27aeb0d3-9eb9-45fb-866b-73c2ecf80fcb" [extensions] -DeviceSparseArraysJLArraysExt = "JLArrays" +GenericSparseArraysJLArraysExt = "JLArrays" [compat] AcceleratedKernels = "0.4" diff --git a/README.md b/README.md index bec6acc..6bb3fee 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,17 @@ -# DeviceSparseArrays +# GenericSparseArrays -[![Stable](https://img.shields.io/badge/docs-stable-blue.svg)](https://albertomercurio.github.io/DeviceSparseArrays.jl/stable/) -[![Dev](https://img.shields.io/badge/docs-dev-blue.svg)](https://albertomercurio.github.io/DeviceSparseArrays.jl/dev/) -[![Build Status](https://github.com/albertomercurio/DeviceSparseArrays.jl/actions/workflows/CI.yml/badge.svg?branch=main)](https://github.com/albertomercurio/DeviceSparseArrays.jl/actions/workflows/CI.yml?query=branch%3Amain) -[![Coverage](https://codecov.io/gh/albertomercurio/DeviceSparseArrays.jl/branch/main/graph/badge.svg)](https://codecov.io/gh/albertomercurio/DeviceSparseArrays.jl) +[![Stable](https://img.shields.io/badge/docs-stable-blue.svg)](https://albertomercurio.github.io/GenericSparseArrays.jl/stable/) +[![Dev](https://img.shields.io/badge/docs-dev-blue.svg)](https://albertomercurio.github.io/GenericSparseArrays.jl/dev/) +[![Build Status](https://github.com/albertomercurio/GenericSparseArrays.jl/actions/workflows/CI.yml/badge.svg?branch=main)](https://github.com/albertomercurio/GenericSparseArrays.jl/actions/workflows/CI.yml?query=branch%3Amain) +[![Coverage](https://codecov.io/gh/albertomercurio/GenericSparseArrays.jl/branch/main/graph/badge.svg)](https://codecov.io/gh/albertomercurio/GenericSparseArrays.jl) [![Aqua](https://raw.githubusercontent.com/JuliaTesting/Aqua.jl/master/badge.svg)](https://github.com/JuliaTesting/Aqua.jl) -[![Benchmarks](https://github.com/albertomercurio/DeviceSparseArrays.jl/actions/workflows/Benchmarks.yml/badge.svg?branch=main)](https://albertomercurio.github.io/DeviceSparseArrays.jl/benchmarks/) +[![Benchmarks](https://github.com/albertomercurio/GenericSparseArrays.jl/actions/workflows/Benchmarks.yml/badge.svg?branch=main)](https://albertomercurio.github.io/GenericSparseArrays.jl/benchmarks/) [![code style: runic][runic-img]][runic-url] [runic-img]: https://img.shields.io/badge/code_style-%E1%9A%B1%E1%9A%A2%E1%9A%BE%E1%9B%81%E1%9A%B2-black [runic-url]: https://github.com/fredrikekre/Runic.jl -DeviceSparseArrays.jl is a Julia package that provides backend-agnostic sparse array types and operations for CPU, GPU, and other accelerators. It aims to offer a unified interface for sparse data structures that can seamlessly operate across different hardware backends. For example, a `DeviceSparseMatrixCSC` type could represent a sparse matrix stored in Compressed Sparse Column format, where the underlying data could reside in CPU, GPU, or any other memory type, dispatching specific implementations based on the target device. This allows users to write code that is portable and efficient across various hardware platforms without needing to change their code for different backends. The aim of the package is to support a wide range of different sparse formats (e.g., CSC, CSR, COO) as well as different backends like: +GenericSparseArrays.jl is a Julia package that provides backend-agnostic sparse array types and operations for CPU, GPU, and other accelerators. It aims to offer a unified interface for sparse data structures that can seamlessly operate across different hardware backends. For example, a `GenericSparseMatrixCSC` type could represent a sparse matrix stored in Compressed Sparse Column format, where the underlying data could reside in CPU, GPU, or any other memory type, dispatching specific implementations based on the target device. This allows users to write code that is portable and efficient across various hardware platforms without needing to change their code for different backends. The aim of the package is to support a wide range of different sparse formats (e.g., CSC, CSR, COO) as well as different backends like: - CPU (using standard Julia arrays) - GPU (using [CUDA.jl](https://github.com/JuliaGPU/CUDA.jl), [AMDGPU.jl](https://github.com/JuliaGPU/AMDGPU.jl), [oneAPI.jl](https://github.com/JuliaGPU/oneAPI.jl), [Metal.jl](https://github.com/JuliaGPU/Metal.jl), etc.) - [DistributedArrays.jl](https://github.com/JuliaParallel/DistributedArrays.jl) (for distributed computing) @@ -28,7 +28,7 @@ The package aims to use [KernelAbstractions.jl](https://github.com/JuliaGPU/Kern You can install the package using Julia's package manager. In the Julia REPL, run: ```julia using Pkg -Pkg.add(url="https://github.com/albertomercurio/DeviceSparseArrays.jl") +Pkg.add(url="https://github.com/albertomercurio/GenericSparseArrays.jl") ``` ## Usage Examples @@ -36,15 +36,15 @@ Pkg.add(url="https://github.com/albertomercurio/DeviceSparseArrays.jl") ### Basic Usage with CSC Matrices ```julia -using DeviceSparseArrays +using GenericSparseArrays using SparseArrays using LinearAlgebra # Create a 100x80 sparse matrix with 10% sparsity A_sparse = sprand(Float64, 100, 80, 0.1) -# Convert to DeviceSparseMatrixCSC (CPU by default) -A_device = DeviceSparseMatrixCSC(A_sparse) +# Convert to GenericSparseMatrixCSC (CPU by default) +A_device = GenericSparseMatrixCSC(A_sparse) # Create a vector for matrix-vector multiplication b = rand(Float64, 80) @@ -86,7 +86,7 @@ c_reactant = A_reactant * b_reactant ```julia # Create a sparse matrix and convert to CSR format A_sparse = sprand(Float64, 100, 80, 0.1) # 100x80 matrix with 10% sparsity -A_csr = DeviceSparseMatrixCSR(A_sparse) +A_csr = GenericSparseMatrixCSR(A_sparse) # Convert to different backends A_csr_cuda = adapt(CuArray, A_csr) diff --git a/benchmarks/Project.toml b/benchmarks/Project.toml index aa64bac..c2ca607 100644 --- a/benchmarks/Project.toml +++ b/benchmarks/Project.toml @@ -1,7 +1,7 @@ [deps] Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" -DeviceSparseArrays = "da3fe0eb-88a8-4d14-ae1a-857c283e9c70" +GenericSparseArrays = "da3fe0eb-88a8-4d14-ae1a-857c283e9c70" JLArrays = "27aeb0d3-9eb9-45fb-866b-73c2ecf80fcb" KernelAbstractions = "63c18a36-062a-441e-b654-da1e3ab1ce7c" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" diff --git a/benchmarks/README.md b/benchmarks/README.md index aa9c64e..9b601bb 100644 --- a/benchmarks/README.md +++ b/benchmarks/README.md @@ -1,6 +1,6 @@ -# DeviceSparseArrays.jl Benchmarks +# GenericSparseArrays.jl Benchmarks -This directory contains benchmark tracking for the DeviceSparseArrays.jl package using [BenchmarkTools.jl](https://github.com/JuliaCI/BenchmarkTools.jl) and [github-action-benchmark](https://github.com/benchmark-action/github-action-benchmark). +This directory contains benchmark tracking for the GenericSparseArrays.jl package using [BenchmarkTools.jl](https://github.com/JuliaCI/BenchmarkTools.jl) and [github-action-benchmark](https://github.com/benchmark-action/github-action-benchmark). ## Structure @@ -75,7 +75,7 @@ The workflow: ## Viewing Benchmark Results Benchmark results are tracked over time and can be viewed at: -https://albertomercurio.github.io/DeviceSparseArrays.jl/benchmarks/ +https://albertomercurio.github.io/GenericSparseArrays.jl/benchmarks/ ## Adding New Benchmarks @@ -87,7 +87,7 @@ To add new benchmarks: function benchmark_new_feature!(SUITE, array_constructor, array_type_name; N=10000, T=Float64) # Create test data using sprand data = sprand(T, N, N, 0.05) - adapted_data = adapt(array_constructor, DeviceSparseMatrix...(data)) + adapted_data = adapt(array_constructor, GenericSparseMatrix...(data)) # Add to suite group_name = "Feature Name" diff --git a/benchmarks/benchmark_utils.jl b/benchmarks/benchmark_utils.jl index a7f8df5..a1b1f6a 100644 --- a/benchmarks/benchmark_utils.jl +++ b/benchmarks/benchmark_utils.jl @@ -14,11 +14,11 @@ This function uses multiple dispatch to handle different array types: # Examples ```julia # GPU array with KernelAbstractions - will synchronize -gpu_arr = adapt(CuArray, DeviceSparseVector(...)) +gpu_arr = adapt(CuArray, GenericSparseVector(...)) _synchronize_backend(gpu_arr) # CPU array or arrays without KernelAbstractions - no-op -cpu_arr = DeviceSparseVector(...) +cpu_arr = GenericSparseVector(...) _synchronize_backend(cpu_arr) # Extend for custom array types: @@ -28,11 +28,11 @@ _synchronize_backend(cpu_arr) _synchronize_backend(arr) = nothing # Fallback: no-op for arrays without KernelAbstractions """ - _synchronize_backend(arr::AbstractDeviceSparseArray) + _synchronize_backend(arr::AbstractGenericSparseArray) -Synchronize KernelAbstractions backend for DeviceSparseArray types. +Synchronize KernelAbstractions backend for GenericSparseArray types. """ -_synchronize_backend(arr::AbstractDeviceSparseArray) = _synchronize_backend(nonzeros(arr)) +_synchronize_backend(arr::AbstractGenericSparseArray) = _synchronize_backend(nonzeros(arr)) function _synchronize_backend(x::AbstractArray) backend = KernelAbstractions.get_backend(x) diff --git a/benchmarks/conversion_benchmarks.jl b/benchmarks/conversion_benchmarks.jl index 2ea8b8c..7317c50 100644 --- a/benchmarks/conversion_benchmarks.jl +++ b/benchmarks/conversion_benchmarks.jl @@ -23,9 +23,9 @@ function benchmark_conversions!( sm_csc_std = sprand(T, N, N, 0.01) # Convert to different formats - sm_csc = DeviceSparseMatrixCSC(sm_csc_std) - sm_csr = DeviceSparseMatrixCSR(sm_csc_std) - sm_coo = DeviceSparseMatrixCOO(sm_csc_std) + sm_csc = GenericSparseMatrixCSC(sm_csc_std) + sm_csr = GenericSparseMatrixCSR(sm_csc_std) + sm_coo = GenericSparseMatrixCOO(sm_csc_std) # Adapt to device dsm_csc = adapt(array_constructor, sm_csc) @@ -34,25 +34,25 @@ function benchmark_conversions!( # CSC → COO conversion SUITE["Format Conversions"][array_type_name]["CSC → COO"] = @benchmarkable begin - DeviceSparseMatrixCOO($dsm_csc) + GenericSparseMatrixCOO($dsm_csc) _synchronize_backend($dsm_csc) end # COO → CSC conversion SUITE["Format Conversions"][array_type_name]["COO → CSC"] = @benchmarkable begin - DeviceSparseMatrixCSC($dsm_coo) + GenericSparseMatrixCSC($dsm_coo) _synchronize_backend($dsm_coo) end # CSR → COO conversion SUITE["Format Conversions"][array_type_name]["CSR → COO"] = @benchmarkable begin - DeviceSparseMatrixCOO($dsm_csr) + GenericSparseMatrixCOO($dsm_csr) _synchronize_backend($dsm_csr) end # COO → CSR conversion SUITE["Format Conversions"][array_type_name]["COO → CSR"] = @benchmarkable begin - DeviceSparseMatrixCSR($dsm_coo) + GenericSparseMatrixCSR($dsm_coo) _synchronize_backend($dsm_coo) end diff --git a/benchmarks/matrix_benchmarks.jl b/benchmarks/matrix_benchmarks.jl index afb0c4f..85f6a18 100644 --- a/benchmarks/matrix_benchmarks.jl +++ b/benchmarks/matrix_benchmarks.jl @@ -23,9 +23,9 @@ function benchmark_matrix_vector_mul!( sm_csc_std = sprand(T, N, N, 0.01) # Convert to different formats - sm_csc = DeviceSparseMatrixCSC(sm_csc_std) - sm_csr = DeviceSparseMatrixCSR(sm_csc_std) - sm_coo = DeviceSparseMatrixCOO(sm_csc_std) + sm_csc = GenericSparseMatrixCSC(sm_csc_std) + sm_csr = GenericSparseMatrixCSR(sm_csc_std) + sm_coo = GenericSparseMatrixCOO(sm_csc_std) # Adapt to device dsm_csc = adapt(array_constructor, sm_csc) @@ -83,9 +83,9 @@ function benchmark_matrix_matrix_mul!( sm_csc_std = sprand(T, N, N, 0.01) # Convert to different formats - sm_csc = DeviceSparseMatrixCSC(sm_csc_std) - sm_csr = DeviceSparseMatrixCSR(sm_csc_std) - sm_coo = DeviceSparseMatrixCOO(sm_csc_std) + sm_csc = GenericSparseMatrixCSC(sm_csc_std) + sm_csr = GenericSparseMatrixCSR(sm_csc_std) + sm_coo = GenericSparseMatrixCOO(sm_csc_std) # Adapt to device dsm_csc = adapt(array_constructor, sm_csc) @@ -140,9 +140,9 @@ function benchmark_three_arg_dot!( sm_csc_std = sprand(T, N, N, 0.01) # Convert to different formats - sm_csc = DeviceSparseMatrixCSC(sm_csc_std) - sm_csr = DeviceSparseMatrixCSR(sm_csc_std) - sm_coo = DeviceSparseMatrixCOO(sm_csc_std) + sm_csc = GenericSparseMatrixCSC(sm_csc_std) + sm_csr = GenericSparseMatrixCSR(sm_csc_std) + sm_coo = GenericSparseMatrixCOO(sm_csc_std) # Adapt to device dsm_csc = adapt(array_constructor, sm_csc) @@ -197,9 +197,9 @@ function benchmark_sparse_dense_add!( sm_csc_std = sprand(T, N, N, 0.01) # Convert to different formats - sm_csc = DeviceSparseMatrixCSC(sm_csc_std) - sm_csr = DeviceSparseMatrixCSR(sm_csc_std) - sm_coo = DeviceSparseMatrixCOO(sm_csc_std) + sm_csc = GenericSparseMatrixCSC(sm_csc_std) + sm_csr = GenericSparseMatrixCSR(sm_csc_std) + sm_coo = GenericSparseMatrixCOO(sm_csc_std) # Adapt to device dsm_csc = adapt(array_constructor, sm_csc) @@ -254,12 +254,12 @@ function benchmark_sparse_sparse_add!( sm_b_csc_std = sprand(T, N, N, 0.01) # Convert to different formats - sm_a_csc = DeviceSparseMatrixCSC(sm_a_csc_std) - sm_b_csc = DeviceSparseMatrixCSC(sm_b_csc_std) - sm_a_csr = DeviceSparseMatrixCSR(sm_a_csc_std) - sm_b_csr = DeviceSparseMatrixCSR(sm_b_csc_std) - sm_a_coo = DeviceSparseMatrixCOO(sm_a_csc_std) - sm_b_coo = DeviceSparseMatrixCOO(sm_b_csc_std) + sm_a_csc = GenericSparseMatrixCSC(sm_a_csc_std) + sm_b_csc = GenericSparseMatrixCSC(sm_b_csc_std) + sm_a_csr = GenericSparseMatrixCSR(sm_a_csc_std) + sm_b_csr = GenericSparseMatrixCSR(sm_b_csc_std) + sm_a_coo = GenericSparseMatrixCOO(sm_a_csc_std) + sm_b_coo = GenericSparseMatrixCOO(sm_b_csc_std) # Adapt to device dsm_a_csc = adapt(array_constructor, sm_a_csc) @@ -308,14 +308,14 @@ function benchmark_kron!(SUITE, array_constructor, array_type_name; N = 100, T = sm_b_std = sprand(T, N, N, 0.01) # Convert to different formats - sm_a_csc = DeviceSparseMatrixCSC(sm_a_std) - sm_b_csc = DeviceSparseMatrixCSC(sm_b_std) + sm_a_csc = GenericSparseMatrixCSC(sm_a_std) + sm_b_csc = GenericSparseMatrixCSC(sm_b_std) - sm_a_csr = DeviceSparseMatrixCSR(sm_a_std) - sm_b_csr = DeviceSparseMatrixCSR(sm_b_std) + sm_a_csr = GenericSparseMatrixCSR(sm_a_std) + sm_b_csr = GenericSparseMatrixCSR(sm_b_std) - sm_a_coo = DeviceSparseMatrixCOO(sm_a_std) - sm_b_coo = DeviceSparseMatrixCOO(sm_b_std) + sm_a_coo = GenericSparseMatrixCOO(sm_a_std) + sm_b_coo = GenericSparseMatrixCOO(sm_b_std) # Adapt to device dsm_a_csc = adapt(array_constructor, sm_a_csc) diff --git a/benchmarks/runbenchmarks.jl b/benchmarks/runbenchmarks.jl index 763e879..c06d8eb 100644 --- a/benchmarks/runbenchmarks.jl +++ b/benchmarks/runbenchmarks.jl @@ -1,7 +1,7 @@ using BenchmarkTools using LinearAlgebra using SparseArrays -using DeviceSparseArrays +using GenericSparseArrays using Adapt using JLArrays using KernelAbstractions diff --git a/benchmarks/vector_benchmarks.jl b/benchmarks/vector_benchmarks.jl index e949a17..1ada5cf 100644 --- a/benchmarks/vector_benchmarks.jl +++ b/benchmarks/vector_benchmarks.jl @@ -21,7 +21,7 @@ function benchmark_vector_sum!( ) # Create sparse vector with 1% density sv = sprand(T, N, 0.01) - dsv = adapt(array_constructor, DeviceSparseVector(sv)) + dsv = adapt(array_constructor, GenericSparseVector(sv)) # Level 3: Specific operation (will be plotted together) SUITE["Sparse Vector"][array_type_name]["Sum"] = @benchmarkable begin @@ -55,7 +55,7 @@ function benchmark_vector_sparse_dense_dot!( ) # Create sparse vector with 1% density sv = sprand(T, N, 0.01) - dsv = adapt(array_constructor, DeviceSparseVector(sv)) + dsv = adapt(array_constructor, GenericSparseVector(sv)) # Create dense vector dense_vec = adapt(array_constructor, randn(T, N)) diff --git a/docs/Project.toml b/docs/Project.toml index e9153ab..e7b943c 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -1,6 +1,6 @@ [deps] Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" -DeviceSparseArrays = "da3fe0eb-88a8-4d14-ae1a-857c283e9c70" +GenericSparseArrays = "da3fe0eb-88a8-4d14-ae1a-857c283e9c70" Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" JLArrays = "27aeb0d3-9eb9-45fb-866b-73c2ecf80fcb" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" diff --git a/docs/make.jl b/docs/make.jl index cffcf14..6e4f60b 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,23 +1,23 @@ -using DeviceSparseArrays +using GenericSparseArrays using Documenter DocMeta.setdocmeta!( - DeviceSparseArrays, + GenericSparseArrays, :DocTestSetup, - :(using DeviceSparseArrays); + :(using GenericSparseArrays); recursive = true, ) makedocs(; - modules = [DeviceSparseArrays], + modules = [GenericSparseArrays], authors = "Alberto Mercurio and contributors", - sitename = "DeviceSparseArrays.jl", + sitename = "GenericSparseArrays.jl", format = Documenter.HTML(; - canonical = "https://albertomercurio.github.io/DeviceSparseArrays.jl", + canonical = "https://albertomercurio.github.io/GenericSparseArrays.jl", edit_link = "main", assets = String[], ), pages = ["Home" => "index.md", "API Reference" => "api.md"], ) -deploydocs(; repo = "github.com/albertomercurio/DeviceSparseArrays.jl", devbranch = "main") +deploydocs(; repo = "github.com/albertomercurio/GenericSparseArrays.jl", devbranch = "main") diff --git a/docs/src/api.md b/docs/src/api.md index e5fc13b..f3453a0 100644 --- a/docs/src/api.md +++ b/docs/src/api.md @@ -1,10 +1,10 @@ # API Reference ```@meta -CurrentModule = DeviceSparseArrays +CurrentModule = GenericSparseArrays ``` -This page contains the complete API documentation for DeviceSparseArrays.jl. +This page contains the complete API documentation for GenericSparseArrays.jl. ```@index ``` @@ -12,16 +12,16 @@ This page contains the complete API documentation for DeviceSparseArrays.jl. ## Types ```@docs -AbstractDeviceSparseArray -DeviceSparseVector -DeviceSparseMatrixCSC -DeviceSparseMatrixCSR -DeviceSparseMatrixCOO +AbstractGenericSparseArray +GenericSparseVector +GenericSparseMatrixCSC +GenericSparseMatrixCSR +GenericSparseMatrixCOO ``` ## Functions ```@autodocs -Modules = [DeviceSparseArrays] +Modules = [GenericSparseArrays] Order = [:function] ``` diff --git a/docs/src/index.md b/docs/src/index.md index 0568b39..3a21a60 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -1,20 +1,20 @@ ```@meta -CurrentModule = DeviceSparseArrays +CurrentModule = GenericSparseArrays ``` -# DeviceSparseArrays +# GenericSparseArrays -Documentation for [DeviceSparseArrays](https://github.com/albertomercurio/DeviceSparseArrays.jl). +Documentation for [GenericSparseArrays](https://github.com/albertomercurio/GenericSparseArrays.jl). ## Overview -`DeviceSparseArrays` provides backend-agnostic sparse array container types whose +`GenericSparseArrays` provides backend-agnostic sparse array container types whose internal storage vectors may live on different devices (CPU / accelerators). The initial implementation supplies: -* [`DeviceSparseVector`](@ref) – sparse vector with generic index & value buffers. -* [`DeviceSparseMatrixCSC`](@ref) – Compressed Sparse Column matrix with parametric column pointer, row index, and nonzero value buffers. -* [`DeviceSparseMatrixCSR`](@ref) – Compressed Sparse Row matrix with parametric row pointer, column index, and nonzero value buffers. +* [`GenericSparseVector`](@ref) – sparse vector with generic index & value buffers. +* [`GenericSparseMatrixCSC`](@ref) – Compressed Sparse Column matrix with parametric column pointer, row index, and nonzero value buffers. +* [`GenericSparseMatrixCSR`](@ref) – Compressed Sparse Row matrix with parametric row pointer, column index, and nonzero value buffers. These types mirror the Base `SparseVector` / `SparseMatrixCSC` interfaces for introspection (`size`, `length`, `nonzeros`, etc.) and can roundtrip convert to and from the Base representations. @@ -23,18 +23,18 @@ These types mirror the Base `SparseVector` / `SparseMatrixCSC` interfaces for in ### Basic Usage ```@example example -using DeviceSparseArrays, SparseArrays +using GenericSparseArrays, SparseArrays # Create a sparse vector V = sparsevec([2,5], [1.0, 3.5], 6) -dV = DeviceSparseVector(V) # construct backend-agnostic version on the CPU +dV = GenericSparseVector(V) # construct backend-agnostic version on the CPU @show size(dV) @show SparseVector(dV) == V # Create a sparse matrix A = sparse([1,2,1],[1,1,2],[2.0,3.0,4.0], 2, 2) -dA = DeviceSparseMatrixCSC(A) +dA = GenericSparseMatrixCSC(A) @show size(dA) @show SparseMatrixCSC(dA) == A @@ -47,8 +47,8 @@ dA = DeviceSparseMatrixCSC(A) A_sparse = sparse([1,2,1,3],[1,1,2,3],[2.0,3.0,4.0,5.0], 3, 3) @show A_sparse -# Convert to DeviceSparseMatrixCSC -A_device = DeviceSparseMatrixCSC(A_sparse) +# Convert to GenericSparseMatrixCSC +A_device = GenericSparseMatrixCSC(A_sparse) # Create a vector b = [1.0, 2.0, 3.0] @@ -72,8 +72,8 @@ using Adapt: adapt # Create a sparse matrix A_sparse = sprand(Float64, 5, 4, 0.6) -# Convert to DeviceSparseMatrixCSC -A_device = DeviceSparseMatrixCSC(A_sparse) +# Convert to GenericSparseMatrixCSC +A_device = GenericSparseMatrixCSC(A_sparse) # Adapt to JLArray backend (CPU fallback for CI) A_jl = adapt(JLArray, A_device) @@ -91,14 +91,14 @@ c_jl = A_jl * b_jl ### CSR Matrix Format -`DeviceSparseArrays.jl` also supports the Compressed Sparse Row (CSR) format via the `DeviceSparseMatrixCSR` type. It can be used similarly to the CSC format. +`GenericSparseArrays.jl` also supports the Compressed Sparse Row (CSR) format via the `GenericSparseMatrixCSR` type. It can be used similarly to the CSC format. ```@example example # Create a sparse matrix A_sparse = sparse([1,2,1,3],[1,1,2,3],[2.0,3.0,4.0,5.0], 3, 3) # Convert to CSR format -A_csr = DeviceSparseMatrixCSR(A_sparse) +A_csr = GenericSparseMatrixCSR(A_sparse) @show size(A_csr) # Convert back to standard sparse matrix diff --git a/ext/DeviceSparseArraysJLArraysExt.jl b/ext/DeviceSparseArraysJLArraysExt.jl deleted file mode 100644 index a71257d..0000000 --- a/ext/DeviceSparseArraysJLArraysExt.jl +++ /dev/null @@ -1,11 +0,0 @@ -module DeviceSparseArraysJLArraysExt - -using JLArrays: JLArray -import DeviceSparseArrays - -DeviceSparseArrays._sortperm_AK(x::JLArray) = JLArray(sortperm(collect(x))) -DeviceSparseArrays._cumsum_AK(x::JLArray) = JLArray(cumsum(collect(x))) -DeviceSparseArrays._searchsortedfirst_AK(v::JLArray, x::JLArray) = - JLArray(searchsortedfirst.(Ref(collect(v)), collect(x))) - -end diff --git a/ext/GenericSparseArraysJLArraysExt.jl b/ext/GenericSparseArraysJLArraysExt.jl new file mode 100644 index 0000000..18df791 --- /dev/null +++ b/ext/GenericSparseArraysJLArraysExt.jl @@ -0,0 +1,11 @@ +module GenericSparseArraysJLArraysExt + +using JLArrays: JLArray +import GenericSparseArrays + +GenericSparseArrays._sortperm_AK(x::JLArray) = JLArray(sortperm(collect(x))) +GenericSparseArrays._cumsum_AK(x::JLArray) = JLArray(cumsum(collect(x))) +GenericSparseArrays._searchsortedfirst_AK(v::JLArray, x::JLArray) = + JLArray(searchsortedfirst.(Ref(collect(v)), collect(x))) + +end diff --git a/src/DeviceSparseArrays.jl b/src/GenericSparseArrays.jl similarity index 79% rename from src/DeviceSparseArrays.jl rename to src/GenericSparseArrays.jl index ea6611f..08b6a1d 100644 --- a/src/DeviceSparseArrays.jl +++ b/src/GenericSparseArrays.jl @@ -1,4 +1,4 @@ -module DeviceSparseArrays +module GenericSparseArrays using LinearAlgebra import LinearAlgebra: wrap, copymutable_oftype, __normalize!, kron @@ -26,11 +26,11 @@ using AcceleratedKernels import Adapt -export AbstractDeviceSparseArray, - AbstractDeviceSparseVector, AbstractDeviceSparseMatrix, AbstractDeviceSparseVecOrMat +export AbstractGenericSparseArray, + AbstractGenericSparseVector, AbstractGenericSparseMatrix, AbstractGenericSparseVecOrMat -export DeviceSparseVector, - DeviceSparseMatrixCSC, DeviceSparseMatrixCSR, DeviceSparseMatrixCOO +export GenericSparseVector, + GenericSparseMatrixCSC, GenericSparseMatrixCSR, GenericSparseMatrixCOO include("core.jl") include("helpers.jl") diff --git a/src/conversions/conversions.jl b/src/conversions/conversions.jl index f2fea15..f9465d7 100644 --- a/src/conversions/conversions.jl +++ b/src/conversions/conversions.jl @@ -1,44 +1,44 @@ # Conversions between CSC, CSR, and COO sparse matrix formats # ============================================================================ -# SparseMatrixCSC ↔ DeviceSparseMatrix (CSC-CSR-COO) Conversions +# SparseMatrixCSC ↔ GenericSparseMatrix (CSC-CSR-COO) Conversions # ============================================================================ -DeviceSparseMatrixCSC(A::SparseMatrixCSC) = - DeviceSparseMatrixCSC(size(A, 1), size(A, 2), A.colptr, A.rowval, A.nzval) +GenericSparseMatrixCSC(A::SparseMatrixCSC) = + GenericSparseMatrixCSC(size(A, 1), size(A, 2), A.colptr, A.rowval, A.nzval) -SparseMatrixCSC(A::DeviceSparseMatrixCSC) = SparseMatrixCSC( +SparseMatrixCSC(A::GenericSparseMatrixCSC) = SparseMatrixCSC( size(A, 1), size(A, 2), collect(A.colptr), collect(A.rowval), collect(A.nzval), ) -function SparseMatrixCSC(A::Transpose{Tv, <:DeviceSparseMatrixCSC}) where {Tv} - return SparseMatrixCSC(DeviceSparseMatrixCSR(A)) +function SparseMatrixCSC(A::Transpose{Tv, <:GenericSparseMatrixCSC}) where {Tv} + return SparseMatrixCSC(GenericSparseMatrixCSR(A)) end -function SparseMatrixCSC(A::Adjoint{Tv, <:DeviceSparseMatrixCSC}) where {Tv} - return SparseMatrixCSC(DeviceSparseMatrixCSR(A)) +function SparseMatrixCSC(A::Adjoint{Tv, <:GenericSparseMatrixCSC}) where {Tv} + return SparseMatrixCSC(GenericSparseMatrixCSR(A)) end -function DeviceSparseMatrixCSR(A::SparseMatrixCSC) +function GenericSparseMatrixCSR(A::SparseMatrixCSC) # TODO: Implement a direct CSC to CSR conversion without going through transposition At = transpose(A) At_sparse = transpose(SparseMatrixCSC(At)) - return DeviceSparseMatrixCSR(At_sparse) + return GenericSparseMatrixCSR(At_sparse) end -function SparseMatrixCSC(A::DeviceSparseMatrixCSR) +function SparseMatrixCSC(A::GenericSparseMatrixCSR) # Convert CSR to CSC by creating transposed CSC and then transposing back At_csc = SparseMatrixCSC(A.n, A.m, collect(A.rowptr), collect(A.colval), collect(A.nzval)) return SparseMatrixCSC(transpose(At_csc)) end -function SparseMatrixCSC(A::Transpose{Tv, <:DeviceSparseMatrixCSR}) where {Tv} +function SparseMatrixCSC(A::Transpose{Tv, <:GenericSparseMatrixCSR}) where {Tv} At = A.parent return SparseMatrixCSC(At.n, At.m, collect(At.rowptr), collect(At.colval), collect(At.nzval)) end -function SparseMatrixCSC(A::Adjoint{Tv, <:DeviceSparseMatrixCSR}) where {Tv} +function SparseMatrixCSC(A::Adjoint{Tv, <:GenericSparseMatrixCSR}) where {Tv} At = A.parent return SparseMatrixCSC( size(A, 1), @@ -49,13 +49,13 @@ function SparseMatrixCSC(A::Adjoint{Tv, <:DeviceSparseMatrixCSR}) where {Tv} ) end -function DeviceSparseMatrixCOO(A::SparseMatrixCSC) +function GenericSparseMatrixCOO(A::SparseMatrixCSC) m, n = size(A) rows, cols, vals = findnz(A) - return DeviceSparseMatrixCOO(m, n, rows, cols, vals) + return GenericSparseMatrixCOO(m, n, rows, cols, vals) end -function SparseMatrixCSC(A::DeviceSparseMatrixCOO) +function SparseMatrixCSC(A::GenericSparseMatrixCOO) m, n = size(A) rowind = collect(A.rowind) colind = collect(A.colind) @@ -63,14 +63,14 @@ function SparseMatrixCSC(A::DeviceSparseMatrixCOO) return sparse(rowind, colind, nzval, m, n) end -SparseMatrixCSC(A::Transpose{Tv, <:DeviceSparseMatrixCOO}) where {Tv} = SparseMatrixCSC( +SparseMatrixCSC(A::Transpose{Tv, <:GenericSparseMatrixCOO}) where {Tv} = SparseMatrixCSC( size(A, 1), size(A, 2), collect(A.parent.colind), collect(A.parent.rowind), collect(A.parent.nzval), ) -SparseMatrixCSC(A::Adjoint{Tv, <:DeviceSparseMatrixCOO}) where {Tv} = SparseMatrixCSC( +SparseMatrixCSC(A::Adjoint{Tv, <:GenericSparseMatrixCOO}) where {Tv} = SparseMatrixCSC( size(A, 1), size(A, 2), collect(A.parent.colind), @@ -82,18 +82,18 @@ SparseMatrixCSC(A::Adjoint{Tv, <:DeviceSparseMatrixCOO}) where {Tv} = SparseMatr # CSC ↔ CSR Conversions # ============================================================================ -DeviceSparseMatrixCSC(A::DeviceSparseMatrixCSR) = - DeviceSparseMatrixCSC(DeviceSparseMatrixCOO(A)) -DeviceSparseMatrixCSC(A::Transpose{Tv, <:DeviceSparseMatrixCSR}) where {Tv} = - DeviceSparseMatrixCSC( +GenericSparseMatrixCSC(A::GenericSparseMatrixCSR) = + GenericSparseMatrixCSC(GenericSparseMatrixCOO(A)) +GenericSparseMatrixCSC(A::Transpose{Tv, <:GenericSparseMatrixCSR}) where {Tv} = + GenericSparseMatrixCSC( size(A, 1), size(A, 2), A.parent.rowptr, A.parent.colval, A.parent.nzval, ) -DeviceSparseMatrixCSC(A::Adjoint{Tv, <:DeviceSparseMatrixCSR}) where {Tv} = - DeviceSparseMatrixCSC( +GenericSparseMatrixCSC(A::Adjoint{Tv, <:GenericSparseMatrixCSR}) where {Tv} = + GenericSparseMatrixCSC( size(A, 1), size(A, 2), A.parent.rowptr, @@ -101,19 +101,19 @@ DeviceSparseMatrixCSC(A::Adjoint{Tv, <:DeviceSparseMatrixCSR}) where {Tv} = conj.(A.parent.nzval), ) -DeviceSparseMatrixCSR(A::DeviceSparseMatrixCSC) = - DeviceSparseMatrixCSR(DeviceSparseMatrixCOO(A)) -function DeviceSparseMatrixCSR( - A::Transpose{Tv, <:Union{<:SparseMatrixCSC, <:DeviceSparseMatrixCSC}}, +GenericSparseMatrixCSR(A::GenericSparseMatrixCSC) = + GenericSparseMatrixCSR(GenericSparseMatrixCOO(A)) +function GenericSparseMatrixCSR( + A::Transpose{Tv, <:Union{<:SparseMatrixCSC, <:GenericSparseMatrixCSC}}, ) where {Tv} At = A.parent - return DeviceSparseMatrixCSR(size(A, 1), size(A, 2), At.colptr, rowvals(At), nonzeros(At)) + return GenericSparseMatrixCSR(size(A, 1), size(A, 2), At.colptr, rowvals(At), nonzeros(At)) end -function DeviceSparseMatrixCSR( - A::Adjoint{Tv, <:Union{<:SparseMatrixCSC, <:DeviceSparseMatrixCSC}}, +function GenericSparseMatrixCSR( + A::Adjoint{Tv, <:Union{<:SparseMatrixCSC, <:GenericSparseMatrixCSC}}, ) where {Tv} At = A.parent - return DeviceSparseMatrixCSR( + return GenericSparseMatrixCSR( size(A, 1), size(A, 2), At.colptr, @@ -126,7 +126,7 @@ end # CSC ↔ COO Conversions # ============================================================================ -function DeviceSparseMatrixCOO(A::DeviceSparseMatrixCSC{Tv, Ti}) where {Tv, Ti} +function GenericSparseMatrixCOO(A::GenericSparseMatrixCSC{Tv, Ti}) where {Tv, Ti} m, n = size(A) nnz_count = nnz(A) @@ -141,10 +141,10 @@ function DeviceSparseMatrixCOO(A::DeviceSparseMatrixCSC{Tv, Ti}) where {Tv, Ti} kernel! = kernel_csc_to_coo!(backend) kernel!(rowind, colind, nzval, A.colptr, A.rowval, A.nzval; ndrange = (n,)) - return DeviceSparseMatrixCOO(m, n, rowind, colind, nzval) + return GenericSparseMatrixCOO(m, n, rowind, colind, nzval) end -function DeviceSparseMatrixCSC(A::DeviceSparseMatrixCOO{Tv, Ti}) where {Tv, Ti} +function GenericSparseMatrixCSC(A::GenericSparseMatrixCOO{Tv, Ti}) where {Tv, Ti} m, n = size(A) nnz_count = nnz(A) @@ -175,13 +175,13 @@ function DeviceSparseMatrixCSC(A::DeviceSparseMatrixCOO{Tv, Ti}) where {Tv, Ti} colptr[1:n] .= _searchsortedfirst_AK(colind_sorted, col_indices) @allowscalar colptr[n + 1] = Ti(nnz_count + 1) - return DeviceSparseMatrixCSC(m, n, colptr, rowind_sorted, nzval_sorted) + return GenericSparseMatrixCSC(m, n, colptr, rowind_sorted, nzval_sorted) end # Transpose and Adjoint conversions for COO to CSC -DeviceSparseMatrixCSC(A::Transpose{Tv, <:DeviceSparseMatrixCOO}) where {Tv} = - DeviceSparseMatrixCSC( - DeviceSparseMatrixCOO( +GenericSparseMatrixCSC(A::Transpose{Tv, <:GenericSparseMatrixCOO}) where {Tv} = + GenericSparseMatrixCSC( + GenericSparseMatrixCOO( size(A, 1), size(A, 2), A.parent.colind, @@ -190,9 +190,9 @@ DeviceSparseMatrixCSC(A::Transpose{Tv, <:DeviceSparseMatrixCOO}) where {Tv} = ) ) -DeviceSparseMatrixCSC(A::Adjoint{Tv, <:DeviceSparseMatrixCOO}) where {Tv} = - DeviceSparseMatrixCSC( - DeviceSparseMatrixCOO( +GenericSparseMatrixCSC(A::Adjoint{Tv, <:GenericSparseMatrixCOO}) where {Tv} = + GenericSparseMatrixCSC( + GenericSparseMatrixCOO( size(A, 1), size(A, 2), A.parent.colind, @@ -205,7 +205,7 @@ DeviceSparseMatrixCSC(A::Adjoint{Tv, <:DeviceSparseMatrixCOO}) where {Tv} = # CSR ↔ COO Conversions # ============================================================================ -function DeviceSparseMatrixCOO(A::DeviceSparseMatrixCSR{Tv, Ti}) where {Tv, Ti} +function GenericSparseMatrixCOO(A::GenericSparseMatrixCSR{Tv, Ti}) where {Tv, Ti} m, n = size(A) nnz_count = nnz(A) @@ -220,10 +220,10 @@ function DeviceSparseMatrixCOO(A::DeviceSparseMatrixCSR{Tv, Ti}) where {Tv, Ti} kernel! = kernel_csr_to_coo!(backend) kernel!(rowind, colind, nzval, A.rowptr, A.colval, A.nzval; ndrange = (m,)) - return DeviceSparseMatrixCOO(m, n, rowind, colind, nzval) + return GenericSparseMatrixCOO(m, n, rowind, colind, nzval) end -function DeviceSparseMatrixCSR(A::DeviceSparseMatrixCOO{Tv, Ti}) where {Tv, Ti} +function GenericSparseMatrixCSR(A::GenericSparseMatrixCOO{Tv, Ti}) where {Tv, Ti} m, n = size(A) nnz_count = nnz(A) @@ -254,5 +254,5 @@ function DeviceSparseMatrixCSR(A::DeviceSparseMatrixCOO{Tv, Ti}) where {Tv, Ti} rowptr[1:m] .= _searchsortedfirst_AK(rowind_sorted, row_indices) @allowscalar rowptr[m + 1] = Ti(nnz_count + 1) - return DeviceSparseMatrixCSR(m, n, rowptr, colind_sorted, nzval_sorted) + return GenericSparseMatrixCSR(m, n, rowptr, colind_sorted, nzval_sorted) end diff --git a/src/core.jl b/src/core.jl index 0786734..88d6663 100644 --- a/src/core.jl +++ b/src/core.jl @@ -1,56 +1,56 @@ # Abstract sparse hierarchy and common aliases """ - AbstractDeviceSparseArray{Tv,Ti,N} <: AbstractSparseArray{Tv,Ti,N} + AbstractGenericSparseArray{Tv,Ti,N} <: AbstractSparseArray{Tv,Ti,N} Supertype for sparse arrays that can have their underlying storage on various devices (CPU, GPU, accelerators). This package keeps the hierarchy backend-agnostic; dispatch is expected to leverage the concrete types of internal buffers (e.g. `Vector`, `CuArray`, etc.) rather than an explicit backend flag. """ -abstract type AbstractDeviceSparseArray{Tv, Ti, N} <: AbstractSparseArray{Tv, Ti, N} end +abstract type AbstractGenericSparseArray{Tv, Ti, N} <: AbstractSparseArray{Tv, Ti, N} end -const AbstractDeviceSparseVector{Tv, Ti} = AbstractDeviceSparseArray{Tv, Ti, 1} -const AbstractDeviceSparseMatrix{Tv, Ti} = AbstractDeviceSparseArray{Tv, Ti, 2} -const AbstractDeviceSparseVecOrMat{Tv, Ti} = - Union{AbstractDeviceSparseVector{Tv, Ti}, AbstractDeviceSparseMatrix{Tv, Ti}} +const AbstractGenericSparseVector{Tv, Ti} = AbstractGenericSparseArray{Tv, Ti, 1} +const AbstractGenericSparseMatrix{Tv, Ti} = AbstractGenericSparseArray{Tv, Ti, 2} +const AbstractGenericSparseVecOrMat{Tv, Ti} = + Union{AbstractGenericSparseVector{Tv, Ti}, AbstractGenericSparseMatrix{Tv, Ti}} -const AbstractDeviceSparseMatrixInclAdjointAndTranspose = Union{ - AbstractDeviceSparseMatrix, - Adjoint{<:Any, <:AbstractDeviceSparseMatrix}, - Transpose{<:Any, <:AbstractDeviceSparseMatrix}, +const AbstractGenericSparseMatrixInclAdjointAndTranspose = Union{ + AbstractGenericSparseMatrix, + Adjoint{<:Any, <:AbstractGenericSparseMatrix}, + Transpose{<:Any, <:AbstractGenericSparseMatrix}, } -Base.sum(A::AbstractDeviceSparseArray) = sum(nonzeros(A)) +Base.sum(A::AbstractGenericSparseArray) = sum(nonzeros(A)) -function LinearAlgebra.rmul!(A::AbstractDeviceSparseArray, x::Number) +function LinearAlgebra.rmul!(A::AbstractGenericSparseArray, x::Number) rmul!(nonzeros(A), x) return A end -function LinearAlgebra.lmul!(x::Number, A::AbstractDeviceSparseArray) +function LinearAlgebra.lmul!(x::Number, A::AbstractGenericSparseArray) lmul!(x, nonzeros(A)) return A end -function LinearAlgebra.rdiv!(A::AbstractDeviceSparseArray, x::Number) +function LinearAlgebra.rdiv!(A::AbstractGenericSparseArray, x::Number) rdiv!(nonzeros(A), x) return A end -Base.:+(A::AbstractDeviceSparseArray) = copy(A) +Base.:+(A::AbstractGenericSparseArray) = copy(A) -Base.:*(A::AbstractDeviceSparseArray, J::UniformScaling) = A * J.λ -Base.:*(J::UniformScaling, A::AbstractDeviceSparseArray) = J.λ * A +Base.:*(A::AbstractGenericSparseArray, J::UniformScaling) = A * J.λ +Base.:*(J::UniformScaling, A::AbstractGenericSparseArray) = J.λ * A -SparseArrays.getnzval(A::AbstractDeviceSparseArray) = nonzeros(A) -function SparseArrays.nnz(A::AbstractDeviceSparseArray) +SparseArrays.getnzval(A::AbstractGenericSparseArray) = nonzeros(A) +function SparseArrays.nnz(A::AbstractGenericSparseArray) return length(nonzeros(A)) end -KernelAbstractions.get_backend(A::AbstractDeviceSparseArray) = get_backend(nonzeros(A)) +KernelAbstractions.get_backend(A::AbstractGenericSparseArray) = get_backend(nonzeros(A)) -# called by `show(io, MIME("text/plain"), ::AbstractDeviceSparseMatrixInclAdjointAndTranspose)` -function Base.print_array(io::IO, A::AbstractDeviceSparseMatrixInclAdjointAndTranspose) +# called by `show(io, MIME("text/plain"), ::AbstractGenericSparseMatrixInclAdjointAndTranspose)` +function Base.print_array(io::IO, A::AbstractGenericSparseMatrixInclAdjointAndTranspose) S = SparseMatrixCSC(A) return if max(size(S)...) < 16 Base.print_matrix(io, S) @@ -59,8 +59,8 @@ function Base.print_array(io::IO, A::AbstractDeviceSparseMatrixInclAdjointAndTra end end -# Generic addition between AbstractDeviceSparseMatrix and DenseMatrix -function Base.:+(A::AbstractDeviceSparseMatrix, B::DenseMatrix) +# Generic addition between AbstractGenericSparseMatrix and DenseMatrix +function Base.:+(A::AbstractGenericSparseMatrix, B::DenseMatrix) size(A) == size(B) || throw( DimensionMismatch( "dimensions must match: A has dims $(size(A)), B has dims $(size(B))", @@ -81,7 +81,7 @@ function Base.:+(A::AbstractDeviceSparseMatrix, B::DenseMatrix) return C end -Base.:+(B::DenseMatrix, A::AbstractDeviceSparseMatrix) = A + B +Base.:+(B::DenseMatrix, A::AbstractGenericSparseMatrix) = A + B # Keep this at the end of the file trans_adj_wrappers(fmt) = ( diff --git a/src/matrix_coo/matrix_coo.jl b/src/matrix_coo/matrix_coo.jl index 10e2483..9aedaf2 100644 --- a/src/matrix_coo/matrix_coo.jl +++ b/src/matrix_coo/matrix_coo.jl @@ -1,7 +1,7 @@ -# DeviceSparseMatrixCOO implementation +# GenericSparseMatrixCOO implementation """ - DeviceSparseMatrixCOO{Tv,Ti,RowIndT<:AbstractVector{Ti},ColIndT<:AbstractVector{Ti},NzValT<:AbstractVector{Tv}} <: AbstractDeviceSparseMatrix{Tv,Ti} + GenericSparseMatrixCOO{Tv,Ti,RowIndT<:AbstractVector{Ti},ColIndT<:AbstractVector{Ti},NzValT<:AbstractVector{Tv}} <: AbstractGenericSparseMatrix{Tv,Ti} Coordinate (COO) sparse matrix with generic storage vectors for row indices, column indices, and nonzero values. Buffer types (e.g. `Vector`, GPU array @@ -14,20 +14,20 @@ types) enable dispatch on device characteristics. - `colind::ColIndT` - column indices of stored entries - `nzval::NzValT` - stored values """ -struct DeviceSparseMatrixCOO{ +struct GenericSparseMatrixCOO{ Tv, Ti, RowIndT <: AbstractVector{Ti}, ColIndT <: AbstractVector{Ti}, NzValT <: AbstractVector{Tv}, - } <: AbstractDeviceSparseMatrix{Tv, Ti} + } <: AbstractGenericSparseMatrix{Tv, Ti} m::Int n::Int rowind::RowIndT colind::ColIndT nzval::NzValT - function DeviceSparseMatrixCOO( + function GenericSparseMatrixCOO( m::Integer, n::Integer, rowind::RowIndT, @@ -61,7 +61,7 @@ struct DeviceSparseMatrixCOO{ end # Conversion from SparseMatrixCSC to COO -function DeviceSparseMatrixCOO(A::SparseMatrixCSC{Tv, Ti}) where {Tv, Ti} +function GenericSparseMatrixCOO(A::SparseMatrixCSC{Tv, Ti}) where {Tv, Ti} m, n = size(A) nnz_count = nnz(A) @@ -79,10 +79,10 @@ function DeviceSparseMatrixCOO(A::SparseMatrixCSC{Tv, Ti}) where {Tv, Ti} end end - return DeviceSparseMatrixCOO(m, n, rowind, colind, nzval) + return GenericSparseMatrixCOO(m, n, rowind, colind, nzval) end -Adapt.adapt_structure(to, A::DeviceSparseMatrixCOO) = DeviceSparseMatrixCOO( +Adapt.adapt_structure(to, A::GenericSparseMatrixCOO) = GenericSparseMatrixCOO( A.m, A.n, Adapt.adapt_structure(to, A.rowind), @@ -90,22 +90,22 @@ Adapt.adapt_structure(to, A::DeviceSparseMatrixCOO) = DeviceSparseMatrixCOO( Adapt.adapt_structure(to, A.nzval), ) -Base.size(A::DeviceSparseMatrixCOO) = (A.m, A.n) -Base.length(A::DeviceSparseMatrixCOO) = A.m * A.n -Base.copy(A::DeviceSparseMatrixCOO) = - DeviceSparseMatrixCOO(A.m, A.n, copy(A.rowind), copy(A.colind), copy(A.nzval)) +Base.size(A::GenericSparseMatrixCOO) = (A.m, A.n) +Base.length(A::GenericSparseMatrixCOO) = A.m * A.n +Base.copy(A::GenericSparseMatrixCOO) = + GenericSparseMatrixCOO(A.m, A.n, copy(A.rowind), copy(A.colind), copy(A.nzval)) -Base.collect(A::DeviceSparseMatrixCOO) = collect(SparseMatrixCSC(A)) +Base.collect(A::GenericSparseMatrixCOO) = collect(SparseMatrixCSC(A)) -function Base.zero(A::DeviceSparseMatrixCOO) +function Base.zero(A::GenericSparseMatrixCOO) rowind = similar(A.rowind, 0) colind = similar(A.colind, 0) nzval = similar(A.nzval, 0) - return DeviceSparseMatrixCOO(A.m, A.n, rowind, colind, nzval) + return GenericSparseMatrixCOO(A.m, A.n, rowind, colind, nzval) end -function Base.:(*)(α::Number, A::DeviceSparseMatrixCOO) - return DeviceSparseMatrixCOO( +function Base.:(*)(α::Number, A::GenericSparseMatrixCOO) + return GenericSparseMatrixCOO( A.m, A.n, copy(getrowind(A)), @@ -113,34 +113,34 @@ function Base.:(*)(α::Number, A::DeviceSparseMatrixCOO) α .* nonzeros(A), ) end -Base.:(*)(A::DeviceSparseMatrixCOO, α::Number) = α * A -Base.:(/)(A::DeviceSparseMatrixCOO, α::Number) = (1 / α) * A +Base.:(*)(A::GenericSparseMatrixCOO, α::Number) = α * A +Base.:(/)(A::GenericSparseMatrixCOO, α::Number) = (1 / α) * A -function Base.:-(A::DeviceSparseMatrixCOO) - return DeviceSparseMatrixCOO(A.m, A.n, copy(A.rowind), copy(A.colind), -A.nzval) +function Base.:-(A::GenericSparseMatrixCOO) + return GenericSparseMatrixCOO(A.m, A.n, copy(A.rowind), copy(A.colind), -A.nzval) end -Base.conj(A::DeviceSparseMatrixCOO{<:Real}) = A -function Base.conj(A::DeviceSparseMatrixCOO{<:Complex}) - return DeviceSparseMatrixCOO(A.m, A.n, copy(A.rowind), copy(A.colind), conj.(A.nzval)) +Base.conj(A::GenericSparseMatrixCOO{<:Real}) = A +function Base.conj(A::GenericSparseMatrixCOO{<:Complex}) + return GenericSparseMatrixCOO(A.m, A.n, copy(A.rowind), copy(A.colind), conj.(A.nzval)) end -Base.real(A::DeviceSparseMatrixCOO{<:Real}) = A -function Base.real(A::DeviceSparseMatrixCOO{<:Complex}) - return DeviceSparseMatrixCOO(A.m, A.n, copy(A.rowind), copy(A.colind), real.(A.nzval)) +Base.real(A::GenericSparseMatrixCOO{<:Real}) = A +function Base.real(A::GenericSparseMatrixCOO{<:Complex}) + return GenericSparseMatrixCOO(A.m, A.n, copy(A.rowind), copy(A.colind), real.(A.nzval)) end -Base.imag(A::DeviceSparseMatrixCOO{<:Real}) = zero(A) -function Base.imag(A::DeviceSparseMatrixCOO{<:Complex}) - return DeviceSparseMatrixCOO(A.m, A.n, copy(A.rowind), copy(A.colind), imag.(A.nzval)) +Base.imag(A::GenericSparseMatrixCOO{<:Real}) = zero(A) +function Base.imag(A::GenericSparseMatrixCOO{<:Complex}) + return GenericSparseMatrixCOO(A.m, A.n, copy(A.rowind), copy(A.colind), imag.(A.nzval)) end -SparseArrays.nonzeros(A::DeviceSparseMatrixCOO) = A.nzval -getrowind(A::DeviceSparseMatrixCOO) = A.rowind -getcolind(A::DeviceSparseMatrixCOO) = A.colind -SparseArrays.getnzval(A::DeviceSparseMatrixCOO) = nonzeros(A) +SparseArrays.nonzeros(A::GenericSparseMatrixCOO) = A.nzval +getrowind(A::GenericSparseMatrixCOO) = A.rowind +getcolind(A::GenericSparseMatrixCOO) = A.colind +SparseArrays.getnzval(A::GenericSparseMatrixCOO) = nonzeros(A) -function LinearAlgebra.tr(A::DeviceSparseMatrixCOO) +function LinearAlgebra.tr(A::GenericSparseMatrixCOO) m, n = size(A) m == n || throw(DimensionMismatch("Matrix must be square to compute the trace.")) @@ -164,7 +164,7 @@ function LinearAlgebra.tr(A::DeviceSparseMatrixCOO) end # Matrix-Vector and Matrix-Matrix multiplication -for (wrapa, transa, conja, unwrapa, whereT1) in trans_adj_wrappers(:DeviceSparseMatrixCOO) +for (wrapa, transa, conja, unwrapa, whereT1) in trans_adj_wrappers(:GenericSparseMatrixCOO) for (wrapb, transb, conjb, unwrapb, whereT2) in trans_adj_wrappers(:DenseVecOrMat) TypeA = wrapa(:(T1)) TypeB = wrapb(:(T2)) @@ -233,7 +233,7 @@ for (wrapa, transa, conja, unwrapa, whereT1) in trans_adj_wrappers(:DeviceSparse end # Three-argument dot product: dot(x, A, y) = x' * A * y -for (wrapa, transa, conja, unwrapa, whereT1) in trans_adj_wrappers(:DeviceSparseMatrixCOO) +for (wrapa, transa, conja, unwrapa, whereT1) in trans_adj_wrappers(:GenericSparseMatrixCOO) TypeA = wrapa(:(T1)) kernel_dot! = transa ? :kernel_workgroup_dot_coo_T! : :kernel_workgroup_dot_coo_N! @@ -298,8 +298,8 @@ for (wrapa, transa, conja, unwrapa, whereT1) in trans_adj_wrappers(:DeviceSparse end end -# Helper function for adding DeviceSparseMatrixCOO to dense matrix -function _add_sparse_to_dense!(C::DenseMatrix, A::DeviceSparseMatrixCOO) +# Helper function for adding GenericSparseMatrixCOO to dense matrix +function _add_sparse_to_dense!(C::DenseMatrix, A::GenericSparseMatrixCOO) backend = get_backend(A) nnz_val = nnz(A) @@ -310,7 +310,7 @@ function _add_sparse_to_dense!(C::DenseMatrix, A::DeviceSparseMatrixCOO) end """ - +(A::DeviceSparseMatrixCOO, B::DeviceSparseMatrixCOO) + +(A::GenericSparseMatrixCOO, B::GenericSparseMatrixCOO) Add two sparse matrices in COO format. Both matrices must have the same dimensions and be on the same backend (device). @@ -320,11 +320,11 @@ with duplicate entries (same row and column) combined by summing their values. # Examples ```jldoctest -julia> using DeviceSparseArrays, SparseArrays +julia> using GenericSparseArrays, SparseArrays -julia> A = DeviceSparseMatrixCOO(sparse([1, 2], [1, 2], [1.0, 2.0], 2, 2)); +julia> A = GenericSparseMatrixCOO(sparse([1, 2], [1, 2], [1.0, 2.0], 2, 2)); -julia> B = DeviceSparseMatrixCOO(sparse([1, 2], [2, 1], [3.0, 4.0], 2, 2)); +julia> B = GenericSparseMatrixCOO(sparse([1, 2], [2, 1], [3.0, 4.0], 2, 2)); julia> C = A + B; @@ -334,7 +334,7 @@ julia> collect(C) 4.0 2.0 ``` """ -function Base.:+(A::DeviceSparseMatrixCOO, B::DeviceSparseMatrixCOO) +function Base.:+(A::GenericSparseMatrixCOO, B::GenericSparseMatrixCOO) size(A) == size(B) || throw( DimensionMismatch( "dimensions must match: A has dims $(size(A)), B has dims $(size(B))", @@ -416,13 +416,13 @@ function Base.:+(A::DeviceSparseMatrixCOO, B::DeviceSparseMatrixCOO) ndrange = (nnz_concat,), ) - return DeviceSparseMatrixCOO(m, n, rowind_C, colind_C, nzval_C) + return GenericSparseMatrixCOO(m, n, rowind_C, colind_C, nzval_C) end # Addition with transpose/adjoint support -for (wrapa, transa, conja, unwrapa, whereT1) in trans_adj_wrappers(:DeviceSparseMatrixCOO) +for (wrapa, transa, conja, unwrapa, whereT1) in trans_adj_wrappers(:GenericSparseMatrixCOO) for (wrapb, transb, conjb, unwrapb, whereT2) in - trans_adj_wrappers(:DeviceSparseMatrixCOO) + trans_adj_wrappers(:GenericSparseMatrixCOO) # Skip the case where both are not transposed (already handled above) (transa == false && transb == false) && continue @@ -533,13 +533,13 @@ for (wrapa, transa, conja, unwrapa, whereT1) in trans_adj_wrappers(:DeviceSparse ndrange = (nnz_concat,), ) - return DeviceSparseMatrixCOO(m, n, rowind_C, colind_C, nzval_C) + return GenericSparseMatrixCOO(m, n, rowind_C, colind_C, nzval_C) end end end """ - kron(A::DeviceSparseMatrixCOO, B::DeviceSparseMatrixCOO) + kron(A::GenericSparseMatrixCOO, B::GenericSparseMatrixCOO) Compute the Kronecker product of two sparse matrices in COO format. @@ -549,11 +549,11 @@ entire matrix `B`. # Examples ```jldoctest -julia> using DeviceSparseArrays, SparseArrays +julia> using GenericSparseArrays, SparseArrays -julia> A = DeviceSparseMatrixCOO(sparse([1, 2], [1, 2], [1.0, 2.0], 2, 2)); +julia> A = GenericSparseMatrixCOO(sparse([1, 2], [1, 2], [1.0, 2.0], 2, 2)); -julia> B = DeviceSparseMatrixCOO(sparse([1, 2], [1, 2], [3.0, 4.0], 2, 2)); +julia> B = GenericSparseMatrixCOO(sparse([1, 2], [1, 2], [3.0, 4.0], 2, 2)); julia> C = kron(A, B); @@ -565,8 +565,8 @@ julia> nnz(C) ``` """ function LinearAlgebra.kron( - A::DeviceSparseMatrixCOO{Tv1, Ti1}, - B::DeviceSparseMatrixCOO{Tv2, Ti2}, + A::GenericSparseMatrixCOO{Tv1, Ti1}, + B::GenericSparseMatrixCOO{Tv2, Ti2}, ) where {Tv1, Ti1, Tv2, Ti2} # Result dimensions m_C = size(A, 1) * size(B, 1) @@ -604,11 +604,11 @@ function LinearAlgebra.kron( ndrange = nnz_C, ) - return DeviceSparseMatrixCOO(m_C, n_C, rowind_C, colind_C, nzval_C) + return GenericSparseMatrixCOO(m_C, n_C, rowind_C, colind_C, nzval_C) end """ - *(A::DeviceSparseMatrixCOO, B::DeviceSparseMatrixCOO) + *(A::GenericSparseMatrixCOO, B::GenericSparseMatrixCOO) Multiply two sparse matrices in COO format. Both matrices must have compatible dimensions (number of columns of A equals number of rows of B) and be on the same backend (device). @@ -619,11 +619,11 @@ transpose/adjoint since COO doesn't have an efficient direct multiplication algo # Examples ```jldoctest -julia> using DeviceSparseArrays, SparseArrays +julia> using GenericSparseArrays, SparseArrays -julia> A = DeviceSparseMatrixCOO(sparse([1, 2], [1, 2], [2.0, 3.0], 2, 2)); +julia> A = GenericSparseMatrixCOO(sparse([1, 2], [1, 2], [2.0, 3.0], 2, 2)); -julia> B = DeviceSparseMatrixCOO(sparse([1, 2], [1, 2], [4.0, 5.0], 2, 2)); +julia> B = GenericSparseMatrixCOO(sparse([1, 2], [1, 2], [4.0, 5.0], 2, 2)); julia> C = A * B; @@ -633,7 +633,7 @@ julia> collect(C) 0.0 15.0 ``` """ -function Base.:(*)(A::DeviceSparseMatrixCOO, B::DeviceSparseMatrixCOO) +function Base.:(*)(A::GenericSparseMatrixCOO, B::GenericSparseMatrixCOO) size(A, 2) == size(B, 1) || throw( DimensionMismatch( "second dimension of A, $(size(A, 2)), does not match first dimension of B, $(size(B, 1))", @@ -648,16 +648,16 @@ function Base.:(*)(A::DeviceSparseMatrixCOO, B::DeviceSparseMatrixCOO) # Convert to CSC, multiply, convert back to COO # This is acceptable as COO doesn't have an efficient direct multiplication algorithm # and CSC provides the sorted structure needed for efficient SpGEMM - A_csc = DeviceSparseMatrixCSC(A) - B_csc = DeviceSparseMatrixCSC(B) + A_csc = GenericSparseMatrixCSC(A) + B_csc = GenericSparseMatrixCSC(B) C_csc = A_csc * B_csc - return DeviceSparseMatrixCOO(C_csc) + return GenericSparseMatrixCOO(C_csc) end # Multiplication with transpose/adjoint support - all cases use the same approach -for (wrapa, transa, conja, unwrapa, whereT1) in trans_adj_wrappers(:DeviceSparseMatrixCOO) +for (wrapa, transa, conja, unwrapa, whereT1) in trans_adj_wrappers(:GenericSparseMatrixCOO) for (wrapb, transb, conjb, unwrapb, whereT2) in - trans_adj_wrappers(:DeviceSparseMatrixCOO) + trans_adj_wrappers(:GenericSparseMatrixCOO) # Skip the case where both are not transposed (already handled above) (transa == false && transb == false) && continue @@ -682,10 +682,10 @@ for (wrapa, transa, conja, unwrapa, whereT1) in trans_adj_wrappers(:DeviceSparse # Convert to CSC (handles transpose/adjoint), multiply, convert back to COO # Same approach as the base case since COO doesn't have an efficient # direct multiplication algorithm - A_csc = DeviceSparseMatrixCSC(A) - B_csc = DeviceSparseMatrixCSC(B) + A_csc = GenericSparseMatrixCSC(A) + B_csc = GenericSparseMatrixCSC(B) C_csc = A_csc * B_csc - return DeviceSparseMatrixCOO(C_csc) + return GenericSparseMatrixCOO(C_csc) end end end diff --git a/src/matrix_csc/matrix_csc.jl b/src/matrix_csc/matrix_csc.jl index 806fd0c..8ecd273 100644 --- a/src/matrix_csc/matrix_csc.jl +++ b/src/matrix_csc/matrix_csc.jl @@ -1,7 +1,7 @@ -# DeviceSparseMatrixCSC implementation +# GenericSparseMatrixCSC implementation """ - DeviceSparseMatrixCSC{Tv,Ti,ColPtrT,RowValT,NzValT} <: AbstractDeviceSparseMatrix{Tv,Ti} + GenericSparseMatrixCSC{Tv,Ti,ColPtrT,RowValT,NzValT} <: AbstractGenericSparseMatrix{Tv,Ti} Compressed Sparse Column (CSC) matrix with generic storage vectors for column pointer, row indices, and nonzero values. Buffer types (e.g. `Vector`, GPU array @@ -14,20 +14,20 @@ types) enable dispatch on device characteristics. - `rowval::RowValT` - row indices of stored entries - `nzval::NzValT` - stored values """ -struct DeviceSparseMatrixCSC{ +struct GenericSparseMatrixCSC{ Tv, Ti, ColPtrT <: AbstractVector{Ti}, RowValT <: AbstractVector{Ti}, NzValT <: AbstractVector{Tv}, - } <: AbstractDeviceSparseMatrix{Tv, Ti} + } <: AbstractGenericSparseMatrix{Tv, Ti} m::Int n::Int colptr::ColPtrT rowval::RowValT nzval::NzValT - function DeviceSparseMatrixCSC( + function GenericSparseMatrixCSC( m::Integer, n::Integer, colptr::ColPtrT, @@ -62,7 +62,7 @@ struct DeviceSparseMatrixCSC{ end end -Adapt.adapt_structure(to, A::DeviceSparseMatrixCSC) = DeviceSparseMatrixCSC( +Adapt.adapt_structure(to, A::GenericSparseMatrixCSC) = GenericSparseMatrixCSC( A.m, A.n, Adapt.adapt_structure(to, A.colptr), @@ -70,23 +70,23 @@ Adapt.adapt_structure(to, A::DeviceSparseMatrixCSC) = DeviceSparseMatrixCSC( Adapt.adapt_structure(to, A.nzval), ) -Base.size(A::DeviceSparseMatrixCSC) = (A.m, A.n) -Base.length(A::DeviceSparseMatrixCSC) = A.m * A.n -Base.copy(A::DeviceSparseMatrixCSC) = - DeviceSparseMatrixCSC(A.m, A.n, copy(A.colptr), copy(A.rowval), copy(A.nzval)) +Base.size(A::GenericSparseMatrixCSC) = (A.m, A.n) +Base.length(A::GenericSparseMatrixCSC) = A.m * A.n +Base.copy(A::GenericSparseMatrixCSC) = + GenericSparseMatrixCSC(A.m, A.n, copy(A.colptr), copy(A.rowval), copy(A.nzval)) -Base.collect(A::DeviceSparseMatrixCSC) = collect(SparseMatrixCSC(A)) +Base.collect(A::GenericSparseMatrixCSC) = collect(SparseMatrixCSC(A)) -function Base.zero(A::DeviceSparseMatrixCSC) +function Base.zero(A::GenericSparseMatrixCSC) colptr = similar(A.colptr) rowval = similar(A.rowval, 0) nzval = similar(A.nzval, 0) fill!(colptr, one(eltype(colptr))) - return DeviceSparseMatrixCSC(A.m, A.n, colptr, rowval, nzval) + return GenericSparseMatrixCSC(A.m, A.n, colptr, rowval, nzval) end -function Base.:(*)(α::Number, A::DeviceSparseMatrixCSC) - return DeviceSparseMatrixCSC( +function Base.:(*)(α::Number, A::GenericSparseMatrixCSC) + return GenericSparseMatrixCSC( A.m, A.n, copy(getcolptr(A)), @@ -94,39 +94,39 @@ function Base.:(*)(α::Number, A::DeviceSparseMatrixCSC) α .* nonzeros(A), ) end -Base.:(*)(A::DeviceSparseMatrixCSC, α::Number) = α * A -Base.:(/)(A::DeviceSparseMatrixCSC, α::Number) = (1 / α) * A +Base.:(*)(A::GenericSparseMatrixCSC, α::Number) = α * A +Base.:(/)(A::GenericSparseMatrixCSC, α::Number) = (1 / α) * A -function Base.:-(A::DeviceSparseMatrixCSC) - return DeviceSparseMatrixCSC(A.m, A.n, copy(A.colptr), copy(A.rowval), -A.nzval) +function Base.:-(A::GenericSparseMatrixCSC) + return GenericSparseMatrixCSC(A.m, A.n, copy(A.colptr), copy(A.rowval), -A.nzval) end -Base.conj(A::DeviceSparseMatrixCSC{<:Real}) = A -function Base.conj(A::DeviceSparseMatrixCSC{<:Complex}) - return DeviceSparseMatrixCSC(A.m, A.n, copy(A.colptr), copy(A.rowval), conj.(A.nzval)) +Base.conj(A::GenericSparseMatrixCSC{<:Real}) = A +function Base.conj(A::GenericSparseMatrixCSC{<:Complex}) + return GenericSparseMatrixCSC(A.m, A.n, copy(A.colptr), copy(A.rowval), conj.(A.nzval)) end -Base.real(A::DeviceSparseMatrixCSC{<:Real}) = A -function Base.real(A::DeviceSparseMatrixCSC{<:Complex}) - return DeviceSparseMatrixCSC(A.m, A.n, copy(A.colptr), copy(A.rowval), real.(A.nzval)) +Base.real(A::GenericSparseMatrixCSC{<:Real}) = A +function Base.real(A::GenericSparseMatrixCSC{<:Complex}) + return GenericSparseMatrixCSC(A.m, A.n, copy(A.colptr), copy(A.rowval), real.(A.nzval)) end -Base.imag(A::DeviceSparseMatrixCSC{<:Real}) = zero(A) -function Base.imag(A::DeviceSparseMatrixCSC{<:Complex}) - return DeviceSparseMatrixCSC(A.m, A.n, copy(A.colptr), copy(A.rowval), imag.(A.nzval)) +Base.imag(A::GenericSparseMatrixCSC{<:Real}) = zero(A) +function Base.imag(A::GenericSparseMatrixCSC{<:Complex}) + return GenericSparseMatrixCSC(A.m, A.n, copy(A.colptr), copy(A.rowval), imag.(A.nzval)) end -SparseArrays.nonzeros(A::DeviceSparseMatrixCSC) = A.nzval -SparseArrays.getcolptr(A::DeviceSparseMatrixCSC) = A.colptr -SparseArrays.rowvals(A::DeviceSparseMatrixCSC) = A.rowval -SparseArrays.getrowval(A::DeviceSparseMatrixCSC) = rowvals(A) -function SparseArrays.nzrange(A::DeviceSparseMatrixCSC, col::Integer) +SparseArrays.nonzeros(A::GenericSparseMatrixCSC) = A.nzval +SparseArrays.getcolptr(A::GenericSparseMatrixCSC) = A.colptr +SparseArrays.rowvals(A::GenericSparseMatrixCSC) = A.rowval +SparseArrays.getrowval(A::GenericSparseMatrixCSC) = rowvals(A) +function SparseArrays.nzrange(A::GenericSparseMatrixCSC, col::Integer) get_backend(A) isa KernelAbstractions.CPU || throw(ArgumentError("nzrange is only supported on CPU backend")) return getcolptr(A)[col]:(getcolptr(A)[col + 1] - 1) end -function LinearAlgebra.tr(A::DeviceSparseMatrixCSC) +function LinearAlgebra.tr(A::GenericSparseMatrixCSC) m, n = size(A) m == n || throw(DimensionMismatch("Matrix must be square to compute the trace.")) @@ -153,7 +153,7 @@ function LinearAlgebra.tr(A::DeviceSparseMatrixCSC) end # Matrix-Vector and Matrix-Matrix multiplication -for (wrapa, transa, conja, unwrapa, whereT1) in trans_adj_wrappers(:DeviceSparseMatrixCSC) +for (wrapa, transa, conja, unwrapa, whereT1) in trans_adj_wrappers(:GenericSparseMatrixCSC) for (wrapb, transb, conjb, unwrapb, whereT2) in trans_adj_wrappers(:DenseVecOrMat) TypeA = wrapa(:(T1)) TypeB = wrapb(:(T2)) @@ -225,7 +225,7 @@ for (wrapa, transa, conja, unwrapa, whereT1) in trans_adj_wrappers(:DeviceSparse end # Three-argument dot product: dot(x, A, y) = x' * A * y -for (wrapa, transa, conja, unwrapa, whereT1) in trans_adj_wrappers(:DeviceSparseMatrixCSC) +for (wrapa, transa, conja, unwrapa, whereT1) in trans_adj_wrappers(:GenericSparseMatrixCSC) TypeA = wrapa(:(T1)) kernel_dot! = transa ? :kernel_workgroup_dot_csc_T! : :kernel_workgroup_dot_csc_N! @@ -290,8 +290,8 @@ for (wrapa, transa, conja, unwrapa, whereT1) in trans_adj_wrappers(:DeviceSparse end end -# Helper function for adding DeviceSparseMatrixCSC to dense matrix -function _add_sparse_to_dense!(C::DenseMatrix, A::DeviceSparseMatrixCSC) +# Helper function for adding GenericSparseMatrixCSC to dense matrix +function _add_sparse_to_dense!(C::DenseMatrix, A::GenericSparseMatrixCSC) backend = get_backend(A) n = size(A, 2) @@ -302,18 +302,18 @@ function _add_sparse_to_dense!(C::DenseMatrix, A::DeviceSparseMatrixCSC) end """ - +(A::DeviceSparseMatrixCSC, B::DeviceSparseMatrixCSC) + +(A::GenericSparseMatrixCSC, B::GenericSparseMatrixCSC) Add two sparse matrices in CSC format. Both matrices must have the same dimensions and be on the same backend (device). # Examples ```jldoctest -julia> using DeviceSparseArrays, SparseArrays +julia> using GenericSparseArrays, SparseArrays -julia> A = DeviceSparseMatrixCSC(sparse([1, 2], [1, 2], [1.0, 2.0], 2, 2)); +julia> A = GenericSparseMatrixCSC(sparse([1, 2], [1, 2], [1.0, 2.0], 2, 2)); -julia> B = DeviceSparseMatrixCSC(sparse([1, 2], [2, 1], [3.0, 4.0], 2, 2)); +julia> B = GenericSparseMatrixCSC(sparse([1, 2], [2, 1], [3.0, 4.0], 2, 2)); julia> C = A + B; @@ -323,7 +323,7 @@ julia> collect(C) 4.0 2.0 ``` """ -function Base.:+(A::DeviceSparseMatrixCSC, B::DeviceSparseMatrixCSC) +function Base.:+(A::GenericSparseMatrixCSC, B::GenericSparseMatrixCSC) size(A) == size(B) || throw( DimensionMismatch( "dimensions must match: A has dims $(size(A)), B has dims $(size(B))", @@ -386,13 +386,13 @@ function Base.:+(A::DeviceSparseMatrixCSC, B::DeviceSparseMatrixCSC) ndrange = (n,), ) - return DeviceSparseMatrixCSC(m, n, colptr_C, rowval_C, nzval_C) + return GenericSparseMatrixCSC(m, n, colptr_C, rowval_C, nzval_C) end # Addition with transpose/adjoint support -for (wrapa, transa, conja, unwrapa, whereT1) in trans_adj_wrappers(:DeviceSparseMatrixCSC) +for (wrapa, transa, conja, unwrapa, whereT1) in trans_adj_wrappers(:GenericSparseMatrixCSC) for (wrapb, transb, conjb, unwrapb, whereT2) in - trans_adj_wrappers(:DeviceSparseMatrixCSC) + trans_adj_wrappers(:GenericSparseMatrixCSC) # Skip the case where both are not transposed (already handled above) (transa == false && transb == false) && continue @@ -409,18 +409,18 @@ for (wrapa, transa, conja, unwrapa, whereT1) in trans_adj_wrappers(:DeviceSparse # Convert both to CSR (transpose/adjoint of CSC has CSR structure) # and use existing CSR + CSR addition. The conversion methods # already handle transpose/adjoint correctly. - A_csr = DeviceSparseMatrixCSR(A) - B_csr = DeviceSparseMatrixCSR(B) + A_csr = GenericSparseMatrixCSR(A) + B_csr = GenericSparseMatrixCSR(B) result_csr = A_csr + B_csr # Convert back to CSC - return DeviceSparseMatrixCSC(result_csr) + return GenericSparseMatrixCSC(result_csr) end end end """ - kron(A::DeviceSparseMatrixCSC, B::DeviceSparseMatrixCSC) + kron(A::GenericSparseMatrixCSC, B::GenericSparseMatrixCSC) Compute the Kronecker product of two sparse matrices in CSC format. @@ -429,11 +429,11 @@ product, and converting back to CSC format. # Examples ```jldoctest -julia> using DeviceSparseArrays, SparseArrays +julia> using GenericSparseArrays, SparseArrays -julia> A = DeviceSparseMatrixCSC(sparse([1, 2], [1, 2], [1.0, 2.0], 2, 2)); +julia> A = GenericSparseMatrixCSC(sparse([1, 2], [1, 2], [1.0, 2.0], 2, 2)); -julia> B = DeviceSparseMatrixCSC(sparse([1, 2], [1, 2], [3.0, 4.0], 2, 2)); +julia> B = GenericSparseMatrixCSC(sparse([1, 2], [1, 2], [3.0, 4.0], 2, 2)); julia> C = kron(A, B); @@ -444,16 +444,16 @@ julia> nnz(C) 4 ``` """ -function LinearAlgebra.kron(A::DeviceSparseMatrixCSC, B::DeviceSparseMatrixCSC) +function LinearAlgebra.kron(A::GenericSparseMatrixCSC, B::GenericSparseMatrixCSC) # Convert to COO, compute kron, convert back to CSC - A_coo = DeviceSparseMatrixCOO(A) - B_coo = DeviceSparseMatrixCOO(B) + A_coo = GenericSparseMatrixCOO(A) + B_coo = GenericSparseMatrixCOO(B) C_coo = kron(A_coo, B_coo) - return DeviceSparseMatrixCSC(C_coo) + return GenericSparseMatrixCSC(C_coo) end """ - *(A::DeviceSparseMatrixCSC, B::DeviceSparseMatrixCSC) + *(A::GenericSparseMatrixCSC, B::GenericSparseMatrixCSC) Multiply two sparse matrices in CSC format. Both matrices must have compatible dimensions (number of columns of A equals number of rows of B) and be on the same backend (device). @@ -463,11 +463,11 @@ multiplication (SpGEMM). # Examples ```jldoctest -julia> using DeviceSparseArrays, SparseArrays +julia> using GenericSparseArrays, SparseArrays -julia> A = DeviceSparseMatrixCSC(sparse([1, 2], [1, 2], [2.0, 3.0], 2, 2)); +julia> A = GenericSparseMatrixCSC(sparse([1, 2], [1, 2], [2.0, 3.0], 2, 2)); -julia> B = DeviceSparseMatrixCSC(sparse([1, 2], [1, 2], [4.0, 5.0], 2, 2)); +julia> B = GenericSparseMatrixCSC(sparse([1, 2], [1, 2], [4.0, 5.0], 2, 2)); julia> C = A * B; @@ -477,7 +477,7 @@ julia> collect(C) 0.0 15.0 ``` """ -function Base.:(*)(A::DeviceSparseMatrixCSC, B::DeviceSparseMatrixCSC) +function Base.:(*)(A::GenericSparseMatrixCSC, B::GenericSparseMatrixCSC) size(A, 2) == size(B, 1) || throw( DimensionMismatch( "second dimension of A, $(size(A, 2)), does not match first dimension of B, $(size(B, 1))", @@ -550,13 +550,13 @@ function Base.:(*)(A::DeviceSparseMatrixCSC, B::DeviceSparseMatrixCSC) ndrange = (n,), ) - return DeviceSparseMatrixCSC(m, n, colptr_C, rowval_C, nzval_C) + return GenericSparseMatrixCSC(m, n, colptr_C, rowval_C, nzval_C) end # Multiplication with transpose/adjoint support -for (wrapa, transa, conja, unwrapa, whereT1) in trans_adj_wrappers(:DeviceSparseMatrixCSC) +for (wrapa, transa, conja, unwrapa, whereT1) in trans_adj_wrappers(:GenericSparseMatrixCSC) for (wrapb, transb, conjb, unwrapb, whereT2) in - trans_adj_wrappers(:DeviceSparseMatrixCSC) + trans_adj_wrappers(:GenericSparseMatrixCSC) # Skip the case where both are not transposed (already handled above) (transa == false && transb == false) && continue @@ -583,12 +583,12 @@ for (wrapa, transa, conja, unwrapa, whereT1) in trans_adj_wrappers(:DeviceSparse # For transpose/adjoint, convert to CSR format (which is CSC transposed structurally) # This follows the same pattern as addition with transpose/adjoint - A_csr = DeviceSparseMatrixCSR(A) - B_csr = DeviceSparseMatrixCSR(B) + A_csr = GenericSparseMatrixCSR(A) + B_csr = GenericSparseMatrixCSR(B) result_csr = A_csr * B_csr # Convert back to CSC - return DeviceSparseMatrixCSC(result_csr) + return GenericSparseMatrixCSC(result_csr) end end end diff --git a/src/matrix_csr/matrix_csr.jl b/src/matrix_csr/matrix_csr.jl index 7b1a0ba..dbf6934 100644 --- a/src/matrix_csr/matrix_csr.jl +++ b/src/matrix_csr/matrix_csr.jl @@ -1,7 +1,7 @@ -# DeviceSparseMatrixCSR implementation +# GenericSparseMatrixCSR implementation """ - DeviceSparseMatrixCSR{Tv,Ti,RowPtrT,ColValT,NzValT} <: AbstractDeviceSparseMatrix{Tv,Ti} + GenericSparseMatrixCSR{Tv,Ti,RowPtrT,ColValT,NzValT} <: AbstractGenericSparseMatrix{Tv,Ti} Compressed Sparse Row (CSR) matrix with generic storage vectors for row pointer, column indices, and nonzero values. Buffer types (e.g. `Vector`, GPU array @@ -14,20 +14,20 @@ types) enable dispatch on device characteristics. - `colval::ColValT` - column indices of stored entries - `nzval::NzValT` - stored values """ -struct DeviceSparseMatrixCSR{ +struct GenericSparseMatrixCSR{ Tv, Ti, RowPtrT <: AbstractVector{Ti}, ColValT <: AbstractVector{Ti}, NzValT <: AbstractVector{Tv}, - } <: AbstractDeviceSparseMatrix{Tv, Ti} + } <: AbstractGenericSparseMatrix{Tv, Ti} m::Int n::Int rowptr::RowPtrT colval::ColValT nzval::NzValT - function DeviceSparseMatrixCSR( + function GenericSparseMatrixCSR( m::Integer, n::Integer, rowptr::RowPtrT, @@ -62,7 +62,7 @@ struct DeviceSparseMatrixCSR{ end end -Adapt.adapt_structure(to, A::DeviceSparseMatrixCSR) = DeviceSparseMatrixCSR( +Adapt.adapt_structure(to, A::GenericSparseMatrixCSR) = GenericSparseMatrixCSR( A.m, A.n, Adapt.adapt_structure(to, A.rowptr), @@ -70,23 +70,23 @@ Adapt.adapt_structure(to, A::DeviceSparseMatrixCSR) = DeviceSparseMatrixCSR( Adapt.adapt_structure(to, A.nzval), ) -Base.size(A::DeviceSparseMatrixCSR) = (A.m, A.n) -Base.length(A::DeviceSparseMatrixCSR) = A.m * A.n -Base.copy(A::DeviceSparseMatrixCSR) = - DeviceSparseMatrixCSR(A.m, A.n, copy(A.rowptr), copy(A.colval), copy(A.nzval)) +Base.size(A::GenericSparseMatrixCSR) = (A.m, A.n) +Base.length(A::GenericSparseMatrixCSR) = A.m * A.n +Base.copy(A::GenericSparseMatrixCSR) = + GenericSparseMatrixCSR(A.m, A.n, copy(A.rowptr), copy(A.colval), copy(A.nzval)) -Base.collect(A::DeviceSparseMatrixCSR) = collect(SparseMatrixCSC(A)) +Base.collect(A::GenericSparseMatrixCSR) = collect(SparseMatrixCSC(A)) -function Base.zero(A::DeviceSparseMatrixCSR) +function Base.zero(A::GenericSparseMatrixCSR) rowptr = similar(A.rowptr) rowval = similar(A.colval, 0) nzval = similar(A.nzval, 0) fill!(rowptr, one(eltype(rowptr))) - return DeviceSparseMatrixCSR(A.m, A.n, rowptr, rowval, nzval) + return GenericSparseMatrixCSR(A.m, A.n, rowptr, rowval, nzval) end -function Base.:(*)(α::Number, A::DeviceSparseMatrixCSR) - return DeviceSparseMatrixCSR( +function Base.:(*)(α::Number, A::GenericSparseMatrixCSR) + return GenericSparseMatrixCSR( A.m, A.n, copy(getrowptr(A)), @@ -94,40 +94,40 @@ function Base.:(*)(α::Number, A::DeviceSparseMatrixCSR) α .* nonzeros(A), ) end -Base.:(*)(A::DeviceSparseMatrixCSR, α::Number) = α * A -Base.:(/)(A::DeviceSparseMatrixCSR, α::Number) = (1 / α) * A +Base.:(*)(A::GenericSparseMatrixCSR, α::Number) = α * A +Base.:(/)(A::GenericSparseMatrixCSR, α::Number) = (1 / α) * A -function Base.:-(A::DeviceSparseMatrixCSR) - return DeviceSparseMatrixCSR(A.m, A.n, copy(A.rowptr), copy(A.colval), -A.nzval) +function Base.:-(A::GenericSparseMatrixCSR) + return GenericSparseMatrixCSR(A.m, A.n, copy(A.rowptr), copy(A.colval), -A.nzval) end -Base.conj(A::DeviceSparseMatrixCSR{<:Real}) = A -function Base.conj(A::DeviceSparseMatrixCSR{<:Complex}) - return DeviceSparseMatrixCSR(A.m, A.n, copy(A.rowptr), copy(A.colval), conj.(A.nzval)) +Base.conj(A::GenericSparseMatrixCSR{<:Real}) = A +function Base.conj(A::GenericSparseMatrixCSR{<:Complex}) + return GenericSparseMatrixCSR(A.m, A.n, copy(A.rowptr), copy(A.colval), conj.(A.nzval)) end -Base.real(A::DeviceSparseMatrixCSR{<:Real}) = A -function Base.real(A::DeviceSparseMatrixCSR{<:Complex}) - return DeviceSparseMatrixCSR(A.m, A.n, copy(A.rowptr), copy(A.colval), real.(A.nzval)) +Base.real(A::GenericSparseMatrixCSR{<:Real}) = A +function Base.real(A::GenericSparseMatrixCSR{<:Complex}) + return GenericSparseMatrixCSR(A.m, A.n, copy(A.rowptr), copy(A.colval), real.(A.nzval)) end -Base.imag(A::DeviceSparseMatrixCSR{<:Real}) = zero(A) -function Base.imag(A::DeviceSparseMatrixCSR{<:Complex}) - return DeviceSparseMatrixCSR(A.m, A.n, copy(A.rowptr), copy(A.colval), imag.(A.nzval)) +Base.imag(A::GenericSparseMatrixCSR{<:Real}) = zero(A) +function Base.imag(A::GenericSparseMatrixCSR{<:Complex}) + return GenericSparseMatrixCSR(A.m, A.n, copy(A.rowptr), copy(A.colval), imag.(A.nzval)) end -SparseArrays.nonzeros(A::DeviceSparseMatrixCSR) = A.nzval -getrowptr(A::DeviceSparseMatrixCSR) = A.rowptr -colvals(A::DeviceSparseMatrixCSR) = A.colval -getcolval(A::DeviceSparseMatrixCSR) = colvals(A) -SparseArrays.getnzval(A::DeviceSparseMatrixCSR) = nonzeros(A) -function SparseArrays.nzrange(A::DeviceSparseMatrixCSR, row::Integer) +SparseArrays.nonzeros(A::GenericSparseMatrixCSR) = A.nzval +getrowptr(A::GenericSparseMatrixCSR) = A.rowptr +colvals(A::GenericSparseMatrixCSR) = A.colval +getcolval(A::GenericSparseMatrixCSR) = colvals(A) +SparseArrays.getnzval(A::GenericSparseMatrixCSR) = nonzeros(A) +function SparseArrays.nzrange(A::GenericSparseMatrixCSR, row::Integer) get_backend(A) isa KernelAbstractions.CPU || throw(ArgumentError("nzrange is only supported on CPU backend")) return getrowptr(A)[row]:(getrowptr(A)[row + 1] - 1) end -function LinearAlgebra.tr(A::DeviceSparseMatrixCSR) +function LinearAlgebra.tr(A::GenericSparseMatrixCSR) m, n = size(A) m == n || throw(DimensionMismatch("Matrix must be square to compute the trace.")) @@ -154,7 +154,7 @@ function LinearAlgebra.tr(A::DeviceSparseMatrixCSR) end # Matrix-Vector and Matrix-Matrix multiplication -for (wrapa, transa, conja, unwrapa, whereT1) in trans_adj_wrappers(:DeviceSparseMatrixCSR) +for (wrapa, transa, conja, unwrapa, whereT1) in trans_adj_wrappers(:GenericSparseMatrixCSR) for (wrapb, transb, conjb, unwrapb, whereT2) in trans_adj_wrappers(:DenseVecOrMat) TypeA = wrapa(:(T1)) TypeB = wrapb(:(T2)) @@ -223,7 +223,7 @@ for (wrapa, transa, conja, unwrapa, whereT1) in trans_adj_wrappers(:DeviceSparse end # Three-argument dot product: dot(x, A, y) = x' * A * y -for (wrapa, transa, conja, unwrapa, whereT1) in trans_adj_wrappers(:DeviceSparseMatrixCSR) +for (wrapa, transa, conja, unwrapa, whereT1) in trans_adj_wrappers(:GenericSparseMatrixCSR) TypeA = wrapa(:(T1)) kernel_dot! = transa ? :kernel_workgroup_dot_csr_T! : :kernel_workgroup_dot_csr_N! @@ -288,8 +288,8 @@ for (wrapa, transa, conja, unwrapa, whereT1) in trans_adj_wrappers(:DeviceSparse end end -# Helper function for adding DeviceSparseMatrixCSR to dense matrix -function _add_sparse_to_dense!(C::DenseMatrix, A::DeviceSparseMatrixCSR) +# Helper function for adding GenericSparseMatrixCSR to dense matrix +function _add_sparse_to_dense!(C::DenseMatrix, A::GenericSparseMatrixCSR) backend = get_backend(A) m = size(A, 1) @@ -300,18 +300,18 @@ function _add_sparse_to_dense!(C::DenseMatrix, A::DeviceSparseMatrixCSR) end """ - +(A::DeviceSparseMatrixCSR, B::DeviceSparseMatrixCSR) + +(A::GenericSparseMatrixCSR, B::GenericSparseMatrixCSR) Add two sparse matrices in CSR format. Both matrices must have the same dimensions and be on the same backend (device). # Examples ```jldoctest -julia> using DeviceSparseArrays, SparseArrays +julia> using GenericSparseArrays, SparseArrays -julia> A = DeviceSparseMatrixCSR(sparse([1, 2], [1, 2], [1.0, 2.0], 2, 2)); +julia> A = GenericSparseMatrixCSR(sparse([1, 2], [1, 2], [1.0, 2.0], 2, 2)); -julia> B = DeviceSparseMatrixCSR(sparse([1, 2], [2, 1], [3.0, 4.0], 2, 2)); +julia> B = GenericSparseMatrixCSR(sparse([1, 2], [2, 1], [3.0, 4.0], 2, 2)); julia> C = A + B; @@ -321,7 +321,7 @@ julia> collect(C) 4.0 2.0 ``` """ -function Base.:+(A::DeviceSparseMatrixCSR, B::DeviceSparseMatrixCSR) +function Base.:+(A::GenericSparseMatrixCSR, B::GenericSparseMatrixCSR) size(A) == size(B) || throw( DimensionMismatch( "dimensions must match: A has dims $(size(A)), B has dims $(size(B))", @@ -384,13 +384,13 @@ function Base.:+(A::DeviceSparseMatrixCSR, B::DeviceSparseMatrixCSR) ndrange = (m,), ) - return DeviceSparseMatrixCSR(m, n, rowptr_C, colval_C, nzval_C) + return GenericSparseMatrixCSR(m, n, rowptr_C, colval_C, nzval_C) end # Addition with transpose/adjoint support -for (wrapa, transa, conja, unwrapa, whereT1) in trans_adj_wrappers(:DeviceSparseMatrixCSR) +for (wrapa, transa, conja, unwrapa, whereT1) in trans_adj_wrappers(:GenericSparseMatrixCSR) for (wrapb, transb, conjb, unwrapb, whereT2) in - trans_adj_wrappers(:DeviceSparseMatrixCSR) + trans_adj_wrappers(:GenericSparseMatrixCSR) # Skip the case where both are not transposed (already handled above) (transa == false && transb == false) && continue @@ -407,18 +407,18 @@ for (wrapa, transa, conja, unwrapa, whereT1) in trans_adj_wrappers(:DeviceSparse # Convert both to CSC (transpose/adjoint of CSR has CSC structure) # and use existing CSC + CSC addition. The conversion methods # already handle transpose/adjoint correctly. - A_csc = DeviceSparseMatrixCSC(A) - B_csc = DeviceSparseMatrixCSC(B) + A_csc = GenericSparseMatrixCSC(A) + B_csc = GenericSparseMatrixCSC(B) result_csc = A_csc + B_csc # Convert back to CSR - return DeviceSparseMatrixCSR(result_csc) + return GenericSparseMatrixCSR(result_csc) end end end """ - kron(A::DeviceSparseMatrixCSR, B::DeviceSparseMatrixCSR) + kron(A::GenericSparseMatrixCSR, B::GenericSparseMatrixCSR) Compute the Kronecker product of two sparse matrices in CSR format. @@ -427,15 +427,15 @@ product, and converting back to CSR format. # Examples ```jldoctest -julia> using DeviceSparseArrays, SparseArrays +julia> using GenericSparseArrays, SparseArrays -julia> A_coo = DeviceSparseMatrixCOO(sparse([1, 2], [1, 2], [1.0, 2.0], 2, 2)); +julia> A_coo = GenericSparseMatrixCOO(sparse([1, 2], [1, 2], [1.0, 2.0], 2, 2)); -julia> B_coo = DeviceSparseMatrixCOO(sparse([1, 2], [1, 2], [3.0, 4.0], 2, 2)); +julia> B_coo = GenericSparseMatrixCOO(sparse([1, 2], [1, 2], [3.0, 4.0], 2, 2)); -julia> A = DeviceSparseMatrixCSR(A_coo); +julia> A = GenericSparseMatrixCSR(A_coo); -julia> B = DeviceSparseMatrixCSR(B_coo); +julia> B = GenericSparseMatrixCSR(B_coo); julia> C = kron(A, B); @@ -446,16 +446,16 @@ julia> nnz(C) 4 ``` """ -function LinearAlgebra.kron(A::DeviceSparseMatrixCSR, B::DeviceSparseMatrixCSR) +function LinearAlgebra.kron(A::GenericSparseMatrixCSR, B::GenericSparseMatrixCSR) # Convert to COO, compute kron, convert back to CSR - A_coo = DeviceSparseMatrixCOO(A) - B_coo = DeviceSparseMatrixCOO(B) + A_coo = GenericSparseMatrixCOO(A) + B_coo = GenericSparseMatrixCOO(B) C_coo = kron(A_coo, B_coo) - return DeviceSparseMatrixCSR(C_coo) + return GenericSparseMatrixCSR(C_coo) end """ - *(A::DeviceSparseMatrixCSR, B::DeviceSparseMatrixCSR) + *(A::GenericSparseMatrixCSR, B::GenericSparseMatrixCSR) Multiply two sparse matrices in CSR format. Both matrices must have compatible dimensions (number of columns of A equals number of rows of B) and be on the same backend (device). @@ -465,11 +465,11 @@ multiplication (SpGEMM). # Examples ```jldoctest -julia> using DeviceSparseArrays, SparseArrays +julia> using GenericSparseArrays, SparseArrays -julia> A = DeviceSparseMatrixCSR(DeviceSparseMatrixCOO(sparse([1, 2], [1, 2], [2.0, 3.0], 2, 2))); +julia> A = GenericSparseMatrixCSR(GenericSparseMatrixCOO(sparse([1, 2], [1, 2], [2.0, 3.0], 2, 2))); -julia> B = DeviceSparseMatrixCSR(DeviceSparseMatrixCOO(sparse([1, 2], [1, 2], [4.0, 5.0], 2, 2))); +julia> B = GenericSparseMatrixCSR(GenericSparseMatrixCOO(sparse([1, 2], [1, 2], [4.0, 5.0], 2, 2))); julia> C = A * B; @@ -479,7 +479,7 @@ julia> collect(C) 0.0 15.0 ``` """ -function Base.:(*)(A::DeviceSparseMatrixCSR, B::DeviceSparseMatrixCSR) +function Base.:(*)(A::GenericSparseMatrixCSR, B::GenericSparseMatrixCSR) size(A, 2) == size(B, 1) || throw( DimensionMismatch( "second dimension of A, $(size(A, 2)), does not match first dimension of B, $(size(B, 1))", @@ -552,13 +552,13 @@ function Base.:(*)(A::DeviceSparseMatrixCSR, B::DeviceSparseMatrixCSR) ndrange = (m,), ) - return DeviceSparseMatrixCSR(m, n, rowptr_C, colval_C, nzval_C) + return GenericSparseMatrixCSR(m, n, rowptr_C, colval_C, nzval_C) end # Multiplication with transpose/adjoint support -for (wrapa, transa, conja, unwrapa, whereT1) in trans_adj_wrappers(:DeviceSparseMatrixCSR) +for (wrapa, transa, conja, unwrapa, whereT1) in trans_adj_wrappers(:GenericSparseMatrixCSR) for (wrapb, transb, conjb, unwrapb, whereT2) in - trans_adj_wrappers(:DeviceSparseMatrixCSR) + trans_adj_wrappers(:GenericSparseMatrixCSR) # Skip the case where both are not transposed (already handled above) (transa == false && transb == false) && continue @@ -582,12 +582,12 @@ for (wrapa, transa, conja, unwrapa, whereT1) in trans_adj_wrappers(:DeviceSparse # For transpose/adjoint, convert to CSC format (which is CSR transposed structurally) # This follows the same pattern as addition with transpose/adjoint - A_csc = DeviceSparseMatrixCSC(A) - B_csc = DeviceSparseMatrixCSC(B) + A_csc = GenericSparseMatrixCSC(A) + B_csc = GenericSparseMatrixCSC(B) result_csc = A_csc * B_csc # Convert back to CSR - return DeviceSparseMatrixCSR(result_csc) + return GenericSparseMatrixCSR(result_csc) end end end diff --git a/src/vector/vector.jl b/src/vector/vector.jl index 35f83ca..a838651 100644 --- a/src/vector/vector.jl +++ b/src/vector/vector.jl @@ -1,7 +1,7 @@ -# DeviceSparseVector implementation +# GenericSparseVector implementation """ - DeviceSparseVector{Tv,Ti,IndT<:AbstractVector{Ti},ValT<:AbstractVector{Tv}} <: AbstractDeviceSparseVector{Tv,Ti} + GenericSparseVector{Tv,Ti,IndT<:AbstractVector{Ti},ValT<:AbstractVector{Tv}} <: AbstractGenericSparseVector{Tv,Ti} Sparse vector with generic index and value storage containers which may reside on different devices. The logical length is stored along with index/value buffers. @@ -13,13 +13,13 @@ on different devices. The logical length is stored along with index/value buffer Constructors validate that the index and value vectors have matching length. """ -struct DeviceSparseVector{Tv, Ti, IndT <: AbstractVector{Ti}, ValT <: AbstractVector{Tv}} <: - AbstractDeviceSparseVector{Tv, Ti} +struct GenericSparseVector{Tv, Ti, IndT <: AbstractVector{Ti}, ValT <: AbstractVector{Tv}} <: + AbstractGenericSparseVector{Tv, Ti} n::Int nzind::IndT nzval::ValT - function DeviceSparseVector( + function GenericSparseVector( n::Integer, nzind::IndT, nzval::ValT, @@ -37,69 +37,69 @@ struct DeviceSparseVector{Tv, Ti, IndT <: AbstractVector{Ti}, ValT <: AbstractVe end # Conversions -DeviceSparseVector(V::SparseVector) = DeviceSparseVector(V.n, V.nzind, V.nzval) -SparseVector(V::DeviceSparseVector) = SparseVector(V.n, collect(V.nzind), collect(V.nzval)) +GenericSparseVector(V::SparseVector) = GenericSparseVector(V.n, V.nzind, V.nzval) +SparseVector(V::GenericSparseVector) = SparseVector(V.n, collect(V.nzind), collect(V.nzval)) -Adapt.adapt_structure(to, V::DeviceSparseVector) = DeviceSparseVector( +Adapt.adapt_structure(to, V::GenericSparseVector) = GenericSparseVector( V.n, Adapt.adapt_structure(to, V.nzind), Adapt.adapt_structure(to, V.nzval), ) # Basic methods -Base.length(V::DeviceSparseVector) = V.n -Base.size(V::DeviceSparseVector) = (V.n,) -SparseArrays.nonzeros(V::DeviceSparseVector) = V.nzval -SparseArrays.nonzeroinds(V::DeviceSparseVector) = V.nzind +Base.length(V::GenericSparseVector) = V.n +Base.size(V::GenericSparseVector) = (V.n,) +SparseArrays.nonzeros(V::GenericSparseVector) = V.nzval +SparseArrays.nonzeroinds(V::GenericSparseVector) = V.nzind -Base.copy(V::DeviceSparseVector) = DeviceSparseVector(V.n, copy(V.nzind), copy(V.nzval)) -function Base.copyto!(dest::DeviceSparseVector, src::DeviceSparseVector) +Base.copy(V::GenericSparseVector) = GenericSparseVector(V.n, copy(V.nzind), copy(V.nzval)) +function Base.copyto!(dest::GenericSparseVector, src::GenericSparseVector) _prep_sparsevec_copy_dest!(dest, length(src), nnz(src)) copyto!(nonzeroinds(dest), 1, nonzeroinds(src), 1, nnz(src)) copyto!(nonzeros(dest), 1, nonzeros(src), 1, nnz(src)) return dest end -Base.similar(V::DeviceSparseVector, ::Type{Tv2}) where {Tv2} = - DeviceSparseVector(V.n, copy(V.nzind), similar(V.nzval, Tv2)) +Base.similar(V::GenericSparseVector, ::Type{Tv2}) where {Tv2} = + GenericSparseVector(V.n, copy(V.nzind), similar(V.nzval, Tv2)) -function Base.:(*)(α::Number, V::DeviceSparseVector) - return DeviceSparseVector(V.n, copy(V.nzind), α .* V.nzval) +function Base.:(*)(α::Number, V::GenericSparseVector) + return GenericSparseVector(V.n, copy(V.nzind), α .* V.nzval) end -Base.:(*)(V::DeviceSparseVector, α::Number) = α * V -Base.:(/)(V::DeviceSparseVector, α::Number) = (1 / α) * V +Base.:(*)(V::GenericSparseVector, α::Number) = α * V +Base.:(/)(V::GenericSparseVector, α::Number) = (1 / α) * V -function Base.:-(V::DeviceSparseVector) - return DeviceSparseVector(V.n, copy(V.nzind), -V.nzval) +function Base.:-(V::GenericSparseVector) + return GenericSparseVector(V.n, copy(V.nzind), -V.nzval) end -Base.conj(V::DeviceSparseVector{<:Real}) = V -function Base.conj(V::DeviceSparseVector{<:Complex}) - return DeviceSparseVector(V.n, copy(V.nzind), conj.(V.nzval)) +Base.conj(V::GenericSparseVector{<:Real}) = V +function Base.conj(V::GenericSparseVector{<:Complex}) + return GenericSparseVector(V.n, copy(V.nzind), conj.(V.nzval)) end -Base.real(V::DeviceSparseVector{<:Real}) = V -function Base.real(V::DeviceSparseVector{<:Complex}) - return DeviceSparseVector(V.n, copy(V.nzind), real.(V.nzval)) +Base.real(V::GenericSparseVector{<:Real}) = V +function Base.real(V::GenericSparseVector{<:Complex}) + return GenericSparseVector(V.n, copy(V.nzind), real.(V.nzval)) end -Base.imag(V::DeviceSparseVector{<:Real}) = zero(V) -function Base.imag(V::DeviceSparseVector{<:Complex}) - return DeviceSparseVector(V.n, copy(V.nzind), imag.(V.nzval)) +Base.imag(V::GenericSparseVector{<:Real}) = zero(V) +function Base.imag(V::GenericSparseVector{<:Complex}) + return GenericSparseVector(V.n, copy(V.nzind), imag.(V.nzval)) end -function LinearAlgebra.norm(V::DeviceSparseVector, p::Real = 2) +function LinearAlgebra.norm(V::GenericSparseVector, p::Real = 2) return norm(nonzeros(V), p) end # TODO: Remove this method when the function in LinearAlgebra is fixed -function LinearAlgebra.normalize(V::DeviceSparseVector, p::Real = 2) +function LinearAlgebra.normalize(V::GenericSparseVector, p::Real = 2) nrm = norm(V, p) V2 = copymutable_oftype(V, float(Base.promote_eltype(V, nrm))) return __normalize!(V2, nrm) end -function LinearAlgebra.dot(x::DeviceSparseVector, y::DenseVector) +function LinearAlgebra.dot(x::GenericSparseVector, y::DenseVector) length(x) == length(y) || throw( DimensionMismatch( "Vector x has a length $(length(x)) but y has a length $(length(y))", @@ -137,15 +137,15 @@ function LinearAlgebra.dot(x::DeviceSparseVector, y::DenseVector) return @allowscalar res[1] end -LinearAlgebra.dot(x::DenseVector{T1}, y::DeviceSparseVector{Tv}) where {T1 <: Real, Tv <: Real} = +LinearAlgebra.dot(x::DenseVector{T1}, y::GenericSparseVector{Tv}) where {T1 <: Real, Tv <: Real} = dot(y, x) LinearAlgebra.dot( x::DenseVector{T1}, - y::DeviceSparseVector{Tv}, + y::GenericSparseVector{Tv}, ) where {T1 <: Complex, Tv <: Complex} = conj(dot(y, x)) # Copied from SparseArrays.jl -function _prep_sparsevec_copy_dest!(A::DeviceSparseVector, lB, nnzB) +function _prep_sparsevec_copy_dest!(A::GenericSparseVector, lB, nnzB) lA = length(A) lA >= lB || throw(BoundsError()) # If the two vectors have the same length then all the elements in A will be overwritten. diff --git a/test/cuda/Project.toml b/test/cuda/Project.toml index af339c8..ab3fd3a 100644 --- a/test/cuda/Project.toml +++ b/test/cuda/Project.toml @@ -1,3 +1,3 @@ [deps] CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" -DeviceSparseArrays = "da3fe0eb-88a8-4d14-ae1a-857c283e9c70" +GenericSparseArrays = "da3fe0eb-88a8-4d14-ae1a-857c283e9c70" diff --git a/test/metal/Project.toml b/test/metal/Project.toml index d321ec9..7c8abe1 100644 --- a/test/metal/Project.toml +++ b/test/metal/Project.toml @@ -1,3 +1,3 @@ [deps] -DeviceSparseArrays = "da3fe0eb-88a8-4d14-ae1a-857c283e9c70" +GenericSparseArrays = "da3fe0eb-88a8-4d14-ae1a-857c283e9c70" Metal = "dde4c033-4e86-420c-a63e-0dd931031962" diff --git a/test/runtests.jl b/test/runtests.jl index d4b04d9..76a5cec 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,14 +1,14 @@ using Test using Aqua using JET -using DeviceSparseArrays +using GenericSparseArrays using JLArrays using Adapt using LinearAlgebra using SparseArrays using SparseArrays: nonzeroinds, getcolptr -using DeviceSparseArrays: getrowptr, colvals +using GenericSparseArrays: getrowptr, colvals import Pkg @@ -103,90 +103,90 @@ if GROUP in ("All", "Code-Quality") include(joinpath(@__DIR__, "shared", "code_quality.jl")) @testset "Code quality (Aqua.jl)" begin ambiguities = true # VERSION > v"1.11" - Aqua.test_all(DeviceSparseArrays; ambiguities = ambiguities) + Aqua.test_all(GenericSparseArrays; ambiguities = ambiguities) end @testset "Code linting (JET.jl)" verbose = true begin - # JET.test_package(DeviceSparseArrays; target_defined_modules = true) + # JET.test_package(GenericSparseArrays; target_defined_modules = true) for (name, func) in zip(cpu_backend_names, cpu_backend_funcs) @testset "$name Backend" verbose = true begin - @test_opt target_modules = (@__MODULE__, DeviceSparseArrays) shared_test_vector_quality( + @test_opt target_modules = (@__MODULE__, GenericSparseArrays) shared_test_vector_quality( func, Float64 ) - @test_opt target_modules = (@__MODULE__, DeviceSparseArrays) shared_test_matrix_csc_quality( + @test_opt target_modules = (@__MODULE__, GenericSparseArrays) shared_test_matrix_csc_quality( func, Float64; op_A = adjoint, op_B = identity, ) - @test_opt target_modules = (@__MODULE__, DeviceSparseArrays) shared_test_matrix_csc_quality( + @test_opt target_modules = (@__MODULE__, GenericSparseArrays) shared_test_matrix_csc_quality( func, Float64; op_A = adjoint, op_B = adjoint, ) - @test_opt target_modules = (@__MODULE__, DeviceSparseArrays) shared_test_matrix_csr_quality( + @test_opt target_modules = (@__MODULE__, GenericSparseArrays) shared_test_matrix_csr_quality( func, Float64; op_A = identity, op_B = identity, ) - @test_opt target_modules = (@__MODULE__, DeviceSparseArrays) shared_test_matrix_csr_quality( + @test_opt target_modules = (@__MODULE__, GenericSparseArrays) shared_test_matrix_csr_quality( func, Float64; op_A = identity, op_B = adjoint, ) - @test_opt target_modules = (@__MODULE__, DeviceSparseArrays) shared_test_matrix_coo_quality( + @test_opt target_modules = (@__MODULE__, GenericSparseArrays) shared_test_matrix_coo_quality( func, Float64; op_A = identity, op_B = identity, ) - @test_opt target_modules = (@__MODULE__, DeviceSparseArrays) shared_test_matrix_coo_quality( + @test_opt target_modules = (@__MODULE__, GenericSparseArrays) shared_test_matrix_coo_quality( func, Float64; op_A = transpose, op_B = adjoint, ) - @test_call target_modules = (@__MODULE__, DeviceSparseArrays) shared_test_vector_quality( + @test_call target_modules = (@__MODULE__, GenericSparseArrays) shared_test_vector_quality( func, Float64 ) - @test_call target_modules = (@__MODULE__, DeviceSparseArrays) shared_test_matrix_csc_quality( + @test_call target_modules = (@__MODULE__, GenericSparseArrays) shared_test_matrix_csc_quality( func, Float64; op_A = adjoint, op_B = identity, ) - @test_call target_modules = (@__MODULE__, DeviceSparseArrays) shared_test_matrix_csc_quality( + @test_call target_modules = (@__MODULE__, GenericSparseArrays) shared_test_matrix_csc_quality( func, Float64; op_A = adjoint, op_B = adjoint, ) - @test_call target_modules = (@__MODULE__, DeviceSparseArrays) shared_test_matrix_csr_quality( + @test_call target_modules = (@__MODULE__, GenericSparseArrays) shared_test_matrix_csr_quality( func, Float64; op_A = identity, op_B = identity, ) - @test_call target_modules = (@__MODULE__, DeviceSparseArrays) shared_test_matrix_csr_quality( + @test_call target_modules = (@__MODULE__, GenericSparseArrays) shared_test_matrix_csr_quality( func, Float64; op_A = identity, op_B = adjoint, ) - @test_call target_modules = (@__MODULE__, DeviceSparseArrays) shared_test_matrix_coo_quality( + @test_call target_modules = (@__MODULE__, GenericSparseArrays) shared_test_matrix_coo_quality( func, Float64; op_A = identity, op_B = identity, ) - @test_call target_modules = (@__MODULE__, DeviceSparseArrays) shared_test_matrix_coo_quality( + @test_call target_modules = (@__MODULE__, GenericSparseArrays) shared_test_matrix_coo_quality( func, Float64; op_A = transpose, diff --git a/test/shared/code_quality.jl b/test/shared/code_quality.jl index d4fff90..150c867 100644 --- a/test/shared/code_quality.jl +++ b/test/shared/code_quality.jl @@ -10,15 +10,15 @@ function shared_test_vector_quality_conversion(op, T; kwargs...) sv = SparseVector(10, Int[], T[]) sv2 = sparsevec([3], [T(2.5)], 8) - # Test conversion SparseVector <-> DeviceSparseVector - dsv = adapt(op, DeviceSparseVector(sv)) + # Test conversion SparseVector <-> GenericSparseVector + dsv = adapt(op, GenericSparseVector(sv)) size(dsv) length(dsv) nnz(dsv) collect(nonzeros(dsv)) collect(nonzeroinds(dsv)) - dsv2 = adapt(op, DeviceSparseVector(sv2)) + dsv2 = adapt(op, GenericSparseVector(sv2)) size(dsv2) length(dsv2) nnz(dsv2) @@ -32,7 +32,7 @@ end function shared_test_vector_quality_linearalgebra(op, T; kwargs...) v = sprand(T, 1000, 0.01) y = rand(T, 1000) - dv = adapt(op, DeviceSparseVector(v)) + dv = adapt(op, GenericSparseVector(v)) dy = op(y) sum(dv) @@ -50,7 +50,7 @@ end function shared_test_vector_quality_scalar_operations(op, T; kwargs...) v = sprand(T, 100, 0.3) - dv = adapt(op, DeviceSparseVector(v)) + dv = adapt(op, GenericSparseVector(v)) α = T <: Complex ? T(2.0 + 1.0im) : (T <: Integer ? T(2) : T(2.5)) @@ -78,7 +78,7 @@ function shared_test_vector_quality_unary_operations(op, T; kwargs...) end v = sprand(T, 80, 0.4) - dv = adapt(op, DeviceSparseVector(v)) + dv = adapt(op, GenericSparseVector(v)) # Test unary plus (inherited from AbstractArray) pos_v = +dv @@ -125,7 +125,7 @@ function shared_test_vector_quality_norms(op, T; kwargs...) end v = sprand(T, 50, 0.5) - dv = adapt(op, DeviceSparseVector(v)) + dv = adapt(op, GenericSparseVector(v)) # Test different norms norm2 = norm(dv) @@ -166,13 +166,13 @@ function shared_test_matrix_csc_quality_conversion(op, T; kwargs...) vals = T.([1.0, 2.0, 3.0]) B = sparse(rows, cols, vals, 2, 2) - dA = adapt(op, DeviceSparseMatrixCSC(A)) + dA = adapt(op, GenericSparseMatrixCSC(A)) size(dA) length(dA) nnz(dA) collect(nonzeros(dA)) - dB = adapt(op, DeviceSparseMatrixCSC(B)) + dB = adapt(op, GenericSparseMatrixCSC(B)) size(dB) length(dB) nnz(dB) @@ -186,7 +186,7 @@ end function shared_test_matrix_csc_quality_scalar_operations(op, T; kwargs...) A = sprand(T, 50, 40, 0.1) - dA = adapt(op, DeviceSparseMatrixCSC(A)) + dA = adapt(op, GenericSparseMatrixCSC(A)) α = T <: Complex ? T(1.5 - 0.5im) : (T <: Integer ? T(2) : T(2.0)) @@ -214,7 +214,7 @@ function shared_test_matrix_csc_quality_unary_operations(op, T; kwargs...) end A = sprand(T, 30, 25, 0.15) - dA = adapt(op, DeviceSparseMatrixCSC(A)) + dA = adapt(op, GenericSparseMatrixCSC(A)) # Test unary plus pos_A = +dA @@ -259,7 +259,7 @@ function shared_test_matrix_csc_quality_uniformscaling(op, T; kwargs...) end A = sprand(T, 20, 20, 0.2) - dA = adapt(op, DeviceSparseMatrixCSC(A)) + dA = adapt(op, GenericSparseMatrixCSC(A)) # Test A * I (identity) result_I = dA * I @@ -282,7 +282,7 @@ end function shared_test_matrix_csc_quality_basic_linearalgebra(op, T; kwargs...) A = sprand(T, 1000, 1000, 0.01) - dA = adapt(op, DeviceSparseMatrixCSC(A)) + dA = adapt(op, GenericSparseMatrixCSC(A)) sum(dA) @@ -311,7 +311,7 @@ function shared_test_matrix_csc_quality_spmv_spmm(op, T; kwargs...) B = rand(T, dims_B...) b = rand(T, 80) - dA = adapt(op, DeviceSparseMatrixCSC(A)) + dA = adapt(op, GenericSparseMatrixCSC(A)) dB = op(B) db = op(b) @@ -340,8 +340,8 @@ function shared_test_matrix_csr_quality_conversion(op, T; kwargs...) # Test CSR conversion B_csr = SparseMatrixCSC(transpose(B)) # Get the CSR storage pattern - dB = adapt(op, DeviceSparseMatrixCSR(transpose(B_csr))) - dB2 = adapt(op, DeviceSparseMatrixCSR(B)) # Directly from CSC should also work + dB = adapt(op, GenericSparseMatrixCSR(transpose(B_csr))) + dB2 = adapt(op, GenericSparseMatrixCSR(B)) # Directly from CSC should also work size(dB) length(dB) nnz(dB) @@ -358,7 +358,7 @@ function shared_test_matrix_csr_quality_basic_linearalgebra(op, T; kwargs...) A = sprand(T, 1000, 1000, 0.01) # Convert to CSR storage pattern A_csr = SparseMatrixCSC(transpose(A)) - dA = adapt(op, DeviceSparseMatrixCSR(transpose(A_csr))) + dA = adapt(op, GenericSparseMatrixCSR(transpose(A_csr))) sum(dA) @@ -389,7 +389,7 @@ function shared_test_matrix_csr_quality_spmv(op, T; kwargs...) # Convert to CSR storage pattern A_csr = SparseMatrixCSC(transpose(A)) - dA = adapt(op, DeviceSparseMatrixCSR(transpose(A_csr))) + dA = adapt(op, GenericSparseMatrixCSR(transpose(A_csr))) dB = op(B) db = op(b) @@ -402,7 +402,7 @@ end function shared_test_matrix_csr_quality_scalar_operations(op, T; kwargs...) A = sprand(T, 40, 30, 0.1) - dA = adapt(op, DeviceSparseMatrixCSR(A)) + dA = adapt(op, GenericSparseMatrixCSR(A)) α = T <: Complex ? T(1.0 + 2.0im) : (T <: Integer ? T(2) : T(1.5)) @@ -430,7 +430,7 @@ function shared_test_matrix_csr_quality_unary_operations(op, T; kwargs...) end A = sprand(T, 25, 20, 0.15) - dA = adapt(op, DeviceSparseMatrixCSR(A)) + dA = adapt(op, GenericSparseMatrixCSR(A)) # Test unary plus pos_A = +dA @@ -475,7 +475,7 @@ function shared_test_matrix_csr_quality_uniformscaling(op, T; kwargs...) end A = sprand(T, 15, 15, 0.2) - dA = adapt(op, DeviceSparseMatrixCSR(A)) + dA = adapt(op, GenericSparseMatrixCSR(A)) # Test A * I (identity) result_I = dA * I @@ -513,7 +513,7 @@ function shared_test_matrix_coo_quality_conversion(op, T; kwargs...) B = sparse(rows, cols, vals, 2, 2) # Test COO conversion - dB = adapt(op, DeviceSparseMatrixCOO(B)) + dB = adapt(op, GenericSparseMatrixCOO(B)) size(dB) length(dB) nnz(dB) @@ -525,7 +525,7 @@ end function shared_test_matrix_coo_quality_basic_linearalgebra(op, T; kwargs...) A = sprand(T, 1000, 1000, 0.01) - dA = adapt(op, DeviceSparseMatrixCOO(A)) + dA = adapt(op, GenericSparseMatrixCOO(A)) sum(dA) @@ -554,7 +554,7 @@ function shared_test_matrix_coo_quality_spmv(op, T; kwargs...) B = rand(T, dims_B...) b = rand(T, 80) - dA = adapt(op, DeviceSparseMatrixCOO(A)) + dA = adapt(op, GenericSparseMatrixCOO(A)) dB = op(B) db = op(b) @@ -567,7 +567,7 @@ end function shared_test_matrix_coo_quality_scalar_operations(op, T; kwargs...) A = sprand(T, 45, 35, 0.1) - dA = adapt(op, DeviceSparseMatrixCOO(A)) + dA = adapt(op, GenericSparseMatrixCOO(A)) α = T <: Complex ? T(2.0 + 1.5im) : (T <: Integer ? T(2) : T(1.8)) @@ -595,7 +595,7 @@ function shared_test_matrix_coo_quality_unary_operations(op, T; kwargs...) end A = sprand(T, 28, 22, 0.15) - dA = adapt(op, DeviceSparseMatrixCOO(A)) + dA = adapt(op, GenericSparseMatrixCOO(A)) # Test unary plus pos_A = +dA @@ -640,7 +640,7 @@ function shared_test_matrix_coo_quality_uniformscaling(op, T; kwargs...) end A = sprand(T, 18, 18, 0.2) - dA = adapt(op, DeviceSparseMatrixCOO(A)) + dA = adapt(op, GenericSparseMatrixCOO(A)) # Test A * I (identity) result_I = dA * I diff --git a/test/shared/conversions.jl b/test/shared/conversions.jl index 6c794b9..9991e01 100644 --- a/test/shared/conversions.jl +++ b/test/shared/conversions.jl @@ -13,68 +13,68 @@ function shared_test_conversions( # Test CSC ↔ COO conversions @testset "CSC ↔ COO" begin # CSC → COO - A_csc = adapt(op, DeviceSparseMatrixCSC(A)) - A_coo_from_csc = DeviceSparseMatrixCOO(A_csc) + A_csc = adapt(op, GenericSparseMatrixCSC(A)) + A_coo_from_csc = GenericSparseMatrixCOO(A_csc) @test collect(SparseMatrixCSC(A_coo_from_csc)) ≈ collect(A) # COO → CSC - A_coo = adapt(op, DeviceSparseMatrixCOO(A)) - A_csc_from_coo = DeviceSparseMatrixCSC(A_coo) + A_coo = adapt(op, GenericSparseMatrixCOO(A)) + A_csc_from_coo = GenericSparseMatrixCSC(A_coo) @test collect(SparseMatrixCSC(A_csc_from_coo)) ≈ collect(A) # Round-trip - A_csc_roundtrip = DeviceSparseMatrixCSC(DeviceSparseMatrixCOO(A_csc)) + A_csc_roundtrip = GenericSparseMatrixCSC(GenericSparseMatrixCOO(A_csc)) @test collect(SparseMatrixCSC(A_csc_roundtrip)) ≈ collect(A) end # Test CSR ↔ COO conversions @testset "CSR ↔ COO" begin # CSR → COO - A_csr = adapt(op, DeviceSparseMatrixCSR(A)) - A_coo_from_csr = DeviceSparseMatrixCOO(A_csr) + A_csr = adapt(op, GenericSparseMatrixCSR(A)) + A_coo_from_csr = GenericSparseMatrixCOO(A_csr) @test collect(SparseMatrixCSC(A_coo_from_csr)) ≈ collect(A) # COO → CSR - A_coo = adapt(op, DeviceSparseMatrixCOO(A)) - A_csr_from_coo = DeviceSparseMatrixCSR(A_coo) + A_coo = adapt(op, GenericSparseMatrixCOO(A)) + A_csr_from_coo = GenericSparseMatrixCSR(A_coo) @test collect(SparseMatrixCSC(A_csr_from_coo)) ≈ collect(A) # Round-trip - A_csr_roundtrip = DeviceSparseMatrixCSR(DeviceSparseMatrixCOO(A_csr)) + A_csr_roundtrip = GenericSparseMatrixCSR(GenericSparseMatrixCOO(A_csr)) @test collect(SparseMatrixCSC(A_csr_roundtrip)) ≈ collect(A) end # Test CSC ↔ CSR conversions (through COO internally) @testset "CSC ↔ CSR" begin # CSC → CSR - A_csc = adapt(op, DeviceSparseMatrixCSC(A)) - A_csr_from_csc = DeviceSparseMatrixCSR(A_csc) + A_csc = adapt(op, GenericSparseMatrixCSC(A)) + A_csr_from_csc = GenericSparseMatrixCSR(A_csc) @test collect(SparseMatrixCSC(A_csr_from_csc)) ≈ collect(A) # CSR → CSC - A_csr = adapt(op, DeviceSparseMatrixCSR(A)) - A_csc_from_csr = DeviceSparseMatrixCSC(A_csr) + A_csr = adapt(op, GenericSparseMatrixCSR(A)) + A_csc_from_csr = GenericSparseMatrixCSC(A_csr) @test collect(SparseMatrixCSC(A_csc_from_csr)) ≈ collect(A) # Round-trip - A_csc_roundtrip = DeviceSparseMatrixCSC(DeviceSparseMatrixCSR(A_csc)) + A_csc_roundtrip = GenericSparseMatrixCSC(GenericSparseMatrixCSR(A_csc)) @test collect(SparseMatrixCSC(A_csc_roundtrip)) ≈ collect(A) end # Test conversions from/to SparseMatrixCSC @testset "SparseMatrixCSC Conversions" begin - # SparseMatrixCSC → DeviceSparseMatrixCSC → SparseMatrixCSC - A_csc = DeviceSparseMatrixCSC(A) + # SparseMatrixCSC → GenericSparseMatrixCSC → SparseMatrixCSC + A_csc = GenericSparseMatrixCSC(A) A_csc_device = adapt(op, A_csc) @test collect(SparseMatrixCSC(A_csc_device)) ≈ collect(A) - # SparseMatrixCSC → DeviceSparseMatrixCSR → SparseMatrixCSC - A_csr = DeviceSparseMatrixCSR(A) + # SparseMatrixCSC → GenericSparseMatrixCSR → SparseMatrixCSC + A_csr = GenericSparseMatrixCSR(A) A_csr_device = adapt(op, A_csr) @test collect(SparseMatrixCSC(A_csr_device)) ≈ collect(A) - # SparseMatrixCSC → DeviceSparseMatrixCOO → SparseMatrixCSC - A_coo = DeviceSparseMatrixCOO(A) + # SparseMatrixCSC → GenericSparseMatrixCOO → SparseMatrixCSC + A_coo = GenericSparseMatrixCOO(A) A_coo_device = adapt(op, A_coo) @test collect(SparseMatrixCSC(A_coo_device)) ≈ collect(A) end @@ -82,21 +82,21 @@ function shared_test_conversions( # Test transpose conversions @testset "Transpose Conversions" begin # CSC transpose - A_csc = adapt(op, DeviceSparseMatrixCSC(A)) + A_csc = adapt(op, GenericSparseMatrixCSC(A)) A_csc_t = transpose(A_csc) @test collect(SparseMatrixCSC(A_csc_t)) ≈ collect(transpose(A)) # CSR transpose - A_csr = adapt(op, DeviceSparseMatrixCSR(A)) + A_csr = adapt(op, GenericSparseMatrixCSR(A)) A_csr_t = transpose(A_csr) @test collect(SparseMatrixCSC(A_csr_t)) ≈ collect(transpose(A)) # CSR transpose → CSC conversion (direct path) - A_csc_from_csr_t = DeviceSparseMatrixCSC(A_csr_t) + A_csc_from_csr_t = GenericSparseMatrixCSC(A_csr_t) @test collect(SparseMatrixCSC(A_csc_from_csr_t)) ≈ collect(transpose(A)) # CSC transpose → CSR conversion - A_csr_from_csc_t = DeviceSparseMatrixCSR(A_csc_t) + A_csr_from_csc_t = GenericSparseMatrixCSR(A_csc_t) @test collect(SparseMatrixCSC(A_csr_from_csc_t)) ≈ collect(transpose(A)) end @@ -106,21 +106,21 @@ function shared_test_conversions( A_complex = SparseMatrixCSC{Tvc, Ti}(sprand(ComplexF64, 100, 200, 0.05)) # CSC adjoint - A_csc = adapt(op, DeviceSparseMatrixCSC(A_complex)) + A_csc = adapt(op, GenericSparseMatrixCSC(A_complex)) A_csc_adj = adjoint(A_csc) @test collect(SparseMatrixCSC(A_csc_adj)) ≈ collect(adjoint(A_complex)) # CSR adjoint - A_csr = adapt(op, DeviceSparseMatrixCSR(A_complex)) + A_csr = adapt(op, GenericSparseMatrixCSR(A_complex)) A_csr_adj = adjoint(A_csr) @test collect(SparseMatrixCSC(A_csr_adj)) ≈ collect(adjoint(A_complex)) # CSR adjoint → CSC conversion (direct path) - A_csc_from_csr_adj = DeviceSparseMatrixCSC(A_csr_adj) + A_csc_from_csr_adj = GenericSparseMatrixCSC(A_csr_adj) @test collect(SparseMatrixCSC(A_csc_from_csr_adj)) ≈ collect(adjoint(A_complex)) # CSC adjoint → CSR conversion - A_csr_from_csc_adj = DeviceSparseMatrixCSR(A_csc_adj) + A_csr_from_csc_adj = GenericSparseMatrixCSR(A_csc_adj) @test collect(SparseMatrixCSC(A_csr_from_csc_adj)) ≈ collect(adjoint(A_complex)) end @@ -128,26 +128,26 @@ function shared_test_conversions( @testset "Edge Cases" begin # Single element matrix A_single = sparse(Ti[1], Ti[2], [Tv(5.0)], 3, 4) - A_csc_single = adapt(op, DeviceSparseMatrixCSC(A_single)) - A_coo_single = DeviceSparseMatrixCOO(A_csc_single) + A_csc_single = adapt(op, GenericSparseMatrixCSC(A_single)) + A_coo_single = GenericSparseMatrixCOO(A_csc_single) @test nnz(A_coo_single) == 1 @test collect(SparseMatrixCSC(A_coo_single)) ≈ collect(A_single) # Single element CSR conversion - A_csr_single = DeviceSparseMatrixCSR(A_csc_single) + A_csr_single = GenericSparseMatrixCSR(A_csc_single) @test nnz(A_csr_single) == 1 @test collect(SparseMatrixCSC(A_csr_single)) ≈ collect(A_single) # Full row matrix A_row = sparse(Ti[1, 1, 1, 1], Ti[1, 2, 3, 4], Tv[1, 2, 3, 4], 3, 4) - A_csc_row = adapt(op, DeviceSparseMatrixCSC(A_row)) - A_csr_row = DeviceSparseMatrixCSR(A_csc_row) + A_csc_row = adapt(op, GenericSparseMatrixCSC(A_row)) + A_csr_row = GenericSparseMatrixCSR(A_csc_row) @test collect(SparseMatrixCSC(A_csr_row)) ≈ collect(A_row) # Full column matrix A_col = sparse(Ti[1, 2, 3], Ti[2, 2, 2], Tv[1, 2, 3], 3, 4) - A_csc_col = adapt(op, DeviceSparseMatrixCSC(A_col)) - A_csr_col = DeviceSparseMatrixCSR(A_csc_col) + A_csc_col = adapt(op, GenericSparseMatrixCSC(A_col)) + A_csr_col = GenericSparseMatrixCSR(A_csc_col) @test collect(SparseMatrixCSC(A_csr_col)) ≈ collect(A_col) end end diff --git a/test/shared/matrix_coo.jl b/test/shared/matrix_coo.jl index 5ae3d0c..2cfd701 100644 --- a/test/shared/matrix_coo.jl +++ b/test/shared/matrix_coo.jl @@ -5,7 +5,7 @@ function shared_test_matrix_coo( float_types::Tuple, complex_types::Tuple, ) - return @testset "DeviceSparseMatrixCOO $array_type" verbose = true begin + return @testset "GenericSparseMatrixCOO $array_type" verbose = true begin shared_test_conversion_matrix_coo( op, array_type, @@ -37,22 +37,22 @@ function shared_test_conversion_matrix_coo( vals = float_types[end][1.0, 2.0, 3.0] B = sparse(rows, cols, vals, 2, 2) - # test only conversion SparseMatrixCSC <-> DeviceSparseMatrixCOO + # test only conversion SparseMatrixCSC <-> GenericSparseMatrixCOO if op === Array - dA = DeviceSparseMatrixCOO(A) + dA = GenericSparseMatrixCOO(A) @test size(dA) == (0, 0) @test length(dA) == 0 @test collect(nonzeros(dA)) == int_types[end][] @test SparseMatrixCSC(dA) == A end - dA = adapt(op, DeviceSparseMatrixCOO(A)) + dA = adapt(op, GenericSparseMatrixCOO(A)) @test size(dA) == (0, 0) @test length(dA) == 0 @test nnz(dA) == 0 @test collect(nonzeros(dA)) == float_types[end][] - dB = adapt(op, DeviceSparseMatrixCOO(B)) + dB = adapt(op, GenericSparseMatrixCOO(B)) @test size(dB) == (2, 2) @test length(dB) == 4 @test nnz(dB) == 3 @@ -60,7 +60,7 @@ function shared_test_conversion_matrix_coo( @test collect(nonzeros(dB)) == collect(nonzeros(B)) @test SparseMatrixCSC(dB) == B - @test_throws ArgumentError DeviceSparseMatrixCOO( + @test_throws ArgumentError GenericSparseMatrixCOO( 2, 2, op(int_types[end][1]), @@ -80,7 +80,7 @@ function shared_test_linearalgebra_matrix_coo( @testset "Sum and Trace" begin for T in (int_types..., float_types..., complex_types...) A = sprand(T, 1000, 1000, 0.01) - dA = adapt(op, DeviceSparseMatrixCOO(A)) + dA = adapt(op, GenericSparseMatrixCOO(A)) @test sum(dA) ≈ sum(A) @@ -104,7 +104,7 @@ function shared_test_linearalgebra_matrix_coo( x = rand(T, size(op_A(A), 1)) y = rand(T, size(op_A(A), 2)) - dA = adapt(op, DeviceSparseMatrixCOO(A)) + dA = adapt(op, GenericSparseMatrixCOO(A)) dx = op(x) dy = op(y) @@ -119,7 +119,7 @@ function shared_test_linearalgebra_matrix_coo( @testset "Scalar Operations" begin for T in (int_types..., float_types..., complex_types...) A = sprand(T, 45, 35, 0.1) - dA = adapt(op, DeviceSparseMatrixCOO(A)) + dA = adapt(op, GenericSparseMatrixCOO(A)) α = T <: Complex ? T(2.0 + 1.5im) : (T <: Integer ? T(2) : T(1.8)) @@ -143,7 +143,7 @@ function shared_test_linearalgebra_matrix_coo( @testset "Unary Operations" begin for T in (float_types..., complex_types...) A = sprand(T, 28, 22, 0.15) - dA = adapt(op, DeviceSparseMatrixCOO(A)) + dA = adapt(op, GenericSparseMatrixCOO(A)) # Test unary plus pos_A = +dA @@ -186,7 +186,7 @@ function shared_test_linearalgebra_matrix_coo( @testset "UniformScaling Multiplication" begin for T in (float_types..., complex_types...) A = sprand(T, 18, 18, 0.2) - dA = adapt(op, DeviceSparseMatrixCOO(A)) + dA = adapt(op, GenericSparseMatrixCOO(A)) # Test A * I (identity) result_I = dA * I @@ -225,7 +225,7 @@ function shared_test_linearalgebra_matrix_coo( c = op_A(A) * b C = op_A(A) * op_B(B) - dA = adapt(op, DeviceSparseMatrixCOO(A)) + dA = adapt(op, GenericSparseMatrixCOO(A)) # Matrix-Scalar multiplication if T != Int32 @@ -259,7 +259,7 @@ function shared_test_linearalgebra_matrix_coo( A = sprand(T, m, n, 0.1) B = rand(T, m, n) - dA = adapt(op, DeviceSparseMatrixCOO(A)) + dA = adapt(op, GenericSparseMatrixCOO(A)) dB = op(B) # Test sparse + dense @@ -293,29 +293,29 @@ function shared_test_linearalgebra_matrix_coo( A = sprand(T, dims_A..., 0.1) B = sprand(T, dims_B..., 0.15) - dA = adapt(op, DeviceSparseMatrixCOO(A)) - dB = adapt(op, DeviceSparseMatrixCOO(B)) + dA = adapt(op, GenericSparseMatrixCOO(A)) + dB = adapt(op, GenericSparseMatrixCOO(B)) # Test sparse + sparse result = op_A(dA) + op_B(dB) expected = op_A(A) + op_B(B) @test collect(result) ≈ Matrix(expected) - @test result isa DeviceSparseMatrixCOO + @test result isa GenericSparseMatrixCOO # Additional tests only for identity + identity if op_A === identity && op_B === identity # Test with overlapping entries A_overlap = sparse([1, 2, 3], [1, 2, 3], T[1, 2, 3], m, n) B_overlap = sparse([1, 2, 4], [1, 2, 4], T[4, 5, 6], m, n) - dA_overlap = adapt(op, DeviceSparseMatrixCOO(A_overlap)) - dB_overlap = adapt(op, DeviceSparseMatrixCOO(B_overlap)) + dA_overlap = adapt(op, GenericSparseMatrixCOO(A_overlap)) + dB_overlap = adapt(op, GenericSparseMatrixCOO(B_overlap)) result_overlap = dA_overlap + dB_overlap expected_overlap = A_overlap + B_overlap @test collect(result_overlap) ≈ Matrix(expected_overlap) # Test dimension mismatch B_wrong = sprand(T, m + 1, n, 0.1) - dB_wrong = adapt(op, DeviceSparseMatrixCOO(B_wrong)) + dB_wrong = adapt(op, GenericSparseMatrixCOO(B_wrong)) @test_throws DimensionMismatch dA + dB_wrong end end @@ -338,14 +338,14 @@ function shared_test_linearalgebra_matrix_coo( A = sprand(T, dims_A..., 0.1) B = sprand(T, dims_B..., 0.15) - dA = adapt(op, DeviceSparseMatrixCOO(A)) - dB = adapt(op, DeviceSparseMatrixCOO(B)) + dA = adapt(op, GenericSparseMatrixCOO(A)) + dB = adapt(op, GenericSparseMatrixCOO(B)) # Test sparse * sparse result = op_A(dA) * op_B(dB) expected = op_A(A) * op_B(B) @test collect(result) ≈ Matrix(expected) - @test result isa DeviceSparseMatrixCOO + @test result isa GenericSparseMatrixCOO end end end @@ -356,8 +356,8 @@ function shared_test_linearalgebra_matrix_coo( A_sparse = sprand(T, 30, 25, 0.1) B_sparse = sprand(T, 20, 15, 0.1) - A = adapt(op, DeviceSparseMatrixCOO(A_sparse)) - B = adapt(op, DeviceSparseMatrixCOO(B_sparse)) + A = adapt(op, GenericSparseMatrixCOO(A_sparse)) + B = adapt(op, GenericSparseMatrixCOO(B_sparse)) C = kron(A, B) C_expected = kron(A_sparse, B_sparse) @@ -365,7 +365,7 @@ function shared_test_linearalgebra_matrix_coo( @test size(C) == size(C_expected) @test nnz(C) == nnz(C_expected) @test Matrix(SparseMatrixCSC(C)) ≈ Matrix(C_expected) - @test C isa DeviceSparseMatrixCOO + @test C isa GenericSparseMatrixCOO end end end diff --git a/test/shared/matrix_csc.jl b/test/shared/matrix_csc.jl index d292fdf..1a16778 100644 --- a/test/shared/matrix_csc.jl +++ b/test/shared/matrix_csc.jl @@ -5,7 +5,7 @@ function shared_test_matrix_csc( float_types::Tuple, complex_types::Tuple, ) - return @testset "DeviceSparseMatrixCSC $array_type" verbose = true begin + return @testset "GenericSparseMatrixCSC $array_type" verbose = true begin shared_test_conversion_matrix_csc( op, array_type, @@ -37,22 +37,22 @@ function shared_test_conversion_matrix_csc( vals = float_types[end][1.0, 2.0, 3.0] B = sparse(rows, cols, vals, 2, 2) - # test only conversion SparseMatrixCSC <-> DeviceSparseMatrixCSC + # test only conversion SparseMatrixCSC <-> GenericSparseMatrixCSC if op === Array - dA = DeviceSparseMatrixCSC(A) + dA = GenericSparseMatrixCSC(A) @test size(dA) == (0, 0) @test length(dA) == 0 @test collect(nonzeros(dA)) == float_types[end][] @test SparseMatrixCSC(dA) == A end - dA = adapt(op, DeviceSparseMatrixCSC(A)) + dA = adapt(op, GenericSparseMatrixCSC(A)) @test size(dA) == (0, 0) @test length(dA) == 0 @test nnz(dA) == 0 @test collect(nonzeros(dA)) == float_types[end][] - dB = adapt(op, DeviceSparseMatrixCSC(B)) + dB = adapt(op, GenericSparseMatrixCSC(B)) @test size(dB) == (2, 2) @test length(dB) == 4 @test nnz(dB) == 3 @@ -61,7 +61,7 @@ function shared_test_conversion_matrix_csc( @test collect(getcolptr(dB)) == collect(getcolptr(B)) @test SparseMatrixCSC(dB) == B - @test_throws ArgumentError DeviceSparseMatrixCSC( + @test_throws ArgumentError GenericSparseMatrixCSC( 2, 2, op(int_types[end][1, 3]), @@ -81,7 +81,7 @@ function shared_test_linearalgebra_matrix_csc( @testset "Sum and Trace" begin for T in (int_types..., float_types..., complex_types...) A = sprand(T, 1000, 1000, 0.01) - dA = adapt(op, DeviceSparseMatrixCSC(A)) + dA = adapt(op, GenericSparseMatrixCSC(A)) @test sum(dA) ≈ sum(A) @@ -102,7 +102,7 @@ function shared_test_linearalgebra_matrix_csc( x = rand(T, size(op_A(A), 1)) y = rand(T, size(op_A(A), 2)) - dA = adapt(op, DeviceSparseMatrixCSC(A)) + dA = adapt(op, GenericSparseMatrixCSC(A)) dx = op(x) dy = op(y) @@ -117,7 +117,7 @@ function shared_test_linearalgebra_matrix_csc( @testset "Scalar Operations" begin for T in (int_types..., float_types..., complex_types...) A = sprand(T, 50, 40, 0.1) - dA = adapt(op, DeviceSparseMatrixCSC(A)) + dA = adapt(op, GenericSparseMatrixCSC(A)) α = T <: Complex ? T(1.5 - 0.5im) : (T <: Integer ? T(2) : T(2.0)) @@ -141,7 +141,7 @@ function shared_test_linearalgebra_matrix_csc( @testset "Unary Operations" begin for T in (float_types..., complex_types...) A = sprand(T, 30, 25, 0.15) - dA = adapt(op, DeviceSparseMatrixCSC(A)) + dA = adapt(op, GenericSparseMatrixCSC(A)) # Test unary plus pos_A = +dA @@ -184,7 +184,7 @@ function shared_test_linearalgebra_matrix_csc( @testset "UniformScaling Multiplication" begin for T in (float_types..., complex_types...) A = sprand(T, 20, 20, 0.2) - dA = adapt(op, DeviceSparseMatrixCSC(A)) + dA = adapt(op, GenericSparseMatrixCSC(A)) # Test A * I (identity) result_I = dA * I @@ -223,7 +223,7 @@ function shared_test_linearalgebra_matrix_csc( c = op_A(A) * b C = op_A(A) * op_B(B) - dA = adapt(op, DeviceSparseMatrixCSC(A)) + dA = adapt(op, GenericSparseMatrixCSC(A)) # Matrix-Scalar multiplication if T != Int32 @@ -257,7 +257,7 @@ function shared_test_linearalgebra_matrix_csc( A = sprand(T, m, n, 0.1) B = rand(T, m, n) - dA = adapt(op, DeviceSparseMatrixCSC(A)) + dA = adapt(op, GenericSparseMatrixCSC(A)) dB = op(B) # Test sparse + dense @@ -291,29 +291,29 @@ function shared_test_linearalgebra_matrix_csc( A = sprand(T, dims_A..., 0.1) B = sprand(T, dims_B..., 0.15) - dA = adapt(op, DeviceSparseMatrixCSC(A)) - dB = adapt(op, DeviceSparseMatrixCSC(B)) + dA = adapt(op, GenericSparseMatrixCSC(A)) + dB = adapt(op, GenericSparseMatrixCSC(B)) # Test sparse + sparse result = op_A(dA) + op_B(dB) expected = op_A(A) + op_B(B) @test collect(result) ≈ Matrix(expected) - @test result isa DeviceSparseMatrixCSC + @test result isa GenericSparseMatrixCSC # Additional tests only for identity + identity if op_A === identity && op_B === identity # Test with overlapping entries A_overlap = sparse([1, 2, 3], [1, 2, 3], T[1, 2, 3], m, n) B_overlap = sparse([1, 2, 4], [1, 2, 4], T[4, 5, 6], m, n) - dA_overlap = adapt(op, DeviceSparseMatrixCSC(A_overlap)) - dB_overlap = adapt(op, DeviceSparseMatrixCSC(B_overlap)) + dA_overlap = adapt(op, GenericSparseMatrixCSC(A_overlap)) + dB_overlap = adapt(op, GenericSparseMatrixCSC(B_overlap)) result_overlap = dA_overlap + dB_overlap expected_overlap = A_overlap + B_overlap @test collect(result_overlap) ≈ Matrix(expected_overlap) # Test dimension mismatch B_wrong = sprand(T, m + 1, n, 0.1) - dB_wrong = adapt(op, DeviceSparseMatrixCSC(B_wrong)) + dB_wrong = adapt(op, GenericSparseMatrixCSC(B_wrong)) @test_throws DimensionMismatch dA + dB_wrong end end @@ -336,14 +336,14 @@ function shared_test_linearalgebra_matrix_csc( A = sprand(T, dims_A..., 0.1) B = sprand(T, dims_B..., 0.15) - dA = adapt(op, DeviceSparseMatrixCSC(A)) - dB = adapt(op, DeviceSparseMatrixCSC(B)) + dA = adapt(op, GenericSparseMatrixCSC(A)) + dB = adapt(op, GenericSparseMatrixCSC(B)) # Test sparse * sparse result = op_A(dA) * op_B(dB) expected = op_A(A) * op_B(B) @test collect(result) ≈ Matrix(expected) - @test result isa DeviceSparseMatrixCSC + @test result isa GenericSparseMatrixCSC end end end @@ -355,8 +355,8 @@ function shared_test_linearalgebra_matrix_csc( A_sparse = SparseMatrixCSC{T, int_types[end]}(sprand(T, 30, 25, 0.1)) B_sparse = SparseMatrixCSC{T, int_types[end]}(sprand(T, 20, 15, 0.1)) - A = adapt(op, DeviceSparseMatrixCSC(A_sparse)) - B = adapt(op, DeviceSparseMatrixCSC(B_sparse)) + A = adapt(op, GenericSparseMatrixCSC(A_sparse)) + B = adapt(op, GenericSparseMatrixCSC(B_sparse)) C = kron(A, B) C_expected = kron(A_sparse, B_sparse) @@ -364,7 +364,7 @@ function shared_test_linearalgebra_matrix_csc( @test size(C) == size(C_expected) @test nnz(C) == nnz(C_expected) @test Matrix(SparseMatrixCSC(C)) ≈ Matrix(C_expected) - @test C isa DeviceSparseMatrixCSC + @test C isa GenericSparseMatrixCSC end end end diff --git a/test/shared/matrix_csr.jl b/test/shared/matrix_csr.jl index 53ce5cb..7577931 100644 --- a/test/shared/matrix_csr.jl +++ b/test/shared/matrix_csr.jl @@ -5,7 +5,7 @@ function shared_test_matrix_csr( float_types::Tuple, complex_types::Tuple, ) - return @testset "DeviceSparseMatrixCSR $array_type" verbose = true begin + return @testset "GenericSparseMatrixCSR $array_type" verbose = true begin shared_test_conversion_matrix_csr( op, array_type, @@ -37,9 +37,9 @@ function shared_test_conversion_matrix_csr( vals = float_types[end][1.0, 2.0, 3.0] B = sparse(rows, cols, vals, 2, 2) - # test only conversion SparseMatrixCSC <-> DeviceSparseMatrixCSR + # test only conversion SparseMatrixCSC <-> GenericSparseMatrixCSR if op === Array - dA = DeviceSparseMatrixCSR(A) + dA = GenericSparseMatrixCSR(A) @test size(dA) == (0, 0) @test length(dA) == 0 @test collect(nonzeros(dA)) == int_types[end][] @@ -47,8 +47,8 @@ function shared_test_conversion_matrix_csr( end B_csr = SparseMatrixCSC(transpose(B)) # Get the CSR storage pattern - dB = adapt(op, DeviceSparseMatrixCSR(transpose(B_csr))) - dB2 = adapt(op, DeviceSparseMatrixCSR(B)) # Directly from CSC should also work + dB = adapt(op, GenericSparseMatrixCSR(transpose(B_csr))) + dB2 = adapt(op, GenericSparseMatrixCSR(B)) # Directly from CSC should also work @test size(dB) == (2, 2) @test length(dB) == 4 @test nnz(dB) == 3 @@ -58,7 +58,7 @@ function shared_test_conversion_matrix_csr( @test SparseMatrixCSC(dB) == B @test SparseMatrixCSC(dB2) == B - @test_throws ArgumentError DeviceSparseMatrixCSR( + @test_throws ArgumentError GenericSparseMatrixCSR( 2, 2, op(int_types[end][1, 3]), @@ -79,7 +79,7 @@ function shared_test_linearalgebra_matrix_csr( for T in (int_types..., float_types..., complex_types...) A = sprand(T, 1000, 1000, 0.01) # Convert to CSR storage pattern - dA = adapt(op, DeviceSparseMatrixCSR(A)) + dA = adapt(op, GenericSparseMatrixCSR(A)) @test sum(dA) ≈ sum(A) @@ -100,7 +100,7 @@ function shared_test_linearalgebra_matrix_csr( x = rand(T, size(op_A(A), 1)) y = rand(T, size(op_A(A), 2)) - dA = adapt(op, DeviceSparseMatrixCSR(A)) + dA = adapt(op, GenericSparseMatrixCSR(A)) dx = op(x) dy = op(y) @@ -115,7 +115,7 @@ function shared_test_linearalgebra_matrix_csr( @testset "Scalar Operations" begin for T in (int_types..., float_types..., complex_types...) A = sprand(T, 40, 30, 0.1) - dA = adapt(op, DeviceSparseMatrixCSR(A)) + dA = adapt(op, GenericSparseMatrixCSR(A)) α = T <: Complex ? T(1.0 + 2.0im) : (T <: Integer ? T(2) : T(1.5)) @@ -139,7 +139,7 @@ function shared_test_linearalgebra_matrix_csr( @testset "Unary Operations" begin for T in (float_types..., complex_types...) A = sprand(T, 25, 20, 0.15) - dA = adapt(op, DeviceSparseMatrixCSR(A)) + dA = adapt(op, GenericSparseMatrixCSR(A)) # Test unary plus pos_A = +dA @@ -182,7 +182,7 @@ function shared_test_linearalgebra_matrix_csr( @testset "UniformScaling Multiplication" begin for T in (float_types..., complex_types...) A = sprand(T, 15, 15, 0.2) - dA = adapt(op, DeviceSparseMatrixCSR(A)) + dA = adapt(op, GenericSparseMatrixCSR(A)) # Test A * I (identity) result_I = dA * I @@ -222,7 +222,7 @@ function shared_test_linearalgebra_matrix_csr( C = op_A(A) * op_B(B) # Convert to CSR storage pattern - dA = adapt(op, DeviceSparseMatrixCSR(A)) + dA = adapt(op, GenericSparseMatrixCSR(A)) # Matrix-Scalar multiplication if T != Int32 @@ -256,7 +256,7 @@ function shared_test_linearalgebra_matrix_csr( A = sprand(T, m, n, 0.1) B = rand(T, m, n) - dA = adapt(op, DeviceSparseMatrixCSR(A)) + dA = adapt(op, GenericSparseMatrixCSR(A)) dB = op(B) # Test sparse + dense @@ -290,29 +290,29 @@ function shared_test_linearalgebra_matrix_csr( A = sprand(T, dims_A..., 0.1) B = sprand(T, dims_B..., 0.15) - dA = adapt(op, DeviceSparseMatrixCSR(A)) - dB = adapt(op, DeviceSparseMatrixCSR(B)) + dA = adapt(op, GenericSparseMatrixCSR(A)) + dB = adapt(op, GenericSparseMatrixCSR(B)) # Test sparse + sparse result = op_A(dA) + op_B(dB) expected = op_A(A) + op_B(B) @test collect(result) ≈ Matrix(expected) - @test result isa DeviceSparseMatrixCSR + @test result isa GenericSparseMatrixCSR # Additional tests only for identity + identity if op_A === identity && op_B === identity # Test with overlapping entries A_overlap = sparse([1, 2, 3], [1, 2, 3], T[1, 2, 3], m, n) B_overlap = sparse([1, 2, 4], [1, 2, 4], T[4, 5, 6], m, n) - dA_overlap = adapt(op, DeviceSparseMatrixCSR(A_overlap)) - dB_overlap = adapt(op, DeviceSparseMatrixCSR(B_overlap)) + dA_overlap = adapt(op, GenericSparseMatrixCSR(A_overlap)) + dB_overlap = adapt(op, GenericSparseMatrixCSR(B_overlap)) result_overlap = dA_overlap + dB_overlap expected_overlap = A_overlap + B_overlap @test collect(result_overlap) ≈ Matrix(expected_overlap) # Test dimension mismatch B_wrong = sprand(T, m + 1, n, 0.1) - dB_wrong = adapt(op, DeviceSparseMatrixCSR(B_wrong)) + dB_wrong = adapt(op, GenericSparseMatrixCSR(B_wrong)) @test_throws DimensionMismatch dA + dB_wrong end end @@ -335,14 +335,14 @@ function shared_test_linearalgebra_matrix_csr( A = sprand(T, dims_A..., 0.1) B = sprand(T, dims_B..., 0.15) - dA = adapt(op, DeviceSparseMatrixCSR(A)) - dB = adapt(op, DeviceSparseMatrixCSR(B)) + dA = adapt(op, GenericSparseMatrixCSR(A)) + dB = adapt(op, GenericSparseMatrixCSR(B)) # Test sparse * sparse result = op_A(dA) * op_B(dB) expected = op_A(A) * op_B(B) @test collect(result) ≈ Matrix(expected) - @test result isa DeviceSparseMatrixCSR + @test result isa GenericSparseMatrixCSR end end end @@ -354,8 +354,8 @@ function shared_test_linearalgebra_matrix_csr( A_sparse = SparseMatrixCSC{T, int_types[end]}(sprand(T, 30, 25, 0.1)) B_sparse = SparseMatrixCSC{T, int_types[end]}(sprand(T, 20, 15, 0.1)) - A = adapt(op, DeviceSparseMatrixCSR(A_sparse)) - B = adapt(op, DeviceSparseMatrixCSR(B_sparse)) + A = adapt(op, GenericSparseMatrixCSR(A_sparse)) + B = adapt(op, GenericSparseMatrixCSR(B_sparse)) C = kron(A, B) C_expected = kron(A_sparse, B_sparse) @@ -363,7 +363,7 @@ function shared_test_linearalgebra_matrix_csr( @test size(C) == size(C_expected) @test nnz(C) == nnz(C_expected) @test Matrix(SparseMatrixCSC(C)) ≈ Matrix(C_expected) - @test C isa DeviceSparseMatrixCSR + @test C isa GenericSparseMatrixCSR end end end diff --git a/test/shared/vector.jl b/test/shared/vector.jl index cf95a80..5ba0b59 100644 --- a/test/shared/vector.jl +++ b/test/shared/vector.jl @@ -5,7 +5,7 @@ function shared_test_vector( float_types::Tuple, complex_types::Tuple, ) - return @testset "DeviceSparseVector $array_type" verbose = true begin + return @testset "GenericSparseVector $array_type" verbose = true begin shared_test_conversion_vector(op, array_type, int_types, float_types, complex_types) shared_test_linearalgebra_vector( op, @@ -28,22 +28,22 @@ function shared_test_conversion_vector( sv = SparseVector(10, int_types[end][], float_types[end][]) sv2 = sparsevec(int_types[end][3], float_types[end][2.5], 8) - # test only conversion SparseVector <-> DeviceSparseVector + # test only conversion SparseVector <-> GenericSparseVector if op === Array - dsv = DeviceSparseVector(sv) + dsv = GenericSparseVector(sv) @test size(dsv) == (10,) @test length(dsv) == 10 @test SparseVector(dsv) == sv end - dsv = adapt(op, DeviceSparseVector(sv)) + dsv = adapt(op, GenericSparseVector(sv)) @test size(dsv) == (10,) @test length(dsv) == 10 @test nnz(dsv) == 0 @test collect(nonzeros(dsv)) == float_types[end][] @test collect(nonzeroinds(dsv)) == int_types[end][] - dsv2 = adapt(op, DeviceSparseVector(sv2)) + dsv2 = adapt(op, GenericSparseVector(sv2)) @test size(dsv2) == (8,) @test length(dsv2) == 8 @test nnz(dsv2) == 1 @@ -64,7 +64,7 @@ function shared_test_linearalgebra_vector( for T in (int_types..., float_types..., complex_types...) v = sprand(T, 1000, 0.01) y = rand(T, 1000) - dv = adapt(op, DeviceSparseVector(v)) + dv = adapt(op, GenericSparseVector(v)) dy = op(y) @test sum(dv) ≈ sum(v) @@ -82,7 +82,7 @@ function shared_test_linearalgebra_vector( @testset "Scalar Operations" begin for T in (int_types..., float_types..., complex_types...) v = sprand(T, 100, 0.3) - dv = adapt(op, DeviceSparseVector(v)) + dv = adapt(op, GenericSparseVector(v)) α = T <: Complex ? T(2.0 + 1.0im) : (T <: Integer ? T(2) : T(2.5)) @@ -106,7 +106,7 @@ function shared_test_linearalgebra_vector( @testset "Unary Operations" begin for T in (float_types..., complex_types...) v = sprand(T, 80, 0.4) - dv = adapt(op, DeviceSparseVector(v)) + dv = adapt(op, GenericSparseVector(v)) # Test unary plus (inherited from AbstractArray) pos_v = +dv @@ -149,7 +149,7 @@ function shared_test_linearalgebra_vector( return @testset "Norms and Normalization" begin for T in (float_types..., complex_types...) v = sprand(T, 50, 0.5) - dv = adapt(op, DeviceSparseVector(v)) + dv = adapt(op, GenericSparseVector(v)) # Test different norms norm2 = norm(dv)