/**
 * @brief Wrapper over LAPACKE functions.
 *
 * @author Yunhai Li (liyunhai1016@hotmail.com)
 *
 * @copyright Copyright (c) 2024, TBPLaS develop team.
 *
 * @note DO NOT use Eigen datatypes here in order to avoid conflicts.
 */
#ifdef WITH_LAPACKE
#ifndef TBPLAS_DIAG_LAPACKE_WRAPPER_H
#define TBPLAS_DIAG_LAPACKE_WRAPPER_H

// LAPACKE header handles C++ well, no need to wrap with extern "C"
#ifdef DIAG_USE_MKL
#include <mkl_lapacke.h>
#else
#include <lapacke.h>
#endif

// Treated as C to avoid name mangling
extern "C" {

/**
 * @brief Solving H*x = \lambda*E*x
 * 
 * @param[in] num_orb number of orbitals, dimension of H
 * @param[in] hk Hamiltonian, matrix H
 * @param[inout] eigenvalues dimension (num_orb)
 * @param[inout] eigenvectors dimension (num_orb, num_orb)
 * @param[in] calc_eigenvectors whether to calculate eigenvectors
 */
void lapacke_zheev_wrapper(
    lapack_int num_orb,
    lapack_complex_double* hk,
    double* eigenvalues,
    lapack_complex_double* eigenvectors,
    bool calc_eigenvectors = false);

/**
 * @brief Solving H*x = \lambda*S*x
 * 
 * @param[in] num_orb number of orbitals, dimension of H and S
 * @param[in] hk Hamiltonian, matrix H
 * @param[in] sk overlap, matrix S
 * @param[inout] eigenvalues dimension (num_orb)
 * @param[inout] eigenvectors dimension (num_orb, num_orb)
 * @param[in] calc_eigenvectors whether to calculate eigenvectors
 */
void lapacke_zhegv_wrapper(
    lapack_int num_orb,
    lapack_complex_double* hk,
    lapack_complex_double* sk,
    double* eigenvalues,
    lapack_complex_double* eigenvectors,
    bool calc_eigenvectors = false);

/**
 * @brief Solving A*x = \lambda*E*x.
 * 
 * @param[in] num_orb number of orbitals, dimension of A
 * @param[in] dk matrix A
 * @param[inout] eigenvalues dimension (num_orb)
 */
void lapacke_zgeev_wrapper(
    lapack_int num_orb,
    lapack_complex_double* dk,
    lapack_complex_double* eigenvalues);

} // extern "C"
#endif // TBPLAS_DIAG_LAPACKE_WRAPPER_H
#endif // WITH_LAPACKE