Skip to content

Commit

Permalink
compile against OpenBLAS or MKL
Browse files Browse the repository at this point in the history
  • Loading branch information
Patataman committed May 30, 2023
1 parent 79d05aa commit f1bd469
Show file tree
Hide file tree
Showing 5 changed files with 246 additions and 12 deletions.
5 changes: 4 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,10 @@ else()
set(BLA_VENDOR "Apple")
else()
message(STATUS "Looking for OpenBLAS library...")
if(NOT BLA_VENDOR)
if(MKL)
set(BLA_VENDOR "Intel10_64ilp")
add_compile_definitions(MKL)
elseif(NOT BLA_VENDOR)
set(BLA_VENDOR "OpenBLAS")
endif()
endif()
Expand Down
43 changes: 42 additions & 1 deletion src/framework/lapack_protos.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,46 @@
#include <vector>
#include <array>

#ifdef MKL
#define MKL_Complex16 std::complex<double>
#define MKL_Complex8 std::complex<float>
#define LAPACK_INT size_t
#include <mkl.h>

void zgesvd_(const char *jobu, const char *jobvt, const size_t *m,
const size_t *n, std::complex<double> *a, const size_t *lda,
double *s, std::complex<double> *u,
const size_t *ldu, std::complex<double> *vt,
const size_t *ldvt, std::complex<double> *work,
const size_t *lwork, double *rwork, int *info);

void zgesvd_(const char *jobu, const char *jobvt, const size_t *m,
const size_t *n, std::complex<double> *a, const size_t *lda,
double *s, std::complex<double> *u,
const size_t *ldu, std::complex<double> *vt,
const size_t *ldvt, std::complex<double> *work,
const size_t *lwork, double *rwork, int *info)
{
*info = LAPACKE_zgesvd(CblasColMajor, *jobu, *jobvt, *m, *n, a, *lda, s, u, *ldu, vt, *ldvt, rwork);
}

void zgesdd_(const char *jobu, const size_t *m, const size_t *n,
std::complex<double> *a, const size_t *lda, double *s,
std::complex<double> *u, const size_t *ldu, std::complex<double> *vt,
const size_t *ldvt, std::complex<double> *work,
const size_t *lwork, double *rwork, int *iwork, int *info);

void zgesdd_(const char *jobu, const size_t *m, const size_t *n,
std::complex<double> *a, const size_t *lda, double *s,
std::complex<double> *u, const size_t *ldu, std::complex<double> *vt,
const size_t *ldvt, std::complex<double> *work,
const size_t *lwork, double *rwork, int *iwork, int *info)
{
*info = LAPACKE_zgesdd(CblasColMajor, *jobu, *m, *n, a, *lda, s, u, *ldu, vt, *ldvt);
}

#else

#ifdef __cplusplus
extern "C" {
#endif
Expand All @@ -28,9 +68,10 @@ void zgesdd_(const char *jobz, const size_t *m, const size_t *n,
std::complex<double> *u, const size_t *ldu, std::complex<double> *vt,
const size_t *ldvt, std::complex<double> *work,
const size_t *lwork, double *rwork, int *iwork, int *info);

#ifdef __cplusplus
}
#endif

#endif // MKL or not

#endif // end __lapack_protos_h_
32 changes: 23 additions & 9 deletions src/framework/linalg/eigensystem.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@
#ifndef _aer_framework_linalg_eigensystem_hpp_
#define _aer_framework_linalg_eigensystem_hpp_

#include "framework/blas_protos.hpp"
#ifdef MKL
#include "framework/mklblas_protos.hpp"
#else
#include "framework/blas_protos.hpp"
#endif
#include "framework/matrix.hpp"
#include <type_traits>

Expand Down Expand Up @@ -67,25 +71,35 @@ void eigensystem_hermitian(const matrix<std::complex<T>> &hermitian_matrix,
throw std::runtime_error("Input matrix in eigensystem_hermitian "
"function is not a square matrix.");
}
#ifdef MKL
size_t n = static_cast<int>(hermitian_matrix.GetLD());
size_t ldz{n}, lda{n}, lwork{2 * n};
size_t il{0}, iu{0}; // not referenced if range='A'
size_t m{0}; // number of eigenvalues found
size_t info{0};
auto iwork = std::vector<size_t>(5 * n, 0);
auto ifail = std::vector<size_t>(n, 0);
#else
int n = static_cast<int>(hermitian_matrix.GetLD());
int ldz{n}, lda{n}, lwork{2 * n};
int il{0}, iu{0}; // not referenced if range='A'
int m{0}; // number of eigenvalues found
int info{0};
auto iwork = std::vector<int>(5 * n, 0);
auto ifail = std::vector<int>(n, 0);
#endif

