44 #ifndef TPETRA_DETAILS_COPYOFFSETS_HPP
45 #define TPETRA_DETAILS_COPYOFFSETS_HPP
52 #include "TpetraCore_config.h"
54 #include "Kokkos_Core.hpp"
56 #include <type_traits>
73 template<
class OutputType,
class InputType>
74 struct OutputCanFitInput {
76 static constexpr
bool output_signed = std::is_signed<OutputType>::value;
77 static constexpr
bool input_signed = std::is_signed<InputType>::value;
80 static const bool value =
sizeof (OutputType) >
sizeof (InputType) ||
81 (
sizeof (OutputType) ==
sizeof (InputType) &&
82 ! output_signed && input_signed);
86 template<
class InputType,
87 bool input_signed = std::is_signed<InputType>::value>
90 template<
class InputType>
91 struct Negative<InputType, true> {
92 static KOKKOS_INLINE_FUNCTION
bool
93 negative (
const InputType src) {
94 return src < InputType (0);
98 template<
class InputType>
99 struct Negative<InputType, false> {
100 static KOKKOS_INLINE_FUNCTION
bool
101 negative (
const InputType ) {
106 template<
class InputType>
107 KOKKOS_INLINE_FUNCTION
bool negative (
const InputType src) {
108 return Negative<InputType>::negative (src);
111 template<
class OutputType,
class InputType>
112 struct OverflowChecker {
114 static constexpr
bool output_signed = std::is_signed<OutputType>::value;
115 static constexpr
bool input_signed = std::is_signed<InputType>::value;
121 static constexpr
bool could_overflow =
122 (! output_signed && input_signed) ||
123 (
sizeof (OutputType) <
sizeof (InputType)) ||
124 (
sizeof (OutputType) ==
sizeof (InputType) &&
125 output_signed && ! input_signed);
127 KOKKOS_INLINE_FUNCTION
bool
128 overflows (
const InputType src)
const
130 if (! could_overflow) {
135 if (! output_signed && input_signed) {
136 return negative (src);
140 return src < minDstVal_ || src > maxDstVal_;
147 InputType minDstVal_ = input_signed ?
148 std::numeric_limits<OutputType>::min () : OutputType (0);
149 InputType maxDstVal_ = std::numeric_limits<OutputType>::max ();
153 template<
class OutputViewType,
class InputViewType>
155 errorIfOverflow (
const OutputViewType& dst,
156 const InputViewType& src,
157 const size_t overflowCount)
159 if (overflowCount == 0) {
163 std::ostringstream os;
164 const bool plural = overflowCount != size_t (1);
165 os <<
"copyOffsets: " << overflowCount <<
" value" <<
166 (plural ?
"s" :
"") <<
" in src were too big (in the "
167 "sense of integer overflow) to fit in dst.";
171 constexpr
size_t maxNumToPrint = 100;
172 const size_t srcLen (src.extent (0));
173 if (srcLen <= maxNumToPrint) {
174 auto dst_h = Kokkos::create_mirror_view (dst);
175 auto src_h = Kokkos::create_mirror_view (src);
180 for (
size_t k = 0; k < srcLen; ++k) {
182 if (k +
size_t (1) < srcLen) {
189 for (
size_t k = 0; k < srcLen; ++k) {
191 if (k +
size_t (1) < srcLen) {
198 os <<
" src and dst are too long to print.";
201 TEUCHOS_TEST_FOR_EXCEPTION(
true, std::runtime_error, os.str ());
213 template<
class OutputViewType,
215 const bool outputCanFitInput =
216 OutputCanFitInput<
typename OutputViewType::non_const_value_type,
217 typename InputViewType::non_const_value_type>::value>
218 class CopyOffsetsFunctor {};
221 template<
class OutputViewType,
class InputViewType>
222 class CopyOffsetsFunctor<OutputViewType, InputViewType, false> {
224 using execution_space =
typename OutputViewType::execution_space;
225 using size_type =
typename OutputViewType::size_type;
226 using value_type = size_t;
228 using input_value_type =
typename InputViewType::non_const_value_type;
229 using output_value_type =
typename OutputViewType::non_const_value_type;
231 CopyOffsetsFunctor (
const OutputViewType& dst,
const InputViewType& src) :
232 dst_ (dst), src_ (src)
237 static_assert (Kokkos::Impl::VerifyExecutionCanAccessMemorySpace<
238 typename OutputViewType::memory_space,
239 typename InputViewType::memory_space>::value,
240 "CopyOffsetsFunctor (implements copyOffsets): Output "
241 "View's space must be able to access the input View's "
245 KOKKOS_INLINE_FUNCTION
void
246 operator () (
const size_type i, value_type& overflowCount)
const {
247 const input_value_type src_i = src_(i);
248 if (checker_.overflows (src_i)) {
251 dst_(i) =
static_cast<output_value_type
> (src_i);
254 KOKKOS_INLINE_FUNCTION
void
255 operator () (
const size_type i)
const {
256 const input_value_type src_i = src_(i);
257 dst_(i) =
static_cast<output_value_type
> (src_i);
260 KOKKOS_INLINE_FUNCTION
void init (value_type& overflowCount)
const {
264 KOKKOS_INLINE_FUNCTION
void
265 join (
volatile value_type& result,
266 const volatile value_type& current)
const {
273 OverflowChecker<output_value_type, input_value_type> checker_;
277 template<
class OutputViewType,
class InputViewType>
278 class CopyOffsetsFunctor<OutputViewType, InputViewType, true> {
280 using execution_space =
typename OutputViewType::execution_space;
281 using size_type =
typename OutputViewType::size_type;
282 using value_type = size_t;
284 CopyOffsetsFunctor (
const OutputViewType& dst,
const InputViewType& src) :
291 static_assert (Kokkos::Impl::VerifyExecutionCanAccessMemorySpace<
292 typename OutputViewType::memory_space,
293 typename InputViewType::memory_space>::value,
294 "CopyOffsetsFunctor (implements copyOffsets): Output "
295 "View's space must be able to access the input View's "
299 KOKKOS_INLINE_FUNCTION
void
300 operator () (
const size_type i, value_type& )
const {
305 KOKKOS_INLINE_FUNCTION
void
306 operator () (
const size_type i)
const {
310 KOKKOS_INLINE_FUNCTION
void init (value_type& overflowCount)
const {
314 KOKKOS_INLINE_FUNCTION
void
315 join (
volatile value_type& ,
316 const volatile value_type& )
const
343 template<
class OutputViewType,
345 const bool sameLayoutsSameOffsetTypes =
346 std::is_same<
typename OutputViewType::array_layout,
347 typename InputViewType::array_layout>::value &&
348 std::is_same<
typename OutputViewType::non_const_value_type,
349 typename InputViewType::non_const_value_type>::value,
350 const bool outputExecSpaceCanAccessInputMemSpace =
351 Kokkos::Impl::VerifyExecutionCanAccessMemorySpace<
352 typename OutputViewType::memory_space,
353 typename InputViewType::memory_space>::value>
354 struct CopyOffsetsImpl {
355 static void run (
const OutputViewType& dst,
const InputViewType& src);
366 template<
class OutputViewType,
368 const bool outputExecSpaceCanAccessInputMemSpace>
369 struct CopyOffsetsImpl<OutputViewType, InputViewType,
370 true, outputExecSpaceCanAccessInputMemSpace> {
371 static void run (
const OutputViewType& dst,
const InputViewType& src) {
372 static_assert (std::is_same<
typename OutputViewType::non_const_value_type,
373 typename InputViewType::non_const_value_type>::value,
374 "CopyOffsetsImpl (implementation of copyOffsets): In order"
375 " to call this specialization, the input and output must "
376 "use the same offset type.");
377 static_assert (static_cast<int> (OutputViewType::rank) ==
378 static_cast<int> (InputViewType::rank),
379 "CopyOffsetsImpl (implementation of copyOffsets): In order"
380 " to call this specialization, src and dst must have the "
382 static_assert (std::is_same<
typename OutputViewType::array_layout,
383 typename InputViewType::array_layout>::value,
384 "CopyOffsetsImpl (implementation of copyOffsets): In order"
385 " to call this specialization, src and dst must have the "
386 "the same array_layout.");
402 template<
class OutputViewType,
404 struct CopyOffsetsImpl<OutputViewType, InputViewType,
406 static void run (
const OutputViewType& dst,
const InputViewType& src) {
407 static_assert (static_cast<int> (OutputViewType::rank) ==
408 static_cast<int> (InputViewType::rank),
409 "CopyOffsetsImpl (implementation of copyOffsets): "
410 "src and dst must have the same rank.");
411 constexpr
bool sameLayoutsSameOffsetTypes =
412 std::is_same<
typename OutputViewType::array_layout,
413 typename InputViewType::array_layout>::value &&
414 std::is_same<
typename OutputViewType::non_const_value_type,
415 typename InputViewType::non_const_value_type>::value;
416 static_assert (! sameLayoutsSameOffsetTypes,
417 "CopyOffsetsImpl (implements copyOffsets): In order to "
418 "call this specialization, sameLayoutsSameOffsetTypes "
419 "must be false. That is, either the input and output "
420 "must have different array layouts, or their value types "
425 static_assert (Kokkos::Impl::VerifyExecutionCanAccessMemorySpace<
426 typename OutputViewType::memory_space,
427 typename InputViewType::memory_space>::value,
428 "CopyOffsetsImpl (implements copyOffsets): In order to "
429 "call this specialization, the output View's space must "
430 "be able to access the input View's memory space.");
431 using functor_type = CopyOffsetsFunctor<OutputViewType, InputViewType>;
432 using execution_space =
typename OutputViewType::execution_space;
433 using size_type =
typename OutputViewType::size_type;
434 using range_type = Kokkos::RangePolicy<execution_space, size_type>;
438 size_t overflowCount = 0;
439 Kokkos::parallel_reduce (
"Tpetra::Details::copyOffsets",
440 range_type (0, dst.extent (0)),
441 functor_type (dst, src),
443 errorIfOverflow (dst, src, overflowCount);
446 Kokkos::parallel_for (
"Tpetra::Details::copyOffsets",
447 range_type (0, dst.extent (0)),
448 functor_type (dst, src));
470 template<
class OutputViewType,
class InputViewType>
471 struct CopyOffsetsImpl<OutputViewType, InputViewType,
473 static void run (
const OutputViewType& dst,
const InputViewType& src) {
474 static_assert (static_cast<int> (OutputViewType::rank) ==
475 static_cast<int> (InputViewType::rank),
476 "CopyOffsetsImpl (implementation of copyOffsets): In order"
477 " to call this specialization, src and dst must have the "
479 constexpr
bool sameLayoutsSameOffsetTypes =
480 std::is_same<
typename OutputViewType::array_layout,
481 typename InputViewType::array_layout>::value &&
482 std::is_same<
typename OutputViewType::non_const_value_type,
483 typename InputViewType::non_const_value_type>::value;
484 static_assert (! sameLayoutsSameOffsetTypes,
485 "CopyOffsetsImpl (implements copyOffsets): In order to "
486 "call this specialization, sameLayoutsSameOffsetTypes "
487 "must be false. That is, either the input and output "
488 "must have different array layouts, or their value types "
490 using output_space_copy_type =
491 Kokkos::View<
typename InputViewType::non_const_value_type*,
492 Kokkos::LayoutLeft,
typename OutputViewType::device_type>;
493 using Kokkos::view_alloc;
494 using Kokkos::WithoutInitializing;
495 output_space_copy_type
496 outputSpaceCopy (view_alloc (
"outputSpace", WithoutInitializing),
503 CopyOffsetsFunctor<OutputViewType, output_space_copy_type>;
504 using execution_space =
typename OutputViewType::execution_space;
505 using size_type =
typename OutputViewType::size_type;
506 using range_type = Kokkos::RangePolicy<execution_space, size_type>;
510 size_t overflowCount = 0;
511 Kokkos::parallel_reduce (
"Tpetra::Details::copyOffsets",
512 range_type (0, dst.extent (0)),
513 functor_type (dst, outputSpaceCopy),
515 errorIfOverflow (dst, src, overflowCount);
518 Kokkos::parallel_for (
"Tpetra::Details::copyOffsets",
519 range_type (0, dst.extent (0)),
520 functor_type (dst, outputSpaceCopy));
537 template<
class OutputViewType,
class InputViewType>
541 static_assert (Kokkos::Impl::is_view<OutputViewType>::value,
542 "OutputViewType (the type of dst) must be a Kokkos::View.");
543 static_assert (Kokkos::Impl::is_view<InputViewType>::value,
544 "InputViewType (the type of src) must be a Kokkos::View.");
545 static_assert (std::is_same<
typename OutputViewType::value_type,
546 typename OutputViewType::non_const_value_type>::value,
547 "OutputViewType (the type of dst) must be a nonconst Kokkos::View.");
548 static_assert (static_cast<int> (OutputViewType::rank) == 1,
549 "OutputViewType (the type of dst) must be a rank-1 Kokkos::View.");
550 static_assert (static_cast<int> (InputViewType::rank) == 1,
551 "InputViewType (the type of src) must be a rank-1 Kokkos::View.");
552 static_assert (std::is_integral<
typename std::decay<decltype (dst(0)) >::type>::value,
553 "The entries of dst must be built-in integers.");
554 static_assert (std::is_integral<
typename std::decay<decltype (src(0)) >::type>::value,
555 "The entries of src must be built-in integers.");
557 TEUCHOS_TEST_FOR_EXCEPTION
558 (dst.extent (0) != src.extent (0), std::invalid_argument,
559 "copyOffsets: dst.extent(0) = " << dst.extent (0)
560 <<
" != src.extent(0) = " << src.extent (0) <<
".");
562 CopyOffsetsImpl<OutputViewType, InputViewType>::run (dst, src);
568 #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.
Declaration of Tpetra::Details::Behavior, a class that describes Tpetra's behavior.