HW2: First locally working version of the 2 variations
This commit is contained in:
parent
4d1d7502aa
commit
c5ffec9cca
@ -185,6 +185,8 @@ distbubbletonic: CFLAGS := $(REL_CFLAGS) -DCODE_VERSION=BUBBLETONIC
|
|||||||
distbubbletonic: CXXFLAGS := $(REL_CXXFLAGS) -DCODE_VERSION=BUBBLETONIC
|
distbubbletonic: CXXFLAGS := $(REL_CXXFLAGS) -DCODE_VERSION=BUBBLETONIC
|
||||||
distbubbletonic: TARGET := distbubbletonic
|
distbubbletonic: TARGET := distbubbletonic
|
||||||
distbubbletonic: $(BUILD_DIR)/$(TARGET)
|
distbubbletonic: $(BUILD_DIR)/$(TARGET)
|
||||||
|
@mkdir -p out
|
||||||
|
cp $(BUILD_DIR)/$(TARGET) out/$(TARGET)
|
||||||
|
|
||||||
distbitonic: CC := mpicc
|
distbitonic: CC := mpicc
|
||||||
distbitonic: CXX := mpic++
|
distbitonic: CXX := mpic++
|
||||||
@ -192,6 +194,8 @@ distbitonic: CFLAGS := $(REL_CFLAGS) -DCODE_VERSION=BITONIC
|
|||||||
distbitonic: CXXFLAGS := $(REL_CXXFLAGS) -DCODE_VERSION=BITONIC
|
distbitonic: CXXFLAGS := $(REL_CXXFLAGS) -DCODE_VERSION=BITONIC
|
||||||
distbitonic: TARGET := distbitonic
|
distbitonic: TARGET := distbitonic
|
||||||
distbitonic: $(BUILD_DIR)/$(TARGET)
|
distbitonic: $(BUILD_DIR)/$(TARGET)
|
||||||
|
@mkdir -p out
|
||||||
|
cp $(BUILD_DIR)/$(TARGET) out/$(TARGET)
|
||||||
|
|
||||||
deb_distbubbletonic: CC := mpicc
|
deb_distbubbletonic: CC := mpicc
|
||||||
deb_distbubbletonic: CXX := mpic++
|
deb_distbubbletonic: CXX := mpic++
|
||||||
@ -199,6 +203,8 @@ deb_distbubbletonic: CFLAGS := $(DEB_CFLAGS) -DCODE_VERSION=BUBBLETONIC -DDEBUG
|
|||||||
deb_distbubbletonic: CXXFLAGS := $(DEB_CXXFLAGS) -DCODE_VERSION=BUBBLETONIC -DDEBUG
|
deb_distbubbletonic: CXXFLAGS := $(DEB_CXXFLAGS) -DCODE_VERSION=BUBBLETONIC -DDEBUG
|
||||||
deb_distbubbletonic: TARGET := deb_distbubbletonic
|
deb_distbubbletonic: TARGET := deb_distbubbletonic
|
||||||
deb_distbubbletonic: $(BUILD_DIR)/$(TARGET)
|
deb_distbubbletonic: $(BUILD_DIR)/$(TARGET)
|
||||||
|
@mkdir -p out
|
||||||
|
cp $(BUILD_DIR)/$(TARGET) out/$(TARGET)
|
||||||
|
|
||||||
deb_distbitonic: CC := mpicc
|
deb_distbitonic: CC := mpicc
|
||||||
deb_distbitonic: CXX := mpic++
|
deb_distbitonic: CXX := mpic++
|
||||||
@ -206,6 +212,8 @@ deb_distbitonic: CFLAGS := $(DEB_CFLAGS) -DCODE_VERSION=BITONIC -DDEBUG
|
|||||||
deb_distbitonic: CXXFLAGS := $(DEB_CXXFLAGS) -DCODE_VERSION=BITONIC -DDEBUG
|
deb_distbitonic: CXXFLAGS := $(DEB_CXXFLAGS) -DCODE_VERSION=BITONIC -DDEBUG
|
||||||
deb_distbitonic: TARGET := deb_distbitonic
|
deb_distbitonic: TARGET := deb_distbitonic
|
||||||
deb_distbitonic: $(BUILD_DIR)/$(TARGET)
|
deb_distbitonic: $(BUILD_DIR)/$(TARGET)
|
||||||
|
@mkdir -p out
|
||||||
|
cp $(BUILD_DIR)/$(TARGET) out/$(TARGET)
|
||||||
|
|
||||||
tests: CC := mpicc
|
tests: CC := mpicc
|
||||||
tests: CXX := mpic++
|
tests: CXX := mpic++
|
||||||
@ -213,6 +221,14 @@ tests: CFLAGS := $(DEB_CFLAGS) -DCODE_VERSION=BITONIC -DDEBUG -DTESTING
|
|||||||
tests: CXXFLAGS := $(DEB_CXXFLAGS) -DCODE_VERSION=BITONIC -DDEBUG -DTESTING
|
tests: CXXFLAGS := $(DEB_CXXFLAGS) -DCODE_VERSION=BITONIC -DDEBUG -DTESTING
|
||||||
tests: TARGET := tests
|
tests: TARGET := tests
|
||||||
tests: $(BUILD_DIR)/$(TARGET)
|
tests: $(BUILD_DIR)/$(TARGET)
|
||||||
|
@mkdir -p out
|
||||||
|
cp $(BUILD_DIR)/$(TARGET) out/$(TARGET)
|
||||||
|
|
||||||
|
measurements:
|
||||||
|
make clean
|
||||||
|
make distbubbletonic
|
||||||
|
make clean
|
||||||
|
make distbitonic
|
||||||
|
|
||||||
|
|
||||||
all: debug distbubbletonic distbitonic
|
all: debug distbubbletonic distbitonic
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Value type selection
|
// Value type selection
|
||||||
using distValue_t = uint8_t;
|
using distValue_t = uint32_t;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Session option for each invocation of the executable
|
* Session option for each invocation of the executable
|
||||||
|
@ -45,8 +45,8 @@ template <SortMode Mode> inline bool ascending(mpi_id_t, [[maybe_unused]] size_t
|
|||||||
* Returns the ascending or descending configuration of the node's sequence based on
|
* Returns the ascending or descending configuration of the node's sequence based on
|
||||||
* the current node (MPI process) and the depth of the sorting network
|
* the current node (MPI process) and the depth of the sorting network
|
||||||
*
|
*
|
||||||
* @param node The current node (MPI process)
|
* @param node [mpi_id_t] The current node (MPI process)
|
||||||
* @return True if we need ascending configuration, false otherwise
|
* @return [bool] True if we need ascending configuration, false otherwise
|
||||||
*/
|
*/
|
||||||
template <> inline
|
template <> inline
|
||||||
bool ascending<SortMode::Bubbletonic>(mpi_id_t node, [[maybe_unused]] size_t depth) noexcept {
|
bool ascending<SortMode::Bubbletonic>(mpi_id_t node, [[maybe_unused]] size_t depth) noexcept {
|
||||||
@ -57,10 +57,9 @@ bool ascending<SortMode::Bubbletonic>(mpi_id_t node, [[maybe_unused]] size_t dep
|
|||||||
* Returns the ascending or descending configuration of the node's sequence based on
|
* Returns the ascending or descending configuration of the node's sequence based on
|
||||||
* the current node (MPI process) and the depth of the sorting network
|
* the current node (MPI process) and the depth of the sorting network
|
||||||
*
|
*
|
||||||
* @param node The current node (MPI process)
|
* @param node [mpi_id_t] The current node (MPI process)
|
||||||
* @param depth The total depth of the sorting network (same for each step for a given network)
|
* @param depth [size_t] The total depth of the sorting network (same for each step for a given network)
|
||||||
*
|
* @return [bool] True if we need ascending configuration, false otherwise
|
||||||
* @return True if we need ascending configuration, false otherwise
|
|
||||||
*/
|
*/
|
||||||
template <> inline
|
template <> inline
|
||||||
bool ascending<SortMode::Bitonic>(mpi_id_t node, size_t depth) noexcept {
|
bool ascending<SortMode::Bitonic>(mpi_id_t node, size_t depth) noexcept {
|
||||||
@ -77,9 +76,9 @@ template <SortMode Mode> inline mpi_id_t partner(mpi_id_t, size_t) noexcept = de
|
|||||||
* Returns the node's partner for data exchange during the sorting network iterations
|
* Returns the node's partner for data exchange during the sorting network iterations
|
||||||
* of Bubbletonic
|
* of Bubbletonic
|
||||||
*
|
*
|
||||||
* @param node The current node
|
* @param node [mpi_id_t] The current node
|
||||||
* @param step The step of the sorting network
|
* @param step [size_t] The step of the sorting network
|
||||||
* @return The node id of the partner for data exchange
|
* @return [mpi_id_t] The node id of the partner for data exchange
|
||||||
*/
|
*/
|
||||||
template <> inline
|
template <> inline
|
||||||
mpi_id_t partner<SortMode::Bubbletonic>(mpi_id_t node, size_t step) noexcept {
|
mpi_id_t partner<SortMode::Bubbletonic>(mpi_id_t node, size_t step) noexcept {
|
||||||
@ -91,9 +90,9 @@ mpi_id_t partner<SortMode::Bubbletonic>(mpi_id_t node, size_t step) noexcept {
|
|||||||
* Returns the node's partner for data exchange during the sorting network iterations
|
* Returns the node's partner for data exchange during the sorting network iterations
|
||||||
* of Bitonic
|
* of Bitonic
|
||||||
*
|
*
|
||||||
* @param node The current node
|
* @param node [mpi_id_t] The current node
|
||||||
* @param step The step of the sorting network
|
* @param step [size_t] The step of the sorting network
|
||||||
* @return The node id of the partner for data exchange
|
* @return [mpi_id_t] The node id of the partner for data exchange
|
||||||
*/
|
*/
|
||||||
template <> inline
|
template <> inline
|
||||||
mpi_id_t partner<SortMode::Bitonic>(mpi_id_t node, size_t step) noexcept {
|
mpi_id_t partner<SortMode::Bitonic>(mpi_id_t node, size_t step) noexcept {
|
||||||
@ -105,32 +104,34 @@ mpi_id_t partner<SortMode::Bitonic>(mpi_id_t node, size_t step) noexcept {
|
|||||||
* The primary function template of keepSmall(). It is DISABLED since , it is explicitly specialized
|
* The primary function template of keepSmall(). It is DISABLED since , it is explicitly specialized
|
||||||
* for each of the \c SortMode
|
* for each of the \c SortMode
|
||||||
*/
|
*/
|
||||||
template<SortMode Mode> inline bool keepSmall(mpi_id_t, mpi_id_t, [[maybe_unused]] size_t) noexcept = delete;
|
template<SortMode Mode> inline bool keepSmall(mpi_id_t, mpi_id_t, [[maybe_unused]] size_t) = delete;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Predicate to check if a node keeps the small numbers during the bubbletonic sort network exchange.
|
* Predicate to check if a node keeps the small numbers during the bubbletonic sort network exchange.
|
||||||
*
|
*
|
||||||
* @param node The node for which we check
|
* @param node [mpi_id_t] The node for which we check
|
||||||
* @param partner The partner of the data exchange
|
* @param partner [mpi_id_t] The partner of the data exchange
|
||||||
* @return True if the node should keep the small values, false otherwise
|
* @return [bool] True if the node should keep the small values, false otherwise
|
||||||
*/
|
*/
|
||||||
template <> inline
|
template <> inline
|
||||||
bool keepSmall<SortMode::Bubbletonic>(mpi_id_t node, mpi_id_t partner, [[maybe_unused]] size_t depth) noexcept {
|
bool keepSmall<SortMode::Bubbletonic>(mpi_id_t node, mpi_id_t partner, [[maybe_unused]] size_t depth) {
|
||||||
assert(node != partner);
|
if (node == partner)
|
||||||
|
throw std::runtime_error("(keepSmall) Node and Partner can not be the same\n");
|
||||||
return (node < partner);
|
return (node < partner);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Predicate to check if a node keeps the small numbers during the bitonic sort network exchange.
|
* Predicate to check if a node keeps the small numbers during the bitonic sort network exchange.
|
||||||
*
|
*
|
||||||
* @param node The node for which we check
|
* @param node [mpi_id_t] The node for which we check
|
||||||
* @param partner The partner of the data exchange
|
* @param partner [mpi_id_t] The partner of the data exchange
|
||||||
* @param depth The total depth of the sorting network (same for each step for a given network)
|
* @param depth [size_t] The total depth of the sorting network (same for each step for a given network)
|
||||||
* @return True if the node should keep the small values, false otherwise
|
* @return [bool] True if the node should keep the small values, false otherwise
|
||||||
*/
|
*/
|
||||||
template <> inline
|
template <> inline
|
||||||
bool keepSmall<SortMode::Bitonic>(mpi_id_t node, mpi_id_t partner, size_t depth) noexcept {
|
bool keepSmall<SortMode::Bitonic>(mpi_id_t node, mpi_id_t partner, size_t depth) {
|
||||||
assert(node != partner);
|
if (node == partner)
|
||||||
|
throw std::runtime_error("(keepSmall) Node and Partner can not be the same\n");
|
||||||
return ascending<SortMode::Bitonic>(node, depth) == (node < partner);
|
return ascending<SortMode::Bitonic>(node, depth) == (node < partner);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,24 +139,26 @@ bool keepSmall<SortMode::Bitonic>(mpi_id_t node, mpi_id_t partner, size_t depth)
|
|||||||
* Predicate to check if the node is active in the current iteration of the bubbletonic
|
* Predicate to check if the node is active in the current iteration of the bubbletonic
|
||||||
* sort exchange.
|
* sort exchange.
|
||||||
*
|
*
|
||||||
* @param node The node to check
|
* @param node [mpi_id_t] The node to check
|
||||||
* @param nodes The total number of nodes
|
* @param nodes [size_t] The total number of nodes
|
||||||
* @return True if the node is active, false otherwise
|
* @return [bool] True if the node is active, false otherwise
|
||||||
*/
|
*/
|
||||||
bool isActive(mpi_id_t node, size_t nodes) noexcept;
|
bool isActive(mpi_id_t node, size_t nodes);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ============================== Data utilities ==============================
|
* ============================== Data utilities ==============================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
* Sort a range using the build-in O(Nlog(N)) algorithm
|
||||||
*
|
*
|
||||||
* @tparam RangeT
|
* @tparam RangeT A range type with random access iterator
|
||||||
* @param data
|
*
|
||||||
* @param ascending
|
* @param data [RangeT] The data to be sorted
|
||||||
|
* @param ascending [bool] Flag to indicate the sorting order
|
||||||
*/
|
*/
|
||||||
template<typename RangeT>
|
template<typename RangeT>
|
||||||
void fullSort(RangeT& data, bool ascending) {
|
void fullSort(RangeT& data, bool ascending) noexcept {
|
||||||
// Use introsort from stdlib++ here, unless ...
|
// Use introsort from stdlib++ here, unless ...
|
||||||
if (ascending)
|
if (ascending)
|
||||||
std::sort(data.begin(), data.end(), std::less<>());
|
std::sort(data.begin(), data.end(), std::less<>());
|
||||||
@ -164,66 +167,87 @@ void fullSort(RangeT& data, bool ascending) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
* Core functionality of sort for shadowed buffer types using
|
||||||
|
* the "elbow sort" algorithm.
|
||||||
*
|
*
|
||||||
* @tparam ShadowedT
|
* @note:
|
||||||
* @tparam CompT
|
* This algorithm can not work "in place".
|
||||||
* @param data
|
* We use the active buffer as source and the shadow as target.
|
||||||
* @param comp
|
* At the end we switch which buffer is active and which is the shadow.
|
||||||
|
* @note
|
||||||
|
* This is the core functionality. Use the elbowSort() function instead
|
||||||
|
*
|
||||||
|
* @tparam ShadowedT A Shadowed buffer type with random access iterator.
|
||||||
|
* @tparam CompT A Comparison type for binary operation comparisons
|
||||||
|
*
|
||||||
|
* @param data [ShadowedT] The data to sort
|
||||||
|
* @param ascending [bool] Flag to indicate the sorting order
|
||||||
|
* @param comp [CompT] The binary operator object
|
||||||
*/
|
*/
|
||||||
template<typename ShadowedT, typename CompT>
|
template<typename ShadowedT, typename CompT>
|
||||||
void elbowSortCore(ShadowedT& data, CompT comp) {
|
void elbowSortCore(ShadowedT& data, bool ascending, CompT comp) noexcept {
|
||||||
size_t N = data.size();
|
auto& active = data.getActive(); // Get the source vector (the data to sort)
|
||||||
auto active = data.getActive();
|
auto& shadow = data.getShadow(); // Get the target vector (the sorted data)
|
||||||
auto shadow = data.getShadow();
|
|
||||||
|
size_t N = data.size(); // The total size is the same or both vectors
|
||||||
size_t left = std::distance(
|
size_t left = std::distance(
|
||||||
active.begin(),
|
active.begin(),
|
||||||
std::min_element(active.begin(), active.end())
|
(ascending) ?
|
||||||
);
|
std::min_element(active.begin(), active.end()) :
|
||||||
|
std::max_element(active.begin(), active.end())
|
||||||
|
); // start 'left' from elbow of the bitonic
|
||||||
size_t right = (left == N-1) ? 0 : left + 1;
|
size_t right = (left == N-1) ? 0 : left + 1;
|
||||||
|
|
||||||
|
// Walk in opposite directions from elbow and insert-sort to target vector
|
||||||
for (size_t i = 0 ; i<N ; ++i) {
|
for (size_t i = 0 ; i<N ; ++i) {
|
||||||
if (comp(active[left], active[right])) {
|
if (comp(active[left], active[right])) {
|
||||||
shadow[i] = active[left];
|
shadow[i] = active[left];
|
||||||
left = (left == 0) ? N-1 : left -1;
|
left = (left == 0) ? N-1 : left -1; // cycle decrease
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
shadow[i] = active[right];
|
shadow[i] = active[right];
|
||||||
right = (right + 1) % N;
|
right = (right + 1) % N; // cycle increase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
data.switch_active();
|
data.switch_active(); // Switch active-shadow buffers
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
* Sort a shadowed buffer using the "elbow sort" algorithm.
|
||||||
*
|
*
|
||||||
* @tparam ShadowedT
|
* @tparam ShadowedT A Shadowed buffer type with random access iterator.
|
||||||
* @param data
|
*
|
||||||
* @param ascending
|
* @param data [ShadowedT] The data to sort
|
||||||
|
* @param ascending [bool] Flag to indicate the sorting order
|
||||||
*/
|
*/
|
||||||
template<typename ShadowedT>
|
template<typename ShadowedT>
|
||||||
void elbowSort(ShadowedT& data, bool ascending) {
|
void elbowSort(ShadowedT& data, bool ascending) noexcept {
|
||||||
if (ascending)
|
if (ascending)
|
||||||
elbowSortCore(data, std::less<>());
|
elbowSortCore(data, ascending, std::less<>());
|
||||||
else
|
else
|
||||||
elbowSortCore(data, std::greater<>());
|
elbowSortCore(data, ascending, std::greater<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
* Takes two sorted sequences where one is in increasing and the other is in decreasing order
|
||||||
|
* and selects either the larger or the smaller items in one-to-one comparison between them.
|
||||||
|
* The result is a bitonic sequence.
|
||||||
*
|
*
|
||||||
* @tparam RangeT
|
* @tparam RangeT A range type with random access iterator
|
||||||
* @param local
|
*
|
||||||
* @param remote
|
* @param local [RangeT] Reference to the local sequence
|
||||||
* @param keepsmall
|
* @param remote [const RangeT] Reference to the remote sequence (copied locally by MPI)
|
||||||
|
* @param keepSmall [bool] Flag to indicate if we keep the small items in local sequence
|
||||||
*/
|
*/
|
||||||
template<typename RangeT>
|
template<typename RangeT>
|
||||||
void minmax(RangeT& local, RangeT& remote, bool keepsmall) {
|
void minmax(RangeT& local, const RangeT& remote, bool keepSmall) noexcept {
|
||||||
using value_t = typename RangeT::value_type;
|
using value_t = typename RangeT::value_type;
|
||||||
std::transform(
|
std::transform(
|
||||||
local.begin(), local.end(),
|
local.begin(), local.end(),
|
||||||
remote.begin(),
|
remote.begin(),
|
||||||
local.begin(),
|
local.begin(),
|
||||||
[keepsmall](const value_t& a, const value_t& b){
|
[&keepSmall](const value_t& a, const value_t& b){
|
||||||
return (keepsmall) ? std::min(a, b) : std::max(a, b);
|
return (keepSmall) ? std::min(a, b) : std::max(a, b);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,27 +256,36 @@ void minmax(RangeT& local, RangeT& remote, bool keepsmall) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
* A distributed version of the Bubbletonic sort algorithm.
|
||||||
*
|
*
|
||||||
* @tparam ShadowedT
|
* @note
|
||||||
* @param data
|
* Each MPI process should run an instance of this function.
|
||||||
* @param Processes
|
*
|
||||||
|
* @tparam ShadowedT A Shadowed buffer type with random access iterator.
|
||||||
|
*
|
||||||
|
* @param data [ShadowedT] The local to MPI process data to sort
|
||||||
|
* @param Processes [mpi_id_t] The total number of MPI processes
|
||||||
*/
|
*/
|
||||||
template<typename ShadowedT>
|
template<typename ShadowedT>
|
||||||
void distBubbletonic(ShadowedT& data, mpi_id_t Processes) {
|
void distBubbletonic(ShadowedT& data, mpi_id_t Processes) {
|
||||||
// Initially sort to create a half part of a bitonic sequence
|
// Initially sort to create a half part of a bitonic sequence
|
||||||
fullSort(data, ascending<SortMode::Bubbletonic>(mpi.rank(), 0));
|
fullSort(data, ascending<SortMode::Bubbletonic>(mpi.rank(), 0));
|
||||||
|
|
||||||
// Sort network
|
// Sort network (O(N) iterations)
|
||||||
for (size_t step = 0; step < Processes-1; ++step) {
|
for (size_t step = 0; step < static_cast<size_t>(Processes-1); ++step) {
|
||||||
|
// Find out exchange configuration
|
||||||
auto part = partner<SortMode::Bubbletonic>(mpi.rank(), step);
|
auto part = partner<SortMode::Bubbletonic>(mpi.rank(), step);
|
||||||
auto ks = keepSmall<SortMode::Bubbletonic>(mpi.rank(), part, Processes);
|
auto ks = keepSmall<SortMode::Bubbletonic>(mpi.rank(), part, Processes);
|
||||||
if (isActive(mpi.rank(), Processes)) {
|
if ( isActive(mpi.rank(), Processes) &&
|
||||||
|
isActive(part, Processes) ) {
|
||||||
|
// Exchange with partner, keep nim-or-max and sort - O(N)
|
||||||
mpi.exchange(part, data.getActive(), data.getShadow(), step);
|
mpi.exchange(part, data.getActive(), data.getShadow(), step);
|
||||||
minmax(data.getActive(), data.getShadow(), ks);
|
minmax(data.getActive(), data.getShadow(), ks);
|
||||||
elbowSort(data, ascending<SortMode::Bubbletonic>(mpi.rank(), Processes));
|
elbowSort(data, ascending<SortMode::Bubbletonic>(mpi.rank(), Processes));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Invert if the node was descending.
|
||||||
if (!ascending<SortMode::Bubbletonic>(mpi.rank(), 0))
|
if (!ascending<SortMode::Bubbletonic>(mpi.rank(), 0))
|
||||||
elbowSort(data, true);
|
elbowSort(data, true);
|
||||||
|
|
||||||
@ -260,27 +293,34 @@ void distBubbletonic(ShadowedT& data, mpi_id_t Processes) {
|
|||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
* A distributed version of the Bitonic sort algorithm.
|
||||||
*
|
*
|
||||||
* @tparam ShadowedT
|
* @note
|
||||||
* @param data
|
* Each MPI process should run an instance of this function.
|
||||||
* @param Processes
|
*
|
||||||
|
* @tparam ShadowedT A Shadowed buffer type with random access iterator.
|
||||||
|
*
|
||||||
|
* @param data [ShadowedT] The local to MPI process data to sort
|
||||||
|
* @param Processes [mpi_id_t] The total number of MPI processes
|
||||||
*/
|
*/
|
||||||
template<typename ShadowedT>
|
template<typename ShadowedT>
|
||||||
void distBitonic(ShadowedT& data, mpi_id_t Processes) {
|
void distBitonic(ShadowedT& data, mpi_id_t Processes) {
|
||||||
auto p = static_cast<uint32_t>(std::log2(Processes));
|
|
||||||
|
|
||||||
// Initially sort to create a half part of a bitonic sequence
|
// Initially sort to create a half part of a bitonic sequence
|
||||||
fullSort(data, ascending<SortMode::Bitonic>(mpi.rank(), 0));
|
fullSort(data, ascending<SortMode::Bitonic>(mpi.rank(), 0));
|
||||||
|
|
||||||
// Run through sort network using elbow-sort
|
// Run through sort network using elbow-sort ( O(LogN * LogN) iterations )
|
||||||
|
auto p = static_cast<uint32_t>(std::log2(Processes));
|
||||||
for (size_t depth = 1; depth <= p; ++depth) {
|
for (size_t depth = 1; depth <= p; ++depth) {
|
||||||
for (size_t step = depth; step > 0;) {
|
for (size_t step = depth; step > 0;) {
|
||||||
--step;
|
--step;
|
||||||
|
// Find out exchange configuration
|
||||||
auto part = partner<SortMode::Bitonic>(mpi.rank(), step);
|
auto part = partner<SortMode::Bitonic>(mpi.rank(), step);
|
||||||
auto ks = keepSmall<SortMode::Bitonic>(mpi.rank(), part, depth);
|
auto ks = keepSmall<SortMode::Bitonic>(mpi.rank(), part, depth);
|
||||||
|
// Exchange with partner, keep nim-or-max
|
||||||
mpi.exchange(part, data.getActive(), data.getShadow(), (depth << 8) | step);
|
mpi.exchange(part, data.getActive(), data.getShadow(), (depth << 8) | step);
|
||||||
minmax(data.getActive(), data.getShadow(), ks);
|
minmax(data.getActive(), data.getShadow(), ks);
|
||||||
}
|
}
|
||||||
|
// sort - O(N)
|
||||||
elbowSort (data, ascending<SortMode::Bitonic>(mpi.rank(), depth));
|
elbowSort (data, ascending<SortMode::Bitonic>(mpi.rank(), depth));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,14 +23,19 @@ template <typename T> struct MPI_TypeMapper;
|
|||||||
// Specializations for supported types
|
// Specializations for supported types
|
||||||
template <> struct MPI_TypeMapper<char> { static MPI_Datatype getType() { return MPI_CHAR; } };
|
template <> struct MPI_TypeMapper<char> { static MPI_Datatype getType() { return MPI_CHAR; } };
|
||||||
template <> struct MPI_TypeMapper<unsigned char> { static MPI_Datatype getType() { return MPI_UNSIGNED_CHAR; } };
|
template <> struct MPI_TypeMapper<unsigned char> { static MPI_Datatype getType() { return MPI_UNSIGNED_CHAR; } };
|
||||||
|
|
||||||
template <> struct MPI_TypeMapper<short> { static MPI_Datatype getType() { return MPI_SHORT; } };
|
template <> struct MPI_TypeMapper<short> { static MPI_Datatype getType() { return MPI_SHORT; } };
|
||||||
template <> struct MPI_TypeMapper<int> { static MPI_Datatype getType() { return MPI_INT; } };
|
template <> struct MPI_TypeMapper<int> { static MPI_Datatype getType() { return MPI_INT; } };
|
||||||
template <> struct MPI_TypeMapper<long> { static MPI_Datatype getType() { return MPI_LONG; } };
|
template <> struct MPI_TypeMapper<long> { static MPI_Datatype getType() { return MPI_LONG; } };
|
||||||
template <> struct MPI_TypeMapper<long long> { static MPI_Datatype getType() { return MPI_LONG_LONG; } };
|
template <> struct MPI_TypeMapper<long long> { static MPI_Datatype getType() { return MPI_LONG_LONG; } };
|
||||||
template <> struct MPI_TypeMapper<unsigned short>{ static MPI_Datatype getType() { return MPI_UNSIGNED_SHORT; } };
|
template <> struct MPI_TypeMapper<unsigned short>{ static MPI_Datatype getType() { return MPI_UNSIGNED_SHORT; } };
|
||||||
|
template <> struct MPI_TypeMapper<unsigned int> { static MPI_Datatype getType() { return MPI_UNSIGNED; } };
|
||||||
template <> struct MPI_TypeMapper<unsigned long> { static MPI_Datatype getType() { return MPI_UNSIGNED_LONG; } };
|
template <> struct MPI_TypeMapper<unsigned long> { static MPI_Datatype getType() { return MPI_UNSIGNED_LONG; } };
|
||||||
template <> struct MPI_TypeMapper<unsigned long long> { static MPI_Datatype getType() { return MPI_UNSIGNED_LONG_LONG; } };
|
template <> struct MPI_TypeMapper<unsigned long long> { static MPI_Datatype getType() { return MPI_UNSIGNED_LONG_LONG; } };
|
||||||
|
|
||||||
|
template <> struct MPI_TypeMapper<float> { static MPI_Datatype getType() { return MPI_FLOAT; } };
|
||||||
|
template <> struct MPI_TypeMapper<double> { static MPI_Datatype getType() { return MPI_DOUBLE; } };
|
||||||
|
|
||||||
template<typename TID = int>
|
template<typename TID = int>
|
||||||
struct MPI_t {
|
struct MPI_t {
|
||||||
using ID_t = TID; // Export TID type (currently int defined by the standard)
|
using ID_t = TID; // Export TID type (currently int defined by the standard)
|
||||||
@ -38,6 +43,7 @@ struct MPI_t {
|
|||||||
void init(int *argc, char ***argv) {
|
void init(int *argc, char ***argv) {
|
||||||
// Initialize the MPI environment
|
// Initialize the MPI environment
|
||||||
MPI_Init(argc, argv);
|
MPI_Init(argc, argv);
|
||||||
|
initialized_ = true;
|
||||||
|
|
||||||
// Get the number of processes
|
// Get the number of processes
|
||||||
int size_value, rank_value;
|
int size_value, rank_value;
|
||||||
@ -53,11 +59,6 @@ struct MPI_t {
|
|||||||
name_ = std::string (processor_name, name_len);
|
name_ = std::string (processor_name, name_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void finalize() {
|
|
||||||
// Finalize the MPI environment.
|
|
||||||
MPI_Finalize();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void exchange(ID_t partner, const std::vector<T>& send_data, std::vector<T>& recv_data, int tag) {
|
void exchange(ID_t partner, const std::vector<T>& send_data, std::vector<T>& recv_data, int tag) {
|
||||||
using namespace std::string_literals;
|
using namespace std::string_literals;
|
||||||
@ -83,10 +84,21 @@ struct MPI_t {
|
|||||||
[[nodiscard]] ID_t size() const noexcept { return size_; }
|
[[nodiscard]] ID_t size() const noexcept { return size_; }
|
||||||
[[nodiscard]] const std::string& name() const noexcept { return name_; }
|
[[nodiscard]] const std::string& name() const noexcept { return name_; }
|
||||||
|
|
||||||
|
void finalize() {
|
||||||
|
// Finalize the MPI environment
|
||||||
|
initialized_ = false;
|
||||||
|
MPI_Finalize();
|
||||||
|
}
|
||||||
|
~MPI_t() {
|
||||||
|
// Finalize the MPI environment even on unexpected errors
|
||||||
|
if (initialized_)
|
||||||
|
MPI_Finalize();
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
ID_t rank_{};
|
ID_t rank_{};
|
||||||
ID_t size_{};
|
ID_t size_{};
|
||||||
std::string name_{};
|
std::string name_{};
|
||||||
|
bool initialized_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
extern MPI_t<> mpi;
|
extern MPI_t<> mpi;
|
||||||
@ -100,6 +112,42 @@ struct ShadowedVec_t {
|
|||||||
using const_iterator = typename std::vector<Value_t>::const_iterator;
|
using const_iterator = typename std::vector<Value_t>::const_iterator;
|
||||||
using size_type = typename std::vector<Value_t>::size_type;
|
using size_type = typename std::vector<Value_t>::size_type;
|
||||||
|
|
||||||
|
// Default constructor
|
||||||
|
ShadowedVec_t() = default;
|
||||||
|
|
||||||
|
// Constructor from an std::vector
|
||||||
|
explicit ShadowedVec_t(const std::vector<Value_t>& vec)
|
||||||
|
: North(vec), South(), active(north) {
|
||||||
|
South.resize(North.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit ShadowedVec_t(std::vector<Value_t>&& vec)
|
||||||
|
: North(std::move(vec)), South(), active(north) {
|
||||||
|
South.resize(North.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy assignment operator
|
||||||
|
ShadowedVec_t& operator=(const ShadowedVec_t& other) {
|
||||||
|
if (this != &other) { // Avoid self-assignment
|
||||||
|
North = other.North;
|
||||||
|
South = other.South;
|
||||||
|
active = other.active;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move assignment operator
|
||||||
|
ShadowedVec_t& operator=(ShadowedVec_t&& other) noexcept {
|
||||||
|
if (this != &other) { // Avoid self-assignment
|
||||||
|
North = std::move(other.North);
|
||||||
|
South = std::move(other.South);
|
||||||
|
active = other.active;
|
||||||
|
|
||||||
|
// There is no need to zero out other since it is valid but in a non-defined state
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
// Dispatch to active vector
|
// Dispatch to active vector
|
||||||
Value_t& operator[](size_type index) { return getActive()[index]; }
|
Value_t& operator[](size_type index) { return getActive()[index]; }
|
||||||
const Value_t& operator[](size_type index) const { return getActive()[index]; }
|
const Value_t& operator[](size_type index) const { return getActive()[index]; }
|
||||||
@ -155,10 +203,25 @@ struct ShadowedVec_t {
|
|||||||
const std::vector<Value_t>& getShadow() const {
|
const std::vector<Value_t>& getShadow() const {
|
||||||
return (active == north) ? South : North;
|
return (active == north) ? South : North;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Comparisons
|
||||||
|
bool operator== (const ShadowedVec_t& other) {
|
||||||
|
return getActive() == other.getActive();
|
||||||
|
}
|
||||||
|
bool operator!= (const ShadowedVec_t& other) {
|
||||||
|
return getActive() != other.getActive();
|
||||||
|
}
|
||||||
|
bool operator== (const std::vector<value_type>& other) {
|
||||||
|
return getActive() == other;
|
||||||
|
}
|
||||||
|
bool operator!= (const std::vector<value_type>& other) {
|
||||||
|
return getActive() != other;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum { north, south } active{north};
|
|
||||||
std::vector<Value_t> North{};
|
std::vector<Value_t> North{};
|
||||||
std::vector<Value_t> South{};
|
std::vector<Value_t> South{};
|
||||||
|
enum { north, south } active{north};
|
||||||
};
|
};
|
||||||
|
|
||||||
using distBuffer_t = ShadowedVec_t<distValue_t>;
|
using distBuffer_t = ShadowedVec_t<distValue_t>;
|
||||||
|
@ -6,26 +6,16 @@
|
|||||||
* Christos Choutouridis AEM:8997
|
* Christos Choutouridis AEM:8997
|
||||||
* <cchoutou@ece.auth.gr>
|
* <cchoutou@ece.auth.gr>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if !defined DEBUG
|
|
||||||
#define NDEBUG
|
|
||||||
#endif
|
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
#include "utils.hpp"
|
#include "utils.hpp"
|
||||||
#include "distsort.hpp"
|
#include "distsort.hpp"
|
||||||
|
|
||||||
|
|
||||||
/*!
|
bool isActive(mpi_id_t node, size_t nodes) {
|
||||||
* Predicate to check if the node is active in the current iteration of the bubbletonic
|
if (!((nodes > 0) &&
|
||||||
* sort exchange.
|
(nodes <= std::numeric_limits<mpi_id_t>::max()) ))
|
||||||
*
|
throw std::runtime_error("(isActive) Non-acceptable value of MPI Nodes\n");
|
||||||
* @param node The node to check
|
// ^ Assert that mpi_id_t can hold nodes, and thus we can cast without data loss!
|
||||||
* @param nodes The total number of nodes
|
|
||||||
* @return True if the node is active, false otherwise
|
return (node >= 0) && (node < static_cast<mpi_id_t>(nodes));
|
||||||
*/
|
|
||||||
bool isActive(mpi_id_t node, size_t nodes) noexcept {
|
|
||||||
assert(nodes > 0);
|
|
||||||
return (node >= 0) && (node < (nodes-1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include <exception>
|
#include <exception>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
#include "utils.hpp"
|
#include "utils.hpp"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@ -121,9 +122,15 @@ int main(int argc, char* argv[]) try {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
logger << "Initialize local array of " << session.arraySize << " elements" << logger.endl;
|
logger << "Initialize local array of " << session.arraySize << " elements" << logger.endl;
|
||||||
std::srand(unsigned(std::time(nullptr)));
|
std::random_device rd; // Mersenne seeded from hw if possible. range: [type_min, type_max]
|
||||||
|
std::mt19937 gen(rd());
|
||||||
|
std::uniform_int_distribution<distValue_t > dis(
|
||||||
|
std::numeric_limits<distValue_t>::min(),
|
||||||
|
std::numeric_limits<distValue_t>::max()
|
||||||
|
);
|
||||||
|
// Fill vector
|
||||||
Data.resize(session.arraySize);
|
Data.resize(session.arraySize);
|
||||||
std::generate(Data.begin(), Data.end(), std::rand);
|
std::generate(Data.begin(), Data.end(), [&]() { return dis(gen); });
|
||||||
|
|
||||||
if (mpi.rank() == 0)
|
if (mpi.rank() == 0)
|
||||||
logger << "Starting distributed sorting ... ";
|
logger << "Starting distributed sorting ... ";
|
||||||
@ -139,7 +146,7 @@ int main(int argc, char* argv[]) try {
|
|||||||
std::string timeMsg = "rank " + std::to_string(mpi.rank());
|
std::string timeMsg = "rank " + std::to_string(mpi.rank());
|
||||||
timer.print_dt(timeMsg.c_str());
|
timer.print_dt(timeMsg.c_str());
|
||||||
|
|
||||||
std::cout << "[Data]: Rank " << mpi.rank() << ": [" << (int)Data.front() << " .. " << (int)Data.back() << "]" << std::endl;
|
std::cout << "[Data]: Rank " << mpi.rank() << ": [" << +Data.front() << " .. " << +Data.back() << "]" << std::endl;
|
||||||
mpi.finalize();
|
mpi.finalize();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -230,12 +230,13 @@ TEST(TdistBitonic_UT, partner_test3) {
|
|||||||
/* ================================== keepSmall ================================== */
|
/* ================================== keepSmall ================================== */
|
||||||
/*
|
/*
|
||||||
* bool keepSmall(mpi_id_t node, mpi_id_t partner, size_t depth);
|
* bool keepSmall(mpi_id_t node, mpi_id_t partner, size_t depth);
|
||||||
* Assertion check
|
* Throw check (Not assert - ASSERT_DEATH)
|
||||||
*/
|
*/
|
||||||
TEST(TdistBitonic_UT, keepsmall_test1) {
|
TEST(TdistBitonic_UT, keepsmall_test1) {
|
||||||
ASSERT_DEATH(keepSmall<SortMode::Bitonic>(0, 0, 0), "");
|
// node and partner must differ or else ...
|
||||||
ASSERT_DEATH(keepSmall<SortMode::Bitonic>(1, 1, 42), "");
|
EXPECT_THROW(keepSmall<SortMode::Bitonic>(0, 0, 0), std::runtime_error);
|
||||||
ASSERT_DEATH(keepSmall<SortMode::Bitonic>(7, 7, 42), "");
|
EXPECT_THROW(keepSmall<SortMode::Bitonic>(1, 1, 42), std::runtime_error);
|
||||||
|
EXPECT_THROW(keepSmall<SortMode::Bitonic>(7, 7, 42), std::runtime_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -95,12 +95,13 @@ TEST(TdistBubbletonic_UT, partner_Bubbletonic_test3) {
|
|||||||
/* ================================== keepSmall ================================== */
|
/* ================================== keepSmall ================================== */
|
||||||
/*
|
/*
|
||||||
* bool keepSmall<SortMode::Bubbletonic>(mpi_id_t node, mpi_id_t partner, size_t depth);
|
* bool keepSmall<SortMode::Bubbletonic>(mpi_id_t node, mpi_id_t partner, size_t depth);
|
||||||
* Assertion check
|
* Throw check (Not assert - ASSERT_DEATH)
|
||||||
*/
|
*/
|
||||||
TEST(TdistBubbletonic_UT, keepsmall_test1) {
|
TEST(TdistBubbletonic_UT, keepsmall_test1) {
|
||||||
ASSERT_DEATH(keepSmall<SortMode::Bubbletonic>(0, 0, 0), "");
|
// node and partner must differ or else ...
|
||||||
ASSERT_DEATH(keepSmall<SortMode::Bubbletonic>(1, 1, 42), "");
|
EXPECT_THROW(keepSmall<SortMode::Bubbletonic>(0, 0, 0), std::runtime_error);
|
||||||
ASSERT_DEATH(keepSmall<SortMode::Bubbletonic>(7, 7, 42), "");
|
EXPECT_THROW(keepSmall<SortMode::Bubbletonic>(1, 1, 42), std::runtime_error);
|
||||||
|
EXPECT_THROW(keepSmall<SortMode::Bubbletonic>(7, 7, 42), std::runtime_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -119,6 +120,30 @@ TEST(TdistBubbletonic_UT, keepsmall_test2) {
|
|||||||
EXPECT_EQ(keepSmall<SortMode::Bubbletonic>(4, 9, 42), true);
|
EXPECT_EQ(keepSmall<SortMode::Bubbletonic>(4, 9, 42), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ================================== isActive ================================== */
|
||||||
|
/*
|
||||||
|
* bool isActive(mpi_id_t node, size_t nodes);
|
||||||
|
* Throw check
|
||||||
|
*/
|
||||||
|
TEST(TdistBubbletonic_UT, isActive_test1) {
|
||||||
|
EXPECT_THROW(isActive(0, 0), std::runtime_error);
|
||||||
|
EXPECT_THROW(isActive(0, static_cast<size_t>(std::numeric_limits<mpi_id_t>::max()) + 1), std::runtime_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* bool isActive(mpi_id_t node, size_t nodes);
|
||||||
|
* Boundary 3 BVA
|
||||||
|
*/
|
||||||
|
TEST(TdistBubbletonic_UT, isActive_test2) {
|
||||||
|
EXPECT_EQ(isActive(-1, 8), false);
|
||||||
|
EXPECT_EQ(isActive(0, 8), true);
|
||||||
|
EXPECT_EQ(isActive(1, 8), true);
|
||||||
|
EXPECT_EQ(isActive(7, 8), true);
|
||||||
|
EXPECT_EQ(isActive(8, 8), false);
|
||||||
|
EXPECT_EQ(isActive(9, 8), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
TEST(TdistBubbletonic_UT, distBubbletonic_test1) {
|
TEST(TdistBubbletonic_UT, distBubbletonic_test1) {
|
||||||
|
156
homework_2/test/tests_Common.cpp
Normal file
156
homework_2/test/tests_Common.cpp
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* \brief PDS HW2 tests
|
||||||
|
*
|
||||||
|
* \author
|
||||||
|
* Christos Choutouridis AEM:8997
|
||||||
|
* <cchoutou@ece.auth.gr>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <algorithm> // rand/srand
|
||||||
|
#include <ctime> // rand/srand
|
||||||
|
#include "distsort.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
/* ================================== fullSort ================================== */
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
TEST(TdistCommonUT, fullSort_test1) {
|
||||||
|
std::vector<uint8_t> ts_data = {3, 2, 1, 4, 5, 7, 8, 6};
|
||||||
|
std::vector<uint8_t> ts_expected = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||||
|
bool ts_ascending = true;
|
||||||
|
|
||||||
|
fullSort(ts_data, ts_ascending);
|
||||||
|
EXPECT_EQ((ts_data == ts_expected), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TdistCommonUT, fullSort_test2) {
|
||||||
|
std::vector<uint8_t> ts_data = {3, 2, 1, 4, 5, 7, 8, 6};
|
||||||
|
std::vector<uint8_t> ts_expected = {8, 7, 6, 5, 4, 3, 2, 1};
|
||||||
|
bool ts_ascending = false;
|
||||||
|
|
||||||
|
fullSort(ts_data, ts_ascending);
|
||||||
|
EXPECT_EQ((ts_data == ts_expected), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================== elbowSort ================================== */
|
||||||
|
|
||||||
|
TEST(TdistCommonUT, elbowSort_test1) {
|
||||||
|
ShadowedVec_t<uint8_t> ts_data1(std::vector<uint8_t>{3, 2, 1, 4, 5, 5, 7, 8});
|
||||||
|
ShadowedVec_t<uint8_t> ts_data2(std::vector<uint8_t>{4, 5, 7, 8, 5, 3, 2, 1});
|
||||||
|
ShadowedVec_t<uint8_t> ts_data3(std::vector<uint8_t>{1, 2, 3, 4, 5, 5, 7, 8});
|
||||||
|
ShadowedVec_t<uint8_t> ts_data4(std::vector<uint8_t>{8, 7, 5, 5, 4, 3, 2, 1});
|
||||||
|
std::vector<uint8_t> ts_expected = {1, 2, 3, 4, 5, 5, 7, 8};
|
||||||
|
bool ts_ascending = true;
|
||||||
|
|
||||||
|
elbowSort(ts_data1, ts_ascending);
|
||||||
|
elbowSort(ts_data2, ts_ascending);
|
||||||
|
elbowSort(ts_data3, ts_ascending);
|
||||||
|
elbowSort(ts_data4, ts_ascending);
|
||||||
|
EXPECT_EQ((ts_data1 == ts_expected), true);
|
||||||
|
EXPECT_EQ((ts_data2 == ts_expected), true);
|
||||||
|
EXPECT_EQ((ts_data3 == ts_expected), true);
|
||||||
|
EXPECT_EQ((ts_data4 == ts_expected), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TdistCommonUT, elbowSort_test2) {
|
||||||
|
ShadowedVec_t<uint8_t> ts_data1(std::vector<uint8_t>{3, 2, 1, 4, 5, 5, 7, 8});
|
||||||
|
ShadowedVec_t<uint8_t> ts_data2(std::vector<uint8_t>{4, 5, 7, 8, 5, 3, 2, 1});
|
||||||
|
ShadowedVec_t<uint8_t> ts_data3(std::vector<uint8_t>{1, 2, 3, 4, 5, 5, 7, 8});
|
||||||
|
ShadowedVec_t<uint8_t> ts_data4(std::vector<uint8_t>{8, 7, 5, 5, 4, 3, 2, 1});
|
||||||
|
std::vector<uint8_t> ts_expected = {8, 7, 5, 5, 4, 3, 2, 1};
|
||||||
|
bool ts_ascending = false;
|
||||||
|
|
||||||
|
elbowSort(ts_data1, ts_ascending);
|
||||||
|
elbowSort(ts_data2, ts_ascending);
|
||||||
|
elbowSort(ts_data3, ts_ascending);
|
||||||
|
elbowSort(ts_data4, ts_ascending);
|
||||||
|
EXPECT_EQ((ts_data1 == ts_expected), true);
|
||||||
|
EXPECT_EQ((ts_data2 == ts_expected), true);
|
||||||
|
EXPECT_EQ((ts_data3 == ts_expected), true);
|
||||||
|
EXPECT_EQ((ts_data4 == ts_expected), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TdistCommonUT, elbowSort_test3) {
|
||||||
|
ShadowedVec_t<uint8_t> ts_data(std::vector<uint8_t>{8, 7, 5, 5, 4, 3, 2, 1});
|
||||||
|
std::vector<uint8_t> ts_expected_asc = {1, 2, 3, 4, 5, 5, 7, 8};
|
||||||
|
std::vector<uint8_t> ts_expected_des = {8, 7, 5, 5, 4, 3, 2, 1};
|
||||||
|
|
||||||
|
// Check alternation for active-shadow vector inside Buffer and elbow algorithm
|
||||||
|
elbowSort(ts_data, true);
|
||||||
|
EXPECT_EQ((ts_data == ts_expected_asc), true);
|
||||||
|
elbowSort(ts_data, false);
|
||||||
|
EXPECT_EQ((ts_data == ts_expected_des), true);
|
||||||
|
elbowSort(ts_data, true);
|
||||||
|
EXPECT_EQ((ts_data == ts_expected_asc), true);
|
||||||
|
elbowSort(ts_data, false);
|
||||||
|
EXPECT_EQ((ts_data == ts_expected_des), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
TEST(TdistBubbletonic_UT, distBubbletonic_test1) {
|
||||||
|
AllData_t ts_Data {
|
||||||
|
ShadowedVec_t (8), ShadowedVec_t (8)
|
||||||
|
};
|
||||||
|
|
||||||
|
std::srand(unsigned(std::time(nullptr)));
|
||||||
|
for (auto& v : ts_Data) {
|
||||||
|
std::generate(v.begin(), v.end(), std::rand);
|
||||||
|
}
|
||||||
|
|
||||||
|
distBubbletonic(2, ts_Data);
|
||||||
|
|
||||||
|
auto max = std::numeric_limits<ShadowedVec_t::value_type>::min();
|
||||||
|
for (auto& v : ts_Data) {
|
||||||
|
EXPECT_EQ((max <= v[0]), true);
|
||||||
|
EXPECT_EQ(std::is_sorted(v.begin(), v.end()), true);
|
||||||
|
max = v.back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(TdistBubbletonic_UT, distBubbletonic_test2) {
|
||||||
|
AllData_t ts_Data {
|
||||||
|
ShadowedVec_t (8), ShadowedVec_t (8), ShadowedVec_t (8), ShadowedVec_t (8)
|
||||||
|
};
|
||||||
|
|
||||||
|
std::srand(unsigned(std::time(nullptr)));
|
||||||
|
for (auto& v : ts_Data) {
|
||||||
|
std::generate(v.begin(), v.end(), std::rand);
|
||||||
|
}
|
||||||
|
|
||||||
|
distBubbletonic(4, ts_Data);
|
||||||
|
|
||||||
|
auto max = std::numeric_limits<ShadowedVec_t::value_type>::min();
|
||||||
|
for (auto& v : ts_Data) {
|
||||||
|
EXPECT_EQ((max <= v[0]), true);
|
||||||
|
EXPECT_EQ(std::is_sorted(v.begin(), v.end()), true);
|
||||||
|
max = v.back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TdistBubbletonic_UT, distBubbletonic_test3) {
|
||||||
|
AllData_t ts_Data {
|
||||||
|
ShadowedVec_t (32), ShadowedVec_t (32), ShadowedVec_t (32), ShadowedVec_t (32),
|
||||||
|
ShadowedVec_t (32), ShadowedVec_t (32), ShadowedVec_t (32), ShadowedVec_t (32)
|
||||||
|
};
|
||||||
|
|
||||||
|
std::srand(unsigned(std::time(nullptr)));
|
||||||
|
for (auto& v : ts_Data) {
|
||||||
|
std::generate(v.begin(), v.end(), std::rand);
|
||||||
|
}
|
||||||
|
|
||||||
|
distBubbletonic(8, ts_Data);
|
||||||
|
|
||||||
|
auto max = std::numeric_limits<ShadowedVec_t::value_type>::min();
|
||||||
|
for (auto& v : ts_Data) {
|
||||||
|
EXPECT_EQ((max <= v[0]), true);
|
||||||
|
EXPECT_EQ(std::is_sorted(v.begin(), v.end()), true);
|
||||||
|
max = v.back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
Loading…
x
Reference in New Issue
Block a user