10#ifndef TPETRA_DETAILS_COPYOFFSETS_HPP
11#define TPETRA_DETAILS_COPYOFFSETS_HPP
18#include "TpetraCore_config.h"
20#include "Kokkos_Core.hpp"
39template <
class OutputType,
class InputType>
40struct OutputCanFitInput {
42 static constexpr bool output_signed = std::is_signed<OutputType>::value;
43 static constexpr bool input_signed = std::is_signed<InputType>::value;
46 static const bool value =
sizeof(OutputType) >
sizeof(InputType) ||
47 (
sizeof(OutputType) ==
sizeof(InputType) &&
48 !output_signed && input_signed);
52template <
class InputType,
53 bool input_signed = std::is_signed<InputType>::value>
56template <
class InputType>
57struct Negative<InputType, true> {
58 static KOKKOS_INLINE_FUNCTION
bool
59 negative(
const InputType src) {
60 return src < InputType(0);
64template <
class InputType>
65struct Negative<InputType, false> {
66 static KOKKOS_INLINE_FUNCTION
bool
67 negative(
const InputType ) {
72template <
class InputType>
73KOKKOS_INLINE_FUNCTION
bool negative(
const InputType src) {
74 return Negative<InputType>::negative(src);
77template <
class OutputType,
class InputType>
78struct OverflowChecker {
80 static constexpr bool output_signed = std::is_signed<OutputType>::value;
81 static constexpr bool input_signed = std::is_signed<InputType>::value;
87 static constexpr bool could_overflow =
88 (!output_signed && input_signed) ||
89 (
sizeof(OutputType) <
sizeof(InputType)) ||
90 (
sizeof(OutputType) ==
sizeof(InputType) &&
91 output_signed && !input_signed);
93 KOKKOS_INLINE_FUNCTION
bool
94 overflows(
const InputType src)
const {
95 if (!could_overflow) {
99 if (!output_signed && input_signed) {
100 return negative(src);
104 return src < minDstVal_ || src > maxDstVal_;
111 InputType minDstVal_ = input_signed ? std::numeric_limits<OutputType>::min() : OutputType(0);
112 InputType maxDstVal_ = std::numeric_limits<OutputType>::max();
115template <
class OutputViewType,
class InputViewType>
116void errorIfOverflow(
const OutputViewType& dst,
117 const InputViewType& src,
118 const size_t overflowCount) {
119 if (overflowCount == 0) {
123 std::ostringstream os;
124 const bool plural = overflowCount != size_t(1);
125 os <<
"copyOffsets: " << overflowCount <<
" value" << (plural ?
"s" :
"") <<
" in src were too big (in the "
126 "sense of integer overflow) to fit in dst.";
130 const size_t maxNumToPrint =
132 const size_t srcLen(src.extent(0));
133 if (srcLen <= maxNumToPrint) {
134 auto dst_h = Kokkos::create_mirror_view(dst);
135 auto src_h = Kokkos::create_mirror_view(src);
137 Kokkos::deep_copy(src_h, src);
139 Kokkos::deep_copy(dst_h, dst);
142 for (
size_t k = 0; k < srcLen; ++k) {
144 if (k +
size_t(1) < srcLen) {
151 for (
size_t k = 0; k < srcLen; ++k) {
153 if (k +
size_t(1) < srcLen) {
159 os <<
" src.extent(0) > " << maxNumToPrint <<
", Tpetra's "
160 "verbose print count threshold. To increase this, set the "
161 "environment variable TPETRA_VERBOSE_PRINT_COUNT_THRESHOLD "
162 "to the desired threshold and rerun. You do NOT need to "
166 TEUCHOS_TEST_FOR_EXCEPTION(
true, std::runtime_error, os.str());
178template <
class OutputViewType,
180 const bool outputCanFitInput =
181 OutputCanFitInput<
typename OutputViewType::non_const_value_type,
182 typename InputViewType::non_const_value_type>::value>
183class CopyOffsetsFunctor {};
186template <
class OutputViewType,
class InputViewType>
187class CopyOffsetsFunctor<OutputViewType, InputViewType, false> {
189 using execution_space =
typename OutputViewType::execution_space;
190 using size_type =
typename OutputViewType::size_type;
191 using value_type = size_t;
193 using input_value_type =
typename InputViewType::non_const_value_type;
194 using output_value_type =
typename OutputViewType::non_const_value_type;
196 CopyOffsetsFunctor(
const OutputViewType& dst,
const InputViewType& src)
199 static_assert(Kokkos::SpaceAccessibility<
200 typename OutputViewType::memory_space,
201 typename InputViewType::memory_space>::accessible,
202 "CopyOffsetsFunctor (implements copyOffsets): Output "
203 "View's space must be able to access the input View's "
207 KOKKOS_INLINE_FUNCTION
void
208 operator()(
const size_type i, value_type& overflowCount)
const {
209 const input_value_type src_i = src_(i);
210 if (checker_.overflows(src_i)) {
213 dst_(i) =
static_cast<output_value_type
>(src_i);
216 KOKKOS_INLINE_FUNCTION
void
217 operator()(
const size_type i)
const {
218 const input_value_type src_i = src_(i);
219 dst_(i) =
static_cast<output_value_type
>(src_i);
222 KOKKOS_INLINE_FUNCTION
void init(value_type& overflowCount)
const {
226 KOKKOS_INLINE_FUNCTION
void
227 join(value_type& result,
228 const value_type& current)
const {
235 OverflowChecker<output_value_type, input_value_type> checker_;
239template <
class OutputViewType,
class InputViewType>
240class CopyOffsetsFunctor<OutputViewType, InputViewType, true> {
242 using execution_space =
typename OutputViewType::execution_space;
243 using size_type =
typename OutputViewType::size_type;
244 using value_type = size_t;
246 CopyOffsetsFunctor(
const OutputViewType& dst,
const InputViewType& src)
249 static_assert(Kokkos::SpaceAccessibility<
250 typename OutputViewType::memory_space,
251 typename InputViewType::memory_space>::accessible,
252 "CopyOffsetsFunctor (implements copyOffsets): Output "
253 "View's space must be able to access the input View's "
257 KOKKOS_INLINE_FUNCTION
void
258 operator()(
const size_type i, value_type& )
const {
263 KOKKOS_INLINE_FUNCTION
void
264 operator()(
const size_type i)
const {
268 KOKKOS_INLINE_FUNCTION
void init(value_type& overflowCount)
const {
272 KOKKOS_INLINE_FUNCTION
void
274 const value_type& )
const {}
297template <
class OutputViewType,
299 const bool sameLayoutsSameOffsetTypes =
300 std::is_same<
typename OutputViewType::array_layout,
301 typename InputViewType::array_layout>::value&&
302 std::is_same<
typename OutputViewType::non_const_value_type,
303 typename InputViewType::non_const_value_type>::value,
304 const bool outputExecSpaceCanAccessInputMemSpace =
305 Kokkos::SpaceAccessibility<
306 typename OutputViewType::memory_space,
307 typename InputViewType::memory_space>::accessible>
308struct CopyOffsetsImpl {
309 static void run(
const OutputViewType& dst,
const InputViewType& src);
320template <
class OutputViewType,
322 const bool outputExecSpaceCanAccessInputMemSpace>
323struct CopyOffsetsImpl<OutputViewType, InputViewType,
324 true, outputExecSpaceCanAccessInputMemSpace> {
325 static void run(
const OutputViewType& dst,
const InputViewType& src) {
326 static_assert(std::is_same<
typename OutputViewType::non_const_value_type,
327 typename InputViewType::non_const_value_type>::value,
328 "CopyOffsetsImpl (implementation of copyOffsets): In order"
329 " to call this specialization, the input and output must "
330 "use the same offset type.");
331 static_assert(
static_cast<int>(OutputViewType::rank) ==
332 static_cast<int>(InputViewType::rank),
333 "CopyOffsetsImpl (implementation of copyOffsets): In order"
334 " to call this specialization, src and dst must have the "
336 static_assert(std::is_same<
typename OutputViewType::array_layout,
337 typename InputViewType::array_layout>::value,
338 "CopyOffsetsImpl (implementation of copyOffsets): In order"
339 " to call this specialization, src and dst must have the "
340 "the same array_layout.");
342 using execution_space =
typename OutputViewType::execution_space;
343 Kokkos::deep_copy(execution_space(), dst, src);
358template <
class OutputViewType,
360struct CopyOffsetsImpl<OutputViewType, InputViewType,
362 static void run(
const OutputViewType& dst,
const InputViewType& src) {
363 static_assert(
static_cast<int>(OutputViewType::rank) ==
364 static_cast<int>(InputViewType::rank),
365 "CopyOffsetsImpl (implementation of copyOffsets): "
366 "src and dst must have the same rank.");
367 constexpr bool sameLayoutsSameOffsetTypes =
368 std::is_same<
typename OutputViewType::array_layout,
369 typename InputViewType::array_layout>::value &&
370 std::is_same<
typename OutputViewType::non_const_value_type,
371 typename InputViewType::non_const_value_type>::value;
372 static_assert(!sameLayoutsSameOffsetTypes,
373 "CopyOffsetsImpl (implements copyOffsets): In order to "
374 "call this specialization, sameLayoutsSameOffsetTypes "
375 "must be false. That is, either the input and output "
376 "must have different array layouts, or their value types "
378 static_assert(Kokkos::SpaceAccessibility<
379 typename OutputViewType::memory_space,
380 typename InputViewType::memory_space>::accessible,
381 "CopyOffsetsImpl (implements copyOffsets): In order to "
382 "call this specialization, the output View's space must "
383 "be able to access the input View's memory space.");
384 using functor_type = CopyOffsetsFunctor<OutputViewType, InputViewType>;
385 using execution_space =
typename OutputViewType::execution_space;
386 using size_type =
typename OutputViewType::size_type;
387 using range_type = Kokkos::RangePolicy<execution_space, size_type>;
391 size_t overflowCount = 0;
392 Kokkos::parallel_reduce(
"Tpetra::Details::copyOffsets",
393 range_type(0, dst.extent(0)),
394 functor_type(dst, src),
396 errorIfOverflow(dst, src, overflowCount);
398 Kokkos::parallel_for(
"Tpetra::Details::copyOffsets",
399 range_type(0, dst.extent(0)),
400 functor_type(dst, src));
422template <
class OutputViewType,
class InputViewType>
423struct CopyOffsetsImpl<OutputViewType, InputViewType,
425 static void run(
const OutputViewType& dst,
const InputViewType& src) {
426 static_assert(
static_cast<int>(OutputViewType::rank) ==
427 static_cast<int>(InputViewType::rank),
428 "CopyOffsetsImpl (implementation of copyOffsets): In order"
429 " to call this specialization, src and dst must have the "
431 constexpr bool sameLayoutsSameOffsetTypes =
432 std::is_same<
typename OutputViewType::array_layout,
433 typename InputViewType::array_layout>::value &&
434 std::is_same<
typename OutputViewType::non_const_value_type,
435 typename InputViewType::non_const_value_type>::value;
436 static_assert(!sameLayoutsSameOffsetTypes,
437 "CopyOffsetsImpl (implements copyOffsets): In order to "
438 "call this specialization, sameLayoutsSameOffsetTypes "
439 "must be false. That is, either the input and output "
440 "must have different array layouts, or their value types "
442 using output_space_copy_type =
443 Kokkos::View<
typename InputViewType::non_const_value_type*,
444 Kokkos::LayoutLeft,
typename OutputViewType::device_type>;
445 using Kokkos::view_alloc;
446 using Kokkos::WithoutInitializing;
447 using execution_space =
typename OutputViewType::execution_space;
448 output_space_copy_type
449 outputSpaceCopy(view_alloc(
"outputSpace", WithoutInitializing),
452 Kokkos::deep_copy(execution_space(), outputSpaceCopy, src);
457 CopyOffsetsFunctor<OutputViewType, output_space_copy_type>;
458 using size_type =
typename OutputViewType::size_type;
459 using range_type = Kokkos::RangePolicy<execution_space, size_type>;
463 size_t overflowCount = 0;
464 Kokkos::parallel_reduce(
"Tpetra::Details::copyOffsets",
465 range_type(0, dst.extent(0)),
466 functor_type(dst, outputSpaceCopy),
468 errorIfOverflow(dst, src, overflowCount);
470 Kokkos::parallel_for(
"Tpetra::Details::copyOffsets",
471 range_type(0, dst.extent(0)),
472 functor_type(dst, outputSpaceCopy));
489template <
class OutputViewType,
class InputViewType>
491 static_assert(Kokkos::is_view<OutputViewType>::value,
492 "OutputViewType (the type of dst) must be a Kokkos::View.");
493 static_assert(Kokkos::is_view<InputViewType>::value,
494 "InputViewType (the type of src) must be a Kokkos::View.");
495 static_assert(std::is_same<
typename OutputViewType::value_type,
496 typename OutputViewType::non_const_value_type>::value,
497 "OutputViewType (the type of dst) must be a nonconst Kokkos::View.");
498 static_assert(
static_cast<int>(OutputViewType::rank) == 1,
499 "OutputViewType (the type of dst) must be a rank-1 Kokkos::View.");
500 static_assert(
static_cast<int>(InputViewType::rank) == 1,
501 "InputViewType (the type of src) must be a rank-1 Kokkos::View.");
502 static_assert(std::is_integral<
typename std::decay<
decltype(dst(0))>::type>::value,
503 "The entries of dst must be built-in integers.");
504 static_assert(std::is_integral<
typename std::decay<
decltype(src(0))>::type>::value,
505 "The entries of src must be built-in integers.");
508 "copyOffsets: dst.extent(0) = " << dst.extent(0)
509 <<
" != src.extent(0) = " << src.extent(0) <<
".");
511 CopyOffsetsImpl<OutputViewType, InputViewType>::run(dst, src);
Declaration of Tpetra::Details::Behavior, a class that describes Tpetra's behavior.
Struct that holds views of the contents of a CrsMatrix.
static bool debug()
Whether Tpetra is in debug mode.
static bool verbose()
Whether Tpetra is in verbose mode.
static size_t verbosePrintCountThreshold()
Number of entries below which arrays, lists, etc. will be printed in debug mode.
Implementation details of Tpetra.
void copyOffsets(const OutputViewType &dst, const InputViewType &src)
Copy row offsets (in a sparse graph or matrix) from src to dst. The offsets may have different types.
Namespace Tpetra contains the class and methods constituting the Tpetra library.