blob: f3a9e6a5968f5a81244941bb0f0dd22887a5a4d1 [file] [edit]
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2026 Rasmus Munk Larsen <rmlarsen@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// SPDX-License-Identifier: MPL-2.0
// cuSPARSE-specific support types.
#ifndef EIGEN_GPU_CUSPARSE_SUPPORT_H
#define EIGEN_GPU_CUSPARSE_SUPPORT_H
// IWYU pragma: private
#include "./InternalHeaderCheck.h"
#include "./GpuSupport.h"
#include "./Meta.h"
#include <cusparse.h>
/** \brief 1 when cuSPARSE runs SpMV and SpMM on BSR (block sparse row)
* descriptors, 0 otherwise.
*
* The generic API gained BSR in SpMM with cuSPARSE 12.5 (CUDA 12.8) and in SpMV
* with 12.6.3 (CUDA 13.0 Update 1); older toolkits declare cusparseCreateBsr but
* return CUSPARSE_STATUS_NOT_SUPPORTED from the products. gpu::SparseContext
* uploads a BlockSparseMatrix as BSR only when this is 1, and as CSC otherwise. */
#if defined(CUSPARSE_VERSION) && CUSPARSE_VERSION >= 12603
#define EIGEN_HAS_CUSPARSE_BSR 1
#else
#define EIGEN_HAS_CUSPARSE_BSR 0
#endif
namespace Eigen {
namespace gpu {
namespace internal {
#define EIGEN_CUSPARSE_CHECK(x) \
do { \
const cusparseStatus_t _s = (x); \
if (_s != CUSPARSE_STATUS_SUCCESS) EIGEN_GPU_CHECK_FAILED(cusparseGetErrorName(_s), #x, __FILE__, __LINE__); \
} while (0)
// cuSPARSE rejects CUSPARSE_OPERATION_CONJUGATE_TRANSPOSE for real scalar
// types; for real Scalar, ConjTrans is mathematically equivalent to Trans and
// is silently demoted. Complex Scalar passes through unchanged.
template <typename Scalar>
constexpr cusparseOperation_t to_cusparse_op(GpuOp op) {
const auto op_ = (op == GpuOp::ConjTrans && !NumTraits<Scalar>::IsComplex) ? GpuOp::Trans : op;
switch (op_) {
case GpuOp::Trans:
return CUSPARSE_OPERATION_TRANSPOSE;
case GpuOp::ConjTrans:
return CUSPARSE_OPERATION_CONJUGATE_TRANSPOSE;
default:
return CUSPARSE_OPERATION_NON_TRANSPOSE;
}
}
// Bind without copying when the input already has the target sparse format
// and is compressed; otherwise convert/compress into `storage` and return
// that. Avoids a full host copy + format conversion on the common
// already-matching path. The SFINAE split (rather than plain overloading on
// `const SpMatType&`) is load-bearing: an exact-match overload would bind a
// converted temporary for other input types and return a dangling reference.
template <typename SpMatType, typename InputType, require_same_t<SpMatType, InputType> = 0>
const SpMatType& bind_sparse(const InputType& A, SpMatType& storage) {
if (A.isCompressed()) return A;
storage = A;
storage.makeCompressed();
return storage;
}
template <typename SpMatType, typename InputType, require_not_same_t<SpMatType, InputType> = 0>
const SpMatType& bind_sparse(const InputType& A, SpMatType& storage) {
storage = A;
storage.makeCompressed();
return storage;
}
// Shared guard for the 32-bit index limits of the CUDA sparse libraries
// (cuSPARSE, cuDSS): matrix dimensions and nonzero count must fit StorageIndex.
template <typename StorageIndex>
inline void check_storage_index_bounds(Index rows, Index cols, Index nnz) {
const Index max_storage_index = static_cast<Index>((std::numeric_limits<StorageIndex>::max)());
eigen_assert(rows <= max_storage_index && cols <= max_storage_index && nnz <= max_storage_index &&
"matrix dimensions or nonzeros exceed the index range supported by the CUDA sparse libraries");
EIGEN_UNUSED_VARIABLE(rows);
EIGEN_UNUSED_VARIABLE(cols);
EIGEN_UNUSED_VARIABLE(nnz);
EIGEN_UNUSED_VARIABLE(max_storage_index);
}
} // namespace internal
} // namespace gpu
} // namespace Eigen
#endif // EIGEN_GPU_CUSPARSE_SUPPORT_H