42 #ifndef TPETRA_DETAILS_COPYOFFSETS_HPP
43 #define TPETRA_DETAILS_COPYOFFSETS_HPP
50 #include "TpetraCore_config.h"
52 #include "Kokkos_Core.hpp"
54 #include <type_traits>
71 template<
class OutputType,
class InputType>
72 struct OutputCanFitInput {
74 static constexpr
bool output_signed = std::is_signed<OutputType>::value;
75 static constexpr
bool input_signed = std::is_signed<InputType>::value;
78 static const bool value =
sizeof (OutputType) >
sizeof (InputType) ||
79 (
sizeof (OutputType) ==
sizeof (InputType) &&
80 ! output_signed && input_signed);
84 template<
class InputType,
85 bool input_signed = std::is_signed<InputType>::value>
88 template<
class InputType>
89 struct Negative<InputType, true> {
90 static KOKKOS_INLINE_FUNCTION
bool
91 negative (
const InputType src) {
92 return src < InputType (0);
96 template<
class InputType>
97 struct Negative<InputType, false> {
98 static KOKKOS_INLINE_FUNCTION
bool
99 negative (
const InputType ) {
104 template<
class InputType>
105 KOKKOS_INLINE_FUNCTION
bool negative (
const InputType src) {
106 return Negative<InputType>::negative (src);
109 template<
class OutputType,
class InputType>
110 struct OverflowChecker {
112 static constexpr
bool output_signed = std::is_signed<OutputType>::value;
113 static constexpr
bool input_signed = std::is_signed<InputType>::value;
119 static constexpr
bool could_overflow =
120 (! output_signed && input_signed) ||
121 (
sizeof (OutputType) <
sizeof (InputType)) ||
122 (
sizeof (OutputType) ==
sizeof (InputType) &&
123 output_signed && ! input_signed);
125 KOKKOS_INLINE_FUNCTION
bool
126 overflows (
const InputType src)
const
128 if (! could_overflow) {
133 if (! output_signed && input_signed) {
134 return negative (src);
138 return src < minDstVal_ || src > maxDstVal_;
145 InputType minDstVal_ = input_signed ?
146 std::numeric_limits<OutputType>::min () : OutputType (0);
147 InputType maxDstVal_ = std::numeric_limits<OutputType>::max ();
151 template<
class OutputViewType,
class InputViewType>
153 errorIfOverflow (
const OutputViewType& dst,
154 const InputViewType& src,
155 const size_t overflowCount)
157 if (overflowCount == 0) {
161 std::ostringstream os;
162 const bool plural = overflowCount != size_t (1);
163 os <<
"copyOffsets: " << overflowCount <<
" value" <<
164 (plural ?
"s" :
"") <<
" in src were too big (in the "
165 "sense of integer overflow) to fit in dst.";
169 const size_t maxNumToPrint =
171 const size_t srcLen (src.extent (0));
172 if (srcLen <= maxNumToPrint) {
173 auto dst_h = Kokkos::create_mirror_view (dst);
174 auto src_h = Kokkos::create_mirror_view (src);
179 for (
size_t k = 0; k < srcLen; ++k) {
181 if (k +
size_t (1) < srcLen) {
188 for (
size_t k = 0; k < srcLen; ++k) {
190 if (k +
size_t (1) < srcLen) {
197 os <<
" src.extent(0) > " << maxNumToPrint <<
", Tpetra's "
198 "verbose print count threshold. To increase this, set the "
199 "environment variable TPETRA_VERBOSE_PRINT_COUNT_THRESHOLD "
200 "to the desired threshold and rerun. You do NOT need to "
204 TEUCHOS_TEST_FOR_EXCEPTION(
true, std::runtime_error, os.str ());
216 template<
class OutputViewType,
218 const bool outputCanFitInput =
219 OutputCanFitInput<
typename OutputViewType::non_const_value_type,
220 typename InputViewType::non_const_value_type>::value>
221 class CopyOffsetsFunctor {};
224 template<
class OutputViewType,
class InputViewType>
225 class CopyOffsetsFunctor<OutputViewType, InputViewType, false> {
227 using execution_space =
typename OutputViewType::execution_space;
228 using size_type =
typename OutputViewType::size_type;
229 using value_type = size_t;
231 using input_value_type =
typename InputViewType::non_const_value_type;
232 using output_value_type =
typename OutputViewType::non_const_value_type;
234 CopyOffsetsFunctor (
const OutputViewType& dst,
const InputViewType& src) :
235 dst_ (dst), src_ (src)
240 static_assert (Kokkos::Impl::VerifyExecutionCanAccessMemorySpace<
241 typename OutputViewType::memory_space,
242 typename InputViewType::memory_space>::value,
243 "CopyOffsetsFunctor (implements copyOffsets): Output "
244 "View's space must be able to access the input View's "
248 KOKKOS_INLINE_FUNCTION
void
249 operator () (
const size_type i, value_type& overflowCount)
const {
250 const input_value_type src_i = src_(i);
251 if (checker_.overflows (src_i)) {
254 dst_(i) =
static_cast<output_value_type
> (src_i);
257 KOKKOS_INLINE_FUNCTION
void
258 operator () (
const size_type i)
const {
259 const input_value_type src_i = src_(i);
260 dst_(i) =
static_cast<output_value_type
> (src_i);
263 KOKKOS_INLINE_FUNCTION
void init (value_type& overflowCount)
const {
267 KOKKOS_INLINE_FUNCTION
void
268 join (
volatile value_type& result,
269 const volatile value_type& current)
const {
276 OverflowChecker<output_value_type, input_value_type> checker_;
280 template<
class OutputViewType,
class InputViewType>
281 class CopyOffsetsFunctor<OutputViewType, InputViewType, true> {
283 using execution_space =
typename OutputViewType::execution_space;
284 using size_type =
typename OutputViewType::size_type;
285 using value_type = size_t;
287 CopyOffsetsFunctor (
const OutputViewType& dst,
const InputViewType& src) :
294 static_assert (Kokkos::Impl::VerifyExecutionCanAccessMemorySpace<
295 typename OutputViewType::memory_space,
296 typename InputViewType::memory_space>::value,
297 "CopyOffsetsFunctor (implements copyOffsets): Output "
298 "View's space must be able to access the input View's "
302 KOKKOS_INLINE_FUNCTION
void
303 operator () (
const size_type i, value_type& )
const {
308 KOKKOS_INLINE_FUNCTION
void
309 operator () (
const size_type i)
const {
313 KOKKOS_INLINE_FUNCTION
void init (value_type& overflowCount)
const {
317 KOKKOS_INLINE_FUNCTION
void
318 join (
volatile value_type& ,
319 const volatile value_type& )
const
346 template<
class OutputViewType,
348 const bool sameLayoutsSameOffsetTypes =
349 std::is_same<
typename OutputViewType::array_layout,
350 typename InputViewType::array_layout>::value &&
351 std::is_same<
typename OutputViewType::non_const_value_type,
352 typename InputViewType::non_const_value_type>::value,
353 const bool outputExecSpaceCanAccessInputMemSpace =
354 Kokkos::Impl::VerifyExecutionCanAccessMemorySpace<
355 typename OutputViewType::memory_space,
356 typename InputViewType::memory_space>::value>
357 struct CopyOffsetsImpl {
358 static void run (
const OutputViewType& dst,
const InputViewType& src);
369 template<
class OutputViewType,
371 const bool outputExecSpaceCanAccessInputMemSpace>
372 struct CopyOffsetsImpl<OutputViewType, InputViewType,
373 true, outputExecSpaceCanAccessInputMemSpace> {
374 static void run (
const OutputViewType& dst,
const InputViewType& src) {
375 static_assert (std::is_same<
typename OutputViewType::non_const_value_type,
376 typename InputViewType::non_const_value_type>::value,
377 "CopyOffsetsImpl (implementation of copyOffsets): In order"
378 " to call this specialization, the input and output must "
379 "use the same offset type.");
380 static_assert (static_cast<int> (OutputViewType::rank) ==
381 static_cast<int> (InputViewType::rank),
382 "CopyOffsetsImpl (implementation of copyOffsets): In order"
383 " to call this specialization, src and dst must have the "
385 static_assert (std::is_same<
typename OutputViewType::array_layout,
386 typename InputViewType::array_layout>::value,
387 "CopyOffsetsImpl (implementation of copyOffsets): In order"
388 " to call this specialization, src and dst must have the "
389 "the same array_layout.");
405 template<
class OutputViewType,
407 struct CopyOffsetsImpl<OutputViewType, InputViewType,
409 static void run (
const OutputViewType& dst,
const InputViewType& src) {
410 static_assert (static_cast<int> (OutputViewType::rank) ==
411 static_cast<int> (InputViewType::rank),
412 "CopyOffsetsImpl (implementation of copyOffsets): "
413 "src and dst must have the same rank.");
414 constexpr
bool sameLayoutsSameOffsetTypes =
415 std::is_same<
typename OutputViewType::array_layout,
416 typename InputViewType::array_layout>::value &&
417 std::is_same<
typename OutputViewType::non_const_value_type,
418 typename InputViewType::non_const_value_type>::value;
419 static_assert (! sameLayoutsSameOffsetTypes,
420 "CopyOffsetsImpl (implements copyOffsets): In order to "
421 "call this specialization, sameLayoutsSameOffsetTypes "
422 "must be false. That is, either the input and output "
423 "must have different array layouts, or their value types "
428 static_assert (Kokkos::Impl::VerifyExecutionCanAccessMemorySpace<
429 typename OutputViewType::memory_space,
430 typename InputViewType::memory_space>::value,
431 "CopyOffsetsImpl (implements copyOffsets): In order to "
432 "call this specialization, the output View's space must "
433 "be able to access the input View's memory space.");
434 using functor_type = CopyOffsetsFunctor<OutputViewType, InputViewType>;
435 using execution_space =
typename OutputViewType::execution_space;
436 using size_type =
typename OutputViewType::size_type;
437 using range_type = Kokkos::RangePolicy<execution_space, size_type>;
441 size_t overflowCount = 0;
442 Kokkos::parallel_reduce (
"Tpetra::Details::copyOffsets",
443 range_type (0, dst.extent (0)),
444 functor_type (dst, src),
446 errorIfOverflow (dst, src, overflowCount);
449 Kokkos::parallel_for (
"Tpetra::Details::copyOffsets",
450 range_type (0, dst.extent (0)),
451 functor_type (dst, src));
473 template<
class OutputViewType,
class InputViewType>
474 struct CopyOffsetsImpl<OutputViewType, InputViewType,
476 static void run (
const OutputViewType& dst,
const InputViewType& src) {
477 static_assert (static_cast<int> (OutputViewType::rank) ==
478 static_cast<int> (InputViewType::rank),
479 "CopyOffsetsImpl (implementation of copyOffsets): In order"
480 " to call this specialization, src and dst must have the "
482 constexpr
bool sameLayoutsSameOffsetTypes =
483 std::is_same<
typename OutputViewType::array_layout,
484 typename InputViewType::array_layout>::value &&
485 std::is_same<
typename OutputViewType::non_const_value_type,
486 typename InputViewType::non_const_value_type>::value;
487 static_assert (! sameLayoutsSameOffsetTypes,
488 "CopyOffsetsImpl (implements copyOffsets): In order to "
489 "call this specialization, sameLayoutsSameOffsetTypes "
490 "must be false. That is, either the input and output "
491 "must have different array layouts, or their value types "
493 using output_space_copy_type =
494 Kokkos::View<
typename InputViewType::non_const_value_type*,
495 Kokkos::LayoutLeft,
typename OutputViewType::device_type>;
496 using Kokkos::view_alloc;
497 using Kokkos::WithoutInitializing;
498 output_space_copy_type
499 outputSpaceCopy (view_alloc (
"outputSpace", WithoutInitializing),
506 CopyOffsetsFunctor<OutputViewType, output_space_copy_type>;
507 using execution_space =
typename OutputViewType::execution_space;
508 using size_type =
typename OutputViewType::size_type;
509 using range_type = Kokkos::RangePolicy<execution_space, size_type>;
513 size_t overflowCount = 0;
514 Kokkos::parallel_reduce (
"Tpetra::Details::copyOffsets",
515 range_type (0, dst.extent (0)),
516 functor_type (dst, outputSpaceCopy),
518 errorIfOverflow (dst, src, overflowCount);
521 Kokkos::parallel_for (
"Tpetra::Details::copyOffsets",
522 range_type (0, dst.extent (0)),
523 functor_type (dst, outputSpaceCopy));
540 template<
class OutputViewType,
class InputViewType>
544 static_assert (Kokkos::Impl::is_view<OutputViewType>::value,
545 "OutputViewType (the type of dst) must be a Kokkos::View.");
546 static_assert (Kokkos::Impl::is_view<InputViewType>::value,
547 "InputViewType (the type of src) must be a Kokkos::View.");
548 static_assert (std::is_same<
typename OutputViewType::value_type,
549 typename OutputViewType::non_const_value_type>::value,
550 "OutputViewType (the type of dst) must be a nonconst Kokkos::View.");
551 static_assert (static_cast<int> (OutputViewType::rank) == 1,
552 "OutputViewType (the type of dst) must be a rank-1 Kokkos::View.");
553 static_assert (static_cast<int> (InputViewType::rank) == 1,
554 "InputViewType (the type of src) must be a rank-1 Kokkos::View.");
555 static_assert (std::is_integral<
typename std::decay<decltype (dst(0)) >::type>::value,
556 "The entries of dst must be built-in integers.");
557 static_assert (std::is_integral<
typename std::decay<decltype (src(0)) >::type>::value,
558 "The entries of src must be built-in integers.");
560 TEUCHOS_TEST_FOR_EXCEPTION
561 (dst.extent (0) != src.extent (0), std::invalid_argument,
562 "copyOffsets: dst.extent(0) = " << dst.extent (0)
563 <<
" != src.extent(0) = " << src.extent (0) <<
".");
565 CopyOffsetsImpl<OutputViewType, InputViewType>::run (dst, src);
571 #endif // TPETRA_DETAILS_COPYOFFSETS_HPP
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...
static bool debug()
Whether Tpetra is in debug mode.
void deep_copy(MultiVector< DS, DL, DG, DN > &dst, const MultiVector< SS, SL, SG, SN > &src)
Copy the contents of the MultiVector src into dst.
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.
Declaration of Tpetra::Details::Behavior, a class that describes Tpetra's behavior.