Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
29 changes: 29 additions & 0 deletions tasks/borunov_v_complex_ccs/common/include/common.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#pragma once

#include <complex>
#include <tuple>
#include <vector>

#include "task/include/task.hpp"

namespace borunov_v_complex_ccs_seq {

struct SparseMatrix {
int num_rows = 0;
int num_cols = 0;
std::vector<std::complex<double>> values;
std::vector<int> row_indices;
std::vector<int> col_ptrs;

bool operator==(const SparseMatrix &other) const {
return num_rows == other.num_rows && num_cols == other.num_cols && values == other.values &&
row_indices == other.row_indices && col_ptrs == other.col_ptrs;
}
};

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

} // namespace borunov_v_complex_ccs_seq
9 changes: 9 additions & 0 deletions tasks/borunov_v_complex_ccs/info.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"student": {
"first_name": "Владислав",
"group_number": "3823Б1ПР3",
"last_name": "Борунов",
"middle_name": "Алексеевич",
"task_number": "1"
}
}
22 changes: 22 additions & 0 deletions tasks/borunov_v_complex_ccs/seq/include/ops_seq.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once

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

namespace borunov_v_complex_ccs_seq {

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

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

} // namespace borunov_v_complex_ccs_seq
97 changes: 97 additions & 0 deletions tasks/borunov_v_complex_ccs/seq/src/ops_seq.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#include "borunov_v_complex_ccs/seq/include/ops_seq.hpp"

#include <algorithm>
#include <cmath>
#include <complex>
#include <cstddef>
#include <vector>

#include "borunov_v_complex_ccs/common/include/common.hpp"

namespace borunov_v_complex_ccs_seq {

BorunovVComplexCcsSEQ::BorunovVComplexCcsSEQ(const InType &in) {
SetTypeOfTask(GetStaticTypeOfTask());
GetInput() = in;
GetOutput().resize(1);
}

bool BorunovVComplexCcsSEQ::ValidationImpl() {
if (GetInput().size() != 2) {
return false;
}
const auto &a = GetInput()[0];
const auto &b = GetInput()[1];
if (a.num_cols != b.num_rows) {
return false;
}
if (a.col_ptrs.size() != static_cast<size_t>(a.num_cols) + 1 ||
b.col_ptrs.size() != static_cast<size_t>(b.num_cols) + 1) {
return false;
}
return true;
}

bool BorunovVComplexCcsSEQ::PreProcessingImpl() {
const auto &a = GetInput()[0];
const auto &b = GetInput()[1];
auto &c = GetOutput()[0];

c.num_rows = a.num_rows;
c.num_cols = b.num_cols;
c.col_ptrs.assign(c.num_cols + 1, 0);
c.values.clear();
c.row_indices.clear();

return true;
}

bool BorunovVComplexCcsSEQ::RunImpl() {
const auto &a = GetInput()[0];
const auto &b = GetInput()[1];
auto &c = GetOutput()[0];

std::vector<std::complex<double>> col_accumulator(a.num_rows, {0.0, 0.0});
std::vector<int> non_zero_indices;
std::vector<bool> is_non_zero(a.num_rows, false);

for (int j = 0; j < b.num_cols; ++j) {
for (int b_idx = b.col_ptrs[j]; b_idx < b.col_ptrs[j + 1]; ++b_idx) {
int p = b.row_indices[b_idx];
std::complex<double> b_val = b.values[b_idx];

for (int a_idx = a.col_ptrs[p]; a_idx < a.col_ptrs[p + 1]; ++a_idx) {
int i = a.row_indices[a_idx];
std::complex<double> a_val = a.values[a_idx];

if (!is_non_zero[i]) {
is_non_zero[i] = true;
non_zero_indices.push_back(i);
}
col_accumulator[i] += a_val * b_val;
}
}

std::ranges::sort(non_zero_indices);

for (int i : non_zero_indices) {
if (std::abs(col_accumulator[i]) > 1e-9) {
c.values.push_back(col_accumulator[i]);
c.row_indices.push_back(i);
}
col_accumulator[i] = {0.0, 0.0};
is_non_zero[i] = false;
}
non_zero_indices.clear();

c.col_ptrs[j + 1] = static_cast<int>(c.values.size());
}

return true;
}

bool BorunovVComplexCcsSEQ::PostProcessingImpl() {
return true;
}

} // namespace borunov_v_complex_ccs_seq
10 changes: 10 additions & 0 deletions tasks/borunov_v_complex_ccs/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"tasks": {
"all": "enabled",
"omp": "enabled",
"seq": "enabled",
"stl": "enabled",
"tbb": "enabled"
},
"tasks_type": "threads"
}
183 changes: 183 additions & 0 deletions tasks/borunov_v_complex_ccs/tests/functional/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
#include <gtest/gtest.h>

#include <array>
#include <cmath>
#include <complex>
#include <cstddef>
#include <random>
#include <string>
#include <tuple>
#include <vector>

#include "borunov_v_complex_ccs/common/include/common.hpp"
#include "borunov_v_complex_ccs/seq/include/ops_seq.hpp"
#include "util/include/func_test_util.hpp"
#include "util/include/util.hpp"