int n = static_cast<int>(hermitian_matrix.GetLD());
int ldz{n}, lda{n}, lwork{2 * n};
int il{0}, iu{0}; // not referenced if range='A'
T vl{0.0}, vu{0.0}; // not referenced if range='A'
char cmach{'S'};
T abstol{static_cast<T>(2.0 * HeevxFuncs<T>::lamch(&cmach))};
int m{0}; // number of eigenvalues found
int info{0};

eigenvectors.resize(ldz, n);
eigenvalues.clear();
eigenvalues.resize(n);
matrix<std::complex<T>> heevx_copy{hermitian_matrix};
auto work = std::vector<std::complex<T>>(lwork, {0.0, 0.0});
auto rwork = std::vector<T>(7 * n, 0.0);
auto iwork = std::vector<int>(5 * n, 0);
auto ifail = std::vector<int>(n, 0);


HeevxFuncs<T>::heevx(&AerBlas::Jobz[0], &AerBlas::Range[0], &AerBlas::UpLo[0],
&n, heevx_copy.data(), &lda, &vl, &vu, &il, &iu, &abstol,
&m, eigenvalues.data(), eigenvectors.data(), &ldz,
Expand Down
6 changes: 5 additions & 1 deletion src/framework/matrix.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,11 @@ Multiplication is done with the C wrapper of the fortran blas library.
#include <iostream>
#include <vector>

#include "framework/blas_protos.hpp"
#ifdef MKL
#include "framework/mklblas_protos.hpp"
#else
#include "framework/blas_protos.hpp"
#endif
#include "framework/linalg/enable_if_numeric.hpp"

/*******************************************************************************
Expand Down
172 changes: 172 additions & 0 deletions src/framework/mklblas_protos.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
/**
* This code is part of Qiskit.
*
* (C) Copyright IBM 2018, 2019, 2020.
*
* This code is licensed under the Apache License, Version 2.0. You may
* obtain a copy of this license in the LICENSE.txt file in the root directory
* of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
*
* Any modifications or derivative works of this code must retain this
* copyright notice, and modified files need to carry a notice indicating
* that they have been altered from the originals.
*/

// Dependencies: BLAS
// These are the declarations for the various high-performance matrix routines
// used by the matrix class. An openblas install is required.

#ifndef _aer_framework_blas_protos_hpp
#define _aer_framework_blas_protos_hpp

#include <array>
#include <complex>
#include <iostream>
#include <vector>

#define MKL_Complex16 std::complex<double>
#define MKL_Complex8 std::complex<float>
#define MKL_INT size_t
#include <mkl.h>

#ifdef __cplusplus
extern "C" {
#endif

//===========================================================================
// Prototypes for level 3 BLAS
//===========================================================================

// Reduces a Single-Precison Complex Hermitian matrix A to real symmetric
// tridiagonal form
// void chetrd_(char *TRANS, int *N, std::complex<float> *A, int *LDA, float *d,
// float *e, std::complex<float> *tau, std::complex<float> *work,
// int *lwork, int *info);
//
// // Reduces a Double-Precison Complex Hermitian matrix A to real symmetric
// // tridiagonal form T
// void zhetrd_(char *TRANS, int *N, std::complex<double> *A, int *LDA, double *d,
// double *e, std::complex<double> *tau, std::complex<double> *work,
// int *lwork, int *info);
//
// // Computes all eigenvalues and, optionally, eigenvectors of a
// // Single-Precison Complex symmetric positive definite tridiagonal matrix
// void cpteqr_(char *compz, int *n, float *d, float *e, std::complex<float> *z,
// int *ldz, std::complex<float> *work, int *info);
//
// // Computes all eigenvalues and, optionally, eigenvectors of a
// // Double-Precison Complex symmetric positive definite tridiagonal matrix
// void zpteqr_(char *compz, int *n, double *d, double *e, std::complex<double> *z,
// int *ldz, std::complex<double> *work, int *info);

/***********************************************************
* Function overwrite to keep the same call as in OpenBLAS *
* *********************************************************/
void sgemv_(const CBLAS_TRANSPOSE *TransA, const size_t *M, const size_t *N,
const float *alpha, const float *A, const size_t *lda,
const float *x, const size_t *incx, const float *beta, float *y,
const size_t *lincy)
{
return cblas_sgemv(CblasColMajor, *TransA, *M, *N, *alpha, A, *lda, x, *incx, *beta, y, *lincy);
}

void dgemv_(const CBLAS_TRANSPOSE *TransA, const size_t *M, const size_t *N,
const double *alpha, const double *A, const size_t *lda,
const double *x, const size_t *incx, const double *beta, double *y,
const size_t *lincy)
{
return cblas_dgemv(CblasColMajor, *TransA, *M, *N, *alpha, A, *lda, x, *incx, *beta, y, *lincy);
}

void cgemv_(const CBLAS_TRANSPOSE *TransA, const size_t *M, const size_t *N,
const std::complex<float> *alpha, const std::complex<float> *A,
const size_t *lda, const std::complex<float> *x, const size_t *incx,
const std::complex<float> *beta, std::complex<float> *y,
const size_t *lincy)
{
return cblas_cgemv(CblasColMajor, *TransA, *M, *N, alpha, A, *lda, x, *incx, beta, y, *lincy);
}

void zgemv_(const CBLAS_TRANSPOSE *TransA, const size_t *M, const size_t *N,
const std::complex<double> *alpha, const std::complex<double> *A,
const size_t *lda, const std::complex<double> *x,
const size_t *incx, const std::complex<double> *beta,
std::complex<double> *y, const size_t *lincy)
{
return cblas_zgemv(CblasColMajor, *TransA, *M, *N, alpha, A, *lda, x, *incx, beta, y, *lincy);
}

void sgemm_(const CBLAS_TRANSPOSE *TransA, const CBLAS_TRANSPOSE *TransB, const size_t *M,
const size_t *N, const size_t *K, const float *alpha,
const float *A, const size_t *lda, const float *B,
const size_t *ldb, const float *beta, float *C, size_t *ldc)
{
return cblas_sgemm(CblasColMajor, *TransA, *TransB, *M, *N, *K, *alpha, A, *lda, B, *ldb, *beta, C, *ldc);
}

void dgemm_(const CBLAS_TRANSPOSE *TransA, const CBLAS_TRANSPOSE *TransB, const size_t *M,
const size_t *N, const size_t *K, const double *alpha,
const double *A, const size_t *lda, const double *B,
const size_t *ldb, const double *beta, double *C, size_t *ldc)
{
return cblas_dgemm(CblasColMajor, *TransA, *TransB, *M, *N, *K, *alpha, A, *lda, B, *ldb, *beta, C, *ldc);
}

void cgemm_(const CBLAS_TRANSPOSE *TransA, const CBLAS_TRANSPOSE *TransB, const size_t *M,
const size_t *N, const size_t *K, const std::complex<float> *alpha,
const std::complex<float> *A, const size_t *lda,
const std::complex<float> *B, const size_t *ldb,
const std::complex<float> *beta, std::complex<float> *C,
size_t *ldc)
{
return cblas_cgemm(CblasColMajor, *TransA, *TransB, *M, *N, *K, alpha, A, *lda, B, *ldb, beta, C, *ldc);
}

void zgemm_(const CBLAS_TRANSPOSE *TransA, const CBLAS_TRANSPOSE *TransB, const size_t *M,
const size_t *N, const size_t *K, const std::complex<double> *alpha,
const std::complex<double> *A, const size_t *lda,
const std::complex<double> *B, const size_t *ldb,
const std::complex<double> *beta, std::complex<double> *C,
size_t *ldc)
{
return cblas_zgemm(CblasColMajor, *TransA, *TransB, *M, *N, *K, alpha, A, *lda, B, *ldb, beta, C, *ldc);
}

#ifdef __cplusplus
}
#endif

namespace AerBlas {

// std::array<char, 3> Trans = {'N', 'T', 'C'};
std::array<CBLAS_TRANSPOSE, 3> Trans = {CblasNoTrans, CblasTrans, CblasConjTrans};

/* Trans (input) CHARACTER*1.
On entry, TRANSA specifies the form of op( A ) to be used in the
matrix multiplication as follows:
= 'N' no transpose;
= 'T' transpose of A;
= 'C' hermitian conjugate of A.
*/
std::array<char, 2> UpLo = {'U', 'L'};
/* UpLo (input) CHARACTER*1
= 'U': Upper triangle of A is stored;
= 'L': Lower triangle of A is stored.
*/
std::array<char, 2> Jobz = {'V', 'N'};
/* Jobz (input) CHARACTER*1
= 'N': Compute eigenvalues only;
= 'V': Compute eigenvalues and eigenvectors.
*/
std::array<char, 3> Range = {'A', 'V', 'I'};
/* Range (input) CHARACTER*1
= 'A': all eigenvalues will be found.
= 'V': all eigenvalues in the half-open interval
(VL,VU] will be found.
= 'I': the IL-th through IU-th eigenvalues will
be found.
*/

} // namespace AerBlas

#endif // end _blas_protos_h_

0 comments on commit f1bd469

Please sign in to comment.