Search code examples
c++lapackblas

Are there native C++ (not C) interfaces for Blas and Lapack libraries?


Currently, there are:

  • cblas which is shipped with blas,
  • lapacke which is shipped with lapack,

however, these are C interfaces.

Obviously, you can use them in a C++ code, but you do not get all the benefits you would get if these interfaces were designed for C++. So my question is: are such interfaces exist in native C++?


Solution

  • Recently these two interfaces, from University of Tennessee, has been released:

    There are some immediate benefits of using these native C++ implementations.

    Let's consider a basic generic programming example:

    Imagine that you want to scale a vector: v = alpha*v thanks to the cblas_?scal functions.

    With cblas, if you wanted something "generic" in the sense that it has the same interface for all supported scalar types (float, double, complex<float>, complex<double>,...), all the C functions had to be wrapped:

    void scal(cblas_int n,float alpha, float *x, cblas_int inc) {
        ...
        cblas_sscal(n,alpha,x,inc);  <- s for float
    }
    
    void scal(cblas_int n,double alpha, double *x, cblas_int inc) {
        ...
        cblas_dscal(n,alpha,x,inc);  <- d for double
    }
    
    // do the same for complex<float>, complex<double> ...
    

    The reason is that in C, two functions are differents if they have different names: cblas_sscal, cblas_dscal... In C++ you can have the same name scal and this is the compiler job to dispatch to the right function according to its arguments, here float, double...

    The situation now. With the mentioned https://bitbucket.org/icl/blaspp C++ native interface this boilerplate code has already been written once for all. For instance if you look scal.hh header file you have:

    void scal(int64_t n, float alpha, float *x, int64_t incx ) { ... }
    void scal(int64_t n, double alpha, double *x, int64_t incx ) { ... }
    void scal(int64_t n, std:complex<float> alpha, std:complex<float> *x, int64_t incx ) { ... }
    void scal(int64_t n, std:complex<double> alpha, std:complex<double> *x, int64_t incx ) { ... }
    

    and even a generic implementation:

    template<typename T>
    void scal(int64_t n, T alpha, T *x, int64_t incx ) { ... }
    

    Hence with this C++ interface, it is easy to define a generic interface for your favorit vector/matrix type. As example, with std::vector<T>, you only have to write (independently of the actual T type):

    template<typename T>
    void scal(T alpha, std::vector<T>& v) {
       scal(v.size(),alpha,v.data(),1);
    }
    

    No more boilerplate code!


    This is the idea, however note that:

    • generic implementation are not yet implemented for all subroutines, for instance:

    .

    template< typename TA, typename TX >
    void trmm(
        blas::Layout layout,
        blas::Side side,
        blas::Uplo uplo,
        blas::Op trans,
        blas::Diag diag,
        int64_t m,
        int64_t n,
        typename blas::traits2<TA, TX>::scalar_t alpha,
        TA const *A, int64_t lda,
        TX       *B, int64_t ldb )
    {
        throw std::exception();  // not yet implemented
    }
    
    • The previous example used blas, however, it is even more interesting for lapack which has several hundreds of wrapped subroutines.