namespace borunov_v_complex_ccs_seq {

namespace {

using DenseMatrix = std::vector<std::vector<std::complex<double>>>;

SparseMatrix GenerateRandomSparseMatrix(int num_rows, int num_cols, double sparsity) {
SparseMatrix mat;
mat.num_rows = num_rows;
mat.num_cols = num_cols;
mat.col_ptrs.assign(num_cols + 1, 0);

const int sparsity_seed = static_cast<int>(sparsity * 1000.0);
std::seed_seq seed{num_rows, num_cols, sparsity_seed};
std::mt19937 gen(seed);
std::uniform_real_distribution<double> dist_val(-10.0, 10.0);
std::uniform_real_distribution<double> dist_prob(0.0, 1.0);

for (int j = 0; j < num_cols; ++j) {
for (int i = 0; i < num_rows; ++i) {
if (dist_prob(gen) < sparsity) {
mat.values.emplace_back(dist_val(gen), dist_val(gen));
mat.row_indices.push_back(i);
}
}
mat.col_ptrs[j + 1] = static_cast<int>(mat.values.size());
}
return mat;
}

DenseMatrix BuildDense(const SparseMatrix &mat) {
DenseMatrix dense(mat.num_rows, std::vector<std::complex<double>>(mat.num_cols, {0.0, 0.0}));
for (int j = 0; j < mat.num_cols; ++j) {
for (int idx = mat.col_ptrs[j]; idx < mat.col_ptrs[j + 1]; ++idx) {
dense[mat.row_indices[idx]][j] = mat.values[idx];
}
}
return dense;
}

DenseMatrix MultiplyDenseMatrices(const DenseMatrix &left, const DenseMatrix &right) {
const int rows = static_cast<int>(left.size());
const int inner = rows == 0 ? 0 : static_cast<int>(left[0].size());
const int cols = right.empty() ? 0 : static_cast<int>(right[0].size());
DenseMatrix result(rows, std::vector<std::complex<double>>(cols, {0.0, 0.0}));

for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
for (int k = 0; k < inner; ++k) {
result[i][j] += left[i][k] * right[k][j];
}
}
}

return result;
}

SparseMatrix BuildSparseFromDense(const DenseMatrix &dense) {
SparseMatrix c;
c.num_rows = static_cast<int>(dense.size());
c.num_cols = dense.empty() ? 0 : static_cast<int>(dense[0].size());
c.col_ptrs.assign(c.num_cols + 1, 0);

for (int j = 0; j < c.num_cols; ++j) {
for (int i = 0; i < c.num_rows; ++i) {
if (std::abs(dense[i][j]) > 1e-9) {
c.values.push_back(dense[i][j]);
c.row_indices.push_back(i);
}
}
c.col_ptrs[j + 1] = static_cast<int>(c.values.size());
}

return c;
}

SparseMatrix MultiplyDense(const SparseMatrix &a, const SparseMatrix &b) {
DenseMatrix dense_a = BuildDense(a);
DenseMatrix dense_b = BuildDense(b);
DenseMatrix dense_c = MultiplyDenseMatrices(dense_a, dense_b);
return BuildSparseFromDense(dense_c);
}

} // namespace

class BorunovVRunFuncTestsThreads : public ppc::util::BaseRunFuncTests<InType, OutType, TestType> {
public:
static std::string PrintTestParam(const TestType &test_param) {
return std::to_string(std::get<0>(test_param)) + "_" + std::to_string(std::get<1>(test_param)) + "_" +
std::to_string(std::get<2>(test_param));
}

protected:
void SetUp() override {
TestType params = std::get<static_cast<std::size_t>(ppc::util::GTestParamIndex::kTestParams)>(GetParam());
int m = std::get<0>(params);
int k = std::get<1>(params);
int n = std::get<2>(params);

SparseMatrix a = GenerateRandomSparseMatrix(m, k, 0.2);
SparseMatrix b = GenerateRandomSparseMatrix(k, n, 0.2);

input_data_ = {a, b};
expected_output_ = {MultiplyDense(a, b)};
}

bool CheckTestOutputData(OutType &output_data) final {
if (expected_output_.size() != output_data.size()) {
return false;
}
const auto &expected = expected_output_[0];
const auto &actual = output_data[0];

if (expected.num_rows != actual.num_rows || expected.num_cols != actual.num_cols) {
return false;
}
if (expected.col_ptrs != actual.col_ptrs) {
return false;
}
if (expected.row_indices != actual.row_indices) {
return false;
}
if (expected.values.size() != actual.values.size()) {
return false;
}

for (std::size_t i = 0; i < expected.values.size(); ++i) {
if (std::abs(expected.values[i] - actual.values[i]) > 1e-6) {
return false;
}
}
return true;
}

InType GetTestInputData() final {
return input_data_;
}

private:
InType input_data_;
OutType expected_output_;
};

namespace {

TEST_P(BorunovVRunFuncTestsThreads, MatmulTests) {
ExecuteTest(GetParam());
}

const std::array<TestType, 3> kTestParam = {
std::make_tuple(10, 10, 10),
std::make_tuple(20, 15, 25),
std::make_tuple(5, 30, 5),
};

const auto kTestTasksList = std::tuple_cat(
ppc::util::AddFuncTask<BorunovVComplexCcsSEQ, InType>(kTestParam, PPC_SETTINGS_borunov_v_complex_ccs));

const auto kGtestValues = ppc::util::ExpandToValues(kTestTasksList);

const auto kPerfTestName = BorunovVRunFuncTestsThreads::PrintFuncTestName<BorunovVRunFuncTestsThreads>;

INSTANTIATE_TEST_SUITE_P(SparseMatrixTests, BorunovVRunFuncTestsThreads, kGtestValues, kPerfTestName);

} // namespace

} // namespace borunov_v_complex_ccs_seq
Loading
Loading