Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
1a3a49c
Add test build by sabutay_a_increaseContrast
Imanov-Sabutay Dec 23, 2025
930d038
info.json
Imanov-Sabutay Dec 24, 2025
402d536
Fix precommit by sabutay_a_increaseContrast
Imanov-Sabutay Dec 24, 2025
93ab147
Fix precommit by sabutay_a_increaseContrast
Imanov-Sabutay Dec 24, 2025
0797ea1
FIX precommit by sabutay_a_increaseContrast
Imanov-Sabutay Dec 24, 2025
e9ee77e
FIX___! precommit by sabutay_a_increaseContrast
Imanov-Sabutay Dec 24, 2025
d13d4c7
FIX---X precommit by sabutay_a_increaseContrast
Imanov-Sabutay Dec 24, 2025
18d6521
FIX____-<> precommit by sabutay_a_increaseContrast
Imanov-Sabutay Dec 25, 2025
53a0b12
FIX____-<><><><><><> precommit by sabutay_a_increaseContrast
Imanov-Sabutay Dec 25, 2025
5867eb0
!!!!FIX____-<><><><><><> precommit by sabutay_a_increaseContrast
Imanov-Sabutay Dec 25, 2025
8840bbb
_______FIX____-<><><><><><> precommit by sabutay_a_increaseContrast
Imanov-Sabutay Dec 25, 2025
3dbf54a
!!!_____FIX____-<><><><><><> precommit by sabutay_a_increaseContrast
Imanov-Sabutay Dec 25, 2025
151ba70
Add test build by name
Imanov-Sabutay Dec 25, 2025
9f28f72
----FIX____-<><><><><><>
Imanov-Sabutay Dec 25, 2025
3ecf2dd
----FIX____-<>t
Imanov-Sabutay Dec 25, 2025
e8c0ce6
YU000
Imanov-Sabutay Dec 25, 2025
d08b80f
20____
Imanov-Sabutay Dec 25, 2025
6eba76f
1-
Imanov-Sabutay Dec 25, 2025
e5f2163
3-----!
Imanov-Sabutay Dec 28, 2025
1ca06b8
3-----!
Imanov-Sabutay Dec 28, 2025
0c2219b
3-----!
Imanov-Sabutay Dec 28, 2025
2d484cf
3-----!
Imanov-Sabutay Dec 28, 2025
d732dd4
3-----!
Imanov-Sabutay Dec 28, 2025
4f05e90
3-----!
Imanov-Sabutay Dec 28, 2025
c894857
3-----!
Imanov-Sabutay Dec 28, 2025
48f8722
3-----!
Imanov-Sabutay Dec 28, 2025
4577221
3-----!
Imanov-Sabutay Dec 28, 2025
6e01c93
3-----!
Imanov-Sabutay Dec 28, 2025
9230644
3-----!
Imanov-Sabutay Dec 28, 2025
28ce9bd
3-!
Imanov-Sabutay Dec 29, 2025
af148d6
3--!
Imanov-Sabutay Dec 29, 2025
f5e0bc9
3-!
Imanov-Sabutay Dec 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#pragma once

#include <string>
#include <tuple>
#include <vector>

#include "task/include/task.hpp"

