diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 5c90cec9..e732ed5d 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -74,14 +74,12 @@ jobs: fi # install MKL if want vendor linalg if [ "${{matrix.linalg}}" = "vendor" ]; then - wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS-2019.PUB - sudo apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS-2019.PUB - rm GPG-PUB-KEY-INTEL-SW-PRODUCTS-2019.PUB - sudo sh -c 'echo deb https://apt.repos.intel.com/mkl all main > /etc/apt/sources.list.d/intel-mkl.list' - sudo apt-get update - sudo apt-get install intel-mkl-64bit-2019.4-070 + sudo sh -c 'wget -O - https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB | gpg --dearmor > /usr/share/keyrings/oneapi-archive-keyring.gpg' + sudo sh -c 'echo "deb [signed-by=/usr/share/keyrings/oneapi-archive-keyring.gpg] https://apt.repos.intel.com/oneapi all main" > /etc/apt/sources.list.d/oneAPI.list' + sudo apt-get -yq update + sudo apt-get install intel-oneapi-mkl-devel echo "BLAS_PREFERENCE_LIST=IntelMKL" >> $GITHUB_ENV - echo "MKLROOT=/opt/intel/mkl" >> $GITHUB_ENV + echo "MKLROOT=/opt/intel/oneapi/mkl/latest" >> $GITHUB_ENV else echo "BLAS_PREFERENCE_LIST=ReferenceBLAS" >> $GITHUB_ENV fi diff --git a/CMakeLists.txt b/CMakeLists.txt index 594aa2c2..a367abb9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,9 @@ cmake_minimum_required (VERSION 3.14.0) # FetchContent_MakeAvailable +# Preload versions/tags of all dependencies ==================================== +include(external/versions.cmake) + ############################################################################### # CMake defaults to address key pain points ############################################################################### @@ -24,6 +27,7 @@ FetchContent_Declare( vg_cmake_kit QUIET GIT_REPOSITORY https://github.com/ValeevGroup/kit-cmake.git + GIT_TAG ${BTAS_TRACKED_VGCMAKEKIT_TAG} SOURCE_DIR ${${VG_CMAKE_KIT_PREFIX_DIR}}/cmake/vg BINARY_DIR ${${VG_CMAKE_KIT_PREFIX_DIR}}/cmake/vg-build SUBBUILD_DIR ${${VG_CMAKE_KIT_PREFIX_DIR}}/cmake/vg-subbuild @@ -60,6 +64,7 @@ include(FeatureSummary) include(RedefaultableOption) include(CMakePackageConfigHelpers) include(AddCustomTargetSubproject) +include(CMakePushCheckState) include(CTest) # defines BUILD_TESTING option # Configure options @@ -77,28 +82,27 @@ add_feature_info("TARGET_MAX_INDEX_RANK=${TARGET_MAX_INDEX_RANK}" TRUE "default set(TARGET_ARCH "${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}") -include(CMakePushCheckState) -include(GNUInstallDirs) -include(AppendFlags) - ########################## -# Standard build variables +# INSTALL variables ########################## -set(BTAS_INSTALL_BINDIR "bin" +include(GNUInstallDirs) +set(BTAS_INSTALL_BINDIR "${CMAKE_INSTALL_BINDIR}" CACHE PATH "BTAS BIN install directory") -set(BTAS_INSTALL_INCLUDEDIR "include" +set(BTAS_INSTALL_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}" CACHE PATH "BTAS INCLUDE install directory") -set(BTAS_INSTALL_LIBDIR "lib" +set(BTAS_INSTALL_LIBDIR "${CMAKE_INSTALL_LIBDIR}" CACHE PATH "BTAS LIB install directory") -set(BTAS_INSTALL_SHAREDIR "share/BTAS/${BTAS_MAJOR_VERSION}.${BTAS_MINOR_VERSION}.${BTAS_MICRO_VERSION}" - CACHE PATH "BTAS SHARE install directory") -set(BTAS_INSTALL_DATADIR "${BTAS_INSTALL_SHAREDIR}/data" +set(BTAS_INSTALL_DATADIR "${CMAKE_INSTALL_DATAROOTDIR}/BTAS/${BTAS_EXT_VERSION}" CACHE PATH "BTAS DATA install directory") -set(BTAS_INSTALL_DOCDIR "${BTAS_INSTALL_SHAREDIR}/doc" +set(BTAS_INSTALL_DOCDIR "${BTAS_INSTALL_DATADIR}/doc" CACHE PATH "BTAS DOC install directory") -set(BTAS_INSTALL_CMAKEDIR "lib/cmake/BTAS" +set(BTAS_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/BTAS" CACHE PATH "BTAS CMAKE install directory") +########################## +# Standard build variables +########################## +include(AppendFlags) # Get standard build variables from the environment if they have not already been set if(NOT CMAKE_C_FLAGS OR NOT DEFINED CMAKE_C_FLAGS) set(CMAKE_C_FLAGS "$ENV{CPPFLAGS}") diff --git a/btas/generic/axpy_impl.h b/btas/generic/axpy_impl.h index 8eb991e8..34f4a897 100644 --- a/btas/generic/axpy_impl.h +++ b/btas/generic/axpy_impl.h @@ -52,8 +52,12 @@ template<> struct axpy_impl _IteratorY itrY, const iterator_difference_t<_IteratorY>& incY, blas_lapack_impl_tag) { - blas::axpy( Nsize, alpha, static_cast(&(*itrX)), incX, - static_cast<_T*>(&(*itrY)), incY ); + static_assert(std::is_same_v,iterator_value_t<_IteratorY>>, + "mismatching iterator value types"); + using T = iterator_value_t<_IteratorX>; + + blas::axpy( Nsize, static_cast(alpha), static_cast(&(*itrX)), incX, + static_cast(&(*itrY)), incY ); } #endif diff --git a/btas/generic/dot_impl.h b/btas/generic/dot_impl.h index e23186f9..8d84b6e0 100644 --- a/btas/generic/dot_impl.h +++ b/btas/generic/dot_impl.h @@ -110,19 +110,13 @@ struct dotc_impl { _IteratorY itrY, const iterator_difference_t<_IteratorY>& incY, blas_lapack_impl_tag) { - - using x_traits = std::iterator_traits<_IteratorX>; - using y_traits = std::iterator_traits<_IteratorY>; - - using x_value_type = typename x_traits::value_type; - using y_value_type = typename y_traits::value_type; - - using x_ptr_type = const x_value_type*; - using y_ptr_type = const y_value_type*; + static_assert(std::is_same_v,iterator_value_t<_IteratorY>>, + "mismatching iterator value types"); + using T = iterator_value_t<_IteratorX>; // XXX: DOTC == DOT in BLASPP - return blas::dot( Nsize, static_cast(&(*itrX)), incX, - static_cast(&(*itrY)), incY ); + return blas::dot( Nsize, static_cast(&(*itrX)), incX, + static_cast(&(*itrY)), incY ); } #endif @@ -172,17 +166,12 @@ struct dotu_impl { blas_lapack_impl_tag) { - using x_traits = std::iterator_traits<_IteratorX>; - using y_traits = std::iterator_traits<_IteratorY>; - - using x_value_type = typename x_traits::value_type; - using y_value_type = typename y_traits::value_type; - - using x_ptr_type = const x_value_type*; - using y_ptr_type = const y_value_type*; + static_assert(std::is_same_v,iterator_value_t<_IteratorY>>, + "mismatching iterator value types"); + using T = iterator_value_t<_IteratorX>; - return blas::dotu( Nsize, static_cast(&(*itrX)), incX, - static_cast(&(*itrY)), incY ); + return blas::dotu( Nsize, static_cast(&(*itrX)), incX, + static_cast(&(*itrY)), incY ); } #endif diff --git a/btas/generic/gemm_impl.h b/btas/generic/gemm_impl.h index d939083c..da7f10fc 100644 --- a/btas/generic/gemm_impl.h +++ b/btas/generic/gemm_impl.h @@ -252,24 +252,16 @@ template<> struct gemm_impl const unsigned long& LDC, blas_lapack_impl_tag) { - - using a_traits = std::iterator_traits<_IteratorA>; - using b_traits = std::iterator_traits<_IteratorB>; - using c_traits = std::iterator_traits<_IteratorC>; - - using a_value_type = typename a_traits::value_type; - using b_value_type = typename b_traits::value_type; - using c_value_type = typename c_traits::value_type; - - using a_ptr_type = const a_value_type*; - using b_ptr_type = const b_value_type*; - using c_ptr_type = c_value_type*; - - blas::gemm( order, transA, transB, Msize, Nsize, Ksize, alpha, - static_cast(&(*itrA)), LDA, - static_cast(&(*itrB)), LDB, - beta, - static_cast(&(*itrC)), LDC ); + static_assert(std::is_same_v,iterator_value_t<_IteratorB>> && + std::is_same_v,iterator_value_t<_IteratorC>>, + "mismatching iterator value types"); + using T = iterator_value_t<_IteratorA>; + + blas::gemm( order, transA, transB, Msize, Nsize, Ksize, static_cast(alpha), + static_cast(&(*itrA)), LDA, + static_cast(&(*itrB)), LDB, + static_cast(beta), + static_cast(&(*itrC)), LDC ); } #endif diff --git a/btas/generic/gemv_impl.h b/btas/generic/gemv_impl.h index aeadf415..0414d4e6 100644 --- a/btas/generic/gemv_impl.h +++ b/btas/generic/gemv_impl.h @@ -151,11 +151,16 @@ template<> struct gemv_impl blas_lapack_impl_tag) { - blas::gemv( order, transA, Msize, Nsize, alpha, - static_cast(&(*itrA)), LDA, - static_cast(&(*itrX)), incX, - beta, - static_cast< _T*>(&(*itrY)), incY ); + static_assert(std::is_same_v,iterator_value_t<_IteratorY>> && + std::is_same_v,iterator_value_t<_IteratorA>>, + "mismatching iterator value types"); + using T = iterator_value_t<_IteratorX>; + + blas::gemv( order, transA, Msize, Nsize, static_cast(alpha), + static_cast(&(*itrA)), LDA, + static_cast(&(*itrX)), incX, + static_cast(beta), + static_cast< T*>(&(*itrY)), incY ); } #endif diff --git a/btas/generic/ger_impl.h b/btas/generic/ger_impl.h index 88f9cda1..3a747c67 100644 --- a/btas/generic/ger_impl.h +++ b/btas/generic/ger_impl.h @@ -79,11 +79,15 @@ template<> struct ger_impl const unsigned long& LDA, blas_lapack_impl_tag) { - - blas::geru( order, Msize, Nsize, alpha, - static_cast(&(*itrX)), incX, - static_cast(&(*itrY)), incY, - static_cast< _T*>(&*(itrA)), LDA ); + static_assert(std::is_same_v,iterator_value_t<_IteratorY>> && + std::is_same_v,iterator_value_t<_IteratorA>>, + "mismatching iterator value types"); + using T = iterator_value_t<_IteratorX>; + + blas::geru( order, Msize, Nsize, static_cast(alpha), + static_cast(&(*itrX)), incX, + static_cast(&(*itrY)), incY, + static_cast< T*>(&*(itrA)), LDA ); } #endif diff --git a/btas/generic/gesvd_impl.h b/btas/generic/gesvd_impl.h index 5f026cce..0e821956 100644 --- a/btas/generic/gesvd_impl.h +++ b/btas/generic/gesvd_impl.h @@ -73,8 +73,6 @@ template<> struct gesvd_impl if( inplaceU and inplaceVt ) BTAS_EXCEPTION("SVD cannot return both vectors inplace"); - - value_type dummy; value_type* A = static_cast(&(*itrA)); value_type* U = (needU and not inplaceU) ? diff --git a/btas/generic/scal_impl.h b/btas/generic/scal_impl.h index 0f1cbc73..f184f7a9 100644 --- a/btas/generic/scal_impl.h +++ b/btas/generic/scal_impl.h @@ -44,7 +44,8 @@ template<> struct scal_impl _IteratorX itrX, const iterator_difference_t<_IteratorX>& incX, blas_lapack_impl_tag) { - blas::scal( Nsize, alpha, static_cast<_T*>(&(*itrX)), incX ); + using T = iterator_value_t<_IteratorX>; + blas::scal( Nsize, static_cast(alpha), static_cast(&(*itrX)), incX ); } #endif diff --git a/btas/type_traits.h b/btas/type_traits.h index af073bd8..af466612 100644 --- a/btas/type_traits.h +++ b/btas/type_traits.h @@ -275,6 +275,9 @@ namespace btas { // Convienience traits template + using iterator_value_t = + typename std::iterator_traits<_Iterator>::value_type; + template using iterator_difference_t = typename std::iterator_traits<_Iterator>::difference_type; diff --git a/external/boost.cmake b/external/boost.cmake index 4dcf0605..9570bb53 100644 --- a/external/boost.cmake +++ b/external/boost.cmake @@ -21,9 +21,9 @@ if (NOT TARGET Boost::boost OR NOT TARGET Boost::serialization) # try config first # OPTIONAL_COMPONENTS in FindBoost available since 3.11 cmake_minimum_required(VERSION 3.11.0) - find_package(Boost CONFIG OPTIONAL_COMPONENTS ${Boost_BTAS_DEPS_LIBRARIES}) + find_package(Boost ${BTAS_TRACKED_BOOST_VERSION} CONFIG OPTIONAL_COMPONENTS ${Boost_BTAS_DEPS_LIBRARIES}) if (NOT TARGET Boost::boost) - find_package(Boost OPTIONAL_COMPONENTS ${Boost_BTAS_DEPS_LIBRARIES}) + find_package(Boost ${BTAS_TRACKED_BOOST_VERSION} OPTIONAL_COMPONENTS ${Boost_BTAS_DEPS_LIBRARIES}) if (TARGET Boost::boost) set(Boost_USE_CONFIG FALSE) endif(TARGET Boost::boost) diff --git a/external/versions.cmake b/external/versions.cmake new file mode 100644 index 00000000..2c955352 --- /dev/null +++ b/external/versions.cmake @@ -0,0 +1,7 @@ +set(BTAS_TRACKED_VGCMAKEKIT_TAG d6746098e63deab4032309c4455bb084a17ff51a) + +# likely can use earlier, but +# - as of oct 2023 tested with 1.71 and up only +# - avoids the need to avoid 1.70 in which Boost.Container is broken +# - matches the version provided by https://github.com/Orphis/boost-cmake as of oct 2023 +set(BTAS_TRACKED_BOOST_VERSION 1.71) diff --git a/unittest/tensor_blas_test.cc b/unittest/tensor_blas_test.cc index 2e7d5fff..74113f6f 100644 --- a/unittest/tensor_blas_test.cc +++ b/unittest/tensor_blas_test.cc @@ -112,7 +112,7 @@ TEST_CASE("Tensor Scal") Tensor T(4,2,6,5); T.generate([](){ return randomReal(); }); Tensor Tbak=T; - double d = randomReal(); + const auto d = randomReal(); // N.B. use different types for scalar and tensor scal(d,T); double res=0; for(auto i : T.range()) res+=std::abs(T(i)-Tbak(i)*d); @@ -136,10 +136,11 @@ TEST_CASE("Tensor Scal") Tensor> T(4,2,6,5); T.generate([](){ return randomCplx(); }); Tensor> Tbak=T; - std::complex d = randomCplx(); + const auto d = randomCplx(); // N.B. use different types for scalar and tensor scal(d,T); double res=0; - for(auto i : T.range()) res+=std::abs(T(i)-Tbak(i)*d); + std::complex d_double(d); + for(auto i : T.range()) res+=std::abs(T(i)-Tbak(i)*d_double); CHECK(res < eps_double); } @@ -166,7 +167,7 @@ TEST_CASE("Tensor Axpy") X.generate([](){ return randomReal(); }); Y.generate([](){ return randomReal(); }); Tensor Ybak=Y; - double alpha = randomReal(); + const auto alpha = randomReal(); // N.B. use different types for scalar and tensor axpy(alpha,X,Y); double res=0; for(auto i : Y.range()) res+=std::abs(Ybak(i)+X(i)*alpha-Y(i)); @@ -228,7 +229,7 @@ TEST_CASE("Tensor Ger") X.generate([](){ return randomReal(); }); Y.generate([](){ return randomReal(); }); Tensor Abak=A; - double a = randomReal(); + const auto a = randomReal(); // N.B. use different types for scalar and tensor ger(a,X,Y,A); double res=0; for(auto i : A.range()) res+=std::abs(a*X(i[0],i[1])*Y(i[2],i[3])+Abak(i)-A(i)); @@ -296,8 +297,8 @@ TEST_CASE("Tensor Gemv") A.generate([](){ return randomReal(); }); X.generate([](){ return randomReal(); }); Y.generate([](){ return randomReal(); }); - double alpha = randomReal(); - double beta = randomReal(); + const auto alpha = randomReal(); // N.B. use different types for scalar and tensor + const auto beta = randomReal(); // N.B. use different types for scalar and tensor Tensor Ytest=Y; scal(beta,Ytest); for(long i=0;i(); }); B.generate([](){ return randomReal(); }); C.generate([](){ return randomReal(); }); - double alpha = randomReal(); - double beta = randomReal(); + const auto alpha = randomReal(); // N.B. use different types for scalar and tensor + const auto beta = randomReal(); // N.B. use different types for scalar and tensor Ctest=C; scal(beta,Ctest); contract(alpha,A,{'i','j','k'},B,{'k','j','l','m'},beta,C,{'i','m','l'}); @@ -700,7 +701,7 @@ TEST_CASE("Contraction") Tensor D; Tensor Dtest(2,4,6); Dtest.fill(0.0); - contract(alpha,A,{'i','j','k'},B,{'k','j','l','m'},0.0,D,{'i','m','l'}); + contract(alpha,A,{'i','j','k'},B,{'k','j','l','m'},static_cast(0.0),D,{'i','m','l'}); for(long i=0;i