You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
288 lines
11 KiB
288 lines
11 KiB
11 years ago
|
/*
|
||
|
* Copyright 2008-2012 NVIDIA Corporation
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
|
||
|
/*! \file sort.inl
|
||
|
* \brief Inline file for sort.h
|
||
|
*/
|
||
|
|
||
|
#include <thrust/system/cuda/detail/detail/stable_merge_sort.h>
|
||
|
#include <thrust/system/cuda/detail/detail/stable_primitive_sort.h>
|
||
|
|
||
|
#include <thrust/reverse.h>
|
||
|
#include <thrust/iterator/iterator_traits.h>
|
||
|
#include <thrust/detail/type_traits.h>
|
||
|
#include <thrust/system/cuda/detail/execution_policy.h>
|
||
|
#include <thrust/system/cuda/detail/temporary_indirect_permutation.h>
|
||
|
#include <thrust/detail/trivial_sequence.h>
|
||
|
|
||
|
|
||
|
/*
|
||
|
* This file implements the following dispatch procedure for cuda::stable_sort()
|
||
|
* and cuda::stable_sort_by_key(). The first level inspects the KeyType
|
||
|
* and StrictWeakOrdering to determine whether a sort assuming primitive-typed
|
||
|
* data may be applied.
|
||
|
*
|
||
|
* If a sort assuming primitive-typed data can be applied (i.e., a radix sort),
|
||
|
* the input ranges are first trivialized (turned into simple contiguous ranges
|
||
|
* if they are not already). To implement descending orderings, an ascending
|
||
|
* sort will be reversed.
|
||
|
*
|
||
|
* If a sort assuming primitive-typed data cannot be applied, a comparison-based
|
||
|
* sort is used. Depending on the size of the key and value types, one level of
|
||
|
* indirection may be applied to their input ranges. This transformation
|
||
|
* may be applied to either range to convert an ill-suited problem (i.e. sorting with
|
||
|
* large keys or large value) into a problem more amenable to the underlying
|
||
|
* merge sort algorithm.
|
||
|
*/
|
||
|
|
||
|
|
||
|
namespace thrust
|
||
|
{
|
||
|
namespace system
|
||
|
{
|
||
|
namespace cuda
|
||
|
{
|
||
|
namespace detail
|
||
|
{
|
||
|
|
||
|
|
||
|
namespace stable_sort_detail
|
||
|
{
|
||
|
|
||
|
|
||
|
template<typename KeyType, typename StrictWeakCompare>
|
||
|
struct can_use_primitive_sort
|
||
|
: thrust::detail::and_<
|
||
|
thrust::detail::is_arithmetic<KeyType>,
|
||
|
thrust::detail::or_<
|
||
|
thrust::detail::is_same<StrictWeakCompare,thrust::less<KeyType> >,
|
||
|
thrust::detail::is_same<StrictWeakCompare,thrust::greater<KeyType> >
|
||
|
>
|
||
|
>
|
||
|
{};
|
||
|
|
||
|
|
||
|
template<typename RandomAccessIterator, typename StrictWeakCompare>
|
||
|
struct enable_if_primitive_sort
|
||
|
: thrust::detail::enable_if<
|
||
|
can_use_primitive_sort<
|
||
|
typename iterator_value<RandomAccessIterator>::type,
|
||
|
StrictWeakCompare
|
||
|
>::value
|
||
|
>
|
||
|
{};
|
||
|
|
||
|
|
||
|
template<typename RandomAccessIterator, typename StrictWeakCompare>
|
||
|
struct enable_if_comparison_sort
|
||
|
: thrust::detail::disable_if<
|
||
|
can_use_primitive_sort<
|
||
|
typename iterator_value<RandomAccessIterator>::type,
|
||
|
StrictWeakCompare
|
||
|
>::value
|
||
|
>
|
||
|
{};
|
||
|
|
||
|
|
||
|
template<typename DerivedPolicy,
|
||
|
typename RandomAccessIterator,
|
||
|
typename StrictWeakOrdering>
|
||
|
typename enable_if_primitive_sort<RandomAccessIterator,StrictWeakOrdering>::type
|
||
|
stable_sort(execution_policy<DerivedPolicy> &exec,
|
||
|
RandomAccessIterator first,
|
||
|
RandomAccessIterator last,
|
||
|
StrictWeakOrdering comp)
|
||
|
{
|
||
|
// ensure sequence has trivial iterators
|
||
|
thrust::detail::trivial_sequence<RandomAccessIterator,DerivedPolicy> keys(exec, first, last);
|
||
|
|
||
|
// CUDA path for thrust::stable_sort with primitive keys
|
||
|
// (e.g. int, float, short, etc.) and a less<T> or greater<T> comparison
|
||
|
// method is implemented with a primitive sort
|
||
|
thrust::system::cuda::detail::detail::stable_primitive_sort(exec, keys.begin(), keys.end());
|
||
|
|
||
|
// copy results back, if necessary
|
||
|
if(!thrust::detail::is_trivial_iterator<RandomAccessIterator>::value)
|
||
|
{
|
||
|
thrust::copy(exec, keys.begin(), keys.end(), first);
|
||
|
}
|
||
|
|
||
|
// if comp is greater<T> then reverse the keys
|
||
|
typedef typename thrust::iterator_traits<RandomAccessIterator>::value_type KeyType;
|
||
|
const static bool reverse = thrust::detail::is_same<StrictWeakOrdering, typename thrust::greater<KeyType> >::value;
|
||
|
|
||
|
if(reverse)
|
||
|
{
|
||
|
thrust::reverse(first, last);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
template<typename DerivedPolicy,
|
||
|
typename RandomAccessIterator,
|
||
|
typename StrictWeakOrdering>
|
||
|
typename enable_if_comparison_sort<RandomAccessIterator,StrictWeakOrdering>::type
|
||
|
stable_sort(execution_policy<DerivedPolicy> &exec,
|
||
|
RandomAccessIterator first,
|
||
|
RandomAccessIterator last,
|
||
|
StrictWeakOrdering comp)
|
||
|
{
|
||
|
// decide whether to sort keys indirectly
|
||
|
typedef typename thrust::iterator_value<RandomAccessIterator>::type KeyType;
|
||
|
typedef thrust::detail::integral_constant<bool, (sizeof(KeyType) > 8)> use_key_indirection;
|
||
|
|
||
|
conditional_temporary_indirect_ordering<use_key_indirection, DerivedPolicy, RandomAccessIterator, StrictWeakOrdering> potentially_indirect_keys(derived_cast(exec), first, last, comp);
|
||
|
|
||
|
thrust::system::cuda::detail::detail::stable_merge_sort(exec,
|
||
|
potentially_indirect_keys.begin(),
|
||
|
potentially_indirect_keys.end(),
|
||
|
potentially_indirect_keys.comp());
|
||
|
}
|
||
|
|
||
|
template<typename DerivedPolicy,
|
||
|
typename RandomAccessIterator1,
|
||
|
typename RandomAccessIterator2,
|
||
|
typename StrictWeakOrdering>
|
||
|
typename enable_if_primitive_sort<RandomAccessIterator1,StrictWeakOrdering>::type
|
||
|
stable_sort_by_key(execution_policy<DerivedPolicy> &exec,
|
||
|
RandomAccessIterator1 keys_first,
|
||
|
RandomAccessIterator1 keys_last,
|
||
|
RandomAccessIterator2 values_first,
|
||
|
StrictWeakOrdering comp)
|
||
|
{
|
||
|
// path for thrust::stable_sort_by_key with primitive keys
|
||
|
// (e.g. int, float, short, etc.) and a less<T> or greater<T> comparison
|
||
|
// method is implemented with stable_primitive_sort_by_key
|
||
|
|
||
|
// if comp is greater<T> then reverse the keys and values
|
||
|
typedef typename thrust::iterator_traits<RandomAccessIterator1>::value_type KeyType;
|
||
|
const static bool reverse = thrust::detail::is_same<StrictWeakOrdering, typename thrust::greater<KeyType> >::value;
|
||
|
|
||
|
// note, we also have to reverse the (unordered) input to preserve stability
|
||
|
if (reverse)
|
||
|
{
|
||
|
thrust::reverse(exec, keys_first, keys_last);
|
||
|
thrust::reverse(exec, values_first, values_first + (keys_last - keys_first));
|
||
|
}
|
||
|
|
||
|
// ensure sequences have trivial iterators
|
||
|
thrust::detail::trivial_sequence<RandomAccessIterator1,DerivedPolicy> keys(exec, keys_first, keys_last);
|
||
|
thrust::detail::trivial_sequence<RandomAccessIterator2,DerivedPolicy> values(exec, values_first, values_first + (keys_last - keys_first));
|
||
|
|
||
|
thrust::system::cuda::detail::detail::stable_primitive_sort_by_key(exec, keys.begin(), keys.end(), values.begin());
|
||
|
|
||
|
// copy results back, if necessary
|
||
|
if(!thrust::detail::is_trivial_iterator<RandomAccessIterator1>::value)
|
||
|
thrust::copy(exec, keys.begin(), keys.end(), keys_first);
|
||
|
if(!thrust::detail::is_trivial_iterator<RandomAccessIterator2>::value)
|
||
|
thrust::copy(exec, values.begin(), values.end(), values_first);
|
||
|
|
||
|
if (reverse)
|
||
|
{
|
||
|
thrust::reverse(exec, keys_first, keys_last);
|
||
|
thrust::reverse(exec, values_first, values_first + (keys_last - keys_first));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
template<typename DerivedPolicy,
|
||
|
typename RandomAccessIterator1,
|
||
|
typename RandomAccessIterator2,
|
||
|
typename StrictWeakOrdering>
|
||
|
typename enable_if_comparison_sort<RandomAccessIterator1,StrictWeakOrdering>::type
|
||
|
stable_sort_by_key(execution_policy<DerivedPolicy> &exec,
|
||
|
RandomAccessIterator1 keys_first,
|
||
|
RandomAccessIterator1 keys_last,
|
||
|
RandomAccessIterator2 values_first,
|
||
|
StrictWeakOrdering comp)
|
||
|
{
|
||
|
// decide whether to apply indirection to either range
|
||
|
typedef typename thrust::iterator_value<RandomAccessIterator1>::type KeyType;
|
||
|
typedef typename thrust::iterator_value<RandomAccessIterator2>::type ValueType;
|
||
|
|
||
|
typedef thrust::detail::integral_constant<bool, (sizeof(KeyType) > 8)> use_key_indirection;
|
||
|
typedef thrust::detail::integral_constant<bool, (sizeof(ValueType) > 4)> use_value_indirection;
|
||
|
|
||
|
conditional_temporary_indirect_ordering<
|
||
|
use_key_indirection,
|
||
|
DerivedPolicy,
|
||
|
RandomAccessIterator1,
|
||
|
StrictWeakOrdering
|
||
|
> potentially_indirect_keys(derived_cast(exec), keys_first, keys_last, comp);
|
||
|
|
||
|
conditional_temporary_indirect_permutation<
|
||
|
use_value_indirection,
|
||
|
DerivedPolicy,
|
||
|
RandomAccessIterator2
|
||
|
> potentially_indirect_values(derived_cast(exec), values_first, values_first + (keys_last - keys_first));
|
||
|
|
||
|
thrust::system::cuda::detail::detail::stable_merge_sort_by_key(exec,
|
||
|
potentially_indirect_keys.begin(),
|
||
|
potentially_indirect_keys.end(),
|
||
|
potentially_indirect_values.begin(),
|
||
|
potentially_indirect_keys.comp());
|
||
|
}
|
||
|
|
||
|
|
||
|
} // end namespace stable_sort_detail
|
||
|
|
||
|
|
||
|
template<typename DerivedPolicy,
|
||
|
typename RandomAccessIterator,
|
||
|
typename StrictWeakOrdering>
|
||
|
void stable_sort(execution_policy<DerivedPolicy> &exec,
|
||
|
RandomAccessIterator first,
|
||
|
RandomAccessIterator last,
|
||
|
StrictWeakOrdering comp)
|
||
|
{
|
||
|
// we're attempting to launch a kernel, assert we're compiling with nvcc
|
||
|
// ========================================================================
|
||
|
// X Note to the user: If you've found this line due to a compiler error, X
|
||
|
// X you need to compile your code using nvcc, rather than g++ or cl.exe X
|
||
|
// ========================================================================
|
||
|
THRUST_STATIC_ASSERT( (thrust::detail::depend_on_instantiation<RandomAccessIterator, THRUST_DEVICE_COMPILER == THRUST_DEVICE_COMPILER_NVCC>::value) );
|
||
|
|
||
|
stable_sort_detail::stable_sort(exec, first, last, comp);
|
||
|
}
|
||
|
|
||
|
|
||
|
template<typename DerivedPolicy,
|
||
|
typename RandomAccessIterator1,
|
||
|
typename RandomAccessIterator2,
|
||
|
typename StrictWeakOrdering>
|
||
|
void stable_sort_by_key(execution_policy<DerivedPolicy> &exec,
|
||
|
RandomAccessIterator1 keys_first,
|
||
|
RandomAccessIterator1 keys_last,
|
||
|
RandomAccessIterator2 values_first,
|
||
|
StrictWeakOrdering comp)
|
||
|
{
|
||
|
// we're attempting to launch a kernel, assert we're compiling with nvcc
|
||
|
// ========================================================================
|
||
|
// X Note to the user: If you've found this line due to a compiler error, X
|
||
|
// X you need to compile your code using nvcc, rather than g++ or cl.exe X
|
||
|
// ========================================================================
|
||
|
THRUST_STATIC_ASSERT( (thrust::detail::depend_on_instantiation<RandomAccessIterator1, THRUST_DEVICE_COMPILER == THRUST_DEVICE_COMPILER_NVCC>::value) );
|
||
|
|
||
|
stable_sort_detail::stable_sort_by_key(exec, keys_first, keys_last, values_first, comp);
|
||
|
}
|
||
|
|
||
|
|
||
|
} // end namespace detail
|
||
|
} // end namespace cuda
|
||
|
} // end namespace system
|
||
|
} // end namespace thrust
|
||
|
|