namespace sabutay_a_radixSortDoubleWithMerge {

using InType = std::vector<double>;
using OutType = std::vector<double>;
using TestType = std::tuple<std::vector<double>, std::string>;
using BaseTask = ppc::task::Task<InType, OutType>;

} // namespace sabutay_a_radixSortDoubleWithMerge
9 changes: 9 additions & 0 deletions tasks/sabutay_a_radixSortDoubleWithMerge/info.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"student": {
"first_name": "first_name_p",
"last_name": "last_name_p",
"middle_name": "middle_name_p",
"group_number": "2222222_p",
"task_number": "3"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#pragma once

#include <vector>

#include "sabutay_a_radixSortDoubleWithMerge/common/include/common.hpp"
#include "task/include/task.hpp"

namespace sabutay_a_radixSortDoubleWithMerge {

class SabutayAradixSortDoubleWithMergeMPI : public BaseTask {
public:
static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() {
return ppc::task::TypeOfTask::kMPI;
}
explicit SabutayAradixSortDoubleWithMergeMPI(const InType &in);

private:
bool ValidationImpl() override;
bool PreProcessingImpl() override;
bool RunImpl() override;
bool PostProcessingImpl() override;

std::vector<double> input_;
std::vector<double> output_;
};

} // namespace sabutay_a_radixSortDoubleWithMerge
265 changes: 265 additions & 0 deletions tasks/sabutay_a_radixSortDoubleWithMerge/mpi/src/ops_mpi.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
#include "sabutay_a_radixSortDoubleWithMerge/mpi/include/ops_mpi.hpp"

#include <mpi.h>

#include <algorithm>
#include <cstring>
#include <utility>
#include <vector>

#include "sabutay_a_radixSortDoubleWithMerge/common/include/common.hpp"

namespace sabutay_a_radixSortDoubleWithMerge {

// Constants for radix sort
namespace {
constexpr uint64_t kSignBitMask = 0x8000000000000000ULL;
constexpr int kByteCount = 8;
constexpr int kRadixBase = 256;
constexpr int kBitsPerByte = 8;
constexpr int kMpiTagSize = 0;
constexpr int kMpiTagData = 1;
constexpr int kMpiRootProcess = 0;
} // namespace

SabutayAradixSortDoubleWithMergeMPI::SabutayAradixSortDoubleWithMergeMPI(const InType &in) {
SetTypeOfTask(GetStaticTypeOfTask());
GetInput() = in;
GetOutput() = {};
}

bool SabutayAradixSortDoubleWithMergeMPI::ValidationImpl() {
int rank = 0;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);

int is_valid = 1;
if (rank == kMpiRootProcess) {
is_valid = !GetInput().empty() ? 1 : 0;
}

// Broadcast validation result to all processes
MPI_Bcast(&is_valid, 1, MPI_INT, kMpiRootProcess, MPI_COMM_WORLD);

return is_valid == 1;
}

bool SabutayAradixSortDoubleWithMergeMPI::PreProcessingImpl() {
int rank = 0;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);

if (rank == kMpiRootProcess) {
input_ = std::move(GetInput());
}
return true;
}

static void radixSortDoublesLocal(std::vector<double> &arr) {
if (arr.empty()) {
return;
}

std::vector<uint64_t> int_repr(arr.size());

// Convert doubles to unsigned integers for radix sort
for (size_t i = 0; i < arr.size(); i++) {
uint64_t bits;
std::memcpy(&bits, &arr[i], sizeof(double));

// Handle negative numbers: flip all bits, positive: flip only sign bit
if (bits & kSignBitMask) {
bits = ~bits;
} else {
bits ^= kSignBitMask;
}
int_repr[i] = bits;
}

// Radix sort on the integer representation
std::vector<uint64_t> temp(arr.size());

for (int byte = 0; byte < kByteCount; byte++) {
std::vector<int> count(kRadixBase, 0);

// Count occurrences
for (size_t i = 0; i < int_repr.size(); i++) {
uint64_t key = (int_repr[i] >> (byte * kBitsPerByte)) & 0xFF;
count[key]++;
}

// Compute cumulative counts
for (int i = 1; i < kRadixBase; i++) {
count[i] += count[i - 1];
}

// Build output array
for (int i = static_cast<int>(int_repr.size()) - 1; i >= 0; i--) {
uint64_t key = (int_repr[i] >> (byte * kBitsPerByte)) & 0xFF;
temp[--count[key]] = int_repr[i];
}

// Swap vectors to avoid copy (safe alternative to move + resize)
std::swap(int_repr, temp);
}

// Convert back to doubles
for (size_t i = 0; i < arr.size(); i++) {
uint64_t bits = int_repr[i];

// Reverse the transformation
if (bits & kSignBitMask) {
bits ^= kSignBitMask;
} else {
bits = ~bits;
}

std::memcpy(&arr[i], &bits, sizeof(double));
}
}

static std::vector<double> mergeSorted(std::vector<double> &&left, std::vector<double> &&right) {
std::vector<double> result;
result.reserve(left.size() + right.size());

size_t i = 0;
size_t j = 0;

while (i < left.size() && j < right.size()) {
if (left[i] <= right[j]) {
result.push_back(left[i++]);
} else {
result.push_back(right[j++]);
}
}

while (i < left.size()) {
result.push_back(left[i++]);
}

while (j < right.size()) {
result.push_back(right[j++]);
}

return result;
}

