/**************************************************************************** * Copyright (c) 2017-2023 by the ArborX authors * * All rights reserved. * * * * This file is part of the ArborX library. ArborX is * * distributed under a BSD 3-clause license. For the licensing terms see * * the LICENSE file in the top-level directory. * * * * SPDX-License-Identifier: BSD-3-Clause * ****************************************************************************/ #ifndef ARBORX_BRUTE_FORCE_HPP #define ARBORX_BRUTE_FORCE_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ArborX { template >>, typename GeometryTraits::coordinate_type_t< std::decay_t>>>> class BruteForce { public: using memory_space = MemorySpace; static_assert(Kokkos::is_memory_space::value); using size_type = typename MemorySpace::size_type; using bounding_volume_type = BoundingVolume; using value_type = Value; BruteForce() = default; template BruteForce(ExecutionSpace const &space, Values const &values, IndexableGetter const &indexable_getter = IndexableGetter()); KOKKOS_FUNCTION size_type size() const noexcept { return _size; } KOKKOS_FUNCTION bool empty() const noexcept { return size() == 0; } KOKKOS_FUNCTION bounding_volume_type bounds() const noexcept { return _bounds; } template void query(ExecutionSpace const &space, Predicates const &predicates, Callback const &callback, Ignore = Ignore()) const; template std::enable_if_t>> query(ExecutionSpace const &space, UserPredicates const &user_predicates, CallbackOrView &&callback_or_view, View &&view, Args &&...args) const { Kokkos::Profiling::ScopedRegion guard("ArborX::BruteForce::query_crs"); Details::CrsGraphWrapperImpl:: check_valid_callback_if_first_argument_is_not_a_view( callback_or_view, user_predicates, view); using Predicates = Details::AccessValues; using Tag = typename Predicates::value_type::Tag; // Automatically add LegacyDefaultCallback if // 1. A user does not provide a callback // 2. The index is constructed on PairValueIndex // 3. The output value_type is an integral type constexpr bool use_convenient_shortcut = []() { if constexpr (!Kokkos::is_view_v>) return false; else if constexpr (!Details::is_pair_value_index_v) return false; else return std::is_integral_v< typename std::decay_t::value_type>; }(); if constexpr (use_convenient_shortcut) { // Simplified way to get APIv1 result using APIv2 interface Details::CrsGraphWrapperImpl::queryDispatch( Tag{}, *this, space, Predicates{user_predicates}, Details::LegacyDefaultCallback{}, // inject legacy callback arg std::forward(callback_or_view), std::forward(view), std::forward(args)...); return; } else { Details::CrsGraphWrapperImpl::queryDispatch( Tag{}, *this, space, Predicates{user_predicates}, std::forward(callback_or_view), std::forward(view), std::forward(args)...); } } KOKKOS_FUNCTION auto const &indexable_get() const { return _indexable_getter; } private: size_type _size{0}; bounding_volume_type _bounds; Kokkos::View _values; IndexableGetter _indexable_getter; }; template class BruteForce> : public BruteForce, Details::DefaultIndexableGetter, Box> { using base_type = BruteForce, Details::DefaultIndexableGetter, Box>; public: using bounding_volume_type = typename base_type::bounding_volume_type; BruteForce() = default; template BruteForce(ExecutionSpace const &space, Primitives const &primitives) : base_type( space, // Validate the primitives before calling the base constructor (Details::check_valid_access_traits(PrimitivesTag{}, primitives), Details::LegacyValues{ primitives}), Details::DefaultIndexableGetter()) {} template void query(ExecutionSpace const &space, Predicates const &predicates, Callback const &callback, Ignore = Ignore()) const { Details::check_valid_callback(callback, predicates); base_type::query(space, predicates, Details::LegacyCallbackWrapper{callback}); } template std::enable_if_t>> query(ExecutionSpace const &space, Predicates const &predicates, View &&view, Args &&...args) const { base_type::query(space, predicates, Details::LegacyDefaultCallback{}, std::forward(view), std::forward(args)...); } template std::enable_if_t>> query(ExecutionSpace const &space, Predicates const &predicates, Callback &&callback, OutputView &&out, OffsetView &&offset, Args &&...args) const { if constexpr (!Details::is_tagged_post_callback< std::decay_t>::value) { Details::check_valid_callback(callback, predicates, out); base_type::query(space, predicates, Details::LegacyCallbackWrapper>{ std::forward(callback)}, std::forward(out), std::forward(offset), std::forward(args)...); } else { Kokkos::Profiling::ScopedRegion guard("ArborX::BruteForce::query_crs"); Kokkos::View indices( "ArborX::CrsGraphWrapper::query::indices", 0); base_type::query(space, predicates, Details::LegacyDefaultCallback{}, indices, std::forward(offset), std::forward(args)...); callback(predicates, std::forward(offset), indices, std::forward(out)); } } }; template template BruteForce::BruteForce( ExecutionSpace const &space, UserValues const &user_values, IndexableGetter const &indexable_getter) : _size(AccessTraits::size(user_values)) , _values(Kokkos::view_alloc(space, Kokkos::WithoutInitializing, "ArborX::BruteForce::values"), _size) , _indexable_getter(indexable_getter) { static_assert(Details::KokkosExt::is_accessible_from::value); // FIXME redo with RangeTraits Details::check_valid_access_traits( PrimitivesTag{}, user_values, Details::DoNotCheckGetReturnType()); using Values = Details::AccessValues; Values values{user_values}; // NOLINT static_assert( Details::KokkosExt::is_accessible_from::value, "Values must be accessible from the execution space"); Kokkos::Profiling::ScopedRegion guard("ArborX::BruteForce::BruteForce"); if (empty()) { return; } Details::BruteForceImpl::initializeBoundingVolumesAndReduceBoundsOfTheScene( space, values, _indexable_getter, _values, _bounds); } template template void BruteForce::query( ExecutionSpace const &space, UserPredicates const &user_predicates, Callback const &callback, Ignore) const { static_assert(Details::KokkosExt::is_accessible_from::value); Details::check_valid_access_traits(PredicatesTag{}, user_predicates); Details::check_valid_callback(callback, user_predicates); using Predicates = Details::AccessValues; static_assert( Details::KokkosExt::is_accessible_from::value, "Predicates must be accessible from the execution space"); Predicates predicates{user_predicates}; // NOLINT using Tag = typename Predicates::value_type::Tag; Details::BruteForceImpl::query( Tag{}, space, predicates, _values, Details::Indexables{ _values, _indexable_getter}, callback); } } // namespace ArborX #endif