diff --git a/include/nil/crypto3/math/polynomial/polynomial.hpp b/include/nil/crypto3/math/polynomial/polynomial.hpp index 5dff93b..649e5b5 100644 --- a/include/nil/crypto3/math/polynomial/polynomial.hpp +++ b/include/nil/crypto3/math/polynomial/polynomial.hpp @@ -96,6 +96,7 @@ namespace nil { polynomial(const polynomial& x) : val(x.val) { } + polynomial(const polynomial& x, const allocator_type& a) : val(x.val, a) { } @@ -117,13 +118,8 @@ namespace nil { this->operator[](power) = value; } - explicit polynomial(const container_type &c) : val(c) { - if (val.empty()) { - val.push_back(FieldValueType::zero()); - } - } - - explicit polynomial(container_type &&c) : val(c) { + template + explicit polynomial(T&& c) : val(std::forward(c)) { if (val.empty()) { val.push_back(FieldValueType::zero()); } @@ -179,6 +175,10 @@ namespace nil { return this->val.__alloc(); } + container_type& get_storage() { + return val; + } + iterator begin() BOOST_NOEXCEPT { return val.begin(); } @@ -383,7 +383,7 @@ namespace nil { * Returns true if polynomial is a one polynomial. */ bool is_one() const { - return (*this->begin() == FieldValueType(1)) && + return (*this->begin() == FieldValueType(1)) && std::all_of(++this->begin(), this->end(), [](FieldValueType i) { return i == FieldValueType::zero(); }); } diff --git a/include/nil/crypto3/math/polynomial/polynomial_dfs.hpp b/include/nil/crypto3/math/polynomial/polynomial_dfs.hpp index e448c3d..cb4a89e 100644 --- a/include/nil/crypto3/math/polynomial/polynomial_dfs.hpp +++ b/include/nil/crypto3/math/polynomial/polynomial_dfs.hpp @@ -35,9 +35,10 @@ #include #include -#include -#include #include +#include +#include +#include namespace nil { namespace crypto3 { @@ -164,6 +165,10 @@ namespace nil { return this->val.__alloc(); } + container_type& get_storage() { + return val; + } + iterator begin() BOOST_NOEXCEPT { return val.begin(); } @@ -761,6 +766,35 @@ namespace nil { return os; } + template + static inline polynomial_dfs polynomial_sum( + std::vector> addends) { + using FieldValueType = typename FieldType::value_type; + std::size_t max_size = 0; + std::unordered_map> size_to_part_sum; + for (auto& addend : addends) { + max_size = std::max(max_size, addend.size()); + auto it = size_to_part_sum.find(addend.size()); + if (it == size_to_part_sum.end()) { + size_to_part_sum[addend.size()] = std::move(addend); + } else { + it->second += addend; + // Free the memory we are not going to use anymore. + addend = math::polynomial_dfs(); + } + } + + auto coef_result = polynomial(max_size, FieldValueType::zero()); + for (auto& [_, partial_sum] : size_to_part_sum) { + coef_result += polynomial(std::move(partial_sum.coefficients())); + } + + polynomial_dfs dfs_result; + dfs_result.from_coefficients(coef_result.get_storage()); + + return dfs_result; + } + template static inline polynomial_dfs polynomial_product( std::vector> multipliers) { diff --git a/test/benchmarks/CMakeLists.txt b/test/benchmarks/CMakeLists.txt index 5cc9432..53cc44d 100644 --- a/test/benchmarks/CMakeLists.txt +++ b/test/benchmarks/CMakeLists.txt @@ -6,7 +6,10 @@ # http://www.boost.org/LICENSE_1_0.txt #---------------------------------------------------------------------------# -find_package(Boost REQUIRED COMPONENTS unit_test_framework timer) +find_package(Boost REQUIRED COMPONENTS + timer + unit_test_framework +) cm_test_link_libraries(${CMAKE_WORKSPACE_NAME}_${CURRENT_PROJECT_NAME} diff --git a/test/benchmarks/polynomial_dfs_benchmark.cpp b/test/benchmarks/polynomial_dfs_benchmark.cpp index b924971..96fef13 100644 --- a/test/benchmarks/polynomial_dfs_benchmark.cpp +++ b/test/benchmarks/polynomial_dfs_benchmark.cpp @@ -174,4 +174,42 @@ BENCHMARK_AUTO_TEST_CASE(polynomial_product_test, 20) { STOP_TIMER("polynomial_product") } +BENCHMARK_AUTO_TEST_CASE(polynomial_sum_real_test, 20) { + using Field = nil::crypto3::algebra::fields::bls12_fr<381>; + + std::vector> random_polynomials; + random_polynomials.reserve(8); + Field::value_type a = alg_rnd_engine(); + std::vector sizes = {23, 15, 21, 16, 22, 17, 18}; + for (auto size : sizes) { + random_polynomials.emplace_back( + generate_random_polynomial( + 1u << size, + alg_rnd_engine + ) + ); + } + auto random_polynomials_copy = random_polynomials; + + START_TIMER("polynomial_naive") + std::size_t max_size = 0; + for (const auto& polynomial : random_polynomials_copy) { + max_size = std::max(max_size, polynomial.size()); + } + auto max_domain = make_evaluation_domain(max_size); + for (auto& polynomial : random_polynomials_copy) { + polynomial.resize(max_size, nullptr, max_domain); + } + polynomial_dfs naive_res(0, max_size); + for (auto& polynomial : random_polynomials_copy) { + naive_res += std::move(polynomial); + } + STOP_TIMER("polynomial_naive") + + START_TIMER("polynomial_sum") + const auto res = polynomial_sum(std::move(random_polynomials)); + STOP_TIMER("polynomial_sum") + BOOST_CHECK_EQUAL(naive_res, res); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/test/polynomial_dfs.cpp b/test/polynomial_dfs.cpp index 2c495e3..107803d 100644 --- a/test/polynomial_dfs.cpp +++ b/test/polynomial_dfs.cpp @@ -234,6 +234,42 @@ BOOST_AUTO_TEST_CASE(polynomial_dfs_addition_less_a) { 0x5a8fa2a6cb26338cef1cd76f6106a8baa60293c9c1c0d2c31e813ed413279c47_cppui_modular253}}; BOOST_CHECK_EQUAL(c_res, c); } + +BOOST_AUTO_TEST_CASE(polynomial_dfs_sum) { + std::vector> polynomials = { + { + 7, + { + 0x37_cppui_modular253, + 0x6C17ABF513DFFC886A7F49F970801792C825CFDD829870DC60E8DA51F53633_cppui_modular253, + 0x73EDA753299D7D3ED0CB3E52336E8625A78AA3D929CB5BFEFFEEFFFEFFFFFFFD_cppui_modular253, + 0x53B09574717196328488C7990499B10ABA0C038C321BF5B1C0D1C5A4E10C7330_cppui_modular253, + 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFEFFFFFFEE_cppui_modular253, + 0x73818FA734899D485AE48BE74C1F3B0838E37E245E69C38E23991724AE0AC9C4_cppui_modular253, + 0x9626E99B5D63351DFAC330029D63300000010FFFFFFFFFFFC_cppui_modular253, + 0x203D11DEB82BE718FE9BDD45C91A43E021C3A08591F4664D3F343A5A1EF38CC7_cppui_modular253 + } + }, + { + 6, + { + 0x4e_cppui_modular253, + 0x2984a53ad76597710bc6e589547653b47dcce72f84e0617332e6e0761851f4a9_cppui_modular253, + 0x73eda753299d7d4078c0a4bd957794986b93a3e08bd45bfefff1fffefffffffb_cppui_modular253, + 0x195e04ac5e7749b26f0033b1486ae23bed8b1011de0d893be16ec12aecd863c2_cppui_modular253, + 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfefffffffeffffffff_cppui_modular253, + 0x4a6902185237e5dffc8fbf66155bd15f9620bcfadb4dfa8bcd291f88e7ae0b60_cppui_modular253, + 0x7ba79334a742a436ce82a0022742a0000000dfffffffffffa_cppui_modular253, + 0x5a8fa2a6cb26338cef1cd76f6106a8baa60293c9c1c0d2c31e813ed413279c47_cppui_modular253 + } + } + }; + auto native_sum = polynomial_dfs::zero(); + for (const auto& p : polynomials) { + native_sum += p; + } + BOOST_CHECK_EQUAL(native_sum, polynomial_sum(polynomials)); +} BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE(polynomial_dfs_addition_eq_test_suite)