bool SabutayAradixSortDoubleWithMergeMPI::RunImpl() {
int rank = 0;
int size = 0;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);

int total_size = 0;

// Broadcast size
if (rank == kMpiRootProcess) {
total_size = static_cast<int>(input_.size());
}
MPI_Bcast(&total_size, 1, MPI_INT, kMpiRootProcess, MPI_COMM_WORLD);

if (total_size == 0) {
return false;
}

// Calculate chunk sizes for each process
int chunk_size = total_size / size;
int remainder = total_size % size;

std::vector<int> send_counts(size);
std::vector<int> displs(size);

for (int i = 0; i < size; i++) {
send_counts[i] = chunk_size + (i < remainder ? 1 : 0);
displs[i] = (i == 0) ? 0 : displs[i - 1] + send_counts[i - 1];
}

// Prepare local data
std::vector<double> local_data(send_counts[rank]);

if (rank == kMpiRootProcess) {
input_.resize(total_size);
}

// Scatter data to all processes
if (rank == kMpiRootProcess) {
MPI_Scatterv(input_.data(), send_counts.data(), displs.data(), MPI_DOUBLE, local_data.data(), send_counts[rank],
MPI_DOUBLE, kMpiRootProcess, MPI_COMM_WORLD);
} else {
MPI_Scatterv(nullptr, nullptr, nullptr, MPI_DOUBLE, local_data.data(), send_counts[rank], MPI_DOUBLE,
kMpiRootProcess, MPI_COMM_WORLD);
}

// Each process sorts its local data
radixSortDoublesLocal(local_data);

// Parallel merge using hypercube/binary tree algorithm
// Only processes with ranks that are multiples of (2*step) participate at each level
bool is_active = (send_counts[rank] > 0); // Only processes with data are initially active

for (int step = 1; step < size; step *= 2) {
if (!is_active) {
// Process has already sent its data or has no data, skip this iteration
continue;
}

if (rank % (2 * step) == 0) {
// This is a receiver process
int partner = rank + step;
if (partner < size && send_counts[partner] > 0) {
// Check if partner initially had data
int recv_size = 0;
MPI_Recv(&recv_size, 1, MPI_INT, partner, kMpiTagSize, MPI_COMM_WORLD, MPI_STATUS_IGNORE);

if (recv_size > 0) {
std::vector<double> recv_data(recv_size);
MPI_Recv(recv_data.data(), recv_size, MPI_DOUBLE, partner, kMpiTagData, MPI_COMM_WORLD, MPI_STATUS_IGNORE);

// Merge using move semantics to avoid copies
local_data = mergeSorted(std::move(local_data), std::move(recv_data));
}
}
} else if (rank % (2 * step) == step) {
// This is a sender process (rank is step away from a receiver)
int partner = rank - step;
if (partner >= 0 && partner < size) {
int send_size = static_cast<int>(local_data.size());
MPI_Send(&send_size, 1, MPI_INT, partner, kMpiTagSize, MPI_COMM_WORLD);
if (send_size > 0) {
MPI_Send(local_data.data(), send_size, MPI_DOUBLE, partner, kMpiTagData, MPI_COMM_WORLD);
}
// After sending, this process is done with merging
is_active = false;
}
}
}

// Collect result at root process
if (rank == kMpiRootProcess) {
output_ = std::move(local_data);
}

// Broadcast result size to all processes for synchronization
int result_size = 0;
if (rank == kMpiRootProcess) {
result_size = static_cast<int>(output_.size());
}
MPI_Bcast(&result_size, 1, MPI_INT, kMpiRootProcess, MPI_COMM_WORLD);

// Resize output on non-root processes
if (rank != kMpiRootProcess) {
output_.resize(result_size);
}

// Broadcast the sorted result to all processes
MPI_Bcast(output_.data(), result_size, MPI_DOUBLE, kMpiRootProcess, MPI_COMM_WORLD);

// Final synchronization barrier
MPI_Barrier(MPI_COMM_WORLD);
return true;
}

bool SabutayAradixSortDoubleWithMergeMPI::PostProcessingImpl() {
GetOutput() = std::move(output_);
return true;
}

} // namespace sabutay_a_radixSortDoubleWithMerge
Loading
Loading