From 5bb7c835b9d325d9dba9d407c6119ba65c915d3e Mon Sep 17 00:00:00 2001 From: Francesco Biscani Date: Thu, 28 Jan 2021 16:17:28 +0100 Subject: [PATCH 01/28] Some small tweaks to dpm. --- include/obake/polynomials/d_packed_monomial.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/obake/polynomials/d_packed_monomial.hpp b/include/obake/polynomials/d_packed_monomial.hpp index e7756624..2f5de684 100644 --- a/include/obake/polynomials/d_packed_monomial.hpp +++ b/include/obake/polynomials/d_packed_monomial.hpp @@ -75,14 +75,14 @@ constexpr auto dpm_nexpos_to_vsize(const U &n) noexcept } // namespace detail +// Max psize for d_packed_monomial. +template +inline constexpr unsigned dpm_max_psize = ::obake::detail::kpack_max_size(); + // Dynamic packed monomial. -// NOTE: concept checking on PSize instead of static assert? -// Probably need to make kpack_max_size() public for that. template -class d_packed_monomial + requires(PSize > 0u) && (PSize <= dpm_max_psize)class d_packed_monomial { - static_assert(PSize > 0u && PSize <= ::obake::detail::kpack_max_size()); - friend class ::boost::serialization::access; public: From 1024763c7c86ffc563707f0a29ed8b3baf2e447d Mon Sep 17 00:00:00 2001 From: Francesco Biscani Date: Thu, 28 Jan 2021 17:18:36 +0100 Subject: [PATCH 02/28] Some initial files for d_packed_trig_monomial. --- .../poisson_series/d_packed_trig_monomial.hpp | 152 +++++++++ test/CMakeLists.txt | 1 + test/d_packed_trig_monomial_00.cpp | 299 ++++++++++++++++++ 3 files changed, 452 insertions(+) create mode 100644 include/obake/poisson_series/d_packed_trig_monomial.hpp create mode 100644 test/d_packed_trig_monomial_00.cpp diff --git a/include/obake/poisson_series/d_packed_trig_monomial.hpp b/include/obake/poisson_series/d_packed_trig_monomial.hpp new file mode 100644 index 00000000..388795d3 --- /dev/null +++ b/include/obake/poisson_series/d_packed_trig_monomial.hpp @@ -0,0 +1,152 @@ +// Copyright 2019-2020 Francesco Biscani (bluescarni@gmail.com)::polynomials +// +// This file is part of the obake library. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef OBAKE_POISSON_SERIES_D_PACKED_TRIG_MONOMIAL_HPP +#define OBAKE_POISSON_SERIES_D_PACKED_TRIG_MONOMIAL_HPP + +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include + +namespace obake +{ + +namespace poisson_series +{ + +namespace detail +{ + +// Small helper to determine the container size +// we need to store n exponents in a dynamic packed +// trig monomial of type T. U must be an +// unsigned integral type. +template +constexpr auto dptm_n_expos_to_vsize(const U &n) noexcept +{ + static_assert(is_integral_v && !is_signed_v); + return n / T::psize + static_cast(n % T::psize != 0u); +} + +} // namespace detail + +// Max psize for d_packed_trig_monomial. +template +requires(is_signed_v == true) inline constexpr unsigned dptm_max_psize = ::obake::detail::kpack_max_size(); + +// Dynamic packed trigonometric monomial. +template + requires(is_signed_v == true) && (PSize > 0u) && (PSize <= dptm_max_psize)class d_packed_trig_monomial +{ +public: + // The container type. + using container_t = ::boost::container::small_vector; + +private: + container_t m_container; + // true -> cosine, false -> sine. + bool m_type = true; + +public: + // Alias for PSize + static constexpr unsigned psize = PSize; + + // Alias for T. + using value_type = T; + + // Default constructor. + d_packed_trig_monomial() = default; + + // Constructor from symbol set. + explicit d_packed_trig_monomial(const symbol_set &ss, bool type = true) + : m_container(::obake::safe_cast( + detail::dptm_n_expos_to_vsize(ss.size()))), + m_type(type) + { + } + + // Constructor from input iterator and size. + template + requires InputIterator && + SafelyCastable::reference, T> explicit d_packed_trig_monomial( + It it, ::std::size_t n, bool type = true) + : m_type(type) + { + // Prepare the container. + const auto vsize = detail::dptm_n_expos_to_vsize(n); + m_container.resize(::obake::safe_cast(vsize)); + + ::std::size_t counter = 0; + bool first_nz_found = false; + for (auto &out : m_container) { + kpacker kp(psize); + + // Keep packing until we get to psize or we have + // exhausted the input values. + for (auto j = 0u; j < psize && counter < n; ++j, ++counter, ++it) { + const auto tmp = ::obake::safe_cast(*it); + + if (obake_unlikely(!first_nz_found && tmp < 0)) { + // This is the first nonzero exponent + // and it is negative, thus the canonical + // form of the monomial is violated. + using namespace ::fmt::literals; + obake_throw(::std::invalid_argument, + "Cannot construct a trigonometric monomial whose first nonzero " + "exponent ({}) is negative"_format(tmp)); + } + + // Update first_nz_found. + first_nz_found = (first_nz_found || tmp != 0); + + kp << tmp; + } + + out = kp.get(); + } + } + + container_t &_container() + { + return m_container; + } + const container_t &_container() const + { + return m_container; + } + + bool &_type() + { + return m_type; + } + const bool &type() const + { + return m_type; + } +}; + +} // namespace poisson_series + +// Lift to the obake namespace. +template +using d_packed_trig_monomial = poisson_series::d_packed_trig_monomial; + +} // namespace obake + +#endif diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f13c5450..6aceb56c 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -97,6 +97,7 @@ ADD_OBAKE_TESTCASE(type_name) ADD_OBAKE_TESTCASE(xoroshiro128_plus) ADD_OBAKE_TESTCASE(power_series_00) ADD_OBAKE_TESTCASE(power_series_01) +ADD_OBAKE_TESTCASE(d_packed_trig_monomial_00) add_library(ss_fw_test_lib SHARED ss_fw_test_lib.cpp) target_compile_options(ss_fw_test_lib PRIVATE diff --git a/test/d_packed_trig_monomial_00.cpp b/test/d_packed_trig_monomial_00.cpp new file mode 100644 index 00000000..afa92223 --- /dev/null +++ b/test/d_packed_trig_monomial_00.cpp @@ -0,0 +1,299 @@ +// Copyright 2019-2020 Francesco Biscani (bluescarni@gmail.com) +// +// This file is part of the obake library. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include +// #include +// #include +#include +#include +// #include +// #include +// #include +#include +// #include +#include +#include +#include + +#include +// #include +#include +// #include +// #include +// #include +// #include +// #include +// #include +#include +#include +#include +// #include +#include + +#include "catch.hpp" +#include "test_utils.hpp" + +using namespace obake; + +using int_types = std::tuple; + +// The packed sizes over which we will be testing for type T. +template +using psizes + = std::tuple, std::integral_constant, + std::integral_constant, std::integral_constant()>>; + +// std::mt19937 rng; + +TEST_CASE("basic_test") +{ + obake_test::disable_slow_stack_traces(); + + detail::tuple_for_each(int_types{}, [](const auto &n) { + using int_t = remove_cvref_t; + + detail::tuple_for_each(psizes{}, [](auto b) { + constexpr auto bw = decltype(b)::value; + using pm_t = d_packed_trig_monomial; + + REQUIRE(!std::is_constructible_v); + REQUIRE(!std::is_constructible_v); + REQUIRE(!std::is_constructible_v); + + pm_t t00; + + REQUIRE(t00._container().empty()); + REQUIRE(t00.type() == true); + + t00 = pm_t(symbol_set{}); + REQUIRE(t00._container().empty()); + REQUIRE(t00.type() == true); + + t00 = pm_t(symbol_set{"x"}); + REQUIRE(t00._container().size() == 1u); + REQUIRE(t00._container()[0] == 0); + REQUIRE(t00.type() == true); + + t00 = pm_t(symbol_set{"x"}, false); + REQUIRE(t00._container().size() == 1u); + REQUIRE(t00._container()[0] == 0); + REQUIRE(t00.type() == false); + + t00 = pm_t(symbol_set{"x", "y"}); + REQUIRE(t00._container().size() == (bw == 1u ? 2u : 1u)); + REQUIRE(std::all_of(t00._container().begin(), t00._container().end(), [](auto x) { return x == 0; })); + REQUIRE(t00.type() == true); + + t00 = pm_t(symbol_set{"x", "y"}, false); + REQUIRE(t00._container().size() == (bw == 1u ? 2u : 1u)); + REQUIRE(std::all_of(t00._container().begin(), t00._container().end(), [](auto x) { return x == 0; })); + REQUIRE(t00.type() == false); + + std::vector upack_v; + auto upack = [&upack_v](const pm_t &t, unsigned size) { + upack_v.clear(); + + int_t tmp; + + auto i = 0u; + for (const auto &n : t._container()) { + kunpacker ku(n, pm_t::psize); + + for (auto j = 0u; j < pm_t::psize && i != size; ++j, ++i) { + ku >> tmp; + + upack_v.push_back(tmp); + } + } + }; + + t00 = pm_t(static_cast(nullptr), 0); + REQUIRE(t00._container().empty()); + REQUIRE(t00.type() == true); + + t00 = pm_t(static_cast(nullptr), 0, false); + REQUIRE(t00._container().empty()); + REQUIRE(t00.type() == false); + + upack_v = std::vector{1}; + t00 = pm_t(upack_v.data(), 1); + upack(t00, 1); + REQUIRE(upack_v == std::vector{1}); + REQUIRE(t00.type() == true); + + upack_v = std::vector{2}; + t00 = pm_t(upack_v.data(), 1, false); + upack(t00, 1); + REQUIRE(upack_v == std::vector{2}); + REQUIRE(t00.type() == false); + + upack_v = std::vector{1, -1, 3, 3}; + t00 = pm_t(upack_v.data(), 4); + upack(t00, 4); + REQUIRE(upack_v == std::vector{1, -1, 3, 3}); + REQUIRE(t00.type() == true); + + upack_v = std::vector{0, 0, 3, 3}; + t00 = pm_t(upack_v.data(), 4, false); + upack(t00, 4); + REQUIRE(upack_v == std::vector{0, 0, 3, 3}); + REQUIRE(t00.type() == false); + + upack_v = std::vector{0, 0, 3, 3}; + t00 = pm_t(upack_v.data(), 4); + upack(t00, 4); + REQUIRE(upack_v == std::vector{0, 0, 3, 3}); + REQUIRE(t00.type() == true); + + upack_v = std::vector{0, 0, 3, 3}; + t00 = pm_t(upack_v.data(), 4, false); + upack(t00, 4); + REQUIRE(upack_v == std::vector{0, 0, 3, 3}); + REQUIRE(t00.type() == false); + + upack_v = std::vector{-1, 0, 3, 3}; + OBAKE_REQUIRES_THROWS_CONTAINS(pm_t(upack_v.data(), 4), std::invalid_argument, + "Cannot construct a trigonometric monomial whose first nonzero " + "exponent (-1) is negative"); + + upack_v = std::vector{0, 0, -3, 3}; + OBAKE_REQUIRES_THROWS_CONTAINS(pm_t(upack_v.data(), 4, false), std::invalid_argument, + "Cannot construct a trigonometric monomial whose first nonzero " + "exponent (-3) is negative"); + +#if 0 + using c_t = typename pm_t::container_t; + + REQUIRE(!std::is_constructible_v); + REQUIRE(!std::is_constructible_v); + REQUIRE(!std::is_constructible_v); + + // Default ctor. + REQUIRE(pm_t{}._container().empty()); + + // Ctor from symbol set. + REQUIRE(pm_t{symbol_set{}}._container().empty()); + REQUIRE(pm_t{symbol_set{"x"}}._container() == c_t{0}); + if constexpr (bw == 1u) { + // With full width, we need an element in the container per symbol. + REQUIRE(pm_t{symbol_set{"x", "y"}}._container() == c_t{0, 0}); + REQUIRE(pm_t{symbol_set{"x", "y", "z"}}._container() == c_t{0, 0, 0}); + } else { + REQUIRE(pm_t{symbol_set{"x", "y"}}._container() + == c_t(polynomials::detail::dpm_nexpos_to_vsize(2u))); + REQUIRE(pm_t{symbol_set{"x", "y", "z"}}._container() + == c_t(polynomials::detail::dpm_nexpos_to_vsize(3u))); + } + + // Constructors from iterators. + int_t arr[] = {1, 1, 1}; + + // Try empty size first. + REQUIRE(pm_t(arr, 0) == pm_t{}); + REQUIRE(pm_t(arr, arr) == pm_t{}); + + REQUIRE(pm_t(arr, 1)._container() == c_t{1}); + REQUIRE(pm_t(arr, arr + 1)._container() == c_t{1}); + if constexpr (bw == 1u) { + REQUIRE(pm_t(arr, 3)._container() == c_t{1, 1, 1}); + REQUIRE(pm_t(arr, arr + 3)._container() == c_t{1, 1, 1}); + } else { + REQUIRE(pm_t(arr, 3)._container().size() == polynomials::detail::dpm_nexpos_to_vsize(3u)); + REQUIRE(pm_t(arr, arr + 3)._container().size() == polynomials::detail::dpm_nexpos_to_vsize(3u)); + } + + // Try the init list ctor as well. + if constexpr (bw == 1u) { + REQUIRE(pm_t{1, 1, 1}._container() == c_t{1, 1, 1}); + } else { + REQUIRE(pm_t{1, 1, 1}._container().size() == polynomials::detail::dpm_nexpos_to_vsize(3u)); + } + + // Random testing. + if constexpr (bw <= 3u) { + using idist_t = std::uniform_int_distribution>; + using param_t = typename idist_t::param_type; + idist_t dist; + + c_t tmp, cmp; + int_t tmp_n; + + for (auto i = 0u; i < 1000u; ++i) { + tmp.resize(i); + + for (auto j = 0u; j < i; ++j) { + if constexpr (is_signed_v) { + tmp[j] = dist(rng, param_t{-10, 10}); + } else { + tmp[j] = dist(rng, param_t{0, 20}); + } + } + + // Construct the monomial. + pm_t pm(tmp.data(), i); + + // Unpack it into cmp. + cmp.clear(); + for (const auto &n : pm._container()) { + kunpacker ku(n, pm.psize); + for (auto j = 0u; j < pm.psize; ++j) { + ku >> tmp_n; + cmp.push_back(tmp_n); + } + } + + // Verify. + REQUIRE(cmp.size() >= tmp.size()); + REQUIRE(std::equal(tmp.begin(), tmp.end(), cmp.begin())); + REQUIRE(std::all_of(cmp.data() + tmp.size(), cmp.data() + cmp.size(), + [](const auto &n) { return n == int_t(0); })); + + // Do the same with input iterators. + pm = pm_t(tmp.begin(), tmp.end()); + + cmp.clear(); + for (const auto &n : pm._container()) { + kunpacker ku(n, pm.psize); + for (auto j = 0u; j < pm.psize; ++j) { + ku >> tmp_n; + cmp.push_back(tmp_n); + } + } + + REQUIRE(cmp.size() >= tmp.size()); + REQUIRE(std::equal(tmp.begin(), tmp.end(), cmp.begin())); + REQUIRE(std::all_of(cmp.data() + tmp.size(), cmp.data() + cmp.size(), + [](const auto &n) { return n == int_t(0); })); + + // Do the same with input range. + pm = pm_t(tmp); + + cmp.clear(); + for (const auto &n : pm._container()) { + kunpacker ku(n, pm.psize); + for (auto j = 0u; j < pm.psize; ++j) { + ku >> tmp_n; + cmp.push_back(tmp_n); + } + } + + REQUIRE(cmp.size() >= tmp.size()); + REQUIRE(std::equal(tmp.begin(), tmp.end(), cmp.begin())); + REQUIRE(std::all_of(cmp.data() + tmp.size(), cmp.data() + cmp.size(), + [](const auto &n) { return n == int_t(0); })); + } + } +#endif + }); + }); +} From 0b06cb70dd7b028abbd4abab619da1b417207c8b Mon Sep 17 00:00:00 2001 From: Francesco Biscani Date: Thu, 28 Jan 2021 17:32:37 +0100 Subject: [PATCH 03/28] Small optimisation in d_packed_monomial. --- include/obake/polynomials/d_packed_monomial.hpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/include/obake/polynomials/d_packed_monomial.hpp b/include/obake/polynomials/d_packed_monomial.hpp index 2f5de684..e9939e9b 100644 --- a/include/obake/polynomials/d_packed_monomial.hpp +++ b/include/obake/polynomials/d_packed_monomial.hpp @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -110,11 +111,12 @@ template requires InputIterator && SafelyCastable::reference, T> explicit d_packed_monomial(It it, ::std::size_t n) + : m_container( + ::obake::safe_cast(detail::dpm_nexpos_to_vsize(n)), + // NOTE: avoid value-init of the elements, as we will + // be setting all of them to some value in the loop below. + ::boost::container::default_init_t{}) { - // Prepare the container. - const auto vsize = detail::dpm_nexpos_to_vsize(n); - m_container.resize(::obake::safe_cast(vsize)); - ::std::size_t counter = 0; for (auto &out : m_container) { kpacker kp(psize); From 35131142f50a3bc22878f413dbd9485b878922a2 Mon Sep 17 00:00:00 2001 From: Francesco Biscani Date: Thu, 28 Jan 2021 17:32:58 +0100 Subject: [PATCH 04/28] Ditto for trig monomial. --- .../obake/poisson_series/d_packed_trig_monomial.hpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/include/obake/poisson_series/d_packed_trig_monomial.hpp b/include/obake/poisson_series/d_packed_trig_monomial.hpp index 388795d3..b4087577 100644 --- a/include/obake/poisson_series/d_packed_trig_monomial.hpp +++ b/include/obake/poisson_series/d_packed_trig_monomial.hpp @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -86,12 +87,13 @@ template requires InputIterator && SafelyCastable::reference, T> explicit d_packed_trig_monomial( It it, ::std::size_t n, bool type = true) - : m_type(type) + : m_container(::obake::safe_cast( + detail::dptm_n_expos_to_vsize(n)), + // NOTE: avoid value-init of the elements, as we will + // be setting all of them to some value in the loop below. + ::boost::container::default_init_t{}), + m_type(type) { - // Prepare the container. - const auto vsize = detail::dptm_n_expos_to_vsize(n); - m_container.resize(::obake::safe_cast(vsize)); - ::std::size_t counter = 0; bool first_nz_found = false; for (auto &out : m_container) { From 5aaf1fbd7676b494a2ca7fe72f21aac19117d648 Mon Sep 17 00:00:00 2001 From: Francesco Biscani Date: Thu, 28 Jan 2021 21:12:05 +0100 Subject: [PATCH 05/28] Small doc addition to d_packed_monomial. --- include/obake/polynomials/d_packed_monomial.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/obake/polynomials/d_packed_monomial.hpp b/include/obake/polynomials/d_packed_monomial.hpp index e9939e9b..51ec8727 100644 --- a/include/obake/polynomials/d_packed_monomial.hpp +++ b/include/obake/polynomials/d_packed_monomial.hpp @@ -135,6 +135,9 @@ template struct input_it_ctor_tag { }; // Implementation of the ctor from input iterators. + // NOTE: a possible optimisation here is to detect + // random-access iterators and delegate to the + // ctor from input iterator and size. template explicit d_packed_monomial(input_it_ctor_tag, It b, It e) { From 81ce008974b982abfbd26f1cd5dd2d7f4918b368 Mon Sep 17 00:00:00 2001 From: Francesco Biscani Date: Fri, 29 Jan 2021 10:07:21 +0100 Subject: [PATCH 06/28] Finish implementing/testing the ctors. --- .../poisson_series/d_packed_trig_monomial.hpp | 67 ++++++ test/d_packed_trig_monomial_00.cpp | 209 +++++++++--------- 2 files changed, 175 insertions(+), 101 deletions(-) diff --git a/include/obake/poisson_series/d_packed_trig_monomial.hpp b/include/obake/poisson_series/d_packed_trig_monomial.hpp index b4087577..a3320225 100644 --- a/include/obake/poisson_series/d_packed_trig_monomial.hpp +++ b/include/obake/poisson_series/d_packed_trig_monomial.hpp @@ -10,6 +10,7 @@ #define OBAKE_POISSON_SERIES_D_PACKED_TRIG_MONOMIAL_HPP #include +#include #include #include @@ -22,6 +23,7 @@ #include #include #include +#include #include #include @@ -124,6 +126,71 @@ template } } +private: + struct input_it_ctor_tag { + }; + // Implementation of the ctor from input iterators. + // NOTE: a possible optimisation here is to detect + // random-access iterators and delegate to the + // ctor from input iterator and size. + template + explicit d_packed_trig_monomial(input_it_ctor_tag, It b, It e, bool type) : m_type(type) + { + bool first_nz_found = false; + + while (b != e) { + kpacker kp(psize); + + for (auto j = 0u; j < psize && b != e; ++j, ++b) { + const auto tmp = ::obake::safe_cast(*b); + + if (obake_unlikely(!first_nz_found && tmp < 0)) { + // This is the first nonzero exponent + // and it is negative, thus the canonical + // form of the monomial is violated. + using namespace ::fmt::literals; + obake_throw(::std::invalid_argument, + "Cannot construct a trigonometric monomial whose first nonzero " + "exponent ({}) is negative"_format(tmp)); + } + + // Update first_nz_found. + first_nz_found = (first_nz_found || tmp != 0); + + kp << tmp; + } + + m_container.push_back(kp.get()); + } + } + +public: + // Ctor from a pair of input iterators. + template + requires InputIterator && + SafelyCastable::reference, T> explicit d_packed_trig_monomial(It b, It e, + bool type + = true) + : d_packed_trig_monomial(input_it_ctor_tag{}, b, e, type) + { + } + + // Ctor from input range. + template + requires InputRange &&SafelyCastable>::reference, + T> explicit d_packed_trig_monomial(Range &&r, bool type = true) + : d_packed_trig_monomial(input_it_ctor_tag{}, ::obake::begin(::std::forward(r)), + ::obake::end(::std::forward(r)), type) + { + } + + // Ctor from init list. + template + requires SafelyCastable explicit d_packed_trig_monomial(::std::initializer_list l) + : d_packed_trig_monomial(input_it_ctor_tag{}, l.begin(), l.end(), true) + { + } + container_t &_container() { return m_container; diff --git a/test/d_packed_trig_monomial_00.cpp b/test/d_packed_trig_monomial_00.cpp index afa92223..2ffc0b3c 100644 --- a/test/d_packed_trig_monomial_00.cpp +++ b/test/d_packed_trig_monomial_00.cpp @@ -13,7 +13,7 @@ #include // #include // #include -// #include +#include #include // #include #include @@ -53,7 +53,7 @@ using psizes = std::tuple, std::integral_constant, std::integral_constant, std::integral_constant()>>; -// std::mt19937 rng; +std::mt19937 rng; TEST_CASE("basic_test") { @@ -120,104 +120,137 @@ TEST_CASE("basic_test") t00 = pm_t(static_cast(nullptr), 0); REQUIRE(t00._container().empty()); REQUIRE(t00.type() == true); + t00 = pm_t(static_cast(nullptr), static_cast(nullptr)); + REQUIRE(t00._container().empty()); + REQUIRE(t00.type() == true); t00 = pm_t(static_cast(nullptr), 0, false); REQUIRE(t00._container().empty()); REQUIRE(t00.type() == false); + t00 = pm_t(static_cast(nullptr), static_cast(nullptr), false); + REQUIRE(t00._container().empty()); + REQUIRE(t00.type() == false); upack_v = std::vector{1}; t00 = pm_t(upack_v.data(), 1); upack(t00, 1); REQUIRE(upack_v == std::vector{1}); REQUIRE(t00.type() == true); + t00 = pm_t(upack_v.begin(), upack_v.end()); + upack(t00, 1); + REQUIRE(upack_v == std::vector{1}); + REQUIRE(t00.type() == true); + t00 = pm_t(upack_v); + upack(t00, 1); + REQUIRE(upack_v == std::vector{1}); + REQUIRE(t00.type() == true); upack_v = std::vector{2}; t00 = pm_t(upack_v.data(), 1, false); upack(t00, 1); REQUIRE(upack_v == std::vector{2}); REQUIRE(t00.type() == false); + t00 = pm_t(upack_v.begin(), upack_v.end(), false); + upack(t00, 1); + REQUIRE(upack_v == std::vector{2}); + REQUIRE(t00.type() == false); + t00 = pm_t(upack_v, false); + upack(t00, 1); + REQUIRE(upack_v == std::vector{2}); + REQUIRE(t00.type() == false); upack_v = std::vector{1, -1, 3, 3}; t00 = pm_t(upack_v.data(), 4); upack(t00, 4); REQUIRE(upack_v == std::vector{1, -1, 3, 3}); REQUIRE(t00.type() == true); + t00 = pm_t(upack_v.begin(), upack_v.end()); + upack(t00, 4); + REQUIRE(upack_v == std::vector{1, -1, 3, 3}); + REQUIRE(t00.type() == true); + t00 = pm_t(upack_v); + upack(t00, 4); + REQUIRE(upack_v == std::vector{1, -1, 3, 3}); + REQUIRE(t00.type() == true); upack_v = std::vector{0, 0, 3, 3}; t00 = pm_t(upack_v.data(), 4, false); upack(t00, 4); REQUIRE(upack_v == std::vector{0, 0, 3, 3}); REQUIRE(t00.type() == false); + t00 = pm_t(upack_v.begin(), upack_v.end(), false); + upack(t00, 4); + REQUIRE(upack_v == std::vector{0, 0, 3, 3}); + REQUIRE(t00.type() == false); + t00 = pm_t(upack_v, false); + upack(t00, 4); + REQUIRE(upack_v == std::vector{0, 0, 3, 3}); + REQUIRE(t00.type() == false); upack_v = std::vector{0, 0, 3, 3}; t00 = pm_t(upack_v.data(), 4); upack(t00, 4); REQUIRE(upack_v == std::vector{0, 0, 3, 3}); REQUIRE(t00.type() == true); + t00 = pm_t(upack_v.begin(), upack_v.end()); + upack(t00, 4); + REQUIRE(upack_v == std::vector{0, 0, 3, 3}); + REQUIRE(t00.type() == true); + t00 = pm_t(upack_v); + upack(t00, 4); + REQUIRE(upack_v == std::vector{0, 0, 3, 3}); + REQUIRE(t00.type() == true); upack_v = std::vector{0, 0, 3, 3}; t00 = pm_t(upack_v.data(), 4, false); upack(t00, 4); REQUIRE(upack_v == std::vector{0, 0, 3, 3}); REQUIRE(t00.type() == false); + t00 = pm_t(upack_v.begin(), upack_v.end(), false); + upack(t00, 4); + REQUIRE(upack_v == std::vector{0, 0, 3, 3}); + REQUIRE(t00.type() == false); + t00 = pm_t(upack_v, false); + upack(t00, 4); + REQUIRE(upack_v == std::vector{0, 0, 3, 3}); + REQUIRE(t00.type() == false); upack_v = std::vector{-1, 0, 3, 3}; OBAKE_REQUIRES_THROWS_CONTAINS(pm_t(upack_v.data(), 4), std::invalid_argument, "Cannot construct a trigonometric monomial whose first nonzero " "exponent (-1) is negative"); + OBAKE_REQUIRES_THROWS_CONTAINS(pm_t(upack_v.begin(), upack_v.end()), std::invalid_argument, + "Cannot construct a trigonometric monomial whose first nonzero " + "exponent (-1) is negative"); + OBAKE_REQUIRES_THROWS_CONTAINS(t00 = pm_t(upack_v), std::invalid_argument, + "Cannot construct a trigonometric monomial whose first nonzero " + "exponent (-1) is negative"); upack_v = std::vector{0, 0, -3, 3}; OBAKE_REQUIRES_THROWS_CONTAINS(pm_t(upack_v.data(), 4, false), std::invalid_argument, "Cannot construct a trigonometric monomial whose first nonzero " "exponent (-3) is negative"); + OBAKE_REQUIRES_THROWS_CONTAINS(pm_t(upack_v.begin(), upack_v.end()), std::invalid_argument, + "Cannot construct a trigonometric monomial whose first nonzero " + "exponent (-3) is negative"); + OBAKE_REQUIRES_THROWS_CONTAINS(t00 = pm_t(upack_v), std::invalid_argument, + "Cannot construct a trigonometric monomial whose first nonzero " + "exponent (-3) is negative"); -#if 0 - using c_t = typename pm_t::container_t; - - REQUIRE(!std::is_constructible_v); - REQUIRE(!std::is_constructible_v); - REQUIRE(!std::is_constructible_v); - - // Default ctor. - REQUIRE(pm_t{}._container().empty()); - - // Ctor from symbol set. - REQUIRE(pm_t{symbol_set{}}._container().empty()); - REQUIRE(pm_t{symbol_set{"x"}}._container() == c_t{0}); - if constexpr (bw == 1u) { - // With full width, we need an element in the container per symbol. - REQUIRE(pm_t{symbol_set{"x", "y"}}._container() == c_t{0, 0}); - REQUIRE(pm_t{symbol_set{"x", "y", "z"}}._container() == c_t{0, 0, 0}); - } else { - REQUIRE(pm_t{symbol_set{"x", "y"}}._container() - == c_t(polynomials::detail::dpm_nexpos_to_vsize(2u))); - REQUIRE(pm_t{symbol_set{"x", "y", "z"}}._container() - == c_t(polynomials::detail::dpm_nexpos_to_vsize(3u))); - } + // Ctor from init list. + t00 = pm_t{1, 2, 3}; + upack(t00, 3); + REQUIRE(upack_v == std::vector{1, 2, 3}); + REQUIRE(t00.type() == true); - // Constructors from iterators. - int_t arr[] = {1, 1, 1}; - - // Try empty size first. - REQUIRE(pm_t(arr, 0) == pm_t{}); - REQUIRE(pm_t(arr, arr) == pm_t{}); - - REQUIRE(pm_t(arr, 1)._container() == c_t{1}); - REQUIRE(pm_t(arr, arr + 1)._container() == c_t{1}); - if constexpr (bw == 1u) { - REQUIRE(pm_t(arr, 3)._container() == c_t{1, 1, 1}); - REQUIRE(pm_t(arr, arr + 3)._container() == c_t{1, 1, 1}); - } else { - REQUIRE(pm_t(arr, 3)._container().size() == polynomials::detail::dpm_nexpos_to_vsize(3u)); - REQUIRE(pm_t(arr, arr + 3)._container().size() == polynomials::detail::dpm_nexpos_to_vsize(3u)); - } + t00 = pm_t{0, 2, -3}; + upack(t00, 3); + REQUIRE(upack_v == std::vector{0, 2, -3}); + REQUIRE(t00.type() == true); - // Try the init list ctor as well. - if constexpr (bw == 1u) { - REQUIRE(pm_t{1, 1, 1}._container() == c_t{1, 1, 1}); - } else { - REQUIRE(pm_t{1, 1, 1}._container().size() == polynomials::detail::dpm_nexpos_to_vsize(3u)); - } + OBAKE_REQUIRES_THROWS_CONTAINS((t00 = pm_t{0, 0, -2}), std::invalid_argument, + "Cannot construct a trigonometric monomial whose first nonzero " + "exponent (-2) is negative"); // Random testing. if constexpr (bw <= 3u) { @@ -225,75 +258,49 @@ TEST_CASE("basic_test") using param_t = typename idist_t::param_type; idist_t dist; - c_t tmp, cmp; - int_t tmp_n; + std::vector copy; for (auto i = 0u; i < 1000u; ++i) { - tmp.resize(i); + upack_v.resize(i); + bool first_nz_found = false; for (auto j = 0u; j < i; ++j) { - if constexpr (is_signed_v) { - tmp[j] = dist(rng, param_t{-10, 10}); - } else { - tmp[j] = dist(rng, param_t{0, 20}); + auto tmp = dist(rng, param_t{-10, 10}); + + if (!first_nz_found && tmp < 0) { + tmp = -tmp; } + + upack_v[j] = tmp; + + first_nz_found = (first_nz_found || tmp != 0); } // Construct the monomial. - pm_t pm(tmp.data(), i); - - // Unpack it into cmp. - cmp.clear(); - for (const auto &n : pm._container()) { - kunpacker ku(n, pm.psize); - for (auto j = 0u; j < pm.psize; ++j) { - ku >> tmp_n; - cmp.push_back(tmp_n); - } - } + const bool type = (dist(rng, param_t{0, 1}) == 0); + pm_t pm(upack_v.data(), i, type); - // Verify. - REQUIRE(cmp.size() >= tmp.size()); - REQUIRE(std::equal(tmp.begin(), tmp.end(), cmp.begin())); - REQUIRE(std::all_of(cmp.data() + tmp.size(), cmp.data() + cmp.size(), - [](const auto &n) { return n == int_t(0); })); + copy = upack_v; - // Do the same with input iterators. - pm = pm_t(tmp.begin(), tmp.end()); - - cmp.clear(); - for (const auto &n : pm._container()) { - kunpacker ku(n, pm.psize); - for (auto j = 0u; j < pm.psize; ++j) { - ku >> tmp_n; - cmp.push_back(tmp_n); - } - } + // Unpack it. + upack(pm, i); - REQUIRE(cmp.size() >= tmp.size()); - REQUIRE(std::equal(tmp.begin(), tmp.end(), cmp.begin())); - REQUIRE(std::all_of(cmp.data() + tmp.size(), cmp.data() + cmp.size(), - [](const auto &n) { return n == int_t(0); })); + REQUIRE(upack_v == copy); + REQUIRE(pm.type() == type); - // Do the same with input range. - pm = pm_t(tmp); - - cmp.clear(); - for (const auto &n : pm._container()) { - kunpacker ku(n, pm.psize); - for (auto j = 0u; j < pm.psize; ++j) { - ku >> tmp_n; - cmp.push_back(tmp_n); - } - } + // Do the same with input iterators. + pm = pm_t(upack_v.begin(), upack_v.end(), type); + upack(pm, i); + REQUIRE(upack_v == copy); + REQUIRE(pm.type() == type); - REQUIRE(cmp.size() >= tmp.size()); - REQUIRE(std::equal(tmp.begin(), tmp.end(), cmp.begin())); - REQUIRE(std::all_of(cmp.data() + tmp.size(), cmp.data() + cmp.size(), - [](const auto &n) { return n == int_t(0); })); + // Do the same with input range. + pm = pm_t(upack_v, type); + upack(pm, i); + REQUIRE(upack_v == copy); + REQUIRE(pm.type() == type); } } -#endif }); }); } From 4dc78cbd5470321ca1b39a8f1196e4fa93c1d219 Mon Sep 17 00:00:00 2001 From: Francesco Biscani Date: Fri, 29 Jan 2021 12:30:30 +0100 Subject: [PATCH 07/28] More WIP for trig_monomial. --- .../poisson_series/d_packed_trig_monomial.hpp | 132 ++++++++++++++ test/d_packed_trig_monomial_00.cpp | 172 ++++++++++++++++-- 2 files changed, 290 insertions(+), 14 deletions(-) diff --git a/include/obake/poisson_series/d_packed_trig_monomial.hpp b/include/obake/poisson_series/d_packed_trig_monomial.hpp index a3320225..121d2a4a 100644 --- a/include/obake/poisson_series/d_packed_trig_monomial.hpp +++ b/include/obake/poisson_series/d_packed_trig_monomial.hpp @@ -9,13 +9,29 @@ #ifndef OBAKE_POISSON_SERIES_D_PACKED_TRIG_MONOMIAL_HPP #define OBAKE_POISSON_SERIES_D_PACKED_TRIG_MONOMIAL_HPP +#include #include +#include #include #include #include #include #include +#include +#include +#include + +// NOTE: the header for hash_combine changed in version 1.67. +#if (BOOST_VERSION / 100000 > 1) || (BOOST_VERSION / 100000 == 1 && BOOST_VERSION / 100 % 1000 >= 67) + +#include + +#else + +#include + +#endif #include @@ -24,6 +40,7 @@ #include #include #include +#include #include #include @@ -57,6 +74,8 @@ requires(is_signed_v == true) inline constexpr unsigned dptm_max_psize = ::ob template requires(is_signed_v == true) && (PSize > 0u) && (PSize <= dptm_max_psize)class d_packed_trig_monomial { + friend class ::boost::serialization::access; + public: // The container type. using container_t = ::boost::container::small_vector; @@ -208,8 +227,110 @@ template { return m_type; } + +private: + // Serialisation. + // NOTE: when improve the s11n experience, + // we will probably want to verify + // canonical form when loading from non-binary + // archives. + template + void save(Archive &ar, unsigned) const + { + ar << m_container.size(); + + for (const auto &n : m_container) { + ar << n; + } + + ar << m_type; + } + template + void load(Archive &ar, unsigned) + { + decltype(m_container.size()) size; + ar >> size; + m_container.resize(size); + + for (auto &n : m_container) { + ar >> n; + } + + ar >> m_type; + } + BOOST_SERIALIZATION_SPLIT_MEMBER() }; +// Default PSize for d_packed_trig_monomial. +inline constexpr unsigned dptm_default_psize = +#if defined(OBAKE_PACKABLE_INT64) + 8 +#else + 4 +#endif + ; + +// Default type for the exponents. +using dptm_default_t = +#if defined(OBAKE_PACKABLE_INT64) + ::std::int64_t +#else + ::std::int32_t +#endif + ; + +// Implementation of key_is_zero(). A trigonometric monomial is zero +// if it is a sine and all the exponents are zero. +template +inline bool key_is_zero(const d_packed_trig_monomial &d, const symbol_set &) +{ + return d.type() == false + && ::std::all_of(d._container().cbegin(), d._container().cend(), [](const T &n) { return n == T(0); }); +} + +// Implementation of key_is_one(). A trigonometric monomial is one if it is a cosine +// and all its exponents are zero. +template +inline bool key_is_one(const d_packed_trig_monomial &d, const symbol_set &) +{ + return d.type() == true + && ::std::all_of(d._container().cbegin(), d._container().cend(), [](const T &n) { return n == T(0); }); +} + +// Comparisons. +template +inline bool operator==(const d_packed_trig_monomial &d1, const d_packed_trig_monomial &d2) +{ + return d1.type() == d2.type() && d1._container() == d2._container(); +} + +template +inline bool operator!=(const d_packed_trig_monomial &d1, const d_packed_trig_monomial &d2) +{ + return !(d1 == d2); +} + +// Hash implementation. +// NOTE: this is not homomorphic at this time, +// and it is not clear if that is needed at all. +// A homomorphic implementation would ignore the +// type of the monomial and just add the exponents, +// at the price of a possible +// increase in collisions. +// NOTE: perhaps the extra mixing via hash_combine() +// is not really necessary, but on the other hand +// performance in poisson_series should not be really +// bottlenecked by this. Revisit when we have more data. +template +inline ::std::size_t hash(const d_packed_trig_monomial &d) +{ + auto ret = static_cast<::std::size_t>(d.type()); + for (const auto &n : d._container()) { + ::boost::hash_combine(ret, n); + } + return ret; +} + } // namespace poisson_series // Lift to the obake namespace. @@ -218,4 +339,15 @@ using d_packed_trig_monomial = poisson_series::d_packed_trig_monomial; } // namespace obake +namespace boost::serialization +{ + +// Disable tracking for d_packed_trig_monomial. +template +struct tracking_level<::obake::d_packed_trig_monomial> + : ::obake::detail::s11n_no_tracking<::obake::d_packed_trig_monomial> { +}; + +} // namespace boost::serialization + #endif diff --git a/test/d_packed_trig_monomial_00.cpp b/test/d_packed_trig_monomial_00.cpp index 2ffc0b3c..fd1c6e91 100644 --- a/test/d_packed_trig_monomial_00.cpp +++ b/test/d_packed_trig_monomial_00.cpp @@ -7,32 +7,27 @@ // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #include -// #include -// #include #include #include -// #include -// #include +#include #include #include -// #include #include #include #include +#include +#include + #include -// #include #include -// #include -// #include -// #include -// #include -// #include -// #include +#include +#include +#include #include #include #include -// #include +#include #include #include "catch.hpp" @@ -50,7 +45,8 @@ using int_types = std::tuple using psizes - = std::tuple, std::integral_constant, + = std::tuple, + std::integral_constant, std::integral_constant, std::integral_constant, std::integral_constant()>>; std::mt19937 rng; @@ -304,3 +300,151 @@ TEST_CASE("basic_test") }); }); } + +TEST_CASE("s11n_test") +{ + detail::tuple_for_each(int_types{}, [](const auto &n) { + using int_t = remove_cvref_t; + + detail::tuple_for_each(psizes{}, [](auto b) { + constexpr auto bw = decltype(b)::value; + using pm_t = d_packed_trig_monomial; + + auto test_s11n = [](const pm_t &t) { + std::stringstream ss; + + { + boost::archive::binary_oarchive oa(ss); + oa << t; + } + + pm_t out; + + { + boost::archive::binary_iarchive ia(ss); + ia >> out; + } + + REQUIRE(t == out); + REQUIRE(!(t != out)); + }; + + pm_t t; + test_s11n(t); + + t._type() = false; + test_s11n(t); + + t = pm_t{1, -2, 3}; + test_s11n(t); + + t._type() = false; + test_s11n(t); + + t = pm_t{0, 0, 1, -2, -3, 2}; + test_s11n(t); + + t._type() = false; + test_s11n(t); + }); + }); +} + +TEST_CASE("comparison") +{ + detail::tuple_for_each(int_types{}, [](const auto &n) { + using int_t = remove_cvref_t; + + detail::tuple_for_each(psizes{}, [](auto b) { + constexpr auto bw = decltype(b)::value; + using pm_t = d_packed_trig_monomial; + + REQUIRE(pm_t{} == pm_t{}); + REQUIRE(!(pm_t{} != pm_t{})); + + REQUIRE(pm_t{1, 2, -3} == pm_t{1, 2, -3}); + REQUIRE(pm_t{1, 2, -3} != pm_t{1, -2, -3}); + REQUIRE(pm_t{0, 2, -3} == pm_t{0, 2, -3}); + REQUIRE(pm_t{0, 2, -3} != pm_t{1, -2, -3}); + + // Checks on the type. + pm_t t0, t1; + t1._type() = false; + REQUIRE(t0 != t1); + REQUIRE(t1 != t0); + + t0 = pm_t{1, -2, 3, 0}; + t1 = t0; + t1._type() = false; + REQUIRE(t0 != t1); + REQUIRE(t1 != t0); + }); + }); +} + +TEST_CASE("is zero one") +{ + detail::tuple_for_each(int_types{}, [](const auto &n) { + using int_t = remove_cvref_t; + + detail::tuple_for_each(psizes{}, [](auto b) { + constexpr auto bw = decltype(b)::value; + using pm_t = d_packed_trig_monomial; + + REQUIRE(obake::key_is_one(pm_t{}, symbol_set{})); + REQUIRE(!obake::key_is_zero(pm_t{}, symbol_set{})); + + pm_t t00; + t00._type() = false; + REQUIRE(!obake::key_is_one(t00, symbol_set{})); + REQUIRE(obake::key_is_zero(t00, symbol_set{})); + + t00 = pm_t{0, 2, 3}; + REQUIRE(!obake::key_is_one(t00, symbol_set{})); + REQUIRE(!obake::key_is_zero(t00, symbol_set{})); + + t00._type() = false; + REQUIRE(!obake::key_is_one(t00, symbol_set{})); + REQUIRE(!obake::key_is_zero(t00, symbol_set{})); + + t00 = pm_t{1, -2, 3}; + REQUIRE(!obake::key_is_one(t00, symbol_set{})); + REQUIRE(!obake::key_is_zero(t00, symbol_set{})); + + t00._type() = false; + REQUIRE(!obake::key_is_one(t00, symbol_set{})); + REQUIRE(!obake::key_is_zero(t00, symbol_set{})); + + t00 = pm_t{0, 0, 0}; + REQUIRE(obake::key_is_one(t00, symbol_set{})); + REQUIRE(!obake::key_is_zero(t00, symbol_set{})); + + t00._type() = false; + REQUIRE(!obake::key_is_one(t00, symbol_set{})); + REQUIRE(obake::key_is_zero(t00, symbol_set{})); + }); + }); +} + +TEST_CASE("hash") +{ + detail::tuple_for_each(int_types{}, [](const auto &n) { + using int_t = remove_cvref_t; + + detail::tuple_for_each(psizes{}, [](auto b) { + constexpr auto bw = decltype(b)::value; + using pm_t = d_packed_trig_monomial; + + REQUIRE(obake::hash(pm_t{}) == 1u); + + pm_t t00; + t00._type() = false; + REQUIRE(obake::hash(t00) == 0u); + + t00 = pm_t{1, -2, 3, 0, 1}; + std::cout << "Sample hash for cos: " << obake::hash(t00) << '\n'; + t00._type() = false; + std::cout << "Sample hash for sin: " << obake::hash(t00) << '\n'; + }); + }); +} From e11041c8bfe988d3811f6da8e68a0cafeaf65a8e Mon Sep 17 00:00:00 2001 From: Francesco Biscani Date: Fri, 29 Jan 2021 12:32:51 +0100 Subject: [PATCH 08/28] Some testing additions to d_packed_monomial. --- test/polynomials_d_packed_monomial_00.cpp | 5 +++-- test/polynomials_d_packed_monomial_01.cpp | 5 +++-- test/polynomials_d_packed_monomial_02.cpp | 5 +++-- test/polynomials_d_packed_monomial_03.cpp | 5 +++-- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/test/polynomials_d_packed_monomial_00.cpp b/test/polynomials_d_packed_monomial_00.cpp index c62f2f54..b8b3b301 100644 --- a/test/polynomials_d_packed_monomial_00.cpp +++ b/test/polynomials_d_packed_monomial_00.cpp @@ -49,8 +49,9 @@ using int_types = std::tuple using psizes - = std::tuple, std::integral_constant, - std::integral_constant, std::integral_constant()>>; + = std::tuple, std::integral_constant, + std::integral_constant, std::integral_constant, + std::integral_constant()>>; std::mt19937 rng; diff --git a/test/polynomials_d_packed_monomial_01.cpp b/test/polynomials_d_packed_monomial_01.cpp index 1126062c..d2f551e8 100644 --- a/test/polynomials_d_packed_monomial_01.cpp +++ b/test/polynomials_d_packed_monomial_01.cpp @@ -49,8 +49,9 @@ using int_types = std::tuple using psizes - = std::tuple, std::integral_constant, - std::integral_constant, std::integral_constant()>>; + = std::tuple, std::integral_constant, + std::integral_constant, std::integral_constant, + std::integral_constant()>>; std::mt19937 rng; diff --git a/test/polynomials_d_packed_monomial_02.cpp b/test/polynomials_d_packed_monomial_02.cpp index 4af692e1..d5d686e2 100644 --- a/test/polynomials_d_packed_monomial_02.cpp +++ b/test/polynomials_d_packed_monomial_02.cpp @@ -52,8 +52,9 @@ using int_types = std::tuple using psizes - = std::tuple, std::integral_constant, - std::integral_constant, std::integral_constant()>>; + = std::tuple, std::integral_constant, + std::integral_constant, std::integral_constant, + std::integral_constant()>>; TEST_CASE("byte_size_test") { diff --git a/test/polynomials_d_packed_monomial_03.cpp b/test/polynomials_d_packed_monomial_03.cpp index 6050b87a..fd8c9042 100644 --- a/test/polynomials_d_packed_monomial_03.cpp +++ b/test/polynomials_d_packed_monomial_03.cpp @@ -40,8 +40,9 @@ using int_types = std::tuple using psizes - = std::tuple, std::integral_constant, - std::integral_constant, std::integral_constant()>>; + = std::tuple, std::integral_constant, + std::integral_constant, std::integral_constant, + std::integral_constant()>>; TEST_CASE("degree_overflow_test") { From a7bc70afa474a922602bc6e93dd055f238513ee9 Mon Sep 17 00:00:00 2001 From: Francesco Biscani Date: Fri, 29 Jan 2021 13:12:25 +0100 Subject: [PATCH 09/28] Small simplification in a benchmark. --- benchmark/audi_01.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/benchmark/audi_01.cpp b/benchmark/audi_01.cpp index 815eaf75..811ea1ef 100644 --- a/benchmark/audi_01.cpp +++ b/benchmark/audi_01.cpp @@ -9,7 +9,6 @@ #include #include -#include #include #include @@ -44,14 +43,7 @@ auto truncated_pow(const T &x, unsigned n, unsigned limit) int main() { - using p_type = polynomial, - double>; + using p_type = polynomial; auto polys = make_polynomials("x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10"); From c31774e95376b13f778e6837869b4abf557ccb0d Mon Sep 17 00:00:00 2001 From: Francesco Biscani Date: Fri, 29 Jan 2021 17:51:44 +0100 Subject: [PATCH 10/28] Factor out for re-use in d_packed_monomial. --- .../obake/polynomials/d_packed_monomial.hpp | 32 +++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/include/obake/polynomials/d_packed_monomial.hpp b/include/obake/polynomials/d_packed_monomial.hpp index 51ec8727..fc7b4a7d 100644 --- a/include/obake/polynomials/d_packed_monomial.hpp +++ b/include/obake/polynomials/d_packed_monomial.hpp @@ -67,12 +67,12 @@ namespace detail // we need to store n exponents in a dynamic packed // monomial of type T. U must be an // unsigned integral type. -template -constexpr auto dpm_nexpos_to_vsize(const U &n) noexcept +template +inline constexpr auto dpm_nexpos_to_vsize = [](const U &n) constexpr noexcept { static_assert(is_integral_v && !is_signed_v); return n / T::psize + static_cast(n % T::psize != 0u); -} +}; } // namespace detail @@ -282,16 +282,20 @@ inline ::std::size_t hash(const d_packed_monomial &d) return ret; } -// Symbol set compatibility implementation. -template -inline bool key_is_compatible(const d_packed_monomial &d, const symbol_set &s) +namespace detail +{ + +// Implementation of symbol set compatibility check. +// NOTE: factored out for re-use. +template +inline bool dpm_key_is_compatible(const T &d, const symbol_set &s, const F &f, unsigned psize) { const auto s_size = s.size(); const auto &c = d._container(); // Determine the size the container must have in order // to be able to represent s_size exponents. - const auto exp_size = detail::dpm_nexpos_to_vsize>(s_size); + const auto exp_size = f(s_size); // Check if c has the expected size. if (c.size() != exp_size) { @@ -300,7 +304,7 @@ inline bool key_is_compatible(const d_packed_monomial &d, const symbol // We need to check if the encoded values in the container // are within the limits. - const auto [klim_min, klim_max] = ::obake::detail::kpack_get_klims(PSize); + const auto [klim_min, klim_max] = ::obake::detail::kpack_get_klims(psize); for (const auto &n : c) { if (n < klim_min || n > klim_max) { return false; @@ -310,6 +314,15 @@ inline bool key_is_compatible(const d_packed_monomial &d, const symbol return true; } +} // namespace detail + +// Symbol set compatibility implementation. +template +inline bool key_is_compatible(const d_packed_monomial &d, const symbol_set &s) +{ + return detail::dpm_key_is_compatible(d, s, detail::dpm_nexpos_to_vsize>, PSize); +} + // Implementation of stream insertion. // NOTE: requires that d is compatible with s. template @@ -346,7 +359,8 @@ inline void key_stream_insert(::std::ostream &os, const d_packed_monomial Date: Fri, 29 Jan 2021 17:52:11 +0100 Subject: [PATCH 11/28] From free function to lambda. --- include/obake/poisson_series/d_packed_trig_monomial.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/obake/poisson_series/d_packed_trig_monomial.hpp b/include/obake/poisson_series/d_packed_trig_monomial.hpp index 121d2a4a..7030c8d7 100644 --- a/include/obake/poisson_series/d_packed_trig_monomial.hpp +++ b/include/obake/poisson_series/d_packed_trig_monomial.hpp @@ -57,12 +57,12 @@ namespace detail // we need to store n exponents in a dynamic packed // trig monomial of type T. U must be an // unsigned integral type. -template -constexpr auto dptm_n_expos_to_vsize(const U &n) noexcept +template +inline constexpr auto dptm_n_expos_to_vsize = [](const U &n) constexpr noexcept { static_assert(is_integral_v && !is_signed_v); return n / T::psize + static_cast(n % T::psize != 0u); -} +}; } // namespace detail From 2bded5feebbc488fdaf2d7cb02f06434f5800aed Mon Sep 17 00:00:00 2001 From: Francesco Biscani Date: Mon, 1 Feb 2021 09:56:47 +0100 Subject: [PATCH 12/28] Minor doc bit. --- include/obake/poisson_series/d_packed_trig_monomial.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/obake/poisson_series/d_packed_trig_monomial.hpp b/include/obake/poisson_series/d_packed_trig_monomial.hpp index 7030c8d7..3b4146bf 100644 --- a/include/obake/poisson_series/d_packed_trig_monomial.hpp +++ b/include/obake/poisson_series/d_packed_trig_monomial.hpp @@ -230,7 +230,7 @@ template private: // Serialisation. - // NOTE: when improve the s11n experience, + // NOTE: when we improve the s11n experience, // we will probably want to verify // canonical form when loading from non-binary // archives. @@ -321,6 +321,8 @@ inline bool operator!=(const d_packed_trig_monomial &d1, const d_packe // is not really necessary, but on the other hand // performance in poisson_series should not be really // bottlenecked by this. Revisit when we have more data. +// Also, once we have benchmarks, we should also +// investigate the absl hashing performance. template inline ::std::size_t hash(const d_packed_trig_monomial &d) { From 603d9b493fba8330decf6b0cffc796f2b9736f7e Mon Sep 17 00:00:00 2001 From: Francesco Biscani Date: Mon, 1 Feb 2021 10:01:17 +0100 Subject: [PATCH 13/28] Renaming in dpm for clarity. --- include/obake/polynomials/d_packed_monomial.hpp | 8 ++++---- test/polynomials_d_packed_monomial_00.cpp | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/obake/polynomials/d_packed_monomial.hpp b/include/obake/polynomials/d_packed_monomial.hpp index fc7b4a7d..b3a6fe49 100644 --- a/include/obake/polynomials/d_packed_monomial.hpp +++ b/include/obake/polynomials/d_packed_monomial.hpp @@ -68,7 +68,7 @@ namespace detail // monomial of type T. U must be an // unsigned integral type. template -inline constexpr auto dpm_nexpos_to_vsize = [](const U &n) constexpr noexcept +inline constexpr auto dpm_n_expos_to_vsize = [](const U &n) constexpr noexcept { static_assert(is_integral_v && !is_signed_v); return n / T::psize + static_cast(n % T::psize != 0u); @@ -102,7 +102,7 @@ template // Constructor from symbol set. explicit d_packed_monomial(const symbol_set &ss) : m_container(::obake::safe_cast( - detail::dpm_nexpos_to_vsize(ss.size()))) + detail::dpm_n_expos_to_vsize(ss.size()))) { } @@ -112,7 +112,7 @@ template SafelyCastable::reference, T> explicit d_packed_monomial(It it, ::std::size_t n) : m_container( - ::obake::safe_cast(detail::dpm_nexpos_to_vsize(n)), + ::obake::safe_cast(detail::dpm_n_expos_to_vsize(n)), // NOTE: avoid value-init of the elements, as we will // be setting all of them to some value in the loop below. ::boost::container::default_init_t{}) @@ -320,7 +320,7 @@ inline bool dpm_key_is_compatible(const T &d, const symbol_set &s, const F &f, u template inline bool key_is_compatible(const d_packed_monomial &d, const symbol_set &s) { - return detail::dpm_key_is_compatible(d, s, detail::dpm_nexpos_to_vsize>, PSize); + return detail::dpm_key_is_compatible(d, s, detail::dpm_n_expos_to_vsize>, PSize); } // Implementation of stream insertion. diff --git a/test/polynomials_d_packed_monomial_00.cpp b/test/polynomials_d_packed_monomial_00.cpp index b8b3b301..e63a636c 100644 --- a/test/polynomials_d_packed_monomial_00.cpp +++ b/test/polynomials_d_packed_monomial_00.cpp @@ -83,9 +83,9 @@ TEST_CASE("basic_test") REQUIRE(pm_t{symbol_set{"x", "y", "z"}}._container() == c_t{0, 0, 0}); } else { REQUIRE(pm_t{symbol_set{"x", "y"}}._container() - == c_t(polynomials::detail::dpm_nexpos_to_vsize(2u))); + == c_t(polynomials::detail::dpm_n_expos_to_vsize(2u))); REQUIRE(pm_t{symbol_set{"x", "y", "z"}}._container() - == c_t(polynomials::detail::dpm_nexpos_to_vsize(3u))); + == c_t(polynomials::detail::dpm_n_expos_to_vsize(3u))); } // Constructors from iterators. @@ -101,15 +101,15 @@ TEST_CASE("basic_test") REQUIRE(pm_t(arr, 3)._container() == c_t{1, 1, 1}); REQUIRE(pm_t(arr, arr + 3)._container() == c_t{1, 1, 1}); } else { - REQUIRE(pm_t(arr, 3)._container().size() == polynomials::detail::dpm_nexpos_to_vsize(3u)); - REQUIRE(pm_t(arr, arr + 3)._container().size() == polynomials::detail::dpm_nexpos_to_vsize(3u)); + REQUIRE(pm_t(arr, 3)._container().size() == polynomials::detail::dpm_n_expos_to_vsize(3u)); + REQUIRE(pm_t(arr, arr + 3)._container().size() == polynomials::detail::dpm_n_expos_to_vsize(3u)); } // Try the init list ctor as well. if constexpr (bw == 1u) { REQUIRE(pm_t{1, 1, 1}._container() == c_t{1, 1, 1}); } else { - REQUIRE(pm_t{1, 1, 1}._container().size() == polynomials::detail::dpm_nexpos_to_vsize(3u)); + REQUIRE(pm_t{1, 1, 1}._container().size() == polynomials::detail::dpm_n_expos_to_vsize(3u)); } // Random testing. From 46a21bd8c74dd67865cdf44fa9fef1edd6ab10c2 Mon Sep 17 00:00:00 2001 From: Francesco Biscani Date: Mon, 1 Feb 2021 10:01:36 +0100 Subject: [PATCH 14/28] Re-use a helper function instead of re-implementing it. --- .../poisson_series/d_packed_trig_monomial.hpp | 21 +++---------------- 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/include/obake/poisson_series/d_packed_trig_monomial.hpp b/include/obake/poisson_series/d_packed_trig_monomial.hpp index 3b4146bf..73af4c7c 100644 --- a/include/obake/poisson_series/d_packed_trig_monomial.hpp +++ b/include/obake/poisson_series/d_packed_trig_monomial.hpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -50,22 +51,6 @@ namespace obake namespace poisson_series { -namespace detail -{ - -// Small helper to determine the container size -// we need to store n exponents in a dynamic packed -// trig monomial of type T. U must be an -// unsigned integral type. -template -inline constexpr auto dptm_n_expos_to_vsize = [](const U &n) constexpr noexcept -{ - static_assert(is_integral_v && !is_signed_v); - return n / T::psize + static_cast(n % T::psize != 0u); -}; - -} // namespace detail - // Max psize for d_packed_trig_monomial. template requires(is_signed_v == true) inline constexpr unsigned dptm_max_psize = ::obake::detail::kpack_max_size(); @@ -98,7 +83,7 @@ template // Constructor from symbol set. explicit d_packed_trig_monomial(const symbol_set &ss, bool type = true) : m_container(::obake::safe_cast( - detail::dptm_n_expos_to_vsize(ss.size()))), + polynomials::detail::dpm_n_expos_to_vsize(ss.size()))), m_type(type) { } @@ -109,7 +94,7 @@ template SafelyCastable::reference, T> explicit d_packed_trig_monomial( It it, ::std::size_t n, bool type = true) : m_container(::obake::safe_cast( - detail::dptm_n_expos_to_vsize(n)), + polynomials::detail::dpm_n_expos_to_vsize(n)), // NOTE: avoid value-init of the elements, as we will // be setting all of them to some value in the loop below. ::boost::container::default_init_t{}), From cacf3c3e4b3eb5e8c734765751844d9de4f51da4 Mon Sep 17 00:00:00 2001 From: Francesco Biscani Date: Mon, 1 Feb 2021 15:29:58 +0100 Subject: [PATCH 15/28] Change the canonical form of trig_monomial to consider the last nonzero exponent, rather than the first. --- .../poisson_series/d_packed_trig_monomial.hpp | 81 ++++++++++--------- test/d_packed_trig_monomial_00.cpp | 73 +++++++++-------- 2 files changed, 83 insertions(+), 71 deletions(-) diff --git a/include/obake/poisson_series/d_packed_trig_monomial.hpp b/include/obake/poisson_series/d_packed_trig_monomial.hpp index 73af4c7c..8d960ecf 100644 --- a/include/obake/poisson_series/d_packed_trig_monomial.hpp +++ b/include/obake/poisson_series/d_packed_trig_monomial.hpp @@ -10,6 +10,7 @@ #define OBAKE_POISSON_SERIES_D_PACKED_TRIG_MONOMIAL_HPP #include +#include #include #include #include @@ -33,8 +34,6 @@ #endif -#include - #include #include #include @@ -101,32 +100,37 @@ template m_type(type) { ::std::size_t counter = 0; - bool first_nz_found = false; + bool cur_positive = true; for (auto &out : m_container) { kpacker kp(psize); // Keep packing until we get to psize or we have // exhausted the input values. for (auto j = 0u; j < psize && counter < n; ++j, ++counter, ++it) { - const auto tmp = ::obake::safe_cast(*it); - - if (obake_unlikely(!first_nz_found && tmp < 0)) { - // This is the first nonzero exponent - // and it is negative, thus the canonical - // form of the monomial is violated. - using namespace ::fmt::literals; - obake_throw(::std::invalid_argument, - "Cannot construct a trigonometric monomial whose first nonzero " - "exponent ({}) is negative"_format(tmp)); - } - - // Update first_nz_found. - first_nz_found = (first_nz_found || tmp != 0); - - kp << tmp; + kp << ::obake::safe_cast(*it); } out = kp.get(); + + // Check if we added a positive + // or negative value. If we added + // a zero value, we don't alter + // cur_positive. + if (kp.get() < 0) { + cur_positive = false; + } else if (kp.get() > 0) { + cur_positive = true; + } else { + // For coverage purposes. + assert(kp.get() == 0); + } + } + + if (obake_unlikely(!cur_positive)) { + // The last nonzero value added to the container + // was negative: the monomial is not in canonical form. + obake_throw(::std::invalid_argument, "Cannot construct a trigonometric monomial whose last nonzero " + "exponent is negative"); } } @@ -140,31 +144,36 @@ template template explicit d_packed_trig_monomial(input_it_ctor_tag, It b, It e, bool type) : m_type(type) { - bool first_nz_found = false; + bool cur_positive = true; while (b != e) { kpacker kp(psize); for (auto j = 0u; j < psize && b != e; ++j, ++b) { - const auto tmp = ::obake::safe_cast(*b); - - if (obake_unlikely(!first_nz_found && tmp < 0)) { - // This is the first nonzero exponent - // and it is negative, thus the canonical - // form of the monomial is violated. - using namespace ::fmt::literals; - obake_throw(::std::invalid_argument, - "Cannot construct a trigonometric monomial whose first nonzero " - "exponent ({}) is negative"_format(tmp)); - } - - // Update first_nz_found. - first_nz_found = (first_nz_found || tmp != 0); - - kp << tmp; + kp << ::obake::safe_cast(*b); } m_container.push_back(kp.get()); + + // Check if we added a positive + // or negative value. If we added + // a zero value, we don't alter + // cur_positive. + if (kp.get() < 0) { + cur_positive = false; + } else if (kp.get() > 0) { + cur_positive = true; + } else { + // For coverage purposes. + assert(kp.get() == 0); + } + } + + if (obake_unlikely(!cur_positive)) { + // The last nonzero value added to the container + // was negative: the monomial is not in canonical form. + obake_throw(::std::invalid_argument, "Cannot construct a trigonometric monomial whose last nonzero " + "exponent is negative"); } } diff --git a/test/d_packed_trig_monomial_00.cpp b/test/d_packed_trig_monomial_00.cpp index fd1c6e91..8efd1d96 100644 --- a/test/d_packed_trig_monomial_00.cpp +++ b/test/d_packed_trig_monomial_00.cpp @@ -169,69 +169,69 @@ TEST_CASE("basic_test") REQUIRE(upack_v == std::vector{1, -1, 3, 3}); REQUIRE(t00.type() == true); - upack_v = std::vector{0, 0, 3, 3}; + upack_v = std::vector{3, 3, 0, 0}; t00 = pm_t(upack_v.data(), 4, false); upack(t00, 4); - REQUIRE(upack_v == std::vector{0, 0, 3, 3}); + REQUIRE(upack_v == std::vector{3, 3, 0, 0}); REQUIRE(t00.type() == false); t00 = pm_t(upack_v.begin(), upack_v.end(), false); upack(t00, 4); - REQUIRE(upack_v == std::vector{0, 0, 3, 3}); + REQUIRE(upack_v == std::vector{3, 3, 0, 0}); REQUIRE(t00.type() == false); t00 = pm_t(upack_v, false); upack(t00, 4); - REQUIRE(upack_v == std::vector{0, 0, 3, 3}); + REQUIRE(upack_v == std::vector{3, 3, 0, 0}); REQUIRE(t00.type() == false); - upack_v = std::vector{0, 0, 3, 3}; + upack_v = std::vector{3, 3, 0, 0}; t00 = pm_t(upack_v.data(), 4); upack(t00, 4); - REQUIRE(upack_v == std::vector{0, 0, 3, 3}); + REQUIRE(upack_v == std::vector{3, 3, 0, 0}); REQUIRE(t00.type() == true); t00 = pm_t(upack_v.begin(), upack_v.end()); upack(t00, 4); - REQUIRE(upack_v == std::vector{0, 0, 3, 3}); + REQUIRE(upack_v == std::vector{3, 3, 0, 0}); REQUIRE(t00.type() == true); t00 = pm_t(upack_v); upack(t00, 4); - REQUIRE(upack_v == std::vector{0, 0, 3, 3}); + REQUIRE(upack_v == std::vector{3, 3, 0, 0}); REQUIRE(t00.type() == true); - upack_v = std::vector{0, 0, 3, 3}; + upack_v = std::vector{3, 3, 0, 0}; t00 = pm_t(upack_v.data(), 4, false); upack(t00, 4); - REQUIRE(upack_v == std::vector{0, 0, 3, 3}); + REQUIRE(upack_v == std::vector{3, 3, 0, 0}); REQUIRE(t00.type() == false); t00 = pm_t(upack_v.begin(), upack_v.end(), false); upack(t00, 4); - REQUIRE(upack_v == std::vector{0, 0, 3, 3}); + REQUIRE(upack_v == std::vector{3, 3, 0, 0}); REQUIRE(t00.type() == false); t00 = pm_t(upack_v, false); upack(t00, 4); - REQUIRE(upack_v == std::vector{0, 0, 3, 3}); + REQUIRE(upack_v == std::vector{3, 3, 0, 0}); REQUIRE(t00.type() == false); - upack_v = std::vector{-1, 0, 3, 3}; + upack_v = std::vector{1, 0, 3, -3}; OBAKE_REQUIRES_THROWS_CONTAINS(pm_t(upack_v.data(), 4), std::invalid_argument, - "Cannot construct a trigonometric monomial whose first nonzero " - "exponent (-1) is negative"); + "Cannot construct a trigonometric monomial whose last nonzero " + "exponent is negative"); OBAKE_REQUIRES_THROWS_CONTAINS(pm_t(upack_v.begin(), upack_v.end()), std::invalid_argument, - "Cannot construct a trigonometric monomial whose first nonzero " - "exponent (-1) is negative"); + "Cannot construct a trigonometric monomial whose last nonzero " + "exponent is negative"); OBAKE_REQUIRES_THROWS_CONTAINS(t00 = pm_t(upack_v), std::invalid_argument, - "Cannot construct a trigonometric monomial whose first nonzero " - "exponent (-1) is negative"); + "Cannot construct a trigonometric monomial whose last nonzero " + "exponent is negative"); - upack_v = std::vector{0, 0, -3, 3}; + upack_v = std::vector{3, -3, 0, 0}; OBAKE_REQUIRES_THROWS_CONTAINS(pm_t(upack_v.data(), 4, false), std::invalid_argument, - "Cannot construct a trigonometric monomial whose first nonzero " - "exponent (-3) is negative"); + "Cannot construct a trigonometric monomial whose last nonzero " + "exponent is negative"); OBAKE_REQUIRES_THROWS_CONTAINS(pm_t(upack_v.begin(), upack_v.end()), std::invalid_argument, - "Cannot construct a trigonometric monomial whose first nonzero " - "exponent (-3) is negative"); + "Cannot construct a trigonometric monomial whose last nonzero " + "exponent is negative"); OBAKE_REQUIRES_THROWS_CONTAINS(t00 = pm_t(upack_v), std::invalid_argument, - "Cannot construct a trigonometric monomial whose first nonzero " - "exponent (-3) is negative"); + "Cannot construct a trigonometric monomial whose last nonzero " + "exponent is negative"); // Ctor from init list. t00 = pm_t{1, 2, 3}; @@ -239,14 +239,14 @@ TEST_CASE("basic_test") REQUIRE(upack_v == std::vector{1, 2, 3}); REQUIRE(t00.type() == true); - t00 = pm_t{0, 2, -3}; + t00 = pm_t{-3, 2, 0}; upack(t00, 3); - REQUIRE(upack_v == std::vector{0, 2, -3}); + REQUIRE(upack_v == std::vector{-3, 2, 0}); REQUIRE(t00.type() == true); - OBAKE_REQUIRES_THROWS_CONTAINS((t00 = pm_t{0, 0, -2}), std::invalid_argument, - "Cannot construct a trigonometric monomial whose first nonzero " - "exponent (-2) is negative"); + OBAKE_REQUIRES_THROWS_CONTAINS((t00 = pm_t{-2, 0, 0}), std::invalid_argument, + "Cannot construct a trigonometric monomial whose last nonzero " + "exponent is negative"); // Random testing. if constexpr (bw <= 3u) { @@ -272,6 +272,9 @@ TEST_CASE("basic_test") first_nz_found = (first_nz_found || tmp != 0); } + // Reverse it. + std::reverse(upack_v.begin(), upack_v.end()); + // Construct the monomial. const bool type = (dist(rng, param_t{0, 1}) == 0); pm_t pm(upack_v.data(), i, type); @@ -362,10 +365,10 @@ TEST_CASE("comparison") REQUIRE(pm_t{} == pm_t{}); REQUIRE(!(pm_t{} != pm_t{})); - REQUIRE(pm_t{1, 2, -3} == pm_t{1, 2, -3}); - REQUIRE(pm_t{1, 2, -3} != pm_t{1, -2, -3}); - REQUIRE(pm_t{0, 2, -3} == pm_t{0, 2, -3}); - REQUIRE(pm_t{0, 2, -3} != pm_t{1, -2, -3}); + REQUIRE(pm_t{-1, 2, 3} == pm_t{-1, 2, 3}); + REQUIRE(pm_t{1, 2, 3} != pm_t{1, -2, 3}); + REQUIRE(pm_t{-3, 2, 0} == pm_t{-3, 2, 0}); + REQUIRE(pm_t{-3, 2, 0} != pm_t{-3, 2, 1}); // Checks on the type. pm_t t0, t1; From 2631ddbadec3b4587ab103b8d2a244e3a2562e4f Mon Sep 17 00:00:00 2001 From: Francesco Biscani Date: Mon, 1 Feb 2021 16:08:15 +0100 Subject: [PATCH 16/28] Add optional type argument to the ctor from init list. --- .../obake/poisson_series/d_packed_trig_monomial.hpp | 5 +++-- test/d_packed_trig_monomial_00.cpp | 10 ++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/include/obake/poisson_series/d_packed_trig_monomial.hpp b/include/obake/poisson_series/d_packed_trig_monomial.hpp index 8d960ecf..f49d0df3 100644 --- a/include/obake/poisson_series/d_packed_trig_monomial.hpp +++ b/include/obake/poisson_series/d_packed_trig_monomial.hpp @@ -199,8 +199,9 @@ template // Ctor from init list. template - requires SafelyCastable explicit d_packed_trig_monomial(::std::initializer_list l) - : d_packed_trig_monomial(input_it_ctor_tag{}, l.begin(), l.end(), true) + requires SafelyCastable explicit d_packed_trig_monomial(::std::initializer_list l, + bool type = true) + : d_packed_trig_monomial(input_it_ctor_tag{}, l.begin(), l.end(), type) { } diff --git a/test/d_packed_trig_monomial_00.cpp b/test/d_packed_trig_monomial_00.cpp index 8efd1d96..8632ad30 100644 --- a/test/d_packed_trig_monomial_00.cpp +++ b/test/d_packed_trig_monomial_00.cpp @@ -244,6 +244,16 @@ TEST_CASE("basic_test") REQUIRE(upack_v == std::vector{-3, 2, 0}); REQUIRE(t00.type() == true); + t00 = pm_t({1, 2, 3}, false); + upack(t00, 3); + REQUIRE(upack_v == std::vector{1, 2, 3}); + REQUIRE(t00.type() == false); + + t00 = pm_t({-3, 2, 0}, false); + upack(t00, 3); + REQUIRE(upack_v == std::vector{-3, 2, 0}); + REQUIRE(t00.type() == false); + OBAKE_REQUIRES_THROWS_CONTAINS((t00 = pm_t{-2, 0, 0}), std::invalid_argument, "Cannot construct a trigonometric monomial whose last nonzero " "exponent is negative"); From 2ca72151e59b1a56d34509dc42862dbb939786d7 Mon Sep 17 00:00:00 2001 From: Francesco Biscani Date: Mon, 1 Feb 2021 16:28:51 +0100 Subject: [PATCH 17/28] Key compat check for trig_monomial. --- .../poisson_series/d_packed_trig_monomial.hpp | 61 +++++++++++++++++++ test/d_packed_trig_monomial_00.cpp | 42 +++++++++++++ 2 files changed, 103 insertions(+) diff --git a/include/obake/poisson_series/d_packed_trig_monomial.hpp b/include/obake/poisson_series/d_packed_trig_monomial.hpp index f49d0df3..6d8039ef 100644 --- a/include/obake/poisson_series/d_packed_trig_monomial.hpp +++ b/include/obake/poisson_series/d_packed_trig_monomial.hpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -328,6 +329,66 @@ inline ::std::size_t hash(const d_packed_trig_monomial &d) return ret; } +// Symbol set compatibility implementation. +template +inline bool key_is_compatible(const d_packed_trig_monomial &d, const symbol_set &s) +{ + const auto s_size = s.size(); + const auto &c = d._container(); + + // Determine the size the container must have in order + // to be able to represent s_size exponents. + const auto exp_size = polynomials::detail::dpm_n_expos_to_vsize>(s_size); + + // Check if c has the expected size. + if (c.size() != exp_size) { + return false; + } + + // We need to check if the encoded values in the container + // are within the limits, and if the canonical form is respected. + const auto [klim_min, klim_max] = ::obake::detail::kpack_get_klims(PSize); + bool cur_positive = true; + for (const auto &n : c) { + if (n < klim_min || n > klim_max) { + return false; + } + + if (n < 0) { + cur_positive = false; + } else if (n > 0) { + cur_positive = true; + } else { + assert(n == 0); + } + } + + return cur_positive; +} + +// Implementation of stream insertion. +// NOTE: requires that d is compatible with s. +template +inline void key_stream_insert(::std::ostream &os, const d_packed_trig_monomial &d, const symbol_set &s) +{ + assert(poisson_series::key_is_compatible(d, s)); + + const auto &c = d._container(); + auto s_it = s.cbegin(); + const auto s_end = s.cend(); + + // Don't print anything in case all exponents are zero. + // NOTE: if this is a sine, it should not have all exponents + // set to zero in a series, because otherwise d itself would + // be zero and it should not be in a series in the first place. + if (::std::all_of(c.begin(), c.end(), [](const T &n) { return n == T(0); })) { + return; + } + + // Print the type. + os << (d.type() ? "cos(" : "sin("); +} + } // namespace poisson_series // Lift to the obake namespace. diff --git a/test/d_packed_trig_monomial_00.cpp b/test/d_packed_trig_monomial_00.cpp index 8632ad30..d9df77ca 100644 --- a/test/d_packed_trig_monomial_00.cpp +++ b/test/d_packed_trig_monomial_00.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -461,3 +462,44 @@ TEST_CASE("hash") }); }); } + +TEST_CASE("key_is_compatible") +{ + detail::tuple_for_each(int_types{}, [](const auto &n) { + using int_t = remove_cvref_t; + + detail::tuple_for_each(psizes{}, [](auto b) { + constexpr auto bw = decltype(b)::value; + using pm_t = d_packed_trig_monomial; + + REQUIRE(obake::key_is_compatible(pm_t{}, symbol_set{})); + REQUIRE(obake::key_is_compatible(pm_t{1, 2, 3}, symbol_set{"x", "y", "z"})); + REQUIRE(obake::key_is_compatible(pm_t{1, -2, 3}, symbol_set{"x", "y", "z"})); + REQUIRE(obake::key_is_compatible(pm_t{-1, -2, 3}, symbol_set{"x", "y", "z"})); + REQUIRE(obake::key_is_compatible(pm_t{-1, -2, 3, 0, 0, 0}, symbol_set{"x", "y", "z", "a", "b", "c"})); + REQUIRE(obake::key_is_compatible(pm_t{0, 0, 3, 0, 0, 0}, symbol_set{"x", "y", "z", "a", "b", "c"})); + + // Size mismatch. + REQUIRE(!obake::key_is_compatible(pm_t{}, symbol_set{"x", "y", "z"})); + + // klim overflow. + pm_t t00{0}; + t00._container()[0] = detail::kpack_get_klims(bw).second + 1; + REQUIRE(!obake::key_is_compatible(t00, symbol_set{"x"})); + + // Non-canonical form. + t00 = pm_t{1, 2, 3}; + REQUIRE(obake::key_is_compatible(t00, symbol_set{"x", "y", "z"})); + t00._container().back() *= -1; + REQUIRE(!obake::key_is_compatible(t00, symbol_set{"x", "y", "z"})); + t00 = pm_t{-1, -2, 3}; + REQUIRE(obake::key_is_compatible(t00, symbol_set{"x", "y", "z"})); + t00._container().back() *= -1; + REQUIRE(!obake::key_is_compatible(t00, symbol_set{"x", "y", "z"})); + t00 = pm_t{-1, -2, 0, 0, 0, 3}; + REQUIRE(obake::key_is_compatible(t00, symbol_set{"x", "y", "z", "a", "b", "c"})); + t00._container().back() *= -1; + REQUIRE(!obake::key_is_compatible(t00, symbol_set{"x", "y", "z", "a", "b", "c"})); + }); + }); +} From f801d3eda0cb9930b6e652bcd59b21c6b81abdd6 Mon Sep 17 00:00:00 2001 From: Francesco Biscani Date: Mon, 1 Feb 2021 19:31:15 +0100 Subject: [PATCH 18/28] Some initial attempts at working around coverage issues. --- include/obake/poisson_series/d_packed_trig_monomial.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/obake/poisson_series/d_packed_trig_monomial.hpp b/include/obake/poisson_series/d_packed_trig_monomial.hpp index 6d8039ef..ed9ae4ab 100644 --- a/include/obake/poisson_series/d_packed_trig_monomial.hpp +++ b/include/obake/poisson_series/d_packed_trig_monomial.hpp @@ -123,7 +123,7 @@ template cur_positive = true; } else { // For coverage purposes. - assert(kp.get() == 0); + assert(kp.get() == 0); // LCOV_EXCL_LINE } } @@ -166,7 +166,7 @@ template cur_positive = true; } else { // For coverage purposes. - assert(kp.get() == 0); + assert(kp.get() == 0); // LCOV_EXCL_LINE } } @@ -359,7 +359,7 @@ inline bool key_is_compatible(const d_packed_trig_monomial &d, const s } else if (n > 0) { cur_positive = true; } else { - assert(n == 0); + assert(n == 0); // LCOV_EXCL_LINE } } @@ -371,7 +371,7 @@ inline bool key_is_compatible(const d_packed_trig_monomial &d, const s template inline void key_stream_insert(::std::ostream &os, const d_packed_trig_monomial &d, const symbol_set &s) { - assert(poisson_series::key_is_compatible(d, s)); + assert(poisson_series::key_is_compatible(d, s)); // LCOV_EXCL_LINE const auto &c = d._container(); auto s_it = s.cbegin(); From 088423454296c2d0aef673aeaf7707b83a3af7d7 Mon Sep 17 00:00:00 2001 From: Francesco Biscani Date: Tue, 2 Feb 2021 17:05:37 +0100 Subject: [PATCH 19/28] Stream insertion for trig monomial. --- CMakeLists.txt | 1 + .../poisson_series/d_packed_trig_monomial.hpp | 47 +++++++++++- src/poisson_series/d_packed_trig_monomial.cpp | 22 ++++++ test/d_packed_trig_monomial_00.cpp | 74 +++++++++++++++++++ 4 files changed, 140 insertions(+), 4 deletions(-) create mode 100644 src/poisson_series/d_packed_trig_monomial.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c0e24004..4998f6ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -194,6 +194,7 @@ set(OBAKE_SRC_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/kpack.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/polynomials/packed_monomial.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/polynomials/d_packed_monomial.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/src/poisson_series/d_packed_trig_monomial.cpp" ) if(OBAKE_WITH_LIBBACKTRACE) diff --git a/include/obake/poisson_series/d_packed_trig_monomial.hpp b/include/obake/poisson_series/d_packed_trig_monomial.hpp index ed9ae4ab..6b57a3e5 100644 --- a/include/obake/poisson_series/d_packed_trig_monomial.hpp +++ b/include/obake/poisson_series/d_packed_trig_monomial.hpp @@ -377,18 +377,57 @@ inline void key_stream_insert(::std::ostream &os, const d_packed_trig_monomial ku(n, PSize); + + for (auto j = 0u; j < PSize && s_it != s_end; ++j, ++s_it) { + ku >> tmp; + + if (tmp != 0) { + if (tmp > 0 && !empty_output) { + // A positive exponent, in case previous output exists, + // must be preceded by a "+" sign. + os << '+'; + } + + if (tmp == -1) { + // The exponent is -1, just print the + // minus sign. + os << '-'; + } else if (tmp != 1) { + // The exponent is not 1, print it. + using namespace ::fmt::literals; + os << "{}*"_format(tmp); + } + + // Finally, print name of variable. + os << *s_it; + + // Flag that we wrote something. + empty_output = false; + } + } + } + + os << ')'; } +extern template void key_stream_insert(::std::ostream &, + const d_packed_trig_monomial &, + const symbol_set &); + } // namespace poisson_series // Lift to the obake namespace. diff --git a/src/poisson_series/d_packed_trig_monomial.cpp b/src/poisson_series/d_packed_trig_monomial.cpp new file mode 100644 index 00000000..f88aa8fb --- /dev/null +++ b/src/poisson_series/d_packed_trig_monomial.cpp @@ -0,0 +1,22 @@ +// Copyright 2019-2020 Francesco Biscani (bluescarni@gmail.com) +// +// This file is part of the obake library. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include + +#include +#include +#include + +namespace obake::poisson_series +{ + +template OBAKE_DLL_PUBLIC void key_stream_insert(::std::ostream &, + const d_packed_trig_monomial &, + const symbol_set &); + +} // namespace obake::poisson_series diff --git a/test/d_packed_trig_monomial_00.cpp b/test/d_packed_trig_monomial_00.cpp index d9df77ca..83beed00 100644 --- a/test/d_packed_trig_monomial_00.cpp +++ b/test/d_packed_trig_monomial_00.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -503,3 +505,75 @@ TEST_CASE("key_is_compatible") }); }); } + +TEST_CASE("key_stream_insert") +{ + detail::tuple_for_each(int_types{}, [](const auto &n) { + using int_t = remove_cvref_t; + + detail::tuple_for_each(psizes{}, [](auto b) { + constexpr auto bw = decltype(b)::value; + using pm_t = d_packed_trig_monomial; + + auto stream = [](const pm_t &k, const symbol_set &ss) { + std::ostringstream oss; + + obake::key_stream_insert(oss, k, ss); + + return oss.str(); + }; + + // Check 0/1 printing. + REQUIRE(stream(pm_t{}, symbol_set{}) == "1"); + REQUIRE(stream(pm_t{0}, symbol_set{"x"}) == "1"); + REQUIRE(stream(pm_t{0, 0, 0}, symbol_set{"x", "y", "z"}) == "1"); + + REQUIRE(stream(pm_t({}, false), symbol_set{}) == "0"); + REQUIRE(stream(pm_t({0}, false), symbol_set{"x"}) == "0"); + REQUIRE(stream(pm_t({0, 0, 0}, false), symbol_set{"x", "y", "z"}) == "0"); + + // General test cases. + REQUIRE(stream(pm_t{1}, symbol_set{"x"}) == "cos(x)"); + REQUIRE(stream(pm_t({1}, false), symbol_set{"x"}) == "sin(x)"); + + REQUIRE(stream(pm_t{1, 1}, symbol_set{"x", "y"}) == "cos(x+y)"); + REQUIRE(stream(pm_t({1, 1}, false), symbol_set{"x", "y"}) == "sin(x+y)"); + + REQUIRE(stream(pm_t{1, 2}, symbol_set{"x", "y"}) == "cos(x+2*y)"); + REQUIRE(stream(pm_t({1, 2}, false), symbol_set{"x", "y"}) == "sin(x+2*y)"); + + REQUIRE(stream(pm_t{-1, 2}, symbol_set{"x", "y"}) == "cos(-x+2*y)"); + REQUIRE(stream(pm_t({-1, 2}, false), symbol_set{"x", "y"}) == "sin(-x+2*y)"); + + REQUIRE(stream(pm_t{3, 2}, symbol_set{"x", "y"}) == "cos(3*x+2*y)"); + REQUIRE(stream(pm_t({3, 2}, false), symbol_set{"x", "y"}) == "sin(3*x+2*y)"); + + REQUIRE(stream(pm_t{-3, 2}, symbol_set{"x", "y"}) == "cos(-3*x+2*y)"); + REQUIRE(stream(pm_t({-3, 2}, false), symbol_set{"x", "y"}) == "sin(-3*x+2*y)"); + + REQUIRE(stream(pm_t{3, 1, 2}, symbol_set{"x", "y", "z"}) == "cos(3*x+y+2*z)"); + REQUIRE(stream(pm_t({3, 1, 2}, false), symbol_set{"x", "y", "z"}) == "sin(3*x+y+2*z)"); + + REQUIRE(stream(pm_t{3, -1, 2}, symbol_set{"x", "y", "z"}) == "cos(3*x-y+2*z)"); + REQUIRE(stream(pm_t({3, -1, 2}, false), symbol_set{"x", "y", "z"}) == "sin(3*x-y+2*z)"); + + REQUIRE(stream(pm_t{0, 0, 2}, symbol_set{"x", "y", "z"}) == "cos(2*z)"); + REQUIRE(stream(pm_t({0, 0, 2}, false), symbol_set{"x", "y", "z"}) == "sin(2*z)"); + + REQUIRE(stream(pm_t{0, 0, 1}, symbol_set{"x", "y", "z"}) == "cos(z)"); + REQUIRE(stream(pm_t({0, 0, 1}, false), symbol_set{"x", "y", "z"}) == "sin(z)"); + + REQUIRE(stream(pm_t{2, 0, 1}, symbol_set{"x", "y", "z"}) == "cos(2*x+z)"); + REQUIRE(stream(pm_t({2, 0, 1}, false), symbol_set{"x", "y", "z"}) == "sin(2*x+z)"); + + REQUIRE(stream(pm_t{-2, 0, 1}, symbol_set{"x", "y", "z"}) == "cos(-2*x+z)"); + REQUIRE(stream(pm_t({-2, 0, 1}, false), symbol_set{"x", "y", "z"}) == "sin(-2*x+z)"); + + REQUIRE(stream(pm_t{-1, 0, 1}, symbol_set{"x", "y", "z"}) == "cos(-x+z)"); + REQUIRE(stream(pm_t({-1, 0, 1}, false), symbol_set{"x", "y", "z"}) == "sin(-x+z)"); + + REQUIRE(stream(pm_t{1, 0, 1}, symbol_set{"x", "y", "z"}) == "cos(x+z)"); + REQUIRE(stream(pm_t({1, 0, 1}, false), symbol_set{"x", "y", "z"}) == "sin(x+z)"); + }); + }); +} From 7a7e830a39655c487cb661bab88054cc9407d781 Mon Sep 17 00:00:00 2001 From: Francesco Biscani Date: Tue, 2 Feb 2021 17:19:18 +0100 Subject: [PATCH 20/28] Small tweaks to the stream operators of packed monomials. --- include/obake/polynomials/d_packed_monomial.hpp | 10 ++++++---- src/polynomials/packed_monomial.cpp | 13 +++++++++---- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/include/obake/polynomials/d_packed_monomial.hpp b/include/obake/polynomials/d_packed_monomial.hpp index 8e100729..d38edf7f 100644 --- a/include/obake/polynomials/d_packed_monomial.hpp +++ b/include/obake/polynomials/d_packed_monomial.hpp @@ -390,6 +390,8 @@ inline void key_tex_stream_insert(::std::ostream &os, const d_packed_monomial #include +#include #include @@ -128,11 +129,15 @@ void packed_monomial_tex_stream_insert(::std::ostream &os, const packed_monomial { assert(polynomials::key_is_compatible(m, s)); + using namespace ::fmt::literals; + // Use separate streams for numerator and denominator // (the denominator is used only in case of negative powers). ::std::ostringstream oss_num, oss_den, *cur_oss; oss_num.exceptions(::std::ios_base::failbit | ::std::ios_base::badbit); + oss_num.flags(os.flags()); oss_den.exceptions(::std::ios_base::failbit | ::std::ios_base::badbit); + oss_den.flags(os.flags()); // NOTE: we know s is not too large from the assert. const auto s_size = static_cast(s.size()); @@ -164,11 +169,11 @@ void packed_monomial_tex_stream_insert(::std::ostream &os, const packed_monomial } // Print the symbol name. - *cur_oss << '{' << var << '}'; + *cur_oss << "{{{}}}"_format(var); // Raise to power, if the exponent is not one. if (!tmp_mp.is_one()) { - *cur_oss << "^{" << tmp_mp << '}'; + *cur_oss << "^{{{}}}"_format(tmp_mp); } } } @@ -178,13 +183,13 @@ void packed_monomial_tex_stream_insert(::std::ostream &os, const packed_monomial if (!num_str.empty() && !den_str.empty()) { // We have both negative and positive exponents, // print them both in a fraction. - os << "\\frac{" << num_str << "}{" << den_str << '}'; + os << "\\frac{{{}}}{{{}}}"_format(num_str, den_str); } else if (!num_str.empty() && den_str.empty()) { // Only positive exponents. os << num_str; } else if (num_str.empty() && !den_str.empty()) { // Only negative exponents, display them as 1/something. - os << "\\frac{1}{" << den_str << '}'; + os << "\\frac{{1}}{{{}}}"_format(den_str); } else { // We did not write anything to the stream. // It means that all variables have zero From fcad84578934c0c3757cf334ad30712d8e601d91 Mon Sep 17 00:00:00 2001 From: Francesco Biscani Date: Tue, 2 Feb 2021 17:29:25 +0100 Subject: [PATCH 21/28] Tentative clang warning workaround. --- include/obake/type_traits.hpp | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/include/obake/type_traits.hpp b/include/obake/type_traits.hpp index 8649e101..8b14e187 100644 --- a/include/obake/type_traits.hpp +++ b/include/obake/type_traits.hpp @@ -342,10 +342,23 @@ OBAKE_CONCEPT_DECL InPlaceAddable = requires(T &&x, U &&y) namespace detail { +#if defined(__clang__) + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wincrement-bool" + +#endif + template using preinc_t = decltype(++::std::declval()); -} +#if defined(__clang__) + +#pragma clang diagnostic pop + +#endif + +} // namespace detail // Pre-incrementable type-trait. template @@ -367,10 +380,23 @@ OBAKE_CONCEPT_DECL PreIncrementable = requires(T &&x) namespace detail { +#if defined(__clang__) + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wincrement-bool" + +#endif + template using postinc_t = decltype(::std::declval()++); -} +#if defined(__clang__) + +#pragma clang diagnostic pop + +#endif + +} // namespace detail // Post-incrementable type-trait. template From e4890b9d377d268bdb7d049e207b1c5aec421b17 Mon Sep 17 00:00:00 2001 From: Francesco Biscani Date: Tue, 2 Feb 2021 19:27:39 +0100 Subject: [PATCH 22/28] Another coverage fix. --- include/obake/poisson_series/d_packed_trig_monomial.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/obake/poisson_series/d_packed_trig_monomial.hpp b/include/obake/poisson_series/d_packed_trig_monomial.hpp index 6b57a3e5..3da3ea06 100644 --- a/include/obake/poisson_series/d_packed_trig_monomial.hpp +++ b/include/obake/poisson_series/d_packed_trig_monomial.hpp @@ -93,12 +93,14 @@ template requires InputIterator && SafelyCastable::reference, T> explicit d_packed_trig_monomial( It it, ::std::size_t n, bool type = true) + // LCOV_EXCL_START : m_container(::obake::safe_cast( polynomials::detail::dpm_n_expos_to_vsize(n)), // NOTE: avoid value-init of the elements, as we will // be setting all of them to some value in the loop below. ::boost::container::default_init_t{}), m_type(type) + // LCOV_EXCL_STOP { ::std::size_t counter = 0; bool cur_positive = true; From 35ed93b95d7167c8898c2d36c02338e81c4fd33f Mon Sep 17 00:00:00 2001 From: Francesco Biscani Date: Wed, 3 Feb 2021 13:52:04 +0100 Subject: [PATCH 23/28] Finish up tex stream and test it. --- .../poisson_series/d_packed_trig_monomial.hpp | 65 +++++++++++++++- src/poisson_series/d_packed_trig_monomial.cpp | 4 + test/d_packed_trig_monomial_00.cpp | 74 +++++++++++++++++++ 3 files changed, 142 insertions(+), 1 deletion(-) diff --git a/include/obake/poisson_series/d_packed_trig_monomial.hpp b/include/obake/poisson_series/d_packed_trig_monomial.hpp index 3da3ea06..557a6158 100644 --- a/include/obake/poisson_series/d_packed_trig_monomial.hpp +++ b/include/obake/poisson_series/d_packed_trig_monomial.hpp @@ -381,7 +381,7 @@ inline void key_stream_insert(::std::ostream &os, const d_packed_trig_monomial &, const symbol_set &); +// Implementation of tex stream insertion. +// NOTE: requires that d is compatible with s. +template +inline void key_tex_stream_insert(::std::ostream &os, const d_packed_trig_monomial &d, const symbol_set &s) +{ + assert(poisson_series::key_is_compatible(d, s)); // LCOV_EXCL_LINE + + const auto &c = d._container(); + auto s_it = s.cbegin(); + const auto s_end = s.cend(); + + // Check if all exponents are zero. + if (::std::all_of(c.begin(), c.end(), [](const T &n) { return n == T(0); })) { + os << (d.type() ? '1' : '0'); + + return; + } + + // Print the type. + os << (d.type() ? "\\cos{\\left(" : "\\sin{\\left("); + + T tmp; + bool empty_output = true; + for (const auto &n : c) { + using namespace ::fmt::literals; + + kunpacker ku(n, PSize); + + for (auto j = 0u; j < PSize && s_it != s_end; ++j, ++s_it) { + ku >> tmp; + + if (tmp != 0) { + if (tmp > 0 && !empty_output) { + // A positive exponent, in case previous output exists, + // must be preceded by a "+" sign. + os << '+'; + } + + if (tmp == -1) { + // The exponent is -1, just print the + // minus sign. + os << '-'; + } else if (tmp != 1) { + // The exponent is not 1, print it. + os << "{}"_format(tmp); + } + + // Finally, print name of variable. + os << "{{{}}}"_format(*s_it); + + // Flag that we wrote something. + empty_output = false; + } + } + } + + os << "\\right)}"; +} + +extern template void key_tex_stream_insert(::std::ostream &, + const d_packed_trig_monomial &, + const symbol_set &); + } // namespace poisson_series // Lift to the obake namespace. diff --git a/src/poisson_series/d_packed_trig_monomial.cpp b/src/poisson_series/d_packed_trig_monomial.cpp index f88aa8fb..c9141989 100644 --- a/src/poisson_series/d_packed_trig_monomial.cpp +++ b/src/poisson_series/d_packed_trig_monomial.cpp @@ -19,4 +19,8 @@ template OBAKE_DLL_PUBLIC void key_stream_insert(::std::ostream &, const d_packed_trig_monomial &, const symbol_set &); +template OBAKE_DLL_PUBLIC void key_tex_stream_insert(::std::ostream &, + const d_packed_trig_monomial &, + const symbol_set &); + } // namespace obake::poisson_series diff --git a/test/d_packed_trig_monomial_00.cpp b/test/d_packed_trig_monomial_00.cpp index 83beed00..180add7f 100644 --- a/test/d_packed_trig_monomial_00.cpp +++ b/test/d_packed_trig_monomial_00.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -577,3 +578,76 @@ TEST_CASE("key_stream_insert") }); }); } + +TEST_CASE("key_tex_stream_insert") +{ + detail::tuple_for_each(int_types{}, [](const auto &n) { + using int_t = remove_cvref_t; + + detail::tuple_for_each(psizes{}, [](auto b) { + constexpr auto bw = decltype(b)::value; + using pm_t = d_packed_trig_monomial; + + auto stream = [](const pm_t &k, const symbol_set &ss) { + std::ostringstream oss; + + obake::key_tex_stream_insert(oss, k, ss); + + return oss.str(); + }; + + // Check 0/1 printing. + REQUIRE(stream(pm_t{}, symbol_set{}) == "1"); + REQUIRE(stream(pm_t{0}, symbol_set{"x"}) == "1"); + REQUIRE(stream(pm_t{0, 0, 0}, symbol_set{"x", "y", "z"}) == "1"); + + REQUIRE(stream(pm_t({}, false), symbol_set{}) == "0"); + REQUIRE(stream(pm_t({0}, false), symbol_set{"x"}) == "0"); + REQUIRE(stream(pm_t({0, 0, 0}, false), symbol_set{"x", "y", "z"}) == "0"); + + // General test cases. + REQUIRE(stream(pm_t{1}, symbol_set{"x"}) == R"(\cos{\left({x}\right)})"); + REQUIRE(stream(pm_t({1}, false), symbol_set{"x"}) == R"(\sin{\left({x}\right)})"); + + REQUIRE(stream(pm_t{1, 1}, symbol_set{"x", "y"}) == R"(\cos{\left({x}+{y}\right)})"); + REQUIRE(stream(pm_t({1, 1}, false), symbol_set{"x", "y"}) == R"(\sin{\left({x}+{y}\right)})"); + + REQUIRE(stream(pm_t{1, 2}, symbol_set{"x", "y"}) == R"(\cos{\left({x}+2{y}\right)})"); + REQUIRE(stream(pm_t({1, 2}, false), symbol_set{"x", "y"}) == R"(\sin{\left({x}+2{y}\right)})"); + + REQUIRE(stream(pm_t{-1, 2}, symbol_set{"x", "y"}) == R"(\cos{\left(-{x}+2{y}\right)})"); + REQUIRE(stream(pm_t({-1, 2}, false), symbol_set{"x", "y"}) == R"(\sin{\left(-{x}+2{y}\right)})"); + + REQUIRE(stream(pm_t{3, 2}, symbol_set{"x", "y"}) == R"(\cos{\left(3{x}+2{y}\right)})"); + REQUIRE(stream(pm_t({3, 2}, false), symbol_set{"x", "y"}) == R"(\sin{\left(3{x}+2{y}\right)})"); + + REQUIRE(stream(pm_t{-3, 2}, symbol_set{"x", "y"}) == R"(\cos{\left(-3{x}+2{y}\right)})"); + REQUIRE(stream(pm_t({-3, 2}, false), symbol_set{"x", "y"}) == R"(\sin{\left(-3{x}+2{y}\right)})"); + + REQUIRE(stream(pm_t{3, 1, 2}, symbol_set{"x", "y", "z"}) == R"(\cos{\left(3{x}+{y}+2{z}\right)})"); + REQUIRE(stream(pm_t({3, 1, 2}, false), symbol_set{"x", "y", "z"}) == R"(\sin{\left(3{x}+{y}+2{z}\right)})"); + + REQUIRE(stream(pm_t{3, -1, 2}, symbol_set{"x", "y", "z"}) == R"(\cos{\left(3{x}-{y}+2{z}\right)})"); + REQUIRE(stream(pm_t({3, -1, 2}, false), symbol_set{"x", "y", "z"}) + == R"(\sin{\left(3{x}-{y}+2{z}\right)})"); + + REQUIRE(stream(pm_t{0, 0, 2}, symbol_set{"x", "y", "z"}) == R"(\cos{\left(2{z}\right)})"); + REQUIRE(stream(pm_t({0, 0, 2}, false), symbol_set{"x", "y", "z"}) == R"(\sin{\left(2{z}\right)})"); + + REQUIRE(stream(pm_t{0, 0, 1}, symbol_set{"x", "y", "z"}) == R"(\cos{\left({z}\right)})"); + REQUIRE(stream(pm_t({0, 0, 1}, false), symbol_set{"x", "y", "z"}) == R"(\sin{\left({z}\right)})"); + + REQUIRE(stream(pm_t{2, 0, 1}, symbol_set{"x", "y", "z"}) == R"(\cos{\left(2{x}+{z}\right)})"); + REQUIRE(stream(pm_t({2, 0, 1}, false), symbol_set{"x", "y", "z"}) == R"(\sin{\left(2{x}+{z}\right)})"); + + REQUIRE(stream(pm_t{-2, 0, 1}, symbol_set{"x", "y", "z"}) == R"(\cos{\left(-2{x}+{z}\right)})"); + REQUIRE(stream(pm_t({-2, 0, 1}, false), symbol_set{"x", "y", "z"}) == R"(\sin{\left(-2{x}+{z}\right)})"); + + REQUIRE(stream(pm_t{-1, 0, 1}, symbol_set{"x", "y", "z"}) == R"(\cos{\left(-{x}+{z}\right)})"); + REQUIRE(stream(pm_t({-1, 0, 1}, false), symbol_set{"x", "y", "z"}) == R"(\sin{\left(-{x}+{z}\right)})"); + + REQUIRE(stream(pm_t{1, 0, 1}, symbol_set{"x", "y", "z"}) == R"(\cos{\left({x}+{z}\right)})"); + REQUIRE(stream(pm_t({1, 0, 1}, false), symbol_set{"x", "y", "z"}) == R"(\sin{\left({x}+{z}\right)})"); + }); + }); +} From 8993468f2c8fe200be9d5f7f527b693283d1788c Mon Sep 17 00:00:00 2001 From: Francesco Biscani Date: Wed, 3 Feb 2021 14:05:21 +0100 Subject: [PATCH 24/28] Add convenience typedef. --- include/obake/poisson_series/d_packed_trig_monomial.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/obake/poisson_series/d_packed_trig_monomial.hpp b/include/obake/poisson_series/d_packed_trig_monomial.hpp index 557a6158..6b6702d8 100644 --- a/include/obake/poisson_series/d_packed_trig_monomial.hpp +++ b/include/obake/poisson_series/d_packed_trig_monomial.hpp @@ -499,6 +499,9 @@ extern template void key_tex_stream_insert(::std::ostream &, template using d_packed_trig_monomial = poisson_series::d_packed_trig_monomial; +// Definition of the default dynamically-packed trig monomial type. +using d_trig_monomial = d_packed_trig_monomial; + } // namespace obake namespace boost::serialization From 75614d78acd37f149f0f9b6b22f2af59eabedba4 Mon Sep 17 00:00:00 2001 From: Francesco Biscani Date: Wed, 3 Feb 2021 15:40:45 +0100 Subject: [PATCH 25/28] A couple of small tweaks in the polynomial code. --- include/obake/polynomials/d_packed_monomial.hpp | 11 ++++------- include/obake/polynomials/polynomial.hpp | 3 ++- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/include/obake/polynomials/d_packed_monomial.hpp b/include/obake/polynomials/d_packed_monomial.hpp index d38edf7f..3ca95290 100644 --- a/include/obake/polynomials/d_packed_monomial.hpp +++ b/include/obake/polynomials/d_packed_monomial.hpp @@ -490,13 +490,10 @@ inline d_packed_monomial key_merge_symbols(const d_packed_monomial tmp_v; + // NOTE: store the merged monomial in a temporary + // vector and then pack it at the end. + thread_local ::std::vector tmp_v; + tmp_v.clear(); for (const auto &n : c) { kunpacker ku(n, PSize); diff --git a/include/obake/polynomials/polynomial.hpp b/include/obake/polynomials/polynomial.hpp index e20097ab..0169c41c 100644 --- a/include/obake/polynomials/polynomial.hpp +++ b/include/obake/polynomials/polynomial.hpp @@ -521,7 +521,8 @@ inline auto poly_mul_estimate_product_size(const ::std::vector &x, const ::s decltype(detail::poly_mul_impl_par_make_idx_vector(y)) vidx2; // Concurrently create the degree data for x and y, and fill - // in the vidx1/vidx2 vectors. + // in the vidx1/vidx2 vectors. vidx2 and y's degree data + // will also be sorted, if the multiplication is truncated. ::tbb::parallel_invoke( [&vidx1, &x, &ss, °ree_data, &args...]() { if constexpr (sizeof...(args) == 1u) { From 820ef050e9dc031952d3a3a9f2a859287f7a52d4 Mon Sep 17 00:00:00 2001 From: Francesco Biscani Date: Fri, 12 Feb 2021 14:49:05 +0100 Subject: [PATCH 26/28] Factor out a function for reuse. --- .../obake/polynomials/d_packed_monomial.hpp | 41 +++++++++++++------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/include/obake/polynomials/d_packed_monomial.hpp b/include/obake/polynomials/d_packed_monomial.hpp index 3ca95290..938f312b 100644 --- a/include/obake/polynomials/d_packed_monomial.hpp +++ b/include/obake/polynomials/d_packed_monomial.hpp @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -473,36 +474,42 @@ extern template void key_tex_stream_insert(::std::ostream &, const d_packed_monomial &, const symbol_set &); +namespace detail +{ + // Implementation of symbols merging. -// NOTE: requires that m is compatible with s, and ins_map consistent with s. -template -inline d_packed_monomial key_merge_symbols(const d_packed_monomial &d, - const symbol_idx_map &ins_map, const symbol_set &s) +// NOTE: requires that d is compatible with s, and ins_map consistent with s. +// NOTE: factored out for re-use. +template +inline T dpm_key_merge_symbols(const T &d, const symbol_idx_map &ins_map, const symbol_set &s) { - assert(polynomials::key_is_compatible(d, s)); + assert(::obake::key_is_compatible(d, s)); // The last element of the insertion map must be at most s.size(), which means that there // are symbols to be appended at the end. assert(ins_map.empty() || ins_map.rbegin()->first <= s.size()); + using value_type = typename T::value_type; + const auto &c = d._container(); symbol_idx idx = 0; const auto s_size = s.size(); auto map_it = ins_map.begin(); const auto map_end = ins_map.end(); - T tmp; + value_type tmp; // NOTE: store the merged monomial in a temporary // vector and then pack it at the end. - thread_local ::std::vector tmp_v; + thread_local ::std::vector tmp_v; tmp_v.clear(); for (const auto &n : c) { - kunpacker ku(n, PSize); + kunpacker ku(n, T::psize); - for (auto j = 0u; j < PSize && idx < s_size; ++j, ++idx) { + for (auto j = 0u; j < T::psize && idx < s_size; ++j, ++idx) { if (map_it != map_end && map_it->first == idx) { // We reached an index at which we need to // insert new elements. Insert as many // zeroes as necessary in the temporary vector. - tmp_v.insert(tmp_v.end(), ::obake::safe_cast(map_it->second.size()), T(0)); + tmp_v.insert(tmp_v.end(), ::obake::safe_cast(map_it->second.size()), + value_type(0)); // Move to the next element in the map. ++map_it; } @@ -517,11 +524,21 @@ inline d_packed_monomial key_merge_symbols(const d_packed_monomial(map_it->second.size()), T(0)); + tmp_v.insert(tmp_v.end(), ::obake::safe_cast(map_it->second.size()), value_type(0)); assert(map_it + 1 == map_end); } - return d_packed_monomial(tmp_v); + return T(tmp_v); +} + +} // namespace detail + +// Implementation of symbols merging. +template +inline d_packed_monomial key_merge_symbols(const d_packed_monomial &d, + const symbol_idx_map &ins_map, const symbol_set &s) +{ + return detail::dpm_key_merge_symbols(d, ins_map, s); } extern template d_packed_monomial From 953ff0785a2818426aba70f7a4e6cf2c96b3dc14 Mon Sep 17 00:00:00 2001 From: Francesco Biscani Date: Fri, 12 Feb 2021 14:49:54 +0100 Subject: [PATCH 27/28] Symbols merging for the trig monomial. --- .../poisson_series/d_packed_trig_monomial.hpp | 19 +++ src/poisson_series/d_packed_trig_monomial.cpp | 4 + test/CMakeLists.txt | 1 + test/d_packed_trig_monomial_01.cpp | 142 ++++++++++++++++++ 4 files changed, 166 insertions(+) create mode 100644 test/d_packed_trig_monomial_01.cpp diff --git a/include/obake/poisson_series/d_packed_trig_monomial.hpp b/include/obake/poisson_series/d_packed_trig_monomial.hpp index 6b6702d8..da754824 100644 --- a/include/obake/poisson_series/d_packed_trig_monomial.hpp +++ b/include/obake/poisson_series/d_packed_trig_monomial.hpp @@ -493,6 +493,25 @@ extern template void key_tex_stream_insert(::std::ostream &, const d_packed_trig_monomial &, const symbol_set &); +// Implementation of symbols merging. +template +inline d_packed_trig_monomial key_merge_symbols(const d_packed_trig_monomial &d, + const symbol_idx_map &ins_map, + const symbol_set &s) +{ + // Do the merging for the exponents. + auto ret = polynomials::detail::dpm_key_merge_symbols(d, ins_map, s); + + // Assign the type. + ret._type() = d.type(); + + return ret; +} + +extern template d_packed_trig_monomial +key_merge_symbols(const d_packed_trig_monomial &, + const symbol_idx_map &, const symbol_set &); + } // namespace poisson_series // Lift to the obake namespace. diff --git a/src/poisson_series/d_packed_trig_monomial.cpp b/src/poisson_series/d_packed_trig_monomial.cpp index c9141989..b1a66de6 100644 --- a/src/poisson_series/d_packed_trig_monomial.cpp +++ b/src/poisson_series/d_packed_trig_monomial.cpp @@ -23,4 +23,8 @@ template OBAKE_DLL_PUBLIC void key_tex_stream_insert(::std::ostream &, const d_packed_trig_monomial &, const symbol_set &); +template OBAKE_DLL_PUBLIC d_packed_trig_monomial +key_merge_symbols(const d_packed_trig_monomial &, + const symbol_idx_map &, const symbol_set &); + } // namespace obake::poisson_series diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6aceb56c..8531c52b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -98,6 +98,7 @@ ADD_OBAKE_TESTCASE(xoroshiro128_plus) ADD_OBAKE_TESTCASE(power_series_00) ADD_OBAKE_TESTCASE(power_series_01) ADD_OBAKE_TESTCASE(d_packed_trig_monomial_00) +ADD_OBAKE_TESTCASE(d_packed_trig_monomial_01) add_library(ss_fw_test_lib SHARED ss_fw_test_lib.cpp) target_compile_options(ss_fw_test_lib PRIVATE diff --git a/test/d_packed_trig_monomial_01.cpp b/test/d_packed_trig_monomial_01.cpp new file mode 100644 index 00000000..6efabab2 --- /dev/null +++ b/test/d_packed_trig_monomial_01.cpp @@ -0,0 +1,142 @@ +// Copyright 2019-2020 Francesco Biscani (bluescarni@gmail.com) +// +// This file is part of the obake library. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "catch.hpp" +#include "test_utils.hpp" + +using namespace obake; + +using int_types = std::tuple; + +// The packed sizes over which we will be testing for type T. +template +using psizes + = std::tuple, + std::integral_constant, std::integral_constant, + std::integral_constant, std::integral_constant()>>; + +TEST_CASE("key_merge_symbols_test") +{ + obake_test::disable_slow_stack_traces(); + + detail::tuple_for_each(int_types{}, [](const auto &n) { + using int_t = remove_cvref_t; + + detail::tuple_for_each(psizes{}, [](auto b) { + constexpr auto bw = decltype(b)::value; + using pm_t = d_packed_trig_monomial; + + REQUIRE(is_symbols_mergeable_key_v); + REQUIRE(is_symbols_mergeable_key_v); + REQUIRE(is_symbols_mergeable_key_v); + REQUIRE(is_symbols_mergeable_key_v); + + if constexpr (bw <= 3u) { + REQUIRE(key_merge_symbols(pm_t{}, symbol_idx_map{}, symbol_set{}) == pm_t{}); + REQUIRE(key_merge_symbols(pm_t({}, false), symbol_idx_map{}, symbol_set{}) + == pm_t({}, false)); + + REQUIRE(key_merge_symbols(pm_t{}, symbol_idx_map{{0, {"x"}}}, symbol_set{}) == pm_t{0}); + REQUIRE(key_merge_symbols(pm_t({}, false), symbol_idx_map{{0, {"x"}}}, symbol_set{}) + == pm_t({0}, false)); + + REQUIRE(key_merge_symbols(pm_t{1}, symbol_idx_map{}, symbol_set{"x"}) == pm_t{1}); + REQUIRE(key_merge_symbols(pm_t({1}, false), symbol_idx_map{}, symbol_set{"x"}) + == pm_t({1}, false)); + + REQUIRE(key_merge_symbols(pm_t{1}, symbol_idx_map{{0, {"y"}}}, symbol_set{"x"}) + == pm_t{0, 1}); + REQUIRE(key_merge_symbols(pm_t({1}, false), symbol_idx_map{{0, {"y"}}}, symbol_set{"x"}) + == pm_t({0, 1}, false)); + + REQUIRE(key_merge_symbols(pm_t{1}, symbol_idx_map{{1, {"y"}}}, symbol_set{"x"}) + == pm_t{1, 0}); + REQUIRE(key_merge_symbols(pm_t({1}, false), symbol_idx_map{{1, {"y"}}}, symbol_set{"x"}) + == pm_t({1, 0}, false)); + + REQUIRE(key_merge_symbols(pm_t{1, 2, 3}, + symbol_idx_map{{0, {"a", "b"}}, {1, {"c"}}, {3, {"d", "e"}}}, + symbol_set{"x", "y", "z"}) + == pm_t{0, 0, 1, 0, 2, 3, 0, 0}); + REQUIRE(key_merge_symbols(pm_t({1, 2, 3}, false), + symbol_idx_map{{0, {"a", "b"}}, {1, {"c"}}, {3, {"d", "e"}}}, + symbol_set{"x", "y", "z"}) + == pm_t({0, 0, 1, 0, 2, 3, 0, 0}, false)); + + REQUIRE(key_merge_symbols(pm_t{1, 2, 3}, symbol_idx_map{{3, {"d", "e"}}}, + symbol_set{"x", "y", "z"}) + == pm_t{1, 2, 3, 0, 0}); + REQUIRE(key_merge_symbols(pm_t({1, 2, 3}, false), symbol_idx_map{{3, {"d", "e"}}}, + symbol_set{"x", "y", "z"}) + == pm_t({1, 2, 3, 0, 0}, false)); + + REQUIRE(key_merge_symbols(pm_t{1, 2, 3}, symbol_idx_map{{0, {"d", "e"}}}, + symbol_set{"x", "y", "z"}) + == pm_t{0, 0, 1, 2, 3}); + REQUIRE(key_merge_symbols(pm_t({1, 2, 3}, false), symbol_idx_map{{0, {"d", "e"}}}, + symbol_set{"x", "y", "z"}) + == pm_t({0, 0, 1, 2, 3}, false)); + + REQUIRE(key_merge_symbols(pm_t{1, 2, 3}, symbol_idx_map{{1, {"d", "e"}}}, + symbol_set{"x", "y", "z"}) + == pm_t{1, 0, 0, 2, 3}); + REQUIRE(key_merge_symbols(pm_t({1, 2, 3}, false), symbol_idx_map{{1, {"d", "e"}}}, + symbol_set{"x", "y", "z"}) + == pm_t({1, 0, 0, 2, 3}, false)); + + REQUIRE(key_merge_symbols(pm_t{-1, -2, 3}, + symbol_idx_map{{0, {"a", "b"}}, {1, {"c"}}, {3, {"d", "e"}}}, + symbol_set{"x", "y", "z"}) + == pm_t{0, 0, -1, 0, -2, 3, 0, 0}); + REQUIRE(key_merge_symbols(pm_t({-1, -2, 3}, false), + symbol_idx_map{{0, {"a", "b"}}, {1, {"c"}}, {3, {"d", "e"}}}, + symbol_set{"x", "y", "z"}) + == pm_t({0, 0, -1, 0, -2, 3, 0, 0}, false)); + + REQUIRE(key_merge_symbols(pm_t{-1, -2, 3}, symbol_idx_map{{3, {"d", "e"}}}, + symbol_set{"x", "y", "z"}) + == pm_t{-1, -2, 3, 0, 0}); + REQUIRE(key_merge_symbols(pm_t({-1, -2, 3}, false), symbol_idx_map{{3, {"d", "e"}}}, + symbol_set{"x", "y", "z"}) + == pm_t({-1, -2, 3, 0, 0}, false)); + + REQUIRE(key_merge_symbols(pm_t{-1, -2, 3}, symbol_idx_map{{0, {"d", "e"}}}, + symbol_set{"x", "y", "z"}) + == pm_t{0, 0, -1, -2, 3}); + REQUIRE(key_merge_symbols(pm_t({-1, -2, 3}, false), symbol_idx_map{{0, {"d", "e"}}}, + symbol_set{"x", "y", "z"}) + == pm_t({0, 0, -1, -2, 3}, false)); + + REQUIRE(key_merge_symbols(pm_t{-1, -2, 3}, symbol_idx_map{{1, {"d", "e"}}}, + symbol_set{"x", "y", "z"}) + == pm_t{-1, 0, 0, -2, 3}); + REQUIRE(key_merge_symbols(pm_t({-1, -2, 3}, false), symbol_idx_map{{1, {"d", "e"}}}, + symbol_set{"x", "y", "z"}) + == pm_t({-1, 0, 0, -2, 3}, false)); + } + }); + }); +} From 738e4d9569eb11e0658eb0b7a6472f37be49e68a Mon Sep 17 00:00:00 2001 From: Francesco Biscani Date: Sun, 6 Jun 2021 23:16:50 +0200 Subject: [PATCH 28/28] Fix after merge. --- include/obake/polynomials/d_packed_monomial.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/obake/polynomials/d_packed_monomial.hpp b/include/obake/polynomials/d_packed_monomial.hpp index fc9e4390..b3616cc9 100644 --- a/include/obake/polynomials/d_packed_monomial.hpp +++ b/include/obake/polynomials/d_packed_monomial.hpp @@ -491,10 +491,10 @@ inline T dpm_key_merge_symbols(const T &d, const symbol_idx_map &ins const auto s_size = s.size(); auto map_it = ins_map.begin(); const auto map_end = ins_map.end(); - T tmp; + value_type tmp; // NOTE: store the merged monomial in a temporary // vector and then pack it at the end. - thread_local ::std::vector tmp_v; + thread_local ::std::vector tmp_v; tmp_v.clear(); for (const auto &n : c) { kunpacker ku(n, T::psize);