#ifndef INCLUDE_GUARD_HIP_CUPY_ROCSOLVER_H #define INCLUDE_GUARD_HIP_CUPY_ROCSOLVER_H #include "cupy_hip.h" #include "cupy_hipblas.h" #include // for gcc 10.0 extern "C" { // TODO(leofang): perhaps these should be merged with the support of hipBLAS? static rocblas_fill convert_rocblas_fill(cublasFillMode_t mode) { switch(static_cast(mode)) { case 0 /* CUBLAS_FILL_MODE_LOWER */: return rocblas_fill_lower; case 1 /* CUBLAS_FILL_MODE_UPPER */: return rocblas_fill_upper; default: throw std::runtime_error("unrecognized mode"); } } static rocblas_operation convert_rocblas_operation(cublasOperation_t op) { return static_cast(static_cast(op) + 111); } static rocblas_side convert_rocblas_side(cublasSideMode_t mode) { return static_cast(static_cast(mode) + 141); } #if HIP_VERSION >= 309 static rocblas_svect convert_rocblas_svect(signed char mode) { switch(mode) { case 'A': return rocblas_svect_all; case 'S': return rocblas_svect_singular; case 'O': return rocblas_svect_overwrite; case 'N': return rocblas_svect_none; default: throw std::runtime_error("unrecognized mode"); } } #endif // rocSOLVER /* ---------- helpers ---------- */ cusolverStatus_t cusolverDnCreate(cusolverDnHandle_t *handle) { return rocblas_create_handle(handle); } cusolverStatus_t cusolverDnDestroy(cusolverDnHandle_t handle) { return rocblas_destroy_handle(handle); } cusolverStatus_t cusolverDnGetStream(cusolverDnHandle_t handle, cudaStream_t *streamId) { return rocblas_get_stream(handle, streamId); } cusolverStatus_t cusolverDnSetStream (cusolverDnHandle_t handle, cudaStream_t streamId) { return rocblas_set_stream(handle, streamId); } cusolverStatus_t cusolverGetProperty(libraryPropertyType type, int* val) { switch(type) { case MAJOR_VERSION: { *val = ROCSOLVER_VERSION_MAJOR; break; } case MINOR_VERSION: { *val = ROCSOLVER_VERSION_MINOR; break; } case PATCH_LEVEL: { *val = ROCSOLVER_VERSION_PATCH; break; } default: throw std::runtime_error("invalid type"); } return rocblas_status_success; } typedef enum cusolverDnParams_t {}; cusolverStatus_t cusolverDnCreateParams(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnDestroyParams(...) { return rocblas_status_not_implemented; } /* ---------- potrf ---------- */ cusolverStatus_t cusolverDnSpotrf_bufferSize(cusolverDnHandle_t handle, cublasFillMode_t uplo, int n, float *A, int lda, int *Lwork) { // this needs to return 0 because rocSolver does not rely on it *Lwork = 0; return rocblas_status_success; } cusolverStatus_t cusolverDnDpotrf_bufferSize(cusolverDnHandle_t handle, cublasFillMode_t uplo, int n, double *A, int lda, int *Lwork) { // this needs to return 0 because rocSolver does not rely on it *Lwork = 0; return rocblas_status_success; } cusolverStatus_t cusolverDnCpotrf_bufferSize(cusolverDnHandle_t handle, cublasFillMode_t uplo, int n, cuComplex *A, int lda, int *Lwork) { // this needs to return 0 because rocSolver does not rely on it *Lwork = 0; return rocblas_status_success; } cusolverStatus_t cusolverDnZpotrf_bufferSize(cusolverDnHandle_t handle, cublasFillMode_t uplo, int n, cuDoubleComplex *A, int lda, int *Lwork) { // this needs to return 0 because rocSolver does not rely on it *Lwork = 0; return rocblas_status_success; } cusolverStatus_t cusolverDnSpotrf(cusolverDnHandle_t handle, cublasFillMode_t uplo, int n, float *A, int lda, float *Workspace, int Lwork, int *devInfo) { // ignore Workspace and Lwork as rocSOLVER does not need them return rocsolver_spotrf(handle, convert_rocblas_fill(uplo), n, A, lda, devInfo); } cusolverStatus_t cusolverDnDpotrf(cusolverDnHandle_t handle, cublasFillMode_t uplo, int n, double *A, int lda, double *Workspace, int Lwork, int *devInfo ) { // ignore Workspace and Lwork as rocSOLVER does not need them return rocsolver_dpotrf(handle, convert_rocblas_fill(uplo), n, A, lda, devInfo); } cusolverStatus_t cusolverDnCpotrf(cusolverDnHandle_t handle, cublasFillMode_t uplo, int n, cuComplex *A, int lda, cuComplex *Workspace, int Lwork, int *devInfo) { #if HIP_VERSION < 306 return rocblas_status_not_implemented; #else // ignore Workspace and Lwork as rocSOLVER does not need them return rocsolver_cpotrf(handle, convert_rocblas_fill(uplo), n, reinterpret_cast(A), lda, devInfo); #endif } cusolverStatus_t cusolverDnZpotrf(cusolverDnHandle_t handle, cublasFillMode_t uplo, int n, cuDoubleComplex *A, int lda, cuDoubleComplex *Workspace, int Lwork, int *devInfo) { #if HIP_VERSION < 306 return rocblas_status_not_implemented; #else // ignore Workspace and Lwork as rocSOLVER does not need them return rocsolver_zpotrf(handle, convert_rocblas_fill(uplo), n, reinterpret_cast(A), lda, devInfo); #endif } cusolverStatus_t cusolverDnSpotrfBatched(cusolverDnHandle_t handle, cublasFillMode_t uplo, int n, float *Aarray[], int lda, int *infoArray, int batchSize) { return rocsolver_spotrf_batched(handle, convert_rocblas_fill(uplo), n, Aarray, lda, infoArray, batchSize); } cusolverStatus_t cusolverDnDpotrfBatched(cusolverDnHandle_t handle, cublasFillMode_t uplo, int n, double *Aarray[], int lda, int *infoArray, int batchSize) { return rocsolver_dpotrf_batched(handle, convert_rocblas_fill(uplo), n, Aarray, lda, infoArray, batchSize); } cusolverStatus_t cusolverDnCpotrfBatched(cusolverDnHandle_t handle, cublasFillMode_t uplo, int n, cuComplex *Aarray[], int lda, int *infoArray, int batchSize) { #if HIP_VERSION < 306 return rocblas_status_not_implemented; #else return rocsolver_cpotrf_batched(handle, convert_rocblas_fill(uplo), n, reinterpret_cast(Aarray), lda, infoArray, batchSize); #endif } cusolverStatus_t cusolverDnZpotrfBatched(cusolverDnHandle_t handle, cublasFillMode_t uplo, int n, cuDoubleComplex *Aarray[], int lda, int *infoArray, int batchSize) { #if HIP_VERSION < 306 return rocblas_status_not_implemented; #else return rocsolver_zpotrf_batched(handle, convert_rocblas_fill(uplo), n, reinterpret_cast(Aarray), lda, infoArray, batchSize); #endif } /* ---------- getrf ---------- */ cusolverStatus_t cusolverDnSgetrf_bufferSize(cusolverDnHandle_t handle, int m, int n, float *A, int lda, int *Lwork) { // this needs to return 0 because rocSolver does not rely on it *Lwork = 0; return rocblas_status_success; } cusolverStatus_t cusolverDnDgetrf_bufferSize(cusolverDnHandle_t handle, int m, int n, double *A, int lda, int *Lwork) { // this needs to return 0 because rocSolver does not rely on it *Lwork = 0; return rocblas_status_success; } cusolverStatus_t cusolverDnCgetrf_bufferSize(cusolverDnHandle_t handle, int m, int n, cuComplex *A, int lda, int *Lwork) { // this needs to return 0 because rocSolver does not rely on it *Lwork = 0; return rocblas_status_success; } cusolverStatus_t cusolverDnZgetrf_bufferSize(cusolverDnHandle_t handle, int m, int n, cuDoubleComplex *A, int lda, int *Lwork) { // this needs to return 0 because rocSolver does not rely on it *Lwork = 0; return rocblas_status_success; } cusolverStatus_t cusolverDnSgetrf(cusolverDnHandle_t handle, int m, int n, float *A, int lda, float *Workspace, int *devIpiv, int *devInfo) { // ignore Workspace as rocSOLVER does not need it return rocsolver_sgetrf(handle, m, n, A, lda, devIpiv, devInfo); } cusolverStatus_t cusolverDnDgetrf(cusolverDnHandle_t handle, int m, int n, double *A, int lda, double *Workspace, int *devIpiv, int *devInfo) { // ignore Workspace as rocSOLVER does not need it return rocsolver_dgetrf(handle, m, n, A, lda, devIpiv, devInfo); } cusolverStatus_t cusolverDnCgetrf(cusolverDnHandle_t handle, int m, int n, cuComplex *A, int lda, cuComplex *Workspace, int *devIpiv, int *devInfo) { // ignore Workspace as rocSOLVER does not need it return rocsolver_cgetrf(handle, m, n, reinterpret_cast(A), lda, devIpiv, devInfo); } cusolverStatus_t cusolverDnZgetrf(cusolverDnHandle_t handle, int m, int n, cuDoubleComplex *A, int lda, cuDoubleComplex *Workspace, int *devIpiv, int *devInfo) { // ignore Workspace as rocSOLVER does not need it return rocsolver_zgetrf(handle, m, n, reinterpret_cast(A), lda, devIpiv, devInfo); } /* ---------- getrs ---------- */ cusolverStatus_t cusolverDnSgetrs(cusolverDnHandle_t handle, cublasOperation_t trans, int n, int nrhs, const float *A, int lda, const int *devIpiv, float *B, int ldb, int *devInfo) { // ignore devInfo as rocSOLVER does not need it return rocsolver_sgetrs(handle, convert_rocblas_operation(trans), n, nrhs, const_cast(A), lda, devIpiv, B, ldb); } cusolverStatus_t cusolverDnDgetrs(cusolverDnHandle_t handle, cublasOperation_t trans, int n, int nrhs, const double *A, int lda, const int *devIpiv, double *B, int ldb, int *devInfo) { // ignore devInfo as rocSOLVER does not need it return rocsolver_dgetrs(handle, convert_rocblas_operation(trans), n, nrhs, const_cast(A), lda, devIpiv, B, ldb); } cusolverStatus_t cusolverDnCgetrs(cusolverDnHandle_t handle, cublasOperation_t trans, int n, int nrhs, const cuComplex *A, int lda, const int *devIpiv, cuComplex *B, int ldb, int *devInfo) { // ignore devInfo as rocSOLVER does not need it return rocsolver_cgetrs(handle, convert_rocblas_operation(trans), n, nrhs, (rocblas_float_complex*)(A), lda, devIpiv, reinterpret_cast(B), ldb); } cusolverStatus_t cusolverDnZgetrs(cusolverDnHandle_t handle, cublasOperation_t trans, int n, int nrhs, const cuDoubleComplex *A, int lda, const int *devIpiv, cuDoubleComplex *B, int ldb, int *devInfo) { // ignore devInfo as rocSOLVER does not need it return rocsolver_zgetrs(handle, convert_rocblas_operation(trans), n, nrhs, (rocblas_double_complex*)(A), lda, devIpiv, reinterpret_cast(B), ldb); } /* ---------- geqrf ---------- */ cusolverStatus_t cusolverDnSgeqrf_bufferSize(cusolverDnHandle_t handle, int m, int n, float *A, int lda, int *lwork) { // this needs to return 0 because rocSolver does not rely on it *lwork = 0; return rocblas_status_success; } cusolverStatus_t cusolverDnDgeqrf_bufferSize(cusolverDnHandle_t handle, int m, int n, double *A, int lda, int *lwork) { // this needs to return 0 because rocSolver does not rely on it *lwork = 0; return rocblas_status_success; } cusolverStatus_t cusolverDnCgeqrf_bufferSize(cusolverDnHandle_t handle, int m, int n, cuComplex *A, int lda, int *lwork) { // this needs to return 0 because rocSolver does not rely on it *lwork = 0; return rocblas_status_success; } cusolverStatus_t cusolverDnZgeqrf_bufferSize(cusolverDnHandle_t handle, int m, int n, cuDoubleComplex *A, int lda, int *lwork) { // this needs to return 0 because rocSolver does not rely on it *lwork = 0; return rocblas_status_success; } cusolverStatus_t cusolverDnSgeqrf(cusolverDnHandle_t handle, int m, int n, float *A, int lda, float *TAU, float *Workspace, int Lwork, int *devInfo) { // ignore Workspace, Lwork and devInfo as rocSOLVER does not need them return rocsolver_sgeqrf(handle, m, n, A, lda, TAU); } cusolverStatus_t cusolverDnDgeqrf(cusolverDnHandle_t handle, int m, int n, double *A, int lda, double *TAU, double *Workspace, int Lwork, int *devInfo) { // ignore Workspace, Lwork and devInfo as rocSOLVER does not need them return rocsolver_dgeqrf(handle, m, n, A, lda, TAU); } cusolverStatus_t cusolverDnCgeqrf(cusolverDnHandle_t handle, int m, int n, cuComplex *A, int lda, cuComplex *TAU, cuComplex *Workspace, int Lwork, int *devInfo) { // ignore Workspace, Lwork and devInfo as rocSOLVER does not need them return rocsolver_cgeqrf(handle, m, n, reinterpret_cast(A), lda, reinterpret_cast(TAU)); } cusolverStatus_t cusolverDnZgeqrf(cusolverDnHandle_t handle, int m, int n, cuDoubleComplex *A, int lda, cuDoubleComplex *TAU, cuDoubleComplex *Workspace, int Lwork, int *devInfo) { // ignore Workspace, Lwork and devInfo as rocSOLVER does not need them return rocsolver_zgeqrf(handle, m, n, reinterpret_cast(A), lda, reinterpret_cast(TAU)); } /* ---------- orgqr ---------- */ cusolverStatus_t cusolverDnSorgqr_bufferSize(cusolverDnHandle_t handle, int m, int n, int k, const float *A, int lda, const float *tau, int *lwork) { // this needs to return 0 because rocSolver does not rely on it *lwork = 0; return rocblas_status_success; } cusolverStatus_t cusolverDnDorgqr_bufferSize(cusolverDnHandle_t handle, int m, int n, int k, const double *A, int lda, const double *tau, int *lwork) { // this needs to return 0 because rocSolver does not rely on it *lwork = 0; return rocblas_status_success; } cusolverStatus_t cusolverDnSorgqr(cusolverDnHandle_t handle, int m, int n, int k, float *A, int lda, const float *tau, float *work, int lwork, int *info) { // ignore work, lwork and info as rocSOLVER does not need them return rocsolver_sorgqr(handle, m, n, k, A, lda, const_cast(tau)); } cusolverStatus_t cusolverDnDorgqr(cusolverDnHandle_t handle, int m, int n, int k, double *A, int lda, const double *tau, double *work, int lwork, int *info) { // ignore work, lwork and info as rocSOLVER does not need them return rocsolver_dorgqr(handle, m, n, k, A, lda, const_cast(tau)); } /* ---------- ungqr ---------- */ cusolverStatus_t cusolverDnCungqr_bufferSize(cusolverDnHandle_t handle, int m, int n, int k, const cuComplex *A, int lda, const cuComplex *tau, int *lwork) { // this needs to return 0 because rocSolver does not rely on it *lwork = 0; return rocblas_status_success; } cusolverStatus_t cusolverDnZungqr_bufferSize(cusolverDnHandle_t handle, int m, int n, int k, const cuDoubleComplex *A, int lda, const cuDoubleComplex *tau, int *lwork) { // this needs to return 0 because rocSolver does not rely on it *lwork = 0; return rocblas_status_success; } cusolverStatus_t cusolverDnCungqr(cusolverDnHandle_t handle, int m, int n, int k, cuComplex *A, int lda, const cuComplex *tau, cuComplex *work, int lwork, int *info) { #if HIP_VERSION < 306 return rocblas_status_not_implemented; #else // ignore work, lwork and info as rocSOLVER does not need them return rocsolver_cungqr(handle, m, n, k, reinterpret_cast(A), lda, reinterpret_cast(const_cast(tau))); #endif } cusolverStatus_t cusolverDnZungqr(cusolverDnHandle_t handle, int m, int n, int k, cuDoubleComplex *A, int lda, const cuDoubleComplex *tau, cuDoubleComplex *work, int lwork, int *info) { #if HIP_VERSION < 306 return rocblas_status_not_implemented; #else // ignore work, lwork and info as rocSOLVER does not need them return rocsolver_zungqr(handle, m, n, k, reinterpret_cast(A), lda, reinterpret_cast(const_cast(tau))); #endif } /* ---------- ormqr ---------- */ cusolverStatus_t cusolverDnSormqr_bufferSize(cusolverDnHandle_t handle, cublasSideMode_t side, cublasOperation_t trans, int m, int n, int k, const float *A, int lda, const float *tau, const float *C, int ldc, int *lwork) { // this needs to return 0 because rocSolver does not rely on it *lwork = 0; return rocblas_status_success; } cusolverStatus_t cusolverDnDormqr_bufferSize(cusolverDnHandle_t handle, cublasSideMode_t side, cublasOperation_t trans, int m, int n, int k, const double *A, int lda, const double *tau, const double *C, int ldc, int *lwork) { // this needs to return 0 because rocSolver does not rely on it *lwork = 0; return rocblas_status_success; } cusolverStatus_t cusolverDnSormqr(cusolverDnHandle_t handle, cublasSideMode_t side, cublasOperation_t trans, int m, int n, int k, const float *A, int lda, const float *tau, float *C, int ldc, float *work, int lwork, int *devInfo) { // ignore work, lwork and devInfo as rocSOLVER does not need them return rocsolver_sormqr(handle, convert_rocblas_side(side), convert_rocblas_operation(trans), m, n, k, const_cast(A), lda, const_cast(tau), C, ldc); } cusolverStatus_t cusolverDnDormqr(cusolverDnHandle_t handle, cublasSideMode_t side, cublasOperation_t trans, int m, int n, int k, const double *A, int lda, const double *tau, double *C, int ldc, double *work, int lwork, int *devInfo) { // ignore work, lwork and devInfo as rocSOLVER does not need them return rocsolver_dormqr(handle, convert_rocblas_side(side), convert_rocblas_operation(trans), m, n, k, const_cast(A), lda, const_cast(tau), C, ldc); } /* ---------- unmqr ---------- */ cusolverStatus_t cusolverDnCunmqr_bufferSize(cusolverDnHandle_t handle, cublasSideMode_t side, cublasOperation_t trans, int m, int n, int k, const cuComplex *A, int lda, const cuComplex *tau, const cuComplex *C, int ldc, int *lwork) { // this needs to return 0 because rocSolver does not rely on it *lwork = 0; return rocblas_status_success; } cusolverStatus_t cusolverDnZunmqr_bufferSize(cusolverDnHandle_t handle, cublasSideMode_t side, cublasOperation_t trans, int m, int n, int k, const cuDoubleComplex *A, int lda, const cuDoubleComplex *tau, const cuDoubleComplex *C, int ldc, int *lwork) { // this needs to return 0 because rocSolver does not rely on it *lwork = 0; return rocblas_status_success; } cusolverStatus_t cusolverDnCunmqr(cusolverDnHandle_t handle, cublasSideMode_t side, cublasOperation_t trans, int m, int n, int k, const cuComplex *A, int lda, const cuComplex *tau, cuComplex *C, int ldc, cuComplex *work, int lwork, int *devInfo) { #if HIP_VERSION < 306 return rocblas_status_not_implemented; #else // ignore work, lwork and devInfo as rocSOLVER does not need them return rocsolver_cunmqr(handle, convert_rocblas_side(side), convert_rocblas_operation(trans), m, n, k, reinterpret_cast(const_cast(A)), lda, reinterpret_cast(const_cast(tau)), reinterpret_cast(C), ldc); #endif } cusolverStatus_t cusolverDnZunmqr(cusolverDnHandle_t handle, cublasSideMode_t side, cublasOperation_t trans, int m, int n, int k, const cuDoubleComplex *A, int lda, const cuDoubleComplex *tau, cuDoubleComplex *C, int ldc, cuDoubleComplex *work, int lwork, int *devInfo) { #if HIP_VERSION < 306 return rocblas_status_not_implemented; #else // ignore work, lwork and devInfo as rocSOLVER does not need them return rocsolver_zunmqr(handle, convert_rocblas_side(side), convert_rocblas_operation(trans), m, n, k, reinterpret_cast(const_cast(A)), lda, reinterpret_cast(const_cast(tau)), reinterpret_cast(C), ldc); #endif } /* ---------- gesvd ---------- */ cusolverStatus_t cusolverDnSgesvd_bufferSize(cusolverDnHandle_t handle, int m, int n, int *lwork) { // this needs to return 0 because rocSolver does not rely on it *lwork = 0; return rocblas_status_success; } cusolverStatus_t cusolverDnDgesvd_bufferSize(cusolverDnHandle_t handle, int m, int n, int *lwork) { // this needs to return 0 because rocSolver does not rely on it *lwork = 0; return rocblas_status_success; } cusolverStatus_t cusolverDnCgesvd_bufferSize(cusolverDnHandle_t handle, int m, int n, int *lwork) { // this needs to return 0 because rocSolver does not rely on it *lwork = 0; return rocblas_status_success; } cusolverStatus_t cusolverDnZgesvd_bufferSize(cusolverDnHandle_t handle, int m, int n, int *lwork) { // this needs to return 0 because rocSolver does not rely on it *lwork = 0; return rocblas_status_success; } cusolverStatus_t cusolverDnSgesvd(cusolverDnHandle_t handle, signed char jobu, signed char jobvt, int m, int n, float *A, int lda, float *S, float *U, int ldu, float *VT, int ldvt, float *work, int lwork, float *rwork, int *info) { #if HIP_VERSION < 309 return rocblas_status_not_implemented; #else // ignore work and lwork as rocSOLVER does not need them return rocsolver_sgesvd(handle, convert_rocblas_svect(jobu), convert_rocblas_svect(jobvt), m, n, A, lda, S, U, ldu, VT, ldvt, rwork, rocblas_outofplace, // always out-of-place info); #endif } cusolverStatus_t cusolverDnDgesvd(cusolverDnHandle_t handle, signed char jobu, signed char jobvt, int m, int n, double *A, int lda, double *S, double *U, int ldu, double *VT, int ldvt, double *work, int lwork, double *rwork, int *info) { #if HIP_VERSION < 309 return rocblas_status_not_implemented; #else // ignore work and lwork as rocSOLVER does not need them return rocsolver_dgesvd(handle, convert_rocblas_svect(jobu), convert_rocblas_svect(jobvt), m, n, A, lda, S, U, ldu, VT, ldvt, rwork, rocblas_outofplace, // always out-of-place info); #endif } cusolverStatus_t cusolverDnCgesvd(cusolverDnHandle_t handle, signed char jobu, signed char jobvt, int m, int n, cuComplex *A, int lda, float *S, cuComplex *U, int ldu, cuComplex *VT, int ldvt, cuComplex *work, int lwork, float *rwork, int *info) { #if HIP_VERSION < 309 return rocblas_status_not_implemented; #else // ignore work and lwork as rocSOLVER does not need them return rocsolver_cgesvd(handle, convert_rocblas_svect(jobu), convert_rocblas_svect(jobvt), m, n, reinterpret_cast(A), lda, S, reinterpret_cast(U), ldu, reinterpret_cast(VT), ldvt, rwork, rocblas_outofplace, // always out-of-place info); #endif } cusolverStatus_t cusolverDnZgesvd(cusolverDnHandle_t handle, signed char jobu, signed char jobvt, int m, int n, cuDoubleComplex *A, int lda, double *S, cuDoubleComplex *U, int ldu, cuDoubleComplex *VT, int ldvt, cuDoubleComplex *work, int lwork, double *rwork, int *info) { #if HIP_VERSION < 309 return rocblas_status_not_implemented; #else // ignore work and lwork as rocSOLVER does not need them return rocsolver_zgesvd(handle, convert_rocblas_svect(jobu), convert_rocblas_svect(jobvt), m, n, reinterpret_cast(A), lda, S, reinterpret_cast(U), ldu, reinterpret_cast(VT), ldvt, rwork, rocblas_outofplace, // always out-of-place info); #endif } /* ---------- batched gesvd ---------- */ // Because rocSOLVER provides no counterpart for gesvdjBatched, we wrap its batched version directly. typedef enum { CUSOLVER_EIG_MODE_NOVECTOR=0, CUSOLVER_EIG_MODE_VECTOR=1 } cusolverEigMode_t; typedef void* gesvdjInfo_t; cusolverStatus_t cusolverDnCreateGesvdjInfo(...) { // should always success as rocSOLVER does not need it return rocblas_status_success; } cusolverStatus_t cusolverDnDestroyGesvdjInfo(...) { // should always success as rocSOLVER does not need it return rocblas_status_success; } cusolverStatus_t cusolverDnSgesvdjBatched_bufferSize( cusolverDnHandle_t handle, cusolverEigMode_t jobz, int m, int n, const float *A, int lda, const float *S, const float *U, int ldu, const float *V, int ldv, int *lwork, gesvdjInfo_t params, int batchSize) { // rocSOLVER does not need extra workspace, but it needs to allocate memory for storing // the bidiagonal matrix B associated with A, which we don't need, so we use this workspace // to store it *lwork = batchSize * (m(A), lda, S, m(A), lda, S, m(A), lda, S, m(U), ldu, stU, reinterpret_cast(V), ldv, stV, // since we can't pass in another array through the API, and work is unused, // we use it to store the temporary E array, to be discarded after calculation reinterpret_cast(work), (m(A), lda, S, m(U), ldu, stU, reinterpret_cast(V), ldv, stV, // since we can't pass in another array through the API, and work is unused, // we use it to store the temporary E array, to be discarded after calculation reinterpret_cast(work), (m(A), lda, D, E, reinterpret_cast(TAUQ), reinterpret_cast(TAUP)); #endif } cusolverStatus_t cusolverDnZgebrd(cusolverDnHandle_t handle, int m, int n, cuDoubleComplex *A, int lda, double *D, double *E, cuDoubleComplex *TAUQ, cuDoubleComplex *TAUP, cuDoubleComplex *Work, int Lwork, int *devInfo) { #if HIP_VERSION < 306 return rocblas_status_not_implemented; #else // ignore work, lwork and devinfo as rocSOLVER does not need them return rocsolver_zgebrd(handle, m, n, reinterpret_cast(A), lda, D, E, reinterpret_cast(TAUQ), reinterpret_cast(TAUP)); #endif } /* ---------- syevj ---------- */ typedef void* syevjInfo_t; #if HIP_VERSION >= 402 static rocblas_evect convert_rocblas_evect(cusolverEigMode_t mode) { switch(mode) { // as of ROCm 4.2.0 rocblas_evect_tridiagonal is not supported case 0 /* CUSOLVER_EIG_MODE_NOVECTOR */: return rocblas_evect_none; case 1 /* CUSOLVER_EIG_MODE_VECTOR */ : return rocblas_evect_original; default: throw std::runtime_error("unrecognized mode"); } } #endif cusolverStatus_t cusolverDnCreateSyevjInfo(syevjInfo_t *info) { // TODO(leofang): set info to NULL? We don't use it anyway... return rocblas_status_success; } cusolverStatus_t cusolverDnDestroySyevjInfo(syevjInfo_t info) { return rocblas_status_success; } cusolverStatus_t cusolverDnSsyevj_bufferSize(cusolverDnHandle_t handle, cusolverEigMode_t jobz, cublasFillMode_t uplo, int n, const float *A, int lda, const float *W, int *lwork, syevjInfo_t params) { // rocSOLVER does not need extra workspace, but it needs to allocate memory for storing // the tridiagonal matrix T associated with A, which we don't need, so we use this workspace // to store it *lwork = n; // note: counts, not bytes! return rocblas_status_success; } cusolverStatus_t cusolverDnDsyevj_bufferSize(cusolverDnHandle_t handle, cusolverEigMode_t jobz, cublasFillMode_t uplo, int n, const double *A, int lda, const double *W, int *lwork, syevjInfo_t params) { // rocSOLVER does not need extra workspace, but it needs to allocate memory for storing // the tridiagonal matrix T associated with A, which we don't need, so we use this workspace // to store it *lwork = n; // note: counts, not bytes! return rocblas_status_success; } cusolverStatus_t cusolverDnCheevj_bufferSize(cusolverDnHandle_t handle, cusolverEigMode_t jobz, cublasFillMode_t uplo, int n, const cuComplex *A, int lda, const float *W, int *lwork, syevjInfo_t params) { // rocSOLVER does not need extra workspace, but it needs to allocate memory for storing // the tridiagonal matrix T associated with A, which we don't need, so we use this workspace // to store it *lwork = n; // note: counts, not bytes! return rocblas_status_success; } cusolverStatus_t cusolverDnZheevj_bufferSize(cusolverDnHandle_t handle, cusolverEigMode_t jobz, cublasFillMode_t uplo, int n, const cuDoubleComplex *A, int lda, const double *W, int *lwork, syevjInfo_t params) { // rocSOLVER does not need extra workspace, but it needs to allocate memory for storing // the tridiagonal matrix T associated with A, which we don't need, so we use this workspace // to store it *lwork = n; // note: counts, not bytes! return rocblas_status_success; } cusolverStatus_t cusolverDnSsyevj(cusolverDnHandle_t handle, cusolverEigMode_t jobz, cublasFillMode_t uplo, int n, float *A, int lda, float *W, float *work, int lwork, int *info, syevjInfo_t params) { #if HIP_VERSION < 402 return rocblas_status_not_implemented; #else return rocsolver_ssyev(handle, convert_rocblas_evect(jobz), convert_rocblas_fill(uplo), n, A, lda, W, // since we can't pass in another array through the API, and work is unused, // we use it to store the temporary E array, to be discarded after calculation work, info); #endif } cusolverStatus_t cusolverDnDsyevj(cusolverDnHandle_t handle, cusolverEigMode_t jobz, cublasFillMode_t uplo, int n, double *A, int lda, double *W, double *work, int lwork, int *info, syevjInfo_t params) { #if HIP_VERSION < 402 return rocblas_status_not_implemented; #else return rocsolver_dsyev(handle, convert_rocblas_evect(jobz), convert_rocblas_fill(uplo), n, A, lda, W, // since we can't pass in another array through the API, and work is unused, // we use it to store the temporary E array, to be discarded after calculation work, info); #endif } cusolverStatus_t cusolverDnCheevj(cusolverDnHandle_t handle, cusolverEigMode_t jobz, cublasFillMode_t uplo, int n, cuComplex *A, int lda, float *W, cuComplex *work, int lwork, int *info, syevjInfo_t params) { #if HIP_VERSION < 402 return rocblas_status_not_implemented; #else return rocsolver_cheev(handle, convert_rocblas_evect(jobz), convert_rocblas_fill(uplo), n, reinterpret_cast(A), lda, W, // since we can't pass in another array through the API, and work is unused, // we use it to store the temporary E array, to be discarded after calculation reinterpret_cast(work), info); #endif } cusolverStatus_t cusolverDnZheevj(cusolverDnHandle_t handle, cusolverEigMode_t jobz, cublasFillMode_t uplo, int n, cuDoubleComplex *A, int lda, double *W, cuDoubleComplex *work, int lwork, int *info, syevjInfo_t params) { #if HIP_VERSION < 402 return rocblas_status_not_implemented; #else return rocsolver_zheev(handle, convert_rocblas_evect(jobz), convert_rocblas_fill(uplo), n, reinterpret_cast(A), lda, W, // since we can't pass in another array through the API, and work is unused, // we use it to store the temporary E array, to be discarded after calculation reinterpret_cast(work), info); #endif } /* ---------- batched syevj ---------- */ cusolverStatus_t cusolverDnSsyevjBatched_bufferSize(cusolverDnHandle_t handle, cusolverEigMode_t jobz, cublasFillMode_t uplo, int n, const float *A, int lda, const float *W, int *lwork, syevjInfo_t params, int batchSize) { // rocSOLVER does not need extra workspace, but it needs to allocate memory for storing // the tridiagonal matrix T associated with A, which we don't need, so we use this workspace // to store it *lwork = batchSize * n; // note: counts, not bytes! return rocblas_status_success; } cusolverStatus_t cusolverDnDsyevjBatched_bufferSize(cusolverDnHandle_t handle, cusolverEigMode_t jobz, cublasFillMode_t uplo, int n, const double *A, int lda, const double *W, int *lwork, syevjInfo_t params, int batchSize) { // rocSOLVER does not need extra workspace, but it needs to allocate memory for storing // the tridiagonal matrix T associated with A, which we don't need, so we use this workspace // to store it *lwork = batchSize * n; // note: counts, not bytes! return rocblas_status_success; } cusolverStatus_t cusolverDnCheevjBatched_bufferSize(cusolverDnHandle_t handle, cusolverEigMode_t jobz, cublasFillMode_t uplo, int n, const cuComplex *A, int lda, const float *W, int *lwork, syevjInfo_t params, int batchSize) { // rocSOLVER does not need extra workspace, but it needs to allocate memory for storing // the tridiagonal matrix T associated with A, which we don't need, so we use this workspace // to store it *lwork = batchSize * n; // note: counts, not bytes! return rocblas_status_success; } cusolverStatus_t cusolverDnZheevjBatched_bufferSize(cusolverDnHandle_t handle, cusolverEigMode_t jobz, cublasFillMode_t uplo, int n, const cuDoubleComplex *A, int lda, const double *W, int *lwork, syevjInfo_t params, int batchSize) { // rocSOLVER does not need extra workspace, but it needs to allocate memory for storing // the tridiagonal matrix T associated with A, which we don't need, so we use this workspace // to store it *lwork = batchSize * n; // note: counts, not bytes! return rocblas_status_success; } cusolverStatus_t cusolverDnSsyevjBatched(cusolverDnHandle_t handle, cusolverEigMode_t jobz, cublasFillMode_t uplo, int n, float *A, int lda, float *W, float *work, int lwork, int *info, syevjInfo_t params, int batchSize) { #if HIP_VERSION < 402 return rocblas_status_not_implemented; #else return rocsolver_ssyev_batched(handle, convert_rocblas_evect(jobz), convert_rocblas_fill(uplo), n, reinterpret_cast(A), lda, W, n, // since we can't pass in another array through the API, and work is unused, // we use it to store the temporary E array, to be discarded after calculation work, n, info, batchSize); #endif } cusolverStatus_t cusolverDnDsyevjBatched(cusolverDnHandle_t handle, cusolverEigMode_t jobz, cublasFillMode_t uplo, int n, double *A, int lda, double *W, double *work, int lwork, int *info, syevjInfo_t params, int batchSize) { #if HIP_VERSION < 402 return rocblas_status_not_implemented; #else return rocsolver_dsyev_batched(handle, convert_rocblas_evect(jobz), convert_rocblas_fill(uplo), n, reinterpret_cast(A), lda, W, n, // since we can't pass in another array through the API, and work is unused, // we use it to store the temporary E array, to be discarded after calculation work, n, info, batchSize); #endif } cusolverStatus_t cusolverDnCheevjBatched(cusolverDnHandle_t handle, cusolverEigMode_t jobz, cublasFillMode_t uplo, int n, cuComplex *A, int lda, float *W, cuComplex *work, int lwork, int *info, syevjInfo_t params, int batchSize) { #if HIP_VERSION < 402 return rocblas_status_not_implemented; #else return rocsolver_cheev_batched(handle, convert_rocblas_evect(jobz), convert_rocblas_fill(uplo), n, reinterpret_cast(A), lda, W, n, // since we can't pass in another array through the API, and work is unused, // we use it to store the temporary E array, to be discarded after calculation reinterpret_cast(work), n, info, batchSize); #endif } cusolverStatus_t cusolverDnZheevjBatched(cusolverDnHandle_t handle, cusolverEigMode_t jobz, cublasFillMode_t uplo, int n, cuDoubleComplex *A, int lda, double *W, cuDoubleComplex *work, int lwork, int *info, syevjInfo_t params, int batchSize) { #if HIP_VERSION < 402 return rocblas_status_not_implemented; #else return rocsolver_zheev_batched(handle, convert_rocblas_evect(jobz), convert_rocblas_fill(uplo), n, reinterpret_cast(A), lda, W, n, // since we can't pass in another array through the API, and work is unused, // we use it to store the temporary E array, to be discarded after calculation reinterpret_cast(work), n, info, batchSize); #endif } /* all of the stubs below are unsupported functions; the supported ones are moved to above */ typedef enum{} cusolverEigType_t; typedef void* cusolverSpHandle_t; typedef void* cusparseMatDescr_t; cusolverStatus_t cusolverSpGetStream(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverSpSetStream(...) { return rocblas_status_not_implemented; } /* ---------- potrs ---------- */ cusolverStatus_t cusolverDnSpotrs(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnDpotrs(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnCpotrs(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnZpotrs(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnSpotrsBatched(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnDpotrsBatched(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnCpotrsBatched(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnZpotrsBatched(...) { return rocblas_status_not_implemented; } /* ---------- sytrf ---------- */ cusolverStatus_t cusolverDnSsytrf_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnDsytrf_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnCsytrf_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnZsytrf_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnSsytrf(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnDsytrf(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnCsytrf(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnZsytrf(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnXgesvdjSetTolerance(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnXgesvdjSetMaxSweeps(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnXgesvdjSetSortEig(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnXgesvdjGetResidual(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnXgesvdjGetSweeps(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnSgesvdj_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnDgesvdj_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnCgesvdj_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnZgesvdj_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnSgesvdj(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnDgesvdj(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnCgesvdj(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnZgesvdj(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnSgesvdaStridedBatched_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnDgesvdaStridedBatched_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnCgesvdaStridedBatched_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnZgesvdaStridedBatched_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnSgesvdaStridedBatched(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnDgesvdaStridedBatched(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnCgesvdaStridedBatched(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnZgesvdaStridedBatched(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnZZgels_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnZCgels_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnZYgels_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnZKgels_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnCCgels_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnCYgels_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnCKgels_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnDDgels_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnDSgels_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnDXgels_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnDHgels_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnSSgels_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnSXgels_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnSHgels_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnZZgels(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnZCgels(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnZYgels(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnZKgels(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnCCgels(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnCYgels(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnCKgels(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnDDgels(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnDSgels(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnDXgels(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnDHgels(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnSSgels(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnSXgels(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnSHgels(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnSsyevd_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnDsyevd_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnCheevd_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnZheevd_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnSsyevd(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnDsyevd(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnCheevd(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnZheevd(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnXsyevjSetTolerance(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnXsyevjSetMaxSweeps(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnXsyevjSetSortEig(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnXsyevjGetResidual(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnXsyevjGetSweeps(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnZZgesv_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnZCgesv_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnZYgesv_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnZKgesv_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnCCgesv_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnCYgesv_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnCKgesv_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnDDgesv_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnDSgesv_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnDXgesv_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnDHgesv_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnSSgesv_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnSXgesv_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnSHgesv_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnZZgesv(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnZCgesv(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnZYgesv(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnZKgesv(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnCCgesv(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnCYgesv(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnCKgesv(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnDDgesv(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnDSgesv(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnDXgesv(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnDHgesv(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnSSgesv(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnSXgesv(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnSHgesv(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnXsyevd_bufferSize(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverDnXsyevd(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverSpCreate(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverSpDestroy(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverSpScsrlsvqr(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverSpDcsrlsvqr(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverSpCcsrlsvqr(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverSpZcsrlsvqr(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverSpScsrlsvchol(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverSpDcsrlsvchol(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverSpCcsrlsvchol(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverSpZcsrlsvchol(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverSpScsreigvsi(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverSpDcsreigvsi(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverSpCcsreigvsi(...) { return rocblas_status_not_implemented; } cusolverStatus_t cusolverSpZcsreigvsi(...) { return rocblas_status_not_implemented; } } // extern "C" #endif // #ifdef INCLUDE_GUARD_HIP_CUPY_ROCSOLVER_H