diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2339070e54..143c88f8ea 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,16 +12,26 @@ jobs: strategy: fail-fast: false matrix: - os : [ macos-latest ] - cxx : [ clang++, /opt/homebrew/bin/g++-11 ] + os : [ macos-latest, ubuntu-22.04 ] build_type : [ Release, Debug ] task_backend: [ Pthreads, PaRSEC ] - prerequisites : [ gcc@11 boost eigen open-mpi bison scalapack ] + include: + - os: ubuntu-22.04 + cc: /usr/bin/gcc-12 + cxx: /usr/bin/g++-12 + - os: macos-latest + cc: clang + cxx: clang++ name: "${{ matrix.os }}: ${{ matrix.cxx }} ${{ matrix.build_type }} ${{ matrix.task_backend }}" runs-on: ${{ matrix.os }} env: CXX : ${{ matrix.cxx }} + CCACHE_DIR : ${{github.workspace}}/build/.ccache + CCACHE_COMPRESS : true + CCACHE_COMPRESSLEVEL : 6 + OMPI_MCA_btl_vader_single_copy_mechanism : none + PARSEC_MCA_runtime_bind_threads : 0 BUILD_CONFIG : > -DMADNESS_TASK_BACKEND=${{ matrix.task_backend }} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} @@ -33,31 +43,53 @@ jobs: steps: - uses: actions/checkout@v2 - - uses: maxim-lobanov/setup-xcode@v1 - with: - xcode-version: 'latest-stable' - - name: Host system info shell: bash run: cmake -P ${{github.workspace}}/ci/host_system_info.cmake - - name: Install ${{matrix.prerequisites}} + + - name: Install prerequisite MacOS packages + if: ${{ matrix.os == 'macos-latest' }} + run: | + brew install ninja boost eigen open-mpi bison scalapack ccache + echo "MPIEXEC=/opt/homebrew/bin/mpiexec" >> $GITHUB_ENV + + - name: Install prerequisites Ubuntu packages + if: ${{ matrix.os == 'ubuntu-22.04' }} run: | - brew install ${{matrix.prerequisites}} - echo "/usr/local/opt/bison/bin" >> $GITHUB_PATH + wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | sudo tee /etc/apt/trusted.gpg.d/kitware.gpg >/dev/null + sudo apt-add-repository "deb https://apt.kitware.com/ubuntu/ $(lsb_release -cs) main" + sudo apt-get update + sudo apt-get -y install ninja-build g++-12 liblapack-dev libboost-dev libboost-serialization-dev libboost-random-dev libeigen3-dev openmpi-bin libopenmpi-dev libtbb-dev ccache flex bison libscalapack-mpi-dev cmake doxygen + sudo ln -s /usr/lib/x86_64-linux-gnu/libscalapack-openmpi.so /usr/lib/x86_64-linux-gnu/libscalapack.so + echo "MPIEXEC=/usr/bin/mpiexec" >> $GITHUB_ENV + + - name: Prepare ccache timestamp + id: ccache_cache_timestamp + shell: cmake -P {0} + run: | + string(TIMESTAMP current_date "%Y-%m-%d-%H;%M;%S" UTC) + message("::set-output name=timestamp::${current_date}") + + - name: Setup ccache cache files + uses: actions/cache@v1.1.0 + with: + path: ${{github.workspace}}/build/.ccache + key: ${{ matrix.config.name }}-ccache-${{ steps.ccache_cache_timestamp.outputs.timestamp }} + restore-keys: | + ${{ matrix.config.name }}-ccache- - name: "Configure build: ${{ env.BUILD_CONFIG }}" shell: bash run: | set -x; - cmake -B${{github.workspace}}/build $BUILD_CONFIG || (cat CMakeFiles/CMakeOutput.log && cat CMakeFiles/CMakeError.log) + cmake -B${{github.workspace}}/build $BUILD_CONFIG || (cat CMakeFiles/CMakeConfigureLog.yaml) - name: Build working-directory: ${{github.workspace}}/build shell: bash run: | - cmake --build . --target tiledarray - cmake --build . --target examples + ccache -p && ccache -z && cmake --build . --target tiledarray && cmake --build . --target examples && ccache -s - name: Test working-directory: ${{github.workspace}}/build diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 02c3edc266..8b675a692c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -57,22 +57,10 @@ ubuntu: metrics: build/metrics.txt parallel: matrix: - - IMAGE : [ "ubuntu:20.04" ] - CXX: [ g++ ] - BUILD_TYPE : [ "RelWithDebInfo" ] - BLA_VENDOR : [ "BLAS_PREFERENCE_LIST=IntelMKL" ] - BLA_THREADS : [ "IntelMKL_THREAD_LAYER=tbb" ] - # ENABLE_SCALAPACK : [ "ENABLE_SCALAPACK=ON", "ENABLE_SCALAPACK=OFF" ] - TA_PYTHON : [ "TA_PYTHON=OFF" ] # needs to be fixed for MKL - RUNNER_TAGS: [ saas-linux-small-amd64 ] - - IMAGE : [ "ubuntu:22.04" ] - CXX: [ g++, clang++-13 ] - BUILD_TYPE : [ "RelWithDebInfo" ] - ENABLE_SCALAPACK : [ "ENABLE_SCALAPACK=ON", "ENABLE_SCALAPACK=OFF" ] - RUNNER_TAGS: [ saas-linux-small-amd64 ] - IMAGE : [ "ubuntu:22.04" ] CXX: [ g++ ] BUILD_TYPE : [ "RelWithDebInfo" ] + TA_PYTHON : [ "TA_PYTHON=OFF" ] ENABLE_CUDA : [ "ENABLE_CUDA=ON" ] TA_TARGETS : [ "tiledarray examples-tiledarray check_serial-tiledarray" ] RUNNER_TAGS: [ cuda ] diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c426d1ffbe..80f2a49710 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -133,8 +133,8 @@ TiledArray/expressions/index_list.h TiledArray/external/btas.h TiledArray/external/madness.h TiledArray/external/umpire.h +TiledArray/host/env.cpp TiledArray/host/env.h -TiledArray/host/allocator.h TiledArray/math/blas.h TiledArray/math/gemm_helper.h TiledArray/math/outer.h @@ -207,11 +207,7 @@ TiledArray/util/vector.h if(HIP_FOUND OR CUDA_FOUND) list(APPEND TILEDARRAY_HEADER_FILES TiledArray/external/device.h - TiledArray/external/librett.h) -endif() - -if(CUDA_FOUND OR HIP_FOUND) - list(APPEND TILEDARRAY_HEADER_FILES + TiledArray/external/librett.h TiledArray/device/blas.cpp TiledArray/device/blas.h TiledArray/device/btas.h @@ -223,7 +219,6 @@ if(CUDA_FOUND OR HIP_FOUND) TiledArray/device/kernel/thrust/reduce_kernel.h TiledArray/device/platform.h TiledArray/device/thrust.h - TiledArray/device/allocators.h TiledArray/device/um_storage.h) if(CUDA_FOUND) list(APPEND TILEDARRAY_HEADER_FILES diff --git a/src/TiledArray/device/allocators.h b/src/TiledArray/device/allocators.h deleted file mode 100644 index 2bda79e768..0000000000 --- a/src/TiledArray/device/allocators.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * This file is a part of TiledArray. - * Copyright (C) 2018 Virginia Tech - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Eduard Valeyev - * Department of Chemistry, Virginia Tech - * Jan 31, 2018 - * - */ - -#ifndef TILEDARRAY_DEVICE_ALLOCATORS_H___INCLUDED -#define TILEDARRAY_DEVICE_ALLOCATORS_H___INCLUDED - -#include - -#ifdef TILEDARRAY_HAS_DEVICE - -#include -#include - -#include - -#include -#include - -namespace TiledArray { - -template -class umpire_based_allocator - : public umpire_based_allocator_impl { - public: - using base_type = umpire_based_allocator_impl; - using typename base_type::const_pointer; - using typename base_type::const_reference; - using typename base_type::pointer; - using typename base_type::reference; - using typename base_type::value_type; - - umpire_based_allocator() noexcept : base_type(&UmpireAllocatorAccessor{}()) {} - - template - umpire_based_allocator( - const umpire_based_allocator& - rhs) noexcept - : base_type( - static_cast&>( - rhs)) {} - - template - friend bool operator==( - const umpire_based_allocator& - lhs, - const umpire_based_allocator& - rhs) noexcept; -}; // class umpire_based_allocator - -template -bool operator==( - const umpire_based_allocator& lhs, - const umpire_based_allocator& - rhs) noexcept { - return lhs.umpire_allocator() == rhs.umpire_allocator(); -} - -template -bool operator!=( - const umpire_based_allocator& lhs, - const umpire_based_allocator& - rhs) noexcept { - return !(lhs == rhs); -} - -namespace detail { - -struct get_um_allocator { - umpire::Allocator& operator()() { - return deviceEnv::instance()->um_allocator(); - } -}; - -struct get_pinned_allocator { - umpire::Allocator& operator()() { - return deviceEnv::instance()->pinned_allocator(); - } -}; - -} // namespace detail - -} // namespace TiledArray - -namespace madness { -namespace archive { - -template -struct ArchiveLoadImpl> { - static inline void load( - const Archive& ar, - TiledArray::umpire_based_allocator& allocator) { - allocator = TiledArray::umpire_based_allocator{}; - } -}; - -template -struct ArchiveStoreImpl> { - static inline void store( - const Archive& ar, - const TiledArray::umpire_based_allocator< - T, StaticLock, UmpireAllocatorAccessor>& allocator) {} -}; - -} // namespace archive -} // namespace madness - -#endif // TILEDARRAY_HAS_DEVICE - -#endif // TILEDARRAY_DEVICE_ALLOCATORS_H___INCLUDED diff --git a/src/TiledArray/device/um_storage.cu b/src/TiledArray/device/um_storage.cu index cc3a1aae55..8879c246f8 100644 --- a/src/TiledArray/device/um_storage.cu +++ b/src/TiledArray/device/um_storage.cu @@ -22,7 +22,7 @@ */ -#include +#include #include #ifdef TILEDARRAY_HAS_CUDA diff --git a/src/TiledArray/device/um_storage.h b/src/TiledArray/device/um_storage.h index d151a3c316..d91c032312 100644 --- a/src/TiledArray/device/um_storage.h +++ b/src/TiledArray/device/um_storage.h @@ -24,7 +24,7 @@ #ifndef TILEDARRAY_DEVICE_UM_VECTOR_H__INCLUDED #define TILEDARRAY_DEVICE_UM_VECTOR_H__INCLUDED -#include +#include #ifdef TILEDARRAY_HAS_DEVICE diff --git a/src/TiledArray/external/device.h b/src/TiledArray/external/device.h index 38bcbbc745..4f9d365e0a 100644 --- a/src/TiledArray/external/device.h +++ b/src/TiledArray/external/device.h @@ -41,8 +41,6 @@ #include #endif -#include - #include #include #include @@ -51,6 +49,20 @@ #include #include +#include + +namespace TiledArray::detail { + +struct get_um_allocator { + inline umpire::Allocator& operator()(); +}; + +struct get_pinned_allocator { + inline umpire::Allocator& operator()(); +}; + +} // namespace TiledArray::detail + #if defined(TILEDARRAY_HAS_CUDA) inline void __DeviceSafeCall(cudaError err, const char* file, const int line) { @@ -798,9 +810,10 @@ class Env { static std::unique_ptr instance_{nullptr}; return instance_; } -}; +}; // class Env namespace detail { + // in a madness device task point to its local optional stream to use by // madness_task_stream_opt; set to nullptr after task callable finished inline std::optional*& madness_task_stream_opt_ptr_accessor() { @@ -892,6 +905,18 @@ device::Stream stream_for(const Range& range) { } // namespace device +namespace detail { + +inline umpire::Allocator& get_um_allocator::operator()() { + return deviceEnv::instance()->um_allocator(); +} + +inline umpire::Allocator& get_pinned_allocator::operator()() { + return deviceEnv::instance()->pinned_allocator(); +} + +} // namespace detail + #endif // TILEDARRAY_HAS_DEVICE #ifdef TILEDARRAY_HAS_CUDA diff --git a/src/TiledArray/external/umpire.h b/src/TiledArray/external/umpire.h index e8d0d48632..ac23a60260 100644 --- a/src/TiledArray/external/umpire.h +++ b/src/TiledArray/external/umpire.h @@ -156,6 +156,54 @@ bool operator!=( return !(lhs == rhs); } +template +class umpire_based_allocator + : public umpire_based_allocator_impl { + public: + using base_type = umpire_based_allocator_impl; + using typename base_type::const_pointer; + using typename base_type::const_reference; + using typename base_type::pointer; + using typename base_type::reference; + using typename base_type::value_type; + + umpire_based_allocator() noexcept : base_type(&UmpireAllocatorAccessor{}()) {} + + template + umpire_based_allocator( + const umpire_based_allocator& + rhs) noexcept + : base_type( + static_cast&>( + rhs)) {} + + template + friend bool operator==( + const umpire_based_allocator& + lhs, + const umpire_based_allocator& + rhs) noexcept; +}; // class umpire_based_allocator + +template +bool operator==( + const umpire_based_allocator& lhs, + const umpire_based_allocator& + rhs) noexcept { + return lhs.umpire_allocator() == rhs.umpire_allocator(); +} + +template +bool operator!=( + const umpire_based_allocator& lhs, + const umpire_based_allocator& + rhs) noexcept { + return !(lhs == rhs); +} + /// see /// https://stackoverflow.com/questions/21028299/is-this-behavior-of-vectorresizesize-type-n-under-c11-and-boost-container/21028912#21028912 template @@ -202,7 +250,7 @@ struct ArchiveLoadImpl& allocator) { std::string allocator_name; - ar& allocator_name; + ar & allocator_name; allocator = TiledArray::umpire_based_allocator_impl( umpire::ResourceManager::getInstance().getAllocator(allocator_name)); } @@ -214,7 +262,7 @@ struct ArchiveStoreImpl< static inline void store( const Archive& ar, const TiledArray::umpire_based_allocator_impl& allocator) { - ar& allocator.umpire_allocator()->getName(); + ar & allocator.umpire_allocator()->getName(); } }; @@ -224,7 +272,7 @@ struct ArchiveLoadImpl> { TiledArray::default_init_allocator& allocator) { if constexpr (!std::allocator_traits::is_always_equal::value) { A base_allocator; - ar& base_allocator; + ar & base_allocator; allocator = TiledArray::default_init_allocator(base_allocator); } } @@ -244,4 +292,33 @@ struct ArchiveStoreImpl> { } // namespace archive } // namespace madness +namespace madness { +namespace archive { + +template +struct ArchiveLoadImpl> { + static inline void load( + const Archive& ar, + TiledArray::umpire_based_allocator& allocator) { + allocator = TiledArray::umpire_based_allocator{}; + } +}; + +template +struct ArchiveStoreImpl> { + static inline void store( + const Archive& ar, + const TiledArray::umpire_based_allocator< + T, StaticLock, UmpireAllocatorAccessor>& allocator) {} +}; + +} // namespace archive +} // namespace madness + #endif // TILEDARRAY_EXTERNAL_UMPIRE_H___INCLUDED diff --git a/src/TiledArray/fwd.h b/src/TiledArray/fwd.h index 97d91a9a00..652b835fab 100644 --- a/src/TiledArray/fwd.h +++ b/src/TiledArray/fwd.h @@ -36,12 +36,30 @@ class aligned_allocator; // fwddecl host_allocator namespace TiledArray { -template -class host_allocator_impl; -template +namespace detail { +struct get_host_allocator; +struct NullLock; +template +class MutexLock; +} // namespace detail + +template +class umpire_based_allocator; + +template > class default_init_allocator; + +namespace host { +class Env; +} +using hostEnv = host::Env; + +/// pooled thread-safe host memory allocator template -using host_allocator = default_init_allocator>; +using host_allocator = + default_init_allocator, + detail::get_host_allocator>>; } // namespace TiledArray namespace madness { @@ -87,18 +105,9 @@ class Env; } using deviceEnv = device::Env; -template -class umpire_based_allocator; - -template > -class default_init_allocator; - namespace detail { struct get_um_allocator; struct get_pinned_allocator; -struct NullLock; -template -class MutexLock; } // namespace detail /// pooled thread-safe unified memory (UM) allocator for device computing diff --git a/src/TiledArray/host/allocator.h b/src/TiledArray/host/allocator.h deleted file mode 100644 index a22613fb38..0000000000 --- a/src/TiledArray/host/allocator.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * This file is a part of TiledArray. - * Copyright (C) 2021 Virginia Tech - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Eduard Valeyev - * Department of Chemistry, Virginia Tech - * Jan 31, 2018 - * - */ - -#ifndef TILEDARRAY_HOST_ALLOCATOR_H___INCLUDED -#define TILEDARRAY_HOST_ALLOCATOR_H___INCLUDED - -#include - -#include -#include - -#include - -#include -#include - -namespace TiledArray { - -/// pooled, thread-safe allocator for host memory -template -class host_allocator_impl - : public umpire_based_allocator_impl> { - public: - using base_type = umpire_based_allocator_impl>; - using typename base_type::const_pointer; - using typename base_type::const_reference; - using typename base_type::pointer; - using typename base_type::reference; - using typename base_type::value_type; - - host_allocator_impl() noexcept - : base_type(&hostEnv::instance()->host_allocator()) {} - - template - host_allocator_impl(const host_allocator_impl& rhs) noexcept - : base_type(static_cast>&>(rhs)) {} - - template - friend bool operator==(const host_allocator_impl& lhs, - const host_allocator_impl& rhs) noexcept; -}; // class host_allocator_impl - -template -bool operator==(const host_allocator_impl& lhs, - const host_allocator_impl& rhs) noexcept { - return lhs.umpire_allocator() == rhs.umpire_allocator(); -} - -template -bool operator!=(const host_allocator_impl& lhs, - const host_allocator_impl& rhs) noexcept { - return !(lhs == rhs); -} - -} // namespace TiledArray - -#endif // TILEDARRAY_HOST_ALLOCATOR_H___INCLUDED diff --git a/src/TiledArray/host/env.cpp b/src/TiledArray/host/env.cpp new file mode 100644 index 0000000000..16d3a71a50 --- /dev/null +++ b/src/TiledArray/host/env.cpp @@ -0,0 +1,36 @@ +/* + * This file is a part of TiledArray. + * Copyright (C) 2021 Virginia Tech + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Chong Peng + * Department of Chemistry, Virginia Tech + * July 23, 2018 + * + */ + +#include + +namespace TiledArray { + +namespace detail { + +umpire::Allocator& get_host_allocator::operator()() { + return TiledArray::host::Env::instance()->host_allocator(); +} + +} // namespace detail + +} // namespace TiledArray diff --git a/src/TiledArray/host/env.h b/src/TiledArray/host/env.h index 1b3c4f277f..b469704a72 100644 --- a/src/TiledArray/host/env.h +++ b/src/TiledArray/host/env.h @@ -41,24 +41,34 @@ namespace TiledArray { +namespace detail { + +struct get_host_allocator { + umpire::Allocator& operator()(); +}; + +} // namespace detail + +namespace host { + /** - * hostEnv maintains the (host-side, as opposed to device-side) environment, + * Env maintains the (host-side, as opposed to device-side) environment, * such as memory allocators * * \note this is a Singleton */ -class hostEnv { +class Env { public: - ~hostEnv() = default; + ~Env() = default; - hostEnv(const hostEnv&) = delete; - hostEnv(hostEnv&&) = delete; - hostEnv& operator=(const hostEnv&) = delete; - hostEnv& operator=(hostEnv&&) = delete; + Env(const Env&) = delete; + Env(Env&&) = delete; + Env& operator=(const Env&) = delete; + Env& operator=(Env&&) = delete; /// access the singleton instance; if not initialized will be - /// initialized via hostEnv::initialize() with the default params - static std::unique_ptr& instance() { + /// initialized via Env::initialize() with the default params + static std::unique_ptr& instance() { if (!instance_accessor()) { initialize(); } @@ -103,8 +113,7 @@ class hostEnv { "QuickPool_SizeLimited_HOST", host_size_limited_alloc, page_size, page_size, /* alignment */ TILEDARRAY_ALIGN_SIZE); - auto host_env = - std::unique_ptr(new hostEnv(world, host_dynamic_pool)); + auto host_env = std::unique_ptr(new Env(world, host_dynamic_pool)); instance_accessor() = std::move(host_env); } } @@ -131,7 +140,7 @@ class hostEnv { } protected: - hostEnv(World& world, umpire::Allocator host_alloc) + Env(World& world, umpire::Allocator host_alloc) : world_(&world), host_allocator_(host_alloc) {} private: @@ -142,12 +151,14 @@ class hostEnv { // N.B. not thread safe, so must be wrapped into umpire_based_allocator_impl umpire::Allocator host_allocator_; - inline static std::unique_ptr& instance_accessor() { - static std::unique_ptr instance_{nullptr}; + inline static std::unique_ptr& instance_accessor() { + static std::unique_ptr instance_{nullptr}; return instance_; } }; +} // namespace host + } // namespace TiledArray #endif // TILEDARRAY_HOST_ENV_H__INCLUDED diff --git a/src/TiledArray/tensor/tensor.h b/src/TiledArray/tensor/tensor.h index 12479ef53c..bf729e59d9 100644 --- a/src/TiledArray/tensor/tensor.h +++ b/src/TiledArray/tensor/tensor.h @@ -22,7 +22,8 @@ #include "TiledArray/config.h" -#include "TiledArray/host/allocator.h" +#include "TiledArray/external/umpire.h" +#include "TiledArray/host/env.h" #include "TiledArray/math/blas.h" #include "TiledArray/math/gemm_helper.h" @@ -704,7 +705,7 @@ class Tensor { const_reference operator[](const Ordinal ord) const { TA_ASSERT(!this->empty()); // can't distinguish between operator[](Index...) and operator[](ordinal) - // thus assume at_ordinal() if this->rank()==1 + // thus insist on at_ordinal() if this->rank()==1 TA_ASSERT(this->range_.rank() != 1 && "use Tensor::operator[](index) or " "Tensor::at_ordinal(index_ordinal) if this->range().rank()==1"); @@ -725,7 +726,7 @@ class Tensor { reference operator[](const Ordinal ord) { TA_ASSERT(!this->empty()); // can't distinguish between operator[](Index...) and operator[](ordinal) - // thus assume at_ordinal() if this->rank()==1 + // thus insist on at_ordinal() if this->rank()==1 TA_ASSERT(this->range_.rank() != 1 && "use Tensor::operator[](index) or " "Tensor::at_ordinal(index_ordinal) if this->range().rank()==1"); @@ -847,7 +848,7 @@ class Tensor { TA_ASSERT(!this->empty()); TA_ASSERT(this->nbatch() == 1); // can't distinguish between operator[](Index...) and operator[](ordinal) - // thus assume at_ordinal() if this->rank()==1 + // thus insist on at_ordinal() if this->rank()==1 TA_ASSERT(this->range_.rank() != 1 && "use Tensor::operator()(index) or " "Tensor::at_ordinal(index_ordinal) if this->range().rank()==1"); @@ -868,7 +869,7 @@ class Tensor { TA_ASSERT(!this->empty()); TA_ASSERT(this->nbatch() == 1); // can't distinguish between operator[](Index...) and operator[](ordinal) - // thus assume at_ordinal() if this->rank()==1 + // thus insist on at_ordinal() if this->rank()==1 TA_ASSERT(this->range_.rank() != 1 && "use Tensor::operator()(index) or " "Tensor::at_ordinal(index_ordinal) if this->range().rank()==1"); @@ -959,6 +960,12 @@ class Tensor { const_reference operator()(const Index&... i) const { TA_ASSERT(!this->empty()); TA_ASSERT(this->nbatch() == 1); + TA_ASSERT(this->range().rank() == sizeof...(Index)); + // can't distinguish between operator()(Index...) and operator()(ordinal) + // thus insist on at_ordinal() if this->rank()==1 + TA_ASSERT(this->range_.rank() != 1 && + "use Tensor::operator()(index) or " + "Tensor::at_ordinal(index_ordinal) if this->range().rank()==1"); using Int = std::common_type_t; const auto iord = this->range_.ordinal( std::array{{static_cast(i)...}}); @@ -981,6 +988,12 @@ class Tensor { reference operator()(const Index&... i) { TA_ASSERT(!this->empty()); TA_ASSERT(this->nbatch() == 1); + TA_ASSERT(this->range().rank() == sizeof...(Index)); + // can't distinguish between operator()(Index...) and operator()(ordinal) + // thus insist on at_ordinal() if this->rank()==1 + TA_ASSERT(this->range_.rank() != 1 && + "use Tensor::operator()(index) or " + "Tensor::at_ordinal(index_ordinal) if this->range().rank()==1"); using Int = std::common_type_t; const auto iord = this->range_.ordinal( std::array{{static_cast(i)...}}); diff --git a/src/TiledArray/tile.h b/src/TiledArray/tile.h index b8c62d95b8..39fca37d9e 100644 --- a/src/TiledArray/tile.h +++ b/src/TiledArray/tile.h @@ -250,6 +250,11 @@ class Tile { std::enable_if_t::value>* = nullptr> const_reference operator[](const Ordinal ord) const { TA_ASSERT(pimpl_); + // can't distinguish between operator[](Index...) and operator[](ordinal) + // thus insist on at_ordinal() if this->rank()==1 + TA_ASSERT(this->range().rank() != 1 && + "use Tile::operator[](index) or " + "Tile::at_ordinal(index_ordinal) if this->range().rank()==1"); TA_ASSERT(tensor().range().includes_ordinal(ord)); return tensor().data()[ord]; } @@ -264,6 +269,41 @@ class Tile { template ::value>* = nullptr> reference operator[](const Ordinal ord) { + TA_ASSERT(pimpl_); + // can't distinguish between operator[](Index...) and operator[](ordinal) + // thus insist on at_ordinal() if this->rank()==1 + TA_ASSERT(this->range().rank() != 1 && + "use Tile::operator[](index) or " + "Tile::at_ordinal(index_ordinal) if this->range().rank()==1"); + TA_ASSERT(tensor().range().includes_ordinal(ord)); + return tensor().data()[ord]; + } + + /// Const element accessor + + /// \tparam Ordinal an integer type that represents an ordinal + /// \param[in] ord an ordinal index + /// \return Const reference to the element at position \c ord . + /// \note This asserts (using TA_ASSERT) that this is not empty and ord is + /// included in the range + template ::value>* = nullptr> + const_reference at_ordinal(const Ordinal ord) const { + TA_ASSERT(pimpl_); + TA_ASSERT(tensor().range().includes_ordinal(ord)); + return tensor().data()[ord]; + } + + /// Element accessor + + /// \tparam Ordinal an integer type that represents an ordinal + /// \param[in] ord an ordinal index + /// \return Reference to the element at position \c ord . + /// \note This asserts (using TA_ASSERT) that this is not empty and ord is + /// included in the range + template ::value>* = nullptr> + reference at_ordinal(const Ordinal ord) { TA_ASSERT(pimpl_); TA_ASSERT(tensor().range().includes_ordinal(ord)); return tensor().data()[ord]; @@ -401,6 +441,12 @@ class Tile { detail::is_integral_list::value>* = nullptr> const_reference operator()(const Index&... i) const { TA_ASSERT(pimpl_); + TA_ASSERT(this->range().rank() == sizeof...(Index)); + // can't distinguish between operator()(Index...) and operator()(ordinal) + // thus insist on at_ordinal() if this->rank()==1 + TA_ASSERT(this->range().rank() != 1 && + "use Tile::operator()(index) or " + "Tile::at_ordinal(index_ordinal) if this->range().rank()==1"); TA_ASSERT(tensor().range().includes(i...)); return tensor().data()[tensor().range().ordinal(i...)]; } @@ -417,6 +463,12 @@ class Tile { detail::is_integral_list::value>* = nullptr> reference operator()(const Index&... i) { TA_ASSERT(pimpl_); + TA_ASSERT(this->range().rank() == sizeof...(Index)); + // can't distinguish between operator()(Index...) and operator()(ordinal) + // thus insist on at_ordinal() if this->rank()==1 + TA_ASSERT(this->range().rank() != 1 && + "use Tile::operator()(index) or " + "Tile::at_ordinal(index_ordinal) if this->range().rank()==1"); TA_ASSERT(tensor().range().includes(i...)); return tensor().data()[tensor().range().ordinal(i...)]; } diff --git a/tests/expressions_device_um.cpp b/tests/expressions_device_um.cpp index e624756561..d49b425372 100644 --- a/tests/expressions_device_um.cpp +++ b/tests/expressions_device_um.cpp @@ -85,7 +85,8 @@ struct UMExpressionsFixture : public TiledRangeFixture { template static Tile make_rand_tile(const typename TA::Range& r) { Tile tile(r); - for (std::size_t i = 0ul; i < tile.size(); ++i) set_random(tile[i]); + for (std::size_t i = 0ul; i < tile.size(); ++i) + set_random(tile.at_ordinal(i)); return tile; }