diff --git a/tasks/smyshlaev_a_sle_cg_seq/common/include/common.hpp b/tasks/smyshlaev_a_sle_cg_seq/common/include/common.hpp new file mode 100644 index 00000000..40b83210 --- /dev/null +++ b/tasks/smyshlaev_a_sle_cg_seq/common/include/common.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include +#include +#include + +#include "task/include/task.hpp" + +namespace smyshlaev_a_sle_cg_seq { + +using CGVector = std::vector; +using CGMatrix = std::vector; + +struct InputType { + CGMatrix A; + CGVector b; +}; + +using InType = InputType; +using OutType = CGVector; +using TestType = std::tuple; +using BaseTask = ppc::task::Task; + +} // namespace smyshlaev_a_sle_cg_seq diff --git a/tasks/smyshlaev_a_sle_cg_seq/info.json b/tasks/smyshlaev_a_sle_cg_seq/info.json new file mode 100644 index 00000000..170da60c --- /dev/null +++ b/tasks/smyshlaev_a_sle_cg_seq/info.json @@ -0,0 +1,9 @@ +{ + "student": { + "first_name": "Александр", + "group_number": "3823Б1ФИ2", + "last_name": "Смышляев", + "middle_name": "Павлович", + "task_number": "1" + } +} diff --git a/tasks/smyshlaev_a_sle_cg_seq/seq/include/ops_seq.hpp b/tasks/smyshlaev_a_sle_cg_seq/seq/include/ops_seq.hpp new file mode 100644 index 00000000..d0addd6a --- /dev/null +++ b/tasks/smyshlaev_a_sle_cg_seq/seq/include/ops_seq.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include + +#include "smyshlaev_a_sle_cg_seq/common/include/common.hpp" +#include "task/include/task.hpp" + +namespace smyshlaev_a_sle_cg_seq { + +class SmyshlaevASleCgTaskSEQ : public BaseTask { + public: + static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() { + return ppc::task::TypeOfTask::kSEQ; + } + explicit SmyshlaevASleCgTaskSEQ(const InType &in); + + private: + std::vector flat_A_; + bool ValidationImpl() override; + bool PreProcessingImpl() override; + bool RunImpl() override; + bool PostProcessingImpl() override; +}; + +} // namespace smyshlaev_a_sle_cg_seq diff --git a/tasks/smyshlaev_a_sle_cg_seq/seq/src/ops_seq.cpp b/tasks/smyshlaev_a_sle_cg_seq/seq/src/ops_seq.cpp new file mode 100644 index 00000000..c044c2d4 --- /dev/null +++ b/tasks/smyshlaev_a_sle_cg_seq/seq/src/ops_seq.cpp @@ -0,0 +1,139 @@ +#include "smyshlaev_a_sle_cg_seq/seq/include/ops_seq.hpp" + +#include +#include +#include + +#include "smyshlaev_a_sle_cg_seq/common/include/common.hpp" + +namespace smyshlaev_a_sle_cg_seq { + +namespace { + +double ComputeDotProduct(const std::vector &v1, const std::vector &v2) { + double result = 0.0; + size_t n = v1.size(); + for (size_t i = 0; i < n; ++i) { + result += v1[i] * v2[i]; + } + return result; +} + +void ComputeAp(const std::vector &matrix, const std::vector &p, std::vector &ap, size_t n) { + for (size_t i = 0; i < n; ++i) { + double sum = 0.0; + for (size_t j = 0; j < n; ++j) { + sum += matrix[(i * n) + j] * p[j]; + } + ap[i] = sum; + } +} + +double UpdateResultAndResidual(std::vector &result, std::vector &r, const std::vector &p, + const std::vector &ap, double alpha) { + double rs_new = 0.0; + size_t n = result.size(); + for (size_t i = 0; i < n; ++i) { + result[i] += alpha * p[i]; + r[i] -= alpha * ap[i]; + rs_new += r[i] * r[i]; + } + return rs_new; +} + +void UpdateP(std::vector &p, const std::vector &r, double beta) { + size_t n = p.size(); + for (size_t i = 0; i < n; ++i) { + p[i] = r[i] + (beta * p[i]); + } +} + +} // namespace + +SmyshlaevASleCgTaskSEQ::SmyshlaevASleCgTaskSEQ(const InType &in) { + SetTypeOfTask(GetStaticTypeOfTask()); + GetInput() = in; +} + +bool SmyshlaevASleCgTaskSEQ::ValidationImpl() { + const auto &a = GetInput().A; + const auto &b = GetInput().b; + if (a.empty() || b.empty()) { + return false; + } + if (a.size() != b.size()) { + return false; + } + if (a.size() != a[0].size()) { + return false; + } + return true; +} + +bool SmyshlaevASleCgTaskSEQ::PreProcessingImpl() { + const auto &a = GetInput().A; + size_t n = a.size(); + flat_A_.resize(n * n); + for (size_t i = 0; i < n; ++i) { + for (size_t j = 0; j < n; ++j) { + flat_A_[(i * n) + j] = a[i][j]; + } + } + + return true; +} + +bool SmyshlaevASleCgTaskSEQ::RunImpl() { + const auto &b = GetInput().b; + size_t n = b.size(); + + if (n == 0) { + return true; + } + + std::vector r = b; + std::vector p = r; + std::vector ap(n, 0.0); + std::vector result(n, 0.0); + + double rs_old = ComputeDotProduct(r, r); + + const int max_iterations = static_cast(n) * 2; + const double epsilon = 1e-9; + + if (std::sqrt(rs_old) < epsilon) { + GetOutput() = result; + return true; + } + + for (int iter = 0; iter < max_iterations; ++iter) { + ComputeAp(flat_A_, p, ap, n); + + double p_ap = ComputeDotProduct(p, ap); + + if (std::abs(p_ap) < 1e-15) { + break; + } + + double alpha = rs_old / p_ap; + double rs_new = UpdateResultAndResidual(result, r, p, ap, alpha); + + if (std::sqrt(rs_new) < epsilon) { + break; + } + + double beta = rs_new / rs_old; + UpdateP(p, r, beta); + + rs_old = rs_new; + } + + GetOutput() = result; + return true; +} + +bool SmyshlaevASleCgTaskSEQ::PostProcessingImpl() { + return true; +} + +} // namespace smyshlaev_a_sle_cg_seq diff --git a/tasks/smyshlaev_a_sle_cg_seq/settings.json b/tasks/smyshlaev_a_sle_cg_seq/settings.json new file mode 100644 index 00000000..0be0208f --- /dev/null +++ b/tasks/smyshlaev_a_sle_cg_seq/settings.json @@ -0,0 +1,10 @@ +{ + "tasks": { + "all": "enabled", + "omp": "enabled", + "seq": "enabled", + "stl": "enabled", + "tbb": "enabled" + }, + "tasks_type": "threads" +} diff --git a/tasks/smyshlaev_a_sle_cg_seq/tests/functional/main.cpp b/tasks/smyshlaev_a_sle_cg_seq/tests/functional/main.cpp new file mode 100644 index 00000000..f1ef7c21 --- /dev/null +++ b/tasks/smyshlaev_a_sle_cg_seq/tests/functional/main.cpp @@ -0,0 +1,87 @@ +#include + +#include +#include +#include +#include +#include + +#include "smyshlaev_a_sle_cg_seq/common/include/common.hpp" +#include "smyshlaev_a_sle_cg_seq/seq/include/ops_seq.hpp" +#include "util/include/func_test_util.hpp" +#include "util/include/util.hpp" + +namespace smyshlaev_a_sle_cg_seq { + +class SmyshlaevASleCgFuncTests : public ppc::util::BaseRunFuncTests { + public: + static std::string PrintTestParam(const TestType &test_param) { + return std::to_string(std::get<0>(test_param)) + "_" + std::get<1>(test_param); + } + + protected: + void SetUp() override { + TestType params = std::get(ppc::util::GTestParamIndex::kTestParams)>(GetParam()); + int test_id = std::get<0>(params); + + if (test_id == 1) { + input_data_.A = {{4.0, 1.0}, {1.0, 3.0}}; + input_data_.b = {9.0, 5.0}; + expected_x_ = {2.0, 1.0}; + } else if (test_id == 2) { + input_data_.A = {{10.0, -1.0, 2.0}, {-1.0, 11.0, -1.0}, {2.0, -1.0, 10.0}}; + input_data_.b = {14.0, 18.0, 30.0}; + expected_x_ = {1.0, 2.0, 3.0}; + } else if (test_id == 3) { + input_data_.A = {{1.0, 0.0, 0.0, 0.0}, {0.0, 1.0, 0.0, 0.0}, {0.0, 0.0, 1.0, 0.0}, {0.0, 0.0, 0.0, 1.0}}; + input_data_.b = {5.0, -2.0, 8.0, 1.0}; + expected_x_ = {5.0, -2.0, 8.0, 1.0}; + } else if (test_id == 4) { + input_data_.A = {{4.0, 1.0}, {1.0, 3.0}}; + input_data_.b = {1.0, 2.0}; + expected_x_ = {1.0 / 11.0, 7.0 / 11.0}; + } + } + + bool CheckTestOutputData(OutType &output_data) final { + if (output_data.size() != expected_x_.size()) { + return false; + } + const double epsilon = 1e-6; + for (size_t i = 0; i < output_data.size(); ++i) { + if (std::fabs(output_data[i] - expected_x_[i]) > epsilon) { + return false; + } + } + return true; + } + + InType GetTestInputData() final { + return input_data_; + } + + private: + InType input_data_; + OutType expected_x_; +}; + +namespace { + +TEST_P(SmyshlaevASleCgFuncTests, SleCgSeqTests) { + ExecuteTest(GetParam()); +} + +const std::array kTestParam = {std::make_tuple(1, "Simple2x2"), std::make_tuple(2, "Medium3x3"), + std::make_tuple(3, "IdentityMatrix4x4"), std::make_tuple(4, "Harder2x2")}; + +const auto kTestTasksList = std::tuple_cat( + ppc::util::AddFuncTask(kTestParam, PPC_SETTINGS_smyshlaev_a_sle_cg_seq)); + +const auto kGtestValues = ppc::util::ExpandToValues(kTestTasksList); + +const auto kPerfTestName = SmyshlaevASleCgFuncTests::PrintFuncTestName; + +INSTANTIATE_TEST_SUITE_P(SleCgSeqFunctionalTests, SmyshlaevASleCgFuncTests, kGtestValues, kPerfTestName); + +} // namespace +} // namespace smyshlaev_a_sle_cg_seq diff --git a/tasks/smyshlaev_a_sle_cg_seq/tests/performance/main.cpp b/tasks/smyshlaev_a_sle_cg_seq/tests/performance/main.cpp new file mode 100644 index 00000000..004e2714 --- /dev/null +++ b/tasks/smyshlaev_a_sle_cg_seq/tests/performance/main.cpp @@ -0,0 +1,90 @@ +#include + +#include +#include +#include +#include + +#include "smyshlaev_a_sle_cg_seq/common/include/common.hpp" +#include "smyshlaev_a_sle_cg_seq/seq/include/ops_seq.hpp" +#include "util/include/perf_test_util.hpp" + +namespace smyshlaev_a_sle_cg_seq { + +class SmyshlaevASleCgPerfTests : public ppc::util::BaseRunPerfTests { + static constexpr int kSystemSize = 512; + InType input_data_{}; + OutType expected_x_; + + void SetUp() override { + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_real_distribution dis(-1.0, 1.0); + + CGMatrix a(kSystemSize, CGVector(kSystemSize, 0.0)); + expected_x_.assign(kSystemSize, 1.0); + CGVector b(kSystemSize, 0.0); + + for (int i = 0; i < kSystemSize; ++i) { + for (int j = i + 1; j < kSystemSize; ++j) { + double val = dis(gen); + a[i][j] = val; + a[j][i] = val; + } + } + + for (int i = 0; i < kSystemSize; ++i) { + double row_sum = 0.0; + for (int j = 0; j < kSystemSize; ++j) { + if (i != j) { + row_sum += std::abs(a[i][j]); + } + } + a[i][i] = row_sum + 1.0; + } + + for (int i = 0; i < kSystemSize; ++i) { + for (int j = 0; j < kSystemSize; ++j) { + b[i] += a[i][j] * expected_x_[j]; + } + } + + input_data_.A = std::move(a); + input_data_.b = std::move(b); + } + + bool CheckTestOutputData(OutType &output_data) final { + if (output_data.size() != expected_x_.size()) { + return false; + } + const double epsilon = 1e-6; + for (size_t i = 0; i < output_data.size(); ++i) { + if (std::isnan(output_data[i]) || std::fabs(output_data[i] - expected_x_[i]) > epsilon) { + return false; + } + } + return true; + } + + InType GetTestInputData() final { + return input_data_; + } +}; + +TEST_P(SmyshlaevASleCgPerfTests, RunPerfModes) { + ExecuteTest(GetParam()); +} + +namespace { + +const auto kAllPerfTasks = + ppc::util::MakeAllPerfTasks(PPC_SETTINGS_smyshlaev_a_sle_cg_seq); + +const auto kGtestValues = ppc::util::TupleToGTestValues(kAllPerfTasks); + +const auto kPerfTestName = SmyshlaevASleCgPerfTests::CustomPerfTestName; + +INSTANTIATE_TEST_SUITE_P(RunModeTests, SmyshlaevASleCgPerfTests, kGtestValues, kPerfTestName); + +} // namespace +} // namespace smyshlaev_a_sle_cg_seq